nut-2.8.1/0000755000175000017500000000000014520277777007353 500000000000000nut-2.8.1/LICENSE-GPL30000644000175000017500000010437414273170601010773 00000000000000 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 . nut-2.8.1/NEWS0000644000175000017500000000005114517510721007747 00000000000000Please see NEWS.adoc for actual contents nut-2.8.1/data/0000755000175000017500000000000014520277776010263 500000000000000nut-2.8.1/data/html/0000755000175000017500000000000014520277775011226 500000000000000nut-2.8.1/data/html/nut-banner.png0000644000175000017500000000527614273170601013720 00000000000000PNG  IHDR("S$PLTE?8Uql tEXtSoftwaregif2png 1.1.1,!qtEXtmimencode_-d_gzip_-dc H4sICOfSNEAAA3owAKVUS2/jNhA+h79ijglq0ZQc+aFsF039wLpYZQPLLQoUPdDy2GZXJgWS ipOiP75D2Umd3Q1aoLyIEGe+x8yQM2v2MJHWouZ5eYeqqn6QdVnykv4vdw3McAXxCMQgi9NM JJAIcc0W6Buro3vpdxm8eyP9PYWVqB5wncEm0GgX4R7l3kv+QnH5Wz/h8YAnaY+PRr9fsYvV E2xR2pV55PhYV0Z5x43dwuWQxxQquqfvFRyU38G0yJf3oNag4p8ms9jNhYiHaZ9dbIyFd/az NSTpHOj9TfDVCaaCt+Dn2V0MkegL8aXuUre6tdtLVfGwDfpP8uN0xJM4JUGCXwcD8LLIyTct fzS+cTAxe6UNLLBC6RD6XPDeefZrd0GmSOJRnKTDdCDSKIn7AwE3ZwlfuYqTLB1m6QC+E7SA /RrlZABtBkcFd8ajexGQkoABQC5tuYMk7gSMmOXzfBr9gtYpozOIuWBFs/oDS5/B7f0YSrmq ENboCdixpcm+XXKWo3Nyi9F8QhGfZv3r3nT843jCR4NBcivGw+jT3VAkaX/am3GSnl4Pr3tn gzSjNmRvjSmbSI/Zv9kP7snL0srycwYFWiUr9SeGJi1M49GC0ZArrc2hO82nt12yN7581Z2/ Cqw97lcUm/Tb+vSuQHpGrF2RdF+RdtjFnGJPDG0XifPhSBPw82VLQZ//SEIMxPPa2X1OPG94 +b8kIj7diS9IqOJ1hR4p/o1wNjbao/aRf6qpMR4ffbeupNI3UO6kdei//7mIbovxfM4KL2kU M1iwl/VBdRibE4JF55XegjdgUa6DKb9DOFCDn0xjn8cO5IpMt0dhJIu9tB4KtdWyqiidtTPK GZs+oIa9sQjqDPwgHaWSF4IEWfqGsp6gblaVcjtc05lyZ8wdkI6F/TO52bRHx4sgbaiP3qg1 2ad6cZpK/ErRKVgdgT6qEnWJEN6roN+ZjT8QUId2pBRws6Hr1srbyQdKI4xtK7I0tcI1q44A rkUIdamtWTclXT3GiN79o7XNXyGVoZbOBXOmFW9pNqg4nhgbS0iUuMCttGtHnTjeOjjdOiqj K2UlPb0HUDR1bcjaVG+VRrShezvv66zbPRwOz48k/fwb3RDCHGYGAAA= NG~IDATxYMOWf1` ɂՊ]Yb{e%%"ɤ ;T7cpdqEߝ܏!O<ʃ_ۀE6`A@#&@|9 ϗv EYYk48 dlp>ܫLU^}ا<@BQQpm%!0 _|'r\ y\.nt2Yͱy[]%JD=R"Gy+G g^tUS|h8_,JPEz"A!+" }..<6f%jf2Ni.`6?xPﰹP 2"==u In 7?30lt4xnjSMډӧg_13q| EX>XXDהKMqk@Q>ֳ_;TVl Mi`L+wm'Q _n8\@@ Y__Q[ Y@ C6Qf%eI&m5%*Ɩ+؉!%y߳݌2V @>8 ;kۄNIzz}h)]DP&K^d(5F#@Ʃ+jnsޱbç@uFBs| h3aj"PnlQ<hVj,uڴ)+VuX ľ6=yI}ޚ kuIng3crﳍ*hkFg?=8yd.?{B% hbPIENDB`nut-2.8.1/data/html/bottom.html0000644000175000017500000000007614273170601013324 00000000000000 nut-2.8.1/data/html/Makefile.in0000644000175000017500000005403314520274662013210 00000000000000# Makefile.in generated by automake 1.16.5 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2021 Free Software Foundation, Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. @SET_MAKE@ VPATH = @srcdir@ am__is_gnu_make = { \ if test -z '$(MAKELEVEL)'; then \ false; \ elif test -n '$(MAKE_HOST)'; then \ true; \ elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \ true; \ else \ false; \ fi; \ } am__make_running_with_option = \ case $${target_option-} in \ ?) ;; \ *) echo "am__make_running_with_option: internal error: invalid" \ "target option '$${target_option-}' specified" >&2; \ exit 1;; \ esac; \ has_opt=no; \ sane_makeflags=$$MAKEFLAGS; \ if $(am__is_gnu_make); then \ sane_makeflags=$$MFLAGS; \ else \ case $$MAKEFLAGS in \ *\\[\ \ ]*) \ bs=\\; \ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ esac; \ fi; \ skip_next=no; \ strip_trailopt () \ { \ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ }; \ for flg in $$sane_makeflags; do \ test $$skip_next = yes && { skip_next=no; continue; }; \ case $$flg in \ *=*|--*) continue;; \ -*I) strip_trailopt 'I'; skip_next=yes;; \ -*I?*) strip_trailopt 'I';; \ -*O) strip_trailopt 'O'; skip_next=yes;; \ -*O?*) strip_trailopt 'O';; \ -*l) strip_trailopt 'l'; skip_next=yes;; \ -*l?*) strip_trailopt 'l';; \ -[dEDm]) skip_next=yes;; \ -[JT]) skip_next=yes;; \ esac; \ case $$flg in \ *$$target_option*) has_opt=yes; break;; \ esac; \ done; \ test $$has_opt = yes am__make_dryrun = (target_option=n; $(am__make_running_with_option)) am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkglibexecdir = $(libexecdir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ target_triplet = @target@ subdir = data/html ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/m4/ax_c___attribute__.m4 \ $(top_srcdir)/m4/ax_c_pragmas.m4 \ $(top_srcdir)/m4/ax_check_compile_flag.m4 \ $(top_srcdir)/m4/ax_compare_version.m4 \ $(top_srcdir)/m4/ax_realpath.m4 \ $(top_srcdir)/m4/ax_run_or_link_ifelse.m4 \ $(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \ $(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \ $(top_srcdir)/m4/lt~obsolete.m4 \ $(top_srcdir)/m4/nut_arg_with.m4 \ $(top_srcdir)/m4/nut_check_asciidoc.m4 \ $(top_srcdir)/m4/nut_check_aspell.m4 \ $(top_srcdir)/m4/nut_check_cppcheck.m4 \ $(top_srcdir)/m4/nut_check_headers_windows.m4 \ $(top_srcdir)/m4/nut_check_libavahi.m4 \ $(top_srcdir)/m4/nut_check_libfreeipmi.m4 \ $(top_srcdir)/m4/nut_check_libgd.m4 \ $(top_srcdir)/m4/nut_check_libgpiod.m4 \ $(top_srcdir)/m4/nut_check_libltdl.m4 \ $(top_srcdir)/m4/nut_check_libmodbus.m4 \ $(top_srcdir)/m4/nut_check_libneon.m4 \ $(top_srcdir)/m4/nut_check_libnetsnmp.m4 \ $(top_srcdir)/m4/nut_check_libnss.m4 \ $(top_srcdir)/m4/nut_check_libopenssl.m4 \ $(top_srcdir)/m4/nut_check_libpowerman.m4 \ $(top_srcdir)/m4/nut_check_libregex.m4 \ $(top_srcdir)/m4/nut_check_libsystemd.m4 \ $(top_srcdir)/m4/nut_check_libusb.m4 \ $(top_srcdir)/m4/nut_check_libwrap.m4 \ $(top_srcdir)/m4/nut_check_os.m4 \ $(top_srcdir)/m4/nut_check_pkgconfig.m4 \ $(top_srcdir)/m4/nut_check_python.m4 \ $(top_srcdir)/m4/nut_check_socketlib.m4 \ $(top_srcdir)/m4/nut_compiler_family.m4 \ $(top_srcdir)/m4/nut_func_getnameinfo_argtypes.m4 \ $(top_srcdir)/m4/nut_report_feature.m4 \ $(top_srcdir)/m4/nut_stash_warnings.m4 \ $(top_srcdir)/m4/nut_type_socklen_t.m4 \ $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) DIST_COMMON = $(srcdir)/Makefile.am $(am__dist_html_DATA_DIST) \ $(am__DIST_COMMON) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/include/config.h CONFIG_CLEAN_FILES = header.html CONFIG_CLEAN_VPATH_FILES = AM_V_P = $(am__v_P_@AM_V@) am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) am__v_P_0 = false am__v_P_1 = : AM_V_GEN = $(am__v_GEN_@AM_V@) am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) am__v_GEN_0 = @echo " GEN " $@; am__v_GEN_1 = AM_V_at = $(am__v_at_@AM_V@) am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) am__v_at_0 = @ am__v_at_1 = SOURCES = DIST_SOURCES = am__can_run_installinfo = \ case $$AM_UPDATE_INFO_DIR in \ n|no|NO) false;; \ *) (install-info --version) >/dev/null 2>&1;; \ esac am__dist_html_DATA_DIST = index.html bottom.html nut-banner.png am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; am__vpath_adj = case $$p in \ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ *) f=$$p;; \ esac; am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`; am__install_max = 40 am__nobase_strip_setup = \ srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'` am__nobase_strip = \ for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||" am__nobase_list = $(am__nobase_strip_setup); \ for p in $$list; do echo "$$p $$p"; done | \ sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \ $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \ if (++n[$$2] == $(am__install_max)) \ { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \ END { for (dir in files) print dir, files[dir] }' am__base_list = \ sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' am__uninstall_files_from_dir = { \ test -z "$$files" \ || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \ || { echo " ( cd '$$dir' && rm -f" $$files ")"; \ $(am__cd) "$$dir" && rm -f $$files; }; \ } am__installdirs = "$(DESTDIR)$(htmldir)" "$(DESTDIR)$(htmldir)" DATA = $(dist_html_DATA) $(nodist_html_DATA) am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) am__DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/header.html.in \ README DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) A2X = @A2X@ ACLOCAL = @ACLOCAL@ ALTPIDPATH = @ALTPIDPATH@ AMTAR = @AMTAR@ AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ AR = @AR@ ASCIIDOC = @ASCIIDOC@ ASPELL = @ASPELL@ ASPELL_FILTER_LIB_PATH = @ASPELL_FILTER_LIB_PATH@ ASPELL_FILTER_SHARE_PATH = @ASPELL_FILTER_SHARE_PATH@ ASPELL_FILTER_TEX_PATH = @ASPELL_FILTER_TEX_PATH@ AUGPARSE = @AUGPARSE@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ BINDIR = @BINDIR@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CONFIG_FLAGS = @CONFIG_FLAGS@ CONFPATH = @CONFPATH@ CPP = @CPP@ CPPCHECK = @CPPCHECK@ CPPFLAGS = @CPPFLAGS@ CPPUNIT_CFLAGS = @CPPUNIT_CFLAGS@ CPPUNIT_LIBS = @CPPUNIT_LIBS@ CSCOPE = @CSCOPE@ CTAGS = @CTAGS@ CXX = @CXX@ CXXCPP = @CXXCPP@ CXXDEPMODE = @CXXDEPMODE@ CXXFLAGS = @CXXFLAGS@ CYGPATH_W = @CYGPATH_W@ DBLATEX = @DBLATEX@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ DEPLOYED_UPSC = @DEPLOYED_UPSC@ DEPLOYED_UPSD = @DEPLOYED_UPSD@ DLLTOOL = @DLLTOOL@ DOC_BUILD_LIST = @DOC_BUILD_LIST@ DOC_CHECK_LIST = @DOC_CHECK_LIST@ DRIVER_BUILD_LIST = @DRIVER_BUILD_LIST@ DRIVER_INSTALL_TARGET = @DRIVER_INSTALL_TARGET@ DRIVER_MAN_LIST = @DRIVER_MAN_LIST@ DRIVER_MAN_LIST_PAGES = @DRIVER_MAN_LIST_PAGES@ DRVPATH = @DRVPATH@ DSYMUTIL = @DSYMUTIL@ DUMPBIN = @DUMPBIN@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ ETAGS = @ETAGS@ EXEEXT = @EXEEXT@ FGREP = @FGREP@ FORCE_NUT_VERSION = @FORCE_NUT_VERSION@ GDLIB_CONFIG = @GDLIB_CONFIG@ GREP = @GREP@ HAVE_SYS_SOCKET_H = @HAVE_SYS_SOCKET_H@ HAVE_WINSOCK2_H = @HAVE_WINSOCK2_H@ HAVE_WS2TCPIP_H = @HAVE_WS2TCPIP_H@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ LD = @LD@ LDFLAGS = @LDFLAGS@ LIBAVAHI_CFLAGS = @LIBAVAHI_CFLAGS@ LIBAVAHI_LIBS = @LIBAVAHI_LIBS@ LIBDIR = @LIBDIR@ LIBGD_CFLAGS = @LIBGD_CFLAGS@ LIBGD_LDFLAGS = @LIBGD_LDFLAGS@ LIBGPIO_CFLAGS = @LIBGPIO_CFLAGS@ LIBGPIO_LIBS = @LIBGPIO_LIBS@ LIBI2C_LIBS = @LIBI2C_LIBS@ LIBIPMI_CFLAGS = @LIBIPMI_CFLAGS@ LIBIPMI_LIBS = @LIBIPMI_LIBS@ LIBLTDL_CFLAGS = @LIBLTDL_CFLAGS@ LIBLTDL_LIBS = @LIBLTDL_LIBS@ LIBMODBUS_CFLAGS = @LIBMODBUS_CFLAGS@ LIBMODBUS_LIBS = @LIBMODBUS_LIBS@ LIBNEON_CFLAGS = @LIBNEON_CFLAGS@ LIBNEON_LIBS = @LIBNEON_LIBS@ LIBNETSNMP_CFLAGS = @LIBNETSNMP_CFLAGS@ LIBNETSNMP_LIBS = @LIBNETSNMP_LIBS@ LIBOBJS = @LIBOBJS@ LIBPOWERMAN_CFLAGS = @LIBPOWERMAN_CFLAGS@ LIBPOWERMAN_LIBS = @LIBPOWERMAN_LIBS@ LIBREGEX_LIBS = @LIBREGEX_LIBS@ LIBS = @LIBS@ LIBSSL_CFLAGS = @LIBSSL_CFLAGS@ LIBSSL_LIBS = @LIBSSL_LIBS@ LIBSSL_REQUIRES = @LIBSSL_REQUIRES@ LIBSYSTEMD_CFLAGS = @LIBSYSTEMD_CFLAGS@ LIBSYSTEMD_LIBS = @LIBSYSTEMD_LIBS@ LIBTOOL = @LIBTOOL@ LIBTOOL_DEPS = @LIBTOOL_DEPS@ LIBUSB_CFLAGS = @LIBUSB_CFLAGS@ LIBUSB_CONFIG = @LIBUSB_CONFIG@ LIBUSB_LIBS = @LIBUSB_LIBS@ LIBWRAP_CFLAGS = @LIBWRAP_CFLAGS@ LIBWRAP_LIBS = @LIBWRAP_LIBS@ LIPO = @LIPO@ LN_S = @LN_S@ LN_S_R = @LN_S_R@ LTLIBOBJS = @LTLIBOBJS@ LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@ MAINT = @MAINT@ MAKEINFO = @MAKEINFO@ MANIFEST_TOOL = @MANIFEST_TOOL@ MKDIR_P = @MKDIR_P@ MSGFMT = @MSGFMT@ NETLIBS = @NETLIBS@ NET_SNMP_CONFIG = @NET_SNMP_CONFIG@ NM = @NM@ NMEDIT = @NMEDIT@ NUT_DATADIR = @NUT_DATADIR@ NUT_LIBEXECDIR = @NUT_LIBEXECDIR@ NUT_NETVERSION = @NUT_NETVERSION@ NUT_SOURCE_GITREV = @NUT_SOURCE_GITREV@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ OS_NAME = @OS_NAME@ OTOOL = @OTOOL@ OTOOL64 = @OTOOL64@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_SEPARATOR = @PATH_SEPARATOR@ PIDPATH = @PIDPATH@ PKGCONFIGDIR = @PKGCONFIGDIR@ PKG_CONFIG = @PKG_CONFIG@ PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@ PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ PORT = @PORT@ POWERDOWNFLAG = @POWERDOWNFLAG@ PREFIX = @PREFIX@ PYTHON = @PYTHON@ PYTHON2 = @PYTHON2@ PYTHON2_SITE_PACKAGES = @PYTHON2_SITE_PACKAGES@ PYTHON3 = @PYTHON3@ PYTHON3_SITE_PACKAGES = @PYTHON3_SITE_PACKAGES@ PYTHON_SITE_PACKAGES = @PYTHON_SITE_PACKAGES@ RANLIB = @RANLIB@ REALPATH = @REALPATH@ RUN_AS_GROUP = @RUN_AS_GROUP@ RUN_AS_USER = @RUN_AS_USER@ SBINDIR = @SBINDIR@ SED = @SED@ SEMLIBS = @SEMLIBS@ SERLIBS = @SERLIBS@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ SOURCE_HIGHLIGHT = @SOURCE_HIGHLIGHT@ STATEPATH = @STATEPATH@ STRIP = @STRIP@ SUN_LIBUSB = @SUN_LIBUSB@ SYSTEMD_ANALYZE_PROGRAM = @SYSTEMD_ANALYZE_PROGRAM@ SYSTEMD_DAEMON_ARGS_DRIVER = @SYSTEMD_DAEMON_ARGS_DRIVER@ SYSTEMD_DAEMON_ARGS_UPSD = @SYSTEMD_DAEMON_ARGS_UPSD@ SYSTEMD_DAEMON_ARGS_UPSMON = @SYSTEMD_DAEMON_ARGS_UPSMON@ SYSTEMD_DAEMON_NOTIFYACCESS_DRIVER = @SYSTEMD_DAEMON_NOTIFYACCESS_DRIVER@ SYSTEMD_DAEMON_NOTIFYACCESS_UPSD = @SYSTEMD_DAEMON_NOTIFYACCESS_UPSD@ SYSTEMD_DAEMON_NOTIFYACCESS_UPSMON = @SYSTEMD_DAEMON_NOTIFYACCESS_UPSMON@ SYSTEMD_DAEMON_TYPE_DRIVER = @SYSTEMD_DAEMON_TYPE_DRIVER@ SYSTEMD_DAEMON_TYPE_UPSD = @SYSTEMD_DAEMON_TYPE_UPSD@ SYSTEMD_DAEMON_TYPE_UPSMON = @SYSTEMD_DAEMON_TYPE_UPSMON@ SYSTEMD_DAEMON_WATCHDOG_DRIVER = @SYSTEMD_DAEMON_WATCHDOG_DRIVER@ SYSTEMD_DAEMON_WATCHDOG_UPSD = @SYSTEMD_DAEMON_WATCHDOG_UPSD@ SYSTEMD_DAEMON_WATCHDOG_UPSMON = @SYSTEMD_DAEMON_WATCHDOG_UPSMON@ SYSTEMD_TMPFILES_PROGRAM = @SYSTEMD_TMPFILES_PROGRAM@ TREE_VERSION = @TREE_VERSION@ VALGRIND = @VALGRIND@ VERSION = @VERSION@ WINDMC = @WINDMC@ WINDRES = @WINDRES@ WORDS_BIGENDIAN = @WORDS_BIGENDIAN@ XMLLINT = @XMLLINT@ XSLTPROC = @XSLTPROC@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_AR = @ac_ct_AR@ ac_ct_CC = @ac_ct_CC@ ac_ct_CXX = @ac_ct_CXX@ ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__tar = @am__tar@ am__untar = @am__untar@ auglensdir = @auglensdir@ bindir = @bindir@ build = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ cgiexecdir = @cgiexecdir@ datadir = @datadir@ datarootdir = @datarootdir@ devddir = @devddir@ docdir = @docdir@ driverexecdir = @driverexecdir@ dummy_PKG_CONFIG = @dummy_PKG_CONFIG@ dummy_PKG_CONFIG_CFLAGS = @dummy_PKG_CONFIG_CFLAGS@ dummy_PKG_CONFIG_LIBS = @dummy_PKG_CONFIG_LIBS@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ hotplugdir = @hotplugdir@ htmldir = @htmldir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libdir = @libdir@ libexecdir = @libexecdir@ localedir = @localedir@ localstatedir = @localstatedir@ mandir = @mandir@ mkdir_p = @mkdir_p@ now = @now@ nut_with_nut_monitor = @nut_with_nut_monitor@ nut_with_nut_monitor_desktop = @nut_with_nut_monitor_desktop@ nut_with_nut_monitor_dir = @nut_with_nut_monitor_dir@ nut_with_nut_monitor_py2gtk2 = @nut_with_nut_monitor_py2gtk2@ nut_with_nut_monitor_py3qt5 = @nut_with_nut_monitor_py3qt5@ nut_with_pynut = @nut_with_pynut@ nut_with_pynut_py = @nut_with_pynut_py@ nut_with_pynut_py2 = @nut_with_pynut_py2@ nut_with_pynut_py3 = @nut_with_pynut_py3@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ pkgconfigdir = @pkgconfigdir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ runstatedir = @runstatedir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ sysconfdir = @sysconfdir@ systemdshutdowndir = @systemdshutdowndir@ systemdsystemunitdir = @systemdsystemunitdir@ systemdtmpfilesdir = @systemdtmpfilesdir@ target = @target@ target_alias = @target_alias@ target_cpu = @target_cpu@ target_os = @target_os@ target_vendor = @target_vendor@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ udevdir = @udevdir@ # Network UPS Tools: data/html # install these only if configured --with-cgi @WITH_CGI_TRUE@dist_html_DATA = index.html bottom.html nut-banner.png @WITH_CGI_TRUE@nodist_html_DATA = header.html EXTRA_DIST = README MAINTAINERCLEANFILES = Makefile.in .dirstamp # Generated by configure script: DISTCLEANFILES = header.html all: all-am .SUFFIXES: $(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu data/html/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --gnu data/html/Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): header.html: $(top_builddir)/config.status $(srcdir)/header.html.in cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ mostlyclean-libtool: -rm -f *.lo clean-libtool: -rm -rf .libs _libs install-dist_htmlDATA: $(dist_html_DATA) @$(NORMAL_INSTALL) @list='$(dist_html_DATA)'; test -n "$(htmldir)" || list=; \ if test -n "$$list"; then \ echo " $(MKDIR_P) '$(DESTDIR)$(htmldir)'"; \ $(MKDIR_P) "$(DESTDIR)$(htmldir)" || exit 1; \ fi; \ for p in $$list; do \ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ echo "$$d$$p"; \ done | $(am__base_list) | \ while read files; do \ echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(htmldir)'"; \ $(INSTALL_DATA) $$files "$(DESTDIR)$(htmldir)" || exit $$?; \ done uninstall-dist_htmlDATA: @$(NORMAL_UNINSTALL) @list='$(dist_html_DATA)'; test -n "$(htmldir)" || list=; \ files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ dir='$(DESTDIR)$(htmldir)'; $(am__uninstall_files_from_dir) install-nodist_htmlDATA: $(nodist_html_DATA) @$(NORMAL_INSTALL) @list='$(nodist_html_DATA)'; test -n "$(htmldir)" || list=; \ if test -n "$$list"; then \ echo " $(MKDIR_P) '$(DESTDIR)$(htmldir)'"; \ $(MKDIR_P) "$(DESTDIR)$(htmldir)" || exit 1; \ fi; \ for p in $$list; do \ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ echo "$$d$$p"; \ done | $(am__base_list) | \ while read files; do \ echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(htmldir)'"; \ $(INSTALL_DATA) $$files "$(DESTDIR)$(htmldir)" || exit $$?; \ done uninstall-nodist_htmlDATA: @$(NORMAL_UNINSTALL) @list='$(nodist_html_DATA)'; test -n "$(htmldir)" || list=; \ files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ dir='$(DESTDIR)$(htmldir)'; $(am__uninstall_files_from_dir) tags TAGS: ctags CTAGS: cscope cscopelist: distdir: $(BUILT_SOURCES) $(MAKE) $(AM_MAKEFLAGS) distdir-am distdir-am: $(DISTFILES) @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ dist_files=`for file in $$list; do echo $$file; done | \ sed -e "s|^$$srcdirstrip/||;t" \ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ case $$dist_files in \ */*) $(MKDIR_P) `echo "$$dist_files" | \ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ sort -u` ;; \ esac; \ for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d "$(distdir)/$$file"; then \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ else \ test -f "$(distdir)/$$file" \ || cp -p $$d/$$file "$(distdir)/$$file" \ || exit 1; \ fi; \ done check-am: all-am check: check-am all-am: Makefile $(DATA) installdirs: for dir in "$(DESTDIR)$(htmldir)" "$(DESTDIR)$(htmldir)"; do \ test -z "$$dir" || $(MKDIR_P) "$$dir"; \ done install: install-am install-exec: install-exec-am install-data: install-data-am uninstall: uninstall-am install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-am install-strip: if test -z '$(STRIP)'; then \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ install; \ else \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ fi mostlyclean-generic: clean-generic: distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) -test -z "$(DISTCLEANFILES)" || rm -f $(DISTCLEANFILES) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." -test -z "$(MAINTAINERCLEANFILES)" || rm -f $(MAINTAINERCLEANFILES) clean: clean-am clean-am: clean-generic clean-libtool mostlyclean-am distclean: distclean-am -rm -f Makefile distclean-am: clean-am distclean-generic dvi: dvi-am dvi-am: html: html-am html-am: info: info-am info-am: install-data-am: install-dist_htmlDATA install-nodist_htmlDATA install-dvi: install-dvi-am install-dvi-am: install-exec-am: install-html: install-html-am install-html-am: install-info: install-info-am install-info-am: install-man: install-pdf: install-pdf-am install-pdf-am: install-ps: install-ps-am install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-am -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-am mostlyclean-am: mostlyclean-generic mostlyclean-libtool pdf: pdf-am pdf-am: ps: ps-am ps-am: uninstall-am: uninstall-dist_htmlDATA uninstall-nodist_htmlDATA .MAKE: install-am install-strip .PHONY: all all-am check check-am clean clean-generic clean-libtool \ cscopelist-am ctags-am distclean distclean-generic \ distclean-libtool distdir dvi dvi-am html html-am info info-am \ install install-am install-data install-data-am \ install-dist_htmlDATA install-dvi install-dvi-am install-exec \ install-exec-am install-html install-html-am install-info \ install-info-am install-man install-nodist_htmlDATA \ install-pdf install-pdf-am install-ps install-ps-am \ install-strip installcheck installcheck-am installdirs \ maintainer-clean maintainer-clean-generic mostlyclean \ mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \ tags-am uninstall uninstall-am uninstall-dist_htmlDATA \ uninstall-nodist_htmlDATA .PRECIOUS: Makefile # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: nut-2.8.1/data/html/Makefile.am0000644000175000017500000000046714500336654013177 00000000000000# Network UPS Tools: data/html # install these only if configured --with-cgi if WITH_CGI dist_html_DATA = index.html bottom.html nut-banner.png nodist_html_DATA = header.html endif EXTRA_DIST = README MAINTAINERCLEANFILES = Makefile.in .dirstamp # Generated by configure script: DISTCLEANFILES = header.html nut-2.8.1/data/html/index.html0000644000175000017500000000077014501607135013131 00000000000000 Network UPS Tools -- https://www.networkupstools.org <body> </body> nut-2.8.1/data/html/README0000644000175000017500000000524514273170601012015 00000000000000Desc: NUT HTML complementary information File: README Date: 27 Jul 2005 Auth: Arnaud Quette Dave Breiland This file provides some complementary information about the use and integration of NUT HTML pages. 1) Introduction --------------- NUT HTML pages have been created as a central point that ease the access to the various CGI scripts providing the NUT web interface. It consists of three .html files: - index.html: defines the two container frames, topFrame and mainFrame - header.html: contain the header including links to NUT website, and upsstat.cgi/upsset.cgi - bottom.html: empty frame that will be replaced with the content of upsstat.cgi or upsset.cgi. 2) Integration -------------- You first need to install NUT CGI (ie using ./configure --with-cgi). Refer to the README file for more information There are two ways to integrate NUT HTML with your webserver, with the same results: a) take advantage of the existing tree ====================================== - the cgi are for example installed in /usr/lib/cgi-bin, which is already configured in your webserver as the default CGI path - in the same spirit, we will use the existing DocumentRoot and create a "nut" subdirectory, and copy the three .html files (index, header and bottom) Note that the links to cgi scripts in header.html are pre configured to work in this situation, which ease the packagers work. b) configure manually ===================== - copy the data/html directory to somepath (ie /usr/local/nut for a standard installation from source) -Now edit your webserver configuration file, adding for example (for Apache): #Begin Section ScriptAlias /nut/cgi-bin/ /usr/local/nut/cgi-bin/ AllowOverride AuthConfig Options ExecCGI Order allow,deny Allow from all Alias /nut/ /usr/local/nut/html/ Options None AllowOverride AuthConfig Order allow,deny Allow from all #End Section -Make sure to change the links path in header.html according to your configuration and installation. 3) Conclusion ============= - Make sure to restart your webserver. -Configure the CGI scripts. Manpages can be found from: --prompt> man -M /usr/local/nut/man/ upsstats.cgi --prompt> man -M /usr/local/nut/man/ upsset.cgi --prompt> man -M /usr/local/nut/man/ upsimage.cgi --prompt> man -M /usr/local/nut/man/ hosts.conf -It is recommended that you use .htaccess files in the cgi-bin folder and the html folder. Please reference: http://httpd.apache.org/docs/howto/htaccess.html - You will then be able to access the NUT HTML page at: http://localhost/nut nut-2.8.1/data/html/header.html.in0000644000175000017500000000115714501607135013657 00000000000000 Network UPS Tools

Statistics Settings
nut-2.8.1/data/evolution500.seq0000644000175000017500000000257214501607123013152 00000000000000# dummy-ups example power sequence file # # Base is the same as .dev files, generated using: # $ upsc ups@host > evolution500.seq # # TIMER have then been added to generate power events. battery.charge: 90 battery.charge.low: 30 battery.runtime: 3690 battery.voltage: 230.0 driver.name: usbhid-ups driver.parameter.port: auto driver.version: 2.2.0 driver.version.data: MGE HID 0.7 driver.version.internal: 0.23 input.frequency: 49.0 input.transfer.boost.low: 184.0 input.transfer.high: 294.0 input.transfer.low: 160.0 input.transfer.trim.high: 265.0 input.voltage: 230.0 outlet.desc: Main Outlet outlet.id: 0 outlet.switchable: 0 outlet.1.autoswitch.charge.low: 0 outlet.1.delay.shutdown: -1 outlet.1.delay.start: -1 outlet.1.desc: PowerShare Outlet 1 outlet.1.id: 1 outlet.1.switch: 1 outlet.1.switchable: 1 outlet.2.autoswitch.charge.low: 0 outlet.2.delay.shutdown: -1 outlet.2.delay.start: -1 outlet.2.desc: PowerShare Outlet 2 outlet.2.id: 2 outlet.2.switch: 1 outlet.2.switchable: 1 output.current: 0.00 output.frequency: 49.0 output.voltage: 230.0 output.voltage.nominal: 230.0 ups.delay.shutdown: -1 ups.delay.start: -10 ups.load: 10 ups.mfr: MGE UPS SYSTEMS ups.model: Pulsar Evolution 500 ups.power.nominal: 500 ups.serial: AV2G3300L ups.status: OL CHRG ups.test.interval: 604800 ups.test.result: Done and passed TIMER 300 ups.status: OB DISCHRG TIMER 300 ups.status: OB LB DISCHRG TIMER 60 nut-2.8.1/data/Makefile.in0000644000175000017500000007143714520274662012253 00000000000000# Makefile.in generated by automake 1.16.5 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2021 Free Software Foundation, Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. @SET_MAKE@ # Network UPS Tools: data VPATH = @srcdir@ am__is_gnu_make = { \ if test -z '$(MAKELEVEL)'; then \ false; \ elif test -n '$(MAKE_HOST)'; then \ true; \ elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \ true; \ else \ false; \ fi; \ } am__make_running_with_option = \ case $${target_option-} in \ ?) ;; \ *) echo "am__make_running_with_option: internal error: invalid" \ "target option '$${target_option-}' specified" >&2; \ exit 1;; \ esac; \ has_opt=no; \ sane_makeflags=$$MAKEFLAGS; \ if $(am__is_gnu_make); then \ sane_makeflags=$$MFLAGS; \ else \ case $$MAKEFLAGS in \ *\\[\ \ ]*) \ bs=\\; \ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ esac; \ fi; \ skip_next=no; \ strip_trailopt () \ { \ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ }; \ for flg in $$sane_makeflags; do \ test $$skip_next = yes && { skip_next=no; continue; }; \ case $$flg in \ *=*|--*) continue;; \ -*I) strip_trailopt 'I'; skip_next=yes;; \ -*I?*) strip_trailopt 'I';; \ -*O) strip_trailopt 'O'; skip_next=yes;; \ -*O?*) strip_trailopt 'O';; \ -*l) strip_trailopt 'l'; skip_next=yes;; \ -*l?*) strip_trailopt 'l';; \ -[dEDm]) skip_next=yes;; \ -[JT]) skip_next=yes;; \ esac; \ case $$flg in \ *$$target_option*) has_opt=yes; break;; \ esac; \ done; \ test $$has_opt = yes am__make_dryrun = (target_option=n; $(am__make_running_with_option)) am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkglibexecdir = $(libexecdir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ target_triplet = @target@ subdir = data ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/m4/ax_c___attribute__.m4 \ $(top_srcdir)/m4/ax_c_pragmas.m4 \ $(top_srcdir)/m4/ax_check_compile_flag.m4 \ $(top_srcdir)/m4/ax_compare_version.m4 \ $(top_srcdir)/m4/ax_realpath.m4 \ $(top_srcdir)/m4/ax_run_or_link_ifelse.m4 \ $(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \ $(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \ $(top_srcdir)/m4/lt~obsolete.m4 \ $(top_srcdir)/m4/nut_arg_with.m4 \ $(top_srcdir)/m4/nut_check_asciidoc.m4 \ $(top_srcdir)/m4/nut_check_aspell.m4 \ $(top_srcdir)/m4/nut_check_cppcheck.m4 \ $(top_srcdir)/m4/nut_check_headers_windows.m4 \ $(top_srcdir)/m4/nut_check_libavahi.m4 \ $(top_srcdir)/m4/nut_check_libfreeipmi.m4 \ $(top_srcdir)/m4/nut_check_libgd.m4 \ $(top_srcdir)/m4/nut_check_libgpiod.m4 \ $(top_srcdir)/m4/nut_check_libltdl.m4 \ $(top_srcdir)/m4/nut_check_libmodbus.m4 \ $(top_srcdir)/m4/nut_check_libneon.m4 \ $(top_srcdir)/m4/nut_check_libnetsnmp.m4 \ $(top_srcdir)/m4/nut_check_libnss.m4 \ $(top_srcdir)/m4/nut_check_libopenssl.m4 \ $(top_srcdir)/m4/nut_check_libpowerman.m4 \ $(top_srcdir)/m4/nut_check_libregex.m4 \ $(top_srcdir)/m4/nut_check_libsystemd.m4 \ $(top_srcdir)/m4/nut_check_libusb.m4 \ $(top_srcdir)/m4/nut_check_libwrap.m4 \ $(top_srcdir)/m4/nut_check_os.m4 \ $(top_srcdir)/m4/nut_check_pkgconfig.m4 \ $(top_srcdir)/m4/nut_check_python.m4 \ $(top_srcdir)/m4/nut_check_socketlib.m4 \ $(top_srcdir)/m4/nut_compiler_family.m4 \ $(top_srcdir)/m4/nut_func_getnameinfo_argtypes.m4 \ $(top_srcdir)/m4/nut_report_feature.m4 \ $(top_srcdir)/m4/nut_stash_warnings.m4 \ $(top_srcdir)/m4/nut_type_socklen_t.m4 \ $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) DIST_COMMON = $(srcdir)/Makefile.am $(dist_data_DATA) \ $(am__DIST_COMMON) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/include/config.h CONFIG_CLEAN_FILES = driver.list CONFIG_CLEAN_VPATH_FILES = AM_V_P = $(am__v_P_@AM_V@) am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) am__v_P_0 = false am__v_P_1 = : AM_V_GEN = $(am__v_GEN_@AM_V@) am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) am__v_GEN_0 = @echo " GEN " $@; am__v_GEN_1 = AM_V_at = $(am__v_at_@AM_V@) am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) am__v_at_0 = @ am__v_at_1 = SOURCES = DIST_SOURCES = RECURSIVE_TARGETS = all-recursive check-recursive cscopelist-recursive \ ctags-recursive dvi-recursive html-recursive info-recursive \ install-data-recursive install-dvi-recursive \ install-exec-recursive install-html-recursive \ install-info-recursive install-pdf-recursive \ install-ps-recursive install-recursive installcheck-recursive \ installdirs-recursive pdf-recursive ps-recursive \ tags-recursive uninstall-recursive am__can_run_installinfo = \ case $$AM_UPDATE_INFO_DIR in \ n|no|NO) false;; \ *) (install-info --version) >/dev/null 2>&1;; \ esac am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; am__vpath_adj = case $$p in \ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ *) f=$$p;; \ esac; am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`; am__install_max = 40 am__nobase_strip_setup = \ srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'` am__nobase_strip = \ for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||" am__nobase_list = $(am__nobase_strip_setup); \ for p in $$list; do echo "$$p $$p"; done | \ sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \ $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \ if (++n[$$2] == $(am__install_max)) \ { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \ END { for (dir in files) print dir, files[dir] }' am__base_list = \ sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' am__uninstall_files_from_dir = { \ test -z "$$files" \ || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \ || { echo " ( cd '$$dir' && rm -f" $$files ")"; \ $(am__cd) "$$dir" && rm -f $$files; }; \ } am__installdirs = "$(DESTDIR)$(datadir)" "$(DESTDIR)$(datadir)" DATA = $(dist_data_DATA) $(nodist_data_DATA) RECURSIVE_CLEAN_TARGETS = mostlyclean-recursive clean-recursive \ distclean-recursive maintainer-clean-recursive am__recursive_targets = \ $(RECURSIVE_TARGETS) \ $(RECURSIVE_CLEAN_TARGETS) \ $(am__extra_recursive_targets) AM_RECURSIVE_TARGETS = $(am__recursive_targets:-recursive=) TAGS CTAGS \ distdir distdir-am am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) # Read a list of newline-separated strings from the standard input, # and print each of them once, without duplicates. Input order is # *not* preserved. am__uniquify_input = $(AWK) '\ BEGIN { nonempty = 0; } \ { items[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in items) print i; }; } \ ' # Make sure the list of sources is unique. This is necessary because, # e.g., the same source file might be shared among _SOURCES variables # for different programs/libraries. am__define_uniq_tagged_files = \ list='$(am__tagged_files)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | $(am__uniquify_input)` DIST_SUBDIRS = $(SUBDIRS) am__DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/driver.list.in DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) am__relativize = \ dir0=`pwd`; \ sed_first='s,^\([^/]*\)/.*$$,\1,'; \ sed_rest='s,^[^/]*/*,,'; \ sed_last='s,^.*/\([^/]*\)$$,\1,'; \ sed_butlast='s,/*[^/]*$$,,'; \ while test -n "$$dir1"; do \ first=`echo "$$dir1" | sed -e "$$sed_first"`; \ if test "$$first" != "."; then \ if test "$$first" = ".."; then \ dir2=`echo "$$dir0" | sed -e "$$sed_last"`/"$$dir2"; \ dir0=`echo "$$dir0" | sed -e "$$sed_butlast"`; \ else \ first2=`echo "$$dir2" | sed -e "$$sed_first"`; \ if test "$$first2" = "$$first"; then \ dir2=`echo "$$dir2" | sed -e "$$sed_rest"`; \ else \ dir2="../$$dir2"; \ fi; \ dir0="$$dir0"/"$$first"; \ fi; \ fi; \ dir1=`echo "$$dir1" | sed -e "$$sed_rest"`; \ done; \ reldir="$$dir2" A2X = @A2X@ ACLOCAL = @ACLOCAL@ ALTPIDPATH = @ALTPIDPATH@ AMTAR = @AMTAR@ AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ AR = @AR@ ASCIIDOC = @ASCIIDOC@ ASPELL = @ASPELL@ ASPELL_FILTER_LIB_PATH = @ASPELL_FILTER_LIB_PATH@ ASPELL_FILTER_SHARE_PATH = @ASPELL_FILTER_SHARE_PATH@ ASPELL_FILTER_TEX_PATH = @ASPELL_FILTER_TEX_PATH@ AUGPARSE = @AUGPARSE@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ BINDIR = @BINDIR@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CONFIG_FLAGS = @CONFIG_FLAGS@ CONFPATH = @CONFPATH@ CPP = @CPP@ CPPCHECK = @CPPCHECK@ CPPFLAGS = @CPPFLAGS@ CPPUNIT_CFLAGS = @CPPUNIT_CFLAGS@ CPPUNIT_LIBS = @CPPUNIT_LIBS@ CSCOPE = @CSCOPE@ CTAGS = @CTAGS@ CXX = @CXX@ CXXCPP = @CXXCPP@ CXXDEPMODE = @CXXDEPMODE@ CXXFLAGS = @CXXFLAGS@ CYGPATH_W = @CYGPATH_W@ DBLATEX = @DBLATEX@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ DEPLOYED_UPSC = @DEPLOYED_UPSC@ DEPLOYED_UPSD = @DEPLOYED_UPSD@ DLLTOOL = @DLLTOOL@ DOC_BUILD_LIST = @DOC_BUILD_LIST@ DOC_CHECK_LIST = @DOC_CHECK_LIST@ DRIVER_BUILD_LIST = @DRIVER_BUILD_LIST@ DRIVER_INSTALL_TARGET = @DRIVER_INSTALL_TARGET@ DRIVER_MAN_LIST = @DRIVER_MAN_LIST@ DRIVER_MAN_LIST_PAGES = @DRIVER_MAN_LIST_PAGES@ DRVPATH = @DRVPATH@ DSYMUTIL = @DSYMUTIL@ DUMPBIN = @DUMPBIN@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ ETAGS = @ETAGS@ EXEEXT = @EXEEXT@ FGREP = @FGREP@ FORCE_NUT_VERSION = @FORCE_NUT_VERSION@ GDLIB_CONFIG = @GDLIB_CONFIG@ GREP = @GREP@ HAVE_SYS_SOCKET_H = @HAVE_SYS_SOCKET_H@ HAVE_WINSOCK2_H = @HAVE_WINSOCK2_H@ HAVE_WS2TCPIP_H = @HAVE_WS2TCPIP_H@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ LD = @LD@ LDFLAGS = @LDFLAGS@ LIBAVAHI_CFLAGS = @LIBAVAHI_CFLAGS@ LIBAVAHI_LIBS = @LIBAVAHI_LIBS@ LIBDIR = @LIBDIR@ LIBGD_CFLAGS = @LIBGD_CFLAGS@ LIBGD_LDFLAGS = @LIBGD_LDFLAGS@ LIBGPIO_CFLAGS = @LIBGPIO_CFLAGS@ LIBGPIO_LIBS = @LIBGPIO_LIBS@ LIBI2C_LIBS = @LIBI2C_LIBS@ LIBIPMI_CFLAGS = @LIBIPMI_CFLAGS@ LIBIPMI_LIBS = @LIBIPMI_LIBS@ LIBLTDL_CFLAGS = @LIBLTDL_CFLAGS@ LIBLTDL_LIBS = @LIBLTDL_LIBS@ LIBMODBUS_CFLAGS = @LIBMODBUS_CFLAGS@ LIBMODBUS_LIBS = @LIBMODBUS_LIBS@ LIBNEON_CFLAGS = @LIBNEON_CFLAGS@ LIBNEON_LIBS = @LIBNEON_LIBS@ LIBNETSNMP_CFLAGS = @LIBNETSNMP_CFLAGS@ LIBNETSNMP_LIBS = @LIBNETSNMP_LIBS@ LIBOBJS = @LIBOBJS@ LIBPOWERMAN_CFLAGS = @LIBPOWERMAN_CFLAGS@ LIBPOWERMAN_LIBS = @LIBPOWERMAN_LIBS@ LIBREGEX_LIBS = @LIBREGEX_LIBS@ LIBS = @LIBS@ LIBSSL_CFLAGS = @LIBSSL_CFLAGS@ LIBSSL_LIBS = @LIBSSL_LIBS@ LIBSSL_REQUIRES = @LIBSSL_REQUIRES@ LIBSYSTEMD_CFLAGS = @LIBSYSTEMD_CFLAGS@ LIBSYSTEMD_LIBS = @LIBSYSTEMD_LIBS@ LIBTOOL = @LIBTOOL@ LIBTOOL_DEPS = @LIBTOOL_DEPS@ LIBUSB_CFLAGS = @LIBUSB_CFLAGS@ LIBUSB_CONFIG = @LIBUSB_CONFIG@ LIBUSB_LIBS = @LIBUSB_LIBS@ LIBWRAP_CFLAGS = @LIBWRAP_CFLAGS@ LIBWRAP_LIBS = @LIBWRAP_LIBS@ LIPO = @LIPO@ LN_S = @LN_S@ LN_S_R = @LN_S_R@ LTLIBOBJS = @LTLIBOBJS@ LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@ MAINT = @MAINT@ MAKEINFO = @MAKEINFO@ MANIFEST_TOOL = @MANIFEST_TOOL@ MKDIR_P = @MKDIR_P@ MSGFMT = @MSGFMT@ NETLIBS = @NETLIBS@ NET_SNMP_CONFIG = @NET_SNMP_CONFIG@ NM = @NM@ NMEDIT = @NMEDIT@ NUT_DATADIR = @NUT_DATADIR@ NUT_LIBEXECDIR = @NUT_LIBEXECDIR@ NUT_NETVERSION = @NUT_NETVERSION@ NUT_SOURCE_GITREV = @NUT_SOURCE_GITREV@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ OS_NAME = @OS_NAME@ OTOOL = @OTOOL@ OTOOL64 = @OTOOL64@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_SEPARATOR = @PATH_SEPARATOR@ PIDPATH = @PIDPATH@ PKGCONFIGDIR = @PKGCONFIGDIR@ PKG_CONFIG = @PKG_CONFIG@ PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@ PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ PORT = @PORT@ POWERDOWNFLAG = @POWERDOWNFLAG@ PREFIX = @PREFIX@ PYTHON = @PYTHON@ PYTHON2 = @PYTHON2@ PYTHON2_SITE_PACKAGES = @PYTHON2_SITE_PACKAGES@ PYTHON3 = @PYTHON3@ PYTHON3_SITE_PACKAGES = @PYTHON3_SITE_PACKAGES@ PYTHON_SITE_PACKAGES = @PYTHON_SITE_PACKAGES@ RANLIB = @RANLIB@ REALPATH = @REALPATH@ RUN_AS_GROUP = @RUN_AS_GROUP@ RUN_AS_USER = @RUN_AS_USER@ SBINDIR = @SBINDIR@ SED = @SED@ SEMLIBS = @SEMLIBS@ SERLIBS = @SERLIBS@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ SOURCE_HIGHLIGHT = @SOURCE_HIGHLIGHT@ STATEPATH = @STATEPATH@ STRIP = @STRIP@ SUN_LIBUSB = @SUN_LIBUSB@ SYSTEMD_ANALYZE_PROGRAM = @SYSTEMD_ANALYZE_PROGRAM@ SYSTEMD_DAEMON_ARGS_DRIVER = @SYSTEMD_DAEMON_ARGS_DRIVER@ SYSTEMD_DAEMON_ARGS_UPSD = @SYSTEMD_DAEMON_ARGS_UPSD@ SYSTEMD_DAEMON_ARGS_UPSMON = @SYSTEMD_DAEMON_ARGS_UPSMON@ SYSTEMD_DAEMON_NOTIFYACCESS_DRIVER = @SYSTEMD_DAEMON_NOTIFYACCESS_DRIVER@ SYSTEMD_DAEMON_NOTIFYACCESS_UPSD = @SYSTEMD_DAEMON_NOTIFYACCESS_UPSD@ SYSTEMD_DAEMON_NOTIFYACCESS_UPSMON = @SYSTEMD_DAEMON_NOTIFYACCESS_UPSMON@ SYSTEMD_DAEMON_TYPE_DRIVER = @SYSTEMD_DAEMON_TYPE_DRIVER@ SYSTEMD_DAEMON_TYPE_UPSD = @SYSTEMD_DAEMON_TYPE_UPSD@ SYSTEMD_DAEMON_TYPE_UPSMON = @SYSTEMD_DAEMON_TYPE_UPSMON@ SYSTEMD_DAEMON_WATCHDOG_DRIVER = @SYSTEMD_DAEMON_WATCHDOG_DRIVER@ SYSTEMD_DAEMON_WATCHDOG_UPSD = @SYSTEMD_DAEMON_WATCHDOG_UPSD@ SYSTEMD_DAEMON_WATCHDOG_UPSMON = @SYSTEMD_DAEMON_WATCHDOG_UPSMON@ SYSTEMD_TMPFILES_PROGRAM = @SYSTEMD_TMPFILES_PROGRAM@ TREE_VERSION = @TREE_VERSION@ VALGRIND = @VALGRIND@ VERSION = @VERSION@ WINDMC = @WINDMC@ WINDRES = @WINDRES@ WORDS_BIGENDIAN = @WORDS_BIGENDIAN@ XMLLINT = @XMLLINT@ XSLTPROC = @XSLTPROC@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_AR = @ac_ct_AR@ ac_ct_CC = @ac_ct_CC@ ac_ct_CXX = @ac_ct_CXX@ ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__tar = @am__tar@ am__untar = @am__untar@ auglensdir = @auglensdir@ bindir = @bindir@ build = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ cgiexecdir = @cgiexecdir@ datadir = @datadir@ datarootdir = @datarootdir@ devddir = @devddir@ docdir = @docdir@ driverexecdir = @driverexecdir@ dummy_PKG_CONFIG = @dummy_PKG_CONFIG@ dummy_PKG_CONFIG_CFLAGS = @dummy_PKG_CONFIG_CFLAGS@ dummy_PKG_CONFIG_LIBS = @dummy_PKG_CONFIG_LIBS@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ hotplugdir = @hotplugdir@ htmldir = @htmldir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libdir = @libdir@ libexecdir = @libexecdir@ localedir = @localedir@ localstatedir = @localstatedir@ mandir = @mandir@ mkdir_p = @mkdir_p@ now = @now@ nut_with_nut_monitor = @nut_with_nut_monitor@ nut_with_nut_monitor_desktop = @nut_with_nut_monitor_desktop@ nut_with_nut_monitor_dir = @nut_with_nut_monitor_dir@ nut_with_nut_monitor_py2gtk2 = @nut_with_nut_monitor_py2gtk2@ nut_with_nut_monitor_py3qt5 = @nut_with_nut_monitor_py3qt5@ nut_with_pynut = @nut_with_pynut@ nut_with_pynut_py = @nut_with_pynut_py@ nut_with_pynut_py2 = @nut_with_pynut_py2@ nut_with_pynut_py3 = @nut_with_pynut_py3@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ pkgconfigdir = @pkgconfigdir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ runstatedir = @runstatedir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ sysconfdir = @sysconfdir@ systemdshutdowndir = @systemdshutdowndir@ systemdsystemunitdir = @systemdsystemunitdir@ systemdtmpfilesdir = @systemdtmpfilesdir@ target = @target@ target_alias = @target_alias@ target_cpu = @target_cpu@ target_os = @target_os@ target_vendor = @target_vendor@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ udevdir = @udevdir@ SUBDIRS = html dist_data_DATA = cmdvartab nodist_data_DATA = driver.list EXTRA_DIST = evolution500.seq epdu-managed.dev MAINTAINERCLEANFILES = Makefile.in .dirstamp CLEANFILES = *.pdf *.html *-spellchecked all: all-recursive .SUFFIXES: $(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu data/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --gnu data/Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): driver.list: $(top_builddir)/config.status $(srcdir)/driver.list.in cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ mostlyclean-libtool: -rm -f *.lo clean-libtool: -rm -rf .libs _libs install-dist_dataDATA: $(dist_data_DATA) @$(NORMAL_INSTALL) @list='$(dist_data_DATA)'; test -n "$(datadir)" || list=; \ if test -n "$$list"; then \ echo " $(MKDIR_P) '$(DESTDIR)$(datadir)'"; \ $(MKDIR_P) "$(DESTDIR)$(datadir)" || exit 1; \ fi; \ for p in $$list; do \ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ echo "$$d$$p"; \ done | $(am__base_list) | \ while read files; do \ echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(datadir)'"; \ $(INSTALL_DATA) $$files "$(DESTDIR)$(datadir)" || exit $$?; \ done uninstall-dist_dataDATA: @$(NORMAL_UNINSTALL) @list='$(dist_data_DATA)'; test -n "$(datadir)" || list=; \ files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ dir='$(DESTDIR)$(datadir)'; $(am__uninstall_files_from_dir) install-nodist_dataDATA: $(nodist_data_DATA) @$(NORMAL_INSTALL) @list='$(nodist_data_DATA)'; test -n "$(datadir)" || list=; \ if test -n "$$list"; then \ echo " $(MKDIR_P) '$(DESTDIR)$(datadir)'"; \ $(MKDIR_P) "$(DESTDIR)$(datadir)" || exit 1; \ fi; \ for p in $$list; do \ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ echo "$$d$$p"; \ done | $(am__base_list) | \ while read files; do \ echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(datadir)'"; \ $(INSTALL_DATA) $$files "$(DESTDIR)$(datadir)" || exit $$?; \ done uninstall-nodist_dataDATA: @$(NORMAL_UNINSTALL) @list='$(nodist_data_DATA)'; test -n "$(datadir)" || list=; \ files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ dir='$(DESTDIR)$(datadir)'; $(am__uninstall_files_from_dir) # This directory's subdirectories are mostly independent; you can cd # into them and run 'make' without going through this Makefile. # To change the values of 'make' variables: instead of editing Makefiles, # (1) if the variable is set in 'config.status', edit 'config.status' # (which will cause the Makefiles to be regenerated when you run 'make'); # (2) otherwise, pass the desired values on the 'make' command line. $(am__recursive_targets): @fail=; \ if $(am__make_keepgoing); then \ failcom='fail=yes'; \ else \ failcom='exit 1'; \ fi; \ dot_seen=no; \ target=`echo $@ | sed s/-recursive//`; \ case "$@" in \ distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \ *) list='$(SUBDIRS)' ;; \ esac; \ for subdir in $$list; do \ echo "Making $$target in $$subdir"; \ if test "$$subdir" = "."; then \ dot_seen=yes; \ local_target="$$target-am"; \ else \ local_target="$$target"; \ fi; \ ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ || eval $$failcom; \ done; \ if test "$$dot_seen" = "no"; then \ $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \ fi; test -z "$$fail" ID: $(am__tagged_files) $(am__define_uniq_tagged_files); mkid -fID $$unique tags: tags-recursive TAGS: tags tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) set x; \ here=`pwd`; \ if ($(ETAGS) --etags-include --version) >/dev/null 2>&1; then \ include_option=--etags-include; \ empty_fix=.; \ else \ include_option=--include; \ empty_fix=; \ fi; \ list='$(SUBDIRS)'; for subdir in $$list; do \ if test "$$subdir" = .; then :; else \ test ! -f $$subdir/TAGS || \ set "$$@" "$$include_option=$$here/$$subdir/TAGS"; \ fi; \ done; \ $(am__define_uniq_tagged_files); \ shift; \ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ test -n "$$unique" || unique=$$empty_fix; \ if test $$# -gt 0; then \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ "$$@" $$unique; \ else \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ $$unique; \ fi; \ fi ctags: ctags-recursive CTAGS: ctags ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) $(am__define_uniq_tagged_files); \ test -z "$(CTAGS_ARGS)$$unique" \ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ $$unique GTAGS: here=`$(am__cd) $(top_builddir) && pwd` \ && $(am__cd) $(top_srcdir) \ && gtags -i $(GTAGS_ARGS) "$$here" cscopelist: cscopelist-recursive cscopelist-am: $(am__tagged_files) list='$(am__tagged_files)'; \ case "$(srcdir)" in \ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \ *) sdir=$(subdir)/$(srcdir) ;; \ esac; \ for i in $$list; do \ if test -f "$$i"; then \ echo "$(subdir)/$$i"; \ else \ echo "$$sdir/$$i"; \ fi; \ done >> $(top_builddir)/cscope.files distclean-tags: -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags distdir: $(BUILT_SOURCES) $(MAKE) $(AM_MAKEFLAGS) distdir-am distdir-am: $(DISTFILES) @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ dist_files=`for file in $$list; do echo $$file; done | \ sed -e "s|^$$srcdirstrip/||;t" \ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ case $$dist_files in \ */*) $(MKDIR_P) `echo "$$dist_files" | \ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ sort -u` ;; \ esac; \ for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d "$(distdir)/$$file"; then \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ else \ test -f "$(distdir)/$$file" \ || cp -p $$d/$$file "$(distdir)/$$file" \ || exit 1; \ fi; \ done @list='$(DIST_SUBDIRS)'; for subdir in $$list; do \ if test "$$subdir" = .; then :; else \ $(am__make_dryrun) \ || test -d "$(distdir)/$$subdir" \ || $(MKDIR_P) "$(distdir)/$$subdir" \ || exit 1; \ dir1=$$subdir; dir2="$(distdir)/$$subdir"; \ $(am__relativize); \ new_distdir=$$reldir; \ dir1=$$subdir; dir2="$(top_distdir)"; \ $(am__relativize); \ new_top_distdir=$$reldir; \ echo " (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) top_distdir="$$new_top_distdir" distdir="$$new_distdir" \\"; \ echo " am__remove_distdir=: am__skip_length_check=: am__skip_mode_fix=: distdir)"; \ ($(am__cd) $$subdir && \ $(MAKE) $(AM_MAKEFLAGS) \ top_distdir="$$new_top_distdir" \ distdir="$$new_distdir" \ am__remove_distdir=: \ am__skip_length_check=: \ am__skip_mode_fix=: \ distdir) \ || exit 1; \ fi; \ done check-am: all-am check: check-recursive all-am: Makefile $(DATA) installdirs: installdirs-recursive installdirs-am: for dir in "$(DESTDIR)$(datadir)" "$(DESTDIR)$(datadir)"; do \ test -z "$$dir" || $(MKDIR_P) "$$dir"; \ done install: install-recursive install-exec: install-exec-recursive install-data: install-data-recursive uninstall: uninstall-recursive install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-recursive install-strip: if test -z '$(STRIP)'; then \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ install; \ else \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ fi mostlyclean-generic: clean-generic: -test -z "$(CLEANFILES)" || rm -f $(CLEANFILES) distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." -test -z "$(MAINTAINERCLEANFILES)" || rm -f $(MAINTAINERCLEANFILES) clean: clean-recursive clean-am: clean-generic clean-libtool mostlyclean-am distclean: distclean-recursive -rm -f Makefile distclean-am: clean-am distclean-generic distclean-tags dvi: dvi-recursive dvi-am: html: html-recursive html-am: info: info-recursive info-am: install-data-am: install-dist_dataDATA install-nodist_dataDATA install-dvi: install-dvi-recursive install-dvi-am: install-exec-am: install-html: install-html-recursive install-html-am: install-info: install-info-recursive install-info-am: install-man: install-pdf: install-pdf-recursive install-pdf-am: install-ps: install-ps-recursive install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-recursive -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-recursive mostlyclean-am: mostlyclean-generic mostlyclean-libtool pdf: pdf-recursive pdf-am: ps: ps-recursive ps-am: uninstall-am: uninstall-dist_dataDATA uninstall-nodist_dataDATA .MAKE: $(am__recursive_targets) install-am install-strip .PHONY: $(am__recursive_targets) CTAGS GTAGS TAGS all all-am check \ check-am clean clean-generic clean-libtool cscopelist-am ctags \ ctags-am distclean distclean-generic distclean-libtool \ distclean-tags distdir dvi dvi-am html html-am info info-am \ install install-am install-data install-data-am \ install-dist_dataDATA install-dvi install-dvi-am install-exec \ install-exec-am install-html install-html-am install-info \ install-info-am install-man install-nodist_dataDATA \ install-pdf install-pdf-am install-ps install-ps-am \ install-strip installcheck installcheck-am installdirs \ installdirs-am maintainer-clean maintainer-clean-generic \ mostlyclean mostlyclean-generic mostlyclean-libtool pdf pdf-am \ ps ps-am tags tags-am uninstall uninstall-am \ uninstall-dist_dataDATA uninstall-nodist_dataDATA .PRECIOUS: Makefile # NOTE: Due to portability, we do not use a GNU percent-wildcard extension: #%-spellchecked: % Makefile.am $(top_srcdir)/docs/Makefile.am $(abs_srcdir)/$(NUT_SPELL_DICT) # $(MAKE) -s -f $(top_builddir)/docs/Makefile SPELLCHECK_SRC_ONE="$<" SPELLCHECK_SRCDIR="$(srcdir)" SPELLCHECK_BUILDDIR="$(builddir)" $@ cmdvartab-spellchecked: cmdvartab Makefile.am $(top_srcdir)/docs/Makefile.am $(abs_srcdir)/$(NUT_SPELL_DICT) $(MAKE) -s -f $(top_builddir)/docs/Makefile SPELLCHECK_SRC_ONE="$<" SPELLCHECK_SRCDIR="$(srcdir)" SPELLCHECK_BUILDDIR="$(builddir)" $@ spellcheck spellcheck-interactive spellcheck-sortdict: $(MAKE) -f $(top_builddir)/docs/Makefile SPELLCHECK_SRC="cmdvartab" SPELLCHECK_SRCDIR="$(srcdir)" SPELLCHECK_BUILDDIR="$(builddir)" $@ # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: nut-2.8.1/data/cmdvartab0000644000175000017500000003544014514200703012052 00000000000000# Network UPS Tools: variable and command descriptions # # This file is optional. You may delete it to save resources, but # clients will receive "Unavailable" for any description requests. # # *** NOTE *** : When updating this file, also update docs/nut-names.txt VARDESC ups.alarm "UPS alarms" VARDESC ups.status "UPS status" VARDESC ups.time "Internal UPS clock time" VARDESC ups.date "Internal UPS clock date" VARDESC ups.efficiency "Efficiency of the UPS" VARDESC ups.model "UPS model" VARDESC ups.mfr "UPS manufacturer" VARDESC ups.mfr.date "UPS manufacturing date" VARDESC ups.serial "UPS serial number" VARDESC ups.vendorid "Vendor ID for USB devices" VARDESC ups.productid "Product ID for USB devices" VARDESC ups.firmware "UPS firmware" VARDESC ups.firmware.aux "Auxiliary device firmware" VARDESC ups.temperature "UPS temperature (degrees C)" VARDESC ups.load "Load on UPS (percent of full)" VARDESC ups.load.energysave "Load on UPS that triggers energysave (percent)" VARDESC ups.load.high "Load when UPS switches to overload condition (percent)" VARDESC ups.id "UPS system identifier" VARDESC ups.delay.start "Interval to wait before (re)starting the load (seconds)" VARDESC ups.delay.reboot "Interval to wait before rebooting the UPS (seconds)" VARDESC ups.delay.shutdown "Interval to wait after shutdown with delay command (seconds)" VARDESC ups.timer.start "Time before the load will be started (seconds)" VARDESC ups.timer.reboot "Time before the load will be rebooted (seconds)" VARDESC ups.timer.shutdown "Time before the load will be shutdown (seconds)" VARDESC ups.test.interval "Interval between self tests (seconds)" VARDESC ups.test.result "Results of last self test" VARDESC ups.display.language "Language to use on front panel" VARDESC ups.contacts "UPS external contact sensors" VARDESC ups.power "Current value of apparent power (VA)" VARDESC ups.power.nominal "UPS power rating (VA)" VARDESC ups.realpower "Current value of real power (W)" VARDESC ups.realpower.nominal "UPS real power rating (W)" VARDESC ups.beeper.status "UPS beeper status" VARDESC ups.type "UPS type" VARDESC ups.start.auto "UPS starts when mains is (re)applied" VARDESC ups.start.battery "Allow to start UPS from battery" VARDESC ups.start.reboot "UPS reboots when power returns during shutdown delay" VARDESC input.voltage "Input voltage (V)" VARDESC input.voltage.extended "Extended input voltage range" VARDESC input.voltage.maximum "Maximum incoming voltage seen (V)" VARDESC input.voltage.minimum "Minimum incoming voltage seen (V)" VARDESC input.voltage.status "Voltage status relative to the thresholds" VARDESC input.voltage.low.warning "Input voltage low warning threshold (V)" VARDESC input.voltage.low.critical "Input voltage low critical threshold (V)" VARDESC input.voltage.high.warning "Input voltage high warning threshold (V)" VARDESC input.voltage.high.critical "Input voltage high critical threshold (V)" VARDESC input.voltage.nominal "Nominal input voltage (V)" VARDESC input.transfer.reason "Reason for last transfer to battery" VARDESC input.transfer.low "Low voltage transfer point (V)" VARDESC input.transfer.high "High voltage transfer point (V)" VARDESC input.transfer.low.min "smallest settable low voltage transfer point (V)" VARDESC input.transfer.low.max "greatest settable low voltage transfer point (V)" VARDESC input.transfer.high.min "smallest settable high voltage transfer point (V)" VARDESC input.transfer.high.max "greatest settable high voltage transfer point (V)" VARDESC input.sensitivity "Input power sensitivity" VARDESC input.quality "Input power quality" VARDESC input.current "Input current (A)" VARDESC input.current.nominal "Nominal input current (A)" VARDESC input.current.status "Current status relative to the thresholds" VARDESC input.current.low.warning "Input current low warning threshold (A)" VARDESC input.current.low.critical "Input current low critical threshold (A)" VARDESC input.current.high.warning "Input current high warning threshold (A)" VARDESC input.current.high.critical "Input current high critical threshold (A)" VARDESC input.frequency "Input line frequency (Hz)" VARDESC input.frequency.extended "Extended input frequency range" VARDESC input.frequency.status "Frequency status" VARDESC input.frequency.nominal "Nominal input line frequency (Hz)" VARDESC input.frequency.low "Minimum input line frequency (Hz)" VARDESC input.frequency.high "Maximum input line frequency (Hz)" VARDESC input.transfer.boost.low "Low voltage boosting transfer point (V)" VARDESC input.transfer.boost.high "High voltage boosting transfer point (V)" VARDESC input.transfer.trim.low "Low voltage trimming transfer point (V)" VARDESC input.transfer.trim.high "High voltage trimming transfer point (V)" VARDESC input.transfer.delay "Delay before transfer to mains" VARDESC input.load "Load on (ePDU) input (percent of full)" VARDESC input.realpower "Current sum value of all (ePDU) phases real power (W)" VARDESC input.power "Current sum value of all (ePDU) phases apparent power (VA)" VARDESC input.source "The current input power source" VARDESC input.source.preferred "The preferred input power source" VARDESC output.voltage "Output voltage (V)" VARDESC output.voltage.nominal "Nominal output voltage (V)" VARDESC output.frequency "Output frequency (Hz)" VARDESC output.frequency.nominal "Nominal output frequency (Hz)" VARDESC output.current "Output current (A)" VARDESC output.current.nominal "Nominal output current (A)" VARDESC battery.charge "Battery charge (percent of full)" VARDESC battery.charge.approx "Rough approximation of battery charge" VARDESC battery.charge.low "Remaining battery level when UPS switches to LB (percent)" VARDESC battery.charge.restart "Minimum battery level for restart after power off (percent)" VARDESC battery.charge.warning "Battery level when UPS switches to Warning state (percent)" VARDESC battery.voltage "Battery voltage (V)" VARDESC battery.current "Battery current (A)" VARDESC battery.capacity "Battery capacity (Ah)" VARDESC battery.temperature "Battery temperature (degrees C)" VARDESC battery.voltage.nominal "Nominal battery voltage (V)" VARDESC battery.runtime "Battery runtime (seconds)" VARDESC battery.runtime.low "Remaining battery runtime when UPS switches to LB (seconds)" VARDESC battery.alarm.threshold "Battery alarm threshold" VARDESC battery.date "Battery change date" VARDESC battery.mfr.date "Battery manufacturing date" VARDESC battery.packs "Number of battery packs" VARDESC battery.packs.bad "Number of bad battery packs" VARDESC battery.type "Battery chemistry" VARDESC battery.protection "Prevent deep discharge of battery" VARDESC battery.energysave "Switch off when running on battery and no/low load" VARDESC battery.energysave.load "Switch off UPS if on battery and load level lower (percent)" VARDESC battery.energysave.delay "Delay before switch off UPS if on battery and load level low (min)" VARDESC battery.energysave.realpower "Switch off UPS if on battery and load level lower (Watts)" VARDESC battery.charger.status "Battery charger status" VARDESC ambient.temperature "Ambient temperature (degrees C)" VARDESC ambient.temperature.alarm "Ambient temperature alarm is active" VARDESC ambient.temperature.status "Ambient temperature status relative to the configured thresholds" VARDESC ambient.temperature.alarm.maximum "Maximum allowed ambient temperature (degrees C)" VARDESC ambient.temperature.alarm.minimum "Minimum allowed ambient temperature (degrees C)" VARDESC ambient.temperature.alarm.enable "Enable ambient temperature alarm" VARDESC ambient.temperature.low "Temperature threshold low (degrees C)" VARDESC ambient.temperature.low.warning "Temperature threshold low warning (degrees C)" VARDESC ambient.temperature.low.critical "Temperature threshold low critical (degrees C)" VARDESC ambient.temperature.high "Temperature threshold high (degrees C)" VARDESC ambient.temperature.high.warning "Temperature threshold high warning (degrees C)" VARDESC ambient.temperature.high.critical "Temperature threshold high critical (degrees C)" VARDESC ambient.humidity "Ambient humidity (percent)" VARDESC ambient.humidity.alarm "Ambient humidity alarm is active" VARDESC ambient.humidity.status "Ambient humidity status relative to the configured thresholds" VARDESC ambient.humidity.alarm.maximum "Maximum allowed ambient humidity (percent)" VARDESC ambient.humidity.alarm.minimum "Minimum allowed ambient humidity (percent)" VARDESC ambient.humidity.alarm.enable "Enable ambient humidity alarm" VARDESC ambient.humidity.low "Ambient humidity threshold low (percent)" VARDESC ambient.humidity.low.warning "Ambient humidity threshold low warning (percent)" VARDESC ambient.humidity.low.critical "Ambient humidity threshold low critical (percent)" VARDESC ambient.humidity.high "Ambient humidity threshold high (percent)" VARDESC ambient.humidity.high.warning "Ambient humidity threshold high warning (percent)" VARDESC ambient.humidity.high.critical "Ambient humidity threshold high critical (percent)" VARDESC ambient.present "Ambient sensor presence" VARDESC ambient.contacts.1.status "State of the dry contact sensor 1" VARDESC ambient.contacts.2.status "State of the dry contact sensor 2" # FIXME: the outlet collection is indexed - solve with regexps? # # VARDESC outlet.[[:digit:]]+.id "Outlet system identifier ()" VARDESC outlet.id "Outlet system identifier" VARDESC outlet.desc "Outlet description" VARDESC outlet.switch "Outlet switch control" VARDESC outlet.status "Outlet switch status" VARDESC outlet.switchable "Outlet switch ability" VARDESC outlet.autoswitch.charge.low "Remaining battery level to power off this outlet (percent)" VARDESC outlet.delay.shutdown "Interval to wait before shutting down this outlet (seconds)" VARDESC outlet.delay.start "Interval to wait before restarting this outlet (seconds)" VARDESC outlet.1.id "Outlet system identifier" VARDESC outlet.1.desc "Outlet description" VARDESC outlet.1.switch "Outlet switch control" VARDESC outlet.1.status "Outlet switch status" VARDESC outlet.1.switchable "Outlet switch ability" VARDESC outlet.1.autoswitch.charge.low "Remaining battery level to power off this outlet (percent)" VARDESC outlet.1.delay.shutdown "Interval to wait before shutting down this outlet (seconds)" VARDESC outlet.1.delay.start "Interval to wait before restarting this outlet (seconds)" VARDESC outlet.2.id "Outlet system identifier" VARDESC outlet.2.desc "Outlet description" VARDESC outlet.2.switch "Outlet switch control" VARDESC outlet.2.status "Outlet switch status" VARDESC outlet.2.switchable "Outlet switch ability" VARDESC outlet.2.autoswitch.charge.low "Remaining battery level to power off this outlet (percent)" VARDESC outlet.2.delay.shutdown "Interval to wait before shutting down this outlet (seconds)" VARDESC outlet.2.delay.start "Interval to wait before restarting this outlet (seconds)" VARDESC device.part "Device Part Number" VARDESC server.info "Server information" VARDESC server.version "Server version" VARDESC driver.name "Driver name" VARDESC driver.debug "Current debug verbosity level of the driver program" # Note: normally a `drivername -k` call is used during shutdowns, # and at that time the daemon instance of the driver must be stopped: VARDESC driver.flag.allow_killpower "Safety flip-switch to allow the driver daemon to send UPS shutdown command (accessible via driver.killpower)" VARDESC driver.version "Driver version - NUT release" VARDESC driver.version.internal "Internal driver version" VARDESC driver.version.usb "USB library version" # FIXME: driver.parameter and driver.flag can have many possible members # # VARDESC driver.parameter.[[:alpha:]]+ "Driver parameter: " # VARDESC driver.flag.[[:alpha:]]+ "Driver flag: " CMDDESC driver.killpower "Tell the driver daemon to initiate UPS shutdown; should be unlocked with driver.flag.allow_killpower option or variable setting" CMDDESC driver.reload "Reload running driver configuration from the file system (only works for changes in some options)" CMDDESC driver.reload-or-error "Reload running driver configuration from the file system (only works for changes in some options); return an error if something changed and could not be applied live (so the caller can restart it with new options)" CMDDESC driver.reload-or-exit "Reload running driver configuration from the file system (only works for changes in some options); exit the running driver if something changed and could not be applied live (so service management framework can restart it with new options)" CMDDESC load.off "Turn off the load immediately" CMDDESC load.on "Turn on the load immediately" CMDDESC shutdown.return "Turn off the load and return when power is back" CMDDESC shutdown.stayoff "Turn off the load and remain off" CMDDESC shutdown.stop "Stop a shutdown in progress" CMDDESC shutdown.reboot "Shut down the load briefly while rebooting the UPS" CMDDESC shutdown.reboot.graceful "Delay briefly then shut down the load while rebooting the UPS" CMDDESC test.panel.start "Start testing the UPS panel" CMDDESC test.panel.stop "Stop a UPS panel test" CMDDESC test.failure.start "Start a simulated power failure" CMDDESC test.failure.stop "Stop simulating a power failure" CMDDESC test.battery.start "Start a battery test" CMDDESC test.battery.start.quick "Start a quick battery test" CMDDESC test.battery.start.deep "Start a deep battery test" CMDDESC test.battery.stop "Stop the battery test" CMDDESC test.system.start "Start a system test" CMDDESC calibrate.start "Start run time calibration" CMDDESC calibrate.stop "Stop run time calibration" CMDDESC bypass.start "Put the UPS in bypass mode" CMDDESC bypass.stop "Take the UPS out of bypass mode" CMDDESC reset.input.minmax "Reset minimum and maximum input voltage status" CMDDESC reset.watchdog "Reset watchdog timer" CMDDESC beeper.on "Obsolete (use beeper.enable)" CMDDESC beeper.off "Obsolete (use beeper.disable or beeper.mute)" CMDDESC beeper.enable "Enable the UPS beeper" CMDDESC beeper.disable "Disable the UPS beeper" CMDDESC beeper.mute "Temporarily mute the UPS beeper" CMDDESC beeper.toggle "Toggle the UPS beeper" CMDDESC outlet.1.load.off "Turn off the load on outlet 1 immediately" CMDDESC outlet.1.load.on "Turn on the load on outlet 1 immediately" CMDDESC outlet.1.shutdown.return "Turn off the outlet 1 and return when power is back" CMDDESC outlet.2.load.off "Turn off the load on outlet 2 immediately" CMDDESC outlet.2.load.on "Turn on the load on outlet 2 immediately" CMDDESC outlet.2.shutdown.return "Turn off the outlet 2 and return when power is back" # The following two commands should *only* be defined when you need # to compose a 'shutdown.return' command by sending both a switch-off # with delay and a switch-on with delay command to the UPS. If this # can be done with a single command, use 'shutdown.return' instead. # Note that the switch-on with delay command *must not* turn on the # load if the UPS is on battery. # CMDDESC load.off.delay "Turn off the load with a delay (seconds)" CMDDESC load.on.delay "Turn on the load with a delay (seconds)" nut-2.8.1/data/Makefile.am0000644000175000017500000000172514502413024012216 00000000000000# Network UPS Tools: data SUBDIRS = html dist_data_DATA = cmdvartab nodist_data_DATA = driver.list EXTRA_DIST = evolution500.seq epdu-managed.dev # NOTE: Due to portability, we do not use a GNU percent-wildcard extension: #%-spellchecked: % Makefile.am $(top_srcdir)/docs/Makefile.am $(abs_srcdir)/$(NUT_SPELL_DICT) # $(MAKE) -s -f $(top_builddir)/docs/Makefile SPELLCHECK_SRC_ONE="$<" SPELLCHECK_SRCDIR="$(srcdir)" SPELLCHECK_BUILDDIR="$(builddir)" $@ cmdvartab-spellchecked: cmdvartab Makefile.am $(top_srcdir)/docs/Makefile.am $(abs_srcdir)/$(NUT_SPELL_DICT) $(MAKE) -s -f $(top_builddir)/docs/Makefile SPELLCHECK_SRC_ONE="$<" SPELLCHECK_SRCDIR="$(srcdir)" SPELLCHECK_BUILDDIR="$(builddir)" $@ spellcheck spellcheck-interactive spellcheck-sortdict: $(MAKE) -f $(top_builddir)/docs/Makefile SPELLCHECK_SRC="cmdvartab" SPELLCHECK_SRCDIR="$(srcdir)" SPELLCHECK_BUILDDIR="$(builddir)" $@ MAINTAINERCLEANFILES = Makefile.in .dirstamp CLEANFILES = *.pdf *.html *-spellchecked nut-2.8.1/data/epdu-managed.dev0000644000175000017500000000317214273170601013215 00000000000000# dummy-ups example device definition file # # Generated using: # $ upsc ups@host > epdu-managed.dev device.mfr: EATON | Powerware device.model: DBQ10634/5 device.serial: ADO6750531 device.type: pdu driver.name: snmp-ups driver.parameter.pollinterval: 2 driver.parameter.port: somewhere.org driver.version: 2.3.0-1540MS driver.version.internal: 0.44 (mib: aphel_revelation 0.2) outlet.1.current: 0.00 outlet.1.current.maximum: 0.00 outlet.1.desc: Outlet 1 outlet.1.id: 1 outlet.1.power: 0.00 outlet.1.powerfactor: 0.05 outlet.1.realpower: 0.00 outlet.1.status: on outlet.1.switchable: 0.00 outlet.1.voltage: 247.00 outlet.2.current: 0.00 outlet.2.current.maximum: 0.16 outlet.2.desc: Outlet 2 outlet.2.id: 2 outlet.2.power: 0.00 outlet.2.powerfactor: 0.01 outlet.2.realpower: 0.00 outlet.2.status: on outlet.2.switchable: 1.00 outlet.2.voltage: 247.00 outlet.3.current: 0.00 outlet.3.current.maximum: 0.16 outlet.3.desc: Outlet 3 outlet.3.id: 3 outlet.3.power: 0.00 outlet.3.powerfactor: 0.13 outlet.3.realpower: 0.00 outlet.3.status: on outlet.3.switchable: 2.00 outlet.3.voltage: 247.00 outlet.4.current: 0.19 outlet.4.current.maximum: 0.56 outlet.4.desc: Outlet 4 outlet.4.id: 2 outlet.4.power: 46.00 outlet.4.powerfactor: 0.60 outlet.4.realpower: 28.00 outlet.4.status: on outlet.4.switchable: 3.00 outlet.4.voltage: 247.00 outlet.count: 4.00 outlet.current: 0.19 outlet.desc: All outlets outlet.id: 0 outlet.power: 46.00 outlet.realpower: 28.00 outlet.voltage: 247.00 ups.firmware: 01.01.00 ups.id: my_device234 ups.macaddr: ups.mfr: EATON | Powerware ups.model: DBQ10634/5 ups.serial: ADO6750531 ups.status: ups.temperature: 49.00 device.type: pdu nut-2.8.1/data/driver.list.in0000644000175000017500000027732514520277776013020 00000000000000# Network UPS Tools - @PACKAGE_VERSION@ - Hardware Compatibility List # version=2 # # This file is used for various purposes, like building the HTML compatibility # list or displaying information in NUT configuration tools. # # If you write a new driver, modify an existing one to add more support, # or just know about some equipment that isn't listed but should be, # please send us a patch to update this file. # # Format: # ======= # # # Details: # ======== # - device type: # "ups" for Uninterruptible Power Supply # "pdu" for Power Distribution Unit # "scd" for Solar Controller Device # "ats" for Automatic Transfer Switch # # - support level: a number from "1" to "5" (stars) meaning: # * protocol based on reverse engineering # ** based on fragments of publicly available protocol # *** based on publicly available protocol # **** vendor provided protocol # ***** vendor provided protocol and hardware # # - driver [parameters]: mention the driver(s) (separated by "or" if there are # several possibilities). Any mandatory parameter(s) must be referenced, as # they will be parsed by configuration helper software. # For example, genericups entries must mention the "upstype=nn" format. # # Duplicate text in the last field will be cooked out during the conversion # to HTML with ROWSPAN magic. They must be an exact match for this to work. "Ablerex" "ups" "2" "625L" "USB" "blazer_usb" "Ablerex" "ups" "2" "Hope Office 400/600" "" "blazer_ser" "Ablerex" "ups" "2" "MARS MS3000RT" "" "blazer_ser" "Ablerex" "ups" "2" "MS-RT" "" "blazer_ser" "Ablerex" "ups" "2" "MP series" "USB" "nutdrv_qx" "Ablerex" "ups" "2" "ARES Plus series" "USB" "nutdrv_qx" "Ablerex" "ups" "2" "MSII series" "USB" "nutdrv_qx" "Ablerex" "ups" "2" "MSIII series" "USB" "nutdrv_qx" "Ablerex" "ups" "2" "GRs series" "USB" "nutdrv_qx" "Ablerex" "ups" "2" "GRs Plus series" "USB" "nutdrv_qx" "ActivePower" "ups" "2" "400VA" "" "blazer_ser" "ActivePower" "ups" "2" "1400VA" "" "blazer_ser" "ActivePower" "ups" "2" "2000VA" "" "blazer_ser" "Advice" "ups" "2" "TopGuard 2000" "" "blazer_ser" "Advice" "ups" "2" "Top V Pro 6-10K" "USB" "blazer_usb" # https://www.advice.co.il/en/advice-products/ups-systems/ups-online-systems/one-phase-ups-5k-10k/%D7%90%D7%9C-%D7%A4%D7%A1%D7%A7-%D7%90%D7%95%D7%9F-%D7%9C%D7%99%D7%99%D7%9F-top-v-pro-6-10k-detail https://github.com/networkupstools/nut/issues/744 "Advice" "ups" "2" "PRS850" "USB" "blazer_usb" "Advice" "ups" "2" "PRV700 Pro" "USB" "blazer_usb" "AEC" "ups" "1" "MiniGuard UPS 700" "Megatec M2501 cable" "genericups upstype=21" "AEG Power Solutions" "ups" "2" "PROTECT HOME" "" "blazer_ser or blazer_usb" "AEG Power Solutions" "ups" "3" "PROTECT NAS" "USB" "usbhid-ups" "AEG Power Solutions" "ups" "3" "PROTECT B" "USB" "usbhid-ups" "APC" "ups" "3" "APC AP9584 Serial-to-USB kit" "USB" "usbhid-ups" # Allows USB connections to Serial-port APC devices, https://github.com/networkupstools/nut/pull/181 "APC" "ups" "2" "Back-UPS 1200BR (Microsol)" "" "solis" "APC" "ups" "2" "Back-UPS BZ2200BI-BR (Microsol)" "" "solis" "APC" "ups" "1" "Back-UPS Pro" "" "apcsmart" "APC" "ups" "1" "Matrix-UPS" "" "apcsmart" "APC" "ups" "1" "Smart-UPS" "" "apcsmart" "APC" "ups" "1" "Smart-UPS SMT/SMX/SURTD" "Microlink models with RJ45 socket - they *require* AP9620 SmartSlot expansion card and smart cable" "apcsmart" "APC" "ups" "3" "Back-UPS Pro USB" "USB" "usbhid-ups" "APC" "ups" "3" "Back-UPS (USB)" "USB" "usbhid-ups" "APC" "ups" "3" "Back-UPS CS USB" "USB" "usbhid-ups" "APC" "ups" "3" "Back-UPS RS USB" "USB" "usbhid-ups" "APC" "ups" "3" "Back-UPS LS USB" "USB" "usbhid-ups" "APC" "ups" "3" "Back-UPS ES/CyberFort 350" "USB" "usbhid-ups" "APC" "ups" "3" "Back-UPS BF500" "USB" "usbhid-ups" "APC" "ups" "3" "BACK-UPS XS LCD" "USB" "usbhid-ups" "APC" "ups" "3" "Back-UPS XS 1000M (Back-UPS Pro 1000, Model BX1000M)" "USB" "usbhid-ups" # https://github.com/networkupstools/nut/issues/139 "APC" "ups" "3" "SMC2200BI-BR" "USB" "usbhid-ups" # https://github.com/networkupstools/nut/issues/557 "APC" "ups" "3" "Smart-UPS (USB)" "USB" "usbhid-ups" "APC" "ups" "3" "Smart-UPS 750 (SMT750I, USB)" "USB" "usbhid-ups" "APC" "ups" "3" "Smart-UPS 1500 (SMT1500I, USB)" "USB" "usbhid-ups" "APC" "ups" "3" "Smart-UPS X 750 (SMX750I, USB)" "USB" "usbhid-ups" "APC" "ups" "3" "Smart-UPS X 1500 (SMX1500I, USB)" "USB" "usbhid-ups" "APC" "ups" "3" "SMC2200BI-BR" "USB" "apc_modbus" # https://github.com/networkupstools/nut/issues/557 "APC" "ups" "3" "Smart-UPS (USB)" "USB" "apc_modbus" "APC" "ups" "3" "Smart-UPS 750 (SMT750I, USB)" "USB" "apc_modbus" "APC" "ups" "3" "Smart-UPS 1500 (SMT1500I, USB)" "USB" "apc_modbus" "APC" "ups" "3" "Smart-UPS X 750 (SMX750I, USB)" "USB" "apc_modbus" "APC" "ups" "3" "Smart-UPS X 1500 (SMX1500I, USB)" "USB" "apc_modbus" "APC" "ups" "3" "CS500" "USB" "usbhid-ups (limited data available)" # https://github.com/networkupstools/nut/issues/1776#issuecomment-1377784584 "APC" "ups" "1" "Back-UPS" "940-0095A/C cables" "genericups upstype=1" "APC" "ups" "1" "Back-UPS" "940-0020B/C cables" "genericups upstype=2" "APC" "ups" "1" "Back-UPS" "940-0023A cable" "genericups upstype=9" "APC" "ups" "1" "Back-UPS Office" "940-0119A cable" "genericups upstype=12" "APC" "ups" "1" "Back-UPS RS 500" "custom non-USB cable" "genericups upstype=20" "APC" "ups" "3" "Smart-UPS SUA 1000" "" "snmp-ups" "APC" "ups" "3" "Smart-UPS 3000" "" "snmp-ups" "APC" "ups" "3" "Smart-UPS RT XL" "AP9618 SNMP monitoring card" "snmp-ups" "APC" "ups" "3" "(various)" "AP9618 SNMP monitoring card" "snmp-ups" "APC" "ups" "3" "(various)" "AP9630 SNMP monitoring card" "snmp-ups privProtocol=AES" "APC" "ups" "3" "(various)" "APCUPSD-controlled devices" "apcupsd-ups" "APC" "pdu" "1" "Masterswitch" "940-0020 cable" "genericups upstype=12" "APC" "pdu" "1" "AP9210" "8 outlets" "powerman-pdu (experimental)" "APC" "pdu" "1" "AP79xx" "8 to 24 outlets" "powerman-pdu (experimental)" "APC" "pdu" "3" "(various APxxxx)" "SNMP monitoring card" "snmp-ups" "APC" "ats" "3" "ATS AP7724" "" "snmp-ups (experimental)" "Aphel" "pdu" "3" "various PDU" "" "snmp-ups (experimental)" "Apollo" "ups" "1" "1000A" "" "genericups upstype=4" "Apollo" "ups" "1" "1000F" "" "genericups upstype=4" "Apollo" "ups" "2" "850VA" "USB" "blazer_usb" "Appro" "pdu" "1" "SWPDU" "48 outlets" "powerman-pdu (experimental)" "ARES" "ups" "2" "AR265i" "USB" "nutdrv_qx port=auto vendorid=0001 productid=0000 protocol=hunnox langid_fix=0x0409 novendor noscanlangid" # https://github.com/networkupstools/nut/pull/638 did not explicitly mention the driver parameters, but other reports in the discussion did "ARTronic" "ups" "2" "ARTon Millenium 1/2/3/6/10 kVA" "Serial" "blazer_ser" "ARTronic" "ups" "2" "ARTon Millenium 3.1 10/15/20 kVA" "Serial" "blazer_ser" "ARTronic" "ups" "2" "ARTon Titanium 6/10 kVA" "Serial" "blazer_ser" "ARTronic" "ups" "2" "ARTon Titanium 3.1 10/15/20 kVA" "Serial" "blazer_ser" "ARTronic" "ups" "2" "ARTon Optimum 1/2/3/6/10 kVA" "Serial" "blazer_ser" "ARTronic" "ups" "2" "ARTon Titanium Plus 1/2/3 kVA" "USB" "blazer_usb" "ARTronic" "ups" "2" "ARTon Platinium 6/10 kVA" "USB" "blazer_usb" "ARTronic" "ups" "2" "ARTon Platinium Combo 3.1 10/15/20 kVA" "USB" "blazer_usb" "ARTronic" "ups" "2" "ARTon Platinium RT 1/2/3/6/10 kVA" "USB" "blazer_usb" "Armac" "ups" "2" "R/2000I/PSW and PF1 series" "(USB ID 0925:1234)" "nutdrv_qx" "ASEM SPA" "ups" "5" "PB1300 UPS" "i2c" "asem" "Asium" "ups" "3" "P700" "USB" "blazer_usb" # http://www.asiumpower.com/Asium-ASIUM-P700-650VA-360W/dp/B009SMEQ10 "ATEK" "ups" "2" "Defensor 1K Tower / Rack" "USB" "blazer_usb" "ATEK" "ups" "2" "Defensor 2K Tower / Rack" "USB" "blazer_usb" "ATEK" "ups" "2" "Defensor 3K Tower / Rack" "USB" "blazer_usb" "ATEK" "ups" "2" "Defensor 6K Tower / Rack" "USB" "blazer_usb" "ATEK" "ups" "2" "Defensor 10K Tower / Rack" "USB" "blazer_usb" "Atlantis Land" "ups" "2" "A03-P826" "" "blazer_ser" "Atlantis Land" "ups" "2" "A03-P551" "USB" "blazer_usb langid_fix=0x0409" # http://www.atlantisland.it/pub/prodotti.php?famiglia=1&l1=7&l2=24&articolo=QTAzLVA1NTE= "Atlantis Land" "ups" "2" "HostPower 851 (A03-HP851)" "USB" "nutdrv_qx" "Atlantis Land" "ups" "2" "LinePower 1151 (A03-OP1151)" "Serial" "nutdrv_qx" "Atlantis Land" "ups" "2" "LinePower 1151 (A03-OP1151)" "USB" "nutdrv_qx" "Atlantis Land" "ups" "2" "OnePower 841+ (A03-P841)" "USB" "nutdrv_qx" "Atlantis Land" "ups" "2" "(various)" "Serial" "nutdrv_qx" "Atlantis Land" "ups" "2" "(various)" "USB" "nutdrv_qx" "Aviem Systems" "ups" "2" "Aviem Power RT 1000-3000VA" "" "blazer_ser" "Aviem Systems" "ups" "2" "Aviem Pro 2000VA" "USB" "blazer_usb" # https://github.com/networkupstools/nut/issues/827 "Baytech" "pdu" "1" "RPC3" "8 outlets" "powerman-pdu (experimental)" "Baytech" "pdu" "1" "RPC3-20NC" "8 outlets" "powerman-pdu (experimental)" "Baytech" "pdu" "1" "RPC28-30NC" "20 outlets" "powerman-pdu (experimental)" "Baytech" "pdu" "3" "various RPC" "" "snmp-ups" "Belkin" "ups" "2" "Active Battery Backup BU30 series" "USB" "blazer_usb" "Belkin" "ups" "1" "Home Office F6H350-SER" "" "genericups upstype=7" "Belkin" "ups" "1" "Home Office F6H500-SER" "" "genericups upstype=7" "Belkin" "ups" "1" "Home Office F6H650-SER" "" "genericups upstype=7" "Belkin" "ups" "3" "F6H375-USB" "USB (<= 2005 models, vendor id: 050d)" "usbhid-ups" "Belkin" "ups" "2" "F6H375-USB" "USB (2007 models, vendor id: 0665)" "blazer_usb" "Belkin" "ups" "3" "Office Series F6C550-AVR" "USB" "usbhid-ups" "Belkin" "ups" "3" "Regulator PRO-USB" "USB (~2000, product id: 0f51)" "usbhid-ups" "Belkin" "ups" "2" "Regulator Pro" "F6C525-SER, F6C625-SER" "belkin" "Belkin" "ups" "1" "Resource" "" "genericups upstype=4" "Belkin" "ups" "2" "Small Enterprise F6C1500-TW-RK" "serial port" "belkin" "Belkin" "ups" "3" "Small Enterprise F6C1500-TW-RK" "USB" "usbhid-ups" "Belkin" "ups" "3" "Universal UPS F6C100-UNV" "USB" "usbhid-ups" "Belkin" "ups" "1" "Universal UPS F6C120-UNV" "serial port" "belkinunv" "Belkin" "ups" "3" "Universal UPS F6C120-UNV" "USB" "usbhid-ups" "Belkin" "ups" "1" "Universal UPS F6C800-UNV" "serial port" "belkinunv" "Belkin" "ups" "3" "Universal UPS F6C800-UNV" "USB" "usbhid-ups" "Belkin" "ups" "1" "Universal UPS F6C1100-UNV" "serial port (<= 2005 models)" "belkinunv" "Belkin" "ups" "3" "Universal UPS F6C1100-UNV" "USB (<= 2005 models, vendor id: 050d)" "usbhid-ups" "Belkin" "ups" "2" "Universal UPS F6C1100-UNV" "USB (2007 models, vendor id: 0665)" "blazer_usb" "Belkin" "ups" "3" "Universal UPS F6C1200-UNV" "USB (<= 2005 models, vendor id: 050d)" "usbhid-ups" "Belkin" "ups" "2" "Universal UPS F6C1200-UNV" "USB (2007 models, vendor id: 0665)" "blazer_usb" "Belkin" "ups" "2" "Universal UPS F6H350deUNV" "serial port" "blazer_ser" "Belkin" "ups" "2" "Universal UPS F6H350ukUNV" "serial port" "blazer_ser" "Belkin" "ups" "2" "Universal UPS F6H500ukUNV" "serial port" "blazer_ser" "Belkin" "ups" "2" "Universal UPS F6H650ukUNV" "serial port" "blazer_ser" "Belkin" "ups" "2" "F6S600auUSB" "USB" "blazer_usb" "Best Power" "ups" "1" "Fortress (older)" "" "bestfortress" "Best Power" "ups" "1" "Fortress (newer)" "" "blazer_ser or bestups" "Best Power" "ups" "1" "Fortress Telecom" "" "blazer_ser or bestups" "Best Power" "ups" "1" "Axxium Rackmount" "" "blazer_ser or bestups" "Best Power" "ups" "1" "Patriot Pro" "" "blazer_ser or bestups" "Best Power" "ups" "1" "Patriot Pro II" "" "blazer_ser or bestups" "Best Power" "ups" "1" "Patriot" "INT51 cable" "genericups upstype=6" "Best Power" "ups" "1" "Micro-Ferrups" "" "bestuferrups" "Best Power" "ups" "1" "Fortress/Ferrups" "f-command support" "bestfcom" "Borri" "ups" "2" "B400-010-B/B400-020-B/B400-030-B/B400-010-C/B400-020-C/B400-030-C" "USB" "blazer_usb" "Borri" "ups" "2" "B400-R010-B/B400-R020-B/B400-R030-B/B400-R010-C/B400-R020-C/B400-R030-C" "USB" "blazer_usb" "Borri" "ups" "2" "B500-060-B/B500-100-B/B500-060-C/B500-100-C" "USB" "blazer_usb" "Borri" "ups" "2" "B500-R060-B/B500-R100-B" "USB" "blazer_usb" "Borri" "ups" "2" "B500EVO-100-B/B500EVO-200-B" "USB" "blazer_usb" "CABAC" "ups" "2" "UPS-1700DV2" "USB" "blazer_usb" "Chloride" "ups" "2" "Desk Power 650" "serial port" "blazer_ser" "Cito Power" "ups" "2" "CPG-SR1000" "" "blazer_ser" "Clary" "ups" "4" "ST-800" "" "gamatronic" "Compaq" "ups" "4" "T1500h" "" "upscode2 use_pre_lf" "Compaq" "ups" "4" "R3000h" "" "upscode2" "Compaq" "ups" "4" "R3000 XR" "" "bcmxcp" "Compaq" "ups" "4" "R5500 XR" "" "bcmxcp" "COVER ENERGY SA" "ups" "2" "COVER PRM 1K/2K/3K/6K/10K" "USB" "blazer_usb" "COVER ENERGY SA" "ups" "2" "COVER PRM 1K/2K/3K/6K/10K EC" "USB" "blazer_usb" "COVER ENERGY SA" "ups" "2" "COVER PRM 6K/10K PR" "USB" "blazer_usb" "CPC" "ups" "2" "RACK850VA" "USB" "nutdrv_qx port=auto vendorid=0001 productid=0000 product=MEC0003 protocol=hunnox langid_fix=0x0409 novendor noscanlangid" # https://github.com/networkupstools/nut/pull/638 caveats at https://github.com/networkupstools/nut/issues/537 "Crown" "ups" "2" "CMU-SP1200IEC" "USB" "nutdrv_qx port=auto vendorid=0001 productid=0000 protocol=hunnox langid_fix=0x0409 novendor noscanlangid" # https://github.com/networkupstools/nut/pull/638 caveats at https://github.com/networkupstools/nut/issues/1014 "Cyber Power Systems" "ups" "1" "550SL" "" "genericups upstype=7" "Cyber Power Systems" "ups" "1" "725SL" "" "genericups upstype=7" "Cyber Power Systems" "ups" "1" "CPS1100AVR" "" "powerpanel" "Cyber Power Systems" "ups" "1" "CPS1200AVR" "" "powerpanel" "Cyber Power Systems" "ups" "1" "CPS1250AVR" "" "powerpanel" "Cyber Power Systems" "ups" "1" "CPS1500AVR" "" "powerpanel" "Cyber Power Systems" "ups" "1" "CPS1500AVR-HO" "" "powerpanel" "Cyber Power Systems" "ups" "1" "CPS320AVR" "" "powerpanel" "Cyber Power Systems" "ups" "1" "CPS500AVR" "" "powerpanel" "Cyber Power Systems" "ups" "1" "CPS650AVR" "" "powerpanel" "Cyber Power Systems" "ups" "1" "CPS700AVR" "" "powerpanel" "Cyber Power Systems" "ups" "1" "CPS800AVR" "" "powerpanel" "Cyber Power Systems" "ups" "1" "CPS825VA" "" "powerpanel" "Cyber Power Systems" "ups" "1" "CPS850AVR" "" "powerpanel" "Cyber Power Systems" "ups" "1" "CPS900AVR" "" "powerpanel" # http://www.cyberpowersystems.com/products/ups-systems/other-ups/CPS900AVR.html "Cyber Power Systems" "ups" "1" "PR2200" "" "powerpanel" "Cyber Power Systems" "ups" "1" "Power99" "" "genericups upstype=7" "Cyber Power Systems" "ups" "3" "AE550" "USB" "usbhid-ups" "Cyber Power Systems" "ups" "3" "BL1250U" "USB" "usbhid-ups" # https://www.cyberpowersystems.com/product/ups/battery-backup/bl1250u/ https://github.com/networkupstools/nut/issues/1012 "Cyber Power Systems" "ups" "3" "BR1000ELCD" "USB" "usbhid-ups" # https://www.cyberpower.com/eu/en/product/sku/BR1000ELCD https://github.com/networkupstools/nut/issues/552 "Cyber Power Systems" "ups" "3" "CP1350AVRLCD" "USB" "usbhid-ups" "Cyber Power Systems" "ups" "3" "CP1500AVRLCD" "USB" "usbhid-ups" "Cyber Power Systems" "ups" "3" "CP850PFCLCD" "USB" "usbhid-ups" # https://github.com/networkupstools/nut/issues/605 "Cyber Power Systems" "ups" "3" "CP1350PFCLCD" "USB" "usbhid-ups" # https://alioth-lists.debian.net/pipermail/nut-upsuser/2023-October/013441.html "Cyber Power Systems" "ups" "3" "CP1500PFCLCD" "USB" "usbhid-ups" # https://www.cyberpowersystems.com/product/ups/cp1500pfclcd/ https://github.com/networkupstools/nut/issues/520 "Cyber Power Systems" "ups" "3" "CPJ500" "USB" "usbhid-ups" # https://www.cyberpower.com/jp/ja/product/sku/cpj500#downloads https://github.com/networkupstools/nut/issues/1403 "Cyber Power Systems" "ups" "3" "CP900AVR" "USB" "usbhid-ups" "Cyber Power Systems" "ups" "3" "CPS685AVR" "USB" "usbhid-ups" "Cyber Power Systems" "ups" "3" "CPS800AVR" "USB" "usbhid-ups" "Cyber Power Systems" "ups" "2" "OL3000RMXL2U" "" "powerpanel" "Cyber Power Systems" "ups" "2" "PR3000E" "" "powerpanel" "Cyber Power Systems" "ups" "3" "Value 1500ELCD-RU" "USB" "usbhid-ups" "Cyber Power Systems" "ups" "3" "Value 400E" "USB" "usbhid-ups" "Cyber Power Systems" "ups" "3" "Value 600E" "USB" "usbhid-ups" "Cyber Power Systems" "ups" "3" "Value 800E" "USB" "usbhid-ups" "Cyber Power Systems" "ups" "3" "VP1200ELCD (ValueII_1200E)" "USB" "usbhid-ups" "Cyber Power Systems" "ups" "3" "CP 1500C" "USB" "usbhid-ups" "Cyber Power Systems" "ups" "3" "CP1000PFCLCD" "USB" "usbhid-ups" "Cyber Power Systems" "ups" "3" "CP1500EPFCLCD" "USB" "usbhid-ups" # http://www.cyberpower-eu.com/products/ups_systems/pfc-sinewave/cp1500epfclcd.htm "Cyber Power Systems" "ups" "3" "CP825AVR-G / LE825G" "USB" "usbhid-ups" # http://www.cyberpowersystems.com/products/ups-systems/retail-products/LE825G.html "Cyber Power Systems" "ups" "3" "EC350G" "USB" "usbhid-ups" # https://www.cyberpowersystems.com/products/ups/ecologic/ec350g "Cyber Power Systems" "ups" "3" "EC750G" "USB" "usbhid-ups" # https://www.cyberpowersystems.com/products/ups/desktop/ec750g "Cyber Power Systems" "ups" "3" "EC850LCD" "USB" "usbhid-ups" # https://www.cyberpowersystems.com/product/ups/ec850lcd/ https://github.com/networkupstools/nut/issues/622 "Cyber Power Systems" "ups" "3" "OR1500ERM1U" "USB" "usbhid-ups" # https://github.com/networkupstools/nut/issues/1338 "Cyber Power Systems" "ups" "3" "OR2200LCDRM2U" "USB" "usbhid-ups" "Cyber Power Systems" "ups" "3" "OR700LCDRM1U" "USB" "usbhid-ups" "Cyber Power Systems" "ups" "3" "OR500LCDRM1U" "USB" "usbhid-ups" # https://www.cyberpowersystems.com/product/ups/or500lcdrm1u/ https://github.com/networkupstools/nut/issues/578 "Cyber Power Systems" "ups" "3" "RT650EI" "USB" "usbhid-ups" # http://www.cyberpowersystems.de/produkte/backup-usv-serien/rt-serie.html https://github.com/networkupstools/nut/issues/453 "Cyber Power Systems" "ups" "3" "UT2200E" "USB" "usbhid-ups" # https://www.cyberpower.com/ww/en/product/sku/UT2200E https://github.com/networkupstools/nut/issues/556 "Cyber Power Systems" "ups" "3" "PR1500RT2U" "USB" "usbhid-ups" # https://www.cyberpowersystems.com/product/ups/new-smart-app-sinewave/pr1500rt2u/ https://github.com/networkupstools/nut/issues/1191 "Cyber Power Systems" "ups" "3" "PR6000LCDRTXL5U" "USB" "usbhid-ups" "Cyber Power Systems" "ups" "3" "PR2200LCDRT2U" "" "snmp-ups" "Cyber Power Systems" "ups" "3" "RMCARD100" "" "snmp-ups" "Cyber Power Systems" "ups" "3" "RMCARD201" "" "snmp-ups" "Cyber Power Systems" "ups" "3" "RMCARD202" "" "snmp-ups" "Cyber Power Systems" "ups" "3" "RMCARD205" "" "snmp-ups" "Cyber Power Systems" "ups" "3" "RMCARD301" "" "snmp-ups" "Cyclades" "pdu" "1" "PM8" "8 outlets" "powerman-pdu (experimental)" "Cyclades" "pdu" "1" "PM10" "10 outlets" "powerman-pdu (experimental)" "Dell" "ups" "5" "Tower 500W LV / HV" "Serial port" "mge-shut" "Dell" "ups" "5" "Rack/Tower 1000W LV / HV" "Serial port" "mge-shut" "Dell" "ups" "5" "Rack/Tower 1500W LV" "Serial port" "mge-shut" "Dell" "ups" "5" "Rack/Tower 1920W LV / HV" "Serial port" "mge-shut" "Dell" "ups" "5" "Rack/Tower 2300W LV" "Serial port" "mge-shut" "Dell" "ups" "5" "Rack/Tower 2700W LV / HV" "Serial port" "mge-shut" "Dell" "ups" "5" "Short Depth Rack 2700W Online LV / HV" "High Efficiency, Serial port" "mge-shut" "Dell" "ups" "5" "Rack 3750W High Efficiency Online HV" "Serial port" "mge-shut" "Dell" "ups" "5" "Rack 4200W High Efficiency Online HV" "Serial port" "mge-shut" "Dell" "ups" "5" "Rack 5600W HV" "Serial port" "mge-shut" "Dell" "ups" "5" "Tower 500W LV / HV" "USB port" "usbhid-ups" "Dell" "ups" "5" "Rack/Tower 1000W LV / HV" "USB port" "usbhid-ups" "Dell" "ups" "5" "Rack/Tower 1500W LV" "USB port" "usbhid-ups" "Dell" "ups" "5" "Rack/Tower 1920W LV / HV" "USB port" "usbhid-ups" "Dell" "ups" "5" "Rack/Tower 2300W LV" "USB port" "usbhid-ups" "Dell" "ups" "5" "Rack/Tower 2700W LV / HV" "USB port" "usbhid-ups" "Dell" "ups" "5" "Short Depth Rack 2700W Online LV / HV" "High Efficiency, USB port" "usbhid-ups" "Dell" "ups" "5" "Rack 3750W High Efficiency Online HV" "USB port" "usbhid-ups" "Dell" "ups" "5" "Rack 4200W High Efficiency Online HV" "USB port" "usbhid-ups" "Dell" "ups" "5" "Rack 5600W HV" "USB port" "usbhid-ups" "Dell" "ups" "5" "Various (SNMP mode)" "UPS Network Management Card" "snmp-ups" "Dell" "ups" "5" "Various (XML/HTTP mode)" "UPS Network Management Card" "netxml-ups (experimental)" "Delta" "ups" "1" "GES602N" "" "belkin" "Delta" "ups" "4" "Delta UPS Amplon R Series" "USB port" "usbhid-ups" "Deltec" "ups" "1" "PowerRite Pro II" "" "genericups upstype=15" "Deltec" "ups" "4" "PRM 450/700/1000/1500" "" "upscode2" "DEXP" "ups" "2" "MIX 850VA" "USB" "blazer_usb langid_fix=0x0409 runtimecal=240,100,720,50 default.battery.voltage.high=2.27 default.battery.voltage.low=1.72" # https://github.com/networkupstools/nut/issues/721 "Digital Loggers" "pdu" "1" "LPC, EPCR2, DIN" "8 outlets" "powerman-pdu (experimental)" "DigiTECH" "ups" "2" "Computer 650VA" "USB" "nutdrv_qx port=auto vendorid=0001 productid=0000 protocol=hunnox langid_fix=0x0409 novendor noscanlangid" # https://github.com/networkupstools/nut/pull/638 caveats at https://github.com/networkupstools/nut/issues/674 (may need longer pollinterval) "Digitus" "ups" "1" "DN-170014" "USB" "richcomm_usb" # http://www.digitus.info/en/products/professional-network/security-and-surveillance/power-supply/uninterrruptable-power-supplies/ups-uninterruptible-power-systems-dn-170014/section/prof/ "Digitus" "ups" "2" "DN-170020" "" "blazer_ser" "Digitus" "ups" "2" "DN-170040" "USB" "blazer_usb" # https://github.com/networkupstools/nut/issues/1251 "Digitus" "ups" "2" "DN-170041" "USB" "blazer_usb" # https://github.com/networkupstools/nut/issues/1251 "Digitus" "ups" "2" "DN-170040" "USB" "nutdrv_qx" # https://github.com/networkupstools/nut/issues/1251 "Digitus" "ups" "2" "DN-170041" "USB" "nutdrv_qx" # https://github.com/networkupstools/nut/issues/1251 "Digitus" "ups" "2" "DN-170076" "USB" "nutdrv_qx" # https://www.digitus.info/en/products/network-and-server-cabinets/power-supply/uninterruptible-power-supplies/dn-170076/ https://github.com/networkupstools/nut/issues/948 "Dynamix" "ups" "2" "UPS1700D" "" "blazer_ser" "Dynamix" "ups" "2" "UPS-650VA" "" "blazer_ser" "Dynamix" "ups" "2" "650VA/1000VA" "USB" "blazer_usb langid_fix=0x0409" "Dynex" "ups" "1" "975AVR" "" "genericups upstype=7" "Dynex" "ups" "3" "DX-800U" "USB" "usbhid-ups" "Eaton" "ups" "5" "3S" "USB" "usbhid-ups" "Eaton" "ups" "5" "Protection Station 500/650/800 VA" "USB" "usbhid-ups" "Eaton" "ups" "5" "Ellipse ECO 650/800/1200/1600 VA" "USB" "usbhid-ups" "Eaton" "ups" "5" "Ellipse ASR USBS 600/750/1000/1500 VA" "USB cable" "usbhid-ups" "Eaton" "ups" "5" "Ellipse MAX USBS 600/850/1100/1500 VA" "USB cable" "usbhid-ups" "Eaton" "ups" "5" "Ellipse PRO 650 VA" "USB cable" "usbhid-ups" "Eaton" "ups" "5" "Evolution 650/850/1150/1550/2000 VA" "USB port" "usbhid-ups" "Eaton" "ups" "5" "Evolution S 1250/1750/2500/3000 VA" "USB port" "usbhid-ups" "Eaton" "ups" "5" "EX 700/1000/1500 VA" "USB port" "usbhid-ups" "Eaton" "ups" "5" "EX 2200/3000/3000 XL VA" "USB port" "usbhid-ups" "Eaton" "ups" "5" "EX 1000 RT2U / 1500 RT2U" "USB port" "usbhid-ups" "Eaton" "ups" "5" "MX 5/8/10/15/20 kVA" "USB port" "usbhid-ups" "Eaton" "ups" "5" "5 PX" "USB port" "usbhid-ups" "Eaton" "ups" "5" "Nova AVR 625/1250" "USB" "usbhid-ups" "Eaton" "ups" "5" "5E650iUSB" "USB port" "usbhid-ups" "Eaton" "ups" "5" "5E1100iUSB" "USB port" "usbhid-ups" # http://powerquality.eaton.com/5E1100iUSB.aspx?CX&GUID=8D85FE66-3102-427C-8F33-B8D56BBDD4D3 "Eaton" "ups" "4" "5E2200" "USB port" "nutdrv_qx" "Eaton" "ups" "5" "5S" "USB port" "usbhid-ups" "Eaton" "ups" "5" "5SC" "USB port" "usbhid-ups" "Eaton" "ups" "5" "5P" "USB port" "usbhid-ups" "Eaton" "ups" "5" "9SX" "USB port" "usbhid-ups" "Eaton" "ups" "5" "9PX" "USB port" "usbhid-ups" "Eaton" "ups" "5" "9PX Split Phase 6/8/10 kVA" "USB port" "usbhid-ups" "Eaton" "ups" "5" "Ellipse ASR USBS 600/750/1000/1500 VA" "Serial cable" "mge-shut" "Eaton" "ups" "5" "Ellipse MAX USBS 600/850/1100/1500 VA" "Serial cable" "mge-shut" "Eaton" "ups" "5" "Evolution 650/850/1150/1550/2000 VA" "Serial port" "mge-shut" "Eaton" "ups" "5" "Evolution S 1250/1750/2500/3000 VA" "Serial port" "mge-shut" "Eaton" "ups" "5" "EX 700/1000/1500 VA" "Serial port" "mge-shut" "Eaton" "ups" "5" "EX 2200/3000/3000 XL VA" "Serial port" "mge-shut" "Eaton" "ups" "5" "EX 1000 RT2U / 1500 RT2U" "Serial port" "mge-shut" "Eaton" "ups" "5" "MX 5/8/10/15/20 kVA" "Serial port" "mge-shut" "Eaton" "ups" "5" "5 PX" "Serial port" "mge-shut" "Eaton" "ups" "5" "EX RT 1:1 7/11 kVA" "" "mge-shut" "Eaton" "ups" "5" "EX RT 3:1 5/7/11 kVA" "" "mge-shut" "Eaton" "ups" "5" "5SC" "Serial port" "mge-shut" "Eaton" "ups" "5" "5P" "Serial port" "mge-shut" "Eaton" "ups" "5" "9SX" "Serial port" "mge-shut" "Eaton" "ups" "5" "9PX" "Serial port" "mge-shut" "Eaton" "ups" "5" "9PX 2000 RT" "USB port" "mge-shut" # https://github.com/networkupstools/nut/issues/540 "Eaton" "ups" "5" "9PX Split Phase 6/8/10 kVA" "Serial port" "mge-shut" "Eaton" "ups" "5" "9PX" "SNMP/Web card" "netxml-ups" "Eaton" "ups" "5" "9PX Split Phase 6/8/10 kVA" "SNMP/Web card" "netxml-ups" "Eaton" "ups" "5" "EX RT (XML/HTTP)" "NMC Transverse card (ref 66074)" "netxml-ups (experimental)" "Eaton" "ups" "5" "EX RT (SNMP)" "NMC Transverse card (ref 66074)" "snmp-ups (experimental)" "Eaton" "ups" "5" "E Series NV UPS 400-2000 VA" "USB" "blazer_usb" "Eaton" "ups" "5" "E Series DX UPS 1-20 kVA" "" "blazer_ser" # http://www.eaton.com/Eaton/ESeriesUPS/DXUPS/ "Eaton" "ups" "4" "NetUPS SE 450/700/1000/1500" "" "upscode2" "Eaton" "ups" "5" "BladeUPS (SNMP)" "ConnectUPS Web/SNMP Card" "snmp-ups (experimental)" "Eaton" "ups" "5" "various models (SNMP mode)" "Power Xpert Gateway UPS Card" "snmp-ups (experimental)" "Eaton" "ups" "5" "various models (XML/HTTP mode)" "NMC Minislot (ref 66102)" "netxml-ups (experimental)" "Eaton" "ups" "5" "various models (SNMP mode)" "NMC Minislot (ref 66102)" "snmp-ups (experimental)" "Eaton" "ups" "5" "various models (XML/HTTP mode)" "SNMP/Web Minislot card (ref 66244)" "netxml-ups (experimental)" "Eaton" "ups" "5" "various models (SNMP mode)" "SNMP/Web Minislot card (ref 66244)" "snmp-ups (experimental)" "Eaton" "ups" "5" "various models (SNMP mode)" "Eaton Gigabit Network Card (Network-M2)" "snmp-ups (experimental)" "Eaton" "ups" "5" "various models (serial mode)" "Management Card Contact (ref 66104)" "mge-shut or mge-utalk" "Eaton" "pdu" "5" "ePDU Managed" "" "snmp-ups" "Eaton" "pdu" "5" "ePDU Switched" "" "snmp-ups" "Eaton" "pdu" "5" "ePDU Monitored" "" "snmp-ups or netxml-ups" "Eaton" "ups" "5" "ePDU EMSV0001" "nLogic rebranded" "snmp-ups" "Eaton" "ups" "5" "Powerware 3105" "USB" "bcmxcp_usb" # http://powerquality.eaton.com/Products-services/Backup-Power-UPS/3105-eol.aspx "Eaton" "ups" "5" "Powerware 9125" "USB card" "bcmxcp_usb" "Eaton" "ups" "5" "Powerware 9130" "" "bcmxcp or usbhid-ups" "Eaton" "ups" "5" "Powerware 9140" "" "bcmxcp or usbhid-ups" "Eaton" "ups" "5" "Powerware 5130" "USB" "usbhid-ups" "Eaton" "ups" "5" "9395" "Serial port" "bcmxcp" "Eaton" "ups" "5" "Best Ferrups" "older ConnectUPS" "snmp-ups" "Eaton" "ups" "5" "ConnectUPS X / BD / E Slot" "Serial Pass-through mode" "bcmxcp" "Eaton" "ups" "5" "ConnectUPS X / BD / E Slot" "Network port" "snmp-ups" "Eaton" "ups" "5" "Management Card Contact" "Config 3 - Cable 66033" "genericups upstype=7" "Eaton" "ats" "5" "Eaton ATS16" "" "snmp-ups" "Eaton" "ats" "5" "Eaton ATS30" "" "snmp-ups" "Effekta" "ups" "2" "MI/MT/MH" "2502 cable" "blazer_ser" "Effekta" "ups" "2" "RM2000MH" "" "blazer_ser" "Electrys" "ups" "2" "UPS 2500" "" "nutdrv_qx or blazer_ser" "Elsist" "ups" "2" "Nemo2.0 160" "USB" "blazer_usb" # http://www.naicon.com/company/wp-content/uploads/2017/05/Manual-NEMO2.0-Ver.02-Eng.pdf https://github.com/networkupstools/nut/issues/719 "Emerson" "pdu" "3" "PM3000 metered & switched" "" "snmp-ups" "Energy Sistem" "ups" "2" "(various)" "" "blazer_ser" "Energy Technologies" "ups" "2" "DPK1/1-3" "Serial" "blazer_ser" # https://www.tensy.ru/podderzhka/dokumentatsiya/ibp-serii-dpk/ https://github.com/networkupstools/nut/issues/762 "ETA" "ups" "1" "mini+UPS" "WinNT/Upsoft cable" "genericups upstype=7" "ETA" "ups" "1" "mini+UPS PRO" "UPS Explorer cable" "etapro" "EUROCASE" "ups" "2" "EA200N 2000VA" "USB" "nutdrv_qx" # http://partis.cz/index.php?gid=2551 "EVER" "ups" "1" "NET DPC series" "Serial port" "everups" "EVER" "ups" "1" "AP Pro series" "Serial port" "everups" "EVER" "ups" "1" "625/1000" "" "safenet" "EVER" "ups" "2" "POWERLINE RT 1-3kVA series" "Serial port" "blazer_ser" "EVER" "ups" "2" "POWERLINE RT 6-10kVA series" "Serial port" "blazer_ser" "EVER" "ups" "2" "POWERLINE 11 series" "Serial port" "blazer_ser" "EVER" "ups" "2" "POWERLINE 31 series" "Serial port" "blazer_ser" "EVER" "ups" "2" "DUO II Pro series" "USB port" "blazer_usb" "EVER" "ups" "2" "POWERLINE RT 1-3kVA series" "USB port" "blazer_usb" "EVER" "ups" "2" "POWERLINE RT 6-10kVA series" "USB port" "blazer_usb" "EVER" "ups" "4" "ECO Pro AVR CDS series" "USB port" "usbhid-ups" "Exide" "ups" "1" "NetUPS SE" "" "genericups upstype=15" "Exide" "ups" "4" "NetUPS SE 450/700/1000/1500" "" "upscode2" "Fenton Technologies" "ups" "1" "PowerPal" "P-series" "safenet" "Fenton Technologies" "ups" "5" "PowerPal" "L-series" "blazer_ser" "Fenton Technologies" "ups" "5" "PowerOn" "" "blazer_ser" "Fenton Technologies" "ups" "5" "PowerPure" "" "blazer_ser" "Fairstone" "ups" "1" "L525/L625/L750" "" "safenet" "Fideltronik" "ups" "1" "Ares 700 and larger" "" "genericups upstype=6" "Fideltronik" "ups" "2" "LUPUS 500" "USB" "nutdrv_qx" "Fideltronik" "ups" "1" "Other Ares models" "" "genericups upstype=19" "Fideltronik INIGO" "ups" "2" "Viper 1200" "USB" "nutdrv_qx" # http://fideltronikinigo.com/viper/viper-1200/ "Fiskars" "ups" "4" "PowerRite MAX" "" "upscode2" "Fiskars" "ups" "4" "PowerServer 10" "" "upscode2" "Fiskars" "ups" "4" "PowerServer 30" "" "upscode2" "Fiskars" "ups" "4" "9200" "UPS Information Unit" "upscode2" "Flight Technic & International (FTUPS)" "ups" "2" "FT-1000BS" "Serial" "nutdrv_qx" "Flight Technic & International (FTUPS)" "ups" "2" "FT-1000BS" "USB" "nutdrv_qx" "Flight Technic & International (FTUPS)" "ups" "2" "FT-1000BS(T)" "Serial" "nutdrv_qx" "Flight Technic & International (FTUPS)" "ups" "2" "FT-1000BS(T)" "USB" "nutdrv_qx" "Flight Technic & International (FTUPS)" "ups" "2" "Smart On Line UPS 1KVA" "Serial" "nutdrv_qx" "Flight Technic & International (FTUPS)" "ups" "2" "Smart On Line UPS 1KVA" "USB" "nutdrv_qx" "Flight Technic & International (FTUPS)" "ups" "2" "(various)" "Serial" "nutdrv_qx" "Flight Technic & International (FTUPS)" "ups" "2" "(various)" "USB" "nutdrv_qx" "Forza Power Technologies" "ups" "2" "SL-1001" "USB" "blazer_usb" "Forza Power Technologies" "ups" "2" "FX-1500LCD" "USB" "blazer_usb" "FSP" "ups" "2" "EP650" "USB" "blazer_usb" "FSP" "ups" "2" "Fortron UPS Champ 1000 VA Tower" "USB" "blazer_usb" "FSP" "ups" "2" "Fortron UPS Champ 1000 VA Tower" "USB" "nutdrv_qx" "FSP" "ups" "2" "Fortron UPS Champ 2000 VA Tower" "USB" "blazer_usb" "FSP" "ups" "2" "Fortron UPS Champ 3000 VA Tower" "USB" "blazer_usb" "Gamatronic" "ups" "5" "All models with alarm interface" "" "genericups upstype=22" "Gamatronic" "ups" "2" "G-SmartCompact 2000" "" "blazer_ser" "Gamatronic" "ups" "5" "MP110/210" "" "gamatronic" "Gamatronic" "ups" "5" "MS-T" "" "gamatronic" "Gamatronic" "ups" "5" "MS" "" "gamatronic" "Gamatronic" "ups" "5" "µPS3/1" "" "gamatronic" "GE Digital Energy" "ups" "2" "EP Series" "USB" "blazer_usb" "GE Digital Energy" "ups" "2" "GT Series 1000/1500/2000/3000 VA Rack/Tower" "UL-version" "blazer_ser" "Geek Squad" "ups" "3" "GS1285U" "USB" "usbhid-ups" "Gemini" "ups" "1" "UPS625/UPS1000" "" "safenet" "Grafenthal" "ups" "3" "PR-3000-HS" "SNMP/Web Minislot card (ref 149G0006)" "snmp-ups" # http://grafenthal.de/produkte/usv/online/pr-hs-serie/pr-3000-hs/?L=3et8 "Greencell" "ups" "2" "Micropower 600" "USB" "nutdrv_qx" # https://github.com/networkupstools/nut/issues/1080 "Greencell" "ups" "2" "Micropower 600" "USB" "blazer_usb" # https://github.com/networkupstools/nut/issues/1080 "Gtec" "ups" "2" "ZP120N-1K / ZP120N-1KS / ZP120N-2K / ZP120N-2KS / ZP120N-3K / ZP120N-3KS" "USB" "blazer_usb" "Gtec" "ups" "2" "ZP120N-6K / ZP120N-6KS / ZP120N-10K-11 / ZP120N-10KS-11" "USB" "blazer_usb" "Gtec" "ups" "2" "ZP120N-10K-31-00 / ZP120N-10K-31-07 / ZP120N-10K-31-09 / ZP120N-10K-31-99 / ZP120N-20K" "USB port" "blazer_usb" "Gtec" "ups" "2" "AP160N-1K / AP160LCD-1K-KS / AP160N-2K / AP160LCD-2K-KS / AP160N-3K / AP160LCD-3K-KS / AP160N-6K-PDU / AP160N-10K-PDU" "USB port" "blazer_usb" "Gtec" "ups" "2" "ZP120N-10K-31-00 / ZP120N-10K-31-07 / ZP120N-10K-31-09 / ZP120N-10K-31-99 / ZP120N-20K" "Serial port" "blazer_ser" "Gtec" "ups" "2" "AP160N-1K / AP160LCD-1K-KS / AP160N-2K / AP160LCD-2K-KS / AP160N-3K / AP160LCD-3K-KS / AP160N-6K-PDU / AP160N-10K-PDU" "Serial port" "blazer_ser" "Guardian" "ups" "2" "LCD 1500 AP (IGA1500LCD)" "Serial" "nutdrv_qx" "HP" "ups" "1" "PowerTrust 2997A" "HP 5061-2575 cable" "apcsmart" "HP" "ups" "3" "T750 G2" "Serial port" "bcmxcp" "HP" "ups" "3" "T1000 G3" "Serial port" "bcmxcp" "HP" "ups" "3" "T1500 G3" "Serial port" "bcmxcp" "HP" "ups" "3" "R1500 G2" "Serial port" "bcmxcp" "HP" "ups" "4" "R3000 XR" "" "bcmxcp" "HP" "ups" "4" "R5500 XR" "" "bcmxcp" "HP" "ups" "3" "T500 / T750" "older models, USB port" "bcmxcp_usb" "HP" "ups" "3" "R/T3000" "Serial port" "mge-shut" "HP" "ups" "3" "R5000 / R7000" "Serial port" "mge-shut" "HP" "ups" "3" "T750 INTL" "USB" "usbhid-ups" "HP" "ups" "3" "T1000 INTL" "USB" "usbhid-ups" "HP" "ups" "3" "T1500 INTL" "USB" "usbhid-ups" "HP" "ups" "3" "T750 G2" "USB port" "usbhid-ups" "HP" "ups" "3" "T1000 G3" "USB port" "usbhid-ups" "HP" "ups" "3" "T1500 G3" "USB port" "usbhid-ups" "HP" "ups" "3" "R1500 G2 INTL" "USB port" "usbhid-ups" "HP" "ups" "3" "R/T 2200 G2" "USB" "usbhid-ups" "HP" "ups" "3" "R/T3000" "USB port" "usbhid-ups" "HP" "ups" "3" "R5000 / R7000" "USB port" "usbhid-ups" "HP" "ups" "4" "Various (SNMP mode)" "HP UPS Management Module" "snmp-ups" "HP" "pdu" "1" "HP3488 Switch/Control Unit" "" "powerman-pdu (experimental)" "HPE" "pdu" "5" "Various (SNMP mode)" "" "snmp-ups" "HPE" "pdu" "5" "G2 Metered & Switched PDU" "" "snmp-ups" "Huawei" "ups" "4" "UPS5000-E" "" "snmp-ups" "Huawei" "ups" "3" "UPS2000-G and UPS2000-A series" "MODBUS (USB with Linux 5.12+, or Serial RS-232)" "huawei-ups2000" # https://github.com/networkupstools/nut/issues/1066 https://github.com/networkupstools/nut/pull/1198 https://github.com/networkupstools/nut/pull/954 https://github.com/networkupstools/nut/issues/1017 "Hunnox" "ups" "2" "HNX-850" "USB" "nutdrv_qx port=auto vendorid=0001 productid=0000 protocol=hunnox langid_fix=0x0409 novendor noscanlangid" # https://github.com/networkupstools/nut/pull/638 "IBM" "ups" "5" "Various" "USB port" "usbhid-ups" "IBM" "ups" "5" "Various" "Serial port" "mge-shut" "IBM" "pdu" "1" "Blade Center Management Module" "15 outlets" "powerman-pdu (experimental)" "ICS" "pdu" "1" "8064 Ethernet Relay Interface" "16 outlets" "powerman-pdu (experimental)" "iDowell" "ups" "3" "iBox UPS" "USB" "usbhid-ups" "INELT" "ups" "2" "Monolith 1000LT" "" "blazer_ser" "INELT" "ups" "2" "Monolith 3000RT" "" "blazer_ser" "Inform" "ups" "1" "GUARD" "Line Interactive AP model" "powercom" "Inform" "ups" "2" "Guard S 1500AP" "" "blazer_ser" "Inform" "ups" "2" "Informer Compact 1000-2000-3000 VA" "" "blazer_ser" "Inform" "ups" "2" "Sinus SS 210" "" "blazer_ser" "Infosec" "ups" "2" "iPEL 350" "" "blazer_ser" "Infosec" "ups" "2" "iPEL 500" "" "blazer_ser" "Infosec" "ups" "2" "iPEL 750" "" "blazer_ser" "Infosec" "ups" "2" "iPEL 1000" "" "blazer_ser" "Infosec" "ups" "2" "500XP" "" "blazer_ser" "Infosec" "ups" "2" "X2, X3, X4, E2, E3, E4" "USB" "blazer_usb" "Infosec" "ups" "2" "XP 500" "USB" "blazer_usb" "Infosec" "ups" "2" "XP 1000" "" "blazer_ser" "IPAR" "ups" "2" "Mini Energy ME 800" "USB" "blazer_usb" "IPMI" "pdu" "1" "" "" "powerman-pdu (experimental)" "Ippon" "ups" "2" "Back Basic 850 Euro" "USB" "blazer_usb (experimental)" # https://github.com/networkupstools/nut/issues/802 "Ippon" "ups" "2" "Back Power Pro 400/500/600/700/800" "" "blazer_ser" "Ippon" "ups" "2" "Back Power Pro 400/500/600/700/800" "USB" "blazer_usb (experimental)" "Ippon" "ups" "2" "Back Comfo Pro 600/800" "" "blazer_ser" "Ippon" "ups" "2" "Back Comfo Pro 600/800" "USB" "blazer_usb (experimental)" "Ippon" "ups" "2" "Back Comfo Pro II 650/850/1050" "USB" "blazer_usb (experimental)" "Ippon" "ups" "2" "Smart Power Pro 1000/1400/2000" "" "blazer_ser" "Ippon" "ups" "2" "Smart Power Pro 1000/1400/2000" "USB" "blazer_usb (experimental)" "Ippon" "ups" "2" "Smart Power Pro II 1200/1600/2200" "USB" "usbhid-ups" "Ippon" "ups" "2" "Smart Power Pro II Euro 1200/1600/2200" "USB" "usbhid-ups" "Ippon" "ups" "2" "Smart Winner 750/1000/1500/2000/3000" "" "blazer_ser" "Ippon" "ups" "2" "Smart Winner 750/1000/1500/2000/3000" "USB" "blazer_usb (experimental)" "Ippon" "ups" "2" "(various)" "" "blazer_ser" "Ippon" "ups" "2" "(various)" "USB" "blazer_usb" "Ippon" "ups" "2" "INNOVA RT 1K/1.5K/2K/3K" "USB" "blazer_usb" "IVT" "scd" "1" "SCD series" "" "ivtscd" "Jageson Technology" "ups" "1" "Jasuny USPS" "" "genericups upstype=4" "JAWAN" "ups" "2" "JW-UPSLC02" "USB" "blazer_usb" "Kanji" "ups" "1" "800 VA" "USB" "nutdrv_atcl_usb" "Kebo" "ups" "2" "1200D/D Series" "" "blazer_ser" "Kebo" "ups" "2" "UPS-1000D (UPS-1000VA)" "USB" "blazer_usb" # https://github.com/networkupstools/nut/issues/981 "Kebo" "ups" "2" "UPS-650VA" "USB" "megatec_usb" "KOLFF" "ups" "2" "BLACK NOVA 1K/2K/3K/6K/10K/20K TOWER" "USB" "blazer_usb" "KOLFF" "ups" "2" "BLACK NOVA 1K/2K/3K/6K/10K/20K XL TOWER" "USB" "blazer_usb" "KOLFF" "ups" "2" "BLACK NOVA 1K/1.5K/2K/3K/6K/10K RACK" "USB" "blazer_usb" "KOLFF" "ups" "2" "BLACK NOVA 1K/1.5K/2K/3K/6K/10K XL RACK" "USB" "blazer_usb" "Krauler" "ups" "2" "UP-D1200VA" "USB" "blazer_usb" "Krauler" "ups" "2" "UP-M500VA" "USB" "blazer_usb" "Lacerda" "ups" "2" "New Orion 800VA" "USB" "blazer_usb" "LDLC" "ups" "2" "UPS-1200D" "USB" "blazer_usb langid_fix=0x4095" "Legrand" "ups" "2" "Daker DK" "Serial" "nutdrv_qx" "Legrand" "ups" "2" "Daker DK" "USB" "nutdrv_qx" "Legrand" "ups" "2" "Daker DK Plus" "Serial" "nutdrv_qx" "Legrand" "ups" "2" "Daker DK Plus" "USB" "nutdrv_qx" "Legrand" "ups" "2" "Keor Line RT" "Serial" "nutdrv_qx" "Legrand" "ups" "2" "Keor Line RT" "USB" "nutdrv_qx" "Legrand" "ups" "2" "Keor LP" "Serial" "nutdrv_qx" "Legrand" "ups" "2" "Keor Multiplug" "USB" "nutdrv_qx" "Legrand" "ups" "2" "Keor S" "Serial" "nutdrv_qx" "Legrand" "ups" "2" "Keor S" "USB" "nutdrv_qx" "Legrand" "ups" "3" "Keor PDU" "USB" "usbhid-ups" "Legrand" "ups" "3" "Keor SP" "USB" "usbhid-ups" "Legrand" "ups" "2" "Keor SPX" "USB" "nutdrv_qx" "Legrand" "ups" "4" "Megaline 1250" "Serial" "metasys" "Legrand" "ups" "4" "Megaline 2500" "Serial" "metasys" "Legrand" "ups" "4" "Megaline 3750" "Serial" "metasys" "Legrand" "ups" "4" "Megaline 5000" "Serial" "metasys" "Legrand" "ups" "4" "Megaline 5000 /2" "Serial" "metasys" "Legrand" "ups" "4" "Megaline 6250 /2" "Serial" "metasys" "Legrand" "ups" "4" "Megaline 7500 /2" "Serial" "metasys" "Legrand" "ups" "4" "Megaline 8750 /2" "Serial" "metasys" "Legrand" "ups" "4" "Megaline 10000 /2" "Serial" "metasys" "Legrand" "ups" "2" "Niky" "Serial" "nutdrv_qx" "Legrand" "ups" "2" "Niky" "USB" "nutdrv_qx" "Legrand" "ups" "2" "Niky S" "Serial" "nutdrv_qx" "Legrand" "ups" "2" "Niky S" "USB" "nutdrv_qx" "Legrand" "ups" "4" "WHAD 800" "Serial" "metasys" "Legrand" "ups" "4" "WHAD 1000" "Serial" "metasys" "Legrand" "ups" "4" "WHAD 1250" "Serial" "metasys" "Legrand" "ups" "4" "WHAD 1500" "Serial" "metasys" "Legrand" "ups" "4" "WHAD 2000" "Serial" "metasys" "Legrand" "ups" "4" "WHAD 2500" "Serial" "metasys" "Legrand" "ups" "4" "WHAD CAB 1250" "Serial" "metasys" "Legrand" "ups" "4" "WHAD CAB 2500" "Serial" "metasys" "Legrand" "ups" "4" "WHAD HE 800" "Serial" "metasys" "Legrand" "ups" "4" "WHAD HE 1000" "Serial" "metasys" "Legrand" "ups" "4" "WHAD HE 1500" "Serial" "metasys" "Lestar" "ups" "2" "MD-800E" "" "blazer_ser" "Lexis" "ups" "2" "X-Power Tigra 1kVA" "" "blazer_ser or bestups" "Liebert" "ups" "2" "ITON 600VA" "" "blazer_ser" "Liebert" "ups" "5" "UPStation GXT2" "contact-closure cable" "liebert" "Liebert" "ups" "1" "GXT2-3000RT230" "" "liebert-esp2 (experimental)" "Liebert" "ups" "3" "PowerSure Personal XT" "USB" "usbhid-ups" "Liebert" "ups" "3" "PowerSure PSA" "USB" "usbhid-ups" "Liebert" "ups" "3" "PowerSure PSA 500" "USB" "usbhid-ups" "Liebert" "ups" "3" "PowerSure PSA500MT3-230U" "USB" "usbhid-ups" # https://github.com/networkupstools/nut/issues/601 "Liebert" "ups" "3" "PowerSure PSI 1440" "USB" "usbhid-ups" # http://www.emersonnetworkpower.com/en-US/Products/ACPower/Pages/LiebertPowerSurePSILineInteractiveUPS10003000VA.aspx "LNXI" "pdu" "1" "Icebox" "10 outlets" "powerman-pdu (experimental)" "Lyonn" "ups" "2" "CTB-800V" "" "nutdrv_qx" "Lyonn" "ups" "2" "CTB-1200" "USB" "blazer_usb" "Masterguard" "ups" "1" "(various)" "" "masterguard" "Maxxtro" "ups" "2" "UPS 600 VA" "serial port" "blazer_ser" "Mecer" "ups" "2" "ME-1000-WTU" "USB" "nutdrv_qx" # http://www.comx-computers.co.za/download/mecer/ME-1000-WTU.pdf "Mecer" "ups" "2" "ME-2000" "" "blazer_ser" "Meta System" "ups" "4" "HF Line" "1..4 boards" "metasys" "Meta System" "ups" "4" "HF Line /2" "5..8 boards" "metasys" "Meta System" "ups" "4" "HF Millennium 810" "" "metasys" "Meta System" "ups" "4" "HF Millennium 820" "" "metasys" "Meta System" "ups" "4" "HF TOP Line 910" "" "metasys" "Meta System" "ups" "4" "HF TOP Line 920" "" "metasys" "Meta System" "ups" "4" "HF TOP Line 930" "" "metasys" "Meta System" "ups" "4" "HF TOP Line 940" "" "metasys" "Meta System" "ups" "4" "HF TOP Line 950" "" "metasys" "Meta System" "ups" "4" "HF TOP Line 960" "" "metasys" "Meta System" "ups" "4" "HF TOP Line 970" "" "metasys" "Meta System" "ups" "4" "HF TOP Line 980" "" "metasys" "Meta System" "ups" "4" "ECO Network 750" "" "metasys" "Meta System" "ups" "4" "ECO Network 1000" "" "metasys" "Meta System" "ups" "4" "ECO Network 1050" "" "metasys" "Meta System" "ups" "4" "ECO Network 1500" "" "metasys" "Meta System" "ups" "4" "ECO Network 1800" "" "metasys" "Meta System" "ups" "4" "ECO Network 2000" "" "metasys" "Meta System" "ups" "4" "ECO Network 2100" "" "metasys" "Meta System" "ups" "4" "ECO Network 2500" "" "metasys" "Meta System" "ups" "4" "ECO Network 3000" "" "metasys" "Meta System" "ups" "4" "ECO 305" "" "metasys" "Meta System" "ups" "4" "ECO 308" "" "metasys" "Meta System" "ups" "4" "ECO 311" "" "metasys" "Meta System" "ups" "4" "ECO 511" "" "metasys" "Meta System" "ups" "4" "ECO 516" "" "metasys" "Meta System" "ups" "4" "ECO 519" "" "metasys" "Meta System" "ups" "4" "ECO 522" "" "metasys" "Meta System" "ups" "4" "ally HF 800" "" "metasys" "Meta System" "ups" "4" "ally HF 1000" "" "metasys" "Meta System" "ups" "4" "ally HF 1250" "" "metasys" "Meta System" "ups" "4" "ally HF 1600" "" "metasys" "Meta System" "ups" "4" "ally HF 2000" "" "metasys" "Meta System" "ups" "4" "ally HF 2500" "" "metasys" "Meta System" "ups" "4" "Megaline 1250" "" "metasys" "Meta System" "ups" "4" "Megaline 2500" "" "metasys" "Meta System" "ups" "4" "Megaline 3750" "" "metasys" "Meta System" "ups" "4" "Megaline 5000" "" "metasys" "Meta System" "ups" "4" "Megaline 6250" "" "metasys" "Meta System" "ups" "4" "Megaline 7500" "" "metasys" "Meta System" "ups" "4" "Megaline 8750" "" "metasys" "Meta System" "ups" "4" "Megaline 10000" "" "metasys" "Meta System" "ups" "4" "DHEA 1000" "Serial" "metasys" "Meta System" "ups" "4" "DHEA 1500" "Serial" "metasys" "MGE Office Protection Systems" "ups" "5" "Protection Center 500/675 VA" "USB" "usbhid-ups" "MGE Office Protection Systems" "ups" "5" "Protection Station 500/650/800 VA" "USB" "usbhid-ups" "MGE Office Protection Systems" "ups" "5" "Ellipse ASR USBS 600/750/1000/1500 VA" "USB cable" "usbhid-ups" "MGE Office Protection Systems" "ups" "5" "Ellipse MAX USBS 600/850/1100/1500 VA" "USB cable" "usbhid-ups" "MGE Office Protection Systems" "ups" "5" "Evolution 650/850/1150/1550/2000 VA" "USB port" "usbhid-ups" "MGE Office Protection Systems" "ups" "5" "Evolution S 1250/1750/2500/3000 VA" "USB port" "usbhid-ups" "MGE Office Protection Systems" "ups" "5" "Pulsar 700/1000/1500 VA" "USB port" "usbhid-ups" "MGE Office Protection Systems" "ups" "5" "Pulsar M 2200/3000 VA" "USB port" "usbhid-ups" "MGE Office Protection Systems" "ups" "5" "Pulsar MX 5/8/10/15/20 kVA" "USB port" "usbhid-ups" "MGE Office Protection Systems" "ups" "5" "Ellipse ASR USBS 600/750/1000/1500 VA" "Serial cable" "mge-shut" "MGE Office Protection Systems" "ups" "5" "Ellipse MAX USBS 600/850/1100/1500 VA" "Serial cable" "mge-shut" "MGE Office Protection Systems" "ups" "5" "Evolution 650/850/1150/1550/2000 VA" "Serial port" "mge-shut" "MGE Office Protection Systems" "ups" "5" "Evolution S 1250/1750/2500/3000 VA" "Serial port" "mge-shut" "MGE Office Protection Systems" "ups" "5" "Pulsar 700/1000/1500 VA" "Serial port" "mge-shut" "MGE Office Protection Systems" "ups" "5" "Pulsar M 2200/3000 VA" "Serial port" "mge-shut" "MGE Office Protection Systems" "ups" "5" "Pulsar MX 5/8/10/15/20 kVA" "Serial port" "mge-shut" "MGE Office Protection Systems" "ups" "5" "Comet EX RT 1:1 7/11 kVA" "" "mge-shut" "MGE Office Protection Systems" "ups" "5" "Comet EX RT 3:1 5/7/11 kVA" "" "mge-shut" "MGE Office Protection Systems" "ups" "5" "Comet EX RT (XML/HTTP)" "NMC Transverse card (ref 66074)" "netxml-ups (experimental)" "MGE Office Protection Systems" "ups" "5" "Comet EX RT (SNMP)" "NMC Transverse card (ref 66074)" "snmp-ups (experimental)" "MGE Office Protection Systems" "ups" "5" "various models (XML/HTTP mode)" "NMC Minislot (Ref 66102)" "netxml-ups (experimental)" "MGE Office Protection Systems" "ups" "5" "various models (SNMP mode)" "NMC Minislot (Ref 66102)" "snmp-ups (experimental)" "MGE Office Protection Systems" "ups" "5" "various models (XML/HTTP mode)" "SNMP/Web Minislot card (ref 66244)" "netxml-ups (experimental)" "MGE Office Protection Systems" "ups" "5" "various models (SNMP mode)" "SNMP/Web Minislot card (ref 66244)" "snmp-ups (experimental)" "MGE UPS SYSTEMS" "ups" "5" "Comet EX RT" "USB" "usbhid-ups" "MGE UPS SYSTEMS" "ups" "5" "Comet EX RT 3:1" "USB" "usbhid-ups" "MGE UPS SYSTEMS" "ups" "5" "Protection Center 420" "USB" "usbhid-ups" "MGE UPS SYSTEMS" "ups" "5" "Protection Center 500" "USB" "usbhid-ups" "MGE UPS SYSTEMS" "ups" "5" "Protection Center 675" "USB" "usbhid-ups" "MGE UPS SYSTEMS" "ups" "5" "NOVA AVR 600 USB" "USB" "usbhid-ups" "MGE UPS SYSTEMS" "ups" "5" "NOVA AVR 1100 USB" "USB" "usbhid-ups" "MGE UPS SYSTEMS" "ups" "5" "Pulsar Ellipse USBS" "USB" "usbhid-ups" "MGE UPS SYSTEMS" "ups" "5" "Pulsar Ellipse USB" "USB" "usbhid-ups" "MGE UPS SYSTEMS" "ups" "5" "Pulsar Ellipse Premium USBS" "USB" "usbhid-ups" "MGE UPS SYSTEMS" "ups" "5" "Pulsar Ellipse Premium USB" "USB" "usbhid-ups" "MGE UPS SYSTEMS" "ups" "5" "Ellipse Office 600" "USB" "usbhid-ups" "MGE UPS SYSTEMS" "ups" "5" "Ellipse Office 750" "USB" "usbhid-ups" "MGE UPS SYSTEMS" "ups" "5" "Ellipse Office 1000" "USB" "usbhid-ups" "MGE UPS SYSTEMS" "ups" "5" "Ellipse Office 1500" "USB" "usbhid-ups" "MGE UPS SYSTEMS" "ups" "5" "Ellipse MAX 600" "USB" "usbhid-ups" "MGE UPS SYSTEMS" "ups" "5" "Ellipse MAX 850" "USB" "usbhid-ups" "MGE UPS SYSTEMS" "ups" "5" "Ellipse MAX 1100" "USB" "usbhid-ups" "MGE UPS SYSTEMS" "ups" "5" "Ellipse MAX 1500" "USB" "usbhid-ups" "MGE UPS SYSTEMS" "ups" "5" "Pulsar Evolution" "USB" "usbhid-ups" "MGE UPS SYSTEMS" "ups" "5" "Evolution 650" "USB" "usbhid-ups" "MGE UPS SYSTEMS" "ups" "5" "Evolution 850" "USB" "usbhid-ups" "MGE UPS SYSTEMS" "ups" "5" "Evolution 1150" "USB" "usbhid-ups" "MGE UPS SYSTEMS" "ups" "5" "Evolution S 1250" "USB" "usbhid-ups" "MGE UPS SYSTEMS" "ups" "5" "Evolution 1550" "USB" "usbhid-ups" "MGE UPS SYSTEMS" "ups" "5" "Evolution S 1750" "USB" "usbhid-ups" "MGE UPS SYSTEMS" "ups" "5" "Evolution 2000" "USB" "usbhid-ups" "MGE UPS SYSTEMS" "ups" "5" "Evolution S 2500" "USB" "usbhid-ups" "MGE UPS SYSTEMS" "ups" "5" "Evolution S 3000" "USB" "usbhid-ups" "MGE UPS SYSTEMS" "ups" "5" "Pulsar M 2200" "USB" "usbhid-ups" "MGE UPS SYSTEMS" "ups" "5" "Pulsar M 3000" "USB" "usbhid-ups" "MGE UPS SYSTEMS" "ups" "5" "Pulsar M 3000 XL" "USB" "usbhid-ups" "MGE UPS SYSTEMS" "ups" "5" "Pulsar 700" "USB" "usbhid-ups" "MGE UPS SYSTEMS" "ups" "5" "Pulsar 1000" "USB" "usbhid-ups" "MGE UPS SYSTEMS" "ups" "5" "Pulsar 1500" "USB" "usbhid-ups" "MGE UPS SYSTEMS" "ups" "5" "Pulsar 1000 RT2U" "USB" "usbhid-ups" "MGE UPS SYSTEMS" "ups" "5" "Pulsar 1500 RT2U" "USB" "usbhid-ups" "MGE UPS SYSTEMS" "ups" "5" "Pulsar MX 4000 RT" "USB" "usbhid-ups" "MGE UPS SYSTEMS" "ups" "5" "Pulsar MX 5000 RT" "USB" "usbhid-ups" "MGE UPS SYSTEMS" "ups" "5" "Comet / Galaxy (USB)" "USB Card (ref 66067)" "usbhid-ups" "MGE UPS SYSTEMS" "ups" "5" "NOVA AVR 600 Serial" "" "mge-shut" "MGE UPS SYSTEMS" "ups" "5" "NOVA AVR 1100 Serial" "" "mge-shut" "MGE UPS SYSTEMS" "ups" "5" "Pulsar Ellipse USBS" "Serial cable" "mge-shut" "MGE UPS SYSTEMS" "ups" "5" "Pulsar Ellipse S" "" "mge-shut" "MGE UPS SYSTEMS" "ups" "5" "Pulsar Ellipse Premium USBS" "Serial cable" "mge-shut" "MGE UPS SYSTEMS" "ups" "5" "Pulsar Ellipse Premium S" "" "mge-shut" "MGE UPS SYSTEMS" "ups" "5" "Ellipse Office 600" "Serial cable" "mge-shut" "MGE UPS SYSTEMS" "ups" "5" "Ellipse Office 750" "Serial cable" "mge-shut" "MGE UPS SYSTEMS" "ups" "5" "Ellipse Office 1000" "Serial cable" "mge-shut" "MGE UPS SYSTEMS" "ups" "5" "Ellipse Office 1500" "Serial cable" "mge-shut" "MGE UPS SYSTEMS" "ups" "5" "Ellipse MAX 600" "Serial cable" "mge-shut" "MGE UPS SYSTEMS" "ups" "5" "Ellipse MAX 850" "Serial cable" "mge-shut" "MGE UPS SYSTEMS" "ups" "5" "Ellipse MAX 1100" "Serial cable" "mge-shut" "MGE UPS SYSTEMS" "ups" "5" "Ellipse MAX 1500" "Serial cable" "mge-shut" "MGE UPS SYSTEMS" "ups" "5" "Pulsar EXtreme C / EX RT" "" "mge-shut" "MGE UPS SYSTEMS" "ups" "5" "Comet EX RT" "Serial port" "mge-shut" "MGE UPS SYSTEMS" "ups" "5" "Comet EX RT 3:1" "Serial port" "mge-shut" "MGE UPS SYSTEMS" "ups" "5" "Pulsar Esprit" "" "mge-shut" "MGE UPS SYSTEMS" "ups" "5" "Evolution 650" "Serial port" "mge-shut" "MGE UPS SYSTEMS" "ups" "5" "Evolution 850" "Serial port" "mge-shut" "MGE UPS SYSTEMS" "ups" "5" "Evolution 1150" "Serial port" "mge-shut" "MGE UPS SYSTEMS" "ups" "5" "Evolution S 1250" "Serial port" "mge-shut" "MGE UPS SYSTEMS" "ups" "5" "Evolution 1550" "Serial port" "mge-shut" "MGE UPS SYSTEMS" "ups" "5" "Evolution S 1750" "Serial port" "mge-shut" "MGE UPS SYSTEMS" "ups" "5" "Evolution 2000" "Serial port" "mge-shut" "MGE UPS SYSTEMS" "ups" "5" "Evolution S 2500" "Serial port" "mge-shut" "MGE UPS SYSTEMS" "ups" "5" "Evolution S 3000" "Serial port" "mge-shut" "MGE UPS SYSTEMS" "ups" "5" "Pulsar M 2200" "Serial port" "mge-shut" "MGE UPS SYSTEMS" "ups" "5" "Pulsar M 3000" "Serial port" "mge-shut" "MGE UPS SYSTEMS" "ups" "5" "Pulsar M 3000 XL" "Serial port" "mge-shut" "MGE UPS SYSTEMS" "ups" "5" "Pulsar 700" "Serial port" "mge-shut" "MGE UPS SYSTEMS" "ups" "5" "Pulsar 1000" "Serial port" "mge-shut" "MGE UPS SYSTEMS" "ups" "5" "Pulsar 1500" "Serial port" "mge-shut" "MGE UPS SYSTEMS" "ups" "5" "Pulsar 1000 RT2U" "Serial port" "mge-shut" "MGE UPS SYSTEMS" "ups" "5" "Pulsar 1500 RT2U" "Serial port" "mge-shut" "MGE UPS SYSTEMS" "ups" "5" "Pulsar MX 4000 RT" "Serial port" "mge-shut" "MGE UPS SYSTEMS" "ups" "5" "Pulsar MX 5000 RT" "Serial port" "mge-shut" "MGE UPS SYSTEMS" "ups" "5" "Pulsar Evolution" "Serial port" "mge-shut or mge-utalk" "MGE UPS SYSTEMS" "ups" "5" "Pulsar EXtreme C" "" "mge-shut or mge-utalk" "MGE UPS SYSTEMS" "ups" "5" "Pulsar ES+" "" "mge-utalk" "MGE UPS SYSTEMS" "ups" "5" "Pulsar ESV+" "" "mge-utalk" "MGE UPS SYSTEMS" "ups" "5" "Pulsar SV" "" "mge-utalk" "MGE UPS SYSTEMS" "ups" "5" "Pulsar ESV" "" "mge-utalk" "MGE UPS SYSTEMS" "ups" "5" "Pulsar EX" "" "mge-utalk" "MGE UPS SYSTEMS" "ups" "5" "Pulsar EXL" "" "mge-utalk" "MGE UPS SYSTEMS" "ups" "5" "Pulsar PSX" "" "mge-utalk" "MGE UPS SYSTEMS" "ups" "5" "Pulsar SX" "" "mge-utalk" "MGE UPS SYSTEMS" "ups" "5" "Pulsar EXtreme" "" "mge-utalk" "MGE UPS SYSTEMS" "ups" "5" "Comet EXtreme" "" "mge-utalk" "MGE UPS SYSTEMS" "ups" "5" "Comet / Galaxy (Serial)" "Utalk Serial Card (ref 66060)" "mge-utalk" "MGE UPS SYSTEMS" "ups" "5" "Comet / Galaxy (Serial)" "HID COM Serial Card (ref 66066)" "mge-shut" "MGE UPS SYSTEMS" "ups" "5" "Pulsar / Comet / Galaxy (SNMP)" "SNMP/Web Transverse card (ref 66074)" "snmp-ups (experimental)" "MGE UPS SYSTEMS" "ups" "5" "various models (XML/HTTP mode)" "NMC Minislot (Ref 66102)" "netxml-ups (experimental)" "MGE UPS SYSTEMS" "ups" "5" "various models (SNMP mode)" "NMC Minislot (Ref 66102)" "snmp-ups (experimental)" "MGE UPS SYSTEMS" "ups" "5" "Pulsar (XML/HTTP mode)" "SNMP/Web Minislot card (ref 66244)" "netxml-ups (experimental)" "MGE UPS SYSTEMS" "ups" "5" "Pulsar (SNMP mode)" "SNMP/Web Minislot card (ref 66244)" "snmp-ups (experimental)" "MGE UPS SYSTEMS" "ups" "5" "Pulsar / Comet / Galaxy (SNMP)" "SNMP card (ref 66062)" "snmp-ups (experimental)" "MGE UPS SYSTEMS" "ups" "5" "Pulsar (SNMP)" "SNMP card (ref 66045)" "snmp-ups (experimental)" "MGE UPS SYSTEMS" "ups" "5" "UM-Link (SNMP)" "Not a UPS (ref 66850)" "snmp-ups (experimental)" "MicroDowell" "ups" "1" "B.Box BP 500" "" "powerpanel" "MicroDowell" "ups" "1" "B.Box BP 750" "" "powerpanel" "MicroDowell" "ups" "1" "B.Box BP 1000" "" "powerpanel" "MicroDowell" "ups" "1" "B.Box BP 1500" "" "powerpanel" "MicroDowell" "ups" "1" "B.Box LP 500" "" "genericups upstype=7" "MicroDowell" "ups" "5" "Enterprise B8" "" "microdowell" "MicroDowell" "ups" "5" "Enterprise B10" "" "microdowell" "MicroDowell" "ups" "5" "Enterprise N8" "" "microdowell" "MicroDowell" "ups" "5" "Enterprise N11" "" "microdowell" "MicroDowell" "ups" "5" "Enterprise N15" "" "microdowell" "MicroDowell" "ups" "5" "Enterprise N20" "" "microdowell" "MicroDowell" "ups" "5" "Enterprise N22" "" "microdowell" "MicroDowell" "ups" "5" "Enterprise N30" "" "microdowell" "MicroDowell" "ups" "5" "Enterprise N40" "" "microdowell" "MicroDowell" "ups" "5" "Enterprise N50" "" "microdowell" "MicroDowell" "ups" "5" "Enterprise N60" "" "microdowell" "MicroDowell" "ups" "5" "Enterprise HiBox ST" "" "microdowell" "Microline" "ups" "2" "C-Lion Innova RT 2K/3K" "USB" "blazer_usb" "Microline" "ups" "2" "C-Lion Innova RT 6K/10K (Parallel)" "USB" "blazer_usb" "Microline" "ups" "2" "C-Lion Innova Tower 6K/10K" "USB" "blazer_usb" "Microline" "ups" "2" "C-Lion Innova Combo 10K/20K (3/1)" "USB" "blazer_usb" "Micropower" "ups" "2" "LCD 1000" "USB" "blazer_usb" "Microsol" "ups" "4" "Solis 1.0" "1000VA" "solis" "Microsol" "ups" "4" "Solis 1.5" "1500VA" "solis" "Microsol" "ups" "4" "Solis 2.0" "2000VA" "solis" "Microsol" "ups" "4" "Solis 3.0" "3000VA" "solis" "Microsol" "ups" "5" "Rhino 6.0" "6000VA" "rhino" "Microsol" "ups" "5" "Rhino 7.5" "7500VA" "rhino" "Microsol" "ups" "5" "Rhino 10.0" "10000VA" "rhino" "Microsol" "ups" "5" "Rhino 20.0" "20000VA" "rhino" "Minibox" "ups" "5" "openUPS Intelligent UPS" "USB port" "usbhid-ups" "Mustek" "ups" "2" "Powermust" "400VA Plus" "blazer_ser" "Mustek" "ups" "2" "Powermust" "600VA Plus" "blazer_ser" "Mustek" "ups" "2" "Powermust" "800VA Pro" "blazer_ser" "Mustek" "ups" "2" "Powermust" "1000VA Plus" "blazer_ser" "Mustek" "ups" "2" "Powermust" "1000VA USB" "blazer_usb" "Mustek" "ups" "2" "Powermust" "1400VA Plus" "blazer_ser" "Mustek" "ups" "2" "Powermust" "2000VA USB" "blazer_ser" "Mustek" "ups" "2" "Powermust Office 650" "USB" "blazer_usb" "Mustek" "ups" "2" "PowerMust 424 / 636 / 848" "USB" "blazer_usb" "Mustek" "ups" "2" "Yukai PowerMust" "1000 USB (PID: 5161)" "blazer_usb" "Mustek" "ups" "2" "Various" "" "blazer_ser" "Neus" "ups" "2" "400va / 600va" "" "blazer_ser" "NHS Sistemas de Energia" "ups" "5" "Expert C Online 6000" "" "gamatronic" # http://www.nhs.com.br/produtos_interna/id/TWpFeQ== "NHS Sistemas de Energia" "ups" "5" "Expert C Online 8000" "" "gamatronic" "NHS Sistemas de Energia" "ups" "5" "Expert C Online 10000" "" "gamatronic" "NHS Sistemas de Energia" "ups" "5" "Expert S Online 6000" "" "gamatronic" "NHS Sistemas de Energia" "ups" "5" "Expert S Online 8000" "" "gamatronic" "NHS Sistemas de Energia" "ups" "5" "Expert S Online 10000" "" "gamatronic" "NHS Sistemas de Energia" "ups" "5" "Expert S Online 10000" "" "gamatronic" "NHS Sistemas de Energia" "ups" "5" "Laser Senoidal 5000VA" "USB" "gamatronic" # http://www.nhs.com.br/produtos_interna/id/T0RrPQ== "Nitram" "ups" "1" "Elite 500" "" "genericups upstype=8" "Nitram" "ups" "1" "Elite 2002" "" "genericups upstype=16" "Nitram" "ups" "1" "Elite 2005" "" "powerpanel" "nJoy" "ups" "2" "Keen 600" "USB" "blazer_ser port=/dev/ttyUSB0" # https://www.njoy.ro/UPS/keen-600 "nJoy" "ups" "2" "Keen 600" "USB" "nutdrv_qx port=/dev/ttyUSB0" # https://www.njoy.ro/UPS/keen-600 "nJoy" "ups" "3" "Aten PRO 3000" "SNMP" "snmp-ups" # At least basic status is served; https://www.njoy.global/product/aten-pro-3000 "Novex" "ups" "1" "NUPS-650" "USB" "blazer_usb protocol=megatec" # http://komp.1k.by/periphery-ups/novex/Novex_NUPS_650-130052.html "Numeric" "ups" "2" "3000 SW" "" "blazer_ser" "Numeric" "ups" "2" "Digital 800 plus" "USB" "nutdrv_qx or blazer_usb" "Oneac" "ups" "1" "ON400" "advanced interface" "oneac" "Oneac" "ups" "1" "ON600" "advanced interface" "oneac" "Oneac" "ups" "1" "ON900" "advanced interface" "oneac" "Oneac" "ups" "1" "ON1300" "advanced interface" "oneac" "Oneac" "ups" "1" "EG Series" "advanced interface" "oneac" "Oneac" "ups" "1" "ON700" "advanced interface" "oneac" "Oneac" "ups" "1" "ON700XAU" "advanced interface" "oneac" "Oneac" "ups" "1" "ON700XIU" "advanced interface" "oneac" "Oneac" "ups" "1" "ON1000" "advanced interface" "oneac" "Oneac" "ups" "1" "ON1000XAU" "advanced interface" "oneac" "Oneac" "ups" "1" "ON1000XIU" "advanced interface" "oneac" "Oneac" "ups" "1" "ON1500" "advanced interface" "oneac" "Oneac" "ups" "1" "ON1500XAU" "advanced interface" "oneac" "Oneac" "ups" "1" "ON1500XIU" "advanced interface" "oneac" "Oneac" "ups" "1" "ON2000" "advanced interface" "oneac" "Oneac" "ups" "1" "ON2000XAU" "advanced interface" "oneac" "Oneac" "ups" "1" "ON2000XIU" "advanced interface" "oneac" "Online" "ups" "1" "P-Series" "" "genericups upstype=14" "Online" "ups" "2" "Zinto A" "USB" "blazer_usb" "Online" "ups" "1" "Zinto D" "" "optiups" "Online" "ups" "2" "Yunto YQ450" "USB" "blazer_usb" "Online" "ups" "2" "Xanto S700" "/dev/ttyUSB0" "nutdrv_qx" # https://github.com/networkupstools/nut/issues/1279 "OnLite" "ups" "2" "AQUA" "50" "blazer_ser" "Opti-UPS" "ups" "1" "PowerES" "420E" "optiups" "Opti-UPS" "ups" "1" "VS 575C" "type=OPTI" "powercom" "Opti-UPS" "ups" "1" "Power Series" "PS1500E" "blazer_usb" "Opti-UPS" "ups" "1" "Power Series" "PS1440RM" "optiups" "Orvaldi Power Protection" "ups" "2" "various" "not 400 or 600" "blazer_ser" "Orvaldi Power Protection" "ups" "2" "750 / 900SP" "USB" "blazer_usb" "Phasak" "ups" "2" "400VA / 600VA" "" "blazer_ser" "Phasak" "ups" "2" "9465 or P6N" "USB" "nutdrv_qx" # https://github.com/networkupstools/nut/issues/1187 => Voltronic-QS-Hex protocol detected "PhoenixContact" "ups" "4" "QUINT-UPS/24DC" "2320461" "phoenixcontact_modbus" #https://www.phoenixcontact.com/online/portal/us?uri=pxc-oc-itemdetail:pid=2320461 "PiJuice" "ups" "5" "PiJuice HAT" "" "pijuice" # https://github.com/PiSupply/PiJuice/issues/124 "PiJuice" "ups" "5" "PiJuice Zero pHAT" "" "pijuice" "Plexus" "ups" "2" "500VA" "USB" "blazer_usb" "Plexus" "ups" "2" "1000VA Pro" "USB" "blazer_usb" "Plexus" "ups" "1" "800 VA" "USB" "nutdrv_atcl_usb" "Powercom" "ups" "4" "SMK" "" "blazer_ser" "Powercom" "ups" "4" "SXL" "" "blazer_ser" "Powercom" "ups" "4" "ULT" "" "blazer_ser" "Powercom" "ups" "4" "Trust 425/625" "" "powercom" "Powercom" "ups" "4" "Advice Partner/King Pr750" "" "powercom" "Powercom" "ups" "4" "Black Knight PRO" "" "powercom" "Powercom" "ups" "5" "Black Knight PRO" "USB (2009 models, product id: 00a6)" "usbhid-ups (experimental)" "Powercom" "ups" "4" "Smart KING Pro (all Smart series)" "" "powercom" "Powercom" "ups" "5" "Smart KING Pro (all Smart series)" "USB (2009 models, product id: 00a3)" "usbhid-ups (experimental)" "Powercom" "ups" "4" "Imperial" "" "powercom" "Powercom" "ups" "5" "Imperial" "USB (2009 models, product id: 00a2)" "usbhid-ups (experimental)" "Powercom" "ups" "4" "Vanguard" "" "blazer_ser" "Powercom" "ups" "5" "Vanguard" "USB (2009 models, product id: 0004 or 00a5)" "usbhid-ups (experimental)" "Powercom" "ups" "4" "WOW" "USB (<= 2009 models, product id: 0002)" "powercom (requires 'usbserial' kernel module)" "Powercom" "ups" "5" "WOW" "USB (2009 models, product id: 00a4)" "usbhid-ups (experimental)" "Powercom" "ups" "4" "(various)" "USB (<= 2009 models, product id: 0002)" "powercom (requires 'usbserial' kernel module)" "Powercom" "ups" "5" "(various)" "USB (2009 models, product id: 00a?)" "usbhid-ups (experimental)" "Powercom" "ups" "5" "BNT-xxxAP" "USB (product id: 0004)" "usbhid-ups (experimental)" "Powercom" "ups" "3" "BNT-xxxAP" "USB (product id: 0001)" "usbhid-ups (experimental)" "Powercom" "ups" "3" "RPT-600AP" "USB" "usbhid-ups" # http://pcmups.com.tw/eA/html/product/show.php?num=226&root=13&kind=105&page=1&keyword= https://github.com/networkupstools/nut/issues/633 "Powercom" "ups" "3" "Raptor 2000" "USB" "usbhid-ups" # https://github.com/networkupstools/nut/issues/633 "Powercool" "ups" "1" "350VA to 1600VA" "USB" "nutdrv_atcl_usb" "Powercool" "ups" "2" "650VA" "USB" "nutdrv_qx port=auto vendorid=0001 productid=0000 product=MEC0003 protocol=hunnox langid_fix=0x0409 novendor noscanlangid" # https://github.com/networkupstools/nut/pull/638 caveats at https://github.com/networkupstools/nut/issues/537 "Powercool" "ups" "2" "650VA" "USB" "nutdrv_qx port=auto vendorid=0001 productid=0000 bus=001 product=MEC0003 protocol=hunnox langid_fix=0x0409 novendor norating noscanlangid" # https://github.com/networkupstools/nut/pull/638 caveats at https://github.com/networkupstools/nut/issues/537 "Powercool" "ups" "2" "1200VA" "USB" "nutdrv_qx port=auto vendorid=0001 productid=0000 product=MEC0003 protocol=hunnox subdriver=hunnox langid_fix=0x0409 novendor norating noscanlangid" # https://github.com/networkupstools/nut/pull/1539 "Powercool" "ups" "2" "1500VA" "USB" "nutdrv_qx port=auto vendorid=0001 productid=0000 product=MEC0003 protocol=hunnox langid_fix=0x0409 novendor noscanlangid" # https://github.com/networkupstools/nut/pull/638 caveats at https://github.com/networkupstools/nut/issues/537 - e.g. battery percentage is not being returned "Powercool" "ups" "2" "2000VA" "USB" "nutdrv_qx port=auto vendorid=0001 productid=0000 product=MEC0003 protocol=hunnox langid_fix=0x0409 novendor noscanlangid" # https://github.com/networkupstools/nut/pull/638 caveats at https://github.com/networkupstools/nut/issues/537 "POWEREX" "ups" "2" "VI 1000 LED" "USB" "blazer_usb" "PowerGuard" "ups" "2" "PG-600" "" "blazer_ser" "PowerKinetics" "ups" "1" "9001" "" "genericups upstype=17" "PowerKinetics" "ups" "2" "BlackOut Buster" "" "blazer_ser" "PowerMan" "ups" "2" "RealSmart 800" "" "blazer_ser" "PowerMan" "ups" "2" "RealSmart 1000" "" "blazer_ser" "PowerMan" "ups" "1" "BackPro" "" "genericups upstype=4" "PowerShield" "ups" "2" "Defender 1200VA" "USB" "blazer_usb" "PowerTech" "ups" "1" "Comp1000" "DTR cable power" "genericups upstype=3" "PowerTech" "ups" "2" "SMK-800" "" "blazer_ser" "PowerWalker" "ups" "2" "Line-Interactive VI 1000" "" "blazer_ser" "PowerWalker" "ups" "2" "Line-Interactive VI 400/800" "" "blazer_ser" "PowerWalker" "ups" "2" "Line-Interactive VI 600" "" "blazer_ser" "PowerWalker" "ups" "2" "Line-Interactive VI 600 SE" "USB" "blazer_usb" "PowerWalker" "ups" "2" "Line-Interactive VI 800 SE" "USB" "blazer_usb" "PowerWalker" "ups" "2" "Line-Interactive VI 1400" "USB" "blazer_usb" "PowerWalker" "ups" "2" "Line-Interactive VI 2000" "USB" "blazer_usb" "PowerWalker" "ups" "2" "Line-Interactive VI 850 LCD" "USB" "blazer_usb" "PowerWalker" "ups" "2" "Online VFI 1000RT/1500RT/2000RT/3000RT/6000RT/10000RT LCD" "USB" "blazer_usb" "PowerWalker" "ups" "2" "Line-Interactive VI 1000RT/1500RT/2000RT/3000RT LCD" "USB" "blazer_usb" "PowerWalker" "ups" "2" "VFI 1000 CG PF1" "" "nutdrv_qx" # https://powerwalker.com/?page=product&item=10122108&lang=en "PowerWalker" "ups" "3" "VFI 2000 TGS" "USB" "usbhid-ups" # https://github.com/networkupstools/nut/issues/560 and https://github.com/networkupstools/nut/pull/564 "PowerWalker" "ups" "3" "VI 650 SH" "USB" "usbhid-ups" # https://github.com/networkupstools/nut/issues/483 "PowerWalker" "ups" "3" "VI 650/850 SHL" "USB" "usbhid-ups" # https://github.com/networkupstools/nut/issues/646 "PowerWalker" "ups" "3" "VI 1200 SHL" "USB" "usbhid-ups" # https://github.com/networkupstools/nut/issues/1270 "PowerWalker" "ups" "3" "VI 2200 SHL" "USB" "usbhid-ups" # https://github.com/networkupstools/nut/issues/756 "PowerWalker" "ups" "3" "VI 1200 SH" "USB" "usbhid-ups" # https://github.com/networkupstools/nut/issues/646 "PowerWalker" "ups" "3" "VI 2200 SH" "USB" "usbhid-ups" # https://github.com/networkupstools/nut/issues/646 "PowerWalker" "ups" "3" "Basic VI 1000 SB" "USB" "usbhid-ups" # https://github.com/networkupstools/nut/issues/818 "PowerWalker" "ups" "3" "PR1500LCDRT2U" "USB" "usbhid-ups" # https://github.com/networkupstools/nut/issues/818 "PowerWalker" "ups" "2" "VI 3000 SCL" "USB" "blazer_usb" # https://github.com/networkupstools/nut/issues/971 "PowerWalker" "ups" "3" "VI 750T/HID" "USB" "usbhid-ups" # https://powerwalker.com/?page=select&cat=VI_THID&lang=en https://github.com/networkupstools/nut/issues/774 "Powerware" "ups" "4" "3110" "" "genericups upstype=7" "Powerware" "ups" "4" "3115" "" "genericups upstype=11" "Powerware" "ups" "4" "5119, 5125" "" "genericups upstype=15" "Powerware" "ups" "4" "5119 RM" "" "genericups upstype=20" "Powerware" "ups" "5" "5119 RM" "" "upscode2" "Powerware" "ups" "5" "PW3105" "USB" "bcmxcp_usb" "Powerware" "ups" "5" "PW5110" "USB" "bcmxcp_usb" "Powerware" "ups" "5" "PW5115" "Serial port" "bcmxcp" "Powerware" "ups" "5" "PW5115" "USB port" "bcmxcp_usb" "Powerware" "ups" "5" "PW5125" "" "bcmxcp" "Powerware" "ups" "5" "PW9120" "Serial port" "bcmxcp" "Powerware" "ups" "5" "PW9120" "USB port" "bcmxcp_usb" "Powerware" "ups" "5" "PW9125" "" "bcmxcp" "Powerware" "ups" "5" "PW9315" "3-phase" "bcmxcp" "Powerware" "ups" "5" "9110" "" "upscode2" "Powerware" "ups" "5" "9120" "" "upscode2" "Powerware" "ups" "5" "9150" "" "upscode2" "Powerware" "ups" "5" "9305" "" "upscode2" "Powerware" "ups" "5" "BladeUPS (SNMP)" "ConnectUPS Web/SNMP Card" "snmp-ups (experimental)" "Powerware" "ups" "5" "(various)" "ConnectUPS Web/SNMP card" "snmp-ups (experimental)" "Powerwell" "ups" "1" "PM525A/-625A/-800A/-1000A/-1250A" "" "safenet" "Phantom" "pdu" "1" "Rackable Systems" "1 outlets" "powerman-pdu (experimental)" "Raritan" "pdu" "3" "Intelligent PDU - Dominion PX" "no report, but should be supported" "snmp-ups (experimental)" "Raritan" "pdu" "3" "Metered PDU - Raritan PM" "no report, but should be supported" "snmp-ups (experimental)" "Raritan" "pdu" "3" "Switched PDU - Raritan RPC" "no report, but should be supported" "snmp-ups (experimental)" "Raritan" "pdu" "3" "Dominion PX2" "" "snmp-ups" "REDi" "ups" "2" "Blazer 400VA / 600VA / 800VA" "" "blazer_ser" "Repotec" "ups" "1" "RPF525/625/800/1000" "" "safenet" "Repotec" "ups" "1" "RPT-800A" "" "genericups upstype=13" "Repotec" "ups" "1" "RPT-162A" "" "genericups upstype=13" "Riello" "ups" "3" "Sentinel SDL 6000-7" "Netman Plus 102 SNMP Card" "snmp-ups" "Riello" "ups" "3" "Sentinel Dual SDH 1000-7" "Netman Plus 102 SNMP Card" "snmp-ups" "Riello" "ups" "4" "IDG 400/600/800/1200/1600" "USB" "riello_usb" "Riello" "ups" "4" "IPG 600/800" "USB" "riello_usb" "Riello" "ups" "5" "WPG 400/600/800" "USB" "riello_usb" "Riello" "ups" "5" "NPW 600/800/1000/1500/2000" "USB" "riello_usb" "Riello" "ups" "5" "NDG 800/1000/1500/2000" "USB" "riello_usb" "Riello" "ups" "5" "DVT 500/800/1100/1500/2000" "USB" "riello_usb" "Riello" "ups" "5" "DVR 500/800/1100" "USB" "riello_usb" "Riello" "ups" "5" "DVD 1500/2200/3000" "USB" "riello_usb" "Riello" "ups" "5" "VST 800/1100/1500/2000" "USB" "riello_usb" "Riello" "ups" "5" "VSR 800/1100" "USB" "riello_usb" "Riello" "ups" "5" "VSD 1100/1500/2200/3000" "USB" "riello_usb" "Riello" "ups" "5" "SEP 700/1000/1500/2200/3000" "USB" "riello_usb" "Riello" "ups" "5" "SDH 1000/1500/2200/3000" "USB" "riello_usb" "Riello" "ups" "5" "SDL 3300/4000/5000/6000/6500/8000/10000" "USB" "riello_usb" "Riello" "ups" "5" "SDU 4000/5000/6000/8000/10000" "USB" "riello_usb" "Riello" "ups" "5" "SPW" "USB" "riello_usb" "Riello" "ups" "5" "SPT" "USB" "riello_usb" "Riello" "ups" "5" "STW 5000/6000/8000/10000" "USB" "riello_usb" "Riello" "ups" "5" "S3M" "USB" "riello_usb" "Riello" "ups" "5" "S3T" "USB" "riello_usb" "Riello" "ups" "5" "NDG 800/1000/1500/2000" "" "riello_ser" "Riello" "ups" "5" "DVT 500/800/1100/1500/2000" "" "riello_ser" "Riello" "ups" "5" "DVR 500/800/1100" "" "riello_ser" "Riello" "ups" "5" "DVD 1500/2200/3000" "" "riello_ser" "Riello" "ups" "5" "VST 800/1100/1500/2000" "" "riello_ser" "Riello" "ups" "5" "VSR 800/1100" "" "riello_ser" "Riello" "ups" "5" "VSD 1100/1500/2200/3000" "" "riello_ser" "Riello" "ups" "5" "SEP 700/1000/1500/2200/3000" "" "riello_ser" "Riello" "ups" "5" "SDH 1000/1500/2200/3000" "" "riello_ser" "Riello" "ups" "5" "SDL 3300/4000/5000/6000/6500/8000/10000" "" "riello_ser" "Riello" "ups" "5" "SDU 4000/5000/6000/8000/10000" "" "riello_ser" "Riello" "ups" "5" "SPW" "" "riello_ser" "Riello" "ups" "5" "SPT" "" "riello_ser" "Riello" "ups" "5" "STW 5000/6000/8000/10000" "" "riello_ser" "Riello" "ups" "5" "S3M" "" "riello_ser" "Riello" "ups" "5" "S3T" "" "riello_ser" "Riello" "ups" "5" "MCT" "" "riello_ser" "Riello" "ups" "5" "MST" "" "riello_ser" "Riello" "ups" "5" "MCM" "" "riello_ser" "Riello" "ups" "5" "MCT" "" "riello_ser" "Riello" "ups" "5" "MHE" "" "riello_ser" "Riello" "ups" "5" "MHT" "" "riello_ser" "Riello" "ups" "5" "MPT" "" "riello_ser" "Riello" "ups" "5" "MPM" "" "riello_ser" "Riello" "ups" "5" "NXE" "" "riello_ser" "Riello" "ups" "3" "(various)" "Netman Plus 101 SNMP Box" "snmp-ups" "Riello" "ups" "3" "(various)" "Netman Plus 102 SNMP Card" "snmp-ups" "Riello" "ups" "3" "(various)" "Netman Plus 202 SNMP Card" "snmp-ups" "Riello" "ups" "3" "(various)" "Netman 204 SNMP Card" "snmp-ups" # Note: in https://github.com/networkupstools/nut/issues/1878 submitted not as "Netman Plus", clarification requested "Riello" "ups" "3" "(various)" "Netman 208 SNMP Card" "snmp-ups" # Note: in https://github.com/networkupstools/nut/issues/1878 submitted not as "Netman Plus", clarification requested "Rocketfish" "ups" "3" "RF-1000VA / RF-1025VA" "USB" "usbhid-ups" "Rucelf" "ups" "2" "Rucelf UPOII-3000-96-EL" "" "blazer_ser" # http://www.rucelf.ua/en/catalog/upoii-3000-96-el/ "Salicru" "ups" "2" "SPS ONE 700VA" "USB" "blazer_usb" "Salicru" "ups" "2" "SPS ONE 2000VA" "USB" "nutdrv_qx" # https://www.salicru.com/en/ups/sps-one.html https://github.com/networkupstools/nut/issues/554 "Salicru" "ups" "3" "SPS 650/850 HOME" "usb" "usbhid-ups (experimental)" "Salicru" "ups" "3" "SLC TWIN PRO2" "usb" "usbhid-ups (experimental)" # https://github.com/networkupstools/nut/issues/450 "Salicru" "ups" "3" "SLC-1500-TWIN PRO3" "usb" "usbhid-ups (experimental)" # https://github.com/networkupstools/nut/issues/1142 "Salicru" "ups" "3" "SLC TWINPRO3" "usb" "usbhid-ups (experimental)" "Salicru" "ups" "3" "SLC TWIN RT3" "usb" "usbhid-ups (experimental)" "Salicru" "ups" "3" "SPS 850 ADV T" "usb" "usbhid-ups (experimental)" # https://www.salicru.com/sps-850-adv-t.html https://github.com/networkupstools/nut/issues/1416 "Salicru" "ups" "3" "SPS 3000 ADV RT2" "usb" "usbhid-ups (experimental)" # https://www.salicru.com/sps-3000-adv-rt2.html "Santak" "ups" "2" "Castle C*K" "Serial" "blazer_ser" # https://github.com/networkupstools/nut/issues/1039 "Santak" "ups" "2" "MT*-PRO" "Serial" "blazer_ser" # https://github.com/networkupstools/nut/issues/1039 "Siemens" "ups" "4" "SITOP UPS500" "serial" "nutdrv_siemens_sitop (experimental, untested)" "Siemens" "ups" "4" "SITOP UPS500" "USB" "nutdrv_siemens_sitop (experimental)" "SKE" "ups" "2" "SK600" "USB" "nutdrv_qx port=auto vendorid=0001 productid=0000 bus=003" "SmartLabs" "pdu" "1" "2412S Power Line Modem" "for X10/Insteon" "powerman-pdu (experimental)" "SMS (Brazil)" "ups" "2" "Manager III" "" "blazer_ser" "SNR" "ups" "2" "SNR-UPS-LID-600" "" "nutdrv_qx" "SNR" "ups" "2" "SNR-UPS-LID-600-XPS" "" "nutdrv_qx" "SNR" "ups" "2" "SNR-UPS-LID-600-LED-C13" "" "nutdrv_qx" "SNR" "ups" "2" "SNR-UPS-LID-600-LED-C13-PRO" "" "nutdrv_qx" "SNR" "ups" "2" "SNR-UPS-LID-800" "" "nutdrv_qx" "SNR" "ups" "2" "SNR-UPS-LID-800-LED-С13" "" "nutdrv_qx" "SNR" "ups" "2" "SNR-UPS-LID-1000-XPS" "" "nutdrv_qx" "SNR" "ups" "2" "SNR-UPS-LID-1200" "" "nutdrv_qx" "SNR" "ups" "2" "SNR-UPS-LID-1500" "" "nutdrv_qx" "SNR" "ups" "2" "SNR-UPS-LID-2000" "" "nutdrv_qx" "SNR" "ups" "2" "SNR-UPS-LID-2000-XPS" "" "nutdrv_qx" "SNR" "ups" "2" "SNR-UPS-LID-3000-XPS" "" "nutdrv_qx" "SOLA" "ups" "1" "305" "cable INT-0025C" "genericups upstype=7" "SOLA" "ups" "1" "325" "" "blazer_ser or bestups" "SOLA" "ups" "1" "520" "" "blazer_ser or bestups" "SOLA" "ups" "1" "610" "use ID= in ups.conf" "blazer_ser or bestups" "SOLA" "ups" "1" "620" "" "blazer_ser or bestups" "SOLA" "ups" "4" "330" "" "blazer_ser" "SOLA/BASIC Mexico" "ups" "1" "various" "ISBMEX protocol" "isbmex" "Socomec Sicon" "ups" "2" "NeTYS-PE 600VA" "" "blazer_ser" "Socomec Sicon" "ups" "1" "Egys" "420 VA" "powercom" "Socomec Sicon" "ups" "3" "MASTERYS 3/3 SYSTEM 60 kVA" "Net Vision v5.05 SNMP card" "snmp-ups (experimental)" "Socomec Sicon" "ups" "3" "NETYS RT 1/1" "Net Vision SNMP card" "snmp-ups (experimental)" "Socomec Sicon" "ups" "3" "Netvision" "UPS equipped with Netvision WEB/SNMP card/external box" "snmp-ups (experimental)" "Soltec" "ups" "1" "Winmate 525/625/800/1000" "" "safenet" "Soyntec" "ups" "2" "Sekury C 500" "" "blazer_ser" "Soyntec" "ups" "2" "Sekury C 800" "" "blazer_ser" "SquareOne Power" "ups" "2" "QP1000" "" "blazer_ser" "StarPower" "ups" "1" "PCF-800VA" "USB" "richcomm_usb" # http://www.sako.com.cn/products01.asp?Id=29&proid=53 "Sun" "pdu" "1" "ILOM Management Module" "1 outlet" "powerman-pdu (experimental)" "SuperPower" "ups" "2" "HP360, Hope-550" "" "blazer_ser" "SVEN" "ups" "2" "Power Pro+ series" "USB" "blazer_usb (USB ID ffff:0000)" "SVEN" "ups" "2" "Power Pro+ series" "USB" "blazer_usb (USB ID 05b8:0000)" "SVEN" "ups" "1" "Power Pro+ series" "USB" "richcomm_usb (USB ID 0925:1234)" "SVEN" "ups" "2" "Power Smart RM 2000" "USB" "blazer_usb (USB ID 05b8:0000)" "Sweex" "ups" "1" "500/1000" "smart - shipped with SafeNet" "safenet" "Sweex" "ups" "1" "500/1000" "" "genericups upstype=7" "Sweex" "ups" "1" "1000" "USB" "richcomm_usb" "Sweex" "ups" "2" "(various)" "" "blazer_ser" "Sweex" "ups" "2" "INTELLIGENT UPS 1500VA P220" "USB" "blazer_usb (USB ID 0665:5161)" # http://www.sweex.com/en/notebook-pc-accessoires/ups/PP220/ "Syndome" "ups" "2" "Era 500VA" "USB" "blazer_usb" "Syndome" "ups" "3" "Atom LCD-1000" "USB" "usbhid-ups" # https://github.com/networkupstools/nut/issues/483 "Sysgration" "ups" "2" "UPGUARDS Pro650" "" "blazer_ser" "Tecnoware" "ups" "2" "Easy Power 1200" "" "blazer_ser" "Tecnoware" "ups" "2" "UPS ERA LCD 0.65" "USB" "blazer_usb langid_fix=0x409" "Tecnoware" "ups" "2" "UPS ERA PLUS 1100" "USB" "blazer_usb" # https://www.tecnoware.com/Prodotti/FGCERAPL1100/ups-era-plus-1100.aspx https://github.com/networkupstools/nut/issues/747 "Tripp Lite" "ups" "1" "(various)" "Lan 2.2 interface - black 73-0844 cable" "genericups upstype=5" "Tripp Lite" "ups" "3" "1500 LCD" "USB" "usbhid-ups" "Tripp Lite" "ups" "3" "AVR550U" "USB (protocol 2010)" "usbhid-ups" # http://www.tripplite.com/en/products/model.cfm?txtSeriesID=930&txtModelID=3090 "Tripp Lite" "ups" "3" "AVR700U" "USB (protocol 2010)" "usbhid-ups" # http://www.tripplite.com/en/products/model.cfm?txtSeriesID=930&txtModelID=4785 "Tripp Lite" "ups" "3" "AVR750U" "USB (protocol 2010)" "usbhid-ups" # http://www.tripplite.com/en/products/model.cfm?txtSeriesID=930&txtModelID=3141 "Tripp Lite" "ups" "3" "AVR900U" "USB (protocol 2010)" "usbhid-ups" # http://www.tripplite.com/en/products/model.cfm?txtSeriesID=930&txtModelID=3649 "Tripp Lite" "ups" "3" "AVR900UTAA" "USB (protocol 2010)" "usbhid-ups" # http://www.tripplite.com/en/products/model.cfm?txtModelID=4375 "Tripp Lite" "ups" "3" "AVRX550U" "USB (protocol 2009)" "usbhid-ups" # http://www.tripplite.com/en/products/model.cfm?txtModelID=3079 "Tripp Lite" "ups" "3" "AVRX550UD" "USB (protocol 2010)" "usbhid-ups" # http://www.tripplite.com/en/products/model.cfm?txtSeriesID=930&txtModelID=4620 "Tripp Lite" "ups" "3" "AVRX750U" "USB (protocol 2009)" "usbhid-ups" # http://www.tripplite.com/en/products/model.cfm?txtSeriesID=930&txtModelID=3190 "Tripp Lite" "ups" "3" "AVRX750UD" "USB (protocol 2010)" "usbhid-ups" # http://www.tripplite.com/en/products/model.cfm?txtSeriesID=930&txtModelID=4755 "Tripp Lite" "ups" "3" "AVRX750UF" "USB (protocol 2010)" "usbhid-ups" # http://www.tripplite.com/en/products/model.cfm?txtSeriesID=930&txtModelID=4756 "Tripp Lite" "ups" "3" "BC600SINE" "USB (protocol 2011)" "usbhid-ups" # http://www.tripplite.com/en/products/model.cfm?txtModelID=4863 "Tripp Lite" "ups" "3" "BCPERS450" "USB (protocol 2010)" "usbhid-ups" # http://www.tripplite.com/en/products/model.cfm?txtModelID=4 "Tripp Lite" "ups" "3" "BCPRO600" "USB (protocol 2012)" "usbhid-ups" # http://www.tripplite.com/en/products/model.cfm?txtSeriesID=931&txtModelID=5 "Tripp Lite" "ups" "3" "ECO350UPS" "USB (protocol 2012)" "usbhid-ups" # http://www.tripplite.com/en/products/model.cfm?txtSeriesID=743&txtModelID=4149 "Tripp Lite" "ups" "3" "ECO550UPS" "USB (protocol 2012)" "usbhid-ups" # http://www.tripplite.com/en/products/model.cfm?txtSeriesID=743&txtModelID=4148 "Tripp Lite" "ups" "3" "ECO650LCD" "USB (protocol 2011)" "usbhid-ups" # http://www.tripplite.com/en/products/model.cfm?txtModelID=4861 "Tripp Lite" "ups" "3" "ECO750UPS" "USB (protocol 2012)" "usbhid-ups" # http://www.tripplite.com/en/products/model.cfm?txtSeriesID=743&txtModelID=4147 "Tripp Lite" "ups" "3" "ECO850LCD" "USB (protocol 2011)" "usbhid-ups" # http://www.tripplite.com/en/products/model.cfm?txtSeriesID=743&txtModelID=4862 "Tripp Lite" "ups" "3" "HT850UPS" "USB (protocol 2010)" "usbhid-ups" # http://www.tripplite.com/en/products/model.cfm?txtModelID=3197 "Tripp Lite" "ups" "3" "HTR05-1U" "USB (protocol 3005)" "usbhid-ups" # http://www.tripplite.com/en/products/model.cfm?txtModelID=3202 "Tripp Lite" "ups" "3" "HTR10-2U" "USB (protocol 4001)" "usbhid-ups" # http://www.tripplite.com/en/products/model.cfm?txtModelID=3343 "Tripp Lite" "ups" "3" "INTERNET350U" "USB (protocol 2010)" "usbhid-ups" # http://www.tripplite.com/en/products/model.cfm?txtModelID=2663 "Tripp Lite" "ups" "3" "INTERNET550U" "USB (protocol 2010)" "usbhid-ups" # http://www.tripplite.com/en/products/model.cfm?txtSeriesID=930&txtModelID=3063 "Tripp Lite" "ups" "3" "INTERNET600U" "USB (protocol 2010)" "usbhid-ups" # http://www.tripplite.com/en/products/model.cfm?txtSeriesID=930&txtModelID=3033 "Tripp Lite" "ups" "3" "INTERNET750U" "USB (protocol 1007)" "usbhid-ups" # http://www.tripplite.com/en/products/model.cfm?txtModelID=3142 "Tripp Lite" "ups" "3" "INTERNET900U" "USB (protocol 1007)" "usbhid-ups" # http://www.tripplite.com/en/products/model.cfm?txtSeriesID=930&txtModelID=3657 "Tripp Lite" "ups" "3" "INTERNETOFFICE500" "USB (protocol 2010)" "usbhid-ups" # http://www.tripplite.com/en/products/model.cfm?txtSeriesID=930&txtModelID=11 "Tripp Lite" "ups" "1" "INTERNETOFFICE700" "USB (older; product ID: 0001)" "tripplite_usb" "Tripp Lite" "ups" "3" "INTERNETOFFICE700" "USB (protocol 2012)" "usbhid-ups" # http://www.tripplite.com/en/products/model.cfm?txtSeriesID=930&txtModelID=14 "Tripp Lite" "ups" "3" "OMNI650LCD" "USB (protocol 2010)" "usbhid-ups" # http://www.tripplite.com/en/products/model.cfm?txtModelID=3195 "Tripp Lite" "ups" "3" "OMNI900LCD" "USB (protocol 2010)" "usbhid-ups" # http://www.tripplite.com/en/products/model.cfm?txtSeriesID=932&txtModelID=3082 "Tripp Lite" "ups" "3" "OMNI1000LCD" "USB" "usbhid-ups" "Tripp Lite" "ups" "3" "OMNISMART300PNP" "USB (protocol 2010)" "usbhid-ups" # http://www.tripplite.com/en/products/model.cfm?txtSeriesID=932&txtModelID=19 "Tripp Lite" "ups" "1" "OMNISMART500" "USB (older; product ID: 0001)" "tripplite_usb" "Tripp Lite" "ups" "3" "OMNISMART500" "USB (protocol 2010)" "usbhid-ups" # http://www.tripplite.com/en/products/model.cfm?txtSeriesID=932&txtModelID=21 "Tripp Lite" "ups" "3" "OMNISMART700" "USB (protocol 2012)" "usbhid-ups" # http://www.tripplite.com/en/products/model.cfm?txtModelID=23 "Tripp Lite" "ups" "2" "OMNIVSINT800" "USB (older; product ID: 0001)" "tripplite_usb" "Tripp Lite" "ups" "3" "OMNIVS800" "USB (protocol 2012)" "usbhid-ups" # http://www.tripplite.com/en/products/model.cfm?txtSeriesID=932&txtModelID=2729 "Tripp Lite" "ups" "2" "OMNIVS1000" "USB (older; product ID: 0001)" "tripplite_usb" "Tripp Lite" "ups" "3" "OMNIVS1000" "USB (protocol 2012)" "usbhid-ups" # http://www.tripplite.com/en/products/model.cfm?txtSeriesID=932&txtModelID=2656 "Tripp Lite" "ups" "1" "OMNIVS1500XL" "USB" "tripplite_usb" "Tripp Lite" "ups" "3" "POS500" "USB (protocol 2007)" "usbhid-ups" # http://www.tripplite.com/en/products/model.cfm?txtModelID=3742 "Tripp Lite" "ups" "3" "SM2200RMDVTAA" "USB (protocol 3014)" "usbhid-ups" # http://www.tripplite.com/en/products/model.cfm?txtModelID=4648 "Tripp Lite" "ups" "1" "SmartUPS" "" "tripplite" "Tripp Lite" "ups" "1" "SmartOnline" "" "tripplitesu" "Tripp Lite" "ups" "1" "SMART550USB" "USB (older; product ID: 0001)" "tripplite_usb" "Tripp Lite" "ups" "3" "SMART550USB" "USB (protocol 2010)" "usbhid-ups" # http://www.tripplite.com/en/products/model.cfm?txtSeriesID=932&txtModelID=2002 "Tripp Lite" "ups" "3" "SMART550USBWD" "USB (protocol 2010)" "usbhid-ups" # http://www.tripplite.com/en/products/model.cfm?txtSeriesID=932&txtModelID=2591 "Tripp Lite" "ups" "1" "SMART700USB" "USB" "tripplite_usb" "Tripp Lite" "ups" "3" "SMART750RMXL2U" "USB (protocol 3015)" "usbhid-ups" # http://www.tripplite.com/en/products/model.cfm?txtSeriesID=933&txtModelID=3020 "Tripp Lite" "ups" "3" "SMART750SLT" "USB (protocol 3014)" "usbhid-ups" # http://www.tripplite.com/en/products/model.cfm?txtSeriesID=933&txtModelID=3007 "Tripp Lite" "ups" "3" "SMART750USB" "USB (protocol 2012)" "usbhid-ups" # http://www.tripplite.com/en/products/model.cfm?txtSeriesID=932&txtModelID=2679 "Tripp Lite" "ups" "3" "SMART750XLA" "USB (protocol 3014)" "usbhid-ups" # http://www.tripplite.com/en/products/model.cfm?txtSeriesID=933&txtModelID=3820 "Tripp Lite" "ups" "3" "SMART1000LCD" "USB (protocol 2010)" "usbhid-ups" # http://www.tripplite.com/en/products/model.cfm?txtSeriesID=932&txtModelID=3071 "Tripp Lite" "ups" "3" "SMART1000RM2U" "USB (protocol 3015)" "usbhid-ups" # http://www.tripplite.com/en/products/model.cfm?txtModelID=2657 "Tripp Lite" "ups" "3" "SMART1000RMXL2U" "USB (protocol 3015)" "usbhid-ups" # http://www.tripplite.com/en/products/model.cfm?txtSeriesID=933&txtModelID=5262 "Tripp Lite" "ups" "3" "SMART1050SLT" "USB (protocol 3012)" "usbhid-ups" # http://www.tripplite.com/en/products/model.cfm?txtSeriesID=933&txtModelID=3253 "Tripp Lite" "ups" "3" "SMART1050SLTAA" "USB (protocol 3012)" "usbhid-ups" # http://www.tripplite.com/en/products/model.cfm?txtModelID=4389 "Tripp Lite" "ups" "3" "SMART1200LCD" "USB (protocol 2009)" "usbhid-ups" # http://www.tripplite.com/en/products/model.cfm?txtModelID=3193 "Tripp Lite" "ups" "1" "SMART1500RM2U" "USB (older; product ID: 0001)" "tripplite_usb" "Tripp Lite" "ups" "3" "SMART1500CRMXL" "USB (protocol 3014)" "usbhid-ups" # http://www.tripplite.com/en/products/model.cfm?txtModelID=3826 "Tripp Lite" "ups" "3" "SMART1500LCD" "USB (protocol 2009)" "usbhid-ups" # http://www.tripplite.com/en/products/model.cfm?txtSeriesID=932&txtModelID=3151 "Tripp Lite" "ups" "3" "SMART1500LCDXL" "USB (protocol 2012)" "usbhid-ups" # http://www.tripplite.com/en/products/model.cfm?txtSeriesID=932&txtModelID=4978 "Tripp Lite" "ups" "3" "SMART1500RM2U" "USB (protocol 3015)" "usbhid-ups" # http://www.tripplite.com/en/products/model.cfm?txtSeriesID=933&txtModelID=2658 "Tripp Lite" "ups" "3" "SMART1500RM2UN" "USB (protocol 3015)" "usbhid-ups" # http://www.tripplite.com/en/products/model.cfm?txtSeriesID=933&txtModelID=5424 "Tripp Lite" "ups" "3" "SMART1500RMXL2UA" "USB (protocol 3015)" "usbhid-ups" # http://www.tripplite.com/en/products/model.cfm?txtSeriesID=933&txtModelID=3982 "Tripp Lite" "ups" "3" "SMART1500RMXLN" "USB (protocol 3015)" "usbhid-ups" # http://www.tripplite.com/en/products/model.cfm?txtSeriesID=933&txtModelID=5429 "Tripp Lite" "ups" "3" "SMART1500SLT" "USB (protocol 3012)" "usbhid-ups" # http://www.tripplite.com/en/products/model.cfm?txtSeriesID=933&txtModelID=3254 "Tripp Lite" "ups" "3" "SMART2200CRMXL" "USB (protocol 3014)" "usbhid-ups" # http://www.tripplite.com/en/products/model.cfm?txtSeriesID=933&txtModelID=3825 "Tripp Lite" "ups" "3" "SMART2200RM2U" "USB (protocol 3015)" "usbhid-ups" # http://www.tripplite.com/en/products/model.cfm?txtSeriesID=933&txtModelID=4403 "Tripp Lite" "ups" "3" "SMART2200RM2UN" "USB (protocol 3015)" "usbhid-ups" # http://www.tripplite.com/en/products/model.cfm?txtSeriesID=933&txtModelID=5428 "Tripp Lite" "ups" "1" "SMART2200RMXL2U" "USB (older; product ID: 0001)" "tripplite_usb (experimental)" "Tripp Lite" "ups" "3" "SMART2200RMXL2U" "USB (protocol 3015)" "usbhid-ups" # http://www.tripplite.com/en/products/model.cfm?txtSeriesID=933&txtModelID=3264 "Tripp Lite" "ups" "3" "SMART2200RMXL2UP" "USB (protocol 3015)" "usbhid-ups" # http://www.tripplite.com/en/products/model.cfm?txtSeriesID=933&txtModelID=4672 "Tripp Lite" "ups" "3" "SMART2200RMXLN" "USB (protocol 3015)" "usbhid-ups" # http://www.tripplite.com/en/products/model.cfm?txtSeriesID=933&txtModelID=5427 "Tripp Lite" "ups" "3" "SMART2200SLT" "USB (protocol 3013)" "usbhid-ups" # http://www.tripplite.com/en/products/model.cfm?txtSeriesID=933&txtModelID=3489 "Tripp Lite" "ups" "3" "SMART2200SLTAA" "USB (protocol 3013)" "usbhid-ups" # http://www.tripplite.com/en/products/model.cfm?txtModelID=4390 "Tripp Lite" "ups" "3" "SMART2500XLHG" "USB (protocol 3015)" "usbhid-ups" # http://www.tripplite.com/en/products/model.cfm?txtModelID=5440 "Tripp Lite" "ups" "3" "SMART2600RM2U" "USB (protocol 3014)" "usbhid-ups" # http://www.tripplite.com/en/products/model.cfm?txtSeriesID=933&txtModelID=3024 "Tripp Lite" "ups" "3" "SMART3000CRMXL" "USB (protocol 3014)" "usbhid-ups" # http://www.tripplite.com/en/products/model.cfm?txtSeriesID=933&txtModelID=3824 "Tripp Lite" "ups" "3" "SMART3000RM2U" "USB (protocol 3015)" "usbhid-ups" # http://www.tripplite.com/en/products/model.cfm?txtSeriesID=933&txtModelID=3025 "Tripp Lite" "ups" "3" "SMART3000RM2UN" "USB (protocol 3015)" "usbhid-ups" # http://www.tripplite.com/en/products/model.cfm?txtSeriesID=933&txtModelID=5426 "Tripp Lite" "ups" "3" "SMART3000RMOD2U" "USB (protocol 3014)" "usbhid-ups" # http://www.tripplite.com/en/products/model.cfm?txtSeriesID=933&txtModelID=4249 "Tripp Lite" "ups" "3" "SMART3000RMXL2U" "USB (protocol 3015)" "usbhid-ups" # http://www.tripplite.com/en/products/model.cfm?txtSeriesID=933&txtModelID=4418 "Tripp Lite" "ups" "3" "SMART3000RMXLN" "USB (protocol 3015)" "usbhid-ups" # http://www.tripplite.com/en/products/model.cfm?txtSeriesID=933&txtModelID=5425 "Tripp Lite" "ups" "3" "SMART3000SLT" "USB (protocol 3013)" "usbhid-ups" # http://www.tripplite.com/en/products/model.cfm?txtSeriesID=933&txtModelID=3490 "Tripp Lite" "ups" "2" "SMART500RT1U" "USB (older; product ID 0001, protocol 3005)" "tripplite_usb" "Tripp Lite" "ups" "3" "SMART500RT1U" "USB (newer; protocol/product ID 3005)" "usbhid-ups" # http://www.tripplite.com/en/products/model.cfm?txtModelID=2853 "Tripp Lite" "ups" "3" "SMC15002URM" "USB (protocol 3015)" "usbhid-ups" # https://www.tripplite.com/smartpro-120v-1-5kva-1kw-line-interactive-sine-wave-ups-2u-rack-tower-lcd-usb-db9-8-outlets~SMC15002URM "Tripp Lite" "ups" "3" "SMX1000LCD" "USB (protocol 2005)" "usbhid-ups" # http://www.tripplite.com/en/products/model.cfm?txtModelID=3200 "Tripp Lite" "ups" "3" "SMX1000RT2U" "USB (protocol 3015)" "usbhid-ups" # http://www.tripplite.com/en/products/model.cfm?txtModelID=2798 "Tripp Lite" "ups" "3" "SMX1050SLT" "USB (protocol 3012)" "usbhid-ups" # http://www.tripplite.com/en/products/model.cfm?txtModelID=3249 "Tripp Lite" "ups" "3" "SMX1500LCD" "USB (protocol 2009)" "usbhid-ups" # http://www.tripplite.com/en/products/model.cfm?txtSeriesID=932&txtModelID=3303 "Tripp Lite" "ups" "3" "SMX1500SLT" "USB (protocol 3012)" "usbhid-ups" # http://www.tripplite.com/en/products/model.cfm?txtModelID=3248 "Tripp Lite" "ups" "3" "SMX1500XLRT2U" "USB (protocol 3015)" "usbhid-ups" # http://www.tripplite.com/en/products/model.cfm?txtSeriesID=933&txtModelID=2687 "Tripp Lite" "ups" "3" "SMX2200XLRT2U" "USB (protocol 3015)" "usbhid-ups" # http://www.tripplite.com/en/products/model.cfm?txtModelID=3251 "Tripp Lite" "ups" "3" "SMX3000RT2UTAA" "USB (protocol 3015)" "usbhid-ups" # http://www.tripplite.com/en/products/model.cfm?txtModelID=4396 "Tripp Lite" "ups" "3" "SMX3000XLRT2U" "USB (protocol 3015)" "usbhid-ups" # http://www.tripplite.com/en/products/model.cfm?txtSeriesID=933&txtModelID=2694 "Tripp Lite" "ups" "3" "SMX3000XLRT2UA" "USB (protocol 3015)" "usbhid-ups" # http://www.tripplite.com/en/products/model.cfm?txtModelID=5658 "Tripp Lite" "ups" "3" "SMX500RT1U" "USB (older; product ID 0001, protocol 3005)" "tripplite_usb" # https://www.tripplite.com/support/product/part-number/SMX500RT1U https://github.com/networkupstools/nut/pull/584 "Tripp Lite" "ups" "3" "SMX500RT1U" "USB (newer; protocol/product ID 3005)" "usbhid-ups" # https://www.tripplite.com/support/product/part-number/SMX500RT1U "Tripp Lite" "ups" "3" "SMX750SLT" "USB (protocol 3014)" "usbhid-ups" # http://www.tripplite.com/en/products/model.cfm?txtModelID=3021 "Tripp Lite" "ups" "3" "SU750RTXL2U" "USB (protocol 4001)" "usbhid-ups" # http://www.tripplite.com/en/products/model.cfm?txtModelID=3194 "Tripp Lite" "ups" "3" "SU750RTXLCD2U" "USB (protocol 4004)" "usbhid-ups" # http://www.tripplite.com/en/products/model.cfm?txtModelID=5070 "Tripp Lite" "ups" "3" "SU750XL" "USB (protocol 4001)" "usbhid-ups" # http://www.tripplite.com/en/products/model.cfm?txtModelID=3299 "Tripp Lite" "ups" "3" "SU1000RTXL2UA" "USB (protocol 4001)" "usbhid-ups" # http://www.tripplite.com/en/products/model.cfm?txtSeriesID=934&txtModelID=2948 "Tripp Lite" "ups" "3" "SU1000RTXLCD2U" "USB (protocol 4004)" "usbhid-ups" # http://www.tripplite.com/en/products/model.cfm?txtSeriesID=745&txtModelID=4980 "Tripp Lite" "ups" "3" "SU1000XLA" "USB (protocol 4001)" "usbhid-ups" # http://www.tripplite.com/en/products/model.cfm?txtSeriesID=934&txtModelID=3180 "Tripp Lite" "ups" "3" "SU1000XLCD" "USB (protocol 4004)" "usbhid-ups" # http://www.tripplite.com/en/products/model.cfm?txtModelID=5320 "Tripp Lite" "ups" "3" "SU1500RTXL2UA (SmartOnline)" "USB (protocol 4001)" "usbhid-ups" # http://www.tripplite.com/en/products/model.cfm?txtSeriesID=934&txtModelID=2949 "Tripp Lite" "ups" "3" "SU1500RTXLCD2U" "USB (protocol 4004)" "usbhid-ups" # http://www.tripplite.com/en/products/model.cfm?txtSeriesID=745&txtModelID=5037 "Tripp Lite" "ups" "3" "SU1500XL" "USB (protocol 4001)" "usbhid-ups" # http://www.tripplite.com/en/products/model.cfm?txtSeriesID=934&txtModelID=3300 "Tripp Lite" "ups" "3" "SU1500XLCD" "USB (protocol 4004)" "usbhid-ups" # http://www.tripplite.com/en/products/model.cfm?txtSeriesID=744&txtModelID=5339 "Tripp Lite" "ups" "3" "SU2200RTXL2UA" "USB (protocol 4001)" "usbhid-ups" # http://www.tripplite.com/en/products/model.cfm?txtSeriesID=934&txtModelID=2950 "Tripp Lite" "ups" "3" "SU2200RTXLCD2U" "USB (protocol 4004)" "usbhid-ups" # http://www.tripplite.com/en/products/model.cfm?txtSeriesID=745&txtModelID=5069 "Tripp Lite" "ups" "3" "SU2200XLA" "USB (protocol 4001)" "usbhid-ups" # http://www.tripplite.com/en/products/model.cfm?txtSeriesID=934&txtModelID=3594 "Tripp Lite" "ups" "3" "SU2200XLCD" "USB (protocol 4004)" "usbhid-ups" # http://www.tripplite.com/en/products/model.cfm?txtSeriesID=744&txtModelID=5340 "Tripp Lite" "ups" "3" "SU3000RTXL2U" "USB (protocol 4005)" "usbhid-ups" # http://www.tripplite.com/en/products/model.cfm?txtModelID=4210 "Tripp Lite" "ups" "3" "SU3000RTXL3U" "USB (protocol 4001)" "usbhid-ups" # http://www.tripplite.com/en/products/model.cfm?txtSeriesID=934&txtModelID=3023 "Tripp Lite" "ups" "3" "SU3000RTXLCD3U" "USB (protocol 4004)" "usbhid-ups" # http://www.tripplite.com/en/products/model.cfm?txtSeriesID=745&txtModelID=5071 "Tripp Lite" "ups" "3" "SU3000RTXR3U" "USB (protocol 4001)" "usbhid-ups" # http://www.tripplite.com/en/products/model.cfm?txtSeriesID=934&txtModelID=3080 "Tripp Lite" "ups" "3" "SU3000RTXR3UHW" "USB (protocol 4001)" "usbhid-ups" # http://www.tripplite.com/en/products/model.cfm?txtSeriesID=934&txtModelID=4976 "Tripp Lite" "ups" "3" "SU3000XL" "USB (protocol 4001)" "usbhid-ups" # http://www.tripplite.com/en/products/model.cfm?txtSeriesID=934&txtModelID=3601 "Tripp Lite" "ups" "3" "SU3000XLCD" "USB (protocol 4004)" "usbhid-ups" # http://www.tripplite.com/en/products/model.cfm?txtSeriesID=744&txtModelID=5342 "Tripp Lite" "ups" "3" "SUINT1000RTXL2UA" "USB (protocol 4001)" "usbhid-ups" # http://www.tripplite.com/en/products/model.cfm?txtModelID=3983 "Tripp Lite" "ups" "3" "SUINT1500RTXL2UA" "USB (protocol 4001)" "usbhid-ups" # http://www.tripplite.com/en/products/model.cfm?txtSeriesID=934&txtModelID=2720 "Tripp Lite" "ups" "3" "SUINT2200RTXL2UA" "USB (protocol 4001)" "usbhid-ups" # http://www.tripplite.com/en/products/model.cfm?txtSeriesID=934&txtModelID=3970 "Tripp Lite" "ups" "3" "SUINT3000RTXL2U" "USB (protocol 4005)" "usbhid-ups" # http://www.tripplite.com/en/products/model.cfm?txtModelID=4523 "Trust" "ups" "2" "UPS 1000 Management PW-4105" "" "blazer_ser" "Trust" "ups" "2" "UPS 1200VA Management PW-4120M" "" "blazer_ser" "Trust" "ups" "2" "UPS 1300VA Management PW-4130M" "" "blazer_ser" "TS Shara" "ups" "4" "(various)" "" "nutdrv_qx" "UltraMax" "ups" "2" "1000SC" "USB" "nutdrv_qx" # https://github.com/networkupstools/nut/issues/1634 "UNITEK" "ups" "2" "ALPHA 500 IC" "" "blazer_ser" "UNITEK" "ups" "2" "Alpha 1000is" "" "blazer_ser" "UNITEK" "ups" "2" "Alpha 500" "" "blazer_ser" "UNITEK" "ups" "2" "Alpha 500 ipE" "" "blazer_ser" "UNITEK" "ups" "2" "Alpha650ipF" "USB" "blazer_usb" "UNITEK" "ups" "2" "Alpha650ipE" "USB" "blazer_usb" "UNITEK" "ups" "2" "Alpha 2600" "" "blazer_ser" "UNITEK" "ups" "2" "Alpha 1200Sx" "USB" "blazer_usb" "UNITEK" "ups" "2" "Alpha 1250xD" "USB" "blazer_usb" "UPSonic" "ups" "2" "CXR1000" "" "blazer_ser" "UPSonic" "ups" "1" "LAN Saver 600" "" "genericups upstype=0" "UPSonic" "ups" "1" "Power Guardian" "" "genericups upstype=7" "UPSonic" "ups" "2" "PrOffice 650" "USB" "blazer_usb" "UPSonic" "ups" "2" "DS-800" "USB" "blazer_usb" "UPSonic" "ups" "2" "IRT-3K 2U" "USB" "megatec_usb" # Worked in NUT 2.4.3 "UPSonic" "ups" "2" "IRT-3K 2U" "USB" "nutdrv_qx" # Should work since 2.8.0; protocol broken vs. strict checks in 2.7.4; https://github.com/networkupstools/nut/issues/441#issuecomment-1288238345 "V7" "ups" "2" "UPS1RM2U1500-1E" "USB" "blazer_usb" # http://www.v7world.com/uk/ups-1500va-rack-mount-2u-eu.html https://github.com/networkupstools/nut/issues/716 "Various" "ups" "4" "(various)" "SEC protocol" "gamatronic" "Various" "ups" "1" "(various)" "Generic RUPS model" "genericups upstype=4" "Various" "ups" "1" "(various)" "Generic RUPS 2000 (Megatec M2501 cable)" "genericups upstype=21" "Various" "ups" "2" "(various serial)" "Q1 / Megatec protocol" "blazer_ser" "Various" "ups" "2" "(various USB)" "Q1 / Megatec protocol" "blazer_usb" "Various" "ups" "2" "(various)" "PhoenixTec protocol" "blazer_ser or bestups" "Various" "ups" "3" "(various)" "SNMP - RFC 1628" "snmp-ups (experimental)" "Various" "ups" "1" "(various)" "Safenet software" "safenet" "Various" "ups" "2" "(Various USB)" "UPSilon 2000 software" "blazer_usb langid_fix=0x409" "Various" "ups" "2" "(Various serial)" "ViewPower software" "nutdrv_qx" "Various" "ups" "2" "(Various USB)" "ViewPower software" "nutdrv_qx" "Various" "ups" "2" "(Various serial)" "WinPower software" "blazer_ser" "Various" "ups" "2" "(Various USB)" "WinPower software" "blazer_usb" "Various" "ups" "2" "Various Innova T" "(USB ID 06da:0201)" "blazer_ser or blazer_usb" "Various" "ups" "2" "Various Innova RT" "(USB ID 06da:0005)" "blazer_ser or blazer_usb" "Various" "ups" "2" "Various Innova 3/1 T" "(USB ID 06da:0004)" "blazer_ser or blazer_usb" "Victron/IMV" "ups" "1" "(various)" "" "victronups" "Victron/IMV" "ups" "1" "Lite" "crack cable" "genericups upstype=10" "Viewsonic" "ups" "1" "PowerES" "420E" "optiups" "Vivaldi" "ups" "1" "EA200 LED" "USB" "richcomm_usb" "Voltronic Power" "ups" "2" "Apex 1KVA" "Serial" "nutdrv_qx" "Voltronic Power" "ups" "2" "Apex 1KVA" "USB" "nutdrv_qx" "Voltronic Power" "ups" "2" "Frigate TX 1KVA" "Serial" "nutdrv_qx" "Voltronic Power" "ups" "2" "Frigate TX 1KVA" "USB" "nutdrv_qx" "Voltronic Power" "ups" "2" "Galleon 1KVA" "Serial" "nutdrv_qx" "Voltronic Power" "ups" "2" "Galleon 1KVA" "USB" "nutdrv_qx" "Voltronic Power" "ups" "2" "Galleon X9-RT LCD-1-3K" "USB" "blazer_usb" # https://github.com/networkupstools/nut/issues/1251 "Voltronic Power" "ups" "2" "Galleon X9-RT LCD-1-3K" "USB" "nutdrv_qx" # https://github.com/networkupstools/nut/issues/1251 "Voltronic Power" "ups" "2" "Imperial 1KVA" "Serial" "nutdrv_qx" "Voltronic Power" "ups" "2" "Imperial 1KVA" "USB" "nutdrv_qx" "Voltronic Power" "ups" "2" "Prosine 800" "Serial" "nutdrv_qx" "Voltronic Power" "ups" "2" "Prosine 800" "USB" "nutdrv_qx" "Voltronic Power" "ups" "2" "Vesta LED 850VA" "USB" "nutdrv_qx" "Voltronic Power" "ups" "2" "(various)" "Serial" "nutdrv_qx" "Voltronic Power" "ups" "2" "(various)" "USB" "nutdrv_qx" "WinPower" "ups" "2" "CPM-800" "" "blazer_ser" "WTI" "pdu" "1" "RPS-10" "10 outlets" "powerman-pdu (experimental)" "WTI" "pdu" "1" "NPS" "8 outlets" "powerman-pdu (experimental)" nut-2.8.1/README.adoc0000644000175000017500000006414314501607135011050 00000000000000Network UPS Tools Overview =========================== // NOTE: No blank line here, document-header include processing should kick in! //GH_MARKUP_1095//ifdef::top_srcdir[] //GH_MARKUP_1095//include::{top_srcdir}docs/asciidoc-vars.conf[] //GH_MARKUP_1095//endif::top_srcdir[] //GH_MARKUP_1095//ifndef::top_srcdir[] //GH_MARKUP_1095//include::docs/asciidoc-vars.conf[] //GH_MARKUP_1095//endif::top_srcdir[] //GH_MARKUP_1095_INCLUDE_BEGIN//7c5e90132 (2023-09-13) docs/asciidoc-vars.conf: fence against re-definitions of website-url and (top_)(src|build)dir attributes ifndef::asciidoc-vars-nut-included[] :asciidoc-vars-nut-included: true // NOTE: The big block of comments and definitions below comes from // NUT::docs/asciidoc-vars.conf and is included into top-level document // sources by maintenance recipes directly (`make maintainer-asciidocs`), // due to current limitations of the GitHub Web UI asciidoc renderer. // Hopefully it can be dropped in favor of compact include definitions // (see README.adoc for anticipated example) after this issue is resolved // on their side: // * https://github.com/github/markup/issues/1095 // // This file should be included into NUT documentation sources to consistently // define certain expandable attributes, with contents defined based on the // rendition target (e.g. GitHub Web UI, plain text, locally built HTML/PDF...) // Note that currently GitHub Web UI references lead to nut-website (as of // last built and published revision), not to neighboring documents in the // source browser (which would make sense for branch revisions, etc.) due // to certain complexity about referencing other-document sections with a // partially functional rendering engine there. Exploration and fixes are // welcome (actually working links like // https://github.com/networkupstools/nut/tree/master#installing or // https://github.com/networkupstools/nut/blob/master/UPGRADING.adoc#changes-from-274-to-280 // do seem promising)! // // Since the GitHub UI does not allow use of custom asciidoc configuration // files, or generally does not process the `include:` requests at this time, // clumsy expandable attributes had to be used (usually a set including a // prefix with meaningful name, and one or more separators and/or a suffix // with shortened names). For our classic documentation renditions, they // should resolve to properly defined macros from `docs/asciidoc.conf` // (usually named same as the variables defined here, for simplicity): // * `linkdoc` allows to refer to a file under `docs/` directory (or // its nut-website rendition). // * `xref` substitutes the asciidoc shorthand '<< >>' syntax with // attributes that conditionally expand to: // - links on GitHub (references can point at most to a section of // level docs/common.xsl's ), or // - xref asciidoc macros when generating docs. // * `linksingledoc` guarantees that, when chunked HTML is generated, // the link always points to a non-chunked file. // * `linkman2` allows to support different names for the manpage and // the command shown. This is also needed to properly display links // to manpages in both GitHub and generated docs without defining an // attribute for each manpage. // // Optional attributes set by callers: // * `website-url` (defaulted below) may be used for "historic website" // snapshot builds... hopefully // * `website` is used as a boolean toggle in our recipes for nut-website // vs. offline documentation renditions // * `env-github` is used as a boolean toggle, set by GitHub Web-UI renderer // * `(top_)srcdir` and `(top_)builddir` can be set by `Makefile.am` // calling the `a2x` tool, since some of the files with the asciidoc // mark-up are only generated or post-processed during build and // (due to `make dist` restrictions) being build products, they may // not reside in same directory as static source text files which // reference or include them. Note that the non-`top` paths would // normally differ based on location of the `Makefile` involved // (e.g. workspace root, or the `docs`, or `docs/man` directories). // These variables are expected to be absolute paths, or ones relative // to asciidoc-selected `:base_dir`, and to end with a relevant path // separator, or be empty -- so in all cases letting the resulting // string resolve meaningfully in the filesystem during docs build. // // Please keep the remaining comments and definitions as one big block // so it does not become a series of empty paragraphs in the rendered // documents! // ifndef::website-url[] :website-url: https://www.networkupstools.org/ endif::website-url[] // ifndef::srcdir[] :srcdir: endif::srcdir[] // ifndef::builddir[] :builddir: endif::builddir[] // ifndef::top_srcdir[] :top_srcdir: endif::top_srcdir[] // ifndef::top_builddir[] :top_builddir: endif::top_builddir[] // // // Address links on GitHub vs docs // (note: 'env-github' attribute is set on GitHub) // // - when generating docs: ifndef::env-github[] // * xref -> xref // syntax: {xref}{x-s}[] // -> xref:[] :xref: xref: :x-s: // * link to doc -> our macro // syntax: {linkdoc}{ld-s}[] // -> linkdoc:[] :linkdoc: linkdoc: :ld-s: // * link to single doc -> our macro // syntax: {linksingledoc}{lsd-s}[] // -> linksingledoc:[] :linksingledoc: linksingledoc: :lsd-s: // * link to manpage -> our macro // syntax: {linkman2}{lm-s}{lm-c}{lm-e} // -> linkman2:[,] :linkman2: linkman2: :lm-s: [ :lm-c: , :lm-e: ] endif::env-github[] // // - on GitHub: ifdef::env-github[] // * xref -> link // syntax: {xref}{x-s}[] // In order for it to work, can reference at most a section of // level docs/common.xsl's // -> {website-url}docs/user-manual.chunked/.html[] :xref: {website-url}docs/user-manual.chunked/ :x-s: .html // * link to doc -> link // syntax: {linkdoc}{ld-s}[] // -> {website-url}docs/.chunked/index.html[] :linkdoc: {website-url}docs/ :ld-s: .chunked/index.html // * link to single doc -> link // syntax: {linksingledoc}{lsd-s}[] // -> {website-url}docs/.html[] :linksingledoc: {website-url}docs/ :lsd-s: .html // * link to manpage -> link // syntax: {linkman2}{lm-s}{lm-c}{lm-e} // All the fields are mandatory. // -> {website-url}docs/man/.html[()] :linkman2: {website-url}docs/man/ :lm-s: .html[ :lm-c: ( :lm-e: )] endif::env-github[] endif::asciidoc-vars-nut-included[] // //GH_MARKUP_1095_INCLUDE_END// Description ----------- Network UPS Tools is a collection of programs which provide a common interface for monitoring and administering UPS, PDU and SCD hardware. It uses a layered approach to connect all of the parts. Drivers are provided for a wide assortment of equipment. They understand the specific language of each device and map it back to a compatibility layer. This means both an expensive high end UPS, a simple "power strip" PDU, or any other power device can be handled transparently with a uniform management interface. This information is cached by the network server `upsd`, which then answers queries from the clients. upsd contains a number of access control features to limit the abilities of the clients. Only authorized hosts may monitor or control your hardware if you wish. Since the notion of monitoring over the network is built into the software, you can hang many systems off one large UPS, and they will all shut down together. You can also use NUT to power on, off or cycle your data center nodes, individually or globally through PDU outlets. Clients such as `upsmon` check on the status of the hardware and do things when necessary. The most important task is shutting down the operating system cleanly before the UPS runs out of power. Other programs are also provided to log information regularly, monitor status through your web browser, and more. Installing ---------- If you are installing these programs for the first time, go read the {xref}_installation_instructions{x-s}[installation instructions] to find out how to do that. This document contains more information on what all of this stuff does. Upgrading --------- When upgrading from an older version, always check the {xref}Upgrading_notes{x-s}[upgrading notes] to see what may have changed. Compatibility issues and other changes will be listed there to ease the process. Configuring and using --------------------- Once NUT is installed, refer to the {xref}Configuration_notes{x-s}[configuration notes] for directions. Documentation ------------- This is just an overview of the software. You should read the man pages, included example configuration files, and auxiliary documentation for the parts that you intend to use. Network Information ------------------- These programs are designed to share information over the network. In the examples below, `localhost` is used as the hostname. This can also be an IP address or a fully qualified domain name. You can specify a port number if your upsd process runs on another port. In the case of the program `upsc`, to view the variables on the UPS called sparky on the `upsd` server running on the local machine, you'd do this: /usr/local/ups/bin/upsc sparky@localhost The default port number is 3493. You can change this with "configure --with-port" at compile-time. To make a client talk to upsd on a specific port, add it after the hostname with a colon, like this: /usr/local/ups/bin/upsc sparky@localhost:1234 This is handy when you have a mixed environment and some of the systems are on different ports. The general form for UPS identifiers is this: [@[:]] Keep this in mind when viewing the examples below. Manifest -------- This package is broken down into several categories: - *drivers* - These programs talk directly to your UPS hardware. - *server* - upsd serves data from the drivers to the network. - *clients* - They talk to upsd and do things with the status data. - *cgi-bin* - Special class of clients that you can use with your web server. - *scripts* - Contains various scripts, like the Perl and Python binding, integration bits and applications. Drivers ------- These programs provide support for specific UPS models. They understand the protocols and port specifications which define status information and convert it to a form that upsd can understand. To configure drivers, edit ups.conf. For this example, we'll have a UPS called "sparky" that uses the apcsmart driver and is connected to `/dev/ttyS1`. That's the second serial port on most Linux-based systems. The entry in `ups.conf` looks like this: [sparky] driver = apcsmart port = /dev/ttyS1 To start and stop drivers, use upsdrvctl of upsdrvsvcctl (installed on operating systems with a service management framework supported by NUT). By default, it will start or stop every UPS in the config file: /usr/local/ups/sbin/upsdrvctl start /usr/local/ups/sbin/upsdrvctl stop However, you can also just start or stop one by adding its name: /usr/local/ups/sbin/upsdrvctl start sparky /usr/local/ups/sbin/upsdrvctl stop sparky On operating systems with a supported service management framework, you might wrap your NUT drivers into individual services instances with: /usr/local/ups/sbin/upsdrvsvcctl resync and then manage those service instances with commands like: /usr/local/ups/sbin/upsdrvsvcctl start sparky /usr/local/ups/sbin/upsdrvsvcctl stop sparky To find the driver name for your device, refer to the section below called "HARDWARE SUPPORT TABLE". Extra Settings ~~~~~~~~~~~~~~ Some drivers may require additional settings to properly communicate with your hardware. If it doesn't detect your UPS by default, check the driver's man page or help (-h) to see which options are available. For example, the usbhid-ups driver allows you to use USB serial numbers to distinguish between units via the "serial" configuration option. To use this feature, just add another line to your ups.conf section for that UPS: [sparky] driver = usbhid-ups port = auto serial = 1234567890 Hardware Compatibility List ~~~~~~~~~~~~~~~~~~~~~~~~~~~ The {xref}HCL{x-s}[Hardware Compatibility List] is available in the source directory ('nut-X.Y.Z/data/driver.list'), and is generally distributed with packages. For example, it is available on Debian systems as: /usr/share/nut/driver.list This table is also available link:{website-url}stable-hcl.html[online]. If your driver has vanished, see the {linksingledoc}FAQ{lsd-s}[FAQ] and {xref}Upgrading_notes{x-s}[Upgrading notes]. Generic Device Drivers ~~~~~~~~~~~~~~~~~~~~~~ NUT provides several generic drivers that support a variety of very similar models. - The `genericups` driver supports many serial models that use the same basic principle to communicate with the computer. This is known as "contact closure", and basically involves raising or lowering signals to indicate power status. + This type of UPS tends to be cheaper, and only provides the very simplest data about power and battery status. Advanced features like battery charge readings and such require a "smart" UPS and a driver which supports it. + See the {linkman2}genericups{lm-s}genericups{lm-c}8{lm-e} man page for more information. - The `usbhid-ups` driver attempts to communicate with USB HID Power Device Class (PDC) UPSes. These units generally implement the same basic protocol, with minor variations in the exact set of supported attributes. This driver also applies several correction factors when the UPS firmware reports values with incorrect scale factors. + See the {linkman2}usbhid-ups{lm-s}usbhid-ups{lm-c}8{lm-e} man page for more information. - The `nutdrv_qx` driver supports the Megatec / Q1 protocol that is used in many brands (Blazer, Energy Sistem, Fenton Technologies, Mustek, Voltronic Power and many others). + See the {linkman2}nutdrv_qx{lm-s}nutdrv_qx{lm-c}8{lm-e} man page for more information. - The `snmp-ups` driver handles various SNMP enabled devices, from many different manufacturers. In SNMP terms, `snmp-ups` is a manager, that monitors SNMP agents. + See the {linkman2}snmp-ups{lm-s}snmp-ups{lm-c}8{lm-e} man page for more information. - The `powerman-pdu` is a bridge to the PowerMan daemon, thus handling all PowerMan supported devices. The PowerMan project supports several serial and networked PDU, along with Blade and IPMI enabled servers. + See the {linkman2}powerman-pdu{lm-s}powerman-pdu{lm-c}8{lm-e} man page for more information. - The `apcupsd-ups` driver is a bridge to the Apcupsd daemon, thus handling all Apcupsd supported devices. The Apcupsd project supports many serial, USB and networked APC UPS. + See the {linkman2}apcupsd-ups{lm-s}apcupsd-ups{lm-c}8{lm-e} man page for more information. UPS Shutdowns ~~~~~~~~~~~~~ upsdrvctl can also shut down (power down) all of your UPS hardware. WARNING: if you play around with this command, expect your filesystems to die. Don't power off your computers unless they're ready for it: /usr/local/ups/sbin/upsdrvctl shutdown /usr/local/ups/sbin/upsdrvctl shutdown sparky You should read the {xref}UPS_shutdown{x-s}[Configuring automatic UPS shutdowns] chapter to learn more about when to use this feature. If called at the wrong time, you may cause data loss by turning off a system with a filesystem mounted read-write. Power distribution unit management ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ NUT also provides an advanced support for power distribution units. You should read the {xref}outlet_management{x-s}[NUT outlets management and PDU notes] chapter to learn more about when to use this feature. Network Server -------------- `upsd` is responsible for passing data from the drivers to the client programs via the network. It should be run immediately after `upsdrvctl` in your system's startup scripts. `upsd` should be kept running whenever possible, as it is the only source of status information for the monitoring clients like `upsmon`. Monitoring client ----------------- `upsmon` provides the essential feature that you expect to find in UPS monitoring software: safe shutdowns when the power fails. In the layered scheme of NUT software, it is a client. It has this separate section in the documentation since it is so important. You configure it by telling it about UPSes that you want to monitor in upsmon.conf. Each UPS can be defined as one of two possible types: a "primary" or "secondary". Primary ~~~~~~~ The monitored UPS possibly supplies power to this system running `upsmon`, but more importantly -- this system can manage the UPS (typically, this instance of `upsmon` runs on the same system as the `upsd` and driver(s)): it is capable and responsible for shutting it down when the battery is depleted (or in another approach, lingering to deplete it or to tell the UPS to reboot its load after too much time has elapsed and this system is still alive -- meaning wall power returned at a "wrong" moment). The shutdown of this (primary) system itself, as well as eventually an UPS shutdown, occurs after any secondary systems ordered to shut down first have disconnected, or a critical urgency threshold was passed. If your UPS is plugged directly into a system's serial or USB port, the `upsmon` process on that system should define its relation to that UPS as a primary. It may be more complicated for higher-end UPSes with a shared network management capability (typically via SNMP) or several serial/USB ports that can be used simultaneously, and depends on what vendors and drivers implement. Setups with several competing primaries (for redundancy) are technically possible, if each one runs its own full stack of NUT, but results can be random (currently NUT does not provide a way to coordinate several entities managing the same device). For a typical home user, there's one computer connected to one UPS. That means you would run on the same computer the whole NUT stack -- a suitable driver, `upsd`, and `upsmon` in primary mode. Secondary ~~~~~~~~~ The monitored UPS may supply power to the system running `upsmon` (or alternatively, it may be a monitoring station with zero PSUs fed by that UPS), but more importantly, this system can't manage the UPS -- e.g. shut it down directly (through a locally running NUT driver). Use this mode when you run multiple computers on the same UPS. Obviously, only one can be connected to the serial or USB port on a typical UPS, and that system is the primary. Everything else is a secondary. For a typical home user, there's one computer connected to one UPS. That means you run a driver, `upsd`, and `upsmon` in primary mode. Additional Information ~~~~~~~~~~~~~~~~~~~~~~ More information on configuring upsmon can be found in these places: - The {linkman2}upsmon{lm-s}upsmon{lm-c}8{lm-e} man page - {xref}BigServers{x-s}[Typical setups for big servers] - {xref}UPS_shutdown{x-s}[Configuring automatic UPS shutdowns] chapter - The stock `upsmon.conf` that comes with the package Clients ------- Clients talk to upsd over the network and do useful things with the data from the drivers. There are tools for command line access, and a few special clients which can be run through your web server as CGI programs. For more details on specific programs, refer to their man pages. upsc ~~~~ `upsc` is a simple client that will display the values of variables known to `upsd` and your UPS drivers. It will list every variable by default, or just one if you specify an additional argument. This can be useful in shell scripts for monitoring something without writing your own network code. `upsc` is a quick way to find out if your driver(s) and upsd are working together properly. Just run `upsc ` to see what's going on, i.e.: morbo:~$ upsc sparky@localhost ambient.humidity: 035.6 ambient.humidity.alarm.maximum: NO,NO ambient.humidity.alarm.minimum: NO,NO ambient.temperature: 25.14 ... If you are interested in writing a simple client that monitors `upsd`, the source code for `upsc` is a good way to learn about using the upsclient functions. See the {linkman2}upsc{lm-s}upsc{lm-c}8{lm-e} man page and {xref}nut-names{x-s}[NUT command and variable naming scheme] for more information. upslog ~~~~~~ `upslog` will write status information from `upsd` to a file at set intervals. You can use this to generate graphs or reports with other programs such as `gnuplot`. upsrw ~~~~~ `upsrw` allows you to display and change the read/write variables in your UPS hardware. Not all devices or drivers implement this, so this may not have any effect on your system. A driver that supports read/write variables will give results like this: $ upsrw sparky@localhost ( many skipped ) [ups.test.interval] Interval between self tests Type: ENUM Option: "1209600" Option: "604800" SELECTED Option: "0" ( more skipped ) On the other hand, one that doesn't support them won't print anything: $ upsrw fenton@gearbox ( nothing ) `upsrw` requires administrator powers to change settings in the hardware. Refer to {linkman2}upsd.users{lm-s}upsd.users{lm-c}5{lm-e} for information on defining users in `upsd`. upscmd ~~~~~~ Some UPS hardware and drivers support the notion of an instant command - a feature such as starting a battery test, or powering off the load. You can use upscmd to list or invoke instant commands if your hardware/drivers support them. Use the -l command to list them, like this: $ upscmd -l sparky@localhost Instant commands supported on UPS [sparky@localhost]: load.on - Turn on the load immediately test.panel.start - Start testing the UPS panel calibrate.start - Start run time calibration calibrate.stop - Stop run time calibration ... `upscmd` requires administrator powers to start instant commands. To define users and passwords in `upsd`, see {linkman2}upsd.users{lm-s}upsd.users{lm-c}5{lm-e}. CGI Programs ------------ The CGI programs are clients that run through your web server. They allow you to see UPS status and perform certain administrative commands from any web browser. Javascript and cookies are not required. These programs are not installed or compiled by default. To compile and install them, first run `configure --with-cgi`, then do `make` and `make install`. If you receive errors about "gd" during configure, go get it and install it before continuing. You can get the source here: - http://www.libgd.org/ In the event that you need libpng or zlib in order to compile gd, they can be found at these URLs: - http://www.libpng.org/pub/png/pngcode.html - http://www.zlib.net/ Access Restrictions ~~~~~~~~~~~~~~~~~~~ The CGI programs use hosts.conf to see if they are allowed to talk to a host. This keeps malicious visitors from creating queries from your web server to random hosts on the Internet. If you get error messages that say "Access to that host is not authorized", you're probably missing an entry in your hosts.conf. upsstats ~~~~~~~~ `upsstats` generates web pages from HTML templates, and plugs in status information in the right places. It looks like a distant relative of APC's old Powerchute interface. You can use it to monitor several systems or just focus on one. It also can generate IMG references to `upsimage`. upsimage ~~~~~~~~ This is usually called by upsstats via IMG SRC tags to draw either the utility or outgoing voltage, battery charge percent, or load percent. upsset ~~~~~~ `upsset` provides several useful administration functions through a web interface. You can use `upsset` to kick off instant commands on your UPS hardware like running a battery test. You can also use it to change variables in your UPS that accept user-specified values. Essentially, `upsset` provides the functions of `upsrw` and `upscmd`, but with a happy pointy-clicky interface. `upsset` will not run until you convince it that you have secured your system. You *must* secure your CGI path so that random interlopers can't run this program remotely. See the `upsset.conf` file. Once you have secured the directory, you can enable this program in that configuration file. It is not active by default. Version Numbering ----------------- The version numbers work like this: if the middle number is odd, it's a development tree, otherwise it is the stable tree. The past stable trees were 1.0, 1.2, 1.4, 2.0, 2.2 and 2.4, with the latest such stable tree designated 2.6. The development trees were 1.1, 1.3, 1.5, 2.1 and 2.3. Since the 2.4 release, there is no real separate development branch anymore since the code is available through a revision control system (namely, Git -- or actually Subversion back then) and its snapshots become published releases. Since 2.7 line of releases, sources are tracked in Git revision control system, with the project ecosystem being hosted on GitHub, and any code improvements or other contributions merged through common pull request approach and custom NUT CI testing on multiple platforms. Major release jumps are mostly due to large changes to the features list. There have also been a number of architectural changes which may not be noticeable to most users, but which can impact developers. Backwards and Forwards Compatibility ------------------------------------ The network protocol for the current version of NUT should be backwards-compatible all the way back to version 1.4. A newer client should fail gracefully when querying an older server. If you need more details about cross-compatibility of older NUT releases (1.x vs. 2.x), please see the {xref}Project_History{x-s}[Project history] chapter. Support / Help / etc. --------------------- If you are in need of help, refer to the {xref}Support_Request{x-s}[Support instructions] in the user manual. Hacking / Development Info -------------------------- Additional documentation can be found in: - the {linkdoc}developer-guide{ld-s}[Developer Guide], - the {linkdoc}packager-guide{ld-s}[Packager Guide]. Acknowledgements / Contributions -------------------------------- The many people who have participated in creating and improving NUT are listed in the user manual {xref}Acknowledgements{x-s}[acknowledgements appendix]. nut-2.8.1/test-driver0000755000175000017500000001141714517510736011464 00000000000000#! /bin/sh # test-driver - basic testsuite driver script. scriptversion=2018-03-07.03; # UTC # Copyright (C) 2011-2021 Free Software Foundation, Inc. # # 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 2, 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 . # As a special exception to the GNU General Public License, if you # distribute this file as part of a program that contains a # configuration script generated by Autoconf, you may include it under # the same distribution terms that you use for the rest of that program. # This file is maintained in Automake, please report # bugs to or send patches to # . # Make unconditional expansion of undefined variables an error. This # helps a lot in preventing typo-related bugs. set -u usage_error () { echo "$0: $*" >&2 print_usage >&2 exit 2 } print_usage () { cat <"$log_file" "$@" >>"$log_file" 2>&1 estatus=$? if test $enable_hard_errors = no && test $estatus -eq 99; then tweaked_estatus=1 else tweaked_estatus=$estatus fi case $tweaked_estatus:$expect_failure in 0:yes) col=$red res=XPASS recheck=yes gcopy=yes;; 0:*) col=$grn res=PASS recheck=no gcopy=no;; 77:*) col=$blu res=SKIP recheck=no gcopy=yes;; 99:*) col=$mgn res=ERROR recheck=yes gcopy=yes;; *:yes) col=$lgn res=XFAIL recheck=no gcopy=yes;; *:*) col=$red res=FAIL recheck=yes gcopy=yes;; esac # Report the test outcome and exit status in the logs, so that one can # know whether the test passed or failed simply by looking at the '.log' # file, without the need of also peaking into the corresponding '.trs' # file (automake bug#11814). echo "$res $test_name (exit status: $estatus)" >>"$log_file" # Report outcome to console. echo "${col}${res}${std}: $test_name" # Register the test result, and other relevant metadata. echo ":test-result: $res" > $trs_file echo ":global-test-result: $res" >> $trs_file echo ":recheck: $recheck" >> $trs_file echo ":copy-in-global-log: $gcopy" >> $trs_file # Local Variables: # mode: shell-script # sh-indentation: 2 # eval: (add-hook 'before-save-hook 'time-stamp) # time-stamp-start: "scriptversion=" # time-stamp-format: "%:y-%02m-%02d.%02H" # time-stamp-time-zone: "UTC0" # time-stamp-end: "; # UTC" # End: nut-2.8.1/include/0000755000175000017500000000000014520277775010774 500000000000000nut-2.8.1/include/wincompat.h0000644000175000017500000002354614513167372013071 00000000000000#ifndef NUT_WINCOMPAT_H #define NUT_WINCOMPAT_H 1 /* Copyright (C) 2001 Andrew Delpha (delpha@computer.org) 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 2 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, WRITE to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ /* This header is provided to map Windows system calls to be compatible with the NUT code. */ #include "common.h" #include /* This value is defined in the error.h file of the libusb-win32 sources * FIXME: Should only be relevant for builds WITH_LIBUSB_0_1 - #ifdef it so? * Conflicts with e.g. /msys64/mingw64/include/errno.h which defines it as 138 */ #ifndef ETIMEDOUT # define ETIMEDOUT 116 #endif #define random() rand() typedef const char * uid_t; struct passwd { const char *pw_name; int pw_uid; /* Fake value, alwaus set to 0 */ }; uid_t getuid(void); struct passwd *getpwuid(uid_t uid); char *getpass( const char *prompt); #define system(a) win_system(a) #define sleep(n) Sleep(1000 * n) char * strtok_r(char *str, const char *delim, char **saveptr); char * filter_path(const char * source); /* Network compatibility */ /* This is conditional because read/write are generic in unix, and this will make them network specific */ #ifdef W32_NETWORK_CALL_OVERRIDE #define close(h) sktclose(h) #define read(h,b,s) sktread(h,b,s) #define write(h,b,s) sktwrite( h ,(char *) b , s ) #define connect(h,n,l) sktconnect(h,n,l) #endif #ifndef strcasecmp #define strcasecmp(a,b) _stricmp(a,b) #endif #ifndef snprintf #define snprintf _snprintf #endif #ifndef vsnprintf #define vsnprintf _vsnprintf #endif int sktconnect(int fh, struct sockaddr * name, int len); int sktread(int fh, char *buf, int size); int sktwrite(int fh, char *buf, int size); int sktclose(int fh); #if ! HAVE_INET_NTOP /* NOTE: This fallback can get used on systems that do have inet_ntop() * but their antivirus precluded the configure-script test program linking. * A symptom of that would be: * warning: 'inet_ntop' redeclared without dllimport attribute: * previous dllimport ignored [-Wattributes] * ...and adding the attributes would cause a conflict of private fallback * and system DLL symbols. So the lesser of two evils, we use fallback. * People who see the warning should however fix their build environment * and use the native OS-provided implementation ;) */ # if (0) /* Some old winapi? or just sloppy original commits? * Why is this here at all if there's something per ws2tcpip.h - * maybe should be configure-detected? */ const char* inet_ntop(int af, const void* src, char* dst, int cnt); # else const char* inet_ntop(int af, const void* src, char* dst, size_t /* socklen_t */ cnt); # endif #endif #if ! HAVE_INET_PTON int inet_pton(int af, const char *src, void *dst); #endif /* from the MSDN getaddrinfo documentation : */ #define EAI_AGAIN WSATRY_AGAIN #define EAI_BADFLAGS WSAEINVAL #define EAI_FAIL WSANO_RECOVERY #define EAI_FAMILY WSAEAFNOSUPPORT #define EAI_MEMORY WSA_NOT_ENOUGH_MEMORY #define EAI_NONAME WSAHOST_NOT_FOUND #define EAI_SERVICE WSATYPE_NOT_FOUND #define EAI_SOCKTYPE WSAESOCKTNOSUPPORT /* not from MS docs : */ #define EAI_SYSTEM WSANO_RECOVERY #ifndef EAFNOSUPPORT # define EAFNOSUPPORT WSAEAFNOSUPPORT #endif /* "system" function */ int win_system(const char * command); /* syslog compatibility */ void syslog(int priority, const char *fmt, ...); extern const char * EventLogName; /* Signal emulation via named pipe */ typedef struct pipe_conn_s { HANDLE handle; OVERLAPPED overlapped; char buf[LARGEBUF]; struct pipe_conn_s *prev; struct pipe_conn_s *next; } pipe_conn_t; extern pipe_conn_t *pipe_connhead; extern OVERLAPPED pipe_connection_overlapped; void pipe_create(const char * pipe_name); void pipe_connect(); void pipe_disconnect(pipe_conn_t *conn); int pipe_ready(pipe_conn_t *conn); int send_to_named_pipe(const char * pipe_name, const char * data); #define COMMAND_FSD "COMMAND_FSD" #define COMMAND_STOP "COMMAND_STOP" #define COMMAND_RELOAD "COMMAND_RELOAD" /* serial function compatibility */ int w32_setcomm ( serial_handler_t * h, int * flags ); int w32_getcomm ( serial_handler_t * h, int * flags ); int tcsendbreak (serial_handler_t * sh, int duration); typedef unsigned char cc_t; typedef unsigned int speed_t; typedef unsigned int tcflag_t; #define NCCS 19 struct termios { tcflag_t c_iflag; /* input mode flags */ tcflag_t c_oflag; /* output mode flags */ tcflag_t c_cflag; /* control mode flags */ tcflag_t c_lflag; /* local mode flags */ cc_t c_line; /* line discipline */ cc_t c_cc[NCCS]; /* control characters */ speed_t c_ispeed; /* input speed */ speed_t c_ospeed; /* output speed */ }; serial_handler_t * w32_serial_open (const char *name, int flags); int w32_serial_close (serial_handler_t * sh); int w32_serial_write (serial_handler_t * sh, const void *ptr, size_t len); int w32_serial_read (serial_handler_t * sh, void *ptr, size_t ulen, DWORD timeout); int tcgetattr (serial_handler_t * sh, struct termios *t); int tcsetattr (serial_handler_t * sh, int action, const struct termios *t); int tcflush (serial_handler_t * sh, int queue); #define HAVE_CFSETISPEED void cfsetispeed(struct termios * t, speed_t speed); void cfsetospeed(struct termios * t, speed_t speed); speed_t cfgetispeed(const struct termios *t); speed_t cfgetospeed(const struct termios *t); #define _POSIX_VDISABLE '\0' /* c_cc characters */ #define VINTR 0 #define VQUIT 1 #define VERASE 2 #define VKILL 3 #define VEOF 4 #define VTIME 5 #define VMIN 6 #define VSWTC 7 #define VSTART 8 #define VSTOP 9 #define VSUSP 10 #define VEOL 11 #define VREPRINT 12 #define VDISCARD 13 #define VWERASE 14 #define VLNEXT 15 #define VEOL2 16 /* c_iflag bits */ #define IGNBRK 0000001 #define BRKINT 0000002 #define IGNPAR 0000004 #define PARMRK 0000010 #define INPCK 0000020 #define ISTRIP 0000040 #define INLCR 0000100 #define IGNCR 0000200 #define ICRNL 0000400 #define IUCLC 0001000 #define IXON 0002000 #define IXANY 0004000 #define IXOFF 0010000 #define IMAXBEL 0020000 #define IUTF8 0040000 /* c_oflag bits */ #define OPOST 0000001 #define OLCUC 0000002 #define ONLCR 0000004 #define OCRNL 0000010 #define ONOCR 0000020 #define ONLRET 0000040 #define OFILL 0000100 #define OFDEL 0000200 #define NLDLY 0000400 #define NL0 0000000 #define NL1 0000400 #define CRDLY 0003000 #define CR0 0000000 #define CR1 0001000 #define CR2 0002000 #define CR3 0003000 #define TABDLY 0014000 #define TAB0 0000000 #define TAB1 0004000 #define TAB2 0010000 #define TAB3 0014000 #define XTABS 0014000 #define BSDLY 0020000 #define BS0 0000000 #define BS1 0020000 #define VTDLY 0040000 #define VT0 0000000 #define VT1 0040000 #define FFDLY 0100000 #define FF0 0000000 #define FF1 0100000 /* c_cflag bit meaning */ #define CBAUD 0010017 #define B0 0000000 /* hang up */ #define B50 0000001 #define B75 0000002 #define B110 0000003 #define B134 0000004 #define B150 0000005 #define B200 0000006 #define B300 0000007 #define B600 0000010 #define B1200 0000011 #define B1800 0000012 #define B2400 0000013 #define B4800 0000014 #define B9600 0000015 #define B19200 0000016 #define B38400 0000017 #define EXTA B19200 #define EXTB B38400 #define CSIZE 0000060 #define CS5 0000000 #define CS6 0000020 #define CS7 0000040 #define CS8 0000060 #define CSTOPB 0000100 #define CREAD 0000200 #define PARENB 0000400 #define PARODD 0001000 #define HUPCL 0002000 #define CLOCAL 0004000 #define CBAUDEX 0010000 #define BOTHER 0010000 #define B57600 0010001 #define B115200 0010002 #define B230400 0010003 #define B460800 0010004 #define B500000 0010005 #define B576000 0010006 #define B921600 0010007 #define B1000000 0010010 #define B1152000 0010011 #define B1500000 0010012 #define B2000000 0010013 #define B2500000 0010014 #define B3000000 0010015 #define B3500000 0010016 #define B4000000 0010017 #define CIBAUD 002003600000 /* input baud rate */ #define CMSPAR 010000000000 /* mark or space (stick) parity */ #define CRTSCTS 020000000000 /* flow control */ #define IBSHIFT 16 /* Shift from CBAUD to CIBAUD */ /* c_lflag bits */ #define ISIG 0000001 #define ICANON 0000002 #define XCASE 0000004 #define ECHO 0000010 #define ECHOE 0000020 #define ECHOK 0000040 #define ECHONL 0000100 #define NOFLSH 0000200 #define TOSTOP 0000400 #define ECHOCTL 0001000 #define ECHOPRT 0002000 #define ECHOKE 0004000 #define FLUSHO 0010000 #define PENDIN 0040000 #define IEXTEN 0100000 /* tcflow() and TCXONC use these */ #define TCOOFF 0 #define TCOON 1 #define TCIOFF 2 #define TCION 3 /* tcflush() and TCFLSH use these */ #define TCIFLUSH 0 #define TCOFLUSH 1 #define TCIOFLUSH 2 /* tcsetattr uses these */ #define TCSANOW 0 #define TCSADRAIN 1 #define TCSAFLUSH 2 #define TIOCM_DTR 0x0001 #define TIOCM_RTS 0x0002 #define TIOCM_ST 0x0004 #define TIOCM_CTS MS_CTS_ON /* 0x0010*/ #define TIOCM_DSR MS_DSR_ON /* 0x0020*/ #define TIOCM_RNG MS_RING_ON /*0x0040*/ #define TIOCM_RI TIOCM_RNG /* at least that's the definition in Linux */ #define TIOCM_CD MS_RLSD_ON /*0x0080*/ #if !defined(PATH_MAX) && defined(MAX_PATH) /* PATH_MAX is the POSIX equivalent for Microsoft's MAX_PATH * both should be defined in (mingw) limits.h */ # define PATH_MAX MAX_PATH #endif #endif /* NUT_WINCOMPAT_H */ nut-2.8.1/include/timehead.h0000644000175000017500000000444014501607135012631 00000000000000/* timehead.h - from the autoconf docs: sanely include the right time headers everywhere Copyright (C) 2001 Russell Kroll 2005 Arnaud Quette 2020 Jim Klimov 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 2 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, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef NUT_TIMEHEAD_H_SEEN #define NUT_TIMEHEAD_H_SEEN 1 #ifdef __cplusplus /* *INDENT-OFF* */ extern "C" { /* *INDENT-ON* */ #endif #ifdef TIME_WITH_SYS_TIME # include # include #else # ifdef HAVE_SYS_TIME_H # include # else # include # endif #endif #ifndef HAVE_STRPTIME /* Use fallback implementation provided in e.g. libcommon(client).la: */ char * strptime(const char *buf, const char *fmt, struct tm *tm); #endif #ifndef HAVE_LOCALTIME_R # ifdef HAVE_LOCALTIME_S /* A bit of a silly trick, but should help on MSYS2 builds it seems */ # define localtime_r(timer, buf) localtime_s(timer, buf) # else # include /* memcpy */ static inline struct tm *localtime_r( const time_t *timer, struct tm *buf ) { /* Note: not thread-safe per se! */ struct tm *tmp = localtime (timer); memcpy(buf, tmp, sizeof(struct tm)); return buf; } # endif #endif #ifndef HAVE_GMTIME_R # ifdef HAVE_GMTIME_S # define gmtime_r(timer, buf) gmtime_s(timer, buf) # else # include /* memcpy */ static inline struct tm *gmtime_r( const time_t *timer, struct tm *buf ) { /* Note: not thread-safe per se! */ struct tm *tmp = gmtime (timer); memcpy(buf, tmp, sizeof(struct tm)); return buf; } # endif #endif #ifdef __cplusplus /* *INDENT-OFF* */ } /* *INDENT-ON* */ #endif #endif /* NUT_TIMEHEAD_H_SEEN */ nut-2.8.1/include/nut_platform.h0000644000175000017500000000701614500336654013571 00000000000000/** * \brief Platform-specific checks * * The header performs checks to resolve the actual build platform. * It defines macra that may be later used to produce platform-tailored * code. * * Be careful when writing platform-specific code; avoid that if possible. * * References: * http://nadeausoftware.com/articles/2012/01/c_c_tip_how_use_compiler_predefined_macros_detect_operating_system * * \author Vaclav Krpec * \date 2012/10/12 */ #ifndef NUT_PLATFORM_H_SEEN #define NUT_PLATFORM_H_SEEN 1 /* * In case doxygen source doc isn't generated * (which is the case at time of writing this), * just check the doxygen-documented (i.e. "**" * prefixed) NUT_PLATFORM_* macra, below. */ /* Apple Mac OS X, iOS and Darwin */ #if (defined __APPLE__ && defined __MACH__) /** Apple OS based on Mach ukernel */ #define NUT_PLATFORM_APPLE_MACH #include #if (defined TARGET_OS_EMBEDDED) /** iOS (implies \ref NUT_PLATFORM_APPLE_MACH) */ #define NUT_PLATFORM_APPLE_IOS #endif #if (defined TARGET_IPHONE_SIMULATOR) /** iOS simulator (implies \ref NUT_PLATFORM_APPLE_MACH) */ #define NUT_PLATFORM_APPLE_IOS_SIMULATOR #endif #if (defined TARGET_OS_IPHONE) /** iPhone (implies \ref NUT_PLATFORM_APPLE_MACH) */ #define NUT_PLATFORM_APPLE_IPHONE #endif #if (defined TARGET_OS_MAC) /** Mac OS X (implies \ref NUT_PLATFORM_APPLE_MACH) */ #define NUT_PLATFORM_APPLE_OSX #endif #endif /* * GCC AIX issue: __unix__ nor __unix are not defined in older GCC * Addressed in GCC 4.7.0, see * http://gcc.gnu.org/bugzilla/show_bug.cgi?id=39950 * Remove if no longer necessary */ #if (defined _AIX && !defined __unix__) #define __unix__ #endif /* Microsoft Windows */ #if (defined _WIN32 || defined _WIN64) /** Windows */ #define NUT_PLATFORM_MS_WINDOWS #if (defined NTDDI_WIN8 && NTDDI_VERSION >= NTDDI_WIN8) /** Windows 8 */ #define NUT_PLATFORM_MS_WINDOWS8 #endif /* UNIX */ /* Note that Apple OSX doesn't define __unix__ nor __unix; are they ashamed or something? */ #elif (defined __unix__ || defined __unix || defined NUT_PLATFORM_APPLE_MACH) #include #include /** UNIX */ #define NUT_PLATFORM_UNIX #if (defined _POSIX_VERSION) /** POSIX (implies \ref NUT_PLATFORM_UNIX), expands to POSIX version */ #define NUT_PLATFORM_POSIX _POSIX_VERSION #endif #if (defined __linux__) /** Linux (implies \ref NUT_PLATFORM_UNIX) */ #define NUT_PLATFORM_LINUX #endif #if (defined __sun && defined __SVR4) /** Solaris (implies \ref NUT_PLATFORM_UNIX) */ #define NUT_PLATFORM_SOLARIS #endif #if (defined __hpux) /** Hewlett-Packard HP-UX (implies \ref NUT_PLATFORM_UNIX) */ #define NUT_PLATFORM_HPUX #endif #if (defined _AIX) /** AIX (implies \ref NUT_PLATFORM_UNIX) */ #define NUT_PLATFORM_AIX #endif /* Note that BSD is defined in sys/param.h */ #if (defined BSD) /** BSD (implies \ref NUT_PLATFORM_UNIX) */ #define NUT_PLATFORM_BSD #if (defined __DragonFly__) /** DragonFly (implies \ref NUT_PLATFORM_UNIX, \ref NUT_PLATFORM_BSD) */ #define NUT_PLATFORM_DRAGONFLY #elif (defined __FreeBSD__) /** FreeBSD (implies \ref NUT_PLATFORM_UNIX, \ref NUT_PLATFORM_BSD) */ #define NUT_PLATFORM_FREEBSD #elif (defined __OpenBSD__) /** OpenBSD (implies \ref NUT_PLATFORM_UNIX, \ref NUT_PLATFORM_BSD) */ #define NUT_PLATFORM_OPENBSD #elif (defined __NetBSD__) /** NetBSD (implies \ref NUT_PLATFORM_UNIX, \ref NUT_PLATFORM_BSD) */ #define NUT_PLATFORM_NETBSD #endif #endif #endif #endif /* NUT_PLATFORM_H_SEEN */ nut-2.8.1/include/str.h0000644000175000017500000001534214514200703011656 00000000000000/* str.h - Common string-related functions * * Copyright (C) * 2000 Russell Kroll * 2015 Daniele Pezzini * * 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 2 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, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #ifndef NUT_STR_H_SEEN #define NUT_STR_H_SEEN 1 #ifdef __cplusplus /* *INDENT-OFF* */ extern "C" { /* *INDENT-ON* */ #endif /* Some compilers and/or C libraries do not handle printf("%s", NULL) correctly */ #ifndef NUT_STRARG # if (defined REQUIRE_NUT_STRARG) && (REQUIRE_NUT_STRARG == 0) # define NUT_STRARG(x) x # else /* Is required, or not defined => err on safe side */ # define NUT_STRARG(x) (x?x:"(null)") # endif #endif /* Remove all * - leading and trailing (str_trim[_m]()) * - leading (str_ltrim[_m]()) * - trailing (str_rtrim[_m])) * instances of * - *character* (plain versions) * - each character in *characters* ('_m' versions) * from a string. * - *string*: null-terminated byte string from which characters are to be removed; * - *character*: character that has to be removed from *string*; * - *characters*: null-terminated byte string of characters to be removed from string. * Return: * - NULL, if *string* is NULL, otherwise * - *string* without the specified characters (upto an empty string). */ char *str_trim(char *string, const char character); char *str_trim_m(char *string, const char *characters); char *str_ltrim(char *string, const char character); char *str_ltrim_m(char *string, const char *characters); char *str_rtrim(char *string, const char character); char *str_rtrim_m(char *string, const char *characters); /* Remove all * - leading and trailing (str_trim_space()) * - leading (str_ltrim_space()) * - trailing (str_rtrim_space()) * spaces (as identified by isspace()) from a string. * - *string*: null-terminated byte string from which spaces are to be removed. * Return: * - NULL, if *string* is NULL, otherwise * - *string* without the specified spaces (upto an empty string). */ char *str_trim_space(char *string); char *str_ltrim_space(char *string); char *str_rtrim_space(char *string); /* Tell whether a string can be converted to a number of type str_is_[_strict](). * - *string*: the null-terminated byte string to check; * - *base*: the base the string must conform to. * The same restrictions of the corresponding str_to_[_strict]() functions apply. * If *string* can be converted to a valid number of type , return 1. * Otherwise, return 0 with errno set to: * - ENOMEM, if available memory is insufficient; * - EINVAL, if the value of *base* is not supported or no conversion could be performed; * - ERANGE, if the converted value would be out of the acceptable range of . */ int str_is_short(const char *string, const int base); int str_is_short_strict(const char *string, const int base); int str_is_ushort(const char *string, const int base); int str_is_ushort_strict(const char *string, const int base); int str_is_int(const char *string, const int base); int str_is_int_strict(const char *string, const int base); int str_is_uint(const char *string, const int base); int str_is_uint_strict(const char *string, const int base); int str_is_long(const char *string, const int base); int str_is_long_strict(const char *string, const int base); int str_is_ulong(const char *string, const int base); int str_is_ulong_strict(const char *string, const int base); int str_is_double(const char *string, const int base); int str_is_double_strict(const char *string, const int base); /* Convert a string to a number of type str_to_[_strict](). * - *string*: the null-terminated byte string to convert, * 'strict' versions' strings shall not contain spaces (as identified by isspace()), * - short, int, long: strtol()'s restrictions apply, * - ushort, uint, ulong: strtoul()'s restrictions apply, plus: * - plus ('+') and minus ('-') signs (and hence negative values) are not supported, * - double: strtod()'s restrictions apply, plus: * - infinity and nan are not supported, * - radix character (decimal point character) must be a period ('.'); * - *number*: a pointer to a that will be filled upon execution; * - *base*: the base the string must conform to, * - short, ushort, int, uint, long, ulong: acceptable values as in strtol()/strtoul(), * - double: 0 for auto-select, 10 or 16. * On success, return 1 with *number* being the result of the conversion of *string*. * On failure, return 0 with *number* being 0 and errno set to: * - ENOMEM, if available memory is insufficient; * - EINVAL, if the value of *base* is not supported or no conversion can be performed; * - ERANGE, if the converted value is out of the acceptable range of . */ int str_to_short(const char *string, short *number, const int base); int str_to_short_strict(const char *string, short *number, const int base); int str_to_ushort(const char *string, unsigned short *number, const int base); int str_to_ushort_strict(const char *string, unsigned short *number, const int base); int str_to_int(const char *string, int *number, const int base); int str_to_int_strict(const char *string, int *number, const int base); int str_to_uint(const char *string, unsigned int *number, const int base); int str_to_uint_strict(const char *string, unsigned int *number, const int base); int str_to_long(const char *string, long *number, const int base); int str_to_long_strict(const char *string, long *number, const int base); int str_to_ulong(const char *string, unsigned long *number, const int base); int str_to_ulong_strict(const char *string, unsigned long *number, const int base); int str_to_double(const char *string, double *number, const int base); int str_to_double_strict(const char *string, double *number, const int base); /* Return non-zero if string s ends exactly with suff * Note: s=NULL always fails the test; otherwise suff=NULL always matches */ int str_ends_with(const char *s, const char *suff); #ifndef HAVE_STRSEP /* Makefile should add the implem to libcommon(client).la */ char *strsep(char **stringp, const char *delim); #define HAVE_STRSEP 1 #endif #ifdef __cplusplus /* *INDENT-OFF* */ } /* *INDENT-ON* */ #endif #endif /* NUT_STR_H_SEEN */ nut-2.8.1/include/attribute.h0000644000175000017500000000461314500336654013062 00000000000000/* attribute.h - portability hacks for __attribute__ usage in other header files Copyright (C) 2001 Russell Kroll 2005 Arnaud Quette 2020 Jim Klimov 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 2 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, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef NUT_ATTRIBUTE_H_SEEN #define NUT_ATTRIBUTE_H_SEEN 1 /* To complicate matters, compilers with native support * for the keyword may expose or not expose it as a macro... * but for those that perform such courtesy, or are known * supporters, we can put up the flag. For others, someone * with those compilers should check and file PRs to NUT. */ #if (!defined HAVE___ATTRIBUTE__) || (HAVE___ATTRIBUTE__ == 0) # if ( defined(__GNUC__) && ( __GNUC__ < 2 || (__GNUC__ == 2 && __GNUC_MINOR__ < 8) ) ) || ( defined(__STRICT_ANSI__) && __STRICT_ANSI__ ) # ifndef __attribute__ # define __attribute__(x) # endif # ifndef HAVE___ATTRIBUTE__ # define HAVE___ATTRIBUTE__ 0 # endif # else # if defined(__clang__) || defined(__GNUC__) || defined(__SUNPRO_C) # ifndef HAVE___ATTRIBUTE__ # define HAVE___ATTRIBUTE__ 1 # endif # else # ifndef HAVE___ATTRIBUTE__ # define HAVE___ATTRIBUTE__ 0 # endif # endif # endif #endif #if (!defined HAVE___ATTRIBUTE__) || (HAVE___ATTRIBUTE__ == 0) # ifdef HAVE___ATTRIBUTE__UNUSED_ARG # undef HAVE___ATTRIBUTE__UNUSED_ARG # endif # ifdef HAVE___ATTRIBUTE__UNUSED_FUNC # undef HAVE___ATTRIBUTE__UNUSED_FUNC # endif # ifdef HAVE___ATTRIBUTE__NORETURN # undef HAVE___ATTRIBUTE__NORETURN # endif # ifdef HAVE___ATTRIBUTE__ # undef HAVE___ATTRIBUTE__ # endif #endif /* Other source files now can simply check for `ifdef HAVE___ATTRIBUTE__*` * as usual, and not bother about 0/1 values of the macro as well. */ #endif /* NUT_ATTRIBUTE_H_SEEN */ nut-2.8.1/include/Makefile.in0000644000175000017500000006300114520274662012751 00000000000000# Makefile.in generated by automake 1.16.5 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2021 Free Software Foundation, Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. @SET_MAKE@ VPATH = @srcdir@ am__is_gnu_make = { \ if test -z '$(MAKELEVEL)'; then \ false; \ elif test -n '$(MAKE_HOST)'; then \ true; \ elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \ true; \ else \ false; \ fi; \ } am__make_running_with_option = \ case $${target_option-} in \ ?) ;; \ *) echo "am__make_running_with_option: internal error: invalid" \ "target option '$${target_option-}' specified" >&2; \ exit 1;; \ esac; \ has_opt=no; \ sane_makeflags=$$MAKEFLAGS; \ if $(am__is_gnu_make); then \ sane_makeflags=$$MFLAGS; \ else \ case $$MAKEFLAGS in \ *\\[\ \ ]*) \ bs=\\; \ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ esac; \ fi; \ skip_next=no; \ strip_trailopt () \ { \ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ }; \ for flg in $$sane_makeflags; do \ test $$skip_next = yes && { skip_next=no; continue; }; \ case $$flg in \ *=*|--*) continue;; \ -*I) strip_trailopt 'I'; skip_next=yes;; \ -*I?*) strip_trailopt 'I';; \ -*O) strip_trailopt 'O'; skip_next=yes;; \ -*O?*) strip_trailopt 'O';; \ -*l) strip_trailopt 'l'; skip_next=yes;; \ -*l?*) strip_trailopt 'l';; \ -[dEDm]) skip_next=yes;; \ -[JT]) skip_next=yes;; \ esac; \ case $$flg in \ *$$target_option*) has_opt=yes; break;; \ esac; \ done; \ test $$has_opt = yes am__make_dryrun = (target_option=n; $(am__make_running_with_option)) am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkglibexecdir = $(libexecdir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ target_triplet = @target@ @WITH_DEV_FALSE@am__append_1 = parseconf.h subdir = include ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/m4/ax_c___attribute__.m4 \ $(top_srcdir)/m4/ax_c_pragmas.m4 \ $(top_srcdir)/m4/ax_check_compile_flag.m4 \ $(top_srcdir)/m4/ax_compare_version.m4 \ $(top_srcdir)/m4/ax_realpath.m4 \ $(top_srcdir)/m4/ax_run_or_link_ifelse.m4 \ $(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \ $(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \ $(top_srcdir)/m4/lt~obsolete.m4 \ $(top_srcdir)/m4/nut_arg_with.m4 \ $(top_srcdir)/m4/nut_check_asciidoc.m4 \ $(top_srcdir)/m4/nut_check_aspell.m4 \ $(top_srcdir)/m4/nut_check_cppcheck.m4 \ $(top_srcdir)/m4/nut_check_headers_windows.m4 \ $(top_srcdir)/m4/nut_check_libavahi.m4 \ $(top_srcdir)/m4/nut_check_libfreeipmi.m4 \ $(top_srcdir)/m4/nut_check_libgd.m4 \ $(top_srcdir)/m4/nut_check_libgpiod.m4 \ $(top_srcdir)/m4/nut_check_libltdl.m4 \ $(top_srcdir)/m4/nut_check_libmodbus.m4 \ $(top_srcdir)/m4/nut_check_libneon.m4 \ $(top_srcdir)/m4/nut_check_libnetsnmp.m4 \ $(top_srcdir)/m4/nut_check_libnss.m4 \ $(top_srcdir)/m4/nut_check_libopenssl.m4 \ $(top_srcdir)/m4/nut_check_libpowerman.m4 \ $(top_srcdir)/m4/nut_check_libregex.m4 \ $(top_srcdir)/m4/nut_check_libsystemd.m4 \ $(top_srcdir)/m4/nut_check_libusb.m4 \ $(top_srcdir)/m4/nut_check_libwrap.m4 \ $(top_srcdir)/m4/nut_check_os.m4 \ $(top_srcdir)/m4/nut_check_pkgconfig.m4 \ $(top_srcdir)/m4/nut_check_python.m4 \ $(top_srcdir)/m4/nut_check_socketlib.m4 \ $(top_srcdir)/m4/nut_compiler_family.m4 \ $(top_srcdir)/m4/nut_func_getnameinfo_argtypes.m4 \ $(top_srcdir)/m4/nut_report_feature.m4 \ $(top_srcdir)/m4/nut_stash_warnings.m4 \ $(top_srcdir)/m4/nut_type_socklen_t.m4 \ $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) DIST_COMMON = $(srcdir)/Makefile.am $(am__dist_noinst_HEADERS_DIST) \ $(am__include_HEADERS_DIST) $(am__DIST_COMMON) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = AM_V_P = $(am__v_P_@AM_V@) am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) am__v_P_0 = false am__v_P_1 = : AM_V_GEN = $(am__v_GEN_@AM_V@) am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) am__v_GEN_0 = @echo " GEN " $@; am__v_GEN_1 = AM_V_at = $(am__v_at_@AM_V@) am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) am__v_at_0 = @ am__v_at_1 = SOURCES = DIST_SOURCES = am__can_run_installinfo = \ case $$AM_UPDATE_INFO_DIR in \ n|no|NO) false;; \ *) (install-info --version) >/dev/null 2>&1;; \ esac am__dist_noinst_HEADERS_DIST = attribute.h common.h extstate.h proto.h \ state.h str.h timehead.h upsconf.h nut_float.h nut_stdint.h \ nut_platform.h wincompat.h parseconf.h am__include_HEADERS_DIST = parseconf.h am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; am__vpath_adj = case $$p in \ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ *) f=$$p;; \ esac; am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`; am__install_max = 40 am__nobase_strip_setup = \ srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'` am__nobase_strip = \ for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||" am__nobase_list = $(am__nobase_strip_setup); \ for p in $$list; do echo "$$p $$p"; done | \ sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \ $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \ if (++n[$$2] == $(am__install_max)) \ { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \ END { for (dir in files) print dir, files[dir] }' am__base_list = \ sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' am__uninstall_files_from_dir = { \ test -z "$$files" \ || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \ || { echo " ( cd '$$dir' && rm -f" $$files ")"; \ $(am__cd) "$$dir" && rm -f $$files; }; \ } am__installdirs = "$(DESTDIR)$(includedir)" HEADERS = $(dist_noinst_HEADERS) $(include_HEADERS) am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) \ config.h.in # Read a list of newline-separated strings from the standard input, # and print each of them once, without duplicates. Input order is # *not* preserved. am__uniquify_input = $(AWK) '\ BEGIN { nonempty = 0; } \ { items[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in items) print i; }; } \ ' # Make sure the list of sources is unique. This is necessary because, # e.g., the same source file might be shared among _SOURCES variables # for different programs/libraries. am__define_uniq_tagged_files = \ list='$(am__tagged_files)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | $(am__uniquify_input)` am__DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/config.h.in DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) A2X = @A2X@ ACLOCAL = @ACLOCAL@ ALTPIDPATH = @ALTPIDPATH@ AMTAR = @AMTAR@ AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ AR = @AR@ ASCIIDOC = @ASCIIDOC@ ASPELL = @ASPELL@ ASPELL_FILTER_LIB_PATH = @ASPELL_FILTER_LIB_PATH@ ASPELL_FILTER_SHARE_PATH = @ASPELL_FILTER_SHARE_PATH@ ASPELL_FILTER_TEX_PATH = @ASPELL_FILTER_TEX_PATH@ AUGPARSE = @AUGPARSE@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ BINDIR = @BINDIR@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CONFIG_FLAGS = @CONFIG_FLAGS@ CONFPATH = @CONFPATH@ CPP = @CPP@ CPPCHECK = @CPPCHECK@ CPPFLAGS = @CPPFLAGS@ CPPUNIT_CFLAGS = @CPPUNIT_CFLAGS@ CPPUNIT_LIBS = @CPPUNIT_LIBS@ CSCOPE = @CSCOPE@ CTAGS = @CTAGS@ CXX = @CXX@ CXXCPP = @CXXCPP@ CXXDEPMODE = @CXXDEPMODE@ CXXFLAGS = @CXXFLAGS@ CYGPATH_W = @CYGPATH_W@ DBLATEX = @DBLATEX@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ DEPLOYED_UPSC = @DEPLOYED_UPSC@ DEPLOYED_UPSD = @DEPLOYED_UPSD@ DLLTOOL = @DLLTOOL@ DOC_BUILD_LIST = @DOC_BUILD_LIST@ DOC_CHECK_LIST = @DOC_CHECK_LIST@ DRIVER_BUILD_LIST = @DRIVER_BUILD_LIST@ DRIVER_INSTALL_TARGET = @DRIVER_INSTALL_TARGET@ DRIVER_MAN_LIST = @DRIVER_MAN_LIST@ DRIVER_MAN_LIST_PAGES = @DRIVER_MAN_LIST_PAGES@ DRVPATH = @DRVPATH@ DSYMUTIL = @DSYMUTIL@ DUMPBIN = @DUMPBIN@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ ETAGS = @ETAGS@ EXEEXT = @EXEEXT@ FGREP = @FGREP@ FORCE_NUT_VERSION = @FORCE_NUT_VERSION@ GDLIB_CONFIG = @GDLIB_CONFIG@ GREP = @GREP@ HAVE_SYS_SOCKET_H = @HAVE_SYS_SOCKET_H@ HAVE_WINSOCK2_H = @HAVE_WINSOCK2_H@ HAVE_WS2TCPIP_H = @HAVE_WS2TCPIP_H@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ LD = @LD@ LDFLAGS = @LDFLAGS@ LIBAVAHI_CFLAGS = @LIBAVAHI_CFLAGS@ LIBAVAHI_LIBS = @LIBAVAHI_LIBS@ LIBDIR = @LIBDIR@ LIBGD_CFLAGS = @LIBGD_CFLAGS@ LIBGD_LDFLAGS = @LIBGD_LDFLAGS@ LIBGPIO_CFLAGS = @LIBGPIO_CFLAGS@ LIBGPIO_LIBS = @LIBGPIO_LIBS@ LIBI2C_LIBS = @LIBI2C_LIBS@ LIBIPMI_CFLAGS = @LIBIPMI_CFLAGS@ LIBIPMI_LIBS = @LIBIPMI_LIBS@ LIBLTDL_CFLAGS = @LIBLTDL_CFLAGS@ LIBLTDL_LIBS = @LIBLTDL_LIBS@ LIBMODBUS_CFLAGS = @LIBMODBUS_CFLAGS@ LIBMODBUS_LIBS = @LIBMODBUS_LIBS@ LIBNEON_CFLAGS = @LIBNEON_CFLAGS@ LIBNEON_LIBS = @LIBNEON_LIBS@ LIBNETSNMP_CFLAGS = @LIBNETSNMP_CFLAGS@ LIBNETSNMP_LIBS = @LIBNETSNMP_LIBS@ LIBOBJS = @LIBOBJS@ LIBPOWERMAN_CFLAGS = @LIBPOWERMAN_CFLAGS@ LIBPOWERMAN_LIBS = @LIBPOWERMAN_LIBS@ LIBREGEX_LIBS = @LIBREGEX_LIBS@ LIBS = @LIBS@ LIBSSL_CFLAGS = @LIBSSL_CFLAGS@ LIBSSL_LIBS = @LIBSSL_LIBS@ LIBSSL_REQUIRES = @LIBSSL_REQUIRES@ LIBSYSTEMD_CFLAGS = @LIBSYSTEMD_CFLAGS@ LIBSYSTEMD_LIBS = @LIBSYSTEMD_LIBS@ LIBTOOL = @LIBTOOL@ LIBTOOL_DEPS = @LIBTOOL_DEPS@ LIBUSB_CFLAGS = @LIBUSB_CFLAGS@ LIBUSB_CONFIG = @LIBUSB_CONFIG@ LIBUSB_LIBS = @LIBUSB_LIBS@ LIBWRAP_CFLAGS = @LIBWRAP_CFLAGS@ LIBWRAP_LIBS = @LIBWRAP_LIBS@ LIPO = @LIPO@ LN_S = @LN_S@ LN_S_R = @LN_S_R@ LTLIBOBJS = @LTLIBOBJS@ LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@ MAINT = @MAINT@ MAKEINFO = @MAKEINFO@ MANIFEST_TOOL = @MANIFEST_TOOL@ MKDIR_P = @MKDIR_P@ MSGFMT = @MSGFMT@ NETLIBS = @NETLIBS@ NET_SNMP_CONFIG = @NET_SNMP_CONFIG@ NM = @NM@ NMEDIT = @NMEDIT@ NUT_DATADIR = @NUT_DATADIR@ NUT_LIBEXECDIR = @NUT_LIBEXECDIR@ NUT_NETVERSION = @NUT_NETVERSION@ NUT_SOURCE_GITREV = @NUT_SOURCE_GITREV@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ OS_NAME = @OS_NAME@ OTOOL = @OTOOL@ OTOOL64 = @OTOOL64@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_SEPARATOR = @PATH_SEPARATOR@ PIDPATH = @PIDPATH@ PKGCONFIGDIR = @PKGCONFIGDIR@ PKG_CONFIG = @PKG_CONFIG@ PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@ PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ PORT = @PORT@ POWERDOWNFLAG = @POWERDOWNFLAG@ PREFIX = @PREFIX@ PYTHON = @PYTHON@ PYTHON2 = @PYTHON2@ PYTHON2_SITE_PACKAGES = @PYTHON2_SITE_PACKAGES@ PYTHON3 = @PYTHON3@ PYTHON3_SITE_PACKAGES = @PYTHON3_SITE_PACKAGES@ PYTHON_SITE_PACKAGES = @PYTHON_SITE_PACKAGES@ RANLIB = @RANLIB@ REALPATH = @REALPATH@ RUN_AS_GROUP = @RUN_AS_GROUP@ RUN_AS_USER = @RUN_AS_USER@ SBINDIR = @SBINDIR@ SED = @SED@ SEMLIBS = @SEMLIBS@ SERLIBS = @SERLIBS@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ SOURCE_HIGHLIGHT = @SOURCE_HIGHLIGHT@ STATEPATH = @STATEPATH@ STRIP = @STRIP@ SUN_LIBUSB = @SUN_LIBUSB@ SYSTEMD_ANALYZE_PROGRAM = @SYSTEMD_ANALYZE_PROGRAM@ SYSTEMD_DAEMON_ARGS_DRIVER = @SYSTEMD_DAEMON_ARGS_DRIVER@ SYSTEMD_DAEMON_ARGS_UPSD = @SYSTEMD_DAEMON_ARGS_UPSD@ SYSTEMD_DAEMON_ARGS_UPSMON = @SYSTEMD_DAEMON_ARGS_UPSMON@ SYSTEMD_DAEMON_NOTIFYACCESS_DRIVER = @SYSTEMD_DAEMON_NOTIFYACCESS_DRIVER@ SYSTEMD_DAEMON_NOTIFYACCESS_UPSD = @SYSTEMD_DAEMON_NOTIFYACCESS_UPSD@ SYSTEMD_DAEMON_NOTIFYACCESS_UPSMON = @SYSTEMD_DAEMON_NOTIFYACCESS_UPSMON@ SYSTEMD_DAEMON_TYPE_DRIVER = @SYSTEMD_DAEMON_TYPE_DRIVER@ SYSTEMD_DAEMON_TYPE_UPSD = @SYSTEMD_DAEMON_TYPE_UPSD@ SYSTEMD_DAEMON_TYPE_UPSMON = @SYSTEMD_DAEMON_TYPE_UPSMON@ SYSTEMD_DAEMON_WATCHDOG_DRIVER = @SYSTEMD_DAEMON_WATCHDOG_DRIVER@ SYSTEMD_DAEMON_WATCHDOG_UPSD = @SYSTEMD_DAEMON_WATCHDOG_UPSD@ SYSTEMD_DAEMON_WATCHDOG_UPSMON = @SYSTEMD_DAEMON_WATCHDOG_UPSMON@ SYSTEMD_TMPFILES_PROGRAM = @SYSTEMD_TMPFILES_PROGRAM@ TREE_VERSION = @TREE_VERSION@ VALGRIND = @VALGRIND@ VERSION = @VERSION@ WINDMC = @WINDMC@ WINDRES = @WINDRES@ WORDS_BIGENDIAN = @WORDS_BIGENDIAN@ XMLLINT = @XMLLINT@ XSLTPROC = @XSLTPROC@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_AR = @ac_ct_AR@ ac_ct_CC = @ac_ct_CC@ ac_ct_CXX = @ac_ct_CXX@ ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__tar = @am__tar@ am__untar = @am__untar@ auglensdir = @auglensdir@ bindir = @bindir@ build = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ cgiexecdir = @cgiexecdir@ datadir = @datadir@ datarootdir = @datarootdir@ devddir = @devddir@ docdir = @docdir@ driverexecdir = @driverexecdir@ dummy_PKG_CONFIG = @dummy_PKG_CONFIG@ dummy_PKG_CONFIG_CFLAGS = @dummy_PKG_CONFIG_CFLAGS@ dummy_PKG_CONFIG_LIBS = @dummy_PKG_CONFIG_LIBS@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ hotplugdir = @hotplugdir@ htmldir = @htmldir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libdir = @libdir@ libexecdir = @libexecdir@ localedir = @localedir@ localstatedir = @localstatedir@ mandir = @mandir@ mkdir_p = @mkdir_p@ now = @now@ nut_with_nut_monitor = @nut_with_nut_monitor@ nut_with_nut_monitor_desktop = @nut_with_nut_monitor_desktop@ nut_with_nut_monitor_dir = @nut_with_nut_monitor_dir@ nut_with_nut_monitor_py2gtk2 = @nut_with_nut_monitor_py2gtk2@ nut_with_nut_monitor_py3qt5 = @nut_with_nut_monitor_py3qt5@ nut_with_pynut = @nut_with_pynut@ nut_with_pynut_py = @nut_with_pynut_py@ nut_with_pynut_py2 = @nut_with_pynut_py2@ nut_with_pynut_py3 = @nut_with_pynut_py3@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ pkgconfigdir = @pkgconfigdir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ runstatedir = @runstatedir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ sysconfdir = @sysconfdir@ systemdshutdowndir = @systemdshutdowndir@ systemdsystemunitdir = @systemdsystemunitdir@ systemdtmpfilesdir = @systemdtmpfilesdir@ target = @target@ target_alias = @target_alias@ target_cpu = @target_cpu@ target_os = @target_os@ target_vendor = @target_vendor@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ udevdir = @udevdir@ dist_noinst_HEADERS = attribute.h common.h extstate.h proto.h state.h \ str.h timehead.h upsconf.h nut_float.h nut_stdint.h \ nut_platform.h wincompat.h $(am__append_1) # Optionally deliverable as part of NUT public API: @WITH_DEV_TRUE@include_HEADERS = parseconf.h # http://www.gnu.org/software/automake/manual/automake.html#Clean BUILT_SOURCES = nut_version.h CLEANFILES = nut_version.h MAINTAINERCLEANFILES = Makefile.in .dirstamp all: $(BUILT_SOURCES) config.h $(MAKE) $(AM_MAKEFLAGS) all-am .SUFFIXES: $(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu include/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --gnu include/Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): config.h: stamp-h1 @test -f $@ || rm -f stamp-h1 @test -f $@ || $(MAKE) $(AM_MAKEFLAGS) stamp-h1 stamp-h1: $(srcdir)/config.h.in $(top_builddir)/config.status @rm -f stamp-h1 cd $(top_builddir) && $(SHELL) ./config.status include/config.h $(srcdir)/config.h.in: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) ($(am__cd) $(top_srcdir) && $(AUTOHEADER)) rm -f stamp-h1 touch $@ distclean-hdr: -rm -f config.h stamp-h1 mostlyclean-libtool: -rm -f *.lo clean-libtool: -rm -rf .libs _libs install-includeHEADERS: $(include_HEADERS) @$(NORMAL_INSTALL) @list='$(include_HEADERS)'; test -n "$(includedir)" || list=; \ if test -n "$$list"; then \ echo " $(MKDIR_P) '$(DESTDIR)$(includedir)'"; \ $(MKDIR_P) "$(DESTDIR)$(includedir)" || exit 1; \ fi; \ for p in $$list; do \ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ echo "$$d$$p"; \ done | $(am__base_list) | \ while read files; do \ echo " $(INSTALL_HEADER) $$files '$(DESTDIR)$(includedir)'"; \ $(INSTALL_HEADER) $$files "$(DESTDIR)$(includedir)" || exit $$?; \ done uninstall-includeHEADERS: @$(NORMAL_UNINSTALL) @list='$(include_HEADERS)'; test -n "$(includedir)" || list=; \ files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ dir='$(DESTDIR)$(includedir)'; $(am__uninstall_files_from_dir) ID: $(am__tagged_files) $(am__define_uniq_tagged_files); mkid -fID $$unique tags: tags-am TAGS: tags tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) set x; \ here=`pwd`; \ $(am__define_uniq_tagged_files); \ shift; \ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ test -n "$$unique" || unique=$$empty_fix; \ if test $$# -gt 0; then \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ "$$@" $$unique; \ else \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ $$unique; \ fi; \ fi ctags: ctags-am CTAGS: ctags ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) $(am__define_uniq_tagged_files); \ test -z "$(CTAGS_ARGS)$$unique" \ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ $$unique GTAGS: here=`$(am__cd) $(top_builddir) && pwd` \ && $(am__cd) $(top_srcdir) \ && gtags -i $(GTAGS_ARGS) "$$here" cscopelist: cscopelist-am cscopelist-am: $(am__tagged_files) list='$(am__tagged_files)'; \ case "$(srcdir)" in \ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \ *) sdir=$(subdir)/$(srcdir) ;; \ esac; \ for i in $$list; do \ if test -f "$$i"; then \ echo "$(subdir)/$$i"; \ else \ echo "$$sdir/$$i"; \ fi; \ done >> $(top_builddir)/cscope.files distclean-tags: -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags distdir: $(BUILT_SOURCES) $(MAKE) $(AM_MAKEFLAGS) distdir-am distdir-am: $(DISTFILES) @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ dist_files=`for file in $$list; do echo $$file; done | \ sed -e "s|^$$srcdirstrip/||;t" \ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ case $$dist_files in \ */*) $(MKDIR_P) `echo "$$dist_files" | \ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ sort -u` ;; \ esac; \ for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d "$(distdir)/$$file"; then \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ else \ test -f "$(distdir)/$$file" \ || cp -p $$d/$$file "$(distdir)/$$file" \ || exit 1; \ fi; \ done $(MAKE) $(AM_MAKEFLAGS) \ top_distdir="$(top_distdir)" distdir="$(distdir)" \ dist-hook check-am: all-am check: $(BUILT_SOURCES) $(MAKE) $(AM_MAKEFLAGS) check-am all-am: Makefile $(HEADERS) config.h installdirs: for dir in "$(DESTDIR)$(includedir)"; do \ test -z "$$dir" || $(MKDIR_P) "$$dir"; \ done install: $(BUILT_SOURCES) $(MAKE) $(AM_MAKEFLAGS) install-am install-exec: $(BUILT_SOURCES) $(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data: install-data-am uninstall: uninstall-am install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-am install-strip: if test -z '$(STRIP)'; then \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ install; \ else \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ fi mostlyclean-generic: clean-generic: -test -z "$(CLEANFILES)" || rm -f $(CLEANFILES) distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." -test -z "$(BUILT_SOURCES)" || rm -f $(BUILT_SOURCES) -test -z "$(MAINTAINERCLEANFILES)" || rm -f $(MAINTAINERCLEANFILES) clean: clean-am clean-am: clean-generic clean-libtool mostlyclean-am distclean: distclean-am -rm -f Makefile distclean-am: clean-am distclean-generic distclean-hdr distclean-tags dvi: dvi-am dvi-am: html: html-am html-am: info: info-am info-am: install-data-am: install-includeHEADERS install-dvi: install-dvi-am install-dvi-am: install-exec-am: install-html: install-html-am install-html-am: install-info: install-info-am install-info-am: install-man: install-pdf: install-pdf-am install-pdf-am: install-ps: install-ps-am install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-am -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-am mostlyclean-am: mostlyclean-generic mostlyclean-libtool pdf: pdf-am pdf-am: ps: ps-am ps-am: uninstall-am: uninstall-includeHEADERS .MAKE: all check install install-am install-exec install-strip .PHONY: CTAGS GTAGS TAGS all all-am check check-am clean clean-generic \ clean-libtool cscopelist-am ctags ctags-am dist-hook distclean \ distclean-generic distclean-hdr distclean-libtool \ distclean-tags distdir dvi dvi-am html html-am info info-am \ install install-am install-data install-data-am install-dvi \ install-dvi-am install-exec install-exec-am install-html \ install-html-am install-includeHEADERS install-info \ install-info-am install-man install-pdf install-pdf-am \ install-ps install-ps-am install-strip installcheck \ installcheck-am installdirs maintainer-clean \ maintainer-clean-generic mostlyclean mostlyclean-generic \ mostlyclean-libtool pdf pdf-am ps ps-am tags tags-am uninstall \ uninstall-am uninstall-includeHEADERS .PRECIOUS: Makefile # magic to include Git version information in NUT version string # (for builds not made from the tagged commit in a Git workspace) nut_version.h: @FORCE_NUT_VERSION@ @GITREV="`git describe --tags --match 'v[0-9]*.[0-9]*.[0-9]' --exclude '*-signed' --exclude '*rc*' --exclude '*alpha*' --exclude '*beta*' 2>/dev/null | sed -e 's/^v\([0-9]\)/\1/' -e 's,^.*/,,'`" || GITREV=""; \ { echo '/* Autogenerated file. Do not change. */' ; \ echo '/* This file was generated by "make". */' ; \ if [ -z "$$GITREV" ]; then \ NUT_VERSION="$(PACKAGE_VERSION)"; \ echo '/* The version number is set by AC_INIT in configure.ac. */' ; \ else \ NUT_VERSION="$$GITREV"; \ echo '/* The version number is determined by Git source commit hash' ; \ echo ' * and number of commits since the most recent Git tag (if not' ; \ echo ' * building the newest tagged commit itself - then just the tag).'; \ echo ' */' ; \ fi ; \ echo "#define NUT_VERSION_MACRO \"$$NUT_VERSION\"" ; \ } > "$@.tmp" ; \ echo "NUT_VERSION: \"$$NUT_VERSION\"" -test -f "$@" || cp "$@.tmp" "$@" -cmp -s "$@.tmp" "$@" || cp "$@.tmp" "$@" -rm -f "$@.tmp" FORCE: # counter part of BUILT_SOURCES: since nut_version is not a direct # deps of a local target, we must clean it by ourselves before the # distribution dist-hook: $(AM_V_at)rm -f $(distdir)/nut_version.h # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: nut-2.8.1/include/common.h0000644000175000017500000004007014515702041012335 00000000000000/* common.h - prototypes for the common useful functions Copyright (C) 2000 Russell Kroll 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 2 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, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef NUT_COMMON_H_SEEN #define NUT_COMMON_H_SEEN 1 #include "config.h" /* must be the first header */ #ifdef WIN32 # ifndef __POSIX_VISIBLE /* for fcntl() and its flags in MSYS2 */ # define __POSIX_VISIBLE 200809 # endif #endif /* Need this on AIX when using xlc to get alloca */ #ifdef _AIX #pragma alloca #endif /* _AIX */ #include #include #include #include #include /* suseconds_t among other things */ #include #ifdef HAVE_SYS_SIGNAL_H #include #endif #ifdef HAVE_SIGNAL_H #include #endif #include #ifdef HAVE_STRINGS_H #include /* for strncasecmp() and strcasecmp() */ #endif #ifdef HAVE_STRING_H #include /* for strdup() and many others */ #endif #ifndef WIN32 #include #else #include #include #include #endif #include /* useconds_t */ #ifndef HAVE_USECONDS_T # define useconds_t unsigned long int #endif #ifndef HAVE_SUSECONDS_T /* Note: WIN32 may have this defined as just "long" which should * hopefully be identical to the definition below, which we test * in our configure script. See also struct timeval fields for a * platform, if in doubt. */ # define suseconds_t signed long int #endif #include #include "timehead.h" #include "attribute.h" #include "proto.h" #include "str.h" #if (defined HAVE_LIBREGEX && HAVE_LIBREGEX) # include #endif #ifdef __cplusplus /* *INDENT-OFF* */ extern "C" { /* *INDENT-ON* */ #endif /* POSIX requires these, and most but not all systems use same * magical numbers for the file descriptors... yep, not all do! */ #ifndef STDIN_FILENO # define STDIN_FILENO 0 /* standard input file descriptor */ #endif #ifndef STDOUT_FILENO # define STDOUT_FILENO 1 /* standard output file descriptor */ #endif #ifndef STDERR_FILENO # define STDERR_FILENO 2 /* standard error file descriptor */ #endif /* porting stuff for WIN32, used by serial and SHUT codebases */ #ifndef WIN32 /* Just match three macro groups defined for WIN32 */ /* Type of what file open() and close() use, * including pipes for driver-upsd communications: */ # define TYPE_FD int # define ERROR_FD (-1) # define VALID_FD(a) (a>=0) /* Type of what NUT serial/SHUT methods juggle: */ # define TYPE_FD_SER TYPE_FD # define ERROR_FD_SER ERROR_FD # define VALID_FD_SER(a) VALID_FD(a) /* Type of what socket() returns, mostly for networked code: */ # define TYPE_FD_SOCK TYPE_FD # define ERROR_FD_SOCK ERROR_FD # define VALID_FD_SOCK(a) VALID_FD(a) #else /* WIN32 */ /* Separate definitions of TYPE_FD, ERROR_FD, VALID_FD() macros * for usual file descriptors vs. types needed for serial port * work or for networking sockets. */ # define TYPE_FD HANDLE # define ERROR_FD (INVALID_HANDLE_VALUE) # define VALID_FD(a) (a!=INVALID_HANDLE_VALUE) # ifndef INVALID_SOCKET # define INVALID_SOCKET -1 # endif # define TYPE_FD_SOCK SOCKET # define ERROR_FD_SOCK INVALID_SOCKET # define VALID_FD_SOCK(a) (a!=INVALID_SOCKET) typedef struct serial_handler_s { HANDLE handle; OVERLAPPED io_status; int overlapped_armed; unsigned int vmin_; unsigned int vtime_; unsigned int r_binary; unsigned int w_binary; } serial_handler_t; # define TYPE_FD_SER serial_handler_t * # define ERROR_FD_SER (NULL) # define VALID_FD_SER(a) (a!=NULL) /* difftime returns erroneous value so we use this macro */ # undef difftime # define difftime(t1,t0) (double)(t1 - t0) #endif /* WIN32 */ /* Two uppercase letters are more readable than one exclamation */ #define INVALID_FD_SER(a) (!VALID_FD_SER(a)) #define INVALID_FD_SOCK(a) (!VALID_FD_SOCK(a)) #define INVALID_FD(a) (!VALID_FD(a)) #define SIZEOF_ARRAY(a) (sizeof(a) / sizeof(a[0])) extern const char *UPS_VERSION; /* Use in code to notify the developers and quiesce the compiler that * (for this codepath) the argument or variable is unused intentionally. * void f(int x) { * NUT_UNUSED_VARIABLE(x); * ... * } * * Note that solutions which mark up function arguments or employ this or * that __attribute__ proved not portable enough for wherever NUT builds. */ #define NUT_UNUSED_VARIABLE(x) (void)(x) /** @brief Default timeout (in seconds) for network operations, as used by `upsclient` and `nut-scanner`. */ #define DEFAULT_NETWORK_TIMEOUT 5 /** @brief Default timeout (in seconds) for retrieving the result of a `TRACKING`-enabled operation (e.g. `INSTCMD`, `SET VAR`). */ #define DEFAULT_TRACKING_TIMEOUT 10 /* get the syslog ready for us */ void open_syslog(const char *progname); /* close ttys and become a daemon */ void background(void); /* do this here to keep pwd/grp stuff out of the main files */ struct passwd *get_user_pwent(const char *name); /* change to the user defined in the struct */ void become_user(struct passwd *pw); /* drop down into a directory and throw away pointers to the old path */ void chroot_start(const char *path); /* write a pid file - is a full pathname *or* just the program name */ void writepid(const char *name); /* parses string buffer into a pid_t if it passes * a few sanity checks; returns -1 on error */ pid_t parsepid(const char *buf); /* send a signal to another running process */ #ifndef WIN32 int sendsignal(const char *progname, int sig); #else int sendsignal(const char *progname, const char * sig); #endif int snprintfcat(char *dst, size_t size, const char *fmt, ...) __attribute__ ((__format__ (__printf__, 3, 4))); /* Report maximum platform value for the pid_t */ pid_t get_max_pid_t(void); /* send sig to pid after some sanity checks, returns * -1 for error, or zero for a successfully sent signal */ int sendsignalpid(pid_t pid, int sig); /* open , get the pid, then send it * returns zero for successfully sent signal, * negative for errors: * -3 PID file not found * -2 PID file not parsable * -1 Error sending signal */ #ifndef WIN32 /* open , get the pid, then send it */ int sendsignalfn(const char *pidfn, int sig); #else int sendsignalfn(const char *pidfn, const char * sig); #endif const char *xbasename(const char *file); /* enable writing upslog_with_errno() and upslogx() type messages to the syslog */ void syslogbit_set(void); /* Return the default path for the directory containing configuration files */ const char * confpath(void); /* Return the default path for the directory containing state files */ const char * dflt_statepath(void); /* Return the alternate path for pid files */ const char * altpidpath(void); /* Die with a standard message if socket filename is too long */ void check_unix_socket_filename(const char *fn); /* Send (daemon) state-change notifications to an * external service management framework such as systemd. * State types below are initially loosely modeled after * https://www.freedesktop.org/software/systemd/man/sd_notify.html */ typedef enum eupsnotify_state { NOTIFY_STATE_READY = 1, NOTIFY_STATE_READY_WITH_PID, NOTIFY_STATE_RELOADING, NOTIFY_STATE_STOPPING, NOTIFY_STATE_STATUS, /* Send a text message per "fmt" below */ NOTIFY_STATE_WATCHDOG /* Ping the framework that we are still alive */ } upsnotify_state_t; /* Note: here fmt may be null, then the STATUS message would not be sent/added */ int upsnotify(upsnotify_state_t state, const char *fmt, ...) __attribute__ ((__format__ (__printf__, 2, 3))); /* upslog*() messages are sent to syslog always; * their life after that is out of NUT's control */ void upslog_with_errno(int priority, const char *fmt, ...) __attribute__ ((__format__ (__printf__, 2, 3))); void upslogx(int priority, const char *fmt, ...) __attribute__ ((__format__ (__printf__, 2, 3))); /* upsdebug*() messages are only logged if debugging * level is high enough. To speed up a bit (minimize * passing of ultimately ignored data trough the stack) * these are "hidden" implementations wrapped into * macros for earlier routine names spread around the * codebase, they would check debug level first and * only if logging should happen - call the routine * and pass around pointers and other data. */ void s_upsdebug_with_errno(int level, const char *fmt, ...) __attribute__ ((__format__ (__printf__, 2, 3))); void s_upsdebugx(int level, const char *fmt, ...) __attribute__ ((__format__ (__printf__, 2, 3))); void s_upsdebug_hex(int level, const char *msg, const void *buf, size_t len); void s_upsdebug_ascii(int level, const char *msg, const void *buf, size_t len); /* These macros should help avoid run-time overheads * passing data for messages nobody would ever see. * * Also NOTE: the "level" may be specified by callers in various ways, * e.g. as a "X ? Y : Z" style expression; to catch those expansions * transparently we hide them into parentheses as "(label)". * * For stricter C99 compatibility, all parameters specified to a macro * must be populated by caller (so we do not handle "fmt, args..." where * the args part may be skipped by caller because fmt is a fixed string). * Note it is then up to the caller (and compiler checks) that at least * one argument is provided, the format string (maybe fixed) -- as would * be required by the actual s_upsdebugx*() method after macro evaluation. */ #define upsdebug_with_errno(level, ...) \ do { if (nut_debug_level >= (level)) { s_upsdebug_with_errno((level), __VA_ARGS__); } } while(0) #define upsdebugx(level, ...) \ do { if (nut_debug_level >= (level)) { s_upsdebugx((level), __VA_ARGS__); } } while(0) #define upsdebug_hex(level, msg, buf, len) \ do { if (nut_debug_level >= (level)) { s_upsdebug_hex((level), msg, buf, len); } } while(0) #define upsdebug_ascii(level, msg, buf, len) \ do { if (nut_debug_level >= (level)) { s_upsdebug_ascii((level), msg, buf, len); } } while(0) void fatal_with_errno(int status, const char *fmt, ...) __attribute__ ((__format__ (__printf__, 2, 3))) __attribute__((noreturn)); void fatalx(int status, const char *fmt, ...) __attribute__ ((__format__ (__printf__, 2, 3))) __attribute__((noreturn)); /* Report CONFIG_FLAGS used for this build of NUT similarly to how * upsdebugx(1, ...) would do it, but not limiting the string length */ void nut_report_config_flags(void); /* Report search paths used by ltdl-augmented code to discover and * load shared binary object files at run-time (nut-scanner, DMF...) */ void upsdebugx_report_search_paths(int level, int report_search_paths_builtin); void nut_prepare_search_paths(void); extern int nut_debug_level; extern int nut_log_level; void *xmalloc(size_t size); void *xcalloc(size_t number, size_t size); void *xrealloc(void *ptr, size_t size); char *xstrdup(const char *string); /**** REGEX helper methods ****/ /* helper function: version of strcmp that tolerates NULL * pointers. NULL is considered to come before all other strings * alphabetically. */ int strcmp_null(const char *s1, const char *s2); #if (defined HAVE_LIBREGEX && HAVE_LIBREGEX) /* Helper function for compiling a regular expression. On success, * store the compiled regular expression (or NULL) in *compiled, and * return 0. On error with errno set, return -1. If the supplied * regular expression is unparseable, return -2 (an error message can * then be retrieved with regerror(3)). Note that *compiled will be an * allocated value, and must be freed with regfree(), then free(), see * regex(3). As a special case, if regex==NULL, then set * *compiled=NULL (regular expression NULL is intended to match * anything). */ int compile_regex(regex_t **compiled, const char *regex, const int cflags); /* Helper function for regular expression matching. Check if the * entire string str (minus any initial and trailing whitespace) * matches the compiled regular expression preg. Return 1 if it * matches, 0 if not. Return -1 on error with errno set. Special * cases: if preg==NULL, it matches everything (no contraint). If * str==NULL, then it is treated as "". */ int match_regex(const regex_t *preg, const char *str); /* Helper function, similar to match_regex, but the argument being * matched is a (hexadecimal) number, rather than a string. It is * converted to a 4-digit hexadecimal string. */ int match_regex_hex(const regex_t *preg, const int n); #endif /* HAVE_LIBREGEX */ /* Note: different method signatures instead of TYPE_FD_SER due to "const" */ #ifndef WIN32 ssize_t select_read(const int fd, void *buf, const size_t buflen, const time_t d_sec, const suseconds_t d_usec); ssize_t select_write(const int fd, const void *buf, const size_t buflen, const time_t d_sec, const suseconds_t d_usec); #else ssize_t select_read(serial_handler_t *fd, void *buf, const size_t buflen, const time_t d_sec, const suseconds_t d_usec); /* Note: currently not implemented de-facto for Win32 */ ssize_t select_write(serial_handler_t * fd, const void *buf, const size_t buflen, const time_t d_sec, const suseconds_t d_usec); #endif char * get_libname(const char* base_libname); /* Buffer sizes used for various functions */ #define SMALLBUF 512 #define LARGEBUF 1024 /** @brief (Minimum) Size that a string must have to hold a UUID4 (i.e. UUID4 length + the terminating null character). */ #define UUID4_LEN 37 /* Provide declarations for getopt() global variables */ #ifdef NEED_GETOPT_H #include #else #ifdef NEED_GETOPT_DECLS extern char *optarg; extern int optind; #endif /* NEED_GETOPT_DECLS */ #endif /* HAVE_GETOPT_H */ /* logging flags: bitmask! */ #define UPSLOG_STDERR 0x0001 #define UPSLOG_SYSLOG 0x0002 #define UPSLOG_STDERR_ON_FATAL 0x0004 #define UPSLOG_SYSLOG_ON_FATAL 0x0008 #ifndef HAVE_SETEUID # define seteuid(x) setresuid(-1,x,-1) /* Works for HP-UX 10.20 */ # define setegid(x) setresgid(-1,x,-1) /* Works for HP-UX 10.20 */ #endif #ifdef WIN32 /* FIXME : this might not be the optimal mapping between syslog and ReportEvent*/ #define LOG_ERR EVENTLOG_ERROR_TYPE #define LOG_INFO EVENTLOG_INFORMATION_TYPE #define LOG_DEBUG EVENTLOG_WARNING_TYPE #define LOG_NOTICE EVENTLOG_INFORMATION_TYPE #define LOG_ALERT EVENTLOG_ERROR_TYPE #define LOG_WARNING EVENTLOG_WARNING_TYPE #define LOG_CRIT EVENTLOG_ERROR_TYPE #define LOG_EMERG EVENTLOG_ERROR_TYPE #define closelog() #define SVCNAME TEXT("Network UPS Tools") #define EVENTLOG_PIPE_NAME TEXT("nut") #define UPSMON_PIPE_NAME TEXT("upsmon") #define UPSD_PIPE_NAME TEXT("upsd") char * getfullpath(char * relative_path); #define PATH_ETC "\\..\\etc" #define PATH_VAR_RUN "\\..\\var\\run" #define PATH_SHARE "\\..\\share" #define PATH_BIN "\\..\\bin" #define PATH_SBIN "\\..\\sbin" #define PATH_LIB "\\..\\lib" #endif /* WIN32*/ /* Return a difference of two timevals as a floating-point number */ double difftimeval(struct timeval x, struct timeval y); #if defined(HAVE_CLOCK_GETTIME) && defined(HAVE_CLOCK_MONOTONIC) && HAVE_CLOCK_GETTIME && HAVE_CLOCK_MONOTONIC double difftimespec(struct timespec x, struct timespec y); #endif #ifndef HAVE_USLEEP /* int __cdecl usleep(unsigned int useconds); */ /* Note: if we'd need to define an useconds_t for obscure systems, * it should be an int capable of string 0..1000000 value range, * so probably unsigned long int */ int __cdecl usleep(useconds_t useconds); #endif /* HAVE_USLEEP */ #ifndef HAVE_STRNLEN size_t strnlen(const char *s, size_t maxlen); #endif /* Not all platforms support the flag; this method abstracts * its use (or not) to simplify calls in the actual codebase */ /* TODO: Extend for TYPE_FD and WIN32 eventually? */ void set_close_on_exec(int fd); #ifdef __cplusplus /* *INDENT-OFF* */ } /* *INDENT-ON* */ #endif #endif /* NUT_COMMON_H_SEEN */ nut-2.8.1/include/nut_stdint.h0000644000175000017500000001101314501607135013236 00000000000000/* * nut_stdint.h - Network UPS Tools sets of integer types having specified widths * * Copyright (C) 2011 Arjen de Korte * * 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 2 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, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef NUT_STDINT_H_SEEN #define NUT_STDINT_H_SEEN 1 #include "config.h" #ifndef __STDC_LIMIT_MACROS #define __STDC_LIMIT_MACROS 1 #endif #ifndef __STDC_CONSTANT_MACROS #define __STDC_CONSTANT_MACROS 1 #endif #if defined HAVE_INTTYPES_H # include #endif #if defined HAVE_STDINT_H # include #endif #if defined HAVE_LIMITS_H # include #endif #ifndef SIZE_MAX #define SIZE_MAX ((size_t)(-1LL)) #endif #ifndef SSIZE_MAX #define SSIZE_MAX ((ssize_t)(-1LL)) #endif /* Printing format for size_t and ssize_t */ #ifndef PRIuSIZE # ifdef PRIsize # define PRIuSIZE PRIsize # else # if defined(__MINGW32__) || defined (WIN32) # define PRIuSIZE "llu" # else # define PRIuSIZE "zu" # endif # endif #endif #ifndef PRIxSIZE # if defined(__MINGW32__) || defined (WIN32) # define PRIxSIZE "llx" # else # define PRIxSIZE "zx" # endif #endif /* Note: Windows headers are known to define at least "d" values, * so macros below revolve around that and not "i" directly */ #ifndef PRIiSIZE # ifdef PRIssize # define PRIiSIZE PRIssize # else # ifdef PRIdSIZE # define PRIiSIZE PRIdSIZE # else # if defined(__MINGW32__) || defined (WIN32) # define PRIiSIZE "lld" # else # define PRIiSIZE "zd" # endif # define PRIdSIZE PRIiSIZE # endif # endif #else # ifndef PRIdSIZE # define PRIdSIZE PRIiSIZE # endif #endif /* format for size_t and ssize_t */ /* Printing format for uintmax_t and intmax_t */ #ifndef PRIuMAX # if defined(__MINGW32__) || defined (WIN32) # if (SIZEOF_VOID_P == 8) # ifdef PRIu64 # define PRIuMAX PRIu64 # else /* assume new enough compiler and standard, and no Windows %I64 etc... check "%ll" support via configure? */ # define PRIuMAX "llu" # endif # endif # if (SIZEOF_VOID_P == 4) # ifdef PRIu32 # define PRIuMAX PRIu32 # else /* assume new enough compiler and standard, and no Windows %I64 etc... check "%ll" support via configure? */ # define PRIuMAX "lu" # endif # endif # else /* assume new enough compiler and standard... check "%j" support via configure? */ # define PRIuMAX "ju" # endif #endif /* format for uintmax_t and intmax_t */ #ifndef PRIdMAX # ifdef PRIiMAX # define PRIdMAX PRIiMAX # else # if defined(__MINGW32__) || defined (WIN32) # if (SIZEOF_VOID_P == 8) # ifdef PRId64 # define PRIdMAX PRId64 # else /* assume new enough compiler and standard, and no Windows %I64 etc... check "%ll" support via configure? */ # define PRIdMAX "lld" # endif # endif # if (SIZEOF_VOID_P == 4) # ifdef PRId32 # define PRIdMAX PRId32 # else /* assume new enough compiler and standard, and no Windows %I64 etc... check "%ll" support via configure? */ # define PRIdMAX "ld" # endif # endif # else /* assume new enough compiler and standard... check "%j" support via configure? */ # define PRIdMAX "jd" # endif # define PRIiMAX PRIdMAX # endif #else # ifndef PRIiMAX # define PRIiMAX PRIdMAX # endif #endif /* format for uintmax_t and intmax_t */ #ifndef PRIxMAX # if defined(__MINGW32__) || defined (WIN32) # if (SIZEOF_VOID_P == 8) # ifdef PRIx64 # define PRIxMAX PRIx64 # else /* assume new enough compiler and standard, and no Windows %I64 etc... check "%ll" support via configure? */ # define PRIxMAX "llx" # endif # endif # if (SIZEOF_VOID_P == 4) # ifdef PRIx32 # define PRIxMAX PRIx32 # else /* assume new enough compiler and standard, and no Windows %I64 etc... check "%ll" support via configure? */ # define PRIxMAX "lx" # endif # endif # else /* assume new enough compiler and standard... check "%j" support via configure? */ # define PRIxMAX "jx" # endif #endif /* format for uintmax_t and intmax_t */ #endif /* NUT_STDINT_H_SEEN */ nut-2.8.1/include/extstate.h0000644000175000017500000000363414500336654012722 00000000000000/* extstate.h - external state structures used by things like upsd Copyright (C) 2001 Russell Kroll 2005 Arnaud Quette 2007 Peter Selinger 2008 Arjen de Korte 2013 Emilien Kia 2020 Jim Klimov 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 2 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, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef NUT_EXTSTATE_H_SEEN #define NUT_EXTSTATE_H_SEEN 1 #ifdef __cplusplus /* *INDENT-OFF* */ extern "C" { /* *INDENT-ON* */ #endif /* this could be made dynamic if someone really needs more than this... */ #define ST_MAX_VALUE_LEN 256 /* state tree flags */ #define ST_FLAG_NONE 0x0000 #define ST_FLAG_RW 0x0001 #define ST_FLAG_STRING 0x0002 /* not STRING implies NUMBER */ #define ST_FLAG_NUMBER 0x0004 #define ST_FLAG_IMMUTABLE 0x0008 /* list of possible ENUM values */ typedef struct enum_s { char *val; struct enum_s *next; } enum_t; /* RANGE boundaries */ typedef struct range_s { int min; int max; struct range_s *next; } range_t; /* list of instant commands */ typedef struct cmdlist_s { char *name; struct cmdlist_s *next; } cmdlist_t; #ifdef __cplusplus /* *INDENT-OFF* */ } /* *INDENT-ON* */ #endif #endif /* NUT_EXTSTATE_H_SEEN */ nut-2.8.1/include/parseconf.h0000644000175000017500000000550714501607135013036 00000000000000/* parseconf.h - state machine-driven dynamic configuration file parser Copyright (C) 2002 Russell Kroll 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 2 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, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef PARSECONF_H_SEEN #define PARSECONF_H_SEEN 1 #include /* Not including nut_stdint.h because this is part of end-user API */ #if defined HAVE_INTTYPES_H #include #endif #if defined HAVE_STDINT_H #include #endif #if defined HAVE_LIMITS_H #include #endif #ifdef __cplusplus /* *INDENT-OFF* */ extern "C" { /* *INDENT-ON* */ #endif #define PCONF_CTX_t_MAGIC 0x00726630 #define PCONF_ERR_LEN 256 /* conservative defaults: use at most 16 KB for parsing any given line */ #define PCONF_DEFAULT_ARG_LIMIT 32 #define PCONF_DEFAULT_WORDLEN_LIMIT 512 typedef struct { FILE *f; /* stream to current file */ int state; /* current parser state */ int ch; /* last character read */ char **arglist; /* array of pointers to words */ size_t *argsize; /* list of sizes for realloc */ size_t numargs; /* max usable in arglist */ size_t maxargs; /* for reallocing arglist */ char *wordbuf; /* accumulator for current word */ char *wordptr; /* where next char goes in word */ size_t wordbufsize; /* for reallocing wordbuf */ int linenum; /* for good error reporting */ int error; /* set when an error occurred */ char errmsg[PCONF_ERR_LEN]; /* local buffer for errors */ void (*errhandler)(const char *); /* user's error handler */ int magic; /* buffer validity check */ /* these may be redefined by the caller to customize memory use */ size_t arg_limit; /* halts growth of arglist */ size_t wordlen_limit; /* halts growth of any wordbuf */ } PCONF_CTX_t; int pconf_init(PCONF_CTX_t *ctx, void errhandler(const char *)); int pconf_file_begin(PCONF_CTX_t *ctx, const char *fn); int pconf_file_next(PCONF_CTX_t *ctx); int pconf_parse_error(PCONF_CTX_t *ctx); int pconf_line(PCONF_CTX_t *ctx, const char *line); void pconf_finish(PCONF_CTX_t *ctx); char *pconf_encode(const char *src, char *dest, size_t destsize); int pconf_char(PCONF_CTX_t *ctx, char ch); #ifdef __cplusplus /* *INDENT-OFF* */ } /* *INDENT-ON* */ #endif #endif /* PARSECONF_H_SEEN */ nut-2.8.1/include/Makefile.am0000644000175000017500000000354714501607135012743 00000000000000dist_noinst_HEADERS = attribute.h common.h extstate.h proto.h \ state.h str.h timehead.h upsconf.h nut_float.h nut_stdint.h nut_platform.h \ wincompat.h # Optionally deliverable as part of NUT public API: if WITH_DEV include_HEADERS = parseconf.h else dist_noinst_HEADERS += parseconf.h endif # http://www.gnu.org/software/automake/manual/automake.html#Clean BUILT_SOURCES = nut_version.h CLEANFILES = nut_version.h MAINTAINERCLEANFILES = Makefile.in .dirstamp # magic to include Git version information in NUT version string # (for builds not made from the tagged commit in a Git workspace) nut_version.h: @FORCE_NUT_VERSION@ @GITREV="`git describe --tags --match 'v[0-9]*.[0-9]*.[0-9]' --exclude '*-signed' --exclude '*rc*' --exclude '*alpha*' --exclude '*beta*' 2>/dev/null | sed -e 's/^v\([0-9]\)/\1/' -e 's,^.*/,,'`" || GITREV=""; \ { echo '/* Autogenerated file. Do not change. */' ; \ echo '/* This file was generated by "make". */' ; \ if [ -z "$$GITREV" ]; then \ NUT_VERSION="$(PACKAGE_VERSION)"; \ echo '/* The version number is set by AC_INIT in configure.ac. */' ; \ else \ NUT_VERSION="$$GITREV"; \ echo '/* The version number is determined by Git source commit hash' ; \ echo ' * and number of commits since the most recent Git tag (if not' ; \ echo ' * building the newest tagged commit itself - then just the tag).'; \ echo ' */' ; \ fi ; \ echo "#define NUT_VERSION_MACRO \"$$NUT_VERSION\"" ; \ } > "$@.tmp" ; \ echo "NUT_VERSION: \"$$NUT_VERSION\"" -test -f "$@" || cp "$@.tmp" "$@" -cmp -s "$@.tmp" "$@" || cp "$@.tmp" "$@" -rm -f "$@.tmp" FORCE: # counter part of BUILT_SOURCES: since nut_version is not a direct # deps of a local target, we must clean it by ourselves before the # distribution dist-hook: $(AM_V_at)rm -f $(distdir)/nut_version.h nut-2.8.1/include/upsconf.h0000644000175000017500000000301114501607135012517 00000000000000/* upsconf.h - prototypes for upsconf.c Copyright (C) 2001 Russell Kroll 2005 Arnaud Quette 2013 Emilien Kia 2020 Jim Klimov 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 2 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, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef NUT_UPSCONF_H_SEEN #define NUT_UPSCONF_H_SEEN 1 #ifdef __cplusplus /* *INDENT-OFF* */ extern "C" { /* *INDENT-ON* */ #endif /* callback function from read_upsconf */ void do_upsconf_args(char *upsname, char *var, char *val); /* open the ups.conf, parse it, and call back do_upsconf_args() * returns -1 (or aborts the program) in case of errors; * returns 1 if processing finished successfully * See also reload_flag support in main.c for live-reload feature */ int read_upsconf(int fatal_errors); #ifdef __cplusplus /* *INDENT-OFF* */ } /* *INDENT-ON* */ #endif #endif /* NUT_UPSCONF_H_SEEN */ nut-2.8.1/include/config.h.in0000644000175000017500000011510514520275036012726 00000000000000/* include/config.h.in. Generated from configure.ac by autoheader. */ /* Define if building universal (internal helper macro) */ #undef AC_APPLE_UNIVERSAL_BUILD /* Path for pid files of processes not running as root */ #undef ALTPIDPATH /* host env spec we built on */ #undef AUTOTOOLS_BUILD_ALIAS /* host OS short spec we built on */ #undef AUTOTOOLS_BUILD_SHORT_ALIAS /* host env spec we run on */ #undef AUTOTOOLS_HOST_ALIAS /* host OS short spec we run on */ #undef AUTOTOOLS_HOST_SHORT_ALIAS /* host env spec we built for */ #undef AUTOTOOLS_TARGET_ALIAS /* host OS short spec we built for */ #undef AUTOTOOLS_TARGET_SHORT_ALIAS /* Default path for user executables */ #undef BINDIR /* Compact version of C compiler */ #undef CC_VERSION /* Default path for CGI programs */ #undef CGIPATH /* Flags passed to configure script */ #undef CONFIG_FLAGS /* Default path for configuration files */ #undef CONFPATH /* Compiler flags for cppunit tests */ #undef CPPUNIT_NUT_CXXFLAGS /* Compact version of C preprocessor */ #undef CPP_VERSION /* Define processor type */ #undef CPU_TYPE /* Define to 1 if your C++ compiler doesn't accept -c and -o together. */ #undef CXX_NO_MINUS_C_MINUS_O /* Compact version of C++ compiler */ #undef CXX_VERSION /* Default path for UPS drivers */ #undef DRVPATH /* Define to nothing if C supports flexible array members, and to 1 if it does not. That way, with a declaration like `struct s { int n; double d[FLEXIBLE_ARRAY_MEMBER]; };', the struct hack can be used with pre-C99 compilers. When computing the size of such an object, don't use 'sizeof (struct s)' as it overestimates the size. Use 'offsetof (struct s, d)' instead. Don't use 'offsetof (struct s, d[0])', as this doesn't work with MSVC and with C++ compilers. */ #undef FLEXIBLE_ARRAY_MEMBER /* Define to the type of arg 1 for getnameinfo. */ #undef GETNAMEINFO_TYPE_ARG1 /* Define to the type of arg 2 for getnameinfo. */ #undef GETNAMEINFO_TYPE_ARG2 /* Define to the type of args 4 and 6 for getnameinfo. */ #undef GETNAMEINFO_TYPE_ARG46 /* Define to the type of arg 7 for getnameinfo. */ #undef GETNAMEINFO_TYPE_ARG7 /* Define to 1 if you have the `abs' function. */ #undef HAVE_ABS /* Define to 1 if you have the `abs_val' function. */ #undef HAVE_ABS_VAL /* Define to 1 if you have the `atexit' function. */ #undef HAVE_ATEXIT /* Define to 1 if you have the header file. */ #undef HAVE_AVAHI_CLIENT_CLIENT_H /* Define to 1 if you have the `avahi_client_new' function. */ #undef HAVE_AVAHI_CLIENT_NEW /* Define to 1 if you have the header file. */ #undef HAVE_AVAHI_COMMON_MALLOC_H /* Define to 1 if you have the `avahi_free' function. */ #undef HAVE_AVAHI_FREE /* Define to 1 if you have the `cfsetispeed' function. */ #undef HAVE_CFSETISPEED /* defined if standard library has, and C standard allows, the clock_gettime(clkid,ts) method */ #undef HAVE_CLOCK_GETTIME /* defined if standard library has, and C standard allows, the CLOCK_MONOTONIC macro or token */ #undef HAVE_CLOCK_MONOTONIC /* Define to enable CPPUNIT tests */ #undef HAVE_CPPUNIT /* Define to enable C++11 support */ #undef HAVE_CXX11 /* Define to 1 if C supports variable-length arrays. */ #undef HAVE_C_VARARRAYS /* Define to 1 if you have the declaration of `fabs', and to 0 if you don't. */ #undef HAVE_DECL_FABS /* Define to 1 if you have the declaration of `fabsf', and to 0 if you don't. */ #undef HAVE_DECL_FABSF /* Define to 1 if you have the declaration of `fabsl', and to 0 if you don't. */ #undef HAVE_DECL_FABSL /* Define to 1 if you have the declaration of `i2c_smbus_access', and to 0 if you don't. */ #undef HAVE_DECL_I2C_SMBUS_ACCESS /* Define to 1 if you have the declaration of `i2c_smbus_read_block_data', and to 0 if you don't. */ #undef HAVE_DECL_I2C_SMBUS_READ_BLOCK_DATA /* Define to 1 if you have the declaration of `i2c_smbus_read_byte_data', and to 0 if you don't. */ #undef HAVE_DECL_I2C_SMBUS_READ_BYTE_DATA /* Define to 1 if you have the declaration of `i2c_smbus_read_word_data', and to 0 if you don't. */ #undef HAVE_DECL_I2C_SMBUS_READ_WORD_DATA /* Define to 1 if you have the declaration of `i2c_smbus_write_byte_data', and to 0 if you don't. */ #undef HAVE_DECL_I2C_SMBUS_WRITE_BYTE_DATA /* Define to 1 if you have the declaration of `i2c_smbus_write_word_data', and to 0 if you don't. */ #undef HAVE_DECL_I2C_SMBUS_WRITE_WORD_DATA /* Define to 1 if you have the declaration of `LOG_UPTO', and to 0 if you don't. */ #undef HAVE_DECL_LOG_UPTO /* Define to 1 if you have the declaration of `optind', and to 0 if you don't. */ #undef HAVE_DECL_OPTIND /* Define to 1 if you have the declaration of `pow10', and to 0 if you don't. */ #undef HAVE_DECL_POW10 /* Define to 1 if you have the declaration of `realpath', and to 0 if you don't. */ #undef HAVE_DECL_REALPATH /* Define to 1 if you have the declaration of `regcomp', and to 0 if you don't. */ #undef HAVE_DECL_REGCOMP /* Define to 1 if you have the declaration of `regexec', and to 0 if you don't. */ #undef HAVE_DECL_REGEXEC /* Define to 1 if you have the declaration of `round', and to 0 if you don't. */ #undef HAVE_DECL_ROUND /* Define to 1 if you have the declaration of `uu_lock', and to 0 if you don't. */ #undef HAVE_DECL_UU_LOCK /* Define to 1 if you have the declaration of `__FUNCTION__', and to 0 if you don't. */ #undef HAVE_DECL___FUNCTION__ /* Define to 1 if you have the declaration of `__func__', and to 0 if you don't. */ #undef HAVE_DECL___FUNC__ /* Define to 1 if you have the header file. */ #undef HAVE_DLFCN_H /* Define to 1 if you have the `dup' function. */ #undef HAVE_DUP /* Define to 1 if you have the `dup2' function. */ #undef HAVE_DUP2 /* Define to 1 if you have the `fcvt' function. */ #undef HAVE_FCVT /* Define to 1 if you have the `fcvtl' function. */ #undef HAVE_FCVTL /* Define to 1 if you have the `fileno' function. */ #undef HAVE_FILENO /* Define to 1 if you have . */ #undef HAVE_FLOAT_H /* Define to 1 if you have the `flock' function. */ #undef HAVE_FLOCK /* Define if FreeIPMI support is available */ #undef HAVE_FREEIPMI /* Define if FreeIPMI 1.1.X / 1.2.X support is available */ #undef HAVE_FREEIPMI_11X_12X /* Define to 1 if you have the header file. */ #undef HAVE_FREEIPMI_FREEIPMI_H /* Define if FreeIPMI monitoring support is available */ #undef HAVE_FREEIPMI_MONITORING /* Define to 1 if you have the header file. */ #undef HAVE_GDFONTMB_H /* Define to 1 if you have the header file. */ #undef HAVE_GD_H /* Define to 1 if you have the header file. */ #undef HAVE_GETOPT_H /* Define to 1 if you have the `getopt_long' function. */ #undef HAVE_GETOPT_LONG /* Define to 1 if you have the `getpassphrase' function. */ #undef HAVE_GETPASSPHRASE /* Define to 1 if you have the `gmtime_r' function. */ #undef HAVE_GMTIME_R /* Define to 1 if you have the `gmtime_s' function. */ #undef HAVE_GMTIME_S /* Define to 1 if you have the `gpiod_chip_close' function. */ #undef HAVE_GPIOD_CHIP_CLOSE /* Define to 1 if you have the `gpiod_chip_open_by_name' function. */ #undef HAVE_GPIOD_CHIP_OPEN_BY_NAME /* Define to 1 if you have the header file. */ #undef HAVE_GPIOD_H /* defined if system has the inet_ntop() method */ #undef HAVE_INET_NTOP /* defined if system has the inet_pton() method */ #undef HAVE_INET_PTON /* Define to 1 if you have the `init_snmp' function. */ #undef HAVE_INIT_SNMP /* Define to 1 if you have the header file. */ #undef HAVE_INTTYPES_H /* Define to 1 if you have the header file. */ #undef HAVE_IPMI_MONITORING_H /* Define if you have Boutell's libgd installed */ #undef HAVE_LIBGD /* Define to enable libltdl support */ #undef HAVE_LIBLTDL /* Define to 1 if you have the header file. */ #undef HAVE_LIBPOWERMAN_H /* Define to 1 for build where we can support general regex matching. */ #undef HAVE_LIBREGEX /* Define to 1 if you have the `libusb_detach_kernel_driver' function. */ #undef HAVE_LIBUSB_DETACH_KERNEL_DRIVER /* Define to 1 if you have the `libusb_detach_kernel_driver_np' function. */ #undef HAVE_LIBUSB_DETACH_KERNEL_DRIVER_NP /* Define to 1 if you have the `libusb_get_port_number' function. */ #undef HAVE_LIBUSB_GET_PORT_NUMBER /* Define to 1 if you have the header file. */ #undef HAVE_LIBUSB_H /* Define to 1 if you have the `libusb_init' function. */ #undef HAVE_LIBUSB_INIT /* Define to 1 if you have the `libusb_kernel_driver_active' function. */ #undef HAVE_LIBUSB_KERNEL_DRIVER_ACTIVE /* Define to 1 if you have the `libusb_set_auto_detach_kernel_driver' function. */ #undef HAVE_LIBUSB_SET_AUTO_DETACH_KERNEL_DRIVER /* Define to 1 if you have the `libusb_strerror' function. */ #undef HAVE_LIBUSB_STRERROR /* Define to 1 if you have . */ #undef HAVE_LIMITS_H /* Define to 1 if you have . */ #undef HAVE_LINUX_I2C_DEV_H /* Define to 1 if you have . */ #undef HAVE_LINUX_SMBUS_H /* Define to 1 if you have the `localtime_r' function. */ #undef HAVE_LOCALTIME_R /* Define to 1 if you have the `localtime_s' function. */ #undef HAVE_LOCALTIME_S /* Define to 1 if you have the `lockf' function. */ #undef HAVE_LOCKF /* Define to 1 if the system has the type `long double'. */ #undef HAVE_LONG_DOUBLE /* Define to 1 if the system has the type `long long int'. */ #undef HAVE_LONG_LONG_INT /* Define to 1 if you have the header file. */ #undef HAVE_LTDL_H /* Define to 1 if you have the header file. */ #undef HAVE_LUSB0_USB_H /* Define to 1 if you have . */ #undef HAVE_MATH_H /* Define to 1 if you have the header file. */ #undef HAVE_MINIX_CONFIG_H /* Define to 1 if you have the header file. */ #undef HAVE_MODBUS_H /* Define to 1 if you have the `modbus_new_rtu' function. */ #undef HAVE_MODBUS_NEW_RTU /* Define to 1 if you have the `modbus_new_rtu_usb' function. */ #undef HAVE_MODBUS_NEW_RTU_USB /* Define to 1 if you have the `modbus_new_tcp' function. */ #undef HAVE_MODBUS_NEW_TCP /* Define to 1 if you have the `modbus_set_byte_timeout' function. */ #undef HAVE_MODBUS_SET_BYTE_TIMEOUT /* Define to 1 if you have the `modbus_set_response_timeout' function. */ #undef HAVE_MODBUS_SET_RESPONSE_TIMEOUT /* Define to 1 if you have the header file. */ #undef HAVE_NETDB_H /* Define to 1 if you have the header file. */ #undef HAVE_NET_SNMP_NET_SNMP_CONFIG_H /* Define to 1 if you have the `ne_set_connect_timeout' function. */ #undef HAVE_NE_SET_CONNECT_TIMEOUT /* Define to 1 if you have the `ne_sock_connect_timeout' function. */ #undef HAVE_NE_SOCK_CONNECT_TIMEOUT /* Define to 1 if you have the header file. */ #undef HAVE_NE_XMLREQ_H /* Define to 1 if you have the `ne_xml_dispatch_request' function. */ #undef HAVE_NE_XML_DISPATCH_REQUEST /* Define to 1 if you have the header file. */ #undef HAVE_NSS_H /* Define to 1 if you have the `NSS_Init' function. */ #undef HAVE_NSS_INIT /* Define to 1 if you have the `on_exit' function. */ #undef HAVE_ON_EXIT /* Define to 1 if you have the header file. */ #undef HAVE_OPENSSL_SSL_H /* Define to 1 if you have the `pm_connect' function. */ #undef HAVE_PM_CONNECT /* Define to 1 if you have . */ #undef HAVE_POLL_H /* define if your compiler has pragmas for GCC diagnostic ignored "-Wc++98-compat(-pedantic)" and for push-pop support */ #undef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_CXX98_COMPAT /* define if your compiler has pragmas for GCC diagnostic ignored "-Wc++98-compat(-pedantic)" and for push-pop support (outside function bodies) */ #undef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_CXX98_COMPAT_BESIDEFUNC /* define if your compiler has pragmas for GCC diagnostic ignored "-Wformat-nonliteral" or "-Wformat-security" and for push-pop support */ #undef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL /* define if your compiler has pragmas for GCC diagnostic ignored "-Wformat-nonliteral" or "-Wformat-security" and for push-pop support (outside function bodies) */ #undef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL_BESIDEFUNC /* define if your compiler has pragmas for GCC diagnostic ignored "-Wformat-truncation" or "-Werror=stringop-truncation" and for push-pop support */ #undef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_FORMAT_TRUNCATION /* define if your compiler has pragmas for GCC diagnostic ignored "-Wformat-truncation" or "-Werror=stringop-truncation" and for push-pop support (outside function bodies) */ #undef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_FORMAT_TRUNCATION_BESIDEFUNC /* define if your compiler has pragmas for GCC diagnostic ignored "-Wunreachable-code(-break)" and for push-pop support */ #undef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_UNREACHABLE_CODE /* define if your compiler has pragmas for GCC diagnostic ignored "-Wunreachable-code(-break)" and for push-pop support (outside function bodies) */ #undef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_UNREACHABLE_CODE_BESIDEFUNC /* define if your compiler has #pragma clang diagnostic ignored "-Wunreachable-code-return" */ #undef HAVE_PRAGMA_CLANG_DIAGNOSTIC_IGNORED_UNREACHABLE_CODE_RETURN /* define if your compiler has #pragma clang diagnostic ignored "-Wunreachable-code-return" (outside functions) */ #undef HAVE_PRAGMA_CLANG_DIAGNOSTIC_IGNORED_UNREACHABLE_CODE_RETURN_BESIDEFUNC /* define if your compiler has #pragma clang diagnostic push and pop */ #undef HAVE_PRAGMA_CLANG_DIAGNOSTIC_PUSH_POP /* define if your compiler has #pragma clang diagnostic push and pop outside function bodies */ #undef HAVE_PRAGMA_CLANG_DIAGNOSTIC_PUSH_POP_BESIDEFUNC /* define if your compiler has #pragma clang diagnostic push and pop inside function bodies */ #undef HAVE_PRAGMA_CLANG_DIAGNOSTIC_PUSH_POP_INSIDEFUNC /* define if your compiler has #pragma GCC diagnostic ignored "-Warray-bounds" */ #undef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_ARRAY_BOUNDS /* define if your compiler has #pragma GCC diagnostic ignored "-Warray-bounds" (outside functions) */ #undef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_ARRAY_BOUNDS_BESIDEFUNC /* define if your compiler has #pragma GCC diagnostic ignored "-Wassign-enum" */ #undef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_ASSIGN_ENUM /* define if your compiler has #pragma GCC diagnostic ignored "-Wassign-enum" (outside functions) */ #undef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_ASSIGN_ENUM_BESIDEFUNC /* define if your compiler has #pragma GCC diagnostic ignored "-Wcast-align" */ #undef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_CAST_ALIGN /* define if your compiler has #pragma GCC diagnostic ignored "-Wcast-align" (outside functions) */ #undef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_CAST_ALIGN_BESIDEFUNC /* define if your compiler has #pragma GCC diagnostic ignored "-Wcast-function-type-strict" */ #undef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_CAST_FUNCTION_TYPE_STRICT /* define if your compiler has #pragma GCC diagnostic ignored "-Wcast-function-type-strict" (outside functions) */ #undef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_CAST_FUNCTION_TYPE_STRICT_BESIDEFUNC /* define if your compiler has #pragma GCC diagnostic ignored "-Wcovered-switch-default" */ #undef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_COVERED_SWITCH_DEFAULT /* define if your compiler has #pragma GCC diagnostic ignored "-Wcovered-switch-default" (outside functions) */ #undef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_COVERED_SWITCH_DEFAULT_BESIDEFUNC /* define if your compiler has #pragma GCC diagnostic ignored "-Wc++98-compat" */ #undef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_CXX98_COMPAT /* define if your compiler has #pragma GCC diagnostic ignored "-Wc++98-compat" (outside functions) */ #undef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_CXX98_COMPAT_BESIDEFUNC /* define if your compiler has #pragma GCC diagnostic ignored "-Wc++98-compat-pedantic" */ #undef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_CXX98_COMPAT_PEDANTIC /* define if your compiler has #pragma GCC diagnostic ignored "-Wc++98-compat-pedantic" (outside functions) */ #undef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_CXX98_COMPAT_PEDANTIC_BESIDEFUNC /* define if your compiler has #pragma GCC diagnostic ignored "-Wexit-time-destructors" */ #undef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_EXIT_TIME_DESTRUCTORS /* define if your compiler has #pragma GCC diagnostic ignored "-Wexit-time-destructors" (outside functions) */ #undef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_EXIT_TIME_DESTRUCTORS_BESIDEFUNC /* define if your compiler has #pragma GCC diagnostic ignored "-Wextra-semi-stmt" */ #undef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_EXTRA_SEMI_STMT /* define if your compiler has #pragma GCC diagnostic ignored "-Wextra-semi-stmt" (outside functions) */ #undef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_EXTRA_SEMI_STMT_BESIDEFUNC /* define if your compiler has #pragma GCC diagnostic ignored "-Wformat-nonliteral" */ #undef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL /* define if your compiler has #pragma GCC diagnostic ignored "-Wformat-nonliteral" (outside functions) */ #undef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL_BESIDEFUNC /* define if your compiler has #pragma GCC diagnostic ignored "-Wformat-overflow" */ #undef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_FORMAT_OVERFLOW /* define if your compiler has #pragma GCC diagnostic ignored "-Wformat-overflow" (outside functions) */ #undef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_FORMAT_OVERFLOW_BESIDEFUNC /* define if your compiler has #pragma GCC diagnostic ignored "-Wformat-security" */ #undef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_FORMAT_SECURITY /* define if your compiler has #pragma GCC diagnostic ignored "-Wformat-security" (outside functions) */ #undef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_FORMAT_SECURITY_BESIDEFUNC /* define if your compiler has #pragma GCC diagnostic ignored "-Wformat-truncation" */ #undef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_FORMAT_TRUNCATION /* define if your compiler has #pragma GCC diagnostic ignored "-Wformat-truncation" (outside functions) */ #undef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_FORMAT_TRUNCATION_BESIDEFUNC /* define if your compiler has #pragma GCC diagnostic ignored "-Wglobal-constructors" */ #undef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_GLOBAL_CONSTRUCTORS /* define if your compiler has #pragma GCC diagnostic ignored "-Wglobal-constructors" (outside functions) */ #undef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_GLOBAL_CONSTRUCTORS_BESIDEFUNC /* define if your compiler has #pragma GCC diagnostic ignored "-Wsign-compare" */ #undef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_SIGN_COMPARE /* define if your compiler has #pragma GCC diagnostic ignored "-Wsign-compare" (outside functions) */ #undef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_SIGN_COMPARE_BESIDEFUNC /* define if your compiler has #pragma GCC diagnostic ignored "-Wsign-conversion" */ #undef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_SIGN_CONVERSION /* define if your compiler has #pragma GCC diagnostic ignored "-Wsign-conversion" (outside functions) */ #undef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_SIGN_CONVERSION_BESIDEFUNC /* define if your compiler has #pragma GCC diagnostic ignored "-Wstrict-prototypes" */ #undef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_STRICT_PROTOTYPES /* define if your compiler has #pragma GCC diagnostic ignored "-Wstrict-prototypes" (outside functions) */ #undef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_STRICT_PROTOTYPES_BESIDEFUNC /* define if your compiler has #pragma GCC diagnostic ignored "-Wstringop-truncation" */ #undef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_STRINGOP_TRUNCATION /* define if your compiler has #pragma GCC diagnostic ignored "-Wstringop-truncation" (outside functions) */ #undef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_STRINGOP_TRUNCATION_BESIDEFUNC /* define if your compiler has #pragma GCC diagnostic ignored "-Wtautological-compare" */ #undef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_TAUTOLOGICAL_COMPARE /* define if your compiler has #pragma GCC diagnostic ignored "-Wtautological-compare" (outside functions) */ #undef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_TAUTOLOGICAL_COMPARE_BESIDEFUNC /* define if your compiler has #pragma GCC diagnostic ignored "-Wtautological-constant-out-of-range-compare" */ #undef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_TAUTOLOGICAL_CONSTANT_OUT_OF_RANGE_COMPARE /* define if your compiler has #pragma GCC diagnostic ignored "-Wtautological-constant-out-of-range-compare" (outside functions) */ #undef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_TAUTOLOGICAL_CONSTANT_OUT_OF_RANGE_COMPARE_BESIDEFUNC /* define if your compiler has #pragma GCC diagnostic ignored "-Wtautological-type-limit-compare" */ #undef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_TAUTOLOGICAL_TYPE_LIMIT_COMPARE /* define if your compiler has #pragma GCC diagnostic ignored "-Wtautological-type-limit-compare" (outside functions) */ #undef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_TAUTOLOGICAL_TYPE_LIMIT_COMPARE_BESIDEFUNC /* define if your compiler has #pragma GCC diagnostic ignored "-Wtautological-unsigned-zero-compare" */ #undef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_TAUTOLOGICAL_UNSIGNED_ZERO_COMPARE /* define if your compiler has #pragma GCC diagnostic ignored "-Wtautological-unsigned-zero-compare" (outside functions) */ #undef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_TAUTOLOGICAL_UNSIGNED_ZERO_COMPARE_BESIDEFUNC /* define if your compiler has #pragma GCC diagnostic ignored "-Wtype-limits" */ #undef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_TYPE_LIMITS /* define if your compiler has #pragma GCC diagnostic ignored "-Wtype-limits" (outside functions) */ #undef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_TYPE_LIMITS_BESIDEFUNC /* define if your compiler has #pragma GCC diagnostic ignored "-Wunreachable-code" */ #undef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_UNREACHABLE_CODE /* define if your compiler has #pragma GCC diagnostic ignored "-Wunreachable-code" (outside functions) */ #undef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_UNREACHABLE_CODE_BESIDEFUNC /* define if your compiler has #pragma GCC diagnostic ignored "-Wunreachable-code-break" */ #undef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_UNREACHABLE_CODE_BREAK /* define if your compiler has #pragma GCC diagnostic ignored "-Wunreachable-code-break" (outside functions) */ #undef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_UNREACHABLE_CODE_BREAK_BESIDEFUNC /* define if your compiler has #pragma GCC diagnostic ignored "-Wunreachable-code-return" */ #undef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_UNREACHABLE_CODE_RETURN /* define if your compiler has #pragma GCC diagnostic ignored "-Wunreachable-code-return" (outside functions) */ #undef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_UNREACHABLE_CODE_RETURN_BESIDEFUNC /* define if your compiler has #pragma GCC diagnostic ignored "-Wunused-function" */ #undef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_UNUSED_FUNCTION /* define if your compiler has #pragma GCC diagnostic push and pop */ #undef HAVE_PRAGMA_GCC_DIAGNOSTIC_PUSH_POP /* define if your compiler has #pragma GCC diagnostic push and pop outside function bodies */ #undef HAVE_PRAGMA_GCC_DIAGNOSTIC_PUSH_POP_BESIDEFUNC /* define if your compiler has #pragma GCC diagnostic push and pop inside function bodies */ #undef HAVE_PRAGMA_GCC_DIAGNOSTIC_PUSH_POP_INSIDEFUNC /* Define to enable pthread support code */ #undef HAVE_PTHREAD /* Define to enable pthread_tryjoin support code */ #undef HAVE_PTHREAD_TRYJOIN /* Define to 1 if you have . */ #undef HAVE_REGEX_H /* Define to 1 if you have the `sd_booted' function. */ #undef HAVE_SD_BOOTED /* Define to 1 if you have the `sd_notify' function. */ #undef HAVE_SD_NOTIFY /* Define to 1 if you have the `sd_notify_barrier' function. */ #undef HAVE_SD_NOTIFY_BARRIER /* Define to 1 if you have the `sd_watchdog_enabled' function. */ #undef HAVE_SD_WATCHDOG_ENABLED /* Define to 1 if you have with usable sem_t sem_init() and sem_destroy(). */ #undef HAVE_SEMAPHORE /* Define to 1 if you have . */ #undef HAVE_SEMAPHORE_H /* Define to 1 if you have the `setenv' function. */ #undef HAVE_SETENV /* Define to 1 if you have the `seteuid' function. */ #undef HAVE_SETEUID /* Define to 1 if you have the `setlogmask' function. */ #undef HAVE_SETLOGMASK /* Define to 1 if you have the `setsid' function. */ #undef HAVE_SETSID /* Define to 1 if you have the `sigaction' function. */ #undef HAVE_SIGACTION /* Define to 1 if you have the `sigemptyset' function. */ #undef HAVE_SIGEMPTYSET /* Define to 1 if you have . */ #undef HAVE_SIGNAL_H /* Define to 1 if you have the `snprintf' function. */ #undef HAVE_SNPRINTF /* Define to 1 if you have the `SSL_CTX_new' function. */ #undef HAVE_SSL_CTX_NEW /* Define to 1 if you have the header file. */ #undef HAVE_SSL_H /* Define to 1 if you have the header file. */ #undef HAVE_STDARG_H /* Define to 1 if you have the header file. */ #undef HAVE_STDINT_H /* Define to 1 if you have the header file. */ #undef HAVE_STDIO_H /* Define to 1 if you have . */ #undef HAVE_STDLIB_H /* defined if standard library has, and C standard allows, the strcasecmp(s1,s2) method */ #undef HAVE_STRCASECMP /* defined if standard library has, and C standard allows, the strcasestr(s1,s2) method */ #undef HAVE_STRCASESTR /* defined if standard library has, and C standard allows, the strdup(s) method */ #undef HAVE_STRDUP /* Define to 1 if you have the `strerror' function. */ #undef HAVE_STRERROR /* Define to 1 if you have . */ #undef HAVE_STRINGS_H /* Define to 1 if you have . */ #undef HAVE_STRING_H /* defined if standard library has, and C standard allows, the strlwr(s1,s2) method */ #undef HAVE_STRLWR /* defined if standard library has, and C standard allows, the strncasecmp(s1,s2,n) method */ #undef HAVE_STRNCASECMP /* defined if standard library has, and C standard allows, the strnlen(s1,s2) method */ #undef HAVE_STRNLEN /* defined if standard library has, and C standard allows, the strptime(s1,s2,tm) method */ #undef HAVE_STRPTIME /* defined if standard library has, and C standard allows, the strsep(s1,s2) method */ #undef HAVE_STRSEP /* defined if standard library has, and C standard allows, the strstr(s1,s2) method */ #undef HAVE_STRSTR /* Define to 1 if you have the `strtok_r' function. */ #undef HAVE_STRTOK_R /* defined if system has the struct pollfd type */ #undef HAVE_STRUCT_POLLFD /* defined if standard library has, and C standard allows, the suseconds_t type */ #undef HAVE_SUSECONDS_T /* Define to consider basic systemd support (provide units and configuration files) */ #undef HAVE_SYSTEMD /* Define to 1 if you have the header file. */ #undef HAVE_SYSTEMD_SD_DAEMON_H /* Define to 1 if you have the header file. */ #undef HAVE_SYS_MODEM_H /* Define to 1 if you have with usable struct rlimit and getrlimit(). */ #undef HAVE_SYS_RESOURCE_H /* Define to 1 if you have . */ #undef HAVE_SYS_SELECT_H /* Define to 1 if you have . */ #undef HAVE_SYS_SIGNAL_H /* Define to 1 if you have the header file. */ #undef HAVE_SYS_SOCKET_H /* Define to 1 if you have the header file. */ #undef HAVE_SYS_STAT_H /* Define to 1 if you have the header file. */ #undef HAVE_SYS_TERMIOS_H /* Define to 1 if you have the header file. */ #undef HAVE_SYS_TIME_H /* Define to 1 if you have the header file. */ #undef HAVE_SYS_TYPES_H /* Define to 1 if you have the header file. */ #undef HAVE_TCPD_H /* Define to 1 if you have the `tcsendbreak' function. */ #undef HAVE_TCSENDBREAK /* Define to 1 if you have the header file. */ #undef HAVE_TERMIOS_H /* Define to 1 if you have the header file. */ #undef HAVE_TIME_H /* Define to 1 if you have the header file. */ #undef HAVE_UNISTD_H /* Define to 1 if the system has the type `unsigned long long int'. */ #undef HAVE_UNSIGNED_LONG_LONG_INT /* Define to 1 if you have the `usb_detach_kernel_driver_np' function. */ #undef HAVE_USB_DETACH_KERNEL_DRIVER_NP /* Define to 1 if you have the header file. */ #undef HAVE_USB_H /* Define to 1 if you have the `usb_init' function. */ #undef HAVE_USB_INIT /* defined if standard library has, and C standard allows, the useconds_t type */ #undef HAVE_USECONDS_T /* defined if standard library has, and C standard allows, the usleep(us) method */ #undef HAVE_USLEEP /* Use uu_lock for locking (FreeBSD) */ #undef HAVE_UU_LOCK /* Define to 1 if you have the header file. */ #undef HAVE_VARARGS_H /* Define to 1 if you have the `vsnprintf' function. */ #undef HAVE_VSNPRINTF /* Define to 1 if you have the header file. */ #undef HAVE_WCHAR_H /* Define to 1 if you have the windows.h header file. */ #undef HAVE_WINDOWS_H /* Define to 1 if you have the header file. */ #undef HAVE_WINSOCK2_H /* Define to enable libwrap support */ #undef HAVE_WRAP /* Define to 1 if you have the header file. */ #undef HAVE_WS2TCPIP_H /* define if your compiler has __attribute__ */ #undef HAVE___ATTRIBUTE__ /* define if your compiler has __attribute__((noreturn)) */ #undef HAVE___ATTRIBUTE__NORETURN /* define if your compiler has __attribute__((unused)) for function arguments */ #undef HAVE___ATTRIBUTE__UNUSED_ARG /* define if your compiler has __attribute__((unused)) for functions */ #undef HAVE___ATTRIBUTE__UNUSED_FUNC /* Default path for HTML files (CGI templates) */ #undef HTMLPATH /* Default path for system libraries */ #undef LIBDIR /* Default path for system exec-libraries */ #undef LIBEXECDIR /* Desired syslog facility - see syslog(3) */ #undef LOG_FACILITY /* Define to the sub-directory where libtool stores uninstalled libraries. */ #undef LT_OBJDIR /* host multiarch spec we build for (as suggested by compiler being used) */ #undef MULTIARCH_TARGET_ALIAS /* Define to use explicit getopt declarations */ #undef NEED_GETOPT_DECLS /* Define if getopt.h is needed */ #undef NEED_GETOPT_H /* Default path for data files */ #undef NUT_DATADIR /* Variable or macro by this name is not resolvable */ #undef NUT_HAVE_LIBNETSNMP_DRAFT_BLUMENTHAL_AES_04 /* Variable or macro by this name is not resolvable */ #undef NUT_HAVE_LIBNETSNMP_usmAES128PrivProtocol /* Variable or macro by this name is not resolvable */ #undef NUT_HAVE_LIBNETSNMP_usmAES192PrivProtocol /* Variable or macro by this name is not resolvable */ #undef NUT_HAVE_LIBNETSNMP_usmAES256PrivProtocol /* Variable or macro by this name is not resolvable */ #undef NUT_HAVE_LIBNETSNMP_usmAESPrivProtocol /* Variable or macro by this name is not resolvable */ #undef NUT_HAVE_LIBNETSNMP_usmDESPrivProtocol /* Variable or macro by this name is not resolvable */ #undef NUT_HAVE_LIBNETSNMP_usmHMAC192SHA256AuthProtocol /* Variable or macro by this name is not resolvable */ #undef NUT_HAVE_LIBNETSNMP_usmHMAC256SHA384AuthProtocol /* Variable or macro by this name is not resolvable */ #undef NUT_HAVE_LIBNETSNMP_usmHMAC384SHA512AuthProtocol /* Variable or macro by this name is not resolvable */ #undef NUT_HAVE_LIBNETSNMP_usmHMACMD5AuthProtocol /* Variable or macro by this name is not resolvable */ #undef NUT_HAVE_LIBNETSNMP_usmHMACSHA1AuthProtocol /* Define to use libmodbus USB backend */ #undef NUT_MODBUS_HAS_USB /* ${COMMENT} */ #undef NUT_MODBUS_TIMEOUT_ARG_sec_usec_uint32 /* ${COMMENT} */ #undef NUT_MODBUS_TIMEOUT_ARG_sec_usec_uint32_cast_timeval_fields /* ${COMMENT} */ #undef NUT_MODBUS_TIMEOUT_ARG_timeval /* ${COMMENT} */ #undef NUT_MODBUS_TIMEOUT_ARG_timeval_numeric_fields /* NUT network protocol version */ #undef NUT_NETVERSION /* Name of package */ #undef PACKAGE /* Define to the address where bug reports for this package should be sent. */ #undef PACKAGE_BUGREPORT /* Define to the full name of this package. */ #undef PACKAGE_NAME /* Define to the full name and version of this package. */ #undef PACKAGE_STRING /* Define to the one symbol short name of this package. */ #undef PACKAGE_TARNAME /* Define to the home page for this package. */ #undef PACKAGE_URL /* Define to the version of this package. */ #undef PACKAGE_VERSION /* Path for pid files of processes running as root */ #undef PIDPATH /* Port for network communications */ #undef PORT /* Default installation prefix path */ #undef PREFIX /* Define to 0 if your libc can printf("%s", NULL) sanely, or to 1 if your libc requires workarounds to print NULL values. */ #undef REQUIRE_NUT_STRARG /* Group membership of user to switch to if started as root */ #undef RUN_AS_GROUP /* User to switch to if started as root */ #undef RUN_AS_USER /* Default path for system executables */ #undef SBINDIR /* The size of `void *', as computed by sizeof. */ #undef SIZEOF_VOID_P /* Path for UPS driver state files */ #undef STATEPATH /* Define to 1 if all of the C90 standard headers exist (not just the ones required in a freestanding environment). This macro is provided for backward compatibility; new code need not use it. */ #undef STDC_HEADERS /* Define to 1 for Sun version of the libusb. */ #undef SUN_LIBUSB /* Define to 1 if you can safely include both and . This macro is deemed obsolete by autotools. */ #undef TIME_WITH_SYS_TIME /* NUT tree version */ #undef TREE_VERSION /* Enable extensions on AIX 3, Interix. */ #ifndef _ALL_SOURCE # undef _ALL_SOURCE #endif /* Enable general extensions on macOS. */ #ifndef _DARWIN_C_SOURCE # undef _DARWIN_C_SOURCE #endif /* Enable general extensions on Solaris. */ #ifndef __EXTENSIONS__ # undef __EXTENSIONS__ #endif /* Enable GNU extensions on systems that have them. */ #ifndef _GNU_SOURCE # undef _GNU_SOURCE #endif /* Enable X/Open compliant socket functions that do not require linking with -lxnet on HP-UX 11.11. */ #ifndef _HPUX_ALT_XOPEN_SOCKET_API # undef _HPUX_ALT_XOPEN_SOCKET_API #endif /* Identify the host operating system as Minix. This macro does not affect the system headers' behavior. A future release of Autoconf may stop defining this macro. */ #ifndef _MINIX # undef _MINIX #endif /* Enable general extensions on NetBSD. Enable NetBSD compatibility extensions on Minix. */ #ifndef _NETBSD_SOURCE # undef _NETBSD_SOURCE #endif /* Enable OpenBSD compatibility extensions on NetBSD. Oddly enough, this does nothing on OpenBSD. */ #ifndef _OPENBSD_SOURCE # undef _OPENBSD_SOURCE #endif /* Define to 1 if needed for POSIX-compatible behavior. */ #ifndef _POSIX_SOURCE # undef _POSIX_SOURCE #endif /* Define to 2 if needed for POSIX-compatible behavior. */ #ifndef _POSIX_1_SOURCE # undef _POSIX_1_SOURCE #endif /* Enable POSIX-compatible threading on Solaris. */ #ifndef _POSIX_PTHREAD_SEMANTICS # undef _POSIX_PTHREAD_SEMANTICS #endif /* Enable extensions specified by ISO/IEC TS 18661-5:2014. */ #ifndef __STDC_WANT_IEC_60559_ATTRIBS_EXT__ # undef __STDC_WANT_IEC_60559_ATTRIBS_EXT__ #endif /* Enable extensions specified by ISO/IEC TS 18661-1:2014. */ #ifndef __STDC_WANT_IEC_60559_BFP_EXT__ # undef __STDC_WANT_IEC_60559_BFP_EXT__ #endif /* Enable extensions specified by ISO/IEC TS 18661-2:2015. */ #ifndef __STDC_WANT_IEC_60559_DFP_EXT__ # undef __STDC_WANT_IEC_60559_DFP_EXT__ #endif /* Enable extensions specified by ISO/IEC TS 18661-4:2015. */ #ifndef __STDC_WANT_IEC_60559_FUNCS_EXT__ # undef __STDC_WANT_IEC_60559_FUNCS_EXT__ #endif /* Enable extensions specified by ISO/IEC TS 18661-3:2015. */ #ifndef __STDC_WANT_IEC_60559_TYPES_EXT__ # undef __STDC_WANT_IEC_60559_TYPES_EXT__ #endif /* Enable extensions specified by ISO/IEC TR 24731-2:2010. */ #ifndef __STDC_WANT_LIB_EXT2__ # undef __STDC_WANT_LIB_EXT2__ #endif /* Enable extensions specified by ISO/IEC 24747:2009. */ #ifndef __STDC_WANT_MATH_SPEC_FUNCS__ # undef __STDC_WANT_MATH_SPEC_FUNCS__ #endif /* Enable extensions on HP NonStop. */ #ifndef _TANDEM_SOURCE # undef _TANDEM_SOURCE #endif /* Enable X/Open extensions. Define to 500 only if necessary to make mbstate_t available. */ #ifndef _XOPEN_SOURCE # undef _XOPEN_SOURCE #endif /* Version number of package */ #undef VERSION /* Define if WSAStartup is needed. */ #undef WINDOWS_SOCKETS /* Define to enable Asciidoc support */ #undef WITH_ASCIIDOC /* Define to enable Avahi support */ #undef WITH_AVAHI /* Define to enable CGI (HTTP) support */ #undef WITH_CGI /* Define to enable development files support */ #undef WITH_DEV /* Define to enable overall documentation generation */ #undef WITH_DOCS /* Define to enable IPMI support using FreeIPMI */ #undef WITH_FREEIPMI /* Define to enable GPIO support */ #undef WITH_GPIO /* Define to enable IPMI support */ #undef WITH_IPMI /* Define to enable libltdl (Libtool dlopen abstraction) support */ #undef WITH_LIBLTDL /* Define to enable Powerman PDU support */ #undef WITH_LIBPOWERMAN /* Define to build with tighter systemd support (sd_notify etc) */ #undef WITH_LIBSYSTEMD /* Define to 1 for version 0.1 of the libusb (via pkg-config or libusb-config). */ #undef WITH_LIBUSB_0_1 /* Define to 1 for version 1.0 of the libusb (via pkg-config). */ #undef WITH_LIBUSB_1_0 /* Define to enable I2C support */ #undef WITH_LINUX_I2C /* Define to enable Mac OS X meta-driver */ #undef WITH_MACOSX /* Define to enable Modbus support */ #undef WITH_MODBUS /* Define to enable Neon HTTP support */ #undef WITH_NEON /* Define to enable SSL support using Mozilla NSS */ #undef WITH_NSS /* Define to enable NUT-Monitor desktop application installation */ #undef WITH_NUT_MONITOR /* Define to enable nut-scanner tool support */ #undef WITH_NUT_SCANNER /* Define to enable SSL support using OpenSSL */ #undef WITH_OPENSSL /* Define to enable PyNUT module installation */ #undef WITH_PYNUT /* Define to enable serial support */ #undef WITH_SERIAL /* Define to enable SNMP support */ #undef WITH_SNMP /* Define to use SNMP support with a statically linked libnetsnmp */ #undef WITH_SNMP_STATIC /* Define to enable SSL */ #undef WITH_SSL /* Define to enable data points discovered during subdriver generation but not mapped to nut-names yet */ #undef WITH_UNMAPPED_DATA_POINTS /* Define to enable USB support */ #undef WITH_USB /* Define to 1 for libusb versions where we can support "busport" USB matching value. */ #undef WITH_USB_BUSPORT /* Define to enable libwrap (tcp-wrappers) support */ #undef WITH_WRAP /* Define WORDS_BIGENDIAN to 1 if your processor stores words with the most significant byte first (like Motorola and SPARC, unlike Intel). */ #if defined AC_APPLE_UNIVERSAL_BUILD # if defined __BIG_ENDIAN__ # define WORDS_BIGENDIAN 1 # endif #else # ifndef WORDS_BIGENDIAN # undef WORDS_BIGENDIAN # endif #endif /* Define to 1 if C does not support variable-length arrays, and if the compiler does not already define this. */ #undef __STDC_NO_VLA__ /* Replace missing __func__ declaration */ #undef __func__ /* Define to `__inline__' or `__inline' if that's what the C compiler calls it, or to nothing if 'inline' is not supported under any name. */ #ifndef __cplusplus #undef inline #endif /* type to use in place of socklen_t if not defined */ #undef socklen_t nut-2.8.1/include/proto.h0000644000175000017500000000650114501607135012214 00000000000000/* proto.h - fill in the gaps about prototypes and definitions for portability Copyright (C) 2001 Russell Kroll 2005 Arnaud Quette 2006 Peter Selinger 2013 Emilien Kia 2020 Jim Klimov 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 2 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, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef NUT_PROTO_H_SEEN #define NUT_PROTO_H_SEEN 1 #include "config.h" #include "attribute.h" #ifdef __cplusplus /* *INDENT-OFF* */ extern "C" { /* *INDENT-ON* */ #endif #if !defined(HAVE_SNPRINTF) || !defined(HAVE_VSNPRINTF) /* Define this as a fall through, HAVE_STDARG_H is probably already set */ #ifndef HAVE_VARARGS_H #define HAVE_VARARGS_H #endif /* varargs declarations: */ #if defined(HAVE_STDARG_H) # include # define HAVE_STDARGS /* let's hope that works everywhere (mj) */ # define VA_LOCAL_DECL va_list ap # define VA_START(f) va_start(ap, f) # define VA_SHIFT(v,t) ; /* no-op for ANSI */ # define VA_END va_end(ap) #else # if defined(HAVE_VARARGS_H) # include # undef HAVE_STDARGS # define VA_LOCAL_DECL va_list ap # define VA_START(f) va_start(ap) /* f is ignored! */ # define VA_SHIFT(v,t) v = va_arg(ap,t) # define VA_END va_end(ap) # else /*XX ** NO VARARGS ** XX*/ # endif #endif #if !defined (HAVE_SNPRINTF) || defined (__Lynx__) int snprintf (char *str, size_t count, const char *fmt, ...) __attribute__ ((__format__ (__printf__, 3, 4))); #endif #if !defined (HAVE_VSNPRINTF) int vsnprintf (char *str, size_t count, const char *fmt, va_list arg); #endif #endif #ifndef HAVE_SETENV int nut_setenv(const char *name, const char *value, int overwrite); static inline int setenv(const char *name, const char *value, int overwrite) { return nut_setenv(name, value, overwrite); } #endif #ifdef __hpux #ifdef HAVE_SYS_MODEM_H #include #endif /* See sys/termio.h and sys/modem.h The following serial bits are not defined by HPUX. The numbers are octal like I found in BSD. TIOCM_ST is used in genericups.[ch] for the Powerware 3115. These defines make it compile, but I have no idea if it works. */ #define TIOCM_LE 0001 /* line enable */ #define TIOCM_ST 0010 /* secondary transmit */ #define TIOCM_SR 0020 /* secondary receive */ #endif #ifdef HAVE_GETPASSPHRASE #define GETPASS getpassphrase #else #define GETPASS getpass #endif #ifdef __Lynx__ /* Missing prototypes on LynxOS */ int seteuid(uid_t); int vprintf(const char *, va_list); int putenv(char *); #endif #ifdef __cplusplus /* *INDENT-OFF* */ } /* *INDENT-ON* */ #endif #endif /* NUT_PROTO_H_SEEN */ nut-2.8.1/include/nut_float.h0000644000175000017500000000435114500336654013051 00000000000000/* * nut_float.h - Network UPS Tools include files for floating point routines * and ways to compare if non-integers are close enough to assume equal * * Copyright (C) 2020 Jim Klimov * * 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 2 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, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef NUT_FLOAT_H_SEEN #define NUT_FLOAT_H_SEEN 1 #include "config.h" #if defined HAVE_FLOAT_H # include #endif #if defined HAVE_MATH_H # include #endif /* Modern compilers frown upon direct comparisons of floating point numbers * since their imprecise internal representations can misfire, and really we * care if they are indiscernably close. To aviod warnings like -Wfloat-equal * we prefer to compare with methods defined below. Note: despite the "floating" * name, fabs() seems to be defined over doubles or wider types, e.g.: * double fabs(double x); * float fabsf(float x); * long double fabsl(long double x); * To be on the safer side, we compare the difference to be smaller or equal to * the Epsilon for the respective numeric type, in order to be equivalent to a * zero for our needs. Various libs define it as "the next representable number * after 1.0 which is not equal to 1.0" for the discrete maths involved; no talk * about exactly comparing it to zero or whether it is the smallest representable * non-zero value... */ #define f_equal(x, y) ( fabsf((float)(x) - (float)(y)) <= FLT_EPSILON ) #define d_equal(x, y) ( fabs((double)(x) - (double)(y)) <= DBL_EPSILON ) #define ld_equal(x, y) ( fabsl((long double)(x) - (long double)(y)) <= LDBL_EPSILON ) #endif /* NUT_FLOAT_H_SEEN */ nut-2.8.1/include/state.h0000644000175000017500000000631614501607135012175 00000000000000/* state.h - Network UPS Tools common state management functions Copyright (C) 2003 Russell Kroll 2012 Arnaud Quette 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 2 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, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef NUT_STATE_H_SEEN #define NUT_STATE_H_SEEN 1 #include "extstate.h" #ifdef __cplusplus /* *INDENT-OFF* */ extern "C" { /* *INDENT-ON* */ #endif #define ST_SOCK_BUF_LEN 512 #if defined(HAVE_CLOCK_GETTIME) && defined(HAVE_CLOCK_MONOTONIC) && HAVE_CLOCK_GETTIME && HAVE_CLOCK_MONOTONIC typedef struct timespec st_tree_timespec_t; #else typedef struct timeval st_tree_timespec_t; #endif typedef struct st_tree_s { char *var; char *val; /* points to raw or safe */ char *raw; /* raw data from caller */ size_t rawsize; char *safe; /* safe data from pconf_encode */ size_t safesize; int flags; long aux; /* When was this entry last written (meaning that * val/raw/safe, flags, aux, enum or range value * was added, changed or deleted)? */ st_tree_timespec_t lastset; struct enum_s *enum_list; struct range_s *range_list; struct st_tree_s *left; struct st_tree_s *right; } st_tree_t; int state_get_timestamp(st_tree_timespec_t *now); int st_tree_node_compare_timestamp(const st_tree_t *node, const st_tree_timespec_t *cutoff); int state_setinfo(st_tree_t **nptr, const char *var, const char *val); int state_addenum(st_tree_t *root, const char *var, const char *val); int state_addrange(st_tree_t *root, const char *var, const int min, const int max); int state_setaux(st_tree_t *root, const char *var, const char *auxs); const char *state_getinfo(st_tree_t *root, const char *var); int state_getflags(st_tree_t *root, const char *var); long state_getaux(st_tree_t *root, const char *var); const enum_t *state_getenumlist(st_tree_t *root, const char *var); const range_t *state_getrangelist(st_tree_t *root, const char *var); void state_setflags(st_tree_t *root, const char *var, size_t numflags, char **flags); int state_addcmd(cmdlist_t **list, const char *cmd); void state_infofree(st_tree_t *node); void state_cmdfree(cmdlist_t *list); int state_delcmd(cmdlist_t **list, const char *cmd); int state_delinfo(st_tree_t **root, const char *var); int state_delinfo_olderthan(st_tree_t **root, const char *var, const st_tree_timespec_t *cutoff); int state_delenum(st_tree_t *root, const char *var, const char *val); int state_delrange(st_tree_t *root, const char *var, const int min, const int max); st_tree_t *state_tree_find(st_tree_t *node, const char *var); #ifdef __cplusplus /* *INDENT-OFF* */ } /* *INDENT-ON* */ #endif #endif /* NUT_STATE_H_SEEN */ nut-2.8.1/INSTALL.nut.adoc0000644000175000017500000006351514520271213012023 00000000000000Installation instructions ========================= This chapter describes the various methods for installing Network UPS Tools. Whenever it is possible, prefer <>. Packagers have done an excellent and hard work at improving NUT integration into their operating system. On the other hand, distributions and appliances tend to package "official releases" of projects such as NUT, and so do not deliver latest and greatest fixes, new drivers, bugs and other features. [[Installing_source]] Installing from source ---------------------- These are the essential steps for compiling and installing this software from distribution archives (usually "release tarballs") which include a pre-built copy of the `configure` script and some other generated source files. To build NUT from a Git checkout you may need some additional tools (referenced just a bit below) and run `./autogen.sh` to generate the needed files. For common developer iterations, porting to new platforms, or in-place testing, running the `./ci_build.sh` script can be helpful. The "<>" section details some more hints about such workflow, including some `systemd` integration. The NUT linkdoc:packager-guide[Packager Guide], which presents the best practices for installing and integrating NUT, is also a good reading. The <> document suggests prerequisite packages with tools and dependencies available and needed to build and test as much as possible of NUT on numerous platforms, written from perspective of CI testing (if you are interested in getting updated drivers for a particular device, you might select a sub-set of those suggestions). NOTE: This "Config Prereqs" document for latest NUT iteration can be found at https://github.com/networkupstools/nut/blob/master/docs/config-prereqs.txt or as `docs/config-prereqs.txt` in your build workspace (from Git or tarball). [NOTE] .Keep in mind that... ================================================================================ - the paths shown below are the default values you get by just calling configure by itself. If you have used --prefix or similar, things will be different. Also, if you didn't install this program from source yourself, the paths will probably have a number of differences. - by default, your system probably won't find the man pages, since they install to /usr/local/ups/man. You can fix this by editing your MANPATH, or just do this: man -M /usr/local/ups/man - if your favorite system offers up to date binary packages, you should always prefer these over a source installation (unless there are known deficiencies in the package or one is too obsolete). Along with the known advantages of such systems for installation, upgrade and removal, there are many integration issues that have been addressed. ================================================================================ Prepare your system ~~~~~~~~~~~~~~~~~~~~ System User creation ^^^^^^^^^^^^^^^^^^^^ Create at least one system user and a group for running this software. You might call them "ups" and "nut". The exact names aren't important as long as you are consistent. The process for doing this varies from one system to the next, and explaining how to add users is beyond the scope of this document. For the purposes of this document, the user name and group name will be 'ups' and 'nut' respectively. Be sure the new user is a member of the new group! If you forget to do this, you will have problems later on when you try to start upsd. Build and install ~~~~~~~~~~~~~~~~~ NOTE: See also <>. [[Configuration]] Configuration ^^^^^^^^^^^^^ Configure the source tree for your system. Add the '--with-user' and '--with-group' switch to set the user name and group that you created above. ./configure --with-user=ups --with-group=nut If you need any other switches for configure, add them here. For example: * to build and install USB drivers, add '--with-usb' (note that you need to install libusb development package or files). * to build and install SNMP drivers, add '--with-snmp' (note that you need to install libsnmp development package or files). * to build and install CGI scripts, add '--with-cgi'. See <> from the User Manual, docs/configure.txt or './configure --help' for all the available options. If you alter paths with additional switches, be sure to use those new paths while reading the rest of the steps. Reference: <> from the User Manual. Build the programs ^^^^^^^^^^^^^^^^^^ make This will build the NUT client and server programs and the selected drivers. It will also build any other features that were selected during <> step above. Installation ^^^^^^^^^^^^ [NOTE] ===================================================================== you should now gain privileges for installing software if necessary: su ===================================================================== Install the files to a system level directory: make install This will install the compiled programs and man pages, as well as some data files required by NUT. Any optional features selected during configuration will also be installed. This will also install sample versions of the NUT configuration files. Sample files are installed with names like ups.conf.sample so they will not overwrite any existing real config files you may have created. If you are packaging this software, then you will probably want to use the DESTDIR variable to redirect the build into another place, i.e.: make DESTDIR=/tmp/package install make DESTDIR=/tmp/package install-conf [[StatePath]] State path creation ^^^^^^^^^^^^^^^^^^^ Create the state path directory for the driver(s) and server to use for storing UPS status data and other auxiliary files, and make it group-writable by the group of the system user you created. mkdir -p /var/state/ups chmod 0770 /var/state/ups chown root:nut /var/state/ups [[Ownership]] Ownership and permissions ^^^^^^^^^^^^^^^^^^^^^^^^^ Set ownership data and permissions on your serial or USB ports that go to your UPS hardware. Be sure to limit access to just the user you created earlier. These examples assume the second serial port (ttyS1) on a typical Slackware system. On FreeBSD, that would be cuaa1. Serial ports vary greatly, so yours may be called something else. chmod 0660 /dev/ttyS1 chown root:nut /dev/ttyS1 //////////////////////////////////////////////////////////////////////////////// FIXME: TBR //////////////////////////////////////////////////////////////////////////////// The setup for USB ports is slightly more complicated. Device files for USB devices, such as /proc/bus/usb/002/001, are usually created "on the fly" when a device is plugged in, and disappear when the device is disconnected. Moreover, the names of these device files can change randomly. To set up the correct permissions for the USB device, you may need to set up (operating system dependent) hotplugging scripts. Sample scripts and information are provided in the scripts/hotplug and scripts/udev directories. For most users, the hotplugging scripts will be installed automatically by "make install". (If you want to try if a driver works without setting up hotplugging, you can add the "-u root" option to upsd, upsmon, and drivers; this should allow you to follow the below instructions. However, don't forget to set up the correct permissions later!). NOTE: if you are using something like udev or devd, make sure these permissions stay set across a reboot. If they revert to the old values, your drivers may fail to start. You are now ready to configure NUT, and start testing and using it. You can jump directly to the <>. [[Installing_inplace]] Building NUT for in‐place upgrades or non‐disruptive tests ---------------------------------------------------------- NOTE: The NUT GitHub Wiki article at https://github.com/networkupstools/nut/wiki/Building-NUT-for-in%E2%80%90place-upgrades-or-non%E2%80%90disruptive-tests may contain some more hints as contributed by the community. Overview ~~~~~~~~ Since late 2022/early 2023 NUT codebase supports "in-place" builds which try their best to discover the configuration of an earlier build (configuration and run-time paths and OS accounts involved, maybe an exact configuration if stored in deployed binaries). This optional mode is primarily intended for several use-cases: * Test recent GitHub "master" branch or a proposed PR to see if it solves a practical problem for a particular user; * Replace an existing deployment, e.g. if OS-provided packages deliver obsolete code, to use newer NUT locally in "production mode". - In such cases ideally get your distribution, NAS vendor, etc. to provide current NUT -- and benefit from a better integrated and tested product. Note that "just testing" often involves building the codebase and new drivers or tools in question, and running them right from the build workspace (without installing into the system and so risking an unpredictable-stability state). In case of testing new driver builds, note that you would need to stop the normally running instances to free up the communications resources (USB/serial ports, etc.), run the new driver program in data-dump mode, and restart the normal systems operations. Such tests still benefit from matching the build configuration to what is already deployed, in order to request same configuration files and system access permissions (e.g. to own device nodes for physical-media ports involved, and to read the production configuration files). Pre-requisites ^^^^^^^^^^^^^^ The <> document details tools and dependencies that were added on NUT CI build environments, which now cover many operating systems. This should provide a decent starting point for the build on yours (PRs to update the document are welcome!) Note that unlike distribution tarballs, Git sources do not include a `configure` script and some other files -- these should be generated by running `autogen.sh` (or `ci_build.sh` that calls it). Getting the right sources ^^^^^^^^^^^^^^^^^^^^^^^^^ To build the current tip of development iterations (usually after PR merges that passed CI, reviews and/or other tests), just clone the NUT repository and "master" branch should get checked out by default (also can request that explicitly, per example posted below). If you want to quickly test a particular pull request, see the link on top of the PR page that says `... wants to merge ... from : ...` and copy the proposed-source URL of that "from" part. For example, in some PR this says `jimklimov:issue-1234` and links to `https://github.com/jimklimov/nut/tree/issue-1234`. For manual git-cloning, just paste that URL into the shell and replace the `/tree/` with "`-b`" CLI option for branch selection, like this: :; cd /tmp ### Checkout https://github.com/jimklimov/nut/tree/issue-1234 :; git clone https://github.com/jimklimov/nut -b issue-1234 Testing with CI helper ~~~~~~~~~~~~~~~~~~~~~~ NOTE: this uses the `ci_build.sh` script to arrange some rituals and settings, in this case primarily to default the choice of drivers to auto-detection of what can be built, and to skip building documentation. Also note that this script supports many other scenarios for CI and developers, managed by `BUILD_TYPE` and other environment variables, which are not explored here. An "in-place" _testing_ build and run would probably go along these lines: :; cd /tmp :; git clone -b master https://github.com/networkupstools/nut :; cd nut :; ./ci_build.sh inplace ### Temporarily stop your original drivers :; ./drivers/nutdrv_qx -a DEVNAME_FROM_UPS_CONF -d1 -DDDDDD \ # -x override...=... -x subdriver=... ### Can start back your original drivers ### Analyze and/or post back the data-dump [NOTE] ====== To probe a device for which you do not have an `ups.conf` section yet, you must specify `-s name` and all config options (including `port`) on command-line with `-x` arguments, e.g.: :; ./drivers/nutdrv_qx -s temp-ups \ -d1 -DDDDDD -x port=auto \ -x vendorid=... -x productid=... \ -x subdriver=... ====== Replacing a NUT deployment ~~~~~~~~~~~~~~~~~~~~~~~~~~ While `ci_build.sh inplace` can be a viable option for preparation of local builds, you may want to have precise control over `configure` options (e.g. choice of required drivers, or enabled documentation). A sound starting point would be to track down packaging recipes used by your distribution (e.g. link:https://src.fedoraproject.org/rpms/nut/blob/rawhide/f/nut.spec[RPM spec] or link:https://salsa.debian.org/debian/nut/-/blob/debian/debian/rules[DEB rules] files, etc.) to detail the same paths if you intend to replace those, and copy the parameters for `configure` script from there -- especially if your system is not currently running NUT v2.8.1 or newer (which embeds this information to facilitate in-place upgrade rebuilds). Note that the primary focus of in-place automated configuration mode is about critical run-time options, such as OS user accounts, configuration location and state/PID paths, so it alone might not replace your driver binaries that the package would put into an obscure location like `/lib/nut`. It would however install init-scripts or systemd units that would refer to new locations specified by the current build, so such old binaries would just consume disk space but not run. Replacing any NUT deployment ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ NOTE: For deployments on OSes with `systemd` see the next section. This goes similar to usual build and install from Git: :; cd /tmp :; git clone https://github.com/networkupstools/nut :; cd nut :; ./autogen.sh :; ./configure --enable-inplace-runtime # --maybe-some-other-options :; make -j 4 all && make -j 4 check && sudo make install Note that `make install` does not currently handle all the nuances that packaging installation scripts would, such as customizing filesystem object ownership, daemon restarts, etc. or even creating locations like `/var/state/ups` and `/var/run/nut` as part of the `make` target (but e.g. the delivered `systemd-tmpfiles` configuration can handle that for a large part of the audience). This aspect is tracked as link:https://github.com/networkupstools/nut/issues/1298[issue #1298] At this point you should revise the locations for PID files (e.g. `/var/run/nut`) and pipe files (e.g. `/var/state/ups`) that they exist and permissions remain suitable for NUT run-time user selected by your configuration, and typically stop your original NUT drivers, data-server (upsd) and upsmon, and restart them using the new binaries. Replacing a systemd-enabled NUT deployment ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ For modern Linux distributions with `systemd` this replacement procedure could be enhanced like below, to also re-enable services (creating proper symlinks) and to get them started: :; cd /tmp :; git clone https://github.com/networkupstools/nut :; cd nut :; ./autogen.sh :; ./configure --enable-inplace-runtime # --maybe-some-other-options :; make -j 4 all && make -j 4 check && \ { sudo systemctl stop nut-monitor nut-server || true ; } && \ { sudo systemctl stop nut-driver.service || true ; } && \ { sudo systemctl stop nut-driver.target || true ; } && \ { sudo systemctl stop nut.target || true ; } && \ sudo make install && \ sudo systemctl daemon-reload && \ sudo systemd-tmpfiles --create && \ sudo systemctl disable nut.target nut-driver.target \ nut-monitor nut-server nut-driver-enumerator.path \ nut-driver-enumerator.service && \ sudo systemctl enable nut.target nut-driver.target \ nut-monitor nut-server nut-driver-enumerator.path \ nut-driver-enumerator.service && \ { sudo systemctl restart udev || true ; } && \ sudo systemctl restart nut-driver-enumerator.service \ nut-monitor nut-server Note the several attempts to stop old service units -- naming did change from 2.7.4 and older releases, through 2.8.0, and up to current codebase. Most of the NUT units are now `WantedBy=nut.target` (which is in turn `WantedBy=multi-user.target` and so bound to system startup). You should only `systemctl enable` those units you need on this system -- this allows it to not start the daemons you do not need (e.g. not run `upsd` NUT data server on systems which are only `upsmon secondary` clients). The `nut-driver-enumerator` units (and corresponding shell script) are part of a new feature introduced in NUT 2.8.0, which automatically discovers `ups.conf` sections and changes to their contents, and manages instances of a `nut-driver@.service` definition. You may also have to restart (or reload if supported) some system services if your updates impact them, like `udev` for updates USB support (note also link:https://github.com/networkupstools/nut/pull/1342[PR #1342] regarding the change from `udev.rules` to `udev.hwdb` file with NUT v2.8.0 or later -- you may have to remove the older file manually). Iterating with a systemd deployment ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ If you are regularly building NUT from GitHub "master" branch, or iterating local development branches of your own, you *may* get away with shorter constructs to just restart the services after installing newly built files (if you know there were no changes to unit file definitions and dependencies), e.g.: :; cd /tmp :; git clone https://github.com/networkupstools/nut :; cd nut :; git checkout -b issue-1234 ### your PR branch name, arbitrary :; ./autogen.sh :; ./configure --enable-inplace-runtime # --maybe-some-other-options ### Iterate your code changes (e.g. PR draft), build and install with: :; make -j 4 all && make -j 4 check && \ sudo make install && \ sudo systemctl daemon-reload && \ sudo systemd-tmpfiles --create && \ sudo systemctl restart \ nut-driver-enumerator.service nut-monitor nut-server Next steps after an in-place upgrade ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ You can jump directly to the <> if you need to revise the settings for your new NUT version, take advantage of new configuration options, etc. Check the linkdoc:NEWS and linkdoc:UPGRADING[Upgrade Notes] files in your Git workspace to review features that should be present in your new build. [[Installing_packages]] Installing from packages ------------------------ This chapter describes the specific installation steps when using binary packages that exist on various major systems. [[Debian]] Debian, Ubuntu and other derivatives ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ NOTE: NUT is packaged and well maintained in these systems. The official Debian packager is part of the NUT Team. Using your preferred method (apt-get, aptitude, Synaptic, ...), install the 'nut' package, and optionally the following: - 'nut-cgi', if you need the CGI (HTML) option, - 'nut-snmp', if you need the snmp-ups driver, - 'nut-xml', for the netxml-ups driver, - 'nut-powerman-pdu', to control the PowerMan daemon (PDU management) - 'nut-dev', if you need the development files. //////////////////////////////////////////////////////////////////////////////// - nut-client //////////////////////////////////////////////////////////////////////////////// Configuration files are located in /etc/nut. linkman:nut.conf[5] must be edited to be able to invoke /etc/init.d/nut NOTE: Ubuntu users can access the APT URL installation by clicking on link:apt://nut[this link]. [[Mandriva]] Mandriva ~~~~~~~~ NOTE: NUT is packaged and well maintained in these systems. The official Mandriva packager is part of the NUT Team. Using your preferred method (urpmi, RPMdrake, ...), install one of the two below packages: - 'nut-server' if you have a 'standalone' or 'netserver' installation, - 'nut' if you have a 'netclient' installation. Optionally, you can also install the following: - 'nut-cgi', if you need the CGI (HTML) option, - 'nut-devel', if you need the development files. [[SUSE]] SUSE / openSUSE ~~~~~~~~~~~~~~~ NOTE: NUT is packaged and well maintained in these systems. The official SUSE packager is part of the NUT Team. Install the 'nut-classic' package, and optionally the following: - 'nut-drivers-net', if you need the snmp-ups or the netxml-ups drivers, - 'nut-cgi', if you need the CGI (HTML) option, - 'nut-devel', if you need the development files, NOTE: SUSE and openSUSE users can use the link:http://software.opensuse.org/search?baseproject=ALL&p=1&q=nut[one-click install method] to install NUT. [[RedHat]] Red Hat, Fedora and CentOS ~~~~~~~~~~~~~~~~~~~~~~~~~~ NOTE: NUT is packaged and well maintained in these systems. The official Red Hat packager is part of the NUT Team. Using your preferred method (yum, Add/Remove Software, ...), install one of the two below packages: - 'nut' if you have a 'standalone' or 'netserver' installation, - 'nut-client' if you have a 'netclient' installation. Optionally, you can also install the following: - 'nut-cgi', if you need the CGI (HTML) option, - 'nut-xml', if you need the netxml-ups driver, - 'nut-devel', if you need the development files. [[FreeBSD]] FreeBSD ~~~~~~~ You can either install NUT as a binary package or as a port. Binary package ^^^^^^^^^^^^^^ To install NUT as a package execute: # pkg install nut Port ^^^^ The port is located under +sysutils/nut+. Use +make config+ to select configuration options, e.g. to build the optional CGI scripts. To install it, use: # make install clean USB UPS on FreeBSD ^^^^^^^^^^^^^^^^^^ For USB UPS devices the NUT package/port installs devd rules in +/usr/local/etc/devd/nut-usb.conf+ to set USB device permissions. 'devd' needs to be restarted for these rules to apply: # service devd restart (Re-)connect the device after restarting 'devd' and check that the USB device has the proper permissions. Check the last entries of the system message buffer. You should find an entry like: # dmesg | tail [...] ugen0.2: at usbus0 The device file must be owned by group +uucp+ and must be group read-/writable. In the example from above this would be # ls -Ll /dev/ugen0.2 crw-rw---- 1 root uucp 0xa5 Mar 12 10:33 /dev/ugen0.2 If the permissions are not correct, verify that your device is registered in +/usr/local/etc/devd/nut-usb.conf+. The vendor and product id can be found using: # usbconfig -u 0 -a 2 dump_device_desc where +-u+ specifies the USB bus number and +-a+ specifies the USB device index. [[Windows]] Windows ~~~~~~~ Windows binary package ^^^^^^^^^^^^^^^^^^^^^^ [NOTE] ====== NUT binary package built for Windows platform was last issued for a much older codebase (using NUT v2.6.5 as a baseline). While the current state of the codebase you are looking at aims to refresh the effort of delivering NUT on Windows, the aim at the moment is to help developers build and modernize it after a decade of blissful slumber, and packages are not being regularly produced yet. Functionality of such builds varies a lot depending on build environment used. This effort is generally tracked at https://github.com/orgs/networkupstools/projects/2/views/1 and help would be welcome! It should currently be possible to build the codebase in native Windows with MSYS2/MinGW and cross-building from Linux with mingw (preferably in a Debian/Ubuntu container). Refer to link:config-prereqs.txt[Prerequisites for building NUT on different OSes] and link:scripts/Windows/README.adoc[scripts/Windows/README.adoc file] for respective build environment preparation instructions. Note that to use NUT for Windows, non-system dependency DLL files must be located in same directory as each EXE file that uses them. This can be accomplished for FOSS libraries (copying them from the build environment) by calling `make install-win-bundle DESTDIR=/some/valid/location` easily. Archives with binaries built by recent iterations of continuous integration jobs should be available for exploration on the respective CI platforms. ====== *Information below may be currently obsolete, but the NUT project wishes it to become actual and factual again :)* NUT binary package built for Windows platform comes in a `.msi` file. If you are using Windows 95, 98 or Me, you should install link:http://www.microsoft.com/downloads/en/details.aspx?familyid=cebbacd8-c094-4255-b702-de3bb768148f&displaylang=en[Windows Installer 2.0] from Microsoft site. If you are using Windows 2000 or NT 4.0, you can link:http://www.microsoft.com/downloads/en/details.aspx?FamilyID=4b6140f9-2d36-4977-8fa1-6f8a0f5dca8f&DisplayLang=en[download it here]. Newer Windows releases should include the Windows Installer natively. Run `NUT-Installer.msi` and follow the wizard indications. If you plan to use an UPS which is locally connected to an USB port, you have to install link:https://sourceforge.net/projects/libusb-win32/files/[libUSB-win32] on your system. Then you must install your device via libusb's "Inf Wizard". NOTE: If you intend to build from source, relevant sources may be available at https://github.com/mcuee/libusb-win32 and keep in mind that it is a variant of libusb-0.1. Current NUT supports libusb-1.0 as well, and that project should have Windows support out of the box (but it was not explored for NUT yet). If you have selected default directory, all configuration files are located in `C:\Program Files\NUT\ups\etc` Building for Windows ^^^^^^^^^^^^^^^^^^^^ For suggestions about setting up the NUT build environment variants for Windows, please see link:docs/config-prereqs.txt and/or link:scripts/Windows/README.adoc files. Note this is rather experimental at this point. Runtime configuration ~~~~~~~~~~~~~~~~~~~~~ You are now ready to configure NUT, and start testing and using it. You can jump directly to the <>. nut-2.8.1/drivers/0000755000175000017500000000000014520277776011030 500000000000000nut-2.8.1/drivers/mge-utalk.c0000644000175000017500000006422414502253356012776 00000000000000/* mge-utalk.c - monitor MGE UPS for NUT with UTalk protocol * * Copyright (C) 2002 - 2005 * Arnaud Quette * Hans Ekkehard Plesser * Martin Loyer * Patrick Agrain * Nicholas Reilly * Dave Abbott * Marek Kralewski * * This driver is a collaborative effort by the above people, * Sponsored by MGE UPS SYSTEMS * * 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 2 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, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /* * IMPLEMENTATION DETAILS * * Not all UTalk models provide all possible information, settings and commands. * mge-utalk checks on startup which variables and commands are available from * the UPS, and re-reads these regularly. Thus, startup is a bit slow, but this * should not matter much. * * mge-utalk.h defines a struct array that tells the driver how to read * variables from the UPS and publish them as NUT data. * * "ups.status" variable is not included in this array, since it contains * information that requires several calls to the UPS and more advanced analysis * of the reponses. The function get_ups_status does this job. * * Note that MGE enumerates the status "bits" from right to left, * i.e., if buf[] contains the reponse to command "Ss" (read system status), * then buf[0] contains "bit" Ss.1.7 (General alarm), while buf[7] contains * "bit" Ss.1.0 (Load unprotected). * * enable_ups_comm() is called before each attempt to read/write data * from/to the UPS to re synchronise the communication. */ #include "config.h" /* must be the first header */ #include #ifndef WIN32 #include #endif #include "timehead.h" #include "main.h" #include "serial.h" #include "mge-utalk.h" #include "nut_stdint.h" /* --------------------------------------------------------------- */ /* Define "technical" constants */ /* --------------------------------------------------------------- */ #define DRIVER_NAME "MGE UPS SYSTEMS/U-Talk driver" #define DRIVER_VERSION "0.95" /* driver description structure */ upsdrv_info_t upsdrv_info = { DRIVER_NAME, DRIVER_VERSION, "Arnaud Quette \n" \ "Hans Ekkehard Plesser \n" \ "Martin Loyer \n" \ "Patrick Agrain \n" \ "Nicholas Reilly \n" \ "Dave Abbott \n" \ "Marek Kralewski ", DRV_STABLE, { NULL } }; /* delay after sending each char to UPS (in MICROSECONDS) */ #define MGE_CHAR_DELAY 0 /* delay after command, before reading UPS reply (in MICROSECONDS) */ #define MGE_REPLY_DELAY 1000 /* delay after enable_ups_comm */ #define MGE_CONNECT_DELAY 500000 #define MGE_COMMAND_ENDCHAR "\r\n" /* some UPS need \r and \n */ #define MGE_REPLY_ENDCHAR '\r' #define MGE_REPLY_IGNCHAR "\r\n" #define MAXTRIES 10 /* max number of connect tries */ #define BUFFLEN 256 #define SD_RETURN 0 #define SD_STAYOFF 1 static int sdtype = SD_RETURN; static time_t lastpoll; /* Timestamp the last polling */ /* --------------------------------------------------------------- */ /* Structure with information about UPS */ /* --------------------------------------------------------------- */ static struct { int MultTab; int LowBatt; /* percent */ int OnDelay; /* minutes */ int OffDelay; /* seconds */ } mge_ups = { 0, DEFAULT_LOWBATT, DEFAULT_ONDELAY, DEFAULT_OFFDELAY }; /* --------------------------------------------------------------- */ /* Declaration of internal functions */ /* --------------------------------------------------------------- */ static int instcmd(const char *cmdname, const char *extra); static int setvar(const char *varname, const char *val); static void enable_ups_comm(void); static void disable_ups_comm(void); static void extract_info(const char *buf, const mge_info_item_t *mge, char *infostr, size_t infolen); static const char *info_variable_cmd(const char *type); static bool_t info_variable_ok(const char *type); static int get_ups_status(void); static ssize_t mge_command(char *reply, size_t replylen, const char *fmt, ...); /* --------------------------------------------------------------- */ /* UPS Driver Functions */ /* --------------------------------------------------------------- */ void upsdrv_makevartable(void) { char temp[BUFFLEN]; snprintf(temp, sizeof(temp), "Low battery level, in %% (default = %3d)", DEFAULT_LOWBATT); addvar (VAR_VALUE, "LowBatt", temp); snprintf(temp, sizeof(temp), "Delay before startup, in minutes (default = %3d)", DEFAULT_ONDELAY); addvar (VAR_VALUE, "OnDelay", temp); snprintf(temp, sizeof(temp), "Delay before shutdown, in seconds (default = %3d)", DEFAULT_OFFDELAY); addvar (VAR_VALUE, "OffDelay", temp); addvar(VAR_FLAG, "oldmac", "Enable Oldworld Apple Macintosh support"); } /* --------------------------------------------------------------- */ void upsdrv_initups(void) { char buf[BUFFLEN]; #ifndef WIN32 int RTS = TIOCM_RTS; #endif upsfd = ser_open(device_path); ser_set_speed(upsfd, device_path, B2400); /* read command line/conf variable that affect comm. */ #ifndef WIN32 if (testvar ("oldmac")) RTS = ~TIOCM_RTS; /* Init serial line */ ioctl(upsfd, TIOCMBIC, &RTS); #else if (testvar ("oldmac")) { EscapeCommFunction(((serial_handler_t *)upsfd)->handle,CLRRTS); } else { EscapeCommFunction(((serial_handler_t *)upsfd)->handle,SETRTS); } #endif enable_ups_comm(); /* Try to set "Low Battery Level" (if supported and given) */ if (getval ("lowbatt")) { mge_ups.LowBatt = atoi (getval ("lowbatt")); /* Set the value in the UPS */ mge_command(buf, sizeof(buf), "Bl %d", mge_ups.LowBatt); if(!strcmp(buf, "OK")) upsdebugx(1, "Low Battery Level set to %d%%", mge_ups.LowBatt); else upsdebugx(1, "initups: Low Battery Level cannot be set"); } /* Try to set "ON delay" (if supported and given) */ if (getval ("ondelay")) { mge_ups.OnDelay = atoi (getval ("ondelay")); /* Set the value in the UPS */ mge_command(buf, sizeof(buf), "Sm %d", mge_ups.OnDelay); if(!strcmp(buf, "OK")) upsdebugx(1, "ON delay set to %d min", mge_ups.OnDelay); else upsdebugx(1, "initups: OnDelay unavailable"); } /* Try to set "OFF delay" (if supported and given) */ if (getval ("offdelay")) { mge_ups.OffDelay = atoi (getval ("offdelay")); /* Set the value in the UPS */ mge_command(buf, sizeof(buf), "Sn %d", mge_ups.OffDelay); if(!strcmp(buf, "OK")) upsdebugx(1, "OFF delay set to %d sec", mge_ups.OffDelay); else upsdebugx(1, "initups: OffDelay unavailable"); } } /* --------------------------------------------------------------- */ void upsdrv_initinfo(void) { char buf[BUFFLEN]; const char *model = NULL; char *firmware = NULL; char *p; char *v = NULL; /* for parsing Si output, get Version ID */ int table; int tries; int status_ok = 0; ssize_t bytes_rcvd; int si_data1 = 0; int si_data2 = 0; mge_info_item_t *item; models_name_t *model_info; mge_model_info_t *legacy_model; char infostr[32]; ssize_t chars_rcvd; /* manufacturer -------------------------------------------- */ dstate_setinfo("ups.mfr", "MGE UPS SYSTEMS"); /* loop until we have at status */ tries = 0; do { printf("."); /* get model information in ASCII string form: */ bytes_rcvd = mge_command(buf, sizeof(buf), "Si 1"); if(bytes_rcvd > 0 && buf[0] != '?') { dstate_setinfo("ups.id", "%s", buf); /* raw id */ model = buf; p = strrchr(buf, ' '); if ( p != NULL ) { *p = '\0'; firmware = p+1; } if( firmware && strlen(firmware) < 1 ) firmware = NULL; /* no firmware information */ /* Parsing model names table */ for ( model_info = Si1_models_names ; model_info->basename != NULL ; model_info++ ) { if(!strcasecmp(model_info->basename, model)) { model = model_info->finalname; upsdebugx(1, "initinfo: UPS model == >%s<", model); break; } } } else { upsdebugx(1, "initinfo: 'Si 1' unavailable, switching to 'Si' command"); /* get model information, numbered form, : */ bytes_rcvd = mge_command(buf, sizeof(buf), "Si"); if(bytes_rcvd > 0 && buf[0] != '?') { upsdebugx(1, "initinfo: Si == >%s<", buf); printf("\nCAUTION : This is an older model. It may not support too much polling.\nPlease read man mge-utalk and use pollinterval\n"); p = strchr(buf, ' '); if ( p != NULL ) { *p = '\0'; si_data1 = atoi(buf); v = p+1; p = strchr(v, ' '); } if ( p != NULL ) { *p = '\0'; si_data2 = atoi(v); } /* Parsing legacy model table in order to find it */ for ( legacy_model = mge_model ; legacy_model->name != NULL ; legacy_model++ ) { if(legacy_model->Data1 == si_data1 && legacy_model->Data2 == si_data2){ model = legacy_model->name; upsdebugx(1, "initinfo: UPS model == >%s<", model); break; } } if( model == NULL ) printf("No model found by that model and version ID\nPlease contact us with UPS model, name and reminder info\nReminder info : Data1=%i , Data2=%i\n", si_data1, si_data2); } } if ( model ) { upsdebugx(2, "Got model name: %s", model); /* deal with truncated model names */ if (!strncmp(model, "Evolutio", 8)) { dstate_setinfo("ups.model", "Evolution %i", atoi(strchr(model, ' '))); } else { dstate_setinfo("ups.model", "%s", model); } } if (firmware && firmware[0] != '\0') dstate_setinfo("ups.firmware", "%s", firmware); else dstate_setinfo("ups.firmware", "unknown"); /* multiplier table */ /* */ bytes_rcvd = mge_command(buf, sizeof(buf), "Ai"); if (bytes_rcvd > 0 && buf[0] != '?') { p = strchr(buf, ' '); if ( p != NULL ) { table = atoi(p + 1); if ( 0 < table && table < 4 ) mge_ups.MultTab = table; } } /* status --- try only system status, to get the really important * information (OL, OB, LB); all else is added later by updateinfo */ status_ok = get_ups_status(); } while ( (!status_ok) && (tries++ < MAXTRIES) && (exit_flag != 1) ); if ( tries == MAXTRIES && !status_ok ) fatalx(EXIT_FAILURE, "Could not get status from UPS."); if ( mge_ups.MultTab == 0 ) upslogx(LOG_WARNING, "Could not get multiplier table: using raw readings."); /* all other variables ------------------------------------ */ for ( item = mge_info ; item->type != NULL ; item++ ) { /* Check if we are asked to stop (reactivity++) */ if (exit_flag != 0) return; /* send request, read answer */ chars_rcvd = mge_command(buf, sizeof(buf), item->cmd); if ( chars_rcvd < 1 || buf[0] == '?' ) { item->ok = FALSE; upsdebugx(1, "initinfo: %s unavailable", item->type); } else { item->ok = TRUE; extract_info(buf, item, infostr, sizeof(infostr)); dstate_setinfo(item->type, "%s", infostr); dstate_setflags(item->type, item->flags); upsdebugx(1, "initinfo: %s == >%s<", item->type, infostr); /* Set max length for strings */ if (item->flags & ST_FLAG_STRING) dstate_setaux(item->type, item->length); } } /* for item */ /* store timestamp */ lastpoll = time(NULL); /* commands ----------------------------------------------- */ /* FIXME: check if available before adding! */ dstate_addcmd("load.off"); dstate_addcmd("load.on"); dstate_addcmd("shutdown.return"); dstate_addcmd("shutdown.stayoff"); dstate_addcmd("test.panel.start"); dstate_addcmd("test.battery.start"); dstate_addcmd("bypass.start"); dstate_addcmd("bypass.stop"); /* install handlers */ upsh.setvar = setvar; upsh.instcmd = instcmd; printf("Detected %s on %s\n", dstate_getinfo("ups.model"), device_path); } /* --------------------------------------------------------------- */ void upsdrv_updateinfo(void) { char buf[BUFFLEN]; char infostr[32]; int status_ok; ssize_t bytes_rcvd; mge_info_item_t *item; /* make sure that communication is enabled */ enable_ups_comm(); /* update status */ status_ok = get_ups_status(); /* only sys status is critical */ if ( !status_ok ) { upslogx(LOG_NOTICE, "updateinfo: Cannot update system status"); /* try to re enable communication */ disable_ups_comm(); enable_ups_comm(); } else { dstate_dataok(); } /* Don't overload old units (at startup) */ if ( time(NULL) <= (lastpoll + poll_interval) ) return; /* update all other ok variables */ for ( item = mge_info ; item->type != NULL ; item++ ) { /* Check if we are asked to stop (reactivity++) */ if (exit_flag != 0) return; if ( item->ok ) { /* send request, read answer */ bytes_rcvd = mge_command(buf, sizeof(buf), item->cmd); if ( bytes_rcvd > 0 && buf[0] != '?' ) { extract_info(buf, item, infostr, sizeof(infostr)); dstate_setinfo(item->type, "%s", infostr); upsdebugx(2, "updateinfo: %s == >%s<", item->type, infostr); dstate_dataok(); } else { upslogx(LOG_NOTICE, "updateinfo: Cannot update %s", item->type); /* try to re enable communication */ disable_ups_comm(); enable_ups_comm(); } } /* if item->ok */ } /* store timestamp */ lastpoll = time(NULL); } /* --------------------------------------------------------------- */ void upsdrv_shutdown(void) { char buf[BUFFLEN]; /* static time_t lastcmd = 0; */ memset(buf, 0, sizeof(buf)); if (sdtype == SD_RETURN) { /* enable automatic restart */ mge_command(buf, sizeof(buf), "Sx 5"); upslogx(LOG_INFO, "UPS response to Automatic Restart was %s", buf); } /* Only call the effective shutoff if restart is ok */ /* or if we need only a stayoff... */ if (!strcmp(buf, "OK") || (sdtype == SD_STAYOFF)) { /* shutdown UPS */ mge_command(buf, sizeof(buf), "Sx 0"); upslogx(LOG_INFO, "UPS response to Shutdown was %s", buf); } /* if(strcmp(buf, "OK")) */ /* call the cleanup to disable/close the comm link */ upsdrv_cleanup(); } /* --------------------------------------------------------------- */ void upsdrv_help(void) { } /* --------------------------------------------------------------- */ /* Internal Functions */ /* --------------------------------------------------------------- */ /* handler for commands to be sent to UPS */ int instcmd(const char *cmdname, const char *extra) { char temp[BUFFLEN]; /* Start battery test */ if (!strcasecmp(cmdname, "test.battery.start")) { mge_command(temp, sizeof(temp), "Bx 1"); upsdebugx(2, "UPS response to %s was %s", cmdname, temp); if(strcmp(temp, "OK")) return STAT_INSTCMD_UNKNOWN; else return STAT_INSTCMD_HANDLED; } /* Start front panel test */ if (!strcasecmp(cmdname, "test.panel.start")) { mge_command(temp, sizeof(temp), "Sx 129"); upsdebugx(2, "UPS response to %s was %s", cmdname, temp); if(strcmp(temp, "OK")) return STAT_INSTCMD_UNKNOWN; else return STAT_INSTCMD_HANDLED; } /* Shutdown UPS */ if (!strcasecmp(cmdname, "shutdown.stayoff")) { sdtype = SD_STAYOFF; upsdrv_shutdown(); } if (!strcasecmp(cmdname, "shutdown.return")) { sdtype = SD_RETURN; upsdrv_shutdown(); } /* Power Off [all] plugs */ if (!strcasecmp(cmdname, "load.off")) { /* TODO: Powershare (per plug) control */ mge_command(temp, sizeof(temp), "Wy 65535"); upsdebugx(2, "UPS response to Select All Plugs was %s", temp); if(strcmp(temp, "OK")) return STAT_INSTCMD_UNKNOWN; else { mge_command(temp, sizeof(temp), "Wx 0"); upsdebugx(2, "UPS response to %s was %s", cmdname, temp); if(strcmp(temp, "OK")) return STAT_INSTCMD_UNKNOWN; else return STAT_INSTCMD_HANDLED; } } /* Power On all plugs */ if (!strcasecmp(cmdname, "load.on")) { /* TODO: add per plug control */ mge_command(temp, sizeof(temp), "Wy 65535"); upsdebugx(2, "UPS response to Select All Plugs was %s", temp); if(strcmp(temp, "OK")) return STAT_INSTCMD_UNKNOWN; else { mge_command(temp, sizeof(temp), "Wx 1"); upsdebugx(2, "UPS response to %s was %s", cmdname, temp); if(strcmp(temp, "OK")) return STAT_INSTCMD_UNKNOWN; else return STAT_INSTCMD_HANDLED; } } /* Switch on/off Maintenance Bypass */ if ((!strcasecmp(cmdname, "bypass.start")) || (!strcasecmp(cmdname, "bypass.stop"))) { /* TODO: add control on bypass value */ /* read maintenance bypass status */ if(mge_command(temp, sizeof(temp), "Ps") > 0) { if (temp[0] == '1') { /* Disable Maintenance Bypass */ mge_command(temp, sizeof(temp), "Px 2"); upsdebugx(2, "UPS response to Select All Plugs was %s", temp); } else { /* Enable Maintenance Bypass */ mge_command(temp, sizeof(temp), "Px 3"); } upsdebugx(2, "UPS response to %s was %s", cmdname, temp); if(strcmp(temp, "OK")) return STAT_INSTCMD_UNKNOWN; else return STAT_INSTCMD_HANDLED; } } upslogx(LOG_NOTICE, "instcmd: unknown command [%s] [%s]", cmdname, extra); return STAT_INSTCMD_UNKNOWN; } /* --------------------------------------------------------------- */ /* handler for settable variables in UPS*/ int setvar(const char *varname, const char *val) { char temp[BUFFLEN]; char cmd[15]; /* TODO : add some controls */ if(info_variable_ok(varname)) { /* format command */ snprintf(cmd, sizeof(cmd), "%s", info_variable_cmd(varname)); sprintf(strchr(cmd, '?'), "%s", val); /* Execute command */ mge_command(temp, sizeof(temp), cmd); upslogx(LOG_INFO, "setvar: UPS response to Set %s to %s was %s", varname, val, temp); } else upsdebugx(1, "setvar: Variable %s not supported by UPS", varname); return STAT_SET_UNKNOWN; } /* --------------------------------------------------------------- */ /* disable communication with UPS to avoid interference with * kernel serial init at boot time (ie with V24 init) */ static void disable_ups_comm(void) { upsdebugx(1, "disable_ups_comm()"); ser_flush_in(upsfd, "?\r\n", 0); usleep(MGE_CONNECT_DELAY); mge_command(NULL, 0, "Ax 0"); } /* enable communication with UPS */ static void enable_ups_comm(void) { char buf[8]; /* send Z twice --- speeds up re-connect */ mge_command(NULL, 0, "Z"); mge_command(NULL, 0, "Z"); /* only enable communication if needed! */ if ( mge_command(buf, 8, "Si") <= 0) { mge_command(NULL, 0, "Ax 1"); usleep(MGE_CONNECT_DELAY); } ser_flush_in(upsfd, "?\r\n", nut_debug_level); } /* --------------------------------------------------------------- */ /* extract information from buffer in: buf : reply from UPS item : INFO item queried out: infostr: to be placed in INFO_ variable NOTE: buf="?" must be handled before calling extract_info buf is changed inspite of const !!!!! */ static void extract_info(const char *buf, const mge_info_item_t *item, char *infostr, size_t infolen) { /* initialize info string */ infostr[0] = '\0'; #ifdef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL #pragma GCC diagnostic push #endif #ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL #pragma GCC diagnostic ignored "-Wformat-nonliteral" #endif #ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_FORMAT_SECURITY #pragma GCC diagnostic ignored "-Wformat-security" #endif /* write into infostr with proper formatting */ if ( strpbrk(item->fmt, "feEgG") ) { /* float */ snprintf(infostr, infolen, item->fmt, multiplier[mge_ups.MultTab][item->unit] * atof(buf)); } else if ( strpbrk(item->fmt, "dioxXuc") ) { /* int */ snprintf(infostr, infolen, item->fmt, (int) (multiplier[mge_ups.MultTab][item->unit] * atof(buf))); } else { snprintf(infostr, infolen, item->fmt, buf); } #ifdef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL #pragma GCC diagnostic pop #endif } /* --------------------------------------------------------------- */ /* get system status, at least: OB, OL, LB calls set_status appropriately tries MAXTRIES times returns non-nil if successful NOTE: MGE counts bytes/chars the opposite way as C, see mge-utalk manpage. If status commands send two data items, these are separated by a space, so the elements of the second item are in buf[16..9]. */ static int get_ups_status(void) { char buf[BUFFLEN]; int rb_set= FALSE; /* has RB flag been set ? */ int over_set= FALSE; /* has OVER flag been set ? */ int tries = 0; int ok = FALSE; ssize_t bytes_rcvd = 0; do { /* Check if we are asked to stop (reactivity++) */ if (exit_flag != 0) return FALSE; /* must clear status buffer before each round */ status_init(); /* system status */ /* FIXME: some old units sometimes return "Syst Stat >1<" resulting in an temporary OB status */ bytes_rcvd = mge_command(buf, sizeof(buf), "Ss"); upsdebugx(1, "Syst Stat >%s<", buf); if ( bytes_rcvd > 0 && strlen(buf) > 7 ) { ok = TRUE; if (buf[6] == '1') { over_set = TRUE; status_set("OVER"); } if (buf[5] == '1') status_set("OB"); else status_set("OL"); if (buf[4] == '1') status_set("LB"); if (buf[3] == '1') { rb_set = TRUE; status_set("RB"); } /* buf[2] not used */ if (buf[1] == '1') status_set("COMMFAULT"); /* self-invented */ /* FIXME: better to call datastale()?! */ if (buf[0] == '1') status_set("ALARM"); /* self-invented */ /* FIXME: better to use ups.alarm */ } /* if strlen */ /* battery status */ mge_command(buf, sizeof(buf), "Bs"); upsdebugx(1, "Batt Stat >%s<", buf); if ( strlen(buf) > 7 ) { if ( !rb_set && ( buf[7] == '1' || buf[3] == '1' ) ) status_set("RB"); if (buf[1] == '1') status_set("CHRG"); if (buf[0] == '1') status_set("DISCHRG"); } /* if strlen */ /* load status */ mge_command(buf, sizeof(buf), "Ls"); upsdebugx(1, "Load Stat >%s<", buf); if ( strlen(buf) > 7 ) { if (buf[4] == '1') status_set("BOOST"); if ( !over_set && ( buf[3] == '1' ) ) status_set("OVER"); if (buf[2] == '1') status_set("TRIM"); } /* if strlen */ if ( strlen(buf) > 15 ) { /* second "byte", skip */ if (buf[16] == '1') { status_set("OB"); status_set("LB"); } /* FIXME: to be checked (MUST be buf[8]) !! */ /* if ( !(buf[9] == '1') ) */ /* This is not the OFF status! if ( !(buf[8] == '1') ) status_set("OFF"); */ } /* if strlen */ /* Bypass status */ mge_command(buf, sizeof(buf), "Ps"); upsdebugx(1, "Bypass Stat >%s<", buf); if ( strlen(buf) > 7 ) { /* FIXME: extend ups.status for BYPASS: */ /* Manual Bypass */ if (buf[7] == '1') status_set("BYPASS"); /* Automatic Bypass */ if (buf[6] == '1') status_set("BYPASS"); } /* if strlen */ } while ( !ok && tries++ < MAXTRIES ); status_commit(); return ok; } /* --------------------------------------------------------------- */ /* return proper variable "ok" given INFO_ type */ static bool_t info_variable_ok(const char *type) { mge_info_item_t *item = mge_info ; while ( strcasecmp(item->type, type )) item++; return item->ok; } /* --------------------------------------------------------------- */ /* return proper variable "cmd" given INFO_ type */ static const char *info_variable_cmd(const char *type) { mge_info_item_t *item = mge_info ; while ( strcasecmp(item->type, type )) item++; return item->cmd; } /* --------------------------------------------------------------- */ /* send command to UPS and read reply if requested reply : buffer for reply, NULL if no reply expected replylen: length of buffer reply fmt : format string, followed by optional data for command returns : no of chars received, -1 if error */ static ssize_t mge_command(char *reply, size_t replylen, const char *fmt, ...) { const char *p; char command[BUFFLEN]; ssize_t bytes_sent = 0; ssize_t bytes_rcvd = 0; int ret; va_list ap; /* build command string */ va_start(ap, fmt); #ifdef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL #pragma GCC diagnostic push #endif #ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL #pragma GCC diagnostic ignored "-Wformat-nonliteral" #endif #ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_FORMAT_SECURITY #pragma GCC diagnostic ignored "-Wformat-security" #endif ret = vsnprintf(command, sizeof(command), fmt, ap); #ifdef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL #pragma GCC diagnostic pop #endif if ((ret < 1) || (ret >= (int) sizeof(command))) upsdebugx(4, "mge_command: command truncated"); va_end(ap); /* Delay a bit to avoid overlap of a previous answer (500 ms), as per * http://old.networkupstools.org/protocols/mge/9261zwfa.pdf § 6.1. Timings */ usleep(500000); /* flush received, unread data */ tcflush(upsfd, TCIFLUSH); /* send command */ for (p = command; *p; p++) { if ( isprint((unsigned char)*p & 0xFF) ) upsdebugx(4, "mge_command: sending [%c]", *p); else upsdebugx(4, "mge_command: sending [%02X]", *p); if (write(upsfd, p, 1) != 1) return -1; bytes_sent++; usleep(MGE_CHAR_DELAY); } /* send terminating string */ for (p = MGE_COMMAND_ENDCHAR; *p; p++) { if ( isprint((unsigned char)*p & 0xFF) ) upsdebugx(4, "mge_command: sending [%c]", *p); else upsdebugx(4, "mge_command: sending [%02X]", *p); if (write(upsfd, p, 1) != 1) return -1; bytes_sent++; usleep(MGE_CHAR_DELAY); } if ( !reply ) return bytes_rcvd; else usleep(MGE_REPLY_DELAY); bytes_rcvd = ser_get_line(upsfd, reply, replylen, MGE_REPLY_ENDCHAR, MGE_REPLY_IGNCHAR, 3, 0); upsdebugx(4, "mge_command: sent %" PRIiSIZE ", received %" PRIiSIZE " byte(s)", bytes_sent, bytes_rcvd); return bytes_rcvd; } void upsdrv_cleanup(void) { upsdebugx(1, "cleaning up"); disable_ups_comm(); ser_close(upsfd, device_path); } nut-2.8.1/drivers/everups.c0000644000175000017500000001036314501607135012571 00000000000000/* everups.c - support for Ever UPS models (serial) Copyright (C) 2001 Bartek Szady 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 2 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, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "main.h" #include "serial.h" #define DRIVER_NAME "Ever UPS driver (serial)" #define DRIVER_VERSION "0.05" /* driver description structure */ upsdrv_info_t upsdrv_info = { DRIVER_NAME, DRIVER_VERSION, "Bartek Szady ", DRV_STABLE, { NULL } }; static unsigned char upstype = 0; static void init_serial(void) { ser_set_dtr(upsfd, 0); ser_set_rts(upsfd, 0); } static int Code(int tries) { unsigned char cRecv; do { ser_send_char(upsfd, 208); ser_get_char(upsfd, &cRecv, 3, 0); if (cRecv==208) return 1; } while (--tries>0); return 0; } static int InitUpsType(void) { if (Code(1)) { ser_send_char(upsfd, 173); ser_get_char(upsfd, &upstype, 3, 0); return 1; } else return 0; } static const char *GetTypeUpsName(void) { switch(upstype) { case 67: return "NET 500-DPC"; case 68: return "NET 700-DPC"; case 69: return "NET 1000-DPC"; case 70: return "NET 1400-DPC"; case 71: return "NET 2200-DPC"; case 73: return "NET 700-DPC (new)"; case 74: return "NET 1000-DPC (new)"; case 75: return "NET 1400-DPC (new)"; case 76: return "NET 500-DPC (new)"; case 81: return "AP 450-PRO"; case 82: return "AP 650-PRO"; default: return "Unknown"; } } void upsdrv_initinfo(void) { dstate_setinfo("ups.mfr", "Ever"); dstate_setinfo("ups.model", "%s", GetTypeUpsName()); } void upsdrv_updateinfo(void) { int battery=0,standby=0; unsigned char recBuf[2]; unsigned long acuV; unsigned long lineV; double fVal; if (!Code(2)) { upslog_with_errno(LOG_INFO, "Code failed"); dstate_datastale(); return; } /*Line status*/ ser_send_char(upsfd, 175); ser_get_char(upsfd, recBuf, 3, 0); if ((recBuf[0] & 1) !=0) standby=1; else battery=(recBuf[0] &4) !=0; if (Code(1)) { /*Accumulator voltage value*/ ser_send_char(upsfd, 189); ser_get_char(upsfd, recBuf, 3, 0); acuV=((unsigned long)recBuf[0])*150; acuV/=255; } else { upslog_with_errno(LOG_INFO, "Code failed"); dstate_datastale(); return; } if (Code(1)) { /*Line voltage*/ ser_send_char(upsfd, 245); ser_get_buf_len(upsfd, recBuf, 2, 3, 0); if ( upstype > 72 && upstype < 77) lineV=(recBuf[0]*100+recBuf[1]*25600)/352; else lineV=(recBuf[0]*100+recBuf[1]*25600)/372; } else { upslog_with_errno(LOG_INFO, "Code failed"); dstate_datastale(); return; } status_init(); if (battery && acuV<105) status_set("LB"); /* low battery */ if (battery) status_set("OB"); /* on battery */ else status_set("OL"); /* on line */ status_commit(); dstate_setinfo("input.voltage", "%03ld", lineV); dstate_setinfo("battery.voltage", "%03.2f", (double)acuV /10.0); fVal=((double)acuV-95.0)*100.0; if (standby) fVal/=(135.5-95.0); else fVal/=(124.5-95.0); if (fVal>100) fVal=100; else if (fVal<0) fVal=0; dstate_setinfo("battery.charge", "%03.1f", fVal); dstate_dataok(); } void upsdrv_shutdown(void) { if (!Code(2)) { upslog_with_errno(LOG_INFO, "Code failed"); return; } ser_send_char(upsfd, 28); ser_send_char(upsfd, 1); /* 1.28 sec */ if (!Code(1)) { upslog_with_errno(LOG_INFO, "Code failed"); return; } ser_send_char(upsfd, 13); ser_send_char(upsfd, 8); } void upsdrv_help(void) { } /* list flags and values that you want to receive via -x */ void upsdrv_makevartable(void) { } void upsdrv_initups(void) { upsfd = ser_open(device_path); ser_set_speed(upsfd, device_path, B300); init_serial(); InitUpsType(); } void upsdrv_cleanup(void) { ser_close(upsfd, device_path); } nut-2.8.1/drivers/serial.h0000644000175000017500000000722714501607135012371 00000000000000#ifndef SERIAL_H_SEEN #define SERIAL_H_SEEN 1 #include "config.h" /* should be first */ #include "attribute.h" #include "common.h" /* for TYPE_FD_SER, possibly fallback suseconds_t */ #ifndef WIN32 # if defined(HAVE_SYS_TERMIOS_H) # include /* for speed_t */ # else # include # endif /* HAVE_SYS_TERMIOS_H */ #else /* WIN32 */ # include "wincompat.h" #endif /* WIN32 */ #include /* for usleep() and useconds_t, latter also might be via */ #include #if defined(HAVE_SYS_SELECT_H) #include /* for suseconds_t */ #endif /* limit the amount of spew that goes in the syslog when we lose the UPS */ #define SER_ERR_LIMIT 10 /* start limiting after 10 in a row */ #define SER_ERR_RATE 100 /* then only print every 100th error */ /* porting stuff for WIN32 */ #ifdef WIN32 /* TODO : support "open" flags */ # define O_NONBLOCK 0 # define O_NOCTTY 0 /* Builds on Windows MSYS2 environment did not recognize this macro: */ # ifndef TIOCM_ST # define TIOCM_ST 0x008 # endif #endif /* WIN32 */ TYPE_FD_SER ser_open_nf(const char *port); TYPE_FD_SER ser_open(const char *port); int ser_set_speed(TYPE_FD_SER fd, const char *port, speed_t speed); int ser_set_speed_nf(TYPE_FD_SER fd, const char *port, speed_t speed); /* set the state of modem control lines */ int ser_set_dtr(TYPE_FD_SER fd, int state); int ser_set_rts(TYPE_FD_SER fd, int state); /* get the status of modem control lines */ int ser_get_dsr(TYPE_FD_SER fd); int ser_get_cts(TYPE_FD_SER fd); int ser_get_dcd(TYPE_FD_SER fd); int ser_close(TYPE_FD_SER fd, const char *port); ssize_t ser_send_char(TYPE_FD_SER fd, unsigned char ch); /* send the results of the format string with d_usec delay after each char */ ssize_t ser_send_pace(TYPE_FD_SER fd, useconds_t d_usec, const char *fmt, ...) __attribute__ ((__format__ (__printf__, 3, 4))); /* send the results of the format string with no delay */ ssize_t ser_send(TYPE_FD_SER fd, const char *fmt, ...) __attribute__ ((__format__ (__printf__, 2, 3))); /* send buflen bytes from buf with no delay */ ssize_t ser_send_buf(TYPE_FD_SER fd, const void *buf, size_t buflen); /* send buflen bytes from buf with d_usec delay after each char */ ssize_t ser_send_buf_pace(TYPE_FD_SER fd, useconds_t d_usec, const void *buf, size_t buflen); ssize_t ser_get_char(TYPE_FD_SER fd, void *ch, time_t d_sec, useconds_t d_usec); ssize_t ser_get_buf(TYPE_FD_SER fd, void *buf, size_t buflen, time_t d_sec, useconds_t d_usec); /* keep reading until buflen bytes are received or a timeout occurs */ ssize_t ser_get_buf_len(TYPE_FD_SER fd, void *buf, size_t buflen, time_t d_sec, useconds_t d_usec); /* reads a line up to , discarding anything else that may follow, with callouts to the handler if anything matches the alertset */ ssize_t ser_get_line_alert(TYPE_FD_SER fd, void *buf, size_t buflen, char endchar, const char *ignset, const char *alertset, void handler (char ch), time_t d_sec, useconds_t d_usec); /* as above, only with no alertset handling (just a wrapper) */ ssize_t ser_get_line(TYPE_FD_SER fd, void *buf, size_t buflen, char endchar, const char *ignset, time_t d_sec, useconds_t d_usec); ssize_t ser_flush_in(TYPE_FD_SER fd, const char *ignset, int verbose); int ser_flush_io(TYPE_FD_SER fd); /* unified failure reporting: call these often */ void ser_comm_fail(const char *fmt, ...) __attribute__ ((__format__ (__printf__, 1, 2))); void ser_comm_good(void); #ifdef WIN32 #define open(a,b) w32_serial_open(a,b) #define close(a) w32_serial_close(a) #define read(a,b,c) w32_serial_read(a,b,c,INFINITE) #define write(a,b,c) w32_serial_write(a,b,c) #endif #endif /* SERIAL_H_SEEN */ nut-2.8.1/drivers/riello.c0000644000175000017500000006022414517666470012405 00000000000000/* * riello.c: driver core for Riello protocol based UPSes * * Documents describing the protocol implemented by this driver can be * found online at: * * https://www.networkupstools.org/protocols/riello/PSGPSER-0104.pdf * https://www.networkupstools.org/protocols/riello/PSSENTR-0100.pdf * * Copyright (C) 2012 - Elio Parisi * * 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 2 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, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * Reference of the derivative work: blazer driver */ #include #include "main.h" #include "riello.h" static uint8_t foundheader = 0; uint16_t buf_ptr_length; uint8_t wait_packet = 0; uint8_t foundnak = 0; uint8_t foundbadcrc = 0; uint8_t commbyte; uint8_t requestSENTR; static unsigned char LAST_DATA[6]; uint16_t riello_calc_CRC(uint8_t type, uint8_t *buff, uint16_t size, uint8_t checksum) { uint16_t i; uint16_t pom, CRC_Word; CRC_Word = 0; switch (type) { case DEV_RIELLOSENTRY: CRC_Word = 0; if (size == 101) { for (i=0; i<100; i++) CRC_Word += buff[i]; } else { for (i=0; i> 4); CRC_Word = (CRC_Word >> 8) ^ pom; buff++; } } else { CRC_Word = 0; for (i=1; iIdentification, &buffer[7], 16); data->Identification[16] = 0; memcpy(data->ModelStr, &buffer[23], 16); data->ModelStr[16] = 0; data->ModelStr[15] = 0; memcpy(data->Version, &buffer[39], 12); data->Version[12] = 0; memcpy(data->Identif_bytes, &buffer[51], 12); data->Identif_bytes[11] = 0; data->NumBat = data->Identif_bytes[7] - 0x30; } void riello_parse_gn(uint8_t* buffer, TRielloData* data) { uint16_t pom_word; uint32_t pom_long; uint8_t j; j = 7; pom_long = (buffer[j++]-0x30)*65536; pom_long += (buffer[j++]-0x30)*4096; pom_long += (buffer[j++]-0x30)*256; pom_long += (buffer[j++]-0x30)*16; pom_long += (buffer[j++]-0x30); if (data->Identif_bytes[0] != '1') pom_long/=100; assert (pom_long < UINT16_MAX); data->NomPowerKVA = (uint16_t)pom_long; pom_long = (buffer[j++]-0x30)*65536; pom_long += (buffer[j++]-0x30)*4096; pom_long += (buffer[j++]-0x30)*256; pom_long += (buffer[j++]-0x30)*16; pom_long += (buffer[j++]-0x30); if (data->Identif_bytes[0] != '1') pom_long/=100; assert (pom_long < UINT16_MAX); data->NomPowerKW = (uint16_t)pom_long; pom_word = (buffer[j++]-0x30)*256; pom_word += (buffer[j++]-0x30)*16; pom_word += (buffer[j++]-0x30); data->NomUbat = pom_word; pom_word = (buffer[j++]-0x30)*256; pom_word += (buffer[j++]-0x30)*16; pom_word += (buffer[j++]-0x30); data->NomBatCap = pom_word; pom_word = (buffer[j++]-0x30)*256; pom_word += (buffer[j++]-0x30)*16; pom_word += (buffer[j++]-0x30); data->NominalUout = pom_word; pom_word = (buffer[j++]-0x30)*256; pom_word += (buffer[j++]-0x30)*16; pom_word += (buffer[j++]-0x30); data->NomFout = pom_word; } void riello_parse_rs(uint8_t* buffer, TRielloData* data, uint8_t numread) { uint16_t pom_word; uint8_t j; j = 7; memcpy(data->StatusCode, &buffer[j], 5); data->StatusCode[5] = 0; data->Boost = riello_test_bit(&buffer[j], 9); data->Buck = riello_test_bit(&buffer[j], 8); data->LockUPS = riello_test_bit(&buffer[j], 2); j+=5; pom_word = (buffer[j++]-0x30)*256; pom_word += (buffer[j++]-0x30)*16; pom_word += (buffer[j++]-0x30); data->Finp = pom_word; pom_word = (buffer[j++]-0x30)*256; pom_word += (buffer[j++]-0x30)*16; pom_word += (buffer[j++]-0x30); data->Uinp1 = pom_word; pom_word = (buffer[j++]-0x30)*256; pom_word += (buffer[j++]-0x30)*16; pom_word += (buffer[j++]-0x30); if (!riello_test_bit(&data->StatusCode[0], 3)) pom_word = 0; data->Fout = pom_word; pom_word = (buffer[j++]-0x30)*256; pom_word += (buffer[j++]-0x30)*16; pom_word += (buffer[j++]-0x30); data->Uout1 = pom_word; pom_word = (buffer[j++]-0x30)*16; pom_word += (buffer[j++]-0x30); data->Pout1 = pom_word; pom_word = (buffer[j++]-0x30)*256; pom_word += (buffer[j++]-0x30)*16; pom_word += (buffer[j++]-0x30); data->Fbypass = pom_word; pom_word = (buffer[j++]-0x30)*256; pom_word += (buffer[j++]-0x30)*16; pom_word += (buffer[j++]-0x30); data->Ubypass1 = pom_word; pom_word = (buffer[j++]-0x30)*4096; pom_word += (buffer[j++]-0x30)*256; pom_word += (buffer[j++]-0x30)*16; pom_word += (buffer[j++]-0x30); data->Ubat = pom_word; pom_word = (buffer[j++]-0x30)*16; pom_word += (buffer[j++]-0x30); data->BatCap = pom_word; pom_word = (buffer[j++]-0x30)*256; pom_word += (buffer[j++]-0x30)*16; pom_word += (buffer[j++]-0x30); data->BatTime = pom_word; if (data->BatTime == 0xfff) data->BatTime = 0xffff; pom_word = (buffer[j++]-0x30)*16; pom_word += (buffer[j++]-0x30); data->Tsystem = pom_word; if (numread > 42) { pom_word = (buffer[j++]-0x30)*256; pom_word += (buffer[j++]-0x30)*16; pom_word += (buffer[j++]-0x30); data->Uinp2 = pom_word; pom_word = (buffer[j++]-0x30)*256; pom_word += (buffer[j++]-0x30)*16; pom_word += (buffer[j++]-0x30); data->Uinp3 = pom_word; } else { data->Uinp2 = 0; data->Uinp3 = 0; } if (numread > 48) { pom_word = (buffer[j++]-0x30)*256; pom_word += (buffer[j++]-0x30)*16; pom_word += (buffer[j++]-0x30); data->Uout2 = pom_word; pom_word = (buffer[j++]-0x30)*16; pom_word += (buffer[j++]-0x30); data->Pout2 = pom_word; pom_word = (buffer[j++]-0x30)*256; pom_word += (buffer[j++]-0x30)*16; pom_word += (buffer[j++]-0x30); data->Ubypass2 = pom_word; pom_word = (buffer[j++]-0x30)*256; pom_word += (buffer[j++]-0x30)*16; pom_word += (buffer[j++]-0x30); data->Uout3 = pom_word; pom_word = (buffer[j++]-0x30)*16; pom_word += (buffer[j++]-0x30); data->Pout3 = pom_word; pom_word = (buffer[j++]-0x30)*256; pom_word += (buffer[j++]-0x30)*16; pom_word += (buffer[j++]-0x30); data->Ubypass3 = pom_word; } else { data->Uout2 = 0; data->Pout2 = 0; data->Ubypass2 = 0; data->Uout3 = 0; data->Pout3 = 0; data->Ubypass3 = 0; } } void riello_parse_re(uint8_t* buffer, TRielloData* data) { uint16_t pom_word; uint32_t pom_long; uint8_t j; j = 23; data->Iinp1 = 0xFFFF; data->Iinp2 = 0xFFFF; data->Iinp3 = 0xFFFF; pom_word = (buffer[j++]-0x30)*4096; pom_word += (buffer[j++]-0x30)*256; pom_word += (buffer[j++]-0x30)*16; pom_word += (buffer[j++]-0x30); data->Iout1 = pom_word; pom_word = (buffer[j++]-0x30)*4096; pom_word += (buffer[j++]-0x30)*256; pom_word += (buffer[j++]-0x30)*16; pom_word += (buffer[j++]-0x30); data->Iout2 = pom_word; pom_word = (buffer[j++]-0x30)*4096; pom_word += (buffer[j++]-0x30)*256; pom_word += (buffer[j++]-0x30)*16; pom_word += (buffer[j++]-0x30); data->Iout3 = pom_word; pom_long = (buffer[j++]-0x30)*65536; pom_long += (buffer[j++]-0x30)*4096; pom_long += (buffer[j++]-0x30)*256; pom_long += (buffer[j++]-0x30)*16; pom_long += (buffer[j++]-0x30); data->Pout1W = pom_long; pom_long = (buffer[j++]-0x30)*65536; pom_long += (buffer[j++]-0x30)*4096; pom_long += (buffer[j++]-0x30)*256; pom_long += (buffer[j++]-0x30)*16; pom_long += (buffer[j++]-0x30); data->Pout2W = pom_long; pom_long = (buffer[j++]-0x30)*65536; pom_long += (buffer[j++]-0x30)*4096; pom_long += (buffer[j++]-0x30)*256; pom_long += (buffer[j++]-0x30)*16; pom_long += (buffer[j++]-0x30); data->Pout3W = pom_long; pom_long = (buffer[j++]-0x30)*65536; pom_long += (buffer[j++]-0x30)*4096; pom_long += (buffer[j++]-0x30)*256; pom_long += (buffer[j++]-0x30)*16; pom_long += (buffer[j++]-0x30); data->Pout1VA = pom_long; pom_long = (buffer[j++]-0x30)*65536; pom_long += (buffer[j++]-0x30)*4096; pom_long += (buffer[j++]-0x30)*256; pom_long += (buffer[j++]-0x30)*16; pom_long += (buffer[j++]-0x30); data->Pout2VA = pom_long; pom_long = (buffer[j++]-0x30)*65536; pom_long += (buffer[j++]-0x30)*4096; pom_long += (buffer[j++]-0x30)*256; pom_long += (buffer[j++]-0x30)*16; pom_long += (buffer[j++]-0x30); data->Pout3VA = pom_long; } void riello_parse_rc(uint8_t* buffer, TRielloData* data) { uint8_t j, i; j = 7; for (i = 0; i < 22; i++, j+=2) { data->StatusCodeT[i] = (char)(buffer[j+1]-0x30); data->StatusCodeT[i] |= ((buffer[j]-0x30) << 4); } data->StatusCodeT[23] = 0; data->StatusCodeT[24] = 0; } void riello_parse_sentr(uint8_t* buffer, TRielloData* data) { uint32_t pom; data->Model = buffer[2]+256*buffer[3]; if (data->Model < 3000) { if ((data->Model % 10) >= 4) { if (buffer[100] & 0x01) requestSENTR = SENTR_EXT176; else requestSENTR = SENTR_ALSO240; } else requestSENTR = SENTR_ONLY192; data->NomPowerKVA = data->Model/10; } else { if (((data->Model-3000) % 10) >= 4) { if (buffer[100] & 0x01) requestSENTR = SENTR_EXT176; else requestSENTR = SENTR_ALSO240; } else requestSENTR = SENTR_ONLY192; data->NomPowerKVA = (data->Model-3000)/10; } if (buffer[76] & 0x08) data->NomPowerKW = ((data->NomPowerKVA * 1000) * 9 / 10) / 1000; else data->NomPowerKW = ((data->NomPowerKVA * 1000) * 8 / 10) / 1000; data->NomPowerKVA *= 1000; data->NomPowerKW *= 1000; if (data->Model < 3000) data->Identif_bytes[0] = '3'; else data->Identif_bytes[0] = '4'; data->Identif_bytes[1] = '3'; data->Identif_bytes[6] = '2'; data->SWversion = buffer[4]+256*buffer[5]; data->Version[0] = (char)(uint8_t)(48 + ((data->SWversion / 1000) % 10)); data->Version[1] = (char)(uint8_t)(48 + ((data->SWversion / 100) % 10)); data->Version[2] = '.'; data->Version[3] = (char)(uint8_t)(48 + ((data->SWversion / 10) % 10)); data->Version[4] = (char)(uint8_t)(48 + (data->SWversion % 10)); if (data->Model < 3000) pom = data->Model*100; else pom = (data->Model-3000)*100; if (buffer[0] == SENTR_EXT176) { data->Uinp1 = (buffer[117]+buffer[118]*256)/10; data->Uinp2 = (buffer[119]+buffer[120]*256)/10; data->Uinp3 = (buffer[121]+buffer[122]*256)/10; data->Iinp1 = (buffer[123]+buffer[124]*256)/10; data->Iinp2 = (buffer[125]+buffer[126]*256)/10; data->Iinp3 = (buffer[127]+buffer[128]*256)/10; data->Finp = buffer[41]+256*buffer[42]; data->Uout1 = (buffer[135]+buffer[136]*256)/10; data->Uout2 = (buffer[137]+buffer[138]*256)/10; data->Uout3 = (buffer[139]+buffer[140]*256)/10; data->Iout1 = (buffer[141]+buffer[142]*256)/10; data->Iout2 = (buffer[143]+buffer[144]*256)/10; data->Iout3 = (buffer[145]+buffer[146]*256)/10; data->Pout1 = buffer[62]; data->Pout2 = buffer[63]; data->Pout3 = buffer[64]; data->Ipout1 = buffer[65]*3; } else { data->Uinp1 = buffer[35]*230/100; data->Uinp2 = buffer[36]*230/100; data->Uinp3 = buffer[37]*230/100; /* TODO: Range-check the casts to uint16_t? */ data->Iinp1 = (uint16_t)(((pom/690)*buffer[38])/100); data->Iinp2 = (uint16_t)(((pom/690)*buffer[39])/100); data->Iinp3 = (uint16_t)(((pom/690)*buffer[40])/100); data->Finp = buffer[41]+256*buffer[42]; if (buffer[79] & 0x80) { data->Uout1 = buffer[59]*2; data->Uout2 = buffer[60]*2; data->Uout3 = buffer[61]*2; } else { data->Uout1 = buffer[59]; data->Uout2 = buffer[60]; data->Uout3 = buffer[61]; } if (buffer[73]) { /* FIXME: Wondering how the addition below works for uint8_t[] buffer... */ /* TODO: Range-check the casts to uint16_t? */ if (buffer[73] < 100) buffer[73]+=256; if (data->Model < 3000) /* singlephase */ data->Iout1 = (uint16_t)(((pom/buffer[73])*buffer[62])/100); else data->Iout1 = (uint16_t)(((pom/buffer[73])*buffer[62])/100/3); data->Iout2 = (uint16_t)(((pom/buffer[73])*buffer[63])/100/3); data->Iout3 = (uint16_t)(((pom/buffer[73])*buffer[64])/100/3); } else { data->Iout1 = 0; data->Iout2 = 0; data->Iout3 = 0; } if ((data->Model & 0x0007) < 4) { data->Iout1 *= 0.9; data->Iout2 *= 0.9; data->Iout3 *= 0.9; } data->Pout1 = buffer[62]; data->Pout2 = buffer[63]; data->Pout3 = buffer[64]; data->Ipout1 = buffer[65]*3; } if (data->Model < 3000) { data->Ipout2 = 0; data->Ipout3 = 0; } else { data->Ipout2 = buffer[66]*3; data->Ipout3 = buffer[67]*3; } data->Fout = buffer[68]+256*buffer[69]; data->BatTime = buffer[6]+256*buffer[7]; data->BatCap = buffer[8]; if ((buffer[0] == SENTR_ALSO240) || (buffer[0] == SENTR_EXT176)) { if (buffer[100] & 0x80) data->Ubat = buffer[43]+256*buffer[44]; else { if (buffer[44] < buffer[43]) data->Ubat = buffer[44]*2; else data->Ubat = buffer[43]*2; } } else data->Ubat = buffer[43]+256*buffer[44]; data->Ubat *= 10; data->Ibat = buffer[45]+256*buffer[46]; if (!buffer[47]) data->Ibat = data->Ibat*10; data->Tsystem = buffer[48]; data->NomBatCap = buffer[74]+256*buffer[75]; switch (buffer[0]) { case SENTR_EXT176: data->Ubypass1 = (buffer[129]+buffer[130]*256)/10; data->Ubypass2 = (buffer[131]+buffer[132]*256)/10; data->Ubypass3 = (buffer[133]+buffer[134]*256)/10; data->Fbypass = buffer[57]+256*buffer[58]; break; case SENTR_ALSO240: data->Ubypass1 = buffer[51]*2; data->Ubypass2 = buffer[53]*2; data->Ubypass3 = buffer[55]*2; data->Fbypass = buffer[57]+256*buffer[58]; break; default: data->Ubypass1 = buffer[51]+256*buffer[52]; data->Ubypass2 = buffer[53]+256*buffer[54]; data->Ubypass3 = buffer[55]+256*buffer[56]; data->Fbypass = buffer[57]+256*buffer[58]; break; } data->StatusCode[0] = 0x08; data->StatusCode[1] = 0x00; data->StatusCode[2] = 0x00; data->StatusCode[3] = 0x00; data->StatusCode[4] = 0x00; /* Overload if (riello_test_bit(&DevData.StatusCode[4], 2)) */ if (buffer[31] & 128) data->StatusCode[4] |= 0x04; /* Bypass if (riello_test_bit(&DevData.StatusCode[1], 3)) */ if (((buffer[31] & 2) || (riello_test_bit(&buffer[32], 0)) || (riello_test_bit(&buffer[32], 12)) || (riello_test_bit(&buffer[32], 13)) || (riello_test_bit(&buffer[32], 14))) && (!(buffer[34] & 8))) data->StatusCode[1] |= 0x08; /* AC Fail if (riello_test_bit(&DevData.StatusCode[0], 1)) */ if (buffer[31] & 8) data->StatusCode[0] |= 0x02; /* LowBatt if ((riello_test_bit(&DevData.StatusCode[0], 1)) && (riello_test_bit(&DevData.StatusCode[0], 0))) */ if (buffer[31] & 16) { if (buffer[31] & 8) { data->StatusCode[0] |= 0x02; data->StatusCode[0] |= 0x01; } } /* Standby if (!riello_test_bit(&DevData.StatusCode[0], 3)) */ if ((buffer[22] & 2) || (buffer[34] & 4) || (buffer[34] & 8)) data->StatusCode[0] &= 0xF7; /* Battery bad (Replace battery) if (riello_test_bit(&DevData.StatusCode[2], 0)) */ if (buffer[31] & 0x40) data->StatusCode[2] |= 0x01; } void riello_init_serial(void) { wait_packet = 1; buf_ptr_length = 0; foundbadcrc = 0; foundnak = 0; } uint8_t riello_header(uint8_t type, uint8_t a, uint8_t* length) { LAST_DATA[0] = LAST_DATA[1]; LAST_DATA[1] = LAST_DATA[2]; LAST_DATA[2] = LAST_DATA[3]; LAST_DATA[3] = LAST_DATA[4]; LAST_DATA[4] = LAST_DATA[5]; LAST_DATA[5] = (uint8_t) a; switch (type) { case DEV_RIELLOSENTRY: if (((LAST_DATA[4]>=192) && (LAST_DATA[5]==103)) || ((LAST_DATA[4]==176) && (LAST_DATA[5]==164))) { *length = LAST_DATA[5]; return(1); } break; case DEV_RIELLOGPSER: if ((buf_ptr_length==0) && (LAST_DATA[5]>0x20) && (LAST_DATA[4]==0x2)) return(1); break; } return(0); } uint8_t riello_tail(uint8_t type, uint8_t length) { uint8_t number; switch (type) { case DEV_RIELLOSENTRY: number = length; if (buf_ptr_length >= number) return(1); break; case DEV_RIELLOGPSER: if (LAST_DATA[5] == 0x03) return(1); break; } return(0); } uint8_t riello_test_nak(uint8_t type, uint8_t* buffer) { switch (type) { case DEV_RIELLOGPSER: if (buffer[3] == 0x15) return(1); break; } return(0); } void riello_parse_serialport(uint8_t typedev, uint8_t* buffer, uint8_t checksum) { static uint8_t actual_char, int_i; static uint8_t length; actual_char = commbyte; if ((riello_header(typedev, actual_char, &length)) && (!foundheader)) { upsdebugx(5,"Header detected: LAST_DATA:%X,%X,%X,%X,%X,%X buf_ptr:%i \n\r", LAST_DATA[0], LAST_DATA[1], LAST_DATA[2], LAST_DATA[3], LAST_DATA[4], LAST_DATA[5], buf_ptr_length); foundheader = 1; buf_ptr_length = 1; memset(buffer, 0, BUFFER_SIZE); buffer[0] = LAST_DATA[4]; } if ((foundheader) && (buf_ptr_length < BUFFER_SIZE)) buffer[buf_ptr_length++] = actual_char; if ((foundheader) && (riello_tail(typedev, length))) { upsdebugx(5,"\n\rEnd detected: LAST_DATA:%X,%X,%X,%X,%X,%X buf_ptr:%i \n\r", LAST_DATA[0], LAST_DATA[1], LAST_DATA[2], LAST_DATA[3], LAST_DATA[4], LAST_DATA[5], buf_ptr_length); foundheader = 0; for (int_i=0; int_i<6; int_i++) LAST_DATA[int_i] = 0; if (riello_test_nak(typedev, buffer)) { wait_packet = 0; foundnak = 1; } if (riello_test_crc(typedev, buffer, buf_ptr_length, checksum)) { wait_packet = 0; foundbadcrc = 1; } else { wait_packet = 0; foundbadcrc = 0; } } } nut-2.8.1/drivers/snmp-ups-helpers.c0000644000175000017500000000722414500336654014330 00000000000000/* snmp-ups-helpers.c - Shared helper functions and data mapping tables * for NUT Generic SNMP driver core * * Copyright (C) * 2015 - 2021 Eaton (author: Arnaud Quette ) * 2016 - 2021 Eaton (author: Jim Klimov ) * * Sponsored by Eaton * * 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 2 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, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /* NUT SNMP common functions */ #include "common.h" /* includes "config.h" which must be the first header */ /* #include "config.h" #include "main.h" #include "nut_float.h" #include "nut_stdint.h" */ #include "snmp-ups.h" #include "timehead.h" /* time.h => strptime() */ #include /* for isprint() */ /*********************************************************************** * Subdrivers shared helpers functions * Code below is primarily used in snmp-ups driver, but may be part * of other compilation units, so separated into a stand-alone file **********************************************************************/ static char su_scratch_buf[255]; /* Temperature handling, to convert back to Celsius */ int temperature_unit = TEMPERATURE_UNKNOWN; /* Convert a US formated date (mm/dd/yyyy) to an ISO 8601 Calendar date (yyyy-mm-dd) */ const char *su_usdate_to_isodate_info_fun(void *raw_date) { const char *usdate = (char *)raw_date; struct tm tm; memset(&tm, 0, sizeof(struct tm)); memset(&su_scratch_buf, 0, sizeof(su_scratch_buf)); upsdebugx(3, "%s: US date = %s", __func__, usdate); /* Try to convert from US date string to time */ /* Note strptime returns NULL upon failure, and a ptr to the last null char of the string upon success. Just try blindly the conversion! */ strptime(usdate, "%m/%d/%Y", &tm); if (strftime(su_scratch_buf, 254, "%F", &tm) != 0) { upsdebugx(3, "%s: successfully reformated: %s", __func__, su_scratch_buf); return su_scratch_buf; } return NULL; } info_lkp_t su_convert_to_iso_date_info[] = { /* array index = FUNMAP_USDATE_TO_ISODATE: */ { 1, "dummy", su_usdate_to_isodate_info_fun, NULL }, { 0, NULL, NULL, NULL } }; /* Process temperature value according to 'temperature_unit' */ const char *su_temperature_read_fun(void *raw_snmp_value) { const long snmp_value = *((long*)raw_snmp_value); long celsius_value = snmp_value; memset(su_scratch_buf, 0, sizeof(su_scratch_buf)); switch (temperature_unit) { case TEMPERATURE_KELVIN: celsius_value = (snmp_value / 10) - 273.15; snprintf(su_scratch_buf, sizeof(su_scratch_buf), "%.1ld", celsius_value); break; case TEMPERATURE_CELSIUS: snprintf(su_scratch_buf, sizeof(su_scratch_buf), "%.1ld", (snmp_value / 10)); break; case TEMPERATURE_FAHRENHEIT: celsius_value = (((snmp_value / 10) - 32) * 5) / 9; snprintf(su_scratch_buf, sizeof(su_scratch_buf), "%.1ld", celsius_value); break; case TEMPERATURE_UNKNOWN: default: upsdebugx(1, "%s: not a known temperature unit for conversion!", __func__); break; } upsdebugx(2, "%s: %.1ld => %s", __func__, (snmp_value / 10), su_scratch_buf); return su_scratch_buf; } nut-2.8.1/drivers/powerp-bin.h0000644000175000017500000000210614500336654013167 00000000000000/* * powerp-bin.h - Model specific data/definitions for CyberPower text/binary * protocol UPSes * * Copyright (C) * 2007 Doug Reynolds * 2007-2008 Arjen de Korte * * 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 2 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, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef POWERP_BIN_H #define POWERP_BIN_H #include "powerpanel.h" extern subdriver_t powpan_binary; #endif /* POWERP_BIN_H */ nut-2.8.1/drivers/bcmxcp.h0000644000175000017500000011574014501607135012366 00000000000000/* * bcmxcp.h -- header for BCM/XCP module */ #ifndef NUT_BCMXCP_H_SEEN #define NUT_BCMXCP_H_SEEN 1 #include "timehead.h" /* Have to wait at least 0,25 sec max 16 sec */ /* 1 second is too short for PW9120 (leads to communication errors). So we set it to 2 seconds */ #define PW_SLEEP 2 #define PW_MAX_TRY 3 /* How many times we try to send data. */ #define PW_COMMAND_START_BYTE (unsigned char)0xAB #define PW_LAST_SEQ (unsigned char)0x80 /* bit flag to indicate final sequence */ #define PW_SEQ_MASK (unsigned char)0x7F /* bit mask to extract just the sequence # */ #define PW_HEADER_LENGTH 4 /* Size of response header */ #define PW_ANSWER_MAX_SIZE 256 /* No Autorisation required */ #define PW_ID_BLOCK_REQ (unsigned char)0x31 /* Model name, ... length 1 */ #define PW_EVENT_HISTORY_LOG_REQ (unsigned char)0x32 /* List alarms that have occurred. length 1 */ #define PW_STATUS_REQ (unsigned char)0x33 /* On Line, On Bypass, ... length 1-2 */ #define PW_METER_BLOCK_REQ (unsigned char)0x34 /* Current UPS status (Load, utility,...) length 1 */ #define PW_CUR_ALARM_REQ (unsigned char)0x35 /* Current alarm and event request. length 1 */ #define PW_CONFIG_BLOCK_REQ (unsigned char)0x36 /* Model serial#, ... length 1 */ #define PW_UTILITY_STATISTICS_BLOCK_REQ (unsigned char)0x38 /* List utility power quality. length 1 */ #define PW_WAVEFORM_BLOCK_REQ (unsigned char)0x3A /* Sampled waveform data. length 7 */ #define PW_BATTERY_REQ (unsigned char)0x3B /* Charging, floating, ... length 1 */ #define PW_LIMIT_BLOCK_REQ (unsigned char)0x3C /* Configuration (Bypass thresholds,...). length 1 */ #define PW_TEST_RESULT_REQ (unsigned char)0x3F /* Get the results for a system test. length 1 */ #define PW_COMMAND_LIST_REQ (unsigned char)0x40 /* Available commands. length 1 */ #define PW_OUT_MON_BLOCK_REQ (unsigned char)0x41 /* Outlet monitor request length 1 */ #define PW_COM_CAP_REQ (unsigned char)0x42 /* Request communication capabilities. length 2 */ #define PW_UPS_TOP_DATA_REQ (unsigned char)0x43 /* Request ups topology data requset. length 1 */ #define PW_COM_PORT_LIST_BLOCK_REQ (unsigned char)0x44 /* Request communication port list. length 1 */ #define PW_REQUEST_SCRATCHPAD_DATA_REQ (unsigned char)0x45 /* Request data from scratchpad. length 2*/ /* Need autorisation before these commands */ #define PW_GO_TO_BYPASS (unsigned char)0x88 /* Transfer load from inverter to bypass. length 1 or 3 */ #define PW_UPS_ON (unsigned char)0x89 /* UPS on command. length 1-2 */ #define PW_LOAD_OFF_RESTART (unsigned char)0x8A /* Delayed LoadPowerOff & Restart command. length 2-4 */ #define PW_UPS_OFF (unsigned char)0x8B /* UPS off command. length 1-2 */ #define PW_DECREMENT_OUTPUT_VOLTAGE (unsigned char)0x8C /* Decrease output voltage. length 1 */ #define PW_INCREMENT_OUTPUT_VOLTAGE (unsigned char)0x8D /* Increase output voltage. length 1 */ #define PW_SET_TIME_AND_DATE (unsigned char)0x90 /* Set the real-time clock inside UPS. length 8 */ #define PW_UPS_ON_TIME (unsigned char)0x91 /* Scheduled UPS on in n minutes. length 3-4 */ #define PW_UPS_ON_AT_TIME (unsigned char)0x92 /* Schedule UPS on at specified date and time. length 7-8 */ #define PW_UPS_OFF_TIME (unsigned char)0x93 /* Scheduled UPS off in n minutes. length 3-4 */ #define PW_UPS_OFF_AT_TIME (unsigned char)0x94 /* Schedule UPS off at specified date and time. length 7-8 */ #define PW_SET_CONF_COMMAND (unsigned char)0x95 /* Set configuration command. length 4 */ #define PW_SET_OUTLET_COMMAND (unsigned char)0x97 /* Set outlet parameter command length 5. not in 5115 */ #define PW_SET_COM_COMMAND (unsigned char)0x98 /* Set communication parameter command. length 5 */ #define PW_SET_SCRATHPAD_SECTOR (unsigned char)0x99 /* Write data to scratchpad. length 3 or 18 */ #define PW_SET_POWER_STRATEGY (unsigned char)0x9A /* Set the power strategy. length 2 */ #define PW_SET_REQ_ONLY_MODE (unsigned char)0xA0 /* Set request only mode command. length 1 */ #define PW_SET_UNREQUESTED_MODE (unsigned char)0xA1 /* Set unrequested mode command. length 1 */ #define PW_INIT_BAT_TEST (unsigned char)0xB1 /* Initiate battery test command. length 3 */ #define PW_INIT_SYS_TEST (unsigned char)0xB2 /* Initiate general system test command. length 2 */ #define PW_SELECT_SUBMODULE (unsigned char)0xCE /* Select a sub module. length 2-7 */ #define PW_AUTHORIZATION_CODE (unsigned char)0xCF /* Authorization code. length 4 or 7 */ /* Define the XCP system test */ #define PW_SYS_TEST_GENERAL (unsigned char)0x01 /* Initiate General system Test */ #define PW_SYS_TEST_SCHEDULE_BATTERY_COMMISSION (unsigned char)0x02 /* Schedule Battery Commissioning Test */ #define PW_SYS_TEST_ALTERNATE_AC_INPUT (unsigned char)0x03 /* Test Alternate AC Input */ #define PW_SYS_TEST_FLASH_LIGHTS (unsigned char)0x04 /* Flash the Lights Test */ #define PW_SYS_TEST_REPORT_CAPABILITIES (unsigned char)0xFF /* Report Systems Test Capabilities */ /* Outlet operations */ #define PW_ALL_OUTLETS 0 #define PW_AUTO_OFF_DELAY 1 #define PW_AUTO_ON_DELAY 2 /* 0 means Abort countdown */ #define PW_TURN_OFF_DELAY 3 #define PW_TURN_ON_DELAY 4 /* Config vars*/ #define PW_CONF_BYPASS_FREQ_DEV_LIMIT 0x01 #define PW_CONF_LOW_DEV_LIMIT 0x02 #define PW_CONF_HIGH_DEV_LIMIT 0x03 #define PW_CONF_PHASE_DEV_LIMIT 0x04 #define PW_CONF_LOW_BATT 0x05 #define PW_CONF_BEEPER 0x06 #define PW_CONF_RETURN_DELAY 0x07 #define PW_CONF_RETURN_CAP 0x08 #define PW_CONF_MAX_TEMP 0x0a #define PW_CONF_NOMINAL_OUT_VOLTAGE 0x0b #define PW_CONF_SLEEP_TH_LOAD 0x0d #define PW_CONF_SLEEP_DELAY 0x0e #define PW_CONF_BATT_STRINGS 0x0f #define PW_CONF_REQ 0xff /* Config block offsets */ #define BCMXCP_CONFIG_BLOCK_MACHINE_TYPE_CODE 0 #define BCMXCP_CONFIG_BLOCK_MODEL_NUMBER 2 #define BCMXCP_CONFIG_BLOCK_MODEL_CONF_WORD 4 #define BCMXCP_CONFIG_BLOCK_INPUT_FREQ_DEV_LIMIT 6 #define BCMXCP_CONFIG_BLOCK_NOMINAL_OUTPUT_VOLTAGE 8 #define BCMXCP_CONFIG_BLOCK_NOMINAL_OUTPUT_FREQ 10 #define BCMXCP_CONFIG_BLOCK_OUTPUT_PHASE_ANGLE 12 #define BCMXCP_CONFIG_BLOCK_HW_MODULES_INSTALLED_WORD1 14 #define BCMXCP_CONFIG_BLOCK_HW_MODULES_INSTALLED_BYTE3 16 /* KEEP THIS UNTILL PARSING OK. USE THIS BYTE. */ #define BCMXCP_CONFIG_BLOCK_HW_MODULES_INSTALLED_WORD2 16 #define BCMXCP_CONFIG_BLOCK_HW_MODULES_INSTALLED_WORD3 18 #define BCMXCP_CONFIG_BLOCK_HW_MODULES_INSTALLED_WORD4 20 #define BCMXCP_CONFIG_BLOCK_BATTERY_DATA_WORD1 22 /* Undefined at this time.*/ #define BCMXCP_CONFIG_BLOCK_BATTERY_DATA_WORD2 24 /* Per cell inverter shutdown voltage at full rated load. (volt/cell)* 100 */ #define BCMXCP_CONFIG_BLOCK_BATTERY_DATA_WORD3 26 /* LOW BYTE Number of battery strings. HIGH BYTE undefined at this time.*/ #define BCMXCP_CONFIG_BLOCK_EXTENDED_BLOCK_LENGTH 47 #define BCMXCP_CONFIG_BLOCK_PART_NUMBER 48 #define BCMXCP_CONFIG_BLOCK_SERIAL_NUMBER 64 /*Battery block offsets*/ #define BCMXCP_BATTDATA_BLOCK_BATT_TEST_STATUS 0 #define BCMXCP_BATTDATA_BLOCK_BATT_VOLTS_T1 1 #define BCMXCP_BATTDATA_BLOCK_BATT_VOLTS_T2 5 #define BCMXCP_BATTDATA_BLOCK_TEST_DURATION 9 #define BCMXCP_BATTDATA_BLOCK_UTIL_VOLT 10 #define BCMXCP_BATTDATA_BLOCK_INPUT_CURRENT 14 #define BCMXCP_BATTDATA_BLOCK_NUMBER_OF_STRINGS 18 /*BATT_TEST_STATUS for external strings (1 byte each) if BCMXCP_BATTDATA_BLOCK_NUMBER_OF_STRINGS == 0 no external test statuses at all*/ /*next - number of ABM Statuses - at least 1 for internal batteries*/ /* Index for Extende Limits block offsets */ #define BCMXCP_EXT_LIMITS_BLOCK_NOMINAL_INPUT_VOLTAGE 0 #define BCMXCP_EXT_LIMITS_BLOCK_NOMINAL_INPUT_FREQ 2 #define BCMXCP_EXT_LIMITS_BLOCK_NOMINAL_TRUE_POWER 4 #define BCMXCP_EXT_LIMITS_BLOCK_COMM_SPEC_VERSION 6 #define BCMXCP_EXT_LIMITS_BLOCK_FREQ_DEV_LIMIT 8 #define BCMXCP_EXT_LIMITS_BLOCK_VOLTAGE_LOW_DEV_LIMIT 10 #define BCMXCP_EXT_LIMITS_BLOCK_VOLTAGE_HIGE_DEV_LIMIT 12 #define BCMXCP_EXT_LIMITS_BLOCK_PHASE_DEV_LIMIT 14 #define BCMXCP_EXT_LIMITS_BLOCK_LOW_BATT_WARNING 16 #define BCMXCP_EXT_LIMITS_BLOCK_HORN_STATUS 17 #define BCMXCP_EXT_LIMITS_BLOCK_MIN_INPUT_VOLTAGE 18 #define BCMXCP_EXT_LIMITS_BLOCK_MAX_INPUT_VOLTAGE 20 #define BCMXCP_EXT_LIMITS_BLOCK_RETURN_STAB_DELAY 22 #define BCMXCP_EXT_LIMITS_BLOCK_BATT_CAPACITY_RETURN 24 #define BCMXCP_EXT_LIMITS_BLOCK_AMBIENT_TEMP_LOW 25 #define BCMXCP_EXT_LIMITS_BLOCK_AMBIENT_TEMP_HIGE 26 #define BCMXCP_EXT_LIMITS_BLOCK_SLEEP_TH_LOAD 29 #define BCMXCP_EXT_LIMITS_BLOCK_SLEEP_DELAY 30 /* Indexes for meter map */ #define BCMXCP_METER_MAP_OUTPUT_VOLTS_AB 0 /* mapped */ #define BCMXCP_METER_MAP_OUTPUT_VOLTS_BC 1 /* mapped */ #define BCMXCP_METER_MAP_OUTPUT_VOLTS_CA 2 /* mapped */ #define BCMXCP_METER_MAP_INPUT_VOLTS_AB 3 /* mapped */ #define BCMXCP_METER_MAP_INPUT_VOLTS_BC 4 /* mapped */ #define BCMXCP_METER_MAP_INPUT_VOLTS_CA 5 /* mapped */ #define BCMXCP_METER_MAP_INVERTER_VOLTS_AB 6 #define BCMXCP_METER_MAP_INVERTER_VOLTS_BC 7 #define BCMXCP_METER_MAP_INVERTER_VOLTS_CA 8 #define BCMXCP_METER_MAP_BYPASS_VOLTS_AB 9 #define BCMXCP_METER_MAP_BYPASS_VOLTS_BC 10 #define BCMXCP_METER_MAP_BYPASS_VOLTS_CA 11 #define BCMXCP_METER_MAP_MAIN_LOGIC_POWER 12 #define BCMXCP_METER_MAP_SECONDARY_V_PLUS_POWER 13 #define BCMXCP_METER_MAP_SECONDARY_V_MINUS_POWER 14 #define BCMXCP_METER_MAP_INVERTER_AVG_CURRENT_PHASE_A 15 #define BCMXCP_METER_MAP_INVERTER_AVG_CURRENT_PHASE_B 16 #define BCMXCP_METER_MAP_INVERTER_AVG_CURRENT_PHASE_C 17 #define BCMXCP_METER_MAP_INPUT_CURRENT_PHASE_A 18 /* mapped */ #define BCMXCP_METER_MAP_INPUT_CURRENT_PHASE_B 19 /* mapped */ #define BCMXCP_METER_MAP_INPUT_CURRENT_PHASE_C 20 /* mapped */ #define BCMXCP_METER_MAP_OUTPUT_WATTS 21 #define BCMXCP_METER_MAP_INPUT_WATTS 22 /* mapped */ #define BCMXCP_METER_MAP_OUTPUT_VA 23 /* mapped */ #define BCMXCP_METER_MAP_INPUT_VA 24 /* mapped */ #define BCMXCP_METER_MAP_OUTPUT_POWER_FACTOR 25 /* mapped */ #define BCMXCP_METER_MAP_INPUT_POWER_FACTOR 26 /* mapped */ #define BCMXCP_METER_MAP_OUTPUT_FREQUENCY 27 /* mapped */ #define BCMXCP_METER_MAP_INPUT_FREQUENCY 28 /* mapped */ #define BCMXCP_METER_MAP_INVERTER_FREQUENCY 29 #define BCMXCP_METER_MAP_BYPASS_FREQUENCY 30 /* mapped */ #define BCMXCP_METER_MAP_DC_LINK_VOLTS_DC 31 #define BCMXCP_METER_MAP_BATTERY_CURRENT 32 /* mapped */ #define BCMXCP_METER_MAP_BATTERY_VOLTAGE 33 /* mapped */ #define BCMXCP_METER_MAP_PERCENT_BATTERY_LEFT 34 /* mapped */ #define BCMXCP_METER_MAP_BATTERY_TIME_REMAINING 35 /* mapped */ #define BCMXCP_METER_MAP_BATTERY_CHARGE_TIME 36 #define BCMXCP_METER_MAP_PEAK_INVERTER_CURRENT_PHASE_A 37 #define BCMXCP_METER_MAP_PEAK_INVERTER_CURRENT_PHASE_B 38 #define BCMXCP_METER_MAP_PEAK_INVERTER_CURRENT_PHASE_C 39 #define BCMXCP_METER_MAP_AVG_INPUT_CURRENT_3_PHASE_SUM 40 #define BCMXCP_METER_MAP_BATTERY_DCUV_BAR_CHART 41 /* mapped */ #define BCMXCP_METER_MAP_INPUT_CURRENT_BAR_CHART 42 #define BCMXCP_METER_MAP_LOW_BATTERY_WARNING_V_BAR_CHART 43 /* mapped */ #define BCMXCP_METER_MAP_DC_VOLTS_BAR_CHART 44 #define BCMXCP_METER_MAP_BATTERY_CHARGING_CURRENT_BAR_CHART 45 #define BCMXCP_METER_MAP_BATTERY_DISCHARGING_CURRENT_BAR_CHART 46 /* mapped */ #define BCMXCP_METER_MAP_PERCENT_LOAD_PHASE_A 47 /* mapped */ #define BCMXCP_METER_MAP_PERCENT_LOAD_PHASE_B 48 /* mapped */ #define BCMXCP_METER_MAP_PERCENT_LOAD_PHASE_C 49 /* mapped */ #define BCMXCP_METER_MAP_OUTPUT_VA_PHASE_A 50 /* mapped */ #define BCMXCP_METER_MAP_OUTPUT_VA_PHASE_B 51 /* mapped */ #define BCMXCP_METER_MAP_OUTPUT_VA_PHASE_C 52 /* mapped */ #define BCMXCP_METER_MAP_BYPASS_VOLTS_PHASE_A 53 /* mapped */ #define BCMXCP_METER_MAP_BYPASS_VOLTS_PHASE_B 54 /* mapped */ #define BCMXCP_METER_MAP_BYPASS_VOLTS_PHASE_C 55 /* mapped */ #define BCMXCP_METER_MAP_INPUT_VOLTS_PHASE_A 56 /* mapped */ #define BCMXCP_METER_MAP_INPUT_VOLTS_PHASE_B 57 /* mapped */ #define BCMXCP_METER_MAP_INPUT_VOLTS_PHASE_C 58 /* mapped */ #define BCMXCP_METER_MAP_INVERTER_VOLTS_PHASE_A 59 #define BCMXCP_METER_MAP_INVERTER_VOLTS_PHASE_B 60 #define BCMXCP_METER_MAP_INVERTER_VOLTS_PHASE_C 61 #define BCMXCP_METER_MAP_AMBIENT_TEMPERATURE 62 /* mapped */ #define BCMXCP_METER_MAP_HEATSINK_TEMPERATURE 63 /* mapped */ #define BCMXCP_METER_MAP_POWER_SUPPLY_TEMPERATURE 64 /* mapped */ #define BCMXCP_METER_MAP_LOAD_CURRENT_PHASE_A 65 /* mapped */ #define BCMXCP_METER_MAP_LOAD_CURRENT_PHASE_B 66 /* mapped */ #define BCMXCP_METER_MAP_LOAD_CURRENT_PHASE_C 67 /* mapped */ #define BCMXCP_METER_MAP_LOAD_CURRENT_PHASE_A_BAR_CHART 68 /* mapped */ #define BCMXCP_METER_MAP_LOAD_CURRENT_PHASE_B_BAR_CHART 69 /* mapped */ #define BCMXCP_METER_MAP_LOAD_CURRENT_PHASE_C_BAR_CHART 70 /* mapped */ #define BCMXCP_METER_MAP_OUTPUT_VA_BAR_CHART 71 /* mapped */ #define BCMXCP_METER_MAP_DATE 72 /* mapped */ #define BCMXCP_METER_MAP_TIME 73 /* mapped */ #define BCMXCP_METER_MAP_POSITIVE_DC_LINK_RAIL_VOLTAGE 74 #define BCMXCP_METER_MAP_NEGATIVE_DC_LINK_RAIL_VOLTAGE 75 #define BCMXCP_METER_MAP_AUTO_BALANCE_VOLTAGE_DC 76 #define BCMXCP_METER_MAP_BATTERY_TEMPERATURE 77 /* mapped */ #define BCMXCP_METER_MAP_OUTPUT_VOLTS_A 78 /* mapped */ #define BCMXCP_METER_MAP_OUTPUT_VOLTS_B 79 /* mapped */ #define BCMXCP_METER_MAP_OUTPUT_VOLTS_C 80 /* mapped */ #define BCMXCP_METER_MAP_NEUTRAL_CURRENT 81 #define BCMXCP_METER_MAP_OUTPUT_WATTS_PHASE_A 82 /* mapped */ #define BCMXCP_METER_MAP_OUTPUT_WATTS_PHASE_B 83 /* mapped */ #define BCMXCP_METER_MAP_OUTPUT_WATTS_PHASE_C 84 /* mapped */ #define BCMXCP_METER_MAP_OUTPUT_WATTS_PHASE_A_B_C_BAR_CHART 85 /* mapped */ #define BCMXCP_METER_MAP_RECTIFIER_DC_CURRENT 86 #define BCMXCP_METER_MAP_POSITIVE_BATTERY_VOLTAGE 87 #define BCMXCP_METER_MAP_NEGATIVE_BATTERY_VOLTAGE 88 #define BCMXCP_METER_MAP_POSITIVE_BATTERY_CURRENT 89 #define BCMXCP_METER_MAP_NEGATIVE_BATTERY_CURRENT 90 #define BCMXCP_METER_MAP_LINE_EVENT_COUNTER 91 /* mapped */ #define BCMXCP_METER_MAP_OUTPUT_V1_PERCENT 92 #define BCMXCP_METER_MAP_OUTPUT_V2_PERCENT 93 #define BCMXCP_METER_MAP_OUTPUT_V3_PERCENT 94 #define BCMXCP_METER_MAP_OUTPUT_I1_PERCENT 95 #define BCMXCP_METER_MAP_OUTPUT_I2_PERCENT 96 #define BCMXCP_METER_MAP_OUTPUT_I3_PERCENT 97 #define BCMXCP_METER_MAP_INPUT_V1_PERCENT 98 #define BCMXCP_METER_MAP_INPUT_V2_PERCENT 99 #define BCMXCP_METER_MAP_INPUT_V3_PERCENT 100 #define BCMXCP_METER_MAP_INPUT_I1_PERCENT 101 #define BCMXCP_METER_MAP_INPUT_I2_PERCENT 102 #define BCMXCP_METER_MAP_INPUT_I3_PERCENT 103 #define BCMXCP_METER_MAP_GROUND_CURRENT 104 #define BCMXCP_METER_MAP_OUTPUT_CREST_FACTOR_L1 105 #define BCMXCP_METER_MAP_OUTPUT_CREST_FACTOR_L2 106 #define BCMXCP_METER_MAP_OUTPUT_CREST_FACTOR_L3 107 #define BCMXCP_METER_MAP_OUTPUT_KW_HOUR 108 #define BCMXCP_METER_MAP_INPUT_VOLTAGE_THD_LINE1 109 #define BCMXCP_METER_MAP_INPUT_VOLTAGE_THD_LINE2 110 #define BCMXCP_METER_MAP_INPUT_VOLTAGE_THD_LINE3 111 #define BCMXCP_METER_MAP_INPUT_CURRENT_THD_LINE1 112 #define BCMXCP_METER_MAP_INPUT_CURRENT_THD_LINE2 113 #define BCMXCP_METER_MAP_INPUT_CURRENT_THD_LINE3 114 #define BCMXCP_METER_MAP_OUTPUT_VOLTAGE_THD_LINE1 115 #define BCMXCP_METER_MAP_OUTPUT_VOLTAGE_THD_LINE2 116 #define BCMXCP_METER_MAP_OUTPUT_VOLTAGE_THD_LINE3 117 #define BCMXCP_METER_MAP_OUTPUT_CURRENT_THD_LINE1 118 #define BCMXCP_METER_MAP_OUTPUT_CURRENT_THD_LINE2 119 #define BCMXCP_METER_MAP_OUTPUT_CURRENT_THD_LINE3 120 #define BCMXCP_METER_MAP_INPUT_CREST_FACTOR_L1 121 #define BCMXCP_METER_MAP_INPUT_CREST_FACTOR_L2 122 #define BCMXCP_METER_MAP_INPUT_CREST_FACTOR_L3 123 #define BCMXCP_METER_MAP_INPUT_KW_HOUR 124 #define BCMXCP_METER_MAP_BATTERY_LIFE_REMAINING 125 #define BCMXCP_METER_MAP_SECONDARY_NEUTRAL_CURRENT 126 #define BCMXCP_METER_MAP_SECONDARY_GROUND_CURRENT 127 #define BCMXCP_METER_MAP_HOURS_OF_OPERATION 128 /* Indexes for alarm map */ #define BCMXCP_ALARM_INVERTER_AC_OVER_VOLTAGE 0 #define BCMXCP_ALARM_INVERTER_AC_UNDER_VOLTAGE 1 #define BCMXCP_ALARM_INVERTER_OVER_OR_UNDER_FREQ 2 #define BCMXCP_ALARM_BYPASS_AC_OVER_VOLTAGE 3 #define BCMXCP_ALARM_BYPASS_AC_UNDER_VOLTAGE 4 #define BCMXCP_ALARM_BYPASS_OVER_OR_UNDER_FREQ 5 #define BCMXCP_ALARM_INPUT_AC_OVER_VOLTAGE 6 #define BCMXCP_ALARM_INPUT_AC_UNDER_VOLTAGE 7 #define BCMXCP_ALARM_INPUT_UNDER_OR_OVER_FREQ 8 #define BCMXCP_ALARM_OUTPUT_OVER_VOLTAGE 9 #define BCMXCP_ALARM_OUTPUT_UNDER_VOLTAGE 10 #define BCMXCP_ALARM_OUTPUT_UNDER_OR_OVER_FREQ 11 #define BCMXCP_ALARM_REMOTE_EMERGENCY_PWR_OFF 12 #define BCMXCP_ALARM_REMOTE_GO_TO_BYPASS 13 #define BCMXCP_ALARM_BUILDING_ALARM_6 14 #define BCMXCP_ALARM_BUILDING_ALARM_5 15 #define BCMXCP_ALARM_BUILDING_ALARM_4 16 #define BCMXCP_ALARM_BUILDING_ALARM_3 17 #define BCMXCP_ALARM_BUILDING_ALARM_2 18 #define BCMXCP_ALARM_BUILDING_ALARM_1 19 #define BCMXCP_ALARM_STATIC_SWITCH_OVER_TEMP 20 #define BCMXCP_ALARM_CHARGER_OVER_TEMP 21 #define BCMXCP_ALARM_CHARGER_LOGIC_PWR_FAIL 22 #define BCMXCP_ALARM_CHARGER_OVER_VOLTAGE_OR_CURRENT 23 #define BCMXCP_ALARM_INVERTER_OVER_TEMP 24 #define BCMXCP_ALARM_OUTPUT_OVERLOAD 25 #define BCMXCP_ALARM_RECTIFIER_INPUT_OVER_CURRENT 26 #define BCMXCP_ALARM_INVERTER_OUTPUT_OVER_CURRENT 27 #define BCMXCP_ALARM_DC_LINK_OVER_VOLTAGE 28 #define BCMXCP_ALARM_DC_LINK_UNDER_VOLTAGE 29 #define BCMXCP_ALARM_RECTIFIER_FAILED 30 #define BCMXCP_ALARM_INVERTER_FAULT 31 #define BCMXCP_ALARM_BATTERY_CONNECTOR_FAIL 32 #define BCMXCP_ALARM_BYPASS_BREAKER_FAIL 33 #define BCMXCP_ALARM_CHARGER_FAIL 34 #define BCMXCP_ALARM_RAMP_UP_FAILED 35 #define BCMXCP_ALARM_STATIC_SWITCH_FAILED 36 #define BCMXCP_ALARM_ANALOG_AD_REF_FAIL 37 #define BCMXCP_ALARM_BYPASS_UNCALIBRATED 38 #define BCMXCP_ALARM_RECTIFIER_UNCALIBRATED 39 #define BCMXCP_ALARM_OUTPUT_UNCALIBRATED 40 #define BCMXCP_ALARM_INVERTER_UNCALIBRATED 41 #define BCMXCP_ALARM_DC_VOLT_UNCALIBRATED 42 #define BCMXCP_ALARM_OUTPUT_CURRENT_UNCALIBRATED 43 #define BCMXCP_ALARM_RECTIFIER_CURRENT_UNCALIBRATED 44 #define BCMXCP_ALARM_BATTERY_CURRENT_UNCALIBRATED 45 #define BCMXCP_ALARM_INVERTER_ON_OFF_STAT_FAIL 46 #define BCMXCP_ALARM_BATTERY_CURRENT_LIMIT 47 #define BCMXCP_ALARM_INVERTER_STARTUP_FAIL 48 #define BCMXCP_ALARM_ANALOG_BOARD_AD_STAT_FAIL 49 #define BCMXCP_ALARM_OUTPUT_CURRENT_OVER_100 50 #define BCMXCP_ALARM_BATTERY_GROUND_FAULT 51 #define BCMXCP_ALARM_WAITING_FOR_CHARGER_SYNC 52 #define BCMXCP_ALARM_NV_RAM_FAIL 53 #define BCMXCP_ALARM_ANALOG_BOARD_AD_TIMEOUT 54 #define BCMXCP_ALARM_SHUTDOWN_IMMINENT 55 #define BCMXCP_ALARM_BATTERY_LOW 56 #define BCMXCP_ALARM_UTILITY_FAIL 57 #define BCMXCP_ALARM_OUTPUT_SHORT_CIRCUIT 58 #define BCMXCP_ALARM_UTILITY_NOT_PRESENT 59 #define BCMXCP_ALARM_FULL_TIME_CHARGING 60 #define BCMXCP_ALARM_FAST_BYPASS_COMMAND 61 #define BCMXCP_ALARM_AD_ERROR 62 #define BCMXCP_ALARM_INTERNAL_COM_FAIL 63 #define BCMXCP_ALARM_RECTIFIER_SELFTEST_FAIL 64 #define BCMXCP_ALARM_RECTIFIER_EEPROM_FAIL 65 #define BCMXCP_ALARM_RECTIFIER_EPROM_FAIL 66 #define BCMXCP_ALARM_INPUT_LINE_VOLTAGE_LOSS 67 #define BCMXCP_ALARM_BATTERY_DC_OVER_VOLTAGE 68 #define BCMXCP_ALARM_POWER_SUPPLY_OVER_TEMP 69 #define BCMXCP_ALARM_POWER_SUPPLY_FAIL 70 #define BCMXCP_ALARM_POWER_SUPPLY_5V_FAIL 71 #define BCMXCP_ALARM_POWER_SUPPLY_12V_FAIL 72 #define BCMXCP_ALARM_HEATSINK_OVER_TEMP 73 #define BCMXCP_ALARM_HEATSINK_TEMP_SENSOR_FAIL 74 #define BCMXCP_ALARM_RECTIFIER_CURRENT_OVER_125 75 #define BCMXCP_ALARM_RECTIFIER_FAULT_INTERRUPT_FAIL 76 #define BCMXCP_ALARM_RECTIFIER_POWER_CAPACITOR_FAIL 77 #define BCMXCP_ALARM_RECTIFIER_POWER_CAPASITOR_FAIL 77 /* Legacy - typo */ #define BCMXCP_ALARM_INVERTER_PROGRAM_STACK_ERROR 78 #define BCMXCP_ALARM_INVERTER_BOARD_SELFTEST_FAIL 79 #define BCMXCP_ALARM_INVERTER_AD_SELFTEST_FAIL 80 #define BCMXCP_ALARM_INVERTER_RAM_SELFTEST_FAIL 81 #define BCMXCP_ALARM_NV_MEMORY_CHECKSUM_FAIL 82 #define BCMXCP_ALARM_PROGRAM_CHECKSUM_FAIL 83 #define BCMXCP_ALARM_INVERTER_CPU_SELFTEST_FAIL 84 #define BCMXCP_ALARM_NETWORK_NOT_RESPONDING 85 #define BCMXCP_ALARM_FRONT_PANEL_SELFTEST_FAIL 86 #define BCMXCP_ALARM_NODE_EEPROM_VERIFICATION_ERROR 87 #define BCMXCP_ALARM_OUTPUT_AC_OVER_VOLT_TEST_FAIL 88 #define BCMXCP_ALARM_OUTPUT_DC_OVER_VOLTAGE 89 #define BCMXCP_ALARM_INPUT_PHASE_ROTATION_ERROR 90 #define BCMXCP_ALARM_INVERTER_RAMP_UP_TEST_FAILED 91 #define BCMXCP_ALARM_INVERTER_OFF_COMMAND 92 #define BCMXCP_ALARM_INVERTER_ON_COMMAND 93 #define BCMXCP_ALARM_TO_BYPASS_COMMAND 94 #define BCMXCP_ALARM_FROM_BYPASS_COMMAND 95 #define BCMXCP_ALARM_AUTO_MODE_COMMAND 96 #define BCMXCP_ALARM_EMERGENCY_SHUTDOWN_COMMAND 97 #define BCMXCP_ALARM_SETUP_SWITCH_OPEN 98 #define BCMXCP_ALARM_INVERTER_OVER_VOLT_INT 99 #define BCMXCP_ALARM_INVERTER_UNDER_VOLT_INT 100 #define BCMXCP_ALARM_ABSOLUTE_DCOV_ACOV 101 #define BCMXCP_ALARM_PHASE_A_CURRENT_LIMIT 102 #define BCMXCP_ALARM_PHASE_B_CURRENT_LIMIT 103 #define BCMXCP_ALARM_PHASE_C_CURRENT_LIMIT 104 #define BCMXCP_ALARM_BYPASS_NOT_AVAILABLE 105 #define BCMXCP_ALARM_RECTIFIER_BREAKER_OPEN 106 #define BCMXCP_ALARM_BATTERY_CONTACTOR_OPEN 107 #define BCMXCP_ALARM_INVERTER_CONTACTOR_OPEN 108 #define BCMXCP_ALARM_BYPASS_BREAKER_OPEN 109 #define BCMXCP_ALARM_INV_BOARD_ACOV_INT_TEST_FAIL 110 #define BCMXCP_ALARM_INVERTER_OVER_TEMP_TRIP 111 #define BCMXCP_ALARM_INV_BOARD_ACUV_INT_TEST_FAIL 112 #define BCMXCP_ALARM_INVERTER_VOLTAGE_FEEDBACK_ERROR 113 #define BCMXCP_ALARM_DC_UNDER_VOLTAGE_TIMEOUT 114 #define BCMXCP_ALARM_AC_UNDER_VOLTAGE_TIMEOUT 115 #define BCMXCP_ALARM_DC_UNDER_VOLTAGE_WHILE_CHARGE 116 #define BCMXCP_ALARM_INVERTER_VOLTAGE_BIAS_ERROR 117 #define BCMXCP_ALARM_RECTIFIER_PHASE_ROTATION 118 #define BCMXCP_ALARM_BYPASS_PHASER_ROTATION 119 #define BCMXCP_ALARM_SYSTEM_INTERFACE_BOARD_FAIL 120 #define BCMXCP_ALARM_PARALLEL_BOARD_FAIL 121 #define BCMXCP_ALARM_LOST_LOAD_SHARING_PHASE_A 122 #define BCMXCP_ALARM_LOST_LOAD_SHARING_PHASE_B 123 #define BCMXCP_ALARM_LOST_LOAD_SHARING_PHASE_C 124 #define BCMXCP_ALARM_DC_OVER_VOLTAGE_TIMEOUT 125 #define BCMXCP_ALARM_BATTERY_TOTALLY_DISCHARGED 126 #define BCMXCP_ALARM_INVERTER_PHASE_BIAS_ERROR 127 #define BCMXCP_ALARM_INVERTER_VOLTAGE_BIAS_ERROR_2 128 #define BCMXCP_ALARM_DC_LINK_BLEED_COMPLETE 129 #define BCMXCP_ALARM_LARGE_CHARGER_INPUT_CURRENT 130 #define BCMXCP_ALARM_INV_VOLT_TOO_LOW_FOR_RAMP_LEVEL 131 #define BCMXCP_ALARM_LOSS_OF_REDUNDANCY 132 #define BCMXCP_ALARM_LOSS_OF_SYNC_BUS 133 #define BCMXCP_ALARM_RECTIFIER_BREAKER_SHUNT_TRIP 134 #define BCMXCP_ALARM_LOSS_OF_CHARGER_SYNC 135 #define BCMXCP_ALARM_INVERTER_LOW_LEVEL_TEST_TIMEOUT 136 #define BCMXCP_ALARM_OUTPUT_BREAKER_OPEN 137 #define BCMXCP_ALARM_CONTROL_POWER_ON 138 #define BCMXCP_ALARM_INVERTER_ON 139 #define BCMXCP_ALARM_CHARGER_ON 140 #define BCMXCP_ALARM_BYPASS_ON 141 #define BCMXCP_ALARM_BYPASS_POWER_LOSS 142 #define BCMXCP_ALARM_ON_MANUAL_BYPASS 143 #define BCMXCP_ALARM_BYPASS_MANUAL_TURN_OFF 144 #define BCMXCP_ALARM_INVERTER_BLEEDING_DC_LINK_VOLT 145 #define BCMXCP_ALARM_CPU_ISR_ERROR 146 #define BCMXCP_ALARM_SYSTEM_ISR_RESTART 147 #define BCMXCP_ALARM_PARALLEL_DC 148 #define BCMXCP_ALARM_BATTERY_NEEDS_SERVICE 149 #define BCMXCP_ALARM_BATTERY_CHARGING 150 #define BCMXCP_ALARM_BATTERY_NOT_CHARGED 151 #define BCMXCP_ALARM_DISABLED_BATTERY_TIME 152 #define BCMXCP_ALARM_SERIES_7000_ENABLE 153 #define BCMXCP_ALARM_OTHER_UPS_ON 154 #define BCMXCP_ALARM_PARALLEL_INVERTER 155 #define BCMXCP_ALARM_UPS_IN_PARALLEL 156 #define BCMXCP_ALARM_OUTPUT_BREAKER_REALY_FAIL 157 #define BCMXCP_ALARM_CONTROL_POWER_OFF 158 #define BCMXCP_ALARM_LEVEL_2_OVERLOAD_PHASE_A 159 #define BCMXCP_ALARM_LEVEL_2_OVERLOAD_PHASE_B 160 #define BCMXCP_ALARM_LEVEL_2_OVERLOAD_PHASE_C 161 #define BCMXCP_ALARM_LEVEL_3_OVERLOAD_PHASE_A 162 #define BCMXCP_ALARM_LEVEL_3_OVERLOAD_PHASE_B 163 #define BCMXCP_ALARM_LEVEL_3_OVERLOAD_PHASE_C 164 #define BCMXCP_ALARM_LEVEL_4_OVERLOAD_PHASE_A 165 #define BCMXCP_ALARM_LEVEL_4_OVERLOAD_PHASE_B 166 #define BCMXCP_ALARM_LEVEL_4_OVERLOAD_PHASE_C 167 #define BCMXCP_ALARM_UPS_ON_BATTERY 168 #define BCMXCP_ALARM_UPS_ON_BYPASS 169 #define BCMXCP_ALARM_LOAD_DUMPED 170 #define BCMXCP_ALARM_LOAD_ON_INVERTER 171 #define BCMXCP_ALARM_UPS_ON_COMMAND 172 #define BCMXCP_ALARM_UPS_OFF_COMMAND 173 #define BCMXCP_ALARM_LOW_BATTERY_SHUTDOWN 174 #define BCMXCP_ALARM_AUTO_ON_ENABLED 175 #define BCMXCP_ALARM_SOFTWARE_INCOMPABILITY_DETECTED 176 #define BCMXCP_ALARM_INVERTER_TEMP_SENSOR_FAILED 177 #define BCMXCP_ALARM_DC_START_OCCURED 178 #define BCMXCP_ALARM_IN_PARALLEL_OPERATION 179 #define BCMXCP_ALARM_SYNCING_TO_BYPASS 180 #define BCMXCP_ALARM_RAMPING_UPS_UP 181 #define BCMXCP_ALARM_INVERTER_ON_DELAY 182 #define BCMXCP_ALARM_CHARGER_ON_DELAY 183 #define BCMXCP_ALARM_WAITING_FOR_UTIL_INPUT 184 #define BCMXCP_ALARM_CLOSE_BYPASS_BREAKER 185 #define BCMXCP_ALARM_TEMPORARY_BYPASS_OPERATION 186 #define BCMXCP_ALARM_SYNCING_TO_OUTPUT 187 #define BCMXCP_ALARM_BYPASS_FAILURE 188 #define BCMXCP_ALARM_AUTO_OFF_COMMAND_EXECUTED 189 #define BCMXCP_ALARM_AUTO_ON_COMMAND_EXECUTED 190 #define BCMXCP_ALARM_BATTERY_TEST_FAILED 191 #define BCMXCP_ALARM_FUSE_FAIL 192 #define BCMXCP_ALARM_FAN_FAIL 193 #define BCMXCP_ALARM_SITE_WIRING_FAULT 194 #define BCMXCP_ALARM_BACKFEED_CONTACTOR_FAIL 195 #define BCMXCP_ALARM_ON_BUCK 196 #define BCMXCP_ALARM_ON_BOOST 197 #define BCMXCP_ALARM_ON_DOUBLE_BOOST 198 #define BCMXCP_ALARM_BATTERIES_DISCONNECTED 199 #define BCMXCP_ALARM_UPS_CABINET_OVER_TEMP 200 #define BCMXCP_ALARM_TRANSFORMER_OVER_TEMP 201 #define BCMXCP_ALARM_AMBIENT_UNDER_TEMP 202 #define BCMXCP_ALARM_AMBIENT_OVER_TEMP 203 #define BCMXCP_ALARM_CABINET_DOOR_OPEN 204 #define BCMXCP_ALARM_CABINET_DOOR_OPEN_VOLT_PRESENT 205 #define BCMXCP_ALARM_AUTO_SHUTDOWN_PENDING 206 #define BCMXCP_ALARM_TAP_SWITCHING_REALY_PENDING 207 #define BCMXCP_ALARM_UNABLE_TO_CHARGE_BATTERIES 208 #define BCMXCP_ALARM_STARTUP_FAILURE_CHECK_EPO 209 #define BCMXCP_ALARM_AUTOMATIC_STARTUP_PENDING 210 #define BCMXCP_ALARM_MODEM_FAILED 211 #define BCMXCP_ALARM_INCOMING_MODEM_CALL_STARTED 212 #define BCMXCP_ALARM_OUTGOING_MODEM_CALL_STARTED 213 #define BCMXCP_ALARM_MODEM_CONNECTION_ESTABLISHED 214 #define BCMXCP_ALARM_MODEM_CALL_COMPLETED_SUCCESS 215 #define BCMXCP_ALARM_MODEM_CALL_COMPLETED_FAIL 216 #define BCMXCP_ALARM_INPUT_BREAKER_FAIL 217 #define BCMXCP_ALARM_SYSINIT_IN_PROGRESS 218 #define BCMXCP_ALARM_AUTOCALIBRATION_FAIL 219 #define BCMXCP_ALARM_SELECTIVE_TRIP_OF_MODULE 220 #define BCMXCP_ALARM_INVERTER_OUTPUT_FAILURE 221 #define BCMXCP_ALARM_ABNORMAL_OUTPUT_VOLT_AT_STARTUP 222 #define BCMXCP_ALARM_RECTIFIER_OVER_TEMP 223 #define BCMXCP_ALARM_CONFIG_ERROR 224 #define BCMXCP_ALARM_REDUNDANCY_LOSS_DUE_TO_OVERLOAD 225 #define BCMXCP_ALARM_ON_ALTERNATE_AC_SOURCE 226 #define BCMXCP_ALARM_IN_HIGH_EFFICIENCY_MODE 227 #define BCMXCP_ALARM_SYSTEM_NOTICE_ACTIVE 228 #define BCMXCP_ALARM_SYSTEM_ALARM_ACTIVE 229 #define BCMXCP_ALARM_ALTERNATE_POWER_SOURCE_NOT_AVAILABLE 230 #define BCMXCP_ALARM_CURRENT_BALANCE_FAILURE 231 #define BCMXCP_ALARM_CHECK_AIR_FILTER 232 #define BCMXCP_ALARM_SUBSYSTEM_NOTICE_ACTIVE 233 #define BCMXCP_ALARM_SUBSYSTEM_ALARM_ACTIVE 234 #define BCMXCP_ALARM_CHARGER_ON_COMMAND 235 #define BCMXCP_ALARM_CHARGER_OFF_COMMAND 236 #define BCMXCP_ALARM_UPS_NORMAL 237 #define BCMXCP_ALARM_INVERTER_PHASE_ROTATION 238 #define BCMXCP_ALARM_UPS_OFF 239 #define BCMXCP_ALARM_EXTERNAL_COMMUNICATION_FAILURE 240 #define BCMXCP_ALARM_BATTERY_TEST_INPROGRESS 256 #define BCMXCP_ALARM_SYSTEM_TEST_INPROGRESS 257 #define BCMXCP_ALARM_BATTERY_TEST_ABORTED 258 #define BCMXCP_COMMAND_MAP_MAX 208 /* Max no of entries in BCM/XCP meter map (adjusted upwards to nearest multi of 8) */ #define BCMXCP_METER_MAP_MAX 136 /* Max no of entries in BCM/XCP meter map (adjusted upwards to nearest multi of 8) */ #define BCMXCP_ALARM_MAP_MAX 264 /* Max no of entries in BCM/XCP alarm map (adjusted upwards to nearest multi of 8) */ /* Return codes for XCP ACK block responses */ #define BCMXCP_RETURN_ACCEPTED 0x31 /* Accepted and executed (or execution in progress) */ #define BCMXCP_RETURN_NOT_IMPLEMENTED 0x32 /* Recognized but not implemented */ #define BCMXCP_RETURN_BUSY 0x33 /* Recognized but not currently able to execute (busy) */ #define BCMXCP_RETURN_UNRECOGNISED 0x34 /* Unrecognized -- e.g., command byte not in valid range, or command has been corrupted (bad checksum) */ #define BCMXCP_RETURN_PARAMETER_OUT_OF_RANGE 0x35 /* Command recognized, but its Parameter value is out of range */ #define BCMXCP_RETURN_INVALID_PARAMETER 0x36 /* Command recognized, but its Parameter is invalid (e.g., no such parameter, bad Outlet number) */ #define BCMXCP_RETURN_ACCEPTED_PARAMETER_ADJUST 0x37 /* Accepted, with parameter adjusted to nearest good value */ /*#define BCMXCP_RETURN_READONLY 0x38 */ /* Parameter is Read-only - cannot be written (at this privilege level) (this is not listed in spec document */ /* UPS status */ #define BCMXCP_STATUS_ONLINE 0x50 #define BCMXCP_STATUS_ONBATTERY 0xf0 #define BCMXCP_STATUS_OVERLOAD 0xe0 #define BCMXCP_STATUS_TRIM 0x63 #define BCMXCP_STATUS_BOOST1 0x61 #define BCMXCP_STATUS_BOOST2 0x62 #define BCMXCP_STATUS_BYPASS 0x60 #define BCMXCP_STATUS_OFF 0x10 /* UPS topology block info */ #define BCMXCP_TOPOLOGY_NONE 0x0000 /* None; use the Table of Elements */ #define BCMXCP_TOPOLOGY_OFFLINE_SWITCHER_1P 0x0010 /* Off-line switcher, Single Phase */ #define BCMXCP_TOPOLOGY_LINEINT_UPS_1P 0x0020 /* Line-Interactive UPS, Single Phase */ #define BCMXCP_TOPOLOGY_LINEINT_UPS_2P 0x0021 /* Line-Interactive UPS, Two Phase */ #define BCMXCP_TOPOLOGY_LINEINT_UPS_3P 0x0022 /* Line-Interactive UPS, Three Phase */ #define BCMXCP_TOPOLOGY_DUAL_AC_ONLINE_UPS_1P 0x0030 /* Dual AC Input, On-Line UPS, Single Phase */ #define BCMXCP_TOPOLOGY_DUAL_AC_ONLINE_UPS_2P 0x0031 /* Dual AC Input, On-Line UPS, Two Phase */ #define BCMXCP_TOPOLOGY_DUAL_AC_ONLINE_UPS_3P 0x0032 /* Dual AC Input, On-Line UPS, Three Phase */ #define BCMXCP_TOPOLOGY_ONLINE_UPS_1P 0x0040 /* On-Line UPS, Single Phase */ #define BCMXCP_TOPOLOGY_ONLINE_UPS_2P 0x0041 /* On-Line UPS, Two Phase */ #define BCMXCP_TOPOLOGY_ONLINE_UPS_3P 0x0042 /* On-Line UPS, Three Phase */ #define BCMXCP_TOPOLOGY_PARA_REDUND_ONLINE_UPS_1P 0x0050 /* Parallel Redundant On-Line UPS, Single Phase */ #define BCMXCP_TOPOLOGY_PARA_REDUND_ONLINE_UPS_2P 0x0051 /* Parallel Redundant On-Line UPS, Two Phase */ #define BCMXCP_TOPOLOGY_PARA_REDUND_ONLINE_UPS_3P 0x0052 /* Parallel Redundant On-Line UPS, Three Phase */ #define BCMXCP_TOPOLOGY_PARA_CAPACITY_ONLINE_UPS_1P 0x0060 /* Parallel for Capacity On-Line UPS, Single Phase */ #define BCMXCP_TOPOLOGY_PARA_CAPACITY_ONLINE_UPS_2P 0x0061 /* Parallel for Capacity On-Line UPS, Two Phase */ #define BCMXCP_TOPOLOGY_PARA_CAPACITY_ONLINE_UPS_3P 0x0062 /* Parallel for Capacity On-Line UPS, Three Phase */ #define BCMXCP_TOPOLOGY_SYSTEM_BYPASS_MODULE_3P 0x0102 /* System Bypass Module, Three Phase */ #define BCMXCP_TOPOLOGY_HOT_TIE_CABINET_3P 0x0122 /* Hot-Tie Cabinet, Three Phase */ #define BCMXCP_TOPOLOGY_OUTLET_CONTROLLER_1P 0x0200 /* Outlet Controller, Single Phase */ #define BCMXCP_TOPOLOGY_DUAL_AC_STATIC_SWITCH_3P 0x0222 /* Dual AC Input Static Switch Module, 3 Phase */ typedef struct { /* Entry in BCM/XCP - UPS mapping table */ const char *command_desc; /* Description of this command */ unsigned char command_byte; /* The command byte for this command, 0 = not supported */ } BCMXCP_COMMAND_MAP_ENTRY_t; extern BCMXCP_COMMAND_MAP_ENTRY_t bcmxcp_command_map[BCMXCP_COMMAND_MAP_MAX]; typedef struct { /* Entry in BCM/XCP - UPS - NUT mapping table */ const char *nut_entity; /* The NUT variable name */ unsigned char format; /* The format of the data - float, long etc */ unsigned int meter_block_index; /* The position of this meter in the UPS meter block */ } BCMXCP_METER_MAP_ENTRY_t; extern BCMXCP_METER_MAP_ENTRY_t bcmxcp_meter_map[BCMXCP_METER_MAP_MAX]; typedef struct { /* Entry in BCM/XCP - UPS mapping table */ int alarm_block_index; /* Index of this alarm in alarm block. -1 = not existing */ const char *alarm_desc; /* Description of this alarm */ } BCMXCP_ALARM_MAP_ENTRY_t; extern BCMXCP_ALARM_MAP_ENTRY_t bcmxcp_alarm_map[BCMXCP_ALARM_MAP_MAX]; typedef struct { /* A place to store status info and other data not for NUT */ unsigned char topology_mask; /* Configuration block byte 16, masks valid status bits */ unsigned int lowbatt; /* Seconds of runtime left left when LB alarm is set */ unsigned int shutdowndelay; /* Shutdown delay in seconds, from ups.conf */ int alarm_on_battery; /* On Battery alarm active? */ int alarm_low_battery; /* Battery Low alarm active? */ int alarm_replace_battery; /* Battery needs replacement! */ } BCMXCP_STATUS_t; extern BCMXCP_STATUS_t bcmxcp_status; int checksum_test(const unsigned char*); unsigned char calc_checksum(const unsigned char *buf); /* from usbhid-ups.h */ typedef struct { const long xcp_value; /* XCP value */ const char *nut_value; /* NUT value */ const char *(*fun)(double xcp_value); /* optional XCP to NUT mapping */ double (*nuf)(const char *nut_value); /* optional NUT to HID mapping */ } info_lkp_t; /* use explicit booleans */ #ifndef FALSE typedef enum ebool { FALSE, TRUE } bool_t; #else typedef int bool_t; #endif #endif /* NUT_BCMXCP_H_SEEN */ nut-2.8.1/drivers/bestuferrups.c0000644000175000017500000003351414502253356013637 00000000000000/* bestuferrups.c - model specific routines for Best Power Micro-Ferrups This module is a 40% rewritten mangle of the bestfort module by Grant, which is a 75% rewritten mangle of the bestups module by Russell. It has no test battery command since my ME3100 does this by itself. (same as Grant's driver in this respect) Support for model RE added by Tim Thompson (7/22/04) Copyright (C) 2002 Andreas Wrede Copyright (C) 2000 John Stone Copyright (C) 2000 Grant Taylor Copyright (C) 1999 Russell Kroll 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 2 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, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "main.h" #include "serial.h" #define DRIVER_NAME "Best Ferrups Series ME/RE/MD driver" #define DRIVER_VERSION "0.05" /* driver description structure */ upsdrv_info_t upsdrv_info = { DRIVER_NAME, DRIVER_VERSION, "Andreas Wrede \n" \ "John Stone \n" \ "Grant Taylor \n" \ "Russell Kroll \n" \ "Tim Thompson", DRV_BETA, /* FIXME: STABLE? */ { NULL } }; #define ENDCHAR '\r' #define IGNCHARS "\012" /* UPS Model Codes */ #define UNKNOWN 100 #define ME3100 200 #define MD1KVA 300 /* Software version P5.05 dated 05/18/89 */ #define RE1800 400 #include #include #include static int debugging = 0; /* Blob of UPS configuration data from the formatconfig string */ static struct { int valid; /* set to 1 when this is filled in */ float idealbvolts; /* various interestin battery voltages */ float fullvolts; float emptyvolts; int va; /* capacity of UPS in Volt-Amps */ int watts; /* capacity of UPS in watts */ int model; /* enumerated model type */ } fc; /* Forward decls */ /* Set up all the funky shared memory stuff used to communicate with upsd */ void upsdrv_initinfo (void) { /* now set up room for all future variables that are supported */ dstate_setinfo("ups.mfr", "%s", "Best Power"); switch(fc.model) { case ME3100: dstate_setinfo("ups.model", "Micro Ferrups (ME) %d", fc.va); break; case MD1KVA: dstate_setinfo("ups.model", "Micro Ferrups (MD) %d", fc.va); break; case RE1800: dstate_setinfo("ups.model", "Micro Ferrups (RE) %d", fc.va); break; default: fatalx(EXIT_FAILURE, "UPS model not matched!"); /* Will never get here, upsdrv_initups() will catch */ } fprintf(stderr, "Best Power %s detected\n", dstate_getinfo("ups.model")); fprintf(stderr, "Battery voltages %5.1f nominal, %5.1f full, %5.1f empty\n", fc.idealbvolts, fc.fullvolts, fc.emptyvolts); } /* Debugging display from kermit: ---------------------------------------------------- time^M^M^JFeb 20, 22:13:32^M^J^M^J=>id^M^JUnit ID "ME3.1K12345"^M^J^M^J=> ---------------------------------------------------- */ static ssize_t execute(const char *cmd, char *result, size_t resultsize) { ssize_t ret; char buf[256]; ser_send(upsfd, "%s", cmd); ser_get_line(upsfd, buf, sizeof(buf), '\012', "", 3, 0); ret = ser_get_line(upsfd, result, resultsize, '\015', "\012", 3, 0); ser_get_line(upsfd, buf, sizeof(buf), '>', "", 3, 0); return ret; } void upsdrv_updateinfo(void) { char fstring[512]; if (! fc.valid) { fprintf(stderr, "upsupdate run before ups_ident() read ups config\n"); #ifdef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_UNREACHABLE_CODE #pragma GCC diagnostic push #endif #ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_UNREACHABLE_CODE #pragma GCC diagnostic ignored "-Wunreachable-code" #endif #ifdef __clang__ #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wunreachable-code" #endif /* NOTE: This assert() always fails because of "0": * error: will never be executed [-Werror,-Wunreachable-code] * ((0) ? (void) (0) : __assert_fail ("0", "bestuferrups.c", 138, __PRETTY_FUNCTION__)); * ^ */ assert(0); #ifdef __clang__ #pragma clang diagnostic pop #endif #ifdef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_UNREACHABLE_CODE #pragma GCC diagnostic pop #endif } if (execute("f\r", fstring, sizeof(fstring)) > 0) { int inverter=0, charger=0, vin=0, vout=0, btimeleft=0, linestat=0, alstat=0, vaout=0; double ampsout=0.0, vbatt=0.0, battpercent=0.0, loadpercent=0.0, hstemp=0.0, acfreq=0.0, ambtemp=0.0; char tmp[16]; /* Inverter status: 0=off 1=on */ memcpy(tmp, fstring+16, 2); tmp[2] = '\0'; inverter = atoi(tmp); /* Charger status: 0=off 1=on */ memcpy(tmp, fstring+18, 2); tmp[2] = '\0'; charger = atoi(tmp); /* Input Voltage. integer number */ memcpy(tmp, fstring+24, 4); tmp[4] = '\0'; vin = atoi(tmp); /* Output Voltage. integer number */ memcpy(tmp, fstring+28, 4); tmp[4] = '\0'; vout = atoi(tmp); /* Iout: int times 10 */ memcpy(tmp, fstring+36, 4); tmp[4] = '\0'; ampsout = ((double)(atoi(tmp)) / 10.0); /* Battery voltage: int times 10 */ memcpy(tmp, fstring+50, 4); tmp[4] = '\0'; vbatt = ((double)(atoi(tmp)) / 10.0); /* Volt-amps out: int */ memcpy(tmp, fstring+40, 6); tmp[6] = '\0'; vaout = atoi(tmp); /* Line status. Bitmask */ memcpy(tmp, fstring+72, 2); tmp[2] = '\0'; linestat = atoi(tmp); /* Alarm status reg 1. Bitmask */ memcpy(tmp, fstring+20, 2); tmp[2] = '\0'; alstat = atoi(tmp); /* Alarm status reg 2. Bitmask */ memcpy(tmp, fstring+22, 2); tmp[2] = '\0'; alstat = alstat | (atoi(tmp) << 8); /* AC line frequency */ memcpy(tmp, fstring+54, 4); tmp[4]= '\0'; acfreq = ((double)(atoi(tmp)) / 100.0); /* Runtime remaining */ memcpy(tmp, fstring+58, 4); tmp[4]= '\0'; btimeleft = atoi(tmp); /* UPS Temperature */ memcpy(tmp, fstring+62, 4); tmp[4]= '\0'; ambtemp = (double)(atoi(tmp)); /* Percent Load */ switch(fc.model) { case ME3100: if (execute("d 16\r", fstring, sizeof(fstring)) > 0) { int l; sscanf(fstring, "16 FullLoad%% %d", &l); loadpercent = (double) l; } break; case RE1800: if (execute("d 16\r", fstring, sizeof(fstring)) > 0) { int l; sscanf(fstring, "16 FullLoad%% %d", &l); loadpercent = (double) l; } if (execute("d 12\r", fstring, sizeof(fstring)) > 0) { int l; sscanf(fstring, "12 HS Temp %dC", &l); hstemp = (double) l; } break; case MD1KVA: if (execute("d 22\r", fstring, sizeof(fstring)) > 0) { int l; sscanf(fstring, "22 FullLoad%% %d", &l); loadpercent = (double) l; } break; default: /* Will never happen, caught in upsdrv_initups() */ fatalx(EXIT_FAILURE, "Unknown model in upsdrv_updateinfo()"); } /* Compute battery percent left based on battery voltages. */ battpercent = ((vbatt - fc.emptyvolts) / (fc.fullvolts - fc.emptyvolts) * 100.0); if (battpercent < 0.0) battpercent = 0.0; else if (battpercent > 100.0) battpercent = 100.0; /* Compute status string */ { int lowbatt, overload, replacebatt, boosting, trimming; lowbatt = alstat & (1<<1); overload = alstat & (1<<6); replacebatt = alstat & (1<<10); boosting = inverter && (linestat & (1<<2)) && (vin < 115); trimming = inverter && (linestat & (1<<2)) && (vin > 115); status_init(); if (inverter) status_set("OB"); else status_set("OL"); if (lowbatt) status_set("LB"); if (trimming) status_set("TRIM"); if (boosting) status_set("BOOST"); if (replacebatt) status_set("RB"); if (overload) status_set("OVER"); status_commit(); } /* FIXME: change to upsdebugx() and friends */ if (debugging) { fprintf(stderr, "Poll: inverter %d charger %d vin %d vout %d vaout %d btimeleft %d\n", inverter, charger, vin, vout, vaout, btimeleft); fprintf(stderr, " ampsout %5.1f vbatt %5.1f batpcnt %5.1f loadpcnt %5.1f upstemp %5.1f acfreq %5.2f ambtemp %5.1f\n", ampsout, vbatt, battpercent, loadpercent, hstemp, acfreq, ambtemp); } /* Stuff information into info structures */ dstate_setinfo("input.voltage", "%05.1f", (double)vin); dstate_setinfo("output.voltage", "%05.1f", (double)vout); dstate_setinfo("battery.charge", "%02.1f", battpercent); dstate_setinfo("ups.load", "%02.1f", loadpercent); dstate_setinfo("battery.voltage", "%02.1f", vbatt); dstate_setinfo("input.frequency", "%05.2f", (double)acfreq); dstate_setinfo("ups.temperature", "%05.1f", (double)hstemp); dstate_setinfo("battery.runtime", "%d", btimeleft); dstate_setinfo("ambient.temperature", "%05.1f", (double)ambtemp); dstate_dataok(); /* Tim: With out this return, it always falls over to the datastate() at the end of the function */ return; } else { dstate_datastale(); } /* if (execute("f\r", fstring, sizeof(fstring)) > 0) */ dstate_datastale(); return; } static void ups_sync(void) { char buf[256]; printf ("Syncing: "); fflush (stdout); /* A bit better sanity might be good here. As is, we expect the human to observe the time being totally not a time. */ if (execute("time\r", buf, sizeof(buf)) > 0) { fprintf(stderr, "UPS Time: %s\n", buf); } else { fatalx(EXIT_FAILURE, "Error connecting to UPS"); } } /* power down the attached load immediately */ void upsdrv_shutdown(void) { /* NB: hard-wired password */ ser_send(upsfd, "pw377\r"); ser_send(upsfd, "off 1 a\r"); /* power off in 1 second and restart when line power returns */ } /* list flags and values that you want to receive via -x */ void upsdrv_makevartable(void) { } void upsdrv_help(void) { } static void sync_serial(void) { char buffer[10]; ser_send(upsfd, "\r"); ser_get_line(upsfd, buffer, sizeof(buffer), '\r', "\012", 3, 0); ser_get_line(upsfd, buffer, sizeof(buffer), ENDCHAR, IGNCHARS, 3, 0); while (ser_get_line(upsfd, buffer, sizeof(buffer), '>', "\012", 3, 0) <= 0) { ser_send(upsfd, "\r"); } } /* Begin code stolen from bestups.c */ static void setup_serial(void) { struct termios tio; if (tcgetattr(upsfd, &tio) == -1) fatal_with_errno(EXIT_FAILURE, "tcgetattr"); tio.c_iflag = IXON | IXOFF; tio.c_oflag = 0; tio.c_cflag = (CS8 | CREAD | HUPCL | CLOCAL); tio.c_lflag = 0; tio.c_cc[VMIN] = 1; tio.c_cc[VTIME] = 0; #ifdef HAVE_CFSETISPEED cfsetispeed(&tio, B1200); /* baud change here */ cfsetospeed(&tio, B1200); #else #error This system lacks cfsetispeed() and has no other means to set the speed #endif if (tcsetattr(upsfd, TCSANOW, &tio) == -1) fatal_with_errno(EXIT_FAILURE, "tcsetattr"); /* end code stolen from bestups.c */ sync_serial(); } void upsdrv_initups (void) { char temp[256], fcstring[512]; upsfd = ser_open(device_path); ser_set_speed(upsfd, device_path, B1200); setup_serial(); ups_sync(); fc.model = UNKNOWN; /* Obtain Model */ if (execute("id\r", fcstring, sizeof(fcstring)) < 1) { fatalx(EXIT_FAILURE, "Failed execute in ups_ident()"); } /* response is a one-line packed string starting with $ */ if (memcmp(fcstring, "Unit", 4)) { fatalx(EXIT_FAILURE, "Bad response from formatconfig command in ups_ident()\n" "id: %s\n", fcstring ); } /* FIXME: upsdebugx() */ if (debugging) fprintf(stderr, "id: %s\n", fcstring); /* chars 4:2 are a two-digit ascii hex enumerated model code */ memcpy(temp, fcstring+9, 2); temp[2] = '\0'; if (memcmp(temp, "ME", 2) == 0) { fc.model = ME3100; } else if ((memcmp(temp, "RE", 2) == 0)) { fc.model = RE1800; } else if (memcmp(temp, "C1", 2) == 0) { /* Better way to identify unit is using "d 15\r", which results in "15 M# MD1KVA", "id\r" yields "Unit ID "C1K03588"" */ fc.model = MD1KVA; } switch(fc.model) { case ME3100: fc.va = 3100; fc.watts = 2200; /* determine shutdown battery voltage */ if (execute("d 29\r", fcstring, sizeof(fcstring)) > 0) { sscanf(fcstring, "29 LowBat %f", &fc.emptyvolts); } /* determine fully charged battery voltage */ if (execute("d 31\r", fcstring, sizeof(fcstring)) > 0) { sscanf(fcstring, "31 HiBatt %f", &fc.fullvolts); } fc.fullvolts = 54.20; /* determine "ideal" voltage by a guess */ fc.idealbvolts = ((fc.fullvolts - fc.emptyvolts) * 0.7) + fc.emptyvolts; break; case RE1800: fc.va = 1800; fc.watts = 1200; /* determine shutdown battery voltage */ if (execute("d 29\r", fcstring, sizeof(fcstring)) > 0) { sscanf(fcstring, "29 LowBat %f", &fc.emptyvolts); } /* determine fully charged battery voltage */ if (execute("d 31\r", fcstring, sizeof(fcstring)) > 0) { sscanf(fcstring, "31 HiBatt %f", &fc.fullvolts); } fc.fullvolts = 54.20; /* determine "ideal" voltage by a guess */ fc.idealbvolts = ((fc.fullvolts - fc.emptyvolts) * 0.7) + fc.emptyvolts; break; case MD1KVA: fc.va = 1100; fc.watts = 770; /* Approximate, based on 0.7 power factor */ /* determine shutdown battery voltage */ if (execute("d 27\r", fcstring, sizeof(fcstring)) > 0) { sscanf(fcstring, "27 LowBatt %f", &fc.emptyvolts); } /* determine fully charged battery voltage */ if (execute("d 28\r", fcstring, sizeof(fcstring)) > 0) { sscanf(fcstring, "28 Hi Batt %f", &fc.fullvolts); } fc.fullvolts = 13.70; /* determine "ideal" voltage by a guess */ fc.idealbvolts = ((fc.fullvolts - fc.emptyvolts) * 0.7) + fc.emptyvolts; break; default: fatalx(EXIT_FAILURE, "Unknown model %s in ups_ident()", temp); } fc.valid = 1; return; } void upsdrv_cleanup(void) { ser_close(upsfd, device_path); } nut-2.8.1/drivers/nutdrv_qx_ablerex.h0000755000175000017500000000206014500336654014643 00000000000000/* nutdrv_qx_ablerex.h - Subdriver for Ablerex Qx protocol based UPSes * * Copyright (C) * 2013 Daniele Pezzini * 2021 Ablerex Software * * 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 2 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, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #ifndef NUTDRV_QX_ABLEREX_H #define NUTDRV_QX_ABLEREX_H #include "nutdrv_qx.h" extern subdriver_t ablerex_subdriver; #endif /* NUTDRV_QX_ABLEREX_H */ nut-2.8.1/drivers/nutdrv_qx_bestups.h0000644000175000017500000000176314273170601014707 00000000000000/* nutdrv_qx_bestups.h - Subdriver for Best Power/Sola Australia UPSes * * Copyright (C) * 2014 Daniele Pezzini * * 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 2 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, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #ifndef NUTDRV_QX_BESTUPS_H #define NUTDRV_QX_BESTUPS_H #include "nutdrv_qx.h" extern subdriver_t bestups_subdriver; #endif /* NUTDRV_QX_BESTUPS_H */ nut-2.8.1/drivers/ietf-mib.h0000644000175000017500000000025314273170601012575 00000000000000#ifndef IETF_MIB_H #define IETF_MIB_H #include "main.h" #include "snmp-ups.h" extern mib2nut_info_t ietf; extern mib2nut_info_t tripplite_ietf; #endif /* IETF_MIB_H */ nut-2.8.1/drivers/salicru-hid.h0000644000175000017500000000217014500336654013312 00000000000000/* salicru-hid.h - subdriver to monitor Salicru USB/HID devices with NUT * * Copyright (C) * 2003 - 2009 Arnaud Quette * 2005 - 2006 Peter Selinger * 2008 - 2009 Arjen de Korte * * 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 2 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, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef SALICRU_HID_H #define SALICRU_HID_H #include "usbhid-ups.h" extern subdriver_t salicru_subdriver; #endif /* SALICRU_HID_H */ nut-2.8.1/drivers/bestpower-mib.h0000644000175000017500000000023114273170601013654 00000000000000#ifndef BESTPOWER_MIB_H #define BESTPOWER_MIB_H #include "main.h" #include "snmp-ups.h" extern mib2nut_info_t bestpower; #endif /* BESTPOWER_MIB_H */ nut-2.8.1/drivers/cyberpower-mib.c0000644000175000017500000002371014501607135014026 00000000000000/* cyberpower-mib.c - data to monitor Cyberpower RMCARD * * Copyright (C) 2010 - Eric Schultz * * derived (i.e. basically copied and modified) of bestpower by: * Copyright (C) 2010 - Arnaud Quette * * 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 2 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, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #include "cyberpower-mib.h" #define CYBERPOWER_MIB_VERSION "0.55" #define CYBERPOWER_OID_MODEL_NAME ".1.3.6.1.4.1.3808.1.1.1.1.1.1.0" /* CPS-MIB::ups */ #define CYBERPOWER_SYSOID ".1.3.6.1.4.1.3808.1.1.1" /* Per https://github.com/networkupstools/nut/issues/1997 * some CPS devices offer the shorter vendor OID as sysOID */ #define CYBERPOWER_SYSOID2 ".1.3.6.1.4.1.3808" /* https://www.cyberpowersystems.com/products/software/mib-files/ */ /* Per CPS MIB 2.9 upsBaseOutputStatus OBJECT-TYPE: */ static info_lkp_t cyberpower_power_status[] = { { 2, "OL", NULL, NULL }, /* onLine */ { 3, "OB", NULL, NULL }, /* onBattery */ { 4, "OL BOOST", NULL, NULL }, /* onBoost */ { 5, "OFF", NULL, NULL }, /* onSleep */ { 6, "OFF", NULL, NULL }, /* off */ { 7, "OL", NULL, NULL }, /* rebooting */ { 8, "OL", NULL, NULL }, /* onECO */ { 9, "OL BYPASS", NULL, NULL }, /* onBypass */ { 10, "OL TRIM", NULL, NULL }, /* onBuck */ { 11, "OL OVER", NULL, NULL }, /* onOverload */ /* Note: a "NULL" string must be last due to snmp-ups.c parser logic */ { 1, "NULL", NULL, NULL }, /* unknown */ { 0, NULL, NULL, NULL } } ; static info_lkp_t cyberpower_battery_status[] = { { 1, "", NULL, NULL }, /* unknown */ { 2, "", NULL, NULL }, /* batteryNormal */ { 3, "LB", NULL, NULL }, /* batteryLow */ { 0, NULL, NULL, NULL } } ; static info_lkp_t cyberpower_cal_status[] = { { 1, "", NULL, NULL }, /* Calibration Successful */ { 2, "", NULL, NULL }, /* Calibration Invalid */ { 3, "CAL", NULL, NULL }, /* Calibration in progress */ { 0, NULL, NULL, NULL } }; static info_lkp_t cyberpower_battrepl_status[] = { { 1, "", NULL, NULL }, /* No battery needs replacing */ { 2, "RB", NULL, NULL }, /* Batteries need to be replaced */ { 0, NULL, NULL, NULL } }; static info_lkp_t cyberpower_ups_alarm_info[] = { { 1, "", NULL, NULL }, /* Normal */ { 2, "Temperature too high!", NULL, NULL }, /* Overheat */ { 3, "Internal UPS fault!", NULL, NULL }, /* Hardware Fault */ { 0, NULL, NULL, NULL } }; static info_lkp_t cyberpower_transfer_reasons[] = { { 1, "noTransfer", NULL, NULL }, { 2, "highLineVoltage", NULL, NULL }, { 3, "brownout", NULL, NULL }, { 4, "selfTest", NULL, NULL }, { 0, NULL, NULL, NULL } }; static info_lkp_t cyberpower_testdiag_results[] = { { 1, "Ok", NULL, NULL }, { 2, "Failed", NULL, NULL }, { 3, "InvalidTest", NULL, NULL }, { 4, "TestInProgress", NULL, NULL }, { 0, NULL, NULL, NULL } }; /* Snmp2NUT lookup table for CyberPower MIB */ static snmp_info_t cyberpower_mib[] = { /* standard MIB items */ { "device.description", ST_FLAG_STRING | ST_FLAG_RW, SU_INFOSIZE, ".1.3.6.1.2.1.1.1.0", NULL, SU_FLAG_OK, NULL }, { "device.contact", ST_FLAG_STRING | ST_FLAG_RW, SU_INFOSIZE, ".1.3.6.1.2.1.1.4.0", NULL, SU_FLAG_OK, NULL }, { "device.location", ST_FLAG_STRING | ST_FLAG_RW, SU_INFOSIZE, ".1.3.6.1.2.1.1.6.0", NULL, SU_FLAG_OK, NULL }, /* Device page */ { "device.type", ST_FLAG_STRING, SU_INFOSIZE, NULL, "ups", SU_FLAG_STATIC | SU_FLAG_ABSENT | SU_FLAG_OK, NULL }, { "ups.mfr", ST_FLAG_STRING, SU_INFOSIZE, NULL, "CYBERPOWER", SU_FLAG_STATIC | SU_FLAG_ABSENT | SU_FLAG_OK, NULL }, { "ups.model", ST_FLAG_STRING, SU_INFOSIZE, CYBERPOWER_OID_MODEL_NAME, "CyberPower", SU_FLAG_STATIC, NULL }, { "ups.id", ST_FLAG_STRING | ST_FLAG_RW, 8, ".1.3.6.1.4.1.3808.1.1.1.1.1.2.0", "", SU_FLAG_OK | SU_FLAG_STATIC, NULL }, { "ups.serial", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.3808.1.1.1.1.2.3.0", "", SU_FLAG_STATIC, NULL }, { "ups.firmware", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.3808.1.1.1.1.2.1.0", "", SU_FLAG_STATIC, NULL }, { "ups.mfr.date", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.3808.1.1.1.1.2.2.0", "", 0, NULL }, { "ups.status", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.3808.1.1.1.4.1.1.0", "", SU_FLAG_OK | SU_STATUS_PWR, &cyberpower_power_status[0] }, { "ups.status", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.3808.1.1.1.2.1.1.0", "", SU_FLAG_OK | SU_STATUS_BATT, &cyberpower_battery_status[0] }, { "ups.status", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.3808.1.1.1.7.2.7.0", "", SU_FLAG_OK | SU_STATUS_CAL, &cyberpower_cal_status[0] }, { "ups.status", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.3808.1.1.1.2.2.5.0", "", SU_FLAG_OK | SU_STATUS_RB, &cyberpower_battrepl_status[0] }, { "ups.load", 0, 1.0, ".1.3.6.1.4.1.3808.1.1.1.4.2.3.0", "", 0, NULL }, { "ups.temperature", 0, 1, ".1.3.6.1.4.1.3808.1.1.1.10.2.0", "", SU_FLAG_OK, NULL }, { "ups.alarm", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.3808.1.1.1.10.1.0", "", SU_FLAG_OK, &cyberpower_ups_alarm_info[0] }, /* Battery runtime is expressed in seconds */ { "battery.runtime", 0, 1.0, ".1.3.6.1.4.1.3808.1.1.1.2.2.4.0", "", 0, NULL }, /* The elapsed time in seconds since the * UPS has switched to battery power */ { "battery.runtime.elapsed", 0, 1.0, ".1.3.6.1.4.1.3808.1.1.1.2.1.2.0", "", 0, NULL }, /* Different generations/models reported "battery.voltage" by different OIDs: */ { "battery.voltage", 0, 0.1, ".1.3.6.1.2.1.33.1.2.5.0", "", 0, NULL }, { "battery.voltage", 0, 0.1, ".1.3.6.1.4.1.3808.1.1.1.2.2.2.0", "", 0, NULL }, { "battery.voltage.nominal", 0, 1.0, ".1.3.6.1.4.1.3808.1.1.1.2.2.8.0", "", 0, NULL }, /* Different generations/models reported "battery.current" by different OIDs: */ { "battery.current", 0, 0.1, ".1.3.6.1.4.1.3808.1.1.1.4.2.4.0", "", 0, NULL }, { "battery.current", 0, 0.1, ".1.3.6.1.4.1.3808.1.1.1.2.2.7.0", "", 0, NULL }, { "battery.charge", 0, 1.0, ".1.3.6.1.4.1.3808.1.1.1.2.2.1.0", "", 0, NULL }, { "battery.temperature", 0, 1.0, ".1.3.6.1.4.1.3808.1.1.1.2.2.3.0", "", 0, NULL }, /* upsBaseBatteryLastReplaceDate */ { "battery.date", ST_FLAG_STRING, 8, ".1.3.6.1.4.1.3808.1.1.1.2.1.3.0", "", SU_FLAG_OK | SU_FLAG_SEMI_STATIC, NULL }, { "input.voltage", 0, 0.1, ".1.3.6.1.4.1.3808.1.1.1.3.2.1.0", "", 0, NULL }, { "input.frequency", 0, 0.1, ".1.3.6.1.4.1.3808.1.1.1.3.2.4.0", "", 0, NULL }, /* upsAdvanceInputLineFailCause */ { "input.transfer.reason", ST_FLAG_STRING, 1, ".1.3.6.1.4.1.3808.1.1.1.3.2.5.0", "", SU_TYPE_INT | SU_FLAG_OK, &cyberpower_transfer_reasons[0] }, { "output.voltage", 0, 0.1, ".1.3.6.1.4.1.3808.1.1.1.4.2.1.0", "", 0, NULL }, { "output.frequency", 0, 0.1, ".1.3.6.1.4.1.3808.1.1.1.4.2.2.0", "", 0, NULL }, { "output.current", 0, 0.1, ".1.3.6.1.4.1.3808.1.1.1.4.2.4.0", "", 0, NULL }, /* Delays affecting instant commands */ /* upsAdvanceConfigReturnDelay */ { "ups.delay.start", ST_FLAG_RW, 1.0, ".1.3.6.1.4.1.3808.1.1.1.5.2.9.0", "0", SU_FLAG_OK | SU_TYPE_TIME, NULL }, /* Not provided by CPS-MIB */ { "ups.delay.reboot", 0, 1.0, NULL, "0", SU_FLAG_OK | SU_FLAG_ABSENT, NULL }, /* upsAdvanceConfigSleepDelay */ { "ups.delay.shutdown", ST_FLAG_RW, 1.0, ".1.3.6.1.4.1.3808.1.1.1.5.2.11.0", "60", SU_FLAG_OK | SU_TYPE_TIME, NULL }, /* instant commands. */ /* upsAdvanceControlUpsOff */ { "load.off", 0, 1, ".1.3.6.1.4.1.3808.1.1.1.6.2.1.0", "2", SU_TYPE_CMD | SU_FLAG_OK, NULL }, /* upsAdvanceControlTurnOnUPS */ { "load.on", 0, 1, ".1.3.6.1.4.1.3808.1.1.1.6.2.6.0", "2", SU_TYPE_CMD | SU_FLAG_OK, NULL }, /* upsAdvanceControlUpsOff */ { "shutdown.stayoff", 0, 1, ".1.3.6.1.4.1.3808.1.1.1.6.2.6.0", "3", SU_TYPE_CMD | SU_FLAG_OK, NULL }, #if 0 /* upsBaseControlConserveBattery - note that this command * is not suitable here because it puts ups to sleep only * in battery mode. If power is restored during the shutdown * process, the command is not executed by ups hardware. */ { "shutdown.return", 0, 1, ".1.3.6.1.4.1.3808.1.1.1.6.1.1.0", "2", SU_TYPE_CMD | SU_FLAG_OK, NULL }, #endif /* upsAdvanceControlUpsSleep */ { "shutdown.return", 0, 1, ".1.3.6.1.4.1.3808.1.1.1.6.2.3.0", "3", SU_TYPE_CMD | SU_FLAG_OK, NULL }, /* upsAdvanceControlSimulatePowerFail */ { "test.failure.start", 0, 1, ".1.3.6.1.4.1.3808.1.1.1.6.2.4.0", "2", SU_TYPE_CMD | SU_FLAG_OK, NULL }, /* upsAdvanceTestIndicators */ { "test.panel.start", 0, 1, ".1.3.6.1.4.1.3808.1.1.1.7.2.5.0", "2", SU_TYPE_CMD | SU_FLAG_OK, NULL }, /* upsAdvanceTestDiagnostics */ { "test.battery.start", 0, 1, ".1.3.6.1.4.1.3808.1.1.1.7.2.2.0", "2", SU_TYPE_CMD | SU_FLAG_OK, NULL }, /* upsAdvanceTestRuntimeCalibration */ { "calibrate.start", 0, 1, ".1.3.6.1.4.1.3808.1.1.1.7.2.6.0", "2", SU_TYPE_CMD | SU_FLAG_OK, NULL }, { "calibrate.stop", 0, 1, ".1.3.6.1.4.1.3808.1.1.1.7.2.6.0", "3", SU_TYPE_CMD | SU_FLAG_OK, NULL }, /* upsAdvanceTestLastDiagnosticsDate */ { "ups.test.date", ST_FLAG_STRING, 8, ".1.3.6.1.4.1.3808.1.1.1.7.2.4.0", "", SU_FLAG_OK | SU_FLAG_SEMI_STATIC, NULL }, /* upsAdvanceTestDiagnosticsResults */ { "ups.test.result", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.3808.1.1.1.7.2.3.0", "", SU_FLAG_OK, &cyberpower_testdiag_results[0] }, /* end of structure. */ { NULL, 0, 0, NULL, NULL, 0, NULL } } ; mib2nut_info_t cyberpower = { "cyberpower", CYBERPOWER_MIB_VERSION, NULL, CYBERPOWER_OID_MODEL_NAME, cyberpower_mib, CYBERPOWER_SYSOID, NULL }; mib2nut_info_t cyberpower2 = { "cyberpower", CYBERPOWER_MIB_VERSION, NULL, CYBERPOWER_OID_MODEL_NAME, cyberpower_mib, CYBERPOWER_SYSOID2, NULL }; nut-2.8.1/drivers/safenet.c0000644000175000017500000003071714501607135012532 00000000000000/* * safenet.c - model specific routines for following units: * * - Fairstone L525/-625/-750 * - Fenton P400/-600/-800 * - Gemini UPS625/-1000 * - Powerwell PM525A/-625A/-800A/-1000A/-1250A * - Repotec RPF525/-625/-800/-1000 * - Soltec Winmate 525/625/800/1000 * - Sweex 500/1000 * - others using SafeNet software and serial interface * * Status: * 20081102/Revision 1.41 - Arjen de Korte * - allow more time for reading reply to command * 20081106/Revision 1.5 - Arjen de Korte * - changed communication with UPS * - improved handling of battery & system test * 20081228/Revision 1.6 - Arjen de Korte * - add ondelay and offdelay * * Copyright (C) 2003-2008 Arjen de Korte * * 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 2 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, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "main.h" #include "serial.h" #include "safenet.h" #define DRIVER_NAME "Generic SafeNet UPS driver" #define DRIVER_VERSION "1.80" /* driver description structure */ upsdrv_info_t upsdrv_info = { DRIVER_NAME, DRIVER_VERSION, "Arjen de Korte ", DRV_STABLE, { NULL } }; /* * Here we keep the last known status of the UPS */ static union { char reply[10]; struct safenet status; } ups; static long ondelay = 1; /* minutes */ static long offdelay = 30; /* seconds */ static int safenet_command(const char *command) { char reply[32]; size_t i; ssize_t ret; /* * Get rid of whatever is in the in- and output buffers. */ ser_flush_io(upsfd); /* * Send the command and read back the status line. When we just send * a status polling command, it will return the actual status. */ ret = ser_send(upsfd, "%s", command); if (ret < 0) { upsdebug_with_errno(3, "send"); return -1; } if (ret == 0) { upsdebug_with_errno(3, "send: timeout"); return -1; } upsdebugx(3, "send: %.*s", (int)strcspn(command, "\r"), command); /* * Read the reply from the UPS. */ ret = ser_get_buf(upsfd, reply, sizeof(reply), 1, 0); if (ret < 0) { upsdebug_with_errno(3, "read"); return -1; } if (ret == 0) { upsdebugx(3, "read: timeout"); return -1; } upsdebugx(3, "read: %.*s", (int)strcspn(reply, "\r"), reply); /* * We check if the reply looks like a valid status. */ if ((ret != 12) || (reply[0] != '$') || (strspn(reply+1, "AB") != 10)) { return -1; } for (i = 0; i < 10; i++) { ups.reply[i] = ((reply[i+1] == 'B') ? 1 : 0); } return 0; } static void safenet_update(void) { status_init(); if (ups.status.onbattery) { status_set("OB"); } else { status_set("OL"); } if (ups.status.batterylow) { status_set("LB"); } if (ups.status.overload) { status_set("OVER"); } if (ups.status.batteryfail) { status_set("RB"); } if (ups.status.systemtest) { status_set("CAL"); } alarm_init(); if (ups.status.systemfail) { alarm_set("System selftest fail!"); } alarm_commit(); status_commit(); } static int instcmd(const char *cmdname, const char *extra) { if (!strcasecmp(cmdname, "beeper.off")) { /* compatibility mode for old command */ upslogx(LOG_WARNING, "The 'beeper.off' command has been renamed to 'beeper.mute' for this driver"); return instcmd("beeper.mute", NULL); } if (!strcasecmp(cmdname, "beeper.on")) { /* compatibility mode for old command */ upslogx(LOG_WARNING, "The 'beeper.on' command has been renamed to 'beeper.enable'"); return instcmd("beeper.enable", NULL); } /* * Start the UPS selftest */ if (!strcasecmp(cmdname, "test.battery.start")) { if (safenet_command(COM_BATT_TEST)) { return STAT_INSTCMD_FAILED; } else { return STAT_INSTCMD_HANDLED; } } /* * Stop the UPS selftest */ if (!strcasecmp(cmdname, "test.battery.stop")) { if (safenet_command(COM_STOP_TEST)) { return STAT_INSTCMD_FAILED; } else { return STAT_INSTCMD_HANDLED; } } /* * Start simulated mains failure */ if (!strcasecmp (cmdname, "test.failure.start")) { if (safenet_command(COM_MAINS_TEST)) { return STAT_INSTCMD_FAILED; } else { return STAT_INSTCMD_HANDLED; } } /* * Stop simulated mains failure */ if (!strcasecmp (cmdname, "test.failure.stop")) { if (safenet_command(COM_STOP_TEST)) { return STAT_INSTCMD_FAILED; } else { return STAT_INSTCMD_HANDLED; } } /* * If beeper is off, toggle beeper state (so it should be ON after this) */ if (!strcasecmp(cmdname, "beeper.enable")) { if (ups.status.silenced && safenet_command(COM_TOGGLE_BEEP)) { return STAT_INSTCMD_FAILED; } else { return STAT_INSTCMD_HANDLED; } } /* * If beeper is not off, toggle beeper state (so it should be OFF after this) * Unfortunately, this only mutes the beeper, it turns back on for the next * event automatically (no way to stop this, besides side cutters) */ if (!strcasecmp(cmdname, "beeper.mute")) { if (!ups.status.silenced && safenet_command(COM_TOGGLE_BEEP)) { return STAT_INSTCMD_FAILED; } else { return STAT_INSTCMD_HANDLED; } } /* * Toggle beeper state unconditionally */ if (!strcasecmp(cmdname, "beeper.toggle")) { if (safenet_command(COM_TOGGLE_BEEP)) { return STAT_INSTCMD_FAILED; } else { return STAT_INSTCMD_HANDLED; } } /* * Shutdown and wait for the power to return */ if (!strcasecmp(cmdname, "shutdown.return")) { char command[] = SHUTDOWN_RETURN; command[4] += ((offdelay % 1000) / 100); command[5] += ((offdelay % 100) / 10); command[6] += (offdelay % 10); safenet_command(command); return STAT_INSTCMD_HANDLED; } /* * Shutdown and reboot */ if (!strcasecmp(cmdname, "shutdown.reboot")) { char command[] = SHUTDOWN_REBOOT; command[3] += ((offdelay % 1000) / 100); command[4] += ((offdelay % 100) / 10); command[5] += (offdelay % 10); command[7] += ((ondelay % 10000) / 1000); command[8] += ((ondelay % 1000) / 100); command[9] += ((ondelay % 100) / 10); command[10] += (ondelay % 10); safenet_command(command); return STAT_INSTCMD_HANDLED; } upslogx(LOG_NOTICE, "instcmd: unknown command [%s] [%s]", cmdname, extra); return STAT_INSTCMD_UNKNOWN; } void upsdrv_initinfo(void) { int retry = 3; char *v; usleep(100000); /* * Very crude hardware detection. If an UPS is attached, it will set DSR * to 1. Bail out if it isn't. */ if (!ser_get_dsr(upsfd)) { fatalx(EXIT_FAILURE, "Serial cable problem or nothing attached to %s", device_path); } /* * Initialize the serial interface of the UPS by sending the magic * string. If it does not respond with a valid status reply, * display an error message and give up. */ while (safenet_command(COM_INITIALIZE)) { if (--retry) { continue; } fatalx(EXIT_FAILURE, "SafeNet protocol compatible UPS not found on %s", device_path); } /* * Read the commandline settings for the following parameters, since we can't * autodetect them. */ dstate_setinfo("ups.mfr", "%s", ((v = getval("manufacturer")) != NULL) ? v : "unknown"); dstate_setinfo("ups.model", "%s", ((v = getval("modelname")) != NULL) ? v : "unknown"); dstate_setinfo("ups.serial", "%s", ((v = getval("serialnumber")) != NULL) ? v : "unknown"); dstate_setinfo("ups.delay.start", "%ld", 60 * ondelay); dstate_setinfo("ups.delay.shutdown", "%ld", offdelay); /* * These are the instant commands we support. */ dstate_addcmd ("test.battery.start"); dstate_addcmd ("test.battery.stop"); dstate_addcmd ("test.failure.start"); dstate_addcmd ("test.failure.stop"); dstate_addcmd ("beeper.on"); dstate_addcmd ("beeper.off"); dstate_addcmd ("beeper.enable"); dstate_addcmd ("beeper.mute"); dstate_addcmd ("beeper.toggle"); dstate_addcmd ("shutdown.return"); dstate_addcmd ("shutdown.reboot"); upsh.instcmd = instcmd; } /* * The status polling commands are *almost* random. Whatever the reason * is, there is a certain pattern in them. The first character after the * start character 'Z' determines how many positions there are between * that character and the single 'L' character that's in each command (A=0, * B=1,...,J=9). The rest is filled with random (?) data [A...J]. But why? * No idea. The UPS *does* check if the polling commands match this format. * And as the SafeNet software uses "random" polling commands, so do we. * * Note: if you don't use ASCII, the characters will be different! */ void upsdrv_updateinfo(void) { char command[] = COM_POLL_STAT; int i; static int retry = 0; /* * Fill the command portion with random characters from the range * [A...J]. */ for (i = 1; i < 12; i++) { command[i] = (random() % 10) + 'A'; } /* * Find which character must be an 'L' and put it there. */ command[command[1]-'A'+2] = 'L'; /* * Do a status poll. */ if (safenet_command(command)) { ser_comm_fail("Status read failed"); if (retry < 2) { retry++; } else { dstate_datastale(); } return; } ser_comm_good(); retry = 0; if (ups.status.systemtest && ups.status.batterylow) { /* * Don't update status after stopping battery test, to * allow UPS to update the status flags (OB+LB glitch) */ if (safenet_command(COM_STOP_TEST)) { upslogx(LOG_WARNING, "Can't terminate battery test!"); } else { upslogx(LOG_INFO, "Battery test finished"); return; } } safenet_update(); dstate_dataok(); } void upsdrv_shutdown(void) { int retry = 3; /* * Since we may have arrived here before the hardware is initialized, * try to initialize it here. * * Initialize the serial interface of the UPS by sending the magic * string. If it does not respond with a valid status reply, * display an error message and give up. */ while (safenet_command(COM_INITIALIZE)) { if (--retry) { continue; } upslogx(LOG_ERR, "SafeNet protocol compatible UPS not found on %s", device_path); set_exit_flag(-1); return; } /* * Since the UPS will happily restart on battery, we must use a * different shutdown command depending on the line status, so * we need to check the status of the UPS here. */ if (ups.status.onbattery) { instcmd("shutdown.return", NULL); } else { instcmd("shutdown.reboot", NULL); } } void upsdrv_help(void) { } void upsdrv_makevartable(void) { addvar(VAR_VALUE, "manufacturer", "manufacturer [unknown]"); addvar(VAR_VALUE, "modelname", "modelname [unknown]"); addvar(VAR_VALUE, "serialnumber", "serialnumber [unknown]"); addvar(VAR_VALUE, "ondelay", "Delay before UPS startup (minutes)"); addvar(VAR_VALUE, "offdelay", "Delay before UPS shutdown (seconds)"); } void upsdrv_initups(void) { struct termios tio; const char *val; /* * Open and lock the serial port and set the speed to 1200 baud. */ upsfd = ser_open(device_path); ser_set_speed(upsfd, device_path, B1200); if (tcgetattr(upsfd, &tio)) { fatal_with_errno(EXIT_FAILURE, "tcgetattr"); } /* * Use canonical mode input processing (to read reply line) */ tio.c_lflag |= ICANON; /* Canonical input (erase and kill processing) */ tio.c_cc[VEOF] = _POSIX_VDISABLE; tio.c_cc[VEOL] = '\r'; tio.c_cc[VERASE] = _POSIX_VDISABLE; tio.c_cc[VINTR] = _POSIX_VDISABLE; tio.c_cc[VKILL] = _POSIX_VDISABLE; tio.c_cc[VQUIT] = _POSIX_VDISABLE; tio.c_cc[VSUSP] = _POSIX_VDISABLE; tio.c_cc[VSTART] = _POSIX_VDISABLE; tio.c_cc[VSTOP] = _POSIX_VDISABLE; if (tcsetattr(upsfd, TCSANOW, &tio)) { fatal_with_errno(EXIT_FAILURE, "tcsetattr"); } /* * Set DTR and clear RTS to provide power for the serial interface. */ ser_set_dtr(upsfd, 1); ser_set_rts(upsfd, 0); val = getval("ondelay"); if (val) { ondelay = strtol(val, NULL, 10); } if ((ondelay < 0) || (ondelay > 9999)) { fatalx(EXIT_FAILURE, "Start delay '%ld' out of range [0..9999]", ondelay); } val = getval("offdelay"); if (val) { offdelay = strtol(val, NULL, 10); } if ((offdelay < 0) || (offdelay > 999)) { fatalx(EXIT_FAILURE, "Shutdown delay '%ld' out of range [0..999]", offdelay); } } void upsdrv_cleanup(void) { ser_set_dtr(upsfd, 0); ser_close(upsfd, device_path); } nut-2.8.1/drivers/generic_modbus.h0000644000175000017500000000526014500336654014076 00000000000000/* generic_modbus.h - Driver for generic UPS connected via modbus RIO * * Copyright (C) * 2021 Dimitris Economou * * 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 2 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, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #ifndef NUT_GENERIC_MODBUS_H #define NUT_GENERIC_MODBUS_H /* UPS device details */ #define DEVICE_MFR "UNKNOWN" #define DEVICE_MODEL "unknown" /* serial access parameters */ #define BAUD_RATE 9600 #define PARITY 'N' #define DATA_BIT 8 #define STOP_BIT 1 /* * modbus response and byte timeouts * us: 1 - 999999 */ #define MODRESP_TIMEOUT_s 0 #define MODRESP_TIMEOUT_us 200000 #define MODBYTE_TIMEOUT_s 0 #define MODBYTE_TIMEOUT_us 50000 /* modbus access parameters */ #define MODBUS_SLAVE_ID 5 /* shutdown repeat on error */ #define FSD_REPEAT_CNT 3 /* shutdown repeat interval in ms */ #define FSD_REPEAT_INTRV 1500 /* definition of register type */ enum regtype { COIL = 0, INPUT_B, INPUT_R, HOLDING }; typedef enum regtype regtype_t; /* UPS device state enum */ enum devstate { OL_T = 0, OB_T, LB_T, HB_T, RB_T, CHRG_T, DISCHRG_T, BYPASS_T, CAL_T, OFF_T, OVER_T, TRIM_T, BOOST_T, FSD_T }; typedef enum devstate devstate_t; /* UPS state signal attributes */ struct sigattr { int addr; /* register address */ regtype_t type; /* register type */ int noro; /* 1: normally open contact 0: normally closed contact. */ /* noro is used to indicate the logical ON or OFF in regard of the contact state. if noro is set to 1 then ON corresponds to an open contact */ }; typedef struct sigattr sigattr_t; #define NUMOF_SIG_STATES 14 #define NOTUSED -1 /* define the duration of the shutdown pulse */ #define SHTDOWN_PULSE_DURATION NOTUSED /* * associate PULS signals to NUT device states * * Ready contact <--> 1:HB, 0:CHRG * Buffering contact <--> 1:OB, 0:OL * Battery-low <--> 1:LB * Replace Battery <--> 1:RB * Inhibit buffering <--> 1:FSD */ #endif /* NUT_GENERIC_MODBUS_H */ nut-2.8.1/drivers/nutdrv_qx_megatec-old.c0000644000175000017500000001501414501607135015371 00000000000000/* nutdrv_qx_megatec-old.c - Subdriver for Megatec/old protocol based UPSes * * Copyright (C) * 2013 Daniele Pezzini * * 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 2 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, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #include "main.h" #include "nutdrv_qx.h" #include "nutdrv_qx_blazer-common.h" #include "nutdrv_qx_megatec-old.h" #define MEGATEC_OLD_VERSION "Megatec/old 0.08" /* qx2nut lookup table */ static item_t megatec_old_qx2nut[] = { /* * > [D\r] * < [(226.0 195.0 226.0 014 49.0 27.5 30.0 00001000\r] * 01234567890123456789012345678901234567890123456 * 0 1 2 3 4 */ { "input.voltage", 0, NULL, "D\r", "", 47, '(', "", 1, 5, "%.1f", 0, NULL, NULL, NULL }, { "input.voltage.fault", 0, NULL, "D\r", "", 47, '(', "", 7, 11, "%.1f", 0, NULL, NULL, NULL }, { "output.voltage", 0, NULL, "D\r", "", 47, '(', "", 13, 17, "%.1f", 0, NULL, NULL, NULL }, { "ups.load", 0, NULL, "D\r", "", 47, '(', "", 19, 21, "%.0f", 0, NULL, NULL, NULL }, { "input.frequency", 0, NULL, "D\r", "", 47, '(', "", 23, 26, "%.1f", 0, NULL, NULL, NULL }, { "battery.voltage", 0, NULL, "D\r", "", 47, '(', "", 28, 31, "%.2f", 0, NULL, NULL, qx_multiply_battvolt }, { "ups.temperature", 0, NULL, "D\r", "", 47, '(', "", 33, 36, "%.1f", 0, NULL, NULL, NULL }, /* Status bits */ { "ups.status", 0, NULL, "D\r", "", 47, '(', "", 38, 38, NULL, QX_FLAG_QUICK_POLL, NULL, NULL, blazer_process_status_bits }, /* Utility Fail (Immediate) */ { "ups.status", 0, NULL, "D\r", "", 47, '(', "", 39, 39, NULL, QX_FLAG_QUICK_POLL, NULL, NULL, blazer_process_status_bits }, /* Battery Low */ { "ups.status", 0, NULL, "D\r", "", 47, '(', "", 40, 40, NULL, QX_FLAG_QUICK_POLL, NULL, NULL, blazer_process_status_bits }, /* Bypass/Boost or Buck Active */ { "ups.alarm", 0, NULL, "D\r", "", 47, '(', "", 41, 41, NULL, 0, NULL, NULL, blazer_process_status_bits }, /* UPS Failed */ { "ups.type", 0, NULL, "D\r", "", 47, '(', "", 42, 42, "%s", QX_FLAG_STATIC, NULL, NULL, blazer_process_status_bits }, /* UPS Type */ { "ups.status", 0, NULL, "D\r", "", 47, '(', "", 43, 43, NULL, QX_FLAG_QUICK_POLL, NULL, NULL, blazer_process_status_bits }, /* Test in Progress */ { "ups.status", 0, NULL, "D\r", "", 47, '(', "", 44, 44, NULL, QX_FLAG_QUICK_POLL, NULL, NULL, blazer_process_status_bits }, /* Shutdown Active */ { "ups.beeper.status", 0, NULL, "D\r", "", 47, '(', "", 45, 45, "%s", 0, NULL, NULL, blazer_process_status_bits }, /* Beeper status */ /* * > [F\r] * < [#220.0 000 024.0 50.0\r] * 0123456789012345678901 * 0 1 2 */ { "input.voltage.nominal", 0, NULL, "F\r", "", 22, '#', "", 1, 5, "%.0f", QX_FLAG_STATIC, NULL, NULL, NULL }, { "input.current.nominal", 0, NULL, "F\r", "", 22, '#', "", 7, 9, "%.1f", QX_FLAG_STATIC, NULL, NULL, NULL }, { "battery.voltage.nominal", 0, NULL, "F\r", "", 22, '#', "", 11, 15, "%.1f", QX_FLAG_STATIC, NULL, NULL, NULL }, { "input.frequency.nominal", 0, NULL, "F\r", "", 22, '#', "", 17, 20, "%.0f", QX_FLAG_STATIC, NULL, NULL, NULL }, /* * > [I\r] * < [#------------- ------ VT12046Q \r] * 012345678901234567890123456789012345678 * 0 1 2 3 */ { "device.mfr", 0, NULL, "I\r", "", 39, '#', "", 1, 15, "%s", QX_FLAG_STATIC | QX_FLAG_TRIM, NULL, NULL, NULL }, { "device.model", 0, NULL, "I\r", "", 39, '#', "", 17, 26, "%s", QX_FLAG_STATIC | QX_FLAG_TRIM, NULL, NULL, NULL }, { "ups.firmware", 0, NULL, "I\r", "", 39, '#', "", 28, 37, "%s", QX_FLAG_STATIC | QX_FLAG_TRIM, NULL, NULL, NULL }, /* Instant commands */ { "beeper.toggle", 0, NULL, "Q\r", "", 0, 0, "", 0, 0, NULL, QX_FLAG_CMD, NULL, NULL, NULL }, { "load.off", 0, NULL, "S00R0000\r", "", 0, 0, "", 0, 0, NULL, QX_FLAG_CMD, NULL, NULL, NULL }, { "load.on", 0, NULL, "C\r", "", 0, 0, "", 0, 0, NULL, QX_FLAG_CMD, NULL, NULL, NULL }, { "shutdown.return", 0, NULL, "S%s\r", "", 0, 0, "", 0, 0, NULL, QX_FLAG_CMD, NULL, NULL, blazer_process_command }, { "shutdown.stayoff", 0, NULL, "S%sR0000\r", "", 0, 0, "", 0, 0, NULL, QX_FLAG_CMD, NULL, NULL, blazer_process_command }, { "shutdown.stop", 0, NULL, "C\r", "", 0, 0, "", 0, 0, NULL, QX_FLAG_CMD, NULL, NULL, NULL }, { "test.battery.start", 0, NULL, "T%02d\r", "", 0, 0, "", 0, 0, NULL, QX_FLAG_CMD, NULL, NULL, blazer_process_command }, { "test.battery.start.deep", 0, NULL, "TL\r", "", 0, 0, "", 0, 0, NULL, QX_FLAG_CMD, NULL, NULL, NULL }, { "test.battery.start.quick", 0, NULL, "T\r", "", 0, 0, "", 0, 0, NULL, QX_FLAG_CMD, NULL, NULL, NULL }, { "test.battery.stop", 0, NULL, "CT\r", "", 0, 0, "", 0, 0, NULL, QX_FLAG_CMD, NULL, NULL, NULL }, /* Server-side settable vars */ { "ups.delay.start", ST_FLAG_RW, blazer_r_ondelay, NULL, "", 0, 0, "", 0, 0, DEFAULT_ONDELAY, QX_FLAG_ABSENT | QX_FLAG_SETVAR | QX_FLAG_RANGE, NULL, NULL, blazer_process_setvar }, { "ups.delay.shutdown", ST_FLAG_RW, blazer_r_offdelay, NULL, "", 0, 0, "", 0, 0, DEFAULT_OFFDELAY, QX_FLAG_ABSENT | QX_FLAG_SETVAR | QX_FLAG_RANGE, NULL, NULL, blazer_process_setvar }, /* End of structure. */ { NULL, 0, NULL, NULL, "", 0, 0, "", 0, 0, NULL, 0, NULL, NULL, NULL } }; /* Testing table */ #ifdef TESTING static testing_t megatec_old_testing[] = { { "D\r", "(215.0 195.0 230.0 014 49.0 22.7 30.0 00000000\r", -1 }, { "F\r", "#230.0 000 024.0 50.0\r", -1 }, { "I\r", "#NOT_A_LIVE_UPS TESTING TESTING \r", -1 }, { "Q\r", "", -1 }, { "S03\r", "", -1 }, { "C\r", "", -1 }, { "S02R0005\r", "", -1 }, { "S.5R0000\r", "", -1 }, { "T04\r", "", -1 }, { "TL\r", "", -1 }, { "T\r", "", -1 }, { "CT\r", "", -1 }, { NULL } }; #endif /* TESTING */ /* Subdriver-specific initups */ static void megatec_old_initups(void) { blazer_initups(megatec_old_qx2nut); } /* Subdriver interface */ subdriver_t megatec_old_subdriver = { MEGATEC_OLD_VERSION, blazer_claim_light, megatec_old_qx2nut, megatec_old_initups, NULL, blazer_makevartable, "ACK", NULL, #ifdef TESTING megatec_old_testing, #endif /* TESTING */ }; nut-2.8.1/drivers/upsdrvctl.c0000644000175000017500000011651514517664247013152 00000000000000/* upsdrvctl.c - UPS driver controller Copyright (C) 2001 Russell Kroll 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 2 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, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "config.h" /* must be the first header */ #include #include #include #include #include #ifndef WIN32 #include #else #include "wincompat.h" #endif #include "proto.h" #include "common.h" #include "upsconf.h" #include "attribute.h" #include "nut_stdint.h" #include "main.h" #include "upsdrvquery.h" typedef struct { char *upsname; char *driver; char *port; int sdorder; int maxstartdelay; int exceeded_timeout; #ifndef WIN32 pid_t pid; #else int pid; /* for WIN32 used just as a flag that this UPS was started by this tool in this run */ #endif void *next; } ups_t; static ups_t *upstable = NULL; static int upscount = 0; static int maxsdorder = 0, testmode = 0, exec_error = 0, exec_timeout = 0; /* Should we wait for driver (1) or "parallelize" drivers start (0) */ static int waitfordrivers = 1; /* timer - keeps us from getting stuck if a driver hangs */ static int maxstartdelay = 45; /* counter - retry that many time(s) to start the driver if it fails to */ static int maxretry = 1; /* timer - delay between each restart attempt of the driver(s) */ static int retrydelay = 5; /* Directory where driver executables live */ static char *driverpath = NULL; /* passthrough to the drivers: chroot path and new user name; signal/command */ static char *pt_root = NULL, *pt_user = NULL, *pt_cmd = NULL; /* flag to pass nut_debug_level to launched drivers (as their -D... args) */ static int nut_debug_level_passthrough = 0; static int nut_foreground_passthrough = -1; /* Keep track of requested operation (function pointer) */ static void (*command)(const ups_t *) = NULL; /* signal handling */ int exit_flag = 0; #ifndef WIN32 static int reload_flag = 0; static time_t last_dangerous_reload = 0; #endif #ifndef WIN32 static int signal_flag = 0; #else static char *signal_flag = NULL; #endif void do_upsconf_args(char *arg_upsname, char *var, char *val) { ups_t *tmp, *last; /* handle global declarations */ if (!arg_upsname) { if (!strcmp(var, "maxstartdelay")) maxstartdelay = atoi(val); if (!strcmp(var, "driverpath")) { free(driverpath); driverpath = xstrdup(val); } if (!strcmp(var, "maxretry")) maxretry = atoi(val); if (!strcmp(var, "retrydelay")) retrydelay = atoi(val); if (!strcmp(var, "nowait")) { char * s = getenv("NUT_IGNORE_NOWAIT"); if (s && !strcmp(s, "true")) { upsdebugx(0, "NOTE: 'nowait' setting ignored due to NUT_IGNORE_NOWAIT envvar"); } else { waitfordrivers = 0; } } /* ignore anything else - it's probably for main */ return; } last = tmp = upstable; while (tmp) { last = tmp; if (!strcmp(tmp->upsname, arg_upsname)) { if (!strcmp(var, "driver")) tmp->driver = xstrdup(val); if (!strcmp(var, "port")) tmp->port = xstrdup(val); if (!strcmp(var, "maxstartdelay")) tmp->maxstartdelay = atoi(val); if (!strcmp(var, "sdorder")) { tmp->sdorder = atoi(val); if (tmp->sdorder > maxsdorder) maxsdorder = tmp->sdorder; } return; } tmp = tmp->next; } tmp = xmalloc(sizeof(ups_t)); tmp->upsname = xstrdup(arg_upsname); tmp->driver = NULL; tmp->port = NULL; tmp->pid = -1; tmp->next = NULL; tmp->sdorder = 0; tmp->maxstartdelay = -1; /* use global value by default */ tmp->exceeded_timeout = 0; if (!strcmp(var, "driver")) tmp->driver = xstrdup(val); if (!strcmp(var, "port")) tmp->port = xstrdup(val); if (last) last->next = tmp; else upstable = tmp; } static void signal_driver_cmd(const ups_t *ups, #ifndef WIN32 int cmd #else const char *cmd #endif ) { #ifndef WIN32 char pidfn[SMALLBUF]; #endif int ret; #ifndef WIN32 if (cmd == SIGCMD_RELOAD_OR_ERROR) #else if (cmd && !strcmp(cmd, SIGCMD_RELOAD_OR_ERROR)) #endif { /* not a signal, use socket protocol */ char buf[LARGEBUF]; struct timeval tv; upsdebugx(1, "Signalling UPS [%s]: %s", ups->upsname, "driver.reload-or-error"); if (testmode) return; /* Post the query and wait for reply */ /* FIXME: coordinate with pollfreq? */ tv.tv_sec = 15; tv.tv_usec = 0; ret = upsdrvquery_oneshot(ups->driver, ups->upsname, "INSTCMD driver.reload-or-error\n", buf, sizeof(buf), &tv); if (ret < 0) { goto socket_error; } else { upslogx(LOG_INFO, "Request to reload-or-error returned code %d", ret); if (ret != STAT_INSTCMD_HANDLED) exec_error++; /* TODO: Propagate "ret" to caller, eventually CLI exit-code? */ } return; socket_error: upslog_with_errno(LOG_ERR, "Socket dialog with the other driver instance"); exec_error++; return; } #ifndef WIN32 /* TODO: implement WIN32 */ /* handle generally signalling the UPS */ /* Real signals */ #ifndef WIN32 upsdebugx(1, "Signalling UPS [%s]: %d (%s)", ups->upsname, cmd, strsignal(cmd)); #else upsdebugx(1, "Signalling UPS [%s]: %s", ups->upsname, cmd); #endif #ifndef WIN32 if (ups->pid == -1) { struct stat fs; snprintf(pidfn, sizeof(pidfn), "%s/%s-%s.pid", altpidpath(), ups->driver, ups->upsname); ret = stat(pidfn, &fs); if ((ret != 0) && (ups->port != NULL)) { upslog_with_errno(LOG_ERR, "Can't open %s", pidfn); snprintf(pidfn, sizeof(pidfn), "%s/%s-%s.pid", altpidpath(), ups->driver, xbasename(ups->port)); ret = stat(pidfn, &fs); } if (ret != 0) { upslog_with_errno(LOG_ERR, "Can't open %s either", pidfn); exec_error++; return; } } else { /* We started the driver in this run of upsdrvctl * tool, stayed foregrounded, and now are singnalling * the driver(s) tracked by this process. * NOTE: Not a filename here, but using same variable * name makes the code below simpler to maintain. */ snprintf(pidfn, sizeof(pidfn), "PID %" PRIdMAX, (intmax_t)ups->pid); } #else snprintf(pidfn, sizeof(pidfn), "%s-%s", ups->driver, ups->upsname); #endif upsdebugx(2, "Sending signal to %s", pidfn); if (testmode) return; #ifndef WIN32 if (ups->pid == -1) { ret = sendsignalfn(pidfn, cmd); } else { ret = sendsignalpid(ups->pid, cmd); /* reap zombie if this child died */ if (waitpid(ups->pid, NULL, WNOHANG) == ups->pid) { upslog_with_errno(LOG_WARNING, "Child process %s exited; signal return code is %d", pidfn, ret); } } #else ret = sendsignal(pidfn, cmd); #endif if (ret < 0) { upslog_with_errno(LOG_ERR, "Signalling %s failed: %d", pidfn, ret); exec_error++; } #endif /* WIN32 */ } /* handle generally signalling the UPS with recently raised signal */ static void signal_driver(const ups_t *ups) { signal_driver_cmd(ups, signal_flag); } /* handle sending the signal */ static void stop_driver(const ups_t *ups) { char pidfn[SMALLBUF]; int ret, i; upsdebugx(1, "Stopping UPS: %s", ups->upsname); #ifndef WIN32 if (ups->pid == -1) { struct stat fs; snprintf(pidfn, sizeof(pidfn), "%s/%s-%s.pid", altpidpath(), ups->driver, ups->upsname); ret = stat(pidfn, &fs); if ((ret != 0) && (ups->port != NULL)) { upslog_with_errno(LOG_ERR, "Can't open %s", pidfn); snprintf(pidfn, sizeof(pidfn), "%s/%s-%s.pid", altpidpath(), ups->driver, xbasename(ups->port)); ret = stat(pidfn, &fs); } if (ret != 0) { upslog_with_errno(LOG_ERR, "Can't open %s either", pidfn); exec_error++; return; } } else { /* We started the driver in this run of upsdrvctl * tool, stayed foregrounded, and now are exiting. * NOTE: Not a filename here, but using same variable * name makes the code below simpler to maintain. */ snprintf(pidfn, sizeof(pidfn), "PID %" PRIdMAX, (intmax_t)ups->pid); } #else snprintf(pidfn, sizeof(pidfn), "%s-%s", ups->driver, ups->upsname); #endif upsdebugx(2, "Sending signal to %s", pidfn); if (testmode) return; #ifndef WIN32 if (ups->pid == -1) { ret = sendsignalfn(pidfn, SIGTERM); } else { ret = sendsignalpid(ups->pid, SIGTERM); /* reap zombie if this child died */ if (waitpid(ups->pid, NULL, WNOHANG) == ups->pid) { return; } } #else ret = sendsignal(pidfn, COMMAND_STOP); #endif if (ret < 0) { #ifndef WIN32 upsdebugx(2, "SIGTERM to %s failed, retrying with SIGKILL", pidfn); if (ups->pid == -1) { ret = sendsignalfn(pidfn, SIGKILL); } else { ret = sendsignalpid(ups->pid, SIGKILL); /* reap zombie if this child died */ if (waitpid(ups->pid, NULL, WNOHANG) == ups->pid) { return; } } #else upsdebugx(2, "Stopping %s failed, retrying again", pidfn); ret = sendsignal(pidfn, COMMAND_STOP); #endif if (ret < 0) { upslog_with_errno(LOG_ERR, "Stopping %s failed", pidfn); exec_error++; return; } } for (i = 0; i < 5 ; i++) { #ifndef WIN32 if (ups->pid == -1) { ret = sendsignalfn(pidfn, 0); } else { /* reap zombie if this child died */ if (waitpid(ups->pid, NULL, WNOHANG) == ups->pid) { return; } ret = sendsignalpid(ups->pid, 0); } #else ret = sendsignalfn(pidfn, 0); #endif if (ret != 0) { upsdebugx(2, "Sending signal to %s failed, driver is finally down or wrongly owned", pidfn); return; } sleep(1); } #ifndef WIN32 upslog_with_errno(LOG_ERR, "Stopping %s failed, retrying harder", pidfn); if (ups->pid == -1) { ret = sendsignalfn(pidfn, SIGKILL); } else { /* reap zombie if this child died */ if (waitpid(ups->pid, NULL, WNOHANG) == ups->pid) { return; } ret = sendsignalpid(ups->pid, SIGKILL); } #else upslog_with_errno(LOG_ERR, "Stopping %s failed, retrying again", pidfn); ret = sendsignal(pidfn, COMMAND_STOP); #endif if (ret == 0) { for (i = 0; i < 5 ; i++) { #ifndef WIN32 if (ups->pid == -1) { ret = sendsignalfn(pidfn, 0); } else { /* reap zombie if this child died */ if (waitpid(ups->pid, NULL, WNOHANG) == ups->pid) { return; } ret = sendsignalpid(ups->pid, 0); } #else ret = sendsignalfn(pidfn, 0); #endif if (ret != 0) { upsdebugx(2, "Sending signal to %s failed, driver is finally down or wrongly owned", pidfn); // While a TERMinated driver cleans up, // a stuck and KILLed one does not, so: if (ups->pid == -1) { unlink(pidfn); } return; } sleep(1); } } upslog_with_errno(LOG_ERR, "Stopping %s failed", pidfn); exec_error++; } void set_exit_flag(const int sig) { exit_flag = sig; } static void set_signal_flag(const #ifndef WIN32 int #else char * #endif sig ) { /* non-const, so some casting trickery */ signal_flag = ( #ifndef WIN32 int #else char * #endif )sig; } static void reset_signal_flag(void) { #ifndef WIN32 set_signal_flag(0); #else set_signal_flag(NULL); #endif } #ifndef WIN32 /* TODO: Equivalent for WIN32 - see SIGCMD_RELOAD in upd and upsmon */ static void set_reload_flag(const #ifndef WIN32 int #else char * #endif sig ) { set_signal_flag(sig); switch (sig) { case SIGCMD_RELOAD_OR_EXIT: /* SIGUSR1 */ /* reload-or-exit (this driver instance may die) */ reload_flag = 2; break; # ifdef SIGCMD_RELOAD_OR_RESTART case SIGCMD_RELOAD_OR_RESTART: /* SIGUSR2 */ /* reload-or-restart (this driver instance may recycle itself) */ /* FIXME: Not implemented yet */ reload_flag = 3; break; # endif case SIGCMD_RELOAD: /* SIGHUP */ case SIGCMD_RELOAD_OR_ERROR: /* Not even a signal, but a socket protocol action */ default: /* reload what we can, log what needs a restart so skipped */ reload_flag = 1; } upsdebugx(1, "%s: raising reload flag due to signal %d (%s) => reload_flag=%d", __func__, sig, strsignal(sig), reload_flag); } #endif static void setup_signals(void) { #ifndef WIN32 struct sigaction sa; #endif set_exit_flag(0); reset_signal_flag(); #ifndef WIN32 /* Keep in sync with signal handling in drivers/main.c */ sigemptyset(&sa.sa_mask); sa.sa_flags = 0; sa.sa_handler = set_exit_flag; sigaction(SIGTERM, &sa, NULL); sigaction(SIGINT, &sa, NULL); sigaction(SIGQUIT, &sa, NULL); #if (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_PUSH_POP) && (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_STRICT_PROTOTYPES) # pragma GCC diagnostic push # pragma GCC diagnostic ignored "-Wstrict-prototypes" #endif sa.sa_handler = SIG_IGN; #if (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_PUSH_POP) && (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_STRICT_PROTOTYPES) # pragma GCC diagnostic pop #endif sigaction(SIGPIPE, &sa, NULL); /* handle reloading */ sa.sa_handler = set_reload_flag; sigaction(SIGCMD_RELOAD, &sa, NULL); /* SIGHUP */ sigaction(SIGCMD_RELOAD_OR_EXIT, &sa, NULL); /* SIGUSR1 */ # ifdef SIGCMD_RELOAD_OR_RESTART /* FIXME: Want SIGCMD_RELOAD_OR_RESTART implemented */ sigaction(SIGCMD_RELOAD_OR_RESTART, &sa, NULL); /* SIGUSR2 */ # endif # ifdef SIGCMD_DATA_DUMP /* handle run-time data dump (may be limited to non-backgrounding lifetimes) */ sa.sa_handler = set_signal_flag; sigaction(SIGCMD_DATA_DUMP, &sa, NULL); /* SIGURG or SIGWINCH something else on obscure systems */ # endif #endif /* WIN32 */ } #ifndef WIN32 static void waitpid_timeout(const int sig) { NUT_UNUSED_VARIABLE(sig); /* do nothing */ return; } #endif /* print out a command line at the given debug level. */ static void debugcmdline(int level, const char *msg, char *const argv[]) { char cmdline[LARGEBUF]; snprintf(cmdline, sizeof(cmdline), "%s", msg); while (*argv) { snprintfcat(cmdline, sizeof(cmdline), " %s", *argv++); } upsdebugx(level, "%s", cmdline); } static void forkexec(char *const argv[], const ups_t *ups) { #ifndef WIN32 int ret; if (nut_foreground_passthrough > 0 && upscount == 1) { upsdebugx(1, "Starting the only driver with explicitly " "requested foregrounding mode, not forking"); } else { pid_t pid, waitret; pid = fork(); if (pid < 0) fatal_with_errno(EXIT_FAILURE, "fork"); if (pid != 0) { /* parent */ int wstat; struct sigaction sa; /* work around const for this one... */ int *pupid = (int *)&(ups->pid); int *puexectimeout = (int *)&(ups->exceeded_timeout); *pupid = pid; *puexectimeout = 0; /* Handle "parallel" drivers startup */ if (waitfordrivers == 0) { upsdebugx(2, "'nowait' set, continuing..."); return; } if (nut_foreground_passthrough > 0 && upscount > 1) { /* Let upsdrvctl fork to run its numerous children * but without further forking on their side - so * not waiting for them to complete start-ups. */ upsdebugx(1, "Starting driver with explicitly " "requested foregrounding mode: will not " "wait for it to fork and detach, continuing..."); return; } if (nut_foreground_passthrough != 0 && nut_debug_level > 0 && nut_debug_level_passthrough > 0 ) { upsdebugx(2, "Starting driver with debug but " "without explicit backgrounding: " "will not wait for it to fork and " "detach, continuing..."); return; } sigemptyset(&sa.sa_mask); sa.sa_flags = 0; sa.sa_handler = waitpid_timeout; sigaction(SIGALRM, &sa, NULL); /* Use the local maxstartdelay, if available */ if (ups->maxstartdelay != -1) { if (ups->maxstartdelay >= 0) alarm((unsigned int)ups->maxstartdelay); } else { /* Otherwise, use the global (or default) value */ if (maxstartdelay >= 0) alarm((unsigned int)maxstartdelay); } waitret = waitpid(pid, &wstat, 0); alarm(0); if (waitret == -1) { upslogx(LOG_WARNING, "Startup timer elapsed, continuing..."); exec_timeout++; *puexectimeout = 1; return; } if (WIFEXITED(wstat) == 0) { upslogx(LOG_WARNING, "Driver exited abnormally"); exec_error++; return; } /* the rest only work when WIFEXITED is nonzero */ if (WEXITSTATUS(wstat) != 0) { upslogx(LOG_WARNING, "Driver failed to start" " (exit status=%d)", WEXITSTATUS(wstat)); exec_error++; return; } if (WIFSIGNALED(wstat)) { upslog_with_errno(LOG_WARNING, "Driver died after signal %d", WTERMSIG(wstat)); exec_error++; } return; } } /* child or foreground mode (no fork) */ ret = execv(argv[0], argv); /* shouldn't get here normally */ upsdebugx(1, "%s: execv returned %d", __func__, ret); fatal_with_errno(EXIT_FAILURE, "execv"); #else BOOL ret; DWORD res; DWORD exit_code = 0; char commandline[SMALLBUF]; STARTUPINFO StartupInfo; PROCESS_INFORMATION ProcessInformation; int i = 1; memset(&StartupInfo, 0, sizeof(STARTUPINFO)); /* the command line is made of the driver name followed by args */ snprintf(commandline, sizeof(commandline), "%s", ups->driver); while (argv[i] != NULL) { snprintfcat(commandline, sizeof(commandline), " %s", argv[i]); i++; } ret = CreateProcess( argv[0], commandline, NULL, NULL, FALSE, CREATE_NEW_PROCESS_GROUP, NULL, NULL, &StartupInfo, &ProcessInformation ); if (ret == 0) { fatal_with_errno(EXIT_FAILURE, "execv"); } /* Wait a bit then look at driver process. * Unlike under Linux, Windows spawn drivers directly. If the driver is alive, all is OK. * An optimization can probably be implemented to prevent waiting so much time when all is OK. */ res = WaitForSingleObject(ProcessInformation.hProcess, (ups->maxstartdelay!=-1?ups->maxstartdelay:maxstartdelay)*1000); if (res != WAIT_TIMEOUT) { GetExitCodeProcess( ProcessInformation.hProcess, &exit_code ); upslogx(LOG_WARNING, "Driver failed to start (exit status=%d)", ret); exec_error++; return; } else { /* work around const for this one... */ int *pupid = (int *)&(ups->pid); int *puexectimeout = (int *)&(ups->exceeded_timeout); *pupid = 0; /* For WIN32, just a flag (not "-1" has a meaning) */ *puexectimeout = 1; } return; #endif } static void start_driver(const ups_t *ups) { char *argv[10]; char dfn[SMALLBUF], dbg[SMALLBUF]; int ret, arg = 0; int initial_exec_error = exec_error, initial_exec_timeout = exec_timeout, drv_maxretry = maxretry; struct stat fs; upsdebugx(1, "Starting UPS: %s", ups->upsname); #ifndef WIN32 snprintf(dfn, sizeof(dfn), "%s/%s", driverpath, ups->driver); #else snprintf(dfn, sizeof(dfn), "%s/%s.exe", driverpath, ups->driver); #endif ret = stat(dfn, &fs); if (ret < 0) fatal_with_errno(EXIT_FAILURE, "Can't start %s", dfn); argv[arg++] = dfn; if (nut_debug_level_passthrough > 0 && nut_debug_level > 0 && sizeof(dbg) > 3 ) { size_t d, m; /* cut-off point: buffer size or requested debug level */ m = sizeof(dbg) - 1; /* leave a place for '\0' */ #if (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_PUSH_POP) && ( (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_TYPE_LIMITS) || (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_TAUTOLOGICAL_CONSTANT_OUT_OF_RANGE_COMPARE) || (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_UNREACHABLE_CODE) ) # pragma GCC diagnostic push #endif #ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_UNREACHABLE_CODE # pragma GCC diagnostic ignored "-Wunreachable-code" #endif #ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_TYPE_LIMITS # pragma GCC diagnostic ignored "-Wtype-limits" #endif #ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_TAUTOLOGICAL_CONSTANT_OUT_OF_RANGE_COMPARE # pragma GCC diagnostic ignored "-Wtautological-constant-out-of-range-compare" #endif #ifdef __clang__ # pragma clang diagnostic push # pragma clang diagnostic ignored "-Wunreachable-code" # pragma clang diagnostic ignored "-Wtautological-compare" # pragma clang diagnostic ignored "-Wtautological-constant-out-of-range-compare" #endif /* Different platforms, different sizes, none fits all... */ /* can we fit this many 'D's? */ if ((uintmax_t)SIZE_MAX > (uintmax_t)nut_debug_level /* else can't assign, requested debug level is huge */ && (size_t)nut_debug_level + 1 < m ) { #ifdef __clang__ # pragma clang diagnostic pop #endif #if (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_PUSH_POP) && ( (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_TYPE_LIMITS) || (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_TAUTOLOGICAL_CONSTANT_OUT_OF_RANGE_COMPARE) || (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_UNREACHABLE_CODE) ) # pragma GCC diagnostic pop #endif /* need even fewer (leave a place for '-'): */ m = (size_t)nut_debug_level + 1; } else { upsdebugx(1, "Requested debugging level %d is too " "high for pass-through args, truncated to %" PRIuSIZE, nut_debug_level, (m - 1) /* count off '-' (and '\0' already) chars */ ); } dbg[0] = '-'; for (d = 1; d < m ; d++) { dbg[d] = 'D'; } dbg[d] = '\0'; argv[arg++] = dbg; } /* Default: -1, FG/BG depends on debugging level */ /* send_all_drivers() also warns if got many drivers to handle * and foreground mode - it won't loop really */ switch (nut_foreground_passthrough) { case 0: argv[arg++] = (char *)"-B"; /* FIXME: cast away const */ break; case 1: argv[arg++] = (char *)"-F"; /* FIXME: cast away const */ break; case 2: argv[arg++] = (char *)"-FF"; /* FIXME: cast away const */ break; default: if (nut_debug_level_passthrough > 0 && nut_debug_level > 0 ) { upsdebugx(1, "WARNING: Requested a debugging level " "but not explicitly a backgrounding mode - " "driver may never try to fork away; however " "the upsdrvctl tool will fork it and not wait."); } } argv[arg++] = (char *)"-a"; /* FIXME: cast away const */ argv[arg++] = ups->upsname; /* stick on the chroot / user args if given to us */ if (pt_root) { argv[arg++] = (char *)"-r"; /* FIXME: cast away const */ argv[arg++] = pt_root; } if (pt_user) { argv[arg++] = (char *)"-u"; /* FIXME: cast away const */ argv[arg++] = pt_user; } /* tie it off */ argv[arg++] = NULL; while (drv_maxretry > 0) { int cur_exec_error = exec_error; int cur_exec_timeout = exec_timeout; upsdebugx(2, "%i remaining attempts", drv_maxretry); debugcmdline(2, "exec: ", argv); drv_maxretry--; if (!testmode) { forkexec(argv, ups); } /* driver command succeeded */ if (cur_exec_error == exec_error && cur_exec_timeout == exec_timeout) { drv_maxretry = 0; exec_error = initial_exec_error; exec_timeout = initial_exec_timeout; } else { /* otherwise, retry if still needed */ if (drv_maxretry > 0) if (retrydelay >= 0) sleep ((unsigned int)retrydelay); } } } static void help(const char *progname) __attribute__((noreturn)); static void help(const char *arg_progname) { printf("Starts and stops UPS drivers via ups.conf.\n\n"); printf("usage: %s [OPTIONS] (start | stop | shutdown) []\n\n", arg_progname); printf("usage: %s [OPTIONS] -c []\n\n", arg_progname); printf("Common options:\n"); printf(" -h display this help\n"); printf(" -r drivers will chroot to \n"); printf(" -t testing mode - prints actions without doing them\n"); printf(" -u drivers started will switch from root to \n"); printf(" -D raise debugging level\n"); printf(" -d pass debugging level from upsdrvctl to driver\n"); printf(" -F driver stays foregrounded even if no debugging is enabled\n"); printf(" -FF driver stays foregrounded and still saves the PID file\n"); printf(" -B driver(s) stay backgrounded even if debugging is bumped\n"); printf("Signalling a running driver:\n"); printf(" -c send via signal to running driver(s)\n"); printf(" supported commands:\n"); #ifndef WIN32 /* FIXME: port event loop from upsd/upsmon to allow messaging fellow drivers in WIN32 builds */ printf(" - data-dump: if the driver still has STDOUT attached (maybe\n"); printf(" to log), dump its currently collected information there\n"); printf(" - reload: re-read configuration files, ignoring changed\n"); printf(" values which require a driver restart (can not be changed\n"); printf(" on the fly)\n"); #endif /* WIN32 */ printf(" - reload-or-error: re-read configuration files, ignoring but\n"); printf(" counting changed values which require a driver restart (can\n"); printf(" not be changed on the fly), and return a success/fail code\n"); printf(" based on that count, so the caller can decide the fate of\n"); printf(" the currently running driver instance\n"); #ifndef WIN32 /* FIXME: port event loop from upsd/upsmon to allow messaging fellow drivers in WIN32 builds */ # ifdef SIGCMD_RELOAD_OR_RESTART printf(" - reload-or-restart: re-read configuration files (close the\n"); printf(" old driver instance device connection if needed, and have\n"); printf(" it effectively restart)\n"); # endif printf(" - reload-or-exit: re-read configuration files (exit the old\n"); printf(" driver instance if needed, so an external caller like the\n"); printf(" systemd or SMF frameworks would start another copy)\n"); #endif /* WIN32 */ printf("Driver life cycle options:\n"); printf(" start start all UPS drivers in ups.conf\n"); printf(" start only start driver for UPS \n"); printf(" stop stop all UPS drivers in ups.conf\n"); printf(" stop only stop driver for UPS \n"); printf(" shutdown shutdown all UPS drivers in ups.conf\n"); printf(" shutdown only shutdown UPS \n"); exit(EXIT_SUCCESS); } static void shutdown_driver(const ups_t *ups) { char *argv[9]; char dfn[SMALLBUF]; int arg = 0; upsdebugx(1, "Shutdown UPS: %s", ups->upsname); #ifndef WIN32 snprintf(dfn, sizeof(dfn), "%s/%s", driverpath, ups->driver); #else snprintf(dfn, sizeof(dfn), "%s/%s.exe", driverpath, ups->driver); #endif argv[arg++] = dfn; argv[arg++] = (char *)"-a"; /* FIXME: cast away const */ argv[arg++] = ups->upsname; argv[arg++] = (char *)"-k"; /* FIXME: cast away const */ /* stick on the chroot / user args if given to us */ if (pt_root) { argv[arg++] = (char *)"-r"; /* FIXME: cast away const */ argv[arg++] = pt_root; } if (pt_user) { argv[arg++] = (char *)"-u"; /* FIXME: cast away const */ argv[arg++] = pt_user; } argv[arg++] = NULL; debugcmdline(2, "exec: ", argv); if (!testmode) { forkexec(argv, ups); } } static void send_one_driver(void (*command_func)(const ups_t *), const char *arg_upsname) { ups_t *ups = upstable; if (!ups) fatalx(EXIT_FAILURE, "Error: no UPS definitions found in ups.conf!\n"); exec_error = 0; exec_timeout = 0; while (ups) { if (!strcmp(ups->upsname, arg_upsname)) { command_func(ups); return; } ups = ups->next; } fatalx(EXIT_FAILURE, "UPS %s not found in ups.conf", arg_upsname); } /* walk UPS table and send command to all UPSes according to sdorder */ static void send_all_drivers(void (*command_func)(const ups_t *)) { ups_t *ups; int i; if (!upstable) fatalx(EXIT_FAILURE, "Error: no UPS definitions found in ups.conf"); exec_error = 0; exec_timeout = 0; if (command_func != &shutdown_driver) { ups = upstable; /* Only warn when relevant - got more than one device to start */ if (command_func == &start_driver && ups->next && ( (nut_foreground_passthrough > 0) || (nut_foreground_passthrough != 0 && nut_debug_level > 0 && nut_debug_level_passthrough > 0) ) ) { upslogx(LOG_WARNING, "Starting \"all\" drivers but requested the %s!" "This request will not wait for driver(s) to complete " "their initialization%s.", (nut_foreground_passthrough > 0 ? "foreground mode" : "debug mode without backgrounding"), (nut_foreground_passthrough > 0 ? ", but upsdrvctl tool will stay foregrounded" : "") ); } while (ups) { command_func(ups); ups = ups->next; } return; } /* Orderly processing of shutdowns */ for (i = 0; i <= maxsdorder; i++) { ups = upstable; while (ups) { if (ups->sdorder == i) command_func(ups); ups = ups->next; } } } static void exit_cleanup(void) { ups_t *tmp, *next; upsdebugx(1, "Completed the job of upsdrvctl tool, cleaning up and exiting now"); tmp = upstable; if (command == &start_driver && upscount > 0 && nut_foreground_passthrough > 0 ) { /* First stop the drivers, if any are running */ while (tmp) { next = tmp->next; if (tmp->pid != -1) { stop_driver(tmp); } tmp = next; } } tmp = upstable; while (tmp) { next = tmp->next; free(tmp->driver); free(tmp->port); free(tmp->upsname); free(tmp); tmp = next; } free(driverpath); upsdebugx(1, "Completed the job of upsdrvctl tool, clean-up finished, exiting now"); } int main(int argc, char **argv) { int i, lastarg = 0; char *prog; printf("Network UPS Tools - UPS driver controller %s\n", UPS_VERSION); prog = argv[0]; while ((i = getopt(argc, argv, "+htu:r:DdFBVc:")) != -1) { switch(i) { case 'r': pt_root = optarg; break; case 't': testmode = 1; break; case 'u': pt_user = optarg; break; case 'V': exit(EXIT_SUCCESS); case 'D': nut_debug_level++; break; case 'd': nut_debug_level_passthrough = 1; break; case 'F': if (nut_foreground_passthrough > 0) { /* specified twice to save PID file anyway */ nut_foreground_passthrough = 2; } else { nut_foreground_passthrough = 1; } break; case 'B': nut_foreground_passthrough = 0; break; case 'c': if (command || pt_cmd) { fatalx(EXIT_FAILURE, "Error: only one command per run can be " "sent with option -%c. Try -h for help.", i); } command = &signal_driver; if (!strncmp(optarg, "reload-or-error", strlen(optarg))) { signal_flag = SIGCMD_RELOAD_OR_ERROR; } #ifndef WIN32 /* FIXME: port event loop from upsd/upsmon to allow messaging fellow drivers in WIN32 builds */ else if (!strncmp(optarg, "dump", strlen(optarg))) { signal_flag = SIGCMD_DATA_DUMP; } else if (!strncmp(optarg, "data-dump", strlen(optarg))) { signal_flag = SIGCMD_DATA_DUMP; } else if (!strncmp(optarg, "reload", strlen(optarg))) { signal_flag = SIGCMD_RELOAD; } else # ifdef SIGCMD_RELOAD_OR_RESTART if (!strncmp(optarg, "reload-or-restart", strlen(optarg))) { signal_flag = SIGCMD_RELOAD_OR_RESTART; } else # endif if (!strncmp(optarg, "reload-or-exit", strlen(optarg))) { signal_flag = SIGCMD_RELOAD_OR_EXIT; } #endif /* WIN32 */ /* bad command given */ if (!signal_flag) { fatalx(EXIT_FAILURE, "Error: unknown argument to option -%c. Try -h for help.", i); } pt_cmd = optarg; #ifndef WIN32 upsdebugx(1, "Will send signal %d (%s) for command '%s' " "to already-running driver (if any) and exit", signal_flag, strsignal(signal_flag), optarg); #else upsdebugx(1, "Will send request '%s' for command '%s' " "to already-running driver (if any) and exit", signal_flag, optarg); #endif /* WIN32 */ break; case 'h': default: help(prog); } } { /* scoping */ char *s = getenv("NUT_DEBUG_LEVEL"); int l; if (s && str_to_int(s, &l, 10)) { if (l > 0 && nut_debug_level < 1) { upslogx(LOG_INFO, "Defaulting debug verbosity to NUT_DEBUG_LEVEL=%d " "since none was requested by command-line options", l); nut_debug_level = l; } /* else follow -D settings */ } /* else nothing to bother about */ } argc -= optind; argv += optind; /* We expect maybe command (if not signalling above) and maybe UPS name */ if (!command && argc < 1) help(prog); if (testmode) { printf("*** Testing mode: not calling exec/kill/signal\n"); if (nut_debug_level < 2) nut_debug_level = 2; } if (nut_debug_level_passthrough == 0) { upsdebugx(2, "\n" "If you're not a NUT core developer, chances are that you're told to enable debugging\n" "to see why a driver isn't working for you. We're sorry for the confusion, but this is\n" "the 'upsdrvctl' wrapper, not the driver you're interested in.\n\n" "Below you'll find one or more lines starting with 'exec:' followed by an absolute\n" "path to the driver binary and some command line option. This is what the driver\n" "starts and you need to copy and paste that line and append the debug flags to that\n" "line (less the 'exec:' prefix).\n\n" "Alternately, provide an additional '-d' (lower-case) parameter to 'upsdrvctl' to\n" "pass its current debug level to the launched driver, and '-B' keeps it backgrounded.\n"); } if (!command) { if (!strcmp(argv[0], "start")) { command = &start_driver; } else if (!strcmp(argv[0], "stop")) { command = &stop_driver; } else if (!strcmp(argv[0], "shutdown")) { command = &shutdown_driver; } lastarg = 1; } if (!command) fatalx(EXIT_FAILURE, "Error: unrecognized command [%s]", argv[0]); #ifndef WIN32 driverpath = xstrdup(DRVPATH); /* set default */ #else driverpath = getfullpath(NULL); /* Relative path in WIN32 */ #endif atexit(exit_cleanup); read_upsconf(1); if (argc == lastarg) { ups_t *tmp = upstable; upscount = 0; while (tmp) { tmp = tmp->next; upscount++; } upsdebugx(1, "upsdrvctl commanding all drivers (%d found): %s", upscount, (pt_cmd ? pt_cmd : NUT_STRARG(argv[lastarg]))); send_all_drivers(command); } else if (argc == (lastarg + 1)) { upscount = 1; upsdebugx(1, "upsdrvctl commanding one driver (%s): %s", argv[lastarg], (pt_cmd ? pt_cmd : NUT_STRARG(argv[lastarg - 1]))); send_one_driver(command, argv[lastarg]); } else { fatalx(EXIT_FAILURE, "Error: extra arguments left on command line\n" "(common options should be before a command and UPS name)"); } /* Note that the numeric value here is not precise (it reflects * the number of "timeouts" which grows with amount of drivers * and retries. Below we re-check each driver to convert the * value into some amount of known failures (or succeses). */ if (exec_timeout) { #ifndef WIN32 ups_t *tmp = upstable; #endif upsdebugx(1, "upsdrvctl: got some timeouts with preceding operations, revising them now"); #ifndef WIN32 while (tmp) { if (tmp->exceeded_timeout && tmp->pid) { /* reap zombie if this child died, and * get info if we know how it went (or * still goes) */ int wstat; pid_t waitret = waitpid(tmp->pid, &wstat, WNOHANG); upsdebugx(1, "Driver [%s] PID %" PRIdMAX " initially exceeded " "maxstartdelay but now waitpid() returns %" PRIdMAX " and status bits 0x%.*X", tmp->upsname, (intmax_t)tmp->pid, (intmax_t)waitret, (int)(2*sizeof(wstat)), wstat); if (waitret == tmp->pid) { upsdebugx(1, "Driver [%s] PID %" PRIdMAX " initially exceeded " "maxstartdelay but has finished by now", tmp->upsname, (intmax_t)tmp->pid); tmp->exceeded_timeout = 0; } else if (waitret == 0) { /* Special behavior for WNOHANG */ upslogx(LOG_WARNING, "Driver [%s] PID %" PRIdMAX " initially exceeded " "maxstartdelay and is still starting", tmp->upsname, (intmax_t)tmp->pid); /* TOTHINK: Should this "timeout" cause an error * exit code, if this is the only problem? * Maybe as a special case - if this is the only * driver (dedicated starter) vs. start-all? * if (argc != (lastarg + 1)) ... * or if (upscount == 1) ... */ exec_error++; } else if (waitret == -1) { upslog_with_errno(LOG_WARNING, "Driver [%s] PID %" PRIdMAX " initially exceeded " "maxstartdelay and we got an error asking it again", tmp->upsname, (intmax_t)tmp->pid); exec_error++; } else if (WIFEXITED(wstat) == 0) { upslogx(LOG_WARNING, "Driver [%s] PID %" PRIdMAX " initially exceeded " "maxstartdelay and has exited abnormally by now", tmp->upsname, (intmax_t)tmp->pid); exec_error++; } else /* the rest only work when WIFEXITED is nonzero */ if (WEXITSTATUS(wstat) != 0) { upslogx(LOG_WARNING, "Driver [%s] PID %" PRIdMAX " initially exceeded " "maxstartdelay and has failed to start by now " "(exit status=%d)", tmp->upsname, (intmax_t)tmp->pid, WEXITSTATUS(wstat)); exec_error++; } else if (WIFSIGNALED(wstat)) { upslog_with_errno(LOG_WARNING, "Driver [%s] PID %" PRIdMAX " initially exceeded " "maxstartdelay and has died after signal %d by now", tmp->upsname, (intmax_t)tmp->pid, WTERMSIG(wstat)); exec_error++; } } tmp = tmp->next; } #else /* WIN32 */ /* TOTHINK: Is there something we can do on the platform? */ exec_error++; #endif /* WIN32 */ } if (exec_error) { upsdebugx(1, "upsdrvctl: got some errors with preceding operations, exiting with failure now"); exit(EXIT_FAILURE); } if (command == &start_driver && upscount > 0 && nut_foreground_passthrough > 0 ) { /* Note: for a single started driver, we just * exec() it and should not even get here */ upsdebugx(1, "upsdrvctl: was asked for explicit foregrounding - " "not exiting now (driver startup was completed)"); /* raise exit_flag upon SIGTERM, Ctrl+C, etc. */ setup_signals(); while (!exit_flag) { #ifndef WIN32 ups_t *tmp = upstable, *next; /* Track if any child process has stopped (due to * an error, normal exit, signal...) to kill others * and exit the tool - with error if applicable. */ while (tmp) { next = tmp->next; if (tmp->pid != -1) { int status; if (waitpid(tmp->pid, &status, WNOHANG) == tmp->pid) { if (WIFEXITED(status)) { int es = WEXITSTATUS(status); time_t now; double elapsed; time(&now); elapsed = difftime(now, last_dangerous_reload); if (elapsed < 60 || (es - 128) == SIGCMD_RELOAD_OR_EXIT # ifdef SIGCMD_RELOAD_OR_RESTART || (es - 128) == SIGCMD_RELOAD_OR_RESTART # endif ) { /* Arbitrary but generous time to handle * a reload including driver loop lag */ upsdebugx(1, "Driver [%s] for [%s] exited " "soon after reload-or-exit or " "similar signal, restarting it", tmp->driver, tmp->upsname); tmp->pid = -1; start_driver(tmp); } else { /* Quit without excuses, recycle myself */ upsdebugx(1, "Driver [%s] for [%s] exited " "inexplicably with code %d, aborting", tmp->driver, tmp->upsname, es); if (last_dangerous_reload) upsdebugx(1, "Last 'dangerous' signal " "was processed %f sec ago", elapsed); exit_flag = -1; tmp->pid = -1; } } } } tmp = next; } if (exit_flag == -1) { fatalx(EXIT_FAILURE, "At least one tracked driver running " "in foreground mode has exited, stopping upsdrvctl " "(and other tracked drivers) so the bundle can be " "restarted by system properly"); /* NOTE: Users really should run one driver per instance, * wrapped in services where available */ } if (signal_flag) { upsdebugx(1, "upsdrvctl: handling signal: starting"); if (signal_flag == SIGCMD_RELOAD_OR_EXIT # ifdef SIGCMD_RELOAD_OR_RESTART || signal_flag == SIGCMD_RELOAD_OR_RESTART # endif ) time(&last_dangerous_reload); tmp = upstable; while (tmp) { next = tmp->next; signal_driver(tmp); tmp = next; } reset_signal_flag(); upsdebugx(1, "upsdrvctl: handling signal: finished"); } #endif /* WIN32 */ sleep(1); } } upsdebugx(1, "upsdrvctl: successfully finished"); exit(EXIT_SUCCESS); } nut-2.8.1/drivers/nut-ipmi.h0000644000175000017500000000471214500336654012654 00000000000000/* nut-ipmi.h - Abstract IPMI interface, to allow using different IPMI backends * * Copyright (C) 2011 - Arnaud Quette * * 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 2 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, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #ifndef NUT_IPMI_H #define NUT_IPMI_H typedef enum { PSU_STATUS_UNKNOWN = 1, PSU_PRESENT, /* = status OL */ PSU_ABSENT, /* = status stale */ PSU_POWER_FAILURE /* = status OFF */ } psu_status_t; #ifdef HAVE_FREEIPMI_11X_12X /* args 8, 9, 10, 11 of ipmi_fru_multirecord_power_supply_information() */ typedef int input_voltage_range_t; #else /* args 8, 9, 10, 11 of ipmi_fru_parse_multirecord_power_supply_information() */ typedef unsigned int input_voltage_range_t; #endif /* Abstract structure to store information */ typedef struct IPMIDevice_s { int ipmi_id; /* FRU ID */ char* manufacturer; /* Manufacturer Name */ char* product; /* Product Name */ char* serial; /* Product serial number */ char* part; /* Part Number */ char* date; /* Manufacturing Date/Time */ int overall_capacity; /* realpower.nominal? */ input_voltage_range_t input_minvoltage; input_voltage_range_t input_maxvoltage; int input_minfreq; int input_maxfreq; int voltage; /* psu.voltage or device.voltage */ unsigned int sensors_count; /* number of sensors IDs in sensors_id_list */ unsigned int sensors_id_list[20]; /* ID of sensors linked to this FRU */ /* measurements... */ int status; /* values from psu_status_t */ double input_voltage; double input_current; double temperature; } IPMIDevice_t; /* Generic functions, to implement in the backends */ int nut_ipmi_open(int ipmi_id, IPMIDevice_t *ipmi_dev); void nut_ipmi_close(void); int nut_ipmi_monitoring_init(void); int nut_ipmi_get_sensors_status(IPMIDevice_t *ipmi_dev); #endif /* NUT_IPMI_H */ nut-2.8.1/drivers/apc-mib.h0000644000175000017500000000023214500336654012413 00000000000000#ifndef APC_MIB_H #define APC_MIB_H #include "main.h" #include "snmp-ups.h" #include "apc-iem-mib.h" extern mib2nut_info_t apc; #endif /* APC_MIB_H */ nut-2.8.1/drivers/apcsmart-old.h0000644000175000017500000002237614501607135013502 00000000000000/* apcsmart.h - command table for APC smart protocol units Copyright (C) 1999 Russell Kroll (C) 2000 Nigel Metheringham 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 2 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, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef NUT_APCSMART_OLD_H_SEEN #define NUT_APCSMART_OLD_H_SEEN 1 #include #ifndef WIN32 #include #endif #include "serial.h" #include "timehead.h" #define APC_TABLE_VERSION "version 2.2" /* Basic UPS reply line structure */ #define ENDCHAR 10 /* APC ends responses with LF */ /* characters ignored by default */ #define IGNCHARS "\015+$|!~%?=#&" /* special characters to ignore */ /* these one is used only during startup, due to ^Z sending certain characters such as # */ #define MINIGNCHARS "\015+$|!" /* minimum set of special characters to ignore */ /* normal polls: characters we don't want to parse (including a few alerts) */ #define POLL_IGNORE "\015&|" /* alert characters we care about - OL, OB, LB, not LB, RB, OVER, not OVER */ #define POLL_ALERT "$!%+#?=" #define UPSDELAY 50000 /* slow down multicharacter commands */ #define CMDLONGDELAY 1500000 /* some commands need a 1.5s gap for safety */ #define SER_WAIT_SEC 3 /* wait up to 3.0 sec for ser_get calls */ #define SER_WAIT_USEC 0 /* dangerous instant commands must be reconfirmed within a 12 second window */ #define MINCMDTIME 3 #define MAXCMDTIME 15 /* it only does two strings, and they're both the same length */ #define APC_STRLEN 8 /* --------------- */ /* status bits */ #define APC_STAT_CAL 1L /* calibration */ #define APC_STAT_TRIM 2L /* SmartTrim */ #define APC_STAT_BOOST 4L /* SmartBoost */ #define APC_STAT_OL 8L /* on line */ #define APC_STAT_OB 16L /* on battery */ #define APC_STAT_OVER 32L /* overload */ #define APC_STAT_LB 64L /* low battery */ #define APC_STAT_RB 128L /* replace battery */ /* serial protocol: special commands - initialization and such */ #define APC_STATUS 'Q' #define APC_GOSMART 'Y' #define APC_GODUMB 'R' #define APC_CMDSET 'a' #define APC_CAPABILITY 26 /* ^Z */ #define APC_NEXTVAL '-' /* --------------- */ /* Driver command table flag values */ #define APC_POLL 0x0001 /* Poll this variable regularly */ #define APC_PRESENT 0x0004 /* Capability seen on this UPS */ #define APC_RW 0x0010 /* read-write variable */ #define APC_ENUM 0x0020 /* enumerated type */ #define APC_STRING 0x0040 /* string */ #define APC_NASTY 0x0100 /* Nasty command - take care */ #define APC_REPEAT 0x0200 /* Command needs sending twice */ #define APC_FORMATMASK 0xFF0000 /* Mask for apc data formats */ #define APC_F_PERCENT 0x020000 /* Data in a percent format */ #define APC_F_VOLT 0x030000 /* Data in a voltage format */ #define APC_F_AMP 0x040000 /* Data in a current/amp format */ #define APC_F_CELSIUS 0x050000 /* Data in a temp/C format */ #define APC_F_HEX 0x060000 /* Data in a hex number format */ #define APC_F_DEC 0x070000 /* Data in a decimal format */ #define APC_F_SECONDS 0x100000 /* Time in seconds */ #define APC_F_MINUTES 0x110000 /* Time in minutes */ #define APC_F_HOURS 0x120000 /* Time in hours */ #define APC_F_REASON 0x130000 /* Reason of transfer */ #define APC_F_LEAVE 0 /* Just pass this through */ typedef struct { const char *name; /* the variable name */ unsigned int flags; /* various flags */ unsigned char cmd; /* command character */ } apc_vartab_t; static apc_vartab_t apc_vartab[] = { { "ups.firmware.old", 0, 'V' }, { "ups.firmware", 0, 'b' }, { "ups.firmware.aux", 0, 'v' }, { "ups.model", 0, 0x01 }, { "ups.serial", 0, 'n' }, { "ups.mfr.date", 0, 'm' }, { "ups.temperature", APC_POLL|APC_F_CELSIUS, 'C' }, { "ups.load", APC_POLL|APC_F_PERCENT, 'P' }, { "ups.test.interval", APC_F_HOURS, 'E' }, { "ups.test.result", APC_POLL, 'X' }, { "ups.delay.start", APC_F_SECONDS, 'r' }, { "ups.delay.shutdown", APC_F_SECONDS, 'p' }, { "ups.id", APC_STRING, 'c' }, { "ups.contacts", APC_POLL|APC_F_HEX, 'i' }, { "ups.display.language", 0, 0x0C }, { "input.voltage", APC_POLL|APC_F_VOLT, 'L' }, { "input.frequency", APC_POLL|APC_F_DEC, 'F' }, { "input.sensitivity", 0, 's' }, { "input.quality", APC_POLL|APC_F_HEX, '9' }, { "input.transfer.low", APC_F_VOLT, 'l' }, { "input.transfer.high", APC_F_VOLT, 'u' }, { "input.transfer.reason", APC_POLL|APC_F_REASON, 'G' }, { "input.voltage.maximum", APC_POLL|APC_F_VOLT, 'M' }, { "input.voltage.minimum", APC_POLL|APC_F_VOLT, 'N' }, { "output.current", APC_POLL|APC_F_AMP, '/' }, { "output.voltage", APC_POLL|APC_F_VOLT, 'O' }, { "output.voltage.nominal", APC_F_VOLT, 'o' }, { "ambient.humidity", APC_POLL|APC_F_PERCENT, 'h' }, { "ambient.humidity.high", APC_F_PERCENT, '{' }, { "ambient.humidity.low", APC_F_PERCENT, '}' }, { "ambient.temperature", APC_POLL|APC_F_CELSIUS, 't' }, { "ambient.temperature.high", APC_F_CELSIUS, '[' }, { "ambient.temperature.low", APC_F_CELSIUS, ']' }, { "battery.date", APC_STRING, 'x' }, { "battery.charge", APC_POLL|APC_F_PERCENT, 'f' }, { "battery.charge.restart", APC_F_PERCENT, 'e' }, { "battery.voltage", APC_POLL|APC_F_VOLT, 'B' }, { "battery.voltage.nominal", 0, 'g' }, { "battery.runtime", APC_POLL|APC_F_MINUTES, 'j' }, { "battery.runtime.low", APC_F_MINUTES, 'q' }, { "battery.packs", APC_F_DEC, '>' }, { "battery.packs.bad", APC_F_DEC, '<' }, { "battery.alarm.threshold", 0, 'k' }, /* todo: I = alarm enable (hex field) - split into alarm.n.enable J = alarm status (hex field) - split into alarm.n.status 0x15 = output voltage selection (APC_F_VOLT) 0x5C = load power (APC_POLL|APC_F_PERCENT) */ {NULL, 0, 0}, }; /* ------ instant commands ------ */ #define APC_CMD_FPTEST 'A' #define APC_CMD_CALTOGGLE 'D' #define APC_CMD_SHUTDOWN 'K' #define APC_CMD_SOFTDOWN 'S' #define APC_CMD_GRACEDOWN '@' #define APC_CMD_SIMPWF 'U' #define APC_CMD_BTESTTOGGLE 'W' #define APC_CMD_OFF 'Z' #define APC_CMD_ON 0x0E /* ^N */ #define APC_CMD_BYPTOGGLE '^' typedef struct { const char *name; int flags; unsigned char cmd; } apc_cmdtab_t; static apc_cmdtab_t apc_cmdtab[] = { { "load.off", APC_NASTY|APC_REPEAT, APC_CMD_OFF }, { "load.on", APC_REPEAT, APC_CMD_ON }, { "test.panel.start", 0, APC_CMD_FPTEST }, { "test.failure.start", 0, APC_CMD_SIMPWF }, { "test.battery.start", 0, APC_CMD_BTESTTOGGLE }, { "test.battery.stop", 0, APC_CMD_BTESTTOGGLE }, { "shutdown.return.grace", APC_NASTY, APC_CMD_GRACEDOWN }, { "shutdown.return", APC_NASTY, APC_CMD_SOFTDOWN }, { "shutdown.stayoff", APC_NASTY|APC_REPEAT, APC_CMD_SHUTDOWN }, { "calibrate.start", 0, APC_CMD_CALTOGGLE }, { "calibrate.stop", 0, APC_CMD_CALTOGGLE }, { "bypass.start", 0, APC_CMD_BYPTOGGLE }, { "bypass.stop", 0, APC_CMD_BYPTOGGLE }, { NULL, 0, 0 } }; /* compatibility with hardware that doesn't do APC_CMDSET ('a') */ static struct { const char *firmware; const char *cmdchars; int flags; } compat_tab[] = { /* APC Matrix */ { "0XI", "789ABCDEFGKLMNOPQRSTUVWXYZcefgjklmnopqrsuwxz/<>\\^\014\026", 0 }, { "0XM", "789ABCDEFGKLMNOPQRSTUVWXYZcefgjklmnopqrsuwxz/<>\\^\014\026", 0 }, { "0ZI", "79ABCDEFGKLMNOPQRSUVWXYZcefgjklmnopqrsuxz/<>", 0 }, { "5UI", "79ABCDEFGKLMNOPQRSUVWXYZcefgjklmnopqrsuxz/<>", 0 }, { "5ZM", "79ABCDEFGKLMNOPQRSUVWXYZcefgjklmnopqrsuxz/<>", 0 }, /* APC600 */ { "6QD", "79ABCDEFGKLMNOPQRSUVWXYZcefgjklmnopqrsuxz", 0 }, { "6QI", "79ABCDEFGKLMNOPQRSUVWXYZcefgjklmnopqrsuxz", 0 }, { "6TD", "79ABCDEFGKLMNOPQRSUVWXYZcefgjklmnopqrsuxz", 0 }, { "6TI", "79ABCDEFGKLMNOPQRSUVWXYZcefgjklmnopqrsuxz", 0 }, /* SmartUPS 900 */ { "7QD", "79ABCDEFGKLMNOPQRSUVWXYZcefgjklmnopqrsuxz", 0 }, { "7QI", "79ABCDEFGKLMNOPQRSUVWXYZcefgjklmnopqrsuxz", 0 }, { "7TD", "79ABCDEFGKLMNOPQRSUVWXYZcefgjklmnopqrsuxz", 0 }, { "7TI", "79ABCDEFGKLMNOPQRSUVWXYZcefgjklmnopqrsuxz", 0 }, /* SmartUPS 900I */ { "7II", "79ABCEFGKLMNOPQSUVWXYZcfg", 0 }, /* SmartUPS 2000I */ { "9II", "79ABCEFGKLMNOPQSUVWXYZcfg", 0 }, { "9GI", "79ABCEFGKLMNOPQSUVWXYZcfg", 0 }, /* SmartUPS 1250 */ { "8QD", "79ABCDEFGKLMNOPQRSUVWXYZcefgjklmnopqrsuxz", 0 }, { "8QI", "79ABCDEFGKLMNOPQRSUVWXYZcefgjklmnopqrsuxz", 0 }, { "8TD", "79ABCDEFGKLMNOPQRSUVWXYZcefgjklmnopqrsuxz", 0 }, { "8TI", "79ABCDEFGKLMNOPQRSUVWXYZcefgjklmnopqrsuxz", 0 }, /* CS 350 */ { "5.4.D", "\1ABPQRSUYbdfgjmnx9", 0 }, /* Smart-UPS 600 */ { "D9", "789ABCEFGKLMNOPQRSUVWXYZ", 0 }, { "D8", "789ABCEFGKLMNOPQRSUVWXYZ", 0 }, { "D7", "789ABCEFGKLMNOPQRSUVWXYZ", 0 }, { "D6", "789ABCEFGKLMNOPQRSUVWXYZ", 0 }, { "D5", "789ABCEFGKLMNOPQRSUVWXYZ", 0 }, { "D4", "789ABCEFGKLMNOPQRSUVWXYZ", 0 }, { NULL, NULL, 0 }, }; #endif /* NUT_APCSMART_OLD_H_SEEN */ nut-2.8.1/drivers/upsdrvquery.h0000644000175000017500000000400714501607135013514 00000000000000/* upsdrvquery.h - a single query shot over a driver socket, tracked until a response arrives, returning that line and closing a connection Copyright (C) 2023 Jim Klimov 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 2 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, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef NUT_UPSDRVQUERY_H_SEEN #define NUT_UPSDRVQUERY_H_SEEN #include "common.h" /* TYPE_FD etc. */ #include "timehead.h" typedef struct udq_pipe_conn_s { TYPE_FD sockfd; #ifdef WIN32 OVERLAPPED overlapped; int newread; /* Set to 1 to start a new ReadFile, forget old buf */ #endif /* WIN32 */ char buf[LARGEBUF]; char sockfn[LARGEBUF]; } udq_pipe_conn_t; udq_pipe_conn_t *upsdrvquery_connect(const char *sockfn); udq_pipe_conn_t *upsdrvquery_connect_drvname_upsname(const char *drvname, const char *upsname); void upsdrvquery_close(udq_pipe_conn_t *conn); ssize_t upsdrvquery_read_timeout(udq_pipe_conn_t *conn, struct timeval tv); ssize_t upsdrvquery_write(udq_pipe_conn_t *conn, const char *buf); ssize_t upsdrvquery_prepare(udq_pipe_conn_t *conn, struct timeval tv); ssize_t upsdrvquery_request(udq_pipe_conn_t *conn, struct timeval tv, const char *query); /* if buf != NULL, last reply is copied there */ ssize_t upsdrvquery_oneshot(const char *drvname, const char *upsname, const char *query, char *buf, const size_t bufsz, struct timeval *tv); #endif /* NUT_UPSDRVQUERY_H_SEEN */ nut-2.8.1/drivers/microsol-common.c0000644000175000017500000005453614501607135014227 00000000000000/* microsol-common.c - common framework for Microsol Solis-based UPS hardware Copyright (C) 2004 Silvino B. Magalhães 2019 Roberto Panerai Velloso 2021 Ygor A. S. Regados 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 2 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, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 2021/03/19 - Version 0.70 - Initial release, based on solis driver */ #include "main.h" /* Includes "config.h", must be first */ #include #include #include #include "serial.h" #include "nut_float.h" #include "nut_stdint.h" #include "microsol-common.h" #include "timehead.h" #define false 0 #define true 1 #define RESP_END 0xFE #define ENDCHAR 13 /* replies end with CR */ /* solis commands */ #define CMD_UPSCONT 0xCC #define CMD_SHUT 0xDD #define CMD_SHUTRET 0xDE #define CMD_EVENT 0xCE #define CMD_DUMP 0xCD #define M_UNKN "Unknown solis model" #define NO_SOLIS "Solis not detected! aborting ..." #define UPS_DATE "UPS Date %4d/%02d/%02d" #define SYS_DATE "System Date %4d/%02d/%02d day of week %s" #define ERR_PACK "Wrong package" #define NO_EVENT "No events" #define UPS_TIME "UPS internal Time %0d:%02d:%02d" #define PRG_DAYS "Programming Shutdown Sun Mon Tue Wed Thu Fri Sat" #define PRG_ONON "External shutdown programming active" #define PRG_ONOU "Internal shutdown programming active" #define TIME_OFF "UPS Time power off %02d:%02d" #define TIME_ON "UPS Time power on %02d:%02d" #define PRG_ONOF "Shutdown programming not activated" #define TODAY_DD "Shutdown today at %02d:%02d" #define SHUT_NOW "Shutdown now!" #define FMT_DAYS " %d %d %d %d %d %d %d" /* Date, time and programming group */ static int const BASE_YEAR = 1998; /* Note: code below uses relative "unsigned char" years */ static int device_day, device_month, device_year; static int device_hour, device_minute, device_second; static int power_off_hour, power_off_minute; static int power_on_hour, power_on_minute; static uint8_t device_days_on = 0, device_days_off = 0, days_to_shutdown = 0; static int isprogram = 0, progshut = 0, prgups = 0; static int hourshut, minshut; static int host_year, host_month, host_day; static int host_week; static int host_hour, host_minute, host_second; /* buffers */ unsigned char received_packet[PACKET_SIZE]; /* Identification */ const char *model_name; unsigned int ups_model; bool_t input_220v, output_220v; /* logical */ bool_t detected = 0; bool_t line_unpowered, overheat; bool_t overload, critical_battery, inverter_working; static bool_t recharging; static bool_t packet_parsed = false; double input_voltage, input_current, input_frequency; double output_voltage, output_current, output_frequency; double input_low_limit, input_high_limit; int battery_extension; double battery_voltage, battery_charge; double temperature; double apparent_power, real_power, ups_load; int load_power_factor, nominal_power; /** * Convert standard days string to firmware format * This is needed because UPS sends binary date rotated * from current week day (first bit = current day) */ static char *convert_days(char *cop) { static char alt[8]; int ish, fim; /* FIXME? Are range-checks needed for values more than 6? wire noise etc? */ if (host_week == 6) ish = 0; else ish = 1 + host_week; fim = 7 - ish; /* rotate left only 7 bits */ if (fim > 0) { memcpy(alt, &cop[ish], (size_t)fim); } else { fatalx(EXIT_FAILURE, "%s: value out of range: %d (%d)", __func__, fim, ish); } if (ish > 0) memcpy(&alt[fim], cop, (size_t)ish); alt[7] = 0; /* string terminator */ return alt; } /** Convert bitstring (e.g. 1100101) to binary */ static uint8_t bitstring_to_binary(char *binStr) { uint8_t result = 0; unsigned int i; for (i = 0; i < 7; ++i) { char ch = binStr[i]; if (ch == '1' || ch == '0') result += ((ch - '0') << (6 - i)); else return 0; } return result; } /** * Revert firmware format to standard string binary days * This is needed because UPS sends binary date rotated * from current week day (first bit = current day) */ static uint8_t revert_days(unsigned char firmware_week) { char ordered_week[8]; int i; for (i = 0; i < (6 - host_week); ++i) ordered_week[i] = (firmware_week >> (5 - host_week - i)) & 0x01; for (i = 0; i < host_week + 1; ++i) ordered_week[i + (6 - host_week)] = (firmware_week >> (6 - i)) & 0x01; for (i = 0; i < 7; i++) ordered_week[i] += '0'; ordered_week[7] = 0; /* string terminator */ return bitstring_to_binary(ordered_week); } /** Parse time string from parameters and store their values */ static bool_t set_schedule_time(char *hour, bool_t off_time) { int string_hour, string_minute; if ((strlen(hour) != 5) || (sscanf(hour, "%d:%d", &string_hour, &string_minute) != 2)) return 0; if (off_time) { power_off_hour = string_hour; power_off_minute = string_minute; } else { power_on_hour = string_hour; power_on_minute = string_minute; } return 1; } /** Send immediate shutdown command to UPS */ static void send_shutdown(void) { unsigned int i; for (i = 0; i < 10; i++) ser_send_char(upsfd, CMD_SHUT); upslogx(LOG_NOTICE, "UPS shutdown command sent"); } /** Store clock updates and shutdown schedules to UPS */ static void save_ups_config(void) { unsigned int i; int checksum = 0; unsigned char configuration_packet[12]; /* Prepare configuration packet */ /* FIXME? Check for overflows with int => char truncations? */ configuration_packet[0] = (unsigned char)0xCF; configuration_packet[1] = (unsigned char)host_hour; configuration_packet[2] = (unsigned char)host_minute; configuration_packet[3] = (unsigned char)host_second; configuration_packet[4] = (unsigned char)power_on_hour; configuration_packet[5] = (unsigned char)power_on_minute; configuration_packet[6] = (unsigned char)power_off_hour; configuration_packet[7] = (unsigned char)power_off_minute; configuration_packet[8] = (unsigned char)(host_week << 5); configuration_packet[8] = (unsigned char)configuration_packet[8] | (unsigned char)host_day; configuration_packet[9] = (unsigned char)(host_month << 4); configuration_packet[9] = (unsigned char)configuration_packet[9] | (unsigned char)(host_year - BASE_YEAR); configuration_packet[10] = (unsigned char)device_days_off; /* MSB zero */ configuration_packet[10] = configuration_packet[10] & (~(0x80)); /* Calculate packet content checksum */ for (i = 0; i < 11; i++) { checksum += configuration_packet[i]; } /* FIXME? Does truncation to char have same effect as %256 ? */ configuration_packet[11] = (unsigned char)(checksum % 256); /* Send final packet and checksum to serial port */ for (i = 0; i < 12; i++) { ser_send_char(upsfd, configuration_packet[i]); } } /** Log shut-down schedule data stored in UPS */ static void print_info(void) { /* sunday, monday, tuesday, wednesday, thursday, friday, saturday */ char week_days[7] = { 0, 0, 0, 0, 0, 0, 0 }; unsigned int i; upslogx(LOG_NOTICE, UPS_DATE, device_year, device_month, device_day); upslogx(LOG_NOTICE, UPS_TIME, device_hour, device_minute, device_second); if (prgups > 0) { /* this is the string to binary standard */ for (i = 0; i < 7; i++) { week_days[i] = (days_to_shutdown >> (6 - i)) & 0x01; } if (prgups == 3) upslogx(LOG_NOTICE, PRG_ONOU); else upslogx(LOG_NOTICE, PRG_ONON); upslogx(LOG_NOTICE, TIME_ON, power_on_hour, power_on_minute); upslogx(LOG_NOTICE, TIME_OFF, power_off_hour, power_off_minute); upslogx(LOG_NOTICE, PRG_DAYS); upslogx(LOG_NOTICE, FMT_DAYS, week_days[0], week_days[1], week_days[2], week_days[3], week_days[4], week_days[5], week_days[6]); } else { upslogx(LOG_NOTICE, PRG_ONOF); } } /** Parses received packet with UPS readings and configuration. */ static void scan_received_pack(void) { /* UPS internal time */ device_year = (received_packet[19] & 0x0F) + BASE_YEAR; device_month = (received_packet[19] & 0xF0) >> 4; device_day = (received_packet[18] & 0x1F); device_hour = received_packet[11]; device_minute = received_packet[10]; device_second = received_packet[9]; /* UPS power cycle schedule if in programmed shutdown mode */ if (prgups == 3) { device_days_on = received_packet[17]; days_to_shutdown = revert_days(device_days_on); /* Automatic UPS power-off time */ power_off_hour = received_packet[15]; power_off_minute = received_packet[16]; /* Automatic UPS power-on time */ power_on_hour = received_packet[13]; power_on_minute = received_packet[14]; } /* These UPS have 110V- or 220V-output models */ if ((0x01 & received_packet[20]) == 0x01) { output_220v = 1; } /* UPS state flags */ critical_battery = (0x04 & received_packet[20]) == 0x04; inverter_working = (0x08 & received_packet[20]) == 0x08; overheat = (0x10 & received_packet[20]) == 0x10; line_unpowered = (0x20 & received_packet[20]) == 0x20; overload = (0x80 & received_packet[20]) == 0x80; recharging = (0x02 & received_packet[20]) == 0x02; if (line_unpowered) { recharging = false; } /* Check if input voltage is 110V or 220V */ if ((0x40 & received_packet[20]) == 0x40) { input_220v = 1; } else { input_220v = 0; } /* Internal battery temperature */ temperature = 0x7F & received_packet[4]; if (0x80 & received_packet[4]) { temperature -= 128; } /* Parse model-specific data (current and voltages). * Doing it here as these values are used for the next calculations. */ scan_received_pack_model_specific(); ups_load = (apparent_power / nominal_power) * 100.0; if (battery_charge > 100.0) { battery_charge = 100.0; } else if (battery_charge < 0.0) { battery_charge = 0.0; } output_frequency = 60; if (!inverter_working) { output_voltage = 0; output_frequency = 0; } if (!line_unpowered && inverter_working) output_frequency = input_frequency; if (apparent_power < 0) load_power_factor = 0; else { if (d_equal(apparent_power, 0)) load_power_factor = 100; else load_power_factor = ((real_power / apparent_power) * 100); if (load_power_factor > 100) { load_power_factor = 100; } } /* input 110V or 220v */ if (input_220v == 0) { input_low_limit = 75; input_high_limit = 150; } else { input_low_limit = 150; input_high_limit = 300; } } /** * Start processing of received packets * * Packet format: 25-bytes binary structure * Byte 1: Packet type/UPS model * Byte 2: Output voltage data * Byte 3: Input voltage data * Byte 4: Battery voltage data * Byte 5: UPS temperature data * Byte 6: Output current data * Byte 7: Electrical relay setup * Byte 8-9: Real power data * Byte 10: UPS clock - seconds * Byte 11: UPS clock - minutes * Byte 12: UPS clock - hours * Byte 13: Zero * Byte 14: UPS scheduler - power-on hour * Byte 15: UPS scheduler - power-on minute * Byte 16: UPS scheduler - power-off hour * Byte 17: UPS scheduler - power-off minute * Byte 18: UPS scheduler - weekdays * Byte 19: UPS clock - day of month * Byte 20: UPS clock - year (since 1998) (left 4 bits) and month (right 4 bits) * Byte 21: UPS flags (power status, battery status, overload, overheat, nominal input voltage, nominal output voltage) * Byte 22-23: Input frequency data * Byte 24: Packet checksum * Byte 25: Packet delimiter, always 0xFE */ static void comm_receive(const unsigned char *bufptr, size_t size) { size_t i; if (size == PACKET_SIZE) { int checksum = 0; upsdebug_hex(3, "comm_receive: bufptr", bufptr, size); /* Calculate packet checksum */ for (i = 0; i < PACKET_SIZE - 2; i++) { checksum += bufptr[i]; } checksum = checksum % 256; upsdebugx(4, "%s: calculated checksum = 0x%02x, bufptr[23] = 0x%02x", __func__, checksum, bufptr[23]); /* Only proceed if checksum matches and packet delimiter is found */ if (checksum == bufptr[23] && bufptr[24] == 254) { upsdebugx(4, "%s: valid packet received", __func__); memcpy(received_packet, bufptr, PACKET_SIZE); if ((received_packet[0] & 0xF0) == 0xA0 || (received_packet[0] & 0xF0) == 0xB0) { /* If UPS still not detected, compare with available lists */ if (!detected) { ups_model = received_packet[0]; detected = true; } if (!ups_model_defined()) { upslogx(LOG_DEBUG, M_UNKN); } scan_received_pack(); } } } } /** Refresh host time variables */ static void refresh_host_time(void) { const time_t epoch = time(NULL); struct tm now; localtime_r(&epoch, &now); host_year = now.tm_year + 1900; host_month = now.tm_mon + 1; host_day = now.tm_mday; host_week = now.tm_wday; host_hour = now.tm_hour; host_minute = now.tm_min; host_second = now.tm_sec; } /** Query shut-down schedule configuration */ static void setup_poweroff_schedule(void) { bool_t i1 = 0, i2 = 0; char *daysoff; refresh_host_time(); if (testvar("prgshut")) { prgups = atoi(getval("prgshut")); } if (prgups > 0 && prgups < 3) { if (testvar("daysweek")) { device_days_on = bitstring_to_binary(convert_days(getval("daysweek"))); } if (testvar("daysoff")) { daysoff = getval("daysoff"); days_to_shutdown = bitstring_to_binary(daysoff); device_days_off = bitstring_to_binary(convert_days(daysoff)); } if (testvar("houron")) { i1 = set_schedule_time(getval("houron"), 0); } if (testvar("houroff")) { i2 = set_schedule_time(getval("houroff"), 1); } if (i1 && i2 && (device_days_on > 0)) { isprogram = 1; /* If configured to shut-down UPS, push schedule to internal configuration */ if (prgups == 2) { save_ups_config(); } } else { if (i2 == 1 && device_days_off > 0) { isprogram = 1; device_days_on = device_days_off; } } } } /** Check shut-down schedule and sets system to shut down if needed */ static void check_shutdown_schedule(void) { bool_t is_shutdown_day = 0; if (isprogram || prgups == 3) { refresh_host_time(); is_shutdown_day = (days_to_shutdown >> (6 - host_week)) & 0x01; if (is_shutdown_day) { upslogx(LOG_NOTICE, TODAY_DD, hourshut, minshut); if (host_hour == hourshut && host_minute >= minshut) { upslogx(LOG_NOTICE, SHUT_NOW); progshut = 1; } } } } /** Resynchronizes packet boundaries */ static void resynchronize_packet(void) { unsigned char sync_received_byte = 0; unsigned short i; /* Flush serial port buffers */ ser_flush_io(upsfd); upsdebugx(3, "%s: Synchronizing packet boundaries...", __func__); /* * - Read until end-of-response character (0xFE): * read up to 3 packets in size before giving up * synchronizing with the device. */ for (i = 0; i < PACKET_SIZE * 3 && sync_received_byte != RESP_END; i++) { ser_get_char(upsfd, &sync_received_byte, 3, 0); } /* If no packet boundary was found, terminate communication */ if (sync_received_byte != RESP_END) { fatalx(EXIT_FAILURE, NO_SOLIS); } } /** Synchronize packet receiving and setup basic variables */ static void get_base_info(void) { unsigned char packet[PACKET_SIZE]; ssize_t tam; if (testvar("battext")) { battery_extension = atoi(getval("battext")); } setup_poweroff_schedule(); /* dummy read attempt to sync - throw it out */ upsdebugx(3, "%s: sending CMD_UPSCONT and ENDCHAR", __func__); ser_send(upsfd, "%c%c", CMD_UPSCONT, ENDCHAR); resynchronize_packet (); upsdebugx(4, "%s: requesting %d bytes from ser_get_buf_len()", __func__, PACKET_SIZE); tam = ser_get_buf_len(upsfd, packet, PACKET_SIZE, 3, 0); upsdebugx(2, "%s: received %" PRIiSIZE " bytes from ser_get_buf_len()", __func__, tam); if (tam > 0 && nut_debug_level >= 4) { upsdebug_hex(4, "received from ser_get_buf_len()", packet, (size_t)tam); } comm_receive(packet, (size_t)tam); if (!detected) { fatalx(EXIT_FAILURE, NO_SOLIS); } set_ups_model(); /* Setup power-off times */ if (prgups != 0) { if (prgups == 1) { /* If only this host is meant to be powered off, use proper time. */ hourshut = power_off_hour; minshut = power_off_minute; } else { /* If the UPS is to be powered off too, give * a 5-minute grace time to shutdown hosts */ if (power_off_minute < 5) { if (power_off_hour > 1) hourshut = power_off_hour - 1; else hourshut = 23; minshut = 60 - (5 - power_off_minute); } else { hourshut = power_off_hour; minshut = power_off_minute - 5; } } } /* manufacturer */ dstate_setinfo("ups.mfr", "%s", "APC"); dstate_setinfo("ups.model", "%s", model_name); dstate_setinfo("input.transfer.low", "%03.1f", input_low_limit); dstate_setinfo("input.transfer.high", "%03.1f", input_high_limit); dstate_addcmd("shutdown.return"); /* CMD_SHUTRET */ dstate_addcmd("shutdown.stayoff"); /* CMD_SHUT */ upslogx(LOG_NOTICE, "Detected %s on %s", dstate_getinfo("ups.model"), device_path); print_info(); } /** Retrieves new packet from serial connection and parses it */ static void get_updated_info(void) { unsigned char temp[256]; ssize_t tam; check_shutdown_schedule(); /* get update package */ temp[0] = 0; /* flush temp buffer */ upsdebugx(3, "%s: requesting %d bytes from ser_get_buf_len()", __func__, PACKET_SIZE); tam = ser_get_buf_len(upsfd, temp, PACKET_SIZE, 3, 0); upsdebugx(2, "%s: received %" PRIiSIZE " bytes from ser_get_buf_len()", __func__, tam); if (tam > 0 && nut_debug_level >= 4) upsdebug_hex(4, "received from ser_get_buf_len()", temp, (size_t)tam); packet_parsed = false; if (temp[24] == RESP_END) { /* Packet boundary found, process packet */ comm_receive(temp, (size_t)tam); packet_parsed = true; } else { /* Malformed packet received, possible boundary desynchronization. */ upsdebugx(3, "%s: Malformed packet received, trying to resynchronize...", __func__); resynchronize_packet (); } } static int instcmd(const char *cmdname, const char *extra) { /* Power-cycle UPS */ if (!strcasecmp(cmdname, "shutdown.return")) { ser_send_char(upsfd, CMD_SHUTRET); /* 0xDE */ return STAT_INSTCMD_HANDLED; } /* Power-off UPS */ if (!strcasecmp(cmdname, "shutdown.stayoff")) { ser_send_char(upsfd, CMD_SHUT); /* 0xDD */ return STAT_INSTCMD_HANDLED; } upslogx(LOG_NOTICE, "instcmd: unknown command [%s] [%s]", cmdname, extra); return STAT_INSTCMD_UNKNOWN; } void upsdrv_initinfo(void) { get_base_info(); upsh.instcmd = instcmd; } void upsdrv_updateinfo(void) { get_updated_info(); if (packet_parsed) { dstate_setinfo("battery.charge", "%03.1f", battery_charge); dstate_setinfo("battery.voltage", "%02.1f", battery_voltage); dstate_setinfo("input.frequency", "%2.1f", input_frequency); dstate_setinfo("input.voltage", "%03.1f", input_voltage); dstate_setinfo("output.current", "%03.1f", output_current); dstate_setinfo("output.power", "%03.1f", apparent_power); dstate_setinfo("output.powerfactor", "%0.2f", load_power_factor / 100.0); dstate_setinfo("output.realpower", "%03.1f", real_power); dstate_setinfo("output.voltage", "%03.1f", output_voltage); dstate_setinfo("ups.temperature", "%2.2f", temperature); dstate_setinfo("ups.load", "%03.1f", ups_load); status_init(); if (!line_unpowered) { status_set("OL"); /* On line */ } else { status_set("OB"); /* On battery */ } if (overload) { status_set("OVER"); /* Overload */ } if (overheat) { status_set("OVERHEAT"); /* Overheat */ } if (recharging) { status_set("CHRG"); /* Charging battery */ } if (critical_battery) { status_set("LB"); /* Critically low battery */ } if (progshut) { /* Software-based shutdown now */ if (prgups == 2) send_shutdown(); /* Send command to shutdown UPS in 4-5 minutes */ /* Workaround for triggering servers' power-off before UPS power-off */ status_set("LB"); } status_commit(); dstate_dataok(); } else { /* * If no packet was processed, report data as stale. * Most likely to be fixed on next received packet. */ dstate_datastale (); } } /*! @brief Power down the attached load immediately. * Basic idea: find out line status and send appropriate command. * - on battery: send normal shutdown, UPS will return by itself on utility * - on line: send shutdown+return, UPS will cycle and return soon. */ void upsdrv_shutdown(void) { if (!line_unpowered) { /* on line */ upslogx(LOG_NOTICE, "On line, sending power cycle command..."); ser_send_char(upsfd, CMD_SHUTRET); } else { upslogx(LOG_NOTICE, "On battery, sending power off command..."); ser_send_char(upsfd, CMD_SHUT); } } void upsdrv_help(void) { printf("\nAPC/Microsol options\n\n"); printf(" Battery extension (AH)\n"); printf(" battext = 80\n\n"); printf(" Scheduled UPS power on/off\n"); printf(" prgshut = 0 (default, no scheduled shutdown)\n"); printf(" prgshut = 1 (software-based shutdown schedule without UPS power-off)\n"); printf(" prgshut = 2 (software-based shutdown schedule with UPS power-off)\n"); printf(" prgshut = 3 (internal UPS shutdown schedule)\n\n"); printf(" Schedule configuration:\n"); printf(" daysweek = 1010101 (power on days)\n"); printf(" daysoff = 1010101 (power off days)\n"); printf(" where each digit is a day from sun...sat with 0 = off and 1 = on\n\n"); printf(" houron = hh:mm hh = hour 0-23 mm = minute 0-59 separated with :\n"); printf(" houroff = hh:mm hh = hour 0-23 mm = minute 0-59 separated with :\n"); printf(" where houron is power-on hour and houroff is shutdown and power-off hour\n\n"); printf(" Use daysweek and houron to programming and save UPS power on/off\n"); printf(" These are valid only if prgshut = 2 or 3\n"); } void upsdrv_makevartable(void) { addvar(VAR_VALUE, "battext", "Battery extension (0-80AH)"); addvar(VAR_VALUE, "prgshut", "Scheduled power-off mode (0-3)"); addvar(VAR_VALUE, "daysweek", "Days of week for UPS shutdown"); addvar(VAR_VALUE, "daysoff", "Days of week for driver-induced shutdown"); addvar(VAR_VALUE, "houron", "Power on hour (hh:mm)"); addvar(VAR_VALUE, "houroff", "Power off hour (hh:mm)"); } void upsdrv_initups(void) { upsfd = ser_open(device_path); ser_set_speed(upsfd, device_path, B9600); ser_set_dtr(upsfd, 1); ser_set_rts(upsfd, 0); } void upsdrv_cleanup(void) { ser_close(upsfd, device_path); } nut-2.8.1/drivers/powercom.h0000644000175000017500000000646114501607135012744 00000000000000/* * powercom.h - defines for the newpowercom.c driver * * Copyrights: * (C) 2002 Simon Rozman * (C) 1999 Peter Bieringer * * 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 2 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, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #ifndef NUT_POWERCOM_H_SEEN #define NUT_POWERCOM_H_SEEN 1 /* C-libary includes */ #include #include #ifndef WIN32 #include #endif #include /* nut includes */ #include "serial.h" #include "nut_stdint.h" #include "timehead.h" /* supported types */ struct type { const char *name; unsigned char num_of_bytes_from_ups; struct method_of_flow_control { const char *name; void (*setup_flow_control)(void); } flowControl; struct validation_byte { unsigned int index_of_byte, required_value; /* An example might explain the intention better then prose. * Suppose we want to validate the data with: * powercom_raw_data[5] == 0x80 * then we will set index_of_byte to 5U and required_value to * 0x80U: { 5U, 0x80U }. */ } validation[3]; /* The validation array is of length 3 because 3 is longest * validation sequence for any type. */ /* Some UPSs must have a minutes and a seconds arguments for * the COUNTER commands while others are known to work with the * seconds argument alone. */ struct delay_for_power_kill { unsigned char delay[2]; /* { minutes, seconds } */ unsigned char minutesShouldBeUsed; /* 'n' in case the minutes value, which is delay[0], should * be skipped and not sent to the UPS. */ } shutdown_arguments; /* parameters to calculate input and output freq., one pair used for * both input and output functions: * The pair [0],[1] defines parameters for 1/(A*x+B) to calculate freq. * from raw data 'x'. */ float freq[2]; /* parameters to calculate load %, two pairs for each type: * First pair [0],[1] defines the parameters for A*x+B to calculate load * from raw data when offline and the second pair [2],[3] is used when * online */ float loadpct[4]; /* parameters to calculate battery %, five parameters for each type: * First three params [0],[1],[2] defines the parameters for A*x+B*y+C to calculate * battery % (x is raw data, y is load %) when offline. * Fourth and fifth parameters [3],[4] are used to calculate D*x+E when online. */ float battpct[5]; /* parameters to calculate utility and output voltage, two pairs for * each type: * First pair [0],[1] defines the parameters for A*x+B to calculate utility * from raw data when line voltage is >=220 and the second pair [2],[3] * is used otherwise. */ float voltage[4]; }; #endif /* NUT_POWERCOM_H_SEEN */ nut-2.8.1/drivers/pijuice.c0000644000175000017500000005454014502253356012540 00000000000000/* pijuice.c Driver for the PiJuice HAT (www.pijuice.com), addressed via i2c. Copyright (C) 2019 Andrew Anderson 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 2 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, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "main.h" #include #include "nut_stdint.h" /* * Linux I2C userland is a bit of a mess until distros refresh to * the i2c-tools 4.x release that profides i2c/smbus.h for userspace * instead of (re)using linux/i2c-dev.h, which conflicts with a * kernel header of the same name. * * See: * https://i2c.wiki.kernel.org/index.php/Plans_for_I2C_Tools_4 */ #if HAVE_LINUX_SMBUS_H # include #endif #if HAVE_LINUX_I2C_DEV_H # include /* for I2C_SLAVE */ # if !HAVE_LINUX_SMBUS_H # ifndef I2C_FUNC_I2C # include # endif # endif #endif /* * i2c-tools pre-4.0 has a userspace header with a name that conflicts * with a kernel header, so it may be ignored/removed by distributions * when packaging i2c-tools. * * This will cause the driver to be un-buildable on certain * configurations, so include the necessary bits here to handle this * situation. */ #if WITH_LINUX_I2C #if !HAVE_DECL_I2C_SMBUS_ACCESS static inline __s32 i2c_smbus_access(int file, char read_write, __u8 command, int size, union i2c_smbus_data *data) { struct i2c_smbus_ioctl_data args; __s32 err; args.read_write = read_write; args.command = command; args.size = size; args.data = data; err = ioctl(file, I2C_SMBUS, &args); if (err == -1) err = -errno; return err; } #endif #if !HAVE_DECL_I2C_SMBUS_READ_BYTE_DATA static inline __s32 i2c_smbus_read_byte_data(int file, __u8 command) { union i2c_smbus_data data; int err; if ((err = i2c_smbus_access(file, I2C_SMBUS_READ, command, I2C_SMBUS_BYTE_DATA, &data)) < 0) return err; else return 0x0FF & data.byte; } #endif #if !HAVE_DECL_I2C_SMBUS_WRITE_BYTE_DATA static inline __s32 i2c_smbus_write_byte_data(int file, __u8 command, __u8 value) { union i2c_smbus_data data; int err; data.byte = value; if ((err = i2c_smbus_access(file, I2C_SMBUS_WRITE, command, I2C_SMBUS_BYTE_DATA, &data)) < 0) return err; else return 0x0FF & data.byte; } #endif #if !HAVE_DECL_I2C_SMBUS_READ_WORD_DATA static inline __s32 i2c_smbus_read_word_data(int file, __u8 command) { union i2c_smbus_data data; int err; if ((err = i2c_smbus_access(file, I2C_SMBUS_READ, command, I2C_SMBUS_WORD_DATA, &data)) < 0) return err; else return 0x0FFFF & data.word; } #endif #if !HAVE_DECL_I2C_SMBUS_WRITE_WORD_DATA static inline __s32 i2c_smbus_write_word_data(int file, __u8 command, __u16 value) { union i2c_smbus_data data; int err; data.word = value; if ((err = i2c_smbus_access(file, I2C_SMBUS_WRITE, command, I2C_SMBUS_WORD_DATA, &data)) < 0) return err; else return 0x0FFFF & data.word; } #endif #if !HAVE_DECL_I2C_SMBUS_READ_BLOCK_DATA static inline __u8* i2c_smbus_read_i2c_block_data(int file, __u8 command, __u8 length, __u8 *values) { union i2c_smbus_data data; int err; if ( length > I2C_SMBUS_BLOCK_MAX) { length = I2C_SMBUS_BLOCK_MAX; } data.block[0] = length; memcpy(data.block + 1, values, length); if ((err = i2c_smbus_access(file, I2C_SMBUS_READ, command, I2C_SMBUS_I2C_BLOCK_DATA, &data)) < 0) return NULL; else memcpy(values, &data.block[1], data.block[0]); return values; } #endif #endif // if WITH_LINUX_I2C #define STATUS_CMD 0x40 #define CHARGE_LEVEL_CMD 0x41 #define CHARGE_LEVEL_HI_RES_CMD 0x42 #define FAULT_EVENT_CMD 0x44 #define BUTTON_EVENT_CMD 0x45 #define BATTERY_TEMPERATURE_CMD 0x47 #define BATTERY_VOLTAGE_CMD 0x49 #define BATTERY_CURRENT_CMD 0x4b #define IO_VOLTAGE_CMD 0x4d #define IO_CURRENT_CMD 0x4f #define CHARGING_CONFIG_CMD 0x51 #define BATTERY_PROFILE_ID_CMD 0x52 #define BATTERY_PROFILE_CMD 0x53 #define BATTERY_EXT_PROFILE_CMD 0x54 #define BATTERY_TEMP_SENSE_CONFIG_CMD 0x5D #define POWER_INPUTS_CONFIG_CMD 0x5E #define RUN_PIN_CONFIG_CMD 0x5F #define POWER_REGULATOR_CONFIG_CMD 0x60 #define WATCHDOG_ACTIVATION_CMD 0x61 #define POWER_OFF_CMD 0x62 #define WAKEUP_ON_CHARGE_CMD 0x63 #define SYSTEM_POWER_SWITCH_CTRL_CMD 0x64 #define LED_STATE_CMD 0x66 #define LED_BLINK_CMD 0x68 #define LED_CONFIGURATION_CMD 0x6A #define BUTTON_CONFIGURATION_CMD 0x6E #define IO1_CONFIGURATION_CMD 0x72 #define IO1_PIN_ACCESS_CMD 0x75 #define IO2_CONFIGURATION_CMD 0x77 #define IO2_PIN_ACCESS_CMD 0x7A #define I2C_ADDRESS_CMD 0x7C #define ID_EEPROM_WRITE_PROTECT_CTRL_CMD 0x7E #define ID_EEPROM_ADDRESS_CMD 0x7F #define RTC_TIME_CMD 0xB0 #define RTC_ALARM_CMD 0xB9 #define RTC_CTRL_STATUS_CMD 0xC2 #define RESET_TO_DEFAULT_CMD 0xF0 #define FIRMWARE_VERSION_CMD 0xFD #define BATT_NORMAL 0 #define BATT_CHARGING_FROM_IN 1 #define BATT_CHARGING_FROM_5V 2 #define BATT_NOT_PRESENT 3 #define POWER_NOT_PRESENT 0 #define POWER_BAD 1 #define POWER_WEAK 2 #define POWER_PRESENT 3 #define LOW_BATTERY_THRESHOLD 25.0 #define HIGH_BATTERY_THRESHOLD 75.0 #define NOMINAL_BATTERY_VOLTAGE 4.18 #define DRIVER_NAME "PiJuice UPS driver" #define DRIVER_VERSION "0.11" static uint8_t i2c_address = 0x14; static uint8_t shutdown_delay = 30; /* * Flags used to indicate a change in power status */ static uint8_t usb_power = 0; static uint8_t gpio_power = 0; static uint8_t battery_power = 0; /* * Smooth out i2c read errors by holding the most recent * battery charge level reading */ static float battery_charge_level = 0; /* driver description structure */ upsdrv_info_t upsdrv_info = { DRIVER_NAME, DRIVER_VERSION, "Andrew Anderson ", DRV_EXPERIMENTAL, { NULL } }; /* The macros below all write into a "data" variable defined by the routine * scope which calls them, with respective type of uint8_t for "byte" and * uint16_t for "word" macros. Native i2c functions operate with __s32 type * (currently, signed 32-bit ints?) with negative values for error returns. * Note: some manpages refer to "s32" while headers on my and CI systems use * a "__s32" type. Maybe this is something to determine in configure script? * Code below was fixed to convert the valid values and avoid compiler * warnings about comparing whether unsigned ints happened to be negative. */ #define I2C_READ_BYTE(fd, cmd, label) \ { \ __s32 sData; \ if ((sData = i2c_smbus_read_byte_data(upsfd, cmd)) < 0 ) { \ upsdebugx(2, "Failure reading the i2c bus [%s]", label); \ return; \ } ; \ data = (uint8_t) sData; \ } #define I2C_WRITE_BYTE(fd, cmd, value, label) \ { \ if ( i2c_smbus_write_byte_data(upsfd, cmd, value) < 0 ) { \ upsdebugx(2, "Failure writing to the i2c bus [%s]", label); \ return; \ } ; \ } #define I2C_READ_WORD(fd, cmd, label) \ { \ __s32 sData; \ if ((sData = i2c_smbus_read_word_data(upsfd, cmd)) < 0 ) { \ upsdebugx(2, "Failure reading the i2c bus [%s]", label); \ return; \ } ; \ data = (uint16_t) sData; \ } #define I2C_READ_BLOCK(fd, cmd, size, block, label) \ if ((i2c_smbus_read_i2c_block_data(upsfd, cmd, size, block)) < 0 ) { \ upsdebugx(2, "Failure reading the i2c bus [%s]", label); \ return; \ } static inline int open_i2c_bus(char *path, uint8_t addr) { int file; if ((file = open(path, O_RDWR)) < 0) { fatal_with_errno(EXIT_FAILURE, "Failed to open the i2c bus on %s", path); } if (ioctl(file, I2C_SLAVE, addr) < 0) { fatal_with_errno(EXIT_FAILURE, "Failed to acquire the i2c bus and/or talk to the UPS"); } return file; } static void get_charge_level_hi_res(void) { uint8_t cmd = CHARGE_LEVEL_HI_RES_CMD; uint16_t data; upsdebugx( 3, __func__ ); I2C_READ_WORD( upsfd, cmd, __func__ ) /* * Use an external variable to allow for missed i2c bus * reads; the charge level data may be slightly stale, * but no other options seem reasonable: * * 1) store 0 * Leads to a false report of a depleted battery, possibly * triggering an immediate shutdown if on battery power only * 2) store -1 * Adds a lot of logic to "skip" over negative charge levels, * which effectively accomplishes the same thing * 3) retry the read immediately * Could tie up the i2c bus and make matters exponentially worse */ battery_charge_level = data / 10.0; upsdebugx( 1, "Battery Charge Level: %02.1f%%", battery_charge_level ); dstate_setinfo( "battery.charge", "%02.1f", battery_charge_level ); } static void get_status(void) { uint8_t cmd = STATUS_CMD, data, batteryStatus, powerInput, powerInput5vIo; char status_buf[ST_MAX_VALUE_LEN]; upsdebugx( 3, __func__ ); memset( status_buf, 0, ST_MAX_VALUE_LEN ); I2C_READ_BYTE( upsfd, cmd, __func__ ) batteryStatus = data >> 2 & 0x03; switch( batteryStatus ) { case BATT_NORMAL: upsdebugx( 1, "Battery Status: Normal" ); dstate_setinfo( "battery.packs", "%d", 1 ); dstate_setinfo( "battery.packs.bad", "%d", 0 ); break; case BATT_CHARGING_FROM_IN: upsdebugx( 1, "Battery Status: Charging from IN" ); dstate_setinfo( "battery.packs", "%d", 1 ); dstate_setinfo( "battery.packs.bad", "%d", 0 ); break; case BATT_CHARGING_FROM_5V: upsdebugx( 1, "Battery Status: Charging from 5V" ); dstate_setinfo( "battery.packs", "%d", 1 ); dstate_setinfo( "battery.packs.bad", "%d", 0 ); break; case BATT_NOT_PRESENT: upsdebugx( 1, "Battery Status: Not Present" ); dstate_setinfo( "battery.packs", "%d", 0 ); dstate_setinfo( "battery.packs.bad", "%d", 1 ); break; default: upsdebugx( 1, "battery.status: UNKNOWN" ); } powerInput = data >> 4 & 0x03; switch( powerInput ) { case POWER_NOT_PRESENT: upsdebugx( 1, "Power Input: Not Present" ); break; case POWER_BAD: upsdebugx( 1, "Power Input: Bad" ); break; case POWER_WEAK: upsdebugx( 1, "Power Input: Weak" ); break; case POWER_PRESENT: upsdebugx( 1, "Power Input: Present" ); break; default: upsdebugx( 1, "Power Input: UNKNOWN" ); } powerInput5vIo = data >> 6 & 0x03; switch( powerInput5vIo ) { case POWER_NOT_PRESENT : upsdebugx(1, "Power Input 5v: Not Present"); break; case POWER_BAD: upsdebugx(1, "Power Input 5v: Bad"); break; case POWER_WEAK: upsdebugx(1, "Power Input 5v: Weak"); break; case POWER_PRESENT: upsdebugx(1, "Power Input 5v: Present"); break; default: upsdebugx(1, "Power Input 5v: UNKNOWN"); } if ( batteryStatus == BATT_NORMAL || batteryStatus == BATT_CHARGING_FROM_IN || batteryStatus == BATT_CHARGING_FROM_5V ) { get_charge_level_hi_res(); if ( battery_charge_level <= LOW_BATTERY_THRESHOLD ) { upsdebugx( 1, "Battery Charge Status: LOW" ); snprintfcat( status_buf, ST_MAX_VALUE_LEN, "LB " ); } else if ( battery_charge_level > HIGH_BATTERY_THRESHOLD ) { upsdebugx( 1, "Battery Charge Status: HIGH" ); snprintfcat( status_buf, ST_MAX_VALUE_LEN, "HB " ); } } else if ( batteryStatus == BATT_NOT_PRESENT ) { snprintfcat( status_buf, ST_MAX_VALUE_LEN, "RB " ); } if ( batteryStatus <= BATT_NOT_PRESENT && powerInput <= POWER_PRESENT && powerInput5vIo <= POWER_PRESENT ) { if ( powerInput == POWER_NOT_PRESENT && ( powerInput5vIo != POWER_NOT_PRESENT )) { if ( usb_power != 1 || gpio_power != 0 ) { upslogx( LOG_NOTICE, "On USB power" ); } usb_power = 1; gpio_power = 0; battery_power = 0; upsdebugx( 1, "On USB power [%d:%d:%d]", usb_power, gpio_power, battery_power ); snprintfcat( status_buf, sizeof(status_buf), "OL" ); if ( batteryStatus == BATT_CHARGING_FROM_5V ) { snprintfcat( status_buf, sizeof( status_buf ), " CHRG" ); upsdebugx( 1, "Battery Charger Status: charging" ); dstate_setinfo( "battery.charger.status", "%s", "charging" ); } else if ( batteryStatus == BATT_NORMAL ) { upsdebugx( 1, "Battery Charger Status: resting" ); dstate_setinfo( "battery.charger.status", "%s", "resting" ); } status_set( status_buf ); } else if ( powerInput5vIo == POWER_NOT_PRESENT && ( powerInput != POWER_NOT_PRESENT && powerInput <= POWER_PRESENT )) { if ( gpio_power != 1 || usb_power != 0 ) { upslogx( LOG_NOTICE, "On 5V_GPIO power" ); } usb_power = 0; gpio_power = 1; battery_power = 0; upsdebugx( 1, "On 5V_GPIO power [%d:%d:%d]", usb_power, gpio_power, battery_power ); snprintfcat( status_buf, sizeof(status_buf), "OL" ); if ( batteryStatus == BATT_CHARGING_FROM_IN ) { snprintfcat( status_buf, sizeof(status_buf), " CHRG" ); status_set( status_buf ); upsdebugx( 1, "Battery Charger Status: charging" ); dstate_setinfo( "battery.charger.status", "%s", "charging" ); } else if ( batteryStatus == BATT_NORMAL ) { status_set( status_buf ); upsdebugx( 1, "Battery Charger Status: resting" ); dstate_setinfo( "battery.charger.status", "%s", "resting" ); } } else if ( ( powerInput != POWER_NOT_PRESENT && powerInput <= POWER_PRESENT ) && ( powerInput5vIo != POWER_NOT_PRESENT && powerInput5vIo <= POWER_PRESENT )) { if ( usb_power != 1 || gpio_power != 1 ) { upslogx( LOG_NOTICE, "On USB and 5V_GPIO power" ); } usb_power = 1; gpio_power = 1; battery_power = 0; upsdebugx( 1, "On USB and 5V_GPIO power [%d:%d:%d]", usb_power, gpio_power, battery_power ); snprintfcat( status_buf, sizeof( status_buf ), "OL" ); if ( batteryStatus == BATT_CHARGING_FROM_IN ) { snprintfcat( status_buf, sizeof(status_buf), " CHRG"); status_set( status_buf ); upsdebugx( 1, "Battery Charger Status: charging" ); dstate_setinfo("battery.charger.status", "%s", "charging"); } else if ( batteryStatus == BATT_NORMAL ) { status_set( status_buf ); upsdebugx( 1, "Battery Charger Status: resting" ); dstate_setinfo( "battery.charger.status", "%s", "resting" ); } } else if ( powerInput == POWER_NOT_PRESENT && powerInput5vIo == POWER_NOT_PRESENT ) { if ( usb_power != 0 || gpio_power != 0 ) { upslogx( LOG_NOTICE, "On Battery power" ); } usb_power = 0; gpio_power = 0; battery_power = 1; upsdebugx( 1, "On Battery power [%d:%d:%d]", usb_power, gpio_power, battery_power ); snprintfcat( status_buf, sizeof(status_buf), "OB DISCHRG" ); status_set( status_buf ); } } } static void get_battery_temperature(void) { uint8_t cmd = BATTERY_TEMPERATURE_CMD; int16_t data; upsdebugx( 3, __func__ ); I2C_READ_WORD( upsfd, cmd, __func__ ) upsdebugx( 1, "Battery Temperature: %d°C", data ); dstate_setinfo( "battery.temperature", "%d", data ); } static void get_battery_voltage(void) { uint8_t cmd = BATTERY_VOLTAGE_CMD; int16_t data; upsdebugx( 3, __func__ ); I2C_READ_WORD( upsfd, cmd, __func__ ) upsdebugx( 1, "Battery Voltage: %0.3fV", data / 1000.0 ); dstate_setinfo( "battery.voltage", "%0.3f", data / 1000.0 ); } static void get_battery_current(void) { uint8_t cmd = BATTERY_CURRENT_CMD; int16_t data; upsdebugx( 3, __func__ ); /* * The reported current can actually be negative, so we cannot * check for I2C failure by looking for negative values */ data = i2c_smbus_read_word_data(upsfd, cmd); if ( data & ( 1 << 15 ) ) { data = data - ( 1 << 16 ); } upsdebugx( 1, "Battery Current: %0.3fA", data / 1000.0 ); dstate_setinfo( "battery.current", "%0.3f", data / 1000.0 ); } static void get_io_voltage(void) { uint8_t cmd = IO_VOLTAGE_CMD; int16_t data; upsdebugx( 3, __func__ ); I2C_READ_WORD( upsfd, cmd, __func__ ) upsdebugx( 1, "Input Voltage: %.3fV", data / 1000.0 ); dstate_setinfo( "input.voltage", "%.3f", data / 1000.0 ); } static void get_io_current(void) { uint8_t cmd = IO_CURRENT_CMD; int16_t data; upsdebugx( 3, __func__ ); /* * The reported current can actually be negative, so we cannot * check for I2C failure by looking for negative values */ data = i2c_smbus_read_word_data(upsfd, cmd); if ( data & ( 1 << 15 ) ) { data = data - ( 1 << 16 ); } upsdebugx( 1, "Input Current: %.3fA", data / 1000.0 ); dstate_setinfo( "input.current", "%.3f", data / 1000.0 ); } static void get_firmware_version(void) { uint8_t cmd = FIRMWARE_VERSION_CMD; uint16_t data; uint8_t major, minor; upsdebugx( 3, __func__ ); I2C_READ_WORD( upsfd, cmd, __func__ ) major = data >> 4; minor = ( data << 4 & 0xf0 ) >> 4; if (( major != 1 ) || ( minor > 3 )) { upslogx( LOG_WARNING, "Unknown Firmware release: %d.%d", major, minor ); } upsdebugx( 1, "UPS Firmware Version: %d.%d", major, minor ); dstate_setinfo( "ups.firmware", "%d.%d", major, minor ); } static void get_battery_profile(void) { uint8_t cmd = BATTERY_PROFILE_CMD; __u8 block[I2C_SMBUS_BLOCK_MAX]; upsdebugx( 3, __func__ ); I2C_READ_BLOCK( upsfd, cmd, 14, block, __func__ ) upsdebugx( 1, "Battery Capacity: %0.3fAh", ( block[1] << 8 | block[0] ) / 1000.0 ); dstate_setinfo( "battery.capacity", "%0.3f", ( block[1] << 8 | block[0] ) / 1000.0 ); } static void get_battery_profile_ext(void) { uint8_t cmd = BATTERY_EXT_PROFILE_CMD; __u8 block[I2C_SMBUS_BLOCK_MAX]; upsdebugx( 3, __func__ ); I2C_READ_BLOCK( upsfd, cmd, 17, block, __func__ ) switch( block[0] & 0xFF00 ) { case 0: upsdebugx( 1, "Battery Chemistry: LiPO" ); dstate_setinfo( "battery.type", "%s", "LiPO" ); break; case 1: upsdebugx( 1, "Battery Chemistry: LiFePO4" ); dstate_setinfo( "battery.type", "%s", "LiFePO4" ); break; default: upsdebugx( 1, "Battery Chemistry: UNKNOWN" ); dstate_setinfo( "battery.type", "%s", "UNKNOWN" ); } } static void get_power_off(void) { uint8_t cmd = POWER_OFF_CMD; uint8_t data; upsdebugx( 3, __func__ ); I2C_READ_BYTE( upsfd, cmd, __func__ ) if ( data == 255 ) { upsdebugx( 1, "Power Off: DISABLED" ); } else if ( data <= 250 ) { upsdebugx( 1, "Power Off: %d Seconds", data ); } } static void set_power_off(void) { uint8_t cmd = POWER_OFF_CMD; upsdebugx( 3, __func__ ); /* * Acceptable values for shutdown_delay are 1-250, * use 0/255 to clear a scheduled power off command */ if ( shutdown_delay > 250 ) { upslogx( LOG_WARNING, "shutdown delay of >250 seconds requested, shortening to 250 seconds" ); shutdown_delay = 250; } if ( shutdown_delay == 0 ) { upslogx( LOG_WARNING, "shutdown delay of 0 seconds requested, using 1 second instead" ); shutdown_delay = 1; } I2C_WRITE_BYTE( upsfd, cmd, shutdown_delay, __func__ ) } static void get_time(void) { uint8_t cmd = RTC_TIME_CMD; __u8 block[I2C_SMBUS_BLOCK_MAX]; uint8_t second, minute, hour, day, month, subsecond; uint16_t year; upsdebugx( 3, __func__ ); I2C_READ_BLOCK( upsfd, cmd, 9, block, __func__ ) second = (( (block[0] >> 4 ) & 0x07) * 10 ) + ( block[0] & 0x0F ); minute = (( (block[1] >> 4 ) & 0x07) * 10 ) + ( block[1] & 0x0F ); hour = (( (block[2] >> 4 ) & 0x03) * 10 ) + ( block[2] & 0x0F ); day = (( (block[4] >> 4 ) & 0x03) * 10 ) + ( block[4] & 0x0F ); month = (( (block[5] >> 4 ) & 0x01) * 10 ) + ( block[5] & 0x0F ); year = (( (block[6] >> 4 ) & 0x0F) * 10 ) + ( block[6] & 0x0F ) + 2000; subsecond = block[7] * 100 / 256; upsdebugx( 1, "UPS Time: %02d:%02d:%02d.%02d", hour, minute, second, subsecond ); dstate_setinfo( "ups.time", "%02d:%02d:%02d.%02d", hour, minute, second, subsecond ); upsdebugx( 1, "UPS Date: %04d-%02d-%02d", year, month, day ); dstate_setinfo( "ups.date", "%04d-%02d-%02d", year, month, day ); } static void get_i2c_address(void) { uint8_t cmd = I2C_ADDRESS_CMD; uint8_t data; upsdebugx( 3, __func__ ); I2C_READ_BYTE( upsfd, cmd, __func__ ) upsdebugx( 1, "I2C Address: 0x%0x", data ); if ( data == i2c_address ) { upsdebugx( 1, "Found device '0x%0x' on port '%s'", (unsigned int) i2c_address, device_path ); } else { fatalx( EXIT_FAILURE, "Could not find PiJuice HAT at I2C address 0x%0x", i2c_address ); } } void upsdrv_initinfo(void) { dstate_setinfo( "ups.mfr", "%s", "PiJuice" ); dstate_setinfo( "ups.type", "%s", "HAT" ); /* note: for a transition period, these data are redundant */ dstate_setinfo( "device.mfr", "%s", "PiJuice" ); dstate_setinfo( "device.type", "%s", "HAT" ); upsdebugx( 1, "Low Battery Threshold: %0.0f%%", LOW_BATTERY_THRESHOLD ); dstate_setinfo( "battery.charge.low", "%0.0f", LOW_BATTERY_THRESHOLD ); upsdebugx( 1, "Nominal Battery Voltage: %0.3fV", NOMINAL_BATTERY_VOLTAGE ); dstate_setinfo( "battery.voltage.nominal", "%0.3f", NOMINAL_BATTERY_VOLTAGE ); get_i2c_address(); get_battery_profile(); get_battery_profile_ext(); } void upsdrv_updateinfo(void) { status_init(); get_status(); get_battery_temperature(); get_battery_voltage(); get_battery_current(); get_io_voltage(); get_io_current(); get_time(); get_power_off(); status_commit(); dstate_dataok(); } void upsdrv_shutdown(void) { set_power_off(); } void upsdrv_help(void) { printf("\nThe default I2C address is 20 [0x14]\n"); printf("\n"); } void upsdrv_makevartable(void) { addvar(VAR_VALUE, "i2c_address", "Override i2c address setting"); } void upsdrv_initups(void) { upsfd = open_i2c_bus( device_path, i2c_address ); /* probe ups type */ get_firmware_version(); /* get variables and flags from the command line */ if (getval("i2c_address")) i2c_address = atoi(getval("i2c_address")); } void upsdrv_cleanup(void) { close(upsfd); } nut-2.8.1/drivers/raritan-pdu-mib.c0000644000175000017500000001461214500336654014100 00000000000000/* raritan-mib.c - data to monitor Raritan PDUs (Basic and Complex) * * Copyright (C) 2008-2019 * Arnaud Quette * * Sponsored by Eaton * and MGE Office Protection Systems * * 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 2 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, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #include "raritan-pdu-mib.h" #define RARITAN_MIB_VERSION "0.8" /* Raritan MIB * this one uses the same MIB as Eaton Revelation, * but with a different entry point */ #define RARITAN_BASE_OID ".1.3.6.1.4.1.13742" #define RARITAN_SYSOID RARITAN_BASE_OID #define RARITAN_OID_MODEL_NAME ".1.3.6.1.4.1.13742.1.1.12.0" #define DO_OFF "0" #define DO_ON "1" #define DO_CYCLE "2" static info_lkp_t raritan_pdu_outlet_status_info[] = { { -1, "error", NULL, NULL }, { 0, "off", NULL, NULL }, { 1, "on", NULL, NULL }, { 2, "cycling", NULL, NULL }, /* transitional status */ { 0, NULL, NULL, NULL } }; /* Snmp2NUT lookup table for Raritan MIB */ static snmp_info_t raritan_mib[] = { /* standard MIB items */ { "device.description", ST_FLAG_STRING | ST_FLAG_RW, SU_INFOSIZE, ".1.3.6.1.2.1.1.1.0", NULL, SU_FLAG_OK, NULL }, { "device.contact", ST_FLAG_STRING | ST_FLAG_RW, SU_INFOSIZE, ".1.3.6.1.2.1.1.4.0", NULL, SU_FLAG_OK, NULL }, { "device.location", ST_FLAG_STRING | ST_FLAG_RW, SU_INFOSIZE, ".1.3.6.1.2.1.1.6.0", NULL, SU_FLAG_OK, NULL }, /* Device page */ { "device.mfr", ST_FLAG_STRING, SU_INFOSIZE, NULL, "Raritan", SU_FLAG_STATIC | SU_FLAG_ABSENT | SU_FLAG_OK, NULL }, { "device.model", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.13742.1.1.12.0", "Generic SNMP PDU", SU_FLAG_STATIC | SU_FLAG_OK, NULL }, { "device.serial", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.13742.1.1.2.0", "", SU_FLAG_STATIC | SU_FLAG_OK, NULL }, { "device.type", ST_FLAG_STRING, SU_INFOSIZE, NULL, "pdu", SU_FLAG_STATIC | SU_FLAG_ABSENT | SU_FLAG_OK, NULL }, { "device.macaddr", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.13742.1.1.6.0", "", SU_FLAG_STATIC | SU_FLAG_OK, NULL }, /* UPS page */ { "ups.mfr", ST_FLAG_STRING, SU_INFOSIZE, NULL, "Raritan", SU_FLAG_STATIC | SU_FLAG_ABSENT | SU_FLAG_OK, NULL }, { "ups.model", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.13742.1.1.12.0", "Generic SNMP PDU", SU_FLAG_STATIC | SU_FLAG_OK, NULL }, { "ups.id", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.13742.1.1.13.0", "unknown", SU_FLAG_STATIC | SU_FLAG_OK, NULL }, { "ups.serial", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.13742.1.1.2.0", "", SU_FLAG_STATIC | SU_FLAG_OK, NULL }, { "ups.firmware", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.13742.1.1.1.0", "", SU_FLAG_STATIC | SU_FLAG_OK, NULL }, { "ups.type", ST_FLAG_STRING, SU_INFOSIZE, NULL, "pdu", SU_FLAG_STATIC | SU_FLAG_ABSENT | SU_FLAG_OK, NULL }, { "ups.temperature", 0, 1, ".1.3.6.1.4.1.13742.1.3.1.5.0", NULL, 0, NULL }, /* Outlet page */ { "outlet.id", 0, 1, NULL, "0", SU_FLAG_STATIC | SU_FLAG_ABSENT | SU_FLAG_OK, NULL }, { "outlet.desc", ST_FLAG_RW | ST_FLAG_STRING, 20, NULL, "All outlets", SU_FLAG_STATIC | SU_FLAG_ABSENT | SU_FLAG_OK, NULL }, { "outlet.count", 0, 1, ".1.3.6.1.4.1.13742.1.2.1.0", "0", 0, NULL }, { "outlet.current", 0, 0.001, ".1.3.6.1.4.1.13742.1.3.1.1" ".0", NULL, 0, NULL }, { "outlet.voltage", 0, 0.001, ".1.3.6.1.4.1.13742.1.3.1.2" ".0", NULL, 0, NULL }, { "outlet.realpower", 0, 1.0, ".1.3.6.1.4.1.13742.1.3.1.3" ".0", NULL, 0, NULL }, { "outlet.power", 0, 1.0, ".1.3.6.1.4.1.13742.1.3.1.4" ".0", NULL, 0, NULL }, /* outlet template definition * Caution: the index of the data start at 0, while the name is +1 * ie outlet.1 => .0 */ { "outlet.%i.switchable", 0, 1, ".1.3.6.1.4.1.13742.1.2.2.1.1.%i", "yes", SU_FLAG_STATIC | SU_OUTLET, NULL }, { "outlet.%i.id", 0, 1, NULL, "%i", SU_FLAG_STATIC | SU_FLAG_ABSENT | SU_FLAG_OK | SU_OUTLET, NULL }, { "outlet.%i.desc", ST_FLAG_RW | ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.13742.1.2.2.1.2.%i", NULL, SU_OUTLET, NULL }, { "outlet.%i.status", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.13742.1.2.2.1.3.%i", NULL, SU_FLAG_OK | SU_OUTLET, &raritan_pdu_outlet_status_info[0] }, { "outlet.%i.current", 0, 0.001, ".1.3.6.1.4.1.13742.1.2.2.1.4.%i", NULL, SU_OUTLET, NULL }, { "outlet.%i.current.maximum", 0, 0.001, ".1.3.6.1.4.1.13742.1.2.2.1.5.%i", NULL, SU_OUTLET, NULL }, { "outlet.%i.realpower", 0, 1.0, ".1.3.6.1.4.1.13742.1.2.2.1.7.%i", NULL, SU_OUTLET, NULL }, { "outlet.%i.voltage", 0, 1.0, ".1.3.6.1.4.1.13742.1.2.2.1.6.%i", NULL, SU_OUTLET, NULL }, { "outlet.%i.powerfactor", 0, 0.01, ".1.3.6.1.4.1.13742.1.2.2.1.9.%i", NULL, SU_OUTLET, NULL }, { "outlet.%i.power", 0, 1.0, ".1.3.6.1.4.1.13742.1.2.2.1.8.%i", NULL, SU_OUTLET, NULL }, /* FIXME: * - delay for startup/shutdown sequence * - support for Ambient page temperatureSensorCount" src="snmp:$sysoid.2.1.0 ambient.temperature src="snmp:$sysoid.2.2.1.3.$indiceSensor => seems dumb! ambient.humidity src="snmp:$sysoid.2.4.1.3.$indiceSensor */ /* instant commands. */ /* Note that load.cycle might be replaced by / mapped on shutdown.reboot */ /* no counterpart found! { "outlet.load.off", 0, 1, ".1.3.6.1.4.1.13742.1.2.2.1.3.0", DO_OFF, SU_TYPE_CMD, NULL }, { "outlet.load.on", 0, 1, ".1.3.6.1.4.1.13742.1.2.2.1.3.0", DO_ON, SU_TYPE_CMD, NULL }, { "outlet.load.cycle", 0, 1, ".1.3.6.1.4.1.13742.1.2.2.1.3.0", DO_CYCLE, SU_TYPE_CMD, NULL }, */ { "outlet.%i.load.off", 0, 1, ".1.3.6.1.4.1.13742.1.2.2.1.3.%i", DO_OFF, SU_TYPE_CMD | SU_OUTLET, NULL }, { "outlet.%i.load.on", 0, 1, ".1.3.6.1.4.1.13742.1.2.2.1.3.%i", DO_ON, SU_TYPE_CMD | SU_OUTLET, NULL }, { "outlet.%i.load.cycle", 0, 1, ".1.3.6.1.4.1.13742.1.2.2.1.3.%i", DO_CYCLE, SU_TYPE_CMD | SU_OUTLET, NULL }, /* end of structure. */ { NULL, 0, 0, NULL, NULL, 0, NULL } }; mib2nut_info_t raritan = { "raritan", RARITAN_MIB_VERSION, NULL, RARITAN_OID_MODEL_NAME, raritan_mib, RARITAN_SYSOID, NULL }; nut-2.8.1/drivers/eaton-ups-pwnm2-mib.h0000644000175000017500000000025614501607135014626 00000000000000#ifndef EATON_UPS_PWNM2_MIB_H #define EATON_UPS_PWNM2_MIB_H #include "main.h" #include "snmp-ups.h" extern mib2nut_info_t eaton_pw_nm2; #endif /* EATON_UPS_PWNM2_MIB_H */ nut-2.8.1/drivers/upsdrvquery.c0000644000175000017500000004160114513167372013517 00000000000000/* upsdrvquery.c - a single query shot over a driver socket, tracked until a response arrives, returning that line and closing a connection Copyright (C) 2023 Jim Klimov 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 2 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, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "config.h" /* must be the first header */ #include #include #include #include #include #include #ifndef WIN32 #include #include #include #else #include "wincompat.h" #endif #include "common.h" #include "upsdrvquery.h" #include "nut_stdint.h" udq_pipe_conn_t *upsdrvquery_connect(const char *sockfn) { udq_pipe_conn_t *conn = (udq_pipe_conn_t*)xcalloc(1, sizeof(udq_pipe_conn_t)); /* Code borrowed from our numerous sock_connect() implems */ #ifndef WIN32 struct sockaddr_un sa; ssize_t ret; memset(&sa, '\0', sizeof(sa)); sa.sun_family = AF_UNIX; snprintf(sa.sun_path, sizeof(sa.sun_path), "%s", sockfn); conn->sockfd = socket(AF_UNIX, SOCK_STREAM, 0); if (conn->sockfd < 0) { upslog_with_errno(LOG_ERR, "open socket"); free(conn); return NULL; } if (connect(conn->sockfd, (struct sockaddr *) &sa, sizeof(sa)) < 0) { upslog_with_errno(LOG_ERR, "connect to driver socket at %s", sockfn); close(conn->sockfd); free(conn); return NULL; } ret = fcntl(conn->sockfd, F_GETFL, 0); if (ret < 0) { upslog_with_errno(LOG_ERR, "fcntl get on driver socket %s failed", sockfn); close(conn->sockfd); free(conn); return NULL; } if (fcntl(conn->sockfd, F_SETFL, ret | O_NDELAY) < 0) { upslog_with_errno(LOG_ERR, "fcntl set O_NDELAY on driver socket %s failed", sockfn); close(conn->sockfd); free(conn); return NULL; } #else BOOL result = WaitNamedPipe(sockfn, NMPWAIT_USE_DEFAULT_WAIT); if (result == FALSE) { upslog_with_errno(LOG_ERR, "WaitNamedPipe : %d\n", GetLastError()); return NULL; } conn->sockfd = CreateFile( sockfn, // pipe name GENERIC_READ | // read and write access GENERIC_WRITE, 0, // no sharing NULL, // default security attributes FIXME OPEN_EXISTING, // opens existing pipe FILE_FLAG_OVERLAPPED, // enable async IO NULL); // no template file if (conn->sockfd == INVALID_HANDLE_VALUE) { upslog_with_errno(LOG_ERR, "CreateFile : %d\n", GetLastError()); free(conn); return NULL; } memset(&(conn->overlapped), 0, sizeof(conn->overlapped)); conn->overlapped.hEvent = CreateEvent( NULL, /* Security */ FALSE, /* auto-reset */ FALSE, /* initial state = non signaled */ NULL /* no name */ ); if (conn->overlapped.hEvent == NULL) { upslogx(LOG_ERR, "Can't create event for reading event log"); free(conn); return NULL; } memset(conn->buf, 0, sizeof(conn->buf)); /* Start a read IO so we could wait on the event associated with it * Requires the persistent buffer for the connection */ upsdebugx(6, "%s: Queue initial async read", __func__); ReadFile(conn->sockfd, conn->buf, sizeof(conn->buf) - 1, /* -1 to be sure to have a trailing 0 */ NULL, &conn->overlapped); conn->newread = 0; #endif /* WIN32 */ /* Just for fun: stash the name */ if (snprintf(conn->sockfn, sizeof(conn->sockfn), "%s", sockfn) < 0) conn->sockfn[0] = '\0'; return conn; } udq_pipe_conn_t *upsdrvquery_connect_drvname_upsname(const char *drvname, const char *upsname) { char pidfn[SMALLBUF]; #ifndef WIN32 struct stat fs; snprintf(pidfn, sizeof(pidfn), "%s/%s-%s", dflt_statepath(), drvname, upsname); check_unix_socket_filename(pidfn); if (stat(pidfn, &fs)) { upslog_with_errno(LOG_ERR, "Can't open %s", pidfn); return NULL; } #else snprintf(pidfn, sizeof(pidfn), "\\\\.\\pipe\\%s-%s", drvname, upsname); #endif /* WIN32 */ return upsdrvquery_connect(pidfn); } void upsdrvquery_close(udq_pipe_conn_t *conn) { if (!conn) return; #ifndef WIN32 if (VALID_FD(conn->sockfd)) close(conn->sockfd); #else if (VALID_FD(conn->overlapped.hEvent)) { CloseHandle(conn->overlapped.hEvent); } memset(&(conn->overlapped), 0, sizeof(conn->overlapped)); if (VALID_FD(conn->sockfd)) { if (DisconnectNamedPipe(conn->sockfd) == 0) { upslogx(LOG_ERR, "DisconnectNamedPipe error : %d", (int)GetLastError()); } CloseHandle(conn->sockfd); } conn->newread = 0; #endif /* WIN32 */ conn->sockfd = ERROR_FD; memset(conn->buf, 0, sizeof(conn->buf)); memset(conn->sockfn, 0, sizeof(conn->sockfn)); /* caller should free the conn */ } ssize_t upsdrvquery_read_timeout(udq_pipe_conn_t *conn, struct timeval tv) { ssize_t ret; #ifndef WIN32 fd_set rfds; #else DWORD bytesRead = 0; BOOL res = FALSE; struct timeval start, now, presleep; #endif if (!conn || INVALID_FD(conn->sockfd)) { upslog_with_errno(LOG_ERR, "socket not initialized"); return -1; } #ifndef WIN32 FD_ZERO(&rfds); FD_SET(conn->sockfd, &rfds); if (select(conn->sockfd + 1, &rfds, NULL, NULL, &tv) < 0) { upslog_with_errno(LOG_ERR, "select with socket"); /* upsdrvquery_close(conn); */ return -1; } if (!FD_ISSET(conn->sockfd, &rfds)) { upsdebugx(5, "%s: received nothing from driver socket", __func__); return -2; /* timed out, no info */ } memset(conn->buf, 0, sizeof(conn->buf)); ret = read(conn->sockfd, conn->buf, sizeof(conn->buf)); #else /* upslog_with_errno(LOG_ERR, "Support for this platform is not currently implemented"); return -1; */ /* Is GetLastError() required to move on if pipe has more data? * if (GetLastError() == ERROR_IO_PENDING) { */ if (conn->newread) { upsdebugx(6, "%s: Restart async read", __func__); memset(conn->buf, 0, sizeof(conn->buf)); ReadFile(conn->sockfd, conn->buf, sizeof(conn->buf) - 1, NULL, &(conn->overlapped)); conn->newread = 0; } gettimeofday(&start, NULL); while (res == FALSE /*&& bytesRead == 0*/) { res = GetOverlappedResult(conn->sockfd, &conn->overlapped, &bytesRead, FALSE); if (res != FALSE /*|| bytesRead != 0*/) break; if (tv.tv_sec < 1 && tv.tv_usec < 1) { upsdebugx(5, "%s: pipe read error (no incoming data), proceeding now", __func__); break; } upsdebugx(6, "%s: pipe read error, still waiting for data", __func__); /* Throttle down a bit, 0.1 sec (10^5 * 10^-6) should do it conveniently */ gettimeofday(&presleep, NULL); usleep(100000); /* obsoleted in win32, so follow up below */ gettimeofday(&now, NULL); /* NOTE: This code may report a "diff=1.-894714 (0.105286)" * which looks bogus, but for troubleshooting we don't care */ upsdebugx(7, "%s: presleep=%ld.%06ld now=%ld.%06ld diff=%4.0f.%06ld (%f)", __func__, presleep.tv_sec, presleep.tv_usec, now.tv_sec, now.tv_usec, difftime(now.tv_sec, presleep.tv_sec), (long)(now.tv_usec - presleep.tv_usec), difftimeval(now, presleep) ); /* accept shorter delays, Windows does not guarantee a minimum sleep it seems */ if (difftimeval(now, presleep) < 0.05) { /* https://stackoverflow.com/a/17283549 */ HANDLE timer; LARGE_INTEGER ft; /* SetWaitableTimer() uses 100 nanosecond intervals, * and a negative value indicates relative time: */ ft.QuadPart = -(10*100000); /* 100 msec */ timer = CreateWaitableTimer(NULL, TRUE, NULL); SetWaitableTimer(timer, &ft, 0, NULL, NULL, 0); WaitForSingleObject(timer, INFINITE); CloseHandle(timer); gettimeofday(&now, NULL); upsdebugx(7, "%s: presleep=%ld.%06ld now=%ld.%06ld diff=%4.0f.%06ld (%f)", __func__, presleep.tv_sec, presleep.tv_usec, now.tv_sec, now.tv_usec, difftime(now.tv_sec, presleep.tv_sec), (long)(now.tv_usec - presleep.tv_usec), difftimeval(now, presleep) ); } /* If nothing was honored, doze off for a whole second */ if (difftimeval(now, presleep) < 0.05) { sleep(1); gettimeofday(&now, NULL); upsdebugx(7, "%s: presleep=%ld.%06ld now=%ld.%06ld diff=%4.0f.%06ld (%f)", __func__, presleep.tv_sec, presleep.tv_usec, now.tv_sec, now.tv_usec, difftime(now.tv_sec, presleep.tv_sec), (long)(now.tv_usec - presleep.tv_usec), difftimeval(now, presleep) ); } if (difftimeval(now, start) > (tv.tv_sec + 0.000001 * tv.tv_usec)) { upsdebugx(5, "%s: pipe read error, timeout exceeded", __func__); break; } } if (res != FALSE) ret = (ssize_t)bytesRead; else ret = -1; #endif /* WIN32 */ upsdebugx(ret > 0 ? 5 : 6, "%s: received %" PRIiMAX " bytes from driver socket: %s", __func__, (intmax_t)ret, (ret > 0 ? conn->buf : "")); if (ret > 0 && conn->buf[0] == '\0') upsdebug_hex(5, "payload starts with zero byte: ", conn->buf, ((size_t)ret > sizeof(conn->buf) ? sizeof(conn->buf) : (size_t)ret)); return ret; } ssize_t upsdrvquery_write(udq_pipe_conn_t *conn, const char *buf) { size_t buflen = strlen(buf); #ifndef WIN32 ssize_t ret; #else DWORD bytesWritten = 0; BOOL result = FALSE; #endif /* WIN32 */ upsdebugx(5, "%s: write to driver socket: %s", __func__, buf); if (!conn || INVALID_FD(conn->sockfd)) { upslog_with_errno(LOG_ERR, "socket not initialized"); return -1; } #ifndef WIN32 ret = write(conn->sockfd, buf, buflen); if (ret < 0 || ret != (int)buflen) { upslog_with_errno(LOG_ERR, "Write to socket %d failed", conn->sockfd); goto socket_error; } return ret; #else result = WriteFile(conn->sockfd, buf, buflen, &bytesWritten, NULL); if (result == 0 || bytesWritten != (DWORD)buflen) { upslog_with_errno(LOG_ERR, "Write to handle %p failed", conn->sockfd); goto socket_error; } return (ssize_t)bytesWritten; #endif /* WIN32 */ socket_error: /*upsdrvquery_close(conn);*/ return -1; } ssize_t upsdrvquery_prepare(udq_pipe_conn_t *conn, struct timeval tv) { struct timeval start, now; /* Avoid noise */ if (upsdrvquery_write(conn, "NOBROADCAST\n") < 0) goto socket_error; if (tv.tv_sec < 1 && tv.tv_usec < 1) { upsdebugx(5, "%s: proclaiming readiness for tracked commands without flush of server messages", __func__); return 1; } /* flush incoming, if any */ gettimeofday(&start, NULL); if (upsdrvquery_write(conn, "PING\n") < 0) goto socket_error; upsdebugx(5, "%s: waiting for a while to flush server messages", __func__); while (1) { char *buf; upsdrvquery_read_timeout(conn, tv); gettimeofday(&now, NULL); if (difftimeval(now, start) > ((double)(tv.tv_sec) + 0.000001 * (double)(tv.tv_usec))) { upsdebugx(5, "%s: requested timeout expired", __func__); break; } /* Await a PONG for quick confirmation of achieved quietness * (should only happen after the driver handled NOBROADCAST) */ #ifdef WIN32 /* Allow a new read to happen later */ conn->newread = 1; #endif buf = conn->buf; while (buf && *buf) { if (!strncmp(buf, "PONG\n", 5)) { upsdebugx(5, "%s: got expected PONG", __func__); goto finish; } buf = strchr(buf, '\n'); if (buf) { /* upsdebugx(5, "%s: trying next line of multi-line response: %s", __func__, buf); */ buf++; /* skip EOL char */ } } /* Diminishing timeouts for read() */ tv.tv_usec -= (suseconds_t)(difftimeval(now, start)); while (tv.tv_usec < 0) { tv.tv_sec--; tv.tv_usec = 1000000 + tv.tv_usec; // Note it is negative } if (tv.tv_sec <= 0 && tv.tv_usec <= 0) { upsdebugx(5, "%s: requested timeout expired", __func__); break; } } /* Check that we can have a civilized dialog -- * nope, this one is for network protocol */ /* if (upsdrvquery_write(conn, "GET TRACKING\n") < 0) goto socket_error; if (upsdrvquery_read_timeout(conn, tv) < 1) goto socket_error; if (strcmp(conn->buf, "ON")) { upslog_with_errno(LOG_ERR, "Driver does not have TRACKING support enabled"); goto socket_error; } */ finish: upsdebugx(5, "%s: ready for tracked commands", __func__); return 1; socket_error: upsdrvquery_close(conn); return -1; } /* UUID v4 basic implementation * Note: 'dest' must be at least `UUID4_LEN` long */ #define UUID4_BYTESIZE 16 static int upsdrvquery_nut_uuid_v4(char *uuid_str) { size_t i; uint8_t nut_uuid[UUID4_BYTESIZE]; if (!uuid_str) return 0; for (i = 0; i < UUID4_BYTESIZE; i++) nut_uuid[i] = (uint8_t)rand() + (uint8_t)rand(); /* set variant and version */ nut_uuid[6] = (nut_uuid[6] & 0x0F) | 0x40; nut_uuid[8] = (nut_uuid[8] & 0x3F) | 0x80; return snprintf(uuid_str, UUID4_LEN, "%02X%02X%02X%02X-%02X%02X-%02X%02X-%02X%02X-%02X%02X%02X%02X%02X%02X", nut_uuid[0], nut_uuid[1], nut_uuid[2], nut_uuid[3], nut_uuid[4], nut_uuid[5], nut_uuid[6], nut_uuid[7], nut_uuid[8], nut_uuid[9], nut_uuid[10], nut_uuid[11], nut_uuid[12], nut_uuid[13], nut_uuid[14], nut_uuid[15]); } ssize_t upsdrvquery_request( udq_pipe_conn_t *conn, struct timeval tv, const char *query ) { /* Assume TRACKING works; post a socket-protocol * query to driver and return whatever it says */ char qbuf[LARGEBUF]; size_t qlen; char tracking_id[UUID4_LEN]; struct timeval start, now; if (snprintf(qbuf, sizeof(qbuf), "%s", query) < 0) goto socket_error; qlen = strlen(qbuf); while (qlen > 0 && qbuf[qlen - 1] == '\n') { qbuf[qlen - 1] = '\0'; qlen--; } upsdrvquery_nut_uuid_v4(tracking_id); if (snprintf(qbuf + qlen, sizeof(qbuf) - qlen, " TRACKING %s\n", tracking_id) < 0) goto socket_error; /* Post the query and wait for reply */ if (upsdrvquery_write(conn, qbuf) < 0) goto socket_error; if (tv.tv_sec < 1 && tv.tv_usec < 1) { upsdebugx(1, "%s: will wait indefinitely for response to %s", __func__, query); } else { while (tv.tv_usec >= 1000000) { tv.tv_usec -= 1000000; tv.tv_sec++; } upsdebugx(5, "%s: will wait up to %" PRIiMAX ".%06" PRIiMAX " sec for response to %s", __func__, (intmax_t)tv.tv_sec, (intmax_t)tv.tv_usec, query); } gettimeofday(&start, NULL); while (1) { char *buf; if (upsdrvquery_read_timeout(conn, tv) < 1) goto socket_error; #ifdef WIN32 /* Allow a new read to happen later */ conn->newread = 1; #endif buf = conn->buf; while (buf && *buf) { if (!strncmp(buf, "TRACKING ", 9) && !strncmp(buf + 9, tracking_id, UUID4_LEN - 1) ) { int ret; size_t offset = 9 + UUID4_LEN; if (sscanf(buf + offset, " %d", &ret) < 1) { upsdebugx(5, "%s: sscanf failed at offset %" PRIuSIZE " (char '%c')", __func__, offset, buf[offset]); goto socket_error; } upsdebugx(5, "%s: parsed out command status: %d", __func__, ret); return ret; } else { upsdebugx(5, "%s: response did not have expected format", __func__); /* Maybe a rogue send-to-all? */ } buf = strchr(buf, '\n'); if (buf) { upsdebugx(5, "%s: trying next line of multi-line response: %s", __func__, buf); buf++; /* skip EOL char */ } } gettimeofday(&now, NULL); if (tv.tv_sec < 1 && tv.tv_usec < 1) { if ( ((long)(difftimeval(now, start))) % 60 == 0 ) upsdebugx(5, "%s: waiting indefinitely for response to %s", __func__, query); sleep(1); continue; } if (difftimeval(now, start) > ((double)(tv.tv_sec) + 0.000001 * (double)(tv.tv_usec))) { upsdebugx(5, "%s: timed out waiting for expected response", __func__); return -1; } } socket_error: upsdrvquery_close(conn); return -1; } ssize_t upsdrvquery_oneshot( const char *drvname, const char *upsname, const char *query, char *buf, const size_t bufsz, struct timeval *ptv ) { struct timeval tv; ssize_t ret; udq_pipe_conn_t *conn = upsdrvquery_connect_drvname_upsname(drvname, upsname); if (!conn || INVALID_FD(conn->sockfd)) return -1; /* This depends on driver looping delay, polling frequency, * being blocked on other commands, etc. Number so far is * arbitrary and optimistic. A non-zero setting causes a * long initial silence to flush incoming buffers after * the NOBROADCAST. In practice, we do not expect messages * from dstate::send_to_all() to be a nuisance, since we * have just connected and posted the NOBROADCAST so there * is little chance that something appears in that short * time. Also now we know to ignore replies that are not * TRACKING */ tv.tv_sec = 3; tv.tv_usec = 0; /* Here we have a fragile simplistic parser that * expects one line replies to a specific command, * so want to rule out the noise. */ if (upsdrvquery_prepare(conn, tv) < 0) { ret = -1; goto finish; } if (ptv) { tv.tv_sec = ptv->tv_sec; tv.tv_usec = ptv->tv_usec; } else { tv.tv_sec = 5; tv.tv_usec = 0; } if ((ret = upsdrvquery_request(conn, tv, query)) < 0) { ret = -1; goto finish; } if (buf) { snprintf(buf, bufsz, "%s", conn->buf); } finish: upsdrvquery_close(conn); free(conn); return ret; } nut-2.8.1/drivers/eaton-pdu-pulizzi-mib.h0000644000175000017500000000241114377374134015260 00000000000000/* eaton-pdu-pulizzi-mib.h - subdriver to monitor Eaton ePDU SNMP devices with NUT * * Copyright (C) * 2010 Arjen de Korte * 2011 - 2012 Arnaud Quette * 2017 Arnaud Quette * 2017 Jim Klimov * * 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 2 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, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef EATON_EPDU_PULIZZI_MIB_H #define EATON_EPDU_PULIZZI_MIB_H #include "main.h" #include "snmp-ups.h" extern mib2nut_info_t pulizzi_switched1; extern mib2nut_info_t pulizzi_switched2; #endif /* EATON_EPDU_PULIZZI_MIB_H */ nut-2.8.1/drivers/bestpower-mib.c0000644000175000017500000000667714500336654013700 00000000000000/* bestpower-mib.c - data to monitor Eaton Best Power Ferrups * using earlier version of the ConnectUPS * * Copyright (C) 2010 - Arnaud Quette * * 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 2 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, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #include "bestpower-mib.h" #define BESTPOWER_MIB_VERSION "0.4" #define BESTPOWER_OID_MODEL_NAME ".1.3.6.1.4.1.2947.1.1.2.0" /* * http://powerquality.eaton.com/Support/Software-Drivers/Downloads/connectivity-firmware/bestpwr2.mib */ /* TODO: find the right sysOID for this MIB * #define BESTPOWER_SYSOID ".1.3.6.1.4.1.2947???" */ #define BESTPOWER_SYSOID BESTPOWER_OID_MODEL_NAME static info_lkp_t bestpower_power_status[] = { { 1, "OL", NULL, NULL }, { 2, "OB", NULL, NULL }, { 0, NULL, NULL, NULL } } ; /* Snmp2NUT lookup table for Best Power MIB */ static snmp_info_t bestpower_mib[] = { /* standard MIB items */ { "device.description", ST_FLAG_STRING | ST_FLAG_RW, SU_INFOSIZE, ".1.3.6.1.2.1.1.1.0", NULL, SU_FLAG_OK, NULL }, { "device.contact", ST_FLAG_STRING | ST_FLAG_RW, SU_INFOSIZE, ".1.3.6.1.2.1.1.4.0", NULL, SU_FLAG_OK, NULL }, { "device.location", ST_FLAG_STRING | ST_FLAG_RW, SU_INFOSIZE, ".1.3.6.1.2.1.1.6.0", NULL, SU_FLAG_OK, NULL }, /* Device page */ { "device.type", ST_FLAG_STRING, SU_INFOSIZE, NULL, "ups", SU_FLAG_STATIC | SU_FLAG_ABSENT | SU_FLAG_OK, NULL }, { "ups.mfr", ST_FLAG_STRING, SU_INFOSIZE, NULL, "EATON", SU_FLAG_STATIC | SU_FLAG_ABSENT | SU_FLAG_OK, NULL }, /*.1.3.6.1.4.1.2947.1.1.1.0 = STRING: "Ferrups" .1.3.6.1.4.1.2947.1.1.2.0 = STRING: "FE850VA"*/ { "ups.model", ST_FLAG_STRING, SU_INFOSIZE, BESTPOWER_OID_MODEL_NAME, "Best Ferrups", SU_FLAG_STATIC, NULL }, { "ups.serial", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.2947.1.1.5.0", "", SU_FLAG_STATIC, NULL }, { "ups.firmware", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.2947.1.1.7.0", "", SU_FLAG_STATIC, NULL }, { "ups.power", 0, 1, ".1.3.6.1.4.1.2947.1.1.3.0", "", 0, NULL }, { "ups.mfr.date", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.2947.1.1.8.0", "", 0, NULL }, { "ups.status", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.2947.1.2.1.0", "", 0 /*SU_STATUS_PWR*/, &bestpower_power_status[0] }, /* Battery runtime is expressed in minutes */ { "battery.runtime", 0, 60.0, ".1.3.6.1.4.1.2947.1.2.3.0", "", 0, NULL }, /* The elapsed time in seconds since the * UPS has switched to battery power */ { "battery.runtime.elapsed", 0, 1.0, ".1.3.6.1.4.1.2947.1.2.2.0", "", 0, NULL }, { "battery.voltage", 0, 0.1, ".1.3.6.1.4.1.2947.1.2.4.0", "", 0, NULL }, { "battery.current", 0, 0.1, ".1.3.6.1.4.1.2947.1.2.5.0", "", 0, NULL }, /* end of structure. */ { NULL, 0, 0, NULL, NULL, 0, NULL } } ; mib2nut_info_t bestpower = { "bestpower", BESTPOWER_MIB_VERSION, NULL, BESTPOWER_OID_MODEL_NAME, bestpower_mib, BESTPOWER_SYSOID, NULL }; nut-2.8.1/drivers/blazer.h0000644000175000017500000000365614501607135012373 00000000000000/* * blazer.h: defines/macros for Megatec/Q1 protocol based UPSes * * OBSOLETION WARNING: Please to not base new development on this * codebase, instead create a new subdriver for nutdrv_qx which * generally covers all Megatec/Qx protocol family and aggregates * device support from such legacy drivers over time. * * A document describing the protocol implemented by this driver can be * found online at "https://www.networkupstools.org/protocols/megatec.html". * * Copyright (C) 2008 - Arjen de Korte * * 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 2 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, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef BLAZER_H #define BLAZER_H #define MAXTRIES 3 /* * The driver core will do all the protocol handling and provides * the following (interface independent) parts already * * upsdrv_updateinfo() * upsdrv_shutdown() * * Communication with the UPS is done through blazer_command() of which * the prototype is declared below. It shall send a command and reads * a reply if buf is not a NULL pointer and buflen > 0. * * Returns < 0 on error, 0 on timeout and the number of bytes send/read on * success. */ ssize_t blazer_command(const char *cmd, char *buf, size_t buflen); void blazer_makevartable(void); void blazer_initups(void); void blazer_initinfo(void); #endif /* BLAZER_H */ nut-2.8.1/drivers/mge-utalk.h0000644000175000017500000002220614500336654012776 00000000000000/* mge-utalk.h - monitor MGE UPS for NUT with UTalk protocol * * Copyright (C) 2002 - 2005 * Arnaud Quette & * Hans Ekkehard Plesser * Martin Loyer * Patrick Agrain * Nicholas Reilly * Dave Abbott * Marek Kralewski * * This driver is a collaborative effort by the above people, * Sponsored by MGE UPS SYSTEMS * * 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 2 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, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #ifndef NUT_MGE_UTALK_H_SEEN #define NUT_MGE_UTALK_H_SEEN 1 /* --------------------------------------------------------------- */ /* Default Values for UPS Variables */ /* --------------------------------------------------------------- */ #define DEFAULT_LOWBATT 30 /* low battery level, in % */ /* delay between return of utility power and powering up of load (in MINUTES) */ #define DEFAULT_ONDELAY 1 #define DEFAULT_OFFDELAY 20 /* delay before power off, in SECONDS */ #define MIN_CONFIRM_TIME 3 /* shutdown must be confirmed in */ #define MAX_CONFIRM_TIME 15 /* this interval */ /* --------------------------------------------------------------- */ /* Model Name formating entries */ /* --------------------------------------------------------------- */ typedef struct { const char *basename; /* as returned by Si 1 */ const char *finalname; } models_name_t; static models_name_t Si1_models_names [] = { /* Pulsar EX */ { "Pulsar EX7", "Pulsar EX 7" }, { "Pulsar EX10", "Pulsar EX 10" }, { "Pulsar EX15", "Pulsar EX 15" }, { "Pulsar EX20", "Pulsar EX 20" }, { "Pulsar EX30", "Pulsar EX 30" }, { "Pulsar EX40", "Pulsar EX 40" }, /* Pulsar ES+ */ { "Pulsar ES2+", "Pulsar ES 2+" }, { "Pulsar ES5+", "Pulsar ES 5+" }, /* Pulsar ESV+ */ { "Pulsar ESV5+", "Pulsar ESV 5+" }, { "Pulsar ESV8+", "Pulsar ESV 8+" }, { "Pulsar ESV11+", "Pulsar ESV 11+" }, { "Pulsar ESV14+", "Pulsar ESV 14+" }, { "Pulsar ESV22+", "Pulsar ESV 22+" }, /* Pulsar EXtreme */ { "EXTREME 1500", "Pulsar EXtreme 1500" }, { "EXTREME 2000", "Pulsar EXtreme 2000" }, { "EXTREME 2500", "Pulsar EXtreme 2500" }, { "EXTREME 3000", "Pulsar EXtreme 3000" }, /* Comet EXtreme */ { "EXTREME 4.5", "Comet EXtreme 4.5" }, { "EXTREME 6", "Comet EXtreme 6" }, { "EXTREME 9", "Comet EXtreme 9" }, { "EXTREME 12", "Comet EXtreme 12" }, /* Comet */ { "COMET 5", "Comet 5" }, { "COMET 7", "Comet 7.5" }, { "COMET 10", "Comet 10" }, { "COMET 15", "Comet 15" }, { "COMET 20", "Comet 20" }, { "COMET 30", "Comet 30" }, { "COMET 12", "Comet 12" }, { "COMET 18", "Comet 18" }, { "COMET 24", "Comet 24" }, { "COMET 36", "Comet 36" }, /* FIXME: complete with Pulsar ?EL 2/4/7?, EXL, SX, PSX/CSX, Evolution?,... */ /* end of structure. */ { NULL, "Generic UTalk model" } }; /* --------------------------------------------------------------- */ /* Model Information for legacy models */ /* --------------------------------------------------------------- */ /* Structure defining how to get name and model for a particular Si output * This is for older UPS (Pulsar ESV,SV) which don't support Plug'n'Play 'Si 1' command */ typedef struct { int Data1; /* Data1, Family model */ int Data2; /* Data2, Type */ /* Data3, SoftLevel is not implemented here, while it's always null or zero.*/ const char *name; /* ASCII model name (like 'Si 1' output */ } mge_model_info_t; /* Array containing Model information for legacy models * NOTE: * - Array is terminated by element with type NULL. */ static mge_model_info_t mge_model[] = { /* Pulsar SV page */ { 3000, 5, "Pulsar SV3" }, { 3000, 6, "Pulsar SV5/8/11" }, { 3000, 7, "Pulsar SV3" }, { 3000, 8, "Pulsar SV5/8" }, { 3000, 10, "Pulsar SV11/ESV13" }, /* Pulsar ESV page */ { 3000, 11, "Pulsar ESV17" }, { 3000, 12, "Pulsar ESV20" }, { 3000, 13, "Pulsar ESV13" }, { 3000, 14, "Pulsar ESV17" }, { 3000, 15, "Pulsar ESV20" }, { 3000, 17, "Pulsar ESV8" }, /* Pulsar ESV+ compatibility (though these support Si1) */ { 3000, 51, "Pulsar ESV 11+" }, { 0, 0, NULL } }; /* --------------------------------------------------------------- */ /* Multiplier Tables */ /* --------------------------------------------------------------- */ /* First index : Table number, fetched with "Ai" command * Second index: unit, as in enum above * NOTE: * - to make the table index the same as the MGE table number, * dummy table row multiplier[0][] is inserted * - unit MIN2SEC is used to convert values in minutes sent by * the UPS (WAKEDELAY) to seconds * - the final column corresponds to unit NONE */ /* units in multiplier table */ typedef enum eunits { VOLT = 0, AMPERE, HERTZ, VOLTAMP, WATT, DEGCELS, MIN2SEC, NONE } units_t; static const double multiplier[4][8] = { /* V A Hz VA W C MIN2SEC NONE */ { 1 , 1 , 1 , 1, 1, 1, 60, 1 }, { 1 , 1 , 0.1 , 1000, 1000, 1, 60, 1 }, { 0.01, 0.01, 1 , 1, 1, 1, 60, 1 }, { 1 , 0.01, 0.1 , 1, 1, 1, 60, 1 } }; /* --------------------------------------------------------------- */ /* Explicit Booleans */ /* --------------------------------------------------------------- */ /* use explicit booleans */ #ifdef FALSE #undef FALSE #endif /* FALSE */ #ifdef TRUE #undef TRUE #endif /* TRUE */ typedef enum ebool { FALSE=0, TRUE } bool_t; /* --------------------------------------------------------------- */ /* Query Commands and their Mapping to INFO_ Variables */ /* --------------------------------------------------------------- */ /* Structure defining how to query UPS for a variable and write information to INFO structure. */ typedef struct { const char *type; /* INFO_* element */ int flags; /* INFO-element flags to set in addinfo */ int length; /* INFO-element length of strings */ const char *cmd; /* UPS command string to requets element */ const char *fmt; /* printf format string for INFO entry */ units_t unit; /* unit of measurement, or NONE */ bool_t ok; /* flag indicating if item is available */ } mge_info_item_t; /* Array containing information to translate between UTalk and NUT info * NOTE: * - Array is terminated by element with type NULL. * - Essential INFO items (_MFR, _MODEL, _FIRMWARE, _STATUS) are * handled separately. * - Array is NOT const, since "ok" can be changed. */ static mge_info_item_t mge_info[] = { /* Battery page */ { "battery.charge", 0, 0, "Bl", "%05.1f", NONE, TRUE }, { "battery.runtime", 0, 0, "Bn", "%05d", NONE, TRUE }, { "battery.voltage", 0, 0, "Bv", "%05.1f", VOLT, TRUE }, { "battery.charge.low", ST_FLAG_RW | ST_FLAG_STRING, 2, "Bl ?", "%02d", NONE, TRUE }, { "battery.voltage.nominal", 0, 0, "Bv ?", "%05.1f", VOLT, TRUE }, /* UPS page */ { "ups.temperature", 0, 0, "St", "%05.1f", DEGCELS, TRUE }, { "ups.load", 0, 0, "Ll", "%05.1f", NONE, TRUE }, { "ups.delay.start", ST_FLAG_RW | ST_FLAG_STRING, 5, "Sm ?", "%03d", NONE, TRUE }, { "ups.delay.shutdown", ST_FLAG_RW | ST_FLAG_STRING, 5, "Sn ?", "%03d", NONE, TRUE }, { "ups.test.interval", ST_FLAG_RW | ST_FLAG_STRING, 5, "Bp ?", "%03d", NONE, TRUE }, /* Output page */ { "output.voltage", 0, 0, "Lv", "%05.1f", VOLT, TRUE }, { "output.current", 0, 0, "Lc", "%05.1f", AMPERE, TRUE }, /* Input page */ { "input.voltage", 0, 0, "Uv", "%05.1f", VOLT, TRUE }, { "input.frequency", 0, 0, "Uf", "%05.2f", HERTZ, TRUE }, /* same as LOBOOSTXFER */ { "input.transfer.low", ST_FLAG_RW | ST_FLAG_STRING, 5, "Ee ?", "%05.1f", VOLT, TRUE }, { "input.transfer.boost.low", ST_FLAG_RW | ST_FLAG_STRING, 5, "Ee ?", "%05.1f", VOLT, TRUE }, { "input.transfer.boost.high", ST_FLAG_RW | ST_FLAG_STRING, 5, "Eo ?", "%05.1f", VOLT, TRUE }, { "input.transfer.trim.low", ST_FLAG_RW | ST_FLAG_STRING, 5, "Ea ?", "%05.1f", VOLT, TRUE }, /* same as HITRIMXFER */ { "input.transfer.high", ST_FLAG_RW | ST_FLAG_STRING, 5, "Eu ?", "%05.1f", VOLT, TRUE }, { "input.transfer.trim.high", ST_FLAG_RW | ST_FLAG_STRING, 5, "Eu ?", "%05.1f", VOLT, TRUE }, /* terminating element */ { NULL, 0, 0, "\0", "\0", NONE, FALSE } }; #endif /* NUT_MGE_UTALK_H_SEEN */ nut-2.8.1/drivers/victronups.c0000644000175000017500000003372314501607135013321 00000000000000/* victronups.c - Model specific routines for GE/IMV/Victron units * Match, Match Lite, NetUps * * Copyright (C) 1999 Russell Kroll * Copyright (C) 2000 Radek Benedikt * old style "victronups" * Copyright (C) 2001 Daniel.Prynych * porting to now style "newvictron" * Copyright (C) 2003 Gert Lynge * Porting to new serial functions. Now removes \n from data (was causing * periodic misreadings of temperature and voltage levels) * Copyright (C) 2004 Gert Lynge * Implemented some Instant Commands. * * 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 2 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, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #include "main.h" #include "serial.h" #define DRIVER_NAME "GE/IMV/Victron UPS driver" #define DRIVER_VERSION "0.22" /* driver description structure */ upsdrv_info_t upsdrv_info = { DRIVER_NAME, DRIVER_VERSION, "Russell Kroll \n" \ "Radek Benedikt \n" \ "Daniel Prynych \n" \ "Gert Lynge ", DRV_STABLE, { NULL } }; #define ENDCHAR '\r' #define IGNCHARS "\n" #define UPS_DELAY 150000 #define UPS_LONG_DELAY 450000 #define VICTRON_OVER 128 #define VICTRON_RB 1 #define VICTRON_OB 2 #define VICTRON_LB 4 #define VICTRON_NO_TEST 1 #define VICTRON_ABORT_TEST 2 #define VICTRON_SYSTEM_TEST 3 #define VICTRON_BATTERY_TEST 4 #define VICTRON_CALIBRATION 5 #define VICTRON_BYPASS_TEST 101 #define LENGTH_TEMP 256 static int sdwdelay = 0; /* shutdown after 0 second */ static char *model_name; static int start_is_datastale = 1; static int exist_ups_serial = 0; static int exist_ups_temperature = 0; static int exist_output_current = 0; static int exist_battery_charge = 0; static int exist_battery_current = 0; static int exist_battery_temperature = 0; static int exist_battery_runtime = 0; static int test_in_progress = VICTRON_NO_TEST; static int get_data (const char *out_string, char *in_string) { ssize_t ret_code; ser_send(upsfd, "%s%c", out_string, ENDCHAR); usleep (UPS_DELAY); ret_code = ser_get_line(upsfd, in_string, LENGTH_TEMP, ENDCHAR, IGNCHARS, 3, 0); if (ret_code < 1) { dstate_datastale(); return -1; } return 0; } static int instcmd(const char *cmdname, const char *extra) { char temp[ LENGTH_TEMP ]; if(!strcasecmp(cmdname, "calibrate.start")) { if(get_data("vTi5!",temp)) { upsdebugx(1, "instcmd: ser_send calibrate.start failed"); return STAT_INSTCMD_UNKNOWN; /* Or Failed when it get defined */ } else { upsdebugx(1, "instcmd: calibrate.start returned: %s", temp); test_in_progress = VICTRON_CALIBRATION; return STAT_INSTCMD_HANDLED; } } else if(!strcasecmp(cmdname, "calibrate.stop")) { if(get_data("vTi2!",temp)) { upsdebugx(1, "instcmd: ser_send calibrate.stop failed"); return STAT_INSTCMD_UNKNOWN; /* Or Failed when it get defined */ } else { upsdebugx(1, "instcmd: calibrate.stop returned: %s", temp); return STAT_INSTCMD_HANDLED; } } else if(!strcasecmp(cmdname, "test.battery.stop")) { if(get_data("vTi2!",temp)) { upsdebugx(1, "instcmd: ser_send test.battery.stop failed"); return STAT_INSTCMD_UNKNOWN; /* Or Failed when it get defined */ } else { upsdebugx(1, "instcmd: test.battery.stop returned: %s", temp); return STAT_INSTCMD_HANDLED; } } else if(!strcasecmp(cmdname, "test.battery.start")) { if(get_data("vTi4!",temp)) { upsdebugx(1, "instcmd: ser_send test.battery.start failed"); return STAT_INSTCMD_UNKNOWN; /* Or Failed when it get defined */ } else { upsdebugx(1, "instcmd: test.battery.start returned: %s", temp); test_in_progress = VICTRON_BATTERY_TEST; return STAT_INSTCMD_HANDLED; } } else if(!strcasecmp(cmdname, "test.panel.stop")) { if(get_data("vTi2!",temp)) { upsdebugx(1, "instcmd: ser_send test.panel.stop failed"); return STAT_INSTCMD_UNKNOWN; /* Or Failed when it get defined */ } else { upsdebugx(1, "instcmd: test.panel.stop returned: %s", temp); return STAT_INSTCMD_HANDLED; } } else if(!strcasecmp(cmdname, "test.panel.start")) { if(get_data("vTi3!",temp)) { upsdebugx(1, "instcmd: ser_send test.panel.start failed"); return STAT_INSTCMD_UNKNOWN; /* Or Failed when it get defined */ } else { upsdebugx(1, "instcmd: test.panel.start returned: %s", temp); test_in_progress = VICTRON_SYSTEM_TEST; return STAT_INSTCMD_HANDLED; } } else if(!strcasecmp(cmdname, "bypass.stop")) { if(get_data("vTi2!",temp)) { upsdebugx(1, "instcmd: ser_send bypass.stop failed"); return STAT_INSTCMD_UNKNOWN; /* Or Failed when it get defined */ } else { upsdebugx(1, "instcmd: bypass.stop returned: %s", temp); return STAT_INSTCMD_HANDLED; } } else if(!strcasecmp(cmdname, "bypass.start")) { if(get_data("vTi101!",temp)) { upsdebugx(1, "instcmd: ser_send bypass.start failed"); return STAT_INSTCMD_UNKNOWN; /* Or Failed when it get defined */ } else { upsdebugx(1, "instcmd: bypass.start returned: %s", temp); test_in_progress = VICTRON_BYPASS_TEST; return STAT_INSTCMD_HANDLED; } } else { upsdebugx(1, "instcmd: unknown command: [%s] [%s]", cmdname, extra); return STAT_INSTCMD_UNKNOWN; } } void upsdrv_initinfo(void) { if (model_name) dstate_setinfo("ups.model", "%s", model_name); upsh.instcmd = instcmd; dstate_addcmd("test.battery.start"); dstate_addcmd("test.battery.stop"); dstate_addcmd("calibrate.start"); dstate_addcmd("calibrate.stop"); dstate_addcmd("test.panel.start"); /* We need a GeneralSystemTest, but use this one instead */ dstate_addcmd("test.panel.stop"); /* We need a GeneralSystemTest, but use this one instead */ dstate_addcmd("bypass.start"); dstate_addcmd("bypass.stop"); } void upsdrv_updateinfo(void) { int flags; char temp[ LENGTH_TEMP ]; char test_result[ LENGTH_TEMP ]; long runtime_sec = -1; if (start_is_datastale) { if (get_data("vDS?",temp)) return; if (strcmp(temp+3,"NA")) exist_ups_serial=1; if (get_data("vBT?",temp)) return; if (strcmp(temp+3,"NA")) exist_ups_temperature =1; if (get_data("vO0I?",temp)) return; if (strcmp(temp+4,"NA")) exist_output_current =1; if (get_data("vBC?",temp)) return; if (strcmp(temp+3,"NA")) exist_battery_charge = 1; if (get_data("vBI?",temp)) return; if (strcmp(temp+3,"NA")) exist_battery_charge = 1; if (get_data("vBT?",temp)) return; if (strcmp(temp+3,"NA")) exist_battery_temperature = 1; if (get_data("vBt?",temp)) return; if (strcmp(temp+3,"NA")) exist_battery_runtime = 1; start_is_datastale = 0; } /* ups.status */ if (get_data("vAa?",temp)) return; flags = atoi (temp+3); status_init(); if (flags & VICTRON_OVER) status_set("OVER"); if (flags & VICTRON_RB) status_set("RB"); if (flags & VICTRON_LB) status_set("LB"); if (flags & VICTRON_OB) status_set("OB"); else status_set("OL"); /* Get UPS test results */ if (get_data("vTr?",temp)) return; if (get_data("vTd?",test_result)) return; switch(atoi(temp+3)) { case 1: upsdebugx(1, "upsdrv_updateinfo: test %i result = Done, Passed: %s",test_in_progress,test_result+3); test_in_progress = VICTRON_NO_TEST; break; case 2: upsdebugx(1, "upsdrv_updateinfo: test %i result = Done, Warning: %s",test_in_progress,test_result+3); test_in_progress = VICTRON_NO_TEST; break; case 3: upsdebugx(1, "upsdrv_updateinfo: test %i result = Done, Error: %s",test_in_progress,test_result+3); test_in_progress = VICTRON_NO_TEST; break; case 4: upsdebugx(1, "upsdrv_updateinfo: test %i result = Aborted: %s",test_in_progress,test_result+3); test_in_progress = VICTRON_NO_TEST; break; case 5: if(test_in_progress==VICTRON_CALIBRATION) status_set("CAL"); /* calibration in progress */ upsdebugx(1, "upsdrv_updateinfo: test %i result = In Progress: %s", test_in_progress,test_result+3); break; case 6: upsdebugx(1, "upsdrv_updateinfo: test result = No test initiated: %s", test_result+3); break; default: upsdebugx(1, "upsdrv_updateinfo: unknown test result: %s / %s",temp+3,test_result+3); break; } status_commit(); /* dstate_dataok(); */ upsdebugx(1, "upsdrv_updateinfo: ups.status = %s\n", dstate_getinfo("ups.status")); /************** ups.x ***************************/ /* ups model */ if (!model_name) { if (get_data("vDM?",temp)) return; dstate_setinfo("ups.model", "%s", temp+3); upsdebugx(1, "ups.model >%s<>%s<\n",temp,temp+3); } /* ups.mfr */ if (get_data("vDm?",temp)) return; dstate_setinfo("ups.mfr", "%s", temp+3); upsdebugx(1, "ups.mfr >%s<>%s<\n",temp,temp+3); /* ups.serial */ if (exist_ups_serial) { if (get_data("vDS?",temp)) return; dstate_setinfo("ups.serial", "%s", temp+3); } upsdebugx(1, "ups.serial >%s<>%s<\n",temp,temp+3); /* ups.firmware */ if (get_data("vDV?",temp)) return; dstate_setinfo("ups.firmware", "%s", temp+3); upsdebugx(1, "ups.firmware >%s<>%s<\n",temp,temp+3); /* ups.temperature */ if (exist_ups_temperature) { if (get_data("vBT?",temp)) return; dstate_setinfo("ups.temperature", "%s", temp+3); } upsdebugx(1, "ups.temperature >%s<>%s<\n",temp,temp+3); /* ups.load */ if (get_data("vO0L?",temp)) return; dstate_setinfo("ups.load", "%s", temp+4); upsdebugx(1, "ups.load >%s<>%s<\n",temp,temp+4); /* ups protocol */ /* if (get_data("vDC?",temp)) return; dstate_setinfo("ups.protocol", "%s", temp+3; upsdebugx(1, "ups.protocol >%s<>%s<\n",temp,temp+3; */ /************** input.x *****************/ /* input.voltage */ if (get_data("vI0U?",temp)) return; dstate_setinfo("input.voltage", "%s", temp+4); upsdebugx(1, "input.voltage >%s<>%s<\n",temp,temp+4); /* input.transfer.low */ if (get_data("vFi?",temp)) return; dstate_setinfo("input.transfer.low", "%s", temp+3); upsdebugx(1, "input.transfer.low >%s<>%s<\n",temp,temp+3); /* input.transfer.high */ if (get_data("vFj?",temp)) return; dstate_setinfo("input.transfer.high", "%s", temp+3); upsdebugx(1, "input.transfer.high >%s<>%s<\n",temp,temp+3); /* input.frequency */ if (get_data("vI0f?",temp)) return; dstate_setinfo("input.frequency", "%2.1f", atof(temp+4) / 10.0); upsdebugx(1, "input.frequency >%s<>%s<\n",temp,temp+4); /*************** output.x ********************************/ /* output.voltage */ if (get_data("vO0U?",temp)) return; dstate_setinfo("output.voltage", "%s", temp+4); upsdebugx(1, "output.voltage >%s<>%s<\n",temp,temp+4); /* output.frequency */ if (get_data("vOf?",temp)) return; dstate_setinfo("output.frequency", "%2.1f", atof(temp+3) / 10.0); upsdebugx(1, "output.frequency >%s<>%s<\n",temp,temp+3); /* output.current */ if (exist_output_current) { if (get_data("vO0I?",temp)) return; dstate_setinfo("output.current", "%2.1f", atof(temp+4) / 10.0); } upsdebugx(1, "output.current >%s<>%s<\n",temp,temp+4); /*************** battery.x *******************************/ /* battery charge */ if (exist_battery_charge) { if (get_data("vBC?",temp)) return; dstate_setinfo("battery.charge", "%s", temp+3); } upsdebugx(1, "battery.charge >%s<>%s<\n",temp,temp+3); /* battery.voltage */ if (get_data("vBU?",temp)) return; dstate_setinfo("battery.voltage", "%2.1f", atof(temp+3) / 10.0); upsdebugx(1, "battery.voltage >%s<>%s<\n",temp,temp+3); /* battery.current */ if (exist_battery_current) { if (get_data("vBI?",temp)) return; dstate_setinfo("battery.current", "%2.1f", atof(temp+3) / 10.0); } upsdebugx(1, "battery.current >%s<>%s<\n",temp,temp+3); /* battery.temperature */ if (exist_battery_temperature) { if (get_data("vBT?",temp)) return; dstate_setinfo("battery.temperature", "%s", temp+3); } upsdebugx(1, "battery.temperature >%s<>%s<\n",temp,temp+3); /* battery.runtime */ if (exist_battery_runtime) { if (get_data("vBt?",temp)) return; runtime_sec = strtol(temp+3, NULL, 10)*60; snprintf(temp, sizeof(temp), "%ld", runtime_sec); dstate_setinfo("battery.runtime", "%s", temp); } upsdebugx(1, "battery.runtime >%s<>%ld<\n",temp,runtime_sec); dstate_dataok(); } void upsdrv_shutdown(void) { ser_send(upsfd, "vCc0!%c", ENDCHAR); usleep(UPS_DELAY); ser_send(upsfd, "vCb%i!%c", sdwdelay, ENDCHAR); } void upsdrv_help(void) { } /* list flags and values that you want to receive via -x */ void upsdrv_makevartable(void) { addvar(VAR_VALUE, "usd", "Seting delay before shutdown"); addvar(VAR_VALUE, "modelname", "Seting model name"); } void upsdrv_initups(void) { char temp[ LENGTH_TEMP ], *usd = NULL; /* = NULL je dulezite jen pro prekladac */ upsfd = ser_open(device_path); ser_set_speed(upsfd, device_path, B1200); if ((usd = getval("usd"))) { sdwdelay=atoi(usd); upsdebugx(1, "(-x) Delay before shutdown %i",sdwdelay); } if ((model_name = getval("modelname"))) { /* kdyz modelname nebylo zadano je vraceno NULL*/ upsdebugx(1, "(-x) UPS Name %s",model_name); } /* inicializace a synchronizace UPS */ ser_send_char(upsfd, ENDCHAR); usleep (UPS_LONG_DELAY); ser_send(upsfd, "?%c", ENDCHAR); usleep (UPS_LONG_DELAY); ser_get_line(upsfd, temp, sizeof(temp), ENDCHAR, IGNCHARS, 3, 0); ser_send(upsfd, "?%c", ENDCHAR); usleep (UPS_LONG_DELAY); ser_get_line(upsfd, temp, sizeof(temp), ENDCHAR, IGNCHARS, 3, 0); ser_send(upsfd, "?%c", ENDCHAR); usleep (UPS_DELAY); ser_get_line(upsfd, temp, sizeof(temp), ENDCHAR, IGNCHARS, 3, 0); /* the upsh handlers can't be done here, as they get initialized * shortly after upsdrv_initups returns to main. */ } void upsdrv_cleanup(void) { ser_close(upsfd, device_path); } nut-2.8.1/drivers/usb-common.c0000644000175000017500000002422214502413024013147 00000000000000/* usb-common.c - common useful USB functions Copyright (C) 2008 Arnaud Quette 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 2 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, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "config.h" /* must be first */ #include "common.h" #include "usb-common.h" int is_usb_device_supported(usb_device_id_t *usb_device_id_list, USBDevice_t *device) { int retval = NOT_SUPPORTED; usb_device_id_t *usbdev; for (usbdev = usb_device_id_list; (usbdev->vendorID != 0 || usbdev->productID != 0 || usbdev->fun != NULL); usbdev++ ) { if (usbdev->vendorID != device->VendorID) { continue; } /* flag as possibly supported if we see a known vendor */ retval = POSSIBLY_SUPPORTED; if (usbdev->productID != device->ProductID) { continue; } /* call the specific handler, if it exists */ if (usbdev->fun != NULL) { (*usbdev->fun)(device); } return SUPPORTED; } return retval; } /* ---------------------------------------------------------------------- */ /* matchers */ /* private callback function for exact matches */ static int match_function_exact(USBDevice_t *hd, void *privdata) { USBDevice_t *data = (USBDevice_t *)privdata; upsdebugx(3, "%s: matching a device...", __func__); if (hd->VendorID != data->VendorID) { upsdebugx(2, "%s: failed match of %s: %4x != %4x", __func__, "VendorID", hd->VendorID, data->VendorID); return 0; } if (hd->ProductID != data->ProductID) { upsdebugx(2, "%s: failed match of %s: %4x != %4x", __func__, "ProductID", hd->ProductID, data->ProductID); return 0; } if (strcmp_null(hd->Vendor, data->Vendor) != 0) { upsdebugx(2, "%s: failed match of %s: %s != %s", __func__, "Vendor", hd->Vendor, data->Vendor); return 0; } if (strcmp_null(hd->Product, data->Product) != 0) { upsdebugx(2, "%s: failed match of %s: %s != %s", __func__, "Product", hd->Product, data->Product); return 0; } if (strcmp_null(hd->Serial, data->Serial) != 0) { upsdebugx(2, "%s: failed match of %s: %s != %s", __func__, "Serial", hd->Serial, data->Serial); return 0; } #ifdef DEBUG_EXACT_MATCH_BUS if (strcmp_null(hd->Bus, data->Bus) != 0) { upsdebugx(2, "%s: failed match of %s: %s != %s", __func__, "Bus", hd->Bus, data->Bus); return 0; } #endif #if (defined WITH_USB_BUSPORT) && (WITH_USB_BUSPORT) #ifdef DEBUG_EXACT_MATCH_BUSPORT if (strcmp_null(hd->BusPort, data->BusPort) != 0) { upsdebugx(2, "%s: failed match of %s: %s != %s", __func__, "BusPort", hd->BusPort, data->BusPort); return 0; } #endif #endif #ifdef DEBUG_EXACT_MATCH_DEVICE if (strcmp_null(hd->Device, data->Device) != 0) { upsdebugx(2, "%s: failed match of %s: %s != %s", __func__, "Device", hd->Device, data->Device); return 0; } #endif return 1; } /* constructor: create an exact matcher that matches the device. * On success, return 0 and store the matcher in *matcher. On * error, return -1 with errno set */ int USBNewExactMatcher(USBDeviceMatcher_t **matcher, USBDevice_t *hd) { USBDeviceMatcher_t *m; USBDevice_t *data; m = malloc(sizeof(*m)); if (!m) { return -1; } data = calloc(1, sizeof(*data)); if (!data) { free(m); return -1; } m->match_function = &match_function_exact; m->privdata = (void *)data; m->next = NULL; data->VendorID = hd->VendorID; data->ProductID = hd->ProductID; data->Vendor = hd->Vendor ? strdup(hd->Vendor) : NULL; data->Product = hd->Product ? strdup(hd->Product) : NULL; data->Serial = hd->Serial ? strdup(hd->Serial) : NULL; #ifdef DEBUG_EXACT_MATCH_BUS data->Bus = hd->Bus ? strdup(hd->Bus) : NULL; #endif #ifdef DEBUG_EXACT_MATCH_DEVICE data->Device = hd->Device ? strdup(hd->Device) : NULL; #endif *matcher = m; return 0; } /* destructor: free matcher previously created with USBNewExactMatcher */ void USBFreeExactMatcher(USBDeviceMatcher_t *matcher) { USBDevice_t *data; if (!matcher) { return; } data = (USBDevice_t *)matcher->privdata; free(data->Vendor); free(data->Product); free(data->Serial); #ifdef DEBUG_EXACT_MATCH_BUS free(data->Bus); #endif #ifdef DEBUG_EXACT_MATCH_DEVICE free(data->Device); #endif free(data); free(matcher); } /* private data type: hold a set of compiled regular expressions. */ typedef struct regex_matcher_data_s { regex_t *regex[USBMATCHER_REGEXP_ARRAY_LIMIT]; } regex_matcher_data_t; /* private callback function for regex matches */ static int match_function_regex(USBDevice_t *hd, void *privdata) { regex_matcher_data_t *data = (regex_matcher_data_t *)privdata; int r; upsdebugx(3, "%s: matching a device...", __func__); /* NOTE: Here and below the "detailed" logging is commented away * because data->regex[] elements are not strings anymore! */ r = match_regex_hex(data->regex[0], hd->VendorID); if (r != 1) { /* upsdebugx(2, "%s: failed match of %s: %4x !~ %s", __func__, "VendorID", hd->VendorID, data->regex[0]); */ upsdebugx(2, "%s: failed match of %s: %4x", __func__, "VendorID", hd->VendorID); return r; } r = match_regex_hex(data->regex[1], hd->ProductID); if (r != 1) { /* upsdebugx(2, "%s: failed match of %s: %4x !~ %s", __func__, "ProductID", hd->ProductID, data->regex[1]); */ upsdebugx(2, "%s: failed match of %s: %4x", __func__, "ProductID", hd->ProductID); return r; } r = match_regex(data->regex[2], hd->Vendor); if (r != 1) { /* upsdebugx(2, "%s: failed match of %s: %s !~ %s", __func__, "Vendor", hd->Vendor, data->regex[2]); */ upsdebugx(2, "%s: failed match of %s: %s", __func__, "Vendor", hd->Vendor); return r; } r = match_regex(data->regex[3], hd->Product); if (r != 1) { /* upsdebugx(2, "%s: failed match of %s: %s !~ %s", __func__, "Product", hd->Product, data->regex[3]); */ upsdebugx(2, "%s: failed match of %s: %s", __func__, "Product", hd->Product); return r; } r = match_regex(data->regex[4], hd->Serial); if (r != 1) { /* upsdebugx(2, "%s: failed match of %s: %s !~ %s", __func__, "Serial", hd->Serial, data->regex[4]); */ upsdebugx(2, "%s: failed match of %s: %s", __func__, "Serial", hd->Serial); return r; } r = match_regex(data->regex[5], hd->Bus); if (r != 1) { /* upsdebugx(2, "%s: failed match of %s: %s !~ %s", __func__, "Bus", hd->Bus, data->regex[5]); */ upsdebugx(2, "%s: failed match of %s: %s", __func__, "Bus", hd->Bus); return r; } r = match_regex(data->regex[6], hd->Device); if (r != 1) { /* upsdebugx(2, "%s: failed match of %s: %s !~ %s", __func__, "Device", hd->Device, data->regex[6]); */ upsdebugx(2, "%s: failed match of %s: %s", __func__, "Device", hd->Device); return r; } #if (defined WITH_USB_BUSPORT) && (WITH_USB_BUSPORT) r = match_regex(data->regex[7], hd->BusPort); if (r != 1) { /* upsdebugx(2, "%s: failed match of %s: %s !~ %s", __func__, "Device", hd->Device, data->regex[6]); */ upsdebugx(2, "%s: failed match of %s: %s", __func__, "Bus Port", hd->BusPort); return r; } #endif return 1; } /* constructor: create a regular expression matcher. This matcher is * based on seven regular expression strings in regex_array[0..6], * corresponding to: vendorid, productid, vendor, product, serial, * bus, device. Any of these strings can be NULL, which matches * everything. Cflags are as in regcomp(3). Typical values for cflags * are REG_ICASE (case insensitive matching) and REG_EXTENDED (use * extended regular expressions). On success, return 0 and store the * matcher in *matcher. On error, return -1 with errno set, or return * i=1--7 to indicate that the regular expression regex_array[i-1] was * ill-formed (an error message can then be retrieved with * regerror(3)). */ int USBNewRegexMatcher(USBDeviceMatcher_t **matcher, char **regex, int cflags) { int r, i; USBDeviceMatcher_t *m; regex_matcher_data_t *data; m = malloc(sizeof(*m)); if (!m) { return -1; } data = calloc(1, sizeof(*data)); if (!data) { free(m); return -1; } m->match_function = &match_function_regex; m->privdata = (void *)data; m->next = NULL; for (i=0; i < USBMATCHER_REGEXP_ARRAY_LIMIT; i++) { r = compile_regex(&data->regex[i], regex[i], cflags); if (r == -2) { r = i+1; } if (r) { USBFreeRegexMatcher(m); return r; } } *matcher = m; return 0; } void USBFreeRegexMatcher(USBDeviceMatcher_t *matcher) { int i; regex_matcher_data_t *data; if (!matcher) { return; } data = (regex_matcher_data_t *)matcher->privdata; for (i = 0; i < USBMATCHER_REGEXP_ARRAY_LIMIT; i++) { if (!data->regex[i]) { continue; } regfree(data->regex[i]); free(data->regex[i]); } free(data); free(matcher); } void warn_if_bad_usb_port_filename(const char *fn) { /* USB drivers ignore the 'port' setting - log a notice * if it is not "auto". Note: per se, ignoring the port * (or internally the device_path variable from main.c) * is currently not a bug and is actually documented at * docs/config-notes.txt; however it is not something * evident to users during troubleshooting a device. * Documentation and common practice recommend port=auto * so here we warn during driver start if it has some * other value and users might think it is honoured. */ if (!fn) { upslogx(LOG_WARNING, "WARNING: %s(): port argument was not " "specified to the driver", __func__); return; } if (!strcmp(fn, "auto")) return; upslogx(LOG_WARNING, "WARNING: %s(): port argument specified to\n" " the driver is \"%s\" but USB drivers do " "not use it and rely on\n" " libusb walking all devices and matching " "their identification metadata.\n" " NUT documentation recommends port=\"auto\" " "for USB devices to avoid confusion.", __func__, fn); return; } nut-2.8.1/drivers/idowell-hid.c0000644000175000017500000001725614501607135013311 00000000000000/* idowell-hid.c - subdriver to monitor iDowell USB/HID devices with NUT * * Copyright (C) * 2003 - 2009 Arnaud Quette * 2005 - 2006 Peter Selinger * 2008 - 2009 Arjen de Korte * * Note: this subdriver was initially generated as a "stub" by the * gen-usbhid-subdriver script. It must be customized. * * 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 2 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, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "config.h" /* must be first */ #include "usbhid-ups.h" #include "idowell-hid.h" #include "main.h" /* for getval() */ #include "usb-common.h" #define IDOWELL_HID_VERSION "iDowell HID 0.2" /* FIXME: experimental flag to be put in upsdrv_info */ /* iDowell */ #define IDOWELL_VENDORID 0x075d /* USB IDs device table */ static usb_device_id_t idowell_usb_device_table[] = { /* iDowell */ { USB_DEVICE(IDOWELL_VENDORID, 0x0300), NULL }, /* Terminating entry */ { 0, 0, NULL } }; /* --------------------------------------------------------------- */ /* Vendor-specific usage table */ /* --------------------------------------------------------------- */ /* IDOWELL usage table */ static usage_lkp_t idowell_usage_lkp[] = { { NULL, 0 } }; static usage_tables_t idowell_utab[] = { idowell_usage_lkp, hid_usage_lkp, NULL, }; /* --------------------------------------------------------------- */ /* HID2NUT lookup table */ /* --------------------------------------------------------------- */ static hid_info_t idowell_hid2nut[] = { #if WITH_UNMAPPED_DATA_POINTS || (defined DEBUG) { "unmapped.ups.flow.[4].flowid", 0, 0, "UPS.Flow.[4].FlowID", NULL, "%.0f", 0, NULL }, { "unmapped.ups.powerconverter.output.outputid", 0, 0, "UPS.PowerConverter.Output.OutputID", NULL, "%.0f", 0, NULL }, { "unmapped.ups.powerconverter.powerconverterid", 0, 0, "UPS.PowerConverter.PowerConverterID", NULL, "%.0f", 0, NULL }, { "unmapped.ups.powersummary.capacitygranularity1", 0, 0, "UPS.PowerSummary.CapacityGranularity1", NULL, "%.0f", 0, NULL }, { "unmapped.ups.powersummary.capacitymode", 0, 0, "UPS.PowerSummary.CapacityMode", NULL, "%.0f", 0, NULL }, { "unmapped.ups.powersummary.flowid", 0, 0, "UPS.PowerSummary.FlowID", NULL, "%.0f", 0, NULL }, { "unmapped.ups.powersummary.fullchargecapacity", 0, 0, "UPS.PowerSummary.FullChargeCapacity", NULL, "%.0f", 0, NULL }, { "unmapped.ups.powersummary.imanufacturer", 0, 0, "UPS.PowerSummary.iManufacturer", NULL, "%.0f", 0, NULL }, { "unmapped.ups.powersummary.iproduct", 0, 0, "UPS.PowerSummary.iProduct", NULL, "%.0f", 0, NULL }, { "unmapped.ups.powersummary.iserialnumber", 0, 0, "UPS.PowerSummary.iSerialNumber", NULL, "%.0f", 0, NULL }, { "unmapped.ups.powersummary.powersummaryid", 0, 0, "UPS.PowerSummary.PowerSummaryID", NULL, "%.0f", 0, NULL }, { "unmapped.ups.powersummary.presentstatus.undefined", 0, 0, "UPS.PowerSummary.PresentStatus.Undefined", NULL, "%.0f", 0, NULL }, #endif /* if WITH_UNMAPPED_DATA_POINTS || DEBUG */ { "BOOL", 0, 0, "UPS.PowerSummary.PresentStatus.ACPresent", NULL, NULL, HU_FLAG_QUICK_POLL, online_info }, { "BOOL", 0, 0, "UPS.PowerSummary.PresentStatus.BelowRemainingCapacityLimit", NULL, NULL, HU_FLAG_QUICK_POLL, lowbatt_info }, { "BOOL", 0, 0, "UPS.PowerSummary.PresentStatus.Charging", NULL, NULL, HU_FLAG_QUICK_POLL, charging_info }, { "BOOL", 0, 0, "UPS.PowerSummary.PresentStatus.CommunicationLost", NULL, NULL, 0, commfault_info }, { "BOOL", 0, 0, "UPS.PowerSummary.PresentStatus.Discharging", NULL, NULL, HU_FLAG_QUICK_POLL, discharging_info }, { "BOOL", 0, 0, "UPS.PowerSummary.PresentStatus.Good", NULL, NULL, 0, off_info }, { "BOOL", 0, 0, "UPS.PowerSummary.PresentStatus.InternalFailure", NULL, NULL, 0, commfault_info }, { "BOOL", 0, 0, "UPS.PowerSummary.PresentStatus.NeedReplacement", NULL, NULL, 0, replacebatt_info }, { "BOOL", 0, 0, "UPS.PowerSummary.PresentStatus.Overload", NULL, NULL, 0, overload_info }, { "BOOL", 0, 0, "UPS.PowerSummary.PresentStatus.ShutdownImminent", NULL, NULL, 0, shutdownimm_info }, /* battery page */ { "battery.charge", 0, 0, "UPS.PowerSummary.RemainingCapacity", NULL, "%.0f", 0, NULL }, { "battery.charge.low", 0, 0, "UPS.PowerSummary.RemainingCapacityLimit", NULL, "%.0f", HU_FLAG_STATIC , NULL }, /* Read only */ { "battery.runtime", 0, 0, "UPS.PowerSummary.RunTimeToEmpty", NULL, "%.0f", 0, NULL }, { "battery.type", 0, 0, "UPS.PowerSummary.iDeviceChemistry", NULL, "%s", HU_FLAG_STATIC, stringid_conversion }, /* UPS page */ { "ups.delay.start", ST_FLAG_RW | ST_FLAG_STRING, 10, "UPS.PowerSummary.DelayBeforeStartup", NULL, DEFAULT_ONDELAY, HU_FLAG_ABSENT, NULL}, { "ups.delay.shutdown", ST_FLAG_RW | ST_FLAG_STRING, 10, "UPS.PowerSummary.DelayBeforeShutdown", NULL, DEFAULT_OFFDELAY, HU_FLAG_ABSENT, NULL}, { "ups.timer.start", 0, 0, "UPS.PowerSummary.DelayBeforeStartup", NULL, "%.0f", HU_FLAG_QUICK_POLL, NULL}, { "ups.timer.shutdown", 0, 0, "UPS.PowerSummary.DelayBeforeShutdown", NULL, "%.0f", HU_FLAG_QUICK_POLL, NULL}, { "ups.load", 0, 0, "UPS.PowerSummary.PercentLoad", NULL, "%.0f", 0, NULL }, { "ups.power.nominal", 0, 0, "UPS.Flow.[4].ConfigApparentPower", NULL, "%.0f", HU_FLAG_STATIC, NULL }, /* input page */ { "input.transfer.high", 0, 0, "UPS.PowerConverter.Output.HighVoltageTransfer", NULL, "%.0f", HU_FLAG_STATIC, NULL }, { "input.transfer.low", 0, 0, "UPS.PowerConverter.Output.LowVoltageTransfer", NULL, "%.0f", HU_FLAG_STATIC, NULL }, /* output page */ { "output.voltage", 0, 0, "UPS.PowerConverter.Output.Voltage", NULL, "%.1f", 0, NULL }, { "output.voltage.nominal", 0, 0, "UPS.Flow.[4].ConfigVoltage", NULL, "%.0f", HU_FLAG_STATIC, NULL }, { "output.frequency.nominal", 0, 0, "UPS.Flow.[4].ConfigFrequency", NULL, "%.0f", HU_FLAG_STATIC, NULL }, /* instant commands */ { "load.off.delay", 0, 0, "UPS.PowerSummary.DelayBeforeShutdown", NULL, DEFAULT_OFFDELAY, HU_TYPE_CMD, NULL }, { "load.on.delay", 0, 0, "UPS.PowerSummary.DelayBeforeStartup", NULL, DEFAULT_ONDELAY, HU_TYPE_CMD, NULL }, { "shutdown.stop", 0, 0, "UPS.PowerSummary.DelayBeforeShutdown", NULL, "-1", HU_TYPE_CMD, NULL }, /* end of structure. */ { NULL, 0, 0, NULL, NULL, NULL, 0, NULL } }; static const char *idowell_format_model(HIDDevice_t *hd) { return hd->Product; } static const char *idowell_format_mfr(HIDDevice_t *hd) { return hd->Vendor ? hd->Vendor : "iDowell"; } static const char *idowell_format_serial(HIDDevice_t *hd) { return hd->Serial; } /* this function allows the subdriver to "claim" a device: return 1 if * the device is supported by this subdriver, else 0. */ static int idowell_claim(HIDDevice_t *hd) { int status = is_usb_device_supported(idowell_usb_device_table, hd); switch (status) { case POSSIBLY_SUPPORTED: /* by default, reject, unless the productid option is given */ if (getval("productid")) { return 1; } possibly_supported("iDowell", hd); return 0; case SUPPORTED: return 1; case NOT_SUPPORTED: default: return 0; } } subdriver_t idowell_subdriver = { IDOWELL_HID_VERSION, idowell_claim, idowell_utab, idowell_hid2nut, idowell_format_model, idowell_format_mfr, idowell_format_serial, fix_report_desc, }; nut-2.8.1/drivers/nutdrv_qx_zinto.h0000644000175000017500000000174414273170601014364 00000000000000/* nutdrv_qx_zinto.h - Subdriver for Zinto protocol based UPSes * * Copyright (C) * 2013 Daniele Pezzini * * 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 2 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, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #ifndef NUTDRV_QX_ZINTO_H #define NUTDRV_QX_ZINTO_H #include "nutdrv_qx.h" extern subdriver_t zinto_subdriver; #endif /* NUTDRV_QX_ZINTO_H */ nut-2.8.1/drivers/baytech-mib.c0000644000175000017500000001146114501607135013264 00000000000000/* baytech-mib.c - data to monitor BayTech PDUs * * Copyright (C) 2009 * Opengear * Arnaud Quette * * 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 2 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, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #include "baytech-mib.h" /* NOTE: last badly versioned release was "4032" but should be "X.Y[Z]"! */ #define BAYTECH_MIB_VERSION "0.4035" /* Baytech MIB */ #define BAYTECH_OID_MIB ".1.3.6.1.4.1.4779" #define BAYTECH_OID_MODEL_NAME ".1.3.6.1.4.1.4779.1.3.5.2.1.24.1" static info_lkp_t baytech_outlet_status_info[] = { { -1, "error", NULL, NULL }, { 0, "off", NULL, NULL }, { 1, "on", NULL, NULL }, { 2, "cycling", NULL, NULL }, /* transitional status, "reboot" in MIB comments */ { 3, "lockon", NULL, NULL }, { 4, "lockoff", NULL, NULL }, { 5, "unlock", NULL, NULL }, { 6, "unknown", NULL, NULL }, { 0, NULL, NULL, NULL } }; /* Snmp2NUT lookup table for BayTech MIBs */ static snmp_info_t baytech_mib[] = { /* standard MIB items */ { "device.description", ST_FLAG_STRING | ST_FLAG_RW, SU_INFOSIZE, ".1.3.6.1.2.1.1.1.0", NULL, SU_FLAG_OK, NULL }, { "device.contact", ST_FLAG_STRING | ST_FLAG_RW, SU_INFOSIZE, ".1.3.6.1.2.1.1.4.0", NULL, SU_FLAG_OK, NULL }, { "device.location", ST_FLAG_STRING | ST_FLAG_RW, SU_INFOSIZE, ".1.3.6.1.2.1.1.6.0", NULL, SU_FLAG_OK, NULL }, /* Device page */ { "device.mfr", ST_FLAG_STRING, SU_INFOSIZE, NULL, "BayTech", SU_FLAG_STATIC | SU_FLAG_ABSENT | SU_FLAG_OK, NULL }, { "device.model", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.4779.1.3.5.2.1.24.1", "Generic SNMP PDU", SU_FLAG_STATIC | SU_FLAG_OK, NULL }, { "device.serial", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.4779.1.1.2.0", "", SU_FLAG_STATIC | SU_FLAG_OK, NULL }, { "device.type", ST_FLAG_STRING, SU_INFOSIZE, NULL, "pdu", SU_FLAG_STATIC | SU_FLAG_ABSENT | SU_FLAG_OK, NULL }, { "device.macaddr", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.2.1.2.2.1.6.2", "", SU_FLAG_STATIC | SU_FLAG_OK, NULL }, /* UPS page */ { "ups.mfr", ST_FLAG_STRING, SU_INFOSIZE, NULL, "Baytech", SU_FLAG_STATIC | SU_FLAG_ABSENT | SU_FLAG_OK, NULL }, { "ups.model", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.4779.1.3.5.2.1.24.1", "Generic SNMP PDU", SU_FLAG_STATIC | SU_FLAG_OK, NULL }, { "ups.id", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.4779.1.1.3.0", "unknown", SU_FLAG_STATIC | SU_FLAG_OK, NULL }, { "ups.serial", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.4779.1.1.2.0", "", SU_FLAG_STATIC | SU_FLAG_OK, NULL }, { "ups.firmware", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.4779.1.1.1.0", "", SU_FLAG_STATIC | SU_FLAG_OK, NULL }, { "ups.type", ST_FLAG_STRING, SU_INFOSIZE, NULL, "pdu", SU_FLAG_STATIC | SU_FLAG_ABSENT | SU_FLAG_OK, NULL }, { "ups.temperature", 0, 0.1, ".1.3.6.1.4.1.4779.1.3.5.5.1.10.2.1", NULL, 0, NULL }, /* Outlet page */ { "outlet.id", 0, 1, NULL, "0", SU_FLAG_STATIC | SU_FLAG_ABSENT | SU_FLAG_OK, NULL }, { "outlet.desc", ST_FLAG_RW | ST_FLAG_STRING, 20, NULL, "All outlets", SU_FLAG_STATIC | SU_FLAG_ABSENT | SU_FLAG_OK, NULL }, { "outlet.count", 0, 1, ".1.3.6.1.4.1.4779.1.3.5.2.1.15.1", "0", 0, NULL }, { "outlet.current", 0, 0.1, ".1.3.6.1.4.1.4779.1.3.5.5.1.6.2.1", NULL, 0, NULL }, { "outlet.voltage", 0, 0.1, ".1.3.6.1.4.1.4779.1.3.5.5.1.8.2.1", NULL, 0, NULL }, /* outlet template definition */ { "outlet.%i.status", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.4779.1.3.5.3.1.3.1.%i", NULL, SU_OUTLET, &baytech_outlet_status_info[0] }, { "outlet.%i.desc", ST_FLAG_RW | ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.4779.1.3.5.3.1.4.1.%i", NULL, SU_OUTLET, NULL }, { "outlet.%i.id", 0, 1, ".1.3.6.1.4.1.4779.1.3.5.6.1.3.2.1.%i", "%i", SU_FLAG_STATIC | SU_FLAG_ABSENT | SU_OUTLET | SU_FLAG_OK, NULL }, { "outlet.%i.switchable", 0, 1, ".1.3.6.1.4.1.4779.1.3.5.3.1.1.1.%i", "yes", SU_FLAG_STATIC | SU_OUTLET, NULL }, /* instant commands. */ { "outlet.%i.load.off", 0, 1, ".1.3.6.1.4.1.4779.1.3.5.3.1.3.1.%i", "0", SU_TYPE_CMD | SU_OUTLET, NULL }, { "outlet.%i.load.on", 0, 1, ".1.3.6.1.4.1.4779.1.3.5.3.1.3.1.%i", "1", SU_TYPE_CMD | SU_OUTLET, NULL }, /* end of structure. */ { NULL, 0, 0, NULL, NULL, 0, NULL } }; mib2nut_info_t baytech = { "baytech", BAYTECH_MIB_VERSION, NULL, BAYTECH_OID_MODEL_NAME, baytech_mib, BAYTECH_OID_MIB, NULL }; nut-2.8.1/drivers/bcmxcp_ser.h0000644000175000017500000000117314500336654013235 00000000000000/* * bcmxcp_ser.h -- header for BCM/XCP RS-232 module */ #ifndef BCMXCP_SER__ #define BCMXCP_SER__ #include "serial.h" /* pulls termios.h to define speed_t */ /* This header is needed for this line, to avoid warnings about it not * being static in C file (can't hide, is also needed by nut-scanner) */ extern unsigned char BCMXCP_AUTHCMD[4]; typedef struct { speed_t rate; /* Value like B19200 defined in termios.h; note: NOT the bitrate numerically */ size_t name; /* Actual rate... WHY is this "name" - number to print interactively? */ } pw_baud_rate_t; extern pw_baud_rate_t pw_baud_rates[]; #endif /* BCMXCP_SER__ */ nut-2.8.1/drivers/nutdrv_atcl_usb.c0000644000175000017500000004564514502253356014314 00000000000000/* * nutdrv_atcl_usb.c - driver for generic-brand "ATCL FOR UPS" * * Copyright (C) 2013-2014 Charles Lepple * Copyright (C) 2016 Eaton * * Loosely based on richcomm_usb.c, * Copyright (C) 2007 Peter van Valderen * Dirk Teurlings * * 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 2 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, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "main.h" #include "usb-common.h" /* driver version */ #define DRIVER_NAME "'ATCL FOR UPS' USB driver" #define DRIVER_VERSION "1.17" /* driver description structure */ upsdrv_info_t upsdrv_info = { DRIVER_NAME, DRIVER_VERSION, "Charles Lepple ", DRV_EXPERIMENTAL, { NULL } }; #define STATUS_ENDPOINT (USB_ENDPOINT_IN | 1) #define SHUTDOWN_ENDPOINT (USB_ENDPOINT_OUT | 2) #define STATUS_PACKETSIZE 8 #define SHUTDOWN_PACKETSIZE 8 /* Probably can reduce this, since the pcap file shows mostly 1050-ish ms response times */ #define ATCL_USB_TIMEOUT USB_TIMEOUT /* limit the amount of spew that goes in the syslog when we lose the UPS (from nut_usb.h) */ #define USB_ERR_LIMIT 10 /* start limiting after 10 in a row */ #define USB_ERR_RATE 10 /* then only print every 10th error */ #define USB_VENDOR_STRING "ATCL FOR UPS" static usb_device_id_t atcl_usb_id[] = { /* ATCL FOR UPS */ { USB_DEVICE(0x0001, 0x0000), NULL }, /* Terminating entry */ { 0, 0, NULL } }; static usb_dev_handle *udev = NULL; static USBDevice_t usbdevice; static unsigned int comm_failures = 0; static int device_match_func(USBDevice_t *device, void *privdata) { char *requested_vendor; NUT_UNUSED_VARIABLE(privdata); switch (is_usb_device_supported(atcl_usb_id, device)) { case SUPPORTED: if(!device->Vendor) { upsdebugx(1, "Couldn't retrieve USB string descriptor for vendor. Check permissions?"); requested_vendor = getval("vendor"); if(requested_vendor) { if(!strcmp("NULL", requested_vendor)) { upsdebugx(3, "Matched device with NULL vendor string."); return 1; } } upsdebugx(0, "To keep trying (in case your device does not have a vendor string), use vendor=NULL. " "Have you tried the nutdrv_qx driver?"); return 0; } if(!strcmp(device->Vendor, USB_VENDOR_STRING)) { upsdebugx(4, "Matched expected vendor='%s'.", USB_VENDOR_STRING); return 1; } /* Didn't match, but the user provided an alternate vendor ID: */ requested_vendor = getval("vendor"); if(requested_vendor) { if(!strcmp(device->Vendor, requested_vendor)) { upsdebugx(3, "Matched device with vendor='%s'.", requested_vendor); return 1; } else { upsdebugx(0, "idVendor=%04x and idProduct=%04x, " "but provided vendor '%s' does not match device: '%s'. " "Have you tried the nutdrv_qx driver?", device->VendorID, device->ProductID, requested_vendor, device->Vendor); return 0; } } /* TODO: automatic way of suggesting other drivers? */ upsdebugx(0, "idVendor=%04x and idProduct=%04x, " "but device vendor string '%s' does not match expected string '%s'. " "Have you tried the nutdrv_qx driver?", device->VendorID, device->ProductID, device->Vendor, USB_VENDOR_STRING); return 0; case POSSIBLY_SUPPORTED: case NOT_SUPPORTED: default: return 0; } } static USBDeviceMatcher_t device_matcher = { &device_match_func, NULL, NULL }; static int query_ups(char *reply) { int ret; ret = usb_interrupt_read(udev, STATUS_ENDPOINT, (usb_ctrl_charbuf)reply, STATUS_PACKETSIZE, ATCL_USB_TIMEOUT); if (ret <= 0) { upsdebugx(2, "status interrupt read: %s", ret ? nut_usb_strerror(ret) : "timeout"); return ret; } assert ((uintmax_t)ret < (uintmax_t)SIZE_MAX); upsdebug_hex(3, "read", reply, (size_t)ret); return ret; } static void usb_comm_fail(const char *fmt, ...) { int ret; char why[SMALLBUF]; va_list ap; /* this means we're probably here because select was interrupted */ if (exit_flag != 0) { return; /* ignored, since we're about to exit anyway */ } comm_failures++; if ((comm_failures == USB_ERR_LIMIT) || ((comm_failures % USB_ERR_RATE) == 0)) { upslogx(LOG_WARNING, "Warning: excessive comm failures, limiting error reporting"); } /* once it's past the limit, only log once every USB_ERR_LIMIT calls */ if ((comm_failures > USB_ERR_LIMIT) && ((comm_failures % USB_ERR_LIMIT) != 0)) { return; } /* generic message if the caller hasn't elaborated */ if (!fmt) { upslogx(LOG_WARNING, "Communications with UPS lost - check cabling"); return; } va_start(ap, fmt); #ifdef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL #pragma GCC diagnostic push #endif #ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL #pragma GCC diagnostic ignored "-Wformat-nonliteral" #endif #ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_FORMAT_SECURITY #pragma GCC diagnostic ignored "-Wformat-security" #endif ret = vsnprintf(why, sizeof(why), fmt, ap); #ifdef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL #pragma GCC diagnostic pop #endif va_end(ap); if ((ret < 1) || (ret >= (int) sizeof(why))) { upslogx(LOG_WARNING, "usb_comm_fail: vsnprintf needed more than %d bytes", (int)sizeof(why)); } upslogx(LOG_WARNING, "Communications with UPS lost: %s", why); } static void usb_comm_good(void) { if (comm_failures == 0) { return; } upslogx(LOG_NOTICE, "Communications with UPS re-established"); comm_failures = 0; } /* * Callback that is called by usb_device_open() that handles USB device * settings prior to accepting the devide. At the very least claim the * device here. Detaching the kernel driver will be handled by the * caller, don't do this here. Return < 0 on error, 0 or higher on * success. */ static int driver_callback(usb_dev_handle *handle, USBDevice_t *device) { int ret; NUT_UNUSED_VARIABLE(device); if ((ret = usb_set_configuration(handle, 1)) < 0) { upslogx(LOG_WARNING, "Can't set USB configuration: %s", nut_usb_strerror(ret)); return -1; } if ((ret = usb_claim_interface(handle, 0)) < 0) { upslogx(LOG_WARNING, "Can't claim USB interface: %s", nut_usb_strerror(ret)); return -1; } /* TODO: HID SET_IDLE to 0 (not necessary?) */ return 1; } static int usb_device_close(usb_dev_handle *handle) { int ret = 0; if (!handle) { return 0; } /* usb_release_interface() sometimes blocks and goes * into uninterruptible sleep. So don't do it. */ /* usb_release_interface(handle, 0); */ #if WITH_LIBUSB_1_0 libusb_close(handle); libusb_exit(NULL); #else ret = usb_close(handle); #endif return ret; } static int usb_device_open(usb_dev_handle **handlep, USBDevice_t *device, USBDeviceMatcher_t *matcher, int (*callback)(usb_dev_handle *handle, USBDevice_t *device)) { int ret = 0; uint8_t iManufacturer = 0, iProduct = 0, iSerialNumber = 0; #if WITH_LIBUSB_1_0 libusb_device **devlist; ssize_t devcount = 0; libusb_device_handle *handle; struct libusb_device_descriptor dev_desc; uint8_t bus_num; /* TODO: consider device_addr */ int i; #else /* => WITH_LIBUSB_0_1 */ struct usb_bus *bus; #endif /* libusb base init */ #if WITH_LIBUSB_1_0 if (libusb_init(NULL) < 0) { libusb_exit(NULL); fatal_with_errno(EXIT_FAILURE, "Failed to init libusb 1.0"); } #else /* => WITH_LIBUSB_0_1 */ usb_init(); usb_find_busses(); usb_find_devices(); #endif /* WITH_LIBUSB_1_0 */ #ifndef __linux__ /* SUN_LIBUSB (confirmed to work on Solaris and FreeBSD) */ /* Causes a double free corruption in linux if device is detached! */ /* usb_device_close(*handlep); */ if (*handlep) usb_close(*handlep); #endif #if WITH_LIBUSB_1_0 devcount = libusb_get_device_list(NULL, &devlist); if (devcount <= 0) fatal_with_errno(EXIT_FAILURE, "No USB device found"); for (i = 0; i < devcount; i++) { USBDeviceMatcher_t *m; libusb_device *dev = devlist[i]; libusb_get_device_descriptor(dev, &dev_desc); ret = libusb_open(dev, &handle); *handlep = handle; #else /* => WITH_LIBUSB_0_1 */ for (bus = usb_busses; bus; bus = bus->next) { struct usb_device *dev; usb_dev_handle *handle; for (dev = bus->devices; dev; dev = dev->next) { int i; USBDeviceMatcher_t *m; upsdebugx(3, "Checking USB device [%04x:%04x] (%s/%s)", dev->descriptor.idVendor, dev->descriptor.idProduct, bus->dirname, dev->filename); /* supported vendors are now checked by the supplied matcher */ /* open the device */ *handlep = handle = usb_open(dev); #endif /* WITH_LIBUSB_1_0 */ if (!handle) { upsdebugx(4, "Failed to open USB device, skipping: %s", nut_usb_strerror(ret)); continue; } /* collect the identifying information of this device. Note that this is safe, because there's no need to claim an interface for this (and therefore we do not yet need to detach any kernel drivers). */ free(device->Vendor); free(device->Product); free(device->Serial); free(device->Bus); memset(device, 0, sizeof(*device)); #if WITH_LIBUSB_1_0 device->VendorID = dev_desc.idVendor; device->ProductID = dev_desc.idProduct; bus_num = libusb_get_bus_number(dev); device->Bus = (char *)malloc(4); if (device->Bus == NULL) { libusb_free_device_list(devlist, 1); fatal_with_errno(EXIT_FAILURE, "Out of memory"); } sprintf(device->Bus, "%03d", bus_num); iManufacturer = dev_desc.iManufacturer; iProduct = dev_desc.iProduct; iSerialNumber = dev_desc.iSerialNumber; #else /* => WITH_LIBUSB_0_1 */ device->VendorID = dev->descriptor.idVendor; device->ProductID = dev->descriptor.idProduct; device->Bus = xstrdup(bus->dirname); iManufacturer = dev->descriptor.iManufacturer; iProduct = dev->descriptor.iProduct; iSerialNumber = dev->descriptor.iSerialNumber; #endif /* WITH_LIBUSB_1_0 */ if (iManufacturer) { char buf[SMALLBUF]; ret = usb_get_string_simple(handle, iManufacturer, (usb_ctrl_charbuf)buf, sizeof(buf)); if (ret > 0) { device->Vendor = strdup(buf); if (device->Vendor == NULL) { #if WITH_LIBUSB_1_0 libusb_free_device_list(devlist, 1); #endif /* WITH_LIBUSB_1_0 */ fatal_with_errno(EXIT_FAILURE, "Out of memory"); } } } if (iProduct) { char buf[SMALLBUF]; ret = usb_get_string_simple(handle, iProduct, (usb_ctrl_charbuf)buf, sizeof(buf)); if (ret > 0) { device->Product = strdup(buf); if (device->Product == NULL) { #if WITH_LIBUSB_1_0 libusb_free_device_list(devlist, 1); #endif /* WITH_LIBUSB_1_0 */ fatal_with_errno(EXIT_FAILURE, "Out of memory"); } } } if (iSerialNumber) { char buf[SMALLBUF]; ret = usb_get_string_simple(handle, iSerialNumber, (usb_ctrl_charbuf)buf, sizeof(buf)); if (ret > 0) { device->Serial = strdup(buf); if (device->Serial == NULL) { #if WITH_LIBUSB_1_0 libusb_free_device_list(devlist, 1); #endif /* WITH_LIBUSB_1_0 */ fatal_with_errno(EXIT_FAILURE, "Out of memory"); } } } upsdebugx(4, "- VendorID : %04x", device->VendorID); upsdebugx(4, "- ProductID : %04x", device->ProductID); upsdebugx(4, "- Manufacturer : %s", device->Vendor ? device->Vendor : "unknown"); upsdebugx(4, "- Product : %s", device->Product ? device->Product : "unknown"); upsdebugx(4, "- Serial Number: %s", device->Serial ? device->Serial : "unknown"); upsdebugx(4, "- Bus : %s", device->Bus ? device->Bus : "unknown"); for (m = matcher; m; m = m->next) { switch (m->match_function(device, m->privdata)) { case 0: upsdebugx(4, "Device does not match - skipping"); goto next_device; case -1: #if WITH_LIBUSB_1_0 libusb_free_device_list(devlist, 1); #endif /* WITH_LIBUSB_1_0 */ fatal_with_errno(EXIT_FAILURE, "matcher"); #ifndef HAVE___ATTRIBUTE__NORETURN # if (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_PUSH_POP) && (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_UNREACHABLE_CODE) # pragma GCC diagnostic push # pragma GCC diagnostic ignored "-Wunreachable-code" # endif goto next_device; # if (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_PUSH_POP) && (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_UNREACHABLE_CODE) # pragma GCC diagnostic pop # endif #endif case -2: upsdebugx(4, "matcher: unspecified error"); goto next_device; } } #ifdef HAVE_LIBUSB_SET_AUTO_DETACH_KERNEL_DRIVER /* First, try the auto-detach kernel driver method * This function is not available on FreeBSD 10.1-10.3 */ if ((ret = libusb_set_auto_detach_kernel_driver (udev, 1)) < 0) upsdebugx(2, "failed to auto detach kernel driver from USB device: %s", nut_usb_strerror((enum libusb_error)ret)); else upsdebugx(2, "auto detached kernel driver from USB device"); #endif /* HAVE_LIBUSB_SET_AUTO_DETACH_KERNEL_DRIVER */ for (i = 0; i < 3; i++) { ret = callback(handle, device); if (ret >= 0) { upsdebugx(3, "USB device [%04x:%04x] opened", device->VendorID, device->ProductID); #if WITH_LIBUSB_1_0 libusb_free_device_list(devlist, 1); #endif /* WITH_LIBUSB_1_0 */ return ret; } #if WITH_LIBUSB_0_1 && (defined HAVE_USB_DETACH_KERNEL_DRIVER_NP) /* this method requires at least libusb 0.1.8: * it forces device claiming by unbinding * attached driver... From libhid */ if ((ret = usb_detach_kernel_driver_np(handle, 0)) < 0) { upsdebugx(1, "failed to detach kernel driver from USB device: %s", nut_usb_strerror(ret)); } else { upsdebugx(4, "detached kernel driver from USB device..."); } #else # ifdef HAVE_LIBUSB_DETACH_KERNEL_DRIVER if ((ret = libusb_detach_kernel_driver(udev, 0)) < 0) { upsdebugx(4, "failed to detach kernel driver from USB device: %s", nut_usb_strerror(ret)); } else { upsdebugx(4, "detached kernel driver from USB device..."); } # else # ifdef HAVE_LIBUSB_DETACH_KERNEL_DRIVER_NP if ((ret = libusb_detach_kernel_driver_np(udev, 0)) < 0) { upsdebugx(4, "failed to detach kernel driver from USB device: %s", nut_usb_strerror(ret)); } else { upsdebugx(4, "detached kernel driver from USB device..."); } # endif /* HAVE_LIBUSB_DETACH_KERNEL_DRIVER_NP */ # endif /* HAVE_LIBUSB_DETACH_KERNEL_DRIVER */ #endif /* HAVE_USB_DETACH_KERNEL_DRIVER_NP or HAVE_LIBUSB_DETACH_KERNEL_DRIVER or HAVE_LIBUSB_DETACH_KERNEL_DRIVER_NP */ } #if WITH_LIBUSB_1_0 libusb_free_device_list(devlist, 1); #endif /* WITH_LIBUSB_1_0 */ fatalx(EXIT_FAILURE, "USB device [%04x:%04x] matches, but driver callback failed: %s", device->VendorID, device->ProductID, nut_usb_strerror(ret)); next_device: usb_close(handle); #if (!WITH_LIBUSB_1_0) /* => WITH_LIBUSB_0_1 */ } #endif /* WITH_LIBUSB_1_0 */ } *handlep = NULL; #if WITH_LIBUSB_1_0 libusb_free_device_list(devlist, 1); #endif /* WITH_LIBUSB_1_0 */ upsdebugx(3, "No matching USB device found"); return -1; } /* * Initialise the UPS */ void upsdrv_initups(void) { int i; upsdebugx(1, "Searching for USB device..."); for (i = 0; usb_device_open(&udev, &usbdevice, &device_matcher, &driver_callback) < 0; i++) { if (i < 3) { #ifdef WIN32 sleep(5); #else if (sleep(5) == 0) { #endif usb_comm_fail("Can't open USB device, retrying ..."); continue; #ifndef WIN32 } #endif } fatalx(EXIT_FAILURE, "Unable to find ATCL FOR UPS\n\n" "Things to try:\n" " - Connect UPS device to USB bus\n" " - Run this driver as another user (upsdrvctl -u or 'user=...' in ups.conf).\n" " See upsdrvctl(8) and ups.conf(5).\n\n" "Fatal error: unusable configuration"); } } void upsdrv_cleanup(void) { usb_device_close(udev); free(usbdevice.Vendor); free(usbdevice.Product); free(usbdevice.Serial); free(usbdevice.Bus); } void upsdrv_initinfo(void) { dstate_setinfo("ups.mfr", "%s", usbdevice.Vendor ? usbdevice.Vendor : "unknown"); dstate_setinfo("ups.model", "%s", usbdevice.Product ? usbdevice.Product : "unknown"); if(usbdevice.Serial && usbdevice.Product && strcmp(usbdevice.Serial, usbdevice.Product)) { /* Only set "ups.serial" if it isn't the same as "ups.model": */ dstate_setinfo("ups.serial", "%s", usbdevice.Serial); } dstate_setinfo("ups.vendorid", "%04x", usbdevice.VendorID); dstate_setinfo("ups.productid", "%04x", usbdevice.ProductID); } void upsdrv_updateinfo(void) { char reply[STATUS_PACKETSIZE]; int ret; if (!udev) { ret = usb_device_open(&udev, &usbdevice, &device_matcher, &driver_callback); if (ret < 0) { return; } } ret = query_ups(reply); if (ret != STATUS_PACKETSIZE) { usb_comm_fail("Query to UPS failed"); dstate_datastale(); usb_device_close(udev); udev = NULL; return; } usb_comm_good(); dstate_dataok(); status_init(); switch(reply[0]) { case 3: upsdebugx(2, "reply[0] = 0x%02x -> OL", reply[0]); status_set("OL"); break; case 2: upsdebugx(2, "reply[0] = 0x%02x -> LB", reply[0]); status_set("LB"); goto fallthrough_LB_means_OB; /* Note: the comment below existed for years, so wondering * if this device CAN set independently LB and OB? */ /* fall through */ case 1: fallthrough_LB_means_OB: upsdebugx(2, "reply[0] = 0x%02x -> OB", reply[0]); status_set("OB"); break; default: upslogx(LOG_ERR, "Unknown status: 0x%02x", reply[0]); } if(strnlen(reply + 1, 7) != 0) { upslogx(LOG_NOTICE, "Status bytes 1-7 are not all zero"); } status_commit(); } /* If the UPS is on battery, it should shut down about 30 seconds after * receiving this packet. */ void upsdrv_shutdown(void) { /* Not "const" because this mismatches arg type of usb_interrupt_write() */ char shutdown_packet[SHUTDOWN_PACKETSIZE] = { 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; int ret; upslogx(LOG_DEBUG, "%s: attempting to call usb_interrupt_write(01 00 00 00 00 00 00 00)", __func__); ret = usb_interrupt_write(udev, SHUTDOWN_ENDPOINT, (usb_ctrl_charbuf)shutdown_packet, SHUTDOWN_PACKETSIZE, ATCL_USB_TIMEOUT); if (ret <= 0) { upslogx(LOG_NOTICE, "%s: first usb_interrupt_write() failed: %s", __func__, ret ? nut_usb_strerror(ret) : "timeout"); } /* Totally guessing from the .pcap file here. TODO: configurable delay? */ usleep(170*1000); ret = usb_interrupt_write(udev, SHUTDOWN_ENDPOINT, (usb_ctrl_charbuf)shutdown_packet, SHUTDOWN_PACKETSIZE, ATCL_USB_TIMEOUT); if (ret <= 0) { upslogx(LOG_ERR, "%s: second usb_interrupt_write() failed: %s", __func__, ret ? nut_usb_strerror(ret) : "timeout"); } } void upsdrv_help(void) { } void upsdrv_makevartable(void) { /* NOTE: This driver uses a very custom device matching method, * so does not involve nut_usb_addvars() method like others do. */ addvar(VAR_VALUE, "vendor", "USB vendor string (or NULL if none)"); } nut-2.8.1/drivers/apcupsd-ups.c0000644000175000017500000002260514513167372013355 00000000000000/* apcupsd-ups.c - client for apcupsd 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 2 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, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "config.h" #ifndef WIN32 #include #include #include #include #else #include "wincompat.h" #endif #ifdef HAVE_POLL_H # include /* nfds_t */ #else typedef unsigned long int nfds_t; # ifndef POLLRDNORM # define POLLRDNORM 0x0100 # endif # ifndef POLLRDBAND # define POLLRDBAND 0x0200 # endif # ifndef POLLIN # define POLLIN (POLLRDNORM | POLLRDBAND) # endif # if ! HAVE_STRUCT_POLLFD typedef struct pollfd { SOCKET fd; short events; short revents; } pollfd_t; # define HAVE_STRUCT_POLLFD 1 # endif #endif /* !HAVE_POLL_H */ #include "main.h" #include "apcupsd-ups.h" #include "attribute.h" #include "nut_stdint.h" #define DRIVER_NAME "apcupsd network client UPS driver" #define DRIVER_VERSION "0.71" #define POLL_INTERVAL_MIN 10 /* driver description structure */ upsdrv_info_t upsdrv_info = { DRIVER_NAME, DRIVER_VERSION, "Andreas Steinmetz ", DRV_STABLE, { NULL } }; static uint16_t port=3551; static struct sockaddr_in host; static void process(char *item,char *data) { int i; char *p1; char *p2; for(i=0;nut_data[i].info_type;i++)if(!(nut_data[i].apcupsd_item)) dstate_setinfo(nut_data[i].info_type,"%s", nut_data[i].default_value); else if(!strcmp(nut_data[i].apcupsd_item,item)) switch(nut_data[i].drv_flags&~DU_FLAG_INIT) { case DU_FLAG_STATUS: status_init(); if(!strcmp(data,"COMMLOST")||!strcmp(data,"NETWORK ERROR")|| !strcmp(data,"ERROR"))status_set("OFF"); else if(!strcmp(data,"SELFTEST"))status_set("OB"); else for(;(data=strtok(data," "));data=NULL) { if(!strcmp(data,"CAL"))status_set("CAL"); else if(!strcmp(data,"TRIM"))status_set("TRIM"); else if(!strcmp(data,"BOOST"))status_set("BOOST"); else if(!strcmp(data,"ONLINE"))status_set("OL"); else if(!strcmp(data,"ONBATT"))status_set("OB"); else if(!strcmp(data,"OVERLOAD"))status_set("OVER"); else if(!strcmp(data,"SHUTTING DOWN")|| !strcmp(data,"LOWBATT"))status_set("LB"); else if(!strcmp(data,"REPLACEBATT"))status_set("RB"); else if(!strcmp(data,"NOBATT"))status_set("BYPASS"); } status_commit(); break; case DU_FLAG_DATE: if((p1=strchr(data,' '))) { *p1=0; dstate_setinfo(nut_data[i].info_type,"%s",data); *p1=' '; } else dstate_setinfo(nut_data[i].info_type,"%s",data); break; case DU_FLAG_TIME: if((p1=strchr(data,' '))) { *p1=0; if((p2=strchr(p1+1,' '))) { *p2=0; dstate_setinfo(nut_data[i].info_type,"%s",p1+1); *p2=' '; } else dstate_setinfo(nut_data[i].info_type,"%s",p1+1); *p1=' '; } break; case DU_FLAG_FW1: if((p1=strchr(data,'/'))) { for(;p1!=data;p1--)if(p1[-1]!=' ')break; if(*p1==' ') { *p1=0; dstate_setinfo(nut_data[i].info_type,"%s",data); *p1=' '; } else dstate_setinfo(nut_data[i].info_type,"%s",data); } else dstate_setinfo(nut_data[i].info_type,"%s",data); break; case DU_FLAG_FW2: if((p1=strchr(data,'/'))) { for(;*p1;p1++)if(p1[1]!=' ')break; if(*p1&&p1[1])dstate_setinfo(nut_data[i].info_type,"%s", p1+1); } break; default:if(nut_data[i].info_flags&ST_FLAG_STRING) { if((int)strlen(data)>(int)nut_data[i].info_len) data[(int)nut_data[i].info_len]=0; dstate_setinfo(nut_data[i].info_type,"%s",data); } else { #ifdef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL #pragma GCC diagnostic push #endif #ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL #pragma GCC diagnostic ignored "-Wformat-nonliteral" #endif #ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_FORMAT_SECURITY #pragma GCC diagnostic ignored "-Wformat-security" #endif /* default_value acts as a format string in this case */ dstate_setinfo(nut_data[i].info_type, nut_data[i].default_value, atof(data)*nut_data[i].info_len); #ifdef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL #pragma GCC diagnostic pop #endif } break; } } static int getdata(void) { ssize_t x; uint16_t n; char *item; char *data; struct pollfd p; char bfr[1024]; st_tree_timespec_t start; int ret = -1; #ifndef WIN32 int fd_flags; #else /* Note: while the code below uses "pollfd" for simplicity as it is * available in mingw headers (although poll() method usually is not), * WIN32 builds use WaitForMultipleObjects(); see also similar code * in upsd.c for networking. */ HANDLE event = NULL; #endif state_get_timestamp((st_tree_timespec_t *)&start); if (INVALID_FD_SOCK( (p.fd = socket(AF_INET, SOCK_STREAM, 0)) )) { upsdebugx(1,"socket error"); /* return -1; */ ret = -1; goto getdata_return; } if(connect(p.fd,(struct sockaddr *)&host,sizeof(host))) { upsdebugx(1,"can't connect to apcupsd"); /* close(p.fd); return -1; */ ret = -1; goto getdata_return; } #ifndef WIN32 /* WSAEventSelect automatically sets the socket to nonblocking mode */ fd_flags = fcntl(p.fd, F_GETFL); if (fd_flags == -1) { upsdebugx(1,"unexpected fcntl(fd, F_GETFL) failure"); /* close(p.fd); return -1; */ ret = -1; goto getdata_return; } fd_flags |= O_NONBLOCK; if(fcntl(p.fd, F_SETFL, fd_flags) == -1) { upsdebugx(1,"unexpected fcntl(fd, F_SETFL, fd_flags|O_NONBLOCK) failure"); /* close(p.fd); return -1; */ ret = -1; goto getdata_return; } #else event = CreateEvent( NULL, /* Security */ FALSE, /* auto-reset */ FALSE, /* initial state */ NULL); /* no name */ /* Associate socket event to the socket via its Event object */ WSAEventSelect( p.fd, event, FD_CONNECT ); #endif p.events=POLLIN; n=htons(6); x=write(p.fd,&n,2); x=write(p.fd,"status",6); /* TODO: double-check for poll() in configure script */ #ifndef WIN32 while(poll(&p,1,15000)==1) #else while (WaitForMultipleObjects(1, &event, FALSE, 15000) == WAIT_TIMEOUT) #endif { if(read(p.fd,&n,2)!=2) { upsdebugx(1,"apcupsd communication error"); ret = -1; goto getdata_return; } if(!(x=ntohs(n))) { ret = 0; goto getdata_return; } else if(x<0||x>=(int)sizeof(bfr)) /* Note: LGTM.com suggests "Comparison is always false because x >= 0" * for the line above, probably because ntohs() returns an uint type. * I am reluctant to fix this one, because googling for headers from * random OSes showed various types used as the return value (uint16_t, * unsigned_short, u_short, in_port_t...) */ { upsdebugx(1,"apcupsd communication error"); ret = -1; goto getdata_return; } #ifndef WIN32 if(poll(&p,1,15000)!=1)break; #else if (WaitForMultipleObjects(1, &event, FALSE, 15000) != WAIT_OBJECT_0) break; #endif if(read(p.fd,bfr,(size_t)x)!=x) { upsdebugx(1,"apcupsd communication error"); ret = -1; goto getdata_return; } bfr[x]=0; if(!(item=strtok(bfr," \t:\r\n"))) { upsdebugx(1,"apcupsd communication error"); ret = -1; goto getdata_return; } if(!(data=strtok(NULL,"\r\n"))) { upsdebugx(1,"apcupsd communication error"); ret = -1; goto getdata_return; } while(*data==' '||*data=='\t'||*data==':')data++; process(item,data); } upsdebugx(1,"unexpected connection close by apcupsd"); ret = -1; getdata_return: if (VALID_FD_SOCK(p.fd)) close(p.fd); #ifdef WIN32 if (event != NULL) CloseHandle(event); #endif /* Remove any unprotected entries not refreshed in this run */ for(x=0;nut_data[x].info_type;x++) if(!(nut_data[x].drv_flags & DU_FLAG_INIT) && !(nut_data[x].drv_flags & DU_FLAG_PRESERVE)) dstate_delinfo_olderthan(nut_data[x].info_type, &start); return ret; } void upsdrv_initinfo(void) { if(!port)fatalx(EXIT_FAILURE,"invalid host or port specified!"); if(getdata())fatalx(EXIT_FAILURE,"can't communicate with apcupsd!"); else dstate_dataok(); poll_interval = (poll_interval < POLL_INTERVAL_MIN) ? POLL_INTERVAL_MIN : poll_interval; } void upsdrv_updateinfo(void) { if(getdata())upslogx(LOG_ERR,"can't communicate with apcupsd!"); else dstate_dataok(); poll_interval = (poll_interval < POLL_INTERVAL_MIN) ? POLL_INTERVAL_MIN : poll_interval; } void upsdrv_shutdown(void) { /* replace with a proper shutdown function */ upslogx(LOG_ERR, "shutdown not supported"); set_exit_flag(-1); } void upsdrv_help(void) { } void upsdrv_makevartable(void) { } void upsdrv_initups(void) { char *p; struct hostent *h; #ifdef WIN32 WSADATA WSAdata; WSAStartup(2,&WSAdata); atexit((void(*)(void))WSACleanup); #endif if(device_path&&*device_path) { /* TODO: fix parsing since bare IPv6 addresses contain colons */ if((p=strchr(device_path,':'))) { int i; *p++=0; i=atoi(p); if(i<1||i>65535)i=0; port = (uint16_t)i; } } else device_path="localhost"; if(!(h=gethostbyname(device_path)))port=0; else memcpy(&host.sin_addr,h->h_addr,4); /* TODO: add IPv6 support */ host.sin_family=AF_INET; host.sin_port=htons(port); } void upsdrv_cleanup(void) { } nut-2.8.1/drivers/libhid.h0000644000175000017500000001303614501607135012340 00000000000000/*! * @file libhid.h * @brief HID Library - User API * * @author Copyright (C) 2003 - 2007 * Arnaud Quette && * Charles Lepple * Peter Selinger * Arjen de Korte * * This program is sponsored by MGE UPS SYSTEMS - opensource.mgeups.com * * 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 2 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, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * * -------------------------------------------------------------------------- */ #ifndef NUT_LIBHID_H_SEEN #define NUT_LIBHID_H_SEEN #include "config.h" #include #include "nut_stdint.h" #include "hidtypes.h" #include "timehead.h" #if (defined SHUT_MODE) && SHUT_MODE #include "libshut.h" typedef SHUTDevice_t HIDDevice_t; typedef char HIDDeviceMatcher_t; typedef usb_dev_handle hid_dev_handle_t; typedef shut_communication_subdriver_t communication_subdriver_t; #define HID_DEV_HANDLE_CLOSED (hid_dev_handle_t)(ERROR_FD_SER) #else /* !SHUT_MODE => USB */ #include "nut_libusb.h" /* includes usb-common.h */ typedef USBDevice_t HIDDevice_t; typedef USBDeviceMatcher_t HIDDeviceMatcher_t; typedef usb_dev_handle * hid_dev_handle_t; typedef usb_communication_subdriver_t communication_subdriver_t; #define HID_DEV_HANDLE_CLOSED (hid_dev_handle_t)(NULL) #endif /* SHUT_MODE / USB */ /* use explicit booleans */ #ifndef FALSE typedef enum ebool { FALSE, TRUE } bool_t; #else typedef int bool_t; #endif /* Device open modes */ #define MODE_OPEN 0 /* open a HID device for the first time */ #define MODE_REOPEN 1 /* reopen a HID device that was opened before */ #define MAX_TS 2 /* validity period of a gotten report (2 sec) */ /* ---------------------------------------------------------------------- */ /* structure to describe an item in a usage table */ typedef struct { const char *usage_name; const HIDNode_t usage_code; } usage_lkp_t; extern usage_lkp_t hid_usage_lkp[]; /* an object of type usage_tables_t is a NULL-terminated array of * pointers to individual usage tables. */ typedef usage_lkp_t *usage_tables_t; extern communication_subdriver_t *comm_driver; extern HIDDesc_t *pDesc; /* parsed Report Descriptor */ /* report buffer structure: holds data about most recent report for each given report id */ typedef struct reportbuf_s { time_t ts[256]; /* timestamp when report was retrieved */ size_t len[256]; /* size of report data */ unsigned char *data[256]; /* report data (allocated) */ } reportbuf_t; extern reportbuf_t *reportbuf; /* buffer for most recent reports */ extern size_t max_report_size; extern int interrupt_only; extern size_t interrupt_size; /* ---------------------------------------------------------------------- */ /* * HIDGetItemValue * -------------------------------------------------------------------------- */ int HIDGetItemValue(hid_dev_handle_t udev, const char *hidpath, double *Value, usage_tables_t *utab); /* * HIDGetItemString * -------------------------------------------------------------------------- */ char *HIDGetItemString(hid_dev_handle_t udev, const char *hidpath, char *buf, size_t buflen, usage_tables_t *utab); /* * HIDSetItemValue * -------------------------------------------------------------------------- */ bool_t HIDSetItemValue(hid_dev_handle_t udev, const char *hidpath, double value, usage_tables_t *utab); /* * GetItemData * -------------------------------------------------------------------------- */ HIDData_t *HIDGetItemData(const char *hidpath, usage_tables_t *utab); /* * GetDataItem * -------------------------------------------------------------------------- */ char *HIDGetDataItem(const HIDData_t *hiddata, usage_tables_t *utab); /* * HIDGetDataValue * -------------------------------------------------------------------------- */ int HIDGetDataValue(hid_dev_handle_t udev, HIDData_t *hiddata, double *Value, time_t age); /* * HIDSetDataValue * -------------------------------------------------------------------------- */ int HIDSetDataValue(hid_dev_handle_t udev, HIDData_t *hiddata, double Value); /* * HIDGetIndexString * -------------------------------------------------------------------------- */ char *HIDGetIndexString(hid_dev_handle_t udev, int Index, char *buf, size_t buflen); /* * HIDGetEvents * -------------------------------------------------------------------------- */ int HIDGetEvents(hid_dev_handle_t udev, HIDData_t **event, int eventlen); /* * Support functions * -------------------------------------------------------------------------- */ void HIDDumpTree(hid_dev_handle_t udev, HIDDevice_t *hd, usage_tables_t *utab); const char *HIDDataType(const HIDData_t *hiddata); void free_report_buffer(reportbuf_t *rbuf); reportbuf_t *new_report_buffer(HIDDesc_t *pDesc); #endif /* NUT_LIBHID_H_SEEN */ nut-2.8.1/drivers/explore-hid.h0000644000175000017500000000174214273170601013325 00000000000000/* explore-hid.h - this is a "stub" subdriver used to collect data * about HID UPS systems that are not yet supported. * * 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 2 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, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #ifndef EXPLORE_HID_H #define EXPLORE_HID_H #include "usbhid-ups.h" extern subdriver_t explore_subdriver; #endif /* EXPLORE_HID_H */ nut-2.8.1/drivers/eaton-pdu-marlin-mib.c0000644000175000017500000016101214502253356015022 00000000000000/* eaton-pdu-marlin-mib.c - data to monitor Eaton ePDUs branded as: * G2 Marlin SW / MI / MO / MA * G3 Shark SW / MI / MO / MA * * Copyright (C) 2008 - 2020 * Arnaud Quette * Arnaud Quette * Copyright (C) 2015 - 2017 * Jim Klimov * * Supported by Eaton * and previously MGE Office Protection Systems * * 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 2 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, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #include "eaton-pdu-marlin-mib.h" #if WITH_SNMP_LKP_FUN #include "eaton-pdu-marlin-helpers.h" #endif /* Eaton PDU-MIB - Marlin MIB * ************************** */ #define EATON_MARLIN_MIB_VERSION "0.69" #define EATON_MARLIN_SYSOID ".1.3.6.1.4.1.534.6.6.7" #define EATON_MARLIN_OID_MODEL_NAME ".1.3.6.1.4.1.534.6.6.7.1.2.1.2.0" static info_lkp_t marlin_outlet_status_info[] = { { 0, "off", NULL, NULL }, { 1, "on", NULL, NULL }, { 2, "pendingOff", NULL, NULL }, /* transitional status */ { 3, "pendingOn", NULL, NULL }, /* transitional status */ { 0, NULL, NULL, NULL } }; static info_lkp_t marlin_outletgroups_status_info[] = { { 0, "off", NULL, NULL }, { 1, "on", NULL, NULL }, { 2, "rebooting", NULL, NULL }, /* transitional status */ { 3, "mixed", NULL, NULL }, /* transitional status, not sure what it means! */ { 0, NULL, NULL, NULL } }; /* Ugly hack for older G2 ePDU: * having the matching OID present means that the outlet/unit is * switchable. So, it should not require this value lookup */ static info_lkp_t g2_unit_outlet_switchability_info[] = { { -1, "yes", NULL, NULL }, { 0, "yes", NULL, NULL }, { 0, NULL, NULL, NULL } }; static info_lkp_t marlin_outlet_switchability_info[] = { { 1, "yes", NULL, NULL }, /* switchable */ { 2, "no", NULL, NULL }, /* notSwitchable */ { 0, NULL, NULL, NULL } }; /* Overall outlets switchability info for the unit. * This is refined per-outlet, depending on user configuration, * possibly disabling switchability of some outlets */ static info_lkp_t marlin_unit_switchability_info[] = { { 0, "no", NULL, NULL }, /* unknown */ { 1, "yes", NULL, NULL }, /* switched */ { 2, "no", NULL, NULL }, /* advancedMonitored */ { 3, "yes", NULL, NULL }, /* managed */ { 4, "no", NULL, NULL }, /* monitored */ { 0, NULL, NULL, NULL } }; /* The physical type of outlet */ static info_lkp_t marlin_outlet_type_info[] = { { 0, "unknown", NULL, NULL }, { 1, "iecC13", NULL, NULL }, { 2, "iecC19", NULL, NULL }, { 10, "uk", NULL, NULL }, { 11, "french", NULL, NULL }, { 12, "schuko", NULL, NULL }, { 20, "nema515", NULL, NULL }, { 21, "nema51520", NULL, NULL }, { 22, "nema520", NULL, NULL }, { 23, "nemaL520", NULL, NULL }, { 24, "nemaL530", NULL, NULL }, { 25, "nema615", NULL, NULL }, { 26, "nema620", NULL, NULL }, { 27, "nemaL620", NULL, NULL }, { 28, "nemaL630", NULL, NULL }, { 29, "nemaL715", NULL, NULL }, { 30, "rf203p277", NULL, NULL }, { 0, NULL, NULL, NULL } }; static info_lkp_t marlin_ambient_presence_info[] = { { -1, "unknown", NULL, NULL }, { 0, "no", NULL, NULL }, /* disconnected */ { 1, "yes", NULL, NULL }, /* connected */ { 0, NULL, NULL, NULL } }; static info_lkp_t marlin_emp002_ambient_presence_info[] = { { 0, "unknown", NULL, NULL }, { 2, "yes", NULL, NULL }, /* communicationOK */ { 3, "no", NULL, NULL }, /* communicationLost */ { 0, NULL, NULL, NULL } }; static info_lkp_t marlin_threshold_status_info[] = { { 0, "good", NULL, NULL }, /* No threshold triggered */ { 1, "warning-low", NULL, NULL }, /* Warning low threshold triggered */ { 2, "critical-low", NULL, NULL }, /* Critical low threshold triggered */ { 3, "warning-high", NULL, NULL }, /* Warning high threshold triggered */ { 4, "critical-high", NULL, NULL }, /* Critical high threshold triggered */ { 0, NULL, NULL, NULL } }; static info_lkp_t marlin_threshold_frequency_status_info[] = { { 0, "good", NULL, NULL }, /* No threshold triggered */ { 1, "out-of-range", NULL, NULL }, /* Frequency out of range triggered */ { 0, NULL, NULL, NULL } }; static info_lkp_t marlin_ambient_drycontacts_info[] = { { -1, "unknown", NULL, NULL }, { 0, "opened", NULL, NULL }, { 1, "closed", NULL, NULL }, { 0, NULL, NULL, NULL } }; static info_lkp_t marlin_threshold_voltage_alarms_info[] = { { 0, "", NULL, NULL }, /* No threshold triggered */ { 1, "low voltage warning!", NULL, NULL }, /* Warning low threshold triggered */ { 2, "low voltage critical!", NULL, NULL }, /* Critical low threshold triggered */ { 3, "high voltage warning!", NULL, NULL }, /* Warning high threshold triggered */ { 4, "high voltage critical!", NULL, NULL }, /* Critical high threshold triggered */ { 0, NULL, NULL, NULL } }; static info_lkp_t marlin_threshold_current_alarms_info[] = { { 0, "", NULL, NULL }, /* No threshold triggered */ { 1, "low current warning!", NULL, NULL }, /* Warning low threshold triggered */ { 2, "low current critical!", NULL, NULL }, /* Critical low threshold triggered */ { 3, "high current warning!", NULL, NULL }, /* Warning high threshold triggered */ { 4, "high current critical!", NULL, NULL }, /* Critical high threshold triggered */ { 0, NULL, NULL, NULL } }; static info_lkp_t marlin_threshold_frequency_alarm_info[] = { { 0, "", NULL, NULL }, /* No threshold triggered */ { 1, "frequency out of range!", NULL, NULL }, /* Frequency out of range triggered */ { 0, NULL, NULL, NULL } }; static info_lkp_t marlin_threshold_temperature_alarms_info[] = { { 0, "", NULL, NULL }, /* No threshold triggered */ { 1, "low temperature warning!", NULL, NULL }, /* Warning low threshold triggered */ { 2, "low temperature critical!", NULL, NULL }, /* Critical low threshold triggered */ { 3, "high temperature warning!", NULL, NULL }, /* Warning high threshold triggered */ { 4, "high temperature critical!", NULL, NULL }, /* Critical high threshold triggered */ { 0, NULL, NULL, NULL } }; static info_lkp_t marlin_threshold_humidity_alarms_info[] = { { 0, "", NULL, NULL }, /* No threshold triggered */ { 1, "low humidity warning!", NULL, NULL }, /* Warning low threshold triggered */ { 2, "low humidity critical!", NULL, NULL }, /* Critical low threshold triggered */ { 3, "high humidity warning!", NULL, NULL }, /* Warning high threshold triggered */ { 4, "high humidity critical!", NULL, NULL }, /* Critical high threshold triggered */ { 0, NULL, NULL, NULL } }; static info_lkp_t marlin_outlet_group_type_info[] = { { 0, "unknown", NULL, NULL }, { 1, "breaker1pole", NULL, NULL }, { 2, "breaker2pole", NULL, NULL }, { 3, "breaker3pole", NULL, NULL }, { 4, "outlet-section", NULL, NULL }, { 5, "user-defined", NULL, NULL }, { 0, NULL, NULL, NULL } }; static info_lkp_t marlin_input_type_info[] = { { 1, "1", NULL, NULL }, /* singlePhase */ { 2, "2", NULL, NULL }, /* splitPhase */ { 3, "3", NULL, NULL }, /* threePhaseDelta */ { 4, "3", NULL, NULL }, /* threePhaseWye */ { 0, NULL, NULL, NULL } }; static info_lkp_t marlin_outlet_group_phase_info[] = { { 0, "unknown", NULL, NULL }, /* unknown */ { 1, "1", NULL, NULL }, /* singlePhase */ { 2, "1-N", NULL, NULL }, /* phase1toN */ { 3, "2-N", NULL, NULL }, /* phase2toN */ { 4, "3-N", NULL, NULL }, /* phase3toN */ { 5, "1-2", NULL, NULL }, /* phase1to2 */ { 6, "2-3", NULL, NULL }, /* phase2to3 */ { 7, "3-1", NULL, NULL }, /* phase3to1 */ { 0, NULL, NULL, NULL } }; #if WITH_SNMP_LKP_FUN /* Note: eaton_sensor_temperature_unit_fun() is defined in eaton-pdu-marlin-helpers.c * and su_temperature_read_fun() is in snmp-ups.c * Future work for DMF might provide same-named routines via LUA-C gateway. */ #if WITH_SNMP_LKP_FUN_DUMMY /* Temperature unit consideration */ const char *eaton_sensor_temperature_unit_fun(void *raw_snmp_value) { /* snmp_value here would be a (long*) */ NUT_UNUSED_VARIABLE(raw_snmp_value); return "unknown"; } /* FIXME: please DMF, though this should be in snmp-ups.c or equiv. */ const char *su_temperature_read_fun(void *raw_snmp_value) { /* snmp_value here would be a (long*) */ NUT_UNUSED_VARIABLE(raw_snmp_value); return "dummy"; } #endif // WITH_SNMP_LKP_FUN_DUMMY static info_lkp_t eaton_sensor_temperature_unit_info[] = { { 0, "dummy", eaton_sensor_temperature_unit_fun, NULL }, { 0, NULL, NULL, NULL } }; static info_lkp_t eaton_sensor_temperature_read_info[] = { { 0, "dummy", su_temperature_read_fun, NULL }, { 0, NULL, NULL, NULL } }; #else // if not WITH_SNMP_LKP_FUN: /* FIXME: For now, DMF codebase falls back to old implementation with static * lookup/mapping tables for this, which can easily go into the DMF XML file. */ static info_lkp_t eaton_sensor_temperature_unit_info[] = { { 0, "kelvin", NULL, NULL }, { 1, "celsius", NULL, NULL }, { 2, "fahrenheit", NULL, NULL }, { 0, NULL, NULL, NULL } }; #endif // WITH_SNMP_LKP_FUN /* Extracted from powerware-mib.c ; try to commonalize */ static info_lkp_t marlin_ambient_drycontacts_polarity_info[] = { { 0, "normal-opened", NULL, NULL }, { 1, "normal-closed", NULL, NULL }, { 0, NULL, NULL, NULL } }; static info_lkp_t marlin_ambient_drycontacts_state_info[] = { { 0, "inactive", NULL, NULL }, { 1, "active", NULL, NULL }, { 0, NULL, NULL, NULL } }; #if WITH_SNMP_LKP_FUN /* Note: marlin_device_count_fun() is defined in eaton-pdu-marlin-helpers.c * Future work for DMF might provide a same-named routine via LUA-C gateway. */ # if WITH_SNMP_LKP_FUN_DUMMY long marlin_device_count_fun(const char *daisy_dev_list) { return 1; } # endif /* WITH_SNMP_LKP_FUN_DUMMY */ static info_lkp_t marlin_device_count_info[] = { { 1, "dummy", NULL, marlin_device_count_fun }, { 0, NULL, NULL, NULL } }; #else /* if not WITH_SNMP_LKP_FUN: */ /* FIXME: For now, DMF codebase falls back to old implementation with static * lookup/mapping tables for this, which can easily go into the DMF XML file. */ #endif /* WITH_SNMP_LKP_FUN */ /* Snmp2NUT lookup table for Eaton Marlin MIB */ static snmp_info_t eaton_marlin_mib[] = { /* standard MIB items */ { "device.description", ST_FLAG_STRING | ST_FLAG_RW, SU_INFOSIZE, ".1.3.6.1.2.1.1.1.0", NULL, SU_FLAG_OK, NULL }, { "device.contact", ST_FLAG_STRING | ST_FLAG_RW, SU_INFOSIZE, ".1.3.6.1.2.1.1.4.0", NULL, SU_FLAG_OK, NULL }, { "device.location", ST_FLAG_STRING | ST_FLAG_RW, SU_INFOSIZE, ".1.3.6.1.2.1.1.6.0", NULL, SU_FLAG_OK, NULL }, /* Device collection */ { "device.mfr", ST_FLAG_STRING, SU_INFOSIZE, NULL, "EATON", SU_FLAG_STATIC | SU_FLAG_ABSENT | SU_FLAG_OK, NULL }, { "device.model", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.534.6.6.7.1.2.1.2.%i", "Eaton Powerware ePDU", SU_FLAG_STATIC | SU_FLAG_OK, NULL }, { "device.serial", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.534.6.6.7.1.2.1.4.%i", "", SU_FLAG_STATIC | SU_FLAG_OK, NULL }, { "device.type", ST_FLAG_STRING, SU_INFOSIZE, NULL, "pdu", SU_FLAG_STATIC | SU_FLAG_ABSENT | SU_FLAG_OK, NULL }, { "device.part", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.534.6.6.7.1.2.1.3.%i", "", SU_FLAG_STATIC | SU_FLAG_OK, NULL }, /* For daisychain, there is only 1 physical interface! */ { "device.macaddr", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.2.1.2.2.1.6.2", "", SU_FLAG_STATIC | SU_FLAG_OK, NULL }, /* Daisychained devices support */ /* FIXME : Should this be a static value, or can we expect the amount of * daisy-chained devices to change without restart of the driver by user? * If this is a critical matter, should a detected change of amount of * daisy-chained devices, outlet counts, etc. cause restart/reinit of * this running driver instance? */ #if WITH_SNMP_LKP_FUN /* Number of daisychained units is processed according to present units * in the chain with new G3 firmware (02.00.0051, since autumn 2017): * Take string "unitsPresent" (ex: "0,3,4,5"), and count the amount * of "," separators+1 using an inline function */ /* FIXME: inline func */ { "device.count", 0, 1, ".1.3.6.1.4.1.534.6.6.7.1.1.0", "0", SU_FLAG_STATIC | SU_FLAG_UNIQUE, &marlin_device_count_info[0] /* devices_count */ }, #endif /* Notes: this older/fallback definition is used to: * - estimate the number of devices, based on the below OID iteration capabilities * - determine the base index of the SNMP OID (ie 0 or 1) */ { "device.count", 0, 1, ".1.3.6.1.4.1.534.6.6.7.1.2.1.2.%i", "1", SU_FLAG_STATIC #if WITH_SNMP_LKP_FUN | SU_FLAG_UNIQUE #endif , NULL /* devices_count */ }, /* UPS collection */ { "ups.mfr", ST_FLAG_STRING, SU_INFOSIZE, NULL, "EATON", SU_FLAG_STATIC | SU_FLAG_ABSENT | SU_FLAG_OK, NULL }, { "ups.model", ST_FLAG_STRING, SU_INFOSIZE, "1.3.6.1.4.1.534.6.6.7.1.2.1.2.%i", "Eaton Powerware ePDU", SU_FLAG_STATIC | SU_FLAG_OK, NULL }, /* FIXME: use unitName.0 (ePDU)? * { "ups.id", ST_FLAG_STRING, SU_INFOSIZE, AR_OID_DEVICE_NAME, "unknown", SU_FLAG_STATIC | SU_FLAG_OK, NULL }, */ { "ups.serial", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.534.6.6.7.1.2.1.4.%i", "", SU_FLAG_STATIC | SU_FLAG_OK, NULL }, /* FIXME: this entry should be SU_FLAG_SEMI_STATIC */ { "ups.firmware", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.534.6.6.7.1.2.1.5.%i", "", SU_FLAG_OK, NULL }, { "ups.type", ST_FLAG_STRING, SU_INFOSIZE, NULL, "pdu", SU_FLAG_STATIC | SU_FLAG_ABSENT | SU_FLAG_OK, NULL }, /* FIXME: needs a date reformatting callback * 2011-8-29,16:27:25.0,+1:0 * Hex-STRING: 07 DB 08 1D 10 0C 36 00 2B 01 00 00 * { "ups.date", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.534.6.6.7.1.2.1.8.0", "", SU_FLAG_STATIC | SU_FLAG_OK, NULL }, * { "ups.time", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.534.6.6.7.1.2.1.8.0", "", SU_FLAG_STATIC | SU_FLAG_OK, NULL }, */ /* Input collection */ /* Note: a larger ePDU can have several inputs. The "%i" iterators * in key names are currently available for daisychain devs, outlets, * and groups - but not for inputs. These would likely evolve later * to "input.%i.something" with default (non-%i) same as .1 instance. * At this time only a single-input (or first of several inputs) is * supported by this mapping. */ /* Historically, some of these data were previously published as * outlet.{realpower,...} * However, it's more suitable and logic to have these on input.{...} */ /* Note: the below gives the number of input, not the number of phase(s)! */ /* inputCount.0; Value (Integer): 1 { "input.count", 0, 1, ".1.3.6.1.4.1.534.6.6.7.1.2.1.20.0", NULL, SU_FLAG_STATIC, NULL }, */ /* Note: for daisychain mode, we must handle phase(s) per device, * not as a whole. In case of daisychain, support of the UNIQUE * field is not yet implemented (FIXME) so the last resolved OID * value wins. If a more-preferable OID is not implemented by device, * this is ok - the previous available value remains in place. */ /* inputType.%i.1 = INTEGER: singlePhase (1) */ { "input.phases", 0, 1, ".1.3.6.1.4.1.534.6.6.7.3.1.1.2.%i.1", NULL, SU_FLAG_STATIC, &marlin_input_type_info[0] }, /* Frequency is measured globally */ { "input.frequency", 0, 0.1, ".1.3.6.1.4.1.534.6.6.7.3.1.1.3.%i.1", NULL, 0, NULL }, { "input.frequency.status", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.534.6.6.7.3.1.1.4.%i.1", NULL, SU_FLAG_OK, &marlin_threshold_frequency_status_info[0] }, { "ups.alarm", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.534.6.6.7.3.1.1.4.%i.1", NULL, SU_FLAG_OK, &marlin_threshold_frequency_alarm_info[0] }, /* inputCurrentPercentLoad (measured globally) * Current percent load, based on the rated current capacity */ /* FIXME: input.load is mapped on input.L1.load for both single and 3phase !!! */ { "input.load", 0, 1.0, ".1.3.6.1.4.1.534.6.6.7.3.3.1.11.%i.1.1", NULL, SU_FLAG_NEGINVALID | SU_FLAG_OK, NULL }, { "input.L1.load", 0, 1.0, ".1.3.6.1.4.1.534.6.6.7.3.3.1.11.%i.1.1", NULL, SU_FLAG_NEGINVALID | SU_FLAG_OK, NULL }, { "input.L2.load", 0, 1.0, ".1.3.6.1.4.1.534.6.6.7.3.3.1.11.%i.1.2", NULL, SU_FLAG_NEGINVALID | SU_FLAG_OK, NULL }, { "input.L3.load", 0, 1.0, ".1.3.6.1.4.1.534.6.6.7.3.3.1.11.%i.1.3", NULL, SU_FLAG_NEGINVALID | SU_FLAG_OK, NULL }, /* FIXME: * - Voltage is only measured per phase, as mV! * so input.voltage == input.L1.voltage for both single and 3phase * - As per NUT namespace (https://www.networkupstools.org/docs/developer-guide.chunked/apas01.html#_valid_contexts) * Voltage has to be expressed either phase-phase or phase-neutral * This is depending on OID inputVoltageMeasType * INTEGER {singlePhase (1),phase1toN (2),phase2toN (3),phase3toN (4),phase1to2 (5),phase2to3 (6),phase3to1 (7) * => RFC input.Lx.voltage.context */ { "input.voltage", 0, 0.001, ".1.3.6.1.4.1.534.6.6.7.3.2.1.3.%i.1.1", NULL, 0, NULL }, { "input.voltage.status", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.534.6.6.7.3.2.1.4.%i.1.1", NULL, SU_FLAG_OK, &marlin_threshold_status_info[0] }, { "ups.alarm", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.534.6.6.7.3.2.1.4.%i.1.1", NULL, SU_FLAG_OK, &marlin_threshold_voltage_alarms_info[0] }, { "input.voltage.low.warning", ST_FLAG_RW, 0.001, ".1.3.6.1.4.1.534.6.6.7.3.2.1.5.%i.1.1", NULL, SU_FLAG_NEGINVALID, NULL }, { "input.voltage.low.critical", ST_FLAG_RW, 0.001, ".1.3.6.1.4.1.534.6.6.7.3.2.1.6.%i.1.1", NULL, SU_FLAG_NEGINVALID, NULL }, { "input.voltage.high.warning", ST_FLAG_RW, 0.001, ".1.3.6.1.4.1.534.6.6.7.3.2.1.7.%i.1.1", NULL, SU_FLAG_NEGINVALID, NULL }, { "input.voltage.high.critical", ST_FLAG_RW, 0.001, ".1.3.6.1.4.1.534.6.6.7.3.2.1.8.%i.1.1", NULL, SU_FLAG_NEGINVALID, NULL }, { "input.L1.voltage", 0, 0.001, ".1.3.6.1.4.1.534.6.6.7.3.2.1.3.%i.1.1", NULL, 0, NULL }, { "input.L1.voltage.status", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.534.6.6.7.3.2.1.4.%i.1.1", NULL, SU_FLAG_OK, &marlin_threshold_status_info[0] }, { "L1.alarm", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.534.6.6.7.3.2.1.4.%i.1.1", NULL, SU_FLAG_OK, &marlin_threshold_voltage_alarms_info[0] }, { "input.L1.voltage.low.warning", ST_FLAG_RW, 0.001, ".1.3.6.1.4.1.534.6.6.7.3.2.1.5.%i.1.1", NULL, SU_FLAG_NEGINVALID, NULL }, { "input.L1.voltage.low.critical", ST_FLAG_RW, 0.001, ".1.3.6.1.4.1.534.6.6.7.3.2.1.6.%i.1.1", NULL, SU_FLAG_NEGINVALID, NULL }, { "input.L1.voltage.high.warning", ST_FLAG_RW, 0.001, ".1.3.6.1.4.1.534.6.6.7.3.2.1.7.%i.1.1", NULL, SU_FLAG_NEGINVALID, NULL }, { "input.L1.voltage.high.critical", ST_FLAG_RW, 0.001, ".1.3.6.1.4.1.534.6.6.7.3.2.1.8.%i.1.1", NULL, SU_FLAG_NEGINVALID, NULL }, { "input.L2.voltage", 0, 0.001, ".1.3.6.1.4.1.534.6.6.7.3.2.1.3.%i.1.2", NULL, 0, NULL }, { "input.L2.voltage.status", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.534.6.6.7.3.2.1.4.%i.1.2", NULL, SU_FLAG_OK, &marlin_threshold_status_info[0] }, { "L2.alarm", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.534.6.6.7.3.2.1.4.%i.1.2", NULL, SU_FLAG_OK, &marlin_threshold_voltage_alarms_info[0] }, { "input.L2.voltage.low.warning", ST_FLAG_RW, 0.001, ".1.3.6.1.4.1.534.6.6.7.3.2.1.5.%i.1.2", NULL, SU_FLAG_NEGINVALID, NULL }, { "input.L2.voltage.low.critical", ST_FLAG_RW, 0.001, ".1.3.6.1.4.1.534.6.6.7.3.2.1.6.%i.1.2", NULL, SU_FLAG_NEGINVALID, NULL }, { "input.L2.voltage.high.warning", ST_FLAG_RW, 0.001, ".1.3.6.1.4.1.534.6.6.7.3.2.1.7.%i.1.2", NULL, SU_FLAG_NEGINVALID, NULL }, { "input.L2.voltage.high.critical", ST_FLAG_RW, 0.001, ".1.3.6.1.4.1.534.6.6.7.3.2.1.8.%i.1.2", NULL, SU_FLAG_NEGINVALID, NULL }, { "input.L3.voltage", 0, 0.001, ".1.3.6.1.4.1.534.6.6.7.3.2.1.3.%i.1.3", NULL, 0, NULL }, { "input.L3.voltage.status", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.534.6.6.7.3.2.1.4.%i.1.3", NULL, SU_FLAG_OK, &marlin_threshold_status_info[0] }, { "L3.alarm", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.534.6.6.7.3.2.1.4.%i.1.3", NULL, SU_FLAG_OK, &marlin_threshold_voltage_alarms_info[0] }, { "input.L3.voltage.low.warning", ST_FLAG_RW, 0.001, ".1.3.6.1.4.1.534.6.6.7.3.2.1.5.%i.1.3", NULL, SU_FLAG_NEGINVALID, NULL }, { "input.L3.voltage.low.critical", ST_FLAG_RW, 0.001, ".1.3.6.1.4.1.534.6.6.7.3.2.1.6.%i.1.3", NULL, SU_FLAG_NEGINVALID, NULL }, { "input.L3.voltage.high.warning", ST_FLAG_RW, 0.001, ".1.3.6.1.4.1.534.6.6.7.3.2.1.7.%i.1.3", NULL, SU_FLAG_NEGINVALID, NULL }, { "input.L3.voltage.high.critical", ST_FLAG_RW, 0.001, ".1.3.6.1.4.1.534.6.6.7.3.2.1.8.%i.1.3", NULL, SU_FLAG_NEGINVALID, NULL }, /* FIXME: * - input.current is mapped on input.L1.current for both single and 3phase !!! */ { "input.current", 0, 0.001, ".1.3.6.1.4.1.534.6.6.7.3.3.1.4.%i.1.1", NULL, 0, NULL }, { "input.current.nominal", 0, 0.001, ".1.3.6.1.4.1.534.6.6.7.3.3.1.3.%i.1.1", NULL, 0, NULL }, { "input.current.status", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.534.6.6.7.3.3.1.5.%i.1.1", NULL, SU_FLAG_OK, &marlin_threshold_status_info[0] }, { "ups.alarm", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.534.6.6.7.3.3.1.5.%i.1.1", NULL, SU_FLAG_OK, &marlin_threshold_current_alarms_info[0] }, { "input.current.low.warning", ST_FLAG_RW, 0.001, ".1.3.6.1.4.1.534.6.6.7.3.3.1.6.%i.1.1", NULL, SU_FLAG_NEGINVALID, NULL }, { "input.current.low.critical", ST_FLAG_RW, 0.001, ".1.3.6.1.4.1.534.6.6.7.3.3.1.7.%i.1.1", NULL, SU_FLAG_NEGINVALID, NULL }, { "input.current.high.warning", ST_FLAG_RW, 0.001, ".1.3.6.1.4.1.534.6.6.7.3.3.1.8.%i.1.1", NULL, SU_FLAG_NEGINVALID, NULL }, { "input.current.high.critical", ST_FLAG_RW, 0.001, ".1.3.6.1.4.1.534.6.6.7.3.3.1.9.%i.1.1", NULL, SU_FLAG_NEGINVALID, NULL }, { "input.L1.current", 0, 0.001, ".1.3.6.1.4.1.534.6.6.7.3.3.1.4.0.1.1", NULL, 0, NULL }, { "input.L1.current.nominal", 0, 0.001, ".1.3.6.1.4.1.534.6.6.7.3.3.1.3.%i.1.1", NULL, 0, NULL }, { "input.L1.current.status", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.534.6.6.7.3.3.1.5.%i.1.1", NULL, SU_FLAG_OK, &marlin_threshold_status_info[0] }, { "L1.alarm", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.534.6.6.7.3.3.1.5.%i.1.1", NULL, SU_FLAG_OK, &marlin_threshold_current_alarms_info[0] }, { "input.L1.current.low.warning", ST_FLAG_RW, 0.001, ".1.3.6.1.4.1.534.6.6.7.3.3.1.6.%i.1.1", NULL, SU_FLAG_NEGINVALID, NULL }, { "input.L1.current.low.critical", ST_FLAG_RW, 0.001, ".1.3.6.1.4.1.534.6.6.7.3.3.1.7.%i.1.1", NULL, SU_FLAG_NEGINVALID, NULL }, { "input.L1.current.high.warning", ST_FLAG_RW, 0.001, ".1.3.6.1.4.1.534.6.6.7.3.3.1.8.%i.1.1", NULL, SU_FLAG_NEGINVALID, NULL }, { "input.L1.current.high.critical", ST_FLAG_RW, 0.001, ".1.3.6.1.4.1.534.6.6.7.3.3.1.9.%i.1.1", NULL, SU_FLAG_NEGINVALID, NULL }, { "input.L2.current", 0, 0.001, ".1.3.6.1.4.1.534.6.6.7.3.3.1.4.%i.1.2", NULL, 0, NULL }, { "input.L2.current.nominal", 0, 0.001, ".1.3.6.1.4.1.534.6.6.7.3.3.1.3.%i.1.2", NULL, 0, NULL }, { "input.L2.current.status", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.534.6.6.7.3.3.1.5.%i.1.2", NULL, SU_FLAG_OK, &marlin_threshold_status_info[0] }, { "L2.alarm", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.534.6.6.7.3.3.1.5.%i.1.2", NULL, SU_FLAG_OK, &marlin_threshold_current_alarms_info[0] }, { "input.L2.current.low.warning", ST_FLAG_RW, 0.001, ".1.3.6.1.4.1.534.6.6.7.3.3.1.6.%i.1.2", NULL, SU_FLAG_NEGINVALID, NULL }, { "input.L2.current.low.critical", ST_FLAG_RW, 0.001, ".1.3.6.1.4.1.534.6.6.7.3.3.1.7.%i.1.2", NULL, SU_FLAG_NEGINVALID, NULL }, { "input.L2.current.high.warning", ST_FLAG_RW, 0.001, ".1.3.6.1.4.1.534.6.6.7.3.3.1.8.%i.1.2", NULL, SU_FLAG_NEGINVALID, NULL }, { "input.L2.current.high.critical", ST_FLAG_RW, 0.001, ".1.3.6.1.4.1.534.6.6.7.3.3.1.9.%i.1.2", NULL, SU_FLAG_NEGINVALID, NULL }, { "input.L3.current", 0, 0.001, ".1.3.6.1.4.1.534.6.6.7.3.3.1.4.%i.1.3", NULL, 0, NULL }, { "input.L3.current.nominal", 0, 0.001, ".1.3.6.1.4.1.534.6.6.7.3.3.1.3.%i.1.3", NULL, 0, NULL }, { "input.L3.current.status", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.534.6.6.7.3.3.1.5.%i.1.3", NULL, SU_FLAG_OK, &marlin_threshold_status_info[0] }, { "L3.alarm", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.534.6.6.7.3.3.1.5.%i.1.3", NULL, SU_FLAG_OK, &marlin_threshold_current_alarms_info[0] }, { "input.L3.current.low.warning", ST_FLAG_RW, 0.001, ".1.3.6.1.4.1.534.6.6.7.3.3.1.6.%i.1.3", NULL, SU_FLAG_NEGINVALID, NULL }, { "input.L3.current.low.critical", ST_FLAG_RW, 0.001, ".1.3.6.1.4.1.534.6.6.7.3.3.1.7.%i.1.3", NULL, SU_FLAG_NEGINVALID, NULL }, { "input.L3.current.high.warning", ST_FLAG_RW, 0.001, ".1.3.6.1.4.1.534.6.6.7.3.3.1.8.%i.1.3", NULL, SU_FLAG_NEGINVALID, NULL }, { "input.L3.current.high.critical", ST_FLAG_RW, 0.001, ".1.3.6.1.4.1.534.6.6.7.3.3.1.9.%i.1.3", NULL, SU_FLAG_NEGINVALID, NULL }, /* Sum of all phases realpower, valid for Shark 1ph/3ph only */ { "input.realpower", 0, 1.0, ".1.3.6.1.4.1.534.6.6.7.3.5.1.4.%i.1", NULL, SU_FLAG_NEGINVALID | SU_FLAG_UNIQUE | SU_FLAG_OK, NULL }, /* Fallback 1: Sum of all phases realpower, valid for Marlin 3ph only */ { "input.realpower", 0, 1.0, ".1.3.6.1.4.1.534.6.6.7.3.4.1.4.%i.1.4", NULL, SU_FLAG_NEGINVALID | SU_FLAG_UNIQUE | SU_FLAG_OK, NULL }, /* Fallback 2: Sum of the phase realpower, valid for Marlin 1ph only */ { "input.realpower", 0, 1.0, ".1.3.6.1.4.1.534.6.6.7.3.4.1.4.%i.1.2", NULL, SU_FLAG_NEGINVALID | SU_FLAG_OK, NULL }, { "input.L1.realpower", 0, 1.0, ".1.3.6.1.4.1.534.6.6.7.3.4.1.4.%i.1.1", NULL, SU_FLAG_NEGINVALID | SU_FLAG_OK, NULL }, { "input.L2.realpower", 0, 1.0, ".1.3.6.1.4.1.534.6.6.7.3.4.1.4.%i.1.2", NULL, SU_FLAG_NEGINVALID | SU_FLAG_OK, NULL }, { "input.L3.realpower", 0, 1.0, ".1.3.6.1.4.1.534.6.6.7.3.4.1.4.%i.1.3", NULL, SU_FLAG_NEGINVALID | SU_FLAG_OK, NULL }, /* Sum of all phases apparent power, valid for Shark 1ph/3ph only */ { "input.power", 0, 1.0, ".1.3.6.1.4.1.534.6.6.7.3.5.1.3.%i.1", NULL, SU_FLAG_NEGINVALID | SU_FLAG_UNIQUE | SU_FLAG_OK, NULL }, /* Fallback 1: Sum of all phases realpower, valid for Marlin 3ph only */ { "input.power", 0, 1.0, ".1.3.6.1.4.1.534.6.6.7.3.4.1.3.%i.1.4", NULL, SU_FLAG_NEGINVALID | SU_FLAG_UNIQUE | SU_FLAG_OK, NULL }, /* Fallback 2: Sum of the phase realpower, valid for Marlin 1ph only */ { "input.power", 0, 1.0, ".1.3.6.1.4.1.534.6.6.7.3.4.1.3.%i.1.2", NULL, SU_FLAG_NEGINVALID | SU_FLAG_OK, NULL }, { "input.L1.power", 0, 1.0, ".1.3.6.1.4.1.534.6.6.7.3.4.1.3.%i.1.1", NULL, SU_FLAG_NEGINVALID | SU_FLAG_OK, NULL }, { "input.L2.power", 0, 1.0, ".1.3.6.1.4.1.534.6.6.7.3.4.1.3.%i.1.2", NULL, SU_FLAG_NEGINVALID | SU_FLAG_OK, NULL }, { "input.L3.power", 0, 1.0, ".1.3.6.1.4.1.534.6.6.7.3.4.1.3.%i.1.3", NULL, SU_FLAG_NEGINVALID | SU_FLAG_OK, NULL }, /* Input feed: a feed (A or B) is tied to an input, and this * sub-collection describes the properties of an actual cable. */ /* FIXME: RFC on key name is needed when backporting to NUT upstream ; check type (number? string?) and flags */ /* { "input.feed.%i.id", 0, 1, "???.%i.%i", NULL, SU_FLAG_NEGINVALID, NULL }, */ /* Feed name(s) of the ePDU power input(s), can be set by user (FIXME: rename to .desc?) * inputFeedName.0.1 = Value (OctetString): Feed A */ /* FIXME: SU_FLAG_SEMI_STATIC or SU_FLAG_SETTING => refreshed from time to time or upon call to setvar */ /* { "input.%i.feed.desc", ST_FLAG_RW | ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.534.6.6.7.3.1.1.10.%i.%i", NULL, SU_FLAG_SEMI_STATIC | SU_FLAG_OK | SU_TYPE_DAISY_1, NULL }, */ { "input.feed.desc", ST_FLAG_RW | ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.534.6.6.7.3.1.1.10.%i.1", NULL, SU_FLAG_SEMI_STATIC | SU_FLAG_OK | SU_TYPE_DAISY_1, NULL }, /* Feed color (integer RGB) * inputFeedColor.0.1 = Gauge32: 0 (black) */ /* FIXME: RFC on key name is needed when backporting to NUT upstream */ /* { "input.%i.feed.color", 0, 1, ".1.3.6.1.4.1.534.6.6.7.3.1.1.9.%i.%i", NULL, SU_FLAG_STATIC | SU_FLAG_OK | SU_TYPE_DAISY_1, NULL }, */ { "input.feed.color", 0, 1, ".1.3.6.1.4.1.534.6.6.7.3.1.1.9.%i.1", NULL, SU_FLAG_SEMI_STATIC | SU_FLAG_OK | SU_TYPE_DAISY_1, NULL }, /* inputPowerCapacity.0.1 = INTEGER: 2300 */ /* FIXME: RFC on key name is needed when backporting to NUT upstream */ { "input.realpower.nominal", 0, 1.0, ".1.3.6.1.4.1.534.6.6.7.3.5.1.9.%i.1", NULL, SU_FLAG_NEGINVALID | SU_FLAG_OK, NULL }, /* Ambient collection */ /* EMP001 (legacy) mapping */ /* Note: this is still published, beside from the new daisychained version! */ { "ambient.present", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.534.6.6.7.7.1.1.3.%i.1", NULL, SU_FLAG_OK, &marlin_ambient_presence_info[0] }, { "ambient.temperature.status", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.534.6.6.7.7.1.1.5.%i.1", NULL, SU_FLAG_OK, &marlin_threshold_status_info[0] }, { "ups.alarm", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.534.6.6.7.7.1.1.5.%i.1", NULL, SU_FLAG_OK, &marlin_threshold_temperature_alarms_info[0] }, { "ambient.temperature", 0, 0.1, ".1.3.6.1.4.1.534.6.6.7.7.1.1.4.%i.1", NULL, SU_FLAG_OK, NULL }, /* Low and high threshold use the respective critical levels */ { "ambient.temperature.low", ST_FLAG_RW, 0.1, ".1.3.6.1.4.1.534.6.6.7.7.1.1.7.%i.1", NULL, SU_FLAG_NEGINVALID | SU_FLAG_OK, NULL }, { "ambient.temperature.low.critical", ST_FLAG_RW, 0.1, ".1.3.6.1.4.1.534.6.6.7.7.1.1.7.%i.1", NULL, SU_FLAG_NEGINVALID | SU_FLAG_OK, NULL }, { "ambient.temperature.low.warning", ST_FLAG_RW, 0.1, ".1.3.6.1.4.1.534.6.6.7.7.1.1.6.%i.1", NULL, SU_FLAG_NEGINVALID | SU_FLAG_OK, NULL }, { "ambient.temperature.high", ST_FLAG_RW, 0.1, ".1.3.6.1.4.1.534.6.6.7.7.1.1.9.%i.1", NULL, SU_FLAG_NEGINVALID | SU_FLAG_OK, NULL }, { "ambient.temperature.high.warning", ST_FLAG_RW, 0.1, ".1.3.6.1.4.1.534.6.6.7.7.1.1.8.%i.1", NULL, SU_FLAG_NEGINVALID | SU_FLAG_OK, NULL }, { "ambient.temperature.high.critical", ST_FLAG_RW, 0.1, ".1.3.6.1.4.1.534.6.6.7.7.1.1.9.%i.1", NULL, SU_FLAG_NEGINVALID | SU_FLAG_OK, NULL }, { "ambient.humidity.status", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.534.6.6.7.7.2.1.5.%i.1", NULL, SU_FLAG_OK, &marlin_threshold_status_info[0] }, { "ups.alarm", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.534.6.6.7.7.2.1.5.%i.1", NULL, SU_FLAG_OK, &marlin_threshold_humidity_alarms_info[0] }, { "ambient.humidity", 0, 0.1, ".1.3.6.1.4.1.534.6.6.7.7.2.1.4.%i.1", NULL, SU_FLAG_OK, NULL }, /* Low and high threshold use the respective critical levels */ { "ambient.humidity.low", ST_FLAG_RW, 0.1, ".1.3.6.1.4.1.534.6.6.7.7.2.1.7.%i.1", NULL, SU_FLAG_NEGINVALID | SU_FLAG_OK, NULL }, { "ambient.humidity.low.warning", ST_FLAG_RW, 0.1, ".1.3.6.1.4.1.534.6.6.7.7.2.1.6.%i.1", NULL, SU_FLAG_NEGINVALID | SU_FLAG_OK, NULL }, { "ambient.humidity.low.critical", ST_FLAG_RW, 0.1, ".1.3.6.1.4.1.534.6.6.7.7.2.1.7.%i.1", NULL, SU_FLAG_NEGINVALID | SU_FLAG_OK, NULL }, { "ambient.humidity.high", ST_FLAG_RW, 0.1, ".1.3.6.1.4.1.534.6.6.7.7.2.1.9.%i.1", NULL, SU_FLAG_NEGINVALID | SU_FLAG_OK, NULL }, { "ambient.humidity.high.warning", ST_FLAG_RW, 0.1, ".1.3.6.1.4.1.534.6.6.7.7.2.1.8.%i.1", NULL, SU_FLAG_NEGINVALID | SU_FLAG_OK, NULL }, { "ambient.humidity.high.critical", ST_FLAG_RW, 0.1, ".1.3.6.1.4.1.534.6.6.7.7.2.1.9.%i.1", NULL, SU_FLAG_NEGINVALID | SU_FLAG_OK, NULL }, /* Dry contacts on TH module */ { "ambient.contacts.1.status", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.534.6.6.7.7.3.1.4.%i.1", NULL, SU_FLAG_OK, &marlin_ambient_drycontacts_info[0] }, { "ambient.contacts.2.status", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.534.6.6.7.7.3.1.4.%i.2", NULL, SU_FLAG_OK, &marlin_ambient_drycontacts_info[0] }, /* EMP002 (EATON EMP MIB) mapping, including daisychain support */ /* Warning: indexes start at '1' not '0'! */ /* sensorCount.0 */ { "ambient.count", ST_FLAG_RW, 1.0, ".1.3.6.1.4.1.534.6.8.1.1.1.0", "0", SU_TYPE_DAISY_MASTER_ONLY, NULL }, /* CommunicationStatus.n */ { "ambient.%i.present", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.534.6.8.1.1.4.1.1.%i", NULL, SU_AMBIENT_TEMPLATE | SU_TYPE_DAISY_MASTER_ONLY, &marlin_emp002_ambient_presence_info[0] }, /* sensorName.n: OctetString EMPDT1H1C2 @1 */ { "ambient.%i.name", ST_FLAG_STRING, 1.0, ".1.3.6.1.4.1.534.6.8.1.1.3.1.1.%i", "", SU_AMBIENT_TEMPLATE | SU_TYPE_DAISY_MASTER_ONLY, NULL }, /* sensorManufacturer.n */ { "ambient.%i.mfr", ST_FLAG_STRING, 1.0, ".1.3.6.1.4.1.534.6.8.1.1.2.1.6.%i", "", SU_AMBIENT_TEMPLATE | SU_TYPE_DAISY_MASTER_ONLY, NULL }, /* sensorModel.n */ { "ambient.%i.model", ST_FLAG_STRING, 1.0, ".1.3.6.1.4.1.534.6.8.1.1.2.1.7.%i", "", SU_AMBIENT_TEMPLATE | SU_TYPE_DAISY_MASTER_ONLY, NULL }, /* sensorSerialNumber.n */ { "ambient.%i.serial", ST_FLAG_STRING, 1.0, ".1.3.6.1.4.1.534.6.8.1.1.2.1.9.%i", "", SU_AMBIENT_TEMPLATE | SU_TYPE_DAISY_MASTER_ONLY, NULL }, /* sensorUuid.n */ { "ambient.%i.id", ST_FLAG_STRING, 1.0, ".1.3.6.1.4.1.534.6.8.1.1.2.1.2.%i", "", SU_AMBIENT_TEMPLATE | SU_TYPE_DAISY_MASTER_ONLY, NULL }, /* sensorAddress.n */ { "ambient.%i.address", 0, 1, ".1.3.6.1.4.1.534.6.8.1.1.2.1.4.%i", "", SU_AMBIENT_TEMPLATE | SU_TYPE_DAISY_MASTER_ONLY, NULL }, /* sensorMonitoredBy.n */ { "ambient.%i.parent.serial", ST_FLAG_STRING, 1.0, ".1.3.6.1.4.1.534.6.8.1.1.2.1.5.%i", "", SU_AMBIENT_TEMPLATE | SU_TYPE_DAISY_MASTER_ONLY, NULL }, /* sensorFirmwareVersion.n */ { "ambient.%i.firmware", ST_FLAG_STRING, 1.0, ".1.3.6.1.4.1.534.6.8.1.1.2.1.10.%i", "", SU_AMBIENT_TEMPLATE | SU_TYPE_DAISY_MASTER_ONLY, NULL }, /* temperatureUnit.1 * MUST be before the temperature data reading! */ { "ambient.%i.temperature.unit", 0, 1.0, ".1.3.6.1.4.1.534.6.8.1.2.5.0", "", SU_AMBIENT_TEMPLATE | SU_TYPE_DAISY_MASTER_ONLY, &eaton_sensor_temperature_unit_info[0] }, /* temperatureValue.n.1 */ { "ambient.%i.temperature", 0, 0.1, ".1.3.6.1.4.1.534.6.8.1.2.3.1.3.%i.1", "", SU_AMBIENT_TEMPLATE | SU_TYPE_DAISY_MASTER_ONLY, #if WITH_SNMP_LKP_FUN &eaton_sensor_temperature_read_info[0] #else NULL #endif }, { "ambient.%i.temperature.status", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.534.6.8.1.2.3.1.1.%i.1", NULL, SU_AMBIENT_TEMPLATE | SU_TYPE_DAISY_MASTER_ONLY, &marlin_threshold_status_info[0] }, { "ups.alarm", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.534.6.8.1.2.3.1.1.%i.1", NULL, SU_AMBIENT_TEMPLATE | SU_TYPE_DAISY_MASTER_ONLY, &marlin_threshold_temperature_alarms_info[0] }, /* FIXME: ambient.n.temperature.{minimum,maximum} */ /* temperatureThresholdLowCritical.n.1 */ { "ambient.%i.temperature.low.critical", ST_FLAG_RW, 0.1, ".1.3.6.1.4.1.534.6.8.1.2.2.1.6.%i.1", "", SU_AMBIENT_TEMPLATE | SU_TYPE_DAISY_MASTER_ONLY, NULL }, /* temperatureThresholdLowWarning.n.1 */ { "ambient.%i.temperature.low.warning", ST_FLAG_RW, 0.1, ".1.3.6.1.4.1.534.6.8.1.2.2.1.5.%i.1", "", SU_AMBIENT_TEMPLATE | SU_TYPE_DAISY_MASTER_ONLY, NULL }, /* temperatureThresholdHighWarning.n.1 */ { "ambient.%i.temperature.high.warning", ST_FLAG_RW, 0.1, ".1.3.6.1.4.1.534.6.8.1.2.2.1.7.%i.1", "", SU_AMBIENT_TEMPLATE | SU_TYPE_DAISY_MASTER_ONLY, NULL }, /* temperatureThresholdHighCritical.n.1 */ { "ambient.%i.temperature.high.critical", ST_FLAG_RW, 0.1, ".1.3.6.1.4.1.534.6.8.1.2.2.1.8.%i.1", "", SU_AMBIENT_TEMPLATE | SU_TYPE_DAISY_MASTER_ONLY, NULL }, /* humidityValue.n.1 */ { "ambient.%i.humidity", 0, 0.1, ".1.3.6.1.4.1.534.6.8.1.3.3.1.3.%i.1", "", SU_AMBIENT_TEMPLATE | SU_TYPE_DAISY_MASTER_ONLY, NULL }, { "ambient.%i.humidity.status", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.534.6.8.1.3.3.1.1.%i.1", NULL, SU_AMBIENT_TEMPLATE | SU_TYPE_DAISY_MASTER_ONLY, &marlin_threshold_status_info[0] }, { "ups.alarm", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.534.6.8.1.3.3.1.1.%i.1", NULL, SU_AMBIENT_TEMPLATE | SU_TYPE_DAISY_MASTER_ONLY, &marlin_threshold_humidity_alarms_info[0] }, /* FIXME: consider ambient.n.humidity.{minimum,maximum} */ /* humidityThresholdLowCritical.n.1 */ { "ambient.%i.humidity.low.critical", ST_FLAG_RW, 0.1, ".1.3.6.1.4.1.534.6.8.1.3.2.1.6.%i.1", "", SU_AMBIENT_TEMPLATE | SU_TYPE_DAISY_MASTER_ONLY, NULL }, /* humidityThresholdLowWarning.n.1 */ { "ambient.%i.humidity.low.warning", ST_FLAG_RW, 0.1, ".1.3.6.1.4.1.534.6.8.1.3.2.1.5.%i.1", "", SU_AMBIENT_TEMPLATE | SU_TYPE_DAISY_MASTER_ONLY, NULL }, /* humidityThresholdHighWarning.n.1 */ { "ambient.%i.humidity.high.warning", ST_FLAG_RW, 0.1, ".1.3.6.1.4.1.534.6.8.1.3.2.1.7.%i.1", "", SU_AMBIENT_TEMPLATE | SU_TYPE_DAISY_MASTER_ONLY, NULL }, /* humidityThresholdHighCritical.n.1 */ { "ambient.%i.humidity.high.critical", ST_FLAG_RW, 0.1, ".1.3.6.1.4.1.534.6.8.1.3.2.1.8.%i.1", "", SU_AMBIENT_TEMPLATE | SU_TYPE_DAISY_MASTER_ONLY, NULL }, /* digitalInputName.n.{1,2} */ { "ambient.%i.contacts.1.name", ST_FLAG_STRING, 1.0, ".1.3.6.1.4.1.534.6.8.1.4.2.1.1.%i.1", "", SU_AMBIENT_TEMPLATE | SU_TYPE_DAISY_MASTER_ONLY, NULL }, { "ambient.%i.contacts.2.name", ST_FLAG_STRING, 1.0, ".1.3.6.1.4.1.534.6.8.1.4.2.1.1.%i.2", "", SU_AMBIENT_TEMPLATE | SU_TYPE_DAISY_MASTER_ONLY, NULL }, /* digitalInputPolarity.n */ { "ambient.%i.contacts.1.config", ST_FLAG_RW | ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.534.6.8.1.4.2.1.3.%i.1", "", SU_AMBIENT_TEMPLATE | SU_TYPE_DAISY_MASTER_ONLY, &marlin_ambient_drycontacts_polarity_info[0] }, { "ambient.%i.contacts.2.config", ST_FLAG_RW | ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.534.6.8.1.4.2.1.3.%i.2", "", SU_AMBIENT_TEMPLATE | SU_TYPE_DAISY_MASTER_ONLY, &marlin_ambient_drycontacts_polarity_info[0] }, /* XUPS-MIB::xupsContactState.n */ { "ambient.%i.contacts.1.status", ST_FLAG_STRING, 1.0, ".1.3.6.1.4.1.534.6.8.1.4.3.1.3.%i.1", "", SU_AMBIENT_TEMPLATE | SU_TYPE_DAISY_MASTER_ONLY, &marlin_ambient_drycontacts_state_info[0] }, { "ambient.%i.contacts.2.status", ST_FLAG_STRING, 1.0, ".1.3.6.1.4.1.534.6.8.1.4.3.1.3.%i.2", "", SU_AMBIENT_TEMPLATE | SU_TYPE_DAISY_MASTER_ONLY, &marlin_ambient_drycontacts_state_info[0] }, /* Outlet collection */ { "outlet.count", 0, 1, ".1.3.6.1.4.1.534.6.6.7.1.2.1.22.%i", "0", SU_FLAG_STATIC | SU_FLAG_OK, NULL }, { "outlet.id", 0, 1, NULL, "0", SU_FLAG_STATIC | SU_FLAG_ABSENT | SU_FLAG_OK, NULL }, { "outlet.desc", ST_FLAG_RW | ST_FLAG_STRING, 20, NULL, "All outlets", SU_FLAG_STATIC | SU_FLAG_ABSENT | SU_FLAG_OK, NULL }, /* UnitType * used to depict the overall outlets switchability of the unit on G3 and newer ePDU*/ { "outlet.switchable", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.534.6.6.7.1.2.1.10.%i", "no", SU_FLAG_STATIC | SU_FLAG_UNIQUE, &marlin_unit_switchability_info[0] }, /* Ugly hack for older G2 ePDU: check the first outlet to determine unit switchability */ { "outlet.switchable", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.534.6.6.7.6.6.1.3.%i.1", "no", SU_FLAG_STATIC | SU_FLAG_UNIQUE | SU_FLAG_OK | SU_TYPE_DAISY_1, &g2_unit_outlet_switchability_info[0] }, /* The below ones are the same as the input.* equivalent */ /* FIXME: transition period, TO BE REMOVED, moved to input.* */ { "outlet.frequency", 0, 0.1, ".1.3.6.1.4.1.534.6.6.7.3.1.1.3.%i.1", NULL, 0, NULL }, { "outlet.voltage", 0, 0.001, ".1.3.6.1.4.1.534.6.6.7.3.2.1.3.%i.1.1", NULL, 0, NULL }, { "outlet.current", 0, 0.01, ".1.3.6.1.4.1.534.6.6.7.3.3.1.4.%i.1.1", NULL, 0, NULL }, { "outlet.realpower", 0, 1.0, ".1.3.6.1.4.1.534.6.6.7.3.4.1.4.%i.1.4", NULL, 0, NULL }, { "outlet.power", 0, 1.0, ".1.3.6.1.4.1.534.6.6.7.3.4.1.3.%i.1.4", NULL, 0, NULL }, /* outlet template definition * Indexes start from 1, ie outlet.1 => .1 */ /* Note: the first definition is used to determine the base index (ie 0 or 1) */ /* Outlet friendly name, which can be modified by the user * outletName: = OctetString: "Outlet A16" */ /* FIXME: SU_FLAG_SEMI_STATIC or SU_FLAG_SETTING => * refreshed from time to time or upon call to setvar */ { "outlet.%i.desc", ST_FLAG_RW | ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.534.6.6.7.6.1.1.3.%i.%i", NULL, SU_FLAG_SEMI_STATIC | SU_FLAG_OK | SU_OUTLET | SU_TYPE_DAISY_1, NULL }, { "outlet.%i.status", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.534.6.6.7.6.6.1.2.%i.%i", NULL, SU_FLAG_OK | SU_OUTLET | SU_TYPE_DAISY_1, &marlin_outlet_status_info[0] }, /* Numeric identifier of the outlet, tied to the whole unit */ /* NOTE: For daisychain devices ATM the last listed value presented by * the SNMP device is kept by the driver - no SU_FLAG_UNIQUE here yet. * Verified that a non-implemented OID does not publish empty values. */ /* Fallback in firmwares issued before Sep 2017 is to use the * outletID: Outlet physical name, related to its number in the group * ex: first outlet of the second group (B) is B1, or can default to * the outlet number (represented as string) and is a read-only string * outletID.0.8 = Value (OctetString): "8" */ { "outlet.%i.id", 0, 1, ".1.3.6.1.4.1.534.6.6.7.6.6.1.7.%i.%i", NULL, SU_FLAG_STATIC | SU_OUTLET | SU_TYPE_DAISY_1, NULL }, /* Fallback in firmwares issued before Sep 2017 (outletID): */ { "outlet.%i.name", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.534.6.6.7.6.1.1.2.%i.%i", NULL, SU_FLAG_STATIC | SU_FLAG_UNIQUE | SU_FLAG_OK | SU_OUTLET | SU_TYPE_DAISY_1, NULL }, /* Preferred: Outlet physical name OID in new G3 firmware (02.00.0051) * is named outletDesignator (other MIBs outletPhysicalName) * and is a read-only string provided by firmware * outletDesignator.0.1 = Value (OctetString): "A1" * outletPhysicalName.0.16 = Value (OctetString): "A16" */ { "outlet.%i.name", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.534.6.6.7.6.1.1.6.%i.%i", NULL, SU_FLAG_STATIC | SU_FLAG_UNIQUE | SU_FLAG_OK | SU_OUTLET | SU_TYPE_DAISY_1, NULL }, /* FIXME: the last part of the OID gives the group number (i.e. %i.1 means "group 1") * Need to address that, without multiple declaration (%i.%i, SU_OUTLET | SU_OUTLET_GROUP)? */ { "outlet.%i.groupid", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.534.6.6.7.6.2.1.3.%i.%i.1", NULL, SU_FLAG_STATIC | SU_FLAG_UNIQUE | SU_OUTLET | SU_TYPE_DAISY_1, NULL }, { "outlet.%i.groupid", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.534.6.6.7.6.2.1.3.%i.%i.2", NULL, SU_FLAG_STATIC | SU_FLAG_UNIQUE | SU_OUTLET | SU_TYPE_DAISY_1, NULL }, { "outlet.%i.groupid", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.534.6.6.7.6.2.1.3.%i.%i.3", NULL, SU_FLAG_STATIC | SU_FLAG_UNIQUE | SU_OUTLET | SU_TYPE_DAISY_1, NULL }, { "outlet.%i.groupid", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.534.6.6.7.6.2.1.3.%i.%i.4", NULL, SU_FLAG_STATIC | SU_FLAG_UNIQUE | SU_OUTLET | SU_TYPE_DAISY_1, NULL }, { "outlet.%i.groupid", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.534.6.6.7.6.2.1.3.%i.%i.5", NULL, SU_FLAG_STATIC | SU_FLAG_UNIQUE | SU_OUTLET | SU_TYPE_DAISY_1, NULL }, { "outlet.%i.groupid", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.534.6.6.7.6.2.1.3.%i.%i.6", NULL, SU_FLAG_STATIC | SU_FLAG_UNIQUE | SU_OUTLET | SU_TYPE_DAISY_1, NULL }, { "outlet.%i.current", 0, 0.001, ".1.3.6.1.4.1.534.6.6.7.6.4.1.3.%i.%i", NULL, SU_OUTLET | SU_TYPE_DAISY_1, NULL }, { "outlet.%i.current.status", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.534.6.6.7.6.4.1.4.%i.%i", NULL, SU_OUTLET | SU_TYPE_DAISY_1, &marlin_threshold_status_info[0] }, { "outlet.%i.alarm", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.534.6.6.7.6.4.1.4.%i.%i", NULL, SU_OUTLET | SU_TYPE_DAISY_1, &marlin_threshold_current_alarms_info[0] }, { "outlet.%i.current.low.warning", ST_FLAG_RW, 0.001, ".1.3.6.1.4.1.534.6.6.7.6.4.1.5.%i.%i", NULL, SU_FLAG_NEGINVALID | SU_OUTLET | SU_TYPE_DAISY_1, NULL }, { "outlet.%i.current.low.critical", ST_FLAG_RW, 0.001, ".1.3.6.1.4.1.534.6.6.7.6.4.1.6.%i.%i", NULL, SU_FLAG_NEGINVALID | SU_OUTLET | SU_TYPE_DAISY_1, NULL }, { "outlet.%i.current.high.warning", ST_FLAG_RW, 0.001, ".1.3.6.1.4.1.534.6.6.7.6.4.1.7.%i.%i", NULL, SU_FLAG_NEGINVALID | SU_OUTLET | SU_TYPE_DAISY_1, NULL }, { "outlet.%i.current.high.critical", ST_FLAG_RW, 0.001, ".1.3.6.1.4.1.534.6.6.7.6.4.1.8.%i.%i", NULL, SU_FLAG_NEGINVALID | SU_OUTLET | SU_TYPE_DAISY_1, NULL }, { "outlet.%i.realpower", 0, 1.0, ".1.3.6.1.4.1.534.6.6.7.6.5.1.3.%i.%i", NULL, SU_OUTLET | SU_TYPE_DAISY_1, NULL }, { "outlet.%i.voltage", 0, 0.001, ".1.3.6.1.4.1.534.6.6.7.6.3.1.2.%i.%i", NULL, SU_OUTLET | SU_TYPE_DAISY_1, NULL }, { "outlet.%i.voltage.status", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.534.6.6.7.6.3.1.3.%i.%i", NULL, SU_OUTLET | SU_TYPE_DAISY_1, &marlin_threshold_status_info[0] }, { "outlet.%i.alarm", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.534.6.6.7.6.3.1.3.%i.%i", NULL, SU_OUTLET | SU_TYPE_DAISY_1, &marlin_threshold_voltage_alarms_info[0] }, { "outlet.%i.voltage.low.warning", ST_FLAG_RW, 0.001, ".1.3.6.1.4.1.534.6.6.7.6.3.1.4.%i.%i", NULL, SU_FLAG_NEGINVALID | SU_OUTLET | SU_TYPE_DAISY_1, NULL }, { "outlet.%i.voltage.low.critical", ST_FLAG_RW, 0.001, ".1.3.6.1.4.1.534.6.6.7.6.3.1.5.%i.%i", NULL, SU_FLAG_NEGINVALID | SU_OUTLET | SU_TYPE_DAISY_1, NULL }, { "outlet.%i.voltage.high.warning", ST_FLAG_RW, 0.001, ".1.3.6.1.4.1.534.6.6.7.6.3.1.6.%i.%i", NULL, SU_FLAG_NEGINVALID | SU_OUTLET | SU_TYPE_DAISY_1, NULL }, { "outlet.%i.voltage.high.critical", ST_FLAG_RW, 0.001, ".1.3.6.1.4.1.534.6.6.7.6.3.1.7.%i.%i", NULL, SU_FLAG_NEGINVALID | SU_OUTLET | SU_TYPE_DAISY_1, NULL }, { "outlet.%i.power", 0, 1.0, ".1.3.6.1.4.1.534.6.6.7.6.5.1.2.%i.%i", NULL, SU_OUTLET | SU_TYPE_DAISY_1, NULL }, /* outletControlSwitchable */ { "outlet.%i.switchable", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.534.6.6.7.6.6.1.9.%i.%i", "no", SU_OUTLET | SU_FLAG_UNIQUE | SU_TYPE_DAISY_1, &marlin_outlet_switchability_info[0] }, /* FIXME: handle non switchable units (only measurements), which do not expose this OID */ { "outlet.%i.switchable", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.534.6.6.7.6.6.1.3.%i.%i", "no", SU_FLAG_STATIC | SU_FLAG_UNIQUE | SU_OUTLET | SU_FLAG_OK | SU_TYPE_DAISY_1, &g2_unit_outlet_switchability_info[0] }, { "outlet.%i.type", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.534.6.6.7.6.1.1.5.%i.%i", "unknown", SU_FLAG_STATIC | SU_OUTLET | SU_TYPE_DAISY_1, &marlin_outlet_type_info[0] }, /* TODO: handle statistics * outletWh.0.1 * outletWhTimer.0.1 */ /* Outlet groups collection */ { "outlet.group.count", 0, 1, ".1.3.6.1.4.1.534.6.6.7.1.2.1.21.%i", "0", SU_FLAG_STATIC | SU_TYPE_DAISY_1, NULL }, /* outlet groups template definition * Indexes start from 1, ie outlet.group.1 => .1 */ /* Note: the first definition is used to determine the base index (ie 0 or 1) */ /* groupID.0.1 = OctetString: A */ { "outlet.group.%i.id", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.534.6.6.7.5.1.1.2.%i.%i", NULL, SU_FLAG_STATIC | SU_OUTLET_GROUP | SU_TYPE_DAISY_1, NULL }, /* User-friendly (writeable) description of the outlet group: * groupName.0.1 = OctetString: Factory Group 1 * groupName.0.2 = OctetString: Branch Circuit B */ /* FIXME: SU_FLAG_SEMI_STATIC or SU_FLAG_SETTING => * refreshed from time to time or upon call to setvar */ { "outlet.group.%i.desc", ST_FLAG_RW | ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.534.6.6.7.5.1.1.3.%i.%i", NULL, SU_FLAG_SEMI_STATIC | SU_OUTLET_GROUP | SU_TYPE_DAISY_1, NULL }, /* Outlet-group physical name, a read-only string, * is named groupDesignator (other MIBs groupPhysicalName) * groupPhysicalName.0.1 = Value (OctetString): A * groupDesignator.0.2 = Value (OctetString): B */ { "outlet.group.%i.name", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.534.6.6.7.5.1.1.8.%i.%i", NULL, SU_FLAG_STATIC | SU_OUTLET_GROUP | SU_TYPE_DAISY_1, NULL }, /* Outlet-group color: groupColor (other MIBs groupBkgColor) * groupColor.0.1 = Value (Gauge32): 16051527 (0xF4ED47) */ /* FIXME: RFC on key name is needed when backporting to NUT upstream */ { "outlet.group.%i.color", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.534.6.6.7.5.1.1.7.%i.%i", NULL, SU_FLAG_STATIC | SU_OUTLET_GROUP | SU_TYPE_DAISY_1, NULL }, /* groupType.0.1 = Integer: outletSection (4) */ { "outlet.group.%i.type", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.534.6.6.7.5.1.1.4.%i.%i", NULL, SU_FLAG_STATIC | SU_OUTLET_GROUP | SU_TYPE_DAISY_1, &marlin_outlet_group_type_info[0] }, /* Phase to which an outlet-group is connected: * We use the following OID, which gives the voltage measurement type * groupVoltageMeasType.0.1; Value (Integer): singlePhase (1) */ /* FIXME: RFC on key name is needed when backporting to NUT upstream ; check type (number? string?) and flags (daisy?) */ { "outlet.group.%i.phase", 0, SU_INFOSIZE, ".1.3.6.1.4.1.534.6.6.7.5.3.1.2.%i.%i", NULL, SU_FLAG_STATIC | SU_OUTLET_GROUP | SU_TYPE_DAISY_1, &marlin_outlet_group_phase_info[0] }, /* groupControlStatus.0.1 = Integer: on (1) */ { "outlet.group.%i.status", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.534.6.6.7.5.6.1.2.%i.%i", NULL, SU_FLAG_OK | SU_OUTLET_GROUP | SU_TYPE_DAISY_1, &marlin_outletgroups_status_info[0] }, /* groupChildCount.0.1 = Integer: 12 */ { "outlet.group.%i.count", 0, 1, ".1.3.6.1.4.1.534.6.6.7.5.1.1.6.%i.%i", NULL, SU_OUTLET_GROUP | SU_TYPE_DAISY_1, NULL }, /* groupVoltage.0.1 = Integer: 243080 */ { "outlet.group.%i.voltage", 0, 0.001, ".1.3.6.1.4.1.534.6.6.7.5.3.1.3.%i.%i", NULL, SU_OUTLET_GROUP | SU_TYPE_DAISY_1, NULL }, /* groupVoltageThStatus.0.1 = Integer: good (0) */ { "outlet.group.%i.voltage.status", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.534.6.6.7.5.3.1.4.%i.%i", NULL, SU_OUTLET_GROUP | SU_TYPE_DAISY_1, &marlin_threshold_status_info[0] }, { "outlet.group.%i.alarm", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.534.6.6.7.5.3.1.4.%i.%i", NULL, SU_OUTLET_GROUP | SU_TYPE_DAISY_1, &marlin_threshold_voltage_alarms_info[0] }, { "outlet.group.%i.voltage.low.warning", ST_FLAG_RW, 0.001, ".1.3.6.1.4.1.534.6.6.7.5.3.1.5.%i.%i", NULL, SU_FLAG_NEGINVALID | SU_OUTLET_GROUP | SU_TYPE_DAISY_1, NULL }, { "outlet.group.%i.voltage.low.critical", ST_FLAG_RW, 0.001, ".1.3.6.1.4.1.534.6.6.7.5.3.1.6.%i.%i", NULL, SU_FLAG_NEGINVALID | SU_OUTLET_GROUP | SU_TYPE_DAISY_1, NULL }, { "outlet.group.%i.voltage.high.warning", ST_FLAG_RW, 0.001, ".1.3.6.1.4.1.534.6.6.7.5.3.1.7.%i.%i", NULL, SU_FLAG_NEGINVALID | SU_OUTLET_GROUP | SU_TYPE_DAISY_1, NULL }, { "outlet.group.%i.voltage.high.critical", ST_FLAG_RW, 0.001, ".1.3.6.1.4.1.534.6.6.7.5.3.1.8.%i.%i", NULL, SU_FLAG_NEGINVALID | SU_OUTLET_GROUP | SU_TYPE_DAISY_1, NULL }, /* groupCurrent.0.1 = Integer: 0 */ { "outlet.group.%i.current", 0, 0.001, ".1.3.6.1.4.1.534.6.6.7.5.4.1.3.%i.%i", NULL, SU_OUTLET_GROUP | SU_TYPE_DAISY_1, NULL }, /* groupCurrentCapacity.0.1 = Integer: 16000 */ { "outlet.group.%i.current.nominal", 0, 0.001, ".1.3.6.1.4.1.534.6.6.7.5.4.1.2.%i.%i", NULL, SU_OUTLET_GROUP | SU_TYPE_DAISY_1, NULL }, /* groupCurrentThStatus.0.1 = Integer: good (0) */ { "outlet.group.%i.current.status", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.534.6.6.7.5.4.1.4.%i.%i", NULL, SU_OUTLET_GROUP | SU_TYPE_DAISY_1, &marlin_threshold_status_info[0] }, { "outlet.group.%i.alarm", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.534.6.6.7.5.4.1.4.%i.%i", NULL, SU_OUTLET_GROUP | SU_TYPE_DAISY_1, &marlin_threshold_current_alarms_info[0] }, /* groupCurrentPercentLoad.0.1 = Integer: 0 */ { "outlet.group.%i.load", 0, 1.0, ".1.3.6.1.4.1.534.6.6.7.5.4.1.10.%i.%i", NULL, SU_FLAG_NEGINVALID | SU_OUTLET_GROUP | SU_TYPE_DAISY_1, NULL }, /* groupCurrentThLowerWarning.0.1 = Integer: 0 */ { "outlet.group.%i.current.low.warning", ST_FLAG_RW, 0.001, ".1.3.6.1.4.1.534.6.6.7.5.4.1.5.%i.%i", NULL, SU_FLAG_NEGINVALID | SU_OUTLET_GROUP | SU_TYPE_DAISY_1, NULL }, /* groupCurrentThLowerCritical.0.1 = Integer: -1 */ { "outlet.group.%i.current.low.critical", ST_FLAG_RW, 0.001, ".1.3.6.1.4.1.534.6.6.7.5.4.1.6.%i.%i", NULL, SU_FLAG_NEGINVALID | SU_OUTLET_GROUP | SU_TYPE_DAISY_1, NULL }, /* groupCurrentThUpperWarning.0.1 = Integer: 12800 */ { "outlet.group.%i.current.high.warning", ST_FLAG_RW, 0.001, ".1.3.6.1.4.1.534.6.6.7.5.4.1.7.%i.%i", NULL, SU_FLAG_NEGINVALID | SU_OUTLET_GROUP | SU_TYPE_DAISY_1, NULL }, /* groupCurrentThUpperCritical.0.1 = Integer: 16000 */ { "outlet.group.%i.current.high.critical", ST_FLAG_RW, 0.001, ".1.3.6.1.4.1.534.6.6.7.5.4.1.8.%i.%i", NULL, SU_FLAG_NEGINVALID | SU_OUTLET_GROUP | SU_TYPE_DAISY_1, NULL }, /* groupWatts.0.1 = Integer: 2670 */ { "outlet.group.%i.realpower", 0, 1.0, ".1.3.6.1.4.1.534.6.6.7.5.5.1.3.%i.%i", NULL, SU_FLAG_NEGINVALID | SU_OUTLET_GROUP | SU_TYPE_DAISY_1, NULL }, /* groupVA.0.1 = Integer: 3132 */ { "outlet.group.%i.power", 0, 1.0, ".1.3.6.1.4.1.534.6.6.7.5.5.1.2.%i.%i", NULL, SU_FLAG_NEGINVALID | SU_OUTLET_GROUP | SU_TYPE_DAISY_1, NULL }, /* Input to which an outlet-group is connected * groupInputIndex.0.1 = Integer: 1 */ /* FIXME: RFC on key name is needed when backporting to NUT upstream */ { "outlet.group.%i.input", 0, 1, ".1.3.6.1.4.1.534.6.6.7.5.1.1.9.%i.%i", NULL, SU_FLAG_NEGINVALID | SU_OUTLET_GROUP | SU_TYPE_DAISY_1, NULL }, /* instant commands. */ /* Notes: * - load.cycle might be replaced by / mapped on shutdown.reboot * - outletControl{Off,On,Reboot}Cmd values: * 0-n : Timer * -1 : Cancel * we currently use "0", so instant On | Off | Reboot... */ /* no counterpart found! { "outlet.load.off", 0, DO_OFF, AR_OID_OUTLET_STATUS ".0", NULL, SU_TYPE_CMD, NULL }, { "outlet.load.on", 0, DO_ON, AR_OID_OUTLET_STATUS ".0", NULL, SU_TYPE_CMD, NULL }, { "outlet.load.cycle", 0, DO_CYCLE, AR_OID_OUTLET_STATUS ".0", NULL, SU_TYPE_CMD, NULL }, */ /* Delays handling: * 0-n :Time in seconds until the group command is issued * -1:Cancel a pending group-level Off/On/Reboot command */ { "outlet.%i.load.off", 0, 1, ".1.3.6.1.4.1.534.6.6.7.6.6.1.3.%i.%i", "0", SU_TYPE_CMD | SU_OUTLET | SU_TYPE_DAISY_1, NULL }, { "outlet.%i.load.on", 0, 1, ".1.3.6.1.4.1.534.6.6.7.6.6.1.4.%i.%i", "0", SU_TYPE_CMD | SU_OUTLET | SU_TYPE_DAISY_1, NULL }, { "outlet.%i.load.cycle", 0, 1, ".1.3.6.1.4.1.534.6.6.7.6.6.1.5.%i.%i", "0", SU_TYPE_CMD | SU_OUTLET | SU_TYPE_DAISY_1, NULL }, /* Per-outlet shutdown / startup delay (configuration point, not the timers) * outletControlShutoffDelay.0.3 = INTEGER: 120 * outletControlSequenceDelay.0.8 = INTEGER: 8 * (by default each output socket startup is delayed by its number in seconds) */ { "outlet.%i.delay.shutdown", ST_FLAG_RW, 1, ".1.3.6.1.4.1.534.6.6.7.6.6.1.10.%i.%i", NULL, SU_FLAG_NEGINVALID | SU_OUTLET | SU_TYPE_DAISY_1, NULL }, { "outlet.%i.delay.start", ST_FLAG_RW, 1, ".1.3.6.1.4.1.534.6.6.7.6.6.1.7.%i.%i", NULL, SU_FLAG_NEGINVALID | SU_OUTLET | SU_TYPE_DAISY_1, NULL }, /* Delayed version, parameter is mandatory (so dfl is NULL)! */ { "outlet.%i.load.off.delay", 0, 1, ".1.3.6.1.4.1.534.6.6.7.6.6.1.3.%i.%i", NULL, SU_TYPE_CMD | SU_OUTLET | SU_TYPE_DAISY_1, NULL }, { "outlet.%i.load.on.delay", 0, 1, ".1.3.6.1.4.1.534.6.6.7.6.6.1.4.%i.%i", NULL, SU_TYPE_CMD | SU_OUTLET | SU_TYPE_DAISY_1, NULL }, { "outlet.%i.load.cycle.delay", 0, 1, ".1.3.6.1.4.1.534.6.6.7.6.6.1.5.%i.%i", NULL, SU_TYPE_CMD | SU_OUTLET | SU_TYPE_DAISY_1, NULL }, /* Per-outlet shutdown / startup timers * outletControlOffCmd.0.1 = INTEGER: -1 * outletControlOnCmd.0.1 = INTEGER: -1 */ { "outlet.%i.timer.shutdown", 0, 1, ".1.3.6.1.4.1.534.6.6.7.6.6.1.3.%i.%i", NULL, SU_OUTLET | SU_TYPE_DAISY_1, NULL }, { "outlet.%i.timer.start", 0, 1, ".1.3.6.1.4.1.534.6.6.7.6.6.1.4.%i.%i", NULL, SU_OUTLET | SU_TYPE_DAISY_1, NULL }, /* Delays handling: * 0-n :Time in seconds until the group command is issued * -1:Cancel a pending group-level Off/On/Reboot command */ /* groupControlOffCmd.0.1 = Integer: -1 */ { "outlet.group.%i.load.off", 0, 1, ".1.3.6.1.4.1.534.6.6.7.5.6.1.3.%i.%i", "0", SU_TYPE_CMD | SU_OUTLET_GROUP | SU_TYPE_DAISY_1, NULL }, /* groupControl0nCmd.0.1 = Integer: -1 */ { "outlet.group.%i.load.on", 0, 1, ".1.3.6.1.4.1.534.6.6.7.5.6.1.4.%i.%i", "0", SU_TYPE_CMD | SU_OUTLET_GROUP | SU_TYPE_DAISY_1, NULL }, /* groupControlRebootCmd.0.1 = Integer: -1 */ { "outlet.group.%i.load.cycle", 0, 1, ".1.3.6.1.4.1.534.6.6.7.5.6.1.5.%i.%i", "0", SU_TYPE_CMD | SU_OUTLET_GROUP | SU_TYPE_DAISY_1, NULL }, /* Delayed version, parameter is mandatory (so dfl is NULL)! */ { "outlet.group.%i.load.off.delay", 0, 1, ".1.3.6.1.4.1.534.6.6.7.5.6.1.3.%i.%i", NULL, SU_TYPE_CMD | SU_OUTLET_GROUP | SU_TYPE_DAISY_1, NULL }, /* groupControl0nCmd.0.1 = Integer: -1 */ { "outlet.group.%i.load.on.delay", 0, 1, ".1.3.6.1.4.1.534.6.6.7.5.6.1.4.%i.%i", NULL, SU_TYPE_CMD | SU_OUTLET_GROUP | SU_TYPE_DAISY_1, NULL }, /* groupControlRebootCmd.0.1 = Integer: -1 */ { "outlet.group.%i.load.cycle.delay", 0, 1, ".1.3.6.1.4.1.534.6.6.7.5.6.1.5.%i.%i", NULL, SU_TYPE_CMD | SU_OUTLET_GROUP | SU_TYPE_DAISY_1, NULL }, /* end of structure. */ { NULL, 0, 0, NULL, NULL, 0, NULL } }; mib2nut_info_t eaton_marlin = { "eaton_epdu", EATON_MARLIN_MIB_VERSION, NULL, EATON_MARLIN_OID_MODEL_NAME, eaton_marlin_mib, EATON_MARLIN_SYSOID, NULL }; nut-2.8.1/drivers/mge-xml.h0000644000175000017500000000345614500336654012464 00000000000000/* mge-xml.h Model specific data for MGE XML protocol UPSes Copyright (C) 2008 Arjen de Korte 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 2 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, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef MGE_XML_H #define MGE_XML_H #include "netxml-ups.h" extern subdriver_t mge_xml_subdriver; /** * \brief Convert NUT variable name to MGE XML * * \param name NUT variable name * * \return MGE XML variable name */ const char *vname_nut2mge_xml(const char *name); /** * \brief Convert MGE XML variable name to NUT * * \param name MGE XML variable name * * \return NUT variable name */ const char * vname_mge_xml2nut(const char *name); /** * \brief Convert MGE XML variable value to NUT value * * The function produces a newly created C-string that should * be destroyed using \c free. * * \param name NUT variable name * \param value MGE XML variable value * \param len MGE XML variable value length (in characters) * * \return NUT variable value */ char *vvalue_mge_xml2nut(const char *name, const char *value, size_t len); /** * \brief Register set of R/W variables */ void vname_register_rw(void); #endif /* MGE_XML_H */ nut-2.8.1/drivers/apc-epdu-mib.c0000644000175000017500000003513014501607135013342 00000000000000/* apc-epdu-mib.c - subdriver to monitor apc SNMP easy pdu with NUT * * Copyright (C) * 2011 - 2022 Eric Clappier * * Note: this subdriver was initially generated as a "stub" by the * gen-snmp-subdriver script. It must be customized! * * 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 2 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, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "apc-epdu-mib.h" #define APC_EPDU_MIB_VERSION "0.1" #define APC_EPDU_MIB_SYSOID ".1.3.6.1.4.1.318.1.3.4.9" static info_lkp_t apc_epdu_sw_outlet_status_info[] = { { 1, "off", NULL, NULL }, { 2, "on", NULL, NULL }, { 0, NULL, NULL, NULL } }; static info_lkp_t apc_epdu_sw_outlet_switchability_info[] = { { 1, "yes", NULL, NULL }, { 2, "yes", NULL, NULL }, { 0, NULL, NULL, NULL } }; /* POWERNET-MIB Snmp2NUT lookup table */ static snmp_info_t apc_epdu_mib[] = { /* Device page */ { "device.mfr", ST_FLAG_STRING, SU_INFOSIZE, NULL, "APC", SU_FLAG_STATIC | SU_FLAG_ABSENT | SU_FLAG_OK, NULL }, /* ePDUDeviceStatusModelNumber.1 = STRING: "EPDU1016M" */ { "device.model", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.318.1.1.30.2.1.1.4.1", "Easy ePDU", SU_FLAG_STATIC | SU_FLAG_OK, NULL }, { "device.type", ST_FLAG_STRING, SU_INFOSIZE, NULL, "pdu", SU_FLAG_STATIC | SU_FLAG_ABSENT | SU_FLAG_OK, NULL }, { "device.contact", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.2.1.1.4.0", NULL, SU_FLAG_STALE | SU_FLAG_OK, NULL }, { "device.description", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.2.1.1.5.0", NULL, SU_FLAG_STALE | SU_FLAG_OK, NULL }, { "device.location", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.2.1.1.6.0", NULL, SU_FLAG_STALE | SU_FLAG_OK, NULL }, /* FIXME: to be RFC'ed */ { "device.uptime", 0, 1, ".1.3.6.1.2.1.1.3.0", NULL, SU_FLAG_OK | SU_FLAG_NEGINVALID, NULL }, /* ePDUDeviceStatusSerialNumber.1 = STRING: "506255604729" */ { "device.serial", ST_FLAG_STRING, SU_INFOSIZE, " .1.3.6.1.4.1.318.1.1.30.2.1.1.5.1", NULL, SU_FLAG_STATIC | SU_FLAG_OK, NULL }, /* ePDUDeviceStatusModelNumber.1 = STRING: "EPDU1016M" */ { "device.part", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.318.1.1.30.2.1.1.4.1", NULL, SU_FLAG_STATIC | SU_FLAG_OK, NULL }, /* ePDUDeviceStatusVersion.1 = STRING: "Ver16.10" */ { "device.version", ST_FLAG_STRING, SU_INFOSIZE, " .1.3.6.1.4.1.318.1.1.30.2.1.1.3.1", NULL, SU_FLAG_STATIC | SU_FLAG_OK, NULL }, /* Input */ /* ePDUPhaseTableSize = INTEGER: 1 */ { "input.phases", 0, 1, ".1.3.6.1.4.1.318.1.1.30.3.0", NULL, SU_FLAG_OK, NULL }, /* ePDUDeviceStatusActivePower.1 = INTEGER: 785 */ { "input.realpower", 0, 1, ".1.3.6.1.4.1.318.1.1.30.2.1.1.7.1", NULL, SU_FLAG_OK | SU_FLAG_NEGINVALID, NULL }, /* Take first phase for global if single phase */ /* ePDUPhaseStatusVoltage.1 = INTEGER: 2304 */ { "input.voltage", 0, 0.1, ".1.3.6.1.4.1.318.1.1.30.4.2.1.4.1", NULL, SU_FLAG_OK | SU_FLAG_NEGINVALID | SU_INPUT_1, NULL }, /* Take first phase for global if single phase */ /* ePDUPhaseStatusCurrent.1 = INTEGER: 355 */ { "input.current", 0, 0.01, ".1.3.6.1.4.1.318.1.1.30.4.2.1.5.1", NULL, SU_FLAG_OK | SU_FLAG_NEGINVALID | SU_INPUT_1, NULL }, /* Only if tree-phase */ /* ePDUPhaseStatusVoltage.1 = INTEGER: 2304 */ { "input.L1-N.voltage", 0, 0.1, ".1.3.6.1.4.1.318.1.1.30.4.2.1.4.1", NULL, SU_FLAG_OK | SU_FLAG_NEGINVALID | SU_INPUT_3, NULL }, /* ePDUPhaseStatusVoltage.2 = INTEGER: 2304 */ { "input.L2-N.voltage", 0, 0.1, ".1.3.6.1.4.1.318.1.1.30.4.2.1.4.2", NULL, SU_FLAG_OK | SU_FLAG_NEGINVALID | SU_INPUT_3, NULL }, /* ePDUPhaseStatusVoltage.3 = INTEGER: 2304 */ { "input.L3-N.voltage", 0, 0.1, ".1.3.6.1.4.1.318.1.1.30.4.2.1.4.3", NULL, SU_FLAG_OK | SU_FLAG_NEGINVALID | SU_INPUT_3, NULL }, /* ePDUPhaseStatusCurrent.1 = INTEGER: 355 */ { "input.L1.current", 0, 0.01, ".1.3.6.1.4.1.318.1.1.30.4.2.1.5.1", NULL, SU_FLAG_OK | SU_FLAG_NEGINVALID | SU_INPUT_3, NULL }, /* ePDUPhaseStatusCurrent.2 = INTEGER: 355 */ { "input.L2.current", 0, 0.01, ".1.3.6.1.4.1.318.1.1.30.4.2.1.5.2", NULL, SU_FLAG_OK | SU_FLAG_NEGINVALID | SU_INPUT_3, NULL }, /* ePDUPhaseStatusCurrent.3 = INTEGER: 355 */ { "input.L3.current", 0, 0.01, ".1.3.6.1.4.1.318.1.1.30.4.2.1.5.3", NULL, SU_FLAG_OK | SU_FLAG_NEGINVALID | SU_INPUT_3, NULL }, /* ePDUPhaseStatusActivePower.1 = INTEGER: 785 */ { "input.L1.realpower", 0, 1, ".1.3.6.1.4.1.318.1.1.30.4.2.1.6.1", NULL, SU_FLAG_OK | SU_FLAG_NEGINVALID | SU_INPUT_3, NULL }, /* ePDUPhaseStatusActivePower.2 = INTEGER: 785 */ { "input.L2.realpower", 0, 1, ".1.3.6.1.4.1.318.1.1.30.4.2.1.6.2", NULL, SU_FLAG_OK | SU_FLAG_NEGINVALID | SU_INPUT_3, NULL }, /* ePDUPhaseStatusActivePower.3 = INTEGER: 785 */ { "input.L3.realpower", 0, 1, ".1.3.6.1.4.1.318.1.1.30.4.2.1.6.3", NULL, SU_FLAG_OK | SU_FLAG_NEGINVALID | SU_INPUT_3, NULL }, /* Outlets */ /* ePDUOutletTableSize.0 = INTEGER: 1 */ { "outlet.count", 0, 1, ".1.3.6.1.4.1.318.1.1.30.5.0", NULL, SU_FLAG_STATIC | SU_FLAG_OK, NULL }, /* ePDUOutletStatusIndex.%i = INTEGER: 1 */ { "outlet.%i.id", 0, 1, ".1.3.6.1.4.1.318.1.1.30.6.1.1.1.%i", "%i", SU_FLAG_STATIC | SU_FLAG_OK | SU_FLAG_NEGINVALID | SU_OUTLET, NULL }, /* ePDUOutletStatusModule.%i= INTEGER: 1 */ { "outlet.%i.name", 0, 1, ".1.3.6.1.4.1.318.1.1.30.6.2.1.2.%i", NULL, SU_FLAG_OK | SU_FLAG_NEGINVALID | SU_OUTLET, NULL }, /* ePDUOutletStatusNumber.%i = INTEGER: 1 */ { "outlet.%i.desc", 0, 1, NULL, "Outlet %i", SU_FLAG_STATIC | SU_FLAG_ABSENT | SU_OUTLET, NULL }, /* ePDUOutletStatusState.%i = INTEGER: off(1) */ { "outlet.%i.status", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.318.1.1.30.6.1.1.4.%i", NULL, SU_FLAG_OK | SU_FLAG_NEGINVALID | SU_OUTLET, &apc_epdu_sw_outlet_status_info[0] }, /* Also use this OID to determine switchability ; its presence means "yes" */ /* ePDUOutletStatusState.%i = INTEGER: off(1) */ { "outlet.%i.switchable", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.318.1.1.30.6.1.1.4.%i", "yes", SU_FLAG_STATIC | SU_FLAG_ABSENT | SU_FLAG_OK | SU_OUTLET, &apc_epdu_sw_outlet_switchability_info[0] }, #if WITH_UNMAPPED_DATA_POINTS /* keep following scan for future development */ /* iso.3.6.1.4.1.318.1.1.30.1.0 = INTEGER: 1 */ { "unmapped.iso", 0, 1, ".1.3.6.1.4.1.318.1.1.30.1.0", NULL, SU_FLAG_OK, NULL }, /* iso.3.6.1.4.1.318.1.1.30.2.1.1.1.1 = INTEGER: 1 */ { "unmapped.iso", 0, 1, ".1.3.6.1.4.1.318.1.1.30.2.1.1.1.1", NULL, SU_FLAG_OK, NULL }, /* iso.3.6.1.4.1.318.1.1.30.2.1.1.2.1 = INTEGER: 1 */ { "unmapped.iso", 0, 1, ".1.3.6.1.4.1.318.1.1.30.2.1.1.2.1", NULL, SU_FLAG_OK, NULL }, /* iso.3.6.1.4.1.318.1.1.30.2.1.1.3.1 = STRING: "Ver16.10" */ { "unmapped.iso", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.318.1.1.30.2.1.1.3.1", NULL, SU_FLAG_OK, NULL }, /* iso.3.6.1.4.1.318.1.1.30.2.1.1.4.1 = STRING: "EPDU1016M" */ { "unmapped.iso", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.318.1.1.30.2.1.1.4.1", NULL, SU_FLAG_OK, NULL }, /* iso.3.6.1.4.1.318.1.1.30.2.1.1.5.1 = STRING: "506255604717" */ { "unmapped.iso", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.318.1.1.30.2.1.1.5.1", NULL, SU_FLAG_OK, NULL }, /* iso.3.6.1.4.1.318.1.1.30.2.1.1.6.1 = INTEGER: 1 */ { "unmapped.iso", 0, 1, ".1.3.6.1.4.1.318.1.1.30.2.1.1.6.1", NULL, SU_FLAG_OK, NULL }, /* iso.3.6.1.4.1.318.1.1.30.2.1.1.7.1 = INTEGER: 785 */ { "unmapped.iso", 0, 1, ".1.3.6.1.4.1.318.1.1.30.2.1.1.7.1", NULL, SU_FLAG_OK, NULL }, /* iso.3.6.1.4.1.318.1.1.30.2.1.1.8.1 = INTEGER: -1 */ { "unmapped.iso", 0, 1, ".1.3.6.1.4.1.318.1.1.30.2.1.1.8.1", NULL, SU_FLAG_OK, NULL }, /* iso.3.6.1.4.1.318.1.1.30.2.1.1.9.1 = INTEGER: -1 */ { "unmapped.iso", 0, 1, ".1.3.6.1.4.1.318.1.1.30.2.1.1.9.1", NULL, SU_FLAG_OK, NULL }, /* iso.3.6.1.4.1.318.1.1.30.2.1.1.10.1 = INTEGER: 965 */ { "unmapped.iso", 0, 1, ".1.3.6.1.4.1.318.1.1.30.2.1.1.10.1", NULL, SU_FLAG_OK, NULL }, /* iso.3.6.1.4.1.318.1.1.30.2.1.1.11.1 = INTEGER: 9114157 */ { "unmapped.iso", 0, 1, ".1.3.6.1.4.1.318.1.1.30.2.1.1.11.1", NULL, SU_FLAG_OK, NULL }, /* iso.3.6.1.4.1.318.1.1.30.2.1.1.12.1 = INTEGER: 49988 */ { "unmapped.iso", 0, 1, ".1.3.6.1.4.1.318.1.1.30.2.1.1.12.1", NULL, SU_FLAG_OK, NULL }, /* iso.3.6.1.4.1.318.1.1.30.2.2.1.1.1 = INTEGER: 1 */ { "unmapped.iso", 0, 1, ".1.3.6.1.4.1.318.1.1.30.2.2.1.1.1", NULL, SU_FLAG_OK, NULL }, /* iso.3.6.1.4.1.318.1.1.30.2.2.1.2.1 = INTEGER: 1 */ { "unmapped.iso", 0, 1, ".1.3.6.1.4.1.318.1.1.30.2.2.1.2.1", NULL, SU_FLAG_OK, NULL }, /* iso.3.6.1.4.1.318.1.1.30.2.2.1.3.1 = INTEGER: 0 */ { "unmapped.iso", 0, 1, ".1.3.6.1.4.1.318.1.1.30.2.2.1.3.1", NULL, SU_FLAG_OK, NULL }, /* iso.3.6.1.4.1.318.1.1.30.2.2.1.4.1 = INTEGER: 0 */ { "unmapped.iso", 0, 1, ".1.3.6.1.4.1.318.1.1.30.2.2.1.4.1", NULL, SU_FLAG_OK, NULL }, /* iso.3.6.1.4.1.318.1.1.30.2.2.1.5.1 = INTEGER: 2 */ { "unmapped.iso", 0, 1, ".1.3.6.1.4.1.318.1.1.30.2.2.1.5.1", NULL, SU_FLAG_OK, NULL }, /* iso.3.6.1.4.1.318.1.1.30.3.0 = INTEGER: 1 */ { "unmapped.iso", 0, 1, ".1.3.6.1.4.1.318.1.1.30.3.0", NULL, SU_FLAG_OK, NULL }, /* iso.3.6.1.4.1.318.1.1.30.4.1.1.1.1 = INTEGER: 1 */ { "unmapped.iso", 0, 1, ".1.3.6.1.4.1.318.1.1.30.4.1.1.1.1", NULL, SU_FLAG_OK, NULL }, /* iso.3.6.1.4.1.318.1.1.30.4.1.1.2.1 = INTEGER: 1 */ { "unmapped.iso", 0, 1, ".1.3.6.1.4.1.318.1.1.30.4.1.1.2.1", NULL, SU_FLAG_OK, NULL }, /* iso.3.6.1.4.1.318.1.1.30.4.1.1.3.1 = INTEGER: 1 */ { "unmapped.iso", 0, 1, ".1.3.6.1.4.1.318.1.1.30.4.1.1.3.1", NULL, SU_FLAG_OK, NULL }, /* iso.3.6.1.4.1.318.1.1.30.4.1.1.4.1 = INTEGER: 3000 */ { "unmapped.iso", 0, 1, ".1.3.6.1.4.1.318.1.1.30.4.1.1.4.1", NULL, SU_FLAG_OK, NULL }, /* iso.3.6.1.4.1.318.1.1.30.4.1.1.5.1 = INTEGER: 0 */ { "unmapped.iso", 0, 1, ".1.3.6.1.4.1.318.1.1.30.4.1.1.5.1", NULL, SU_FLAG_OK, NULL }, /* iso.3.6.1.4.1.318.1.1.30.4.1.1.6.1 = INTEGER: 3200 */ { "unmapped.iso", 0, 1, ".1.3.6.1.4.1.318.1.1.30.4.1.1.6.1", NULL, SU_FLAG_OK, NULL }, /* iso.3.6.1.4.1.318.1.1.30.4.1.1.7.1 = INTEGER: 0 */ { "unmapped.iso", 0, 1, ".1.3.6.1.4.1.318.1.1.30.4.1.1.7.1", NULL, SU_FLAG_OK, NULL }, /* iso.3.6.1.4.1.318.1.1.30.4.2.1.1.1 = INTEGER: 1 */ { "unmapped.iso", 0, 1, ".1.3.6.1.4.1.318.1.1.30.4.2.1.1.1", NULL, SU_FLAG_OK, NULL }, /* iso.3.6.1.4.1.318.1.1.30.4.2.1.2.1 = INTEGER: 1 */ { "unmapped.iso", 0, 1, ".1.3.6.1.4.1.318.1.1.30.4.2.1.2.1", NULL, SU_FLAG_OK, NULL }, /* iso.3.6.1.4.1.318.1.1.30.4.2.1.3.1 = INTEGER: 1 */ { "unmapped.iso", 0, 1, ".1.3.6.1.4.1.318.1.1.30.4.2.1.3.1", NULL, SU_FLAG_OK, NULL }, /* iso.3.6.1.4.1.318.1.1.30.4.2.1.4.1 = INTEGER: 2304 */ { "unmapped.iso", 0, 1, ".1.3.6.1.4.1.318.1.1.30.4.2.1.4.1", NULL, SU_FLAG_OK, NULL }, /* iso.3.6.1.4.1.318.1.1.30.4.2.1.5.1 = INTEGER: 353 */ { "unmapped.iso", 0, 1, ".1.3.6.1.4.1.318.1.1.30.4.2.1.5.1", NULL, SU_FLAG_OK, NULL }, /* iso.3.6.1.4.1.318.1.1.30.4.2.1.6.1 = INTEGER: 785 */ { "unmapped.iso", 0, 1, ".1.3.6.1.4.1.318.1.1.30.4.2.1.6.1", NULL, SU_FLAG_OK, NULL }, /* iso.3.6.1.4.1.318.1.1.30.4.2.1.7.1 = INTEGER: -1 */ { "unmapped.iso", 0, 1, ".1.3.6.1.4.1.318.1.1.30.4.2.1.7.1", NULL, SU_FLAG_OK, NULL }, /* iso.3.6.1.4.1.318.1.1.30.4.2.1.8.1 = INTEGER: -1 */ { "unmapped.iso", 0, 1, ".1.3.6.1.4.1.318.1.1.30.4.2.1.8.1", NULL, SU_FLAG_OK, NULL }, /* iso.3.6.1.4.1.318.1.1.30.4.2.1.9.1 = INTEGER: 965 */ { "unmapped.iso", 0, 1, ".1.3.6.1.4.1.318.1.1.30.4.2.1.9.1", NULL, SU_FLAG_OK, NULL }, /* iso.3.6.1.4.1.318.1.1.30.4.2.1.10.1 = INTEGER: 9114157 */ { "unmapped.iso", 0, 1, ".1.3.6.1.4.1.318.1.1.30.4.2.1.10.1", NULL, SU_FLAG_OK, NULL }, /* iso.3.6.1.4.1.318.1.1.30.5.0 = INTEGER: 0 */ { "unmapped.iso", 0, 1, ".1.3.6.1.4.1.318.1.1.30.5.0", NULL, SU_FLAG_OK, NULL }, /* iso.3.6.1.4.1.318.1.1.30.6.1.1.1.1 = INTEGER: -1 */ { "unmapped.iso", 0, 1, ".1.3.6.1.4.1.318.1.1.30.6.1.1.1.1", NULL, SU_FLAG_OK, NULL }, /* iso.3.6.1.4.1.318.1.1.30.6.1.1.2.1 = INTEGER: -1 */ { "unmapped.iso", 0, 1, ".1.3.6.1.4.1.318.1.1.30.6.1.1.2.1", NULL, SU_FLAG_OK, NULL }, /* iso.3.6.1.4.1.318.1.1.30.6.1.1.3.1 = INTEGER: -1 */ { "unmapped.iso", 0, 1, ".1.3.6.1.4.1.318.1.1.30.6.1.1.3.1", NULL, SU_FLAG_OK, NULL }, /* iso.3.6.1.4.1.318.1.1.30.6.1.1.4.1 = INTEGER: -1 */ { "unmapped.iso", 0, 1, ".1.3.6.1.4.1.318.1.1.30.6.1.1.4.1", NULL, SU_FLAG_OK, NULL }, /* iso.3.6.1.4.1.318.1.1.30.6.2.1.1.1 = INTEGER: -1 */ { "unmapped.iso", 0, 1, ".1.3.6.1.4.1.318.1.1.30.6.2.1.1.1", NULL, SU_FLAG_OK, NULL }, /* iso.3.6.1.4.1.318.1.1.30.6.2.1.2.1 = INTEGER: -1 */ { "unmapped.iso", 0, 1, ".1.3.6.1.4.1.318.1.1.30.6.2.1.2.1", NULL, SU_FLAG_OK, NULL }, /* iso.3.6.1.4.1.318.1.1.30.6.2.1.3.1 = INTEGER: -1 */ { "unmapped.iso", 0, 1, ".1.3.6.1.4.1.318.1.1.30.6.2.1.3.1", NULL, SU_FLAG_OK, NULL }, /* iso.3.6.1.4.1.318.1.1.30.6.2.1.4.1 = INTEGER: -1 */ { "unmapped.iso", 0, 1, ".1.3.6.1.4.1.318.1.1.30.6.2.1.4.1", NULL, SU_FLAG_OK, NULL }, /* iso.3.6.1.4.1.318.1.1.30.7.0 = INTEGER: 1 */ { "unmapped.iso", 0, 1, ".1.3.6.1.4.1.318.1.1.30.7.0", NULL, SU_FLAG_OK, NULL }, /* iso.3.6.1.4.1.318.1.1.30.8.1.1.1.1 = INTEGER: 1 */ { "unmapped.iso", 0, 1, ".1.3.6.1.4.1.318.1.1.30.8.1.1.1.1", NULL, SU_FLAG_OK, NULL }, /* iso.3.6.1.4.1.318.1.1.30.8.1.1.2.1 = INTEGER: 1 */ { "unmapped.iso", 0, 1, ".1.3.6.1.4.1.318.1.1.30.8.1.1.2.1", NULL, SU_FLAG_OK, NULL }, /* iso.3.6.1.4.1.318.1.1.30.8.1.1.3.1 = INTEGER: 900 */ { "unmapped.iso", 0, 1, ".1.3.6.1.4.1.318.1.1.30.8.1.1.3.1", NULL, SU_FLAG_OK, NULL }, /* iso.3.6.1.4.1.318.1.1.30.8.1.1.4.1 = INTEGER: 0 */ { "unmapped.iso", 0, 1, ".1.3.6.1.4.1.318.1.1.30.8.1.1.4.1", NULL, SU_FLAG_OK, NULL }, /* iso.3.6.1.4.1.318.1.1.30.8.1.1.5.1 = INTEGER: 900 */ { "unmapped.iso", 0, 1, ".1.3.6.1.4.1.318.1.1.30.8.1.1.5.1", NULL, SU_FLAG_OK, NULL }, /* iso.3.6.1.4.1.318.1.1.30.8.1.1.6.1 = INTEGER: 0 */ { "unmapped.iso", 0, 1, ".1.3.6.1.4.1.318.1.1.30.8.1.1.6.1", NULL, SU_FLAG_OK, NULL }, /* iso.3.6.1.4.1.318.1.1.30.8.2.1.1.1 = INTEGER: 1 */ { "unmapped.iso", 0, 1, ".1.3.6.1.4.1.318.1.1.30.8.2.1.1.1", NULL, SU_FLAG_OK, NULL }, /* iso.3.6.1.4.1.318.1.1.30.8.2.1.2.1 = INTEGER: 1 */ { "unmapped.iso", 0, 1, ".1.3.6.1.4.1.318.1.1.30.8.2.1.2.1", NULL, SU_FLAG_OK, NULL }, /* iso.3.6.1.4.1.318.1.1.30.8.2.1.3.1 = INTEGER: 0 */ { "unmapped.iso", 0, 1, ".1.3.6.1.4.1.318.1.1.30.8.2.1.3.1", NULL, SU_FLAG_OK, NULL }, /* iso.3.6.1.4.1.318.1.1.30.8.2.1.4.1 = INTEGER: 0 */ { "unmapped.iso", 0, 1, ".1.3.6.1.4.1.318.1.1.30.8.2.1.4.1", NULL, SU_FLAG_OK, NULL }, #endif /* end of structure. */ { NULL, 0, 0, NULL, NULL, 0, NULL } }; mib2nut_info_t apc_pdu_epdu = { "apc", APC_EPDU_MIB_VERSION, NULL, NULL, apc_epdu_mib, APC_EPDU_MIB_SYSOID, NULL }; nut-2.8.1/drivers/nutdrv_qx_bestups.c0000644000175000017500000006522114502253356014705 00000000000000/* nutdrv_qx_bestups.c - Subdriver for Best Power/Sola Australia UPSes * * Copyright (C) * 2014 Daniele Pezzini * Based on: * bestups.c - Copyright (C) * 1999 Russell Kroll * Jason White * * 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 2 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, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #include "main.h" #include "nut_float.h" #include "nut_stdint.h" #include "nutdrv_qx.h" #include "nutdrv_qx_blazer-common.h" #include "nutdrv_qx_bestups.h" #define BESTUPS_VERSION "BestUPS 0.07" /* Support functions */ static int bestups_claim(void); static void bestups_initups(void); static void bestups_makevartable(void); /* Answer preprocess functions */ static int bestups_preprocess_id_answer(item_t *item, const int len); /* Preprocess functions */ static int bestups_process_setvar(item_t *item, char *value, const size_t valuelen); static int bestups_process_bbb_status_bit(item_t *item, char *value, const size_t valuelen); static int bestups_manufacturer(item_t *item, char *value, const size_t valuelen); static int bestups_model(item_t *item, char *value, const size_t valuelen); static int bestups_batt_runtime(item_t *item, char *value, const size_t valuelen); static int bestups_batt_packs(item_t *item, char *value, const size_t valuelen); static int bestups_get_pins_shutdown_mode(item_t *item, char *value, const size_t valuelen); static int bestups_voltage_settings(item_t *item, char *value, const size_t valuelen); /* ups.conf settings */ static int pins_shutdown_mode; /* General settings */ static int inverted_bbb_bit = 0; /* == Ranges/enums == */ /* Range for ups.delay.start */ static info_rw_t bestups_r_ondelay[] = { { "60", 0 }, { "599940", 0 }, { "", 0 } }; /* Range for ups.delay.shutdown */ static info_rw_t bestups_r_offdelay[] = { { "12", 0 }, { "5940", 0 }, { "", 0 } }; /* Range for number of battery packs */ static info_rw_t bestups_r_batt_packs[] = { { "0", 0 }, { "5", 0 }, { "", 0 } }; /* Range for pin shutdown mode */ static info_rw_t bestups_r_pins_shutdown_mode[] = { { "0", 0 }, { "6", 0 }, { "", 0 } }; /* == qx2nut lookup table == */ static item_t bestups_qx2nut[] = { /* Query UPS for status * > [Q1\r] * < [(226.0 195.0 226.0 014 49.0 27.5 30.0 00001000\r] * 01234567890123456789012345678901234567890123456 * 0 1 2 3 4 */ { "input.voltage", 0, NULL, "Q1\r", "", 47, '(', "", 1, 5, "%.1f", 0, NULL, NULL, NULL }, { "input.voltage.fault", 0, NULL, "Q1\r", "", 47, '(', "", 7, 11, "%.1f", 0, NULL, NULL, NULL }, { "output.voltage", 0, NULL, "Q1\r", "", 47, '(', "", 13, 17, "%.1f", 0, NULL, NULL, NULL }, { "ups.load", 0, NULL, "Q1\r", "", 47, '(', "", 19, 21, "%.0f", 0, NULL, NULL, NULL }, { "input.frequency", 0, NULL, "Q1\r", "", 47, '(', "", 23, 26, "%.1f", 0, NULL, NULL, NULL }, { "battery.voltage", 0, NULL, "Q1\r", "", 47, '(', "", 28, 31, "%.2f", 0, NULL, NULL, qx_multiply_battvolt }, { "ups.temperature", 0, NULL, "Q1\r", "", 47, '(', "", 33, 36, "%.1f", 0, NULL, NULL, NULL }, /* Status bits */ { "ups.status", 0, NULL, "Q1\r", "", 47, '(', "", 38, 38, NULL, QX_FLAG_QUICK_POLL, NULL, NULL, blazer_process_status_bits }, /* Utility Fail (Immediate) */ { "ups.status", 0, NULL, "Q1\r", "", 47, '(', "", 39, 39, NULL, QX_FLAG_QUICK_POLL, NULL, NULL, blazer_process_status_bits }, /* Battery Low */ { "ups.alarm", 0, NULL, "Q1\r", "", 47, '(', "", 41, 41, NULL, 0, NULL, NULL, blazer_process_status_bits }, /* UPS Failed */ { "ups.type", 0, NULL, "Q1\r", "", 47, '(', "", 42, 42, "%s", QX_FLAG_STATIC, NULL, NULL, blazer_process_status_bits }, /* UPS Type */ { "ups.status", 0, NULL, "Q1\r", "", 47, '(', "", 43, 43, NULL, QX_FLAG_QUICK_POLL, NULL, NULL, blazer_process_status_bits }, /* Test in Progress */ { "ups.status", 0, NULL, "Q1\r", "", 47, '(', "", 44, 44, NULL, QX_FLAG_QUICK_POLL, NULL, NULL, blazer_process_status_bits }, /* Shutdown Active */ /* { "ups.beeper.status", 0, NULL, "Q1\r", "", 47, '(', "", 45, 45, "%s", 0, NULL, NULL, blazer_process_status_bits }, *//* Beeper status: not supported; always 0 */ { "ups.status", 0, NULL, "Q1\r", "", 47, '(', "", 40, 40, NULL, QX_FLAG_QUICK_POLL, NULL, NULL, bestups_process_bbb_status_bit }, /* Bypass/Boost or Buck Active - keep this one at the end as it needs the processed data from the previous items */ /* Query UPS for ratings and model infos * > [ID\r] * < [FOR,750,120,120,20.0,27.6\r] case #1: length = 26 * < [FOR,1500,120,120,20.0,27.6\r] case #2: length = 27 * < [FOR,3000,120,120,20.0,100.6\r] case #3: length = 28 * < [FOR, 750,120,120,20.0, 27.6\r] after being preprocessed: length = 28 * 0123456789012345678901234567 * 0 1 2 */ { "device.mfr", 0, NULL, "ID\r", "", 28, 0, "", 0, 2, "%s", QX_FLAG_STATIC, NULL, bestups_preprocess_id_answer, bestups_manufacturer }, { "device.model", 0, NULL, "ID\r", "", 28, 0, "", 0, 2, "%s", QX_FLAG_STATIC, NULL, bestups_preprocess_id_answer, bestups_model }, { "ups.power.nominal", 0, NULL, "ID\r", "", 28, 0, "", 4, 7, "%.0f", QX_FLAG_STATIC, NULL, bestups_preprocess_id_answer, NULL }, { "input.voltage.nominal", 0, NULL, "ID\r", "", 28, 0, "", 9, 11, "%.0f", QX_FLAG_STATIC, NULL, bestups_preprocess_id_answer, NULL }, { "output.voltage.nominal", 0, NULL, "ID\r", "", 28, 0, "", 13, 15, "%.0f", QX_FLAG_STATIC, NULL, bestups_preprocess_id_answer, NULL }, { "battery.voltage.low", 0, NULL, "ID\r", "", 28, 0, "", 17, 20, "%.1f", QX_FLAG_SEMI_STATIC, NULL, bestups_preprocess_id_answer, NULL }, { "battery.voltage.high", 0, NULL, "ID\r", "", 28, 0, "", 22, 26, "%.1f", QX_FLAG_SEMI_STATIC, NULL, bestups_preprocess_id_answer, NULL }, /* Query UPS for battery runtime (not available on the Patriot Pro/Sola 320 model series) * > [RT\r] * < [025\r] * 0123 * 0 */ { "battery.runtime", 0, NULL, "RT\r", "", 4, 0, "", 0, 2, "%.0f", QX_FLAG_SKIP, NULL, NULL, bestups_batt_runtime }, /* Query UPS for number of battery packs (available only on the Axxium/Sola 620 model series) * > [BP?\r] * < [02\r] * 012 * 0 */ { "battery.packs", ST_FLAG_RW, bestups_r_batt_packs, "BP?\r", "", 3, 0, "", 0, 1, "%d", QX_FLAG_SEMI_STATIC | QX_FLAG_RANGE | QX_FLAG_SKIP, NULL, NULL, bestups_batt_packs }, /* Set number of battery packs to n (integer, 0-5) (available only on the Axxium/Sola 620 model series) * > [BPn\r] * < [] */ { "battery.packs", 0, bestups_r_batt_packs, "BP%.0f\r", "", 0, 0, "", 0, 0, NULL, QX_FLAG_SETVAR | QX_FLAG_RANGE | QX_FLAG_SKIP, NULL, NULL, bestups_process_setvar }, /* Query UPS for shutdown mode functionality of Pin 1 and Pin 7 on the UPS DB9 communication port (Per Best Power's EPS-0059) * > [SS?\r] * < [0\r] * 01 * 0 */ { "pins_shutdown_mode", ST_FLAG_RW, bestups_r_pins_shutdown_mode, "SS?\r", "", 2, 0, "", 0, 0, "%.0f", QX_FLAG_SEMI_STATIC | QX_FLAG_RANGE | QX_FLAG_NONUT, NULL, NULL, bestups_get_pins_shutdown_mode }, /* Set shutdown mode functionality of Pin 1 and Pin 7 on the UPS DB9 communication port (Per Best Power's EPS-0059) to n (integer, 0-6) * > [SSn\r] * < [] */ { "pins_shutdown_mode", 0, bestups_r_pins_shutdown_mode, "SS%.0f\r", "", 0, 0, "", 0, 0, NULL, QX_FLAG_SETVAR | QX_FLAG_RANGE | QX_FLAG_NONUT | QX_FLAG_SKIP, NULL, NULL, bestups_process_setvar }, /* Query UPS for voltage settings * > [M\r] * < [0\r] * 01 * 0 */ { "input.transfer.low", 0, NULL, "M\r", "", 2, 0, "", 0, 0, "%d", 0, NULL, NULL, bestups_voltage_settings }, { "input.transfer.boost.low", 0, NULL, "M\r", "", 2, 0, "", 0, 0, "%d", 0, NULL, NULL, bestups_voltage_settings }, { "input.transfer.boost.high", 0, NULL, "M\r", "", 2, 0, "", 0, 0, "%d", 0, NULL, NULL, bestups_voltage_settings }, { "input.voltage.nominal", 0, NULL, "M\r", "", 2, 0, "", 0, 0, "%d", 0, NULL, NULL, bestups_voltage_settings }, { "output.voltage.nominal", 0, NULL, "M\r", "", 2, 0, "", 0, 0, "%d", 0, NULL, NULL, bestups_voltage_settings }, { "input.transfer.trim.low", 0, NULL, "M\r", "", 2, 0, "", 0, 0, "%d", 0, NULL, NULL, bestups_voltage_settings }, { "input.transfer.trim.high", 0, NULL, "M\r", "", 2, 0, "", 0, 0, "%d", 0, NULL, NULL, bestups_voltage_settings }, { "input.transfer.high", 0, NULL, "M\r", "", 2, 0, "", 0, 0, "%d", 0, NULL, NULL, bestups_voltage_settings }, /* Instant commands */ { "shutdown.return", 0, NULL, "S%s\r", "", 0, 0, "", 0, 0, NULL, QX_FLAG_CMD, NULL, NULL, blazer_process_command }, { "shutdown.stayoff", 0, NULL, "S%s\r", "", 0, 0, "", 0, 0, NULL, QX_FLAG_CMD, NULL, NULL, blazer_process_command }, { "shutdown.stop", 0, NULL, "C\r", "", 0, 0, "", 0, 0, NULL, QX_FLAG_CMD, NULL, NULL, NULL }, { "load.on", 0, NULL, "C\r", "", 0, 0, "", 0, 0, NULL, QX_FLAG_CMD, NULL, NULL, NULL }, { "load.off", 0, NULL, "S00R0000\r", "", 0, 0, "", 0, 0, NULL, QX_FLAG_CMD, NULL, NULL, NULL }, { "test.battery.start", 0, NULL, "T%02d\r", "", 0, 0, "", 0, 0, NULL, QX_FLAG_CMD, NULL, NULL, blazer_process_command }, { "test.battery.start.deep", 0, NULL, "TL\r", "", 0, 0, "", 0, 0, NULL, QX_FLAG_CMD, NULL, NULL, NULL }, { "test.battery.start.quick", 0, NULL, "T\r", "", 0, 0, "", 0, 0, NULL, QX_FLAG_CMD, NULL, NULL, NULL }, { "test.battery.stop", 0, NULL, "CT\r", "", 0, 0, "", 0, 0, NULL, QX_FLAG_CMD, NULL, NULL, NULL }, /* Server-side settable vars */ { "ups.delay.start", ST_FLAG_RW, bestups_r_ondelay, NULL, "", 0, 0, "", 0, 0, DEFAULT_ONDELAY, QX_FLAG_ABSENT | QX_FLAG_SETVAR | QX_FLAG_RANGE, NULL, NULL, blazer_process_setvar }, { "ups.delay.shutdown", ST_FLAG_RW, bestups_r_offdelay, NULL, "", 0, 0, "", 0, 0, DEFAULT_OFFDELAY, QX_FLAG_ABSENT | QX_FLAG_SETVAR | QX_FLAG_RANGE, NULL, NULL, blazer_process_setvar }, /* End of structure. */ { NULL, 0, NULL, NULL, "", 0, 0, "", 0, 0, NULL, 0, NULL, NULL, NULL } }; /* == Testing table == */ #ifdef TESTING static testing_t bestups_testing[] = { { "Q1\r", "(215.0 195.0 230.0 014 49.0 22.7 30.0 00100000\r", -1 }, { "ID\r", "FOR,750,120,120,20.0,27.6\r", -1 }, { "RT\r", "015\r", -1 }, { "BP?\r", "02\r", -1 }, { "BP1\r", "", -1 }, { "SS?\r", "0\r", -1 }, { "SS2\r", "", -1 }, { "M\r", "0\r", -1 }, { "S03\r", "", -1 }, { "C\r", "", -1 }, { "S02R0005\r", "", -1 }, { "S.5R0001\r", "", -1 }, { "T04\r", "", -1 }, { "TL\r", "", -1 }, { "T\r", "", -1 }, { "CT\r", "", -1 }, { NULL } }; #endif /* TESTING */ /* == Support functions == */ /* This function allows the subdriver to "claim" a device: return 1 if the device is supported by this subdriver, else 0. */ static int bestups_claim(void) { /* We need at least Q1 and ID to run this subdriver */ item_t *item = find_nut_info("input.voltage", 0, 0); /* Don't know what happened */ if (!item) return 0; /* No reply/Unable to get value */ if (qx_process(item, NULL)) return 0; /* Unable to process value */ if (ups_infoval_set(item) != 1) return 0; /* UPS Model */ item = find_nut_info("device.model", 0, 0); /* Don't know what happened */ if (!item) { dstate_delinfo("input.voltage"); return 0; } /* No reply/Unable to get value */ if (qx_process(item, NULL)) { dstate_delinfo("input.voltage"); return 0; } /* Unable to process value */ if (ups_infoval_set(item) != 1) { dstate_delinfo("input.voltage"); return 0; } return 1; } /* Subdriver-specific initups */ static void bestups_initups(void) { blazer_initups_light(bestups_qx2nut); } /* Subdriver-specific flags/vars */ static void bestups_makevartable(void) { addvar(VAR_VALUE, "pins_shutdown_mode", "Set shutdown mode functionality of Pin 1 and Pin 7 on the UPS DB9 communication port (Per Best Power's EPS-0059) to n (integer, 0-6)"); blazer_makevartable_light(); } /* == Answer preprocess functions == */ /* Preprocess the answer we got back from the UPS when queried with 'ID\r': make data begin always at the same indexes */ static int bestups_preprocess_id_answer(item_t *item, const int len) { int i; char refined[SMALLBUF] = "", rawval[SMALLBUF] = "", *token, *saveptr = NULL; if (len <= 0) return len; if (len < 25 || len > 27) { upsdebugx(4, "%s: wrong length [%s: %d]", __func__, item->info_type, len); return -1; } /* e.g.: * 1. item->answer = "FOR,750,120,120,20.0,27.6\r"; len = 26 * 2. item->answer = "FOR,1500,120,120,20.0,27.6\r"; len = 27 * 3. item->answer = "FOR,3000,120,120,20.0,100.6\r"; len = 28 */ upsdebugx(4, "read: '%.*s'", (int)strcspn(item->answer, "\r"), item->answer); snprintf(rawval, sizeof(rawval), "%s", item->answer); for (i = 1, token = strtok_r(rawval, ",", &saveptr); token != NULL; i++, token = strtok_r(NULL, ",", &saveptr)) { switch (i) { case 1: snprintf(refined, sizeof(refined), "%s", token); continue; case 2: /* Output power */ snprintfcat(refined, sizeof(refined), ",%4s", token); continue; case 6: /* Battery voltage at full charge (+ trailing CR) */ snprintfcat(refined, sizeof(refined), ",%6s", token); continue; default: snprintfcat(refined, sizeof(refined), ",%s", token); } } if (i != 7 || strlen(refined) != 28) { upsdebugx(2, "noncompliant reply: '%.*s'", (int)strcspn(refined, "\r"), refined); return -1; } upsdebugx(4, "read: '%.*s'", (int)strcspn(refined, "\r"), refined); /* e.g.: item->answer = "FOR, 750,120,120,20.0, 27.6\r"; len = 28 */ return snprintf(item->answer, sizeof(item->answer), "%s", refined); } /* == Preprocess functions == */ /* *SETVAR(/NONUT)* Preprocess setvars */ static int bestups_process_setvar(item_t *item, char *value, const size_t valuelen) { double val; if (!strlen(value)) { upsdebugx(2, "%s: value not given for %s", __func__, item->info_type); return -1; } val = strtod(value, NULL); if (!strcasecmp(item->info_type, "pins_shutdown_mode")) { if (d_equal(val, pins_shutdown_mode)) { upslogx(LOG_INFO, "%s is already set to %.0f", item->info_type, val); return -1; } } #ifdef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL #pragma GCC diagnostic push #endif #ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL #pragma GCC diagnostic ignored "-Wformat-nonliteral" #endif #ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_FORMAT_SECURITY #pragma GCC diagnostic ignored "-Wformat-security" #endif snprintf(value, valuelen, item->command, val); #ifdef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL #pragma GCC diagnostic pop #endif return 0; } /* Bypass/Boost or Buck status */ static int bestups_process_bbb_status_bit(item_t *item, char *value, const size_t valuelen) { /* Bypass/Boost/Buck bit is not reliable when a battery test, shutdown or on battery condition occurs: always ignore it in these cases */ if (!((unsigned int)(qx_status()) & STATUS(OL)) || ((unsigned int)(qx_status()) & (STATUS(CALIB) | STATUS(FSD)))) { if (item->value[0] == '1') item->value[0] = '0'; return blazer_process_status_bits(item, value, valuelen); } /* UPSes with inverted bypass/boost/buck bit */ if (inverted_bbb_bit) { if (item->value[0] == '1') item->value[0] = '0'; else if (item->value[0] == '0') item->value[0] = '1'; } return blazer_process_status_bits(item, value, valuelen); } /* Identify UPS manufacturer */ static int bestups_manufacturer(item_t *item, char *value, const size_t valuelen) { #ifdef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL #pragma GCC diagnostic push #endif #ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL #pragma GCC diagnostic ignored "-Wformat-nonliteral" #endif #ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_FORMAT_SECURITY #pragma GCC diagnostic ignored "-Wformat-security" #endif /* Best Power devices */ if ( !strcmp(item->value, "AX1") || !strcmp(item->value, "FOR") || !strcmp(item->value, "FTC") || !strcmp(item->value, "PR2") || !strcmp(item->value, "PRO") ) { snprintf(value, valuelen, item->dfl, "Best Power"); return 0; } /* Sola Australia devices */ if ( !strcmp(item->value, "325") || !strcmp(item->value, "520") || !strcmp(item->value, "620") ) { snprintf(value, valuelen, item->dfl, "Sola Australia"); return 0; } /* Unknown devices */ snprintf(value, valuelen, item->dfl, "Unknown"); #ifdef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL #pragma GCC diagnostic pop #endif return 0; } /* Identify UPS model and unskip qx2nut table's items accordingly */ static int bestups_model(item_t *item, char *value, const size_t valuelen) { item_t *unskip; #ifdef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL #pragma GCC diagnostic push #endif #ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL #pragma GCC diagnostic ignored "-Wformat-nonliteral" #endif #ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_FORMAT_SECURITY #pragma GCC diagnostic ignored "-Wformat-security" #endif /* Best Power devices */ if (!strcmp(item->value, "AX1")) { snprintf(value, valuelen, item->dfl, "Axxium Rackmount"); } else if (!strcmp(item->value, "FOR")) { snprintf(value, valuelen, item->dfl, "Fortress"); } else if (!strcmp(item->value, "FTC")) { snprintf(value, valuelen, item->dfl, "Fortress Telecom"); } else if (!strcmp(item->value, "PR2")) { snprintf(value, valuelen, item->dfl, "Patriot Pro II"); inverted_bbb_bit = 1; } else if (!strcmp(item->value, "PRO")) { snprintf(value, valuelen, item->dfl, "Patriot Pro"); inverted_bbb_bit = 1; /* Sola Australia devices */ } else if ( !strcmp(item->value, "320") || !strcmp(item->value, "325") || !strcmp(item->value, "520") || !strcmp(item->value, "525") || !strcmp(item->value, "620") ) { snprintf(value, valuelen, "Sola %s", item->value); /* Unknown devices */ } else { snprintf(value, valuelen, item->dfl, "Unknown (%s)", item->value); upslogx(LOG_INFO, "Unknown model detected - please report this ID: '%s'", item->value); } /* Unskip qx2nut table's items according to the UPS model */ /* battery.runtime var is not available on the Patriot Pro/Sola 320 model series: leave it skipped in these cases, otherwise unskip it */ if (strcmp(item->value, "PRO") && strcmp(item->value, "320")) { unskip = find_nut_info("battery.runtime", 0, 0); /* Don't know what happened */ if (!unskip) return -1; unskip->qxflags &= ~QX_FLAG_SKIP; } /* battery.packs var is available only on the Axxium/Sola 620 model series: unskip it in these cases */ if (!strcmp(item->value, "AX1") || !strcmp(item->value, "620")) { unskip = find_nut_info("battery.packs", 0, QX_FLAG_SETVAR); /* Don't know what happened */ if (!unskip) return -1; unskip->qxflags &= ~QX_FLAG_SKIP; } #ifdef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL #pragma GCC diagnostic pop #endif return 0; } /* Battery runtime */ static int bestups_batt_runtime(item_t *item, char *value, const size_t valuelen) { double runtime; if (strspn(item->value, "0123456789 .") != strlen(item->value)) { upsdebugx(2, "%s: non numerical value [%s: %s]", __func__, item->info_type, item->value); return -1; } /* Battery runtime is reported by the UPS in minutes, NUT expects seconds */ runtime = strtod(item->value, NULL) * 60; #ifdef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL #pragma GCC diagnostic push #endif #ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL #pragma GCC diagnostic ignored "-Wformat-nonliteral" #endif #ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_FORMAT_SECURITY #pragma GCC diagnostic ignored "-Wformat-security" #endif snprintf(value, valuelen, item->dfl, runtime); #ifdef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL #pragma GCC diagnostic pop #endif return 0; } /* Battery packs */ static int bestups_batt_packs(item_t *item, char *value, const size_t valuelen) { item_t *unskip; if (strspn(item->value, "0123456789 ") != strlen(item->value)) { upsdebugx(2, "%s: non numerical value [%s: %s]", __func__, item->info_type, item->value); return -1; } #ifdef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL #pragma GCC diagnostic push #endif #ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL #pragma GCC diagnostic ignored "-Wformat-nonliteral" #endif #ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_FORMAT_SECURITY #pragma GCC diagnostic ignored "-Wformat-security" #endif snprintf(value, valuelen, item->dfl, strtol(item->value, NULL, 10)); #ifdef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL #pragma GCC diagnostic pop #endif /* Unskip battery.packs setvar */ unskip = find_nut_info("battery.packs", QX_FLAG_SETVAR, 0); /* Don't know what happened */ if (!unskip) return -1; unskip->qxflags &= ~QX_FLAG_SKIP; return 0; } /* *NONUT* Get shutdown mode functionality of Pin 1 and Pin 7 on the UPS DB9 communication port (Per Best Power's EPS-0059) as set in the UPS */ static int bestups_get_pins_shutdown_mode(item_t *item, char *value, const size_t valuelen) { item_t *unskip; long l; if (strspn(item->value, "0123456789") != strlen(item->value)) { upsdebugx(2, "%s: non numerical value [%s: %s]", __func__, item->info_type, item->value); return -1; } l = strtol(item->value, NULL, 10); if (l > INT_MAX) { upsdebugx(2, "%s: pins_shutdown_mode out of range [%s: %s]", __func__, item->info_type, item->value); return -1; } pins_shutdown_mode = (int)l; #ifdef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL #pragma GCC diagnostic push #endif #ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL #pragma GCC diagnostic ignored "-Wformat-nonliteral" #endif #ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_FORMAT_SECURITY #pragma GCC diagnostic ignored "-Wformat-security" #endif snprintf(value, valuelen, item->dfl, pins_shutdown_mode); #ifdef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL #pragma GCC diagnostic pop #endif /* We were not asked by the user to change the value */ if ((item->qxflags & QX_FLAG_NONUT) && !getval(item->info_type)) return 0; /* Unskip setvar */ unskip = find_nut_info(item->info_type, QX_FLAG_SETVAR, 0); /* Don't know what happened */ if (!unskip) return -1; unskip->qxflags &= ~QX_FLAG_SKIP; return 0; } /* Voltage settings */ static int bestups_voltage_settings(item_t *item, char *value, const size_t valuelen) { long index; int val; const char *nominal_voltage; const struct { const int low; /* Low voltage -> input.transfer.low / input.transfer.boost.low */ const int boost; /* Boost voltage -> input.transfer.boost.high */ const int nominal; /* Nominal voltage -> input.voltage.nominal / output.voltage.nominal */ const int buck; /* Buck voltage -> input.transfer.trim.low */ const int high; /* High voltage -> input.transfer.high / input.transfer.trim.high */ } voltage_settings[] = { /* U models voltage limits, for: * - Fortress (750U, 1050U, 1425U, 1800U and 2250U) * - Fortress Rackmount (750, 1050, 1425, 1800, and 2250 VA) * - Patriot Pro II (400U, 750U, and 1000U) */ /* M low boost nominal buck high */ /* 0 */ { 96, 109, 120, 130, 146 }, /* LEDs lit: 2,3,4 (Default) */ /* 1 */ { 96, 109, 120, 138, 156 }, /* LEDs lit: 1,3,4 */ /* 2 */ { 90, 104, 120, 130, 146 }, /* LEDs lit: 2,3,5 */ /* 3 */ { 90, 104, 120, 138, 156 }, /* LEDs lit: 1,3,5 */ /* 4 */ { 90, 104, 110, 120, 130 }, /* LEDs lit: 3,4,5 */ /* 5 */ { 90, 104, 110, 130, 146 }, /* LEDs lit: 2,4,5 */ /* 6 */ { 90, 96, 110, 120, 130 }, /* LEDs lit: 3,4,6 */ /* 7 */ { 90, 96, 110, 130, 146 }, /* LEDs lit: 2,4,6 */ /* 8 */ { 96, 109, 128, 146, 156 }, /* LEDs lit: 1,2,4 */ /* 9 */ { 90, 104, 128, 146, 156 }, /* LEDs lit: 1,2,5 */ /* E models voltage limits, for: * - Fortress (750E, 1050E, 1425E, and 2250E) * - Fortress Rackmount (750, 1050, 1425, and 2250 VA) * - Patriot Pro II (400E, 750E, and 1000E) */ /* M low boost nominal buck high */ /* 0 */ { 200, 222, 240, 250, 284 }, /* LEDs lit: 2,3,4 */ /* 1 */ { 200, 222, 240, 264, 290 }, /* LEDs lit: 1,3,4 */ /* 2 */ { 188, 210, 240, 250, 284 }, /* LEDs lit: 2,3,5 */ /* 3 */ { 188, 210, 240, 264, 290 }, /* LEDs lit: 1,3,5 */ /* 4 */ { 188, 210, 230, 244, 270 }, /* LEDs lit: 3,4,5 (Default) */ /* 5 */ { 188, 210, 230, 250, 284 }, /* LEDs lit: 2,4,5 */ /* 6 */ { 180, 200, 230, 244, 270 }, /* LEDs lit: 3,4,6 */ /* 7 */ { 180, 200, 230, 250, 284 }, /* LEDs lit: 2,4,6 */ /* 8 */ { 165, 188, 208, 222, 244 }, /* LEDs lit: 4,5,6 */ /* 9 */ { 165, 188, 208, 244, 270 } /* LEDs lit: 3,5,6 */ }; if (strspn(item->value, "0123456789") != strlen(item->value)) { upsdebugx(2, "%s: non numerical value [%s: %s]", __func__, item->info_type, item->value); return -1; } index = strtol(item->value, NULL, 10); if (index < 0 || index > 9) { upsdebugx(2, "%s: value '%ld' out of range [0..9]", __func__, index); return -1; } nominal_voltage = dstate_getinfo("input.voltage.nominal"); if (!nominal_voltage) nominal_voltage = dstate_getinfo("output.voltage.nominal"); if (!nominal_voltage) { upsdebugx(2, "%s: unable to get nominal voltage", __func__); return -1; } /* E models */ if (strtol(nominal_voltage, NULL, 10) > 160) index += 10; if (!strcasecmp(item->info_type, "input.transfer.low") || !strcasecmp(item->info_type, "input.transfer.boost.low")) { val = voltage_settings[index].low; } else if (!strcasecmp(item->info_type, "input.transfer.boost.high")) { val = voltage_settings[index].boost; } else if (!strcasecmp(item->info_type, "input.voltage.nominal") || !strcasecmp(item->info_type, "output.voltage.nominal")) { val = voltage_settings[index].nominal; } else if (!strcasecmp(item->info_type, "input.transfer.trim.low")) { val = voltage_settings[index].buck; } else if (!strcasecmp(item->info_type, "input.transfer.trim.high") || !strcasecmp(item->info_type, "input.transfer.high")) { val = voltage_settings[index].high; } else { /* Don't know what happened */ return -1; } #ifdef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL #pragma GCC diagnostic push #endif #ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL #pragma GCC diagnostic ignored "-Wformat-nonliteral" #endif #ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_FORMAT_SECURITY #pragma GCC diagnostic ignored "-Wformat-security" #endif snprintf(value, valuelen, item->dfl, val); #ifdef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL #pragma GCC diagnostic pop #endif return 0; } /* == Subdriver interface == */ subdriver_t bestups_subdriver = { BESTUPS_VERSION, bestups_claim, bestups_qx2nut, bestups_initups, NULL, bestups_makevartable, NULL, NULL, #ifdef TESTING bestups_testing, #endif /* TESTING */ }; nut-2.8.1/drivers/nutdrv_qx_ablerex.c0000755000175000017500000003620314502253356014643 00000000000000/* nutdrv_qx_ablerex.c - Subdriver for Ablerex Qx protocol based UPSes * * Copyright (C) * 2013 Daniele Pezzini * 2021 Ablerex Software * * 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 2 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, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #include "main.h" #include "nutdrv_qx.h" #include "nutdrv_qx_blazer-common.h" #include "nutdrv_qx_ablerex.h" #define ABLEREX_VERSION "Ablerex 0.01" static int Q5_Vbc = -1; static int ablerexQ5Vb = -1; static int ablerex_Q5(item_t *item, char *value, const size_t valuelen) { int Q5_Fout, Q5_Vb, Q5_O_Cur, Q5_Err; /* //int Q5_InvW; int RawValue = 0; RawValue = (unsigned char)item->value[0] * 256 + (unsigned char)item->value[1]; */ //ablerexQ5Vb = (unsigned char)buf[7] * 256 + (unsigned char)buf[8]; //Q5_Vbc = (unsigned char)buf[9] * 256 + (unsigned char)buf[10]; upsdebugx(2, "Q51: %d %d %d %d %d %d", item->answer[0], item->answer[1], item->answer[2], item->answer[3], item->answer[4], item->answer[5]); upsdebugx(2, "Q52: %d %d %d %d %d %d", item->answer[6], item->answer[7], item->answer[8], item->answer[9], item->answer[10], item->answer[11]); upsdebugx(2, "Q53: %d %d %d %d", item->answer[12], item->answer[13], item->answer[14], item->answer[15]); Q5_Fout = (unsigned char)item->answer[1] * 256 + (unsigned char)item->answer[2]; Q5_Vb = (unsigned char)item->answer[7] * 256 + (unsigned char)item->answer[8]; Q5_Vbc = (unsigned char)item->answer[9] * 256 + (unsigned char)item->answer[10]; //int Q5_InvW = (unsigned char)item->answer[11] * 256 + (unsigned char)item->answer[12]; Q5_Err = (unsigned char)item->answer[13] * 256 + (unsigned char)item->answer[14]; Q5_O_Cur = (unsigned char)item->answer[15] * 256 + (unsigned char)item->answer[16]; ablerexQ5Vb = Q5_Vb; upsdebugx(2, "Q5: %.1f %d %.1f", 0.1 * Q5_Fout, Q5_Err, 0.1 * Q5_O_Cur); upsdebugx(2, "Q5Vb: %d Vbc %d", Q5_Vb, Q5_Vbc); dstate_setinfo("output.frequency", "%.1f", 0.1 * Q5_Fout); dstate_setinfo("ups.alarm", "%d", Q5_Err); dstate_setinfo("output.current", "%.1f", 0.1 * Q5_O_Cur); snprintf(value, valuelen, "%.1f", Q5_Fout * 0.1); /* switch (item->from) { case 1: snprintf(value, valuelen, "%.1f", RawValue * 0.1); upsdebugx(2, "Q51: %.1f", 0.1*RawValue); break; case 13: snprintf(value, valuelen, "%.0f", RawValue); upsdebugx(2, "Q52: %.0f", 0.1*RawValue); break; case 15: snprintf(value, valuelen, "%.1f", RawValue * 0.1); upsdebugx(2, "Q53: %.1f", 0.1*RawValue); break; default: //Don't know what happened return -1; } */ return 0; } static int ablerex_battery(item_t *item, char *value, const size_t valuelen) { double BattV = 0.0; double nomBattV = 0.0; double battvoltact = 0.0; BattV = strtod(item->value, NULL); upsdebugx(2, "battvoltact2: %.2f", BattV); if (!dstate_getinfo("battery.voltage.nominal")) { snprintf(value, valuelen, "%.2f", BattV); return 0; } nomBattV = strtod(dstate_getinfo("battery.voltage.nominal"), NULL); upsdebugx(2, "battvoltact1: %.2f", nomBattV); //return 0; if (ablerexQ5Vb > 0) { battvoltact = ablerexQ5Vb * nomBattV / 1200; } else { if (BattV > 3.0) { battvoltact = BattV; } else { battvoltact = BattV * 6 * nomBattV / 12; } } snprintf(value, valuelen, "%.2f", battvoltact); upsdebugx(2, "battvoltact: %.2f / %.2f", battvoltact, BattV); return 0; } static int ablerex_battery_charge(double BattIn) { const double onlineP[] = { 2.22, 2.21, 2.20, 2.19, 2.18, 2.17, 2.16, 2.15, 2.14, 2.13, 2.12, 2.11, 2.10, 2.09, 2.08, 2.07, 2.06, 2.05, 2.04, 2.03, 2.02, 2.01, 2.00, 1.99, 1.98, 1.97, 1.96, 1.95, 1.94, 1.93, 1.92, 1.91, 1.90, 1.89, 1.88, 1.87, 1.86, 1.85, 1.84, 1.83, 1.82, 1.81, 1.80, 1.79, 1.78, 1.77, 1.76, 1.75, 1.74, 1.73, 1.72, 1.71, 1.70, 1.69, 1.68, 1.67 }; const int onlineC[] = { 100, 90, 88, 87, 85, 83, 82, 80, 78, 77, 75, 73, 72, 70, 68, 65, 65, 62, 62, 58, 58, 55, 55, 53, 52, 50, 48, 47, 45, 43, 42, 40, 38, 37, 35, 33, 32, 30, 28, 27, 25, 23, 22, 20, 18, 17, 15, 13, 12, 10, 8, 7, 5, 3, 2, 0, -1 }; const double offlineP[] = { 13.5, 13.3, 13.2, 13.1, 13, 12.9, 12.8, 12.7, 12.6, 12.5, 12.4, 12.3, 12.2, 12.1, 12, 11.9, 11.8, 11.7, 11.6, 11.5, 11.4, 11.3, 11.2, 11.1, 11, 10.9, 10.8, 10.7, 10.6, 10.5, 10.4, 10.3, 10.2, 10.1, 10 }; const int offlineC[] = { 100, 90, 88, 86, 83, 80, 77, 74, 72, 69, 66, 63, 61, 58, 55, 52, 49, 47, 44, 41, 38, 36, 33, 30, 27, 24, 22, 19, 16, 13, 11, 8, 5, 2, 0, -1 }; int charge = 0; int i; if (BattIn < 3.0) { for (i = 0; onlineC[i] > 0; i++) { if (BattIn >= onlineP[i]) { charge = onlineC[i]; break; } } } else { //double nomBattV = strtod(dstate_getinfo("battery.voltage.nominal"), NULL); //double battV = BattIn / (nomBattV / 12); for (i = 0; offlineC[i] > 0; i++) { if (BattIn >= offlineP[i]) { charge = offlineC[i]; break; } } } return charge; } static int ablerex_batterycharge(item_t *item, char *value, const size_t valuelen) { double BattV = 0.0; double nomBattV = 0.0; int BattP; BattV = strtod(item->value, NULL); upsdebugx(2, "battvoltc2: %.2f", BattV); if (!dstate_getinfo("battery.voltage.nominal")) { snprintf(value, valuelen, "%d", 100); return 0; } nomBattV = strtod(dstate_getinfo("battery.voltage.nominal"), NULL); upsdebugx(2, "battvv1: %.2f", nomBattV); //return 0; if (BattV > 3.0) { BattV = BattV / (nomBattV / 12); } BattP = ablerex_battery_charge(BattV); //dstate_setinfo("battery.charge", "%.0f", BattP); snprintf(value, valuelen, "%d", BattP); upsdebugx(2, "battcharge: %d", BattP); return 0; } static int ablerex_initbattery(item_t *item, char *value, const size_t valuelen) { double nomBattV = strtod(dstate_getinfo("battery.voltage.nominal"), NULL); double batthigh = 0.0; double battlow = 0.0; if (Q5_Vbc > 0) { battlow = Q5_Vbc * nomBattV / 1200; } else { battlow = 960 * nomBattV / 1200; } batthigh = 1365 * nomBattV / 1200; switch (item->from) { case 1: snprintf(value, valuelen, "%.2f", battlow); upsdebugx(2, "BattLow: %.2f", battlow); break; case 2: snprintf(value, valuelen, "%.2f", batthigh); upsdebugx(2, "BattHigh: %.2f", batthigh); break; default: /* Don't know what happened */ return -1; } return 0; } static int ablerex_At(item_t *item, char *value, const size_t valuelen) { int RawValue = 0; RawValue = (unsigned char)item->answer[1] * 65536 * 256 + (unsigned char)item->answer[2] * 65536 + (unsigned char)item->answer[3] * 256 + (unsigned char)item->answer[4]; snprintf(value, valuelen, "%d", RawValue); upsdebugx(2, "At: %d", RawValue); return 0; } static int ablerex_TR(item_t *item, char *value, const size_t valuelen) { char TR[8]; TR[0] = item->answer[1]; TR[1] = item->answer[2]; TR[2] = item->answer[3]; TR[3] = item->answer[4]; TR[4] = 0; snprintf(value, valuelen, "%s", TR); upsdebugx(2, "At: %s", TR); return 0; } static int ablerex_process_status_bits(item_t *item, char *value, const size_t valuelen) { char *val = ""; switch (item->from) { case 40: /* Bypass/Boost or Buck Active */ if (item->value[0] == '1') { double vi, vo; vi = strtod(dstate_getinfo("input.voltage"), NULL); vo = strtod(dstate_getinfo("output.voltage"), NULL); if (item->value[2] == '1') {/* UPS Type is Standby (0 is On_line) */ if (vo < 0.5 * vi) { upsdebugx(2, "%s: output voltage too low", __func__); return -1; } else if (vo < 0.95 * vi) { status_set("TRIM"); } else if (vo < 1.05 * vi) { status_set("BYPASS"); } else if (vo < 1.5 * vi) { status_set("BOOST"); } else { upsdebugx(2, "%s: output voltage too high", __func__); return -1; } } else { status_set("BYPASS"); } } break; case 41: /* UPS Failed - ups.alarm */ if (item->value[0] == '1') { /* Battery abnormal */ status_set("RB"); } { /* scope */ double vout = strtod(dstate_getinfo("output.voltage"), NULL); if (vout < 50.0) { status_set("OFF"); } } break; default: /* Don't know what happened */ return -1; } snprintf(value, valuelen, "%s", val); return 0; } /* qx2nut lookup table */ static item_t ablerex_qx2nut[] = { /* * > [Q1\r] * < [(226.0 195.0 226.0 014 49.0 27.5 30.0 00001000\r] * 01234567890123456789012345678901234567890123456 * 0 1 2 3 4 */ { "input.voltage", 0, NULL, "Q1\r", "", 47, '(', "", 1, 5, "%.1f", 0, NULL, NULL, NULL }, { "input.voltage.fault", 0, NULL, "Q1\r", "", 47, '(', "", 7, 11, "%.1f", 0, NULL, NULL, NULL }, { "output.voltage", 0, NULL, "Q1\r", "", 47, '(', "", 13, 17, "%.1f", 0, NULL, NULL, NULL }, { "ups.load", 0, NULL, "Q1\r", "", 47, '(', "", 19, 21, "%.0f", 0, NULL, NULL, NULL }, { "input.frequency", 0, NULL, "Q1\r", "", 47, '(', "", 23, 26, "%.1f", 0, NULL, NULL, NULL }, { "battery.voltage", 0, NULL, "Q1\r", "", 47, '(', "", 28, 31, "%.2f", 0, NULL, NULL, ablerex_battery }, { "battery.charge", 0, NULL, "Q1\r", "", 47, '(', "", 28, 31, "%.2f", 0, NULL, NULL, ablerex_batterycharge }, { "ups.temperature", 0, NULL, "Q1\r", "", 47, '(', "", 33, 36, "%.1f", 0, NULL, NULL, NULL }, /* Status bits */ { "ups.status", 0, NULL, "Q1\r", "", 47, '(', "", 38, 38, NULL, QX_FLAG_QUICK_POLL, NULL, NULL, blazer_process_status_bits }, /* Utility Fail (Immediate) */ { "ups.status", 0, NULL, "Q1\r", "", 47, '(', "", 39, 39, NULL, QX_FLAG_QUICK_POLL, NULL, NULL, blazer_process_status_bits }, /* Battery Low */ { "ups.status", 0, NULL, "Q1\r", "", 47, '(', "", 40, 42, NULL, QX_FLAG_QUICK_POLL, NULL, NULL, ablerex_process_status_bits }, /* Ablerex Bypass/Boost or Buck Active */ { "ups.status", 0, NULL, "Q1\r", "", 47, '(', "", 41, 41, NULL, QX_FLAG_QUICK_POLL, NULL, NULL, ablerex_process_status_bits }, /* Ablerex UPS Failed */ { "ups.alarm", 0, NULL, "Q1\r", "", 47, '(', "", 41, 41, NULL, 0, NULL, NULL, blazer_process_status_bits }, /* UPS Failed */ { "ups.type", 0, NULL, "Q1\r", "", 47, '(', "", 42, 42, "%s", QX_FLAG_STATIC, NULL, NULL, blazer_process_status_bits }, /* UPS Type */ { "ups.status", 0, NULL, "Q1\r", "", 47, '(', "", 43, 43, NULL, QX_FLAG_QUICK_POLL, NULL, NULL, blazer_process_status_bits }, /* Test in Progress */ { "ups.status", 0, NULL, "Q1\r", "", 47, '(', "", 44, 44, NULL, QX_FLAG_QUICK_POLL, NULL, NULL, blazer_process_status_bits }, /* Shutdown Active */ { "ups.beeper.status", 0, NULL, "Q1\r", "", 47, '(', "", 45, 45, "%s", 0, NULL, NULL, blazer_process_status_bits }, /* Beeper status */ /* * > [F\r] * < [#220.0 000 024.0 50.0\r] * 0123456789012345678901 * 0 1 2 */ { "output.voltage.nominal", 0, NULL, "F\r", "", 22, '#', "", 1, 5, "%.1f", QX_FLAG_QUICK_POLL, NULL, NULL, NULL }, { "output.current.nominal", 0, NULL, "F\r", "", 22, '#', "", 7, 9, "%.1f", QX_FLAG_QUICK_POLL, NULL, NULL, NULL }, { "battery.voltage.nominal", 0, NULL, "F\r", "", 22, '#', "", 11, 15, "%.1f", QX_FLAG_QUICK_POLL, NULL, NULL, NULL }, { "output.frequency.nominal", 0, NULL, "F\r", "", 22, '#', "", 17, 20, "%.1f", QX_FLAG_QUICK_POLL, NULL, NULL, NULL }, { "battery.voltage.low", 0, NULL, "F\r", "", 22, '#', "", 1, 2, "%.2f", QX_FLAG_QUICK_POLL, NULL, NULL, ablerex_initbattery }, { "battery.voltage.high", 0, NULL, "F\r", "", 22, '#', "", 2, 3, "%.2f", QX_FLAG_QUICK_POLL, NULL, NULL, ablerex_initbattery }, /* Ablerex */ { "output.frequency", 0, NULL, "Q5\r", "", 22, '(', "", 1, 18, "%.1f", 0, NULL, NULL, ablerex_Q5 }, { "battery.runtime", 0, NULL, "At\r", "", 0, '(', "", 0, 0, "%d", 0, NULL, NULL, ablerex_At }, //{ "ups.alarm", 0, NULL, "Q5\r", "", 22, '(', "", 1, 14, "%.0f", 0, QX_FLAG_QUICK_POLL, NULL, ablerex_Q5 }, { "ups.test.result", 0, NULL, "TR\r", "", 0, '#', "", 0, 0, "%s", 0, NULL, NULL, ablerex_TR }, //{ "output.current", 0, NULL, "Q5\r", "", 22, '(', "", 1, 16, "%.1f", 0, QX_FLAG_QUICK_POLL, NULL, ablerex_Q5 }, /* * > [I\r] * < [#------------- ------ VT12046Q \r] * 012345678901234567890123456789012345678 * 0 1 2 3 */ { "device.mfr", 0, NULL, "I\r", "", 39, '#', "", 1, 15, "%s", QX_FLAG_STATIC | QX_FLAG_TRIM, NULL, NULL, NULL }, { "device.model", 0, NULL, "I\r", "", 39, '#', "", 17, 26, "%s", QX_FLAG_STATIC | QX_FLAG_TRIM, NULL, NULL, NULL }, { "ups.firmware", 0, NULL, "I\r", "", 39, '#', "", 28, 37, "%s", QX_FLAG_STATIC | QX_FLAG_TRIM, NULL, NULL, NULL }, /* Instant commands */ { "beeper.toggle", 0, NULL, "Q\r", "", 0, 0, "", 0, 0, NULL, QX_FLAG_CMD, NULL, NULL, NULL }, { "load.off", 0, NULL, "S.2\r", "", 0, 0, "", 0, 0, NULL, QX_FLAG_CMD, NULL, NULL, NULL }, { "load.on", 0, NULL, "C\r", "", 0, 0, "", 0, 0, NULL, QX_FLAG_CMD, NULL, NULL, NULL }, { "shutdown.return", 0, NULL, "S%s\r", "", 0, 0, "", 0, 0, NULL, QX_FLAG_CMD, NULL, NULL, blazer_process_command }, { "shutdown.stayoff", 0, NULL, "S%sR0000\r", "", 0, 0, "", 0, 0, NULL, QX_FLAG_CMD, NULL, NULL, blazer_process_command }, { "shutdown.stop", 0, NULL, "C\r", "", 0, 0, "", 0, 0, NULL, QX_FLAG_CMD, NULL, NULL, NULL }, { "test.battery.start", 0, NULL, "T%02d\r", "", 0, 0, "", 0, 0, NULL, QX_FLAG_CMD, NULL, NULL, blazer_process_command }, { "test.battery.start.deep", 0, NULL, "TL\r", "", 0, 0, "", 0, 0, NULL, QX_FLAG_CMD, NULL, NULL, NULL }, { "test.battery.start.quick", 0, NULL, "T\r", "", 0, 0, "", 0, 0, NULL, QX_FLAG_CMD, NULL, NULL, NULL }, { "test.battery.stop", 0, NULL, "CT\r", "", 0, 0, "", 0, 0, NULL, QX_FLAG_CMD, NULL, NULL, NULL }, /* Server-side settable vars */ { "ups.delay.start", ST_FLAG_RW, blazer_r_ondelay, NULL, "", 0, 0, "", 0, 0, DEFAULT_ONDELAY, QX_FLAG_ABSENT | QX_FLAG_SETVAR | QX_FLAG_RANGE, NULL, NULL, blazer_process_setvar }, { "ups.delay.shutdown", ST_FLAG_RW, blazer_r_offdelay, NULL, "", 0, 0, "", 0, 0, DEFAULT_OFFDELAY, QX_FLAG_ABSENT | QX_FLAG_SETVAR | QX_FLAG_RANGE, NULL, NULL, blazer_process_setvar }, /* End of structure. */ { NULL, 0, NULL, NULL, "", 0, 0, "", 0, 0, NULL, 0, NULL, NULL, NULL } }; /* Testing table */ #ifdef TESTING static testing_t ablerex_testing[] = { { "Q1\r", "(215.0 195.0 230.0 014 49.0 22.7 30.0 00000000\r", -1 }, { "F\r", "#230.0 000 024.0 50.0\r", -1 }, { "I\r", "#NOT_A_LIVE_UPS TESTING TESTING \r", -1 }, { "Q\r", "", -1 }, { "S03\r", "", -1 }, { "C\r", "", -1 }, { "S02R0005\r", "", -1 }, { "S.5R0000\r", "", -1 }, { "T04\r", "", -1 }, { "TL\r", "", -1 }, { "T\r", "", -1 }, { "CT\r", "", -1 }, { NULL } }; #endif /* TESTING */ /* Subdriver-specific initups */ static void ablerex_initups(void) { blazer_initups(ablerex_qx2nut); } /* Subdriver interface */ subdriver_t ablerex_subdriver = { ABLEREX_VERSION, blazer_claim, ablerex_qx2nut, ablerex_initups, NULL, blazer_makevartable, "ACK", NULL, #ifdef TESTING ablerex_testing, #endif /* TESTING */ }; nut-2.8.1/drivers/apc-ats-mib.h0000644000175000017500000000176714377374134013225 00000000000000/* apcats-mib.h - subdriver to monitor apcats SNMP devices with NUT * * Copyright (C) * 2011 - 2012 Arnaud Quette * * 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 2 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, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef APCATS_MIB_H #define APCATS_MIB_H #include "main.h" #include "snmp-ups.h" extern mib2nut_info_t apc_ats; #endif /* APCATS_MIB_H */ nut-2.8.1/drivers/eaton-pdu-genesis2-mib.h0000644000175000017500000000233714377374134015300 00000000000000/* eaton-pdu-genesis2-mib.h - subdriver to monitor Eaton ePDU SNMP devices with NUT * * Copyright (C) * 2010 Arjen de Korte * 2011 - 2012 Arnaud Quette * 2017 Arnaud Quette * 2017 Jim Klimov * * 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 2 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, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef EATON_EPDU_GENESIS_MIB_H #define EATON_EPDU_GENESIS_MIB_H #include "main.h" #include "snmp-ups.h" extern mib2nut_info_t aphel_genesisII; #endif /* EATON_EPDU_GENESIS_MIB_H */ nut-2.8.1/drivers/eaton-pdu-marlin-mib.h0000644000175000017500000000232714377374134015042 00000000000000/* eaton-pdu-marlin-mib.h - subdriver to monitor Eaton ePDU SNMP devices with NUT * * Copyright (C) * 2010 Arjen de Korte * 2011 - 2012 Arnaud Quette * 2017 Arnaud Quette * 2017 Jim Klimov * * 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 2 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, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef EATON_EPDU_MARLIN_MIB_H #define EATON_EPDU_MARLIN_MIB_H #include "main.h" #include "snmp-ups.h" extern mib2nut_info_t eaton_marlin; #endif /* EATON_EPDU_MARLIN_MIB_H */ nut-2.8.1/drivers/ietf-mib.c0000644000175000017500000004667214501607135012610 00000000000000/* ietf-mib.c - data to monitor SNMP UPS (RFC 1628 compliant) with NUT * * Copyright (C) 2002-2006 * 2002-2012 Arnaud Quette * 2002-2006 Niels Baggesen * 2002-2006 Arjen de Korte * * Sponsored by MGE UPS SYSTEMS * * 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 2 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, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #include "ietf-mib.h" #define IETF_MIB_VERSION "1.55" /* SNMP OIDs set */ #define IETF_OID_UPS_MIB "1.3.6.1.2.1.33.1." #define IETF_SYSOID ".1.3.6.1.2.1.33" /* NOTE: Currently the Tripplite UPSes await user-validation of their * real SNMP OID tree, so temporarily the IETF tree is used as "tripplite" * for the mapping purposes; the devices ave their entry point OID though. * For more details see: * https://github.com/networkupstools/nut/issues/309 * https://github.com/networkupstools/nut/issues/171 * Also related to: * https://github.com/networkupstools/nut/issues/270 */ #define TRIPPLITE_SYSOID ".1.3.6.1.4.1.850.1" /* #define DEBUG */ static info_lkp_t ietf_battery_info[] = { { 1, "" /* unknown */, NULL, NULL }, { 2, "" /* batteryNormal */, NULL, NULL }, { 3, "LB" /* batteryLow */, NULL, NULL }, { 4, "LB" /* batteryDepleted */, NULL, NULL }, { 0, NULL, NULL, NULL } }; static info_lkp_t ietf_power_source_info[] = { { 1, "" /* other */, NULL, NULL }, { 2, "OFF" /* none */, NULL, NULL }, { 3, "OL" /* normal */, NULL, NULL }, { 4, "OL BYPASS" /* bypass */, NULL, NULL }, { 5, "OB" /* battery */, NULL, NULL }, { 6, "OL BOOST" /* booster */, NULL, NULL }, { 7, "OL TRIM" /* reducer */, NULL, NULL }, { 0, NULL, NULL, NULL } }; static info_lkp_t ietf_overload_info[] = { { 1, "OVER", NULL, NULL }, /* output overload */ { 0, NULL, NULL, NULL } }; static info_lkp_t ietf_test_active_info[] = { { 1, "", NULL, NULL }, /* upsTestNoTestsInitiated */ { 2, "", NULL, NULL }, /* upsTestAbortTestInProgress */ { 3, "TEST", NULL, NULL }, /* upsTestGeneralSystemsTest */ { 4, "TEST", NULL, NULL }, /* upsTestQuickBatteryTest */ { 5, "CAL", NULL, NULL }, /* upsTestDeepBatteryCalibration */ { 0, NULL, NULL, NULL } }; static info_lkp_t ietf_test_result_info[] = { { 1, "done and passed", NULL, NULL }, { 2, "done and warning", NULL, NULL }, { 3, "done and error", NULL, NULL }, { 4, "aborted", NULL, NULL }, { 5, "in progress", NULL, NULL }, { 6, "no test initiated", NULL, NULL }, { 0, NULL, NULL, NULL } }; #ifdef DEBUG static info_lkp_t ietf_shutdown_type_info[] = { { 1, "output", NULL, NULL }, { 2, "system", NULL, NULL }, { 0, NULL, NULL, NULL } }; #endif static info_lkp_t ietf_yes_no_info[] = { { 1, "yes", NULL, NULL }, { 2, "no", NULL, NULL }, { 0, NULL, NULL, NULL } }; static info_lkp_t ietf_beeper_status_info[] = { { 1, "disabled", NULL, NULL }, { 2, "enabled", NULL, NULL }, { 3, "muted", NULL, NULL }, { 0, NULL, NULL, NULL } }; /* Snmp2NUT lookup table info_type, info_flags, info_len, OID, dfl, flags, oid2info, setvar */ static snmp_info_t ietf_mib[] = { /* standard MIB items */ { "device.description", ST_FLAG_STRING | ST_FLAG_RW, SU_INFOSIZE, ".1.3.6.1.2.1.1.1.0", NULL, SU_FLAG_OK, NULL }, { "device.contact", ST_FLAG_STRING | ST_FLAG_RW, SU_INFOSIZE, ".1.3.6.1.2.1.1.4.0", NULL, SU_FLAG_OK, NULL }, { "device.location", ST_FLAG_STRING | ST_FLAG_RW, SU_INFOSIZE, ".1.3.6.1.2.1.1.6.0", NULL, SU_FLAG_OK, NULL }, /* The Device Identification group */ { "ups.mfr", ST_FLAG_STRING, SU_INFOSIZE, IETF_OID_UPS_MIB "1.1.0", "Generic", SU_FLAG_STATIC, NULL }, /* upsIdentManufacturer */ { "ups.model", ST_FLAG_STRING, SU_INFOSIZE, IETF_OID_UPS_MIB "1.2.0", "Generic SNMP UPS", SU_FLAG_STATIC, NULL }, /* upsIdentModel */ { "ups.firmware", ST_FLAG_STRING, SU_INFOSIZE, IETF_OID_UPS_MIB "1.3.0", "", SU_FLAG_STATIC, NULL }, /* upsIdentUPSSoftwareVersion */ { "ups.firmware.aux", ST_FLAG_STRING, SU_INFOSIZE, IETF_OID_UPS_MIB "1.4.0", "", SU_FLAG_STATIC, NULL }, /* upsIdentAgentSoftwareVersion */ #ifdef DEBUG { "debug.upsIdentName", ST_FLAG_STRING, SU_INFOSIZE, IETF_OID_UPS_MIB "1.5.0", "", 0, NULL }, /* upsIdentName */ { "debug.upsIdentAttachedDevices", ST_FLAG_STRING, SU_INFOSIZE, IETF_OID_UPS_MIB "1.6.0", "", 0, NULL }, /* upsIdentAttachedDevices */ #endif /* Battery Group */ { "ups.status", ST_FLAG_STRING, SU_INFOSIZE, IETF_OID_UPS_MIB "2.1.0", "", SU_STATUS_BATT, ietf_battery_info }, /* upsBatteryStatus */ #ifdef DEBUG { "debug.upsSecondsOnBattery", 0, 1.0, IETF_OID_UPS_MIB "2.2.0", "", 0, NULL }, /* upsSecondsOnBattery */ #endif { "battery.runtime", 0, 60.0, IETF_OID_UPS_MIB "2.3.0", "", 0, NULL }, /* upsEstimatedMinutesRemaining */ { "battery.charge", 0, 1, IETF_OID_UPS_MIB "2.4.0", "", 0, NULL }, /* upsEstimatedChargeRemaining */ { "battery.voltage", 0, 0.1, IETF_OID_UPS_MIB "2.5.0", "", 0, NULL }, /* upsBatteryVoltage */ { "battery.current", 0, 0.1, IETF_OID_UPS_MIB "2.6.0", "", SU_FLAG_NEGINVALID, NULL }, /* upsBatteryCurrent */ { "battery.temperature", 0, 1.0, IETF_OID_UPS_MIB "2.7.0", "", 0, NULL }, /* upsBatteryTemperature */ /* Input Group */ #ifdef DEBUG { "debug.upsInputLineBads", 0, 1.0, IETF_OID_UPS_MIB "3.1.0", "", 0, NULL }, /* upsInputLineBads */ #endif { "input.phases", 0, 1.0, IETF_OID_UPS_MIB "3.2.0", "", 0, NULL }, /* upsInputNumLines */ #ifdef DEBUG { "debug.upsInputLineIndex", 0, 1.0, IETF_OID_UPS_MIB "3.3.1.1.1", "", SU_INPUT_1, NULL }, /* upsInputLineIndex */ { "debug.[1].upsInputLineIndex", 0, 1.0, IETF_OID_UPS_MIB "3.3.1.1.1", "", SU_INPUT_3, NULL }, { "debug.[2].upsInputLineIndex", 0, 1.0, IETF_OID_UPS_MIB "3.3.1.1.2", "", SU_INPUT_3, NULL }, { "debug.[3].upsInputLineIndex", 0, 1.0, IETF_OID_UPS_MIB "3.3.1.1.3", "", SU_INPUT_3, NULL }, #endif { "input.frequency", 0, 0.1, IETF_OID_UPS_MIB "3.3.1.2.1", "", SU_INPUT_1, NULL }, /* upsInputFrequency */ { "input.L1.frequency", 0, 0.1, IETF_OID_UPS_MIB "3.3.1.2.1", "", SU_INPUT_3, NULL }, { "input.L2.frequency", 0, 0.1, IETF_OID_UPS_MIB "3.3.1.2.2", "", SU_INPUT_3, NULL }, { "input.L3.frequency", 0, 0.1, IETF_OID_UPS_MIB "3.3.1.2.3", "", SU_INPUT_3, NULL }, { "input.voltage", 0, 1.0, IETF_OID_UPS_MIB "3.3.1.3.1", "", SU_INPUT_1, NULL }, /* upsInputVoltage */ { "input.L1-N.voltage", 0, 1.0, IETF_OID_UPS_MIB "3.3.1.3.1", "", SU_INPUT_3, NULL }, { "input.L2-N.voltage", 0, 1.0, IETF_OID_UPS_MIB "3.3.1.3.2", "", SU_INPUT_3, NULL }, { "input.L3-N.voltage", 0, 1.0, IETF_OID_UPS_MIB "3.3.1.3.3", "", SU_INPUT_3, NULL }, { "input.current", 0, 0.1, IETF_OID_UPS_MIB "3.3.1.4.1", "", SU_INPUT_1 |SU_FLAG_NEGINVALID, NULL }, /* upsInputCurrent */ { "input.L1.current", 0, 0.1, IETF_OID_UPS_MIB "3.3.1.4.1", "", SU_INPUT_3, NULL }, { "input.L2.current", 0, 0.1, IETF_OID_UPS_MIB "3.3.1.4.2", "", SU_INPUT_3, NULL }, { "input.L3.current", 0, 0.1, IETF_OID_UPS_MIB "3.3.1.4.3", "", SU_INPUT_3, NULL }, { "input.realpower", 0, 1.0, IETF_OID_UPS_MIB "3.3.1.5.1", "", SU_INPUT_1 | SU_FLAG_NEGINVALID, NULL }, /* upsInputTruePower */ { "input.L1.realpower", 0, 1.0, IETF_OID_UPS_MIB "3.3.1.5.1", "", SU_INPUT_3, NULL }, { "input.L2.realpower", 0, 1.0, IETF_OID_UPS_MIB "3.3.1.5.2", "", SU_INPUT_3, NULL }, { "input.L3.realpower", 0, 1.0, IETF_OID_UPS_MIB "3.3.1.5.3", "", SU_INPUT_3, NULL }, /* Output Group */ { "ups.status", ST_FLAG_STRING, SU_INFOSIZE, IETF_OID_UPS_MIB "4.1.0", "", SU_STATUS_PWR, ietf_power_source_info }, /* upsOutputSource */ { "output.frequency", 0, 0.1, IETF_OID_UPS_MIB "4.2.0", "", 0, NULL }, /* upsOutputFrequency */ { "output.phases", 0, 1.0, IETF_OID_UPS_MIB "4.3.0", "", 0, NULL }, /* upsOutputNumLines */ #ifdef DEBUG { "debug.upsOutputLineIndex", 0, 1.0, IETF_OID_UPS_MIB "4.4.1.1.1", "", SU_OUTPUT_1, NULL }, /* upsOutputLineIndex */ { "debug.[1].upsOutputLineIndex", 0, 1.0, IETF_OID_UPS_MIB "4.4.1.1.1", "", SU_OUTPUT_3, NULL }, { "debug.[2].upsOutputLineIndex", 0, 1.0, IETF_OID_UPS_MIB "4.4.1.1.2", "", SU_OUTPUT_3, NULL }, { "debug.[3].upsOutputLineIndex", 0, 1.0, IETF_OID_UPS_MIB "4.4.1.1.3", "", SU_OUTPUT_3, NULL }, #endif { "output.voltage", 0, 1.0, IETF_OID_UPS_MIB "4.4.1.2.1", "", SU_OUTPUT_1, NULL }, /* upsOutputVoltage */ { "output.L1-N.voltage", 0, 1.0, IETF_OID_UPS_MIB "4.4.1.2.1", "", SU_OUTPUT_3, NULL }, { "output.L2-N.voltage", 0, 1.0, IETF_OID_UPS_MIB "4.4.1.2.2", "", SU_OUTPUT_3, NULL }, { "output.L3-N.voltage", 0, 1.0, IETF_OID_UPS_MIB "4.4.1.2.3", "", SU_OUTPUT_3, NULL }, { "output.current", 0, 0.1, IETF_OID_UPS_MIB "4.4.1.3.1", "", SU_OUTPUT_1 | SU_FLAG_NEGINVALID, NULL }, /* upsOutputCurrent */ { "output.L1.current", 0, 0.1, IETF_OID_UPS_MIB "4.4.1.3.1", "", SU_OUTPUT_3, NULL }, { "output.L2.current", 0, 0.1, IETF_OID_UPS_MIB "4.4.1.3.2", "", SU_OUTPUT_3, NULL }, { "output.L3.current", 0, 0.1, IETF_OID_UPS_MIB "4.4.1.3.3", "", SU_OUTPUT_3, NULL }, { "output.realpower", 0, 1.0, IETF_OID_UPS_MIB "4.4.1.4.1", "", SU_OUTPUT_1 | SU_FLAG_NEGINVALID, NULL }, /* upsOutputPower */ { "output.L1.realpower", 0, 1.0, IETF_OID_UPS_MIB "4.4.1.4.1", "", SU_OUTPUT_3, NULL }, { "output.L2.realpower", 0, 1.0, IETF_OID_UPS_MIB "4.4.1.4.2", "", SU_OUTPUT_3, NULL }, { "output.L3.realpower", 0, 1.0, IETF_OID_UPS_MIB "4.4.1.4.3", "", SU_OUTPUT_3, NULL }, { "ups.load", 0, 1.0, IETF_OID_UPS_MIB "4.4.1.5.1", "", SU_OUTPUT_1, NULL }, /* upsOutputPercentLoad */ { "output.L1.power.percent", 0, 1.0, IETF_OID_UPS_MIB "4.4.1.5.1", "", SU_OUTPUT_3, NULL }, { "output.L2.power.percent", 0, 1.0, IETF_OID_UPS_MIB "4.4.1.5.2", "", SU_OUTPUT_3, NULL }, { "output.L3.power.percent", 0, 1.0, IETF_OID_UPS_MIB "4.4.1.5.3", "", SU_OUTPUT_3, NULL }, /* Bypass Group */ { "input.bypass.phases", 0, 1.0, IETF_OID_UPS_MIB "5.2.0", "", SU_FLAG_NEGINVALID, NULL }, /* upsBypassNumLines */ { "input.bypass.frequency", 0, 0.1, IETF_OID_UPS_MIB "5.1.0", "", SU_BYPASS_1 | SU_BYPASS_3 | SU_FLAG_NEGINVALID, NULL }, /* upsBypassFrequency */ #ifdef DEBUG { "debug.upsBypassLineIndex", 0, 1.0, IETF_OID_UPS_MIB "5.3.1.1.1", "", SU_BYPASS_1, NULL }, /* upsBypassLineIndex */ { "debug.[1].upsBypassLineIndex", 0, 1.0, IETF_OID_UPS_MIB "5.3.1.1.1", "", SU_BYPASS_3, NULL }, { "debug.[2].upsBypassLineIndex", 0, 1.0, IETF_OID_UPS_MIB "5.3.1.1.2", "", SU_BYPASS_3, NULL }, { "debug.[3].upsBypassLineIndex", 0, 1.0, IETF_OID_UPS_MIB "5.3.1.1.3", "", SU_BYPASS_3, NULL }, #endif { "input.bypass.voltage", 0, 1.0, IETF_OID_UPS_MIB "5.3.1.2.1", "", SU_BYPASS_1, NULL }, /* upsBypassVoltage */ { "input.bypass.L1-N.voltage", 0, 1.0, IETF_OID_UPS_MIB "5.3.1.2.1", "", SU_BYPASS_3, NULL }, { "input.bypass.L2-N.voltage", 0, 1.0, IETF_OID_UPS_MIB "5.3.1.2.2", "", SU_BYPASS_3, NULL }, { "input.bypass.L3-N.voltage", 0, 1.0, IETF_OID_UPS_MIB "5.3.1.2.3", "", SU_BYPASS_3, NULL }, { "input.bypass.current", 0, 0.1, IETF_OID_UPS_MIB "5.3.1.3.1", "", SU_BYPASS_1, NULL }, /* upsBypassCurrent */ { "input.bypass.L1.current", 0, 0.1, IETF_OID_UPS_MIB "5.3.1.3.1", "", SU_BYPASS_3, NULL }, { "input.bypass.L2.current", 0, 0.1, IETF_OID_UPS_MIB "5.3.1.3.2", "", SU_BYPASS_3, NULL }, { "input.bypass.L3.current", 0, 0.1, IETF_OID_UPS_MIB "5.3.1.3.3", "", SU_BYPASS_3, NULL }, { "input.bypass.realpower", 0, 1.0, IETF_OID_UPS_MIB "5.3.1.4.1", "", SU_BYPASS_1, NULL }, /* upsBypassPower */ { "input.bypass.L1.realpower", 0, 1.0, IETF_OID_UPS_MIB "5.3.1.4.1", "", SU_BYPASS_3, NULL }, { "input.bypass.L2.realpower", 0, 1.0, IETF_OID_UPS_MIB "5.3.1.4.2", "", SU_BYPASS_3, NULL }, { "input.bypass.L3.realpower", 0, 1.0, IETF_OID_UPS_MIB "5.3.1.4.3", "", SU_BYPASS_3, NULL }, /* Alarm Group */ #ifdef DEBUG { "debug.upsAlarmsPresent", 0, 1.0, IETF_OID_UPS_MIB "6.1.0", "", 0, NULL }, /* upsAlarmsPresent */ { "debug.upsAlarmBatteryBad", ST_FLAG_STRING, SU_INFOSIZE, IETF_OID_UPS_MIB "6.3.1", "", 0, NULL }, /* upsAlarmBatteryBad */ { "debug.upsAlarmOnBattery", ST_FLAG_STRING, SU_INFOSIZE, IETF_OID_UPS_MIB "6.3.2", "", 0, NULL }, /* upsAlarmOnBattery */ { "debug.upsAlarmLowBattery", ST_FLAG_STRING, SU_INFOSIZE, IETF_OID_UPS_MIB "6.3.3", "", 0, NULL }, /* upsAlarmLowBattery */ { "debug.upsAlarmDepletedBattery", ST_FLAG_STRING, SU_INFOSIZE, IETF_OID_UPS_MIB "6.3.4", "", 0, NULL }, /* upsAlarmDepletedBattery */ { "debug.upsAlarmTempBad", ST_FLAG_STRING, SU_INFOSIZE, IETF_OID_UPS_MIB "6.3.5", "", 0, NULL }, /* upsAlarmTempBad */ { "debug.upsAlarmInputBad", ST_FLAG_STRING, SU_INFOSIZE, IETF_OID_UPS_MIB "6.3.6", "", 0, NULL }, /* upsAlarmInputBad */ { "debug.upsAlarmOutputBad", ST_FLAG_STRING, SU_INFOSIZE, IETF_OID_UPS_MIB "6.3.7", "", 0, NULL }, /* upsAlarmOutputBad */ #endif { "ups.status", ST_FLAG_STRING, SU_INFOSIZE, IETF_OID_UPS_MIB "6.3.8", "", 0, ietf_overload_info }, /* upsAlarmOutputOverload */ #ifdef DEBUG { "debug.upsAlarmOnBypass", ST_FLAG_STRING, SU_INFOSIZE, IETF_OID_UPS_MIB "6.3.9", "", 0, NULL }, /* upsAlarmOnBypass */ { "debug.upsAlarmBypassBad", ST_FLAG_STRING, SU_INFOSIZE, IETF_OID_UPS_MIB "6.3.10", "", 0, NULL }, /* upsAlarmBypassBad */ { "debug.upsAlarmOutputOffAsRequested", ST_FLAG_STRING, SU_INFOSIZE, IETF_OID_UPS_MIB "6.3.11", "", 0, NULL }, /* upsAlarmOutputOffAsRequested */ { "debug.upsAlarmUpsOffAsRequested", ST_FLAG_STRING, SU_INFOSIZE, IETF_OID_UPS_MIB "6.3.12", "", 0, NULL }, /* upsAlarmUpsOffAsRequested */ { "debug.upsAlarmChargerFailed", ST_FLAG_STRING, SU_INFOSIZE, IETF_OID_UPS_MIB "6.3.13", "", 0, NULL }, /* upsAlarmChargerFailed */ { "debug.upsAlarmUpsOutputOff", ST_FLAG_STRING, SU_INFOSIZE, IETF_OID_UPS_MIB "6.3.14", "", 0, NULL }, /* upsAlarmUpsOutputOff */ { "debug.upsAlarmUpsSystemOff", ST_FLAG_STRING, SU_INFOSIZE, IETF_OID_UPS_MIB "6.3.15", "", 0, NULL }, /* upsAlarmUpsSystemOff */ { "debug.upsAlarmFanFailure", ST_FLAG_STRING, SU_INFOSIZE, IETF_OID_UPS_MIB "6.3.16", "", 0, NULL }, /* upsAlarmFanFailure */ { "debug.upsAlarmFuseFailure", ST_FLAG_STRING, SU_INFOSIZE, IETF_OID_UPS_MIB "6.3.17", "", 0, NULL }, /* upsAlarmFuseFailure */ { "debug.upsAlarmGeneralFault", ST_FLAG_STRING, SU_INFOSIZE, IETF_OID_UPS_MIB "6.3.18", "", 0, NULL }, /* upsAlarmGeneralFault */ { "debug.upsAlarmDiagnosticTestFailed", ST_FLAG_STRING, SU_INFOSIZE, IETF_OID_UPS_MIB "6.3.19", "", 0, NULL }, /* upsAlarmDiagnosticTestFailed */ { "debug.upsAlarmCommunicationsLost", ST_FLAG_STRING, SU_INFOSIZE, IETF_OID_UPS_MIB "6.3.20", "", 0, NULL }, /* upsAlarmCommunicationsLost */ { "debug.upsAlarmAwaitingPower", ST_FLAG_STRING, SU_INFOSIZE, IETF_OID_UPS_MIB "6.3.21", "", 0, NULL }, /* upsAlarmAwaitingPower */ { "debug.upsAlarmShutdownPending", ST_FLAG_STRING, SU_INFOSIZE, IETF_OID_UPS_MIB "6.3.22", "", 0, NULL }, /* upsAlarmShutdownPending */ { "debug.upsAlarmShutdownImminent", ST_FLAG_STRING, SU_INFOSIZE, IETF_OID_UPS_MIB "6.3.23", "", 0, NULL }, /* upsAlarmShutdownImminent */ { "debug.upsAlarmTestInProgress", ST_FLAG_STRING, SU_INFOSIZE, IETF_OID_UPS_MIB "6.3.24", "", 0, NULL }, /* upsAlarmTestInProgress */ #endif /* Test Group */ { "ups.status", ST_FLAG_STRING, SU_INFOSIZE, IETF_OID_UPS_MIB "7.1.0", "", 0, ietf_test_active_info }, /* upsTestId */ { "test.battery.stop", 0, 1, IETF_OID_UPS_MIB "7.1.0", "0", SU_TYPE_CMD, NULL }, /* upsTestAbortTestInProgress */ { "test.battery.start", 0, 1, IETF_OID_UPS_MIB "7.1.0", "0", SU_TYPE_CMD, NULL }, /* upsTestGeneralSystemsTest */ { "test.battery.start.quick", 0, 1, IETF_OID_UPS_MIB "7.1.0", "0", SU_TYPE_CMD, NULL }, /* upsTestQuickBatteryTest */ { "test.battery.start.deep", 0, 1, IETF_OID_UPS_MIB "7.1.0", "0", SU_TYPE_CMD, NULL }, /* upsTestDeepBatteryCalibration */ #ifdef DEBUG { "debug.upsTestSpinLock", 0, 1.0, IETF_OID_UPS_MIB "7.2.0", "", 0, NULL }, /* upsTestSpinLock */ #endif { "ups.test.result", ST_FLAG_STRING, SU_INFOSIZE, IETF_OID_UPS_MIB "7.3.0", "", 0, ietf_test_result_info }, /* upsTestResultsSummary */ #ifdef DEBUG { "debug.upsTestResultsDetail", ST_FLAG_STRING, SU_INFOSIZE, IETF_OID_UPS_MIB "7.4.0", "", 0, NULL }, /* upsTestResultsDetail */ { "debug.upsTestStartTime", ST_FLAG_STRING, SU_INFOSIZE, IETF_OID_UPS_MIB "7.5.0", "", 0, NULL }, /* upsTestStartTime */ { "debug.upsTestElapsedTime", ST_FLAG_STRING, SU_INFOSIZE, IETF_OID_UPS_MIB "7.6.0", "", 0, NULL }, /* upsTestElapsedTime */ #endif /* Control Group */ #ifdef DEBUG { "debug.upsShutdownType", ST_FLAG_STRING, SU_INFOSIZE, IETF_OID_UPS_MIB "8.1.0", "", 0, ietf_shutdown_type_info }, /* upsShutdownType */ #endif { "ups.timer.shutdown", ST_FLAG_STRING | ST_FLAG_RW, 8, IETF_OID_UPS_MIB "8.2.0", "", 0, NULL }, /* upsShutdownAfterDelay*/ { "load.off", 0, 1, IETF_OID_UPS_MIB "8.2.0", "0", SU_TYPE_CMD, NULL }, { "ups.timer.start", ST_FLAG_STRING | ST_FLAG_RW, 8, IETF_OID_UPS_MIB "8.3.0", "", 0, NULL }, /* upsStartupAfterDelay */ { "load.on", 0, 1, IETF_OID_UPS_MIB "8.3.0", "0", SU_TYPE_CMD, NULL }, { "ups.timer.reboot", ST_FLAG_STRING | ST_FLAG_RW, 8, IETF_OID_UPS_MIB "8.4.0", "", 0, NULL }, /* upsRebootWithDuration */ { "ups.start.auto", ST_FLAG_STRING, SU_INFOSIZE, IETF_OID_UPS_MIB "8.5.0", "", 0, ietf_yes_no_info }, /* upsAutoRestart */ /* Configuration Group */ { "input.voltage.nominal", 0, 1.0, IETF_OID_UPS_MIB "9.1.0", "", SU_FLAG_NEGINVALID, NULL }, /* upsConfigInputVoltage */ { "input.frequency.nominal", 0, 0.1, IETF_OID_UPS_MIB "9.2.0", "", SU_FLAG_NEGINVALID, NULL }, /* upsConfigInputFreq */ { "output.voltage.nominal", 0, 1.0, IETF_OID_UPS_MIB "9.3.0", "", 0, NULL }, /* upsConfigOutputVoltage */ { "output.frequency.nominal", 0, 0.1, IETF_OID_UPS_MIB "9.4.0", "", 0, NULL }, /* upsConfigOutputFreq */ { "output.power.nominal", 0, 1.0, IETF_OID_UPS_MIB "9.5.0", "", SU_FLAG_NEGINVALID, NULL }, /* upsConfigOutputVA */ { "output.realpower.nominal", 0, 1.0, IETF_OID_UPS_MIB "9.6.0", "", SU_FLAG_NEGINVALID, NULL }, /* upsConfigOutputPower */ { "battery.runtime.low", 0, 60.0, IETF_OID_UPS_MIB "9.7.0", "", 0, NULL }, /* upsConfigLowBattTime */ { "ups.beeper.status", ST_FLAG_STRING, SU_INFOSIZE, IETF_OID_UPS_MIB "9.8.0", "", 0, ietf_beeper_status_info }, /* upsConfigAudibleStatus */ { "beeper.disable", 0, 1, IETF_OID_UPS_MIB "9.8.0", "1", SU_TYPE_CMD, NULL }, { "beeper.enable", 0, 1, IETF_OID_UPS_MIB "9.8.0", "2", SU_TYPE_CMD, NULL }, { "beeper.mute", 0, 1, IETF_OID_UPS_MIB "9.8.0", "3", SU_TYPE_CMD, NULL }, { "input.transfer.low", 0, 1.0, IETF_OID_UPS_MIB "9.9.0", "", 0, NULL }, /* upsConfigLowVoltageTransferPoint */ { "input.transfer.high", 0, 1.0, IETF_OID_UPS_MIB "9.10.0", "", 0, NULL }, /* upsConfigHighVoltageTransferPoint */ /* end of structure. */ { NULL, 0, 0, NULL, NULL, 0, NULL } }; /* FIXME: Rename the structure here (or even relocate to new file) * and in snmp-ups.c when the real TrippLite mappings get defined. */ /* FIXME: Duplicate the line below to fix an issue with the code generator (nut-snmpinfo.py -> line is discarding) */ /*mib2nut_info_t tripplite_ietf = { "tripplite", IETF_MIB_VERSION, NULL, NULL, ietf_mib, TRIPPLITE_SYSOID, NULL };*/ mib2nut_info_t tripplite_ietf = { "tripplite", IETF_MIB_VERSION, NULL, NULL, ietf_mib, TRIPPLITE_SYSOID, NULL }; /* FIXME: Duplicate the line below to fix an issue with the code generator (nut-snmpinfo.py -> line is discarding) */ /*mib2nut_info_t ietf = { "ietf", IETF_MIB_VERSION, IETF_OID_UPS_MIB "4.1.0", IETF_OID_UPS_MIB "1.1.0", ietf_mib, IETF_SYSOID, NULL };*/ mib2nut_info_t ietf = { "ietf", IETF_MIB_VERSION, IETF_OID_UPS_MIB "4.1.0", IETF_OID_UPS_MIB "1.1.0", ietf_mib, IETF_SYSOID, NULL }; nut-2.8.1/drivers/powervar-hid.h0000755000175000017500000000217614500336654013526 00000000000000/* powervar-hid.h - subdriver to monitor Powervar USB/HID devices with NUT * * Copyright (C) * 2003 - 2009 Arnaud Quette * 2005 - 2006 Peter Selinger * 2008 - 2009 Arjen de Korte * * 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 2 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, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef POWERVAR_HID_H #define POWERVAR_HID_H #include "usbhid-ups.h" extern subdriver_t powervar_subdriver; #endif /* POWERVAR_HID_H */ nut-2.8.1/drivers/tripplite_usb.c0000644000175000017500000014174314514200703013766 00000000000000/*!@file tripplite_usb.c * @brief Driver for Tripp Lite non-PDC/HID USB models. */ /* tripplite_usb.c was derived from tripplite.c by Charles Lepple tripplite.c was derived from Russell Kroll's bestups.c by Rik Faith. Copyright (C) 1999 Russell Kroll Copyright (C) 2001 Rickard E. (Rik) Faith Copyright (C) 2004 Nicholas J. Kain Copyright (C) 2005-2008, 2014 Charles Lepple Copyright (C) 2016 Eaton Copyright (C) 2023 Eliran Sapir 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 2 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, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ /* % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % * * Protocol 1001 * * OMNIVS Commands: (capital letters are literals, lower-case are variables) * :B -> Bxxxxyy (xxxx/55.0: Hz in, yy/16: battery voltage) * :F -> F1143_A (where _ = \0) Firmware version? * :L -> LvvvvXX (vvvv/2.0: VAC out) * :P -> P01000X (1000VA unit) * :S -> Sbb_XXX (bb = 10: on-line, 11: on battery) * :V -> V102XXX (firmware/protocol version?) * :Wt -> Wt (watchdog; t = time in seconds (binary, not hex), * 0 = disable; if UPS is not pinged in this interval, it * will power off the load, and then power it back on after * a delay.) * * % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % * * The outgoing commands are sent with HID Set_Report commands over EP0 * (control message), and incoming commands are received on EP1IN (interrupt * endpoint). The UPS completely ignores the conventions of Set_Idle (where * you NAK the interrupt read if you have no new data), so you constantly have * to poll EP1IN. * * The descriptors say that bInterval is 10 ms. You generally need to wait at * least 80-90 ms to get some characters back from the device. If it takes * more than 250 ms, you probably need to resend the command. * * All outgoing commands are followed by a checksum, which is 255 - (sum of * characters after ':'), and then by '\r'. All responses should start with * the command letter that was sent (no colon), and should be followed by * '\r'. If the command is not supported (or apparently if there is a serial * timeout internally), the previous response will be echoed back. * * % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % * * SMARTPRO commands (3003): * * :A -> ? (start self-test) * :D -> D7187 (? - doesn't match tripplite.c) * :F -> F1019 A firmware rev * :H__ -> H (delay before action?) * :I_ -> I (set flags for conditions that cause a reset?) * :J__ -> J (set 16-bit unit ID) * :K#0 -> (turn outlet off: # in 0..2; 0 is main relay) * :K#1 -> (turn outlet on: # in 0..2) * :L -> L290D_X * :M -> M007F (min/max voltage seen) * :N__ -> N * :P -> P01500X (max power) * :Q -> (while online: reboot) * :R -> R<01> (query flags for conditions that cause a reset?) * :S -> S100_Z0 (status?) * :T -> T7D2581 (temperature, frequency) * :U -> U (unit ID, 1-65535) * :V -> V1062XX (outlets in groups of 2-2-4, with the groups of 2 * individually switchable.) * :W_ -> W_ (watchdog) * :Z -> Z (reset for max/min; takes a moment to complete) * * % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % * * The SMARTPRO unit seems to be slightly saner with regard to message * polling. It specifies an interrupt in interval of 100 ms, but I just * started at a 2 second timeout to obtain the above table. * * % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % * * Commands from serial tripplite.c: * * :N%02X -- delay the UPS for provided time (hex seconds) * :H%06X -- reboot the UPS. UPS will restart after provided time (hex s) * :A -- begins a self-test * :C -- fetches result of a self-test * :K1 -- turns on power receptacles * :K0 -- turns off power receptacles * :G -- unconfirmed: shuts down UPS until power returns * :Q1 -- enable "Remote Reboot" * :Q0 -- disable "Remote Reboot" * :W -- returns 'W' data * :L -- returns 'L' data * :V -- returns 'V' data (firmware revision) * :X -- returns 'X' data (firmware revision) * :D -- returns general status data * :B -- returns battery voltage (hexadecimal decivolts) * :I -- returns minimum input voltage (hexadecimal hertz) [sic] * :M -- returns maximum input voltage (hexadecimal hertz) [sic] * :P -- returns power rating * :Z -- unknown * :U -- unknown * :O -- unknown * :E -- unknown * :Y -- returns mains frequency (':D' is preferred) * :T -- returns ups temperature (':D' is preferred) * :R -- returns input voltage (':D' is preferred) * :F -- returns load percentage (':D' is preferred) * :S -- enables remote reboot/remote power on */ /* Watchdog for 3005 is 15 - 255 seconds. */ #include "main.h" #include "nut_libusb.h" #include #include #include "usb-common.h" #define DRIVER_NAME "Tripp Lite OMNIVS / SMARTPRO driver" #define DRIVER_VERSION "0.35" /* driver description structure */ upsdrv_info_t upsdrv_info = { DRIVER_NAME, DRIVER_VERSION, "Charles Lepple \n" \ "Russell Kroll \n" \ "Rickard E. (Rik) Faith \n" \ "Nicholas J. Kain \n" \ "Eliran Sapir ", DRV_EXPERIMENTAL, { NULL } }; /* TrippLite */ #define TRIPPLITE_VENDORID 0x09ae /* USB IDs device table */ static usb_device_id_t tripplite_usb_device_table[] = { /* e.g. OMNIVS1000, SMART550USB, ... */ { USB_DEVICE(TRIPPLITE_VENDORID, 0x0001), NULL }, /* Terminating entry */ { 0, 0, NULL } }; static int subdriver_match_func(USBDevice_t *arghd, void *privdata) { NUT_UNUSED_VARIABLE(privdata); /* FIXME? Should we save "arghd" into global "hd" variable? * This was previously shadowed by function argument named "hd"... */ /* hd = arghd; */ switch (is_usb_device_supported(tripplite_usb_device_table, arghd)) { case SUPPORTED: return 1; case POSSIBLY_SUPPORTED: /* by default, reject, unless the productid option is given */ if (getval("productid")) { return 1; } return 0; case NOT_SUPPORTED: default: return 0; } } static USBDeviceMatcher_t subdriver_matcher = { &subdriver_match_func, NULL, NULL }; static enum tl_model_t { TRIPP_LITE_UNKNOWN = 0, TRIPP_LITE_OMNIVS, TRIPP_LITE_OMNIVS_2001, TRIPP_LITE_SMARTPRO, TRIPP_LITE_SMART_0004, TRIPP_LITE_SMART_3005 } tl_model = TRIPP_LITE_UNKNOWN; /*! Are the values encoded in ASCII or binary? * TODO: Add 3004? */ static int is_binary_protocol(void) { switch(tl_model) { case TRIPP_LITE_SMART_3005: return 1; case TRIPP_LITE_SMARTPRO: case TRIPP_LITE_SMART_0004: case TRIPP_LITE_OMNIVS: case TRIPP_LITE_OMNIVS_2001: case TRIPP_LITE_UNKNOWN: #if (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_PUSH_POP) && (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_COVERED_SWITCH_DEFAULT) # pragma GCC diagnostic push # pragma GCC diagnostic ignored "-Wcovered-switch-default" #endif /* All enum cases defined as of the time of coding * have been covered above. Handle later definitions, * memory corruptions and buggy inputs below... */ default: #if (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_PUSH_POP) && (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_COVERED_SWITCH_DEFAULT) # pragma GCC diagnostic pop #endif return 0; } } /*! Is this the "SMART" family of protocols? * TODO: Add 3004? */ static int is_smart_protocol(void) { switch(tl_model) { case TRIPP_LITE_SMARTPRO: case TRIPP_LITE_SMART_0004: case TRIPP_LITE_SMART_3005: return 1; case TRIPP_LITE_OMNIVS: case TRIPP_LITE_OMNIVS_2001: case TRIPP_LITE_UNKNOWN: #if (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_PUSH_POP) && (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_COVERED_SWITCH_DEFAULT) # pragma GCC diagnostic push # pragma GCC diagnostic ignored "-Wcovered-switch-default" #endif /* All enum cases defined as of the time of coding * have been covered above. Handle later definitions, * memory corruptions and buggy inputs below... */ default: #if (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_PUSH_POP) && (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_COVERED_SWITCH_DEFAULT) # pragma GCC diagnostic pop #endif return 0; } } /*!@brief If a character is not printable, return a dot. */ #define toprint(x) (isalnum((int)x) ? (char)(x) : (char)'.') #define ENDCHAR 13 #define MAX_SEND_TRIES 10 #define SEND_WAIT_SEC 0 #define SEND_WAIT_NSEC (1000*1000*100) #define MAX_RECV_TRIES 10 #define RECV_WAIT_MSEC 1000 /*!< was 100 for OMNIVS; SMARTPRO units need longer */ #define MAX_RECONNECT_TRIES 10 #define DEFAULT_OFFDELAY 64 /*!< seconds (max 0xFF) */ #define DEFAULT_STARTDELAY 60 /*!< seconds (max 0xFFFFFF) */ #define DEFAULT_BOOTDELAY 64 /*!< seconds (max 0xFF) */ #define MAX_VOLT 13.4 /*!< Max battery voltage (100%) */ #define MIN_VOLT 11.0 /*!< Min battery voltage (10%) */ #define DEFAULT_UPSID 65535 static USBDevice_t *hd = NULL; static USBDevice_t curDevice; static USBDeviceMatcher_t *reopen_matcher = NULL; static USBDeviceMatcher_t *regex_matcher = NULL; static usb_dev_handle *udev; static usb_communication_subdriver_t *comm_driver = &usb_subdriver; /* We calculate battery charge (q) as a function of voltage (V). * It seems that this function probably varies by firmware revision or * UPS model - the Windows monitoring software gives different q for a * given V than the old open source Tripp Lite monitoring software. * * The discharge curve should be the same for any given battery chemistry, * so it should only be necessary to specify the minimum and maximum * voltages likely to be seen in operation. */ /* Interval notation for Q% = 10% <= [minV, maxV] <= 100% */ static double V_interval[2] = {MIN_VOLT, MAX_VOLT}; static long battery_voltage_nominal = 12, input_voltage_nominal = 120, input_voltage_scaled = 120, /* input_voltage_maximum = -1, input_voltage_minimum = -1, */ switchable_load_banks = 0, unit_id = -1; /*!< range: 1-65535, most likely */ /*! Time in seconds to delay before shutting down. */ static unsigned int offdelay = DEFAULT_OFFDELAY; /* static unsigned int bootdelay = DEFAULT_BOOTDELAY; */ /* Function declaration for send_cmd */ static int send_cmd(const unsigned char *msg, size_t msg_len, unsigned char *reply, size_t reply_len); /* Driver matching by ups.id since serial number isn't exposed on some Tripplite models. Ups.id is the same as Unit Id, and it is a user configurable value between 1-65535. Default Unit Id is 65535. May be set with upsrw, and it persists after powerloss as well. To match by ups id, (upsid='your ups id') must be defined inside the ups.conf */ int match_by_unitid(usb_dev_handle *argudev, USBDevice_t *arghd, usb_ctrl_charbuf rdbuf, usb_ctrl_charbufsize rdlen); int match_by_unitid(usb_dev_handle *argudev, USBDevice_t *arghd, usb_ctrl_charbuf rdbuf, usb_ctrl_charbufsize rdlen) { char *value = getval("upsid"); int config_unit_id = 0; ssize_t ret; unsigned char u_msg[] = "U"; unsigned char u_value[9]; NUT_UNUSED_VARIABLE(argudev); NUT_UNUSED_VARIABLE(arghd); NUT_UNUSED_VARIABLE(rdbuf); NUT_UNUSED_VARIABLE(rdlen); /* Read ups id from the ups.conf */ if (value != NULL) { config_unit_id = atoi(value); } /* Read ups id from the device */ if (tl_model != TRIPP_LITE_OMNIVS && tl_model != TRIPP_LITE_SMART_0004) { /* Unit ID might not be supported by all models: */ ret = send_cmd(u_msg, sizeof(u_msg), u_value, sizeof(u_value) - 1); if (ret <= 0) { upslogx(LOG_INFO, "Unit ID not retrieved (not available on all models)"); } else { unit_id = (int)((unsigned)(u_value[1]) << 8) | (unsigned)(u_value[2]); } } /* Check if the ups ids match */ if (config_unit_id == unit_id) { return 1; } else { return 0; } } /*!@brief Try to reconnect once. * @return 1 if reconnection was successful. */ static int reconnect_ups(void) { int ret; if (hd != NULL) { return 1; } dstate_setinfo("driver.state", "reconnect.trying"); upsdebugx(2, "=================================================="); upsdebugx(2, "= device has been disconnected, try to reconnect ="); upsdebugx(2, "=================================================="); ret = comm_driver->open_dev(&udev, &curDevice, reopen_matcher, match_by_unitid); if (ret < 1) { upslogx(LOG_INFO, "Reconnecting to UPS failed; will retry later..."); dstate_datastale(); return 0; } hd = &curDevice; dstate_setinfo("driver.state", "quiet"); return ret; } /*!@brief Convert a string to printable characters (in-place) * * @param[in,out] str String to convert * @param[in] len Maximum number of characters to convert, or == 0 to * convert all. * * Uses toprint() macro defined above. */ static void toprint_str(char *str, size_t len) { size_t i; if (len == 0) len = strlen(str); /* FIXME? Should we check for '\0' along the way? */ for (i = 0; i < len; i++) str[i] = toprint(str[i]); } /*!@brief Convert N characters from hex to decimal * * @param start Beginning of string to convert * @param len Maximum number of characters to consider (max 32) * * @a len characters of @a start are copied to a temporary buffer, then passed * to strtol() to be converted to decimal. * * @return See strtol(3) */ static long hex2d(const unsigned char *start, unsigned int len) { unsigned char buf[32]; buf[31] = '\0'; strncpy((char *)buf, (const char *)start, (len < (sizeof buf) ? len : (sizeof buf - 1))); if(len < sizeof(buf)) buf[len] = '\0'; return strtol((char *)buf, NULL, 16); } /*!@brief Convert N characters from big-endian binary to decimal * * @param start Beginning of string to convert * @param len Maximum number of characters to consider (max 32) * * @a len characters of @a start are shifted into an accumulator. * * We assume len < sizeof(int), and that value > 0. * * @return the value */ static unsigned int bin2d(const unsigned char *start, unsigned int len) { unsigned int value = 0, index = 0; for(index = 0; index < len; index++) { value <<= 8; value |= start[index]; } return value; } static long hex_or_bin2d(const unsigned char *start, unsigned int len) { if(is_binary_protocol()) { return bin2d(start, len); } return hex2d(start, len); } /*!@brief Dump message in both hex and ASCII * * @param[in] msg Buffer to dump * @param[in] len Number of bytes to dump * * @return Pointer to static buffer with decoded message */ static const char *hexascdump(unsigned char *msg, size_t len) { size_t i; static unsigned char buf[256]; unsigned char *bufp, *end; bufp = buf; end = bufp + sizeof(buf); buf[0] = 0; /* Dump each byte in hex: */ for(i=0; i=3; i++) { bufp += sprintf((char *)bufp, "%02x ", msg[i]); } /* Dump single-quoted string with printable version of each byte: */ if (end-bufp > 0) *bufp++ = '\''; for(i=0; i0; i++) { *bufp++ = (unsigned char)toprint(msg[i]); } if (end-bufp > 0) *bufp++ = '\''; if (end-bufp > 0) *bufp = '\0'; else *--end='\0'; return (char *)buf; } static enum tl_model_t decode_protocol(unsigned int proto) { switch(proto) { case 0x0004: upslogx(3, "Using older SMART protocol (%04x)", proto); return TRIPP_LITE_SMART_0004; case 0x1001: upslogx(3, "Using OMNIVS protocol (%x)", proto); return TRIPP_LITE_OMNIVS; case 0x2001: upslogx(3, "Using OMNIVS 2001 protocol (%x)", proto); return TRIPP_LITE_OMNIVS_2001; case 0x3003: upslogx(3, "Using SMARTPRO protocol (%x)", proto); return TRIPP_LITE_SMARTPRO; case 0x3005: upslogx(3, "Using binary SMART protocol (%x)", proto); return TRIPP_LITE_SMART_3005; default: printf("Unknown protocol (%04x)", proto); break; } return TRIPP_LITE_UNKNOWN; } static void decode_v(const unsigned char *value) { unsigned char ivn, lb; long bv; if(is_binary_protocol()) { /* 0x00 0x0c -> 12V ? */ battery_voltage_nominal = (value[2] << 8) | value[3]; } else { bv = hex2d(value+2, 2); battery_voltage_nominal = bv * 6; } ivn = value[1]; lb = value[4]; switch(ivn) { case '0': input_voltage_nominal = input_voltage_scaled = 100; break; case 2: /* protocol 3005 */ case '1': input_voltage_nominal = input_voltage_scaled = 120; break; case '2': input_voltage_nominal = input_voltage_scaled = 230; break; case '3': input_voltage_nominal = 208; input_voltage_scaled = 230; break; case 6: input_voltage_nominal = input_voltage_scaled = 230; break; default: upslogx(2, "Unknown input voltage range: 0x%02x", (unsigned int)ivn); break; } if( (lb >= '0') && (lb <= '9') ) { switchable_load_banks = lb - '0'; } else { if(is_binary_protocol()) { switchable_load_banks = lb; } else { if( lb != 'X' ) { upslogx(2, "Unknown number of switchable load banks: 0x%02x", (unsigned int)lb); } } } upsdebugx(2, "Switchable load banks: %ld", switchable_load_banks); } void upsdrv_initinfo(void); /*!@brief Report a USB comm failure, and reconnect if necessary * * @param[in] res Result code from libusb/libhid call * @param[in] msg Error message to display */ static void usb_comm_fail(int res, const char *msg) { static int try = 0; switch(res) { case LIBUSB_ERROR_BUSY: upslogx(LOG_WARNING, "%s: Device claimed by another process", msg); fatalx(EXIT_FAILURE, "Terminating: EBUSY"); #ifndef HAVE___ATTRIBUTE__NORETURN break; #endif default: dstate_setinfo("driver.state", "reconnect.trying"); upslogx(LOG_WARNING, "%s: Device detached? (error %d: %s)", msg, res, nut_usb_strerror(res)); upslogx(LOG_NOTICE, "Reconnect attempt #%d", ++try); hd = NULL; reconnect_ups(); if(hd) { upslogx(LOG_NOTICE, "Successfully reconnected"); try = 0; dstate_setinfo("driver.state", "reconnect.updateinfo"); upsdrv_initinfo(); dstate_setinfo("driver.state", "quiet"); } else { if(try > MAX_RECONNECT_TRIES) { fatalx(EXIT_FAILURE, "Too many unsuccessful reconnection attempts"); } } break; } } /*!@brief Send a command to the UPS, and wait for a reply. * * All of the UPS commands are challenge-response. If a command does not have * anything to return, it simply returns the command character. * * @param[in] msg Command string, minus the ':' or CR * @param[in] msg_len Be sure to use sizeof(msg) instead of strlen(msg), * since some commands have embedded NUL characters * @param[out] reply Reply (but check return code for validity) * @param[out] reply_len (currently unused) * * @return number of chars in reply, excluding terminating NUL * @return 0 if command was not accepted */ static int send_cmd(const unsigned char *msg, size_t msg_len, unsigned char *reply, size_t reply_len) { unsigned char buffer_out[8]; unsigned char csum = 0; int ret = 0, send_try, recv_try=0, done = 0; size_t i = 0; NUT_UNUSED_VARIABLE(reply_len); upsdebugx(3, "send_cmd(msg_len=%u, type='%c')", (unsigned)msg_len, msg[0]); if(msg_len > 5) { fatalx(EXIT_FAILURE, "send_cmd(): Trying to pass too many characters to UPS (%u)", (unsigned)msg_len); } buffer_out[0] = ':'; for(i=1; i<8; i++) buffer_out[i] = '\0'; for(i=0; iset_report(udev, 0, (usb_ctrl_charbuf)buffer_out, (usb_ctrl_charbufsize)sizeof(buffer_out)); if(ret != sizeof(buffer_out)) { upslogx(1, "libusb_set_report() returned %d instead of %" PRIuSIZE, ret, sizeof(buffer_out)); return ret; } #if ! defined(__FreeBSD__) usleep(1000*100); /* TODO: nanosleep */ #endif for(recv_try=0; !done && recv_try < MAX_RECV_TRIES; recv_try++) { upsdebugx(7, "send_cmd recv_try %d", recv_try+1); ret = comm_driver->get_interrupt(udev, (usb_ctrl_charbuf)reply, (usb_ctrl_charbufsize)sizeof(buffer_out), RECV_WAIT_MSEC); if(ret != sizeof(buffer_out)) { upslogx(1, "libusb_get_interrupt() returned %d instead of %u while sending %s", ret, (unsigned)(sizeof(buffer_out)), hexascdump(buffer_out, sizeof(buffer_out))); } done = (ret == sizeof(buffer_out)) && (buffer_out[1] == reply[0]); } } if(ret == sizeof(buffer_out)) { upsdebugx(5, "send_cmd: received %s (%s)", hexascdump(reply, sizeof(buffer_out)), done ? "OK" : "bad"); } upsdebugx(((send_try > 2) || (recv_try > 2)) ? 3 : 6, "send_cmd: send_try = %d, recv_try = %d\n", send_try, recv_try); return done ? sizeof(buffer_out) : 0; } /*!@brief Send an unknown command to the UPS, and store response in a variable * * @param msg Command string (usually a character and a null) * @param len Length of command plus null * * The variables are of the form "ups.debug.X" where "X" is the command * character. */ static void debug_message(const char *msg, size_t len) { int ret; unsigned char tmp_value[9]; char var_name[20], err_msg[80]; snprintf(var_name, sizeof(var_name), "ups.debug.%c", *msg); ret = send_cmd((const unsigned char *)msg, len, tmp_value, sizeof(tmp_value)); if(ret <= 0) { sprintf(err_msg, "Error reading '%c' value", *msg); usb_comm_fail(ret, err_msg); return; } dstate_setinfo(var_name, "%s", hexascdump(tmp_value+1, 7)); } #if 0 /* using the watchdog to reboot won't work while polling */ static void do_reboot_wait(unsigned dly) { int ret; char buf[256], cmd_W[]="Wx"; cmd_W[1] = dly; upsdebugx(3, "do_reboot_wait(wait=%d): N", dly); ret = send_cmd(cmd_W, sizeof(cmd_W), buf, sizeof(buf)); } static int do_reboot_now(void) { do_reboot_wait(1); return 0; } static void do_reboot(void) { do_reboot_wait(bootdelay); } #endif /*! Called by 'tripplite_usb -k' */ static int soft_shutdown(void) { int ret; unsigned char buf[256], cmd_N[]="N\0x", cmd_G[] = "G"; /* Already binary: */ /* FIXME: Assumes memory layout / endianness? */ cmd_N[2] = (unsigned char)(offdelay & 0x00FF); cmd_N[1] = (unsigned char)(offdelay >> 8); upsdebugx(3, "soft_shutdown(offdelay=%d): N", offdelay); ret = send_cmd(cmd_N, sizeof(cmd_N), buf, sizeof(buf)); if(ret != 8) { upslogx(LOG_ERR, "Could not set offdelay to %d", offdelay); return ret; } sleep(2); /*! The unit must be on battery for this to work. * * @todo check for on-battery condition, and print error if not. * @todo Find an equivalent command for non-OMNIVS models. */ ret = send_cmd(cmd_G, sizeof(cmd_G), buf, sizeof(buf)); if(ret != 8) { upslogx(LOG_ERR, "Could not turn off UPS (is it still on battery?)"); return 0; } return 1; } #if 0 static int hard_shutdown(void) { int ret; unsigned char buf[256], cmd_N[]="N\0x", cmd_K[] = "K\0"; /* FIXME: Assumes memory layout / endianness? */ cmd_N[2] = (unsigned char)(offdelay & 0x00FF); cmd_N[1] = (unsigned char)(offdelay >> 8); upsdebugx(3, "hard_shutdown(offdelay=%d): N", offdelay); ret = send_cmd(cmd_N, sizeof(cmd_N), buf, sizeof(buf)); if(ret != 8) return ret; sleep(2); ret = send_cmd(cmd_K, sizeof(cmd_K), buf, sizeof(buf)); return (ret == 8); } #endif /*!@brief Turn an outlet on or off. * * @return 1 if the command worked, 0 if not. */ static int control_outlet(int outlet_id, int state) { char k_cmd[10], buf[10]; int ret; switch(tl_model) { case TRIPP_LITE_SMARTPRO: /* tested */ case TRIPP_LITE_SMART_0004: /* untested */ snprintf(k_cmd, sizeof(k_cmd)-1, "N%02X", 5); ret = send_cmd((unsigned char *)k_cmd, strlen(k_cmd) + 1, (unsigned char *)buf, sizeof buf); snprintf(k_cmd, sizeof(k_cmd)-1, "K%d%d", outlet_id, state & 1); ret = send_cmd((unsigned char *)k_cmd, strlen(k_cmd) + 1, (unsigned char *)buf, sizeof buf); if(ret != 8) { upslogx(LOG_ERR, "Could not set outlet %d to state %d, ret = %d", outlet_id, state, ret); return 0; } else { return 1; } #ifdef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_UNREACHABLE_CODE #pragma GCC diagnostic push #endif #ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_UNREACHABLE_CODE_BREAK #pragma GCC diagnostic ignored "-Wunreachable-code-break" #endif #ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_UNREACHABLE_CODE #pragma GCC diagnostic ignored "-Wunreachable-code" #endif break; #ifdef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_UNREACHABLE_CODE #pragma GCC diagnostic pop #endif case TRIPP_LITE_SMART_3005: snprintf(k_cmd, sizeof(k_cmd)-1, "N%c", 5); ret = send_cmd((unsigned char *)k_cmd, strlen(k_cmd) + 1, (unsigned char *)buf, sizeof buf); snprintf(k_cmd, sizeof(k_cmd)-1, "K%c%c", outlet_id, state & 1); ret = send_cmd((unsigned char *)k_cmd, strlen(k_cmd) + 1, (unsigned char *)buf, sizeof buf); if(ret != 8) { upslogx(LOG_ERR, "Could not set outlet %d to state %d, ret = %d", outlet_id, state, ret); return 0; } else { return 1; } #ifdef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_UNREACHABLE_CODE #pragma GCC diagnostic push #endif #ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_UNREACHABLE_CODE_BREAK #pragma GCC diagnostic ignored "-Wunreachable-code-break" #endif #ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_UNREACHABLE_CODE #pragma GCC diagnostic ignored "-Wunreachable-code" #endif break; #ifdef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_UNREACHABLE_CODE #pragma GCC diagnostic pop #endif case TRIPP_LITE_OMNIVS: case TRIPP_LITE_OMNIVS_2001: case TRIPP_LITE_UNKNOWN: #if (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_PUSH_POP) && (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_COVERED_SWITCH_DEFAULT) # pragma GCC diagnostic push # pragma GCC diagnostic ignored "-Wcovered-switch-default" #endif /* All enum cases defined as of the time of coding * have been covered above. Handle later definitions, * memory corruptions and buggy inputs below... */ default: #if (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_PUSH_POP) && (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_COVERED_SWITCH_DEFAULT) # pragma GCC diagnostic pop #endif upslogx(LOG_ERR, "control_outlet unimplemented for protocol %04x", tl_model); } return 0; } /*!@brief Handler for "instant commands" */ static int instcmd(const char *cmdname, const char *extra) { unsigned char buf[10]; if(is_smart_protocol()) { if (!strcasecmp(cmdname, "test.battery.start")) { send_cmd((const unsigned char *)"A", 2, buf, sizeof buf); return STAT_INSTCMD_HANDLED; } if(!strcasecmp(cmdname, "reset.input.minmax")) { return (send_cmd((const unsigned char *)"Z", 2, buf, sizeof buf) == 2) ? STAT_INSTCMD_HANDLED : STAT_INSTCMD_UNKNOWN; } } if (!strcasecmp(cmdname, "load.off")) { return control_outlet(0, 0) ? STAT_INSTCMD_HANDLED : STAT_INSTCMD_UNKNOWN; } if (!strcasecmp(cmdname, "load.on")) { return control_outlet(0, 1) ? STAT_INSTCMD_HANDLED : STAT_INSTCMD_UNKNOWN; } /* code for individual outlets is in setvar() */ #if 0 if (!strcasecmp(cmdname, "shutdown.reboot")) { do_reboot_now(); return STAT_INSTCMD_HANDLED; } if (!strcasecmp(cmdname, "shutdown.reboot.graceful")) { do_reboot(); return STAT_INSTCMD_HANDLED; } if (!strcasecmp(cmdname, "shutdown.stayoff")) { hard_shutdown(); return STAT_INSTCMD_HANDLED; } #endif if (!strcasecmp(cmdname, "shutdown.return")) { soft_shutdown(); return STAT_INSTCMD_HANDLED; } upslogx(LOG_NOTICE, "instcmd: unknown command [%s] [%s]", cmdname, extra); return STAT_INSTCMD_UNKNOWN; } static int setvar(const char *varname, const char *val) { if (!strcasecmp(varname, "ups.delay.shutdown")) { int ival = atoi(val); if (ival >= 0) { offdelay = (unsigned int)ival; dstate_setinfo("ups.delay.shutdown", "%d", offdelay); return STAT_SET_HANDLED; } else { upslogx(LOG_NOTICE, "FAILED to set '%s' to %d", varname, ival); return STAT_SET_UNKNOWN; } } if (unit_id >= 0 && !strcasecmp(varname, "ups.id")) { int new_unit_id, ret; unsigned char J_msg[] = "J__", buf[9]; new_unit_id = atoi(val); /* FIXME: Assumes memory layout / endianness? */ J_msg[1] = (unsigned char)(new_unit_id >> 8); J_msg[2] = (unsigned char)(new_unit_id & 0xff); ret = send_cmd(J_msg, sizeof(J_msg), buf, sizeof(buf)); if(ret <= 0) { upslogx(LOG_NOTICE, "Could not set Unit ID (return code: %d).", ret); return STAT_SET_UNKNOWN; } dstate_setinfo("ups.id", "%s", val); return STAT_SET_HANDLED; } if(!strncmp(varname, "outlet.", strlen("outlet."))) { char outlet_name[80]; char index_str[10], *first_dot, *next_dot; long index_chars; int index, state, ret; first_dot = strstr(varname, "."); next_dot = strstr(first_dot + 1, "."); if (!next_dot) { upslogx(LOG_NOTICE, "FAILED to get outlet index from '%s' (no second dot)", varname); return STAT_SET_UNKNOWN; } index_chars = next_dot - (first_dot + 1); if(index_chars > 9 || index_chars < 0) return STAT_SET_UNKNOWN; if(strcmp(next_dot, ".switch")) return STAT_SET_UNKNOWN; strncpy(index_str, first_dot + 1, (size_t)index_chars); index_str[index_chars] = 0; index = atoi(index_str); upslogx(LOG_DEBUG, "outlet.%d.switch = %s", index, val); if(!strcasecmp(val, "on") || !strcmp(val, "1")) { state = 1; } else { state = 0; } upslogx(LOG_DEBUG, "outlet.%d.switch = %s -> %d", index, val, state); snprintf(outlet_name, sizeof(outlet_name)-1, "outlet.%d.switch", index); ret = control_outlet(index, state); if(ret) { dstate_setinfo(outlet_name, "%d", state); return STAT_SET_HANDLED; } else { return STAT_SET_UNKNOWN; } } #if 0 if (!strcasecmp(varname, "ups.delay.start")) { startdelay = atoi(val); dstate_setinfo("ups.delay.start", val); return STAT_SET_HANDLED; } if (!strcasecmp(varname, "ups.delay.reboot")) { bootdelay = atoi(val); dstate_setinfo("ups.delay.reboot", val); return STAT_SET_HANDLED; } #endif return STAT_SET_UNKNOWN; } void upsdrv_initinfo(void) { const unsigned char proto_msg[] = "\0", f_msg[] = "F", p_msg[] = "P", s_msg[] = "S", u_msg[] = "U", v_msg[] = "V", w_msg[] = "W\0"; char *model, *model_end; unsigned char proto_value[9], f_value[9], p_value[9], s_value[9], u_value[9], v_value[9], w_value[9]; long va; ssize_t ret; unsigned int proto_number = 0; /* Read protocol: */ ret = send_cmd(proto_msg, sizeof(proto_msg), proto_value, sizeof(proto_value)-1); if(ret <= 0) { fatalx(EXIT_FAILURE, "Error reading protocol"); } proto_number = ((unsigned)(proto_value[1]) << 8) | (unsigned)(proto_value[2]); tl_model = decode_protocol(proto_number); if(tl_model == TRIPP_LITE_UNKNOWN) dstate_setinfo("ups.debug.0", "%s", hexascdump(proto_value+1, 7)); dstate_setinfo("ups.firmware.aux", "protocol %04x", proto_number); /* - * - * - * - * - * - * - * - * - * - * - * - * - * - * - */ /* Reset watchdog: */ /* Watchdog not supported on TRIPP_LITE_SMARTPRO models */ if(tl_model != TRIPP_LITE_SMARTPRO ) { ret = send_cmd(w_msg, sizeof(w_msg), w_value, sizeof(w_value)-1); if(ret <= 0) { if(ret == LIBUSB_ERROR_PIPE) { fatalx(EXIT_FAILURE, "Could not reset watchdog. Please check and" "see if usbhid-ups(8) works with this UPS."); } else { upslogx(3, "Could not reset watchdog. Please send model " "information to nut-upsdev mailing list"); } } } /* - * - * - * - * - * - * - * - * - * - * - * - * - * - * - */ ret = send_cmd(s_msg, sizeof(s_msg), s_value, sizeof(s_value)-1); if(ret <= 0) { fatalx(EXIT_FAILURE, "Could not retrieve status ... is this an OMNIVS model?"); } /* - * - * - * - * - * - * - * - * - * - * - * - * - * - * - */ dstate_setinfo("ups.mfr", "%s", "Tripp Lite"); /* Get nominal power: */ ret = send_cmd(p_msg, sizeof(p_msg), p_value, sizeof(p_value)-1); va = strtol((char *)(p_value+1), NULL, 10); if(tl_model == TRIPP_LITE_SMART_0004) { dstate_setinfo("ups.debug.P","%s", hexascdump(p_value+1, 7)); va *= 10; /* TODO: confirm? */ } /* - * - * - * - * - * - * - * - * - * - * - * - * - * - * - */ /* trim "TRIPP LITE" from beginning of model */ model = strdup(hd->Product); if(strstr(model, hd->Vendor) == model) { model += strlen(hd->Vendor); } /* trim leading spaces: */ for(; *model == ' '; model++); /* Trim trailing spaces */ for(model_end = model + strlen(model) - 1; model_end > model && *model_end == ' '; model_end--) { *model_end = '\0'; } dstate_setinfo("ups.model", "%s", model); dstate_setinfo("ups.power.nominal", "%ld", va); /* - * - * - * - * - * - * - * - * - * - * - * - * - * - * - */ /* Fetch firmware version: */ ret = send_cmd(f_msg, sizeof(f_msg), f_value, sizeof(f_value)-1); toprint_str((char *)(f_value+1), 6); f_value[7] = 0; dstate_setinfo("ups.firmware", "F%s", f_value+1); /* - * - * - * - * - * - * - * - * - * - * - * - * - * - * - */ /* Get configuration: */ ret = send_cmd(v_msg, sizeof(v_msg), v_value, sizeof(v_value)-1); decode_v(v_value); /* FIXME: redundant, but since it's static, we don't need to poll * every time. */ debug_message("V", 2); if(switchable_load_banks > 0) { int i; char outlet_name[80]; for(i = 1; i <= switchable_load_banks + 1; i++) { snprintf(outlet_name, sizeof(outlet_name), "outlet.%d.id", i); dstate_setinfo(outlet_name, "%d", i); snprintf(outlet_name, sizeof(outlet_name), "outlet.%d.desc", i); dstate_setinfo(outlet_name, "Load %d", i); snprintf(outlet_name, sizeof(outlet_name), "outlet.%d.switchable", i); if( i <= switchable_load_banks ) { dstate_setinfo(outlet_name, "1"); snprintf(outlet_name, sizeof(outlet_name)-1, "outlet.%d.switch", i); dstate_setinfo(outlet_name, "1"); dstate_setflags(outlet_name, ST_FLAG_RW | ST_FLAG_STRING); dstate_setaux(outlet_name, 3); } else { /* Last bank is not switchable: */ dstate_setinfo(outlet_name, "0"); } } /* For the main relay: */ dstate_addcmd("load.on"); dstate_addcmd("load.off"); } /* - * - * - * - * - * - * - * - * - * - * - * - * - * - * - */ if(tl_model != TRIPP_LITE_OMNIVS && tl_model != TRIPP_LITE_SMART_0004) { /* Unit ID might not be supported by all models: */ ret = send_cmd(u_msg, sizeof(u_msg), u_value, sizeof(u_value)-1); if(ret <= 0) { upslogx(LOG_INFO, "Unit ID not retrieved (not available on all models)"); } else { unit_id = (long)((unsigned)(u_value[1]) << 8) | (unsigned)(u_value[2]); } if(tl_model == TRIPP_LITE_SMART_0004) { debug_message("U", 2); } } if(unit_id >= 0) { dstate_setinfo("ups.id", "%ld", unit_id); dstate_setflags("ups.id", ST_FLAG_RW | ST_FLAG_STRING); dstate_setaux("ups.id", 5); upslogx(LOG_DEBUG,"Unit ID: %ld", unit_id); } /* - * - * - * - * - * - * - * - * - * - * - * - * - * - * - */ dstate_setinfo("input.voltage.nominal", "%ld", input_voltage_nominal); dstate_setinfo("battery.voltage.nominal", "%ld", battery_voltage_nominal); dstate_setinfo("ups.debug.load_banks", "%ld", switchable_load_banks); dstate_setinfo("ups.delay.shutdown", "%u", offdelay); dstate_setflags("ups.delay.shutdown", ST_FLAG_RW | ST_FLAG_STRING); dstate_setaux("ups.delay.shutdown", 3); #if 0 dstate_setinfo("ups.delay.start", "%u", startdelay); dstate_setflags("ups.delay.start", ST_FLAG_RW | ST_FLAG_STRING); dstate_setaux("ups.delay.start", 8); dstate_setinfo("ups.delay.reboot", "%u", bootdelay); dstate_setflags("ups.delay.reboot", ST_FLAG_RW | ST_FLAG_STRING); dstate_setaux("ups.delay.reboot", 3); #endif if(is_smart_protocol()) { dstate_addcmd("test.battery.start"); dstate_addcmd("reset.input.minmax"); } dstate_addcmd("shutdown.return"); #if 0 dstate_addcmd("shutdown.stayoff"); dstate_addcmd("test.battery.start"); /* Turns off automatically */ dstate_addcmd("load.off"); dstate_addcmd("load.on"); dstate_addcmd("shutdown.reboot"); dstate_addcmd("shutdown.reboot.graceful"); #endif upsh.instcmd = instcmd; upsh.setvar = setvar; printf("Attached to %s %s\n", dstate_getinfo("ups.mfr"), dstate_getinfo("ups.model")); } void upsdrv_shutdown(void) { soft_shutdown(); } void upsdrv_updateinfo(void) { unsigned char b_msg[] = "B", d_msg[] = "D", l_msg[] = "L", s_msg[] = "S", m_msg[] = "M", t_msg[] = "T"; unsigned char b_value[9], d_value[9], l_value[9], s_value[9], m_value[9], t_value[9]; int bp; long freq; double bv_12V = 0.0; /*!< battery voltage, relative to a 12V battery */ double battery_voltage; /*!< the total battery voltage */ unsigned int s_value_1; int ret; status_init(); /* - * - * - * - * - * - * - * - * - * - * - * - * - * - * - */ /* General status (e.g. "S10") */ ret = send_cmd(s_msg, sizeof(s_msg), s_value, sizeof(s_value)); if(ret <= 0) { dstate_datastale(); usb_comm_fail(ret, "Error reading S value"); return; } if(tl_model != TRIPP_LITE_OMNIVS && tl_model != TRIPP_LITE_OMNIVS_2001) { dstate_setinfo("ups.debug.S","%s", hexascdump(s_value+1, 7)); } /* - * - * - * - * - * - * - * - * - * - * - * - * - * - * - */ if(tl_model == TRIPP_LITE_OMNIVS) { switch(s_value[2]) { case '0': status_set("OL"); break; case '1': status_set("OB"); break; case '2': /* "charge-only" mode, no AC in or out... the PC * shouldn't see this, because there is no power in * that case (OMNIVS), but it's here for testing. * * Entered by holding down the power button. */ status_set("BYPASS"); break; case '3': /* I have seen this once when switching from off+LB to charging */ upslogx(LOG_WARNING, "Unknown value for s[2]: 0x%02x", s_value[2]); break; default: upslogx(LOG_ERR, "Unknown value for s[2]: 0x%02x", s_value[2]); dstate_datastale(); break; } } /* - * - * - * - * - * - * - * - * - * - * - * - * - * - * - */ if(is_smart_protocol() || tl_model == TRIPP_LITE_OMNIVS_2001) { unsigned int s_value_2 = s_value[2]; if(is_binary_protocol()) { s_value_2 += '0'; } switch(s_value_2) { case '0': dstate_setinfo("battery.test.status", "Battery OK"); break; case '1': dstate_setinfo("battery.test.status", "Battery bad - replace"); break; case '2': status_set("CAL"); break; case '3': status_set("OVER"); dstate_setinfo("battery.test.status", "Overcurrent?"); break; case '4': /* The following message is confusing, and may not be accurate: */ /* dstate_setinfo("battery.test.status", "Battery state unknown"); */ break; case '5': status_set("OVER"); dstate_setinfo("battery.test.status", "Battery fail - overcurrent?"); break; default: upslogx(LOG_ERR, "Unknown value for s[2]: 0x%02x", s_value[2]); dstate_datastale(); break; } if(s_value[4] & 4) { status_set("OFF"); } else { /* Online/on battery: */ if(s_value[4] & 1) { status_set("OB"); } else { status_set("OL"); } } #if 0 /* Apparently, this value changes more frequently when the * battery is discharged, but it does not track the actual * state-of-charge. See battery.charge calculation below. */ if(tl_model == TRIPP_LITE_SMARTPRO) { unsigned battery_charge; battery_charge = (unsigned)(s_value[5]); dstate_setinfo("battery.charge", "%u", battery_charge); } #endif } /* - * - * - * - * - * - * - * - * - * - * - * - * - * - * - */ s_value_1 = s_value[1]; if(is_binary_protocol()) { s_value_1 += '0'; } switch(s_value_1) { case '0': status_set("LB"); break; case '1': /* Depends on s_value[2] */ break; case '2': if( tl_model == TRIPP_LITE_SMARTPRO ) { status_set("RB"); break; } /* else fall through: */ goto fallthrough_case_default; default: fallthrough_case_default: upslogx(LOG_ERR, "Unknown value for s[1]: 0x%02x", s_value[1]); dstate_datastale(); break; } status_commit(); /* - * - * - * - * - * - * - * - * - * - * - * - * - * - * - */ if( tl_model == TRIPP_LITE_OMNIVS || tl_model == TRIPP_LITE_OMNIVS_2001 ) { ret = send_cmd(b_msg, sizeof(b_msg), b_value, sizeof(b_value)); if(ret <= 0) { dstate_datastale(); usb_comm_fail(ret, "Error reading B value"); return; } dstate_setinfo("input.voltage", "%.2f", hex2d(b_value+1, 4)/3600.0*input_voltage_scaled); bv_12V = hex2d(b_value+5, 2)/16.0; /* TODO: use battery_voltage_nominal, even though it is most likely 12V */ dstate_setinfo("battery.voltage", "%.2f", bv_12V); } /* - * - * - * - * - * - * - * - * - * - * - * - * - * - * - */ if( is_smart_protocol() ) { ret = send_cmd(d_msg, sizeof(d_msg), d_value, sizeof(d_value)); if(ret <= 0) { dstate_datastale(); usb_comm_fail(ret, "Error reading D value"); return; } dstate_setinfo("input.voltage", "%ld", hex_or_bin2d(d_value+1, 2) * input_voltage_scaled / 120); /* TODO: factor out the two constants */ bv_12V = hex_or_bin2d(d_value+3, 2) / 10.0 ; battery_voltage = bv_12V * battery_voltage_nominal / 12.0; dstate_setinfo("battery.voltage", "%.2f", battery_voltage); /* - * - * - * - * - * - * - * - * - * - * - * - * - * - * - */ ret = send_cmd(m_msg, sizeof(m_msg), m_value, sizeof(m_value)); if(m_value[5] != 0x0d) { /* we only expect 4 hex/binary digits */ dstate_setinfo("ups.debug.M", "%s", hexascdump(m_value+1, 7)); } if(ret <= 0) { dstate_datastale(); usb_comm_fail(ret, "Error reading M (min/max input voltage)"); return; } dstate_setinfo("input.voltage.minimum", "%3ld", hex_or_bin2d(m_value+1, 2) * input_voltage_scaled / 120); dstate_setinfo("input.voltage.maximum", "%3ld", hex_or_bin2d(m_value+3, 2) * input_voltage_scaled / 120); /* - * - * - * - * - * - * - * - * - * - * - * - * - * - * - */ ret = send_cmd(t_msg, sizeof(t_msg), t_value, sizeof(t_value)); dstate_setinfo("ups.debug.T", "%s", hexascdump(t_value+1, 7)); if(ret <= 0) { dstate_datastale(); usb_comm_fail(ret, "Error reading T value"); return; } if( tl_model == TRIPP_LITE_SMARTPRO ) { freq = hex2d(t_value + 3, 3); dstate_setinfo("input.frequency", "%.1f", freq / 10.0); switch(t_value[6]) { case '1': dstate_setinfo("input.frequency.nominal", "%d", 60); break; case '0': dstate_setinfo("input.frequency.nominal", "%d", 50); break; } } if( tl_model == TRIPP_LITE_SMART_0004 ) { freq = hex2d(t_value + 3, 4); dstate_setinfo("input.frequency", "%.1f", freq / 10.0); } if( tl_model == TRIPP_LITE_SMART_3005 ) { dstate_setinfo("ups.temperature", "%d", (unsigned)(hex2d(t_value+1, 1))); } else { /* I'm guessing this is a calibration constant of some sort. */ dstate_setinfo("ups.temperature", "%.1f", (unsigned)(hex2d(t_value+1, 2)) * 0.3636 - 21); } } /* - * - * - * - * - * - * - * - * - * - * - * - * - * - * - */ if( tl_model == TRIPP_LITE_OMNIVS || tl_model == TRIPP_LITE_OMNIVS_2001 || tl_model == TRIPP_LITE_SMARTPRO || tl_model == TRIPP_LITE_SMART_0004 || tl_model == TRIPP_LITE_SMART_3005) { /* dq ~= sqrt(dV) is a reasonable approximation * Results fit well against the discrete function used in the Tripp Lite * source, but give a continuous result. */ if (bv_12V >= V_interval[1]) bp = 100; else if (bv_12V <= V_interval[0]) bp = 10; else bp = (int)(100*sqrt((bv_12V - V_interval[0]) / (V_interval[1] - V_interval[0]))); dstate_setinfo("battery.charge", "%3d", bp); } /* - * - * - * - * - * - * - * - * - * - * - * - * - * - * - */ ret = send_cmd(l_msg, sizeof(l_msg), l_value, sizeof(l_value)); if(ret <= 0) { dstate_datastale(); usb_comm_fail(ret, "Error reading L value"); return; } switch(tl_model) { case TRIPP_LITE_OMNIVS: case TRIPP_LITE_OMNIVS_2001: dstate_setinfo("output.voltage", "%.1f", hex2d(l_value+1, 4)/240.0*input_voltage_scaled); break; case TRIPP_LITE_SMARTPRO: dstate_setinfo("ups.load", "%ld", hex2d(l_value+1, 2)); break; case TRIPP_LITE_SMART_3005: dstate_setinfo("ups.load", "%ld", hex_or_bin2d(l_value+1, 1)); break; case TRIPP_LITE_SMART_0004: dstate_setinfo("ups.load", "%ld", hex2d(l_value+1, 2)); dstate_setinfo("ups.debug.L","%s", hexascdump(l_value+1, 7)); break; case TRIPP_LITE_UNKNOWN: #if (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_PUSH_POP) && (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_COVERED_SWITCH_DEFAULT) # pragma GCC diagnostic push # pragma GCC diagnostic ignored "-Wcovered-switch-default" #endif /* All enum cases defined as of the time of coding * have been covered above. Handle later definitions, * memory corruptions and buggy inputs below... */ default: #if (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_PUSH_POP) && (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_COVERED_SWITCH_DEFAULT) # pragma GCC diagnostic pop #endif dstate_setinfo("ups.debug.L","%s", hexascdump(l_value+1, 7)); break; } /* - * - * - * - * - * - * - * - * - * - * - * - * - * - * - */ if(tl_model != TRIPP_LITE_OMNIVS && tl_model != TRIPP_LITE_OMNIVS_2001) { debug_message("D", 2); /* We already grabbed these above: */ if(tl_model != TRIPP_LITE_SMARTPRO) { debug_message("V", 2); /* Probably not necessary - seems to be static */ debug_message("M", 2); debug_message("T", 2); debug_message("P", 2); } /* debug_message("U", 2); */ } dstate_dataok(); } void upsdrv_help(void) { } void upsdrv_makevartable(void) { char msg[256]; snprintf(msg, sizeof msg, "Set shutdown delay, in seconds (default=%d)", DEFAULT_OFFDELAY); addvar(VAR_VALUE, "offdelay", msg); /* allow -x vendor=X, vendorid=X, product=X, productid=X, serial=X */ nut_usb_addvars(); snprintf(msg, sizeof msg, "Minimum battery voltage, corresponding to 10%% charge (default=%.1f)", MIN_VOLT); addvar(VAR_VALUE, "battery_min", msg); snprintf(msg, sizeof msg, "Maximum battery voltage, corresponding to 100%% charge (default=%.1f)", MAX_VOLT); addvar(VAR_VALUE, "battery_max", msg); // allow -x upsid=X snprintf(msg, sizeof msg, "UPS ID (Unit ID) (default=%d)", DEFAULT_UPSID); addvar(VAR_VALUE, "upsid", msg); #if 0 snprintf(msg, sizeof msg, "Set start delay, in seconds (default=%d).", DEFAULT_STARTDELAY); addvar(VAR_VALUE, "startdelay", msg); snprintf(msg, sizeof msg, "Set reboot delay, in seconds (default=%d).", DEFAULT_BOOTDELAY); addvar(VAR_VALUE, "rebootdelay", msg); #endif } /*!@brief Initialize UPS and variables from ups.conf * * @todo Allow binding based on firmware version (which seems to vary wildly * from unit to unit) */ void upsdrv_initups(void) { char *regex_array[USBMATCHER_REGEXP_ARRAY_LIMIT]; char *value; int r; warn_if_bad_usb_port_filename(device_path); /* process the UPS selection options */ regex_array[0] = NULL; /* handled by USB IDs device table */ regex_array[1] = getval("productid"); regex_array[2] = getval("vendor"); /* vendor string */ regex_array[3] = getval("product"); /* product string */ regex_array[4] = getval("serial"); /* probably won't see this */ regex_array[5] = getval("bus"); regex_array[6] = getval("device"); #if (defined WITH_USB_BUSPORT) && (WITH_USB_BUSPORT) regex_array[7] = getval("busport"); #endif r = USBNewRegexMatcher(®ex_matcher, regex_array, REG_ICASE | REG_EXTENDED); if (r==-1) { fatal_with_errno(EXIT_FAILURE, "USBNewRegexMatcher"); } else if (r) { fatalx(EXIT_FAILURE, "invalid regular expression: %s", regex_array[r]); } /* link the matchers */ regex_matcher->next = &subdriver_matcher; /* Search for the first supported UPS matching the regular * expression */ r = comm_driver->open_dev(&udev, &curDevice, regex_matcher, match_by_unitid); if (r < 1) { fatalx(EXIT_FAILURE, "No matching USB/HID UPS found"); } hd = &curDevice; upslogx(1, "Detected a UPS: %s/%s", hd->Vendor ? hd->Vendor : "unknown", hd->Product ? hd->Product : "unknown"); dstate_setinfo("ups.vendorid", "%04x", hd->VendorID); dstate_setinfo("ups.productid", "%04x", hd->ProductID); /* create a new matcher for later reopening */ r = USBNewExactMatcher(&reopen_matcher, hd); if (r) { fatal_with_errno(EXIT_FAILURE, "USBNewExactMatcher"); } /* link the two matchers */ reopen_matcher->next = regex_matcher; value = getval("offdelay"); if (value) { int ival = atoi(value); if (ival >= 0) { offdelay = (unsigned int)ival; upsdebugx(2, "Setting 'offdelay' to %u", offdelay); } else { upsdebugx(2, "FAILED to set 'offdelay' to %d", ival); } } value = getval("battery_min"); if (value) { V_interval[0] = atof(value); upsdebugx(2, "Setting 'battery_min' to %.g", V_interval[0]); } value = getval("battery_max"); if (value) { V_interval[1] = atof(value); upsdebugx(2, "Setting 'battery_max' to %.g", V_interval[1]); } #if 0 if (getval("startdelay")) startdelay = atoi(getval("startdelay")); if (getval("rebootdelay")) bootdelay = atoi(getval("rebootdelay")); #endif } void upsdrv_cleanup(void) { comm_driver->close_dev(udev); USBFreeExactMatcher(reopen_matcher); USBFreeRegexMatcher(regex_matcher); free(curDevice.Vendor); free(curDevice.Product); free(curDevice.Serial); free(curDevice.Bus); free(curDevice.Device); #if (defined WITH_USB_BUSPORT) && (WITH_USB_BUSPORT) free(curDevice.BusPort); #endif } nut-2.8.1/drivers/nutdrv_qx_blazer-common.c0000644000175000017500000002540014500336654015761 00000000000000/* nutdrv_qx_blazer-common.c - Common functions/settings for nutdrv_qx_{mecer,megatec,megatec-old,mustek,q1,voltronic-qs,zinto}.{c,h} * * Copyright (C) * 2013 Daniele Pezzini * * 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 2 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, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #include "main.h" #include "nutdrv_qx.h" #include "nutdrv_qx_blazer-common.h" /* == Ranges == */ /* Range for ups.delay.start */ info_rw_t blazer_r_ondelay[] = { { "0", 0 }, { "599940", 0 }, { "", 0 } }; /* Range for ups.delay.shutdown */ info_rw_t blazer_r_offdelay[] = { { "12", 0 }, { "600", 0 }, { "", 0 } }; /* == Support functions == */ /* This function allows the subdriver to "claim" a device: return 1 if the device is supported by this subdriver, else 0. */ int blazer_claim(void) { /* To tell whether the UPS is supported or not, we'll check both status (Q1/QS/D) and vendor (I/FW?) - provided that we were not told not to do it with the ups.conf flag 'novendor'. */ item_t *item = find_nut_info("input.voltage", 0, 0); /* Don't know what happened */ if (!item) return 0; /* No reply/Unable to get value */ if (qx_process(item, NULL)) return 0; /* Unable to process value */ if (ups_infoval_set(item) != 1) return 0; if (testvar("novendor")) return 1; /* Vendor */ item = find_nut_info("ups.firmware", 0, 0); /* Don't know what happened */ if (!item) { dstate_delinfo("input.voltage"); return 0; } /* No reply/Unable to get value */ if (qx_process(item, NULL)) { dstate_delinfo("input.voltage"); return 0; } /* Unable to process value */ if (ups_infoval_set(item) != 1) { dstate_delinfo("input.voltage"); return 0; } return 1; } /* This function allows the subdriver to "claim" a device: return 1 if the device is supported by this subdriver, else 0. * NOTE: this 'light' version only checks for status (Q1/QS/D/..) */ int blazer_claim_light(void) { /* To tell whether the UPS is supported or not, we'll check just status (Q1/QS/D/..). */ item_t *item = find_nut_info("input.voltage", 0, 0); /* Don't know what happened */ if (!item) return 0; /* No reply/Unable to get value */ if (qx_process(item, NULL)) return 0; /* Unable to process value */ if (ups_infoval_set(item) != 1) return 0; return 1; } /* Subdriver-specific flags/vars */ void blazer_makevartable(void) { addvar(VAR_FLAG, "norating", "Skip reading rating information from UPS"); addvar(VAR_FLAG, "novendor", "Skip reading vendor information from UPS"); blazer_makevartable_light(); } /* Subdriver-specific flags/vars * NOTE: this 'light' version only handles vars/flags related to UPS status query (Q1/QS/D/...) */ void blazer_makevartable_light(void) { addvar(VAR_FLAG, "ignoresab", "Ignore 'Shutdown Active' bit in UPS status"); } /* Subdriver-specific initups */ void blazer_initups(item_t *qx2nut) { int nr, nv, isb; item_t *item; nr = testvar("norating"); nv = testvar("novendor"); isb = testvar("ignoresab"); if (!nr && !nv && !isb) return; for (item = qx2nut; item->info_type != NULL; item++) { if (!item->command) continue; /* norating */ if (nr && !strcasecmp(item->command, "F\r")) { upsdebugx(2, "%s: skipping %s", __func__, item->info_type); item->qxflags |= QX_FLAG_SKIP; } /* novendor */ if (nv && (!strcasecmp(item->command, "I\r") || !strcasecmp(item->command, "FW?\r"))) { upsdebugx(2, "%s: skipping %s", __func__, item->info_type); item->qxflags |= QX_FLAG_SKIP; } /* ignoresab */ if (isb && !strcasecmp(item->info_type, "ups.status") && item->from == 44 && item->to == 44) { upsdebugx(2, "%s: skipping %s ('Shutdown Active' bit)", __func__, item->info_type); item->qxflags |= QX_FLAG_SKIP; } } } /* Subdriver-specific initups * NOTE: this 'light' version only checks for status (Q1/QS/D/..) related items */ void blazer_initups_light(item_t *qx2nut) { item_t *item; if (!testvar("ignoresab")) return; for (item = qx2nut; item->info_type != NULL; item++) { if (strcasecmp(item->info_type, "ups.status") || item->from != 44 || item->to != 44) continue; upsdebugx(2, "%s: skipping %s ('Shutdown Active' bit)", __func__, item->info_type); item->qxflags |= QX_FLAG_SKIP; break; } } /* == Preprocess functions == */ /* Preprocess setvars */ int blazer_process_setvar(item_t *item, char *value, const size_t valuelen) { if (!strlen(value)) { upsdebugx(2, "%s: value not given for %s", __func__, item->info_type); return -1; } if (!strcasecmp(item->info_type, "ups.delay.start")) { long ondelay = strtol(value, NULL, 10); if (ondelay < 0) { upslogx(LOG_ERR, "%s: ondelay '%ld' should not be negative", item->info_type, ondelay); return -1; } /* Truncate to minute */ ondelay -= (ondelay % 60); snprintf(value, valuelen, "%ld", ondelay); } else if (!strcasecmp(item->info_type, "ups.delay.shutdown")) { long offdelay = strtol(value, NULL, 10); if (offdelay < 0) { upslogx(LOG_ERR, "%s: offdelay '%ld' should not be negative", item->info_type, offdelay); return -1; } /* Truncate to nearest settable value */ if (offdelay < 60) { offdelay -= (offdelay % 6); } else { offdelay -= (offdelay % 60); } snprintf(value, valuelen, "%ld", offdelay); } else { /* Don't know what happened */ return -1; } return 0; } /* Preprocess instant commands */ int blazer_process_command(item_t *item, char *value, const size_t valuelen) { #ifdef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL #pragma GCC diagnostic push #endif #ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL #pragma GCC diagnostic ignored "-Wformat-nonliteral" #endif #ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_FORMAT_SECURITY #pragma GCC diagnostic ignored "-Wformat-security" #endif if (!strcasecmp(item->info_type, "shutdown.return")) { /* Sn: Shutdown after n minutes and then turn on when mains is back * SnRm: Shutdown after n minutes and then turn on after m minutes * Accepted values for n: .2 -> .9 , 01 -> 10 * Accepted values for m: 0001 -> 9999 * Note: "S01R0001" and "S01R0002" may not work on early (GE) firmware versions. * The failure mode is that the UPS turns off and never returns. * The fix is to push the return value up by 2, i.e. S01R0003, and it will return online properly. * (thus the default of ondelay=3 mins) */ long offdelay = strtol(dstate_getinfo("ups.delay.shutdown"), NULL, 10), ondelay = strtol(dstate_getinfo("ups.delay.start"), NULL, 10) / 60; char buf[SMALLBUF] = ""; if (ondelay <= 0) { if (offdelay < 0) { upslogx(LOG_ERR, "%s: offdelay '%ld' should not be negative", item->info_type, offdelay); return -1; } if (offdelay < 60) { snprintf(buf, sizeof(buf), ".%ld", offdelay / 6); } else { snprintf(buf, sizeof(buf), "%02ld", offdelay / 60); } } else if (offdelay < 60) { if (offdelay < 0) { upslogx(LOG_ERR, "%s: offdelay '%ld' should not be negative", item->info_type, offdelay); return -1; } snprintf(buf, sizeof(buf), ".%ldR%04ld", offdelay / 6, ondelay); } else { if (offdelay < 0) { upslogx(LOG_ERR, "%s: offdelay '%ld' should not be negative", item->info_type, offdelay); return -1; } snprintf(buf, sizeof(buf), "%02ldR%04ld", offdelay / 60, ondelay); } snprintf(value, valuelen, item->command, buf); } else if (!strcasecmp(item->info_type, "shutdown.stayoff")) { /* SnR0000 * Shutdown after n minutes and stay off * Accepted values for n: .2 -> .9 , 01 -> 10 */ long offdelay = strtol(dstate_getinfo("ups.delay.shutdown"), NULL, 10); char buf[SMALLBUF] = ""; if (offdelay < 0) { upslogx(LOG_ERR, "%s: offdelay '%ld' should not be negative", item->info_type, offdelay); return -1; } if (offdelay < 60) { snprintf(buf, sizeof(buf), ".%ld", offdelay / 6); } else { snprintf(buf, sizeof(buf), "%02ld", offdelay / 60); } snprintf(value, valuelen, item->command, buf); } else if (!strcasecmp(item->info_type, "test.battery.start")) { long delay = strlen(value) > 0 ? strtol(value, NULL, 10) : 600; if ((delay < 60) || (delay > 5940)) { upslogx(LOG_ERR, "%s: battery test time '%ld' out of range [60..5940] seconds", item->info_type, delay); return -1; } delay = delay / 60; snprintf(value, valuelen, item->command, delay); } else { /* Don't know what happened */ return -1; } #ifdef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL #pragma GCC diagnostic pop #endif return 0; } /* Process status bits */ int blazer_process_status_bits(item_t *item, char *value, const size_t valuelen) { char *val = ""; if (strspn(item->value, "01") != 1) { upsdebugx(3, "%s: unexpected value %s@%d->%s", __func__, item->value, item->from, item->value); return -1; } switch (item->from) { case 38: /* Utility Fail (Immediate) */ if (item->value[0] == '1') val = "!OL"; else val = "OL"; break; case 39: /* Battery Low */ if (item->value[0] == '1') val = "LB"; else val = "!LB"; break; case 40: /* Bypass/Boost or Buck Active */ if (item->value[0] == '1') { double vi, vo; vi = strtod(dstate_getinfo("input.voltage"), NULL); vo = strtod(dstate_getinfo("output.voltage"), NULL); if (vo < 0.5 * vi) { upsdebugx(2, "%s: output voltage too low", __func__); return -1; } else if (vo < 0.95 * vi) { val = "TRIM"; } else if (vo < 1.05 * vi) { val = "BYPASS"; } else if (vo < 1.5 * vi) { val = "BOOST"; } else { upsdebugx(2, "%s: output voltage too high", __func__); return -1; } } break; case 41: /* UPS Failed - ups.alarm */ if (item->value[0] == '1') val = "UPS selftest failed!"; break; case 42: /* UPS Type - ups.type */ if (item->value[0] == '1') val = "offline / line interactive"; else val = "online"; break; case 43: /* Test in Progress */ if (item->value[0] == '1') val = "CAL"; else val = "!CAL"; break; case 44: /* Shutdown Active */ if (item->value[0] == '1') val = "FSD"; else val = "!FSD"; break; case 45: /* Beeper status - ups.beeper.status */ if (item->value[0] == '1') val = "enabled"; else val = "disabled"; break; default: /* Don't know what happened */ return -1; } snprintf(value, valuelen, "%s", val); return 0; } nut-2.8.1/drivers/main.h0000644000175000017500000001441714501607135012035 00000000000000#ifndef NUT_MAIN_H_SEEN #define NUT_MAIN_H_SEEN #include "common.h" #include "upsconf.h" #include "upshandler.h" #include "dstate.h" #include "extstate.h" #ifdef WIN32 #include "wincompat.h" #endif /* public functions & variables from main.c */ extern const char *progname, *upsname, *device_name; extern char *device_path; extern int broken_driver, experimental_driver, do_lock_port, exit_flag; extern TYPE_FD upsfd, extrafd; extern time_t poll_interval; /* functions & variables required in each driver */ void upsdrv_initups(void); /* open connection to UPS, fail if not found */ void upsdrv_initinfo(void); /* prep data, settings for UPS monitoring */ void upsdrv_updateinfo(void); /* update state data if possible */ void upsdrv_shutdown(void); /* make the UPS power off the load */ void upsdrv_help(void); /* tack on anything useful for the -h text */ void upsdrv_banner(void); /* print your version information */ void upsdrv_cleanup(void); /* free any resources before shutdown */ void set_exit_flag(int sig); /* --- details for the variable/value sharing --- */ /* handle instant commands common for all drivers * (returns STAT_INSTCMD_* state values per enum in upshandler.h) */ int main_instcmd(const char *cmdname, const char *extra, conn_t *conn); /* handle setting variables common for all drivers * (returns STAT_SET_* state values per enum in upshandler.h) */ int main_setvar(const char *varname, const char *val, conn_t *conn); /* main calls this driver function - it needs to call addvar */ void upsdrv_makevartable(void); /* retrieve the value of variable if possible */ char *getval(const char *var); /* see if has been defined, even if no value has been given to it */ int testvar(const char *var); /* extended variable table - used for -x defines/flags */ typedef struct vartab_s { int vartype; /* VAR_* value, below */ char *var; /* left side of =, or whole word if none */ char *val; /* right side of = */ char *desc; /* 40 character description for -h text */ int found; /* set once encountered, for testvar() */ int reloadable; /* driver reload may redefine this value */ struct vartab_s *next; } vartab_t; /* flags to define types in the vartab */ #define VAR_FLAG 0x0001 /* argument is a flag (no value needed) */ #define VAR_VALUE 0x0002 /* argument requires a value setting */ #define VAR_SENSITIVE 0x0004 /* do not publish in driver.parameter */ /* callback from driver - create the table for future -x entries */ void addvar(int vartype, const char *name, const char *desc); void addvar_reloadable(int vartype, const char *name, const char *desc); /* Several helpers for driver configuration reloading follow: * * testval_reloadable() checks if we are currently reloading (or initially * loading) the configuration, and if strings oldval==newval or not, * e.g. for values saved straight into driver source code variables; * * testinfo_reloadable() checks this for a name saved as dstate_setinfo(); * * testvar_reloadable() checks in vartab_t list as maintained by addvar(). * * All these methods check if value can be (re-)loaded now: * * either it is reloadable by argument or vartab_t definition, * * or no value has been saved into it yet (e.g. is NULL), * * or we are handling initial loading and keep legacy behavior of trusting * the inputs (e.g. some values may be defined as defaults in global section * and tuned in a driver section). * * Return values: * * -1 -- if nothing needs to be done and that is not a failure * (e.g. value not modified so we do not care if we may change it or not); * * 0 -- if can not modify this value (but it did change in config); * * 1 -- if we can and should apply a new (maybe initial) value. */ int testvar_reloadable(const char *var, const char *val, int vartype); int testval_reloadable(const char *var, const char *oldval, const char *newval, int reloadable); int testinfo_reloadable(const char *var, const char *infoname, const char *newval, int reloadable); /* subdriver description structure */ typedef struct upsdrv_info_s { const char *name; /* driver full name, for banner printing, ... */ const char *version; /* driver version */ const char *authors; /* authors name */ const int status; /* driver development status */ struct upsdrv_info_s *subdrv_info[2]; /* sub driver information */ } upsdrv_info_t; /* flags to define the driver development status */ #define DRV_BROKEN 0x0001 /* dito... */ #define DRV_EXPERIMENTAL 0x0002 /* dito... */ #define DRV_BETA 0x0004 /* more stable and complete, but still * not suitable for production systems */ #define DRV_STABLE 0x0008 /* suitable for production systems, but * not 100 % feature complete */ #define DRV_COMPLETE 0x0010 /* gold level: implies 100 % of the * protocol implemented and the full QA * pass */ /* FIXME: complete with mfr support, and other interesting info */ /* public driver information from the driver file */ extern upsdrv_info_t upsdrv_info; /* functions and data possibly used via libdummy_mockdrv.la for unit-tests */ #ifdef DRIVERS_MAIN_WITHOUT_MAIN extern vartab_t *vartab_h; void dparam_setinfo(const char *var, const char *val); void storeval(const char *var, char *val); void vartab_free(void); void setup_signals(void); #endif /* DRIVERS_MAIN_WITHOUT_MAIN */ #ifndef WIN32 # define SIGCMD_RELOAD SIGHUP /* not a signal, so negative; relies on socket protocol */ # define SIGCMD_RELOAD_OR_ERROR -SIGCMD_RELOAD # define SIGCMD_RELOAD_OR_EXIT SIGUSR1 /* // FIXME: Implement this self-recycling in drivers (keeping the PID): # define SIGCMD_RELOAD_OR_RESTART SIGUSR2 */ /* This is commonly defined on systems we know; file bugs/PRs for * relevant systems where it is not present (SIGWINCH might be an * option there, though terminal resizes might cause braindumps). * Their packaging may want to add a patch for this bit (and docs). */ # if (defined SIGURG) # define SIGCMD_DATA_DUMP SIGURG # else # if (defined SIGWINCH) # define SIGCMD_DATA_DUMP SIGWINCH # else # pragma warn "This OS lacks SIGURG and SIGWINCH, will not handle SIGCMD_DATA_DUMP" # endif # endif #else /* FIXME: handle WIN32 builds for other signals too */ # define SIGCMD_RELOAD_OR_ERROR "driver.reload-or-error" #endif /* WIN32 */ #endif /* NUT_MAIN_H_SEEN */ nut-2.8.1/drivers/nutdrv_qx_blazer-common.h0000644000175000017500000000314414273170601015762 00000000000000/* nutdrv_qx_blazer-common.h - Common functions/settings for nutdrv_qx_{mecer,megatec,megatec-old,mustek,q1,voltronic-qs,zinto}.{c,h} * * Copyright (C) * 2013 Daniele Pezzini * * 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 2 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, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #ifndef NUTDRV_QX_BLAZER_COMMON_H #define NUTDRV_QX_BLAZER_COMMON_H #include "nutdrv_qx.h" /* Support functions */ void blazer_makevartable(void); void blazer_makevartable_light(void); void blazer_initups(item_t *qx2nut); void blazer_initups_light(item_t *qx2nut); int blazer_claim(void); int blazer_claim_light(void); /* Preprocess functions */ int blazer_process_command(item_t *item, char *value, const size_t valuelen); int blazer_process_setvar(item_t *item, char *value, const size_t valuelen); int blazer_process_status_bits(item_t *item, char *value, const size_t valuelen); /* Ranges */ extern info_rw_t blazer_r_ondelay[]; extern info_rw_t blazer_r_offdelay[]; #endif /* NUTDRV_QX_BLAZER_COMMON_H */ nut-2.8.1/drivers/optiups.c0000644000175000017500000004600614515702041012603 00000000000000/* optiups.c - OptiSafe UPS (very loosely based on the nut 0.45.5 driver) Copyright (C) 1999 Russell Kroll Copyright (C) 2006 Scott Heavner [Use my alioth acct: sheavner] Support for Zinto D from ONLINE USV (only minor differences to OptiSafe UPS) added by Matthias Goebl 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 2 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, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ================================================================================== */ #include "main.h" #include "serial.h" #include "nut_stdint.h" #define DRIVER_NAME "Opti-UPS driver" #define DRIVER_VERSION "1.04" /* driver description structure */ upsdrv_info_t upsdrv_info = { DRIVER_NAME, DRIVER_VERSION, "Russell Kroll \n" \ "Scott Heavner \n" \ "Matthias Goebl ", DRV_STABLE, { NULL } }; #define HELP "\n" \ "**********************************************************" "\n" \ "This driver has been tested only with the OPTI SAFE 420E using" "\n" \ "the custom cable described in the NUT Opti-UPS protocol page." "\n" \ "Seriously, it does _NOT_ work with the [windows] cable provided with" "\n" \ "the UPS or a standard serial cable. (I don't know if OPTI makes other" "\n" \ "UPS models that will work with another cable?) Standard linux serial" "\n" \ "port drivers do not support the required DTR handshaking." "\n" \ "" "\n" \ " UPS 6 -> PC 3 This 3 wire cable pinout maps DTR to CTS." "\n" \ " UPS 9 -> PC 2" "\n" \ " UPS 4 -> PC 5" "\n" \ "" "\n" \ "This driver has also been tested with a Zinto D from Online-USV AG," "\n" \ "using their special cable:" "\n" \ " UPS 6 -> PC 3" "\n" \ " UPS 9 -> PC 2" "\n" \ " UPS 7 -> PC 5" "\n" \ "It works even with a pl2303 usb-serial converter." "\n" \ "**********************************************************" "\n" /* See https://www.networkupstools.org/protocols/optiups.html and the end of this * file for more information on the cable and the OPTI-UPS serial protocol used on * at least the older OPTI UPS models (420E, 820ES). */ #define ENDCHAR '\n' #define IGNCHARS "\r" /* Our custom options available with -x */ #define OPTI_MINPOLL "status_only" #define OPTI_FAKELOW "fake_lowbatt" #define OPTI_NOWARN_NOIMP "nowarn_noimp" #define OPTI_POWERUP "powerup" /* All serial commands put their response in the same buffer space */ static char _buf[256]; /* Model */ static int optimodel = 0; enum { OPTIMODEL_DEFAULT = 0, OPTIMODEL_ZINTO = 1, OPTIMODEL_PS = 2 }; /* Status bits returned by the "AG" command */ enum { OPTISBIT_NOOUTPUT = 2L, OPTISBIT_OVERLOAD = 8L, OPTISBIT_REPLACE_BATTERY = 16L, OPTISBIT_ON_BATTERY_POWER = 32L, OPTISBIT_LOW_BATTERY = 64L }; /* Helper struct for the optifill() function */ typedef struct ezfill_s { const char *cmd; const char *var; const float scale; /* if 0, no conversion is done and the string is passed to dstate as is, otherwise a float conversion with single decimal is applied */ } ezfill_t; /* These can be polled right into a string usable by NUT. * Others such as "AG" and "BV" require some transformation of the return value */ static ezfill_t _pollv[] = { { "NV", "input.voltage", 0 }, { "OL", "ups.load", 1.0 }, { "OV", "output.voltage", 0 }, { "FF", "input.frequency", 0.1 }, { "BT", "ups.temperature", 0 }, }; static ezfill_t _pollv_zinto[] = { { "NV", "input.voltage", 2.0 }, { "OL", "ups.load", 1.0 }, { "OV", "output.voltage", 2.0 }, { "OF", "output.frequency", 0.1 }, { "NF", "input.frequency", 0.1 }, { "BT", "ups.temperature", 0 }, }; /* When on a 220-2400V mains supply, the NV and OV commands return 115V values. FV * returns a value that matches the DIP switch settings for 120/240V models, so * it can be used to scale the valus from NV and OV. * * I suspect this will be the case for other Opti-UPS models, but as I can only * test with a PS-1440RM at 230V the change is only applied to PowerSeries models. */ static ezfill_t _pollv_ps[] = { { "OL", "ups.load", 1.0 }, { "FF", "input.frequency", 0.1 }, { "BT", "ups.temperature", 0 }, }; /* model "IO" is parsed differently in upsdrv_initinfo() */ static ezfill_t _initv[] = { { "IM", "ups.mfr", 0 }, { "IZ", "ups.serial", 0 }, { "IS", "ups.firmware", 0 }, }; /* All serial reads of the OPTI-UPS go through here. We always expect a CR/LF terminated * response. Unknown/Unimplemented commands return ^U (0x15). Actions that complete * successfully return ^F (0x06). */ static inline ssize_t optireadline(void) { ssize_t r; usleep(150000); r = ser_get_line(upsfd, _buf, sizeof(_buf), ENDCHAR, IGNCHARS, 0, 500000 ); _buf[sizeof(_buf)-1] = 0; if ( r > 0 ) { if ( r < (int)sizeof(_buf) ) _buf[r] = 0; if ( _buf[0] == 0x15 ) { r=-2; upsdebugx(1, "READ: "); } if ( _buf[0] == 0x06 ) { upsdebugx(2, "READ: "); } else { upsdebugx(2, "READ: \"%s\"", _buf ); } } else upsdebugx(1, "READ ERROR: %" PRIiSIZE, r); return r; } /* Send a command and read the response. Command response is in global _buf. * Return * > 0 implies success. * -1 serial timeout * -2 unknown/unimplemented command */ static inline ssize_t optiquery( const char *cmd ) { upsdebugx(2, "SEND: \"%s\"", cmd ); ser_send( upsfd, "%s", cmd ); if ( optimodel == OPTIMODEL_ZINTO ) ser_send( upsfd, "\r\n" ); return optireadline(); } /* Uses the ezfill_t structure to map UPS commands to the NUT variable destinations */ static void optifill( ezfill_t *a, size_t len ) { size_t i; ssize_t r; /* Some things are easy to poll and store */ for ( i=0; i 1e-20 ) { float f = strtol( _buf, NULL, 10 ) * a[i].scale; dstate_setinfo( a[i].var, "%.1f", f ); } else { dstate_setinfo( a[i].var, "%s", _buf); } } } /* Handle custom (but standardized) NUT commands */ static int instcmd(const char *cmdname, const char *extra) { if (!strcasecmp(cmdname, "test.failure.start")) { optiquery( "Ts" ); return STAT_INSTCMD_HANDLED; } else if (!strcasecmp(cmdname, "load.off")) { /* You do realize this will kill power to ourself. * Would probably only be useful for killing power for * a computer with upsmon in "secondary" mode */ if ( optimodel == OPTIMODEL_ZINTO ) { optiquery( "Ct1" ); optiquery( "Cs0000000" ); sleep(2); return STAT_INSTCMD_HANDLED; } optiquery( "Ct0" ); optiquery( "Cs00000000" ); return STAT_INSTCMD_HANDLED; } else if (!strcasecmp(cmdname, "load.on")) { if ( optimodel == OPTIMODEL_ZINTO ) { optiquery( "Ct1" ); optiquery( "Cu0000000" ); sleep(2); return STAT_INSTCMD_HANDLED; } optiquery( "Ct0" ); optiquery( "Cu00000000" ); return STAT_INSTCMD_HANDLED; } else if (!strcasecmp(cmdname, "shutdown.return")) { /* This shuts down the UPS. When the power returns to the UPS, * it will power back up in its default state. */ if ( optimodel == OPTIMODEL_ZINTO ) { optiquery( "Ct1" ); optiquery( "Cu0000010" ); optiquery( "Cs0000001" ); return STAT_INSTCMD_HANDLED; } optiquery( "Ct1" ); optiquery( "Cs00000010" ); return STAT_INSTCMD_HANDLED; } else if (!strcasecmp(cmdname, "shutdown.stayoff")) { /* This actually stays off as long as the batteries hold, * if the line power comes back before the batteries die, * the UPS will never powerup its output stage!!! */ if ( optimodel == OPTIMODEL_ZINTO ) { optiquery( "Ct1" ); optiquery( "Cs0000001" ); return STAT_INSTCMD_HANDLED; } optiquery( "Ct0" ); optiquery( "Cs00000010" ); return STAT_INSTCMD_HANDLED; } else if (!strcasecmp(cmdname, "shutdown.stop")) { /* Aborts a shutdown that is couting down via the Cs command */ optiquery( "Cs-0000001" ); return STAT_INSTCMD_HANDLED; } upslogx(LOG_NOTICE, "instcmd: unknown command [%s] [%s]", cmdname, extra); return STAT_INSTCMD_UNKNOWN; } /* Handle variable setting */ static int setvar(const char *varname, const char *val) { int status; if (sscanf(val, "%d", &status) != 1) { return STAT_SET_UNKNOWN; } if (strcasecmp(varname, "outlet.1.switch") == 0) { status = status==1 ? 1 : 0; dstate_setinfo( "outlet.1.switch", "%d", status); optiquery(status ? "Oi11" : "Oi10"); dstate_dataok(); return STAT_SET_HANDLED; } return STAT_SET_UNKNOWN; } void upsdrv_initinfo(void) { ssize_t r; /* If an Zinto Online-USV is off, switch it on first. */ /* It sends only "2" when off, without "\r\n", and doesn't */ /* answer other commands. Therefore without power we'll be */ /* unable to identify the ups. */ if ( testvar(OPTI_POWERUP) && optiquery( "AG" ) < 1 ) { ser_send( upsfd, "AG\r\n" ); r = ser_get_char(upsfd, &_buf[0], 1, 0); if ( r == 1 && _buf[0] == '2' ) { upslogx( LOG_WARNING, "ups was off, switching it on" ); optiquery( "Ct1" ); optiquery( "Cu0000000" ); /* wait for power up */ sleep(15); } } /* Autodetect an Online-USV (only Zinto D is known to work) */ r = optiquery( "IM" ); if ( r > 0 && !strcasecmp(_buf, "ONLINE") ) { optimodel = OPTIMODEL_ZINTO; optiquery( "Om11" ); optiquery( "Om21" ); optiquery( "ON" ); } /* Autodetect an Opti-UPS PS series */ r = optiquery( "IO" ); if ( r > 0 && !strncasecmp(_buf, "PS-", 3) ) { optimodel = OPTIMODEL_PS; } optifill( _initv, SIZEOF_ARRAY(_initv) ); /* Parse out model into longer string -- is this really USEFUL??? */ r = optiquery( "IO" ); if ( r < 1 ) fatal_with_errno(EXIT_FAILURE, "can't retrieve model" ); else { switch ( _buf[r-1] ) { case 'E': case 'P': case 'V': dstate_setinfo("ups.model", "Power%cS %s", _buf[r-1], _buf ); break; default: dstate_setinfo("ups.model", "%s", _buf ); break; } } /* Parse out model into longer string */ r = optiquery( "IM" ); if ( r > 0 && !strcasecmp(_buf, "ONLINE") ) { dstate_setinfo("ups.mfr", "ONLINE USV-Systeme AG"); r = optiquery( "IO" ); if ( r < 1 ) fatal_with_errno(EXIT_FAILURE, "can't retrieve model" ); switch ( _buf[0] ) { case 'D': dstate_setinfo("ups.model", "Zinto %s", _buf ); break; default: dstate_setinfo("ups.model", "%s", _buf ); break; } } dstate_addcmd("test.failure.start"); dstate_addcmd("load.off"); dstate_addcmd("load.on"); if( optimodel != OPTIMODEL_ZINTO ) dstate_addcmd("shutdown.stop"); dstate_addcmd("shutdown.return"); dstate_addcmd("shutdown.stayoff"); upsh.instcmd = instcmd; if ( optimodel == OPTIMODEL_ZINTO ) { dstate_setinfo("outlet.desc", "%s", "Main Outlet 1+2"); dstate_setinfo("outlet.1.desc", "%s", "Switchable Outlet 3+4"); dstate_setinfo("outlet.id", "%d", 1); dstate_setinfo("outlet.1.id", "%d", 2); dstate_setinfo("outlet.switchable", "%d", 0); dstate_setinfo("outlet.1.switchable", "%d", 1); dstate_setinfo("outlet.1.switch", "%d", 1); dstate_setflags("outlet.1.switch", ST_FLAG_RW | ST_FLAG_STRING); dstate_setaux("outlet.1.switch", 1); upsh.setvar = setvar; } } void upsdrv_updateinfo(void) { ssize_t r = optiquery( "AG" ); /* Online-UPS send only "2" when off, without "\r\n" */ if ( r < 1 && optimodel == OPTIMODEL_ZINTO ) { ser_send( upsfd, "AG\r\n" ); r = ser_get_char(upsfd, &_buf[0], 1, 0); if ( r == 1 && _buf[0] == '2' ) { status_init(); status_set("OFF"); status_commit(); return; } } if ( r < 1 ) { upslogx(LOG_ERR, "can't retrieve ups status" ); dstate_datastale(); } else { long s = strtol( _buf, NULL, 16 ); status_init(); if ( s & OPTISBIT_OVERLOAD ) status_set("OVER"); if ( s & OPTISBIT_REPLACE_BATTERY ) status_set("RB"); if ( s & OPTISBIT_ON_BATTERY_POWER ) status_set("OB"); else status_set("OL"); if ( s & OPTISBIT_NOOUTPUT ) status_set("OFF"); if ( s & OPTISBIT_LOW_BATTERY ) status_set("LB"); if ( testvar(OPTI_FAKELOW) ) /* FOR TESTING */ status_set("LB"); status_commit(); dstate_dataok(); } /* Get out of here now if minimum polling is desired */ if ( testvar(OPTI_MINPOLL) ) return; /* read some easy settings */ if ( optimodel == OPTIMODEL_ZINTO ) optifill( _pollv_zinto, SIZEOF_ARRAY(_pollv_zinto) ); else if ( optimodel == OPTIMODEL_PS ) { short inV, outV, fV; optifill( _pollv_ps, SIZEOF_ARRAY(_pollv_ps) ); r = optiquery( "NV" ); str_to_short ( _buf, &inV, 10 ); r = optiquery( "OV" ); str_to_short ( _buf, &outV, 10 ); r = optiquery( "FV" ); if ( r >= 1 ) { str_to_short ( _buf, &fV, 10 ); if ( fV > 180 ) { inV = inV * 2; outV = outV * 2; } } dstate_setinfo( "input.voltage", "%d", inV ); dstate_setinfo( "output.voltage", "%d", outV ); } else optifill( _pollv, SIZEOF_ARRAY(_pollv) ); /* Battery voltage is harder */ r = optiquery( "BV" ); if ( r < 1 ) upslogx( LOG_WARNING, "cannot retrieve battery voltage" ); else { float p, v = strtol( _buf, NULL, 10 ) / 10.0; dstate_setinfo("battery.voltage", "%.1f", v ); if (v > 20) { /* battery voltage range: 20.8 - 26.0 VDC */ p = ((v - 20.8) / 5.2) * 100.0; } else { /* battery voltage range: 10.4 - 13.0 VDC */ p = ((v - 10.4) / 2.6) * 100.0; } if ( p > 100.0 ) p = 100.0; dstate_setinfo("battery.charge", "%.1f", p ); } } void upsdrv_shutdown(void) { /* OL: this must power cycle the load if possible */ /* OB: the load must remain off until the power returns */ /* If get no response, assume on battery & battery low */ long s = OPTISBIT_ON_BATTERY_POWER | OPTISBIT_LOW_BATTERY; ssize_t r = optiquery( "AG" ); if ( r < 1 ) { upslogx(LOG_ERR, "can't retrieve ups status during shutdown" ); } else { s = strtol( _buf, NULL, 16 ); } /* Turn output stage back on if power returns - but really means * turn off ups if on battery */ optiquery( "Ct1" ); /* What happens, if the power comes back *after* reading the ups status and * before the shutdown command? For "Online-UPS Zinto D" *always* asking for * "shutdown shortly and power-up later" works perfectly, because it forces * a power cycle, even for the named race condition. * For Opti-UPS I have no information, so I wouldn't dare to change it. * BTW, Zinto expects only 7 digits after Cu/Cs. * (Matthias Goebl) */ if ( optimodel == OPTIMODEL_ZINTO ) { /* On line power: Power up in 60 seconds (30 seconds after the following shutdown) */ /* On battery: Power up when the line power returns */ optiquery( "Cu0000060" ); /* Shutdown in 30 seconds */ optiquery( "Cs0000030" ); return; } /* Just cycling power, schedule output stage to come back on in 60 seconds */ if ( !(s & OPTISBIT_ON_BATTERY_POWER) ) optiquery( "Cu00000600" ); /* Shutdown in 8 seconds */ optiquery( "Cs00000080" ); } void upsdrv_help(void) { printf(HELP); } /* list flags and values that you want to receive via -x */ void upsdrv_makevartable(void) { addvar(VAR_FLAG, OPTI_MINPOLL, "Only poll for critical status variables"); addvar(VAR_FLAG, OPTI_FAKELOW, "Fake a low battery status" ); addvar(VAR_FLAG, OPTI_NOWARN_NOIMP, "Suppress warnings of unsupported commands"); addvar(VAR_FLAG, OPTI_POWERUP, "(Zinto D) Power-up UPS at start (cannot identify a powered-down Zinto D)"); } void upsdrv_initups(void) { upsfd = ser_open(device_path); ser_set_speed(upsfd, device_path, B2400); /* NO PARSED COMMAND LINE VARIABLES */ } void upsdrv_cleanup(void) { ser_close(upsfd, device_path); } /******************************************* * COMMANDS THAT QUERY THE UPS ******************************************* * IM - manufacturer * IO - model * IS - firmware version * IZ - serial number <> (unsupported on 420E, returns ^U) * * BS - ??? returns <2> * BV - battery voltage (in deciVolts) <0140> * BT - battery temperature (deg C) <0033> (returns ^U on OptiUPS 420E) * * NF - input line frequency <600> * NV - input line voltage <116> * * OS - ?? return <3> * OF - output stage frequency (in 0.1 Hz) <600> * OV - output stage voltage <118> * OL - output stage load <027> * * FV - Input voltage <120> * FF - Input Frequency (0.1Hz) <600> * FO - Output volts <120> * FR - Output Frequency (0.1Hz) <600> * FA - Output VA <420> * FP - Ouptu power <252> * FU - ?? returns <2> * FB - ?? * FH - High Transfer Point <144> * FL - Low Transfer Point <093> * FT - Transfer point? <121> * * AG - UPS status (bitmapped ASCII hex value) <00> * bit 2: 1 = * bit 3: 1 = overload * bit 4: 1 = replace battery * bit 5: 1 = on battery, 0 = on line * bit 6: 1 = low battery * TR - Test results <00> * 00 = Unknown * 01 = Passed * 02 = Warning * 03 = Error * 04 = Aborted * 05 = In Progress * 06 = No test init * ******************************************* * ACTIONS ******************************************* * * Ts - Start test * Ct0 - set power down mode (when running on battery) * Ct0 = power down only ouput stage * Ct1 = complete power down * Cs00000000 - power down after delay (count in 0.1s) * Cs00000100 = power down in 10s * Cs-0000001 = cancel power down request * Cu00000000 - power down after delay (count in 0.1s) * Cu00000050 = power up in 5s * Cu00000000 = power up now * * CT - returns last setting passed to Ct command <0> * ******************************************* * UNKNOWN COMMANDS (on 420e anyways) ******************************************* * Fu * Fv * Ff * Fo * Fr * Fb * Fl * Fh */ nut-2.8.1/drivers/adelsystem_cbi.c0000644000175000017500000011627614502253356014104 00000000000000/* adelsystem_cbi.c - driver for ADELSYSTEM CB/CBI DC-UPS * * Copyright (C) * 2022 Dimitris Economou * * 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 2 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, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /* * code indentation with tabstop=4 */ #include "main.h" #include "adelsystem_cbi.h" #include #include #define DRIVER_NAME "NUT ADELSYSTEM DC-UPS CB/CBI driver" #define DRIVER_VERSION "0.02" /* variables */ static modbus_t *mbctx = NULL; /* modbus memory context */ static devstate_t *dstate = NULL; /* device state context */ static int errcnt = 0; /* modbus access error counter */ static char *device_mfr = DEVICE_MFR; /* device manufacturer */ static char *device_model = DEVICE_MODEL; /* device model */ static char *device_type = DEVICE_TYPE_STRING; /* device type (e.g. UPS, PDU...) */ static int ser_baud_rate = BAUD_RATE; /* serial port baud rate */ static char ser_parity = PARITY; /* serial port parity */ static int ser_data_bit = DATA_BIT; /* serial port data bit */ static int ser_stop_bit = STOP_BIT; /* serial port stop bit */ static int dev_slave_id = MODBUS_SLAVE_ID; /* set device ID to default value */ static uint32_t mod_resp_to_s = MODRESP_TIMEOUT_s; /* set the modbus response time out (s) */ static uint32_t mod_resp_to_us = MODRESP_TIMEOUT_us; /* set the modbus response time out (us) */ static uint32_t mod_byte_to_s = MODBYTE_TIMEOUT_s; /* set the modbus byte time out (us) */ static uint32_t mod_byte_to_us = MODBYTE_TIMEOUT_us; /* set the modbus byte time out (us) */ /* initialize alarm structs */ void alrminit(void); /* initialize register start address and hex address from register number */ void reginit(void); /* read registers' memory region */ int read_all_regs(modbus_t *mb, uint16_t *data); /* get config vars set by -x or defined in ups.conf driver section */ void get_config_vars(void); /* get device state */ int get_dev_state(devreg_t regindx, devstate_t **dvstat); /* create a new modbus context based on connection type (serial or TCP) */ modbus_t *modbus_new(const char *port); /* reconnect upon communication error */ void modbus_reconnect(void); /* modbus register read function */ int register_read(modbus_t *mb, int addr, regtype_t type, void *data); /* modbus register write function */ int register_write(modbus_t *mb, int addr, regtype_t type, void *data); /* instant command triggered by upsd */ int upscmd(const char *cmd, const char *arg); /* count the time elapsed since start */ long time_elapsed(struct timeval *start); /* driver description structure */ upsdrv_info_t upsdrv_info = { DRIVER_NAME, DRIVER_VERSION, "Dimitris Economou \n", DRV_BETA, {NULL} }; /* * driver functions */ /* read configuration variables from ups.conf and connect to ups device */ void upsdrv_initups(void) { int rval; upsdebugx(2, "upsdrv_initups"); dstate = (devstate_t *)xmalloc(sizeof(devstate_t)); alrminit(); reginit(); get_config_vars(); /* open communication port */ mbctx = modbus_new(device_path); if (mbctx == NULL) { fatalx(EXIT_FAILURE, "modbus_new_rtu: Unable to open communication port context"); } /* set slave ID */ rval = modbus_set_slave(mbctx, dev_slave_id); if (rval < 0) { modbus_free(mbctx); fatalx(EXIT_FAILURE, "modbus_set_slave: Invalid modbus slave ID %d", dev_slave_id); } /* connect to modbus device */ if (modbus_connect(mbctx) == -1) { modbus_free(mbctx); fatalx(EXIT_FAILURE, "modbus_connect: unable to connect: error(%s)", modbus_strerror(errno)); } /* set modbus response timeout */ #if (defined NUT_MODBUS_TIMEOUT_ARG_sec_usec_uint32) || (defined NUT_MODBUS_TIMEOUT_ARG_sec_usec_uint32_cast_timeval_fields) rval = modbus_set_response_timeout(mbctx, mod_resp_to_s, mod_resp_to_us); if (rval < 0) { modbus_free(mbctx); fatalx(EXIT_FAILURE, "modbus_set_response_timeout: error(%s)", modbus_strerror(errno)); } #elif (defined NUT_MODBUS_TIMEOUT_ARG_timeval_numeric_fields) { /* Older libmodbus API (with timeval), and we have * checked at configure time that we can put uint32_t * into its fields. They are probably "long" on many * systems as respectively time_t and suseconds_t - * but that is not guaranteed; for more details see * https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/sys_time.h.html */ struct timeval to; memset(&to, 0, sizeof(struct timeval)); to.tv_sec = mod_resp_to_s; to.tv_usec = mod_resp_to_us; /* void */ modbus_set_response_timeout(mbctx, &to); } /* #elif (defined NUT_MODBUS_TIMEOUT_ARG_timeval) // some un-castable type in fields */ #else # error "Can not use libmodbus API for timeouts" #endif /* NUT_MODBUS_TIMEOUT_ARG_* */ /* set modbus byte time out */ #if (defined NUT_MODBUS_TIMEOUT_ARG_sec_usec_uint32) || (defined NUT_MODBUS_TIMEOUT_ARG_sec_usec_uint32_cast_timeval_fields) rval = modbus_set_byte_timeout(mbctx, mod_byte_to_s, mod_byte_to_us); if (rval < 0) { modbus_free(mbctx); fatalx(EXIT_FAILURE, "modbus_set_byte_timeout: error(%s)", modbus_strerror(errno)); } #elif (defined NUT_MODBUS_TIMEOUT_ARG_timeval_numeric_fields) { /* see comments above */ struct timeval to; memset(&to, 0, sizeof(struct timeval)); to.tv_sec = mod_byte_to_s; to.tv_usec = mod_byte_to_us; /* void */ modbus_set_byte_timeout(mbctx, &to); } /* #elif (defined NUT_MODBUS_TIMEOUT_ARG_timeval) // some un-castable type in fields */ #endif /* NUT_MODBUS_TIMEOUT_ARG_* */ } /* initialize ups driver information */ void upsdrv_initinfo(void) { devstate_t *ds = dstate; /* device state context */ upsdebugx(2, "upsdrv_initinfo"); /* set device information */ dstate_setinfo("device.mfr", "%s", device_mfr); dstate_setinfo("device.model", "%s", device_model); dstate_setinfo("device.type", "%s", device_type); /* read ups model */ get_dev_state(PRDN, &ds); dstate_setinfo("ups.model", "%s", ds->product.name); upslogx(LOG_INFO, "ups.model = %s", ds->product.name); /* register instant commands */ dstate_addcmd("load.off"); /* set callback for instant commands */ upsh.instcmd = upscmd; } /* update UPS signal state */ void upsdrv_updateinfo(void) { int rval; /* return value */ int i; /* local index */ devstate_t *ds = dstate; /* device state */ upsdebugx(2, "upsdrv_updateinfo"); errcnt = 0; /* initialize error counter to zero */ status_init(); /* initialize ups.status update */ alarm_init(); /* initialize ups.alarm update */ #if READALL_REGS == 1 rval = read_all_regs(mbctx, regs_data); if (rval == -1) { errcnt++; } else { #endif /* * update UPS status regarding MAINS and SHUTDOWN request * - OL: On line (mains is present) * - OB: On battery (mains is not present) */ rval = get_dev_state(MAIN, &ds); if (rval == -1) { errcnt++; } else { if (ds->alrm->alrm[MAINS_AVAIL_I].actv) { status_set("OB"); alarm_set(mains->alrm[MAINS_AVAIL_I].descr); upslogx(LOG_INFO, "ups.status = OB"); } else { status_set("OL"); upslogx(LOG_INFO, "ups.status = OL"); } if (ds->alrm->alrm[SHUTD_REQST_I].actv) { status_set("FSD"); alarm_set(mains->alrm[SHUTD_REQST_I].descr); upslogx(LOG_INFO, "ups.status = FSD"); } } /* * update UPS status regarding battery voltage */ rval = get_dev_state(BVAL, &ds); if (rval == -1) { errcnt++; } else { if (ds->alrm->alrm[BVAL_LOALRM_I].actv) { status_set("LB"); alarm_set(bval->alrm[BVAL_LOALRM_I].descr); upslogx(LOG_INFO, "ups.status = LB"); } if (ds->alrm->alrm[BVAL_HIALRM_I].actv) { status_set("HB"); alarm_set(bval->alrm[BVAL_HIALRM_I].descr); upslogx(LOG_INFO, "ups.status = HB"); } if (ds->alrm->alrm[BVAL_BSTSFL_I].actv) { alarm_set(bval->alrm[BVAL_BSTSFL_I].descr); upslogx(LOG_INFO, "battery start with battery flat"); } } /* get "battery.voltage" */ rval = get_dev_state(BATV, &ds); if (rval == -1) { errcnt++; } else { dstate_setinfo("battery.voltage", "%s", ds->reg.strval); upslogx(LOG_DEBUG, "battery.voltage = %s", ds->reg.strval); } /* * update UPS status regarding battery charger status */ /* get "battery.charger.status" */ rval = get_dev_state(CHRG, &ds); if (rval == -1) { errcnt++; } else { if (ds->charge.state == CHRG_BULK || ds->charge.state == CHRG_ABSR) { status_set("CHRG"); upslogx(LOG_INFO, "ups.status = CHRG"); } dstate_setinfo("battery.charger.status", "%s", ds->charge.info); upslogx(LOG_DEBUG, "battery.charger.status = %s", ds->charge.info); } rval = get_dev_state(PMNG, &ds); if (rval == -1) { errcnt++; } else { if (ds->power.state == PMNG_BCKUP) { status_set("DISCHRG"); dstate_setinfo("battery.charger.status", "discharging"); upslogx(LOG_INFO, "ups.status = DISCHRG"); } if (ds->power.state == PMNG_BOOST) { status_set("BOOST"); upslogx(LOG_INFO, "ups.status = BOOST"); } } /* * update UPS battery state of charge */ rval = get_dev_state(BSOC, &ds); if (rval == -1) { errcnt++; } else { dstate_setinfo("battery.charge", "%s", ds->reg.strval); upslogx(LOG_DEBUG, "battery.charge = %s", ds->reg.strval); } /* * update UPS AC input state */ rval = get_dev_state(VACA, &ds); if (rval == -1) { errcnt++; } else { for (i = 0; i < ds->alrm->alrm_c; i++) { if (ds->alrm->alrm[i].actv) { alarm_set(ds->alrm->alrm[i].descr); upsdebugx(3, "%s is active", ds->alrm->alrm[i].descr); } } } rval = get_dev_state(VAC, &ds); if (rval == -1) { errcnt++; } else { dstate_setinfo("input.voltage", "%s", ds->reg.strval); upslogx(LOG_DEBUG, "input.voltage = %s", ds->reg.strval); } /* * update UPS onboard temperature state */ rval = get_dev_state(OBTA, &ds); if (rval == -1) { errcnt++; } else { for (i = 0; i < ds->alrm->alrm_c; i++) { if (ds->alrm->alrm[i].actv) { alarm_set(ds->alrm->alrm[i].descr); upsdebugx(3, "%s is active", ds->alrm->alrm[i].descr); } } } rval = get_dev_state(OTMP, &ds); if (rval == -1) { errcnt++; } else { dstate_setinfo("ups.temperature", "%s", ds->reg.strval); upslogx(LOG_DEBUG, "ups.temperature = %s", ds->reg.strval); } /* * update UPS battery temperature state */ rval = get_dev_state(BSTA, &ds); if (rval == -1) { errcnt++; } else { for (i = 0; i < ds->alrm->alrm_c; i++) { if (ds->alrm->alrm[i].actv) { alarm_set(ds->alrm->alrm[i].descr); upsdebugx(3, "%s alarm is active", ds->alrm->alrm[i].descr); } } } rval = get_dev_state(BTMP, &ds); if (rval == -1) { errcnt++; } else { dstate_setinfo("battery.temperature", "%s", ds->reg.strval); upslogx(LOG_DEBUG, "battery.temperature = %s", ds->reg.strval); } rval = get_dev_state(TBUF, &ds); if (rval == -1) { errcnt++; } else { dstate_setinfo("battery.runtime", "%s", ds->reg.strval); upslogx(LOG_DEBUG, "battery.runtime = %s", ds->reg.strval); } /* * update UPS device failure state */ rval = get_dev_state(DEVF, &ds); if (rval == -1) { errcnt++; } else { for (i = 0; i < ds->alrm->alrm_c; i++) { if (ds->alrm->alrm[i].actv) { alarm_set(ds->alrm->alrm[i].descr); upsdebugx(3, "%s alarm is active", ds->alrm->alrm[i].descr); } } } /* * update UPS SoH and SoC states */ rval = get_dev_state(SCSH, &ds); if (rval == -1) { errcnt++; } else { for (i = 0; i < ds->alrm->alrm_c; i++) { if (ds->alrm->alrm[i].actv) { alarm_set(ds->alrm->alrm[i].descr); upsdebugx(3, "%s alarm is active", ds->alrm->alrm[i].descr); } } } /* * update UPS battery state */ rval = get_dev_state(BSTA, &ds); if (rval == -1) { errcnt++; } else { for (i = 0; i < ds->alrm->alrm_c; i++) { if (ds->alrm->alrm[i].actv) { alarm_set(ds->alrm->alrm[i].descr); upsdebugx(3, "%s alarm is active", ds->alrm->alrm[i].descr); } } } /* * update UPS load status */ rval = get_dev_state(LVDC, &ds); if (rval == -1) { errcnt++; } else { dstate_setinfo("output.voltage", "%s", ds->reg.strval); upslogx(LOG_DEBUG, "output.voltage = %s", ds->reg.strval); } rval = get_dev_state(LCUR, &ds); if (rval == -1) { errcnt++; } else { dstate_setinfo("output.current", "%s", ds->reg.strval); upslogx(LOG_DEBUG, "output.current = %s", ds->reg.strval); } #if READALL_REGS == 1 } #endif /* check for communication errors */ if (errcnt == 0) { alarm_commit(); status_commit(); dstate_dataok(); } else { upsdebugx(2, "Communication errors: %d", errcnt); dstate_datastale(); } } /* shutdown UPS */ void upsdrv_shutdown(void) { int rval; int cnt = FSD_REPEAT_CNT; /* shutdown repeat counter */ struct timeval start; long etime; /* retry sending shutdown command on error */ while ((rval = upscmd("load.off", NULL)) != STAT_INSTCMD_HANDLED && cnt > 0) { rval = gettimeofday(&start, NULL); if (rval < 0) { upslogx(LOG_ERR, "upscmd: gettimeofday: %s", strerror(errno)); } /* wait for an increasing time interval before sending shutdown command */ while ((etime = time_elapsed(&start)) < ( FSD_REPEAT_INTRV / cnt)); upsdebugx(2, "ERROR: load.off failed, wait for %lims, retries left: %d\n", etime, cnt - 1); cnt--; } switch (rval) { case STAT_INSTCMD_FAILED: case STAT_INSTCMD_INVALID: fatalx(EXIT_FAILURE, "shutdown failed"); case STAT_INSTCMD_UNKNOWN: fatalx(EXIT_FAILURE, "shutdown not supported"); default: break; } upslogx(LOG_INFO, "shutdown command executed"); } /* print driver usage info */ void upsdrv_help(void) { } /* list flags and values that you want to receive via -x */ void upsdrv_makevartable(void) { addvar(VAR_VALUE, "ser_baud_rate", "serial port baud rate"); addvar(VAR_VALUE, "ser_parity", "serial port parity"); addvar(VAR_VALUE, "ser_data_bit", "serial port data bit"); addvar(VAR_VALUE, "ser_stop_bit", "serial port stop bit"); addvar(VAR_VALUE, "dev_slave_id", "device modbus slave ID"); addvar(VAR_VALUE, "mod_resp_to_s", "modbus response timeout (s)"); addvar(VAR_VALUE, "mod_resp_to_us", "modbus response timeout (us)"); addvar(VAR_VALUE, "mod_byte_to_s", "modbus byte timeout (s)"); addvar(VAR_VALUE, "mod_byte_to_us", "modbus byte timeout (us)"); } /* close modbus connection and free modbus context allocated memory */ void upsdrv_cleanup(void) { if (mbctx != NULL) { modbus_close(mbctx); modbus_free(mbctx); } if (dstate != NULL) { free(dstate); } } /* * driver support functions */ /* initialize alarm structs */ void alrminit(void) { mains = alloc_alrm_ar(mains_c, sizeof(mains_ar)); alrm_ar_init(mains, mains_ar, mains_c); vaca = alloc_alrm_ar(vaca_c, sizeof(vaca_ar)); alrm_ar_init(vaca, vaca_ar, vaca_c); devf = alloc_alrm_ar(devf_c, sizeof(devf_ar)); alrm_ar_init(devf, devf_ar, devf_c); btsf = alloc_alrm_ar(btsf_c, sizeof(btsf_ar)); alrm_ar_init(btsf, btsf_ar, btsf_c); bval = alloc_alrm_ar(bval_c, sizeof(bval_ar)); alrm_ar_init(bval, bval_ar, bval_c); shsc = alloc_alrm_ar(shsc_c, sizeof(shsc_ar)); alrm_ar_init(shsc, shsc_ar, shsc_c); bsta = alloc_alrm_ar(bsta_c, sizeof(bsta_ar)); alrm_ar_init(bsta, bsta_ar, bsta_c); obta = alloc_alrm_ar(obta_c, sizeof(obta_ar)); alrm_ar_init(obta, obta_ar, obta_c); } /* initialize register start address and hex address from register number */ void reginit(void) { int i; /* local index */ for (i = 0; i < MODBUS_NUMOF_REGS; i++) { int rnum = regs[i].num; switch (regs[i].type) { case COIL: regs[i].saddr = rnum - 1; regs[i].xaddr = 0x0 + regs[i].num - 1; break; case INPUT_B: rnum -= 10000; regs[i].saddr = rnum - 1; regs[i].xaddr = 0x10000 + rnum - 1; break; case INPUT_R: rnum -= 30000; regs[i].saddr = rnum - 1; regs[i].xaddr = 0x30000 + rnum - 1; break; case HOLDING: rnum -= 40000; regs[i].saddr = rnum - 1; regs[i].xaddr = 0x40000 + rnum - 1; break; #if (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_PUSH_POP) && ( (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_COVERED_SWITCH_DEFAULT) || (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_UNREACHABLE_CODE) ) # pragma GCC diagnostic push #endif #ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_COVERED_SWITCH_DEFAULT # pragma GCC diagnostic ignored "-Wcovered-switch-default" #endif #ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_UNREACHABLE_CODE # pragma GCC diagnostic ignored "-Wunreachable-code" #endif /* Older CLANG (e.g. clang-3.4) seems to not support the GCC pragmas above */ #ifdef __clang__ # pragma clang diagnostic push # pragma clang diagnostic ignored "-Wunreachable-code" # pragma clang diagnostic ignored "-Wcovered-switch-default" #endif /* All enum cases defined as of the time of coding * have been covered above. Handle later definitions, * memory corruptions and buggy inputs below... */ default: upslogx(LOG_ERR, "Invalid register type %d for register %d", regs[i].type, regs[i].num ); upsdebugx(3, "Invalid register type %d for register %d", regs[i].type, regs[i].num ); #ifdef __clang__ # pragma clang diagnostic pop #endif #if (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_PUSH_POP) && ( (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_COVERED_SWITCH_DEFAULT) || (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_UNREACHABLE_CODE) ) # pragma GCC diagnostic pop #endif } upsdebugx(3, "reginit: num:%d, type: %d saddr: %d, xaddr: 0x%x", regs[i].num, regs[i].type, regs[i].saddr, regs[i].xaddr ); } } /* read registers' memory region */ int read_all_regs(modbus_t *mb, uint16_t *data) { int rval; /* read all HOLDING registers */ rval = modbus_read_registers(mb, regs[H_REG_STARTIDX].xaddr, MAX_H_REGS, data); if (rval == -1) { upslogx(LOG_ERR, "ERROR:(%s) modbus_read: addr:0x%x, length:%8d, path:%s\n", modbus_strerror(errno), regs[H_REG_STARTIDX].xaddr, MAX_H_REGS, device_path ); /* on BROKEN PIPE, INVALID CRC and INVALID DATA error try to reconnect */ if (errno == EPIPE || errno == EMBBADDATA || errno == EMBBADCRC) { upsdebugx(1, "register_read: error(%s)", modbus_strerror(errno)); modbus_reconnect(); } } /* no COIL, INPUT_B or INPUT_R register regions to read */ return rval; } /* Read a modbus register */ int register_read(modbus_t *mb, int addr, regtype_t type, void *data) { int rval = -1; /* register bit masks */ uint16_t mask8 = 0x00FF; uint16_t mask16 = 0xFFFF; switch (type) { case COIL: rval = modbus_read_bits(mb, addr, 1, (uint8_t *)data); *(uint16_t *)data = *(uint16_t *)data & mask8; break; case INPUT_B: rval = modbus_read_input_bits(mb, addr, 1, (uint8_t *)data); *(uint16_t *)data = *(uint16_t *)data & mask8; break; case INPUT_R: rval = modbus_read_input_registers(mb, addr, 1, (uint16_t *)data); *(uint16_t *)data = *(uint16_t *)data & mask16; break; case HOLDING: rval = modbus_read_registers(mb, addr, 1, (uint16_t *)data); *(uint16_t *)data = *(uint16_t *)data & mask16; break; #if (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_PUSH_POP) && ( (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_COVERED_SWITCH_DEFAULT) || (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_UNREACHABLE_CODE) ) # pragma GCC diagnostic push #endif #ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_COVERED_SWITCH_DEFAULT # pragma GCC diagnostic ignored "-Wcovered-switch-default" #endif #ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_UNREACHABLE_CODE # pragma GCC diagnostic ignored "-Wunreachable-code" #endif /* Older CLANG (e.g. clang-3.4) seems to not support the GCC pragmas above */ #ifdef __clang__ # pragma clang diagnostic push # pragma clang diagnostic ignored "-Wunreachable-code" # pragma clang diagnostic ignored "-Wcovered-switch-default" #endif /* All enum cases defined as of the time of coding * have been covered above. Handle later definitions, * memory corruptions and buggy inputs below... */ default: upsdebugx(2,"ERROR: register_read: invalid register type %d\n", type); break; #ifdef __clang__ # pragma clang diagnostic pop #endif #if (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_PUSH_POP) && ( (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_COVERED_SWITCH_DEFAULT) || (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_UNREACHABLE_CODE) ) # pragma GCC diagnostic pop #endif } if (rval == -1) { upslogx(LOG_ERR, "ERROR:(%s) modbus_read: addr:0x%x, type:%8s, path:%s\n", modbus_strerror(errno), addr, (type == COIL) ? "COIL" : (type == INPUT_B) ? "INPUT_B" : (type == INPUT_R) ? "INPUT_R" : "HOLDING", device_path ); /* on BROKEN PIPE, INVALID CRC and INVALID DATA error try to reconnect */ if (errno == EPIPE || errno == EMBBADDATA || errno == EMBBADCRC) { upsdebugx(1, "register_read: error(%s)", modbus_strerror(errno)); modbus_reconnect(); } } upsdebugx(3, "register addr: 0x%x, register type: %d read: %u",addr, type, *(unsigned int *)data); return rval; } /* write a modbus register */ int register_write(modbus_t *mb, int addr, regtype_t type, void *data) { int rval = -1; /* register bit masks */ uint16_t mask8 = 0x00FF; uint16_t mask16 = 0xFFFF; switch (type) { case COIL: *(uint16_t *)data = *(uint16_t *)data & mask8; rval = modbus_write_bit(mb, addr, *(uint8_t *)data); break; case HOLDING: *(uint16_t *)data = *(uint16_t *)data & mask16; rval = modbus_write_register(mb, addr, *(uint16_t *)data); break; case INPUT_B: case INPUT_R: #if (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_PUSH_POP) && (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_COVERED_SWITCH_DEFAULT) # pragma GCC diagnostic push # pragma GCC diagnostic ignored "-Wcovered-switch-default" #endif /* All enum cases defined as of the time of coding * have been covered above. Handle later definitions, * memory corruptions and buggy inputs below... */ default: #if (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_PUSH_POP) && (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_COVERED_SWITCH_DEFAULT) # pragma GCC diagnostic pop #endif upsdebugx(2,"ERROR: register_write: invalid register type %d\n", type); break; } if (rval == -1) { upslogx(LOG_ERR, "ERROR:(%s) modbus_write: addr:0x%x, type:%8s, path:%s\n", modbus_strerror(errno), addr, (type == COIL) ? "COIL" : (type == INPUT_B) ? "INPUT_B" : (type == INPUT_R) ? "INPUT_R" : "HOLDING", device_path ); /* on BROKEN PIPE error try to reconnect */ if (errno == EPIPE) { upsdebugx(1, "register_write: error(%s)", modbus_strerror(errno)); modbus_reconnect(); } } upsdebugx(3, "register addr: 0x%x, register type: %d read: %u",addr, type, *(unsigned int *)data); return rval; } /* returns the time elapsed since start in milliseconds */ long time_elapsed(struct timeval *start) { long rval; struct timeval end; rval = gettimeofday(&end, NULL); if (rval < 0) { upslogx(LOG_ERR, "time_elapsed: %s", strerror(errno)); } if (start->tv_usec < end.tv_usec) { suseconds_t nsec = (end.tv_usec - start->tv_usec) / 1000000 + 1; end.tv_usec -= 1000000 * nsec; end.tv_sec += nsec; } if (start->tv_usec - end.tv_usec > 1000000) { suseconds_t nsec = (start->tv_usec - end.tv_usec) / 1000000; end.tv_usec += 1000000 * nsec; end.tv_sec -= nsec; } rval = (end.tv_sec - start->tv_sec) * 1000 + (end.tv_usec - start->tv_usec) / 1000; return rval; } /* instant command triggered by upsd */ int upscmd(const char *cmd, const char *arg) { int rval; int data; if (!strcasecmp(cmd, "load.off")) { data = 1; rval = register_write(mbctx, regs[FSD].xaddr, regs[FSD].type, &data); if (rval == -1) { upslogx(2, "ERROR:(%s) modbus_write_register: addr:0x%08x, regtype: %d, path:%s\n", modbus_strerror(errno), regs[FSD].xaddr, regs[FSD].type, device_path ); upslogx(LOG_NOTICE, "load.off: failed (communication error) [%s] [%s]", cmd, arg); rval = STAT_INSTCMD_FAILED; } else { upsdebugx(2, "load.off: addr: 0x%x, data: %d", regs[FSD].xaddr, data); rval = STAT_INSTCMD_HANDLED; } } else { upslogx(LOG_NOTICE, "instcmd: unknown command [%s] [%s]", cmd, arg); rval = STAT_INSTCMD_UNKNOWN; } return rval; } /* read device state, returns 0 on success or -1 on communication error it formats state depending on register semantics */ int get_dev_state(devreg_t regindx, devstate_t **dvstat) { int i; /* local index */ int n; int rval; /* return value */ static char *ptr = NULL; /* temporary pointer */ unsigned int reg_val; /* register value */ #if READALL_REGS == 0 unsigned int num; /* register number */ regtype_t rtype; /* register type */ int addr; /* register address */ #endif devstate_t *state; /* device state */ state = *dvstat; #if READALL_REGS == 1 reg_val = regs_data[regindx]; rval = 0; #elif READALL_REGS == 0 num = regs[regindx].num; addr = regs[regindx].xaddr; rtype = regs[regindx].type; rval = register_read(mbctx, addr, rtype, ®_val); if (rval == -1) { return rval; } upsdebugx(3, "get_dev_state: num: %d, addr: 0x%x, regtype: %d, data: %d", num, addr, rtype, reg_val ); #endif /* process register data */ switch (regindx) { case CHRG: /* "ups.charge" */ if (reg_val == CHRG_NONE) { state->charge.state = CHRG_NONE; state->charge.info = chrgs_i[CHRG_NONE]; } else if (reg_val == CHRG_RECV) { state->charge.state = CHRG_RECV; state->charge.info = chrgs_i[CHRG_RECV]; } else if (reg_val == CHRG_BULK) { state->charge.state = CHRG_BULK; state->charge.info = chrgs_i[CHRG_BULK]; } else if (reg_val == CHRG_ABSR) { state->charge.state = CHRG_ABSR; state->charge.info = chrgs_i[CHRG_ABSR]; } else if (reg_val == CHRG_FLOAT) { state->charge.state = CHRG_FLOAT; state->charge.info = chrgs_i[CHRG_FLOAT]; } upsdebugx(3, "get_dev_state: charge.state: %s", state->charge.info); break; case BATV: /* "battery.voltage" */ case LVDC: /* "output.voltage" */ case LCUR: /* "output.current" */ if (reg_val != 0) { char *fval_s; double fval; state->reg.val.ui16 = reg_val; fval = reg_val / 1000.00; /* convert mV to V, mA to A */ n = snprintf(NULL, 0, "%.2f", fval); if (ptr != NULL) { free(ptr); } fval_s = (char *)xmalloc(sizeof(char) * (n + 1)); ptr = fval_s; sprintf(fval_s, "%.2f", fval); state->reg.strval = fval_s; } else { state->reg.val.ui16 = 0; state->reg.strval = "0.00"; } upsdebugx(3, "get_dev_state: variable: %s", state->reg.strval); break; case TBUF: case BSOH: case BCEF: case VAC: /* "input.voltage" */ if (reg_val != 0) { char *reg_val_s; state->reg.val.ui16 = reg_val; n = snprintf(NULL, 0, "%d", reg_val); if (ptr != NULL) { free(ptr); } reg_val_s = (char *)xmalloc(sizeof(char) * (n + 1)); ptr = reg_val_s; sprintf(reg_val_s, "%d", reg_val); state->reg.strval = reg_val_s; } else { state->reg.val.ui16 = 0; state->reg.strval = "0"; } upsdebugx(3, "get_dev_state: variable: %s", state->reg.strval); break; case BSOC: /* "battery.charge" */ if (reg_val != 0) { double fval; char *fval_s; state->reg.val.ui16 = reg_val; fval = (double )reg_val * regs[BSOC].scale; n = snprintf(NULL, 0, "%.2f", fval); if (ptr != NULL) { free(ptr); } fval_s = (char *)xmalloc(sizeof(char) * (n + 1)); ptr = fval_s; sprintf(fval_s, "%.2f", fval); state->reg.strval = fval_s; } else { state->reg.val.ui16 = 0; state->reg.strval = "0.00"; } upsdebugx(3, "get_dev_state: variable: %s", state->reg.strval); break; case BTMP: /* "battery.temperature" */ case OTMP: /* "ups.temperature" */ { /* scoping */ double fval; char *fval_s; state->reg.val.ui16 = reg_val; fval = reg_val - 273.15; n = snprintf(NULL, 0, "%.2f", fval); fval_s = (char *)xmalloc(sizeof(char) * (n + 1)); if (ptr != NULL) { free(ptr); } ptr = fval_s; sprintf(fval_s, "%.2f", fval); state->reg.strval = fval_s; } upsdebugx(3, "get_dev_state: variable: %s", state->reg.strval); break; case PMNG: /* "ups.status" & "battery.charge" */ if (reg_val == PMNG_BCKUP) { state->power.state = PMNG_BCKUP; state->power.info = pwrmng_i[PMNG_BCKUP]; } else if (reg_val == PMNG_CHRGN) { state->power.state = PMNG_CHRGN; state->power.info = pwrmng_i[PMNG_CHRGN]; } else if (reg_val == PMNG_BOOST) { state->power.state = PMNG_BOOST; state->power.info = pwrmng_i[PMNG_BOOST]; } else if (reg_val == PMNG_NCHRG) { state->power.state = PMNG_NCHRG; state->power.info = pwrmng_i[PMNG_NCHRG]; } upsdebugx(3, "get_dev_state: power.state: %s", state->reg.strval); break; case PRDN: /* "ups.model" */ for (i = 0; i < DEV_NUMOF_MODELS; i++) { if (prdnm_i[i].val == reg_val) { break; } } state->product.val = reg_val; state->product.name = prdnm_i[i].name; upsdebugx(3, "get_dev_state: product.name: %s", state->product.name); break; case BSTA: if (reg_val & BSTA_REVPOL_M) { bsta->alrm[BSTA_REVPOL_I].actv = 1; } else { bsta->alrm[BSTA_REVPOL_I].actv = 0; } if (reg_val & BSTA_NOCNND_M) { bsta->alrm[BSTA_NOCNND_I].actv = 1; } else { bsta->alrm[BSTA_NOCNND_I].actv = 0; } if (reg_val & BSTA_CLSHCR_M) { bsta->alrm[BSTA_CLSHCR_I].actv = 1; } else { bsta->alrm[BSTA_CLSHCR_I].actv = 0; } if (reg_val & BSTA_SULPHD_M) { bsta->alrm[BSTA_SULPHD_I].actv = 1; } else { bsta->alrm[BSTA_SULPHD_I].actv = 0; } if (reg_val & BSTA_CHEMNS_M) { bsta->alrm[BSTA_CHEMNS_I].actv = 1; } else { bsta->alrm[BSTA_CHEMNS_I].actv = 0; } if (reg_val & BSTA_CNNFLT_M) { bsta->alrm[BSTA_CNNFLT_I].actv = 1; } else { bsta->alrm[BSTA_CNNFLT_I].actv = 0; } state->alrm = bsta; break; case SCSH: if (reg_val & SHSC_HIRESI_M) { shsc->alrm[SHSC_HIRESI_I].actv = 1; } else { shsc->alrm[SHSC_HIRESI_I].actv = 0; } if (reg_val & SHSC_LOCHEF_M) { shsc->alrm[SHSC_LOCHEF_I].actv = 1; } else { shsc->alrm[SHSC_LOCHEF_I].actv = 0; } if (reg_val & SHSC_LOEFCP_M) { shsc->alrm[SHSC_LOEFCP_I].actv = 1; } else { shsc->alrm[SHSC_LOEFCP_I].actv = 0; } if (reg_val & SHSC_LOWSOC_M) { shsc->alrm[SHSC_LOWSOC_I].actv = 1; } else { shsc->alrm[SHSC_LOWSOC_I].actv = 0; } state->alrm = shsc; break; case BVAL: if (reg_val & BVAL_HIALRM_M) { bval->alrm[BVAL_HIALRM_I].actv = 1; } else { bval->alrm[BVAL_HIALRM_I].actv = 0; } if (reg_val & BVAL_LOALRM_M) { bval->alrm[BVAL_LOALRM_I].actv = 1; } else { bval->alrm[BVAL_LOALRM_I].actv = 0; } if (reg_val & BVAL_BSTSFL_M) { bval->alrm[BVAL_BSTSFL_I].actv = 1; } else { bval->alrm[BVAL_BSTSFL_I].actv = 0; } state->alrm = bval; break; case BTSF: if (reg_val & BTSF_FCND_M) { btsf->alrm[BTSF_FCND_I].actv = 1; } else { btsf->alrm[BTSF_FCND_I].actv = 0; } if (reg_val & BTSF_NCND_M) { btsf->alrm[BTSF_NCND_I].actv = 1; } else { btsf->alrm[BTSF_NCND_I].actv = 0; } state->alrm = btsf; break; case DEVF: if (reg_val & DEVF_RCALRM_M) { devf->alrm[DEVF_RCALRM_I].actv = 1; } else { devf->alrm[DEVF_RCALRM_I].actv = 0; } if (reg_val & DEVF_INALRM_M) { devf->alrm[DEVF_INALRM_I].actv = 1; } else { devf->alrm[DEVF_INALRM_I].actv = 0; } if (reg_val & DEVF_LFNAVL_M) { devf->alrm[DEVF_LFNAVL_I].actv = 1; } else { devf->alrm[DEVF_LFNAVL_I].actv = 0; } state->alrm = devf; break; case VACA: if (reg_val & VACA_HIALRM_M) { vaca->alrm[VACA_HIALRM_I].actv = 1; } else { vaca->alrm[VACA_HIALRM_I].actv = 0; } if (reg_val == VACA_LOALRM_M) { vaca->alrm[VACA_LOALRM_I].actv = 1; } else { vaca->alrm[VACA_LOALRM_I].actv = 0; } state->alrm = vaca; break; case MAIN: if (reg_val & MAINS_AVAIL_M) { mains->alrm[MAINS_AVAIL_I].actv = 1; } else { mains->alrm[MAINS_AVAIL_I].actv = 0; } if (reg_val == SHUTD_REQST_M) { mains->alrm[SHUTD_REQST_I].actv = 1; } else { mains->alrm[SHUTD_REQST_I].actv = 0; } state->alrm = mains; break; case OBTA: if (reg_val == OBTA_HIALRM_V) { obta->alrm[OBTA_HIALRM_I].actv = 1; } state->alrm = obta; break; case BINH: case FSD: break; #if (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_PUSH_POP) && ( (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_COVERED_SWITCH_DEFAULT) || (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_UNREACHABLE_CODE) ) # pragma GCC diagnostic push #endif #ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_COVERED_SWITCH_DEFAULT # pragma GCC diagnostic ignored "-Wcovered-switch-default" #endif #ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_UNREACHABLE_CODE # pragma GCC diagnostic ignored "-Wunreachable-code" #endif /* Older CLANG (e.g. clang-3.4) seems to not support the GCC pragmas above */ #ifdef __clang__ # pragma clang diagnostic push # pragma clang diagnostic ignored "-Wunreachable-code" # pragma clang diagnostic ignored "-Wcovered-switch-default" #endif /* All enum cases defined as of the time of coding * have been covered above. Handle later definitions, * memory corruptions and buggy inputs below... */ default: { /* scoping */ char *reg_val_s; state->reg.val.ui16 = reg_val; n = snprintf(NULL, 0, "%d", reg_val); if (ptr != NULL) { free(ptr); } reg_val_s = (char *)xmalloc(sizeof(char) * (n + 1)); ptr = reg_val_s; sprintf(reg_val_s, "%d", reg_val); state->reg.strval = reg_val_s; } break; #ifdef __clang__ # pragma clang diagnostic pop #endif #if (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_PUSH_POP) && ( (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_COVERED_SWITCH_DEFAULT) || (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_UNREACHABLE_CODE) ) # pragma GCC diagnostic pop #endif } return rval; } /* get driver configuration parameters */ void get_config_vars(void) { /* check if serial baud rate is set and get the value */ if (testvar("ser_baud_rate")) { ser_baud_rate = (int)strtol(getval("ser_baud_rate"), NULL, 10); } upsdebugx(2, "ser_baud_rate %d", ser_baud_rate); /* check if serial parity is set and get the value */ if (testvar("ser_parity")) { /* Dereference the char* we get */ char *sp = getval("ser_parity"); if (sp) { /* TODO? Sanity-check the char we get? */ ser_parity = *sp; } else { upsdebugx(2, "Could not determine ser_parity, will keep default"); } } upsdebugx(2, "ser_parity %c", ser_parity); /* check if serial data bit is set and get the value */ if (testvar("ser_data_bit")) { ser_data_bit = (int)strtol(getval("ser_data_bit"), NULL, 10); } upsdebugx(2, "ser_data_bit %d", ser_data_bit); /* check if serial stop bit is set and get the value */ if (testvar("ser_stop_bit")) { ser_stop_bit = (int)strtol(getval("ser_stop_bit"), NULL, 10); } upsdebugx(2, "ser_stop_bit %d", ser_stop_bit); /* check if device ID is set and get the value */ if (testvar("dev_slave_id")) { dev_slave_id = (int)strtol(getval("dev_slave_id"), NULL, 10); } upsdebugx(2, "dev_slave_id %d", dev_slave_id); /* check if response time out (s) is set and get the value */ if (testvar("mod_resp_to_s")) { mod_resp_to_s = (uint32_t)strtol(getval("mod_resp_to_s"), NULL, 10); } upsdebugx(2, "mod_resp_to_s %d", mod_resp_to_s); /* check if response time out (us) is set and get the value */ if (testvar("mod_resp_to_us")) { mod_resp_to_us = (uint32_t) strtol(getval("mod_resp_to_us"), NULL, 10); if (mod_resp_to_us > 999999) { fatalx(EXIT_FAILURE, "get_config_vars: Invalid mod_resp_to_us %d", mod_resp_to_us); } } upsdebugx(2, "mod_resp_to_us %d", mod_resp_to_us); /* check if byte time out (s) is set and get the value */ if (testvar("mod_byte_to_s")) { mod_byte_to_s = (uint32_t)strtol(getval("mod_byte_to_s"), NULL, 10); } upsdebugx(2, "mod_byte_to_s %d", mod_byte_to_s); /* check if byte time out (us) is set and get the value */ if (testvar("mod_byte_to_us")) { mod_byte_to_us = (uint32_t) strtol(getval("mod_byte_to_us"), NULL, 10); if (mod_byte_to_us > 999999) { fatalx(EXIT_FAILURE, "get_config_vars: Invalid mod_byte_to_us %d", mod_byte_to_us); } } upsdebugx(2, "mod_byte_to_us %d", mod_byte_to_us); } /* create a new modbus context based on connection type (serial or TCP) */ modbus_t *modbus_new(const char *port) { modbus_t *mb; char *sp; if (strstr(port, "/dev/tty") != NULL) { mb = modbus_new_rtu(port, ser_baud_rate, ser_parity, ser_data_bit, ser_stop_bit); if (mb == NULL) { upslogx(LOG_ERR, "modbus_new_rtu: Unable to open serial port context\n"); } } else if ((sp = strchr(port, ':')) != NULL) { char *tcp_port = xmalloc(sizeof(sp)); strcpy(tcp_port, sp + 1); *sp = '\0'; mb = modbus_new_tcp(port, (int)strtoul(tcp_port, NULL, 10)); if (mb == NULL) { upslogx(LOG_ERR, "modbus_new_tcp: Unable to connect to %s\n", port); } free(tcp_port); } else { mb = modbus_new_tcp(port, 502); if (mb == NULL) { upslogx(LOG_ERR, "modbus_new_tcp: Unable to connect to %s\n", port); } } return mb; } /* reconnect to modbus server upon connection error */ void modbus_reconnect(void) { int rval; upsdebugx(1, "modbus_reconnect, trying to reconnect to modbus server"); dstate_setinfo("driver.state", "reconnect.trying"); /* clear current modbus context */ modbus_close(mbctx); modbus_free(mbctx); /* open communication port */ mbctx = modbus_new(device_path); if (mbctx == NULL) { fatalx(EXIT_FAILURE, "modbus_new_rtu: Unable to open communication port context"); } /* set slave ID */ rval = modbus_set_slave(mbctx, dev_slave_id); if (rval < 0) { modbus_free(mbctx); fatalx(EXIT_FAILURE, "modbus_set_slave: Invalid modbus slave ID %d", dev_slave_id); } /* connect to modbus device */ if (modbus_connect(mbctx) == -1) { modbus_free(mbctx); fatalx(EXIT_FAILURE, "modbus_connect: unable to connect: %s", modbus_strerror(errno)); } /* set modbus response timeout */ #if (defined NUT_MODBUS_TIMEOUT_ARG_sec_usec_uint32) || (defined NUT_MODBUS_TIMEOUT_ARG_sec_usec_uint32_cast_timeval_fields) rval = modbus_set_response_timeout(mbctx, mod_resp_to_s, mod_resp_to_us); if (rval < 0) { modbus_free(mbctx); fatalx(EXIT_FAILURE, "modbus_set_response_timeout: error(%s)", modbus_strerror(errno)); } #elif (defined NUT_MODBUS_TIMEOUT_ARG_timeval_numeric_fields) { /* see comments above */ struct timeval to; memset(&to, 0, sizeof(struct timeval)); to.tv_sec = mod_resp_to_s; to.tv_usec = mod_resp_to_us; /* void */ modbus_set_response_timeout(mbctx, &to); } /* #elif (defined NUT_MODBUS_TIMEOUT_ARG_timeval) // some un-castable type in fields */ #endif /* NUT_MODBUS_TIMEOUT_ARG_* */ /* set modbus byte timeout */ #if (defined NUT_MODBUS_TIMEOUT_ARG_sec_usec_uint32) || (defined NUT_MODBUS_TIMEOUT_ARG_sec_usec_uint32_cast_timeval_fields) rval = modbus_set_byte_timeout(mbctx, mod_byte_to_s, mod_byte_to_us); if (rval < 0) { modbus_free(mbctx); fatalx(EXIT_FAILURE, "modbus_set_byte_timeout: error(%s)", modbus_strerror(errno)); } #elif (defined NUT_MODBUS_TIMEOUT_ARG_timeval_numeric_fields) { /* see comments above */ struct timeval to; memset(&to, 0, sizeof(struct timeval)); to.tv_sec = mod_byte_to_s; to.tv_usec = mod_byte_to_us; /* void */ modbus_set_byte_timeout(mbctx, &to); } /* #elif (defined NUT_MODBUS_TIMEOUT_ARG_timeval) // some un-castable type in fields */ #endif /* NUT_MODBUS_TIMEOUT_ARG_* */ dstate_setinfo("driver.state", "quiet"); } nut-2.8.1/drivers/snmp-ups.c0000644000175000017500000041263514506754403012700 00000000000000/* snmp-ups.c - NUT Generic SNMP driver core (supports different MIBs) * * Based on NetSNMP API (Simple Network Management Protocol v1-2c-3) * * Copyright (C) * 2002 - 2014 Arnaud Quette * 2015 - 2022 Eaton (author: Arnaud Quette ) * 2016 - 2022 Eaton (author: Jim Klimov ) * 2002 - 2006 Dmitry Frolov * J.W. Hoogervorst * Niels Baggesen * 2009 - 2010 Arjen de Korte * * Sponsored by Eaton * and originally by MGE UPS SYSTEMS * * 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 2 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, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /* NUT SNMP common functions */ #include "main.h" /* includes "config.h" which must be the first header */ #include "nut_float.h" #include "nut_stdint.h" #include "snmp-ups.h" #include "parseconf.h" #include /* for isprint() */ /* include all known mib2nut lookup tables */ #include "apc-mib.h" #include "mge-mib.h" #include "netvision-mib.h" #include "eaton-pdu-genesis2-mib.h" #include "eaton-pdu-marlin-mib.h" #include "eaton-pdu-pulizzi-mib.h" #include "eaton-pdu-revelation-mib.h" #include "raritan-pdu-mib.h" #include "raritan-px2-mib.h" #include "baytech-mib.h" #include "compaq-mib.h" #include "bestpower-mib.h" #include "cyberpower-mib.h" #include "delta_ups-mib.h" #include "huawei-mib.h" #include "ietf-mib.h" #include "xppc-mib.h" #include "eaton-ats16-nmc-mib.h" #include "eaton-ats16-nm2-mib.h" #include "apc-ats-mib.h" #include "apc-pdu-mib.h" #include "apc-epdu-mib.h" #include "eaton-ats30-mib.h" #include "emerson-avocent-pdu-mib.h" #include "hpe-pdu-mib.h" #include "hpe-pdu3-cis-mib.h" #include "eaton-pdu-nlogic-mib.h" #include "eaton-ups-pwnm2-mib.h" #include "eaton-ups-pxg-mib.h" /* Address API change */ #if ( ! NUT_HAVE_LIBNETSNMP_usmAESPrivProtocol ) && ( ! defined usmAESPrivProtocol ) #define usmAESPrivProtocol usmAES128PrivProtocol #endif #ifdef USM_PRIV_PROTO_AES_LEN # define NUT_securityPrivProtoLen USM_PRIV_PROTO_AES_LEN #else # ifdef USM_PRIV_PROTO_AES128_LEN # define NUT_securityPrivProtoLen USM_PRIV_PROTO_AES128_LEN # else /* FIXME: Find another way to get the size of array(?) to avoid: * error: division 'sizeof (oid * {aka long unsigned int *}) / sizeof (oid {aka long unsigned int})' does not compute the number of array elements [-Werror=sizeof-pointer-div] * See also https://bugs.php.net/bug.php?id=37564 for context * which is due to most values in /usr/include/net-snmp/librarytransform_oids.h * being defined as "oid[10]" or similar arrays, and "backwards compatibility" * usmAESPrivProtocol name is an "oid *" pointer. */ # define NUT_securityPrivProtoLen (sizeof(usmAESPrivProtocol)/sizeof(oid)) # endif #endif static mib2nut_info_t *mib2nut[] = { &apc_ats, /* This struct comes from : apc-ats-mib.c */ &apc_pdu_rpdu, /* This struct comes from : apc-pdu-mib.c */ &apc_pdu_rpdu2, /* This struct comes from : apc-pdu-mib.c */ &apc_pdu_msp, /* This struct comes from : apc-pdu-mib.c */ &apc_pdu_epdu, /* This struct comes from : apc-epdu-mib.c */ &apc, /* This struct comes from : apc-mib.c */ &baytech, /* This struct comes from : baytech-mib.c */ &bestpower, /* This struct comes from : bestpower-mib.c */ &compaq, /* This struct comes from : compaq-mib.c */ &cyberpower, /* This struct comes from : cyberpower-mib.c */ &cyberpower2, /* This struct comes from : cyberpower-mib.c */ &delta_ups, /* This struct comes from : delta_ups-mib.c */ &eaton_ats16_nmc, /* This struct comes from : eaton-ats16-nmc-mib.c */ &eaton_ats16_nm2, /* This struct comes from : eaton-ats16-nm2-mib.c */ &eaton_ats30, /* This struct comes from : eaton-ats30-mib.c */ &eaton_marlin, /* This struct comes from : eaton-mib.c */ &eaton_pdu_nlogic, /* This struct comes from : eaton-pdu-nlogic-mib.c */ &eaton_pxg_ups, /* This struct comes from : eaton-ups-pxg-mib.c */ &eaton_pw_nm2, /* This struct comes from : eaton-ups-pwnm2-mib.c */ &emerson_avocent_pdu, /* This struct comes from : emerson-avocent-pdu-mib.c */ &aphel_revelation, /* This struct comes from : eaton-mib.c */ &aphel_genesisII, /* This struct comes from : eaton-mib.c */ &pulizzi_switched1, /* This struct comes from : eaton-mib.c */ &pulizzi_switched2, /* This struct comes from : eaton-mib.c */ &hpe_pdu, /* This struct comes from : hpe-pdu-mib.c */ &hpe_pdu3_cis, /* This struct comes from : hpe-pdu3-cis-mib.c */ &huawei, /* This struct comes from : huawei-mib.c */ &mge, /* This struct comes from : mge-mib.c */ &netvision, /* This struct comes from : netvision-mib.c */ &raritan, /* This struct comes from : raritan-pdu-mib.c */ &raritan_px2, /* This struct comes from : raritan-px2-mib.c */ &xppc, /* This struct comes from : xppc-mib.c */ /* * Prepend vendor specific MIB mappings before IETF, so that * if a device supports both IETF and vendor specific MIB, * the vendor specific one takes precedence (when mibs=auto) */ &tripplite_ietf, /* This struct comes from : ietf-mib.c */ &ietf, /* This struct comes from : ietf-mib.c */ /* end of structure. */ NULL }; struct snmp_session g_snmp_sess, *g_snmp_sess_p; const char *OID_pwr_status; int g_pwr_battery; int pollfreq; /* polling frequency */ int semistaticfreq; /* semistatic entry update frequency */ static int semistatic_countdown = 0; static int quirk_symmetra_threephase = 0; /* Number of device(s): standard is "1", but talking * to a daisychain (master device) means more than 1 * (a directly addressable member of a daisy chain * would be seen as a single-device chain though) */ static long devices_count = 1; /* global var to handle daisychain iterations - * changed by loops in snmp_ups_walk() and su_addcmd(); * may be 0 for addressing certain values/commands * across all chain devices via master (1); * also may be 0 for non-daisychained devices */ static int current_device_number = 0; /* global var to handle daisychain iterations - * made TRUE if we resolved a "device.count" value */ static bool_t daisychain_enabled = FALSE; static daisychain_info_t **daisychain_info = NULL; /* pointer to the Snmp2Nut lookup table */ mib2nut_info_t *mib2nut_info; /* FIXME: to be trashed */ snmp_info_t *snmp_info; alarms_info_t *alarms_info; static const char *mibname; static const char *mibvers; #define DRIVER_NAME "Generic SNMP UPS driver" #define DRIVER_VERSION "1.30" /* driver description structure */ upsdrv_info_t upsdrv_info = { DRIVER_NAME, DRIVER_VERSION, "Arnaud Quette \n" \ "Arnaud Quette \n" \ "Dmitry Frolov \n" \ "J.W. Hoogervorst \n" \ "Niels Baggesen \n" \ "Jim Klimov \n" \ "Arjen de Korte ", DRV_STABLE, { NULL } }; /* FIXME: integrate MIBs info? do the same as for usbhid-ups! */ static time_t lastpoll = 0; /* Communication status handling */ #define COMM_UNKNOWN 0 #define COMM_OK 1 #define COMM_LOST 2 static int comm_status = COMM_UNKNOWN; /* template OIDs index start with 0 or 1 (estimated stable for a MIB), * automatically guessed at the first pass */ static int template_index_base = -1; /* Not that stable in the end... */ static int device_template_index_base = -1; /* OID index of the 1rst daisychained device */ static int outlet_template_index_base = -1; static int outletgroup_template_index_base = -1; static int ambient_template_index_base = -1; static int device_template_offset = -1; /* sysOID location */ #define SYSOID_OID ".1.3.6.1.2.1.1.2.0" /* Forward functions declarations */ static void disable_transfer_oids(void); bool_t get_and_process_data(int mode, snmp_info_t *su_info_p); int extract_template_number(snmp_info_flags_t template_type, const char* varname); snmp_info_flags_t get_template_type(const char* varname); /* --------------------------------------------- * driver functions implementations * --------------------------------------------- */ void upsdrv_initinfo(void) { snmp_info_t *su_info_p; upsdebugx(1, "SNMP UPS driver: entering %s()", __func__); dstate_setinfo("driver.version.data", "%s MIB %s", mibname, mibvers); if (snmp_info == NULL) { fatalx(EXIT_FAILURE, "%s: snmp_info is not initialized", __func__); } if (snmp_info[0].info_type == NULL) { upsdebugx(1, "%s: WARNING: snmp_info is empty", __func__); } /* add instant commands to the info database. * outlet (and groups) commands are processed later, during initial walk */ for (su_info_p = &snmp_info[0]; (su_info_p != NULL && su_info_p->info_type != NULL) ; su_info_p++) { if (su_info_p->flags == 0UL) { upsdebugx(4, "SNMP UPS driver: %s: MIB2NUT mapping '%s' (OID '%s') did not define flags bits. " "Entry would be treated as SU_FLAG_OK if available in returned data.", __func__, (su_info_p->info_type ? su_info_p->info_type : ""), (su_info_p->OID ? su_info_p->OID : "") ); /* Treat as OK if avail, otherwise discarded */ } su_info_p->flags |= SU_FLAG_OK; if ((SU_TYPE(su_info_p) == SU_TYPE_CMD) && !(su_info_p->flags & SU_OUTLET) && !(su_info_p->flags & SU_OUTLET_GROUP)) { /* first check that this OID actually exists */ /* FIXME: daisychain commands support! */ su_addcmd(su_info_p); /* if (nut_snmp_get(su_info_p->OID) != NULL) { dstate_addcmd(su_info_p->info_type); upsdebugx(1, "upsdrv_initinfo(): adding command '%s'", su_info_p->info_type); } */ } } if (testvar("notransferoids")) disable_transfer_oids(); if (testvar("symmetrathreephase")) quirk_symmetra_threephase = 1; else quirk_symmetra_threephase = 0; /* initialize all other INFO_ fields from list */ if (snmp_ups_walk(SU_WALKMODE_INIT) == TRUE) { dstate_dataok(); comm_status = COMM_OK; } else { dstate_datastale(); comm_status = COMM_LOST; } /* setup handlers for instcmd and setvar functions */ upsh.setvar = su_setvar; upsh.instcmd = su_instcmd; } void upsdrv_updateinfo(void) { upsdebugx(1,"SNMP UPS driver: entering %s()", __func__); /* only update every pollfreq */ /* FIXME: only update status (SU_STATUS_*), à la usbhid-ups, in between */ if (time(NULL) > (lastpoll + pollfreq)) { alarm_init(); status_init(); /* update all dynamic info fields */ if (snmp_ups_walk(SU_WALKMODE_UPDATE)) { upsdebugx(1, "%s: pollfreq: Data OK", __func__); dstate_dataok(); comm_status = COMM_OK; } else { upsdebugx(1, "%s: pollfreq: Data STALE", __func__); dstate_datastale(); comm_status = COMM_LOST; } /* Commit status first, otherwise in daisychain mode, "device.0" may * clear the alarm count since it has an empty alarm buffer and if there * is only one device that has alarms! */ if (daisychain_enabled == FALSE) alarm_commit(); status_commit(); if (daisychain_enabled == TRUE) alarm_commit(); /* store timestamp */ lastpoll = time(NULL); } else { /* Just tell the same status to upsd */ if (comm_status == COMM_OK) dstate_dataok(); else dstate_datastale(); } } void upsdrv_shutdown(void) { /* This driver will probably never support this. In order to be any use, the driver should be called near the end of the system halt script. By that time we in all likelyhood we won't have network capabilities anymore, so we could never send this command to the UPS. This is not an error, but a limitation of the interface used. */ upsdebugx(1, "%s...", __func__); /* set shutdown and autostart delay */ set_delays(); /* Try to shutdown with delay */ if (su_instcmd("shutdown.return", NULL) == STAT_INSTCMD_HANDLED) { /* Shutdown successful */ return; } /* If the above doesn't work, try shutdown.reboot */ if (su_instcmd("shutdown.reboot", NULL) == STAT_INSTCMD_HANDLED) { /* Shutdown successful */ return; } /* If the above doesn't work, try load.off.delay */ if (su_instcmd("load.off.delay", NULL) == STAT_INSTCMD_HANDLED) { /* Shutdown successful */ return; } upslogx(LOG_ERR, "Shutdown failed!"); set_exit_flag(-1); } void upsdrv_help(void) { upsdebugx(1, "entering %s", __func__); } /* list flags and values that you want to receive via -x */ void upsdrv_makevartable(void) { upsdebugx(1, "entering %s()", __func__); addvar(VAR_VALUE, SU_VAR_MIBS, "NOTE: You can run the driver binary with '-x mibs=--list' for an up to date listing)\n" "Set MIB compliance (default=ietf, allowed: mge,apcc,netvision,pw,cpqpower,...)"); addvar(VAR_VALUE | VAR_SENSITIVE, SU_VAR_COMMUNITY, "Set community name (default=public)"); addvar(VAR_VALUE, SU_VAR_VERSION, "Set SNMP version (default=v1, allowed: v2c,v3)"); addvar(VAR_VALUE, SU_VAR_POLLFREQ, "Set polling frequency in seconds, to reduce network flow (default=30)"); addvar(VAR_VALUE, SU_VAR_SEMISTATICFREQ, "Set semistatic value update frequency in update cycles, to reduce network flow (default=10)"); addvar(VAR_VALUE, SU_VAR_RETRIES, "Specifies the number of Net-SNMP retries to be used in the requests (default=5)"); addvar(VAR_VALUE, SU_VAR_TIMEOUT, "Specifies the Net-SNMP timeout in seconds between retries (default=1)"); addvar(VAR_FLAG, "notransferoids", "Disable transfer OIDs (use on APCC Symmetras)"); addvar(VAR_FLAG, "symmetrathreephase", "Enable APCC three phase Symmetra quirks (use on APCC three phase Symmetras)"); addvar(VAR_VALUE, SU_VAR_SECLEVEL, "Set the securityLevel used for SNMPv3 messages (default=noAuthNoPriv, allowed: authNoPriv,authPriv)"); addvar(VAR_VALUE | VAR_SENSITIVE, SU_VAR_SECNAME, "Set the securityName used for authenticated SNMPv3 messages (no default)"); addvar(VAR_VALUE | VAR_SENSITIVE, SU_VAR_AUTHPASSWD, "Set the authentication pass phrase used for authenticated SNMPv3 messages (no default)"); addvar(VAR_VALUE | VAR_SENSITIVE, SU_VAR_PRIVPASSWD, "Set the privacy pass phrase used for encrypted SNMPv3 messages (no default)"); /* Construct addvar() for SU_VAR_AUTHPROT: */ { int comma = 0; char tmp_buf[SU_LARGEBUF]; char *p = tmp_buf; char *pn; /* proto name to add */ size_t remain = sizeof(tmp_buf) - 1; int ret; NUT_UNUSED_VARIABLE(comma); /* potentially, if no protocols are available */ tmp_buf[0] = '\0'; ret = snprintf(p, remain, "%s", "Set the authentication protocol ("); if (ret < 0 || (uintmax_t)ret > (uintmax_t)remain || (uintmax_t)ret > SIZE_MAX) { fatalx(EXIT_FAILURE, "Could not addvar()"); } p += ret; remain -= (size_t)ret; #if NUT_HAVE_LIBNETSNMP_usmHMACMD5AuthProtocol pn = "MD5"; ret = snprintf(p, remain, "%s%s", (comma++ ? ", " : ""), pn ); if (ret < 0 || (uintmax_t)ret > (uintmax_t)remain || (uintmax_t)ret > SIZE_MAX) { fatalx(EXIT_FAILURE, "Could not addvar(%s)", pn); } p += ret; remain -= (size_t)ret; #endif #if NUT_HAVE_LIBNETSNMP_usmHMACSHA1AuthProtocol pn = "SHA"; ret = snprintf(p, remain, "%s%s", (comma++ ? ", " : ""), pn ); if (ret < 0 || (uintmax_t)ret > (uintmax_t)remain || (uintmax_t)ret > SIZE_MAX) { fatalx(EXIT_FAILURE, "Could not addvar(%s)", pn); } p += ret; remain -= (size_t)ret; #endif #if NUT_HAVE_LIBNETSNMP_usmHMAC192SHA256AuthProtocol pn = "SHA256"; ret = snprintf(p, remain, "%s%s", (comma++ ? ", " : ""), pn ); if (ret < 0 || (uintmax_t)ret > (uintmax_t)remain || (uintmax_t)ret > SIZE_MAX) { fatalx(EXIT_FAILURE, "Could not addvar(%s)", pn); } p += ret; remain -= (size_t)ret; #endif #if NUT_HAVE_LIBNETSNMP_usmHMAC256SHA384AuthProtocol pn = "SHA384"; ret = snprintf(p, remain, "%s%s", (comma++ ? ", " : ""), pn ); if (ret < 0 || (uintmax_t)ret > (uintmax_t)remain || (uintmax_t)ret > SIZE_MAX) { fatalx(EXIT_FAILURE, "Could not addvar(%s)", pn); } p += ret; remain -= (size_t)ret; #endif #if NUT_HAVE_LIBNETSNMP_usmHMAC384SHA512AuthProtocol pn = "SHA512"; ret = snprintf(p, remain, "%s%s", (comma++ ? ", " : ""), pn ); if (ret < 0 || (uintmax_t)ret > (uintmax_t)remain || (uintmax_t)ret > SIZE_MAX) { fatalx(EXIT_FAILURE, "Could not addvar(%s)", pn); } p += ret; remain -= (size_t)ret; #endif pn = "none supported"; ret = snprintf(p, remain, "%s", (comma++ ? "" : pn) ); if (ret < 0 || (uintmax_t)ret > (uintmax_t)remain || (uintmax_t)ret > SIZE_MAX) { fatalx(EXIT_FAILURE, "Could not addvar(%s)", pn); } p += ret; remain -= (size_t)ret; ret = snprintf(p, remain, "%s", ") used for authenticated SNMPv3 messages (default=MD5 if available)"); if (ret < 0 || (uintmax_t)ret > (uintmax_t)remain || (uintmax_t)ret > SIZE_MAX) { fatalx(EXIT_FAILURE, "Could not addvar()"); } p += ret; remain -= (size_t)ret; addvar(VAR_VALUE, SU_VAR_AUTHPROT, tmp_buf); } /* Construct addvar() for AUTHPROTO */ /* Construct addvar() for SU_VAR_PRIVPROT: */ { int comma = 0; char tmp_buf[SU_LARGEBUF]; char *p = tmp_buf; char *pn; /* proto name to add */ size_t remain = sizeof(tmp_buf) - 1; int ret; NUT_UNUSED_VARIABLE(comma); /* potentially, if no protocols are available */ tmp_buf[0] = '\0'; ret = snprintf(p, remain, "%s", "Set the privacy protocol ("); if (ret < 0 || (uintmax_t)ret > (uintmax_t)remain || (uintmax_t)ret > SIZE_MAX) { fatalx(EXIT_FAILURE, "Could not addvar()"); } p += ret; remain -= (size_t)ret; #if NUT_HAVE_LIBNETSNMP_usmDESPrivProtocol pn = "DES"; ret = snprintf(p, remain, "%s%s", (comma++ ? ", " : ""), pn ); if (ret < 0 || (uintmax_t)ret > (uintmax_t)remain || (uintmax_t)ret > SIZE_MAX) { fatalx(EXIT_FAILURE, "Could not addvar(%s)", pn); } p += ret; remain -= (size_t)ret; #endif #if NUT_HAVE_LIBNETSNMP_usmAESPrivProtocol || NUT_HAVE_LIBNETSNMP_usmAES128PrivProtocol pn = "AES"; ret = snprintf(p, remain, "%s%s", (comma++ ? ", " : ""), pn ); if (ret < 0 || (uintmax_t)ret > (uintmax_t)remain || (uintmax_t)ret > SIZE_MAX) { fatalx(EXIT_FAILURE, "Could not addvar(%s)", pn); } p += ret; remain -= (size_t)ret; #endif #if NUT_HAVE_LIBNETSNMP_DRAFT_BLUMENTHAL_AES_04 # if NUT_HAVE_LIBNETSNMP_usmAES192PrivProtocol pn = "AES192"; ret = snprintf(p, remain, "%s%s", (comma++ ? ", " : ""), pn ); if (ret < 0 || (uintmax_t)ret > (uintmax_t)remain || (uintmax_t)ret > SIZE_MAX) { fatalx(EXIT_FAILURE, "Could not addvar(%s)", pn); } p += ret; remain -= (size_t)ret; # endif # if NUT_HAVE_LIBNETSNMP_usmAES256PrivProtocol pn = "AES256"; ret = snprintf(p, remain, "%s%s", (comma++ ? ", " : ""), pn ); if (ret < 0 || (uintmax_t)ret > (uintmax_t)remain || (uintmax_t)ret > SIZE_MAX) { fatalx(EXIT_FAILURE, "Could not addvar(%s)", pn); } p += ret; remain -= (size_t)ret; # endif #endif /* NUT_HAVE_LIBNETSNMP_DRAFT_BLUMENTHAL_AES_04 */ pn = "none supported"; ret = snprintf(p, remain, "%s", (comma++ ? "" : pn) ); if (ret < 0 || (uintmax_t)ret > (uintmax_t)remain || (uintmax_t)ret > SIZE_MAX) { fatalx(EXIT_FAILURE, "Could not addvar(%s)", pn); } p += ret; remain -= (size_t)ret; ret = snprintf(p, remain, "%s", ") used for encrypted SNMPv3 messages (default=DES if available)"); if (ret < 0 || (uintmax_t)ret > (uintmax_t)remain || (uintmax_t)ret > SIZE_MAX) { fatalx(EXIT_FAILURE, "Could not addvar()"); } p += ret; remain -= (size_t)ret; addvar(VAR_VALUE, SU_VAR_PRIVPROT, tmp_buf); } /* Construct addvar() for PRIVPROTO */ addvar(VAR_VALUE, SU_VAR_ONDELAY, "Set start delay time after shutdown"); addvar(VAR_VALUE, SU_VAR_OFFDELAY, "Set delay time before shutdown "); } void upsdrv_initups(void) { snmp_info_t *su_info_p, *cur_info_p; char model[SU_INFOSIZE]; bool_t status= FALSE; const char *mibs; int curdev = 0; upsdebugx(1, "SNMP UPS driver: entering %s()", __func__); /* Retrieve user's parameters */ mibs = testvar(SU_VAR_MIBS) ? getval(SU_VAR_MIBS) : "auto"; if (!strcmp(mibs, "--list")) { int i; printf("The 'mibs' argument is '%s', so just listing the mappings this driver knows,\n" "and for 'mibs=auto' these mappings will be tried in the following order until\n" "the first one matches your device\n\n", mibs); printf("%7s\t%-23s\t%-7s\t%-31s\t%-s\n", "NUMBER", "MAPPING NAME", "VERSION", "ENTRY POINT OID", "AUTO CHECK OID"); for (i=0; mib2nut[i] != NULL; i++) { printf(" %4d \t%-23s\t%7s\t%-31s\t%-s\n", (i+1), mib2nut[i]->mib_name ? mib2nut[i]->mib_name : "" , mib2nut[i]->mib_version ? mib2nut[i]->mib_version : "" , mib2nut[i]->sysOID ? mib2nut[i]->sysOID : "" , mib2nut[i]->oid_auto_check ? mib2nut[i]->oid_auto_check : "" ); } printf("\nOverall this driver has loaded %d MIB-to-NUT mapping tables\n", i); exit(EXIT_SUCCESS); } /* init SNMP library, etc... */ nut_snmp_init(progname, device_path); /* FIXME: first test if the device is reachable to avoid timeouts! */ /* FIXME: with the argument called "mibs" (plural) it could make * sense to actually support a list of MIBs to try to get info * from, in order of preference, e.g. both a vendor MIB and the * IETF MIB for missing data points. Or even several vendor MIBs * for devices from companies with a long heritage. */ /* Load the SNMP to NUT translation data */ load_mib2nut(mibs); /* init polling frequency */ if (getval(SU_VAR_POLLFREQ)) pollfreq = atoi(getval(SU_VAR_POLLFREQ)); else pollfreq = DEFAULT_POLLFREQ; /* init semistatic update frequency */ if (getval(SU_VAR_SEMISTATICFREQ)) semistaticfreq = atoi(getval(SU_VAR_SEMISTATICFREQ)); else semistaticfreq = DEFAULT_SEMISTATICFREQ; if (semistaticfreq < 1) { upsdebugx(1, "Bad %s value provided, setting to default", SU_VAR_SEMISTATICFREQ); semistaticfreq = DEFAULT_SEMISTATICFREQ; } semistatic_countdown = semistaticfreq; /* Get UPS Model node to see if there's a MIB */ /* FIXME: extend and use match_model_OID(char *model) */ su_info_p = su_find_info("ups.model"); /* Try to get device.model if ups.model is not available */ if (su_info_p == NULL) su_info_p = su_find_info("device.model"); if (su_info_p != NULL) { /* Daisychain specific: we may have a template (including formatting * string) that needs to be adapted! */ if (strchr(su_info_p->OID, '%') != NULL) { upsdebugx(2, "Found template, need to be adapted"); cur_info_p = (snmp_info_t *)malloc(sizeof(snmp_info_t)); cur_info_p->info_type = (char *)xmalloc(SU_INFOSIZE); cur_info_p->OID = (char *)xmalloc(SU_INFOSIZE); snprintf((char*)cur_info_p->info_type, SU_INFOSIZE, "%s", su_info_p->info_type); /* Use the daisychain master (0) / 1rst device index */ #ifdef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL #pragma GCC diagnostic push #endif #ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL #pragma GCC diagnostic ignored "-Wformat-nonliteral" #endif #ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_FORMAT_SECURITY #pragma GCC diagnostic ignored "-Wformat-security" #endif snprintf((char*)cur_info_p->OID, SU_INFOSIZE, su_info_p->OID, 0); #ifdef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL #pragma GCC diagnostic pop #endif } else { upsdebugx(2, "Found entry, not a template %s", su_info_p->OID); /* Otherwise, just point at what we found */ cur_info_p = su_info_p; } /* Actually get the data */ status = nut_snmp_get_str(cur_info_p->OID, model, sizeof(model), NULL); /* Free our malloc, if it was dynamic */ if (strchr(su_info_p->OID, '%') != NULL) { if (cur_info_p->info_type != NULL) free((char*)cur_info_p->info_type); if (cur_info_p->OID != NULL) free((char*)cur_info_p->OID); if (cur_info_p != NULL) free((char*)cur_info_p); } } if (status == TRUE) upslogx(0, "Detected %s on host %s (mib: %s %s)", model, device_path, mibname, mibvers); else fatalx(EXIT_FAILURE, "%s MIB wasn't found on %s", mibs, g_snmp_sess.peername); /* FIXME: "No supported device detected" */ /* Init daisychain and check if support is required */ daisychain_init(); /* Allocate / init the daisychain info structure (for phases only for now) * daisychain_info[0] is the whole chain! (added +1) */ daisychain_info = (daisychain_info_t**)malloc( sizeof(daisychain_info_t) * (size_t)(devices_count + 1) ); for (curdev = 0 ; curdev <= devices_count ; curdev++) { daisychain_info[curdev] = (daisychain_info_t*)malloc(sizeof(daisychain_info_t)); daisychain_info[curdev]->input_phases = (long)-1; daisychain_info[curdev]->output_phases = (long)-1; daisychain_info[curdev]->bypass_phases = (long)-1; } /* FIXME: also need daisychain awareness (so init)! * i.e load.off.delay+load.off + device.1.load.off.delay+device.1.load.off + ... */ /* FIXME: daisychain commands support! */ if (su_find_info("load.off.delay")) { /* Adds default with a delay value of '0' (= immediate) */ dstate_addcmd("load.off"); } if (su_find_info("load.on.delay")) { /* Adds default with a delay value of '0' (= immediate) */ dstate_addcmd("load.on"); } if (su_find_info("load.off.delay") && su_find_info("load.on.delay")) { /* Add composite instcmds (require setting multiple OID values) */ dstate_addcmd("shutdown.return"); dstate_addcmd("shutdown.stayoff"); } /* Publish sysDescr, sysContact and sysLocation (from IETF standard paths) * for all subdrivers that do not have one defined in their mapping * tables (note: for lack of better knowledge, defined as read-only * entries here, and also read-once - not updated during driver uptime) */ if (NULL == dstate_getinfo("device.description") && NULL == dstate_getinfo("device.1.description") ) { /* sysDescr.0 */ if (nut_snmp_get_str(".1.3.6.1.2.1.1.1.0", model, sizeof(model), NULL) == TRUE) { upsdebugx(2, "Using IETF-MIB default to get and publish sysDescr for device.description (once)"); dstate_setinfo("device.description", "%s", model); } else { upsdebugx(2, "Can't get and publish sysDescr for device.description"); } } if (NULL == dstate_getinfo("device.contact") && NULL == dstate_getinfo("device.1.contact") ) { /* sysContact.0 */ if (nut_snmp_get_str(".1.3.6.1.2.1.1.4.0", model, sizeof(model), NULL) == TRUE) { upsdebugx(2, "Using IETF-MIB default to get and publish sysContact for device.contact (once)"); dstate_setinfo("device.contact", "%s", model); } else { upsdebugx(2, "Can't get and publish sysContact for device.contact"); } } if (NULL == dstate_getinfo("device.location") && NULL == dstate_getinfo("device.1.location") ) { /* sysLocation.0 */ if (nut_snmp_get_str(".1.3.6.1.2.1.1.6.0", model, sizeof(model), NULL) == TRUE) { upsdebugx(2, "Using IETF-MIB default to get and publish sysLocation for device.location (once)"); dstate_setinfo("device.location", "%s", model); } else { upsdebugx(2, "Can't get and publish sysLocation for device.location"); } } /* set shutdown and autostart delay */ set_delays(); } void upsdrv_cleanup(void) { /* General cleanup */ if (daisychain_info) free(daisychain_info); /* Net-SNMP specific cleanup */ nut_snmp_cleanup(); } /* ----------------------------------------------------------- * SNMP functions. * ----------------------------------------------------------- */ void nut_snmp_init(const char *type, const char *hostname) { char *ns_options = NULL; const char *community, *version; const char *secLevel = NULL, *authPassword, *privPassword; const char *authProtocol, *privProtocol; int snmp_retries = DEFAULT_NETSNMP_RETRIES; long snmp_timeout = DEFAULT_NETSNMP_TIMEOUT; upsdebugx(2, "SNMP UPS driver: entering %s(%s)", __func__, type); /* Force numeric OIDs resolution (ie, do not resolve to textual names) * This is mostly for the convenience of debug output */ ns_options = snmp_out_toggle_options("n"); if (ns_options != NULL) { upsdebugx(2, "Failed to enable numeric OIDs resolution"); } /* Initialize the SNMP library */ init_snmp(type); /* Initialize session */ snmp_sess_init(&g_snmp_sess); g_snmp_sess.peername = xstrdup(hostname); /* Net-SNMP timeout and retries */ if (testvar(SU_VAR_RETRIES)) { snmp_retries = atoi(getval(SU_VAR_RETRIES)); } g_snmp_sess.retries = snmp_retries; upsdebugx(2, "Setting SNMP retries to %i", snmp_retries); if (testvar(SU_VAR_TIMEOUT)) { snmp_timeout = atol(getval(SU_VAR_TIMEOUT)); } /* We have to convert from seconds to microseconds */ g_snmp_sess.timeout = snmp_timeout * ONE_SEC; upsdebugx(2, "Setting SNMP timeout to %ld second(s)", snmp_timeout); /* Retrieve user parameters */ version = testvar(SU_VAR_VERSION) ? getval(SU_VAR_VERSION) : "v1"; /* Older CLANG (e.g. clang-3.4) sees short strings in str{n}cmp() * arguments as arrays and claims out-of-bounds accesses */ #if (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_PUSH_POP) && (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_ARRAY_BOUNDS) # pragma GCC diagnostic push # pragma GCC diagnostic ignored "-Warray-bounds" #endif #ifdef __clang__ # pragma clang diagnostic push # pragma clang diagnostic ignored "-Warray-bounds" #endif if ((strcmp(version, "v1") == 0) || (strcmp(version, "v2c") == 0)) { g_snmp_sess.version = (strcmp(version, "v1") == 0) ? SNMP_VERSION_1 : SNMP_VERSION_2c; community = testvar(SU_VAR_COMMUNITY) ? getval(SU_VAR_COMMUNITY) : "public"; g_snmp_sess.community = (unsigned char *)xstrdup(community); g_snmp_sess.community_len = strlen(community); } else if (strcmp(version, "v3") == 0) { #ifdef __clang__ # pragma clang diagnostic pop #endif #if (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_PUSH_POP) && (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_ARRAY_BOUNDS) # pragma GCC diagnostic pop #endif /* SNMP v3 related init */ g_snmp_sess.version = SNMP_VERSION_3; /* Security level */ if (testvar(SU_VAR_SECLEVEL)) { secLevel = getval(SU_VAR_SECLEVEL); if (strcmp(secLevel, "noAuthNoPriv") == 0) g_snmp_sess.securityLevel = SNMP_SEC_LEVEL_NOAUTH; else if (strcmp(secLevel, "authNoPriv") == 0) g_snmp_sess.securityLevel = SNMP_SEC_LEVEL_AUTHNOPRIV; else if (strcmp(secLevel, "authPriv") == 0) g_snmp_sess.securityLevel = SNMP_SEC_LEVEL_AUTHPRIV; else fatalx(EXIT_FAILURE, "Bad SNMPv3 securityLevel: %s", secLevel); } else g_snmp_sess.securityLevel = SNMP_SEC_LEVEL_NOAUTH; /* Security name */ if (testvar(SU_VAR_SECNAME)) { g_snmp_sess.securityName = xstrdup(getval(SU_VAR_SECNAME)); g_snmp_sess.securityNameLen = strlen(g_snmp_sess.securityName); } else fatalx(EXIT_FAILURE, "securityName is required for SNMPv3"); /* Process mandatory fields, based on the security level */ authPassword = testvar(SU_VAR_AUTHPASSWD) ? getval(SU_VAR_AUTHPASSWD) : NULL; privPassword = testvar(SU_VAR_PRIVPASSWD) ? getval(SU_VAR_PRIVPASSWD) : NULL; switch (g_snmp_sess.securityLevel) { case SNMP_SEC_LEVEL_AUTHNOPRIV: if (authPassword == NULL) fatalx(EXIT_FAILURE, "authPassword is required for SNMPv3 in %s mode", secLevel); break; case SNMP_SEC_LEVEL_AUTHPRIV: if ((authPassword == NULL) || (privPassword == NULL)) fatalx(EXIT_FAILURE, "authPassword and privPassword are required for SNMPv3 in %s mode", secLevel); break; default: case SNMP_SEC_LEVEL_NOAUTH: /* nothing else needed */ break; } /* Process authentication protocol and key */ g_snmp_sess.securityAuthKeyLen = USM_AUTH_KU_LEN; authProtocol = testvar(SU_VAR_AUTHPROT) ? getval(SU_VAR_AUTHPROT) : "MD5"; #if NUT_HAVE_LIBNETSNMP_usmHMACMD5AuthProtocol if (strcmp(authProtocol, "MD5") == 0) { g_snmp_sess.securityAuthProto = usmHMACMD5AuthProtocol; g_snmp_sess.securityAuthProtoLen = sizeof(usmHMACMD5AuthProtocol)/sizeof(oid); } else #endif #if NUT_HAVE_LIBNETSNMP_usmHMACSHA1AuthProtocol if (strcmp(authProtocol, "SHA") == 0) { g_snmp_sess.securityAuthProto = usmHMACSHA1AuthProtocol; g_snmp_sess.securityAuthProtoLen = sizeof(usmHMACSHA1AuthProtocol)/sizeof(oid); } else #endif #if NUT_HAVE_LIBNETSNMP_usmHMAC192SHA256AuthProtocol if (strcmp(authProtocol, "SHA256") == 0) { g_snmp_sess.securityAuthProto = usmHMAC192SHA256AuthProtocol; g_snmp_sess.securityAuthProtoLen = sizeof(usmHMAC192SHA256AuthProtocol)/sizeof(oid); } else #endif #if NUT_HAVE_LIBNETSNMP_usmHMAC256SHA384AuthProtocol if (strcmp(authProtocol, "SHA384") == 0) { g_snmp_sess.securityAuthProto = usmHMAC256SHA384AuthProtocol; g_snmp_sess.securityAuthProtoLen = sizeof(usmHMAC256SHA384AuthProtocol)/sizeof(oid); } else #endif #if NUT_HAVE_LIBNETSNMP_usmHMAC384SHA512AuthProtocol if (strcmp(authProtocol, "SHA512") == 0) { g_snmp_sess.securityAuthProto = usmHMAC384SHA512AuthProtocol; g_snmp_sess.securityAuthProtoLen = sizeof(usmHMAC384SHA512AuthProtocol)/sizeof(oid); } else #endif fatalx(EXIT_FAILURE, "Bad SNMPv3 authProtocol: %s", authProtocol); /* set the authentication key to a MD5/SHA1 hashed version of our * passphrase (must be at least 8 characters long) */ if (g_snmp_sess.securityLevel != SNMP_SEC_LEVEL_NOAUTH) { #if (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_PUSH_POP) && ( (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_TYPE_LIMITS) || (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_TAUTOLOGICAL_CONSTANT_OUT_OF_RANGE_COMPARE) ) # pragma GCC diagnostic push #endif #ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_TYPE_LIMITS # pragma GCC diagnostic ignored "-Wtype-limits" #endif #ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_TAUTOLOGICAL_CONSTANT_OUT_OF_RANGE_COMPARE # pragma GCC diagnostic ignored "-Wtautological-constant-out-of-range-compare" #endif /* NOTE: Net-SNMP headers just are weird like that, in the same release: net-snmp/types.h: size_t securityAuthProtoLen; net-snmp/library/keytools.h: int generate_Ku(const oid * hashtype, u_int hashtype_len, ... * Should we match in configure like for "getnameinfo()" arg types? * Currently we cast one to another, below (detecting target type could help). */ if ((uintmax_t)g_snmp_sess.securityAuthProtoLen > UINT_MAX) { #if (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_PUSH_POP) && ( (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_TYPE_LIMITS) || (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_TAUTOLOGICAL_CONSTANT_OUT_OF_RANGE_COMPARE) ) # pragma GCC diagnostic pop #endif fatalx(EXIT_FAILURE, "Bad SNMPv3 securityAuthProtoLen: %" PRIuSIZE, g_snmp_sess.securityAuthProtoLen); } if (generate_Ku(g_snmp_sess.securityAuthProto, (u_int)g_snmp_sess.securityAuthProtoLen, (const unsigned char *) authPassword, strlen(authPassword), g_snmp_sess.securityAuthKey, &g_snmp_sess.securityAuthKeyLen) != SNMPERR_SUCCESS) { fatalx(EXIT_FAILURE, "Error generating Ku from authentication pass phrase"); } } privProtocol = testvar(SU_VAR_PRIVPROT) ? getval(SU_VAR_PRIVPROT) : "DES"; #if NUT_HAVE_LIBNETSNMP_usmDESPrivProtocol if (strcmp(privProtocol, "DES") == 0) { g_snmp_sess.securityPrivProto = usmDESPrivProtocol; g_snmp_sess.securityPrivProtoLen = sizeof(usmDESPrivProtocol)/sizeof(oid); } else #endif #if NUT_HAVE_LIBNETSNMP_usmAESPrivProtocol || NUT_HAVE_LIBNETSNMP_usmAES128PrivProtocol if (strcmp(privProtocol, "AES") == 0) { g_snmp_sess.securityPrivProto = usmAESPrivProtocol; g_snmp_sess.securityPrivProtoLen = NUT_securityPrivProtoLen; } else #endif #if NUT_HAVE_LIBNETSNMP_DRAFT_BLUMENTHAL_AES_04 # if NUT_HAVE_LIBNETSNMP_usmAES192PrivProtocol if (strcmp(privProtocol, "AES192") == 0) { g_snmp_sess.securityPrivProto = usmAES192PrivProtocol; g_snmp_sess.securityPrivProtoLen = (sizeof(usmAES192PrivProtocol)/sizeof(oid)); } else # endif # if NUT_HAVE_LIBNETSNMP_usmAES256PrivProtocol if (strcmp(privProtocol, "AES256") == 0) { g_snmp_sess.securityPrivProto = usmAES256PrivProtocol; g_snmp_sess.securityPrivProtoLen = (sizeof(usmAES256PrivProtocol)/sizeof(oid)); } else # endif #endif /* NUT_HAVE_LIBNETSNMP_DRAFT_BLUMENTHAL_AES_04 */ fatalx(EXIT_FAILURE, "Bad SNMPv3 privProtocol: %s", privProtocol); /* set the privacy key to a MD5/SHA1 hashed version of our * passphrase (must be at least 8 characters long) */ if (g_snmp_sess.securityLevel == SNMP_SEC_LEVEL_AUTHPRIV) { g_snmp_sess.securityPrivKeyLen = USM_PRIV_KU_LEN; #if (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_PUSH_POP) && ( (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_TYPE_LIMITS) || (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_TAUTOLOGICAL_CONSTANT_OUT_OF_RANGE_COMPARE) ) # pragma GCC diagnostic push #endif #ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_TYPE_LIMITS # pragma GCC diagnostic ignored "-Wtype-limits" #endif #ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_TAUTOLOGICAL_CONSTANT_OUT_OF_RANGE_COMPARE # pragma GCC diagnostic ignored "-Wtautological-constant-out-of-range-compare" #endif /* See comment on generate_Ku() a few dozen lines above */ if ((uintmax_t)g_snmp_sess.securityAuthProtoLen > UINT_MAX) { #if (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_PUSH_POP) && ( (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_TYPE_LIMITS) || (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_TAUTOLOGICAL_CONSTANT_OUT_OF_RANGE_COMPARE) ) # pragma GCC diagnostic pop #endif fatalx(EXIT_FAILURE, "Bad SNMPv3 securityAuthProtoLen: %" PRIuSIZE, g_snmp_sess.securityAuthProtoLen); } if (generate_Ku(g_snmp_sess.securityAuthProto, (u_int)g_snmp_sess.securityAuthProtoLen, (const unsigned char *) privPassword, strlen(privPassword), g_snmp_sess.securityPrivKey, &g_snmp_sess.securityPrivKeyLen) != SNMPERR_SUCCESS) { fatalx(EXIT_FAILURE, "Error generating Ku from privacy pass phrase"); } } } else fatalx(EXIT_FAILURE, "Bad SNMP version: %s", version); /* Open the session */ SOCK_STARTUP; /* MS Windows wrapper, not really needed on Unix! */ g_snmp_sess_p = snmp_open(&g_snmp_sess); /* establish the session */ if (g_snmp_sess_p == NULL) { nut_snmp_perror(&g_snmp_sess, 0, NULL, "nut_snmp_init: snmp_open"); fatalx(EXIT_FAILURE, "Unable to establish communication"); } } void nut_snmp_cleanup(void) { /* close snmp session. */ if (g_snmp_sess_p) { snmp_close(g_snmp_sess_p); g_snmp_sess_p = NULL; } SOCK_CLEANUP; /* wrapper not needed on Unix! */ } /* Free a struct snmp_pdu * returned by nut_snmp_walk */ static void nut_snmp_free(struct snmp_pdu ** array_to_free) { struct snmp_pdu ** current_element; if (array_to_free != NULL) { current_element = array_to_free; while (*current_element != NULL) { snmp_free_pdu(*current_element); current_element++; } free( array_to_free ); } } /* Return a NULL terminated array of snmp_pdu * */ static struct snmp_pdu **nut_snmp_walk(const char *OID, int max_iteration) { int status; struct snmp_pdu *pdu, *response = NULL; oid name[MAX_OID_LEN]; size_t name_len = MAX_OID_LEN; oid * current_name; size_t current_name_len; static unsigned int numerr = 0; int nb_iteration = 0; struct snmp_pdu ** ret_array = NULL; int type = SNMP_MSG_GET; upsdebugx(3, "%s(%s)", __func__, OID); upsdebugx(4, "%s: max. iteration = %i", __func__, max_iteration); /* create and send request. */ if (!snmp_parse_oid(OID, name, &name_len)) { upsdebugx(2, "[%s] %s: %s: %s", upsname?upsname:device_name, __func__, OID, snmp_api_errstring(snmp_errno)); return NULL; } current_name = name; current_name_len = name_len; while( nb_iteration < max_iteration ) { struct snmp_pdu **new_ret_array; /* Going to a shorter OID means we are outside our sub-tree */ if( current_name_len < name_len ) { break; } pdu = snmp_pdu_create(type); if (pdu == NULL) { fatalx(EXIT_FAILURE, "Not enough memory"); } snmp_add_null_var(pdu, current_name, current_name_len); status = snmp_synch_response(g_snmp_sess_p, pdu, &response); if (!response) { break; } if (!((status == STAT_SUCCESS) && (response->errstat == SNMP_ERR_NOERROR))) { if (mibname == NULL) { /* We are probing for proper mib - ignore errors */ snmp_free_pdu(response); nut_snmp_free(ret_array); return NULL; } if (response->errstat == SNMP_ERR_NOSUCHNAME) { upsdebugx(4, "%s: OID does not exist, skipping", __func__); snmp_free_pdu(response); nut_snmp_free(ret_array); return NULL; } upsdebugx(3, "status = %i, response->errstat = %li", status, response->errstat); /* Error throttling otherwise */ numerr++; upsdebugx(4, "%s: numerr++ (total=%i)", __func__, numerr); if ((numerr == SU_ERR_LIMIT) || ((numerr % SU_ERR_RATE) == 0)) { upslogx(LOG_WARNING, "[%s] Warning: excessive poll " "failures, limiting error reporting (OID = %s)", upsname?upsname:device_name, OID); } if ((numerr < SU_ERR_LIMIT) || ((numerr % SU_ERR_RATE) == 0)) { if (type == SNMP_MSG_GETNEXT) { upsdebugx(2, "=> No more OID, walk complete"); } else { nut_snmp_perror(g_snmp_sess_p, status, response, "%s: %s", __func__, OID); } } snmp_free_pdu(response); break; } else { /* Checked the "type" field of the returned varbind if * it is a type error exception (only applicable with * SNMPv2 or SNMPv3 protocol, would not happen with * SNMPv1). This allows to proceed interpreting large * responses when one entry in the middle is rejectable. */ if (response->variables->type == SNMP_NOSUCHOBJECT || response->variables->type == SNMP_NOSUCHINSTANCE || response->variables->type == SNMP_ENDOFMIBVIEW) { upslogx(LOG_WARNING, "[%s] Warning: type error exception (OID = %s)", upsname?upsname:device_name, OID); snmp_free_pdu(response); break; } else { /* no error */ numerr = 0; } } nb_iteration++; /* +1 is for the terminating NULL */ new_ret_array = realloc( ret_array, sizeof(struct snmp_pdu*) * ((size_t)nb_iteration+1) ); if (new_ret_array == NULL) { upsdebugx(1, "%s: Failed to realloc thread", __func__); break; } else { ret_array = new_ret_array; } ret_array[nb_iteration-1] = response; ret_array[nb_iteration]=NULL; current_name = response->variables->name; current_name_len = response->variables->name_length; type = SNMP_MSG_GETNEXT; } return ret_array; } struct snmp_pdu *nut_snmp_get(const char *OID) { struct snmp_pdu ** pdu_array; struct snmp_pdu * ret_pdu; if (OID == NULL) return NULL; upsdebugx(3, "%s(%s)", __func__, OID); pdu_array = nut_snmp_walk(OID,1); if(pdu_array == NULL) { return NULL; } ret_pdu = snmp_clone_pdu(*pdu_array); nut_snmp_free(pdu_array); return ret_pdu; } static bool_t decode_str(struct snmp_pdu *pdu, char *buf, size_t buf_len, info_lkp_t *oid2info) { size_t len = 0; char tmp_buf[SU_LARGEBUF]; /* zero out buffer. */ memset(buf, 0, buf_len); switch (pdu->variables->type) { case ASN_OCTET_STR: case ASN_OPAQUE: { /* scoping */ /* Test for hexadecimal values */ int hex = 0, x; unsigned char *cp; len = pdu->variables->val_len > buf_len - 1 ? buf_len - 1 : pdu->variables->val_len; for(cp = pdu->variables->val.string, x = 0; x < (int)pdu->variables->val_len; x++, cp++) { if (!(isprint((size_t)*cp) || isspace((size_t)*cp))) { hex = 1; } } if (hex) snprint_hexstring(buf, buf_len, pdu->variables->val.string, pdu->variables->val_len); else { memcpy(buf, pdu->variables->val.string, len); buf[len] = '\0'; } } break; case ASN_INTEGER: case ASN_COUNTER: case ASN_GAUGE: if(oid2info) { const char *str; /* See union netsnmp_vardata in net-snmp/types.h: "integer" is a "long*" */ assert(sizeof(pdu->variables->val.integer) == sizeof(long*)); /* If in future net-snmp headers val becomes not-a-pointer, * compiler should complain about (void*) arg casting here */ if((str = su_find_infoval(oid2info, pdu->variables->val.integer))) { strncpy(buf, str, buf_len-1); } /* when oid2info returns NULL, don't publish the variable! */ else { /* strncpy(buf, "UNKNOWN", buf_len-1); */ return FALSE; } buf[buf_len-1]='\0'; } else { int ret = snprintf(buf, buf_len, "%ld", *pdu->variables->val.integer); if (ret < 0) upsdebugx(3, "Failed to retrieve ASN_GAUGE"); else len = (size_t)ret; } break; case ASN_TIMETICKS: /* convert timeticks to seconds */ { int ret = snprintf(buf, buf_len, "%ld", *pdu->variables->val.integer / 100); if (ret < 0) upsdebugx(3, "Failed to retrieve ASN_TIMETICKS"); else len = (size_t)ret; } break; case ASN_OBJECT_ID: snprint_objid (tmp_buf, sizeof(tmp_buf), pdu->variables->val.objid, pdu->variables->val_len / sizeof(oid)); upsdebugx(2, "Received an OID value: %s", tmp_buf); /* Try to get the value of the pointed OID */ if (nut_snmp_get_str(tmp_buf, buf, buf_len, oid2info) == FALSE) { char *oid_leaf; upsdebugx(3, "Failed to retrieve OID value, using fallback"); /* Otherwise return the last part of the returned OID (ex: 1.2.3 => 3) */ oid_leaf = strrchr(tmp_buf, '.'); snprintf(buf, buf_len, "%s", oid_leaf+1); upsdebugx(3, "Fallback value: %s", buf); } break; default: return FALSE; } return TRUE; } bool_t nut_snmp_get_str(const char *OID, char *buf, size_t buf_len, info_lkp_t *oid2info) { struct snmp_pdu *pdu; bool_t ret; upsdebugx(3, "Entering %s()", __func__); pdu = nut_snmp_get(OID); if (pdu == NULL) return FALSE; ret = decode_str(pdu,buf,buf_len,oid2info); if(ret == FALSE) { upsdebugx(2, "[%s] unhandled ASN 0x%x received from %s", upsname?upsname:device_name, pdu->variables->type, OID); } snmp_free_pdu(pdu); return ret; } static bool_t decode_oid(struct snmp_pdu *pdu, char *buf, size_t buf_len) { /* zero out buffer. */ memset(buf, 0, buf_len); switch (pdu->variables->type) { case ASN_OBJECT_ID: snprint_objid (buf, buf_len, pdu->variables->val.objid, pdu->variables->val_len / sizeof(oid)); upsdebugx(2, "OID value: %s", buf); break; default: return FALSE; } return TRUE; } /* Return the value stored in OID, which is an OID (sysOID for example) * and don't try to get the value pointed by this OID (no follow). * To achieve the latter behavior, use standard nut_snmp_get_{str,int}() */ bool_t nut_snmp_get_oid(const char *OID, char *buf, size_t buf_len) { struct snmp_pdu *pdu; bool_t ret = FALSE; /* zero out buffer. */ memset(buf, 0, buf_len); upsdebugx(3, "Entering %s()", __func__); pdu = nut_snmp_get(OID); if (pdu == NULL) return FALSE; ret = decode_oid(pdu, buf, buf_len); if(ret == FALSE) { upsdebugx(2, "[%s] unhandled ASN 0x%x received from %s", upsname?upsname:device_name, pdu->variables->type, OID); } snmp_free_pdu(pdu); return ret; } bool_t nut_snmp_get_int(const char *OID, long *pval) { char tmp_buf[SU_LARGEBUF]; struct snmp_pdu *pdu; long value; char *buf; upsdebugx(3, "Entering %s()", __func__); pdu = nut_snmp_get(OID); if (pdu == NULL) return FALSE; switch (pdu->variables->type) { case ASN_OCTET_STR: case ASN_OPAQUE: buf = xmalloc(pdu->variables->val_len + 1); memcpy(buf, pdu->variables->val.string, pdu->variables->val_len); buf[pdu->variables->val_len] = '\0'; value = strtol(buf, NULL, 0); free(buf); break; case ASN_INTEGER: case ASN_COUNTER: case ASN_GAUGE: value = *pdu->variables->val.integer; break; case ASN_TIMETICKS: /* convert timeticks to seconds */ value = *pdu->variables->val.integer / 100; break; case ASN_OBJECT_ID: snprint_objid (tmp_buf, sizeof(tmp_buf), pdu->variables->val.objid, pdu->variables->val_len / sizeof(oid)); upsdebugx(2, "Received an OID value: %s", tmp_buf); /* Try to get the value of the pointed OID */ if (nut_snmp_get_int(tmp_buf, &value) == FALSE) { char *oid_leaf; upsdebugx(3, "Failed to retrieve OID value, using fallback"); /* Otherwise return the last part of the returned OID (ex: 1.2.3 => 3) */ oid_leaf = strrchr(tmp_buf, '.'); value = strtol(oid_leaf+1, NULL, 0); upsdebugx(3, "Fallback value: %ld", value); } break; default: upslogx(LOG_ERR, "[%s] unhandled ASN 0x%x received from %s", upsname?upsname:device_name, pdu->variables->type, OID); return FALSE; } snmp_free_pdu(pdu); if (pval != NULL) *pval = value; return TRUE; } bool_t nut_snmp_set(const char *OID, char type, const char *value) { int status; bool_t ret = FALSE; struct snmp_pdu *pdu, *response = NULL; oid name[MAX_OID_LEN]; size_t name_len = MAX_OID_LEN; upsdebugx(1, "entering %s(%s, %c, %s)", __func__, OID, type, value); if (!snmp_parse_oid(OID, name, &name_len)) { upslogx(LOG_ERR, "[%s] %s: %s: %s", upsname?upsname:device_name, __func__, OID, snmp_api_errstring(snmp_errno)); return FALSE; } pdu = snmp_pdu_create(SNMP_MSG_SET); if (pdu == NULL) fatalx(EXIT_FAILURE, "Not enough memory"); if (snmp_add_var(pdu, name, name_len, type, value)) { upslogx(LOG_ERR, "[%s] %s: %s: %s", upsname?upsname:device_name, __func__, OID, snmp_api_errstring(snmp_errno)); return FALSE; } status = snmp_synch_response(g_snmp_sess_p, pdu, &response); if ((status == STAT_SUCCESS) && (response->errstat == SNMP_ERR_NOERROR)) ret = TRUE; else nut_snmp_perror(g_snmp_sess_p, status, response, "%s: can't set %s", __func__, OID); snmp_free_pdu(response); return ret; } bool_t nut_snmp_set_str(const char *OID, const char *value) { return nut_snmp_set(OID, 's', value); } bool_t nut_snmp_set_int(const char *OID, long value) { char buf[SU_BUFSIZE]; snprintf(buf, sizeof(buf), "%ld", value); return nut_snmp_set(OID, 'i', buf); } bool_t nut_snmp_set_time(const char *OID, long value) { char buf[SU_BUFSIZE]; snprintf(buf, SU_BUFSIZE, "%ld", value * 100); return nut_snmp_set(OID, 't', buf); } /* log descriptive SNMP error message. */ void nut_snmp_perror(struct snmp_session *sess, int status, struct snmp_pdu *response, const char *fmt, ...) { va_list va; int cliberr, snmperr; char *snmperrstr; char buf[SU_LARGEBUF]; va_start(va, fmt); vsnprintf(buf, sizeof(buf), fmt, va); va_end(va); if (response == NULL) { snmp_error(sess, &cliberr, &snmperr, &snmperrstr); upslogx(LOG_ERR, "[%s] %s: %s", upsname?upsname:device_name, buf, snmperrstr); free(snmperrstr); } else if (status == STAT_SUCCESS) { /* Net-SNMP headers provide and consume errstat with different types: net-snmp/output_api.h: const char *snmp_errstring(int snmp_errorno); net-snmp/types.h: long errstat; * Should we match in configure like for "getnameinfo()" arg types? * Currently we cast one to another, below (detecting target type could help). */ switch (response->errstat) { case SNMP_ERR_NOERROR: break; case SNMP_ERR_NOSUCHNAME: /* harmless */ upsdebugx(2, "[%s] %s: %s", upsname?upsname:device_name, buf, (response->errstat > INT_MAX ? "(Net-SNMP errstat value is out of range)" : snmp_errstring((int)response->errstat) )); break; default: upslogx(LOG_ERR, "[%s] %s: Error in packet: %s", upsname?upsname:device_name, buf, (response->errstat > INT_MAX ? "(Net-SNMP errstat value is out of range)" : snmp_errstring((int)response->errstat) )); break; } } else if (status == STAT_TIMEOUT) { upslogx(LOG_ERR, "[%s] %s: Timeout: no response from %s", upsname?upsname:device_name, buf, sess->peername); } else { snmp_sess_error(sess, &cliberr, &snmperr, &snmperrstr); upslogx(LOG_ERR, "[%s] %s: %s", upsname?upsname:device_name, buf, snmperrstr); free(snmperrstr); } } /* ----------------------------------------------------------- * utility functions. * ----------------------------------------------------------- */ /* deal with APCC weirdness on Symmetras */ static void disable_transfer_oids(void) { snmp_info_t *su_info_p; upslogx(LOG_INFO, "Disabling transfer OIDs"); if (snmp_info == NULL) { fatalx(EXIT_FAILURE, "%s: snmp_info is not initialized", __func__); } if (snmp_info[0].info_type == NULL) { upsdebugx(1, "%s: WARNING: snmp_info is empty", __func__); } for (su_info_p = &snmp_info[0]; (su_info_p != NULL && su_info_p->info_type != NULL) ; su_info_p++) { if (!strcasecmp(su_info_p->info_type, "input.transfer.low")) { su_info_p->flags &= ~SU_FLAG_OK; continue; } if (!strcasecmp(su_info_p->info_type, "input.transfer.high")) { su_info_p->flags &= ~SU_FLAG_OK; continue; } } } /* Universal function to add or update info element. * If value is NULL, use the default one (su_info_p->dfl) if provided */ void su_setinfo(snmp_info_t *su_info_p, const char *value) { info_lkp_t *info_lkp; char info_type[128]; /* We tweak incoming "su_info_p->info_type" value in some cases */ /* FIXME: Replace hardcoded 128 with a macro above (use {SU_}LARGEBUF?), * and same macro or sizeof(info_type) below (also more 128 cases below)? */ upsdebugx(1, "entering %s(%s, %s)", __func__, su_info_p->info_type, (value)?value:""); /* FIXME: This 20 seems very wrong (should be "128", macro or sizeof? see above) */ memset(info_type, 0, 20); /* pre-fill with the device name for checking */ snprintf(info_type, 128, "device.%i", current_device_number); /* Daisy-chain template magic should only apply to defaulted * entries (oid==null) or templated entries (contains .%i); * however at this point we see exact OIDs handed down from * su_ups_get() which instantiates a template (if needed - * and knows it was a template) and calls su_setinfo(). * NOTE: For setting the values (or commands) from clients * like `upsrw`, see su_setOID() method. Here we change our * device state records based on readings from a device. */ if ((daisychain_enabled == TRUE) && (devices_count > 1)) { if (su_info_p->OID != NULL && strstr(su_info_p->OID, ".%i") != NULL ) { /* Only inform, do not react so far, * need more understanding if and when * such situation might happen at all: */ upsdebugx(5, "%s: in a daisy-chained device, " "got a templated OID %s for type %s", __func__, su_info_p->OID, su_info_p->info_type); } /* Only append "device.X" for master and slaves, if not already done! */ if ((current_device_number > 0) && (strstr(su_info_p->info_type, info_type) == NULL)) { /* Special case: we remove "device" from the device collection not to * get "device.X.device.", but "device.X." */ if (!strncmp(su_info_p->info_type, "device.", 7)) { upsdebugx(6, "%s: in a daisy-chained device, " "OID %s: TRIM 'device.' from type %s (value %s)", __func__, su_info_p->OID, su_info_p->info_type, (value)?value:""); snprintf(info_type, 128, "device.%i.%s", current_device_number, su_info_p->info_type + 7); } else { upsdebugx(6, "%s: in a daisy-chained device, " "OID %s is templated: for type %s (value %s)", __func__, su_info_p->OID, su_info_p->info_type, (value)?value:""); snprintf(info_type, 128, "device.%i.%s", current_device_number, su_info_p->info_type); } } else { upsdebugx(6, "%s: in a daisy-chained device, " "OID %s: for type %s (value %s) " "device %d is not positive or type already " "contains the prepared expectation: %s", __func__, su_info_p->OID, su_info_p->info_type, (value)?value:"", current_device_number, info_type ); snprintf(info_type, 128, "%s", su_info_p->info_type); } } else { upsdebugx(6, "%s: NOT in a daisy-chained device", __func__); snprintf(info_type, 128, "%s", su_info_p->info_type); } upsdebugx(1, "%s: using info_type '%s'", __func__, info_type); if (SU_TYPE(su_info_p) == SU_TYPE_CMD) return; /* ups.status and {ups, Lx, outlet, outlet.group}.alarm have special * handling, not here! */ if ((strcasecmp(su_info_p->info_type, "ups.status")) && (strcasecmp(strrchr(su_info_p->info_type, '.'), ".alarm"))) { if (value != NULL) dstate_setinfo(info_type, "%s", value); else if (su_info_p->dfl != NULL) dstate_setinfo(info_type, "%s", su_info_p->dfl); else { upsdebugx(3, "%s: no value nor default provided, aborting...", __func__); return; } dstate_setflags(info_type, su_info_p->info_flags); dstate_setaux(info_type, su_info_p->info_len); /* Set enumerated values, only if the data has ST_FLAG_RW and there * are lookup values */ /* FIXME: daisychain settings support: check if applicable */ if ((su_info_p->info_flags & ST_FLAG_RW) && su_info_p->oid2info) { upsdebugx(3, "%s: adding enumerated values", __func__); /* Loop on all existing values */ for (info_lkp = su_info_p->oid2info; info_lkp != NULL && info_lkp->info_value != NULL; info_lkp++) { dstate_addenum(info_type, "%s", info_lkp->info_value); } } /* Commit the current value, to avoid staleness with huge * data collections on slow devices */ dstate_dataok(); } } void su_status_set(snmp_info_t *su_info_p, long value) { const char *info_value = NULL; upsdebugx(2, "SNMP UPS driver: entering %s()", __func__); if ((info_value = su_find_infoval(su_info_p->oid2info, &value)) != NULL) { if (info_value[0] != '\0') { status_set(info_value); } } /* TODO: else */ } void su_alarm_set(snmp_info_t *su_info_p, long value) { const char *info_value = NULL; const char *info_type = NULL; char alarm_info_value[SU_LARGEBUF]; /* number of the outlet or phase */ int item_number = -1; upsdebugx(2, "SNMP UPS driver: entering %s(%s)", __func__, su_info_p->info_type); /* daisychain handling * extract the template part to get the relevant 'info_type' part * ex: device.6.L1.alarm => L1.alarm * ex: device.6.outlet.1.alarm => outlet.1.alarm */ if (!strncmp(su_info_p->info_type, "device.", 7)) { info_type = strchr(su_info_p->info_type + 7, '.') + 1; } else info_type = su_info_p->info_type; upsdebugx(2, "%s: using definition %s", __func__, info_type); if ((info_value = su_find_infoval(su_info_p->oid2info, &value)) != NULL && info_value[0] != 0) { char alarm_info_value_more[SU_LARGEBUF + 32]; /* can sprintf() SU_LARGEBUF plus markup into here */ /* Special handling for outlet & outlet groups alarms */ if ((su_info_p->flags & SU_OUTLET) || (su_info_p->flags & SU_OUTLET_GROUP)) { /* Extract template number */ item_number = extract_template_number(su_info_p->flags, info_type); upsdebugx(2, "%s: appending %s %i", __func__, (su_info_p->flags & SU_OUTLET_GROUP) ? "outlet group" : "outlet", item_number); /* Inject in the alarm string */ snprintf(alarm_info_value, sizeof(alarm_info_value), "outlet%s %i %s", (su_info_p->flags & SU_OUTLET_GROUP) ? " group" : "", item_number, info_value); info_value = &alarm_info_value[0]; } /* Special handling for phase alarms * Note that SU_*PHASE flags are cleared, so match the 'Lx' * start of path */ if (info_type[0] == 'L') { /* Extract phase number */ item_number = atoi(info_type+1); upsdebugx(2, "%s: appending phase L%i", __func__, item_number); /* Inject in the alarm string */ snprintf(alarm_info_value_more, sizeof(alarm_info_value_more), "phase L%i %s", item_number, info_value); info_value = &alarm_info_value_more[0]; } /* Set the alarm value */ alarm_set(info_value); } /* TODO: else */ } /* find info element definition in my info array. */ snmp_info_t *su_find_info(const char *type) { snmp_info_t *su_info_p; if (snmp_info == NULL) { fatalx(EXIT_FAILURE, "%s: snmp_info is not initialized", __func__); } if (snmp_info[0].info_type == NULL) { upsdebugx(1, "%s: WARNING: snmp_info is empty", __func__); } for (su_info_p = &snmp_info[0]; (su_info_p != NULL && su_info_p->info_type != NULL) ; su_info_p++) if (!strcasecmp(su_info_p->info_type, type)) { upsdebugx(3, "%s: \"%s\" found", __func__, type); return su_info_p; } upsdebugx(3, "%s: unknown info type (%s)", __func__, type); return NULL; } /* Counter match the sysOID using {device,ups}.model OID * Return TRUE if this OID can be retrieved, FALSE otherwise */ static bool_t match_model_OID(void) { bool_t retCode = FALSE; snmp_info_t *su_info_p, *cur_info_p; char testOID_buf[LARGEBUF]; /* Try to get device.model first */ su_info_p = su_find_info("device.model"); /* Otherwise, try to get ups.model */ if (su_info_p == NULL) su_info_p = su_find_info("ups.model"); if (su_info_p != NULL) { /* Daisychain specific: we may have a template (including formatting * string) that needs to be adapted! */ if (strchr(su_info_p->OID, '%') != NULL) { upsdebugx(2, "Found template, need to be adapted"); cur_info_p = (snmp_info_t *)malloc(sizeof(snmp_info_t)); cur_info_p->info_type = (char *)xmalloc(SU_INFOSIZE); cur_info_p->OID = (char *)xmalloc(SU_INFOSIZE); snprintf((char*)cur_info_p->info_type, SU_INFOSIZE, "%s", su_info_p->info_type); /* Use the daisychain master (0) / 1rst device index */ #ifdef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL #pragma GCC diagnostic push #endif #ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL #pragma GCC diagnostic ignored "-Wformat-nonliteral" #endif #ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_FORMAT_SECURITY #pragma GCC diagnostic ignored "-Wformat-security" #endif snprintf((char*)cur_info_p->OID, SU_INFOSIZE, su_info_p->OID, 0); #ifdef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL #pragma GCC diagnostic pop #endif } else { upsdebugx(2, "Found entry, not a template %s", su_info_p->OID); /* Otherwise, just point at what we found */ cur_info_p = su_info_p; } upsdebugx(2, "Testing %s using OID %s", cur_info_p->info_type, cur_info_p->OID); retCode = nut_snmp_get_str(cur_info_p->OID, testOID_buf, LARGEBUF, NULL); /* Free our malloc, if it was dynamic */ if (strchr(su_info_p->OID, '%') != NULL) { if (cur_info_p->info_type != NULL) free((char*)cur_info_p->info_type); if (cur_info_p->OID != NULL) free((char*)cur_info_p->OID); if (cur_info_p != NULL) free((char*)cur_info_p); } } return retCode; } /* Try to find the MIB using sysOID matching. * Return a pointer to a mib2nut definition if found, NULL otherwise */ static mib2nut_info_t *match_sysoid(void) { char sysOID_buf[LARGEBUF]; oid device_sysOID[MAX_OID_LEN]; size_t device_sysOID_len = MAX_OID_LEN; oid mib2nut_sysOID[MAX_OID_LEN]; size_t mib2nut_sysOID_len = MAX_OID_LEN; int i; /* Retrieve sysOID value of this device */ if (nut_snmp_get_oid(SYSOID_OID, sysOID_buf, sizeof(sysOID_buf)) != TRUE) { upsdebugx(2, "Can't get sysOID value (using nut_snmp_get_oid())"); /* Fallback for non-compliant device, that returns a string and not an OID */ if (nut_snmp_get_str(SYSOID_OID, sysOID_buf, sizeof(sysOID_buf), NULL) != TRUE) { upsdebugx(2, "Can't get sysOID value (using nut_snmp_get_str())"); return NULL; } } upsdebugx(1, "%s: device sysOID value = %s", __func__, sysOID_buf); /* Build OIDs for comparison */ if (!read_objid(sysOID_buf, device_sysOID, &device_sysOID_len)) { upsdebugx(2, "%s: can't build device_sysOID %s: %s", __func__, sysOID_buf, snmp_api_errstring(snmp_errno)); return NULL; } /* Now, iterate on mib2nut definitions */ for (i = 0; mib2nut[i] != NULL; i++) { upsdebugx(1, "%s: checking MIB %s", __func__, mib2nut[i]->mib_name); if (mib2nut[i]->sysOID == NULL) continue; /* Clear variables */ memset(mib2nut_sysOID, 0, sizeof(mib2nut_sysOID)); mib2nut_sysOID_len = MAX_OID_LEN; if (!read_objid(mib2nut[i]->sysOID, mib2nut_sysOID, &mib2nut_sysOID_len)) { upsdebugx(2, "%s: can't build OID %s: %s", __func__, sysOID_buf, snmp_api_errstring(snmp_errno)); /* Try to continue anyway! */ continue; } /* Now compare these */ upsdebugx(1, "%s: comparing %s with %s", __func__, sysOID_buf, mib2nut[i]->sysOID); if (!netsnmp_oid_equals(device_sysOID, device_sysOID_len, mib2nut_sysOID, mib2nut_sysOID_len)) { upsdebugx(2, "%s: sysOID matches MIB '%s'!", __func__, mib2nut[i]->mib_name); /* Counter verify, using {ups,device}.model */ snmp_info = mib2nut[i]->snmp_info; if (snmp_info == NULL) { upsdebugx(0, "%s: WARNING: snmp_info is not initialized " "for mapping table entry #%d \"%s\"", __func__, i, mib2nut[i]->mib_name ); continue; } else if (snmp_info[0].info_type == NULL) { upsdebugx(1, "%s: WARNING: snmp_info is empty " "for mapping table entry #%d \"%s\"", __func__, i, mib2nut[i]->mib_name); } if (match_model_OID() != TRUE) { upsdebugx(2, "%s: testOID provided and doesn't match MIB '%s'!", __func__, mib2nut[i]->mib_name); snmp_info = NULL; continue; } else upsdebugx(2, "%s: testOID provided and matches MIB '%s'!", __func__, mib2nut[i]->mib_name); return mib2nut[i]; } } /* Yell all to call for user report */ upslogx(LOG_ERR, "No matching MIB found for sysOID '%s'!\n" \ "Please report it to NUT developers, with an 'upsc' output for your device.\n" \ "Going back to the classic MIB detection method.", sysOID_buf); return NULL; } /* Load the right snmp_info_t structure matching mib parameter */ bool_t load_mib2nut(const char *mib) { int i; mib2nut_info_t *m2n = NULL; /* Below we have many checks for "auto"; avoid redundant string walks: */ bool_t mibIsAuto = (0 == strcmp(mib, "auto")); bool_t mibSeen = FALSE; /* Did we see the MIB name while walking mib2nut[]? */ upsdebugx(1, "SNMP UPS driver: entering %s(%s) to detect " "proper MIB for device [%s] (host %s)", __func__, mib, upsname ? upsname : device_name, device_path /* the "port" from config section is hostname/IP for networked drivers */ ); /* First, try to match against sysOID, if no MIB was provided. * This should speed up init stage * (Note: sysOID points the device main MIB entry point) */ if (mibIsAuto) { upsdebugx(2, "%s: trying the new match_sysoid() method with %s", __func__, mib); /* Retry at most 3 times, to maximise chances */ for (i = 0; i < 3 ; i++) { upsdebugx(3, "%s: trying the new match_sysoid() method: attempt #%d", __func__, (i+1)); if ((m2n = match_sysoid()) != NULL) break; if (m2n == NULL) upsdebugx(3, "%s: failed with new match_sysoid() method", __func__); else upsdebugx(3, "%s: found something with new match_sysoid() method", __func__); } } /* Otherwise, revert to the classic method */ if (m2n == NULL) { for (i = 0; mib2nut[i] != NULL; i++) { /* Is there already a MIB name provided? */ upsdebugx(4, "%s: checking against mapping table entry #%d \"%s\"", __func__, i, mib2nut[i]->mib_name); if (!mibIsAuto && strcmp(mib, mib2nut[i]->mib_name)) { /* "mib" is neither "auto" nor the name in mapping table */ upsdebugx(2, "%s: skip the \"%s\" entry from " "the mapping table which is not \"%s\" " "(and which in turn is not \"auto\")", __func__, mib2nut[i]->mib_name, mib); continue; } upsdebugx(2, "%s: trying classic sysOID matching method with '%s' mib", __func__, mib2nut[i]->mib_name); /* Classic method: test an OID specific to this MIB */ snmp_info = mib2nut[i]->snmp_info; if (snmp_info == NULL) { upsdebugx(0, "%s: WARNING: snmp_info is not initialized " "for mapping table entry #%d \"%s\"", __func__, i, mib2nut[i]->mib_name ); continue; } else if (snmp_info[0].info_type == NULL) { upsdebugx(1, "%s: WARNING: snmp_info is empty " "for mapping table entry #%d \"%s\"", __func__, i, mib2nut[i]->mib_name); } /* Device might not support this MIB, but we want to * track that the name string is valid for diags below */ if (!mibIsAuto) { mibSeen = TRUE; } if (match_model_OID() != TRUE) { upsdebugx(3, "%s: testOID provided and doesn't match MIB '%s'!", __func__, mib2nut[i]->mib_name); snmp_info = NULL; continue; } else upsdebugx(3, "%s: testOID provided and matches MIB '%s'!", __func__, mib2nut[i]->mib_name); /* MIB found */ m2n = mib2nut[i]; break; } } /* Store the result, if any */ if (m2n != NULL) { snmp_info = m2n->snmp_info; OID_pwr_status = m2n->oid_pwr_status; mibname = m2n->mib_name; mibvers = m2n->mib_version; alarms_info = m2n->alarms_info; upsdebugx(1, "%s: using %s MIB for device [%s] (host %s)", __func__, mibname, upsname ? upsname : device_name, device_path); return TRUE; } /* Did we find something or is it really an unknown mib */ if (!mibIsAuto) { if (mibSeen) { fatalx(EXIT_FAILURE, "Requested 'mibs' value '%s' " "did not match this device [%s] (host %s)", mib, upsname ? upsname : device_name, device_path); } else { /* String not seen during mib2nut[] walk - * and if we had no hits, we walked it all */ fatalx(EXIT_FAILURE, "Unknown 'mibs' value " "which is neither \"auto\" nor a valid " "name in the mapping table: %s", mib); } } else { fatalx(EXIT_FAILURE, "No supported device detected at [%s] (host %s)", upsname ? upsname : device_name, device_path); } /* Should not get here thanks to fatalx() above, but need to silence a warning */ return FALSE; } /* find the OID value matching that INFO_* value */ long su_find_valinfo(info_lkp_t *oid2info, const char* value) { info_lkp_t *info_lkp; for (info_lkp = oid2info; (info_lkp != NULL) && (strcmp(info_lkp->info_value, "NULL")); info_lkp++) { if (!(strcmp(info_lkp->info_value, value))) { upsdebugx(1, "%s: found %s (value: %s)", __func__, info_lkp->info_value, value); return info_lkp->oid_value; } } upsdebugx(1, "%s: no matching INFO_* value for this OID value (%s)", __func__, value); return -1; } /* String reformatting function */ const char *su_find_strval(info_lkp_t *oid2info, void *value) { #if WITH_SNMP_LKP_FUN /* First test if we have a generic lookup function */ if ( (oid2info != NULL) && (oid2info->fun_vp2s != NULL) ) { const char *retvalue; upsdebugx(2, "%s: using generic lookup function (string reformatting)", __func__); retvalue = oid2info->fun_vp2s(value); upsdebugx(2, "%s: got value '%s'", __func__, retvalue); return retvalue; } upsdebugx(1, "%s: no result value for this OID string value (%s)", __func__, (char*)value); #else NUT_UNUSED_VARIABLE(oid2info); upsdebugx(1, "%s: no mapping function for this OID string value (%s)", __func__, (char*)value); #endif // WITH_SNMP_LKP_FUN return NULL; } /* find the INFO_* value matching that OID numeric (long) value */ const char *su_find_infoval(info_lkp_t *oid2info, void *raw_value) { info_lkp_t *info_lkp; long value = *((long *)raw_value); #if WITH_SNMP_LKP_FUN /* First test if we have a generic lookup function */ if ( (oid2info != NULL) && (oid2info->fun_vp2s != NULL) ) { const char *retvalue; upsdebugx(2, "%s: using generic lookup function", __func__); retvalue = oid2info->fun_vp2s(raw_value); upsdebugx(2, "%s: got value '%s'", __func__, retvalue); return retvalue; } #endif // WITH_SNMP_LKP_FUN /* Otherwise, use the simple values mapping */ for (info_lkp = oid2info; (info_lkp != NULL) && (info_lkp->info_value != NULL) && (strcmp(info_lkp->info_value, "NULL")); info_lkp++) { if (info_lkp->oid_value == value) { upsdebugx(1, "%s: found %s (value: %ld)", __func__, info_lkp->info_value, value); return info_lkp->info_value; } } upsdebugx(1, "%s: no matching INFO_* value for this OID value (%ld)", __func__, value); return NULL; } /* FIXME: doesn't work with templates! */ static void disable_competition(snmp_info_t *entry) { snmp_info_t *p; if (snmp_info == NULL) { fatalx(EXIT_FAILURE, "%s: snmp_info is not initialized", __func__); } if (snmp_info[0].info_type == NULL) { upsdebugx(1, "%s: WARNING: snmp_info is empty", __func__); } for(p = snmp_info; (p != NULL && p->info_type != NULL) ; p++) { if(p!=entry && !strcmp(p->info_type, entry->info_type)) { upsdebugx(2, "%s: disabling %s %s", __func__, p->info_type, p->OID); p->flags &= ~SU_FLAG_OK; } } } /* set shutdown and/or start delays */ void set_delays(void) { int ondelay, offdelay; char su_scratch_buf[255]; if (getval(SU_VAR_ONDELAY)) ondelay = atoi(getval(SU_VAR_ONDELAY)); else ondelay = -1; if (getval(SU_VAR_OFFDELAY)) offdelay = atoi(getval(SU_VAR_OFFDELAY)); else offdelay = -1; if (ondelay >= 0) { sprintf(su_scratch_buf, "%d", ondelay); su_setvar("ups.delay.start", su_scratch_buf); } if (offdelay >= 0) { sprintf(su_scratch_buf, "%d", offdelay); su_setvar("ups.delay.shutdown", su_scratch_buf); } } /*********************************************************************** * Template handling functions **********************************************************************/ /* Test if the template is a multiple one, i.e. with a formatting string that * contains multiple "%i". * Return TRUE if yes (multiple "%i" found), FALSE otherwise */ static bool_t is_multiple_template(const char *OID_template) { bool_t retCode = FALSE; char *format_char = NULL; if (OID_template) { format_char = strchr(OID_template, '%'); upsdebugx(4, "%s(%s)", __func__, OID_template); } else upsdebugx(4, "%s(NULL)", __func__); if (format_char != NULL) { if (strchr(format_char + 1, '%') != NULL) { retCode = TRUE; } } upsdebugx(4, "%s: has %smultiple template definition", __func__, (retCode == FALSE)?"not ":""); return retCode; } /* Instantiate an snmp_info_t from a template. * Useful for device, outlet, outlet.group and ambient templates. * Note: remember to adapt info_type, OID and optionaly dfl */ static snmp_info_t *instantiate_info(snmp_info_t *info_template, snmp_info_t *new_instance) { upsdebugx(1, "%s(%s)", __func__, info_template ? info_template->info_type : "n/a"); /* sanity check */ if (info_template == NULL) return NULL; if (new_instance == NULL) new_instance = (snmp_info_t *)xmalloc(sizeof(snmp_info_t)); /* TOTHINK: Should there be an "else" to free() * the fields which we (re-)allocate below? */ new_instance->info_type = (char *)xmalloc(SU_INFOSIZE); if (new_instance->info_type) memset((char *)new_instance->info_type, 0, SU_INFOSIZE); if (info_template->OID != NULL) { new_instance->OID = (char *)xmalloc(SU_INFOSIZE); if (new_instance->OID) memset((char *)new_instance->OID, 0, SU_INFOSIZE); } else { new_instance->OID = NULL; } new_instance->info_flags = info_template->info_flags; new_instance->info_len = info_template->info_len; /* FIXME: check if we need to adapt this one... */ new_instance->dfl = info_template->dfl; new_instance->flags = info_template->flags; new_instance->oid2info = info_template->oid2info; upsdebugx(2, "instantiate_info: template instantiated"); return new_instance; } /* Free a dynamically allocated snmp_info_t. * Useful for outlet and outlet.group templates */ static void free_info(snmp_info_t *su_info_p) { /* sanity check */ if (su_info_p == NULL) return; if (su_info_p->info_type != NULL) free ((char *)su_info_p->info_type); if (su_info_p->OID != NULL) free ((char *)su_info_p->OID); free (su_info_p); } /* return the base SNMP index (0 or 1) to start template iteration on * the MIB, based on a test using a template OID */ static int base_snmp_template_index(const snmp_info_t *su_info_p) { int base_index = -1; char test_OID[SU_INFOSIZE]; snmp_info_flags_t template_type; if (!su_info_p) return -1; template_type = get_template_type(su_info_p->info_type); upsdebugx(3, "%s: OID template = %s", __func__, (su_info_p->OID ? su_info_p->OID : "") ); /* Try to differentiate between template types which may have * different indexes ; and store it to not redo it again */ switch (template_type) { case SU_OUTLET: template_index_base = outlet_template_index_base; break; case SU_OUTLET_GROUP: template_index_base = outletgroup_template_index_base; break; case SU_DAISY: template_index_base = device_template_index_base; break; case SU_AMBIENT_TEMPLATE: template_index_base = ambient_template_index_base; break; default: /* we should never fall here! */ upsdebugx(3, "%s: unknown template type '%" PRI_SU_FLAGS "' for %s", __func__, template_type, su_info_p->info_type); } base_index = template_index_base; /* If no OID defined, now we can return the good index computed */ if (!su_info_p->OID) return base_index; if (template_index_base == -1) { /* not initialised yet */ for (base_index = 0 ; base_index < 2 ; base_index++) { #ifdef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL #pragma GCC diagnostic push #endif #ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL #pragma GCC diagnostic ignored "-Wformat-nonliteral" #endif #ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_FORMAT_SECURITY #pragma GCC diagnostic ignored "-Wformat-security" #endif /* Test if this template also includes daisychain, in which case * we just use the current device index */ if (is_multiple_template(su_info_p->OID) == TRUE) { if (su_info_p->flags & SU_TYPE_DAISY_1) { snprintf(test_OID, sizeof(test_OID), su_info_p->OID, current_device_number + device_template_offset, base_index); } else { snprintf(test_OID, sizeof(test_OID), su_info_p->OID, base_index, current_device_number + device_template_offset); } } else { snprintf(test_OID, sizeof(test_OID), su_info_p->OID, base_index); } #ifdef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL #pragma GCC diagnostic pop #endif if (nut_snmp_get(test_OID) != NULL) { if (su_info_p->flags & SU_FLAG_ZEROINVALID) { long value; if ((nut_snmp_get_int(test_OID, &value)) && (value!=0)) { break; } } else if (su_info_p->flags & SU_FLAG_NAINVALID) { char value[SU_BUFSIZE]; if ((nut_snmp_get_str(test_OID, value, SU_BUFSIZE, NULL)) && (strncmp(value, "N/A", 3))) { break; } } else { break; } } } /* Only store if it's a template for outlets or outlets groups, * not for daisychain (which has different index) */ if (su_info_p->flags & SU_OUTLET) outlet_template_index_base = base_index; else if (su_info_p->flags & SU_OUTLET_GROUP) outletgroup_template_index_base = base_index; else if (su_info_p->flags & SU_AMBIENT_TEMPLATE) ambient_template_index_base = base_index; else device_template_index_base = base_index; } upsdebugx(3, "%s: template_index_base = %i", __func__, base_index); return base_index; } /* Try to determine the number of items (outlets, outlet groups, ...), * using a template definition. Walk through the template until we can't * get anymore values. I.e., if we can iterate up to 8 item, return 8 */ static int guesstimate_template_count(snmp_info_t *su_info_p) { int base_index = 0; char test_OID[SU_INFOSIZE]; int base_count; const char *OID_template = su_info_p->OID; upsdebugx(1, "%s(%s)", __func__, OID_template); /* Test if OID is indexed: safeguard for infinite loop */ if (strchr(OID_template, '%') == NULL) { upsdebugx(3, "Warning: non-indexed object, discarding (OID = %s)", OID_template); return 0; } /* Determine if OID index starts from 0 or 1? */ #ifdef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL #pragma GCC diagnostic push #endif #ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL #pragma GCC diagnostic ignored "-Wformat-nonliteral" #endif #ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_FORMAT_SECURITY #pragma GCC diagnostic ignored "-Wformat-security" #endif snprintf(test_OID, sizeof(test_OID), OID_template, base_index); #ifdef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL #pragma GCC diagnostic pop #endif if (nut_snmp_get(test_OID) == NULL) { base_index++; } else { if (su_info_p->flags & SU_FLAG_ZEROINVALID) { long value; if ((nut_snmp_get_int(test_OID, &value)) && (value==0)) { base_index++; } } } /* Now, actually iterate */ for (base_count = 0 ; ; base_count++) { #ifdef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL #pragma GCC diagnostic push #endif #ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL #pragma GCC diagnostic ignored "-Wformat-nonliteral" #endif #ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_FORMAT_SECURITY #pragma GCC diagnostic ignored "-Wformat-security" #endif snprintf(test_OID, sizeof(test_OID), OID_template, base_index + base_count); #ifdef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL #pragma GCC diagnostic pop #endif if (nut_snmp_get(test_OID) == NULL) break; } upsdebugx(3, "%s: %i", __func__, base_count); return base_count; } /* Process template definition, instantiate and get data or register * command * type: outlet, outlet.group, device */ static bool_t process_template(int mode, const char* type, snmp_info_t *su_info_p) { /* Default to TRUE, and leave to get_and_process_data() to set * to FALSE when actually getting data from devices, to avoid false * negative with server side data */ bool_t status = TRUE; int cur_template_number = 1; int cur_nut_index = 0; int template_count = 0; int base_snmp_index = 0; snmp_info_t cur_info_p; char template_count_var[SU_BUFSIZE * 2]; /* Needed *2 to fit a max size_t in snprintf() below, * even if that should never happen */ char tmp_buf[SU_INFOSIZE]; upsdebugx(1, "%s template definition found (%s)...", type, su_info_p->info_type); if ((strncmp(type, "device", 6)) && (devices_count > 1) && (current_device_number > 0)) { snprintf(template_count_var, sizeof(template_count_var), "device.%i.%s.count", current_device_number, type); } else { snprintf(template_count_var, sizeof(template_count_var), "%s.count", type); } if(dstate_getinfo(template_count_var) == NULL) { /* FIXME: should we disable it? * su_info_p->flags &= ~SU_FLAG_OK; * or rely on guesstimation? */ template_count = guesstimate_template_count(su_info_p); /* Publish the count estimation */ if (template_count > 0) { dstate_setinfo(template_count_var, "%i", template_count); } } else { template_count = atoi(dstate_getinfo(template_count_var)); } upsdebugx(1, "%i instances found...", template_count); /* Only instantiate templates if needed! */ if (template_count > 0) { /* general init of data using the template */ instantiate_info(su_info_p, &cur_info_p); base_snmp_index = base_snmp_template_index(su_info_p); for (cur_template_number = base_snmp_index ; cur_template_number < (template_count + base_snmp_index) ; cur_template_number++) { upsdebugx(1, "Processing instance %i/%i...", cur_template_number, template_count); /* Special processing for daisychain: * append 'device.x' to the NUT variable name, except for the * whole daisychain ("device.0") */ if (!strncmp(type, "device", 6)) { /* Device(s) 1-N (master + slave(s)) need to append 'device.x' */ if (current_device_number > 0) { char *ptr = NULL; /* Another special processing for daisychain * device collection needs special appending */ if (!strncmp(su_info_p->info_type, "device.", 7)) ptr = (char*)&su_info_p->info_type[7]; else ptr = (char*)su_info_p->info_type; snprintf((char*)cur_info_p.info_type, SU_INFOSIZE, "device.%i.%s", current_device_number, ptr); } else { /* Device 1 ("device.0", whole daisychain) needs no * special processing */ cur_nut_index = cur_template_number; #ifdef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL #pragma GCC diagnostic push #endif #ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL #pragma GCC diagnostic ignored "-Wformat-nonliteral" #endif #ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_FORMAT_SECURITY #pragma GCC diagnostic ignored "-Wformat-security" #endif snprintf((char*)cur_info_p.info_type, SU_INFOSIZE, su_info_p->info_type, cur_nut_index); #ifdef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL #pragma GCC diagnostic pop #endif } } else if (!strncmp(type, "outlet", 6)) /* Outlet and outlet groups templates */ { /* Get the index of the current template instance */ cur_nut_index = cur_template_number; #ifdef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL #pragma GCC diagnostic push #endif #ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL #pragma GCC diagnostic ignored "-Wformat-nonliteral" #endif #ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_FORMAT_SECURITY #pragma GCC diagnostic ignored "-Wformat-security" #endif /* Special processing for daisychain */ if (daisychain_enabled == TRUE) { /* Device(s) 1-N (master + slave(s)) need to append 'device.x' */ if ((devices_count > 1) && (current_device_number > 0)) { memset(&tmp_buf[0], 0, SU_INFOSIZE); strcat(&tmp_buf[0], "device.%i."); strcat(&tmp_buf[0], su_info_p->info_type); upsdebugx(4, "FORMATTING STRING = %s", &tmp_buf[0]); snprintf((char*)cur_info_p.info_type, SU_INFOSIZE, &tmp_buf[0], current_device_number, cur_nut_index); } else { /* FIXME: daisychain-whole, what to do? */ snprintf((char*)cur_info_p.info_type, SU_INFOSIZE, su_info_p->info_type, cur_nut_index); } } else { snprintf((char*)cur_info_p.info_type, SU_INFOSIZE, su_info_p->info_type, cur_nut_index); } } else if (!strncmp(type, "ambient", 7)) { /* FIXME: can be grouped with outlet* above */ /* Get the index of the current template instance */ cur_nut_index = cur_template_number; /* Special processing for daisychain */ if (daisychain_enabled == TRUE) { /* Only publish on the daisychain host */ if ( (su_info_p->flags & SU_TYPE_DAISY_MASTER_ONLY) && (current_device_number != 1) ) { upsdebugx(2, "discarding variable due to daisychain master flag"); continue; } /* Device(s) 1-N (master + slave(s)) need to append 'device.x' */ if ((devices_count > 1) && (current_device_number > 0)) { memset(&tmp_buf[0], 0, SU_INFOSIZE); strcat(&tmp_buf[0], "device.%i."); strcat(&tmp_buf[0], su_info_p->info_type); upsdebugx(4, "FORMATTING STRING = %s", &tmp_buf[0]); snprintf((char*)cur_info_p.info_type, SU_INFOSIZE, &tmp_buf[0], current_device_number, cur_nut_index); } else { /* FIXME: daisychain-whole, what to do? */ snprintf((char*)cur_info_p.info_type, SU_INFOSIZE, su_info_p->info_type, cur_nut_index); } } else { snprintf((char*)cur_info_p.info_type, SU_INFOSIZE, su_info_p->info_type, cur_nut_index); } } else upsdebugx(4, "Error: unknown template type '%s", type); /* check if default value is also a template */ if ((cur_info_p.dfl != NULL) && (strstr(su_info_p->dfl, "%i") != NULL)) { cur_info_p.dfl = (char *)xmalloc(SU_INFOSIZE); snprintf((char *)cur_info_p.dfl, SU_INFOSIZE, su_info_p->dfl, cur_nut_index); } if (cur_info_p.OID != NULL) { /* Special processing for daisychain */ if (!strncmp(type, "device", 6)) { if (current_device_number > 0) { snprintf((char *)cur_info_p.OID, SU_INFOSIZE, su_info_p->OID, current_device_number + device_template_offset); } /*else * FIXME: daisychain-whole, what to do? */ } else { /* Special processing for daisychain: * these outlet | outlet groups also include formatting info, * so we have to check if the daisychain is enabled, and if * the formatting info for it are in 1rst or 2nd position */ if (daisychain_enabled == TRUE) { if (su_info_p->flags & SU_TYPE_DAISY_1) { snprintf((char *)cur_info_p.OID, SU_INFOSIZE, su_info_p->OID, current_device_number + device_template_offset, cur_template_number); } else if (su_info_p->flags & SU_TYPE_DAISY_2) { snprintf((char *)cur_info_p.OID, SU_INFOSIZE, su_info_p->OID, cur_template_number + device_template_offset, current_device_number - device_template_offset); } else { /* Note: no device daisychain templating (SU_TYPE_DAISY_MASTER_ONLY)! */ snprintf((char *)cur_info_p.OID, SU_INFOSIZE, su_info_p->OID, cur_template_number); } } else { snprintf((char *)cur_info_p.OID, SU_INFOSIZE, su_info_p->OID, cur_template_number); } } #ifdef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL #pragma GCC diagnostic pop #endif /* add instant commands to the info database. */ if (SU_TYPE(su_info_p) == SU_TYPE_CMD) { upsdebugx(1, "Adding template command %s", cur_info_p.info_type); /* FIXME: only add if "su_ups_get(cur_info_p) == TRUE" */ if (mode == SU_WALKMODE_INIT) dstate_addcmd(cur_info_p.info_type); } else /* get and process this data */ status = get_and_process_data(mode, &cur_info_p); } else { /* server side (ABSENT) data */ su_setinfo(&cur_info_p, NULL); } /* set back the flag */ su_info_p->flags = cur_info_p.flags; } free((char*)cur_info_p.info_type); if (cur_info_p.OID != NULL) free((char*)cur_info_p.OID); if ((cur_info_p.dfl != NULL) && (strstr(su_info_p->dfl, "%i") != NULL)) free((char*)cur_info_p.dfl); } else { upsdebugx(1, "No %s present, discarding template definition...", type); } return status; } /* Return the type of template, according to a variable name. * Return: SU_OUTLET_GROUP, SU_OUTLET or 0 if not a template */ snmp_info_flags_t get_template_type(const char* varname) { if (!strncmp(varname, "outlet.group", 12)) { upsdebugx(4, "outlet.group template"); return SU_OUTLET_GROUP; } else if (!strncmp(varname, "outlet", 6)) { upsdebugx(4, "outlet template"); return SU_OUTLET; } else if (!strncmp(varname, "device", 6)) { upsdebugx(4, "device template"); return SU_DAISY; } else if (!strncmp(varname, "ambient", 7)) { upsdebugx(4, "ambient template"); return SU_AMBIENT_TEMPLATE; } else { upsdebugx(2, "Unknown template type: %s", varname); return 0; } } /* Extract the id number of an instantiated template. * Example: return '1' for type = 'outlet.1.desc', -1 if unknown */ int extract_template_number(snmp_info_flags_t template_type, const char* varname) { const char* item_number_ptr = NULL; int item_number = -1; if (template_type & SU_OUTLET_GROUP) item_number_ptr = &varname[12]; else if (template_type & SU_OUTLET) item_number_ptr = &varname[6]; else if (template_type & SU_DAISY) item_number_ptr = &varname[6]; else if (template_type & SU_AMBIENT_TEMPLATE) item_number_ptr = &varname[7]; else return -1; item_number = atoi(++item_number_ptr); upsdebugx(3, "%s: item %i", __func__, item_number); return item_number; } /* Extract the id number of a template from a variable name. * Example: return '1' for type = 'outlet.1.desc' */ static int extract_template_number_from_snmp_info_t(const char* varname) { return extract_template_number(get_template_type(varname), varname); } /* end of template functions */ /* process a single data from a walk */ bool_t get_and_process_data(int mode, snmp_info_t *su_info_p) { bool_t status = FALSE; upsdebugx(1, "%s: %s (%s)", __func__, su_info_p->info_type, su_info_p->OID); /* ok, update this element. */ status = su_ups_get(su_info_p); upsdebugx(4, "%s: su_ups_get returned %d", __func__, status); /* set stale flag if data is stale, clear if not. */ if (status == TRUE) { if (su_info_p->flags & SU_FLAG_STALE) { upslogx(LOG_INFO, "[%s] %s: data resumed for %s", upsname?upsname:device_name, __func__, su_info_p->info_type); su_info_p->flags &= ~SU_FLAG_STALE; } if(su_info_p->flags & SU_FLAG_UNIQUE) { /* We should be the only provider of this */ upsdebugx(4, "%s: unique flag", __func__); disable_competition(su_info_p); su_info_p->flags &= ~SU_FLAG_UNIQUE; } dstate_dataok(); } else { if (mode == SU_WALKMODE_INIT) { /* handle unsupported vars */ upsdebugx(4, "%s: Disabling var '%s'", __func__, su_info_p->info_type); su_info_p->flags &= ~SU_FLAG_OK; } else { if (!(su_info_p->flags & SU_FLAG_STALE)) { upslogx(LOG_INFO, "[%s] snmp_ups_walk: data stale for %s", upsname?upsname:device_name, su_info_p->info_type); su_info_p->flags |= SU_FLAG_STALE; } dstate_datastale(); } } return status; } /*********************************************************************** * Daisychain handling functions **********************************************************************/ /*! * Daisychained devices support init: * Determine the number of device(s) and if daisychain support has to be enabled * Set the values of devices_count (internal) and "device.count" (public) * Return TRUE if daisychain support is enabled, FALSE otherwise */ bool_t daisychain_init(void) { snmp_info_t *su_info_p = NULL; upsdebugx(1, "Checking if daisychain support has to be enabled"); su_info_p = su_find_info("device.count"); if (su_info_p != NULL) { upsdebugx(1, "Found device.count entry..."); /* Enable daisychain if there is a device.count entry. * This means that will have templates for entries */ daisychain_enabled = TRUE; /* Try to get the OID value, if it's not a template */ upsdebugx(3, "OID for device.count is %s", su_info_p->OID ? su_info_p->OID : ""); if ((su_info_p->OID != NULL) && (strstr(su_info_p->OID, "%i") == NULL)) { #if WITH_SNMP_LKP_FUN devices_count = -1; /* First test if we have a generic lookup function * FIXME: Check if the field type is a string? */ /* TODO: backport the 2x2 mapping function support * and this would be "fun_s2l" in resulting codebase */ if ( (su_info_p->oid2info != NULL) && (su_info_p->oid2info->nuf_s2l != NULL) ) { char buf[1024]; upsdebugx(2, "%s: using generic string-to-long lookup function", __func__); if (TRUE == nut_snmp_get_str(su_info_p->OID, buf, sizeof(buf), su_info_p->oid2info)) { devices_count = su_info_p->oid2info->nuf_s2l(buf); upsdebugx(2, "%s: got value '%ld'", __func__, devices_count); } } if (devices_count == -1) { #endif /* WITH_SNMP_LKP_FUN */ if (nut_snmp_get_int(su_info_p->OID, &devices_count) == TRUE) upsdebugx(1, "There are %ld device(s) present", devices_count); else { upsdebugx(1, "Error: can't get the number of device(s) present!"); upsdebugx(1, "Falling back to 1 device!"); devices_count = 1; } #if WITH_SNMP_LKP_FUN } #endif /* WITH_SNMP_LKP_FUN */ } /* Otherwise (template), use the guesstimation function to get * the number of devices present */ else { devices_count = guesstimate_template_count(su_info_p); upsdebugx(1, "Guesstimation: there are %ld device(s) present", devices_count); } /* Sanity check before data publication */ if (devices_count < 1) { devices_count = 1; daisychain_enabled = FALSE; upsdebugx(1, "Devices count is less than 1!"); upsdebugx(1, "Falling back to 1 device and disabling daisychain support!"); } else { /* Publish the device(s) count - even if just one * device was recognized at this moment */ dstate_setinfo("device.count", "%ld", devices_count); /* Also publish the default value for mfr and a forged model * for device.0 (whole daisychain) */ su_info_p = su_find_info("device.mfr"); if (su_info_p != NULL) { su_info_p = su_find_info("ups.mfr"); if (su_info_p != NULL) { su_setinfo(su_info_p, NULL); } } /* Forge model using device.type and number */ su_info_p = su_find_info("device.type"); if ((su_info_p != NULL) && (su_info_p->dfl != NULL)) { dstate_setinfo("device.model", "daisychain %s (1+%ld)", su_info_p->dfl, devices_count - 1); dstate_setinfo("device.type", "%s", su_info_p->dfl); } else { dstate_setinfo("device.model", "daisychain (1+%ld)", devices_count - 1); } } } else { daisychain_enabled = FALSE; upsdebugx(1, "No device.count entry found, daisychain support not needed"); } /* Finally, compute and store the base OID index and NUT offset */ su_info_p = su_find_info("device.model"); if (su_info_p != NULL) { device_template_index_base = base_snmp_template_index(su_info_p); upsdebugx(1, "%s: device_template_index_base = %i", __func__, device_template_index_base); device_template_offset = device_template_index_base - 1; upsdebugx(1, "%s: device_template_offset = %i", __func__, device_template_offset); } else { upsdebugx(1, "%s: No device.model entry found.", __func__); } upsdebugx(1, "%s: daisychain support is %s", __func__, (daisychain_enabled==TRUE)?"enabled":"disabled"); return daisychain_enabled; } /*********************************************************************** * SNMP handling functions **********************************************************************/ /* Process a data with regard to SU_OUTPHASES, SU_INPHASES and SU_BYPPHASES. * 3phases related data are disabled if the unit is 1ph, and conversely. * If the related phases data (input, output, bypass) is not yet valued, * retrieve it first. * * type: input, output, bypass * su_info_p: variable to process flags on * Return 0 if OK, 1 if the caller needs to "continue" the walk loop (i.e. * skip the present data) */ static int process_phase_data(const char* type, long *nb_phases, snmp_info_t *su_info_p) { snmp_info_t *tmp_info_p; char tmpOID[SU_INFOSIZE]; char tmpInfo[SU_INFOSIZE]; long tmpValue; snmp_info_flags_t phases_flag = 0, single_phase_flag = 0, three_phase_flag = 0; /* Phase specific data */ if (!strncmp(type, "input", 5)) { phases_flag = SU_INPHASES; single_phase_flag = SU_INPUT_1; three_phase_flag = SU_INPUT_3; } else if (!strncmp(type, "output", 6)) { phases_flag = SU_OUTPHASES; single_phase_flag = SU_OUTPUT_1; three_phase_flag = SU_OUTPUT_3; } else if (!strncmp(type, "input.bypass", 12)) { phases_flag = SU_BYPPHASES; single_phase_flag = SU_BYPASS_1; three_phase_flag = SU_BYPASS_3; } else { upsdebugx(2, "%s: unknown type '%s'", __func__, type); return 1; } /* Init the phase(s) info for this device, if not already done */ if (*nb_phases == -1) { upsdebugx(2, "%s phases information not initialized for device %i", type, current_device_number); memset(tmpInfo, 0, SU_INFOSIZE); /* daisychain specifics... */ if ( (daisychain_enabled == TRUE) && (current_device_number > 0) ) { /* Device(s) 2-N (slave(s)) need to append 'device.x' */ snprintf(tmpInfo, SU_INFOSIZE, "device.%i.%s.phases", current_device_number, type); } else { snprintf(tmpInfo, SU_INFOSIZE, "%s.phases", type); } if (dstate_getinfo(tmpInfo) == NULL) { /* {input,output,bypass}.phases is not yet published, * try to get the template for it */ snprintf(tmpInfo, SU_INFOSIZE, "%s.phases", type); tmp_info_p = su_find_info(tmpInfo); if (tmp_info_p != NULL) { memset(tmpOID, 0, SU_INFOSIZE); /* Daisychain specific: we may have a template (including * formatting string) that needs to be adapted! */ if (strchr(tmp_info_p->OID, '%') != NULL) { upsdebugx(2, "Found template, need to be adapted"); #ifdef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL #pragma GCC diagnostic push #endif #ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL #pragma GCC diagnostic ignored "-Wformat-nonliteral" #endif #ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_FORMAT_SECURITY #pragma GCC diagnostic ignored "-Wformat-security" #endif snprintf((char*)tmpOID, SU_INFOSIZE, tmp_info_p->OID, current_device_number + device_template_offset); #ifdef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL #pragma GCC diagnostic pop #endif } else { /* Otherwise, just point at what we found */ upsdebugx(2, "Found entry, not a template %s", tmp_info_p->OID); snprintf((char*)tmpOID, SU_INFOSIZE, "%s", tmp_info_p->OID); } /* Actually get the data */ if (nut_snmp_get_int(tmpOID, &tmpValue) == TRUE) { *nb_phases = tmpValue; } else { upsdebugx(2, "Can't get %s value. Defaulting to 1 %s.phase", tmpInfo, type); *nb_phases = 1; /* FIXME: return something or process using default?! */ } } else { upsdebugx(2, "No %s entry. Defaulting to 1 %s.phase", tmpInfo, type); *nb_phases = 1; /* FIXME: return something or process using default?! */ } } else { *nb_phases = atoi(dstate_getinfo(tmpInfo)); } /* Publish the number of phase(s) */ dstate_setinfo(tmpInfo, "%ld", *nb_phases); upsdebugx(2, "device %i has %ld %s.phases", current_device_number, *nb_phases, type); } /* FIXME: what to do here? else if (*nb_phases == 0) { return 1; } */ /* Actual processing of phases related data */ /* FIXME: don't clear SU_INPHASES in daisychain mode!!! ??? */ if (su_info_p->flags & single_phase_flag) { if (*nb_phases == 1) { upsdebugx(1, "%s_phases is 1", type); su_info_p->flags &= ~phases_flag; } else { upsdebugx(1, "%s_phases is not 1", type); su_info_p->flags &= ~SU_FLAG_OK; return 1; } } else if (su_info_p->flags & three_phase_flag) { if (*nb_phases == 3) { upsdebugx(1, "%s_phases is 3", type); su_info_p->flags &= ~phases_flag; } else { upsdebugx(1, "%s_phases is not 3", type); su_info_p->flags &= ~SU_FLAG_OK; return 1; } } else { upsdebugx(1, "%s_phases is %ld", type, *nb_phases); } return 0; /* FIXME: remap EXIT_SUCCESS to RETURN_SUCCESS */ } /* walk ups variables and set elements of the info array. */ bool_t snmp_ups_walk(int mode) { long *walked_input_phases, *walked_output_phases, *walked_bypass_phases; #ifdef COUNT_ITERATIONS /* Experimental workaround for stale info */ static unsigned long iterations = 0; #endif snmp_info_t *su_info_p; bool_t status = FALSE; if (mode == SU_WALKMODE_UPDATE) { semistatic_countdown--; if (semistatic_countdown < 0) semistatic_countdown = semistaticfreq; } /* Loop through all device(s) */ /* Note: considering "unitary" and "daisy-chained" devices, we have * several variables (and their values) that can come into play: * devices_count == 1 (default) AND daisychain_enabled == FALSE => unitary * devices_count > 1 (AND/OR?) daisychain_enabled == TRUE => a daisy-chain * The current_device_number == 0 in context of daisy-chain means the * "whole device" with composite or summary values that refer to the * chain as a virtual power device (e.g. might be a sum of outlet counts). * If daisychain_enabled == TRUE and current_device_number == 1 then we * are looking at the "master" device (one that we have direct/networked * connectivity to; the current_device_number > 1 is a slave (chained by * some proprietary link not visible from the outside) and represented * through the master - the slaves are not addressable directly. If the * master dies/reboots, connection to the whole chain is interrupted. * The dstate string names for daisychained sub-devices have the prefix * "device." and number embedded (e.g. "device.3.input.phases") except * for the whole (#0) virtual device, so it *seems* similar to unitary. */ for (current_device_number = (daisychain_enabled == FALSE && devices_count == 1 ? 1 : 0) ; current_device_number <= devices_count; current_device_number++) { upsdebugx(1, "%s: walking device %d", __func__, current_device_number); /* reinit the alarm buffer, before */ if (devices_count > 1) device_alarm_init(); /* better safe than sorry, check sanity on every loop cycle */ if (snmp_info == NULL) { fatalx(EXIT_FAILURE, "%s: snmp_info is not initialized", __func__); } if (snmp_info[0].info_type == NULL) { upsdebugx(1, "%s: WARNING: snmp_info is empty", __func__); } /* Loop through all mapping entries for the current_device_number */ for (su_info_p = &snmp_info[0]; (su_info_p != NULL && su_info_p->info_type != NULL) ; su_info_p++) { /* NOTE: Effectively below we do this: * switch(current_device_number) { * case 0: devtype = "daisychain whole" * case 1: devtype = "daisychain master" * default: devtype = "daisychain slave" * } * with a consideration for directly-addressable * slave devices (can be seen in chain via master, * but also queryable alone with an IP connection) * NOTE: until proven otherwise, "single" may mean * both (either) a daisy-chain enabled master device * without further connected "slave" devices, and * a directly addressable (IP-connected) "slave". * Possibly also an ePDU etc. that serves a MIB * which resolves "device.count" with the selected * subdriver. */ if (daisychain_enabled == TRUE) { upsdebugx(1, "%s: processing daisy-chain device %i (%s)", __func__, current_device_number, (current_device_number == 1) ? (devices_count > 1 ? "master" : "single") : (current_device_number > 1 ? "slave" : "whole") ); } else { upsdebugx(1, "%s: processing unitary device (%i)", __func__, current_device_number); } /* Check if we are asked to stop (reactivity++) */ if (exit_flag != 0) { upsdebugx(1, "%s: aborting because exit_flag was set", __func__); return TRUE; } /* Skip daisychain data count */ if (mode == SU_WALKMODE_INIT && (!strncmp(su_info_p->info_type, "device.count", 12))) { su_info_p->flags &= ~SU_FLAG_OK; continue; } /* FIXME: daisychain-whole, what to do? */ /* Note that when addressing the FIXME above, * if (current_device_number == 0 && daisychain_enabled == FALSE) * then we'd skip it still (unitary device is at current_device_number == 1)... */ /* skip the whole-daisychain for now */ if (current_device_number == 0 && daisychain_enabled == TRUE) { upsdebugx(1, "Skipping daisychain device.0 for now..."); continue; } /* skip instcmd, not linked to outlets */ if ((SU_TYPE(su_info_p) == SU_TYPE_CMD) && !(su_info_p->flags & SU_OUTLET) && !(su_info_p->flags & SU_OUTLET_GROUP)) { upsdebugx(1, "SU_CMD_MASK => %s", su_info_p->OID); continue; } /* skip elements we shouldn't show in update mode */ if ((mode == SU_WALKMODE_UPDATE) && !(su_info_p->flags & SU_FLAG_OK)) continue; /* skip semi-static elements in update mode: only parse when countdown reaches 0 */ if ((mode == SU_WALKMODE_UPDATE) && (su_info_p->flags & SU_FLAG_SEMI_STATIC)) { if (semistatic_countdown != 0) continue; upsdebugx(1, "Refreshing semi-static entry %s", su_info_p->OID); } /* skip static elements in update mode */ if ((mode == SU_WALKMODE_UPDATE) && (su_info_p->flags & SU_FLAG_STATIC)) continue; /* Set default value if we cannot fetch it */ /* and set static flag on this element. * Not applicable to outlets (need SU_FLAG_STATIC tagging) */ if ((su_info_p->flags & SU_FLAG_ABSENT) && !(su_info_p->flags & SU_OUTLET) && !(su_info_p->flags & SU_OUTLET_GROUP) && !(su_info_p->flags & SU_AMBIENT_TEMPLATE)) { if (mode == SU_WALKMODE_INIT) { if (su_info_p->dfl) { if ((daisychain_enabled == TRUE) && (devices_count > 1)) { if (current_device_number == 0) { su_setinfo(su_info_p, NULL); /* FIXME: daisychain-whole, what to do? */ } else { status = process_template(mode, "device", su_info_p); } } else { /* Set default value if we cannot fetch it from ups. */ su_setinfo(su_info_p, NULL); } } su_info_p->flags |= SU_FLAG_STATIC; } continue; } #ifdef COUNT_ITERATIONS /* check stale elements only on each PN_STALE_RETRY iteration. */ if ((su_info_p->flags & SU_FLAG_STALE) && (iterations % SU_STALE_RETRY) != 0) continue; #endif /* Filter 1-phase Vs 3-phase according to {input,output,bypass}.phase. * Non matching items are disabled, and flags are cleared at init * time */ /* Process input phases information */ walked_input_phases = &daisychain_info[current_device_number]->input_phases; if (su_info_p->flags & SU_INPHASES) { upsdebugx(1, "Check input_phases (%ld)", *walked_input_phases); if (process_phase_data("input", walked_input_phases, su_info_p) == 1) continue; } /* Process output phases information */ walked_output_phases = &daisychain_info[current_device_number]->output_phases; if (su_info_p->flags & SU_OUTPHASES) { upsdebugx(1, "Check output_phases (%ld)", *walked_output_phases); if (process_phase_data("output", walked_output_phases, su_info_p) == 1) continue; } /* Process bypass phases information */ walked_bypass_phases = &daisychain_info[current_device_number]->bypass_phases; if (su_info_p->flags & SU_BYPPHASES) { upsdebugx(1, "Check bypass_phases (%ld)", *walked_bypass_phases); if (process_phase_data("input.bypass", walked_bypass_phases, su_info_p) == 1) continue; } /* process template (outlet, outlet group, inc. daisychain) definition */ if (su_info_p->flags & SU_OUTLET) { /* Skip commands after init */ if ((SU_TYPE(su_info_p) == SU_TYPE_CMD) && (mode == SU_WALKMODE_UPDATE)) continue; else status = process_template(mode, "outlet", su_info_p); } else if (su_info_p->flags & SU_OUTLET_GROUP) { /* Skip commands after init */ if ((SU_TYPE(su_info_p) == SU_TYPE_CMD) && (mode == SU_WALKMODE_UPDATE)) continue; else status = process_template(mode, "outlet.group", su_info_p); } else if (su_info_p->flags & SU_AMBIENT_TEMPLATE) { /* Skip commands after init */ if ((SU_TYPE(su_info_p) == SU_TYPE_CMD) && (mode == SU_WALKMODE_UPDATE)) continue; else status = process_template(mode, "ambient", su_info_p); } else { /* if (daisychain_enabled == TRUE) { status = process_template(mode, "device", su_info_p); } else { */ /* get and process this data, including daisychain adaptation */ status = get_and_process_data(mode, su_info_p); /* } */ } } /* for (su_info_p... */ if (devices_count > 1) { /* commit the device alarm buffer */ device_alarm_commit(current_device_number); /* reinit the alarm buffer, after, not to pollute "device.0" */ device_alarm_init(); } } #ifdef COUNT_ITERATIONS iterations++; #endif return status; } bool_t su_ups_get(snmp_info_t *su_info_p) { static char buf[SU_INFOSIZE]; bool_t status; long value; double dvalue; const char *strValue = NULL; struct snmp_pdu ** pdu_array; struct snmp_pdu * current_pdu; alarms_info_t * alarms; int index = 0; char *format_char = NULL; int saved_current_device_number = -1; snmp_info_t *tmp_info_p = NULL; upsdebugx(2, "%s: %s %s", __func__, su_info_p->info_type, su_info_p->OID); /* Check if this is a daisychain template */ if (su_info_p->OID != NULL && (format_char = strchr(su_info_p->OID, '%')) != NULL ) { upsdebugx(3, "%s: calling instantiate_info() for " "daisy-chain template", __func__); tmp_info_p = instantiate_info(su_info_p, tmp_info_p); if (tmp_info_p != NULL) { upsdebugx(3, "%s: instantiate_info() returned " "non-null OID: %s", __func__, tmp_info_p->OID); /* adapt the OID */ if (su_info_p->OID != NULL) { #ifdef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL #pragma GCC diagnostic push #endif #ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL #pragma GCC diagnostic ignored "-Wformat-nonliteral" #endif #ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_FORMAT_SECURITY #pragma GCC diagnostic ignored "-Wformat-security" #endif snprintf((char *)tmp_info_p->OID, SU_INFOSIZE, su_info_p->OID, current_device_number + device_template_offset); #ifdef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL #pragma GCC diagnostic pop #endif upsdebugx(3, "%s: OID %s adapted into %s", __func__, su_info_p->OID, tmp_info_p->OID); } else { free_info(tmp_info_p); return FALSE; } /* adapt info_type */ if (su_info_p->info_type != NULL) { snprintf((char *)tmp_info_p->info_type, SU_INFOSIZE, "%s", su_info_p->info_type); } else { free_info(tmp_info_p); return FALSE; } su_info_p = tmp_info_p; } else { upsdebugx(2, "%s: can't instantiate template", __func__); return FALSE; } } else { /* Non-templated OID, still may be aimed at a * daisy-chained device (master of the chain * makes sense for IETF device.contact etc.). * BUT: It could be a direct request for earlier * resolved OID. So check for "device.N." too. */ if (daisychain_enabled == TRUE && devices_count > 1 && current_device_number > 0 ) { /* So we had a literal OID string, originally * Check for "device.N." in the string: */ char * varname = su_info_p->info_type; if (!strncmp(varname, "device.", 7) && (varname[7] >= '0' && varname[7] <= '9') ) { upsdebugx(2, "%s: keeping original " "current device == %d for " "non-templated daisy value", __func__, current_device_number); } else { upsdebugx(2, "%s: would fake " "current device == 1 for " "non-templated daisy value " "instead of %d", __func__, current_device_number); saved_current_device_number = current_device_number; } /* At this point we applied no hacks yet, * just stashed a non-negative value into * saved_current_device_number */ } } if (!strcasecmp(su_info_p->info_type, "ups.status")) { /* FIXME: daisychain status support! */ upsdebugx(2, "%s: requesting nut_snmp_get_int() for " "ups.status, with%s daisy template originally", __func__, (format_char!=NULL ? "" : "out")); status = nut_snmp_get_int(su_info_p->OID, &value); if (status == TRUE) { su_status_set(su_info_p, value); upsdebugx(2, "=> value: %ld", value); } else upsdebugx(2, "=> Failed"); free_info(tmp_info_p); return status; } /* Handle 'ups.alarm', 'outlet.n.alarm' and 3phase 'Lx.alarm', * nothing else! */ if (!strcmp(strrchr(su_info_p->info_type, '.'), ".alarm")) { upsdebugx(2, "Processing alarm: %s", su_info_p->info_type); /* FIXME: daisychain alarms support! */ upsdebugx(2, "%s: requesting nut_snmp_get_int() for " "some alarm, with%s daisy template originally", __func__, (format_char!=NULL ? "" : "out")); status = nut_snmp_get_int(su_info_p->OID, &value); if (status == TRUE) { su_alarm_set(su_info_p, value); upsdebugx(2, "=> value: %ld", value); } else upsdebugx(2, "=> Failed"); free_info(tmp_info_p); return status; } /* Walk a subtree (array) of alarms, composed of OID references. * The object referenced should not be accessible, but rather when * present, this means that the alarm condition is TRUE. * Only present in powerware-mib.c for now */ if (!strcasecmp(su_info_p->info_type, "ups.alarms")) { upsdebugx(2, "%s: requesting nut_snmp_get_int() for " "ups.alarms, with%s daisy template originally", __func__, (format_char!=NULL ? "" : "out")); status = nut_snmp_get_int(su_info_p->OID, &value); if (status == TRUE) { upsdebugx(2, "=> %ld alarms present", value); if (value > 0) { #if (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_PUSH_POP) && ( (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_TYPE_LIMITS) || (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_TAUTOLOGICAL_CONSTANT_OUT_OF_RANGE_COMPARE) ) # pragma GCC diagnostic push #endif #ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_TYPE_LIMITS # pragma GCC diagnostic ignored "-Wtype-limits" #endif #ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_TAUTOLOGICAL_CONSTANT_OUT_OF_RANGE_COMPARE # pragma GCC diagnostic ignored "-Wtautological-constant-out-of-range-compare" #endif if (value > INT_MAX) { #if (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_PUSH_POP) && ( (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_TYPE_LIMITS) || (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_TAUTOLOGICAL_CONSTANT_OUT_OF_RANGE_COMPARE) ) # pragma GCC diagnostic pop #endif upsdebugx(2, "=> truncating alarms present to INT_MAX"); value = INT_MAX; } pdu_array = nut_snmp_walk(su_info_p->OID, (int)value); if(pdu_array == NULL) { upsdebugx(2, "=> Walk failed"); return FALSE; } current_pdu = pdu_array[index]; while(current_pdu) { /* Retrieve the OID name, for comparison */ if (decode_oid(current_pdu, buf, sizeof(buf)) == TRUE) { alarms = alarms_info; while( alarms->OID ) { if(!strcmp(buf, alarms->OID)) { upsdebugx(3, "Alarm OID found => %s", alarms->OID); /* Check for ups.status value */ if (alarms->status_value) { upsdebugx(3, "Alarm value (status) found => %s", alarms->status_value); status_set(alarms->status_value); } /* Check for ups.alarm value */ if (alarms->alarm_value) { upsdebugx(3, "Alarm value (alarm) found => %s", alarms->alarm_value); alarm_set(alarms->alarm_value); } break; } alarms++; } } index++; current_pdu = pdu_array[index]; } nut_snmp_free(pdu_array); } } else { upsdebugx(2, "=> Failed"); } free_info(tmp_info_p); return status; } /* another special case */ if (!strcasecmp(su_info_p->info_type, "ambient.temperature")) { float temp=0; upsdebugx(2, "%s: requesting nut_snmp_get_int() for " "ambient.temperature, with%s daisy template originally", __func__, (format_char!=NULL ? "" : "out")); status = nut_snmp_get_int(su_info_p->OID, &value); if(status != TRUE) { free_info(tmp_info_p); return status; } /* only do this if using the IEM sensor */ if (!strcmp(su_info_p->OID, APCC_OID_IEM_TEMP)) { int su; long units; su = nut_snmp_get_int(APCC_OID_IEM_TEMP_UNIT, &units); /* no response, or units == F */ if ((su == FALSE) || (units == APCC_IEM_FAHRENHEIT)) temp = (value - 32) / 1.8; else temp = value; } else { temp = value * su_info_p->info_len; } snprintf(buf, sizeof(buf), "%.1f", temp); su_setinfo(su_info_p, buf); free_info(tmp_info_p); return TRUE; } /* special treatment for element without oid but with default value */ if (su_info_p->OID == NULL && su_info_p->dfl != NULL) { status = TRUE; /* FIXME: strlcpy() would fit here safer; not used in NUT yet */ strncpy(buf, su_info_p->dfl, sizeof(buf) - 1); buf[sizeof(buf) - 1] = '\0'; } else if (su_info_p->info_flags & ST_FLAG_STRING) { upsdebugx(2, "%s: requesting nut_snmp_get_str(), " "with%s daisy template originally", __func__, (format_char!=NULL ? "" : "out")); status = nut_snmp_get_str(su_info_p->OID, buf, sizeof(buf), su_info_p->oid2info); if (status == TRUE) { const char *fmt_buf; if (quirk_symmetra_threephase) { if (!strcasecmp(su_info_p->info_type, "input.transfer.low") || !strcasecmp(su_info_p->info_type, "input.transfer.high")) { /* Convert from three phase line-to-line voltage to line-to-neutral voltage */ double tmp_dvalue = atof(buf); tmp_dvalue = tmp_dvalue * 0.707; snprintf(buf, sizeof(buf), "%.2f", tmp_dvalue); } } /* Check if there is a string reformatting function */ fmt_buf = NULL; if ((fmt_buf = su_find_strval(su_info_p->oid2info, buf)) != NULL) { snprintf(buf, sizeof(buf), "%s", fmt_buf); } } } else { upsdebugx(2, "%s: requesting nut_snmp_get_int(), " "with%s daisy template originally", __func__, (format_char!=NULL ? "" : "out")); status = nut_snmp_get_int(su_info_p->OID, &value); if (status == TRUE) { if ((su_info_p->flags&SU_FLAG_NEGINVALID && value<0) || (su_info_p->flags&SU_FLAG_ZEROINVALID && value==0)) { su_info_p->flags &= ~SU_FLAG_OK; if(su_info_p->flags&SU_FLAG_UNIQUE) { disable_competition(su_info_p); su_info_p->flags &= ~SU_FLAG_UNIQUE; } free_info(tmp_info_p); return FALSE; } /* Check if there is a value to be looked up */ if ((strValue = su_find_infoval(su_info_p->oid2info, &value)) != NULL) snprintf(buf, sizeof(buf), "%s", strValue); else { /* Check if there is a need to publish decimal too, * i.e. if switching to integer does not cause a * loss of precision. * FIXME: Use remainder? is (dvalue%1.0)>0 cleaner? */ dvalue = value * su_info_p->info_len; if (f_equal((int)dvalue, dvalue)) snprintf(buf, sizeof(buf), "%i", (int)dvalue); else snprintf(buf, sizeof(buf), "%.2f", (float)dvalue); } } } if (status == TRUE) { if (saved_current_device_number >= 0) { current_device_number = 1; } su_setinfo(su_info_p, buf); if (saved_current_device_number >= 0) { current_device_number = saved_current_device_number; } upsdebugx(2, "=> value: %s", buf); } else { upsdebugx(2, "=> Failed"); } free_info(tmp_info_p); return status; } /* Common function for setting OIDs, from a NUT variable name, * used by su_setvar() and su_instcmd() * Params: * @mode: SU_MODE_INSTCMD for instant commands, SU_MODE_SETVAR for settings * @varname: name of variable or command to set the OID from * @val: value for settings, NULL for commands * Returns * STAT_SET_HANDLED if OK, * STAT_SET_INVALID or STAT_SET_UNKNOWN if the command / setting is not supported * STAT_SET_FAILED otherwise */ static int su_setOID(int mode, const char *varname, const char *val) { snmp_info_t *su_info_p = NULL; bool_t status; int retval = STAT_SET_FAILED; int cmd_offset = 0; /* FIXME: Does not seem to be actually used! */ long value = -1; /* normal (default), outlet, or outlet group variable */ snmp_info_flags_t vartype = 0; int daisychain_device_number = -1; /* variable without the potential "device.X" prefix, to find the template */ char *tmp_varname = NULL; char setOID[SU_INFOSIZE]; /* Used for potentially appending "device.X." to {outlet,outlet.group}.count */ char template_count_var[SU_BUFSIZE]; upsdebugx(2, "entering %s(%s, %s, %s)", __func__, (mode==SU_MODE_INSTCMD)?"instcmd":"setvar", varname, val); memset(setOID, 0, SU_INFOSIZE); memset(template_count_var, 0, SU_BUFSIZE); /* Check if it's a daisychain setting (device.x.varname), * or a non-daisy setting/value/cmd for the "master" unit * (as un-numbered device.varname), or something else? */ if (!strncmp(varname, "device", 6)) { if (varname[7] >= '0' && varname[7] <= '9') { /* Extract the (single-digit) device number * TODO: use strtol() or similar to support multi-digit * chains and offset tmp_varname inside varname properly */ daisychain_device_number = atoi(&varname[7]); /* Point at the command, without the "device.x" prefix */ tmp_varname = strdup(&varname[9]); snprintf(template_count_var, 10, "%s", varname); upsdebugx(2, "%s: got a daisychain %s (%s) for device %i", __func__, (mode==SU_MODE_INSTCMD)?"command":"setting", tmp_varname, daisychain_device_number); if (daisychain_device_number > devices_count) upsdebugx(2, "%s: item is out of bound (%i / %ld)", __func__, daisychain_device_number, devices_count); } else { /* Note: below we check if "OID" contains ".%i" template text * like we do in su_setinfo(); eventually we might get vendor * MIBs that do expose device.contact/location/description * for each link in the chain... */ if (daisychain_enabled == TRUE) { /* Is the original "device.varname" backed by a templated * OID string, so we can commonly set e.g. device.contact * for everything in the chain? */ su_info_p = su_find_info(varname); if (su_info_p && (su_info_p->OID == NULL || strstr(su_info_p->OID, ".%i") != NULL) ) { /* is templated or defaulted */ daisychain_device_number = 0; } else { daisychain_device_number = 1; } upsdebugx(2, "%s: got an un-numbered daisychain %s (%s), " "directing it to %s", __func__, (mode==SU_MODE_INSTCMD)?"command":"setting", varname, (daisychain_device_number==1)?"'master' device":"all devices" ); } else { /* No daisy, no poppy */ daisychain_device_number = 0; } tmp_varname = strdup(varname); } } else { daisychain_device_number = 0; tmp_varname = strdup(varname); } /* skip the whole-daisychain for now: * will send the settings to all devices in the daisychain */ if ((daisychain_enabled == TRUE) && (devices_count > 1) && (daisychain_device_number == 0)) { upsdebugx(2, "daisychain %s for device.0 are not yet supported!", (mode==SU_MODE_INSTCMD)?"command":"setting"); free(tmp_varname); return STAT_SET_INVALID; } /* Check if it is outlet / outlet.group, or standard variable */ if (strncmp(tmp_varname, "outlet", 6)) { su_info_p = su_find_info(tmp_varname); /* what if e.g. "device.x.contact" is not found as a "contact"? */ if (!su_info_p && strcmp(tmp_varname, varname)) { upsdebugx(2, "%s: did not find info for daisychained entry %s, " "retrying with original varname %s", __func__, tmp_varname, varname); su_info_p = su_find_info(varname); /* Still nothing? Try to revert from "device.1." * as a daisychain master? */ if (!su_info_p && daisychain_enabled == TRUE && devices_count > 1 && daisychain_device_number == 1 && !strncmp(varname, "device.1.", 9) ) { char tmp_buf[SU_INFOSIZE]; snprintf(tmp_buf, sizeof(tmp_buf), "device.%s", (varname + 9)); su_info_p = su_find_info(tmp_buf); if (su_info_p) { upsdebugx(2, "%s: finally found " "as daisy master revert %s", __func__, tmp_buf); free(tmp_varname); tmp_varname = strdup(tmp_buf); } } } } else { /* is indeed an outlet.* or device.x.outlet.* */ snmp_info_t *tmp_info_p; /* Point the outlet or outlet group number in the string */ const char *item_number_ptr = NULL; char *item_varname; /* Store the target outlet or group number */ int item_number = extract_template_number_from_snmp_info_t(tmp_varname); /* Store the total number of outlets or outlet groups */ int total_items = -1; /* Check if it is outlet / outlet.group */ vartype = get_template_type(tmp_varname); if (vartype == SU_OUTLET_GROUP) { snprintfcat(template_count_var, SU_BUFSIZE, "outlet.group.count"); total_items = atoi(dstate_getinfo(template_count_var)); item_number_ptr = &tmp_varname[12]; } else { snprintfcat(template_count_var, SU_BUFSIZE, "outlet.count"); total_items = atoi(dstate_getinfo(template_count_var)); item_number_ptr = &tmp_varname[6]; } upsdebugx(3, "Using count variable '%s'", template_count_var); item_number = atoi(++item_number_ptr); upsdebugx(3, "%s: item %i / %i", __func__, item_number, total_items); /* ensure the item number is supported (filtered upstream though)! */ if (item_number > total_items) { /* out of bound item number */ upsdebugx(2, "%s: item is out of bound (%i / %i)", __func__, item_number, total_items); return STAT_SET_INVALID; } /* find back the item template */ item_varname = (char *)xmalloc(SU_INFOSIZE); snprintf(item_varname, SU_INFOSIZE, "%s.%s%s", (vartype == SU_OUTLET)?"outlet":"outlet.group", "%i", strchr(item_number_ptr++, '.')); upsdebugx(3, "%s: searching for template\"%s\"", __func__, item_varname); tmp_info_p = su_find_info(item_varname); free(item_varname); /* for an snmp_info_t instance */ su_info_p = instantiate_info(tmp_info_p, su_info_p); /* check if default value is also a template */ if ((su_info_p->dfl != NULL) && (strstr(tmp_info_p->dfl, "%i") != NULL)) { su_info_p->dfl = (char *)xmalloc(SU_INFOSIZE); #ifdef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL #pragma GCC diagnostic push #endif #ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL #pragma GCC diagnostic ignored "-Wformat-nonliteral" #endif #ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_FORMAT_SECURITY #pragma GCC diagnostic ignored "-Wformat-security" #endif snprintf((char *)su_info_p->dfl, SU_INFOSIZE, tmp_info_p->dfl, item_number); #ifdef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL #pragma GCC diagnostic pop #endif } /* adapt the OID */ if (su_info_p->OID != NULL) { if (mode==SU_MODE_INSTCMD) { /* Workaround buggy Eaton Pulizzi implementation * which have different offsets index for data & commands! */ if (su_info_p->flags & SU_CMD_OFFSET) { cmd_offset++; upsdebugx(3, "Adding command offset, now: %i", cmd_offset); } } /* Special processing for daisychain: * these outlet | outlet groups also include formatting info, * so we have to check if the daisychain is enabled, and if * the formatting info for it are in 1rst or 2nd position */ #ifdef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL #pragma GCC diagnostic push #endif #ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL #pragma GCC diagnostic ignored "-Wformat-nonliteral" #endif #ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_FORMAT_SECURITY #pragma GCC diagnostic ignored "-Wformat-security" #endif if (daisychain_enabled == TRUE) { /* Note: daisychain_enabled == TRUE means that we have * daisychain template. However: * * when there are multiple devices, offset "-1" applies * since device.0 is a fake and actual devices start at * index 1 * * when there is only 1 device, offset doesn't apply since * the device index is "0" */ int daisychain_offset = 0; if (devices_count > 1) daisychain_offset = 1; if (su_info_p->flags & SU_TYPE_DAISY_1) { snprintf((char *)su_info_p->OID, SU_INFOSIZE, tmp_info_p->OID, daisychain_device_number - daisychain_offset, item_number); } else { snprintf((char *)su_info_p->OID, SU_INFOSIZE, tmp_info_p->OID, item_number, daisychain_device_number - daisychain_offset); } } else { snprintf((char *)su_info_p->OID, SU_INFOSIZE, tmp_info_p->OID, item_number); } #ifdef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL #pragma GCC diagnostic pop #endif } /* else, don't return STAT_SET_INVALID for mode==SU_MODE_SETVAR since we * can be setting a server side variable! */ else { if (mode==SU_MODE_INSTCMD) { free_info(su_info_p); return STAT_INSTCMD_UNKNOWN; } else { /* adapt info_type */ if (su_info_p->info_type != NULL) snprintf((char *)su_info_p->info_type, SU_INFOSIZE, "%s", tmp_varname); } } } /* Sanity check */ if (!su_info_p || !su_info_p->info_type || !(su_info_p->flags & SU_FLAG_OK)) { upsdebugx(2, "%s: info element unavailable %s", __func__, varname); /* Free template (outlet and outlet.group) */ free_info(su_info_p); if (tmp_varname != NULL) free(tmp_varname); return STAT_SET_UNKNOWN; } /* set value into the device, using the provided one, or the default one otherwise */ if (mode==SU_MODE_INSTCMD) { /* Sanity check: commands should either have a value or a default */ if ( (val == NULL) && (su_info_p->dfl == NULL) ) { upsdebugx(1, "%s: cannot execute command '%s': a provided or default value is needed!", __func__, varname); return STAT_SET_INVALID; } } if (su_info_p->info_flags & ST_FLAG_STRING) { status = nut_snmp_set_str(su_info_p->OID, val ? val : su_info_p->dfl); } else { if (mode==SU_MODE_INSTCMD) { if ( !str_to_long(val ? val : su_info_p->dfl, &value, 10) ) { upsdebugx(1, "%s: cannot execute command '%s': value is not a number!", __func__, varname); return STAT_SET_INVALID; } } else { /* non string data may imply a value lookup */ if (su_info_p->oid2info) { value = su_find_valinfo(su_info_p->oid2info, val ? val : su_info_p->dfl); } else { /* Convert value and apply multiplier */ if ( !str_to_long(val, &value, 10) ) { upsdebugx(1, "%s: cannot set '%s': value is not a number!", __func__, varname); return STAT_SET_INVALID; } value = (long)((double)value / su_info_p->info_len); } } /* Actually apply the new value */ if (SU_TYPE(su_info_p) == SU_TYPE_TIME) { status = nut_snmp_set_time(su_info_p->OID, value); } else { status = nut_snmp_set_int(su_info_p->OID, value); } } /* Process result */ if (status == FALSE) { if (mode==SU_MODE_INSTCMD) upsdebugx(1, "%s: cannot execute command '%s'", __func__, varname); else upsdebugx(1, "%s: cannot set value %s on OID %s", __func__, val, su_info_p->OID); retval = STAT_SET_FAILED; } else { retval = STAT_SET_HANDLED; if (mode==SU_MODE_INSTCMD) upsdebugx(1, "%s: successfully sent command %s", __func__, varname); else { upsdebugx(1, "%s: successfully set %s to \"%s\"", __func__, varname, val); /* update info array: call dstate_setinfo, since flags and aux are * already published, and this saves us some processing */ dstate_setinfo(varname, "%s", val); } } /* Free template (outlet and outlet.group) */ if (!strncmp(tmp_varname, "outlet", 6)) free_info(su_info_p); free(tmp_varname); return retval; } /* set r/w INFO_ element to a value. * FIXME: make a common function with su_instcmd! */ int su_setvar(const char *varname, const char *val) { return su_setOID(SU_MODE_SETVAR, varname, val); } /* Daisychain-aware function to add instant commands: * Every command that is valid for a device has to be added for device.0 * This then allows to composite commands, called on device.0 and executed * on all devices of the daisychain */ int su_addcmd(snmp_info_t *su_info_p) { upsdebugx(2, "entering %s(%s)", __func__, su_info_p->info_type); if (daisychain_enabled == TRUE) { /* FIXME?: daisychain */ for (current_device_number = 1 ; current_device_number <= devices_count ; current_device_number++) { process_template(SU_WALKMODE_INIT, "device", su_info_p); } } else { if (nut_snmp_get(su_info_p->OID) != NULL) { dstate_addcmd(su_info_p->info_type); upsdebugx(1, "%s: adding command '%s'", __func__, su_info_p->info_type); } } return 0; } /* process instant command and take action. */ int su_instcmd(const char *cmdname, const char *extradata) { return su_setOID(SU_MODE_INSTCMD, cmdname, extradata); } /* FIXME: the below functions can be removed since these were for loading * the mib2nut information from a file instead of the .h definitions... */ /* return 1 if usable, 0 if not */ static int parse_mibconf_args(size_t numargs, char **arg) { bool_t ret; /* everything below here uses up through arg[1] */ if (numargs < 6) return 0; /* */ /* special case for setting some OIDs value at driver startup */ if (!strcmp(arg[0], "init")) { /* set value. */ if (!strcmp(arg[1], "str")) { ret = nut_snmp_set_str(arg[3], arg[4]); } else { ret = nut_snmp_set_int(arg[3], strtol(arg[4], NULL, 0)); } if (ret == FALSE) upslogx(LOG_ERR, "%s: cannot set value %s for %s", __func__, arg[4], arg[3]); else upsdebugx(1, "%s: successfully set %s to \"%s\"", __func__, arg[0], arg[4]); return 1; } /* TODO: create the lookup table */ upsdebugx(2, "%s, %s, %s, %s, %s, %s", arg[0], arg[1], arg[2], arg[3], arg[4], arg[5]); return 1; } /* called for fatal errors in parseconf like malloc failures */ static void mibconf_err(const char *errmsg) { upslogx(LOG_ERR, "Fatal error in parseconf (*mib.conf): %s", errmsg); } /* load *mib.conf into an snmp_info_t structure */ void read_mibconf(char *mib) { char fn[SMALLBUF]; PCONF_CTX_t ctx; upsdebugx(2, "SNMP UPS driver: entering %s(%s)", __func__, mib); snprintf(fn, sizeof(fn), "%s/snmp/%s.conf", CONFPATH, mib); pconf_init(&ctx, mibconf_err); if (!pconf_file_begin(&ctx, fn)) fatalx(EXIT_FAILURE, "%s", ctx.errmsg); while (pconf_file_next(&ctx)) { if (pconf_parse_error(&ctx)) { upslogx(LOG_ERR, "Parse error: %s:%d: %s", fn, ctx.linenum, ctx.errmsg); continue; } if (ctx.numargs < 1) continue; if (!parse_mibconf_args(ctx.numargs, ctx.arglist)) { unsigned int i; char errmsg[SMALLBUF]; snprintf(errmsg, sizeof(errmsg), "mib.conf: invalid directive"); for (i = 0; i < ctx.numargs; i++) snprintfcat(errmsg, sizeof(errmsg), " %s", ctx.arglist[i]); upslogx(LOG_WARNING, "%s", errmsg); } } pconf_finish(&ctx); } nut-2.8.1/drivers/generic_gpio_libgpiod.h0000644000175000017500000000244314501607135015410 00000000000000/* generic_gpio_libgpiod.h - gpiod based NUT driver definitions for GPIO attached UPS devices * * Copyright (C) * 2023 Modris Berzonis * * 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 2 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, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #ifndef GENERIC_GPIO_LIBGPIOD_H_SEEN #define GENERIC_GPIO_LIBGPIOD_H_SEEN #include typedef struct libgpiod_data_t { struct gpiod_chip *gpioChipHandle; /* libgpiod chip handle when opened */ struct gpiod_line_bulk gpioLines; /* libgpiod lines to monitor */ struct gpiod_line_bulk gpioEventLines; /* libgpiod lines for event monitoring */ } libgpiod_data; #endif /* GENERIC_GPIO_LIBGPIOD_H_SEEN */ nut-2.8.1/drivers/bcmxcp_usb.c0000644000175000017500000004204214501607135013224 00000000000000#include "main.h" #include "bcmxcp.h" #include "bcmxcp_io.h" #include "common.h" #include "usb-common.h" #include "timehead.h" #include "nut_stdint.h" /* for uint16_t */ #include #include #include #include #define SUBDRIVER_NAME "USB communication subdriver" #define SUBDRIVER_VERSION "0.27" /* communication driver description structure */ upsdrv_info_t comm_upsdrv_info = { SUBDRIVER_NAME, SUBDRIVER_VERSION, NULL, 0, { NULL } }; #define MAX_TRY 4 #define MAX_TRY_OPENUSB 32 /* Powerware */ #define POWERWARE 0x0592 /* Phoenixtec Power Co., Ltd */ #define PHOENIXTEC 0x06da /* Hewlett Packard */ #define HP_VENDORID 0x03f0 static USBDevice_t curDevice; /* USB functions */ usb_dev_handle *nutusb_open(const char *port); int nutusb_close(usb_dev_handle *dev_h, const char *port); /* unified failure reporting: call these often */ void nutusb_comm_fail(const char *fmt, ...) __attribute__ ((__format__ (__printf__, 1, 2))); void nutusb_comm_good(void); /* function pointer, set depending on which device is used */ /* FIXME? Use usb_ctrl_* typedefs*/ static int (*usb_set_descriptor)(usb_dev_handle *udev, unsigned char type, unsigned char index, void *buf, size_t size); /* usb_set_descriptor() for Powerware devices */ /* FIXME? Use usb_ctrl_* typedefs*/ static int usb_set_powerware(usb_dev_handle *udev, unsigned char type, unsigned char index, void *buf, size_t size) { assert (size < INT_MAX); return usb_control_msg(udev, USB_ENDPOINT_OUT, USB_REQ_SET_DESCRIPTOR, (type << 8) + index, 0, buf, (int)size, 1000); } static void *powerware_ups(USBDevice_t *device) { NUT_UNUSED_VARIABLE(device); usb_set_descriptor = &usb_set_powerware; return NULL; } /* usb_set_descriptor() for Phoenixtec devices */ /* FIXME? Use usb_ctrl_* typedefs*/ static int usb_set_phoenixtec(usb_dev_handle *udev, unsigned char type, unsigned char index, void *buf, size_t size) { NUT_UNUSED_VARIABLE(index); NUT_UNUSED_VARIABLE(type); assert (size < INT_MAX); return usb_control_msg(udev, 0x42, 0x0d, (0x00 << 8) + 0x0, 0, buf, (int)size, 1000); } static void *phoenixtec_ups(USBDevice_t *device) { NUT_UNUSED_VARIABLE(device); usb_set_descriptor = &usb_set_phoenixtec; return NULL; } /* USB IDs device table */ static usb_device_id_t pw_usb_device_table[] = { /* various models */ { USB_DEVICE(POWERWARE, 0x0002), &powerware_ups }, /* various models */ { USB_DEVICE(PHOENIXTEC, 0x0002), &phoenixtec_ups }, /* T500 */ { USB_DEVICE(HP_VENDORID, 0x1f01), &phoenixtec_ups }, /* T750 */ { USB_DEVICE(HP_VENDORID, 0x1f02), &phoenixtec_ups }, /* Terminating entry */ { 0, 0, NULL } }; /* limit the amount of spew that goes in the syslog when we lose the UPS */ #define USB_ERR_LIMIT 10 /* start limiting after 10 in a row */ #define USB_ERR_RATE 10 /* then only print every 10th error */ #define XCP_USB_TIMEOUT 5000 /* in msec */ /* global variables */ static usb_dev_handle *upsdev = NULL; extern int exit_flag; static unsigned int comm_failures = 0; /* Functions implementations */ void send_read_command(unsigned char command) { unsigned char buf[4]; if (upsdev) { buf[0] = PW_COMMAND_START_BYTE; buf[1] = 0x01; /* data length */ buf[2] = command; /* command to send */ buf[3] = calc_checksum(buf); /* checksum */ upsdebug_hex (3, "send_read_command", buf, 4); usb_set_descriptor(upsdev, USB_DT_STRING, 4, buf, 4); /* FIXME: Ignore error */ } } void send_write_command(unsigned char *command, size_t command_length) { unsigned char sbuf[128]; if (upsdev) { /* Prepare the send buffer */ sbuf[0] = PW_COMMAND_START_BYTE; sbuf[1] = (unsigned char)(command_length); memcpy(sbuf+2, command, command_length); command_length += 2; /* Add checksum */ sbuf[command_length] = calc_checksum(sbuf); command_length += 1; upsdebug_hex (3, "send_write_command", sbuf, command_length); usb_set_descriptor(upsdev, USB_DT_STRING, 4, sbuf, command_length); /* FIXME: Ignore error */ } } #define PW_HEADER_SIZE (PW_HEADER_LENGTH + 1) #define PW_CMD_BUFSIZE 256 /* get the answer of a command from the ups. And check that the answer is for this command */ ssize_t get_answer(unsigned char *data, unsigned char command) { unsigned char buf[PW_CMD_BUFSIZE], *my_buf = buf; ssize_t res; int endblock, need_data; long elapsed_time; /* milliseconds */ ssize_t tail; size_t bytes_read, end_length, length; unsigned char block_number, sequence, seq_num; struct timeval start_time, now; if (upsdev == NULL) return -1; need_data = PW_HEADER_SIZE; /* 4 - cmd response header length, 1 for csum */ end_length = 0; /* total length of sequence(s), not counting header(s) */ endblock = 0; /* signal the last sequence in the block */ bytes_read = 0; /* total length of data read, including XCP header */ res = 0; elapsed_time = 0; seq_num = 1; /* current theoric sequence */ upsdebugx(1, "entering get_answer(%x)", command); /* Store current time */ gettimeofday(&start_time, NULL); memset(&buf, 0x0, PW_CMD_BUFSIZE); #ifdef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_UNREACHABLE_CODE #pragma GCC diagnostic push #endif #ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_UNREACHABLE_CODE #pragma GCC diagnostic ignored "-Wunreachable-code" #endif #ifdef __clang__ #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wunreachable-code" #endif /* Stay ahead of possible redefinitions... */ assert (XCP_USB_TIMEOUT < INT_MAX); #ifdef __clang__ #pragma clang diagnostic pop #endif #ifdef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_UNREACHABLE_CODE #pragma GCC diagnostic pop #endif while ( (!endblock) && ((XCP_USB_TIMEOUT - elapsed_time) > 0) ) { /* Get (more) data if needed */ if (need_data > 0) { res = usb_interrupt_read(upsdev, 0x81, (usb_ctrl_charbuf) buf + bytes_read, 128, (int)(XCP_USB_TIMEOUT - elapsed_time)); /* Update time */ gettimeofday(&now, NULL); elapsed_time = (now.tv_sec - start_time.tv_sec)*1000 + (now.tv_usec - start_time.tv_usec)/1000; /* Check libusb return value */ if (res < 0) { /* Clear any possible endpoint stalls */ usb_clear_halt(upsdev, 0x81); /* continue; */ /* FIXME: seems a break would be better! */ break; } /* this seems to occur on XSlot USB card */ if (res == 0) { /* FIXME: */ continue; } /* Else, we got some input bytes */ bytes_read += (size_t)res; need_data -= res; upsdebug_hex(1, "get_answer", buf, bytes_read); } if (need_data > 0) /* We need more data */ continue; /* Now validate XCP frame */ /* Check header */ if ( my_buf[0] != PW_COMMAND_START_BYTE ) { upsdebugx(2, "get_answer: wrong header 0xab vs %02x", my_buf[0]); /* Sometime we read something wrong. bad cables? bad ports? */ my_buf = memchr(my_buf, PW_COMMAND_START_BYTE, bytes_read); if (!my_buf) return -1; } /* Read block number byte */ block_number = my_buf[1]; upsdebugx(1, "get_answer: block_number = %x", block_number); /* Check data length byte (remove the header length) */ length = my_buf[2]; upsdebugx(3, "get_answer: data length = %" PRIuSIZE, length); if (bytes_read < (length + PW_HEADER_SIZE)) { if (need_data < 0) --need_data; /* count zerro byte too */ need_data += length + 1; /* packet lenght + checksum */ upsdebugx(2, "get_answer: need to read %d more data", need_data); continue; } /* Check if Length conforms to XCP (121 for normal, 140 for Test mode) */ /* Use the more generous length for testing */ if (length > 140) { upsdebugx(2, "get_answer: bad length"); return -1; } if (bytes_read >= SSIZE_MAX) { upsdebugx(2, "get_answer: bad length (incredibly large read)"); return -1; } /* Test the Sequence # */ sequence = my_buf[3]; if ((sequence & PW_SEQ_MASK) != seq_num) { nutusb_comm_fail("get_answer: not the right sequence received %x!!!\n", (sequence & PW_SEQ_MASK)); return -1; } else { upsdebugx(2, "get_answer: sequence number (%x) is ok", (sequence & PW_SEQ_MASK)); } /* Validate checksum */ if (!checksum_test(my_buf)) { nutusb_comm_fail("get_answer: checksum error! "); return -1; } else { upsdebugx(2, "get_answer: checksum is ok"); } /* Check if it's the last sequence */ if (sequence & PW_LAST_SEQ) { /* we're done receiving data */ upsdebugx(2, "get_answer: all data received"); endblock = 1; } else { seq_num++; upsdebugx(2, "get_answer: next sequence is %d", seq_num); } /* copy the current valid XCP frame back */ memcpy(data+end_length, my_buf + 4, length); /* increment pointers to process the next sequence */ end_length += length; /* Work around signedness of comparison result, SSIZE_MAX checked above: */ tail = (ssize_t)bytes_read; tail -= (ssize_t)(length + PW_HEADER_SIZE); if (tail > 0) my_buf = memmove(&buf[0], my_buf + length + PW_HEADER_SIZE, (size_t)tail); else if (tail == 0) my_buf = &buf[0]; else { /* if (tail < 0) */ upsdebugx(1, "get_answer(): did not expect to get negative tail size: %" PRIiSIZE, tail); return -1; } bytes_read = (size_t)tail; } upsdebug_hex (5, "get_answer", data, end_length); assert (end_length < SSIZE_MAX); return (ssize_t)end_length; } /* Sends a single command (length=1). and get the answer */ ssize_t command_read_sequence(unsigned char command, unsigned char *data) { ssize_t bytes_read = 0; size_t retry = 0; while ((bytes_read < 1) && (retry < 5)) { send_read_command(command); bytes_read = get_answer(data, command); retry++; } if (bytes_read < 1) { nutusb_comm_fail("Error executing command"); dstate_datastale(); return -1; } return bytes_read; } /* Sends a setup command (length > 1) */ ssize_t command_write_sequence(unsigned char *command, size_t command_length, unsigned char *answer) { ssize_t bytes_read = 0; size_t retry = 0; while ((bytes_read < 1) && (retry < 5)) { send_write_command(command, command_length); sleep(PW_SLEEP); bytes_read = get_answer(answer, command[0]); retry ++; } if (bytes_read < 1) { nutusb_comm_fail("Error executing command"); dstate_datastale(); return -1; } return bytes_read; } void upsdrv_comm_good(void) { nutusb_comm_good(); } void upsdrv_initups(void) { upsdev = nutusb_open("USB"); } void upsdrv_cleanup(void) { upslogx(LOG_ERR, "CLOSING\n"); nutusb_close(upsdev, "USB"); free(curDevice.Vendor); free(curDevice.Product); free(curDevice.Serial); free(curDevice.Bus); free(curDevice.Device); } void upsdrv_reconnect(void) { dstate_setinfo("driver.state", "reconnect.trying"); upsdebugx(4, "=================================================="); upsdebugx(4, "= device has been disconnected, try to reconnect ="); upsdebugx(4, "=================================================="); nutusb_close(upsdev, "USB"); upsdev = NULL; upsdrv_initups(); dstate_setinfo("driver.state", "quiet"); } /* USB functions */ static void nutusb_open_error(const char *port) __attribute__((noreturn)); static void nutusb_open_error(const char *port) { printf("Unable to find POWERWARE UPS device on USB bus (%s)\n\n", port); printf("Things to try:\n\n"); printf(" - Connect UPS device to USB bus\n\n"); printf(" - Run this driver as another user (upsdrvctl -u or 'user=...' in ups.conf).\n"); printf(" See upsdrvctl(8) and ups.conf(5).\n\n"); fatalx(EXIT_FAILURE, "Fatal error: unusable configuration"); } /* FIXME: this part of the opening can go into common... */ static usb_dev_handle *open_powerware_usb(void) { #if WITH_LIBUSB_1_0 libusb_device **devlist; ssize_t devcount = 0; libusb_device_handle *udev; struct libusb_device_descriptor dev_desc; uint8_t bus_num; /* TODO: consider device_addr */ int i; devcount = libusb_get_device_list(NULL, &devlist); if (devcount <= 0) fatal_with_errno(EXIT_FAILURE, "No USB device found"); for (i = 0; i < devcount; i++) { libusb_device *device = devlist[i]; libusb_get_device_descriptor(device, &dev_desc); if (dev_desc.bDeviceClass != LIBUSB_CLASS_PER_INTERFACE) { continue; } curDevice.VendorID = dev_desc.idVendor; curDevice.ProductID = dev_desc.idProduct; bus_num = libusb_get_bus_number(device); curDevice.Bus = (char *)malloc(4); if (curDevice.Bus == NULL) { libusb_free_device_list(devlist, 1); fatal_with_errno(EXIT_FAILURE, "Out of memory"); } sprintf(curDevice.Bus, "%03d", bus_num); /* FIXME: we should also retrieve * dev->descriptor.iManufacturer * dev->descriptor.iProduct * dev->descriptor.iSerialNumber * as in libusb.c->libusb_open() * This is part of the things to put in common... */ if (is_usb_device_supported(pw_usb_device_table, &curDevice) == SUPPORTED) { libusb_open(device, &udev); libusb_free_device_list(devlist, 1); return udev; } } libusb_free_device_list(devlist, 1); #else /* not WITH_LIBUSB_1_0 */ struct usb_bus *busses = usb_get_busses(); struct usb_bus *bus; for (bus = busses; bus; bus = bus->next) { struct usb_device *dev; for (dev = bus->devices; dev; dev = dev->next) { if (dev->descriptor.bDeviceClass != USB_CLASS_PER_INTERFACE) { continue; } curDevice.VendorID = dev->descriptor.idVendor; curDevice.ProductID = dev->descriptor.idProduct; curDevice.Bus = xstrdup(bus->dirname); /* FIXME: we should also retrieve * dev->descriptor.iManufacturer * dev->descriptor.iProduct * dev->descriptor.iSerialNumber * as in libusb.c->libusb_open() * This is part of the things to put in common... */ if (is_usb_device_supported(pw_usb_device_table, &curDevice) == SUPPORTED) { return usb_open(dev); } } } #endif /* WITH_LIBUSB_1_0 */ return 0; } usb_dev_handle *nutusb_open(const char *port) { int dev_claimed = 0; usb_dev_handle *dev_h = NULL; int retry, errout = 0; int ret = 0; upsdebugx(1, "entering nutusb_open()"); warn_if_bad_usb_port_filename(device_path); /* Initialize Libusb */ #if WITH_LIBUSB_1_0 if (libusb_init(NULL) < 0) { libusb_exit(NULL); fatal_with_errno(EXIT_FAILURE, "Failed to init libusb 1.0"); } #else /* not WITH_LIBUSB_1_0 */ usb_init(); usb_find_busses(); usb_find_devices(); #endif /* WITH_LIBUSB_1_0 */ /* for (retry = 0; dev_h == NULL && retry < MAX_TRY_OPENUSB; retry++) */ for (retry = 0; retry < MAX_TRY ; retry++) { dev_h = open_powerware_usb(); if (!dev_h) { upsdebugx(1, "Can't open POWERWARE USB device"); errout = 1; } else { upsdebugx(1, "device %s opened successfully", curDevice.Bus); errout = 0; #ifdef WIN32 if ((ret = usb_set_configuration(dev_h, 1)) < 0) { upsdebugx(1, "Can't set POWERWARE USB configuration: %s", nut_usb_strerror(ret)); errout = 1; } #endif if ((ret = usb_claim_interface(dev_h, 0)) < 0) { upsdebugx(1, "Can't claim POWERWARE USB interface: %s", nut_usb_strerror(ret)); errout = 1; } else { dev_claimed = 1; errout = 0; } /* FIXME: the above part of the opening can go into common... up to here at least */ if ((ret = usb_clear_halt(dev_h, 0x81)) < 0) { upsdebugx(1, "Can't reset POWERWARE USB endpoint: %s", nut_usb_strerror(ret)); if (dev_claimed) usb_release_interface(dev_h, 0); usb_reset(dev_h); sleep(5); /* Wait reconnect */ errout = 1; } else errout = 0; } /* Test if we succeeded */ if ( (dev_h != NULL) && dev_claimed && (errout == 0) ) break; else { /* Clear errors, and try again */ errout = 0; } } if (!dev_h && !dev_claimed && retry == MAX_TRY) errout = 1; else return dev_h; if (dev_h && dev_claimed) usb_release_interface(dev_h, 0); nutusb_close(dev_h, port); if (errout == 1) nutusb_open_error(port); return NULL; } /* FIXME: this part can go into common... */ int nutusb_close(usb_dev_handle *dev_h, const char *port) { int ret = 0; NUT_UNUSED_VARIABLE(port); if (dev_h) { usb_release_interface(dev_h, 0); #if WITH_LIBUSB_1_0 libusb_close(dev_h); libusb_exit(NULL); #else ret = usb_close(dev_h); #endif } return ret; } void nutusb_comm_fail(const char *fmt, ...) { int ret; char why[SMALLBUF]; va_list ap; /* this means we're probably here because select was interrupted */ if (exit_flag != 0) return; /* ignored, since we're about to exit anyway */ comm_failures++; if ((comm_failures == USB_ERR_LIMIT) || ((comm_failures % USB_ERR_RATE) == 0)) { upslogx(LOG_WARNING, "Warning: excessive comm failures, " "limiting error reporting"); } /* once it's past the limit, only log once every USB_ERR_LIMIT calls */ if ((comm_failures > USB_ERR_LIMIT) && ((comm_failures % USB_ERR_LIMIT) != 0)) { /* Try reconnection */ upsdebugx(1, "Got to reconnect!\n"); upsdrv_reconnect(); return; } /* generic message if the caller hasn't elaborated */ if (!fmt) { upslogx(LOG_WARNING, "Communications with UPS lost - check cabling"); return; } va_start(ap, fmt); ret = vsnprintf(why, sizeof(why), fmt, ap); va_end(ap); if ((ret < 1) || (ret >= (int) sizeof(why))) upslogx(LOG_WARNING, "usb_comm_fail: vsnprintf needed " "more than %d bytes", (int)sizeof(why)); upslogx(LOG_WARNING, "Communications with UPS lost: %s", why); } void nutusb_comm_good(void) { if (comm_failures == 0) return; upslogx(LOG_NOTICE, "Communications with UPS re-established"); comm_failures = 0; } nut-2.8.1/drivers/microsol-apc.h0000644000175000017500000002051314500336654013477 00000000000000/* microsol-apc.h - APC Back-UPS BR series UPS driver Copyright (C) 2004 Silvino B. Magalhaes 2019 Roberto Panerai Velloso 2021 Ygor A. S. Regados 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 2 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, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 2021/03/19 - Version 0.70 - Initial release, based on solis driver */ #ifndef INCLUDED_MICROSOL_APC_H #define INCLUDED_MICROSOL_APC_H #define MODEL_COUNT 3 /* Supported UPS models */ static const unsigned int MODELS[MODEL_COUNT] = { 183 /* APC Back-UPS BZ2200I-BR */ , 190 /* APC Back-UPS BZ1500-BR */ , 191 /* APC Back-UPS BZ2200BI-BR */ }; /* Note: int type here is aligned with the "nominal_power" * variable in microsol-common.h and many related drivers. */ static const int NOMINAL_POWER[MODEL_COUNT] = { 2200 /* Model 183 */ , 1500 /* Model 190 */ , 2200 /* Model 191 */ }; /* Curves for output voltage (depends on relay state and battery state) * Second index: On-line (0) or On-battery (1) * Third index: Electric relay state */ /* For on-line UPS */ static const float OUTPUT_VOLTAGE_MULTIPLIER_A[MODEL_COUNT][2][8] = { { { 1.831, 1.831, 1.831, 1.831, 1.831, 1.831, 1.831, 1.831}, { 0.1566, 0.1566, 0.1566, 0.1566, 0.1566, 0.1566, 0.1566, 0.1566} } /* Model 183 */ , { { 0.9266, 0.9266, 0.9266, 0.9266, 0.9266, 0.9266, 0.9266, 0.9266}, { 5.59, 9.47, 13.7, 0.0, 0.0, 0.0, 0.0, 0.0} } /* Model 190 */ , { { 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00}, { 1.26, 1.26, 1.26, 1.26, 1.26, 1.26, 1.26, 1.26} } /* Model 191 */ }; static const float OUTPUT_VOLTAGE_MULTIPLIER_B[MODEL_COUNT][2][8] = { { { -2.1374, -2.1374, -2.1374, -2.1374, -2.1374, -2.1374, -2.1374, -2.1374}, { 204.93, 204.93, 204.93, 204.93, 204.93, 204.93, 204.93, 204.93} } /* Model 183 */ , { { 5.0694, 5.0694, 5.0694, 5.0694, 5.0694, 5.0694, 5.0694, 5.0694}, { 5.4, 6.5, 17.6, 0.0, 0.0, 0.0, 0.0, 0.0} } /* Model 190 */ , { { 20.0, 20.0, 20.0, 20.0, 20.0, 20.0, 20.0, 20.0}, { -5.91, -5.91, -5.91, -5.91, -5.91, -5.91, -5.91, -5.91} } /* Model 191 */ }; /* Curves for output current * Second index: On-line (0) or On-battery (1) */ static const float OUTPUT_CURRENT_MULTIPLIER_A[MODEL_COUNT][2] = { { 0.0892999991774559, 0.09070000052452087 } /* Model 183 */ , { 0.1264, 0.1303 } /* Model 190 */ , { 0.13819999992847443, 0.08959999680519104 } /* Model 191 */ , }; static const float OUTPUT_CURRENT_MULTIPLIER_B[MODEL_COUNT][2] = { { 0.09350000321865082, 0.14550000429153442 } /* Model 183 */ , { 0.522, 0.468 } /* Model 190 */ , { 0.12999999523162842, 0.1881999969482422 } /* Model 191 */ }; /* Curves for input voltage (depends on nominal output voltage) * Second index: Nominal output voltage = 220V (1) or 115V (0). */ static const float INPUT_VOLTAGE_MULTIPLIER_A[MODEL_COUNT][2] = { { 1.7937, 1.7937 } /* Model 183 */ , { 1.8, 1.8 } /* Model 190 */ , { 1.4825, 1.4952 } /* Model 191 */ }; static const float INPUT_VOLTAGE_MULTIPLIER_B[MODEL_COUNT][2] = { { 1.854, 1.854 } /* Model 183 */ , { 2.224, 2.224 } /* Model 190 */ , { 0.0853, -2.4241 } /* Model 191 */ }; /* Curves for battery voltage */ static const float BATTERY_VOLTAGE_MULTIPLIER_A[MODEL_COUNT] = { 0.1551 /* Model 183 */ , 0.1513 /* Model 190 */ , 0.1543 /* Model 191 */ }; static const float BATTERY_VOLTAGE_MULTIPLIER_B[MODEL_COUNT] = { 0.0654 /* Model 183 */ , 0.7153 /* Model 190 */ , 0.1414 /* Model 191 */ }; /* Real power estimation curves (depends on relay state) */ /* * Remarks: * - Model 190 use a direct real power determination (no need for curve selectors) */ static const float REAL_POWER_CURVE_SELECTOR_A1[MODEL_COUNT][8] = { { 0.24, 0.26, 0.0, 0.0, 0.24, 0.26, 0.0, 0.28 } /* Model 183 */ , { 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0 } /* Model 190 */ , { 0.24, 0.26, 0.0, 0.0, 0.24, 0.26, 0.0, 0.28 } /* Model 191 */ }; static const float REAL_POWER_CURVE_SELECTOR_B1[MODEL_COUNT][8] = { { 83.15, 81.23, 0.0, 0.0, 83.49, 79.05, 0.0, 85.67 } /* Model 183 */ , { 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0 } /* Model 190 */ , { 83.15, 81.23, 0.0, 0.0, 83.49, 79.05, 0.0, 85.67 } /* Model 191 */ }; static const float REAL_POWER_CURVE_SELECTOR_A2[MODEL_COUNT][8] = { { 0.0763, 0.081, 0.0919, 0.0, 0.0741, 0.0828, 0.0, 0.0938 } /* Model 183 */ , { 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0 } /* Model 190 */ , { 0.0763, 0.081, 0.0919, 0.0, 0.0741, 0.0828, 0.0, 0.0938 } /* Model 191 */ }; static const float REAL_POWER_CURVE_SELECTOR_B2[MODEL_COUNT][8] = { { 81.732, 94.459, 86.686, 0.0, 84.657, 84.999, 0.0, 78.097 } /* Model 183 */ , { 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0 } /* Model 190 */ , { 81.732, 94.459, 86.686, 0.0, 84.657, 84.999, 0.0, 78.097 } /* Model 191 */ }; static const float REAL_POWER_CURVE_SELECTOR_A3[MODEL_COUNT][8] = { { 0.0744, 0.0808, 0.0885, 0.0, 0.0732, 0.084, 0.0, 0.0955 } /* Model 183 */ , { 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0 } /* Model 190 */ , { 0.0744, 0.0808, 0.0885, 0.0, 0.0732, 0.084, 0.0, 0.0955 } /* Model 191 */ }; static const float REAL_POWER_CURVE_SELECTOR_B3[MODEL_COUNT][8] = { { 122.06, 122.9, 125.75, 0.0, 120.39, 108.52, 0.0, 92.239 } /* Model 183 */ , { 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0 } /* Model 190 */ , { 122.06, 122.9, 125.75, 0.0, 120.39, 108.52, 0.0, 92.239 } /* Model 191 */ }; static const float REAL_POWER_MULTIPLIER_A1[MODEL_COUNT][8] = { { 0.08040007075206226, 0.0894, 0.0999, 0.0, 0.0813, 0.0905, 0.0, 0.1005 } /* Model 183 */ , { 0.1127, 0.1127, 0.1127, 0.1127, 0.1127, 0.1127, 0.1127, 0.1127 } /* Model 190 */ , { 0.08040007075206226, 0.0894, 0.0999, 0.0, 0.0813, 0.0905, 0.0, 0.1005 } /* Model 191 */ }; static const float REAL_POWER_MULTIPLIER_B1[MODEL_COUNT][8] = { { 45.292, 41.928, 41.727, 0.0, 40.269, 41.81, 0.0, 43.458 } /* Model 183 */ , { 50.031, 50.031, 50.031, 50.031, 50.031, 50.031, 50.031, 50.031 } /* Model 190 */ , { 45.292, 41.928, 41.727, 0.0, 40.269, 41.81, 0.0, 43.458 } /* Model 191 */ }; static const float REAL_POWER_MULTIPLIER_A2[MODEL_COUNT][8] = { { 0.08630063689870031, 0.0946, 0.1068, 0.0, 0.086, 0.0967, 0.0, 0.1088 } /* Model 183 */ , { 0.1127, 0.1127, 0.1127, 0.1127, 0.1127, 0.1127, 0.1127, 0.1127 } /* Model 190 */ , { 0.08630063689870031, 0.0946, 0.1068, 0.0, 0.086, 0.0967, 0.0, 0.1088 } /* Model 191 */ }; static const float REAL_POWER_MULTIPLIER_B2[MODEL_COUNT][8] = { { 8.3927, 9.2393, 8.2852, 0.0, 8.301, 6.7636, 0.0, 8.2842 } /* Model 183 */ , { 50.031, 50.031, 50.031, 50.031, 50.031, 50.031, 50.031, 50.031 } /* Model 190 */ , { 8.3927, 9.2393, 8.2852, 0.0, 8.301, 6.7636, 0.0, 8.2842 } /* Model 191 */ }; static const float REAL_POWER_MULTIPLIER_A3[MODEL_COUNT][8] = { { 0.0896001146881468, 0.0991, 0.1116, 0.0, 0.0967, 0.1068, 0.0, 0.1169 } /* Model 183 */ , { 0.1127, 0.1127, 0.1127, 0.1127, 0.1127, 0.1127, 0.1127, 0.1127 } /* Model 190 */ , { 0.0896001146881468, 0.0991, 0.1116, 0.0, 0.0967, 0.1068, 0.0, 0.1169 } /* Model 191 */ }; static const float REAL_POWER_MULTIPLIER_B3[MODEL_COUNT][8] = { { -31.115, -33.777, -33.826, 0.0, -59.513, -57.729, 0.0, -41.333 } /* Model 183 */ , { 50.031, 50.031, 50.031, 50.031, 50.031, 50.031, 50.031, 50.031 } /* Model 190 */ , { -31.115, -33.777, -33.826, 0.0, -59.513, -57.729, 0.0, -41.333 } /* Model 191 */ }; /** * Maximum battery voltage, used to estimate battery charge * Second index: Recharging battery flag: charging (1) or charged/discharging (0) */ static const float MAX_BATTERY_VOLTAGE[MODEL_COUNT][2] = { { 27.0, 29.5 } /* Model 183 */ , { 27.0, 29.5 } /* Model 190 */ , { 27.0, 29.5 } /* Model 191 */ }; /** Minimum battery voltage, used to estimate battery charge */ static const float MIN_BATTERY_VOLTAGE[MODEL_COUNT] = { 20 /* Model 183 */ , 20 /* Model 190 */ , 20 /* Model 191 */ }; #endif /* INCLUDED_MICROSOL_APC_H */ nut-2.8.1/drivers/liebert-hid.h0000644000175000017500000000207114500336654013276 00000000000000/* liebert-hid.h - subdriver to monitor Liebert USB/HID devices with NUT * * Copyright (C) * 2003 - 2005 Arnaud Quette * 2005 - 2006 Peter Selinger * * 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 2 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, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #ifndef LIEBERT_HID_H #define LIEBERT_HID_H #include "usbhid-ups.h" extern subdriver_t liebert_subdriver; #endif /* LIEBERT_HID_H */ nut-2.8.1/drivers/nutdrv_qx.c0000644000175000017500000033266714502413017013143 00000000000000/* nutdrv_qx.c - Driver for USB and serial UPS units with Q* protocols * * Copyright (C) * 2013 Daniele Pezzini * 2016 Eaton * Based on: * usbhid-ups.c - Copyright (C) * 2003-2012 Arnaud Quette * 2005 John Stamp * 2005-2006 Peter Selinger * 2007-2009 Arjen de Korte * blazer.c - Copyright (C) * 2008-2009 Arjen de Korte * 2012 Arnaud Quette * blazer_ser.c - Copyright (C) * 2008 Arjen de Korte * blazer_usb.c - Copyright (C) * 2003-2009 Arjen de Korte * 2011-2012 Arnaud Quette * Masterguard additions * 2020-2021 Edgar Fuß, Mathematisches Institut der Universität Bonn * Armac (Richcomm-variant) additions * 2021 Tomasz Fortuna * * 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 2 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, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #include "config.h" #include #include "main.h" #include "attribute.h" #include "nut_float.h" #include "nut_stdint.h" /* note: QX_USB/QX_SERIAL set through Makefile */ #ifdef QX_USB #include "nut_libusb.h" /* also includes "usb-common.h" */ #ifdef QX_SERIAL #define DRIVER_NAME "Generic Q* USB/Serial driver" #else #define DRIVER_NAME "Generic Q* USB driver" #endif /* QX_SERIAL */ #else #define DRIVER_NAME "Generic Q* Serial driver" #endif /* QX_USB */ #define DRIVER_VERSION "0.36" #ifdef QX_SERIAL #include "serial.h" #define SER_WAIT_SEC 1 /* 3 seconds for Best UPS */ #endif /* QX_SERIAL */ #include "nutdrv_qx.h" /* == Subdrivers == */ /* Include all known subdrivers */ #include "nutdrv_qx_bestups.h" #include "nutdrv_qx_hunnox.h" #include "nutdrv_qx_mecer.h" #include "nutdrv_qx_megatec.h" #include "nutdrv_qx_megatec-old.h" #include "nutdrv_qx_mustek.h" #include "nutdrv_qx_q1.h" #include "nutdrv_qx_voltronic.h" #include "nutdrv_qx_voltronic-qs.h" #include "nutdrv_qx_voltronic-qs-hex.h" #include "nutdrv_qx_zinto.h" #include "nutdrv_qx_masterguard.h" #include "nutdrv_qx_ablerex.h" /* Reference list of available non-USB subdrivers */ static subdriver_t *subdriver_list[] = { &voltronic_subdriver, &voltronic_qs_subdriver, &voltronic_qs_hex_subdriver, &mustek_subdriver, &megatec_old_subdriver, &bestups_subdriver, &mecer_subdriver, &megatec_subdriver, &zinto_subdriver, &masterguard_subdriver, &hunnox_subdriver, &ablerex_subdriver, /* Fallback Q1 subdriver */ &q1_subdriver, NULL }; /* == Driver description structure == */ upsdrv_info_t upsdrv_info = { DRIVER_NAME, DRIVER_VERSION, "Daniele Pezzini " \ "Arnaud Quette " \ "John Stamp " \ "Peter Selinger " \ "Arjen de Korte " \ "Edgar Fuß ", DRV_BETA, #ifdef QX_USB { &comm_upsdrv_info, NULL } #else { NULL } #endif /* QX_USB */ }; /* == Data walk modes == */ typedef enum { QX_WALKMODE_INIT = 0, QX_WALKMODE_QUICK_UPDATE, QX_WALKMODE_FULL_UPDATE } walkmode_t; /* == Global vars == */ /* Pointer to the active subdriver object (changed in subdriver_matcher() function) */ static subdriver_t *subdriver = NULL; static long pollfreq = DEFAULT_POLLFREQ; static unsigned int ups_status = 0; static bool_t data_has_changed = FALSE; /* for SEMI_STATIC data polling */ static time_t lastpoll; /* Timestamp the last polling */ #if defined(QX_USB) && !defined(TESTING) static int hunnox_step = 0; #endif /* QX_USB && !TESTING */ #if defined(QX_USB) && defined(QX_SERIAL) static int is_usb = 0; /* Whether the device is connected through USB (1) or serial (0) */ #endif /* QX_USB && QX_SERIAL */ static struct { char command[SMALLBUF]; /* Command sent to the UPS to get answer/to execute an instant command */ char answer[SMALLBUF]; /* Answer from the UPS, filled at runtime */ } previous_item = { "", "" }; /* Hold the values of the item processed just before the actual one */ /* == Support functions == */ static int subdriver_matcher(void); static ssize_t qx_command(const char *cmd, char *buf, size_t buflen); static int qx_process_answer(item_t *item, const size_t len); /* returns just 0 or -1 */ static bool_t qx_ups_walk(walkmode_t mode); static void ups_status_set(void); static void ups_alarm_set(void); static void qx_set_var(item_t *item); /* == Struct & data for status processing == */ typedef struct { const char *status_str; /* UPS status string */ const unsigned int status_mask; /* UPS status mask */ } status_lkp_t; static status_lkp_t status_info[] = { /* Map status strings to bit masks */ { "OL", STATUS(OL) }, { "LB", STATUS(LB) }, { "RB", STATUS(RB) }, { "CHRG", STATUS(CHRG) }, { "DISCHRG", STATUS(DISCHRG) }, { "BYPASS", STATUS(BYPASS) }, { "CAL", STATUS(CALIB) }, { "OFF", STATUS(OFF) }, { "OVER", STATUS(OVER) }, { "TRIM", STATUS(TRIM) }, { "BOOST", STATUS(BOOST) }, { "FSD", STATUS(FSD) }, { NULL, 0 }, }; /* == battery.{charge,runtime} guesstimation == */ /* Support functions */ static int qx_battery(void); static int qx_load(void); static void qx_initbattery(void); /* Battery data */ static struct { double packs; /* Battery voltage multiplier */ struct { double act; /* Actual runtime on battery */ double nom; /* Nominal runtime on battery (full load) */ double est; /* Estimated runtime remaining (full load) */ double exp; /* Load exponent */ } runt; struct { double act; /* Actual battery voltage */ double high; /* Battery float voltage */ double nom; /* Nominal battery voltage */ double low; /* Battery low voltage */ } volt; struct { double act; /* Actual battery charge */ long time; /* Recharge time from empty to full */ } chrg; } batt = { 1, { -1, -1, 0, 0 }, { -1, -1, -1, -1 }, { -1, 43200 } }; /* Load data */ static struct { double act; /* Actual load (reported by the UPS) */ double low; /* Idle load */ double eff; /* Effective load */ } load = { 0, 0.1, 1 }; static time_t battery_lastpoll = 0; static int battery_voltage_reports_one_pack = 0, battery_voltage_reports_one_pack_considered = 0; /* Optionally multiply device-provided "battery.voltage" reading by * the "battery.packs" (reading or common override setting) to end up * with the dstate value representing the voltage of battery assembly, * not that of a single cell/pack (different devices report different * physically meaningful values for that reading). * This shared method can be referenced from subdriver mapping tables. */ int qx_multiply_battvolt(item_t *item, char *value, const size_t valuelen) { float s = 0; /* Adjusted here or not, this method was called at all * and other code should not multiply again! */ battery_voltage_reports_one_pack_considered = 1; if (!battery_voltage_reports_one_pack || batt.packs < 2) { /* (We assume by default that) this device already reports * the sum-total voltage for the battery assembly - so just * pass it on unmodified. * Or we can't reasonably use a "batt.packs" anyway. */ snprintf(value, valuelen, "%s", item->value); return 0; } if (sscanf(item->value, "%f", &s) != 1) { upsdebugx(2, "unparsable ss.ss %s", item->value); return -1; } snprintf(value, valuelen, "%.2f", s * batt.packs); return 0; } /* Fill batt.volt.act and guesstimate the battery charge * if it isn't already available. */ static int qx_battery(void) { const char *val = dstate_getinfo("battery.voltage"); if (!val) { upsdebugx(2, "%s: unable to get battery.voltage", __func__); return -1; } batt.volt.act = strtod(val, NULL); if (!battery_voltage_reports_one_pack_considered) { batt.volt.act *= batt.packs; } if (d_equal(batt.chrg.act, -1) && batt.volt.low > 0 && batt.volt.high > batt.volt.low) { batt.chrg.act = 100 * (batt.volt.act - batt.volt.low) / (batt.volt.high - batt.volt.low); if (batt.chrg.act < 0) { batt.chrg.act = 0; } if (batt.chrg.act > 100) { batt.chrg.act = 100; } dstate_setinfo("battery.charge", "%.0f", batt.chrg.act); } return 0; } /* Load for battery.{charge,runtime} from runtimecal */ static int qx_load(void) { const char *val = dstate_getinfo("ups.load"); if (!val) { upsdebugx(2, "%s: unable to get ups.load", __func__); return -1; } load.act = strtod(val, NULL); load.eff = pow(load.act / 100, batt.runt.exp); if (load.eff < load.low) { load.eff = load.low; } return 0; } /* Init known (readings, configs) and guessed (if needed) battery related values */ static void qx_initbattery(void) { const char *val; int batt_packs_known = 0; val = dstate_getinfo("battery.voltage.high"); if (val) { batt.volt.high = strtod(val, NULL); } val = dstate_getinfo("battery.voltage.low"); if (val) { batt.volt.low = strtod(val, NULL); } val = dstate_getinfo("battery.voltage.nominal"); if (val) { batt.volt.nom = strtod(val, NULL); } /* If no values are available for both battery.voltage.{low,high} * either from the UPS or provided by the user in ups.conf, * but nominal battery.voltage.nom is known, * try to guesstimate them, but announce it! */ if ( (!d_equal(batt.volt.nom, -1)) && (d_equal(batt.volt.low, -1) || d_equal(batt.volt.high, -1))) { upslogx(LOG_INFO, "No values for battery high/low voltages"); /* Basic formula, which should cover most cases */ batt.volt.low = 104 * batt.volt.nom / 120; /* Per https://www.csb-battery.com.tw/english/01_product/02_detail.php?fid=17&pid=113 * a nominally 12V battery can have "float charging voltage" * at 13.5-13.8V and an "equalization charging voltage" (e.g. * to desulphurize) at 14-15V. Note that per nut-names.txt, * the "battery.voltage.high" is the practical 100% charge * value (so equal or a bit less than actual battery.voltage * reported by the device, when the situation is healthy); * it is not the voltage that the battery CAN reach on the * brink of boiling out: */ batt.volt.high = 130 * batt.volt.nom / 120; /* Publish these data too */ dstate_setinfo("battery.voltage.low", "%.2f", batt.volt.low); dstate_setinfo("battery.voltage.high", "%.2f", batt.volt.high); upslogx(LOG_INFO, "Using 'guesstimation' (low: %f, high: %f)!", batt.volt.low, batt.volt.high); } val = dstate_getinfo("battery.packs"); if (val && (strspn(val, "0123456789 .") == strlen(val))) { batt.packs = strtod(val, NULL); batt_packs_known = 1; } val = getval("battery_voltage_reports_one_pack"); if (val) { battery_voltage_reports_one_pack = 1; /* If we already have a battery.voltage reading from the device, * it is not yet "adjusted" to consider the multiplication for * packs (if known; if not - the guesswork and call below for * qx_battery() should take care of it). Note that it is only * a few lines above that we might have learned the user-set * amount of battery packs and that they know the device only * reports a single pack voltage in the protocol. * Even if the qx_multiply_battvolt() method was called before * and set the battery_voltage_reports_one_pack_considered flag, * it is not too relevant until now *for maths*. However it is * important to know that the mapping table for this subdriver * does reference the adjustment method at all (which it would * encounter and set the flag while querying battery.voltage * from device and having a non-NULL reading now). */ if (battery_voltage_reports_one_pack_considered) { val = dstate_getinfo("battery.voltage"); if (val && batt_packs_known && batt.packs > 1) { batt.volt.act = strtod(val, NULL) * batt.packs; dstate_setinfo("battery.voltage", "%.2f", batt.volt.act); } } } /* Guesstimation: init values if not provided by device/overrides */ if (!dstate_getinfo("battery.charge") || !dstate_getinfo("battery.runtime")) { if (!batt_packs_known) { /* qx_battery -> batt.volt.act */ if (!qx_battery() && (!d_equal(batt.volt.nom, -1))) { const double packs[] = { 120, 100, 80, 60, 48, 36, 30, 24, 18, 12, 8, 6, 4, 3, 2, 1, 0.5, -1 }; int i; /* The battery voltage will quickly return to * at least the nominal value after discharging them. * For overlapping battery.voltage.low/high ranges * therefore choose the one with the highest multiplier. */ for (i = 0; packs[i] > 0; i++) { if (packs[i] * batt.volt.act > 1.25 * batt.volt.nom) { continue; } if (packs[i] * batt.volt.act < 0.8 * batt.volt.nom) { upslogx(LOG_INFO, "Can't autodetect number of battery packs [%.0f/%.2f]", batt.volt.nom, batt.volt.act); break; } batt.packs = packs[i]; upslogx(LOG_INFO, "Autodetected %.0f as number of battery packs [%.0f/%.2f]", batt.packs, batt.volt.nom, batt.volt.act); break; } } else { upslogx(LOG_INFO, "Can't autodetect number of battery packs [%.0f/%.2f]", batt.volt.nom, batt.volt.act); } } /* Update batt.{chrg,volt}.act */ qx_battery(); val = getval("runtimecal"); if (val) { double rh, lh, rl, ll; time(&battery_lastpoll); if (sscanf(val, "%lf,%lf,%lf,%lf", &rh, &lh, &rl, &ll) < 4) { fatalx(EXIT_FAILURE, "Insufficient parameters for runtimecal"); } if ((rl < rh) || (rh <= 0)) { fatalx(EXIT_FAILURE, "Parameter out of range (runtime)"); } if ((lh > 100) || (ll > lh) || (ll <= 0)) { fatalx(EXIT_FAILURE, "Parameter out of range (load)"); } batt.runt.exp = log(rl / rh) / log(lh / ll); upsdebugx(2, "%s: battery runtime exponent: %.3f", __func__, batt.runt.exp); batt.runt.nom = rh * pow(lh / 100, batt.runt.exp); upsdebugx(2, "%s: battery runtime nominal: %.1f", __func__, batt.runt.nom); } else { upslogx(LOG_INFO, "Battery runtime will not be calculated " "(runtimecal not set)"); return; } val = dstate_getinfo("battery.charge"); if (!val && (!d_equal(batt.volt.nom, -1))) { batt.volt.low = batt.volt.nom; batt.volt.high = 1.15 * batt.volt.nom; if (qx_battery()) fatalx(EXIT_FAILURE, "Initial battery charge undetermined"); val = dstate_getinfo("battery.charge"); } if (val) { batt.runt.est = batt.runt.nom * strtod(val, NULL) / 100; upsdebugx(2, "%s: battery runtime estimate: %.1f", __func__, batt.runt.est); } else { fatalx(EXIT_FAILURE, "Initial battery charge undetermined"); } val = getval("chargetime"); if (val) { batt.chrg.time = strtol(val, NULL, 10); if (batt.chrg.time <= 0) { fatalx(EXIT_FAILURE, "Charge time out of range [1..s]"); } upsdebugx(2, "%s: battery charge time: %ld", __func__, batt.chrg.time); } else { upslogx(LOG_INFO, "No charge time specified, " "using built in default [%ld seconds]", batt.chrg.time); } val = getval("idleload"); if (val) { load.low = strtod(val, NULL) / 100; if ((load.low <= 0) || (load.low > 1)) { fatalx(EXIT_FAILURE, "Idle load out of range [0..100]"); } upsdebugx(2, "%s: minimum load used (idle): %.3f", __func__, load.low); } else { upslogx(LOG_INFO, "No idle load specified, using built in default [%.1f %%]", 100 * load.low); } } } /* == USB communication subdrivers == */ #if defined(QX_USB) && !defined(TESTING) static usb_communication_subdriver_t *usb = &usb_subdriver; static usb_dev_handle *udev = NULL; static USBDevice_t usbdevice; static USBDeviceMatcher_t *reopen_matcher = NULL; static USBDeviceMatcher_t *regex_matcher = NULL; static int langid_fix = -1; static int (*subdriver_command)(const char *cmd, char *buf, size_t buflen) = NULL; /* Cypress communication subdriver */ static int cypress_command(const char *cmd, char *buf, size_t buflen) { char tmp[SMALLBUF]; int ret = 0; size_t i; if (buflen > INT_MAX) { upsdebugx(3, "%s: requested to read too much (%" PRIuSIZE "), " "reducing buflen to (INT_MAX-1)", __func__, buflen); buflen = (INT_MAX - 1); } /* Send command */ memset(tmp, 0, sizeof(tmp)); snprintf(tmp, sizeof(tmp), "%s", cmd); for (i = 0; i < strlen(tmp); i += (size_t)ret) { /* Write data in 8-byte chunks */ /* ret = usb->set_report(udev, 0, (unsigned char *)&tmp[i], 8); */ ret = usb_control_msg(udev, USB_ENDPOINT_OUT + USB_TYPE_CLASS + USB_RECIP_INTERFACE, 0x09, 0x200, 0, (usb_ctrl_charbuf)&tmp[i], 8, 5000); if (ret <= 0) { upsdebugx(3, "send: %s (%d)", ret ? nut_usb_strerror(ret) : "timeout", ret); return ret; } } upsdebugx(3, "send: %.*s", (int)strcspn(tmp, "\r"), tmp); /* Read reply */ memset(buf, 0, buflen); for (i = 0; (i <= buflen-8) && (memchr(buf, '\r', buflen) == NULL); i += (size_t)ret) { /* Read data in 8-byte chunks */ /* ret = usb->get_interrupt(udev, (unsigned char *)&buf[i], 8, 1000); */ ret = usb_interrupt_read(udev, 0x81, (usb_ctrl_charbuf)&buf[i], 8, 1000); /* Any errors here mean that we are unable to read a reply * (which will happen after successfully writing a command * to the UPS) */ if (ret <= 0) { upsdebugx(3, "read: %s (%d)", ret ? nut_usb_strerror(ret) : "timeout", ret); return ret; } snprintf(tmp, sizeof(tmp), "read [% 3d]", (int)i); upsdebug_hex(5, tmp, &buf[i], (size_t)ret); } upsdebugx(3, "read: %.*s", (int)strcspn(buf, "\r"), buf); if (i > INT_MAX) { upsdebugx(3, "%s: read too much (%" PRIuSIZE ")", __func__, i); return -1; } return (int)i; } /* SGS communication subdriver */ static int sgs_command(const char *cmd, char *buf, size_t buflen) { char tmp[SMALLBUF]; int ret = 0; size_t cmdlen, i; if (buflen > INT_MAX) { upsdebugx(3, "%s: requested to read too much (%" PRIuSIZE "), " "reducing buflen to (INT_MAX-1)", __func__, buflen); buflen = (INT_MAX - 1); } /* Send command */ cmdlen = strlen(cmd); for (i = 0; i < cmdlen; i += (size_t)ret) { memset(tmp, 0, sizeof(tmp)); /* i and cmdlen are size_t nominally, but diff is not large */ ret = (int)((cmdlen - i) < 7 ? (cmdlen - i) : 7); /* ret is between 0 and 7 */ tmp[0] = (char)ret; memcpy(&tmp[1], &cmd[i], (unsigned char)ret); /* Write data in 8-byte chunks */ ret = usb_control_msg(udev, USB_ENDPOINT_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE, 0x09, 0x200, 0, (usb_ctrl_charbuf)tmp, 8, 5000); if (ret <= 0) { upsdebugx(3, "send: %s (%d)", ret ? nut_usb_strerror(ret) : "timeout", ret); return ret; } ret--; } upsdebugx(3, "send: %.*s", (int)strcspn(cmd, "\r"), cmd); /* Read reply */ memset(buf, 0, buflen); for (i = 0; i <= buflen - 8; i += (size_t)ret) { memset(tmp, 0, sizeof(tmp)); /* Read data in 8-byte chunks */ ret = usb_interrupt_read(udev, 0x81, (usb_ctrl_charbuf)tmp, 8, 1000); /* No error!!! */ /* if (ret == -110) */ if (ret == LIBUSB_ERROR_TIMEOUT) break; /* Any errors here mean that we are unable to read a reply * (which will happen after successfully writing a command * to the UPS) */ if (ret <= 0) { upsdebugx(3, "read: %s (%d)", ret ? nut_usb_strerror(ret) : "timeout", ret); return ret; } /* Every call to read returns 8 bytes * -> actually returned bytes: */ ret = tmp[0] <= 7 ? tmp[0] : 7; if (ret > 0) memcpy(&buf[i], &tmp[1], (unsigned char)ret); snprintf(tmp, sizeof(tmp), "read [% 3d]", (int)i); upsdebug_hex(5, tmp, &buf[i], (size_t)ret); } /* If the reply lacks the expected terminating CR, add it (if there's enough space) */ if (i && memchr(buf, '\r', i) == NULL) { upsdebugx(4, "%s: the reply lacks the expected terminating CR.", __func__); if (i < buflen - 1) { upsdebugx(4, "%s: adding missing terminating CR.", __func__); buf[i++] = '\r'; buf[i] = 0; } } upsdebugx(3, "read: %.*s", (int)strcspn(buf, "\r"), buf); if (i > INT_MAX) { upsdebugx(3, "%s: read too much (%" PRIuSIZE ")", __func__, i); return -1; } return (int)i; } /* Phoenix communication subdriver */ static int phoenix_command(const char *cmd, char *buf, size_t buflen) { char tmp[SMALLBUF]; int ret; size_t i; if (buflen > INT_MAX) { upsdebugx(3, "%s: requested to read too much (%" PRIuSIZE "), " "reducing buflen to (INT_MAX-1)", __func__, buflen); buflen = (INT_MAX - 1); } for (i = 0; i < 8; i++) { /* Read data in 8-byte chunks */ /* ret = usb->get_interrupt(udev, (unsigned char *)tmp, 8, 1000); */ ret = usb_interrupt_read(udev, 0x81, (usb_ctrl_charbuf)tmp, 8, 1000); /* This USB to serial implementation is crappy. * In order to read correct replies we need to flush the * output buffers of the converter until we get no more * data (e.g. it times out). */ switch (ret) { case LIBUSB_ERROR_PIPE: /* Broken pipe */ usb_clear_halt(udev, 0x81); break; case LIBUSB_ERROR_TIMEOUT: /* Connection timed out */ break; } if (ret < 0) { upsdebugx(3, "flush: %s (%d)", nut_usb_strerror(ret), ret); break; } upsdebug_hex(4, "dump", tmp, (size_t)ret); } /* Send command */ memset(tmp, 0, sizeof(tmp)); snprintf(tmp, sizeof(tmp), "%s", cmd); for (i = 0; i < strlen(tmp); i += (size_t)ret) { /* Write data in 8-byte chunks */ /* ret = usb->set_report(udev, 0, (unsigned char *)&tmp[i], 8); */ ret = usb_control_msg(udev, USB_ENDPOINT_OUT + USB_TYPE_CLASS + USB_RECIP_INTERFACE, 0x09, 0x200, 0, (usb_ctrl_charbuf)&tmp[i], 8, 1000); if (ret <= 0) { upsdebugx(3, "send: %s (%d)", ret ? nut_usb_strerror(ret) : "timeout", ret); return ret; } } upsdebugx(3, "send: %.*s", (int)strcspn(tmp, "\r"), tmp); /* Read reply */ memset(buf, 0, buflen); for (i = 0; (i <= buflen-8) && (memchr(buf, '\r', buflen) == NULL); i += (size_t)ret) { /* Read data in 8-byte chunks */ /* ret = usb->get_interrupt(udev, (unsigned char *)&buf[i], 8, 1000); */ ret = usb_interrupt_read(udev, 0x81, (usb_ctrl_charbuf)&buf[i], 8, 1000); /* Any errors here mean that we are unable to read a reply * (which will happen after successfully writing a command * to the UPS) */ if (ret <= 0) { upsdebugx(3, "read: %s (%d)", ret ? nut_usb_strerror(ret) : "timeout", ret); return ret; } snprintf(tmp, sizeof(tmp), "read [% 3d]", (int)i); upsdebug_hex(5, tmp, &buf[i], (size_t)ret); } upsdebugx(3, "read: %.*s", (int)strcspn(buf, "\r"), buf); if (i > INT_MAX) { upsdebugx(3, "%s: read too much (%" PRIuSIZE ")", __func__, i); return -1; } return (int)i; } /* Ippon communication subdriver */ static int ippon_command(const char *cmd, char *buf, size_t buflen) { char tmp[64]; int ret; size_t i, len; if (buflen > INT_MAX) { upsdebugx(3, "%s: requested to read too much (%" PRIuSIZE "), " "reducing buflen to (INT_MAX-1)", __func__, buflen); buflen = (INT_MAX - 1); } /* Send command */ snprintf(tmp, sizeof(tmp), "%s", cmd); for (i = 0; i < strlen(tmp); i += (size_t)ret) { /* Write data in 8-byte chunks */ ret = usb_control_msg(udev, USB_ENDPOINT_OUT + USB_TYPE_CLASS + USB_RECIP_INTERFACE, 0x09, 0x2, 0, (usb_ctrl_charbuf)&tmp[i], 8, 1000); if (ret <= 0) { upsdebugx(3, "send: %s (%d)", (ret != LIBUSB_ERROR_TIMEOUT) ? nut_usb_strerror(ret) : "Connection timed out", ret); return ret; } } upsdebugx(3, "send: %.*s", (int)strcspn(tmp, "\r"), tmp); /* Read all 64 bytes of the reply in one large chunk */ ret = usb_interrupt_read(udev, 0x81, (usb_ctrl_charbuf)tmp, sizeof(tmp), 1000); /* Any errors here mean that we are unable to read a reply * (which will happen after successfully writing a command * to the UPS) */ if (ret <= 0) { upsdebugx(3, "read: %s (%d)", (ret != LIBUSB_ERROR_TIMEOUT) ? nut_usb_strerror(ret) : "Connection timed out", ret); return ret; } /* As Ippon will always return 64 bytes in response, * we have to calculate and return length of actual * response data here. * Empty response will look like 0x00 0x0D, otherwise * it will be data string terminated by 0x0D. */ for (i = 0, len = 0; i < (size_t)ret; i++) { if (tmp[i] != '\r') continue; len = ++i; break; } /* Just in case there wasn't any '\r', fallback to string length, if any */ if (!len) len = strlen(tmp); upsdebug_hex(5, "read", tmp, (size_t)len); upsdebugx(3, "read: %.*s", (int)strcspn(tmp, "\r"), tmp); len = len < buflen ? len : buflen - 1; memset(buf, 0, buflen); memcpy(buf, tmp, len); /* If the reply lacks the expected terminating CR, add it (if there's enough space) */ if (len && memchr(buf, '\r', len) == NULL) { upsdebugx(4, "%s: the reply lacks the expected terminating CR.", __func__); if (len < buflen - 1) { upsdebugx(4, "%s: adding missing terminating CR.", __func__); buf[len++] = '\r'; buf[len] = 0; } } if (len > INT_MAX) { upsdebugx(3, "%s: read too much (%" PRIuSIZE ")", __func__, len); return -1; } return (int)len; } static int hunnox_protocol(int asking_for) { char buf[1030]; int langid_fix_local = 0x0409; if (langid_fix != -1) { langid_fix_local = langid_fix; } switch (hunnox_step) { case 0: upsdebugx(3, "asking for: %02X", 0x00); usb_get_string(udev, 0x00, langid_fix_local, (usb_ctrl_charbuf)buf, 1026); usb_get_string(udev, 0x00, langid_fix_local, (usb_ctrl_charbuf)buf, 1026); usb_get_string(udev, 0x01, langid_fix_local, (usb_ctrl_charbuf)buf, 1026); usleep(10000); break; case 1: if (asking_for != 0x0d) { upsdebugx(3, "asking for: %02X", 0x0d); usb_get_string(udev, 0x0d, langid_fix_local, (usb_ctrl_charbuf)buf, 102); } break; case 2: if (asking_for != 0x03) { upsdebugx(3, "asking for: %02X", 0x03); usb_get_string(udev, 0x03, langid_fix_local, (usb_ctrl_charbuf)buf, 102); } break; case 3: if (asking_for != 0x0c) { upsdebugx(3, "asking for: %02X", 0x0c); usb_get_string(udev, 0x0c, langid_fix_local, (usb_ctrl_charbuf)buf, 102); } break; default: hunnox_step = 0; } hunnox_step++; if (hunnox_step > 3) { hunnox_step = 1; } return 0; } /* Krauler communication subdriver */ static int krauler_command(const char *cmd, char *buf, size_t buflen) { /* Still not implemented: * 0x6 T (don't know how to pass the parameter) * 0x68 and 0x69 both cause shutdown after an undefined interval */ const struct { const char *str; /* Megatec command */ const int index; /* Krauler string index for this command */ const char prefix; /* Character to replace the first byte in reply */ } command[] = { { "Q1\r", 0x03, '(' }, { "F\r", 0x0d, '#' }, { "I\r", 0x0c, '#' }, { "T\r", 0x04, '\r' }, { "TL\r", 0x05, '\r' }, { "Q\r", 0x07, '\r' }, { "C\r", 0x0b, '\r' }, { "CT\r", 0x0b, '\r' }, { NULL, 0, '\0' } }; int i; upsdebugx(3, "send: %.*s", (int)strcspn(cmd, "\r"), cmd); if (buflen > INT_MAX) { upsdebugx(3, "%s: requested to read too much (%" PRIuSIZE "), " "reducing buflen to (INT_MAX-1)", __func__, buflen); buflen = (INT_MAX - 1); } for (i = 0; command[i].str; i++) { int retry; if (strcmp(cmd, command[i].str)) { continue; } for (retry = 0; retry < 10; retry++) { int ret; if (langid_fix != -1) { /* Apply langid_fix value */ ret = usb_get_string(udev, command[i].index, langid_fix, (usb_ctrl_charbuf)buf, buflen); } else { ret = usb_get_string_simple(udev, command[i].index, (usb_ctrl_charbuf)buf, buflen); } if (ret <= 0) { upsdebugx(3, "read: %s (%d)", ret ? nut_usb_strerror(ret) : "timeout", ret); return ret; } /* This may serve in the future */ upsdebugx(1, "received %d (%d)", ret, buf[0]); if (langid_fix != -1) { unsigned int di, si, size; /* Limit this check, at least for now */ /* Invalid receive size - message corrupted */ if (ret != buf[0]) { upsdebugx(1, "size mismatch: %d / %d", ret, buf[0]); continue; } /* Simple unicode -> ASCII inplace conversion * FIXME: this code is at least shared with mge-shut/libshut * Create a common function? */ size = (unsigned int)buf[0]; for (di = 0, si = 2; si < size; si += 2) { if (di >= (buflen - 1)) break; if (buf[si + 1]) /* high byte */ buf[di++] = '?'; else buf[di++] = buf[si]; } /* Note: effective range of di should be unsigned char */ buf[di] = 0; ret = (int)di; } /* If the reply lacks the expected terminating CR, add it (if there's enough space) */ if (ret && memchr(buf, '\r', ret) == NULL) { upsdebugx(4, "%s: the reply lacks the expected terminating CR.", __func__); if ((size_t)ret < buflen - 1) { upsdebugx(4, "%s: adding missing terminating CR.", __func__); buf[ret++] = '\r'; buf[ret] = 0; } } /* "UPS No Ack" has a special meaning */ if ( strcspn(buf, "\r") == 10 && !strncasecmp(buf, "UPS No Ack", 10) ) { upsdebugx(3, "read: %.*s", (int)strcspn(buf, "\r"), buf); continue; } /* Replace the first byte of what we received with the correct one */ buf[0] = command[i].prefix; upsdebug_hex(5, "read", buf, (size_t)ret); upsdebugx(3, "read: %.*s", (int)strcspn(buf, "\r"), buf); return ret; } return 0; } /* Echo the unknown command back */ upsdebugx(3, "read: %.*s", (int)strcspn(cmd, "\r"), cmd); return snprintf(buf, buflen, "%s", cmd); } /* Fabula communication subdriver */ static int fabula_command(const char *cmd, char *buf, size_t buflen) { const struct { const char *str; /* Megatec command */ const int index; /* Fabula string index for this command */ } commands[] = { { "Q1\r", 0x03, }, /* Status */ { "F\r", 0x0d, }, /* Ratings */ { "I\r", 0x0c, }, /* Vendor infos */ { "Q\r", 0x07, }, /* Beeper toggle */ { "C\r", 0x0a, }, /* Cancel shutdown/Load on [0x(0..F)A]*/ { NULL, 0 } }; int i, ret, index = 0; upsdebugx(3, "send: %.*s", (int)strcspn(cmd, "\r"), cmd); if (buflen > INT_MAX) { upsdebugx(3, "%s: requested to read too much (%" PRIuSIZE "), " "reducing buflen to (INT_MAX-1)", __func__, buflen); buflen = (INT_MAX - 1); } for (i = 0; commands[i].str; i++) { if (strcmp(cmd, commands[i].str)) continue; index = commands[i].index; break; } if (!index) { int val2 = -1; double val1 = -1; /* Shutdowns */ if ( sscanf(cmd, "S%lfR%d\r", &val1, &val2) == 2 || sscanf(cmd, "S%lf\r", &val1) == 1 ) { double delay; /* 0x(1+)0 -> shutdown.stayoff (SnR0000) * 0x(1+)8 -> shutdown.return (Sn[Rm], m != 0) * [delay before restart is always 10 seconds] * +0x10 (16dec) = next megatec delay * (min .5 = hex 0x1*; max 10 = hex 0xF*) -> n < 1 ? -> n += .1; n >= 1 ? -> n += 1 */ /* delay: [.5..10] (-> seconds: [30..600]) */ delay = val1 < .5 ? .5 : val1 > 10 ? 10 : val1; if (delay < 1) index = 16 + round((delay - .5) * 10) * 16; else index = 96 + (delay - 1) * 16; /* shutdown.return (Sn[Rm], m != 0) */ if (val2) index += 8; /* Unknown commands */ } else { /* Echo the unknown command back */ upsdebugx(3, "read: %.*s", (int)strcspn(cmd, "\r"), cmd); return snprintf(buf, buflen, "%s", cmd); } } upsdebugx(4, "command index: 0x%02x", index); /* Send command/Read reply */ ret = usb_get_string_simple(udev, index, (usb_ctrl_charbuf)buf, buflen); if (ret <= 0) { upsdebugx(3, "read: %s (%d)", ret ? nut_usb_strerror(ret) : "timeout", ret); return ret; } /* If the reply lacks the expected terminating CR, add it (if there's enough space) */ if (memchr(buf, '\r', ret) == NULL) { upsdebugx(4, "%s: the reply lacks the expected terminating CR.", __func__); if ((size_t)ret < buflen - 1) { upsdebugx(4, "%s: adding missing terminating CR.", __func__); buf[ret++] = '\r'; buf[ret] = 0; } } upsdebug_hex(5, "read", buf, (size_t)ret); upsdebugx(3, "read: %.*s", (int)strcspn(buf, "\r"), buf); /* The UPS always replies "UPS No Ack" when a supported command * is issued (either if it fails or if it succeeds).. */ if ( strcspn(buf, "\r") == 10 && !strncasecmp(buf, "UPS No Ack", 10) ) { /* ..because of that, always return 0 (with buf empty, * as if it was a timeout): queries will see it as a failure, * instant commands ('megatec' protocol) as a success */ memset(buf, 0, buflen); return 0; } return ret; } /* Hunnox communication subdriver, based on Fabula code above so repeats * much of it currently. Possible future optimization is to refactor shared * code into new routines to be called from both (or more) methods.*/ static int hunnox_command(const char *cmd, char *buf, size_t buflen) { /* The hunnox_patch was an argument in initial implementation of PR #638 * which added "hunnox" support; keeping it fixed here helps to visibly * track the modifications compared to original fabula_command() e.g. to * facilitate refactoring commented above, in the future. */ /* char hunnox_patch = 1; */ const struct { const char *str; /* Megatec command */ const int index; /* Fabula string index for this command */ } commands[] = { { "Q1\r", 0x03, }, /* Status */ { "F\r", 0x0d, }, /* Ratings */ { "I\r", 0x0c, }, /* Vendor infos */ { "Q\r", 0x07, }, /* Beeper toggle */ { "C\r", 0x0a, }, /* Cancel shutdown/Load on [0x(0..F)A]*/ { NULL, 0 } }; int i, ret, index = 0; upsdebugx(3, "send: %.*s", (int)strcspn(cmd, "\r"), cmd); if (buflen > INT_MAX) { upsdebugx(3, "%s: requested to read too much (%" PRIuSIZE "), " "reducing buflen to (INT_MAX-1)", __func__, buflen); buflen = (INT_MAX - 1); } for (i = 0; commands[i].str; i++) { if (strcmp(cmd, commands[i].str)) continue; index = commands[i].index; break; } if (!index) { int val2 = -1; double val1 = -1; /* Shutdowns */ if ( sscanf(cmd, "S%lfR%d\r", &val1, &val2) == 2 || sscanf(cmd, "S%lf\r", &val1) == 1 ) { double delay; /* 0x(1+)0 -> shutdown.stayoff (SnR0000) * 0x(1+)8 -> shutdown.return (Sn[Rm], m != 0) * [delay before restart is always 10 seconds] * +0x10 (16dec) = next megatec delay * (min .5 = hex 0x1*; max 10 = hex 0xF*) -> n < 1 ? -> n += .1; n >= 1 ? -> n += 1 */ /* delay: [.5..10] (-> seconds: [30..600]) */ delay = val1 < .5 ? .5 : val1 > 10 ? 10 : val1; if (delay < 1) index = 16 + round((delay - .5) * 10) * 16; else index = 96 + (delay - 1) * 16; /* shutdown.return (Sn[Rm], m != 0) */ if (val2) index += 8; /* Unknown commands */ } else { /* Echo the unknown command back */ upsdebugx(3, "read: %.*s", (int)strcspn(cmd, "\r"), cmd); return snprintf(buf, buflen, "%s", cmd); } } upsdebugx(4, "command index: 0x%02x", index); /* if (hunnox_patch) { */ /* Enable lock-step protocol for Hunnox */ if (hunnox_protocol(index) != 0) { return 0; } /* Seems that if we inform a large buffer, the USB locks. * This value was captured from the Windows "official" client. * Note this should not be a problem programmatically: it just * means that the caller reserved a longer buffer that we need * in practice to write a response into. */ if (buflen > 102) { buflen = 102; } /* } */ /* Send command/Read reply */ if (langid_fix != -1) { ret = usb_get_string(udev, index, langid_fix, (usb_ctrl_charbuf)buf, buflen); } else { ret = usb_get_string_simple(udev, index, (usb_ctrl_charbuf)buf, buflen); } if (ret <= 0) { upsdebugx(3, "read: %s (%d)", ret ? nut_usb_strerror(ret) : "timeout", ret); return ret; } /* if (hunnox_patch) { */ if (langid_fix != -1) { unsigned int di, si, size; /* Limit this check, at least for now */ /* Invalid receive size - message corrupted */ if (ret != buf[0]) { upsdebugx(1, "size mismatch: %d / %d", ret, buf[0]); return 0; } /* Simple unicode -> ASCII inplace conversion * FIXME: this code is at least shared with mge-shut/libshut * Create a common function? */ size = (unsigned int)buf[0]; for (di = 0, si = 2; si < size; si += 2) { if (di >= (buflen - 1)) break; if (buf[si + 1]) /* high byte */ buf[di++] = '?'; else buf[di++] = buf[si]; } /* Note: effective range of di should be unsigned char */ buf[di] = 0; ret = (int)di; } /* } */ upsdebug_hex(5, "read", buf, (size_t)ret); upsdebugx(3, "read: %.*s", (int)strcspn(buf, "\r"), buf); /* The UPS always replies "UPS No Ack" when a supported command * is issued (either if it fails or if it succeeds).. */ if ( strcspn(buf, "\r") == 10 && !strncasecmp(buf, "UPS No Ack", 10) ) { /* ..because of that, always return 0 (with buf empty, * as if it was a timeout): queries will see it as a failure, * instant commands ('megatec' protocol) as a success */ memset(buf, 0, buflen); return 0; } return ret; } /* Fuji communication subdriver */ static int fuji_command(const char *cmd, char *buf, size_t buflen) { unsigned char tmp[8]; char command[SMALLBUF] = "", read[SMALLBUF] = ""; int ret, val2; unsigned char answer_len; double val1; size_t i; const struct { const char *command; /* Megatec command */ const unsigned char answer_len; /* Expected length of the answer * to the ongoing query */ } query[] = { { "Q1", 47 }, { "F", 22 }, { "I", 39 }, { NULL, 0 } }; if (buflen > INT_MAX) { upsdebugx(3, "%s: requested to read too much (%" PRIuSIZE "), " "reducing buflen to (INT_MAX-1)", __func__, buflen); buflen = (INT_MAX - 1); } /* * Queries (b1..b8) sent (as a 8-bytes interrupt) to the UPS * adopt the following scheme: * * b1: 0x80 * b2: 0x06 * b3: * b4: 0x03 * b5..bn: * bn+1..b7: [] * b8: * * Where: * Length (in Hex) of the command (without the trailing CR) + 1 * Command/query (without the trailing CR) * [] 0x00 padding to the 7th byte * Expected length (in Hex) of the answer to the ongoing * query (0 when no reply is expected, i.e. commands) * * Replies to queries (commands are followed by action without * any reply) are sent from the UPS (in 8-byte chunks) with * 0x00 padding after the trailing CR to full 8 bytes. * */ /* Send command */ /* Remove the CR */ snprintf(command, sizeof(command), "%.*s", (int)strcspn(cmd, "\r"), cmd); /* Length of the command that will be sent to the UPS can be * at most: 8 - 5 (0x80, 0x06, , 0x03, ) = 3. * As a consequence also 'SnRm' commands (shutdown.{return,stayoff} * and load.off) are not supported. * So, map all the 'SnRm' shutdown.returns (m != 0) as the * corresponding 'Sn' commands, meanwhile ignoring ups.delay.start * and making the UPS turn on the load as soon as power is back. */ if (sscanf(cmd, "S%lfR%d\r", &val1, &val2) == 2 && val2) { upsdebugx(4, "%s: trimming '%s' to '%.*s'", __func__, command, 3, command); command[3] = 0; } /* Too long command */ if (strlen(command) > 3) { /* Be 'megatec-y': echo the unsupported command back */ upsdebugx(3, "%s: unsupported command %s", __func__, command); return snprintf(buf, buflen, "%s", cmd); } /* Expected length of the answer to the ongoing query * (0 when no reply is expected, i.e. commands) */ answer_len = 0; for (i = 0; query[i].command; i++) { if (strcmp(command, query[i].command)) continue; answer_len = query[i].answer_len; break; } memset(tmp, 0, sizeof(tmp)); /* 0x80 */ tmp[0] = 0x80; /* 0x06 */ tmp[1] = 0x06; /* ; per above under 3 */ tmp[2] = (unsigned char)strlen(command) + 1; /* 0x03 */ tmp[3] = 0x03; /* */ memcpy(&tmp[4], command, strlen(command)); /* */ tmp[7] = answer_len; upsdebug_hex(4, "command", (char *)tmp, 8); /* Write data */ ret = usb_interrupt_write(udev, USB_ENDPOINT_OUT | 2, (const usb_ctrl_charbuf)tmp, 8, USB_TIMEOUT); if (ret <= 0) { upsdebugx(3, "send: %s (%d)", ret ? nut_usb_strerror(ret) : "timeout", ret); return ret; } upsdebugx(3, "send: %s", command); /* Read reply */ memset(buf, 0, buflen); for (i = 0; (i <= buflen - 8) && (memchr(buf, '\r', buflen) == NULL); i += (size_t)ret) { /* Read data in 8-byte chunks */ ret = usb_interrupt_read(udev, USB_ENDPOINT_IN | 1, (usb_ctrl_charbuf)&buf[i], 8, 1000); /* Any errors here mean that we are unable to read a reply * (which will happen after successfully writing a command * to the UPS) */ if (ret <= 0) { upsdebugx(3, "read: %s (%d)", ret ? nut_usb_strerror(ret) : "timeout", ret); return ret; } snprintf(read, sizeof(read), "read [%3d]", (int)i); upsdebug_hex(5, read, &buf[i], (size_t)ret); } upsdebugx(3, "read: %.*s", (int)strcspn(buf, "\r"), buf); /* As Fuji units return the reply in 8-byte chunks always padded to the 8th byte with 0x00, we need to calculate and return the length of the actual response here. */ return (int)strlen(buf); } /* Phoenixtec (Masterguard) communication subdriver */ static int phoenixtec_command(const char *cmd, char *buf, size_t buflen) { int ret; char *p, *e = NULL; char *l[] = { "T", "TL", "S", "C", "CT", "M", "N", "O", "SRC", "FCLR", "SS", "TUD", "SSN", NULL }; /* commands that don't return an answer */ char **lp; size_t cmdlen = strlen(cmd); if (cmdlen > INT_MAX) { upsdebugx(3, "%s: requested command is too long (%" PRIuSIZE ")", __func__, cmdlen); return 0; } if (buflen > INT_MAX) { upsdebugx(3, "%s: requested to read too much (%" PRIuSIZE "), " "reducing buflen to (INT_MAX-1)", __func__, buflen); buflen = (INT_MAX - 1); } if ((ret = usb_control_msg(udev, USB_ENDPOINT_OUT | USB_TYPE_VENDOR | USB_RECIP_ENDPOINT, 0x0d, 0, 0, (usb_ctrl_charbuf)cmd, (int)cmdlen, 1000)) <= 0 ) { upsdebugx(3, "send: %s (%d)", ret ? nut_usb_strerror(ret) : "timeout", ret); *buf = '\0'; return ret; } for (lp = l; *lp != NULL; lp++) { const char *q; int b; p = *lp; q = cmd; b = 1; while (*p != '\0') { if (*p++ != *q++) { b = 0; break; } } if (b && *q >= 'A' && *q <= 'Z') b = 0; /* "M" not to match "MSO" */ if (b) { upsdebugx(4, "command %s returns no answer", *lp); *buf = '\0'; return 0; } } for (p = buf; p < buf + buflen; p += ret) { /* buflen constrained to INT_MAX above, so we can cast: */ if ((ret = usb_interrupt_read(udev, USB_ENDPOINT_IN | 1, (usb_ctrl_charbuf)p, (int)(buf + buflen - p), 1000)) <= 0 ) { upsdebugx(3, "read: %s (%d)", ret ? nut_usb_strerror(ret) : "timeout", ret); *buf = '\0'; return ret; } if ((e = memchr(p, '\r', (size_t)ret)) != NULL) break; } if (e != NULL && ++e < buf + buflen) { *e = '\0'; /* buflen constrained to INT_MAX above, so we can cast: */ return (int)(e - buf); } else { upsdebugx(3, "read: buflen %" PRIuSIZE " too small", buflen); *buf = '\0'; return 0; } } /* SNR communication subdriver */ static int snr_command(const char *cmd, char *buf, size_t buflen) { /*ATTENTION: This subdriver uses short buffer with length 102 byte*/ const struct { const char *str; /* Megatec command */ const int index; /* String index for this command */ const char prefix; /* Character to replace the first byte in reply */ } command[] = { { "Q1\r", 0x03, '(' }, { "F\r", 0x0d, '#' }, { "I\r", 0x0c, '#' }, { NULL, 0, '\0' } }; int i; upsdebugx(3, "send: %.*s", (int)strcspn(cmd, "\r"), cmd); if (buflen > INT_MAX) { upsdebugx(3, "%s: requested to read too much (%" PRIuSIZE "), " "reducing buflen to (INT_MAX-1)", __func__, buflen); buflen = (INT_MAX - 1); } if (buflen < 102) { upsdebugx(4, "size of buf less than 102 byte!"); return 0; } /* Prepare SNR-UPS for communication. * Without the interrupt UPS returns zeros for some time, * and afterwards NUT returns a communications error. */ usb_interrupt_read(udev, 0x81, (usb_ctrl_charbuf)buf, 102, 1000); for (i = 0; command[i].str; i++) { int retry; if (strcmp(cmd, command[i].str)) { continue; } for (retry = 0; retry < 10; retry++) { unsigned int di, si, size; int ret; ret = usb_get_string(udev, command[i].index, langid_fix, (usb_ctrl_charbuf)buf, 102); if (ret <= 0) { upsdebugx(3, "read: %s (%d)", ret ? nut_usb_strerror(ret) : "timeout", ret); return ret; } /* This may serve in the future */ upsdebugx(1, "received %d (%d)", ret, buf[0]); if (ret != buf[0]) { upsdebugx(1, "size mismatch: %d / %d", ret, buf[0]); continue; } /* Simple unicode -> ASCII inplace conversion * FIXME: this code is at least shared with mge-shut/libshut * Create a common function? */ size = (unsigned int)buf[0]; for (di = 0, si = 2; si < size; si += 2) { if (di >= (buflen - 1)) break; if (buf[si + 1]) /* high byte */ buf[di++] = '?'; else buf[di++] = buf[si]; } /* Note: effective range of di should be unsigned char */ buf[di] = 0; ret = (int)di; /* "UPS No Ack" has a special meaning */ if ( strcspn(buf, "\r") == 10 && !strncasecmp(buf, "UPS No Ack", 10) ) { upsdebugx(3, "read: %.*s", (int)strcspn(buf, "\r"), buf); continue; } /* Replace the first byte of what we received with the correct one */ buf[0] = command[i].prefix; upsdebug_hex(5, "read", buf, (size_t)ret); upsdebugx(3, "read: %.*s", (int)strcspn(buf, "\r"), buf); return ret; } return 0; } /* Echo the unknown command back */ upsdebugx(3, "read: %.*s", (int)strcspn(cmd, "\r"), cmd); return snprintf(buf, buflen, "%s", cmd); } static int ablerex_command(const char *cmd, char *buf, size_t buflen) { int iii; int len; int idx; int retry; char tmp[64]; char tmpryy[64]; upsdebugx(3, "send: %.*s", (int)strcspn(cmd, "\r"), cmd); if (buflen > INT_MAX) { upsdebugx(3, "%s: requested to read too much (%" PRIuSIZE "), reducing buflen to (INT_MAX-1)", __func__, buflen); buflen = (INT_MAX - 1); } for (retry = 0; retry < 3; retry++) { int ret; memset(buf, 0, buflen); tmp[0] = 0x05; tmp[1] = 0; tmp[2] = 1 + (char)strcspn(cmd, "\r"); for (iii = 0 ; iii < tmp[2] ; iii++) { tmp[3+iii] = cmd[iii]; } ret = usb_control_msg(udev, 0x21, 0x09, 0x305, 0, (usb_ctrl_charbuf)tmp, 47, 1000); upsdebugx(3, "R11 read: %s", ret ? nut_usb_strerror(ret) : "timeout"); usleep(500000); tmpryy[0] = 0x05; ret = usb_control_msg(udev, 0xA1, 0x01, 0x305, 0, (usb_ctrl_charbuf)tmpryy, 47, 1000); upsdebugx(3, "R2 read%d: %.*s", ret, ret, tmpryy); len = 0; for (idx = 0 ; idx < 47 ; idx++) { buf[idx] = tmpryy[idx]; if (tmpryy[idx] == '\r') { len = idx; break; } } upsdebugx(3, "R3 read%d: %.*s", len, len, tmpryy); if (len > 0) { len ++; } if (ret <= 0) { upsdebugx(3, "read: %s", ret ? nut_usb_strerror(ret) : "timeout"); return ret; } upsdebugx(1, "received %d (%d)", ret, buf[0]); if ((!strcasecmp(cmd, "Q1\r")) && len != 47) continue; if ((!strcasecmp(cmd, "I\r")) && len != 39) continue; if ((!strcasecmp(cmd, "F\r")) && len != 22) continue; if ((!strcasecmp(cmd, "Q5\r")) && len != 22) { buf[0] = '('; for (idx = 1 ; idx < 47 ; idx++) { buf[idx] = 0; } upsdebugx(3, "read Q5 Fail..."); return 22; } upsdebugx(3, "read: %.*s", (int)strcspn(buf, "\r"), buf); return len; } return 0; } static void *ablerex_subdriver_fun(USBDevice_t *device) { NUT_UNUSED_VARIABLE(device); subdriver_command = &ablerex_command; return NULL; } /* Armac communication subdriver * * This reproduces a communication protocol used by an old PowerManagerII * software, which doesn't seem to be Armac specific. The banner is: "2004 * Richcomm Technologies, Inc. Dec 27 2005 ver 1.1." Maybe other Richcomm UPSes * would work with this - better than with the richcomm_usb driver. */ #define ARMAC_READ_SIZE 6 static int armac_command(const char *cmd, char *buf, size_t buflen) { char tmpbuf[ARMAC_READ_SIZE]; int ret = 0; size_t i, bufpos; const size_t cmdlen = strlen(cmd); /* UPS ignores (doesn't echo back) unsupported commands which makes * the initialization long. List commands tested to be unsupported: */ const char *unsupported[] = { "QGS\r", "QS\r", "QPI\r", "M\r", "D\r", NULL }; for (i = 0; unsupported[i] != NULL; i++) { if (strcmp(cmd, unsupported[i]) == 0) { upsdebugx(2, "armac: unsupported cmd: %.*s", (int)strcspn(cmd, "\r"), cmd); return snprintf(buf, buflen, "%s", cmd); } } upsdebugx(4, "armac command %.*s", (int)strcspn(cmd, "\r"), cmd); /* Cleanup buffer before sending a new command */ for (i = 0; i < 10; i++) { ret = usb_interrupt_read(udev, 0x81, (usb_ctrl_charbuf)tmpbuf, ARMAC_READ_SIZE, 100); if (ret != ARMAC_READ_SIZE) { // Timeout - buffer is clean. break; } upsdebugx(4, "armac cleanup ret i=%" PRIuSIZE " ret=%d ctrl=%02hhx", i, ret, tmpbuf[0]); } /* Send command to the UPS in 3-byte chunks. Most fit 1 chunk, except for eg. * parameterized tests. */ for (i = 0; i < cmdlen;) { const size_t bytes_to_send = (cmdlen <= (i + 3)) ? (cmdlen - i) : 3; memset(tmpbuf, 0, sizeof(tmpbuf)); tmpbuf[0] = 0xa0 + bytes_to_send; memcpy(tmpbuf + 1, cmd + i, bytes_to_send); ret = usb_control_msg(udev, USB_ENDPOINT_OUT + USB_TYPE_CLASS + USB_RECIP_INTERFACE, 0x09, 0x200, 0, (usb_ctrl_charbuf)tmpbuf, 4, 5000); i += bytes_to_send; } if (ret <= 0) { upsdebugx(1, "send control: %s (%d)", ret ? nut_usb_strerror(ret) : "timeout", ret); return ret; } /* Wait for response to buffer */ usleep(2000); memset(buf, 0, buflen); bufpos = 0; while (bufpos + ARMAC_READ_SIZE < buflen) { size_t bytes_available; /* Read data in 6-byte chunks */ ret = usb_interrupt_read(udev, 0x81, (usb_ctrl_charbuf)tmpbuf, ARMAC_READ_SIZE, 1000); /* Any errors here mean that we are unable to read a reply * (which will happen after successfully writing a command * to the UPS) */ if (ret != ARMAC_READ_SIZE) { /* NOTE: If end condition is invalid for particular UPS we might make one * request more and get this error. If bufpos > (say) 10 this could be ignored * and the reply correctly read. */ upsdebugx(1, "interrupt read error: %s (%d)", ret ? nut_usb_strerror(ret) : "timeout", ret); return ret; } upsdebugx(4, "read: ret %d buf %02hhx: %02hhx %02hhx %02hhx %02hhx %02hhx >%c%c%c%c%c<", ret, tmpbuf[0], tmpbuf[1], tmpbuf[2], tmpbuf[3], tmpbuf[4], tmpbuf[5], tmpbuf[1], tmpbuf[2], tmpbuf[3], tmpbuf[4], tmpbuf[5]); /* * On most tested devices (including R/2000I/PSW) this was equal to the number of * bytes returned in the buffer, but on some newer UPS (R/3000I/PF1) it was 1 more * (1 control + 5 bytes transferred and bytes_available equal to 6 instead of 5). * * Current assumption is that this is number of bytes available on the UPS side * with up to 5 (ret - 1) transferred. */ bytes_available = (unsigned char)tmpbuf[0] & 0x0f; if (bytes_available == 0) { /* End of transfer */ break; } if (bytes_available > ARMAC_READ_SIZE - 1) { /* Single interrupt transfer has 1 control + 5 data bytes */ bytes_available = ARMAC_READ_SIZE - 1; } /* Copy bytes into the final buffer while detecting end of line - \r */ for (i = 0; i < bytes_available; i++) { if (tmpbuf[i + 1] == 0x00 && bufpos == 0) { /* Happens when a manually turned off UPS is connected to the USB */ upsdebugx(3, "null byte read - is UPS off?"); return 0; } /* Vultech V2000 seems to use 0x00 within status bits. This might mean "unsupported". * or something else completely. */ if (tmpbuf[i + 1] == 0x00) { if (bufpos >= 38) { upsdebugx(3, "found null byte in status bits at %" PRIuSIZE " byte, assuming 0.", bufpos); buf[bufpos++] = '0'; continue; } else { upsdebugx(3, "found null byte in data stream - interrupting read."); /* Break through two loops */ goto end_of_message; } } buf[bufpos++] = tmpbuf[i + 1]; if (tmpbuf[i + 1] == 0x0d) { if (i + 1 != bytes_available) { upsdebugx(3, "trailing bytes in serial transmission found: %" PRIuSIZE " copied out of %" PRIuSIZE, i + 1, bytes_available ); } /* Break through two loops */ goto end_of_message; } } if (bytes_available <= 2) { /* Slow down, let the UPS buffer more bytes */ usleep(10000); } } end_of_message: if (bufpos + 6 >= buflen) { upsdebugx(2, "Protocol error, too much data read."); return -1; } upsdebugx(3, "armac command %.*s response read: '%.*s'", (int)strcspn(cmd, "\r"), cmd, (int)strcspn(buf, "\r"), buf ); return (int)bufpos; } static void *cypress_subdriver(USBDevice_t *device) { NUT_UNUSED_VARIABLE(device); subdriver_command = &cypress_command; return NULL; } static void *sgs_subdriver(USBDevice_t *device) { NUT_UNUSED_VARIABLE(device); subdriver_command = &sgs_command; return NULL; } static void *ippon_subdriver(USBDevice_t *device) { NUT_UNUSED_VARIABLE(device); subdriver_command = &ippon_command; return NULL; } static void *krauler_subdriver(USBDevice_t *device) { NUT_UNUSED_VARIABLE(device); subdriver_command = &krauler_command; return NULL; } static void *phoenix_subdriver(USBDevice_t *device) { NUT_UNUSED_VARIABLE(device); subdriver_command = &phoenix_command; return NULL; } static void *fabula_subdriver(USBDevice_t *device) { NUT_UNUSED_VARIABLE(device); subdriver_command = &fabula_command; return NULL; } static void *phoenixtec_subdriver(USBDevice_t *device) { NUT_UNUSED_VARIABLE(device); subdriver_command = &phoenixtec_command; return NULL; } /* Note: the "hunnox_subdriver" name is taken by the subdriver_t structure */ static void *fabula_hunnox_subdriver(USBDevice_t *device) { NUT_UNUSED_VARIABLE(device); subdriver_command = &hunnox_command; return NULL; } static void *fuji_subdriver(USBDevice_t *device) { NUT_UNUSED_VARIABLE(device); subdriver_command = &fuji_command; return NULL; } static void *snr_subdriver(USBDevice_t *device) { NUT_UNUSED_VARIABLE(device); subdriver_command = &snr_command; return NULL; } static void *armac_subdriver(USBDevice_t *device) { NUT_UNUSED_VARIABLE(device); subdriver_command = &armac_command; return NULL; } /* USB device match structure */ typedef struct { const int vendorID; /* USB device's VendorID */ const int productID; /* USB device's ProductID */ const char *vendor; /* USB device's iManufacturer string */ const char *product; /* USB device's iProduct string */ void *(*fun)(USBDevice_t *); /* Handler for specific processing */ } qx_usb_device_id_t; /* USB VendorID/ProductID/iManufacturer/iProduct match - note: rightmost comment is used for naming rules by tools/nut-usbinfo.pl */ static qx_usb_device_id_t qx_usb_id[] = { { USB_DEVICE(0x05b8, 0x0000), NULL, NULL, &cypress_subdriver }, /* Agiler UPS */ { USB_DEVICE(0xffff, 0x0000), NULL, NULL, &ablerex_subdriver_fun }, /* Ablerex 625L USB (Note: earlier best-fit was "krauler_subdriver" before PR #1135) */ { USB_DEVICE(0x1cb0, 0x0035), NULL, NULL, &krauler_subdriver }, /* Legrand Daker DK / DK Plus */ { USB_DEVICE(0x0665, 0x5161), NULL, NULL, &cypress_subdriver }, /* Belkin F6C1200-UNV/Voltronic Power UPSes */ { USB_DEVICE(0x06da, 0x0002), "Phoenixtec Power","USB Cable (V2.00)", &phoenixtec_subdriver },/* Masterguard A Series */ { USB_DEVICE(0x06da, 0x0002), NULL, NULL, &cypress_subdriver }, /* Online Yunto YQ450 */ { USB_DEVICE(0x06da, 0x0003), NULL, NULL, &ippon_subdriver }, /* Mustek Powermust */ { USB_DEVICE(0x06da, 0x0004), NULL, NULL, &cypress_subdriver }, /* Phoenixtec Innova 3/1 T */ { USB_DEVICE(0x06da, 0x0005), NULL, NULL, &cypress_subdriver }, /* Phoenixtec Innova RT */ { USB_DEVICE(0x06da, 0x0201), NULL, NULL, &cypress_subdriver }, /* Phoenixtec Innova T */ { USB_DEVICE(0x06da, 0x0601), NULL, NULL, &phoenix_subdriver }, /* Online Zinto A */ { USB_DEVICE(0x0f03, 0x0001), NULL, NULL, &cypress_subdriver }, /* Unitek Alpha 1200Sx */ { USB_DEVICE(0x14f0, 0x00c9), NULL, NULL, &phoenix_subdriver }, /* GE EP series */ { USB_DEVICE(0x0483, 0x0035), NULL, NULL, &sgs_subdriver }, /* TS Shara UPSes; vendor ID 0x0483 is from ST Microelectronics - with product IDs delegated to different OEMs */ { USB_DEVICE(0x0001, 0x0000), "MEC", "MEC0003", &fabula_subdriver }, /* Fideltronik/MEC LUPUS 500 USB */ { USB_DEVICE(0x0001, 0x0000), NULL, "MEC0003", &fabula_hunnox_subdriver }, /* Hunnox HNX 850, reported to also help support Powercool and some other devices; closely related to fabula with tweaks */ { USB_DEVICE(0x0001, 0x0000), "ATCL FOR UPS", "ATCL FOR UPS", &fuji_subdriver }, /* Fuji UPSes */ { USB_DEVICE(0x0001, 0x0000), NULL, NULL, &krauler_subdriver }, /* Krauler UP-M500VA */ { USB_DEVICE(0x0001, 0x0000), NULL, "MEC0003", &snr_subdriver }, /* SNR-UPS-LID-XXXX UPSes */ { USB_DEVICE(0x0925, 0x1234), NULL, NULL, &armac_subdriver }, /* Armac UPS and maybe other richcomm-like or using old PowerManagerII software */ /* End of list */ { -1, -1, NULL, NULL, NULL } }; static int qx_is_usb_device_supported(qx_usb_device_id_t *usb_device_id_list, USBDevice_t *device) { int retval = NOT_SUPPORTED; qx_usb_device_id_t *usbdev; for (usbdev = usb_device_id_list; usbdev->vendorID != -1; usbdev++) { if (usbdev->vendorID != device->VendorID) continue; /* Flag as possibly supported if we see a known vendor */ retval = POSSIBLY_SUPPORTED; if (usbdev->productID != device->ProductID) continue; if (usbdev->vendor && (!device->Vendor || strcasecmp(usbdev->vendor, device->Vendor)) ) { continue; } if (usbdev->product && (!device->Product || strcasecmp(usbdev->product, device->Product)) ) { continue; } /* Call the specific handler, if it exists */ if (usbdev->fun != NULL) (*usbdev->fun)(device); return SUPPORTED; } return retval; } static int device_match_func(USBDevice_t *hd, void *privdata) { NUT_UNUSED_VARIABLE(privdata); if (subdriver_command) { return 1; } switch (qx_is_usb_device_supported(qx_usb_id, hd)) { case SUPPORTED: return 1; case POSSIBLY_SUPPORTED: case NOT_SUPPORTED: default: return 0; } } static USBDeviceMatcher_t device_matcher = { &device_match_func, NULL, NULL }; #endif /* QX_USB && !TESTING */ /* == Driver functions implementations == */ /* See header file for details. */ int instcmd(const char *cmdname, const char *extradata) { item_t *item; char value[SMALLBUF]; if (!strcasecmp(cmdname, "beeper.off")) { /* Compatibility mode for old command */ upslogx(LOG_WARNING, "The 'beeper.off' command has been renamed to 'beeper.disable'"); return instcmd("beeper.disable", NULL); } if (!strcasecmp(cmdname, "beeper.on")) { /* Compatibility mode for old command */ upslogx(LOG_WARNING, "The 'beeper.on' command has been renamed to 'beeper.enable'"); return instcmd("beeper.enable", NULL); } upslogx(LOG_INFO, "%s(%s, %s)", __func__, cmdname, extradata ? extradata : "[NULL]"); /* Retrieve item by command name */ item = find_nut_info(cmdname, QX_FLAG_CMD, QX_FLAG_SKIP); /* Check for fallback if not found */ if (item == NULL) { if (!strcasecmp(cmdname, "load.on")) { return instcmd("load.on.delay", "0"); } if (!strcasecmp(cmdname, "load.off")) { return instcmd("load.off.delay", "0"); } if (!strcasecmp(cmdname, "shutdown.return")) { int ret; /* Ensure "ups.start.auto" is set to "yes", if supported */ if (dstate_getinfo("ups.start.auto")) { if (setvar("ups.start.auto", "yes") != STAT_SET_HANDLED) { upslogx(LOG_ERR, "%s: FAILED", __func__); return STAT_INSTCMD_FAILED; } } ret = instcmd("load.on.delay", dstate_getinfo("ups.delay.start")); if (ret != STAT_INSTCMD_HANDLED) { return ret; } return instcmd("load.off.delay", dstate_getinfo("ups.delay.shutdown")); } if (!strcasecmp(cmdname, "shutdown.stayoff")) { int ret; /* Ensure "ups.start.auto" is set to "no", if supported */ if (dstate_getinfo("ups.start.auto")) { if (setvar("ups.start.auto", "no") != STAT_SET_HANDLED) { upslogx(LOG_ERR, "%s: FAILED", __func__); return STAT_INSTCMD_FAILED; } } ret = instcmd("load.on.delay", "-1"); if (ret != STAT_INSTCMD_HANDLED) { return ret; } return instcmd("load.off.delay", dstate_getinfo("ups.delay.shutdown")); } upsdebugx(2, "%s: command %s unavailable", __func__, cmdname); return STAT_INSTCMD_INVALID; } /* If extradata is empty, use the default value * from the QX to NUT table, if any */ extradata = extradata ? extradata : item->dfl; snprintf(value, sizeof(value), "%s", extradata ? extradata : ""); /* Preprocess command */ if (item->preprocess != NULL && item->preprocess(item, value, sizeof(value)) ) { /* Something went wrong */ upslogx(LOG_ERR, "%s: FAILED", __func__); return STAT_INSTCMD_FAILED; } /* No preprocess function -> nothing to do with extradata */ if (item->preprocess == NULL) snprintf(value, sizeof(value), "%s", ""); /* Send the command, get the reply */ if (qx_process(item, strlen(value) > 0 ? value : NULL)) { /* Something went wrong */ upslogx(LOG_ERR, "%s: FAILED", __func__); return STAT_INSTCMD_FAILED; } /* We got a reply from the UPS: * either subdriver->accepted (-> command handled) * or the command itself echoed back (-> command failed) */ if (strlen(item->value) > 0) { if (subdriver->accepted != NULL && !strcasecmp(item->value, subdriver->accepted) ) { upslogx(LOG_INFO, "%s: SUCCEED", __func__); /* Set the status so that SEMI_STATIC vars are polled */ data_has_changed = TRUE; return STAT_INSTCMD_HANDLED; } upslogx(LOG_ERR, "%s: FAILED", __func__); return STAT_INSTCMD_FAILED; } /* No reply from the UPS -> command handled */ upslogx(LOG_INFO, "%s: SUCCEED", __func__); /* Set the status so that SEMI_STATIC vars are polled */ data_has_changed = TRUE; return STAT_INSTCMD_HANDLED; } /* See header file for details. */ int setvar(const char *varname, const char *val) { item_t *item; char value[SMALLBUF]; st_tree_t *root = (st_tree_t *)dstate_getroot(); int ok = 0; /* Retrieve variable */ item = find_nut_info(varname, QX_FLAG_SETVAR, QX_FLAG_SKIP); if (item == NULL) { upsdebugx(2, "%s: element %s unavailable", __func__, varname); return STAT_SET_UNKNOWN; } /* No NUT variable is available for this item, so we're handling * a one-time setvar from ups.conf */ if (item->qxflags & QX_FLAG_NONUT) { const char *userval; /* Nothing to do */ if (!testvar(item->info_type)) { upsdebugx(2, "%s: nothing to do... [%s]", __func__, item->info_type); return STAT_SET_HANDLED; } userval = getval(item->info_type); upslogx(LOG_INFO, "%s(%s, %s)", __func__, varname, userval ? userval : "[NULL]"); snprintf(value, sizeof(value), "%s", userval ? userval : ""); /* This item is available in NUT */ } else { upslogx(LOG_INFO, "%s(%s, %s)", __func__, varname, strlen(val) ? val : "[NULL]"); if (!strlen(val)) { upslogx(LOG_ERR, "%s: value not given for %s", __func__, item->info_type); return STAT_SET_UNKNOWN; /* TODO: HANDLED but FAILED, not UNKNOWN! */ } snprintf(value, sizeof(value), "%s", val); /* Nothing to do */ if (!strcasecmp(dstate_getinfo(item->info_type), value)) { upslogx(LOG_INFO, "%s: nothing to do... [%s]", __func__, item->info_type); return STAT_SET_HANDLED; } } /* Check if given value is in the range of accepted values (range) */ if (item->qxflags & QX_FLAG_RANGE) { long valuetoset, min, max; if (strspn(value, "0123456789 .") != strlen(value)) { upslogx(LOG_ERR, "%s: non numerical value [%s: %s]", __func__, item->info_type, value); return STAT_SET_UNKNOWN; /* TODO: HANDLED but FAILED, not UNKNOWN! */ } valuetoset = strtol(value, NULL, 10); /* No NUT var is available for this item, so * take its range from qx2nut table */ if (item->qxflags & QX_FLAG_NONUT) { info_rw_t *rvalue; if (!strlen(value)) { upslogx(LOG_ERR, "%s: value not given for %s", __func__, item->info_type); return STAT_SET_UNKNOWN; /* TODO: HANDLED but FAILED, not UNKNOWN! */ } min = max = -1; /* Loop on all existing values */ for (rvalue = item->info_rw; rvalue != NULL && strlen(rvalue->value) > 0; rvalue++) { if (rvalue->preprocess && rvalue->preprocess(rvalue->value, sizeof(rvalue->value)) ) { continue; } if (min < 0) { min = strtol(rvalue->value, NULL, 10); continue; } max = strtol(rvalue->value, NULL, 10); /* valuetoset is in the range */ if (min <= valuetoset && valuetoset <= max) { ok = 1; break; } min = -1; max = -1; } /* We have a NUT var for this item, so check given value * against the already set range */ } else { const range_t *range = state_getrangelist(root, item->info_type); /* Unable to find tree node for var */ if (!range) { upsdebugx(2, "%s: unable to find tree node for %s", __func__, item->info_type); return STAT_SET_UNKNOWN; } while (range) { min = range->min; max = range->max; /* valuetoset is in the range */ if (min <= valuetoset && valuetoset <= max) { ok = 1; break; } range = range->next; } } if (!ok) { upslogx(LOG_ERR, "%s: value out of range [%s: %s]", __func__, item->info_type, value); return STAT_SET_UNKNOWN; /* TODO: HANDLED but FAILED, not UNKNOWN! */ } /* Check if given value is in the range of accepted values (enum) */ } else if (item->qxflags & QX_FLAG_ENUM) { /* No NUT var is available for this item, so * take its range from qx2nut table */ if (item->qxflags & QX_FLAG_NONUT) { info_rw_t *envalue; if (!strlen(value)) { upslogx(LOG_ERR, "%s: value not given for %s", __func__, item->info_type); return STAT_SET_UNKNOWN; /* TODO: HANDLED but FAILED, not UNKNOWN! */ } /* Loop on all existing values */ for (envalue = item->info_rw; envalue != NULL && strlen(envalue->value) > 0; envalue++) { if (envalue->preprocess && envalue->preprocess(envalue->value, sizeof(envalue->value)) ) { continue; } if (strcasecmp(envalue->value, value)) continue; /* value found */ ok = 1; break; } /* We have a NUT var for this item, so check given value * against the already set range */ } else { const enum_t *enumlist = state_getenumlist(root, item->info_type); /* Unable to find tree node for var */ if (!enumlist) { upsdebugx(2, "%s: unable to find tree node for %s", __func__, item->info_type); return STAT_SET_UNKNOWN; } while (enumlist) { /* If this is not the right value, go on to the next */ if (strcasecmp(enumlist->val, value)) { enumlist = enumlist->next; continue; } /* value found in enumlist */ ok = 1; break; } } if (!ok) { upslogx(LOG_ERR, "%s: value out of range [%s: %s]", __func__, item->info_type, value); return STAT_SET_UNKNOWN; /* TODO: HANDLED but FAILED, not UNKNOWN! */ } /* Check if given value is not too long (string) */ } else if (item->info_flags & ST_FLAG_STRING) { const long aux = state_getaux(root, item->info_type); /* Unable to find tree node for var */ if (aux < 0) { upsdebugx(2, "%s: unable to find tree node for %s", __func__, item->info_type); return STAT_SET_UNKNOWN; } /* FIXME? Should this cast to "long"? * An int-size string is quite a lot already, * even on architectures with a moderate INTMAX */ if (aux < (int)strlen(value)) { upslogx(LOG_ERR, "%s: value is too long [%s: %s]", __func__, item->info_type, value); return STAT_SET_UNKNOWN; /* TODO: HANDLED but FAILED, not UNKNOWN! */ } } /* Preprocess value: from NUT-compliant to UPS-compliant */ if (item->preprocess != NULL && item->preprocess(item, value, sizeof(value)) ) { /* Something went wrong */ upslogx(LOG_ERR, "%s: FAILED", __func__); return STAT_SET_UNKNOWN; /* TODO: HANDLED but FAILED, not UNKNOWN! */ } /* Handle server side variable */ if (item->qxflags & QX_FLAG_ABSENT) { upsdebugx(2, "%s: setting server side variable %s", __func__, item->info_type); dstate_setinfo(item->info_type, "%s", value); upslogx(LOG_INFO, "%s: SUCCEED", __func__); return STAT_SET_HANDLED; } /* No preprocess function -> nothing to do with val */ if (item->preprocess == NULL) snprintf(value, sizeof(value), "%s", ""); /* Actual variable setting */ if (qx_process(item, strlen(value) > 0 ? value : NULL)) { /* Something went wrong */ upslogx(LOG_ERR, "%s: FAILED", __func__); return STAT_SET_UNKNOWN; /* TODO: HANDLED but FAILED, not UNKNOWN! */ } /* We got a reply from the UPS: * either subdriver->accepted (-> command handled) * or the command itself echoed back (-> command failed) */ if (strlen(item->value) > 0) { if (subdriver->accepted != NULL && !strcasecmp(item->value, subdriver->accepted) ) { upslogx(LOG_INFO, "%s: SUCCEED", __func__); /* Set the status so that SEMI_STATIC vars are polled */ data_has_changed = TRUE; return STAT_SET_HANDLED; } upslogx(LOG_ERR, "%s: FAILED", __func__); return STAT_SET_UNKNOWN; /* TODO: HANDLED but FAILED, not UNKNOWN! */ } /* No reply from the UPS -> command handled */ upslogx(LOG_INFO, "%s: SUCCEED", __func__); /* Set the status so that SEMI_STATIC vars are polled */ data_has_changed = TRUE; return STAT_SET_HANDLED; } /* Try to shutdown the UPS */ void upsdrv_shutdown(void) { int retry; item_t *item; const char *val; upsdebugx(1, "%s...", __func__); /* Get user-defined delays */ /* Start delay */ item = find_nut_info("ups.delay.start", 0, QX_FLAG_SKIP); /* Don't know what happened */ if (!item) { upslogx(LOG_ERR, "Unable to set start delay"); set_exit_flag(-1); return; } /* Set the default value */ dstate_setinfo(item->info_type, "%s", item->dfl); /* Set var flags/range/enum */ qx_set_var(item); /* Retrieve user defined delay settings */ val = getval(QX_VAR_ONDELAY); if (val && setvar(item->info_type, val) != STAT_SET_HANDLED) { upslogx(LOG_ERR, "Start delay '%s' out of range", val); set_exit_flag(-1); return; } /* Shutdown delay */ item = find_nut_info("ups.delay.shutdown", 0, QX_FLAG_SKIP); /* Don't know what happened */ if (!item) { upslogx(LOG_ERR, "Unable to set shutdown delay"); set_exit_flag(-1); return; } /* Set the default value */ dstate_setinfo(item->info_type, "%s", item->dfl); /* Set var flags/range/enum */ qx_set_var(item); /* Retrieve user defined delay settings */ val = getval(QX_VAR_OFFDELAY); if (val && setvar(item->info_type, val) != STAT_SET_HANDLED) { upslogx(LOG_ERR, "Shutdown delay '%s' out of range", val); set_exit_flag(-1); return; } /* Stop pending shutdowns */ if (find_nut_info("shutdown.stop", QX_FLAG_CMD, QX_FLAG_SKIP)) { for (retry = 1; retry <= MAXTRIES; retry++) { if (instcmd("shutdown.stop", NULL) != STAT_INSTCMD_HANDLED) { continue; } break; } if (retry > MAXTRIES) { upslogx(LOG_NOTICE, "No shutdown pending"); } } /* Shutdown */ for (retry = 1; retry <= MAXTRIES; retry++) { if (testvar("stayoff")) { if (instcmd("shutdown.stayoff", NULL) != STAT_INSTCMD_HANDLED) { continue; } } else { if (instcmd("shutdown.return", NULL) != STAT_INSTCMD_HANDLED) { continue; } } upslogx(LOG_ERR, "Shutting down in %s seconds", dstate_getinfo("ups.delay.shutdown")); set_exit_flag(-2); /* EXIT_SUCCESS */ return; } upslogx(LOG_ERR, "Shutdown failed!"); set_exit_flag(-1); } #ifdef QX_USB #ifndef TESTING static const struct { const char *name; int (*command)(const char *cmd, char *buf, size_t buflen); } usbsubdriver[] = { { "cypress", &cypress_command }, { "phoenixtec", &phoenixtec_command }, { "phoenix", &phoenix_command }, { "ippon", &ippon_command }, { "krauler", &krauler_command }, { "fabula", &fabula_command }, { "hunnox", &hunnox_command }, { "fuji", &fuji_command }, { "sgs", &sgs_command }, { "snr", &snr_command }, { "ablerex", &ablerex_command }, { "armac", &armac_command }, { NULL, NULL } }; #endif #endif void upsdrv_help(void) { #ifndef TESTING size_t i; # ifdef QX_USB /* Subdrivers have special SOMETHING_command() handling and * are listed in usbsubdriver[] array (just above in this * source file). */ printf("\nAcceptable values for 'subdriver' via -x or ups.conf in this driver: "); for (i = 0; usbsubdriver[i].name != NULL; i++) { if (i>0) printf(", "); printf("%s", usbsubdriver[i].name); } printf("\n\n"); # endif /* QX_USB*/ /* Protocols are the first token from "name" field in * subdriver_t instances in files like nutdrv_qx_mecer.c */ printf("\nAcceptable values for 'protocol' via -x or ups.conf in this driver: "); for (i = 0; subdriver_list[i] != NULL; i++) { char subdrv_name[SMALLBUF], *p; /* Get rid of subdriver version */ snprintf(subdrv_name, sizeof(subdrv_name), "%.*s", (int)strcspn(subdriver_list[i]->name, " "), subdriver_list[i]->name); /* lowercase the (ASCII) string */ for (p = subdrv_name; *p; ++p) *p = tolower(*p); if (i>0) printf(", "); printf("%s", subdrv_name); } printf("\n\n"); #endif /* TESTING */ printf("Read The Fine Manual ('man 8 nutdrv_qx')\n"); } /* Adding flags/vars */ void upsdrv_makevartable(void) { char temp[SMALLBUF]; int i; upsdebugx(1, "%s...", __func__); snprintf(temp, sizeof(temp), "Set shutdown delay, in seconds (default=%s)", DEFAULT_OFFDELAY); addvar(VAR_VALUE, QX_VAR_OFFDELAY, temp); snprintf(temp, sizeof(temp), "Set startup delay, in seconds (default=%s)", DEFAULT_ONDELAY); addvar(VAR_VALUE, QX_VAR_ONDELAY, temp); addvar(VAR_FLAG, "stayoff", "If invoked the UPS won't return after a shutdown when FSD arises"); snprintf(temp, sizeof(temp), "Set polling frequency, in seconds, to reduce data flow (default=%d)", DEFAULT_POLLFREQ); addvar(VAR_VALUE, QX_VAR_POLLFREQ, temp); addvar(VAR_VALUE, "protocol", "Preselect communication protocol (skip autodetection)"); /* battery.{charge,runtime} guesstimation */ addvar(VAR_VALUE, "runtimecal", "Parameters used for runtime calculation"); addvar(VAR_VALUE, "chargetime", "Nominal charge time for UPS battery"); addvar(VAR_VALUE, "idleload", "Minimum load to be used for runtime calculation"); addvar(VAR_FLAG, "battery_voltage_reports_one_pack", "If your device natively reports battery.voltage of a single cell/pack, " "multiply that into voltage of the whole battery assembly. " "You may need an override.battery.packs=N setting also."); #ifdef QX_USB addvar(VAR_VALUE, "subdriver", "Serial-over-USB subdriver selection"); /* allow -x vendor=X, vendorid=X, product=X, productid=X, serial=X */ nut_usb_addvars(); addvar(VAR_VALUE, "langid_fix", "Apply the language ID workaround to the krauler subdriver " "(0x409 or 0x4095)"); addvar(VAR_FLAG, "noscanlangid", "Don't autoscan valid range for langid"); #endif /* QX_USB */ #ifdef QX_SERIAL addvar(VAR_VALUE, "cablepower", "Set cable power for serial interface"); #endif /* QX_SERIAL */ /* Subdrivers flags/vars */ for (i = 0; subdriver_list[i] != NULL; i++) { if (subdriver_list[i]->makevartable != NULL) subdriver_list[i]->makevartable(); } } /* Update UPS status/infos */ void upsdrv_updateinfo(void) { time_t now; static int retry = 0; upsdebugx(1, "%s...", __func__); time(&now); /* Clear status buffer before beginning */ status_init(); /* Do a full update (polling) every pollfreq or upon data change * (i.e. setvar/instcmd) */ if ((now > (lastpoll + pollfreq)) || (data_has_changed == TRUE)) { upsdebugx(1, "Full update..."); /* Clear ups_status */ ups_status = 0; alarm_init(); if (qx_ups_walk(QX_WALKMODE_FULL_UPDATE) == FALSE) { if (retry < MAXTRIES || retry == MAXTRIES) { upsdebugx(1, "Communications with the UPS lost: status read failed!"); retry++; } else { dstate_datastale(); } return; } lastpoll = now; data_has_changed = FALSE; ups_alarm_set(); alarm_commit(); } else { upsdebugx(1, "Quick update..."); /* Quick poll data only to see if the UPS is still connected */ if (qx_ups_walk(QX_WALKMODE_QUICK_UPDATE) == FALSE) { if (retry < MAXTRIES || retry == MAXTRIES) { upsdebugx(1, "Communications with the UPS lost: status read failed!"); retry++; } else { dstate_datastale(); } return; } } ups_status_set(); status_commit(); if (retry > MAXTRIES) { upslogx(LOG_NOTICE, "Communications with the UPS re-established"); } retry = 0; dstate_dataok(); } /* Initialise data from UPS */ void upsdrv_initinfo(void) { char *val; upsdebugx(1, "%s...", __func__); dstate_setinfo("driver.version.data", "%s", subdriver->name); /* Initialise data */ if (qx_ups_walk(QX_WALKMODE_INIT) == FALSE) { fatalx(EXIT_FAILURE, "Can't initialise data from the UPS"); } /* Init battery guesstimation */ qx_initbattery(); if (dstate_getinfo("ups.delay.start")) { /* Retrieve user defined delay settings */ val = getval(QX_VAR_ONDELAY); if (val && setvar("ups.delay.start", val) != STAT_SET_HANDLED) { fatalx(EXIT_FAILURE, "Start delay '%s' out of range", val); } } if (dstate_getinfo("ups.delay.shutdown")) { /* Retrieve user defined delay settings */ val = getval(QX_VAR_OFFDELAY); if (val && setvar("ups.delay.shutdown", val) != STAT_SET_HANDLED) { fatalx(EXIT_FAILURE, "Shutdown delay '%s' out of range", val); } } if (!find_nut_info("load.off", QX_FLAG_CMD, QX_FLAG_SKIP) && find_nut_info("load.off.delay", QX_FLAG_CMD, QX_FLAG_SKIP) ) { /* Adds default with a delay value of '0' (= immediate) */ dstate_addcmd("load.off"); } if (!find_nut_info("load.on", QX_FLAG_CMD, QX_FLAG_SKIP) && find_nut_info("load.on.delay", QX_FLAG_CMD, QX_FLAG_SKIP) ) { /* Adds default with a delay value of '0' (= immediate) */ dstate_addcmd("load.on"); } /* Init polling frequency */ val = getval(QX_VAR_POLLFREQ); if (val) pollfreq = strtol(val, NULL, 10); dstate_setinfo("driver.parameter.pollfreq", "%ld", pollfreq); time(&lastpoll); /* Install handlers */ upsh.setvar = setvar; upsh.instcmd = instcmd; /* Subdriver initinfo */ if (subdriver->initinfo != NULL) subdriver->initinfo(); } /* Open the port and the like and choose the subdriver */ void upsdrv_initups(void) { #ifdef QX_USB # ifndef TESTING int ret, langid; char tbuf[255]; /* Some devices choke on size > 255 */ char *regex_array[USBMATCHER_REGEXP_ARRAY_LIMIT]; char *subdrv; # endif #endif upsdebugx(1, "%s...", __func__); #if defined(QX_SERIAL) && defined(QX_USB) /* Whether the device is connected through USB or serial */ if ( !strcasecmp(dstate_getinfo("driver.parameter.port"), "auto") || getval("subdriver") || getval("vendorid") || getval("productid") || getval("vendor") || getval("product") || getval("serial") || getval("bus") || getval("langid_fix") #if (defined WITH_USB_BUSPORT) && (WITH_USB_BUSPORT) || getval("busport") #endif ) { /* USB */ is_usb = 1; } else { /* Serial */ is_usb = 0; } #endif /* QX_SERIAL && QX_USB */ /* Serial */ #ifdef QX_SERIAL #ifdef QX_USB if (!is_usb) { #else { /* scoping */ #endif /* QX_USB */ #ifndef TESTING const struct { const char *val; const int dtr; const int rts; } cablepower[] = { { "normal", 1, 0 }, /* Default */ { "reverse", 0, 1 }, { "both", 1, 1 }, { "none", 0, 0 }, { NULL, 0, 0 } }; int i; const char *val; struct termios tio; /* Open and lock the serial port and set the speed to 2400 baud. */ upsfd = ser_open(device_path); ser_set_speed(upsfd, device_path, B2400); if (tcgetattr(upsfd, &tio)) { fatal_with_errno(EXIT_FAILURE, "tcgetattr"); } /* Use canonical mode input processing (to read reply line) */ tio.c_lflag |= ICANON; /* Canonical input (erase and kill processing) */ tio.c_cc[VEOF] = _POSIX_VDISABLE; tio.c_cc[VEOL] = '\r'; tio.c_cc[VERASE] = _POSIX_VDISABLE; tio.c_cc[VINTR] = _POSIX_VDISABLE; tio.c_cc[VKILL] = _POSIX_VDISABLE; tio.c_cc[VQUIT] = _POSIX_VDISABLE; tio.c_cc[VSUSP] = _POSIX_VDISABLE; tio.c_cc[VSTART] = _POSIX_VDISABLE; tio.c_cc[VSTOP] = _POSIX_VDISABLE; if (tcsetattr(upsfd, TCSANOW, &tio)) { fatal_with_errno(EXIT_FAILURE, "tcsetattr"); } val = getval("cablepower"); for (i = 0; val && cablepower[i].val; i++) { if (!strcasecmp(val, cablepower[i].val)) { break; } } if (!cablepower[i].val) { fatalx(EXIT_FAILURE, "Value '%s' not valid for 'cablepower'", val); } ser_set_dtr(upsfd, cablepower[i].dtr); ser_set_rts(upsfd, cablepower[i].rts); /* Allow some time to settle for the cablepower */ usleep(100000); #endif /* TESTING */ #ifdef QX_USB } else { /* is_usb */ #else } /* end of scoping */ #endif /* QX_USB */ #endif /* QX_SERIAL */ /* USB */ #ifdef QX_USB warn_if_bad_usb_port_filename(device_path); # ifndef TESTING subdrv = getval("subdriver"); regex_array[0] = getval("vendorid"); regex_array[1] = getval("productid"); regex_array[2] = getval("vendor"); regex_array[3] = getval("product"); regex_array[4] = getval("serial"); regex_array[5] = getval("bus"); regex_array[6] = getval("device"); # if (defined WITH_USB_BUSPORT) && (WITH_USB_BUSPORT) regex_array[7] = getval("busport"); # else if (getval("busport")) { upslogx(LOG_WARNING, "\"busport\" is configured for the device, but is not actually handled by current build combination of NUT and libusb (ignored)"); } # endif /* Check for language ID workaround (#1) */ if (getval("langid_fix")) { /* Skip "0x" prefix and set back to hexadecimal */ unsigned int u_langid_fix; if ( (sscanf(getval("langid_fix") + 2, "%x", &u_langid_fix) != 1) || (u_langid_fix > INT_MAX) ) { upslogx(LOG_NOTICE, "Error enabling language ID workaround"); } else { langid_fix = (int)u_langid_fix; upsdebugx(2, "Language ID workaround enabled (using '0x%x')", langid_fix); } } /* Pick up the subdriver name if set explicitly */ if (subdrv) { int i; if (!regex_array[0] || !regex_array[1]) { fatalx(EXIT_FAILURE, "When specifying a subdriver, " "'vendorid' and 'productid' are mandatory."); } for (i = 0; usbsubdriver[i].name; i++) { if (strcasecmp(subdrv, usbsubdriver[i].name)) { continue; } subdriver_command = usbsubdriver[i].command; break; } if (!subdriver_command) { fatalx(EXIT_FAILURE, "Subdriver '%s' not found!", subdrv); } } ret = USBNewRegexMatcher(®ex_matcher, regex_array, REG_ICASE | REG_EXTENDED); switch (ret) { case -1: fatal_with_errno(EXIT_FAILURE, "USBNewRegexMatcher"); case 0: break; /* All is well */ default: fatalx(EXIT_FAILURE, "Invalid regular expression: %s", regex_array[ret]); } /* Link the matchers */ regex_matcher->next = &device_matcher; ret = usb->open_dev(&udev, &usbdevice, regex_matcher, NULL); if (ret < 0) { fatalx(EXIT_FAILURE, "No supported devices found. " "Please check your device availability with 'lsusb'\n" "and make sure you have an up-to-date version of NUT. " "If this does not help,\n" "try running the driver with at least 'subdriver', " "'vendorid' and 'productid'\n" "options specified. Please refer to the man page " "for details about these options\n" "(man 8 nutdrv_qx).\n"); } if (!subdriver_command) { fatalx(EXIT_FAILURE, "No subdriver selected"); } /* Create a new matcher for later reopening */ ret = USBNewExactMatcher(&reopen_matcher, &usbdevice); if (ret) { fatal_with_errno(EXIT_FAILURE, "USBNewExactMatcher"); } /* Link the matchers */ reopen_matcher->next = regex_matcher; dstate_setinfo("ups.vendorid", "%04x", usbdevice.VendorID); dstate_setinfo("ups.productid", "%04x", usbdevice.ProductID); /* Check for language ID workaround (#2) */ if ((langid_fix != -1) && (!getval("noscanlangid"))) { /* Future improvement: * Asking for the zero'th index is special - it returns * a string descriptor that contains all the language * IDs supported by the device. * Typically there aren't many - often only one. * The language IDs are 16 bit numbers, and they start at * the third byte in the descriptor. * See USB 2.0 specification, section 9.6.7, for more * information on this. * This should allow automatic application of the workaround */ ret = usb_get_string(udev, 0, 0, (usb_ctrl_charbuf)tbuf, sizeof(tbuf)); if (ret >= 4) { langid = ((uint8_t)tbuf[2]) | (((uint8_t)tbuf[3]) << 8); upsdebugx(1, "First supported language ID: 0x%x " "(please report to the NUT maintainer!)", langid); } } # endif /* TESTING */ # ifdef QX_SERIAL } /* is_usb */ # endif /* QX_SERIAL */ #endif /* QX_USB */ /* Choose subdriver */ if (!subdriver_matcher()) fatalx(EXIT_FAILURE, "Device not supported!"); /* Subdriver initups */ if (subdriver->initups != NULL) subdriver->initups(); } /* Close the ports and the like */ void upsdrv_cleanup(void) { upsdebugx(1, "%s...", __func__); #ifndef TESTING # ifdef QX_SERIAL # ifdef QX_USB if (!is_usb) { # endif /* QX_USB */ ser_set_dtr(upsfd, 0); ser_close(upsfd, device_path); # ifdef QX_USB } else { /* is_usb */ # endif /* QX_USB */ # endif /* QX_SERIAL */ # ifdef QX_USB usb->close_dev(udev); USBFreeExactMatcher(reopen_matcher); USBFreeRegexMatcher(regex_matcher); free(usbdevice.Vendor); free(usbdevice.Product); free(usbdevice.Serial); free(usbdevice.Bus); free(usbdevice.Device); # if (defined WITH_USB_BUSPORT) && (WITH_USB_BUSPORT) free(usbdevice.BusPort); # endif # ifdef QX_SERIAL } /* is_usb */ # endif /* QX_SERIAL */ # endif /* QX_USB */ #endif /* TESTING */ } /* == Support functions == */ /* Generic command processing function: send a command and read a reply. * Returns < 0 on error, 0 on timeout and the number of bytes read on success. */ static ssize_t qx_command(const char *cmd, char *buf, size_t buflen) { #ifndef TESTING ssize_t ret = -1; #endif /* NOTE: Could not find in which ifdef-ed codepath, but clang complained * about unused parameters here. Reference them just in case... */ NUT_UNUSED_VARIABLE(cmd); NUT_UNUSED_VARIABLE(buf); NUT_UNUSED_VARIABLE(buflen); #ifndef TESTING # ifdef QX_USB # ifdef QX_SERIAL /* Communication: USB */ if (is_usb) { # endif /* QX_SERIAL (&& QX_USB)*/ if (udev == NULL) { dstate_setinfo("driver.state", "reconnect.trying"); ret = usb->open_dev(&udev, &usbdevice, reopen_matcher, NULL); if (ret < 1) { return ret; } dstate_setinfo("driver.state", "reconnect.updateinfo"); } ret = (*subdriver_command)(cmd, buf, buflen); if (ret >= 0) { return ret; } switch (ret) { case LIBUSB_ERROR_BUSY: /* Device or resource busy */ fatal_with_errno(EXIT_FAILURE, "Got disconnected by another driver"); #ifndef HAVE___ATTRIBUTE__NORETURN # if (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_PUSH_POP) && (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_UNREACHABLE_CODE) # pragma GCC diagnostic push # pragma GCC diagnostic ignored "-Wunreachable-code" # endif exit(EXIT_FAILURE); /* Should not get here in practice, but compiler is afraid we can fall through */ # if (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_PUSH_POP) && (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_UNREACHABLE_CODE) # pragma GCC diagnostic pop # endif #endif #if WITH_LIBUSB_0_1 /* limit to libusb 0.1 implementation */ case -EPERM: /* Operation not permitted */ fatal_with_errno(EXIT_FAILURE, "Permissions problem"); #ifndef HAVE___ATTRIBUTE__NORETURN # if (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_PUSH_POP) && (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_UNREACHABLE_CODE) # pragma GCC diagnostic push # pragma GCC diagnostic ignored "-Wunreachable-code" # endif exit(EXIT_FAILURE); /* Should not get here in practice, but compiler is afraid we can fall through */ # if (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_PUSH_POP) && (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_UNREACHABLE_CODE) # pragma GCC diagnostic pop # endif #endif #endif /* WITH_LIBUSB_0_1 */ case LIBUSB_ERROR_PIPE: /* Broken pipe */ if (usb_clear_halt(udev, 0x81) == 0) { upsdebugx(1, "Stall condition cleared"); break; } #if (defined ETIME) && ETIME && WITH_LIBUSB_0_1 /* limit to libusb 0.1 implementation */ goto fallthrough_case_ETIME; case -ETIME: /* Timer expired */ fallthrough_case_ETIME: #endif /* ETIME && WITH_LIBUSB_0_1 */ if (usb_reset(udev) == 0) { upsdebugx(1, "Device reset handled"); } goto fallthrough_case_reconnect; case LIBUSB_ERROR_NO_DEVICE: /* No such device */ case LIBUSB_ERROR_ACCESS: /* Permission denied */ case LIBUSB_ERROR_IO: /* I/O error */ #if WITH_LIBUSB_0_1 /* limit to libusb 0.1 implementation */ case -ENXIO: /* No such device or address */ #endif /* WITH_LIBUSB_0_1 */ case LIBUSB_ERROR_NOT_FOUND: /* No such file or directory */ fallthrough_case_reconnect: /* Uh oh, got to reconnect! */ dstate_setinfo("driver.state", "reconnect.trying"); usb->close_dev(udev); udev = NULL; break; case LIBUSB_ERROR_TIMEOUT: /* Connection timed out */ case LIBUSB_ERROR_OVERFLOW: /* Value too large for defined data type */ #if EPROTO && WITH_LIBUSB_0_1 /* limit to libusb 0.1 implementation */ case -EPROTO: /* Protocol error */ #endif default: break; } # ifdef QX_SERIAL /* Communication: serial */ } else { /* !is_usb */ # endif /* QX_SERIAL (&& QX_USB) */ # endif /* QX_USB (&& TESTING) */ # ifdef QX_SERIAL ser_flush_io(upsfd); ret = ser_send(upsfd, "%s", cmd); if (ret <= 0) { upsdebugx(3, "send: %s (%" PRIiSIZE ")", ret ? strerror(errno) : "timeout", ret); return ret; } upsdebugx(3, "send: '%.*s'", (int)strcspn(cmd, "\r"), cmd); ret = ser_get_buf(upsfd, buf, buflen, SER_WAIT_SEC, 0); if (ret <= 0) { upsdebugx(3, "read: %s (%" PRIiSIZE ")", ret ? strerror(errno) : "timeout", ret); return ret; } upsdebug_hex(5, "read", buf, (size_t)ret); upsdebugx(3, "read: '%.*s'", (int)strcspn(buf, "\r"), buf); # ifdef QX_USB } /* !is_usb */ # endif /* QX_USB (&& QX_SERIAL) */ # endif /* QX_SERIAL (&& TESTING) */ return ret; #else /* TESTING */ testing_t *testing = subdriver->testing; int i; memset(buf, 0, buflen); upsdebugx(3, "send: '%.*s'", (int)strcspn(cmd, "\r"), cmd); for (i = 0; cmd && testing[i].cmd; i++) { if (strcasecmp(cmd, testing[i].cmd)) { continue; } upsdebugx(3, "read: '%.*s'", (int)strcspn(testing[i].answer, "\r"), testing[i].answer); /* If requested to do so and this is the case, try to preserve inner '\0's (treat answer as a sequence of bytes) */ if (testing[i].answer_len > 0 && strlen(testing[i].answer) < (size_t)testing[i].answer_len) { size_t len; len = buflen <= (size_t)testing[i].answer_len ? buflen - 1 : (size_t)testing[i].answer_len; len = len <= sizeof(testing[i].answer) ? len : sizeof(testing[i].answer); memcpy(buf, testing[i].answer, len); upsdebug_hex(4, "read", buf, (int)len); return len; } return snprintf(buf, buflen, "%s", testing[i].answer); } /* If the driver expects some kind of reply in case of error.. */ if (subdriver->rejected != NULL) { /* ..fulfill its expectations.. */ upsdebugx(3, "read: '%.*s'", (int)strcspn(subdriver->rejected, "\r"), subdriver->rejected); return snprintf(buf, buflen, "%s", subdriver->rejected); /* ..otherwise.. */ } else { /* ..echo back the command */ upsdebugx(3, "read: '%.*s'", (int)strcspn(cmd, "\r"), cmd); return snprintf(buf, buflen, "%s", cmd); } #endif /* TESTING */ } /* See header file for details. * Interpretation is done in ups_status_set(). */ void update_status(const char *value) { status_lkp_t *status_item; int clear = 0; upsdebugx(5, "%s: %s", __func__, value); if (*value == '!') { value++; clear = 1; } for (status_item = status_info; status_item->status_str != NULL ; status_item++) { if (strcasecmp(status_item->status_str, value)) continue; if (clear) { ups_status &= ~status_item->status_mask; } else { ups_status |= status_item->status_mask; } return; } upsdebugx(5, "%s: Warning! %s not in list of known values", __func__, value); } /* Choose subdriver */ static int subdriver_matcher(void) { const char *protocol = getval("protocol"); int i; /* Select the subdriver for this device */ for (i = 0; subdriver_list[i] != NULL; i++) { int j; /* If protocol is set in ups.conf, use it */ if (protocol) { char subdrv_name[SMALLBUF]; /* Get rid of subdriver version */ snprintf(subdrv_name, sizeof(subdrv_name), "%.*s", (int)strcspn(subdriver_list[i]->name, " "), subdriver_list[i]->name); if (strcasecmp(subdrv_name, protocol)) { upsdebugx(2, "Skipping protocol %s", subdriver_list[i]->name); continue; } } /* Give every subdriver some tries */ for (j = 0; j < MAXTRIES; j++) { subdriver = subdriver_list[i]; if (subdriver->claim()) { break; } subdriver = NULL; } if (subdriver != NULL) break; } if (!subdriver) { upslogx(LOG_ERR, "Device not supported!"); return 0; } upslogx(LOG_INFO, "Using protocol: %s", subdriver->name); return 1; } /* Set vars boundaries */ static void qx_set_var(item_t *item) { if (!(item->qxflags & QX_FLAG_NONUT)) dstate_setflags(item->info_type, item->info_flags); /* Set max length for strings, if needed */ if (item->info_flags & ST_FLAG_STRING && !(item->qxflags & QX_FLAG_NONUT)) dstate_setaux(item->info_type, strtol(item->info_rw[0].value, NULL, 10)); /* Set enum list */ if (item->qxflags & QX_FLAG_ENUM) { info_rw_t *envalue; char buf[LARGEBUF] = ""; /* Loop on all existing values */ for (envalue = item->info_rw; envalue != NULL && strlen(envalue->value) > 0; envalue++) { if (envalue->preprocess && envalue->preprocess(envalue->value, sizeof(envalue->value)) ) { continue; } /* This item is not available yet in NUT, so publish these data in the logs */ if (item->qxflags & QX_FLAG_NONUT) { snprintfcat(buf, sizeof(buf), " %s", envalue->value); /* This item is available in NUT, add its enum to the variable */ } else { dstate_addenum(item->info_type, "%s", envalue->value); } } if (item->qxflags & QX_FLAG_NONUT) upslogx(LOG_INFO, "%s, settable values:%s", item->info_type, strlen(buf) > 0 ? buf : " none"); } /* Set range */ if (item->qxflags & QX_FLAG_RANGE) { info_rw_t *rvalue, *from = NULL, *to = NULL; int ok = 0; /* Loop on all existing values */ for (rvalue = item->info_rw; rvalue != NULL && strlen(rvalue->value) > 0; rvalue++) { if (rvalue->preprocess && rvalue->preprocess(rvalue->value, sizeof(rvalue->value)) ) { continue; } if (!from) { from = rvalue; continue; } to = rvalue; /* This item is not available yet in NUT, so * publish these data in the logs */ if (item->qxflags & QX_FLAG_NONUT) { upslogx(LOG_INFO, "%s, settable range: %s..%s", item->info_type, from->value, to->value); ok++; /* This item is available in NUT, add its range to the variable */ } else { long lFrom = strtol(from->value, NULL, 10), lTo = strtol(to->value, NULL, 10); if (lFrom > INT_MAX || lTo > INT_MAX) { upslogx(LOG_INFO, "%s, settable range exceeds INT_MAX: %ld..%ld", item->info_type, lFrom, lTo); } else { dstate_addrange(item->info_type, (int)lFrom, (int)lTo); } } from = NULL; to = NULL; } /* This item is not available yet in NUT and we weren't able to * get its range; let people know it */ if ((item->qxflags & QX_FLAG_NONUT) && !ok) upslogx(LOG_INFO, "%s, settable range: none", item->info_type); } } /* Walk UPS variables and set elements of the qx2nut array. */ static bool_t qx_ups_walk(walkmode_t mode) { item_t *item; int retcode; /* Clear batt.{chrg,runt}.act for guesstimation */ if (mode == QX_WALKMODE_FULL_UPDATE) { batt.runt.act = -1; batt.chrg.act = -1; battery_voltage_reports_one_pack_considered = 0; } /* Clear data from previous_item */ memset(previous_item.command, 0, sizeof(previous_item.command)); memset(previous_item.answer, 0, sizeof(previous_item.answer)); /* 3 modes: QX_WALKMODE_INIT, QX_WALKMODE_QUICK_UPDATE * and QX_WALKMODE_FULL_UPDATE */ /* Device data walk */ for (item = subdriver->qx2nut; item->info_type != NULL; item++) { /* Skip this item */ if (item->qxflags & QX_FLAG_SKIP) continue; upsdebugx(10, "%s: processing: %s", __func__, item->info_type); /* Filter data according to mode */ switch (mode) { /* Device capabilities enumeration */ case QX_WALKMODE_INIT: /* Special case for handling server side variables */ if (item->qxflags & QX_FLAG_ABSENT) { /* Already set */ if (dstate_getinfo(item->info_type)) continue; dstate_setinfo(item->info_type, "%s", item->dfl); /* Set var flags/range/enum */ qx_set_var(item); continue; } /* Allow duplicates for these NUT variables */ if (!strncmp(item->info_type, "ups.alarm", 9) || !strncmp(item->info_type, "ups.status", 10) ) { break; } /* This one doesn't exist yet */ if (dstate_getinfo(item->info_type) == NULL) break; continue; case QX_WALKMODE_QUICK_UPDATE: /* Quick update only deals with status and alarms! */ if (!(item->qxflags & QX_FLAG_QUICK_POLL)) continue; break; case QX_WALKMODE_FULL_UPDATE: /* These don't need polling after initinfo() */ if (item->qxflags & (QX_FLAG_ABSENT | QX_FLAG_CMD | QX_FLAG_SETVAR | QX_FLAG_STATIC)) continue; /* These need to be polled after user changes (setvar / instcmd) */ if ((item->qxflags & QX_FLAG_SEMI_STATIC) && (data_has_changed == FALSE) ) { continue; } break; #if (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_PUSH_POP) && ( (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_COVERED_SWITCH_DEFAULT) || (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_UNREACHABLE_CODE) ) # pragma GCC diagnostic push #endif #ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_COVERED_SWITCH_DEFAULT # pragma GCC diagnostic ignored "-Wcovered-switch-default" #endif #ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_UNREACHABLE_CODE # pragma GCC diagnostic ignored "-Wunreachable-code" #endif /* Older CLANG (e.g. clang-3.4) seems to not support the GCC pragmas above */ #ifdef __clang__ #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wunreachable-code" #pragma clang diagnostic ignored "-Wcovered-switch-default" #endif /* All enum cases defined as of the time of coding * have been covered above. Handle later definitions, * memory corruptions and buggy inputs below... */ default: fatalx(EXIT_FAILURE, "%s: unknown update mode!", __func__); #ifdef __clang__ # pragma clang diagnostic pop #endif #if (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_PUSH_POP) && ( (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_COVERED_SWITCH_DEFAULT) || (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_UNREACHABLE_CODE) ) # pragma GCC diagnostic pop #endif } /* Instant commands */ if (item->qxflags & QX_FLAG_CMD) { dstate_addcmd(item->info_type); continue; } /* Setvars */ if (item->qxflags & QX_FLAG_SETVAR) { if (item->qxflags & QX_FLAG_NONUT) { setvar(item->info_type, NULL); item->qxflags |= QX_FLAG_SKIP; } continue; } /* Check whether the previous item uses the same command * and then use its answer, if available.. */ if (strlen(previous_item.command) > 0 && strlen(previous_item.answer) > 0 && !strcasecmp(previous_item.command, item->command) ) { snprintf(item->answer, sizeof(item->answer), "%s", previous_item.answer); /* Process the answer */ retcode = qx_process_answer(item, strlen(item->answer)); /* ..otherwise: execute command to get answer from the UPS */ } else { retcode = qx_process(item, NULL); } /* Record item as previous_item */ snprintf(previous_item.command, sizeof(previous_item.command), "%s", item->command); snprintf(previous_item.answer, sizeof(previous_item.answer), "%s", item->answer); if (retcode) { /* Clear data from the item */ memset(item->answer, 0, sizeof(item->answer)); memset(item->value, 0, sizeof(item->value)); if (item->qxflags & QX_FLAG_QUICK_POLL) return FALSE; if (mode == QX_WALKMODE_INIT) /* Skip this item from now on */ item->qxflags |= QX_FLAG_SKIP; /* Don't know what happened, try again later... */ continue; } /* Process the value we got back (set status bits * and set the value of other parameters) */ retcode = ups_infoval_set(item); /* Clear data from the item */ memset(item->answer, 0, sizeof(item->answer)); memset(item->value, 0, sizeof(item->value)); /* Uh-oh! Some error! */ if (retcode == -1) { if (item->qxflags & QX_FLAG_QUICK_POLL) return FALSE; continue; } /* Set var flags/range/enum (not for ups.{alarm.status}, * hence the retcode check) */ if (retcode && mode == QX_WALKMODE_INIT) { qx_set_var(item); } } /* Update battery guesstimation */ if (mode == QX_WALKMODE_FULL_UPDATE && (d_equal(batt.runt.act, -1) || d_equal(batt.chrg.act, -1)) ) { if (getval("runtimecal")) { const char *val; time_t battery_now; time(&battery_now); /* OL */ if (ups_status & STATUS(OL)) { batt.runt.est += batt.runt.nom * difftime(battery_now, battery_lastpoll) / batt.chrg.time; if (batt.runt.est > batt.runt.nom) { batt.runt.est = batt.runt.nom; } /* OB */ } else { batt.runt.est -= load.eff * difftime(battery_now, battery_lastpoll); if (batt.runt.est < 0) { batt.runt.est = 0; } } val = dstate_getinfo("battery.voltage"); if (!val) { upsdebugx(2, "%s: unable to get battery.voltage", __func__); } else { /* For age-corrected estimates below, * see theory and experimental graphs at * https://github.com/networkupstools/nut/pull/1027 */ batt.volt.act = strtod(val, NULL); if (!battery_voltage_reports_one_pack_considered) { batt.volt.act *= batt.packs; } if (batt.volt.act > 0 && batt.volt.low > 0 && batt.volt.high > batt.volt.low) { double voltage_battery_charge = (batt.volt.act - batt.volt.low) / (batt.volt.high - batt.volt.low); if (voltage_battery_charge < 0) { voltage_battery_charge = 0; } if (voltage_battery_charge > 1) { voltage_battery_charge = 1; } /* Correct estimated runtime remaining for old batteries: * this value replacement only happens if the actual * voltage_battery_charge is smaller than expected by * previous (load-based) estimation, thus adapting to a * battery too old and otherwise behaving non-linearly */ if (voltage_battery_charge < (batt.runt.est / batt.runt.nom)) { double estPrev = batt.runt.est; batt.runt.est = voltage_battery_charge * batt.runt.nom; upsdebugx(3, "%s: updating batt.runt.est from '%g' to '%g'", __func__, estPrev, batt.runt.est); } } } if (d_equal(batt.chrg.act, -1)) dstate_setinfo("battery.charge", "%.0f", 100 * batt.runt.est / batt.runt.nom); if (d_equal(batt.runt.act, -1) && !qx_load()) dstate_setinfo("battery.runtime", "%.0f", batt.runt.est / load.eff); battery_lastpoll = battery_now; } else { qx_battery(); } } return TRUE; } /* Convert the local status information to NUT format and set NUT alarms. */ static void ups_alarm_set(void) { if (ups_status & STATUS(RB)) { alarm_set("Replace battery!"); } if (ups_status & STATUS(FSD)) { alarm_set("Shutdown imminent!"); } } /* Convert the local status information to NUT format and set NUT status. */ static void ups_status_set(void) { if (ups_status & STATUS(OL)) { status_set("OL"); /* On line */ } else { status_set("OB"); /* On battery */ } if (ups_status & STATUS(DISCHRG)) { status_set("DISCHRG"); /* Discharging */ } if (ups_status & STATUS(CHRG)) { status_set("CHRG"); /* Charging */ } if (ups_status & STATUS(LB)) { status_set("LB"); /* Low battery */ } if (ups_status & STATUS(OVER)) { status_set("OVER"); /* Overload */ } if (ups_status & STATUS(RB)) { status_set("RB"); /* Replace battery */ } if (ups_status & STATUS(TRIM)) { status_set("TRIM"); /* SmartTrim */ } if (ups_status & STATUS(BOOST)) { status_set("BOOST"); /* SmartBoost */ } if (ups_status & STATUS(BYPASS)) { status_set("BYPASS"); /* On bypass */ } if (ups_status & STATUS(OFF)) { status_set("OFF"); /* UPS is off */ } if (ups_status & STATUS(CALIB)) { status_set("CAL"); /* Calibration */ } if (ups_status & STATUS(FSD)) { status_set("FSD"); /* Forced shutdown */ } } /* See header file for details. */ item_t *find_nut_info(const char *varname, const unsigned long flag, const unsigned long noflag) { item_t *item; for (item = subdriver->qx2nut; item->info_type != NULL; item++) { if (strcasecmp(item->info_type, varname)) continue; if (flag && ((item->qxflags & flag) != flag)) continue; if (noflag && (item->qxflags & noflag)) continue; return item; } upsdebugx(2, "%s: info type %s not found", __func__, varname); return NULL; } /* Process the answer we got back from the UPS * Return -1 on errors, 0 on success */ static int qx_process_answer(item_t *item, const size_t len) { /* Query rejected by the UPS */ if (subdriver->rejected && !strcasecmp(item->answer, subdriver->rejected)) { upsdebugx(2, "%s: query rejected by the UPS (%s)", __func__, item->info_type); return -1; } /* Short reply */ if (item->answer_len && len < item->answer_len) { upsdebugx(2, "%s: short reply (%s)", __func__, item->info_type); return -1; } /* Wrong leading character */ if (item->leading && item->answer[0] != item->leading) { upsdebugx(2, "%s: %s - invalid start character [%02x], expected [%02x]", __func__, item->info_type, item->answer[0], item->leading); return -1; } /* Check boundaries */ if (item->to && item->to < item->from) { upsdebugx(1, "%s: in %s, starting char's position (%d) " "follows ending char's one (%d)", __func__, item->info_type, item->from, item->to); return -1; } /* Get value */ if (strlen(item->answer)) { snprintf(item->value, sizeof(item->value), "%.*s", item->to ? 1 + item->to - item->from : (int)strcspn(item->answer, "\r") - item->from, item->answer + item->from); } else { snprintf(item->value, sizeof(item->value), "%s", ""); } return 0; } /* See header file for details. */ int qx_process(item_t *item, const char *command) { char buf[sizeof(item->answer) - 1] = "", *cmd; ssize_t len; size_t cmdlen = command ? (strlen(command) >= SMALLBUF ? strlen(command) + 1 : SMALLBUF) : (item->command && strlen(item->command) >= SMALLBUF ? strlen(item->command) + 1 : SMALLBUF); size_t cmdsz = (sizeof(char) * cmdlen); /* in bytes, to be pedantic */ if ( !(cmd = xmalloc(cmdsz)) ) { upslogx(LOG_ERR, "qx_process() failed to allocate buffer"); return -1; } /* Prepare the command to be used */ memset(cmd, 0, cmdsz); snprintf(cmd, cmdsz, "%s", command ? command : item->command); /* Preprocess the command */ if ( item->preprocess_command != NULL && item->preprocess_command(item, cmd, cmdsz) == -1 ) { upsdebugx(4, "%s: failed to preprocess command [%s]", __func__, item->info_type); free (cmd); return -1; } /* Send the command */ len = qx_command(cmd, buf, sizeof(buf)); memset(item->answer, 0, sizeof(item->answer)); if (len < 0 || len > INT_MAX) { upsdebugx(4, "%s: failed to preprocess answer [%s]", __func__, item->info_type); free (cmd); return -1; } memcpy(item->answer, buf, sizeof(buf)); /* Preprocess the answer */ if (item->preprocess_answer != NULL) { len = item->preprocess_answer(item, (int)len); if (len < 0 || len > INT_MAX) { upsdebugx(4, "%s: failed to preprocess answer [%s]", __func__, item->info_type); /* Clear the failed answer, preventing it from * being reused by next items with same command */ memset(item->answer, 0, sizeof(item->answer)); free (cmd); return -1; } } free (cmd); /* Process the answer to get the value */ return qx_process_answer(item, (size_t)len); } /* See header file for details. */ int ups_infoval_set(item_t *item) { char value[SMALLBUF] = ""; /* Item need to be preprocessed? */ if (item->preprocess != NULL){ /* Process the value returned by the UPS to NUT standards */ if (item->preprocess(item, value, sizeof(value))) { upsdebugx(4, "%s: failed to preprocess value [%s: %s]", __func__, item->info_type, item->value); return -1; } /* Deal with status items */ if (!strncmp(item->info_type, "ups.status", 10)) { if (strlen(value) > 0) update_status(value); return 0; } /* Deal with alarm items */ if (!strncmp(item->info_type, "ups.alarm", 9)) { if (strlen(value) > 0) alarm_set(value); return 0; } } else { snprintf(value, sizeof(value), "%s", item->value); /* Cover most of the cases: either left/right filled with hashes, * spaces or a mix of both */ if (item->qxflags & QX_FLAG_TRIM) str_trim_m(value, "# "); if (strcasecmp(item->dfl, "%s")) { if (strspn(value, "0123456789 .") != strlen(value)) { upsdebugx(2, "%s: non numerical value [%s: %s]", __func__, item->info_type, value); return -1; } #ifdef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL #pragma GCC diagnostic push #endif #ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL #pragma GCC diagnostic ignored "-Wformat-nonliteral" #endif #ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_FORMAT_SECURITY #pragma GCC diagnostic ignored "-Wformat-security" #endif snprintf(value, sizeof(value), item->dfl, strtod(value, NULL)); #ifdef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL #pragma GCC diagnostic pop #endif } } if (item->qxflags & QX_FLAG_NONUT) { upslogx(LOG_INFO, "%s: %s", item->info_type, value); return 1; } if (!strlen(value)) { upsdebugx(1, "%s: non significant value [%s]", __func__, item->info_type); return -1; } dstate_setinfo(item->info_type, "%s", value); /* Fill batt.{chrg,runt}.act for guesstimation */ if (!strcasecmp(item->info_type, "battery.charge")) batt.chrg.act = strtol(value, NULL, 10); else if (!strcasecmp(item->info_type, "battery.runtime")) batt.runt.act = strtol(value, NULL, 10); return 1; } /* See header file for details. */ unsigned int qx_status(void) { return ups_status; } nut-2.8.1/drivers/adelsystem_cbi.h0000644000175000017500000004142214501607135014074 00000000000000/* adelsystem_cbi.h - Driver for ADELSYSTEM CB/CBI DC-UPS * * Copyright (C) * 2022 Dimitris Economou * * 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 2 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, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /* * code indentation with tabstop=4 */ #ifndef ADELSYSTEM_CBI_H #define ADELSYSTEM_CBI_H #include "nut_stdint.h" /* UPS device details */ #define DEVICE_MFR "ADELSYSTEM" #define DEVICE_TYPE_STRING "DC-UPS" #define DEVICE_MODEL "CBI2801224A" /* serial access parameters */ #define BAUD_RATE 9600 #define PARITY 'N' #define DATA_BIT 8 #define STOP_BIT 1 /* * modbus response and byte timeouts * us: 1 - 999999 */ #define MODRESP_TIMEOUT_s 0 #define MODRESP_TIMEOUT_us 200000 #define MODBYTE_TIMEOUT_s 0 #define MODBYTE_TIMEOUT_us 50000 /* modbus access parameters */ #define MODBUS_SLAVE_ID 5 /* number of modbus registers */ #define MODBUS_NUMOF_REGS 98 /* max HOLDING registers */ #define MAX_H_REGS 120 /* start HOLDING register index */ #define H_REG_STARTIDX 0 /* read all regs preprocessor flag */ #ifndef READALL_REGS #define READALL_REGS 1 #endif /* number of device models */ #define DEV_NUMOF_MODELS 10 /* shutdown repeat on error */ #define FSD_REPEAT_CNT 3 /* shutdown repeat interval in ms */ #define FSD_REPEAT_INTRV 1500 /* definition of register type */ enum regtype { COIL = 0, INPUT_B, INPUT_R, HOLDING }; typedef enum regtype regtype_t; /* product name info, "device.model" */ struct prodname { uint16_t val; char *name; }; typedef struct prodname prodname_t; static prodname_t prdnm_i[] = { {1, "CBI1235A"}, {2, "CBI2420A"}, {3, "CBI4810A"}, {4, "CBI2801224"}, {7, "CBI480W"}, {8, "CB122410A"}, {9, "CB480W"}, {11, "CB12245AJ"}, {12, "CB1235A"}, {13, "CB2420A"}, {14, "CB4810A"} }; /* charging status info, "battery.charger.status" */ static char *chrgs_i[] = { "none", "resting", /* recovering */ "charging", /* bulk */ "charging", /* absorb */ "floating" /* float */ }; struct chrgs { int state; char *info; }; typedef struct chrgs chrgs_t; /* power management info, "ups.status", "battery.charger.status" */ static char *pwrmng_i[] = { "backup", /* "OB", "discharging" */ "charging", /* "OL" */ "boost", "not charging" }; struct pwrmng { int state; char *info; }; typedef struct pwrmng pwrmng_t; /* general modbus register value */ struct reg { union val { uint16_t ui16; uint8_t ui8; } val; char *strval; }; typedef struct reg reg_t; /* general alarm struct */ struct alrm { int actv; /* active flag */ char *descr; /* description field */ }; typedef struct alrm alrm_t; /* general alarm array */ struct alrm_ar { int alrm_c; /* alarm count */ alrm_t *alrm; /* alarm array */ }; typedef struct alrm_ar alrm_ar_t; /* * BIT MASKS and VALUES */ /* Charging status */ #define CHRG_NONE 0 #define CHRG_RECV 1 #define CHRG_BULK 2 #define CHRG_ABSR 3 #define CHRG_FLOAT 4 /* power management */ #define PMNG_BCKUP 0 #define PMNG_CHRGN 1 #define PMNG_BOOST 2 #define PMNG_NCHRG 3 /* product name */ #define PRDN_MAX 14 /* Mains alarm masks */ #define MAINS_AVAIL_M 0x0001 /* 0: available (OL) 1: not available (OB) */ #define SHUTD_REQST_M 0x0002 /* shutdown requested */ /* Mains alarm indices */ #define MAINS_AVAIL_I 0 /* 0: available (OL) 1: not available (OB) */ #define SHUTD_REQST_I 1 /* shutdown requested */ /* AC input voltage alarm masks */ #define VACA_HIALRM_M 0x0001 /* high alarm */ #define VACA_LOALRM_M 0x0002 /* low alarm */ /* AC input voltage alarm indices */ #define VACA_HIALRM_I 0 /* high alarm */ #define VACA_LOALRM_I 1 /* low alarm */ /* Onboard temperature alarm value */ #define OBTA_HIALRM_V 1 /* high alarm */ /* Onboard temperature alarm index */ #define OBTA_HIALRM_I 0 /* high alarm */ /* Device failure alarm masks */ #define DEVF_RCALRM_M 0x0001 /* rectifier failure */ #define DEVF_INALRM_M 0x0006 /* internal failure */ #define DEVF_LFNAVL_M 0x0008 /* lifetest not available */ /* Device failure alarm indices */ #define DEVF_RCALRM_I 0 /* rectifier failure */ #define DEVF_INALRM_I 1 /* internal failure */ #define DEVF_LFNAVL_I 2 /* lifetest not available */ /* Battery temp sensor failure alarm masks */ #define BTSF_FCND_M 0x0001 /* connection fault */ #define BTSF_NCND_M 0x0002 /* not connected */ /* Battery temp sensor failure alarm indices */ #define BTSF_FCND_I 0 /* connection fault */ #define BTSF_NCND_I 1 /* not connected */ /* Battery voltage alarm masks */ #define BVAL_HIALRM_M 0x0001 /* high voltage */ #define BVAL_LOALRM_M 0x0002 /* low voltage */ #define BVAL_BSTSFL_M 0x0004 /* battery start with battery flat */ /* Battery voltage alarm indices */ #define BVAL_HIALRM_I 0 /* high voltage */ #define BVAL_LOALRM_I 1 /* low voltage */ #define BVAL_BSTSFL_I 2 /* battery start with battery flat */ /* SoH and SoC alarm masks */ #define SHSC_HIRESI_M 0x0001 /* high internal resistance */ #define SHSC_LOCHEF_M 0x0002 /* low charge efficiency */ #define SHSC_LOEFCP_M 0x0004 /* low effective capacity */ #define SHSC_LOWSOC_M 0x0040 /* low state of charge */ /* SoH and SoC alarm indices */ #define SHSC_HIRESI_I 0 /* high internal resistance */ #define SHSC_LOCHEF_I 1 /* low charge efficiency */ #define SHSC_LOEFCP_I 2 /* low effective capacity */ #define SHSC_LOWSOC_I 3 /* low state of charge */ /* Battery status alarm masks */ #define BSTA_REVPOL_M 0x0001 /* reversed polarity */ #define BSTA_NOCNND_M 0x0002 /* not connected */ #define BSTA_CLSHCR_M 0x0004 /* cell short circuit */ #define BSTA_SULPHD_M 0x0008 /* sulphated */ #define BSTA_CHEMNS_M 0x0010 /* chemistry not supported */ #define BSTA_CNNFLT_M 0x0020 /* connection fault */ /* Battery status alarm indices */ #define BSTA_REVPOL_I 0 /* reversed polarity */ #define BSTA_NOCNND_I 1 /* not connected */ #define BSTA_CLSHCR_I 2 /* cell short circuit */ #define BSTA_SULPHD_I 3 /* sulphated */ #define BSTA_CHEMNS_I 4 /* chemistry not supported */ #define BSTA_CNNFLT_I 5 /* connection fault */ /* Allocate alarm arrays */ static inline alrm_ar_t *alloc_alrm_ar(int as, size_t n) { alrm_ar_t *ret = xcalloc(sizeof(alrm_t) + n, 1); if (ret) { memcpy(ret, &(alrm_ar_t const) { .alrm_c = as }, sizeof(alrm_ar_t) ); } return ret; } /* Initialize alarm arrays */ static inline void alrm_ar_init(alrm_ar_t *ar_ptr, alrm_t *a_ptr, int as) { ar_ptr->alrm_c = as; ar_ptr->alrm = a_ptr; } /* input mains and shutdown alarms */ static alrm_t mains_ar[] = { {0, "input voltage not available"}, {0, "ups shutdown requested"} }; static int mains_c = 2; static alrm_ar_t *mains; /* AC input voltage alarms */ static alrm_t vaca_ar[] = { {0, "input voltage high alarm"}, {0, "input voltage low alarm"} }; static int vaca_c = 2; static alrm_ar_t *vaca; /* device failure alarms */ static alrm_t devf_ar[] = { {0, "UPS rectifier failure"}, {0, "UPS internal failure"}, {0, "UPS lifetest not available"} }; static int devf_c = 3; static alrm_ar_t *devf; /* battery sensor failure alarms */ static alrm_t btsf_ar[] = { {0, "battery temp sensor connection fault"}, {0, "battery temp sensor not connected"} }; static int btsf_c = 2; static alrm_ar_t *btsf; /* battery voltage alarms */ static alrm_t bval_ar[] = { {0, "battery high voltage"}, {0, "battery low voltage"}, {0, "battery start with battery flat"} }; static int bval_c = 3; static alrm_ar_t *bval; /* battery SoH and SoC alarms */ static alrm_t shsc_ar[] = { {0, "battery high internal resistance"}, {0, "battery low charge efficiency"}, {0, "battery low effective capacity"}, {0, "battery low state of charge"} }; static int shsc_c = 4; static alrm_ar_t *shsc; /* battery status alarm */ static alrm_t bsta_ar[] = { {0, "battery reversed polarity"}, {0, "battery not connected"}, {0, "battery cell short circuit"}, {0, "battery sulphated"}, {0, "battery chemistry not supported"}, {0, "battery connection fault"} }; static int bsta_c = 4; static alrm_ar_t *bsta; /* onboard temperature alarm */ static alrm_t obta_ar[] = { {0, "onboard temperature high"} }; static int obta_c = 4; static alrm_ar_t *obta; /* UPS device reg enum */ enum devreg { CHRG = 4, /* Charging status, "battery.charger.status" */ BATV = 7, /* Battery voltage, "battery.voltage" */ BCEF = 18, /* Battery charge efficiency factor (CEF) */ BSOH = 20, /* Battery state-of-health */ BSOC = 22, /* Battery state-of-charge, "battery.charge" */ BTMP = 25, /* Battery temperature in Kelvin units, "battery.temperature" */ PMNG = 5, /* Power management, "ups.status" */ OTMP = 28, /* Onboard temperature, "ups.temperature" */ PRDN = 67, /* Product name, "ups.model" */ VAC = 29, /* AC voltage, "input.voltage" */ LVDC = 10, /* Load voltage, "output.voltage" */ LCUR = 19, /* Load current, "output.current" */ BINH = 87, /* Backup inhibit */ FSD = 40, /* Force shutdown */ TBUF = 103, /* Time buffering, "battery.runtime" */ BSTA = 31, /* Battery status alarms */ SCSH, /* SoH and SoC alarms */ BVAL = 34, /* Battery voltage alarm */ BTSF = 43, /* Battery temp sensor failure */ DEVF = 42, /* Device failure */ OBTA = 46, /* On board temp alarm */ VACA = 44, /* VAC alarms */ MAIN /* Mains status */ }; typedef enum devreg devreg_t; /* UPS register attributes */ struct regattr { int num; int saddr; /* register start address */ int xaddr; /* register hex address */ float scale; /* scale */ regtype_t type; /* register type */ }; typedef struct regattr regattr_t; /* UPS device state info union */ union devstate { prodname_t product; /* ups model name */ chrgs_t charge; /* charging status */ pwrmng_t power; /* ups status */ reg_t reg; /* state register*/ alrm_ar_t *alrm; /* alarm statuses */ }; typedef union devstate devstate_t; /* device register memory image */ static uint16_t regs_data[MAX_H_REGS]; /* ADELSYSTEM CBI registers */ static regattr_t regs[] = { {40001, 0, 0, 1, HOLDING}, /* Address of slave unit */ {40002, 0, 0, 1, HOLDING}, /* Baud rate for serial communication */ {40003, 0, 0, 1, HOLDING}, /* Parity bit for serial communication */ {40004, 0, 0, 1, HOLDING}, {40005, 0, 0, 1, HOLDING}, /* Charging status */ {40006, 0, 0, 1, HOLDING}, /* Power management * 0:Backup 1:Charging 2:boost 3:Not charging */ {40007, 0, 0, 1, HOLDING}, /* Nominal output voltage */ {40008, 0, 0, 1, HOLDING}, /* Battery voltage */ {40009, 0, 0, 1, HOLDING}, /* Parameter map version ID */ {40010, 0, 0, 1, HOLDING}, /* Software ID */ {40011, 0, 0, 1, HOLDING}, /* Output load voltage */ {40012, 0, 0, 1, HOLDING}, {40013, 0, 0, 1, HOLDING}, {40014, 0, 0, 1, HOLDING}, /* Battery charge current */ {40015, 0, 0, 1, HOLDING}, {40016, 0, 0, .1, HOLDING}, /* Battery capacity consumed */ {40017, 0, 0, 1, HOLDING}, /* Battery discharge current */ {40018, 0, 0, .1, HOLDING}, /* Effective battery capacity */ {40019, 0, 0, 1, HOLDING}, /* Battery charge efficiency factor (CEF) */ {40020, 0, 0, 1, HOLDING}, /* Output load current */ {40021, 0, 0, 1, HOLDING}, /* Battery state-of-health */ {40022, 0, 0, 1, HOLDING}, /* Time remaining to 100% discharge */ {40023, 0, 0, .1, HOLDING}, /* Battery state-of-charge */ {40024, 0, 0, 1, HOLDING}, /* Battery type currently selected */ {40025, 0, 0, 1, HOLDING}, {40026, 0, 0, 1, HOLDING}, /* Battery temperature in Kelvin units */ {40027, 0, 0, 1, HOLDING}, /* Configuration mode */ {40028, 0, 0, .1, HOLDING}, /* Battery net internal resistance */ {40029, 0, 0, 1, HOLDING}, /* On-board temperature */ {40030, 0, 0, 1, HOLDING}, /* AC input voltage */ {40031, 0, 0, 1, HOLDING}, {40032, 0, 0, 1, HOLDING}, /* Battery status alarm */ {40033, 0, 0, 1, HOLDING}, /* Battery State of Charge and State of Health */ {40034, 0, 0, 1, HOLDING}, /* Load output off duration after PC shutdown */ {40035, 0, 0, 1, HOLDING}, /* Battery voltage alarm */ {40036, 0, 0, 1, HOLDING}, /* Low AC input voltage alarm threshold */ {40037, 0, 0, 1, HOLDING}, /* High AC input voltage alarm threshold */ {40038, 0, 0, 1, HOLDING}, /* Load alarm */ {40039, 0, 0, 1, HOLDING}, /* Device variant */ {40040, 0, 0, 1, HOLDING}, {40041, 0, 0, 1, HOLDING}, /* Force shutdown */ {40042, 0, 0, 1, HOLDING}, {40043, 0, 0, 1, HOLDING}, /* Device failure */ {40044, 0, 0, 1, HOLDING}, /* Battery temperature sensor failure */ {40045, 0, 0, 1, HOLDING}, /* AC input voltage alarm */ {40046, 0, 0, 1, HOLDING}, /* Mains status */ {40047, 0, 0, 1, HOLDING}, /* On board temperature alarm */ {40048, 0, 0, 1, HOLDING}, /* Number of charge cycles completed */ {40049, 0, 0, 1, HOLDING}, /* Charge cycles not completed */ {40050, 0, 0, .1, HOLDING}, /* Ah charged */ {40051, 0, 0, 1, HOLDING}, /* Total run time */ {40052, 0, 0, 1, HOLDING}, /* Number of low battery voltage events */ {40053, 0, 0, 1, HOLDING}, /* Number of high battery voltage events */ {40054, 0, 0, 1, HOLDING}, /* Number of low VAC events at mains input */ {40055, 0, 0, 1, HOLDING}, /* Number of High VAC events at mains input */ {40056, 0, 0, 1, HOLDING}, /* Number of over temperature inside events */ {40057, 0, 0, 1, HOLDING}, /* Number of mains-backup transitions */ {40058, 0, 0, 1, HOLDING}, /* Number power boost events */ {40059, 0, 0, 1, HOLDING}, /* Highest battery voltage */ {40060, 0, 0, 1, HOLDING}, /* Highest output load voltage */ {40061, 0, 0, .1, HOLDING}, /* Maximum depth of discharge */ {40062, 0, 0, 1, HOLDING}, /* Lowest battery voltage */ {40063, 0, 0, 1, HOLDING}, /* Lowest output load voltage */ {40064, 0, 0, .1, HOLDING}, /* Average depth of discharge */ {40065, 0, 0, 1, HOLDING}, /* History clear all */ {40066, 0, 0, 1, HOLDING}, /* Factory settings */ {40067, 0, 0, 1, HOLDING}, /* Product name */ {40068, 0, 0, 1, HOLDING}, {40069, 0, 0, 1, HOLDING}, /* Reset internal battery model */ {40070, 0, 0, 1, HOLDING}, {40071, 0, 0, 1, HOLDING}, /* Deep discharge battery prevention */ {40072, 0, 0, 1, HOLDING}, /* Maximum charge current */ {40073, 0, 0, 1, HOLDING}, /* Bulk voltage */ {40074, 0, 0, 1, HOLDING}, /* Max bulk timer */ {40075, 0, 0, 1, HOLDING}, /* Min bulk timer */ {40076, 0, 0, 1, HOLDING}, {40077, 0, 0, 1, HOLDING}, /* Absorption voltage */ {40078, 0, 0, 1, HOLDING}, /* Max absorption timer */ {40079, 0, 0, 1, HOLDING}, /* Min absorption timer */ {40080, 0, 0, 1, HOLDING}, /* Return Amperes to float */ {40081, 0, 0, 1, HOLDING}, /* Return amps timer */ {40082, 0, 0, 1, HOLDING}, /* Float voltage */ {40083, 0, 0, 1, HOLDING}, /* Force boost charge */ {40084, 0, 0, 1, HOLDING}, /* Return to bulk voltage from float */ {40085, 0, 0, 1, HOLDING}, /* Return to bulk delay */ {40086, 0, 0, 1, HOLDING}, {40087, 0, 0, 1, HOLDING}, /* Switchoff voltage without mains */ {40088, 0, 0, 1, HOLDING}, /* Backup Inhibit 0 = Backup allowed * 1 = Backup not allowed */ {40089, 0, 0, 1, HOLDING}, /* Number of battery cells */ {40090, 0, 0, 1, HOLDING}, /* Temperature compensation coefficient */ {40091, 0, 0, 1, HOLDING}, {40092, 0, 0, 1, HOLDING}, /* Lifetest enable */ {40093, 0, 0, 1, HOLDING}, /* Max alarm temp */ {40094, 0, 0, 1, HOLDING}, /* Min alarm temp */ {40095, 0, 0, 1, HOLDING}, {40096, 0, 0, 1, HOLDING}, {40097, 0, 0, 1, HOLDING}, /* Low battery threshold */ {40098, 0, 0, 1, HOLDING}, /* SoC/SoH test period */ {40099, 0, 0, 1, HOLDING}, /* Manual SoC/SoH test request */ {40100, 0, 0, 1, HOLDING}, /* SoC/SoH test possible */ {40101, 0, 0, .1, HOLDING}, /* Nominal battery internal resistance */ {40102, 0, 0, .1, HOLDING}, /* Nominal battery cables resistance */ {40103, 0, 0, 1, HOLDING}, /* Firmware ID */ {40104, 0, 0, 1, HOLDING}, /* Time buffering */ {40105, 0, 0, .1, HOLDING}, /* Battery capacity C20 */ {40106, 0, 0, .1, HOLDING}, /* Battery Capacity C10 */ {40107, 0, 0, 1, HOLDING}, /* Device switchoff delay */ {40108, 0, 0, .1, HOLDING}, /* Battery Capacity C5 */ {40109, 0, 0, .1, HOLDING}, /* Battery Capacity C2 */ {40110, 0, 0, 1, HOLDING}, {40111, 0, 0, 1, HOLDING}, /* PC power supply removal delay */ {40112, 0, 0, .1, HOLDING}, /* Battery Capacity C1 */ {40113, 0, 0, .1, HOLDING}, /* Low state-of-charge */ {40114, 0, 0, 1, HOLDING}, {40115, 0, 0, 1, HOLDING}, {40116, 0, 0, 1, HOLDING}, {40117, 0, 0, 1, HOLDING}, {40118, 0, 0, 1, HOLDING}, {40119, 0, 0, 1, HOLDING}, {40120, 0, 0, 1, HOLDING} /* Zero-SoC reference */ }; #endif /* ADELSYSTEM_CBI_H */ nut-2.8.1/drivers/netvision-mib.h0000644000175000017500000000023114273170601013660 00000000000000#ifndef NETVISION_MIB_H #define NETVISION_MIB_H #include "main.h" #include "snmp-ups.h" extern mib2nut_info_t netvision; #endif /* NETVISION_MIB_H */ nut-2.8.1/drivers/skel.c0000644000175000017500000001025014501607135012031 00000000000000/* anything commented is optional anything else is mandatory for more information, refer to: * docs/developers.txt * docs/new-drivers.txt * docs/new-names.txt and possibly also to: * docs/hid-subdrivers.txt for USB/HID devices * or docs/snmp-subdrivers.txt for SNMP devices */ #include "config.h" #include "main.h" #include "attribute.h" /* #include "serial.h" */ /* #define ENDCHAR '\r' */ /* #define IGNCHARS "" */ #define DRIVER_NAME "Skeleton UPS driver" #define DRIVER_VERSION "0.04" /* driver description structure */ upsdrv_info_t upsdrv_info = { DRIVER_NAME, DRIVER_VERSION, "John Doe ", DRV_STABLE, { NULL } }; void upsdrv_initinfo(void) { /* try to detect the UPS here - call fatal_with_errno(EXIT_FAILURE, ...) * or fatalx(EXIT_FAILURE, ...) if it fails */ /* dstate_setinfo("ups.mfr", "skel manufacturer"); */ /* dstate_setinfo("ups.model", "longrun 15000"); */ /* note: for a transition period, these data are redundant! */ /* dstate_setinfo("device.mfr", "skel manufacturer"); */ /* dstate_setinfo("device.model", "longrun 15000"); */ /* upsh.instcmd = instcmd; */ } void upsdrv_updateinfo(void) { /* int flags; */ /* char temp[256]; */ /* ser_sendchar(upsfd, 'A'); */ /* ser_send(upsfd, "foo%d", 1234); */ /* ser_send_buf(upsfd, bincmd, 12); */ /* * ret = ser_get_line(upsfd, temp, sizeof(temp), ENDCHAR, IGNCHARS); * * if (ret < STATUS_LEN) { * upslogx(LOG_ERR, "Short read from UPS"); * dstate_datastale(); * return; * } */ /* dstate_setinfo("var.name", ""); */ /* if (ioctl(upsfd, TIOCMGET, &flags)) { * upslog_with_errno(LOG_ERR, "TIOCMGET"); * dstate_datastale(); * return; * } */ /* status_init(); * * if (ol) * status_set("OL"); * else * status_set("OB"); * ... * * status_commit(); * * dstate_dataok(); */ /* * poll_interval = 2; */ } void upsdrv_shutdown(void) { /* tell the UPS to shut down, then return - DO NOT SLEEP HERE */ /* maybe try to detect the UPS here, but try a shutdown even if it doesn't respond at first if possible */ /* replace with a proper shutdown function */ upslogx(LOG_ERR, "shutdown not supported"); set_exit_flag(-1); /* you may have to check the line status since the commands for toggling power are frequently different for OL vs. OB */ /* OL: this must power cycle the load if possible */ /* OB: the load must remain off until the power returns */ } /* static int instcmd(const char *cmdname, const char *extra) { if (!strcasecmp(cmdname, "test.battery.stop")) { ser_send_buf(upsfd, ...); return STAT_INSTCMD_HANDLED; } upslogx(LOG_NOTICE, "instcmd: unknown command [%s]", cmdname); return STAT_INSTCMD_UNKNOWN; } */ /* static int setvar(const char *varname, const char *val) { if (!strcasecmp(varname, "ups.test.interval")) { ser_send_buf(upsfd, ...); return STAT_SET_HANDLED; } upslogx(LOG_NOTICE, "setvar: unknown variable [%s]", varname); return STAT_SET_UNKNOWN; } */ void upsdrv_help(void) { } /* list flags and values that you want to receive via -x */ void upsdrv_makevartable(void) { /* allow '-x xyzzy' */ /* addvar(VAR_FLAG, "xyzzy", "Enable xyzzy mode"); */ /* allow '-x foo=' */ /* addvar(VAR_VALUE, "foo", "Override foo setting"); */ } void upsdrv_initups(void) { /* upsfd = ser_open(device_path); */ /* ser_set_speed(upsfd, device_path, B1200); */ /* probe ups type */ /* to get variables and flags from the command line, use this: * * first populate with upsdrv_makevartable() above, then... * * set flag foo : /bin/driver -x foo * set variable 'cable' to '1234' : /bin/driver -x cable=1234 * * to test flag foo in your code: * * if (testvar("foo")) * do_something(); * * to show the value of cable: * * if ((cable = getval("cable"))) * printf("cable is set to %s\n", cable); * else * printf("cable is not set!\n"); * * don't use NULL pointers - test the return result first! */ /* the upsh handlers can't be done here, as they get initialized * shortly after upsdrv_initups returns to main. */ /* don't try to detect the UPS here */ } void upsdrv_cleanup(void) { /* free(dynamic_mem); */ /* ser_close(upsfd, device_path); */ } nut-2.8.1/drivers/liebert-hid.c0000644000175000017500000002205114501607135013265 00000000000000/* liebert-hid.c - subdriver to monitor Liebert USB/HID devices with NUT * * Copyright (C) * 2003 - 2008 Arnaud Quette * 2005 - 2006 Peter Selinger * 2007 Charles Lepple * 2018 Markus "Links2004" * 2023 Blaž Zakrajšek * * 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 2 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, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #include "main.h" /* for getval() */ #include "usbhid-ups.h" #include "liebert-hid.h" #include "usb-common.h" #define LIEBERT_HID_VERSION "Phoenixtec/Liebert HID 0.41" /* FIXME: experimental flag to be put in upsdrv_info */ /* Phoenixtec Power Co., Ltd */ #define LIEBERT_VENDORID 0x06da /*! USB IDs device table. * * Note that this subdriver was named before the USB VendorID was determined to * actually belong to Phoenixtec. The belkin-hid.c file covers the other * Liebert units which share some of the same incorrect exponents as the * Belkin HID firmware. */ static usb_device_id_t liebert_usb_device_table[] = { /* various models */ { USB_DEVICE(LIEBERT_VENDORID, 0xffff), NULL }, /* Terminating entry */ { 0, 0, NULL } }; /* --------------------------------------------------------------- */ /* Vendor-specific usage table */ /* --------------------------------------------------------------- */ /* LIEBERT usage table */ static usage_lkp_t liebert_usage_lkp[] = { { NULL, 0 } }; static usage_tables_t liebert_utab[] = { liebert_usage_lkp, hid_usage_lkp, NULL, }; /* --------------------------------------------------------------- */ /* HID2NUT lookup table */ /* --------------------------------------------------------------- */ static hid_info_t liebert_hid2nut[] = { #if WITH_UNMAPPED_DATA_POINTS { "unmapped.ups.powersummary.flowid", 0, 0, "UPS.PowerSummary.FlowID", NULL, "%.0f", 0, NULL }, { "unmapped.ups.powersummary.powersummaryid", 0, 0, "UPS.PowerSummary.PowerSummaryID", NULL, "%.0f", 0, NULL }, { "unmapped.ups.powersummary.capacitygranularity1", 0, 0, "UPS.PowerSummary.CapacityGranularity1", NULL, "%.0f", 0, NULL }, { "unmapped.ups.powersummary.capacitymode", 0, 0, "UPS.PowerSummary.CapacityMode", NULL, "%.0f", 0, NULL }, { "unmapped.ups.powersummary.rechargeable", 0, 0, "UPS.PowerSummary.Rechargeable", NULL, "%.0f", 0, NULL }, { "unmapped.ups.powersummary.iproduct", 0, 0, "UPS.PowerSummary.iProduct", NULL, "%.0f", 0, NULL }, { "unmapped.ups.powersummary.product", 0, 0, "UPS.PowerSummary.iProduct", NULL, "%s", 0, stringid_conversion }, { "unmapped.ups.powersummary.imanufacturer", 0, 0, "UPS.PowerSummary.iManufacturer", NULL, "%.0f", 0, NULL }, { "unmapped.ups.powersummary.manufacturer", 0, 0, "UPS.PowerSummary.iManufacturer", NULL, "%s", 0, stringid_conversion }, { "unmapped.ups.powersummary.iserialnumber", 0, 0, "UPS.PowerSummary.iSerialNumber", NULL, "%.0f", 0, NULL }, { "unmapped.ups.powersummary.serialnumber", 0, 0, "UPS.PowerSummary.iSerialNumber", NULL, "%s", 0, stringid_conversion }, #endif /* if WITH_UNMAPPED_DATA_POINTS */ /* Battery page */ { "battery.voltage", 0, 0, "UPS.PowerSummary.Voltage", NULL, "%.2f", 0, NULL }, { "battery.charge", 0, 0, "UPS.PowerSummary.RemainingCapacity", NULL, "%.0f", 0, NULL }, { "experimental.battery.capacity", 0, 0, "UPS.PowerSummary.FullChargeCapacity", NULL, "%.0f", 0, NULL }, { "experimental.battery.capacity.nominal", 0, 0, "UPS.PowerSummary.DesignCapacity", NULL, "%.0f", 0, NULL }, { "battery.runtime", 0, 0, "UPS.PowerSummary.RunTimeToEmpty", NULL, "%.0f", 0, NULL }, { "battery.type", 0, 0, "UPS.PowerSummary.iDeviceChemistry", NULL, "%s", 0, stringid_conversion }, /* UPS page */ { "ups.load", 0, 0, "UPS.PowerSummary.PercentLoad", NULL, "%.0f", 0, NULL }, { "ups.power.nominal", 0, 0, "UPS.Flow.[4].ConfigApparentPower", NULL, "%.0f", HU_FLAG_SEMI_STATIC, NULL }, { "ups.test.result", 0, 0, "UPS.BatterySystem.Battery.Test", NULL, "%s", 0, test_read_info }, { "ups.beeper.status", 0 ,0, "UPS.PowerSummary.AudibleAlarmControl", NULL, "%s", HU_FLAG_SEMI_STATIC, beeper_info }, /* Output page */ { "output.voltage", 0, 0, "UPS.PowerConverter.Output.Voltage", NULL, "%.1f", 0, NULL }, { "output.voltage.nominal", 0, 0, "UPS.Flow.[4].ConfigVoltage", NULL, "%.0f", HU_FLAG_SEMI_STATIC, NULL }, { "output.frequency", 0, 0, "UPS.PowerConverter.Output.Frequency", NULL, "%.2f", 0, NULL }, { "output.frequency.nominal", 0, 0, "UPS.Flow.[4].ConfigFrequency", NULL, "%.0f", HU_FLAG_SEMI_STATIC, NULL }, { "output.transfer.high", 0, 0, "UPS.PowerConverter.Output.HighVoltageTransfer", NULL, "%.1f", HU_FLAG_SEMI_STATIC, NULL }, { "output.transfer.low", 0, 0, "UPS.PowerConverter.Output.LowVoltageTransfer", NULL, "%.1f", HU_FLAG_SEMI_STATIC, NULL }, /* Input page */ { "input.voltage", 0, 0, "UPS.PowerConverter.Input.[1].Voltage", NULL, "%.1f", 0, NULL }, { "input.frequency", 0, 0, "UPS.PowerConverter.Input.[1].Frequency", NULL, "%.2f", 0, NULL }, { "input.transfer.low", 0, 0, "UPS.PowerConverter.Output.ffff0057", NULL, "%.0f", HU_FLAG_SEMI_STATIC, NULL }, { "input.transfer.high", 0, 0, "UPS.PowerConverter.Output.ffff0058", NULL, "%.0f", HU_FLAG_SEMI_STATIC, NULL}, { "input.frequency.transfer.low", 0, 0, "UPS.PowerConverter.Output.ffff00f9", NULL, "%.0f", HU_FLAG_SEMI_STATIC, NULL }, { "input.frequency.transfer.high", 0, 0, "UPS.PowerConverter.Output.ffff00f8", NULL, "%.0f", HU_FLAG_SEMI_STATIC, NULL}, /* Status page */ { "BOOL", 0, 0, "UPS.PowerSummary.PresentStatus.ACPresent", NULL, "%.0f", HU_FLAG_QUICK_POLL, online_info }, { "BOOL", 0, 0, "UPS.PowerSummary.PresentStatus.BelowRemainingCapacityLimit", NULL, "%.0f", HU_FLAG_QUICK_POLL, lowbatt_info }, { "BOOL", 0, 0, "UPS.PowerSummary.PresentStatus.Charging", NULL, "%.0f", HU_FLAG_QUICK_POLL, charging_info }, { "BOOL", 0, 0, "UPS.PowerSummary.PresentStatus.Discharging", NULL, "%.0f", HU_FLAG_QUICK_POLL, discharging_info }, { "BOOL", 0, 0, "UPS.PowerSummary.PresentStatus.Overload", NULL, "%.0f", HU_FLAG_QUICK_POLL, overload_info }, { "BOOL", 0, 0, "UPS.PowerSummary.PresentStatus.Good", NULL, NULL, HU_FLAG_QUICK_POLL, off_info }, { "BOOL", 0, 0, "UPS.PowerSummary.PresentStatus.InternalFailure", NULL, NULL, HU_FLAG_QUICK_POLL, commfault_info }, { "BOOL", 0, 0, "UPS.PowerSummary.PresentStatus.ShutdownImminent", NULL, "%.0f", HU_FLAG_QUICK_POLL, shutdownimm_info }, { "BOOL", 0, 0, "UPS.PowerConverter.Input.[1].PresentStatus.Buck", NULL, NULL, 0, trim_info }, { "BOOL", 0, 0, "UPS.PowerConverter.Input.[1].PresentStatus.Boost", NULL, NULL, 0, boost_info }, /* Variables */ { "ups.delay.start", ST_FLAG_RW | ST_FLAG_STRING, 10, "UPS.PowerSummary.DelayBeforeStartup", NULL, DEFAULT_ONDELAY, HU_FLAG_ABSENT, NULL}, { "ups.delay.shutdown", ST_FLAG_RW | ST_FLAG_STRING, 10, "UPS.PowerSummary.DelayBeforeShutdown", NULL, DEFAULT_OFFDELAY, HU_FLAG_ABSENT, NULL}, /* Instant commands */ { "test.battery.start", 0, 0, "UPS.BatterySystem.Battery.Test", NULL, "1", HU_TYPE_CMD, NULL }, { "load.off.delay", 0, 0, "UPS.PowerSummary.DelayBeforeShutdown", NULL, DEFAULT_OFFDELAY, HU_TYPE_CMD, NULL }, { "load.on.delay", 0, 0, "UPS.PowerSummary.DelayBeforeStartup", NULL, DEFAULT_ONDELAY, HU_TYPE_CMD, NULL }, { "shutdown.stop", 0, 0, "UPS.PowerSummary.DelayBeforeShutdown", NULL, "-1", HU_TYPE_CMD, NULL }, { "beeper.toggle", 0, 0, "UPS.PowerSummary.AudibleAlarmControl", NULL, "1", HU_TYPE_CMD, NULL }, /* end of structure. */ { NULL, 0, 0, NULL, NULL, NULL, 0, NULL } }; static const char *liebert_format_model(HIDDevice_t *hd) { return hd->Product; } static const char *liebert_format_mfr(HIDDevice_t *hd) { return hd->Vendor ? hd->Vendor : "Liebert"; } static const char *liebert_format_serial(HIDDevice_t *hd) { return hd->Serial; } /* this function allows the subdriver to "claim" a device: return 1 if * the device is supported by this subdriver, else 0. */ static int liebert_claim(HIDDevice_t *hd) { int status = is_usb_device_supported(liebert_usb_device_table, hd); switch (status) { case POSSIBLY_SUPPORTED: /* by default, reject, unless the productid option is given */ if (getval("productid")) { return 1; } possibly_supported("Liebert", hd); return 0; case SUPPORTED: return 1; case NOT_SUPPORTED: default: return 0; } } subdriver_t liebert_subdriver = { LIEBERT_HID_VERSION, liebert_claim, liebert_utab, liebert_hid2nut, liebert_format_model, liebert_format_mfr, liebert_format_serial, fix_report_desc, }; nut-2.8.1/drivers/nutdrv_qx.h0000644000175000017500000003073514501607135013144 00000000000000/* nutdrv_qx.h - Driver for USB and serial UPS units with Q* protocols * * Copyright (C) * 2013 Daniele Pezzini * Based on usbhid-ups.h - Copyright (C) * 2003-2009 Arnaud Quette * 2005-2006 Peter Selinger * 2007-2009 Arjen de Korte * * 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 2 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, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #ifndef NUTDRV_QX_H #define NUTDRV_QX_H #include #include #include #include #include "config.h" /* For testing purposes */ /*#define TESTING*/ /* Driver's parameters */ #define QX_VAR_ONDELAY "ondelay" #define QX_VAR_OFFDELAY "offdelay" #define QX_VAR_POLLFREQ "pollfreq" /* Parameters default values */ #define DEFAULT_ONDELAY "180" /* Delay between return of utility power and powering up of load, in seconds */ #define DEFAULT_OFFDELAY "30" /* Delay before power off, in seconds */ #define DEFAULT_POLLFREQ 30 /* Polling interval between full updates, in seconds; the driver will do quick polls in the meantime */ #ifndef TRUE typedef enum { FALSE, TRUE } bool_t; #else typedef int bool_t; #endif /* Structure for rw vars */ typedef struct { char value[SMALLBUF]; /* Value for enum/range, or length for ST_FLAG_STRING */ int (*preprocess)(char *value, const size_t len); /* Optional function to preprocess range/enum value. * This function will be given value and its size_t and must return either 0 if value is supported or -1 if not supported. */ } info_rw_t; /* Structure containing information about how to get/set data from/to the UPS and convert these to/from NUT standard */ typedef struct item_t { const char *info_type; /* NUT variable name * If QX_FLAG_NONUT is set, name to print to the logs * If both QX_FLAG_NONUT and QX_FLAG_SETVAR are set, name of the var to retrieve from ups.conf */ const int info_flags; /* NUT flags (ST_FLAG_* values to set in dstate_addinfo) */ info_rw_t *info_rw; /* An array of info_rw_t to handle r/w variables: * If ST_FLAG_STRING is set: length of the string (dstate_setaux) * If QX_FLAG_ENUM is set: enumerated values (dstate_addenum) * If QX_FLAG_RANGE is set: range boundaries (dstate_addrange) * If QX_FLAG_SETVAR is set the value given by the user will be checked against these infos. */ const char *command; /* Command sent to the UPS to get answer/to execute an instant command/to set a variable */ char answer[SMALLBUF]; /* Answer from the UPS, filled at runtime. * If you expect a nonvalid C string (e.g.: inner '\0's) or need to perform actions before the answer is used (and treated as a null-terminated string), you should set a preprocess_answer() function */ const size_t answer_len; /* Expected min length of the answer. Set it to 0 if there's no minimum length to look after. */ const char leading; /* Expected leading character of the answer (optional) */ char value[SMALLBUF]; /* Value from the answer, filled at runtime (i.e. answer between from and to) */ const int from; /* Position of the starting character of the info (i.e. 'value') we're after in the answer */ const int to; /* Position of the ending character of the info (i.e. 'value') we're after in the answer: use 0 if all the remaining of the line is needed */ const char *dfl; /* Format to store value from the UPS in NUT variables. Not used by the driver for QX_FLAG_{CMD,SETVAR} items. * If there's no preprocess function, set it either to %s for strings or to a floating point specifier (e.g. %.1f) for numbers. * Otherwise: * If QX_FLAG_ABSENT: default value * If QX_FLAG_CMD: default command value */ unsigned long qxflags; /* Driver's own flags */ int (*preprocess_command)(struct item_t *item, char *command, const size_t commandlen); /* Last chance to preprocess the command to be sent to the UPS (e.g. to add CRC, ...). * This function is given the currently processed item (item), the command to be sent to the UPS (command) and its size_t (commandlen). * Return -1 in case of errors, else 0. * command must be filled with the actual command to be sent to the UPS. */ int (*preprocess_answer)(struct item_t *item, const int len); /* Function to preprocess the answer we got from the UPS before we do anything else (e.g. for CRC, decoding, ...). * This function is given the currently processed item (item) with the answer we got from the UPS unmolested and already stored in item->answer and the length of that answer (len). * Return -1 in case of errors, else the length of the newly allocated item->answer (from now on, treated as a null-terminated string). */ int (*preprocess)(struct item_t *item, char *value, const size_t valuelen); /* Function to preprocess the data from/to the UPS * This function is given the currently processed item (item), a char array (value) and its size_t (valuelen). * Return -1 in case of errors, else 0. * If QX_FLAG_SETVAR/QX_FLAG_CMD -> process command before it is sent: value must be filled with the command to be sent to the UPS. * Otherwise -> process value we got from answer before it gets stored in a NUT variable: value must be filled with the processed value already compliant to NUT standards. */ } item_t; /* Driver's own flags */ #define QX_FLAG_STATIC 2UL /* Retrieve info only once. */ #define QX_FLAG_SEMI_STATIC 4UL /* Retrieve info smartly, i.e. only when a command/setvar is executed and we expect that data could have been changed. */ #define QX_FLAG_ABSENT 8UL /* Data is absent in the device, use default value. */ #define QX_FLAG_QUICK_POLL 16UL /* Mandatory vars, polled also in QX_WALKMODE_QUICK_UPDATE. * If there's a problem with a var not flagged as QX_FLAG_QUICK_POLL in QX_WALKMODE_INIT, the driver will automagically set QX_FLAG_SKIP on it and then it'll skip that item in QX_WALKMODE_{QUICK,FULL}_UPDATE. * Otherwise, if the item has the flag QX_FLAG_QUICK_POLL set, in case of errors in QX_WALKMODE_INIT the driver will set datastale. */ #define QX_FLAG_CMD 32UL /* Instant command. */ #define QX_FLAG_SETVAR 64UL /* The var is settable and the actual item stores info on how to set it. */ #define QX_FLAG_TRIM 128UL /* This var's value need to be trimmed of leading/trailing spaces/hashes. */ #define QX_FLAG_ENUM 256UL /* Enum values exist and are stored in info_rw. */ #define QX_FLAG_RANGE 512UL /* Ranges for this var available and are stored in info_rw. */ #define QX_FLAG_NONUT 1024UL /* This var doesn't have a corresponding var in NUT. */ #define QX_FLAG_SKIP 2048UL /* Skip this var: this item won't be processed. */ #define MAXTRIES 3 /* Max number of retries */ #ifdef TESTING /* Testing struct */ typedef struct { const char *cmd; /* Command to match */ const char answer[SMALLBUF]; /* Answer for that command. * Note: if 'answer' contains inner '\0's, in order to preserve them, 'answer_len' as well as an item_t->preprocess_answer() function must be set */ const int answer_len; /* Answer length: * - if set to -1 -> auto calculate answer length (treat 'answer' as a null-terminated string) * - otherwise -> use the provided length (if reasonable) and preserve inner '\0's (treat 'answer' as a sequence of bytes till the item_t->preprocess_answer() function gets called) */ } testing_t; #endif /* TESTING */ /* Subdriver interface */ typedef struct { const char *name; /* Name of this subdriver, i.e. name (must be equal to the protocol name) + space + version */ int (*claim)(void); /* Function that allows the subdriver to "claim" a device: return 1 if device is covered by this subdriver, else 0 */ item_t *qx2nut; /* Main table of vars and instcmds */ void (*initups)(void); /* Subdriver specific upsdrv_initups. Called at the end of nutdrv_qx's own upsdrv_initups */ void (*initinfo)(void); /* Subdriver specific upsdrv_initinfo. Called at the end of nutdrv_qx's own upsdrv_initinfo */ void (*makevartable)(void); /* Subdriver specific ups.conf flags/vars */ const char *accepted; /* String to match if the driver is expecting a reply from the UPS on instcmd/setvar. * This comparison is done after the answer we got back from the UPS has been processed to get the value we are searching: * - you don't have to include the trailing carriage return (\r) * - you can decide at which index of the answer the value should start or end setting the appropriate from and to in the item_t */ const char *rejected; /* String to match if the driver is expecting a reply from the UPS in case of error. * This comparison is done on the answer we got back from the UPS before it has been processed: * - include also the trailing carriage return (\r) and whatever character is expected */ #ifdef TESTING testing_t *testing; /* Testing table: commands and the replies used for testing the subdriver */ #endif /* TESTING */ } subdriver_t; /* The following functions are exported for the benefit of subdrivers */ /* Execute an instant command. In detail: * - look up the given 'cmdname' in the qx2nut data structure (if not found, try to fallback to commonly known commands); * - if 'cmdname' is found, call its preprocess function, passing to it 'extradata', if any, otherwise its dfl value, if any; * - send the command to the device and check the reply. * Return STAT_INSTCMD_INVALID if the command is invalid, STAT_INSTCMD_FAILED if it failed, STAT_INSTCMD_HANDLED on success. */ int instcmd(const char *cmdname, const char *extradata); /* Set r/w variable to a value after it has been checked against its info_rw structure. Return STAT_SET_HANDLED on success, otherwise STAT_SET_UNKNOWN. */ int setvar(const char *varname, const char *val); /* Find an item of item_t type in qx2nut data structure by its info_type, optionally filtered by its qxflags, and return it if found, otherwise return NULL. * - 'flag': flags that have to be set in the item, i.e. if one of the flags is absent in the item it won't be returned * - 'noflag': flags that have to be absent in the item, i.e. if at least one of the flags is set in the item it won't be returned */ item_t *find_nut_info(const char *varname, const unsigned long flag, const unsigned long noflag); /* Send 'command' (a null-terminated byte string) or, if it is NULL, send the command stored in the item to the UPS and process the reply, saving it in item->answer. Return -1 on errors, 0 on success. */ int qx_process(item_t *item, const char *command); /* Process the value we got back from the UPS (set status bits and set the value of other parameters), calling the item-specific preprocess function, if any, otherwise executing the standard preprocessing (including trimming if QX_FLAG_TRIM is set). * Return -1 on failure, 0 for a status update and 1 in all other cases. */ int ups_infoval_set(item_t *item); /* Return the currently processed status so that it can be checked with one of the status_bit_t passed to the STATUS() macro. */ unsigned int qx_status(void); /* Edit the current status: it takes one of the NUT status (all but OB are supported, simply set it as not OL), eventually preceded with an exclamation mark to clear it from the status (e.g. !OL). */ void update_status(const char *nutvalue); /* Let subdrivers reference this: for devices that report "battery.voltage" of a single cell/pack, optionally multiply that into representing the whole assembly */ int qx_multiply_battvolt(item_t *item, char *value, const size_t valuelen); /* Data for processing status values */ #define STATUS(x) ((unsigned int)1U< * * 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 2 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, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #ifndef NUTDRV_QX_VOLTRONIC_QS_H #define NUTDRV_QX_VOLTRONIC_QS_H #include "nutdrv_qx.h" extern subdriver_t voltronic_qs_subdriver; #endif /* NUTDRV_QX_VOLTRONIC_QS_H */ nut-2.8.1/drivers/eaton-ats30-mib.c0000644000175000017500000005564414501607135013716 00000000000000/* eaton-ats30-mib.c - subdriver to monitor eaton_ats30 SNMP devices with NUT * * Copyright (C) 2017 Eaton * Author: Tomas Halman * 2011-2012 Arnaud Quette * * Note: this subdriver was initially generated as a "stub" by the * gen-snmp-subdriver script. It must be customized! * * 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 2 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, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "eaton-ats30-mib.h" #define EATON_ATS30_MIB_VERSION "0.03" #define EATON_ATS30_SYSOID ".1.3.6.1.4.1.534.10.1" #define EATON_ATS30_MODEL ".1.3.6.1.4.1.534.10.1.2.1.0" static info_lkp_t eaton_ats30_source_info[] = { { 1, "init", NULL, NULL }, { 2, "diagnosis", NULL, NULL }, { 3, "off", NULL, NULL }, { 4, "1", NULL, NULL }, { 5, "2", NULL, NULL }, { 6, "safe", NULL, NULL }, { 7, "fault", NULL, NULL }, { 0, NULL, NULL, NULL } }; static info_lkp_t eaton_ats30_input_sensitivity[] = { { 1, "high", NULL, NULL }, { 2, "low", NULL, NULL }, { 0, NULL, NULL, NULL } }; /* * bitmap values of atsStatus.atsFailureIndicator * * 1 atsFailureSwitchFault N/A * 2 atsFailureNoOutput OFF * 3 atsFailureOutputOC OVER * 4 atsFailureOverTemperature N/A */ static info_lkp_t eaton_ats30_status_info[] = { { 0, "OL", NULL, NULL }, { 1, "OL", NULL, NULL }, /* SwitchFault */ { 2, "OFF", NULL, NULL }, /* NoOutput */ { 3, "OFF", NULL, NULL }, /* SwitchFault + NoOutput */ { 4, "OL OVER", NULL, NULL }, /* OutputOC */ { 5, "OL OVER", NULL, NULL }, /* OutputOC + SwitchFault */ { 6, "OFF OVER", NULL, NULL }, /* OutputOC + NoOutput */ { 7, "OFF OVER", NULL, NULL }, /* OutputOC + SwitchFault + NoOutput */ { 8, "OL", NULL, NULL }, /* OverTemperature */ { 9, "OL", NULL, NULL }, /* OverTemperature + SwitchFault */ { 10, "OFF", NULL, NULL }, /* OverTemperature + NoOutput */ { 11, "OFF", NULL, NULL }, /* OverTemperature + SwitchFault + NoOutput */ { 12, "OL OVER", NULL, NULL }, /* OverTemperature + OutputOC */ { 13, "OL OVER", NULL, NULL }, /* OverTemperature + OutputOC + SwitchFault */ { 14, "OFF OVER", NULL, NULL }, /* OverTemperature + OutputOC + NoOutput */ { 15, "OFF OVER", NULL, NULL }, /* OverTemperature + OutputOC + SwitchFault + NoOutput */ { 0, NULL, NULL, NULL } }; /* EATON_ATS30 Snmp2NUT lookup table */ static snmp_info_t eaton_ats30_mib[] = { /* device type: ats */ { "device.type", ST_FLAG_STRING, SU_INFOSIZE, NULL, "ats", SU_FLAG_STATIC | SU_FLAG_ABSENT | SU_FLAG_OK, NULL }, /* standard MIB items */ { "device.description", ST_FLAG_STRING | ST_FLAG_RW, SU_INFOSIZE, ".1.3.6.1.2.1.1.1.0", NULL, SU_FLAG_OK, NULL }, { "device.contact", ST_FLAG_STRING | ST_FLAG_RW, SU_INFOSIZE, ".1.3.6.1.2.1.1.4.0", NULL, SU_FLAG_OK, NULL }, { "device.location", ST_FLAG_STRING | ST_FLAG_RW, SU_INFOSIZE, ".1.3.6.1.2.1.1.6.0", NULL, SU_FLAG_OK, NULL }, /* enterprises.534.10.1.1.1.0 = STRING: "Eaton" */ { "device.mfr", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.534.10.1.1.1.0", NULL, SU_FLAG_STATIC | SU_FLAG_OK, NULL }, /* enterprises.534.10.1.1.2.0 = STRING: "01.12.13b" -- SNMP agent version */ /* { "device.firmware", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.534.10.1.1.2.0", NULL, SU_FLAG_OK, NULL }, */ /* enterprises.534.10.1.1.3.1.0 = INTEGER: 1 */ /* { "unmapped.enterprise", 0, 1, ".1.3.6.1.4.1.534.10.1.1.3.1.0", NULL, SU_FLAG_OK, NULL }, */ /* enterprises.534.10.1.2.1.0 = STRING: "STS30002SR10019 " */ { "device.model", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.534.10.1.2.1.0", NULL, SU_FLAG_STATIC | SU_FLAG_OK, NULL }, /* enterprises.534.10.1.2.2.0 = STRING: "1A0003AR00.00.00" -- Firmware */ { "ups.firmware", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.534.10.1.2.2.0", NULL, SU_FLAG_OK, NULL }, /* enterprises.534.10.1.2.3.0 = STRING: "2014-09-17 " -- Release date */ /* { "unmapped.enterprises", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.534.10.1.2.3.0", NULL, SU_FLAG_OK, NULL }, */ /* enterprises.534.10.1.2.4.0 = STRING: "JA00E52021 " */ { "device.serial", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.534.10.1.2.4.0", NULL, SU_FLAG_OK, NULL }, /* enterprises.534.10.1.2.5.0 = STRING: " " -- Device ID codes */ /* { "unmapped.enterprises", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.534.10.1.2.5.0", NULL, SU_FLAG_OK, NULL }, */ /* ats measure */ /* =========== */ /* enterprises.534.10.1.3.1.1.1.1 = INTEGER: 1 */ { "input.1.id", 0, 1, ".1.3.6.1.4.1.534.10.1.3.1.1.1.1", NULL, SU_FLAG_OK, NULL }, /* enterprises.534.10.1.3.1.1.1.2 = INTEGER: 2 */ { "input.2.id", 0, 1, ".1.3.6.1.4.1.534.10.1.3.1.1.1.2", NULL, SU_FLAG_OK, NULL }, /* enterprises.534.10.1.3.1.1.2.1 = INTEGER: 2379 */ { "input.1.voltage", 0, 0.1, ".1.3.6.1.4.1.534.10.1.3.1.1.2.1", NULL, SU_FLAG_OK, NULL }, /* enterprises.534.10.1.3.1.1.2.2 = INTEGER: 0 */ { "input.2.voltage", 0, 0.1, ".1.3.6.1.4.1.534.10.1.3.1.1.2.2", NULL, SU_FLAG_OK, NULL }, /* enterprises.534.10.1.3.1.1.3.1 = INTEGER: 500 */ { "input.1.frequency", 0, 0.1, ".1.3.6.1.4.1.534.10.1.3.1.1.3.1", NULL, SU_FLAG_OK, NULL }, /* enterprises.534.10.1.3.1.1.3.2 = INTEGER: 0 */ { "input.2.frequency", 0, 0.1, ".1.3.6.1.4.1.534.10.1.3.1.1.3.2", NULL, SU_FLAG_OK, NULL }, /* enterprises.534.10.1.3.2.1.0 = INTEGER: 2375 */ { "output.voltage", 0, 0.1, ".1.3.6.1.4.1.534.10.1.3.2.1.0", NULL, SU_FLAG_OK, NULL }, /* enterprises.534.10.1.3.2.2.0 = INTEGER: 0 */ { "output.current", 0, 0.1, ".1.3.6.1.4.1.534.10.1.3.2.2.0", NULL, SU_FLAG_OK, NULL }, /* enterprises.534.10.1.3.3.0 = INTEGER: 25 -- internal temperature in celsius */ { "ups.temperature", 0, 1, ".1.3.6.1.4.1.534.10.1.3.3.0", NULL, SU_FLAG_OK, NULL }, /* enterprises.534.10.1.3.4.0 = INTEGER: 77 -- internal temperature in fahrenheit */ /* { "ups.temperatureF", 0, 1, ".1.3.6.1.4.1.534.10.1.3.4.0", NULL, SU_FLAG_OK, NULL }, */ /* enterprises.534.10.1.3.5.0 = INTEGER: 37937541 */ { "device.uptime", 0, 1, ".1.3.6.1.4.1.534.10.1.3.5.0", NULL, SU_FLAG_OK, NULL }, /* enterprises.534.10.1.3.6.0 = INTEGER: 284 */ /* { "unmapped.atsMessureTransferedTimes", 0, 1, ".1.3.6.1.4.1.534.10.1.3.6.0", NULL, SU_FLAG_OK, NULL }, */ /* enterprises.534.10.1.3.7.0 = INTEGER: 4 */ { "input.source", 0, 1, ".1.3.6.1.4.1.534.10.1.3.7.0", NULL, SU_FLAG_OK, eaton_ats30_source_info }, /* atsStatus */ /* ========= */ #if WITH_UNMAPPED_DATA_POINTS /* NOTE: Unused OIDs are left as comments for potential future improvements */ /* enterprises.534.10.1.4.1.0 = INTEGER: 7 */ { "unmapped.atsInputFlowIndicator", 0, 1, ".1.3.6.1.4.1.534.10.1.4.1.0", NULL, SU_FLAG_OK, NULL }, /* enterprises.534.10.1.4.2.1.1.1 = INTEGER: 1 -- atsInputFlowTable start */ { "unmapped.atsInputFlowIndex.1", 0, 1, ".1.3.6.1.4.1.534.10.1.4.2.1.1.1", NULL, SU_FLAG_OK, NULL }, /* enterprises.534.10.1.4.2.1.1.2 = INTEGER: 2 */ { "unmapped.atsInputFlowIndex.2", 0, 1, ".1.3.6.1.4.1.534.10.1.4.2.1.1.2", NULL, SU_FLAG_OK, NULL }, /* enterprises.534.10.1.4.2.1.2.1 = INTEGER: 1 */ { "unmapped.atsInputFlowRelay.1", 0, 1, ".1.3.6.1.4.1.534.10.1.4.2.1.2.1", NULL, SU_FLAG_OK, NULL }, /* enterprises.534.10.1.4.2.1.2.2 = INTEGER: 2 */ { "unmapped.atsInputFlowRelay.2", 0, 1, ".1.3.6.1.4.1.534.10.1.4.2.1.2.2", NULL, SU_FLAG_OK, NULL }, /* enterprises.534.10.1.4.2.1.3.1 = INTEGER: 1 */ { "unmapped.atsInputFlowSCR.1", 0, 1, ".1.3.6.1.4.1.534.10.1.4.2.1.3.1", NULL, SU_FLAG_OK, NULL }, /* enterprises.534.10.1.4.2.1.3.2 = INTEGER: 2 */ { "unmapped.atsInputFlowSCR.2", 0, 1, ".1.3.6.1.4.1.534.10.1.4.2.1.3.2", NULL, SU_FLAG_OK, NULL }, /* enterprises.534.10.1.4.2.1.4.1 = INTEGER: 1 */ { "unmapped.atsInputFlowParallelRelay.1", 0, 1, ".1.3.6.1.4.1.534.10.1.4.2.1.4.1", NULL, SU_FLAG_OK, NULL }, /* enterprises.534.10.1.4.2.1.4.2 = INTEGER: 2 */ { "unmapped.atsInputFlowParallelRelay.2", 0, 1, ".1.3.6.1.4.1.534.10.1.4.2.1.4.2", NULL, SU_FLAG_OK, NULL }, /* enterprises.534.10.1.4.3.0 = INTEGER: 58720256 */ { "unmapped.atsInputFailureIndicator", 0, 1, ".1.3.6.1.4.1.534.10.1.4.3.0", NULL, SU_FLAG_OK, NULL }, /* enterprises.534.10.1.4.4.1.1.1 = INTEGER: 1 */ { "unmapped.enterprises", 0, 1, ".1.3.6.1.4.1.534.10.1.4.4.1.1.1", NULL, SU_FLAG_OK, NULL }, /* enterprises.534.10.1.4.4.1.1.2 = INTEGER: 2 */ { "unmapped.enterprises", 0, 1, ".1.3.6.1.4.1.534.10.1.4.4.1.1.2", NULL, SU_FLAG_OK, NULL }, /* enterprises.534.10.1.4.4.1.2.1 = INTEGER: 2 */ { "unmapped.enterprises", 0, 1, ".1.3.6.1.4.1.534.10.1.4.4.1.2.1", NULL, SU_FLAG_OK, NULL }, /* enterprises.534.10.1.4.4.1.2.2 = INTEGER: 2 */ { "unmapped.enterprises", 0, 1, ".1.3.6.1.4.1.534.10.1.4.4.1.2.2", NULL, SU_FLAG_OK, NULL }, /* enterprises.534.10.1.4.4.1.3.1 = INTEGER: 2 */ { "unmapped.enterprises", 0, 1, ".1.3.6.1.4.1.534.10.1.4.4.1.3.1", NULL, SU_FLAG_OK, NULL }, /* enterprises.534.10.1.4.4.1.3.2 = INTEGER: 2 */ { "unmapped.enterprises", 0, 1, ".1.3.6.1.4.1.534.10.1.4.4.1.3.2", NULL, SU_FLAG_OK, NULL }, /* enterprises.534.10.1.4.4.1.4.1 = INTEGER: 2 */ { "unmapped.enterprises", 0, 1, ".1.3.6.1.4.1.534.10.1.4.4.1.4.1", NULL, SU_FLAG_OK, NULL }, /* enterprises.534.10.1.4.4.1.4.2 = INTEGER: 2 */ { "unmapped.enterprises", 0, 1, ".1.3.6.1.4.1.534.10.1.4.4.1.4.2", NULL, SU_FLAG_OK, NULL }, /* enterprises.534.10.1.4.4.1.5.1 = INTEGER: 2 */ { "unmapped.enterprises", 0, 1, ".1.3.6.1.4.1.534.10.1.4.4.1.5.1", NULL, SU_FLAG_OK, NULL }, /* enterprises.534.10.1.4.4.1.5.2 = INTEGER: 2 */ { "unmapped.enterprises", 0, 1, ".1.3.6.1.4.1.534.10.1.4.4.1.5.2", NULL, SU_FLAG_OK, NULL }, /* enterprises.534.10.1.4.4.1.6.1 = INTEGER: 2 */ { "unmapped.enterprises", 0, 1, ".1.3.6.1.4.1.534.10.1.4.4.1.6.1", NULL, SU_FLAG_OK, NULL }, /* enterprises.534.10.1.4.4.1.6.2 = INTEGER: 2 */ { "unmapped.enterprises", 0, 1, ".1.3.6.1.4.1.534.10.1.4.4.1.6.2", NULL, SU_FLAG_OK, NULL }, /* enterprises.534.10.1.4.4.1.7.1 = INTEGER: 2 */ { "unmapped.enterprises", 0, 1, ".1.3.6.1.4.1.534.10.1.4.4.1.7.1", NULL, SU_FLAG_OK, NULL }, /* enterprises.534.10.1.4.4.1.7.2 = INTEGER: 2 */ { "unmapped.enterprises", 0, 1, ".1.3.6.1.4.1.534.10.1.4.4.1.7.2", NULL, SU_FLAG_OK, NULL }, /* enterprises.534.10.1.4.4.1.8.1 = INTEGER: 2 */ { "unmapped.enterprises", 0, 1, ".1.3.6.1.4.1.534.10.1.4.4.1.8.1", NULL, SU_FLAG_OK, NULL }, /* enterprises.534.10.1.4.4.1.8.2 = INTEGER: 2 */ { "unmapped.enterprises", 0, 1, ".1.3.6.1.4.1.534.10.1.4.4.1.8.2", NULL, SU_FLAG_OK, NULL }, /* enterprises.534.10.1.4.4.1.9.1 = INTEGER: 2 */ { "unmapped.enterprises", 0, 1, ".1.3.6.1.4.1.534.10.1.4.4.1.9.1", NULL, SU_FLAG_OK, NULL }, /* enterprises.534.10.1.4.4.1.9.2 = INTEGER: 1 */ { "unmapped.enterprises", 0, 1, ".1.3.6.1.4.1.534.10.1.4.4.1.9.2", NULL, SU_FLAG_OK, NULL }, /* enterprises.534.10.1.4.4.1.10.1 = INTEGER: 2 */ { "unmapped.enterprises", 0, 1, ".1.3.6.1.4.1.534.10.1.4.4.1.10.1", NULL, SU_FLAG_OK, NULL }, /* enterprises.534.10.1.4.4.1.10.2 = INTEGER: 1 */ { "unmapped.enterprises", 0, 1, ".1.3.6.1.4.1.534.10.1.4.4.1.10.2", NULL, SU_FLAG_OK, NULL }, /* enterprises.534.10.1.4.4.1.11.1 = INTEGER: 2 */ { "unmapped.enterprises", 0, 1, ".1.3.6.1.4.1.534.10.1.4.4.1.11.1", NULL, SU_FLAG_OK, NULL }, /* enterprises.534.10.1.4.4.1.11.2 = INTEGER: 1 */ { "unmapped.enterprises", 0, 1, ".1.3.6.1.4.1.534.10.1.4.4.1.11.2", NULL, SU_FLAG_OK, NULL }, #endif /* if WITH_UNMAPPED_DATA_POINTS */ /* enterprises.atsFailureIndicator = INTEGER: 0 */ { "ups.status", 0, 1, ".1.3.6.1.4.1.534.10.1.4.5.0", NULL, SU_FLAG_OK, eaton_ats30_status_info }, #if WITH_UNMAPPED_DATA_POINTS /* enterprises.534.10.1.4.6.1.0 = INTEGER: 2 -- atsFailure start */ { "unmapped.enterprises", 0, 1, ".1.3.6.1.4.1.534.10.1.4.6.1.0", NULL, SU_FLAG_OK, NULL }, /* enterprises.534.10.1.4.6.2.0 = INTEGER: 2 */ { "unmapped.enterprises", 0, 1, ".1.3.6.1.4.1.534.10.1.4.6.2.0", NULL, SU_FLAG_OK, NULL }, /* enterprises.534.10.1.4.6.3.0 = INTEGER: 2 */ { "unmapped.enterprises", 0, 1, ".1.3.6.1.4.1.534.10.1.4.6.3.0", NULL, SU_FLAG_OK, NULL }, /* enterprises.534.10.1.4.6.4.0 = INTEGER: 2 */ { "unmapped.enterprises", 0, 1, ".1.3.6.1.4.1.534.10.1.4.6.4.0", NULL, SU_FLAG_OK, NULL }, #endif /* if WITH_UNMAPPED_DATA_POINTS */ /* atsLog */ /* ====== */ #if WITH_UNMAPPED_DATA_POINTS /* We are not interested in log */ /* enterprises.534.10.1.5.1.0 = INTEGER: 272 */ { "unmapped.enterprises", 0, 1, ".1.3.6.1.4.1.534.10.1.5.1.0", NULL, SU_FLAG_OK, NULL }, /* enterprises.534.10.1.5.2.1.1.1 = INTEGER: 1 */ { "unmapped.enterprises", 0, 1, ".1.3.6.1.4.1.534.10.1.5.2.1.1.1", NULL, SU_FLAG_OK, NULL }, /* enterprises.534.10.1.5.2.1.1.2 = INTEGER: 2 */ { "unmapped.enterprises", 0, 1, ".1.3.6.1.4.1.534.10.1.5.2.1.1.2", NULL, SU_FLAG_OK, NULL }, /* enterprises.534.10.1.5.2.1.1.3 = INTEGER: 3 */ { "unmapped.enterprises", 0, 1, ".1.3.6.1.4.1.534.10.1.5.2.1.1.3", NULL, SU_FLAG_OK, NULL }, /* enterprises.534.10.1.5.2.1.1.4 = INTEGER: 4 */ { "unmapped.enterprises", 0, 1, ".1.3.6.1.4.1.534.10.1.5.2.1.1.4", NULL, SU_FLAG_OK, NULL }, /* enterprises.534.10.1.5.2.1.1.5 = INTEGER: 5 */ { "unmapped.enterprises", 0, 1, ".1.3.6.1.4.1.534.10.1.5.2.1.1.5", NULL, SU_FLAG_OK, NULL }, /* enterprises.534.10.1.5.2.1.1.6 = INTEGER: 6 */ { "unmapped.enterprises", 0, 1, ".1.3.6.1.4.1.534.10.1.5.2.1.1.6", NULL, SU_FLAG_OK, NULL }, /* enterprises.534.10.1.5.2.1.1.7 = INTEGER: 7 */ { "unmapped.enterprises", 0, 1, ".1.3.6.1.4.1.534.10.1.5.2.1.1.7", NULL, SU_FLAG_OK, NULL }, /* enterprises.534.10.1.5.2.1.1.8 = INTEGER: 8 */ { "unmapped.enterprises", 0, 1, ".1.3.6.1.4.1.534.10.1.5.2.1.1.8", NULL, SU_FLAG_OK, NULL }, /* enterprises.534.10.1.5.2.1.1.9 = INTEGER: 9 */ { "unmapped.enterprises", 0, 1, ".1.3.6.1.4.1.534.10.1.5.2.1.1.9", NULL, SU_FLAG_OK, NULL }, /* enterprises.534.10.1.5.2.1.1.10 = INTEGER: 10 */ { "unmapped.enterprises", 0, 1, ".1.3.6.1.4.1.534.10.1.5.2.1.1.10", NULL, SU_FLAG_OK, NULL }, /* enterprises.534.10.1.5.2.1.2.1 = INTEGER: 1482323677 */ { "unmapped.enterprises", 0, 1, ".1.3.6.1.4.1.534.10.1.5.2.1.2.1", NULL, SU_FLAG_OK, NULL }, /* enterprises.534.10.1.5.2.1.2.2 = INTEGER: 1480076955 */ { "unmapped.enterprises", 0, 1, ".1.3.6.1.4.1.534.10.1.5.2.1.2.2", NULL, SU_FLAG_OK, NULL }, /* enterprises.534.10.1.5.2.1.2.3 = INTEGER: 1480069128 */ { "unmapped.enterprises", 0, 1, ".1.3.6.1.4.1.534.10.1.5.2.1.2.3", NULL, SU_FLAG_OK, NULL }, /* enterprises.534.10.1.5.2.1.2.4 = INTEGER: 1480069093 */ { "unmapped.enterprises", 0, 1, ".1.3.6.1.4.1.534.10.1.5.2.1.2.4", NULL, SU_FLAG_OK, NULL }, /* enterprises.534.10.1.5.2.1.2.5 = INTEGER: 1478693745 */ { "unmapped.enterprises", 0, 1, ".1.3.6.1.4.1.534.10.1.5.2.1.2.5", NULL, SU_FLAG_OK, NULL }, /* enterprises.534.10.1.5.2.1.2.6 = INTEGER: 1478693741 */ { "unmapped.enterprises", 0, 1, ".1.3.6.1.4.1.534.10.1.5.2.1.2.6", NULL, SU_FLAG_OK, NULL }, /* enterprises.534.10.1.5.2.1.2.7 = INTEGER: 1466604406 */ { "unmapped.enterprises", 0, 1, ".1.3.6.1.4.1.534.10.1.5.2.1.2.7", NULL, SU_FLAG_OK, NULL }, /* enterprises.534.10.1.5.2.1.2.8 = INTEGER: 1466604386 */ { "unmapped.enterprises", 0, 1, ".1.3.6.1.4.1.534.10.1.5.2.1.2.8", NULL, SU_FLAG_OK, NULL }, /* enterprises.534.10.1.5.2.1.2.9 = INTEGER: 1466604386 */ { "unmapped.enterprises", 0, 1, ".1.3.6.1.4.1.534.10.1.5.2.1.2.9", NULL, SU_FLAG_OK, NULL }, /* enterprises.534.10.1.5.2.1.2.10 = INTEGER: 1463038288 */ { "unmapped.enterprises", 0, 1, ".1.3.6.1.4.1.534.10.1.5.2.1.2.10", NULL, SU_FLAG_OK, NULL }, /* enterprises.534.10.1.5.2.1.3.1 = INTEGER: 41 */ { "unmapped.enterprises", 0, 1, ".1.3.6.1.4.1.534.10.1.5.2.1.3.1", NULL, SU_FLAG_OK, NULL }, /* enterprises.534.10.1.5.2.1.3.2 = INTEGER: 41 */ { "unmapped.enterprises", 0, 1, ".1.3.6.1.4.1.534.10.1.5.2.1.3.2", NULL, SU_FLAG_OK, NULL }, /* enterprises.534.10.1.5.2.1.3.3 = INTEGER: 44 */ { "unmapped.enterprises", 0, 1, ".1.3.6.1.4.1.534.10.1.5.2.1.3.3", NULL, SU_FLAG_OK, NULL }, /* enterprises.534.10.1.5.2.1.3.4 = INTEGER: 44 */ { "unmapped.enterprises", 0, 1, ".1.3.6.1.4.1.534.10.1.5.2.1.3.4", NULL, SU_FLAG_OK, NULL }, /* enterprises.534.10.1.5.2.1.3.5 = INTEGER: 44 */ { "unmapped.enterprises", 0, 1, ".1.3.6.1.4.1.534.10.1.5.2.1.3.5", NULL, SU_FLAG_OK, NULL }, /* enterprises.534.10.1.5.2.1.3.6 = INTEGER: 41 */ { "unmapped.enterprises", 0, 1, ".1.3.6.1.4.1.534.10.1.5.2.1.3.6", NULL, SU_FLAG_OK, NULL }, /* enterprises.534.10.1.5.2.1.3.7 = INTEGER: 41 */ { "unmapped.enterprises", 0, 1, ".1.3.6.1.4.1.534.10.1.5.2.1.3.7", NULL, SU_FLAG_OK, NULL }, /* enterprises.534.10.1.5.2.1.3.8 = INTEGER: 46 */ { "unmapped.enterprises", 0, 1, ".1.3.6.1.4.1.534.10.1.5.2.1.3.8", NULL, SU_FLAG_OK, NULL }, /* enterprises.534.10.1.5.2.1.3.9 = INTEGER: 45 */ { "unmapped.enterprises", 0, 1, ".1.3.6.1.4.1.534.10.1.5.2.1.3.9", NULL, SU_FLAG_OK, NULL }, /* enterprises.534.10.1.5.2.1.3.10 = INTEGER: 41 */ { "unmapped.enterprises", 0, 1, ".1.3.6.1.4.1.534.10.1.5.2.1.3.10", NULL, SU_FLAG_OK, NULL }, /* enterprises.534.10.1.5.2.1.4.1 = STRING: "12:34:37 12/21/2016" */ { "unmapped.enterprises", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.534.10.1.5.2.1.4.1", NULL, SU_FLAG_OK, NULL }, /* enterprises.534.10.1.5.2.1.4.2 = STRING: "12:29:15 11/25/2016" */ { "unmapped.enterprises", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.534.10.1.5.2.1.4.2", NULL, SU_FLAG_OK, NULL }, /* enterprises.534.10.1.5.2.1.4.3 = STRING: "10:18:48 11/25/2016" */ { "unmapped.enterprises", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.534.10.1.5.2.1.4.3", NULL, SU_FLAG_OK, NULL }, /* enterprises.534.10.1.5.2.1.4.4 = STRING: "10:18:13 11/25/2016" */ { "unmapped.enterprises", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.534.10.1.5.2.1.4.4", NULL, SU_FLAG_OK, NULL }, /* enterprises.534.10.1.5.2.1.4.5 = STRING: "12:15:45 11/09/2016" */ { "unmapped.enterprises", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.534.10.1.5.2.1.4.5", NULL, SU_FLAG_OK, NULL }, /* enterprises.534.10.1.5.2.1.4.6 = STRING: "12:15:41 11/09/2016" */ { "unmapped.enterprises", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.534.10.1.5.2.1.4.6", NULL, SU_FLAG_OK, NULL }, /* enterprises.534.10.1.5.2.1.4.7 = STRING: "14:06:46 06/22/2016" */ { "unmapped.enterprises", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.534.10.1.5.2.1.4.7", NULL, SU_FLAG_OK, NULL }, /* enterprises.534.10.1.5.2.1.4.8 = STRING: "14:06:26 06/22/2016" */ { "unmapped.enterprises", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.534.10.1.5.2.1.4.8", NULL, SU_FLAG_OK, NULL }, /* enterprises.534.10.1.5.2.1.4.9 = STRING: "14:06:26 06/22/2016" */ { "unmapped.enterprises", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.534.10.1.5.2.1.4.9", NULL, SU_FLAG_OK, NULL }, /* enterprises.534.10.1.5.2.1.4.10 = STRING: "07:31:28 05/12/2016" */ { "unmapped.enterprises", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.534.10.1.5.2.1.4.10", NULL, SU_FLAG_OK, NULL }, #endif /* WITH_UNMAPPED_DATA_POINTS */ /* atsConfig */ /* ========= */ #if WITH_UNMAPPED_DATA_POINTS /* enterprises.534.10.1.6.1.1.0 = INTEGER: 538562409 */ { "unmapped.enterprises", 0, 1, ".1.3.6.1.4.1.534.10.1.6.1.1.0", NULL, SU_FLAG_OK, NULL }, /* enterprises.534.10.1.6.1.2.0 = STRING: "01/24/2017" */ { "unmapped.enterprises", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.534.10.1.6.1.2.0", NULL, SU_FLAG_OK, NULL }, /* enterprises.534.10.1.6.1.3.0 = STRING: "08:40:09" */ { "unmapped.enterprises", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.534.10.1.6.1.3.0", NULL, SU_FLAG_OK, NULL }, /* enterprises.534.10.1.6.2.1.1.1 = INTEGER: 1 */ { "unmapped.enterprises", 0, 1, ".1.3.6.1.4.1.534.10.1.6.2.1.1.1", NULL, SU_FLAG_OK, NULL }, /* enterprises.534.10.1.6.2.1.1.2 = INTEGER: 2 */ { "unmapped.enterprises", 0, 1, ".1.3.6.1.4.1.534.10.1.6.2.1.1.2", NULL, SU_FLAG_OK, NULL }, /* enterprises.534.10.1.6.2.1.2.1 = INTEGER: 1700 */ { "unmapped.enterprises", 0, 1, ".1.3.6.1.4.1.534.10.1.6.2.1.2.1", NULL, SU_FLAG_OK, NULL }, /* enterprises.534.10.1.6.2.1.2.2 = INTEGER: 1700 */ { "unmapped.enterprises", 0, 1, ".1.3.6.1.4.1.534.10.1.6.2.1.2.2", NULL, SU_FLAG_OK, NULL }, /* enterprises.534.10.1.6.2.1.3.1 = INTEGER: 1800 */ { "unmapped.enterprises", 0, 1, ".1.3.6.1.4.1.534.10.1.6.2.1.3.1", NULL, SU_FLAG_OK, NULL }, /* enterprises.534.10.1.6.2.1.3.2 = INTEGER: 1800 */ { "unmapped.enterprises", 0, 1, ".1.3.6.1.4.1.534.10.1.6.2.1.3.2", NULL, SU_FLAG_OK, NULL }, /* enterprises.534.10.1.6.2.1.4.1 = INTEGER: 2640 */ { "unmapped.enterprises", 0, 1, ".1.3.6.1.4.1.534.10.1.6.2.1.4.1", NULL, SU_FLAG_OK, NULL }, /* enterprises.534.10.1.6.2.1.4.2 = INTEGER: 2640 */ { "unmapped.enterprises", 0, 1, ".1.3.6.1.4.1.534.10.1.6.2.1.4.2", NULL, SU_FLAG_OK, NULL }, /* enterprises.534.10.1.6.2.1.5.1 = INTEGER: 3000 */ { "unmapped.enterprises", 0, 1, ".1.3.6.1.4.1.534.10.1.6.2.1.5.1", NULL, SU_FLAG_OK, NULL }, /* enterprises.534.10.1.6.2.1.5.2 = INTEGER: 3000 */ { "unmapped.enterprises", 0, 1, ".1.3.6.1.4.1.534.10.1.6.2.1.5.2", NULL, SU_FLAG_OK, NULL }, /* enterprises.534.10.1.6.2.1.6.1 = INTEGER: 50 */ { "unmapped.enterprises", 0, 1, ".1.3.6.1.4.1.534.10.1.6.2.1.6.1", NULL, SU_FLAG_OK, NULL }, /* enterprises.534.10.1.6.2.1.6.2 = INTEGER: 50 */ { "unmapped.enterprises", 0, 1, ".1.3.6.1.4.1.534.10.1.6.2.1.6.2", NULL, SU_FLAG_OK, NULL }, /* enterprises.534.10.1.6.2.1.7.1 = INTEGER: 40 */ { "unmapped.enterprises", 0, 1, ".1.3.6.1.4.1.534.10.1.6.2.1.7.1", NULL, SU_FLAG_OK, NULL }, /* enterprises.534.10.1.6.2.1.7.2 = INTEGER: 40 */ { "unmapped.enterprises", 0, 1, ".1.3.6.1.4.1.534.10.1.6.2.1.7.2", NULL, SU_FLAG_OK, NULL }, /* enterprises.534.10.1.6.3.0 = INTEGER: 2640 */ { "unmapped.atsConfigInputVoltageRating", 0, 1, ".1.3.6.1.4.1.534.10.1.6.3.0", NULL, SU_FLAG_OK, NULL }, /* enterprises.534.10.1.6.4.0 = INTEGER: 26 */ { "unmapped.atsConfigRandomTime", 0, 1, ".1.3.6.1.4.1.534.10.1.6.4.0", NULL, SU_FLAG_OK, NULL }, #endif /* if WITH_UNMAPPED_DATA_POINTS */ /* enterprises.534.10.1.6.5.0 = INTEGER: 1 */ { "input.source.preferred", ST_FLAG_RW, 1, ".1.3.6.1.4.1.534.10.1.6.5.0", NULL, SU_FLAG_OK, NULL }, /* enterprises.534.10.1.6.6.0 = INTEGER: 2 */ { "input.sensitivity", ST_FLAG_RW, 1, ".1.3.6.1.4.1.534.10.1.6.6.0", NULL, SU_FLAG_OK, eaton_ats30_input_sensitivity }, /* enterprises.534.10.1.6.7.0 = INTEGER: 2 */ /* { "unmapped.atsConfigTest", 0, 1, ".1.3.6.1.4.1.534.10.1.6.7.0", NULL, SU_FLAG_OK, NULL }, */ /* atsUpgrade */ /* ========== */ #if WITH_UNMAPPED_DATA_POINTS /* We are not interested in atsUpgrade */ /* enterprises.534.10.1.7.1.0 = INTEGER: 1 */ /* { "unmapped.enterprises", 0, 1, ".1.3.6.1.4.1.534.10.1.7.1.0", NULL, SU_FLAG_OK, NULL }, */ /* enterprises.534.10.1.7.2.0 = INTEGER: 1 */ /* { "unmapped.enterprises", 0, 1, ".1.3.6.1.4.1.534.10.1.7.2.0", NULL, SU_FLAG_OK, NULL }, */ /* enterprises.534.10.1.7.3.0 = INTEGER: 0 */ /* { "unmapped.enterprises", 0, 1, ".1.3.6.1.4.1.534.10.1.7.3.0", NULL, SU_FLAG_OK, NULL }, */ #endif /* if WITH_UNMAPPED_DATA_POINTS */ /* end of structure. */ { NULL, 0, 0, NULL, NULL, 0, NULL } }; mib2nut_info_t eaton_ats30 = { "eaton_ats30", EATON_ATS30_MIB_VERSION, NULL, EATON_ATS30_MODEL, eaton_ats30_mib, EATON_ATS30_SYSOID, NULL }; nut-2.8.1/drivers/delta_ups-hid.h0000644000175000017500000000227014500336654013631 00000000000000/* delta_ups-hid.h - data mapping subdriver to monitor Delta UPS USB/HID devices with NUT * * Copyright (C) * 2003 - 2009 Arnaud Quette * 2005 - 2006 Peter Selinger * 2008 - 2009 Arjen de Korte * 2021 Jungeon Kim * * 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 2 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, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef DELTA_UPS_HID_H #define DELTA_UPS_HID_H #include "usbhid-ups.h" extern subdriver_t delta_ups_subdriver; #endif /* DELTA_UPS_HID_H */ nut-2.8.1/drivers/compaq-mib.h0000644000175000017500000000021514273170601013124 00000000000000#ifndef COMPAQ_MIB_H #define COMPAQ_MIB_H #include "main.h" #include "snmp-ups.h" extern mib2nut_info_t compaq; #endif /* COMPAQ_MIB_H */ nut-2.8.1/drivers/riello_usb.c0000644000175000017500000007757614517666470013300 00000000000000/* * riello_usb.c: support for Riello USB protocol based UPSes * * A document describing the protocol implemented by this driver can be * found online at: * * https://www.networkupstools.org/protocols/riello/PSGPSER-0104.pdf * * Copyright (C) 2012 - Elio Parisi * Copyright (C) 2016 Eaton * * 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 2 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, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * Reference of the derivative work: blazer driver */ #include "config.h" /* must be the first header */ #include "main.h" #include "nut_libusb.h" #include "usb-common.h" #include "riello.h" #define DRIVER_NAME "Riello USB driver" #define DRIVER_VERSION "0.11" #define DEFAULT_OFFDELAY 5 /*!< seconds (max 0xFF) */ #define DEFAULT_BOOTDELAY 5 /*!< seconds (max 0xFF) */ /* driver description structure */ upsdrv_info_t upsdrv_info = { DRIVER_NAME, DRIVER_VERSION, "Elio Parisi ", DRV_EXPERIMENTAL, { NULL } }; static uint8_t bufOut[BUFFER_SIZE]; static uint8_t bufIn[BUFFER_SIZE]; static uint8_t gpser_error_control; static uint8_t input_monophase; static uint8_t output_monophase; /*! Time in seconds to delay before shutting down. */ static unsigned int offdelay = DEFAULT_OFFDELAY; static unsigned int bootdelay = DEFAULT_BOOTDELAY; static TRielloData DevData; static usb_communication_subdriver_t *usb = &usb_subdriver; static usb_dev_handle *udev = NULL; static USBDevice_t usbdevice; static USBDeviceMatcher_t *reopen_matcher = NULL; static USBDeviceMatcher_t *regex_matcher = NULL; static int (*subdriver_command)(uint8_t *cmd, uint8_t *buf, uint16_t length, uint16_t buflen) = NULL; static void ussleep(useconds_t usec) { if (usec == 1) usec = 400; else usec *= 1000; usleep(usec); } static int cypress_setfeatures(void) { int ret; bufOut[0] = 0xB0; bufOut[1] = 0x4; bufOut[2] = 0x0; bufOut[3] = 0x0; bufOut[4] = 0x3; /* Write features report */ ret = usb_control_msg(udev, USB_ENDPOINT_OUT + USB_TYPE_CLASS + USB_RECIP_INTERFACE, 0x09, /* HID_REPORT_SET = 0x09 */ 0 + (0x03 << 8), /* HID_REPORT_TYPE_FEATURE */ 0, (usb_ctrl_charbuf) bufOut, 0x5, 1000); if (ret <= 0) { upsdebugx(3, "send: %s", ret ? nut_usb_strerror(ret) : "error"); return ret; } upsdebugx(3, "send: features report ok"); return ret; } static int Send_USB_Packet(uint8_t *send_str, uint16_t numbytes) { uint8_t USB_buff_pom[10]; int i, err, size; /*int errno;*/ /* is input correct ? */ if ((!send_str) || (!numbytes)) return -1; size = 7; /* routine which parse report into 4-bytes packet */ for (i=0; i<(numbytes/size); i++) { USB_buff_pom[0] = 0x37; USB_buff_pom[1] = send_str[(i*7)]; USB_buff_pom[2] = send_str[(i*7)+1]; USB_buff_pom[3] = send_str[(i*7)+2]; USB_buff_pom[4] = send_str[(i*7)+3]; USB_buff_pom[5] = send_str[(i*7)+4]; USB_buff_pom[6] = send_str[(i*7)+5]; USB_buff_pom[7] = send_str[(i*7)+6]; err = usb_bulk_write(udev, 0x2, (usb_ctrl_charbuf) USB_buff_pom, 8, 1000); if (err < 0) { upsdebugx(3, "USB: Send_USB_Packet: send_usb_packet, err = %d %s ", err, strerror(errno)); return err; } ussleep(USB_WRITE_DELAY); } /* send rest of packet */ if (numbytes % size) { i = numbytes/size; memset(USB_buff_pom, '0', sizeof(USB_buff_pom)); USB_buff_pom[0] = 0x30+(numbytes%7); if ((i*7) 0) upsdebugx(3, "read: %02X %02X %02X %02X %02X %02X %02X %02X", inBuf[0], inBuf[1], inBuf[2], inBuf[3], inBuf[4], inBuf[5], inBuf[6], inBuf[7]); if (err < 0){ upsdebugx(3, "USB: Get_USB_Packet: send_usb_packet, err = %d %s ", err, strerror(errno)); return err; } /* copy to buffer */ size = (unsigned char)(inBuf[0]) & 0x07; if (size) memcpy(buffer, &inBuf[1], size); if (size > INT_MAX) return -1; return (int)size; } static int cypress_command(uint8_t *buffer, uint8_t *buf, uint16_t length, uint16_t buflen) { int loop = 0; int ret, i = 0; uint8_t USB_buff[BUFFER_SIZE]; /* read to flush buffer */ riello_init_serial(); /* send packet */ ret = Send_USB_Packet(buffer, length); if (ret < 0) { upsdebugx(3, "Cypress_command send: err %d", ret ); return ret; } upsdebugx(3, "send ok"); memset(buf, 0, buflen); while ((buf_ptr_length < BUFFER_SIZE) && wait_packet) { memset(USB_buff, 0, sizeof(USB_buff)); ret = Get_USB_Packet(USB_buff); /* * Any errors here mean that we are unable to read a reply (which * will happen after successfully writing a command to the UPS) */ if (ret < 0) { upsdebugx(3, "Cypress_command read: err %d", ret ); return ret; } for (i = 0; i < ret; i++ ) { commbyte = USB_buff[i]; riello_parse_serialport(DEV_RIELLOGPSER, buf, gpser_error_control); } loop++; if (loop>300){ wait_packet=0; upsdebugx(1, "wait_packet reset"); } ussleep(10); } upsdebugx(3, "in read: %u", buf_ptr_length); return buf_ptr_length; } static void *cypress_subdriver(USBDevice_t *device) { NUT_UNUSED_VARIABLE(device); subdriver_command = &cypress_command; return NULL; } /* Riello (Cypress Semiconductor Corp.) */ #define RIELLO_VENDORID 0x04b4 static usb_device_id_t riello_usb_id[] = { /* various models */ { USB_DEVICE(RIELLO_VENDORID, 0x5500), &cypress_subdriver }, /* Terminating entry */ { 0, 0, NULL } }; static int device_match_func(USBDevice_t *hd, void *privdata) { NUT_UNUSED_VARIABLE(privdata); if (subdriver_command) { return 1; } switch (is_usb_device_supported(riello_usb_id, hd)) { case SUPPORTED: return 1; case POSSIBLY_SUPPORTED: case NOT_SUPPORTED: default: return 0; } } static USBDeviceMatcher_t device_matcher = { &device_match_func, NULL, NULL }; /* * Callback that is called by usb_device_open() that handles USB device * settings prior to accepting the devide. At the very least claim the * device here. Detaching the kernel driver will be handled by the * caller, don't do this here. Return < 0 on error, 0 or higher on * success. */ static int driver_callback(usb_dev_handle *handle, USBDevice_t *device, usb_ctrl_charbuf rdbuf, usb_ctrl_charbufsize rdlen) { int ret = 0; NUT_UNUSED_VARIABLE(device); NUT_UNUSED_VARIABLE(rdbuf); NUT_UNUSED_VARIABLE(rdlen); /* if ((ret = usb_set_configuration(handle, 1)) < 0) { upslogx(LOG_WARNING, "Can't set USB configuration: %s", nut_usb_strerror(ret)); return -1; } */ if ((ret = usb_claim_interface(handle, 0)) < 0) { upslogx(LOG_WARNING, "Can't claim USB interface: %s", nut_usb_strerror(ret)); return -1; } /* TODO: HID SET_IDLE to 0 (not necessary?) */ return 1; } /* * Generic command processing function. Send a command and read a reply. * Returns < 0 on error, 0 on timeout and the number of bytes read on * success. */ static int riello_command(uint8_t *cmd, uint8_t *buf, uint16_t length, uint16_t buflen) { int ret; if (udev == NULL) { dstate_setinfo("driver.state", "reconnect.trying"); ret = usb->open_dev(&udev, &usbdevice, reopen_matcher, &driver_callback); upsdebugx (3, "riello_command err udev NULL : %d ", ret); if (ret < 0) return ret; dstate_setinfo("driver.state", "reconnect.updateinfo"); upsdrv_initinfo(); /* reconnect usb cable */ dstate_setinfo("driver.state", "quiet"); } ret = (*subdriver_command)(cmd, buf, length, buflen); if (ret >= 0) { upsdebugx (3, "riello_command ok: %u", ret); return ret; } upsdebugx (3, "riello_command err: %d", ret); switch (ret) { case LIBUSB_ERROR_BUSY: /* Device or resource busy */ fatal_with_errno(EXIT_FAILURE, "Got disconnected by another driver"); #ifndef HAVE___ATTRIBUTE__NORETURN exit(EXIT_FAILURE); /* Should not get here in practice, but compiler is afraid we can fall through */ #endif #if WITH_LIBUSB_0_1 /* limit to libusb 0.1 implementation */ case -EPERM: /* Operation not permitted */ fatal_with_errno(EXIT_FAILURE, "Permissions problem"); # ifndef HAVE___ATTRIBUTE__NORETURN exit(EXIT_FAILURE); /* Should not get here in practice, but compiler is afraid we can fall through */ # endif #endif case LIBUSB_ERROR_PIPE: /* Broken pipe */ if (usb_clear_halt(udev, 0x81) == 0) { upsdebugx(1, "Stall condition cleared"); break; } #if (defined ETIME) && ETIME && WITH_LIBUSB_0_1 goto fallthrough_case_etime; case -ETIME: /* Timer expired */ fallthrough_case_etime: #endif if (usb_reset(udev) == 0) { upsdebugx(1, "Device reset handled"); } goto fallthrough_case_reconnect; case LIBUSB_ERROR_NO_DEVICE: /* No such device */ case LIBUSB_ERROR_ACCESS: /* Permission denied */ case LIBUSB_ERROR_IO: /* I/O error */ #if WITH_LIBUSB_0_1 /* limit to libusb 0.1 implementation */ case -ENXIO: /* No such device or address */ #endif case LIBUSB_ERROR_NOT_FOUND: /* No such file or directory */ fallthrough_case_reconnect: /* Uh oh, got to reconnect! */ dstate_setinfo("driver.state", "reconnect.trying"); usb->close_dev(udev); udev = NULL; break; case LIBUSB_ERROR_TIMEOUT: /* Connection timed out */ upsdebugx (3, "riello_command err: Resource temporarily unavailable"); break; #ifndef WIN32 /* libusb win32 does not know EPROTO and EOVERFLOW, * it only returns EIO for any IO errors */ case LIBUSB_ERROR_OVERFLOW: /* Value too large for defined data type */ # if EPROTO && WITH_LIBUSB_0_1 case -EPROTO: /* Protocol error */ # endif break; #endif default: break; } return ret; } static int get_ups_nominal(void) { uint8_t length; int recv; length = riello_prepare_gn(&bufOut[0], gpser_error_control); recv = riello_command(&bufOut[0], &bufIn[0], length, LENGTH_GN); if (recv < 0){ upsdebugx (3, "Get nominal err: read byte: %d", recv); return recv; } if (!wait_packet && foundbadcrc) { upsdebugx (3, "Get nominal Ko: bad CRC or Checksum"); return -1; } /* mandatory */ if (!wait_packet && foundnak) { upsdebugx (3, "Get nominal Ko: command not supported"); return -1; } upsdebugx (3, "Get nominal Ok: read byte: %d", recv); riello_parse_gn(&bufIn[0], &DevData); return 0; } static int get_ups_status(void) { uint8_t numread, length; int recv; length = riello_prepare_rs(&bufOut[0], gpser_error_control); if (input_monophase) numread = LENGTH_RS_MM; else if (output_monophase) numread = LENGTH_RS_TM; else numread = LENGTH_RS_TT; recv = riello_command(&bufOut[0], &bufIn[0], length, numread); if (recv < 0){ upsdebugx (3, "Get status err: read byte: %d", recv); return recv; } if (!wait_packet && foundbadcrc) { upsdebugx (3, "Get status Ko: bad CRC or Checksum"); return -1; } /* mandatory */ if (!wait_packet && foundnak) { upsdebugx (3, "Get status Ko: command not supported"); return -1; } upsdebugx (3, "Get status Ok: read byte: %d", recv); riello_parse_rs(&bufIn[0], &DevData, numread); return 0; } static int get_ups_extended(void) { uint8_t length; int recv; length = riello_prepare_re(&bufOut[0], gpser_error_control); recv = riello_command(&bufOut[0], &bufIn[0], length, LENGTH_RE); if (recv < 0){ upsdebugx (3, "Get extended err: read byte: %d", recv); return recv; } if (!wait_packet && foundbadcrc) { upsdebugx (3, "Get extended Ko: bad CRC or Checksum"); return -1; } /* optional */ if (!wait_packet && foundnak) { upsdebugx (3, "Get extended Ko: command not supported"); return 0; } upsdebugx (3, "Get extended Ok: read byte: %d", recv); riello_parse_re(&bufIn[0], &DevData); return 0; } /* Not static, exposed via header. Not used though, currently... */ int get_ups_statuscode(void) { uint8_t length; int recv; length = riello_prepare_rc(&bufOut[0], gpser_error_control); recv = riello_command(&bufOut[0], &bufIn[0], length, LENGTH_RC); if (recv < 0){ upsdebugx (3, "Get statuscode err: read byte: %d", recv); return recv; } if (!wait_packet && foundbadcrc) { upsdebugx (3, "Get statuscode Ko: bad CRC or Checksum"); return -1; } /* optional */ if (!wait_packet && foundnak) { upsdebugx (3, "Get statuscode Ko: command not supported"); return 0; } upsdebugx (3, "Get statuscode Ok: read byte: %d", recv); riello_parse_rc(&bufIn[0], &DevData); return 0; } static int riello_instcmd(const char *cmdname, const char *extra) { uint8_t length; int recv; uint16_t delay; const char *delay_char; if (!riello_test_bit(&DevData.StatusCode[0], 1)) { if (!strcasecmp(cmdname, "load.off")) { delay = 0; length = riello_prepare_cs(bufOut, gpser_error_control, delay); recv = riello_command(&bufOut[0], &bufIn[0], length, LENGTH_DEF); if (recv < 0) { upsdebugx (3, "Command load.off err: read byte: %d", recv); return STAT_INSTCMD_FAILED; } if (!wait_packet && foundbadcrc) { upsdebugx (3, "Command load.off Ko: bad CRC or Checksum"); return STAT_INSTCMD_FAILED; } if (!wait_packet && foundnak) { upsdebugx (3, "Command load.off Ko: command not supported"); return STAT_INSTCMD_FAILED; } upsdebugx (3, "Command load.off Ok: read byte: %d", recv); return STAT_INSTCMD_HANDLED; } if (!strcasecmp(cmdname, "load.off.delay")) { int ipv; delay_char = dstate_getinfo("ups.delay.shutdown"); ipv = atoi(delay_char); /* With a "char" in the name, might assume we fit... but :) */ if (ipv < 0 || (intmax_t)ipv > (intmax_t)UINT16_MAX) return STAT_INSTCMD_FAILED; delay = (uint16_t)ipv; length = riello_prepare_cs(bufOut, gpser_error_control, delay); recv = riello_command(&bufOut[0], &bufIn[0], length, LENGTH_DEF); if (recv < 0) { upsdebugx (3, "Command load.off.delay err: read byte: %d", recv); return STAT_INSTCMD_FAILED; } if (!wait_packet && foundbadcrc) { upsdebugx (3, "Command load.off.delay Ko: bad CRC or Checksum"); return STAT_INSTCMD_FAILED; } if (!wait_packet && foundnak) { upsdebugx (3, "Command load.off.delay Ko: command not supported"); return STAT_INSTCMD_FAILED; } upsdebugx (3, "Command load.off.delay Ok: read byte: %d", recv); return STAT_INSTCMD_HANDLED; } if (!strcasecmp(cmdname, "load.on")) { delay = 0; length = riello_prepare_cr(bufOut, gpser_error_control, delay); recv = riello_command(&bufOut[0], &bufIn[0], length, LENGTH_DEF); if (recv < 0) { upsdebugx (3, "Command load.on err: read byte: %d", recv); return STAT_INSTCMD_FAILED; } if (!wait_packet && foundbadcrc) { upsdebugx (3, "Command load.on Ko: bad CRC or Checksum"); return STAT_INSTCMD_FAILED; } if (!wait_packet && foundnak) { upsdebugx (3, "Command load.on Ko: command not supported"); return STAT_INSTCMD_FAILED; } upsdebugx (3, "Command load.on Ok: read byte: %d", recv); return STAT_INSTCMD_HANDLED; } if (!strcasecmp(cmdname, "load.on.delay")) { int ipv; delay_char = dstate_getinfo("ups.delay.reboot"); ipv = atoi(delay_char); /* With a "char" in the name, might assume we fit... but :) */ if (ipv < 0 || (intmax_t)ipv > (intmax_t)UINT16_MAX) return STAT_INSTCMD_FAILED; delay = (uint16_t)ipv; length = riello_prepare_cr(bufOut, gpser_error_control, delay); recv = riello_command(&bufOut[0], &bufIn[0], length, LENGTH_DEF); if (recv < 0) { upsdebugx (3, "Command load.on.delay err: read byte: %d", recv); return STAT_INSTCMD_FAILED; } if (!wait_packet && foundbadcrc) { upsdebugx (3, "Command load.on.delay Ko: bad CRC or Checksum"); return STAT_INSTCMD_FAILED; } if (!wait_packet && foundnak) { upsdebugx (3, "Command load.on.delay Ko: command not supported"); return STAT_INSTCMD_FAILED; } upsdebugx (3, "Command load.on.delay Ok: read byte: %d", recv); return STAT_INSTCMD_HANDLED; } } else { if (!strcasecmp(cmdname, "shutdown.return")) { int ipv; delay_char = dstate_getinfo("ups.delay.shutdown"); ipv = atoi(delay_char); /* With a "char" in the name, might assume we fit... but :) */ if (ipv < 0 || (intmax_t)ipv > (intmax_t)UINT16_MAX) return STAT_INSTCMD_FAILED; delay = (uint16_t)ipv; length = riello_prepare_cs(bufOut, gpser_error_control, delay); recv = riello_command(&bufOut[0], &bufIn[0], length, LENGTH_DEF); if (recv < 0) { upsdebugx (3, "Command shutdown.return err: read byte: %d", recv); return STAT_INSTCMD_FAILED; } if (!wait_packet && foundbadcrc) { upsdebugx (3, "Command shutdown.return Ko: bad CRC or Checksum"); return STAT_INSTCMD_FAILED; } if (!wait_packet && foundnak) { upsdebugx (3, "Command shutdown.return Ko: command not supported"); return STAT_INSTCMD_FAILED; } upsdebugx (3, "Command shutdown.return Ok: read byte: %d", recv); return STAT_INSTCMD_HANDLED; } } if (!strcasecmp(cmdname, "shutdown.stop")) { length = riello_prepare_cd(bufOut, gpser_error_control); recv = riello_command(&bufOut[0], &bufIn[0], length, LENGTH_DEF); if (recv < 0) { upsdebugx (3, "Command shutdown.stop err: read byte: %d", recv); return STAT_INSTCMD_FAILED; } if (!wait_packet && foundbadcrc) { upsdebugx (3, "Command shutdown.stop Ko: bad CRC or Checksum"); return STAT_INSTCMD_FAILED; } if (!wait_packet && foundnak) { upsdebugx (3, "Command shutdown.stop Ko: command not supported"); return STAT_INSTCMD_FAILED; } upsdebugx (3, "Command shutdown.stop Ok: read byte: %d", recv); return STAT_INSTCMD_HANDLED; } if (!strcasecmp(cmdname, "test.panel.start")) { length = riello_prepare_tp(bufOut, gpser_error_control); recv = riello_command(&bufOut[0], &bufIn[0], length, LENGTH_DEF); if (recv < 0) { upsdebugx (3, "Command test.panel.start err: read byte: %d", recv); return STAT_INSTCMD_FAILED; } if (!wait_packet && foundbadcrc) { upsdebugx (3, "Command test.panel.start Ko: bad CRC or Checksum"); return STAT_INSTCMD_FAILED; } if (!wait_packet && foundnak) { upsdebugx (3, "Command test.panel.start Ko: command not supported"); return STAT_INSTCMD_FAILED; } upsdebugx (3, "Command test.panel.start Ok: read byte: %d", recv); return STAT_INSTCMD_HANDLED; } if (!strcasecmp(cmdname, "test.battery.start")) { length = riello_prepare_tb(bufOut, gpser_error_control); recv = riello_command(&bufOut[0], &bufIn[0], length, LENGTH_DEF); if (recv < 0) { upsdebugx (3, "Command test.battery.start err: read byte: %d", recv); return STAT_INSTCMD_FAILED; } if (!wait_packet && foundbadcrc) { upsdebugx (3, "Command test.battery.start Ko: bad CRC or Checksum"); return STAT_INSTCMD_FAILED; } if (!wait_packet && foundnak) { upsdebugx (3, "Command test.battery.start Ko: command not supported"); return STAT_INSTCMD_FAILED; } upsdebugx (3, "Command test.battery.start Ok: read byte: %d", recv); return STAT_INSTCMD_HANDLED; } upslogx(LOG_NOTICE, "instcmd: unknown command [%s] [%s]", cmdname, extra); return STAT_INSTCMD_UNKNOWN; } static int start_ups_comm(void) { uint16_t length; int recv; upsdebugx (2, "entering start_ups_comm()\n"); cypress_setfeatures(); length = riello_prepare_gi(&bufOut[0]); recv = riello_command(&bufOut[0], &bufIn[0], length, LENGTH_GI); if (recv < 0) { upsdebugx (3, "Get identif err: read byte: %d", recv); return recv; } if (!wait_packet && foundbadcrc) { upsdebugx (3, "Get identif Ko: bad CRC or Checksum"); return 1; } if (!wait_packet && foundnak) { upsdebugx (3, "Get identif Ko: command not supported"); return 1; } upsdebugx (3, "Get identif Ok: read byte: %u", recv); return 0; } void upsdrv_help(void) { } void upsdrv_makevartable(void) { /* allow -x vendor=X, vendorid=X, product=X, productid=X, serial=X */ nut_usb_addvars(); } void upsdrv_initups(void) { const struct { const char *name; int (*command)(uint8_t *cmd, uint8_t *buf, uint16_t length, uint16_t buflen); } subdriver[] = { { "cypress", &cypress_command }, { NULL, NULL } }; int ret; char *regex_array[USBMATCHER_REGEXP_ARRAY_LIMIT]; char *subdrv = getval("subdriver"); warn_if_bad_usb_port_filename(device_path); regex_array[0] = getval("vendorid"); regex_array[1] = getval("productid"); regex_array[2] = getval("vendor"); regex_array[3] = getval("product"); regex_array[4] = getval("serial"); regex_array[5] = getval("bus"); regex_array[6] = getval("device"); #if (defined WITH_USB_BUSPORT) && (WITH_USB_BUSPORT) regex_array[7] = getval("busport"); #else if (getval("busport")) { upslogx(LOG_WARNING, "\"busport\" is configured for the device, but is not actually handled by current build combination of NUT and libusb (ignored)"); } #endif /* pick up the subdriver name if set explicitly */ if (subdrv) { int i; if (!regex_array[0] || !regex_array[1]) { fatalx(EXIT_FAILURE, "When specifying a subdriver, 'vendorid' and 'productid' are mandatory."); } for (i = 0; subdriver[i].name; i++) { if (strcasecmp(subdrv, subdriver[i].name)) { continue; } subdriver_command = subdriver[i].command; break; } if (!subdriver_command) { fatalx(EXIT_FAILURE, "Subdriver \"%s\" not found!", subdrv); } } ret = USBNewRegexMatcher(®ex_matcher, regex_array, REG_ICASE | REG_EXTENDED); switch (ret) { case -1: fatal_with_errno(EXIT_FAILURE, "USBNewRegexMatcher"); case 0: break; /* all is well */ default: fatalx(EXIT_FAILURE, "invalid regular expression: %s", regex_array[ret]); } /* link the matchers */ regex_matcher->next = &device_matcher; ret = usb->open_dev(&udev, &usbdevice, regex_matcher, &driver_callback); if (ret < 0) { fatalx(EXIT_FAILURE, "No supported devices found. Please check your device availability with 'lsusb'\n" "and make sure you have an up-to-date version of NUT. If this does not help,\n" "try running the driver with at least 'subdriver', 'vendorid' and 'productid'\n" "options specified. Please refer to the man page for details about these options\n" "(man 8 riello_usb).\n"); } if (!subdriver_command) { fatalx(EXIT_FAILURE, "No subdriver selected"); } /* create a new matcher for later reopening */ ret = USBNewExactMatcher(&reopen_matcher, &usbdevice); if (ret) { fatal_with_errno(EXIT_FAILURE, "USBNewExactMatcher"); } /* link the matchers */ reopen_matcher->next = regex_matcher; dstate_setinfo("ups.vendorid", "%04x", usbdevice.VendorID); dstate_setinfo("ups.productid", "%04x", usbdevice.ProductID); } void upsdrv_initinfo(void) { int ret; ret = start_ups_comm(); if (ret < 0) fatalx(EXIT_FAILURE, "No communication with UPS"); else if (ret > 0) fatalx(EXIT_FAILURE, "Bad checksum or NACK"); else upsdebugx(2, "Communication with UPS established"); riello_parse_gi(&bufIn[0], &DevData); gpser_error_control = DevData.Identif_bytes[4]-0x30; if ((DevData.Identif_bytes[0] == '1') || (DevData.Identif_bytes[0] == '2')) input_monophase = 1; else { input_monophase = 0; dstate_setinfo("input.phases", "%u", 3); dstate_setinfo("input.phases", "%u", 3); dstate_setinfo("input.bypass.phases", "%u", 3); } if ((DevData.Identif_bytes[0] == '1') || (DevData.Identif_bytes[0] == '3')) output_monophase = 1; else { output_monophase = 0; dstate_setinfo("output.phases", "%u", 3); } dstate_setinfo("device.mfr", "RPS S.p.a."); dstate_setinfo("device.model", "%s", (unsigned char*) DevData.ModelStr); dstate_setinfo("device.serial", "%s", (unsigned char*) DevData.Identification); dstate_setinfo("device.type", "ups"); dstate_setinfo("ups.mfr", "RPS S.p.a."); dstate_setinfo("ups.model", "%s", (unsigned char*) DevData.ModelStr); dstate_setinfo("ups.serial", "%s", (unsigned char*) DevData.Identification); dstate_setinfo("ups.firmware", "%s", (unsigned char*) DevData.Version); if (get_ups_nominal() == 0) { dstate_setinfo("ups.realpower.nominal", "%u", DevData.NomPowerKW); dstate_setinfo("ups.power.nominal", "%u", DevData.NomPowerKVA); dstate_setinfo("output.voltage.nominal", "%u", DevData.NominalUout); dstate_setinfo("output.frequency.nominal", "%.1f", DevData.NomFout/10.0); dstate_setinfo("battery.voltage.nominal", "%u", DevData.NomUbat); dstate_setinfo("battery.capacity", "%u", DevData.NomBatCap); } /* commands ----------------------------------------------- */ dstate_addcmd("load.off"); dstate_addcmd("load.on"); dstate_addcmd("load.off.delay"); dstate_addcmd("load.on.delay"); dstate_addcmd("shutdown.return"); dstate_addcmd("shutdown.stop"); dstate_addcmd("test.battery.start"); dstate_addcmd("test.panel.start"); dstate_setinfo("ups.delay.shutdown", "%u", offdelay); dstate_setflags("ups.delay.shutdown", ST_FLAG_RW | ST_FLAG_STRING); dstate_setaux("ups.delay.shutdown", 3); dstate_setinfo("ups.delay.reboot", "%u", bootdelay); dstate_setflags("ups.delay.reboot", ST_FLAG_RW | ST_FLAG_STRING); dstate_setaux("ups.delay.reboot", 3); /* install handlers */ /* upsh.setvar = hid_set_value; setvar; */ /* note: for a transition period, these data are redundant! */ /* dstate_setinfo("device.mfr", "skel manufacturer"); */ /* dstate_setinfo("device.model", "longrun 15000"); */ upsh.instcmd = riello_instcmd; } void upsdrv_shutdown(void) { /* tell the UPS to shut down, then return - DO NOT SLEEP HERE */ int retry; /* maybe try to detect the UPS here, but try a shutdown even if it doesn't respond at first if possible */ /* replace with a proper shutdown function */ /* you may have to check the line status since the commands for toggling power are frequently different for OL vs. OB */ /* OL: this must power cycle the load if possible */ /* OB: the load must remain off until the power returns */ for (retry = 1; retry <= MAXTRIES; retry++) { if (riello_instcmd("shutdown.stop", NULL) != STAT_INSTCMD_HANDLED) { continue; } if (riello_instcmd("shutdown.return", NULL) != STAT_INSTCMD_HANDLED) { continue; } upslogx(LOG_ERR, "Shutting down"); set_exit_flag(-2); /* EXIT_SUCCESS */ return; } upslogx(LOG_ERR, "Shutdown failed!"); set_exit_flag(-1); } void upsdrv_updateinfo(void) { uint8_t getextendedOK; static int countlost = 0; int stat; upsdebugx(1, "countlost %d",countlost); if (countlost > 0){ upsdebugx(1, "Communication with UPS is lost: status read failed!"); if (countlost == COUNTLOST) { dstate_datastale(); upslogx(LOG_WARNING, "Communication with UPS is lost: status read failed!"); } } stat = get_ups_status(); upsdebugx(1, "get_ups_status() %d",stat ); if (stat < 0) { if (countlost < COUNTLOST) countlost++; return; } if (get_ups_extended() == 0) getextendedOK = 1; else getextendedOK = 0; if (countlost == COUNTLOST) upslogx(LOG_NOTICE, "Communication with UPS is re-established!"); dstate_setinfo("input.frequency", "%.2f", DevData.Finp/10.0); dstate_setinfo("input.bypass.frequency", "%.2f", DevData.Fbypass/10.0); dstate_setinfo("output.frequency", "%.2f", DevData.Fout/10.0); dstate_setinfo("battery.voltage", "%.1f", DevData.Ubat/10.0); if ((DevData.BatCap < 0xFFFF) && (DevData.BatTime < 0xFFFF)) { dstate_setinfo("battery.charge", "%u", DevData.BatCap); dstate_setinfo("battery.runtime", "%u", DevData.BatTime*60); } if (DevData.Tsystem < 0xFF) dstate_setinfo("ups.temperature", "%u", DevData.Tsystem); if (input_monophase) { dstate_setinfo("input.voltage", "%u", DevData.Uinp1); dstate_setinfo("input.bypass.voltage", "%u", DevData.Ubypass1); } else { dstate_setinfo("input.L1-N.voltage", "%u", DevData.Uinp1); dstate_setinfo("input.L2-N.voltage", "%u", DevData.Uinp2); dstate_setinfo("input.L3-N.voltage", "%u", DevData.Uinp3); dstate_setinfo("input.bypass.L1-N.voltage", "%u", DevData.Ubypass1); dstate_setinfo("input.bypass.L2-N.voltage", "%u", DevData.Ubypass2); dstate_setinfo("input.bypass.L3-N.voltage", "%u", DevData.Ubypass3); } if (output_monophase) { dstate_setinfo("output.voltage", "%u", DevData.Uout1); dstate_setinfo("output.power.percent", "%u", DevData.Pout1); dstate_setinfo("ups.load", "%u", DevData.Pout1); } else { dstate_setinfo("output.L1-N.voltage", "%u", DevData.Uout1); dstate_setinfo("output.L2-N.voltage", "%u", DevData.Uout2); dstate_setinfo("output.L3-N.voltage", "%u", DevData.Uout3); dstate_setinfo("output.L1.power.percent", "%u", DevData.Pout1); dstate_setinfo("output.L2.power.percent", "%u", DevData.Pout2); dstate_setinfo("output.L3.power.percent", "%u", DevData.Pout3); dstate_setinfo("ups.load", "%u", (DevData.Pout1+DevData.Pout2+DevData.Pout3)/3); } status_init(); /* AC Fail */ if (riello_test_bit(&DevData.StatusCode[0], 1)) status_set("OB"); else status_set("OL"); /* LowBatt */ if ((riello_test_bit(&DevData.StatusCode[0], 1)) && (riello_test_bit(&DevData.StatusCode[0], 0))) status_set("LB"); /* Standby */ if (!riello_test_bit(&DevData.StatusCode[0], 3)) status_set("OFF"); /* On Bypass */ if (riello_test_bit(&DevData.StatusCode[1], 3)) status_set("BYPASS"); /* Overload */ if (riello_test_bit(&DevData.StatusCode[4], 2)) status_set("OVER"); /* Buck */ if (riello_test_bit(&DevData.StatusCode[1], 0)) status_set("TRIM"); /* Boost */ if (riello_test_bit(&DevData.StatusCode[1], 1)) status_set("BOOST"); /* Replace battery */ if (riello_test_bit(&DevData.StatusCode[2], 0)) status_set("RB"); /* Charging battery */ if (riello_test_bit(&DevData.StatusCode[2], 2)) status_set("CHRG"); status_commit(); dstate_dataok(); if (getextendedOK) { dstate_setinfo("output.L1.power", "%u", DevData.Pout1VA); dstate_setinfo("output.L2.power", "%u", DevData.Pout2VA); dstate_setinfo("output.L3.power", "%u", DevData.Pout3VA); dstate_setinfo("output.L1.realpower", "%u", DevData.Pout1W); dstate_setinfo("output.L2.realpower", "%u", DevData.Pout2W); dstate_setinfo("output.L3.realpower", "%u", DevData.Pout3W); dstate_setinfo("output.L1.current", "%u", DevData.Iout1); dstate_setinfo("output.L2.current", "%u", DevData.Iout2); dstate_setinfo("output.L3.current", "%u", DevData.Iout3); } poll_interval = 2; countlost = 0; /* if (get_ups_statuscode() != 0) upsdebugx(2, "Communication is lost"); else { }*/ /* * ret = ser_get_line(upsfd, temp, sizeof(temp), ENDCHAR, IGNCHARS); * * if (ret < STATUS_LEN) { * upslogx(LOG_ERR, "Short read from UPS"); * dstate_datastale(); * return; * } */ /* dstate_setinfo("var.name", ""); */ /* if (ioctl(upsfd, TIOCMGET, &flags)) { * upslog_with_errno(LOG_ERR, "TIOCMGET"); * dstate_datastale(); * return; * } */ /* status_init(); * * if (ol) * status_set("OL"); * else * status_set("OB"); * ... * * status_commit(); * * dstate_dataok(); */ /* * poll_interval = 2; */ } void upsdrv_cleanup(void) { usb->close_dev(udev); USBFreeExactMatcher(reopen_matcher); USBFreeRegexMatcher(regex_matcher); free(usbdevice.Vendor); free(usbdevice.Product); free(usbdevice.Serial); free(usbdevice.Bus); free(usbdevice.Device); #if (defined WITH_USB_BUSPORT) && (WITH_USB_BUSPORT) free(usbdevice.BusPort); #endif } nut-2.8.1/drivers/huawei-mib.h0000644000175000017500000000021514273170601013126 00000000000000#ifndef HUAWEI_MIB_H #define HUAWEI_MIB_H #include "main.h" #include "snmp-ups.h" extern mib2nut_info_t huawei; #endif /* HUAWEI_MIB_H */ nut-2.8.1/drivers/gamatronic.c0000644000175000017500000002423414501607135013226 00000000000000/* gamatronic.c * * SEC UPS Driver ported to the new NUT API for Gamatronic UPS Usage. * * TODO: Replace lots of printf() by upslogx() or upsdebugx() below! * * Copyright (C) * 2001 John Marley * 2002 Jules Taplin * 2002 Eric Lawson * 2005 Arnaud Quette * 2005 Nadav Moskovitch * * 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 2 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, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #include "main.h" #include "serial.h" #include "gamatronic.h" #include "nut_stdint.h" #define DRIVER_NAME "Gamatronic UPS driver" #define DRIVER_VERSION "0.04" /* driver description structure */ upsdrv_info_t upsdrv_info = { DRIVER_NAME, DRIVER_VERSION, "John Marley \n" \ "Jules Taplin \n" \ "Eric Lawson \n" \ "Arnaud Quette \n" \ "Nadav Moskovitch ", DRV_STABLE, { NULL } }; #define ENDCHAR '\r' #define IGNCHARS "" #define SER_WAIT_SEC 1 /* allow 3.0 sec for ser_get calls */ #define SER_WAIT_USEC 0 static int sec_upsrecv (char *buf) { char lenbuf[4]; int ret; ser_get_line(upsfd, buf, 140, ENDCHAR, IGNCHARS,SER_WAIT_SEC, SER_WAIT_USEC); if (buf[0] == SEC_MSG_STARTCHAR) { switch (buf[1]) { case SEC_NAK: return(-1); case SEC_ACK: return(0); case SEC_DATAMSG: strncpy(lenbuf, buf+2, 3); lenbuf[3] = '\0'; ret = atoi(lenbuf); if (ret > 0) { strcpy(buf,buf+5); return(ret); } else return (-2); default: return(-2); } } else return (-2); } static ssize_t sec_cmd(const char mode, const char *command, char *msgbuf, ssize_t *buflen) { char msg[140]; ssize_t ret; memset(msg, 0, sizeof(msg)); /* create the message string */ if (*buflen > 0) { snprintf(msg, sizeof(msg), "%c%c%03zd%s%s", SEC_MSG_STARTCHAR, mode, (*buflen)+3, command, msgbuf); } else { snprintf(msg, sizeof(msg), "%c%c003%s", SEC_MSG_STARTCHAR, mode, command); } upsdebugx(1, "PC-->UPS: \"%s\"",msg); ret = ser_send(upsfd, "%s", msg); upsdebugx(1, " send returned: %" PRIiSIZE, ret); if (ret == -1) return -1; ret = sec_upsrecv(msg); if (ret < 0) return -1; strncpy(msgbuf, msg, (size_t)ret); upsdebugx(1, "UPS<--PC: \"%s\"",msg); /* *(msgbuf+ret) = '\0'; */ *buflen = ret; return ret; } static void addquery(const char *cmd, int field, int varnum, int pollflag) { int q; for (q=0; q 0) { if (strcmp(sec_varlist[sqv(q,f)].value, r) != 0) { #ifdef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_FORMAT_TRUNCATION #pragma GCC diagnostic push #endif #ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_FORMAT_TRUNCATION #pragma GCC diagnostic ignored "-Wformat-truncation" #endif /* NOTE: We intentionally limit the amount * of characters picked from "r" buffer * into respectively sized "*.value" */ int len = snprintf(sec_varlist[sqv(q,f)].value, sizeof(sec_varlist[sqv(q,f)].value), "%s", r); if (len < 0) { upsdebugx(1, "%s: got an error while extracting value", __func__); } if ((intmax_t)len > (intmax_t)sizeof(sec_varlist[sqv(q,f)].value) || (intmax_t)strnlen(r, sizeof(retbuf)) > (intmax_t)sizeof(sec_varlist[sqv(q,f)].value) ) { upsdebugx(1, "%s: value was truncated", __func__); } #ifdef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_FORMAT_TRUNCATION #pragma GCC diagnostic pop #endif sec_setinfo(sqv(q,f), r); } /* If SEC VAR is alarm and it's on, add it to the alarm property */ if (sec_varlist[sqv(q,f)].flags & FLAG_ALARM && strcmp(r,"1")== 0) { alarm_set(sec_varlist[sqv(q,f)].name); } } if (n == NULL) break; r = n+1; } } } void upsdrv_initinfo(void) { ssize_t msglen; int v; char *a, *p, avail_list[300]; /* find out which variables/commands this UPS supports */ msglen = 0; sec_cmd(SEC_POLLCMD, SEC_AVAILP1, avail_list, &msglen); p = avail_list + msglen; if (p != avail_list) *p++ = ','; msglen = 0; sec_cmd(SEC_POLLCMD, SEC_AVAILP2, p, &msglen); *(p+msglen) = '\0'; if (strlen(avail_list) == 0) { fatalx(EXIT_FAILURE, "No available variables found!"); } a = avail_list; while ((p = strtok(a, ",")) != NULL) { a = NULL; v = atoi(p); /* don't bother adding a write-only variable */ if (sec_varlist[v].flags == FLAG_WONLY) continue; addquery(sec_varlist[v].cmd, sec_varlist[v].field, v, sec_varlist[v].poll); } /* poll one time values */ sec_poll(FLAG_POLLONCE); printf("UPS: %s %s\n", dstate_getinfo("ups.mfr"), dstate_getinfo("ups.model")); } void upsdrv_updateinfo(void) { alarm_init(); /* poll status values values */ sec_poll(FLAG_POLL); alarm_commit(); update_pseudovars(); dstate_dataok(); } void upsdrv_shutdown(void) { ssize_t msglen; char msgbuf[SMALLBUF]; msglen = snprintf(msgbuf, sizeof(msgbuf), "-1"); sec_cmd(SEC_SETCMD, SEC_SHUTDOWN, msgbuf, &msglen); msglen = snprintf(msgbuf, sizeof(msgbuf), "1"); sec_cmd(SEC_SETCMD, SEC_AUTORESTART, msgbuf, &msglen); msglen = snprintf(msgbuf, sizeof(msgbuf), "2"); sec_cmd(SEC_SETCMD, SEC_SHUTTYPE,msgbuf, &msglen); msglen = snprintf(msgbuf, sizeof(msgbuf), "5"); sec_cmd(SEC_SETCMD, SEC_SHUTDOWN, msgbuf, &msglen); } /* int instcmd(const char *cmdname, const char *extra) { if (!strcasecmp(cmdname, "test.battery.stop")) { ser_send_buf(upsfd, ...); return STAT_INSTCMD_HANDLED; } upslogx(LOG_NOTICE, "instcmd: unknown command [%s]", cmdname); return STAT_INSTCMD_UNKNOWN; } */ void upsdrv_help(void) { } /* list flags and values that you want to receive via -x */ void upsdrv_makevartable(void) { /* allow '-x xyzzy' */ /* addvar(VAR_FLAG, "xyzzy", "Enable xyzzy mode"); */ /* allow '-x foo=' */ /* addvar(VAR_VALUE, "foo", "Override foo setting"); */ } static void setup_serial(const char *port) { char temp[140]; int i; ssize_t ret; /* Detect the ups baudrate */ for (i=0; i<5; i++) { ser_set_speed(upsfd, device_path, baud_rates[i].rate); ret = ser_send(upsfd, "^P003MAN"); ret = sec_upsrecv(temp); if (ret >= -1) break; } if (i == 5) { printf("Can't talk to UPS on port %s!\n",port); printf("Check the cabling and portname and try again\n"); printf("Please note that this driver only support UPS Models with SEC Protocol\n"); ser_close(upsfd, device_path); exit (1); } else printf("Connected to UPS on %s baudrate: %" PRIuSIZE "\n", port, baud_rates[i].name); } void upsdrv_initups(void) { upsfd = ser_open(device_path); setup_serial(device_path); /* upsfd = ser_open(device_path); */ /* ser_set_speed(upsfd, device_path, B1200); */ /* probe ups type */ /* to get variables and flags from the command line, use this: * * first populate with upsdrv_buildvartable above, then... * * set flag foo : /bin/driver -x foo * set variable 'cable' to '1234' : /bin/driver -x cable=1234 * * to test flag foo in your code: * * if (testvar("foo")) * do_something(); * * to show the value of cable: * * if ((cable == getval("cable"))) * printf("cable is set to %s\n", cable); * else * printf("cable is not set!\n"); * * don't use NULL pointers - test the return result first! */ /* the upsh handlers can't be done here, as they get initialized * shortly after upsdrv_initups returns to main. */ } void upsdrv_cleanup(void) { /* free(dynamic_mem); */ ser_close(upsfd, device_path); } nut-2.8.1/drivers/eaton-pdu-pulizzi-mib.c0000644000175000017500000001564714501607135015257 00000000000000/* eaton-pdu-pulizzi-mib.c - data to monitor Eaton ePDUs branded as: * G1 Pulizzi Monitored and Switched ePDUs * * Copyright (C) 2008 - 2017 * Arnaud Quette * Arnaud Quette * Copyright (C) 2015 - 2017 * Jim Klimov * * Supported by Eaton * and previously MGE Office Protection Systems * * 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 2 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, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #include "eaton-pdu-pulizzi-mib.h" /* Pulizzi Monitored ePDU (Basic model, SNMP only) * FIXME: to be completed * * Warning: there are 2 versions: * - SA built MI.mib (old MIB) * #define PULIZZI1_OID_MIB ".1.3.6.1.4.1.20677.3.1.1" * #define PULIZZI1_OID_MODEL_NAME ".1.3.6.1.4.1.20677.3.1.1.1.2.0" * - Eaton-Powerware-Monitored-ePDU_1.0.E.mib (new MIB) Vertical SW */ /* Pulizzi Switched ePDU */ #define EATON_PULIZZI_SW_MIB_VERSION "0.5" #define PULIZZI_SW_OID_MIB ".1.3.6.1.4.1.20677.3.1.1" #define PULIZZI_SW_OID_MODEL_NAME ".1.3.6.1.4.1.20677.2.1.1.0" /* Some buggy FW also report sysOID = ".1.3.6.1.4.1.20677.1" */ #define EATON_PULIZZI_SWITCHED1_SYSOID ".1.3.6.1.4.1.20677.1" #define EATON_PULIZZI_SWITCHED2_SYSOID ".1.3.6.1.4.1.20677.2" static info_lkp_t pulizzi_sw_outlet_status_info[] = { { 1, "on", NULL, NULL }, { 2, "off", NULL, NULL }, { 0, NULL, NULL, NULL } }; /* simply remap the above status to "yes" */ static info_lkp_t pulizzi_sw_outlet_switchability_info[] = { { 1, "yes", NULL, NULL }, { 2, "yes", NULL, NULL }, { 0, NULL, NULL, NULL } }; /* Snmp2NUT lookup table for Eaton Pulizzi Switched ePDU MIB */ static snmp_info_t eaton_pulizzi_switched_mib[] = { /* standard MIB items */ { "device.description", ST_FLAG_STRING | ST_FLAG_RW, SU_INFOSIZE, ".1.3.6.1.2.1.1.1.0", NULL, SU_FLAG_OK, NULL }, { "device.contact", ST_FLAG_STRING | ST_FLAG_RW, SU_INFOSIZE, ".1.3.6.1.2.1.1.4.0", NULL, SU_FLAG_OK, NULL }, { "device.location", ST_FLAG_STRING | ST_FLAG_RW, SU_INFOSIZE, ".1.3.6.1.2.1.1.6.0", NULL, SU_FLAG_OK, NULL }, /* Device page */ { "device.mfr", ST_FLAG_STRING, SU_INFOSIZE, NULL, "EATON | Powerware", SU_FLAG_STATIC | SU_FLAG_ABSENT | SU_FLAG_OK, NULL }, { "device.model", ST_FLAG_STRING, SU_INFOSIZE, PULIZZI_SW_OID_MODEL_NAME, "Switched ePDU", SU_FLAG_STATIC | SU_FLAG_OK, NULL }, { "device.type", ST_FLAG_STRING, SU_INFOSIZE, NULL, "pdu", SU_FLAG_STATIC | SU_FLAG_ABSENT | SU_FLAG_OK, NULL }, { "device.macaddr", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.20677.2.2.6.0", "unknown", 0, NULL }, /* UPS page */ { "ups.mfr", ST_FLAG_STRING, SU_INFOSIZE, NULL, "EATON", SU_FLAG_STATIC | SU_FLAG_ABSENT | SU_FLAG_OK, NULL }, { "ups.model", ST_FLAG_STRING, SU_INFOSIZE, PULIZZI_SW_OID_MODEL_NAME, "Switched ePDU", SU_FLAG_STATIC | SU_FLAG_OK, NULL }, /* FIXME: to be moved to the device collection! */ { "ups.date", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.20677.2.1.4.0", "", SU_FLAG_STATIC | SU_FLAG_OK, NULL }, { "ups.time", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.20677.2.1.3.0", "", SU_FLAG_STATIC | SU_FLAG_OK, NULL }, /* Outlet page */ /* Note: outlet.count is deduced, with guesstimate_outlet_count() */ { "outlet.id", 0, 1, NULL, "0", SU_FLAG_STATIC | SU_FLAG_ABSENT | SU_FLAG_OK, NULL }, { "outlet.desc", ST_FLAG_RW | ST_FLAG_STRING, 20, NULL, "All outlets", SU_FLAG_STATIC | SU_FLAG_ABSENT | SU_FLAG_OK, NULL }, { "outlet.current", 0, 1.0, ".1.3.6.1.4.1.20677.2.8.6.4.2.0", NULL, 0, NULL }, { "outlet.voltage", 0, 1.0, ".1.3.6.1.4.1.20677.2.8.6.4.1.0", NULL, 0, NULL }, { "outlet.power", 0, 1.0, ".1.3.6.1.4.1.20677.2.8.6.4.3.0", NULL, 0, NULL }, /* outlet template definition * Notes: * - indexes start from 1, ie outlet.1 => .1 * - the first definition is used to determine the base index (ie 0 or 1) * - outlet.count is estimated, based on the below OID iteration capabilities */ { "outlet.%i.desc", ST_FLAG_RW | ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.20677.2.6.1.%i.1.0", NULL, SU_FLAG_STATIC | SU_FLAG_OK | SU_OUTLET, NULL }, { "outlet.%i.status", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.20677.2.6.3.%i.0", NULL, SU_FLAG_OK | SU_OUTLET, &pulizzi_sw_outlet_status_info[0] }, { "outlet.%i.id", 0, 1, NULL, "%i", SU_FLAG_STATIC | SU_FLAG_ABSENT | SU_FLAG_OK | SU_OUTLET, NULL }, /* we use the same OID as outlet.n.status..., to expose switchability */ { "outlet.%i.switchable", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.20677.2.6.3.%i.0", "yes", SU_FLAG_STATIC | SU_FLAG_OK | SU_OUTLET, &pulizzi_sw_outlet_switchability_info[0] }, /* FIXME: need to be added to the namespace! */ { "outlet.%i.delay.reboot", ST_FLAG_RW, 1, ".1.3.6.1.4.1.20677.2.6.1.%i.5.0", NULL, SU_OUTLET, NULL }, /* "outlet1SequenceTime" is used for global sequence */ { "outlet.%i.delay.start", ST_FLAG_RW, 1, ".1.3.6.1.4.1.20677.2.6.1.%i.4.0", NULL, SU_OUTLET, NULL }, /* instant commands. */ /* FIXME: not exposed as "outlet.load...", or otherwise specific processing applies (template instanciation) */ { "load.on", 0, 1, ".1.3.6.1.4.1.20677.2.6.2.1.0", "1", SU_TYPE_CMD, NULL }, { "load.off", 0, 1, ".1.3.6.1.4.1.20677.2.6.2.1.0", "2", SU_TYPE_CMD, NULL }, { "load.on.delay", 0, 1, ".1.3.6.1.4.1.20677.2.6.2.1.0", "3", SU_TYPE_CMD, NULL }, { "load.off.delay", 0, 1, ".1.3.6.1.4.1.20677.2.6.2.1.0", "4", SU_TYPE_CMD, NULL }, /* WARNING: outlet 1 => index 2, so SU_CMD_OFFSET! */ { "outlet.%i.load.on", 0, 1, ".1.3.6.1.4.1.20677.2.6.2.%i.0", "1", SU_TYPE_CMD | SU_OUTLET | SU_CMD_OFFSET, NULL }, { "outlet.%i.load.off", 0, 1, ".1.3.6.1.4.1.20677.2.6.2.%i.0", "2", SU_TYPE_CMD | SU_OUTLET | SU_CMD_OFFSET, NULL }, { "outlet.%i.load.cycle", 0, 1, ".1.3.6.1.4.1.20677.2.6.2.%i.0", "3", SU_TYPE_CMD | SU_OUTLET | SU_CMD_OFFSET, NULL }, /* end of structure. */ { NULL, 0, 0, NULL, NULL, 0, NULL } }; /*mib2nut_info_t pulizzi_monitored = { "pulizzi_monitored", EATON_PULIZZI_MIB_VERSION, NULL, PULIZZI1_OID_MODEL_NAME, eaton_pulizzi_monitored_mib, PULIZZI1_OID_MIB };*/ mib2nut_info_t pulizzi_switched1 = { "pulizzi_switched1", EATON_PULIZZI_SW_MIB_VERSION, NULL, EATON_PULIZZI_SWITCHED1_SYSOID, eaton_pulizzi_switched_mib, EATON_PULIZZI_SWITCHED1_SYSOID, NULL }; mib2nut_info_t pulizzi_switched2 = { "pulizzi_switched2", EATON_PULIZZI_SW_MIB_VERSION, NULL, EATON_PULIZZI_SWITCHED1_SYSOID, eaton_pulizzi_switched_mib, EATON_PULIZZI_SWITCHED2_SYSOID, NULL }; nut-2.8.1/drivers/riello_ser.c0000644000175000017500000007263314517666470013265 00000000000000/* * riello_ser.c: support for Riello serial protocol based UPSes * * A document describing the protocol implemented by this driver can be * found online at "https://www.networkupstools.org/protocols/riello/PSGPSER-0104.pdf" * and "https://www.networkupstools.org/protocols/riello/PSSENTR-0100.pdf". * * Copyright (C) 2012 - Elio Parisi * * 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 2 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, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * Reference of the derivative work: blazer driver */ #include "config.h" /* must be the first header */ #include #ifdef WIN32 # include "wincompat.h" #endif #include "main.h" #include "serial.h" #include "timehead.h" /* // The serial driver has no need for HID structures/code currently // (maybe there is/was a plan for sharing something between siblings). // Note that HID is tied to libusb or libshut definitions at the moment. #include "hidparser.h" #include "hidtypes.h" */ #include "common.h" /* for upsdebugx() etc */ #include "riello.h" #define DRIVER_NAME "Riello serial driver" #define DRIVER_VERSION "0.09" #define DEFAULT_OFFDELAY 5 #define DEFAULT_BOOTDELAY 5 /* driver description structure */ upsdrv_info_t upsdrv_info = { DRIVER_NAME, DRIVER_VERSION, "Elio Parisi ", DRV_EXPERIMENTAL, { NULL } }; static uint8_t bufOut[BUFFER_SIZE]; static uint8_t bufIn[BUFFER_SIZE]; static uint8_t gpser_error_control; static uint8_t typeRielloProtocol; static uint8_t input_monophase; static uint8_t output_monophase; static unsigned int offdelay = DEFAULT_OFFDELAY; static unsigned int bootdelay = DEFAULT_BOOTDELAY; static TRielloData DevData; /********************************************************************** * char_read (char *bytes, size_t size, int read_timeout) * * reads size bytes from the serial port * * bytes - buffer to store the data * size - size of the data to get * read_timeout - serial timeout (in milliseconds) * * return -1 on error, -2 on timeout, nb_bytes_readen on success * * See also select_read() in common.c (TODO: standardize codebase) * *********************************************************************/ static ssize_t char_read (char *bytes, size_t size, int read_timeout) { ssize_t readen = 0; #ifndef WIN32 int rc = 0; struct timeval serial_timeout; fd_set readfs; FD_ZERO (&readfs); FD_SET (upsfd, &readfs); serial_timeout.tv_usec = (read_timeout % 1000) * 1000; serial_timeout.tv_sec = (read_timeout / 1000); rc = select (upsfd + 1, &readfs, NULL, NULL, &serial_timeout); if (0 == rc) return -2; /* timeout */ if (FD_ISSET (upsfd, &readfs)) { #else DWORD timeout; COMMTIMEOUTS TOut; timeout = read_timeout; /* recast */ GetCommTimeouts(upsfd, &TOut); TOut.ReadIntervalTimeout = MAXDWORD; TOut.ReadTotalTimeoutMultiplier = 0; TOut.ReadTotalTimeoutConstant = timeout; SetCommTimeouts(upsfd, &TOut); #endif ssize_t now; #ifndef WIN32 now = read (upsfd, bytes, size - (size_t)readen); #else /* FIXME? for some reason this compiles, but the first * arg to the method should be serial_handler_t* - not * a HANDLE as upsfd is (in main.c)... then again, many * other drivers seem to use it just fine... */ now = w32_serial_read(upsfd, bytes, size - (size_t)readen, timeout); #endif if (now < 0) { return -1; } else { readen += now; } #ifndef WIN32 } else { return -1; } #endif return readen; } /********************************************************************** * serial_read (int read_timeout) * * return data one byte at a time * * read_timeout - serial timeout (in milliseconds) * * returns 0 on success, -1 on error, -2 on timeout * **********************************************************************/ static ssize_t serial_read (int read_timeout, unsigned char *readbuf) { static unsigned char cache[512]; static unsigned char *cachep = cache; static unsigned char *cachee = cache; ssize_t recv; *readbuf = '\0'; /* if still data in cache, get it */ if (cachep < cachee) { *readbuf = *cachep++; return 0; /* return (int) *cachep++; */ } recv = char_read ((char *)cache, 1, read_timeout); if ((recv == -1) || (recv == -2)) return recv; cachep = cache; cachee = cache + recv; cachep = cache; cachee = cache + recv; if (recv) { upsdebugx(5,"received: %02x", *cachep); *readbuf = *cachep++; return 0; } return -1; } static void riello_serialcomm(uint8_t* arg_bufIn, uint8_t typedev) { time_t realt, nowt; uint8_t commb = 0; realt = time(NULL); while (wait_packet) { serial_read(1000, &commb); nowt = time(NULL); commbyte = commb; riello_parse_serialport(typedev, arg_bufIn, gpser_error_control); if ((nowt - realt) > 4) break; } } static int get_ups_nominal(void) { uint8_t length; riello_init_serial(); length = riello_prepare_gn(&bufOut[0], gpser_error_control); if (ser_send_buf(upsfd, bufOut, length) == 0) { upsdebugx (3, "Communication error while writing to port"); return -1; } riello_serialcomm(&bufIn[0], DEV_RIELLOGPSER); if (!wait_packet && foundbadcrc) { upsdebugx (3, "Get nominal Ko: bad CRC or Checksum"); return -1; } /* mandatory */ if (!wait_packet && foundnak) { upsdebugx (3, "Get nominal Ko: command not supported"); return -1; } upsdebugx (3, "Get nominal Ok: received byte %u", buf_ptr_length); riello_parse_gn(&bufIn[0], &DevData); return 0; } static int get_ups_status(void) { uint8_t numread, length; riello_init_serial(); length = riello_prepare_rs(&bufOut[0], gpser_error_control); if (ser_send_buf(upsfd, bufOut, length) == 0) { upsdebugx (3, "Communication error while writing to port"); return -1; } if (input_monophase) numread = LENGTH_RS_MM; else if (output_monophase) numread = LENGTH_RS_TM; else numread = LENGTH_RS_TT; riello_serialcomm(&bufIn[0], DEV_RIELLOGPSER); if (!wait_packet && foundbadcrc) { upsdebugx (3, "Get status Ko: bad CRC or Checksum"); return -1; } /* mandatory */ if (!wait_packet && foundnak) { upsdebugx (3, "Get status Ko: command not supported"); return -1; } upsdebugx (3, "Get status Ok: received byte %u", buf_ptr_length); riello_parse_rs(&bufIn[0], &DevData, numread); return 0; } static int get_ups_extended(void) { uint8_t length; riello_init_serial(); length = riello_prepare_re(&bufOut[0], gpser_error_control); if (ser_send_buf(upsfd, bufOut, length) == 0) { upsdebugx (3, "Communication error while writing to port"); return -1; } riello_serialcomm(&bufIn[0], DEV_RIELLOGPSER); if (!wait_packet && foundbadcrc) { upsdebugx (3, "Get extended Ko: bad CRC or Checksum"); return -1; } /* optonal */ if (!wait_packet && foundnak) { upsdebugx (3, "Get extended Ko: command not supported"); return 0; } upsdebugx (3, "Get extended Ok: received byte %u", buf_ptr_length); riello_parse_re(&bufIn[0], &DevData); return 0; } /* Not static, exposed via header. Not used though, currently... */ int get_ups_statuscode(void) { uint8_t length; riello_init_serial(); length = riello_prepare_rc(&bufOut[0], gpser_error_control); if (ser_send_buf(upsfd, bufOut, length) == 0) { upsdebugx (3, "Communication error while writing to port"); return -1; } riello_serialcomm(&bufIn[0], DEV_RIELLOGPSER); if (!wait_packet && foundbadcrc) { upsdebugx (3, "Get statuscode Ko: bad CRC or Checksum"); return -1; } /* optional */ if (!wait_packet && foundnak) { upsdebugx (3, "Get statuscode Ko: command not supported"); return 0; } upsdebugx (3, "Get statuscode Ok: received byte %u", buf_ptr_length); riello_parse_rc(&bufIn[0], &DevData); return 0; } static int get_ups_sentr(void) { uint8_t length; riello_init_serial(); bufOut[0] = requestSENTR; if (requestSENTR == SENTR_EXT176) { bufOut[1] = 103; bufOut[2] = 1; bufOut[3] = 0; bufOut[4] = 24; length = 5; } else length = 1; if (ser_send_buf(upsfd, bufOut, length) == 0) { upsdebugx (3, "Communication error while writing to port"); return -1; } riello_serialcomm(&bufIn[0], DEV_RIELLOSENTRY); if (!wait_packet && foundbadcrc) { upsdebugx (3, "Get sentry Ko: bad CRC or Checksum"); return -1; } /* mandatory */ if (!wait_packet && foundnak) { upsdebugx (3, "Get sentry Ko: command not supported"); return -1; } upsdebugx (3, "Get sentry Ok: received byte %u", buf_ptr_length); riello_parse_sentr(&bufIn[0], &DevData); return 0; } static int riello_instcmd(const char *cmdname, const char *extra) { uint8_t length; uint16_t delay; const char *delay_char; if (!riello_test_bit(&DevData.StatusCode[0], 1)) { if (!strcasecmp(cmdname, "load.off")) { delay = 0; riello_init_serial(); if (typeRielloProtocol == DEV_RIELLOGPSER) length = riello_prepare_cs(bufOut, gpser_error_control, delay); else length = riello_prepare_shutsentr(bufOut, delay); if (ser_send_buf(upsfd, bufOut, length) == 0) { upsdebugx (3, "Command load.off communication error"); return STAT_INSTCMD_FAILED; } riello_serialcomm(&bufIn[0], typeRielloProtocol); if (!wait_packet && foundbadcrc) { upsdebugx (3, "Command load.off Ko: bad CRC or Checksum"); return STAT_INSTCMD_FAILED; } if (!wait_packet && foundnak) { upsdebugx (3, "Command load.off Ko: command not supported"); return STAT_INSTCMD_FAILED; } upsdebugx (3, "Command load.off Ok"); return STAT_INSTCMD_HANDLED; } if (!strcasecmp(cmdname, "load.off.delay")) { int ipv; delay_char = dstate_getinfo("ups.delay.shutdown"); ipv = atoi(delay_char); if (ipv < 0 || (intmax_t)ipv > (intmax_t)UINT16_MAX) return STAT_INSTCMD_FAILED; delay = (uint16_t)ipv; riello_init_serial(); if (typeRielloProtocol == DEV_RIELLOGPSER) length = riello_prepare_cs(bufOut, gpser_error_control, delay); else length = riello_prepare_shutsentr(bufOut, delay); if (ser_send_buf(upsfd, bufOut, length) == 0) { upsdebugx (3, "Command load.off delay communication error"); return STAT_INSTCMD_FAILED; } riello_serialcomm(&bufIn[0], typeRielloProtocol); if (!wait_packet && foundbadcrc) { upsdebugx (3, "Command load.off.delay Ko: bad CRC or Checksum"); return STAT_INSTCMD_FAILED; } if (!wait_packet && foundnak) { upsdebugx (3, "Command load.off.delay Ko: command not supported"); return STAT_INSTCMD_FAILED; } upsdebugx (3, "Command load.off delay Ok"); return STAT_INSTCMD_HANDLED; } if (!strcasecmp(cmdname, "load.on")) { delay = 0; riello_init_serial(); if (typeRielloProtocol == DEV_RIELLOGPSER) length = riello_prepare_cr(bufOut, gpser_error_control, delay); else { length = riello_prepare_setrebsentr(bufOut, delay); if (ser_send_buf(upsfd, bufOut, length) == 0) { upsdebugx (3, "Command load.on communication error"); return STAT_INSTCMD_FAILED; } riello_serialcomm(&bufIn[0], typeRielloProtocol); if (!wait_packet && foundbadcrc) { upsdebugx (3, "Command load.on Ko: bad CRC or Checksum"); return STAT_INSTCMD_FAILED; } if (!wait_packet && foundnak) { upsdebugx (3, "Command load.on Ko: command not supported"); return STAT_INSTCMD_FAILED; } length = riello_prepare_rebsentr(bufOut, delay); } if (ser_send_buf(upsfd, bufOut, length) == 0) { upsdebugx (3, "Command load.on communication error"); return STAT_INSTCMD_FAILED; } riello_serialcomm(&bufIn[0], typeRielloProtocol); if (!wait_packet && foundbadcrc) { upsdebugx (3, "Command load.on Ko: bad CRC or Checksum"); return STAT_INSTCMD_FAILED; } if (!wait_packet && foundnak) { upsdebugx (3, "Command load.on Ko: command not supported"); return STAT_INSTCMD_FAILED; } upsdebugx (3, "Command load.on Ok"); return STAT_INSTCMD_HANDLED; } if (!strcasecmp(cmdname, "load.on.delay")) { int ipv; delay_char = dstate_getinfo("ups.delay.reboot"); ipv = atoi(delay_char); if (ipv < 0 || (intmax_t)ipv > (intmax_t)UINT16_MAX) return STAT_INSTCMD_FAILED; delay = (uint16_t)ipv; riello_init_serial(); if (typeRielloProtocol == DEV_RIELLOGPSER) length = riello_prepare_cr(bufOut, gpser_error_control, delay); else { length = riello_prepare_setrebsentr(bufOut, delay); if (ser_send_buf(upsfd, bufOut, length) == 0) { upsdebugx (3, "Command load.on delay communication error"); return STAT_INSTCMD_FAILED; } riello_serialcomm(&bufIn[0], typeRielloProtocol); if (!wait_packet && foundbadcrc) { upsdebugx (3, "Command load.on delay Ko: bad CRC or Checksum"); return STAT_INSTCMD_FAILED; } if (!wait_packet && foundnak) { upsdebugx (3, "Command load.on delay Ko: command not supported"); return STAT_INSTCMD_FAILED; } length = riello_prepare_rebsentr(bufOut, delay); } if (ser_send_buf(upsfd, bufOut, length) == 0) { upsdebugx (3, "Command load.on delay communication error"); return STAT_INSTCMD_FAILED; } riello_serialcomm(&bufIn[0], typeRielloProtocol); if (!wait_packet && foundbadcrc) { upsdebugx (3, "Command load.on.delay Ko: bad CRC or Checksum"); return STAT_INSTCMD_FAILED; } if (!wait_packet && foundnak) { upsdebugx (3, "Command load.on.delay Ko: command not supported"); return STAT_INSTCMD_FAILED; } upsdebugx (3, "Command load.on delay Ok"); return STAT_INSTCMD_HANDLED; } } else { if (!strcasecmp(cmdname, "shutdown.return")) { int ipv; delay_char = dstate_getinfo("ups.delay.shutdown"); ipv = atoi(delay_char); if (ipv < 0 || (intmax_t)ipv > (intmax_t)UINT16_MAX) return STAT_INSTCMD_FAILED; delay = (uint16_t)ipv; riello_init_serial(); if (typeRielloProtocol == DEV_RIELLOGPSER) length = riello_prepare_cs(bufOut, gpser_error_control, delay); else length = riello_prepare_shutsentr(bufOut, delay); if (ser_send_buf(upsfd, bufOut, length) == 0) { upsdebugx (3, "Command shutdown.return communication error"); return STAT_INSTCMD_FAILED; } riello_serialcomm(&bufIn[0], typeRielloProtocol); if (!wait_packet && foundbadcrc) { upsdebugx (3, "Command shutdown.return Ko: bad CRC or Checksum"); return STAT_INSTCMD_FAILED; } if (!wait_packet && foundnak) { upsdebugx (3, "Command shutdown.return Ko: command not supported"); return STAT_INSTCMD_FAILED; } upsdebugx (3, "Command shutdown.return Ok"); return STAT_INSTCMD_HANDLED; } } if (!strcasecmp(cmdname, "shutdown.stop")) { riello_init_serial(); if (typeRielloProtocol == DEV_RIELLOGPSER) length = riello_prepare_cd(bufOut, gpser_error_control); else length = riello_prepare_cancelsentr(bufOut); if (ser_send_buf(upsfd, bufOut, length) == 0) { upsdebugx (3, "Command shutdown.stop communication error"); return STAT_INSTCMD_FAILED; } riello_serialcomm(&bufIn[0], typeRielloProtocol); if (!wait_packet && foundbadcrc) { upsdebugx (3, "Command shutdown.stop Ko: bad CRC or Checksum"); return STAT_INSTCMD_FAILED; } if (!wait_packet && foundnak) { upsdebugx (3, "Command shutdown.stop Ko: command not supported"); return STAT_INSTCMD_FAILED; } upsdebugx (3, "Command shutdown.stop Ok"); return STAT_INSTCMD_HANDLED; } if (!strcasecmp(cmdname, "test.panel.start")) { riello_init_serial(); length = riello_prepare_tp(bufOut, gpser_error_control); if (ser_send_buf(upsfd, bufOut, length) == 0) { upsdebugx (3, "Command test.panel.start communication error"); return STAT_INSTCMD_FAILED; } riello_serialcomm(&bufIn[0], DEV_RIELLOGPSER); if (!wait_packet && foundbadcrc) { upsdebugx (3, "Command test.panel.start Ko: bad CRC or Checksum"); return STAT_INSTCMD_FAILED; } if (!wait_packet && foundnak) { upsdebugx (3, "Command test.panel.start Ko: command not supported"); return STAT_INSTCMD_FAILED; } upsdebugx (3, "Command test.panel.start Ok"); return STAT_INSTCMD_HANDLED; } if (!strcasecmp(cmdname, "test.battery.start")) { riello_init_serial(); if (typeRielloProtocol == DEV_RIELLOGPSER) length = riello_prepare_tb(bufOut, gpser_error_control); else length = riello_prepare_tbsentr(bufOut); if (ser_send_buf(upsfd, bufOut, length) == 0) { upsdebugx (3, "Command test.battery.start communication error"); return STAT_INSTCMD_FAILED; } riello_serialcomm(&bufIn[0], typeRielloProtocol); if (!wait_packet && foundbadcrc) { upsdebugx (3, "Command battery.start Ko: bad CRC or Checksum"); return STAT_INSTCMD_FAILED; } if (!wait_packet && foundnak) { upsdebugx (3, "Command battery.start Ko: command not supported"); return STAT_INSTCMD_FAILED; } upsdebugx (3, "Command test.battery.start Ok"); return STAT_INSTCMD_HANDLED; } upslogx(LOG_NOTICE, "instcmd: unknown command [%s] [%s]", cmdname, extra); return STAT_INSTCMD_UNKNOWN; } static int start_ups_comm(void) { uint8_t length; upsdebugx (2, "entering start_ups_comm()\n"); riello_init_serial(); if (typeRielloProtocol == DEV_RIELLOGPSER) { length = riello_prepare_gi(&bufOut[0]); if (ser_send_buf(upsfd, bufOut, length) == 0) { upsdebugx (3, "Communication error while writing to port"); return -1; } riello_serialcomm(&bufIn[0], DEV_RIELLOGPSER); } else { bufOut[0] = 192; length = 1; if (ser_send_buf(upsfd, bufOut, length) == 0) { upsdebugx (3, "Communication error while writing to port"); return -1; } riello_serialcomm(&bufIn[0], DEV_RIELLOSENTRY); } if (!wait_packet && foundbadcrc) { upsdebugx (3, "Get identif Ko: bad CRC or Checksum"); return 1; } if (!wait_packet && foundnak) { upsdebugx (3, "Get identif Ko: command not supported"); return 1; } upsdebugx (3, "Get identif Ok: received byte %u", buf_ptr_length); return 0; } void upsdrv_initinfo(void) { int ret; ret = start_ups_comm(); if (ret < 0) fatalx(EXIT_FAILURE, "No communication with UPS"); else if (ret > 0) fatalx(EXIT_FAILURE, "Bad checksum or NACK"); else upsdebugx(2, "Communication with UPS established"); if (typeRielloProtocol == DEV_RIELLOGPSER) riello_parse_gi(&bufIn[0], &DevData); else riello_parse_sentr(&bufIn[0], &DevData); gpser_error_control = DevData.Identif_bytes[4]-0x30; if ((DevData.Identif_bytes[0] == '1') || (DevData.Identif_bytes[0] == '2')) input_monophase = 1; else { input_monophase = 0; dstate_setinfo("input.phases", "%u", 3); dstate_setinfo("input.phases", "%u", 3); dstate_setinfo("input.bypass.phases", "%u", 3); } if ((DevData.Identif_bytes[0] == '1') || (DevData.Identif_bytes[0] == '3')) output_monophase = 1; else { output_monophase = 0; dstate_setinfo("output.phases", "%u", 3); } dstate_setinfo("device.mfr", "RPS S.p.a."); dstate_setinfo("device.model", "%s", (unsigned char*) DevData.ModelStr); dstate_setinfo("device.serial", "%s", (unsigned char*) DevData.Identification); dstate_setinfo("device.type", "ups"); dstate_setinfo("ups.mfr", "RPS S.p.a."); dstate_setinfo("ups.model", "%s", (unsigned char*) DevData.ModelStr); dstate_setinfo("ups.serial", "%s", (unsigned char*) DevData.Identification); dstate_setinfo("ups.firmware", "%s", (unsigned char*) DevData.Version); if (typeRielloProtocol == DEV_RIELLOGPSER) { if (get_ups_nominal() == 0) { dstate_setinfo("ups.realpower.nominal", "%u", DevData.NomPowerKW); dstate_setinfo("ups.power.nominal", "%u", DevData.NomPowerKVA); dstate_setinfo("output.voltage.nominal", "%u", DevData.NominalUout); dstate_setinfo("output.frequency.nominal", "%.1f", DevData.NomFout/10.0); dstate_setinfo("battery.voltage.nominal", "%u", DevData.NomUbat); dstate_setinfo("battery.capacity", "%u", DevData.NomBatCap); } } else { if (get_ups_sentr() == 0) { dstate_setinfo("ups.realpower.nominal", "%u", DevData.NomPowerKW); dstate_setinfo("ups.power.nominal", "%u", DevData.NomPowerKVA); dstate_setinfo("output.voltage.nominal", "%u", DevData.NominalUout); dstate_setinfo("output.frequency.nominal", "%.1f", DevData.NomFout/10.0); dstate_setinfo("battery.voltage.nominal", "%u", DevData.NomUbat); dstate_setinfo("battery.capacity", "%u", DevData.NomBatCap); } } /* commands ----------------------------------------------- */ dstate_addcmd("load.off"); dstate_addcmd("load.on"); dstate_addcmd("load.off.delay"); dstate_addcmd("load.on.delay"); dstate_addcmd("shutdown.return"); dstate_addcmd("shutdown.stop"); dstate_addcmd("test.battery.start"); dstate_setinfo("ups.delay.shutdown", "%u", offdelay); dstate_setflags("ups.delay.shutdown", ST_FLAG_RW | ST_FLAG_STRING); dstate_setaux("ups.delay.shutdown", 3); dstate_setinfo("ups.delay.reboot", "%u", bootdelay); dstate_setflags("ups.delay.reboot", ST_FLAG_RW | ST_FLAG_STRING); dstate_setaux("ups.delay.reboot", 3); if (typeRielloProtocol == DEV_RIELLOGPSER) dstate_addcmd("test.panel.start"); /* install handlers */ /* upsh.setvar = hid_set_value; setvar; */ upsh.instcmd = riello_instcmd; } void upsdrv_updateinfo(void) { uint8_t getextendedOK; static int countlost = 0; int stat; upsdebugx(1, "countlost %d",countlost); if (countlost > 0){ upsdebugx(1, "Communication with UPS is lost: status read failed!"); if (countlost == COUNTLOST) { dstate_datastale(); upslogx(LOG_WARNING, "Communication with UPS is lost: status read failed!"); } } if (typeRielloProtocol == DEV_RIELLOGPSER) stat = get_ups_status(); else stat = get_ups_sentr(); if (stat < 0) { if (countlost < COUNTLOST) countlost++; return; } if (typeRielloProtocol == DEV_RIELLOGPSER) { if (get_ups_extended() == 0) getextendedOK = 1; else getextendedOK = 0; } else getextendedOK = 1; if (countlost == COUNTLOST) upslogx(LOG_NOTICE, "Communication with UPS is re-established!"); dstate_setinfo("input.frequency", "%.2f", DevData.Finp/10.0); dstate_setinfo("input.bypass.frequency", "%.2f", DevData.Fbypass/10.0); dstate_setinfo("output.frequency", "%.2f", DevData.Fout/10.0); dstate_setinfo("battery.voltage", "%.1f", DevData.Ubat/10.0); if ((DevData.BatCap < 0xFFFF) && (DevData.BatTime < 0xFFFF)) { dstate_setinfo("battery.charge", "%u", DevData.BatCap); dstate_setinfo("battery.runtime", "%u", DevData.BatTime*60); } if (DevData.Tsystem < 0xFF) dstate_setinfo("ups.temperature", "%u", DevData.Tsystem); if (input_monophase) { dstate_setinfo("input.voltage", "%u", DevData.Uinp1); dstate_setinfo("input.bypass.voltage", "%u", DevData.Ubypass1); } else { dstate_setinfo("input.L1-N.voltage", "%u", DevData.Uinp1); dstate_setinfo("input.L2-N.voltage", "%u", DevData.Uinp2); dstate_setinfo("input.L3-N.voltage", "%u", DevData.Uinp3); dstate_setinfo("input.bypass.L1-N.voltage", "%u", DevData.Ubypass1); dstate_setinfo("input.bypass.L2-N.voltage", "%u", DevData.Ubypass2); dstate_setinfo("input.bypass.L3-N.voltage", "%u", DevData.Ubypass3); } if (output_monophase) { dstate_setinfo("output.voltage", "%u", DevData.Uout1); dstate_setinfo("output.power.percent", "%u", DevData.Pout1); dstate_setinfo("ups.load", "%u", DevData.Pout1); } else { dstate_setinfo("output.L1-N.voltage", "%u", DevData.Uout1); dstate_setinfo("output.L2-N.voltage", "%u", DevData.Uout2); dstate_setinfo("output.L3-N.voltage", "%u", DevData.Uout3); dstate_setinfo("output.L1.power.percent", "%u", DevData.Pout1); dstate_setinfo("output.L2.power.percent", "%u", DevData.Pout2); dstate_setinfo("output.L3.power.percent", "%u", DevData.Pout3); dstate_setinfo("ups.load", "%u", (DevData.Pout1+DevData.Pout2+DevData.Pout3)/3); } status_init(); /* AC Fail */ if (riello_test_bit(&DevData.StatusCode[0], 1)) status_set("OB"); else status_set("OL"); /* LowBatt */ if ((riello_test_bit(&DevData.StatusCode[0], 1)) && (riello_test_bit(&DevData.StatusCode[0], 0))) status_set("LB"); /* Standby */ if (!riello_test_bit(&DevData.StatusCode[0], 3)) status_set("OFF"); /* On Bypass */ if (riello_test_bit(&DevData.StatusCode[1], 3)) status_set("BYPASS"); /* Overload */ if (riello_test_bit(&DevData.StatusCode[4], 2)) status_set("OVER"); /* Buck */ if (riello_test_bit(&DevData.StatusCode[1], 0)) status_set("TRIM"); /* Boost */ if (riello_test_bit(&DevData.StatusCode[1], 1)) status_set("BOOST"); /* Replace battery */ if (riello_test_bit(&DevData.StatusCode[2], 0)) status_set("RB"); /* Charging battery */ if (riello_test_bit(&DevData.StatusCode[2], 2)) status_set("CHRG"); status_commit(); dstate_dataok(); if (getextendedOK) { dstate_setinfo("output.L1.power", "%u", DevData.Pout1VA); dstate_setinfo("output.L2.power", "%u", DevData.Pout2VA); dstate_setinfo("output.L3.power", "%u", DevData.Pout3VA); dstate_setinfo("output.L1.realpower", "%u", DevData.Pout1W); dstate_setinfo("output.L2.realpower", "%u", DevData.Pout2W); dstate_setinfo("output.L3.realpower", "%u", DevData.Pout3W); dstate_setinfo("output.L1.current", "%u", DevData.Iout1); dstate_setinfo("output.L2.current", "%u", DevData.Iout2); dstate_setinfo("output.L3.current", "%u", DevData.Iout3); } poll_interval = 2; countlost = 0; /* if (get_ups_statuscode() != 0) upsdebugx(2, "Communication is lost"); else { }*/ /* * poll_interval = 2; */ } void upsdrv_shutdown(void) { /* tell the UPS to shut down, then return - DO NOT SLEEP HERE */ int retry; /* maybe try to detect the UPS here, but try a shutdown even if it doesn't respond at first if possible */ /* replace with a proper shutdown function */ /* you may have to check the line status since the commands for toggling power are frequently different for OL vs. OB */ /* OL: this must power cycle the load if possible */ /* OB: the load must remain off until the power returns */ upsdebugx(2, "upsdrv Shutdown execute"); for (retry = 1; retry <= MAXTRIES; retry++) { if (riello_instcmd("shutdown.stop", NULL) != STAT_INSTCMD_HANDLED) { continue; } if (riello_instcmd("shutdown.return", NULL) != STAT_INSTCMD_HANDLED) { continue; } upslogx(LOG_ERR, "Shutting down"); set_exit_flag(-2); /* EXIT_SUCCESS */ return; } upslogx(LOG_ERR, "Shutdown failed!"); set_exit_flag(-1); } /* static int setvar(const char *varname, const char *val) { if (!strcasecmp(varname, "ups.test.interval")) { ser_send_buf(upsfd, ...); return STAT_SET_HANDLED; } upslogx(LOG_NOTICE, "setvar: unknown variable [%s]", varname); return STAT_SET_UNKNOWN; } */ void upsdrv_help(void) { } /* list flags and values that you want to receive via -x */ void upsdrv_makevartable(void) { /* allow '-x xyzzy' */ /* addvar(VAR_FLAG, "xyzzy", "Enable xyzzy mode"); */ /* allow '-x foo=' */ /* addvar(VAR_VALUE, "foo", "Override foo setting"); */ } void upsdrv_initups(void) { upsdebugx(2, "entering upsdrv_initups()"); upsfd = ser_open(device_path); riello_comm_setup(device_path); /* probe ups type */ /* to get variables and flags from the command line, use this: * * first populate with upsdrv_buildvartable above, then... * * set flag foo : /bin/driver -x foo * set variable 'cable' to '1234' : /bin/driver -x cable=1234 * * to test flag foo in your code: * * if (testvar("foo")) * do_something(); * * to show the value of cable: * * if ((cable = getval("cable"))) * printf("cable is set to %s\n", cable); * else * printf("cable is not set!\n"); * * don't use NULL pointers - test the return result first! */ /* the upsh handlers can't be done here, as they get initialized * shortly after upsdrv_initups returns to main. */ /* don't try to detect the UPS here */ /* initialise communication */ } void upsdrv_cleanup(void) { /* free(dynamic_mem); */ ser_close(upsfd, device_path); } void riello_comm_setup(const char *port) { uint8_t length; upsdebugx(2, "set baudrate 9600"); ser_set_speed(upsfd, device_path, B9600); upsdebugx(2, "try to detect SENTR"); riello_init_serial(); bufOut[0] = 192; ser_send_buf(upsfd, bufOut, 1); riello_serialcomm(&bufIn[0], DEV_RIELLOSENTRY); if (buf_ptr_length == 103) { typeRielloProtocol = DEV_RIELLOSENTRY; upslogx(LOG_INFO, "Connected to UPS SENTR on %s with baudrate %d", port, 9600); return; } upsdebugx(2, "try to detect GPSER"); riello_init_serial(); length = riello_prepare_gi(&bufOut[0]); ser_send_buf(upsfd, bufOut, length); riello_serialcomm(&bufIn[0], DEV_RIELLOGPSER); if (!wait_packet && !foundbadcrc && !foundnak) { typeRielloProtocol = DEV_RIELLOGPSER; upslogx(LOG_INFO, "Connected to UPS GPSER on %s with baudrate %d", port, 9600); return; } upsdebugx(2, "set baudrate 1200"); ser_set_speed(upsfd, device_path, B1200); upsdebugx(2, "try to detect SENTR"); riello_init_serial(); bufOut[0] = 192; ser_send_buf(upsfd, bufOut, 1); riello_serialcomm(&bufIn[0], DEV_RIELLOSENTRY); if (buf_ptr_length == 103) { typeRielloProtocol = DEV_RIELLOSENTRY; upslogx(LOG_INFO, "Connected to UPS SENTR on %s with baudrate %d", port, 1200); return; } upsdebugx(2, "try to detect GPSER"); riello_init_serial(); length = riello_prepare_gi(&bufOut[0]); ser_send_buf(upsfd, bufOut, length); riello_serialcomm(&bufIn[0], DEV_RIELLOGPSER); if (!wait_packet && !foundbadcrc && !foundnak) { typeRielloProtocol = DEV_RIELLOGPSER; upslogx(LOG_INFO, "Connected to UPS GPSER on %s with baudrate %d", port, 1200); return; } fatalx(EXIT_FAILURE, "Can't connect to the UPS on port %s!\n", port); } nut-2.8.1/drivers/powerp-txt.c0000644000175000017500000003652014501607135013234 00000000000000/* * powerp-txt.c - Model specific routines for CyberPower text * protocol UPSes * * Copyright (C) * 2007 Doug Reynolds * 2007-2008 Arjen de Korte * 2012-2016 Timothy Pearson * * 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 2 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, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ /* * Throughout this driver, READ and WRITE comments are shown. These are * the typical commands to and replies from the UPS that was used for * decoding the protocol (with a serial logger). */ #include "main.h" #include "serial.h" #include "nut_stdint.h" #include "powerp-txt.h" #define POWERPANEL_TEXT_VERSION "Powerpanel-Text 0.5" typedef struct { float i_volt; float o_volt; int o_load; int b_chrg; int u_temp; float i_freq; unsigned char flags[2]; unsigned char has_b_volt; float b_volt; unsigned char has_o_freq; float o_freq; unsigned char has_runtime; int runtime; int c_unknwn; float q_unknwn; } status_t; static long ondelay = 1; /* minutes */ static long offdelay = 60; /* seconds */ static char powpan_answer[SMALLBUF]; static struct { const char *var; const char *get; const char *set; } vartab[] = { { "input.transfer.high", "P6\r", "C2:%03d\r" }, { "input.transfer.low", "P7\r", "C3:%03d\r" }, { "battery.charge.low", "P8\r", "C4:%02d\r" }, { NULL, NULL, NULL } }; static struct { const char *cmd; const char *command; } cmdtab[] = { { "test.battery.start.quick", "T\r" }, { "test.battery.start.deep", "TL\r" }, { "test.battery.stop", "CT\r" }, { "beeper.enable", "C7:1\r" }, { "beeper.disable", "C7:0\r" }, { "beeper.on", NULL }, { "beeper.off", NULL }, { "shutdown.stop", "C\r" }, { NULL, NULL } }; static ssize_t powpan_command(const char *command) { ssize_t ret; ser_flush_io(upsfd); ret = ser_send_pace(upsfd, UPSDELAY, "%s", command); if (ret < 0) { upsdebug_with_errno(3, "send"); return -1; } if (ret == 0) { upsdebug_with_errno(3, "send: timeout"); return -1; } upsdebug_hex(3, "send", command, strlen(command)); usleep(100000); ret = ser_get_line(upsfd, powpan_answer, sizeof(powpan_answer), ENDCHAR, IGNCHAR, SER_WAIT_SEC, SER_WAIT_USEC); if (ret < 0) { upsdebug_with_errno(3, "read"); upsdebug_hex(4, " \\_", powpan_answer, strlen(powpan_answer)); return -1; } if (ret == 0) { upsdebugx(3, "read: timeout"); upsdebug_hex(4, " \\_", powpan_answer, strlen(powpan_answer)); return -1; } upsdebug_hex(3, "read", powpan_answer, (size_t)ret); return ret; } static int powpan_instcmd(const char *cmdname, const char *extra) { int i; char command[SMALLBUF]; if (!strcasecmp(cmdname, "beeper.off")) { /* compatibility mode for old command */ upslogx(LOG_WARNING, "The 'beeper.off' command has been renamed to 'beeper.disable'"); return powpan_instcmd("beeper.disable", NULL); } if (!strcasecmp(cmdname, "beeper.on")) { /* compatibility mode for old command */ upslogx(LOG_WARNING, "The 'beeper.on' command has been renamed to 'beeper.enable'"); return powpan_instcmd("beeper.enable", NULL); } for (i = 0; cmdtab[i].cmd != NULL; i++) { if (strcasecmp(cmdname, cmdtab[i].cmd)) { continue; } if ((powpan_command(cmdtab[i].command) == 2) && (!strcasecmp(powpan_answer, "#0"))) { return STAT_INSTCMD_HANDLED; } upslogx(LOG_ERR, "%s: command [%s] [%s] failed", __func__, cmdname, extra); return STAT_INSTCMD_FAILED; } if (!strcasecmp(cmdname, "shutdown.return")) { if (offdelay < 60) { snprintf(command, sizeof(command), "Z.%ld\r", offdelay / 6); } else { snprintf(command, sizeof(command), "Z%02ld\r", offdelay / 60); } } else if (!strcasecmp(cmdname, "shutdown.stayoff")) { if (offdelay < 60) { snprintf(command, sizeof(command), "S.%ld\r", offdelay / 6); } else { snprintf(command, sizeof(command), "S%02ld\r", offdelay / 60); } } else if (!strcasecmp(cmdname, "shutdown.reboot")) { if (offdelay < 60) { snprintf(command, sizeof(command), "S.%ldR%04ld\r", offdelay / 6, ondelay); } else { snprintf(command, sizeof(command), "S%02ldR%04ld\r", offdelay / 60, ondelay); } } else { upslogx(LOG_NOTICE, "%s: command [%s] [%s] unknown", __func__, cmdname, extra); return STAT_INSTCMD_UNKNOWN; } if ((powpan_command(command) == 2) && (!strcasecmp(powpan_answer, "#0"))) { return STAT_INSTCMD_HANDLED; } upslogx(LOG_ERR, "%s: command [%s] [%s] failed", __func__, cmdname, extra); return STAT_INSTCMD_FAILED; } static int powpan_setvar(const char *varname, const char *val) { char command[SMALLBUF]; int i; for (i = 0; vartab[i].var != NULL; i++) { if (strcasecmp(varname, vartab[i].var)) { continue; } if (!strcasecmp(val, dstate_getinfo(varname))) { upslogx(LOG_INFO, "%s: [%s] no change for variable [%s]", __func__, val, varname); return STAT_SET_HANDLED; } #ifdef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL #pragma GCC diagnostic push #endif #ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL #pragma GCC diagnostic ignored "-Wformat-nonliteral" #endif #ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_FORMAT_SECURITY #pragma GCC diagnostic ignored "-Wformat-security" #endif snprintf(command, sizeof(command), vartab[i].set, atoi(val)); #ifdef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL #pragma GCC diagnostic pop #endif if ((powpan_command(command) == 2) && (!strcasecmp(powpan_answer, "#0"))) { dstate_setinfo(varname, "%s", val); return STAT_SET_HANDLED; } upslogx(LOG_ERR, "%s: setting variable [%s] to [%s] failed", __func__, varname, val); return STAT_SET_UNKNOWN; } upslogx(LOG_ERR, "%s: variable [%s] not found", __func__, varname); return STAT_SET_UNKNOWN; } static void powpan_initinfo(void) { int i; char *s; dstate_setinfo("ups.delay.start", "%ld", 60 * ondelay); dstate_setinfo("ups.delay.shutdown", "%ld", offdelay); /* * NOTE: The reply is already in the buffer, since the P4\r command * was used for autodetection of the UPS. No need to do it again. */ if ((s = strtok(&powpan_answer[1], ",")) != NULL) { dstate_setinfo("ups.model", "%s", str_rtrim(s, ' ')); } if ((s = strtok(NULL, ",")) != NULL) { dstate_setinfo("ups.firmware", "%s", s); } if ((s = strtok(NULL, ",")) != NULL) { dstate_setinfo("ups.serial", "%s", s); } if ((s = strtok(NULL, ",")) != NULL) { dstate_setinfo("ups.mfr", "%s", str_rtrim(s, ' ')); } /* * WRITE P3\r * READ #12.0,002,008.0,00\r */ if (powpan_command("P3\r") > 0) { if ((s = strtok(&powpan_answer[1], ",")) != NULL) { dstate_setinfo("battery.voltage.nominal", "%g", strtod(s, NULL)); } if ((s = strtok(NULL, ",")) != NULL) { dstate_setinfo("battery.packs", "%li", strtol(s, NULL, 10)); } if ((s = strtok(NULL, ",")) != NULL) { dstate_setinfo("battery.capacity", "%g", strtod(s, NULL)); } } /* * WRITE P2\r * READ #1200,0720,120,47,63\r */ if (powpan_command("P2\r") > 0) { if ((s = strtok(&powpan_answer[1], ",")) != NULL) { dstate_setinfo("ups.power.nominal", "%li", strtol(s, NULL, 10)); } if ((s = strtok(NULL, ",")) != NULL) { dstate_setinfo("ups.realpower.nominal", "%li", strtol(s, NULL, 10)); } if ((s = strtok(NULL, ",")) != NULL) { dstate_setinfo("input.voltage.nominal", "%li", strtol(s, NULL, 10)); } if ((s = strtok(NULL, ",")) != NULL) { dstate_setinfo("input.frequency.low", "%li", strtol(s, NULL, 10)); } if ((s = strtok(NULL, ",")) != NULL) { dstate_setinfo("input.frequency.high", "%li", strtol(s, NULL, 10)); } } /* * WRITE P1\r * READ #120,138,088,20\r */ if (powpan_command("P1\r") > 0) { if ((s = strtok(&powpan_answer[1], ",")) != NULL) { dstate_setinfo("input.voltage.nominal", "%li", strtol(s, NULL, 10)); } if ((s = strtok(NULL, ",")) != NULL) { dstate_setinfo("input.transfer.high", "%li", strtol(s, NULL, 10)); } if ((s = strtok(NULL, ",")) != NULL) { dstate_setinfo("input.transfer.low", "%li", strtol(s, NULL, 10)); } if ((s = strtok(NULL, ",")) != NULL) { dstate_setinfo("battery.charge.low", "%li", strtol(s, NULL, 10)); } } for (i = 0; cmdtab[i].cmd != NULL; i++) { dstate_addcmd(cmdtab[i].cmd); } for (i = 0; vartab[i].var != NULL; i++) { if (!dstate_getinfo(vartab[i].var)) { continue; } if (powpan_command(vartab[i].get) < 1) { continue; } if ((s = strtok(&powpan_answer[1], ",")) != NULL) { dstate_setflags(vartab[i].var, ST_FLAG_RW); dstate_addenum(vartab[i].var, "%li", strtol(s, NULL, 10)); } while ((s = strtok(NULL, ",")) != NULL) { dstate_addenum(vartab[i].var, "%li", strtol(s, NULL, 10)); } } /* * WRITE P5\r * READ #\r */ if (powpan_command("P5\r") > 0) { /* * Looking at the format of the commands "P\r" it seems likely * that this command exists also. Let's see if someone cares to * tell us if it does (should be visible when running with -DDDDD). */ } /* * WRITE P9\r * READ #\r */ if (powpan_command("P9\r") > 0) { /* * Looking at the format of the commands "P\r" it seems likely * that this command exists also. Let's see if someone cares to * tell us if it does (should be visible when running with -DDDDD). */ } /* * Cancel pending shutdown. * WRITE C\r * READ #0\r */ powpan_command("C\r"); dstate_addcmd("shutdown.return"); dstate_addcmd("shutdown.stayoff"); dstate_addcmd("shutdown.reboot"); } static ssize_t powpan_status(status_t *status) { ssize_t ret; ser_flush_io(upsfd); /* * WRITE D\r * READ #I119.0O119.0L000B100T027F060.0S..\r * #I118.0O118.0L029B100F060.0R0218S..\r * 01234567890123456789012345678901234 * 0 1 2 3 */ ret = ser_send_pace(upsfd, UPSDELAY, "D\r"); if (ret < 0) { upsdebug_with_errno(3, "send"); return -1; } if (ret == 0) { upsdebug_with_errno(3, "send: timeout"); return -1; } upsdebug_hex(3, "send", "D\r", 2); usleep(200000); ret = ser_get_buf_len(upsfd, powpan_answer, 35, SER_WAIT_SEC, SER_WAIT_USEC); if (ret < 0) { upsdebug_with_errno(3, "read"); upsdebug_hex(4, " \\_", powpan_answer, 35); return -1; } if (ret == 0) { upsdebugx(3, "read: timeout"); upsdebug_hex(4, " \\_", powpan_answer, 35); return -1; } upsdebug_hex(3, "read", powpan_answer, (size_t)ret); ret = sscanf(powpan_answer, "#I%fO%fL%dB%dT%dF%fS%2c\r", &status->i_volt, &status->o_volt, &status->o_load, &status->b_chrg, &status->u_temp, &status->i_freq, status->flags); if (ret >= 7) { status->has_b_volt = 0; status->has_o_freq = 0; status->has_runtime = 0; } else { ret = sscanf(powpan_answer, "#I%fO%fL%dB%dF%fR%dS%2c\r", &status->i_volt, &status->o_volt, &status->o_load, &status->b_chrg, &status->i_freq, &status->runtime, status->flags); if (ret >= 7) { status->has_b_volt = 0; status->has_o_freq = 0; status->has_runtime = 1; } } if (ret < 7) { ret = ser_get_buf_len(upsfd, powpan_answer+35, 23, SER_WAIT_SEC, SER_WAIT_USEC); if (ret < 0) { upsdebug_with_errno(3, "read"); upsdebug_hex(4, " \\_", powpan_answer+35, 23); return -1; } if (ret == 0) { upsdebugx(3, "read: timeout"); upsdebug_hex(4, " \\_", powpan_answer+35, 23); return -1; } upsdebug_hex(3, "read", powpan_answer, (size_t)ret); ret = sscanf(powpan_answer, "#I%fO%fL%dB%dV%fT%dF%fH%fR%dC%dQ%fS%2c\r", &status->i_volt, &status->o_volt, &status->o_load, &status->b_chrg, &status->b_volt, &status->u_temp, &status->i_freq, &status->o_freq, &status->runtime, &status->c_unknwn, &status->q_unknwn, status->flags); status->has_b_volt = 1; status->has_o_freq = 1; status->has_runtime = 1; dstate_setinfo("battery.voltage.nominal", "%g", 72.0); dstate_setinfo("output.voltage.nominal", "%g", 120.0); } if (ret < 7) { upsdebugx(4, "Parsing status string failed"); return -1; } return 0; } static int powpan_updateinfo(void) { status_t status; if (powpan_status(&status)) { return -1; } dstate_setinfo("input.voltage", "%.1f", status.i_volt); dstate_setinfo("output.voltage", "%.1f", status.o_volt); dstate_setinfo("ups.load", "%d", status.o_load); dstate_setinfo("input.frequency", "%.1f", status.i_freq); dstate_setinfo("ups.temperature", "%d", status.u_temp); dstate_setinfo("battery.charge", "%d", status.b_chrg); if (status.has_b_volt) { dstate_setinfo("battery.voltage", "%.1f", status.b_volt); } if (status.has_o_freq) { dstate_setinfo("output.frequency", "%.1f", status.o_freq); } if (status.has_runtime) { dstate_setinfo("battery.runtime", "%d", status.runtime*60); } status_init(); if (status.flags[0] & 0x40) { status_set("OB"); } else { status_set("OL"); } if (status.flags[0] & 0x20) { status_set("LB"); } /* !OB && !TEST */ if (!(status.flags[0] & 0x48)) { if (status.o_volt < 0.5 * status.i_volt) { upsdebugx(2, "%s: output voltage too low", __func__); } else if (status.o_volt < 0.95 * status.i_volt) { status_set("TRIM"); } else if (status.o_volt < 1.05 * status.i_volt) { /* ignore */ } else if (status.o_volt < 1.5 * status.i_volt) { status_set("BOOST"); } else { upsdebugx(2, "%s: output voltage too high", __func__); } } if (status.flags[0] & 0x08) { status_set("TEST"); } if (status.flags[0] == 0) { status_set("OFF"); } status_commit(); return (status.flags[0] & 0x40) ? 1 : 0; } static ssize_t powpan_initups(void) { ssize_t ret; int i; upsdebugx(1, "Trying text protocol..."); ser_set_speed(upsfd, device_path, B2400); /* This fails for many devices, so don't bother to complain */ powpan_command("\r\r"); for (i = 0; i < MAXTRIES; i++) { const char *val; /* * WRITE P4\r * READ #BC1200 ,1.600,000000000000,CYBER POWER * 01234567890123456789012345678901234567890123456 * 0 1 2 3 4 */ ret = powpan_command("P4\r"); if (ret < 1) { continue; } if (ret < 46) { upsdebugx(2, "Expected 46 bytes, but only got %" PRIiSIZE, ret); continue; } if (powpan_answer[0] != '#') { upsdebugx(2, "Expected start character '#', but got '%c'", powpan_answer[0]); continue; } val = getval("ondelay"); if (val) { ondelay = strtol(val, NULL, 10); } if ((ondelay < 0) || (ondelay > 9999)) { fatalx(EXIT_FAILURE, "Start delay '%ld' out of range [0..9999]", ondelay); } val = getval("offdelay"); if (val) { offdelay = strtol(val, NULL, 10); } if ((offdelay < 6) || (offdelay > 600)) { fatalx(EXIT_FAILURE, "Shutdown delay '%ld' out of range [6..600]", offdelay); } /* Truncate to nearest setable value */ if (offdelay < 60) { offdelay -= (offdelay % 6); } else { offdelay -= (offdelay % 60); } return ret; } return -1; } subdriver_t powpan_text = { "text", POWERPANEL_TEXT_VERSION, powpan_instcmd, powpan_setvar, powpan_initups, powpan_initinfo, powpan_updateinfo }; nut-2.8.1/drivers/hidparser.c0000644000175000017500000005117414502253356013071 00000000000000/* * hidparser.c: HID Parser * * This file is part of the MGE UPS SYSTEMS HID Parser * * Copyright (C) * 1998-2003 MGE UPS SYSTEMS, Luc Descotils * * 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 2 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, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * -------------------------------------------------------------------------- */ #include "config.h" /* must be first */ #include #include #include "hidparser.h" #include "nut_stdint.h" /* for int8_t, int16_t, int32_t */ #include "common.h" /* for fatalx() */ static const uint8_t ItemSize[4] = { 0, 1, 2, 4 }; /* * HIDParser struct * -------------------------------------------------------------------------- */ /* FIXME? Should this structure remain with reasonable fixed int types, * or changed to align with libusb API version and usb_ctrl_* typedefs? */ typedef struct { const unsigned char *ReportDesc; /* Report Descriptor */ size_t ReportDescSize; /* Size of Report Descriptor */ uint16_t Pos; /* Store current pos in descriptor */ uint8_t Item; /* Store current Item */ uint32_t Value; /* Store current Value */ HIDData_t Data; /* Store current environment */ uint8_t OffsetTab[MAX_REPORT][4]; /* Store ID, Type, offset & timestamp of report */ uint8_t ReportCount; /* Store Report Count */ uint8_t Count; /* Store local report count */ uint16_t UPage; /* Global UPage */ HIDNode_t UsageTab[USAGE_TAB_SIZE]; /* Usage stack */ uint8_t UsageSize; /* Design number of usage used */ } HIDParser_t; /* return 1 + the position of the leftmost "1" bit of an int, or 0 if none. */ static inline unsigned int hibit(unsigned long x) { unsigned int res = 0; while (x > 0xff) { x >>= 8; res += 8; } while (x) { x >>= 1; res += 1; } return res; } /* Note: The USB HID specification states that Local items do not carry over to the next Main item (version 1.11, section 6.2.2.8). Therefore the local state must be reset after each main item. In particular, any unused usages on the Usage tabs must be discarded and must not carry over to the next Main item. Some APC equipment actually sends multiple redundant "usage" commands for a single control, so resetting the local state is important. */ /* Also note: UsageTab[0] is used as the usage of the next control, even if UsageSize=0. Therefore, this must be initialized */ static void ResetLocalState(HIDParser_t* pParser) { pParser->UsageSize = 0; memset(pParser->UsageTab, 0, sizeof(pParser->UsageTab)); } /* * GetReportOffset * * Return pointer on current offset value for Report designed by * ReportID/ReportType * -------------------------------------------------------------------------- */ static uint8_t *GetReportOffset(HIDParser_t* pParser, const uint8_t ReportID, const uint8_t ReportType) { int Pos; for (Pos = 0; Pos < MAX_REPORT; Pos++) { if (pParser->OffsetTab[Pos][0] == 0) { pParser->OffsetTab[Pos][0] = ReportID; pParser->OffsetTab[Pos][1] = ReportType; pParser->OffsetTab[Pos][2] = 0; } if (pParser->OffsetTab[Pos][0] != ReportID) { continue; } if (pParser->OffsetTab[Pos][1] != ReportType) { continue; } return &pParser->OffsetTab[Pos][2]; } return NULL; } /* * FormatValue(uint32_t Value, uint8_t Size) * Format Value to fit with long format with respect of negative values * -------------------------------------------------------------------------- */ static long FormatValue(uint32_t Value, uint8_t Size) { switch(Size) { case 1: return (long)(int8_t)Value; case 2: return (long)(int16_t)Value; case 4: return (long)(int32_t)Value; default: return (long)Value; } } /* * HIDParse(HIDParser_t* pParser, HIDData_t *pData) * * Analyse Report descriptor stored in HIDParser struct and store local and * global context. * Return in pData the last object found. * Return -1 when there is no other Item to parse, 1 if a new object was found * or 0 if a continuation of a previous object was found. * -------------------------------------------------------------------------- */ static int HIDParse(HIDParser_t *pParser, HIDData_t *pData) { int Found = -1, i; while ((Found < 0) && (pParser->Pos < pParser->ReportDescSize)) { /* Get new pParser->Item if current pParser->Count is empty */ if (pParser->Count == 0) { pParser->Item = pParser->ReportDesc[pParser->Pos++]; pParser->Value = 0; for (i = 0; i < ItemSize[pParser->Item & SIZE_MASK]; i++) { pParser->Value += (uint32_t)(pParser->ReportDesc[(pParser->Pos)+i]) << (8*i); } /* Pos on next item */ pParser->Pos += ItemSize[pParser->Item & SIZE_MASK]; } switch (pParser->Item & ITEM_MASK) { case ITEM_UPAGE: /* Copy UPage in Usage stack */ pParser->UPage=(uint16_t)pParser->Value; break; case ITEM_USAGE: /* Copy global or local UPage if any, in Usage stack */ if ((pParser->Item & SIZE_MASK) > 2) { pParser->UsageTab[pParser->UsageSize] = pParser->Value; } else { pParser->UsageTab[pParser->UsageSize] = ((HIDNode_t)(pParser->UPage) << 16) | (pParser->Value & 0xFFFF); } /* Increment Usage stack size */ pParser->UsageSize++; break; case ITEM_COLLECTION: /* Get UPage/Usage from UsageTab and store them in pParser->Data.Path */ pParser->Data.Path.Node[pParser->Data.Path.Size] = pParser->UsageTab[0]; pParser->Data.Path.Size++; /* Unstack UPage/Usage from UsageTab (never remove the last) */ if (pParser->UsageSize > 0) { int j; for (j = 0; j < pParser->UsageSize; j++) { pParser->UsageTab[j] = pParser->UsageTab[j+1]; } /* Remove Usage */ pParser->UsageSize--; } /* Get Index if any */ if (pParser->Value >= 0x80) { pParser->Data.Path.Node[pParser->Data.Path.Size] = 0x00ff0000 | (pParser->Value & 0x7F); pParser->Data.Path.Size++; } ResetLocalState(pParser); break; case ITEM_END_COLLECTION : pParser->Data.Path.Size--; /* Remove Index if any */ if((pParser->Data.Path.Node[pParser->Data.Path.Size] & 0xffff0000) == 0x00ff0000) { pParser->Data.Path.Size--; } ResetLocalState(pParser); break; case ITEM_FEATURE: case ITEM_INPUT: case ITEM_OUTPUT: if (pParser->UsageTab[0] != 0x00000000) { /* An object was found if the path does not end with 0x00000000 */ Found = 1; } else { /* It is a continuation of a previous object */ Found = 0; } /* Get new pParser->Count from global value */ if(pParser->Count == 0) { pParser->Count = pParser->ReportCount; } /* Get UPage/Usage from UsageTab and store them in pParser->Data.Path */ pParser->Data.Path.Node[pParser->Data.Path.Size] = pParser->UsageTab[0]; pParser->Data.Path.Size++; /* Unstack UPage/Usage from UsageTab (never remove the last) */ if(pParser->UsageSize > 0) { int j; for (j = 0; j < pParser->UsageSize; j++) { pParser->UsageTab[j] = pParser->UsageTab[j+1]; } /* Remove Usage */ pParser->UsageSize--; } /* Copy data type */ pParser->Data.Type = (uint8_t)(pParser->Item & ITEM_MASK); /* Copy data attribute */ pParser->Data.Attribute = (uint8_t)pParser->Value; /* Store offset */ pParser->Data.Offset = *GetReportOffset(pParser, pParser->Data.ReportID, (uint8_t)(pParser->Item & ITEM_MASK)); /* Get Object in pData */ /* -------------------------------------------------------------------------- */ memcpy(pData, &pParser->Data, sizeof(HIDData_t)); /* -------------------------------------------------------------------------- */ /* Increment Report Offset */ *GetReportOffset(pParser, pParser->Data.ReportID, (uint8_t)(pParser->Item & ITEM_MASK)) += pParser->Data.Size; /* Remove path last node */ pParser->Data.Path.Size--; /* Decrement count */ pParser->Count--; if (pParser->Count == 0) { ResetLocalState(pParser); } break; case ITEM_REP_ID : pParser->Data.ReportID = (uint8_t)pParser->Value; break; case ITEM_REP_SIZE : pParser->Data.Size = (uint8_t)pParser->Value; break; case ITEM_REP_COUNT : pParser->ReportCount = (uint8_t)pParser->Value; break; case ITEM_UNIT_EXP : pParser->Data.UnitExp = (int8_t)pParser->Value; if (pParser->Data.UnitExp > 7) { pParser->Data.UnitExp |= 0xF0; } break; case ITEM_UNIT : /* TOTHINK: Are there cases where Unit is not-signed, * but a Value too big becomes signed after casting -- * and unintentionally so? */ pParser->Data.Unit = (long)pParser->Value; break; case ITEM_LOG_MIN : pParser->Data.LogMin = FormatValue(pParser->Value, ItemSize[pParser->Item & SIZE_MASK]); break; case ITEM_LOG_MAX : pParser->Data.LogMax = FormatValue(pParser->Value, ItemSize[pParser->Item & SIZE_MASK]); /* HACK: If treating the value as signed (FormatValue(...)) results in a LogMax that is * less than the LogMin value then it is likely that the LogMax value has been * incorrectly encoded by the UPS firmware (field too short and overflowed into sign * bit). In that case, reinterpret it as an unsigned number and log the problem. * This hack is not correct in the sense that it only looks at the LogMin value for * this item, whereas the HID spec says that Logical values persist in global state. */ if (pParser->Data.LogMax < pParser->Data.LogMin) { upslogx(LOG_WARNING, "%s: LogMax is less than LogMin. " "Vendor HID report descriptor may be incorrect; " "interpreting LogMax %ld as %u in ReportID: 0x%02x", __func__, pParser->Data.LogMax, pParser->Value, pParser->Data.ReportID); pParser->Data.LogMax = (long) pParser->Value; } break; case ITEM_PHY_MIN : pParser->Data.PhyMin=FormatValue(pParser->Value, ItemSize[pParser->Item & SIZE_MASK]); pParser->Data.have_PhyMin = 1; break; case ITEM_PHY_MAX : pParser->Data.PhyMax=FormatValue(pParser->Value, ItemSize[pParser->Item & SIZE_MASK]); pParser->Data.have_PhyMax = 1; break; case ITEM_LONG : /* can't handle long items, but should at least skip them */ pParser->Pos += (uint8_t)(pParser->Value & 0xff); break; } } /* while ((Found < 0) && (pParser->Pos < pParser->ReportDescSize)) */ if(pParser->Data.Path.Size >= PATH_SIZE) upslogx(LOG_ERR, "%s: HID path too long", __func__); if(pParser->ReportDescSize >= REPORT_DSC_SIZE) upslogx(LOG_ERR, "%s: Report descriptor too big", __func__); if(pParser->UsageSize >= USAGE_TAB_SIZE) upslogx(LOG_ERR, "%s: HID Usage too high", __func__); /* FIXME: comparison is always false due to limited range of data type [-Werror=type-limits] * with ReportID being uint8_t and MAX_REPORT being 500 currently */ /* if(pParser->Data.ReportID >= MAX_REPORT) upslogx(LOG_ERR, "%s: Too many HID reports", __func__); */ return Found; } /* * FindObject * Get pData characteristics from pData->Path * Return TRUE if object was found * -------------------------------------------------------------------------- */ int FindObject(HIDDesc_t *pDesc_arg, HIDData_t *pData) { HIDData_t *pFoundData = FindObject_with_Path(pDesc_arg, &pData->Path, pData->Type); if (!pFoundData) { return 0; } memcpy(pData, pFoundData, sizeof(*pData)); return 1; } /* * FindObject_with_Path * Get pData item with given Path and Type. Return NULL if not found. * -------------------------------------------------------------------------- */ HIDData_t *FindObject_with_Path(HIDDesc_t *pDesc_arg, HIDPath_t *Path, uint8_t Type) { size_t i; for (i = 0; i < pDesc_arg->nitems; i++) { HIDData_t *pData = &pDesc_arg->item[i]; if (pData->Type != Type) { continue; } if (memcmp(pData->Path.Node, Path->Node, (Path->Size) * sizeof(HIDNode_t))) { continue; } return pData; } return NULL; } /* * FindObject_with_ID * Get pData item with given ReportID, Offset, and Type. Return NULL * if not found. * -------------------------------------------------------------------------- */ HIDData_t *FindObject_with_ID(HIDDesc_t *pDesc_arg, uint8_t ReportID, uint8_t Offset, uint8_t Type) { size_t i; for (i = 0; i < pDesc_arg->nitems; i++) { HIDData_t *pData = &pDesc_arg->item[i]; if (pData->ReportID != ReportID) { continue; } if (pData->Type != Type) { continue; } if (pData->Offset != Offset) { continue; } return pData; } return NULL; } /* * FindObject_with_ID_Node * Get pData item with given ReportID and Node. Return NULL if not found. * -------------------------------------------------------------------------- */ HIDData_t *FindObject_with_ID_Node(HIDDesc_t *pDesc_arg, uint8_t ReportID, HIDNode_t Node) { size_t i; for (i = 0; i < pDesc_arg->nitems; i++) { HIDData_t *pData = &pDesc_arg->item[i]; HIDPath_t *pPath; uint8_t size; if (pData->ReportID != ReportID) { continue; } pPath = &pData->Path; size = pPath->Size; if (size == 0 || pPath->Node[size-1] != Node) { continue; } return pData; } return NULL; } /* * GetValue * Extract data from a report stored in Buf. * Use Offset, Size, LogMin, and LogMax of pData. * Return response in *pValue. * -------------------------------------------------------------------------- */ void GetValue(const unsigned char *Buf, HIDData_t *pData, long *pValue) { /* Note: https://github.com/networkupstools/nut/issues/1023 This conversion code can easily be sensitive to 32- vs 64- bit compilation environments. Consider the possibility of overflow in 32-bit representations when computing with extreme values, for example LogMax-LogMin+1. Test carefully in both environments if changing any declarations. */ int Weight, Bit; unsigned long mask, signbit, magMax, magMin; long value = 0; Bit = pData->Offset + 8; /* First byte of report is report ID */ for (Weight = 0; Weight < pData->Size; Weight++, Bit++) { int State = Buf[Bit >> 3] & (1 << (Bit & 7)); if(State) { value += (1L << Weight); } } /* translate Value into a signed/unsigned value in the range LogMin..LogMax, as appropriate. See HID spec, p.38: "If both the Logical Minimum and Logical Maximum extents are defined as positive values (0 or greater), then the report field can be assumed to be an unsigned value. Otherwise, all integer values are signed values represented in 2's complement format." Also note that the variable can take values from LogMin (inclusive) to LogMax (inclusive), so there are LogMax - LogMin + 1 possible values. Special cases arise if the value that has been read lies outside the interval LogMin..LogMax. Some devices, notably the APC Back-UPS BF500, do this. In one case I observed, LogMin=0, LogMax=0xffff, Size=32, and the supplied value is 0xffffffff80080a00. Presumably they expect us to throw away the higher-order bits, and use 0x0a00, rather than choosing the closest value in the interval, which would be 0xffff. However, if LogMax - LogMin + 1 isn't a power of 2, it is not clear what "throwing away higher-order bits" exacly means, so we try to do something sensible. -PS */ /* determine representation without sign bit */ magMax = pData->LogMax >= 0 ? (unsigned long)(pData->LogMax) : (unsigned long)(-(pData->LogMax + 1)); magMin = pData->LogMin >= 0 ? (unsigned long)(pData->LogMin) : (unsigned long)(-(pData->LogMin + 1)); /* calculate where the sign bit will be if needed */ signbit = 1L << hibit(magMax > magMin ? magMax : magMin); /* but only include sign bit in mask if negative numbers are involved */ mask = (signbit - 1) | ((pData->LogMin < 0) ? signbit : 0); /* throw away excess high order bits (which may contain garbage) */ value = (long)((unsigned long)(value) & mask); /* sign-extend it, if appropriate */ if (pData->LogMin < 0 && ((unsigned long)(value) & signbit) != 0) { value |= ~mask; } /* clamp returned value to range [LogMin..LogMax] */ if (value < pData->LogMin) { value = pData->LogMin; } else if (value > pData->LogMax) { value = pData->LogMax; } *pValue = value; return; } /* * SetValue * Set a data in a report stored in Buf. Use Value, Offset and Size of pData. * Return response in Buf. * -------------------------------------------------------------------------- */ void SetValue(const HIDData_t *pData, unsigned char *Buf, long Value) { int Weight, Bit; Bit = pData->Offset + 8; /* First byte of report is report ID */ for (Weight = 0; Weight < pData->Size; Weight++, Bit++) { long State = Value & (1L << Weight); if (State) { Buf[Bit >> 3] |= (1 << (Bit & 7)); } else { Buf[Bit >> 3] &= ~(1 << (Bit & 7)); } } } /* ---------------------------------------------------------------------- */ /* parse HID Report Descriptor. Input: byte array ReportDesc[n]. Output: parsed data structure. Returns allocated HIDDesc structure on success, NULL on failure with errno set. Note: the value returned by this function must be freed with Free_ReportDesc(). */ HIDDesc_t *Parse_ReportDesc(const usb_ctrl_charbuf ReportDesc, const usb_ctrl_charbufsize n) { int ret = 0; HIDDesc_t *pDesc_var; HIDParser_t *parser; pDesc_var = calloc(1, sizeof(*pDesc_var)); #if (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_PUSH_POP) && ( (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_TYPE_LIMITS) || (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_TAUTOLOGICAL_CONSTANT_OUT_OF_RANGE_COMPARE) || (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_TAUTOLOGICAL_UNSIGNED_ZERO_COMPARE) || (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_UNREACHABLE_CODE) ) # pragma GCC diagnostic push #endif #ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_TYPE_LIMITS # pragma GCC diagnostic ignored "-Wtype-limits" #endif #ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_TAUTOLOGICAL_CONSTANT_OUT_OF_RANGE_COMPARE # pragma GCC diagnostic ignored "-Wtautological-constant-out-of-range-compare" #endif #ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_TAUTOLOGICAL_UNSIGNED_ZERO_COMPARE # pragma GCC diagnostic ignored "-Wtautological-unsigned-zero-compare" #endif #ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_UNREACHABLE_CODE #pragma GCC diagnostic ignored "-Wunreachable-code" #endif /* Older CLANG (e.g. clang-3.4) seems to not support the GCC pragmas above */ #ifdef __clang__ #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wunreachable-code" #pragma clang diagnostic ignored "-Wtautological-compare" #pragma clang diagnostic ignored "-Wtautological-constant-out-of-range-compare" #endif if (!pDesc_var || n < 0 || (uintmax_t)n > SIZE_MAX ) { return NULL; } #ifdef __clang__ #pragma clang diagnostic pop #endif #if (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_PUSH_POP) && ( (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_TYPE_LIMITS) || (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_TAUTOLOGICAL_CONSTANT_OUT_OF_RANGE_COMPARE) || (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_TAUTOLOGICAL_UNSIGNED_ZERO_COMPARE) || (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_UNREACHABLE_CODE) ) # pragma GCC diagnostic pop #endif pDesc_var->item = calloc(MAX_REPORT, sizeof(*pDesc_var->item)); if (!pDesc_var->item) { Free_ReportDesc(pDesc_var); return NULL; } parser = calloc(1, sizeof(*parser)); if (!parser) { Free_ReportDesc(pDesc_var); return NULL; } parser->ReportDesc = (const unsigned char *)ReportDesc; parser->ReportDescSize = (const size_t)n; for (pDesc_var->nitems = 0; pDesc_var->nitems < MAX_REPORT; pDesc_var->nitems += (size_t)ret) { uint8_t id; size_t max; ret = HIDParse(parser, &pDesc_var->item[pDesc_var->nitems]); if (ret < 0) { break; } id = pDesc_var->item[pDesc_var->nitems].ReportID; /* calculate bit range of this item within report */ max = pDesc_var->item[pDesc_var->nitems].Offset + pDesc_var->item[pDesc_var->nitems].Size; /* convert to bytes */ max = (max + 7) >> 3; /* update report length */ if (max > pDesc_var->replen[id]) { pDesc_var->replen[id] = max; } } /* Sanity check: are there remaining HID objects that can't * be processed? */ if ((pDesc_var->nitems == MAX_REPORT) && (parser->Pos < parser->ReportDescSize)) upslogx(LOG_ERR, "ERROR in %s: Too many HID objects", __func__); free(parser); if (pDesc_var->nitems == 0) { Free_ReportDesc(pDesc_var); return NULL; } pDesc_var->item = realloc(pDesc_var->item, pDesc_var->nitems * sizeof(*pDesc_var->item)); return pDesc_var; } /* free a parsed report descriptor, as allocated by Parse_ReportDesc() */ void Free_ReportDesc(HIDDesc_t *pDesc_arg) { if (!pDesc_arg) { return; } free(pDesc_arg->item); free(pDesc_arg); } nut-2.8.1/drivers/hpe-pdu-mib.h0000644000175000017500000000206714377374134013231 00000000000000/* hpe-pdu-mib.h - subdriver to monitor HPE ePDU SNMP devices with NUT * * Copyright (C) * 2011 - 2016 Arnaud Quette * 2019 Arnaud Quette * * 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 2 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, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef HPE_EPDU_MIB_H #define HPE_EPDU_MIB_H #include "main.h" #include "snmp-ups.h" extern mib2nut_info_t hpe_pdu; #endif /* HPE_EPDU_MIB_H */ nut-2.8.1/drivers/bestfortress.c0000644000175000017500000004144614501607135013633 00000000000000/* bestfortress.c - model specific routines for (very) old Best Power Fortress Copyright (C) 2002 Russell Kroll (skeleton) (C) 2002 Holger Dietze (C) 2009 Stuart D. Gathman 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 2 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, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include "main.h" #include "serial.h" #include "nut_stdint.h" #define UPSDELAY 50000 /* 50 ms delay required for reliable operation */ #define SER_WAIT_SEC 2 /* allow 2.0 sec for ser_get calls */ #define SER_WAIT_USEC 0 #define ENDCHAR '\r' #define IGNCHARS " \n" #if defined(__sgi) && ! defined(__GNUC__) #define inline __inline #endif #define DRIVER_NAME "Best Fortress UPS driver" #define DRIVER_VERSION "0.08" /* driver description structure */ upsdrv_info_t upsdrv_info = { DRIVER_NAME, DRIVER_VERSION, "Holger Dietze \n" "Stuart D. Gathman \n", DRV_EXPERIMENTAL, { NULL } }; /* * Choose 20s for off delay, reading the tea leaves from other drivers. */ static const char *shutdown_delay = "20"; /* * Logging plan: * CRIT: executing poweroff * ERR: indicates a bug in nut * WARNING: indicates a serious misconfiguration that will cause nut * to fail to function * NOTICE: rare situations without a planned reporting path (none so * far) * INFO: One message each for startup, first establishment of comms * DEBUG: Loss/restore of comms, and perhaps things that are normally * reported via other daemons (on battery, low battery) * D1: Things that happen rarely (startup/shutdown, param set, instant * commands) * D2: ? * D3: trace of communications * D4: more io than necessary to see working communications * D5: log even succesful acks */ static int instcmd (const char *cmdname, const char *extra); static int upsdrv_setvar (const char *varname, const char *val); /* Rated maximum VA output as configured by the user. */ static int maxload = 0; /* * NB: Not called for shutdown. */ void upsdrv_initinfo(void) { dstate_setinfo("ups.mfr", "Best Power"); dstate_setinfo("ups.model", "Fortress"); dstate_setinfo("battery.voltage.nominal", "24"); /*dstate_setinfo ("alarm.overload", "0");*/ /* Flag */ /*dstate_setinfo ("alarm.temp", "0");*/ /* Flag */ if (maxload) dstate_setinfo("ups.load", "0"); dstate_setinfo("output.voltamps", "0"); /* tunable via front panel: (european voltage level) parameter factory default range INFO_LOWXFER 196 V p7=nnn 160-210 INFO_HIGHXFER 254 V p8=nnn 215-274 INFO_LOBATTIME 2 min p2=n 1-5 comm mode p6=0 dumb DONT USE (will lose access to parameter setting!) p6=1 B1200 p6=2 B2400 P6=3 B4800 p6=4 B9600 maybe cycle through speeds to autodetect? echo off e0 echo on e1 */ dstate_setinfo("input.transfer.low", "%s", ""); dstate_setflags("input.transfer.low", ST_FLAG_STRING | ST_FLAG_RW); dstate_setaux("input.transfer.low", 3); dstate_setinfo("input.transfer.high", "%s", ""); dstate_setflags("input.transfer.high", ST_FLAG_STRING | ST_FLAG_RW); dstate_setaux("input.transfer.high", 3); dstate_setinfo("battery.runtime.low", "%s", ""); dstate_setflags("battery.runtime.low", ST_FLAG_STRING | ST_FLAG_RW); dstate_setaux("battery.runtime.low", 3); upsh.instcmd = instcmd; upsh.setvar = upsdrv_setvar; dstate_addcmd("shutdown.return"); dstate_addcmd("load.off"); } /* convert hex digit to int */ static inline int fromhex (char c) { return (c >= '0' && c <= '9') ? c - '0' : (c >= 'A' && c <= 'F') ? c - 'A' + 10 : (c >= 'a' && c <= 'f') ? c - 'a' + 10 : 0; } /* do checksumming on UPS response */ static int checksum (char * s) { int i; int sum; for (i = 40, sum = 0; s[0] && s[1] && i > 0; i--, s += 2) { sum += (fromhex (s[0]) << 4) + fromhex (s[1]); } return sum; } /* set info to integer value */ static inline int setinfo_int (const char *key, const char * s, size_t len) { char buf[10]; int val; if (len > sizeof(buf)) len = sizeof(buf)-1; strncpy (buf, s, len); buf[len] = 0; val = atoi(buf); dstate_setinfo (key, "%d", val); return val; } /* set info to integer value (for runtime remaining) value is expressed in minutes, but desired in seconds */ static inline void setinfo_int_minutes (const char *key, const char * s, size_t len) { char buf[10]; if (len > sizeof(buf)) len = sizeof(buf)-1; strncpy (buf, s, len); buf[len] = 0; dstate_setinfo (key, "%d", 60*atoi (buf)); } /* set info to float value */ static inline void setinfo_float (const char *key, const char * fmt, const char * s, size_t len, double factor) { char buf[10]; if (len > sizeof(buf)) len = sizeof(buf)-1; strncpy (buf, s, len); buf[len] = 0; #ifdef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL #pragma GCC diagnostic push #endif #ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL #pragma GCC diagnostic ignored "-Wformat-nonliteral" #endif #ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_FORMAT_SECURITY #pragma GCC diagnostic ignored "-Wformat-security" #endif dstate_setinfo (key, fmt, factor * (double)(atoi (buf))); #ifdef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL #pragma GCC diagnostic pop #endif } static int upssend(const char *fmt,...) { int ret; char buf[1024], *p; va_list ap; unsigned int sent = 0; useconds_t d_usec = UPSDELAY; va_start(ap, fmt); #ifdef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL #pragma GCC diagnostic push #endif #ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL #pragma GCC diagnostic ignored "-Wformat-nonliteral" #endif #ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_FORMAT_SECURITY #pragma GCC diagnostic ignored "-Wformat-security" #endif ret = vsnprintf(buf, sizeof(buf), fmt, ap); #ifdef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL #pragma GCC diagnostic pop #endif va_end(ap); /* Why do we not upsflushin here? */ upsdebugx(3, "%s: sending %d bytes <%s>", __func__, ret, buf); if ((ret < 1) || (ret >= (int) sizeof(buf))) upslogx(LOG_ERR, "%s: vsnprintf needed more than %d bytes", __func__, (int) sizeof(buf)); for (p = buf; *p && sent < INT_MAX - 1; p++) { #ifndef WIN32 if (write(upsfd, p, 1) != 1) #else DWORD bytes_written; BOOL res; res = WriteFile(upsfd, p, 1, &bytes_written,NULL); if (res == 0 || bytes_written == 0) #endif return -1; /* Note: LGTM.com analysis warns that here * "Comparison is always true because d_usec >= 2" * since we initialize with UPSDELAY above. * Do not remove this check just in case that * initialization changes, or run-time value * becomes modified, in later iterations. */ if (d_usec > 0) usleep(d_usec); sent++; if (sent >= INT_MAX) { upslogx(LOG_ERR, "%s: sent >= INT_MAX, aborting", __func__); } } if (ret != (int) sent) { upsdebugx(1, "%s: ret %d != sent %u", __func__, ret, sent); } return (int)sent; } static ssize_t upsrecv(char *buf,size_t bufsize,char ec,const char *ic) { ssize_t nread; nread = ser_get_line(upsfd, buf, bufsize - 1, ec, ic, SER_WAIT_SEC, SER_WAIT_USEC); /* \todo is buf null terminated? */ upsdebugx(4, "%s: read %" PRIiSIZE " <%s>", __func__, nread, buf); return nread; } static ssize_t upsflushin(int f, int verbose, const char *ignset) { NUT_UNUSED_VARIABLE(f); upsdebugx(4, "%s: begin", __func__); return ser_flush_in(upsfd, ignset, verbose); } /* read out UPS and store info */ void upsdrv_updateinfo(void) { char temp[256]; char *p = NULL; int loadva; size_t len = 0; ssize_t recv; int retry; char ch; int checksum_ok = -1, is_online = 1, is_off, low_batt, trimming, boosting; upsdebugx(2, "%s: begin", __func__); for (retry = 0; retry < 5; ++retry) { upsflushin (0, 0, "\r "); upssend ("f\r"); while (ser_get_char(upsfd, &ch, 0, UPSDELAY) > 0 && ch != '\n'); /* response starts with \r\n */ temp[2] = 0; do { if ((recv = upsrecv (temp+2, sizeof temp - 2, ENDCHAR, IGNCHARS)) <= 0) { upsdebugx(1, "%s: upsrecv failed, " "retrying without counting", __func__); upsflushin (0, 0, "\r "); upssend ("f\r"); while (ser_get_char(upsfd, &ch, 0, UPSDELAY) > 0 && ch != '\n'); /* response starts with \r\n */ } } while (temp[2] == 0); upsdebugx(3, "%s: received %" PRIiSIZE " bytes (try %i)", __func__, recv, retry); /* syslog (LOG_DAEMON | LOG_NOTICE,"ups: got %d chars '%s'\n", recv, temp + 2); */ /* status example: 000000000001000000000000012201210000001200014500000280600000990025000000000301BE 000000000001000000000000012401230000001200014800000280600000990025000000000301B7 |Vi||Vo| |Io||Psou| |Vb||f| |tr||Ti| CS 000000000001000000000000023802370000000200004700000267500000990030000000000301BD 1 1 2 2 3 3 4 4 5 5 6 6 7 7 78 0 5 0 5 0 5 0 5 0 5 0 5 0 5 0 5 90 */ /* last bytes are a checksum: interpret response as hex string, sum of all bytes must be zero */ checksum_ok = ( (checksum (temp+2) & 0xff) == 0 ); /* setinfo (INFO_, ""); */ if (!checksum_ok) { upsdebug_hex(5, "upsdrv_updateinfo: " "checksum failure buffer hex", temp, (size_t)recv); upsdebug_ascii(5, "upsdrv_updateinfo: " "checksum failure buffer ascii", temp, (size_t)recv); } /* I can't figure out why this is missing the first two chars. But the first two chars are not used, so just set them to zero when missing. */ len = strlen(temp+2); temp[0] = '0'; temp[1] = '0'; p = temp+2; if (len == 78) p = temp; else if (len != 80) checksum_ok = 0; if (checksum_ok) break; upsdebugx(1, "%s: failed to read status try %d", __func__, retry); sleep(SER_WAIT_SEC); } if (!p || len < 1 || checksum_ok < 0) { /* \todo: Analyze/fix code and rewrite message. */ upsdebugx(2, "%s: pointer to data not initialized after processing", __func__); dstate_datastale(); return; } if (!checksum_ok) { upsdebugx(2, "%s: checksum corruption", __func__); upsdebug_hex(3, "buffer", temp, (size_t)len); dstate_datastale(); return; } /* Log assuming ASCII which it 99% is. \todo Improve. */ upsdebugx(3, "%s: %s", __func__, p); setinfo_int ("input.voltage", p+24,4); setinfo_int ("output.voltage", p+28,4); setinfo_float ("battery.voltage", "%.1f", p+50,4, 0.1); setinfo_float ("output.current", "%.1f", p+36,4, 0.1); loadva = setinfo_int ("output.voltamps", p+40,6); if (maxload) dstate_setinfo ("ups.load", "%d", loadva * 100 / maxload); setinfo_float ("input.frequency", "%.1f", p+54,3, 0.1); setinfo_int_minutes ("battery.runtime", p+58,4); setinfo_int ("ups.temperature", p+62,4); is_online = p[17] == '0'; low_batt = fromhex(p[21]) & 8 || fromhex(p[20]) & 1; is_off = p[11] == '0'; trimming = p[33] == '1'; boosting = 0; /* FIXME, don't know which bit gets set (brownouts are very rare here and I can't simulate one) */ status_init(); if (low_batt) status_set("LB "); else if (trimming) status_set("TRIM"); else if (boosting) status_set("BOOST"); else status_set(is_online ? (is_off ? "OFF " : "OL ") : "OB "); /* setinfo(INFO_STATUS, "%s%s", * (util < lownorm) ? "BOOST ", "", * (util > highnorm) ? "TRIM ", "", * ((flags & TIOCM_CD) == 0) ? "" : "LB ", * ((flags & TIOCM_CTS) == TIOCM_CTS) ? "OB" : "OL"); */ status_commit(); dstate_dataok(); } /* Parameter setting */ /* all UPS tunable parameters are set with command 'p%d=%s' */ static int setparam (int parameter, int dlen, const char * data) { char reply[80]; upsdebugx(2, "%s: begin", __func__); /* Note the use of "%*s" - parameter (int)dlen specifies * the string width reserved for data */ upssend ("p%d=%*s\r", parameter, dlen, data); if (upsrecv (reply, sizeof(reply), ENDCHAR, "") < 0) { upsdebugx(1, "%s: did not get reply", __func__); return 0; } if (strncmp (reply, "OK", 2) == 0) { upsdebugx(5, "%s: reply OK", __func__); return 1; } else { upsdebugx(1, "%s: reply NOT ok", __func__); return 0; } } /* ups_setsuper: set super-user access (allows setting variables) */ static void ups_setsuper (int super) { setparam (999, super ? 4 : 0, super ? "2639" : ""); } /* sets whether UPS will reapply power after it has shut down and line * power returns. */ static void autorestart (int restart) { ups_setsuper (1); setparam (1, 1, restart ? "1" : "0"); ups_setsuper (0); } /* set UPS parameters */ static int upsdrv_setvar (const char *var, const char * data) { int parameter; size_t len = strlen(data); upsdebugx(1, "%s: %s %s (%" PRIuSIZE " bytes)", __func__, var, data, len); if (strcmp("input.transfer.low", var) == 0) { parameter = 7; } else if (strcmp("input.transfer.high", var) == 0) { parameter = 8; } else if (strcmp("battery.runtime.low", var) == 0) { parameter = 2; } else { /* * \todo Figure out if we get here by a code error or * by the user asking for a variable that does not * exist. If the former, change to LOG_ERR and if the * latter change to LOG_DEBUG. */ upslogx(LOG_INFO, "%s: unsettable variable %s", __func__, var); return STAT_SET_UNKNOWN; } ups_setsuper (1); assert (len < INT_MAX); if (setparam (parameter, (int)len, data)) { dstate_setinfo (var, "%*s", (int)len, data); } ups_setsuper (0); return STAT_SET_HANDLED; } /* * The "power down and maybe return command" is "OFF %d\r", with a * delay in seconds before poweroff. As a special case, "OFF 0" does * not shut down. The UPS will power on the load when power returns * (or after a delay if power is not out), according to the front panel * parameter, or the value set via `autorestart()`. */ /* * This is equivalent to the `shutdown.return` instant command, but * invoked with `-k`. * \todo Reduce duplication. */ void upsdrv_shutdown(void) { const char *grace; upsdebugx(2, "%s: begin", __func__); grace = dstate_getinfo("ups.delay.shutdown"); if (!grace) { upsdebugx(1, "%s: ups.delay.shutdown is NULL!", __func__); /* Pick a different value than 20 so we can see it in the logs. */ grace = "30"; } upslogx(LOG_CRIT, "%s: OFF/restart in %s seconds", __func__, grace); /* Start again, overriding front panel setting. */ autorestart (1); upssend ("OFF%s\r", grace); /* I'm nearly dead, Jim */ upsdebugx(2, "%s: end", __func__); } static int instcmd (const char *cmdname, const char *extra) { if (!strcasecmp(cmdname, "load.off")) { upslogx(LOG_CRIT, "%s: %s: OFF/stayoff in 1s", __func__, cmdname); autorestart (0); upssend ("OFF1\r"); return STAT_INSTCMD_HANDLED; } else if (!strcasecmp(cmdname, "shutdown.return")) { upsdebugx(2, "%s: %s: start", __func__, cmdname); upsdrv_shutdown(); return STAT_INSTCMD_HANDLED; } /* \todo Software error or user error? */ upslogx(LOG_ERR, "%s: unknown command [%s] [%s]", __func__, cmdname, extra); return STAT_INSTCMD_UNKNOWN; } void upsdrv_help(void) { } /* list flags and values that you want to receive via -x */ void upsdrv_makevartable(void) { addvar (VAR_VALUE, "baudrate", "serial line speed"); addvar (VAR_VALUE, "max_load", "rated VA load VA"); } static struct { const char * val; speed_t speed; } speed_table[] = { {"1200", B1200}, {"2400", B2400}, {"4800", B4800}, {"9600", B9600}, {NULL, B1200}, }; /* * Called first, for normal operation and for shutdown. */ void upsdrv_initups(void) { speed_t speed = B1200; char * speed_val = getval("baudrate"); char * max_load = getval("max_load"); upsdebugx(1, "%s: begin", __func__); if (max_load) maxload = atoi(max_load); if (speed_val) { int i; for (i=0; speed_table[i].val; i++) { if (strcmp (speed_val, speed_table[i].val) == 0) break; } speed = speed_table[i].speed; } upsfd = ser_open(device_path); if (INVALID_FD(upsfd)) { upslogx(LOG_WARNING, "%s: failed to open %s", __func__, device_path); /* \todo: Deal with the failure */ } /* ser_set_speed returns int 0 always; fatal if ioctl fails */ ser_set_speed(upsfd, device_path, speed); upsdebugx(1, "%s: opened %s speed %s upsfd %d", __func__, device_path, speed_val ? speed_val : "DEFAULT", upsfd); /* Set early so that it is in place for shutdown. */ dstate_setinfo("ups.delay.shutdown", "%s", shutdown_delay); upsdebugx(1, "%s: end", __func__); } void upsdrv_cleanup(void) { upsdebugx(1, "%s: begin/end", __func__); } nut-2.8.1/drivers/eaton-ups-pxg-mib.c0000644000175000017500000011533214501607135014356 00000000000000/* eaton-ups-pxg-mib.c - data to monitor Eaton / Powerware PXG UPS with NUT * (using MIBs described in stdupsv1.mib and Xups.mib) * * Copyright (C) * 2005-2006 Olli Savia * 2005-2006 Niels Baggesen * 2015-2022 Eaton (author: Arnaud Quette ) * * 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 2 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, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #include "eaton-ups-pxg-mib.h" #if WITH_SNMP_LKP_FUN /* FIXME: shared helper code, need to be put in common */ #include "eaton-pdu-marlin-helpers.h" #endif #define EATON_PXG_MIB_VERSION "0.105" /* Powerware UPS newer PXGX UPS cards (BladeUPS, ...) */ #define EATON_PXGX_SYSOID ".1.3.6.1.4.1.534.2.12" /* SNMP OIDs set */ #define PW_OID_MFR_NAME "1.3.6.1.4.1.534.1.1.1.0" /* XUPS-MIB::xupsIdentManufacturer.0 */ #define PW_OID_MODEL_NAME "1.3.6.1.4.1.534.1.1.2.0" /* XUPS-MIB::xupsIdentModel.0 */ #define PW_OID_FIRMREV "1.3.6.1.4.1.534.1.1.3.0" /* XUPS-MIB::xupsIdentSoftwareVersion.0 */ #define PW_OID_BATT_RUNTIME "1.3.6.1.4.1.534.1.2.1.0" /* XUPS-MIB::xupsBatTimeRemaining.0 */ #define PW_OID_BATT_VOLTAGE "1.3.6.1.4.1.534.1.2.2.0" /* XUPS-MIB::xupsBatVoltage.0 */ #define PW_OID_BATT_CURRENT "1.3.6.1.4.1.534.1.2.3.0" /* XUPS-MIB::xupsBatCurrent.0 */ #define PW_OID_BATT_CHARGE "1.3.6.1.4.1.534.1.2.4.0" /* XUPS-MIB::xupsBatCapacity.0 */ #define PW_OID_BATT_STATUS "1.3.6.1.4.1.534.1.2.5.0" /* XUPS-MIB::xupsBatteryAbmStatus.0 */ #define PW_OID_IN_FREQUENCY "1.3.6.1.4.1.534.1.3.1.0" /* XUPS-MIB::xupsInputFrequency.0 */ #define PW_OID_IN_LINE_BADS "1.3.6.1.4.1.534.1.3.2.0" /* XUPS-MIB::xupsInputLineBads.0 */ #define PW_OID_IN_LINES "1.3.6.1.4.1.534.1.3.3.0" /* XUPS-MIB::xupsInputNumPhases.0 */ #define PW_OID_IN_VOLTAGE "1.3.6.1.4.1.534.1.3.4.1.2" /* XUPS-MIB::xupsInputVoltage */ #define PW_OID_IN_CURRENT "1.3.6.1.4.1.534.1.3.4.1.3" /* XUPS-MIB::xupsInputCurrent */ #define PW_OID_IN_POWER "1.3.6.1.4.1.534.1.3.4.1.4" /* XUPS-MIB::xupsInputWatts */ #define PW_OID_OUT_LOAD "1.3.6.1.4.1.534.1.4.1.0" /* XUPS-MIB::xupsOutputLoad.0 */ #define PW_OID_OUT_FREQUENCY "1.3.6.1.4.1.534.1.4.2.0" /* XUPS-MIB::xupsOutputFrequency.0 */ #define PW_OID_OUT_LINES "1.3.6.1.4.1.534.1.4.3.0" /* XUPS-MIB::xupsOutputNumPhases.0 */ #define PW_OID_OUT_VOLTAGE "1.3.6.1.4.1.534.1.4.4.1.2" /* XUPS-MIB::xupsOutputVoltage */ #define PW_OID_OUT_CURRENT "1.3.6.1.4.1.534.1.4.4.1.3" /* XUPS-MIB::xupsOutputCurrent */ #define PW_OID_OUT_POWER "1.3.6.1.4.1.534.1.4.4.1.4" /* XUPS-MIB::xupsOutputWatts */ #define PW_OID_POWER_STATUS "1.3.6.1.4.1.534.1.4.5.0" /* XUPS-MIB::xupsOutputSource.0 */ #define PW_OID_BY_FREQUENCY "1.3.6.1.4.1.534.1.5.1.0" /* XUPS-MIB::xupsBypassFrequency.0 */ #define PW_OID_BY_LINES "1.3.6.1.4.1.534.1.5.2.0" /* XUPS-MIB::xupsBypassNumPhases.0 */ #define PW_OID_BY_VOLTAGE "1.3.6.1.4.1.534.1.5.3.1.2" /* XUPS-MIB::xupsBypassVoltage */ #define PW_OID_BATTEST_START "1.3.6.1.4.1.534.1.8.1" /* XUPS-MIB::xupsTestBattery set to startTest(1) to initiate test*/ #define PW_OID_CONT_OFFDELAY "1.3.6.1.4.1.534.1.9.1.0" /* XUPS-MIB::xupsControlOutputOffDelay */ #define PW_OID_CONT_ONDELAY "1.3.6.1.4.1.534.1.9.2.0" /* XUPS-MIB::xupsControlOutputOnDelay */ #define PW_OID_CONT_OFFT_DEL "1.3.6.1.4.1.534.1.9.3" /* XUPS-MIB::xupsControlOutputOffTrapDelay */ #define PW_OID_CONT_ONT_DEL "1.3.6.1.4.1.534.1.9.4" /* XUPS-MIB::xupsControlOutputOnTrapDelay */ #define PW_OID_CONT_LOAD_SHED_AND_RESTART "1.3.6.1.4.1.534.1.9.6" /* XUPS-MIB::xupsLoadShedSecsWithRestart */ #define PW_OID_CONF_OVOLTAGE "1.3.6.1.4.1.534.1.10.1.0" /* XUPS-MIB::xupsConfigOutputVoltage.0 */ #define PW_OID_CONF_IVOLTAGE "1.3.6.1.4.1.534.1.10.2.0" /* XUPS-MIB::xupsConfigInputVoltage.0 */ #define PW_OID_CONF_POWER "1.3.6.1.4.1.534.1.10.3.0" /* XUPS-MIB::xupsConfigOutputWatts.0 */ #define PW_OID_CONF_FREQ "1.3.6.1.4.1.534.1.10.4.0" /* XUPS-MIB::xupsConfigOutputFreq.0 */ #define PW_OID_ALARMS "1.3.6.1.4.1.534.1.7.1.0" /* XUPS-MIB::xupsAlarms */ #define PW_OID_ALARM_OB "1.3.6.1.4.1.534.1.7.3" /* XUPS-MIB::xupsOnBattery */ #define PW_OID_ALARM_LB "1.3.6.1.4.1.534.1.7.4" /* XUPS-MIB::xupsLowBattery */ #define IETF_OID_AGENTREV "1.3.6.1.2.1.33.1.1.4.0" /* UPS-MIB::upsIdentAgentSoftwareVersion.0 */ #define IETF_OID_IDENT "1.3.6.1.2.1.33.1.1.5.0" /* UPS-MIB::upsIdentName.0 */ #define IETF_OID_CONF_OUT_VA "1.3.6.1.2.1.33.1.9.5.0" /* UPS-MIB::upsConfigOutputVA.0 */ #define IETF_OID_CONF_RUNTIME_LOW "1.3.6.1.2.1.33.1.9.7.0" /* UPS-MIB::upsConfigLowBattTime.0 */ #define IETF_OID_LOAD_LEVEL "1.3.6.1.2.1.33.1.4.4.1.5" /* UPS-MIB::upsOutputPercentLoad */ #define IETF_OID_AUTO_RESTART "1.3.6.1.2.1.33.1.8.5.0" /* UPS-MIB::upsAutoRestart */ /* Delay before powering off in seconds */ #define DEFAULT_OFFDELAY 30 /* Delay before powering on in seconds */ #define DEFAULT_ONDELAY 20 /* Default shutdown.return delay in seconds */ #define DEFAULT_SHUTDOWNDELAY 0 static info_lkp_t pw_alarm_ob[] = { { 1, "OB", NULL, NULL }, { 2, "", NULL, NULL }, { 0, NULL, NULL, NULL } }; static info_lkp_t pw_alarm_lb[] = { { 1, "LB", NULL, NULL }, { 2, "", NULL, NULL }, { 0, NULL, NULL, NULL } }; static info_lkp_t pw_pwr_info[] = { { 0, "OFF" /* off */, NULL, NULL }, { 1, "OL" /* systemNormal */, NULL, NULL }, { 2, "OL" /* systemNormalUPSRedundant */, NULL, NULL }, { 3, "OL" /* systemNormalNotRedundant */, NULL, NULL }, { 4, "OB" /* systemOnDCSource*/, NULL, NULL }, { 5, "OB LB" /* systemOnDCSourceShutdownImminent */, NULL, NULL }, { 6, "OL" /* systemNormalBypassNotAvailable */, NULL, NULL }, { 7, "OL" /* systemNormalOnLine */, NULL, NULL }, { 8, "OL" /* systemNormalEnergySaverSystem */, NULL, NULL }, { 9, "OL" /* systemNormalVMMS */, NULL, NULL }, { 10, "OL" /* systemNormalHRS */, NULL, NULL }, { 13, "OL OVER" /* outputOverload */, NULL, NULL }, { 14, "OL TRIM" /* systemNormalOnBuck */, NULL, NULL }, { 15, "OL BOOST" /* systemNormalOnBoost */, NULL, NULL }, { 16, "BYPASS" /* onBypass */, NULL, NULL }, { 17, "BYPASS" /* onBypassStarting */, NULL, NULL }, { 18, "BYPASS" /* onBypassReady */, NULL, NULL }, { 32, "BYPASS" /* onMaintenanceBypass */, NULL, NULL }, { 33, "OL BYPASS" /* onMBSUPSOnLine */, NULL, NULL }, { 34, "BYPASS" /* onMBSUPSOnBypass */, NULL, NULL }, { 35, "OFF BYPASS" /* onMBSUPSOff */, NULL, NULL }, { 36, "OB BYPASS" /* onMBSUPSOnBattery */, NULL, NULL }, { 37, "OL" /* onMBSUPSOnLineESS */, NULL, NULL }, { 38, "OL" /* onMBSUPSOnLineVMMS */, NULL, NULL }, { 39, "OL" /* onMBSUPSOnLineHRS */, NULL, NULL }, { 40, "OL" /* onMBSStarting */, NULL, NULL }, { 41, "OL" /* onMBSReady */, NULL, NULL }, { 48, "OFF" /* loadOff */, NULL, NULL }, { 49, "OFF" /* loadOffStarting */, NULL, NULL }, { 50, "OFF" /* loadOffReady */, NULL, NULL }, { 64, "OL" /* supportingLoad */, NULL, NULL }, { 80, "OL" /* systemNormalSP */, NULL, NULL }, { 81, "OL" /* systemNormalEnergySaverSystemSP */, NULL, NULL }, { 96, "BYPASS" /* systemOnBypassSP */, NULL, NULL }, { 100, "BYPASS" /* systemOnManualMaintenanceBypassSP (0x64) */, NULL, NULL }, { 224, "OL OVER" /* loadSegmentOverload (0x64) */, NULL, NULL }, { 240, "OB" /* systemOnDCSourceSP */, NULL, NULL }, { 241, "OFF" /* systemOffSP */, NULL, NULL }, { 0, NULL, NULL, NULL } }; /* FIXME: mapped to (experimental.)ups.type, but * should be output.source or ups.mode (need RFC) * to complement the above ups.status * along with having ups.type as described hereafter*/ /* FIXME: should be used by ups.mode or output.source (need RFC); * Note: this define is not set via project options; code was hidden with * original commit to "snmp-ups: support newer Genepi management cards"; * un-hidden to make it "experimental.*" namespace during backporting */ #ifndef USE_PW_MODE_INFO # define USE_PW_MODE_INFO 1 #endif #if USE_PW_MODE_INFO static info_lkp_t pw_mode_info[] = { { 1, "", NULL, NULL }, { 2, "", NULL, NULL }, { 3, "normal", NULL, NULL }, { 4, "", NULL, NULL }, { 5, "", NULL, NULL }, { 6, "", NULL, NULL }, { 7, "", NULL, NULL }, { 8, "parallel capacity", NULL, NULL }, { 9, "parallel redundancy", NULL, NULL }, { 10, "high efficiency", NULL, NULL }, /* Extended status values, * FIXME: check for source and completion */ { 240, "" /* battery (0xF0) */, NULL, NULL }, { 100, "" /* maintenanceBypass (0x64) */, NULL, NULL }, { 96, "" /* Bypass (0x60) */, NULL, NULL }, { 81, "high efficiency" /* high efficiency (0x51) */, NULL, NULL }, { 80, "normal" /* normal (0x50) */, NULL, NULL }, { 64, "" /* UPS supporting load, normal degraded mode (0x40) */, NULL, NULL }, { 16, "" /* none (0x10) */, NULL, NULL }, { 0, NULL, NULL, NULL } }; #endif /* USE_PW_MODE_INFO */ /* FIXME: may be standardized * extracted from bcmxcp.c->BCMXCP_TOPOLOGY_*, Make some common definitions */ static info_lkp_t pw_topology_info[] = { { 0x0000, "", NULL, NULL }, /* None; use the Table of Elements */ { 0x0010, "Off-line switcher, Single Phase", NULL, NULL }, { 0x0020, "Line-Interactive UPS, Single Phase", NULL, NULL }, { 0x0021, "Line-Interactive UPS, Two Phase", NULL, NULL }, { 0x0022, "Line-Interactive UPS, Three Phase", NULL, NULL }, { 0x0030, "Dual AC Input, On-Line UPS, Single Phase", NULL, NULL }, { 0x0031, "Dual AC Input, On-Line UPS, Two Phase", NULL, NULL }, { 0x0032, "Dual AC Input, On-Line UPS, Three Phase", NULL, NULL }, { 0x0040, "On-Line UPS, Single Phase", NULL, NULL }, { 0x0041, "On-Line UPS, Two Phase", NULL, NULL }, { 0x0042, "On-Line UPS, Three Phase", NULL, NULL }, { 0x0050, "Parallel Redundant On-Line UPS, Single Phase", NULL, NULL }, { 0x0051, "Parallel Redundant On-Line UPS, Two Phase", NULL, NULL }, { 0x0052, "Parallel Redundant On-Line UPS, Three Phase", NULL, NULL }, { 0x0060, "Parallel for Capacity On-Line UPS, Single Phase", NULL, NULL }, { 0x0061, "Parallel for Capacity On-Line UPS, Two Phase", NULL, NULL }, { 0x0062, "Parallel for Capacity On-Line UPS, Three Phase", NULL, NULL }, { 0x0102, "System Bypass Module, Three Phase", NULL, NULL }, { 0x0122, "Hot-Tie Cabinet, Three Phase", NULL, NULL }, { 0x0200, "Outlet Controller, Single Phase", NULL, NULL }, { 0x0222, "Dual AC Input Static Switch Module, 3 Phase", NULL, NULL }, { 0, NULL, NULL, NULL } }; /* Legacy implementation */ static info_lkp_t pw_battery_abm_status[] = { { 1, "CHRG", NULL, NULL }, { 2, "DISCHRG", NULL, NULL }, /* { 3, "Floating", NULL, NULL }, */ /* { 4, "Resting", NULL, NULL }, */ /* { 5, "Unknown", NULL, NULL }, */ { 0, NULL, NULL, NULL } }; static info_lkp_t pw_abm_status_info[] = { { 1, "charging", NULL, NULL }, { 2, "discharging", NULL, NULL }, { 3, "floating", NULL, NULL }, { 4, "resting", NULL, NULL }, { 5, "unknown", NULL, NULL }, /* Undefined - ABM is not activated */ { 6, "disabled", NULL, NULL }, /* ABM Charger Disabled */ { 0, NULL, NULL, NULL } }; static info_lkp_t pw_batt_test_info[] = { { 1, "Unknown", NULL, NULL }, { 2, "Done and passed", NULL, NULL }, { 3, "Done and error", NULL, NULL }, { 4, "In progress", NULL, NULL }, { 5, "Not supported", NULL, NULL }, { 6, "Inhibited", NULL, NULL }, { 7, "Scheduled", NULL, NULL }, { 0, NULL, NULL, NULL } }; static info_lkp_t pw_yes_no_info[] = { { 1, "yes", NULL, NULL }, { 2, "no", NULL, NULL }, { 0, NULL, NULL, NULL } }; static info_lkp_t pw_outlet_status_info[] = { { 1, "on", NULL, NULL }, { 2, "off", NULL, NULL }, { 3, "on", NULL, NULL }, /* pendingOff, transitional status */ { 4, "off", NULL, NULL }, /* pendingOn, transitional status */ /* { 5, "", NULL, NULL }, unknown */ /* { 6, "", NULL, NULL }, reserved */ { 7, "off", NULL, NULL }, /* Failed in Closed position */ { 8, "on", NULL, NULL }, /* Failed in Open position */ { 0, NULL, NULL, NULL } }; static info_lkp_t pw_ambient_drycontacts_info[] = { { -1, "unknown", NULL, NULL }, { 1, "opened", NULL, NULL }, { 2, "closed", NULL, NULL }, { 3, "opened", NULL, NULL }, /* openWithNotice */ { 4, "closed", NULL, NULL }, /* closedWithNotice */ { 0, NULL, NULL, NULL } }; #if WITH_SNMP_LKP_FUN /* Note: eaton_sensor_temperature_unit_fun() is defined in eaton-pdu-marlin-helpers.c * and su_temperature_read_fun() is in snmp-ups.c * Future work for DMF might provide same-named routines via LUA-C gateway. */ # if WITH_SNMP_LKP_FUN_DUMMY /* Temperature unit consideration */ const char *eaton_sensor_temperature_unit_fun(void *raw_snmp_value) { /* snmp_value here would be a (long*) */ NUT_UNUSED_VARIABLE(raw_snmp_value); return "unknown"; } /* FIXME: please DMF, though this should be in snmp-ups.c or equiv. */ const char *su_temperature_read_fun(void *raw_snmp_value) { /* snmp_value here would be a (long*) */ NUT_UNUSED_VARIABLE(raw_snmp_value); return "dummy"; }; # endif /* WITH_SNMP_LKP_FUN_DUMMY */ static info_lkp_t pw_sensor_temperature_unit_info[] = { { 0, "dummy", eaton_sensor_temperature_unit_fun, NULL }, { 0, NULL, NULL, NULL } }; static info_lkp_t pw_sensor_temperature_read_info[] = { { 0, "dummy", su_temperature_read_fun, NULL }, { 0, NULL, NULL, NULL } }; #else /* if not WITH_SNMP_LKP_FUN: */ /* FIXME: For now, DMF codebase falls back to old implementation with static * lookup/mapping tables for this, which can easily go into the DMF XML file. */ static info_lkp_t pw_sensor_temperature_unit_info[] = { { 0, "kelvin", NULL, NULL }, { 1, "celsius", NULL, NULL }, { 2, "fahrenheit", NULL, NULL }, { 0, NULL, NULL, NULL } }; #endif /* WITH_SNMP_LKP_FUN */ static info_lkp_t pw_ambient_drycontacts_polarity_info[] = { { 0, "normal-opened", NULL, NULL }, { 1, "normal-closed", NULL, NULL }, { 0, NULL, NULL, NULL } }; static info_lkp_t pw_ambient_drycontacts_state_info[] = { { 0, "inactive", NULL, NULL }, { 1, "active", NULL, NULL }, { 0, NULL, NULL, NULL } }; static info_lkp_t pw_emp002_ambient_presence_info[] = { { 0, "unknown", NULL, NULL }, { 2, "yes", NULL, NULL }, /* communicationOK */ { 3, "no", NULL, NULL }, /* communicationLost */ { 0, NULL, NULL, NULL } }; /* extracted from drivers/eaton-pdu-marlin-mib.c -> marlin_threshold_status_info */ static info_lkp_t pw_threshold_status_info[] = { { 0, "good", NULL, NULL }, /* No threshold triggered */ { 1, "warning-low", NULL, NULL }, /* Warning low threshold triggered */ { 2, "critical-low", NULL, NULL }, /* Critical low threshold triggered */ { 3, "warning-high", NULL, NULL }, /* Warning high threshold triggered */ { 4, "critical-high", NULL, NULL }, /* Critical high threshold triggered */ { 0, NULL, NULL, NULL } }; /* extracted from drivers/eaton-pdu-marlin-mib.c -> marlin_threshold_xxx_alarms_info */ static info_lkp_t pw_threshold_temperature_alarms_info[] = { { 0, "", NULL, NULL }, /* No threshold triggered */ { 1, "low temperature warning!", NULL, NULL }, /* Warning low threshold triggered */ { 2, "low temperature critical!", NULL, NULL }, /* Critical low threshold triggered */ { 3, "high temperature warning!", NULL, NULL }, /* Warning high threshold triggered */ { 4, "high temperature critical!", NULL, NULL }, /* Critical high threshold triggered */ { 0, NULL, NULL, NULL } }; static info_lkp_t pw_threshold_humidity_alarms_info[] = { { 0, "", NULL, NULL }, /* No threshold triggered */ { 1, "low humidity warning!", NULL, NULL }, /* Warning low threshold triggered */ { 2, "low humidity critical!", NULL, NULL }, /* Critical low threshold triggered */ { 3, "high humidity warning!", NULL, NULL }, /* Warning high threshold triggered */ { 4, "high humidity critical!", NULL, NULL }, /* Critical high threshold triggered */ { 0, NULL, NULL, NULL } }; /* Snmp2NUT lookup table */ static snmp_info_t eaton_pxg_mib[] = { /* standard MIB items */ { "device.description", ST_FLAG_STRING | ST_FLAG_RW, SU_INFOSIZE, ".1.3.6.1.2.1.1.1.0", NULL, SU_FLAG_OK, NULL }, { "device.contact", ST_FLAG_STRING | ST_FLAG_RW, SU_INFOSIZE, ".1.3.6.1.2.1.1.4.0", NULL, SU_FLAG_OK, NULL }, { "device.location", ST_FLAG_STRING | ST_FLAG_RW, SU_INFOSIZE, ".1.3.6.1.2.1.1.6.0", NULL, SU_FLAG_OK, NULL }, /* FIXME: miss device page! */ /* UPS page */ /* info_type, info_flags, info_len, OID, dfl, flags, oid2info, setvar */ { "ups.mfr", ST_FLAG_STRING, SU_INFOSIZE, PW_OID_MFR_NAME, "", SU_FLAG_STATIC, NULL }, { "ups.model", ST_FLAG_STRING, SU_INFOSIZE, PW_OID_MODEL_NAME, "", SU_FLAG_STATIC, NULL }, /* FIXME: the 2 "firmware" entries below should be SU_FLAG_SEMI_STATIC */ { "ups.firmware", ST_FLAG_STRING, SU_INFOSIZE, PW_OID_FIRMREV, "", 0, NULL }, { "ups.firmware.aux", ST_FLAG_STRING, SU_INFOSIZE, IETF_OID_AGENTREV, "", 0, NULL }, { "ups.serial", ST_FLAG_STRING, SU_INFOSIZE, IETF_OID_IDENT, "", SU_FLAG_STATIC, NULL }, { "ups.load", 0, 1.0, PW_OID_OUT_LOAD, "", 0, NULL }, /* FIXME: should be removed in favor of output.power */ { "ups.power", 0, 1.0, PW_OID_OUT_POWER ".1", "", 0, NULL }, /* Duplicate of the above entry, but pointing at the first index */ /* xupsOutputWatts.1.0; Value (Integer): 300 */ { "ups.power", 0, 1.0, "1.3.6.1.4.1.534.1.4.4.1.4.1.0", "", 0, NULL }, { "ups.status", ST_FLAG_STRING, SU_INFOSIZE, PW_OID_POWER_STATUS, "OFF", SU_STATUS_PWR, &pw_pwr_info[0] }, { "ups.status", ST_FLAG_STRING, SU_INFOSIZE, PW_OID_ALARM_OB, "", SU_STATUS_BATT, &pw_alarm_ob[0] }, { "ups.status", ST_FLAG_STRING, SU_INFOSIZE, PW_OID_ALARM_LB, "", SU_STATUS_BATT, &pw_alarm_lb[0] }, { "ups.status", ST_FLAG_STRING, SU_INFOSIZE, PW_OID_BATT_STATUS, "", SU_STATUS_BATT, &pw_battery_abm_status[0] }, #if USE_PW_MODE_INFO /* FIXME: should be ups.mode or output.source (need RFC) */ /* Note: this define is not set via project options; code hidden with * commit to "snmp-ups: support newer Genepi management cards" */ { "experimental.ups.type", ST_FLAG_STRING, SU_INFOSIZE, PW_OID_POWER_STATUS, "", SU_FLAG_STATIC | SU_FLAG_OK, &pw_mode_info[0] }, #endif /* USE_PW_MODE_INFO */ /* xupsTopologyType.0; Value (Integer): 32 */ { "ups.type", ST_FLAG_STRING, SU_INFOSIZE, "1.3.6.1.4.1.534.1.13.1.0", "", SU_FLAG_STATIC | SU_FLAG_OK, &pw_topology_info[0] }, /* FIXME: should be removed in favor of their output. equivalent! */ { "ups.realpower.nominal", 0, 1.0, PW_OID_CONF_POWER, "", 0, NULL }, /* FIXME: should be removed in favor of output.power.nominal */ { "ups.power.nominal", 0, 1.0, IETF_OID_CONF_OUT_VA, "", 0, NULL }, /* XUPS-MIB::xupsEnvAmbientTemp.0 */ { "ups.temperature", 0, 1.0, "1.3.6.1.4.1.534.1.6.1.0", "", 0, NULL }, /* FIXME: These 2 data needs RFC! */ /* XUPS-MIB::xupsEnvAmbientLowerLimit.0 */ { "ups.temperature.low", ST_FLAG_RW, 1.0, "1.3.6.1.4.1.534.1.6.2.0", "", 0, NULL }, /* XUPS-MIB::xupsEnvAmbientUpperLimit.0 */ { "ups.temperature.high", ST_FLAG_RW, 1.0, "1.3.6.1.4.1.534.1.6.3.0", "", 0, NULL }, /* XUPS-MIB::xupsTestBatteryStatus */ { "ups.test.result", ST_FLAG_STRING, SU_INFOSIZE, "1.3.6.1.4.1.534.1.8.2.0", "", 0, &pw_batt_test_info[0] }, /* UPS-MIB::upsAutoRestart */ { "ups.start.auto", ST_FLAG_RW | ST_FLAG_STRING, SU_INFOSIZE, "1.3.6.1.2.1.33.1.8.5.0", "", SU_FLAG_OK, &pw_yes_no_info[0] }, /* XUPS-MIB::xupsBatteryAbmStatus.0 */ { "battery.charger.status", ST_FLAG_STRING, SU_INFOSIZE, "1.3.6.1.4.1.534.1.2.5.0", "", SU_STATUS_BATT, &pw_abm_status_info[0] }, /* Battery page */ { "battery.charge", 0, 1.0, PW_OID_BATT_CHARGE, "", 0, NULL }, { "battery.runtime", 0, 1.0, PW_OID_BATT_RUNTIME, "", 0, NULL }, { "battery.voltage", 0, 1.0, PW_OID_BATT_VOLTAGE, "", 0, NULL }, { "battery.current", 0, 0.1, PW_OID_BATT_CURRENT, "", 0, NULL }, { "battery.runtime.low", 0, 60.0, IETF_OID_CONF_RUNTIME_LOW, "", 0, NULL }, { "battery.date", ST_FLAG_RW | ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.534.1.2.6.0", NULL, SU_FLAG_OK, &su_convert_to_iso_date_info[FUNMAP_USDATE_TO_ISODATE] }, /* Output page */ { "output.phases", 0, 1.0, PW_OID_OUT_LINES, "", 0, NULL }, /* XUPS-MIB::xupsOutputFrequency.0 */ { "output.frequency", 0, 0.1, "1.3.6.1.4.1.534.1.4.2.0", "", 0, NULL }, /* XUPS-MIB::xupsConfigOutputFreq.0 */ { "output.frequency.nominal", 0, 0.1, "1.3.6.1.4.1.534.1.10.4.0", "", 0, NULL }, /* XUPS-MIB::xupsOutputVoltage.1 */ { "output.voltage", 0, 1.0, "1.3.6.1.4.1.534.1.4.4.1.2.1", "", SU_OUTPUT_1, NULL }, /* Duplicate of the above entry, but pointing at the first index */ /* xupsOutputVoltage.1.0; Value (Integer): 230 */ { "output.voltage", 0, 1.0, "1.3.6.1.4.1.534.1.4.4.1.2.1.0", "", SU_OUTPUT_1, NULL }, /* XUPS-MIB::xupsConfigOutputVoltage.0 */ { "output.voltage.nominal", 0, 1.0, "1.3.6.1.4.1.534.1.10.1.0", "", 0, NULL }, /* XUPS-MIB::xupsConfigLowOutputVoltageLimit.0 */ { "output.voltage.low", 0, 1.0, ".1.3.6.1.4.1.534.1.10.6.0", "", 0, NULL }, /* XUPS-MIB::xupsConfigHighOutputVoltageLimit.0 */ { "output.voltage.high", 0, 1.0, ".1.3.6.1.4.1.534.1.10.7.0", "", 0, NULL }, { "output.current", 0, 1.0, PW_OID_OUT_CURRENT ".1", "", SU_OUTPUT_1, NULL }, /* Duplicate of the above entry, but pointing at the first index */ /* xupsOutputCurrent.1.0; Value (Integer): 0 */ { "output.current", 0, 1.0, "1.3.6.1.4.1.534.1.4.4.1.3.1.0", "", SU_OUTPUT_1, NULL }, { "output.realpower", 0, 1.0, PW_OID_OUT_POWER ".1", "", SU_OUTPUT_1, NULL }, /* Duplicate of the above entry, but pointing at the first index */ /* Name/OID: xupsOutputWatts.1.0; Value (Integer): 1200 */ { "output.realpower", 0, 1.0, "1.3.6.1.4.1.534.1.4.4.1.4.1.0", "", 0, NULL }, /* Duplicate of "ups.realpower.nominal" * FIXME: map either ups or output, but not both (or have an auto-remap) */ { "output.realpower.nominal", 0, 1.0, PW_OID_CONF_POWER, "", 0, NULL }, { "output.L1-N.voltage", 0, 1.0, PW_OID_OUT_VOLTAGE ".1", "", SU_OUTPUT_3, NULL }, { "output.L2-N.voltage", 0, 1.0, PW_OID_OUT_VOLTAGE ".2", "", SU_OUTPUT_3, NULL }, { "output.L3-N.voltage", 0, 1.0, PW_OID_OUT_VOLTAGE ".3", "", SU_OUTPUT_3, NULL }, { "output.L1.current", 0, 1.0, PW_OID_OUT_CURRENT ".1", "", SU_OUTPUT_3, NULL }, { "output.L2.current", 0, 1.0, PW_OID_OUT_CURRENT ".2", "", SU_OUTPUT_3, NULL }, { "output.L3.current", 0, 1.0, PW_OID_OUT_CURRENT ".3", "", SU_OUTPUT_3, NULL }, { "output.L1.realpower", 0, 1.0, PW_OID_OUT_POWER ".1", "", SU_OUTPUT_3, NULL }, { "output.L2.realpower", 0, 1.0, PW_OID_OUT_POWER ".2", "", SU_OUTPUT_3, NULL }, { "output.L3.realpower", 0, 1.0, PW_OID_OUT_POWER ".3", "", SU_OUTPUT_3, NULL }, /* FIXME: should better be output.Lx.load */ { "output.L1.power.percent", 0, 1.0, IETF_OID_LOAD_LEVEL ".1", "", SU_OUTPUT_3, NULL }, { "output.L2.power.percent", 0, 1.0, IETF_OID_LOAD_LEVEL ".2", "", SU_OUTPUT_3, NULL }, { "output.L3.power.percent", 0, 1.0, IETF_OID_LOAD_LEVEL ".3", "", SU_OUTPUT_3, NULL }, { "output.voltage.nominal", 0, 1.0, PW_OID_CONF_OVOLTAGE, "", 0, NULL }, /* Input page */ { "input.phases", 0, 1.0, PW_OID_IN_LINES, "", 0, NULL }, { "input.frequency", 0, 0.1, PW_OID_IN_FREQUENCY, "", 0, NULL }, { "input.voltage", 0, 1.0, PW_OID_IN_VOLTAGE ".0", "", SU_INPUT_1, NULL }, /* Duplicate of the above entry, but pointing at the first index */ /* xupsInputVoltage.1[.0]; Value (Integer): 245 */ { "input.voltage", 0, 1.0, "1.3.6.1.4.1.534.1.3.4.1.2.1", "", SU_INPUT_1, NULL }, /* XUPS-MIB::xupsConfigInputVoltage.0 */ { "input.voltage.nominal", 0, 1.0, "1.3.6.1.4.1.534.1.10.2.0", "", 0, NULL }, { "input.current", 0, 0.1, PW_OID_IN_CURRENT ".0", "", SU_INPUT_1, NULL }, { "input.L1-N.voltage", 0, 1.0, PW_OID_IN_VOLTAGE ".1", "", SU_INPUT_3, NULL }, { "input.L2-N.voltage", 0, 1.0, PW_OID_IN_VOLTAGE ".2", "", SU_INPUT_3, NULL }, { "input.L3-N.voltage", 0, 1.0, PW_OID_IN_VOLTAGE ".3", "", SU_INPUT_3, NULL }, { "input.L1.current", 0, 1.0, PW_OID_IN_CURRENT ".1", "", SU_INPUT_3, NULL }, { "input.L2.current", 0, 1.0, PW_OID_IN_CURRENT ".2", "", SU_INPUT_3, NULL }, { "input.L3.current", 0, 1.0, PW_OID_IN_CURRENT ".3", "", SU_INPUT_3, NULL }, { "input.L1.realpower", 0, 1.0, PW_OID_IN_POWER ".1", "", SU_INPUT_3, NULL }, { "input.L2.realpower", 0, 1.0, PW_OID_IN_POWER ".2", "", SU_INPUT_3, NULL }, { "input.L3.realpower", 0, 1.0, PW_OID_IN_POWER ".3", "", SU_INPUT_3, NULL }, { "input.quality", 0, 1.0, PW_OID_IN_LINE_BADS, "", 0, NULL }, /* FIXME: this segfaults! do we assume the same number of bypass phases as input phases? { "input.bypass.phases", 0, 1.0, PW_OID_BY_LINES, "", 0, NULL }, */ { "input.bypass.frequency", 0, 0.1, PW_OID_BY_FREQUENCY, "", 0, NULL }, { "input.bypass.voltage", 0, 1.0, PW_OID_BY_VOLTAGE ".0", "", SU_INPUT_1, NULL }, /* Duplicate of the above entry, but pointing at the first index */ /* xupsBypassVoltage.1.0; Value (Integer): 244 */ { "input.bypass.voltage", 0, 1.0, "1.3.6.1.4.1.534.1.5.3.1.2.1.0", "", SU_INPUT_1, NULL }, { "input.bypass.L1-N.voltage", 0, 1.0, PW_OID_BY_VOLTAGE ".1", "", SU_INPUT_3, NULL }, { "input.bypass.L2-N.voltage", 0, 1.0, PW_OID_BY_VOLTAGE ".2", "", SU_INPUT_3, NULL }, { "input.bypass.L3-N.voltage", 0, 1.0, PW_OID_BY_VOLTAGE ".3", "", SU_INPUT_3, NULL }, /* Outlet page */ /* Master outlet id always equal to 0 */ { "outlet.id", 0, 1, NULL, "0", SU_FLAG_STATIC , NULL }, /* XUPS-MIB:: xupsSwitchable.0 */ { "outlet.switchable", 0, 1, ".1.3.6.1.4.1.534.1.9.7.0", NULL, SU_FLAG_STATIC , &pw_yes_no_info[0] }, /* XUPS-MIB::xupsNumReceptacles; Value (Integer): 2 */ { "outlet.count", 0, 1, ".1.3.6.1.4.1.534.1.12.1.0", NULL, SU_FLAG_STATIC, NULL }, /* XUPS-MIB::xupsRecepIndex.X; Value (Integer): X */ { "outlet.%i.id", 0, 1, ".1.3.6.1.4.1.534.1.12.2.1.1.%i", NULL, SU_FLAG_STATIC | SU_OUTLET, NULL }, /* This MIB does not provide outlets switchability info. So map to a nearby OID, for data activation, and map all values to "yes" */ { "outlet.%i.switchable", 0, 1, ".1.3.6.1.4.1.534.1.12.2.1.1.%i", NULL, SU_FLAG_STATIC | SU_OUTLET, NULL }, /* XUPS-MIB::xupsRecepStatus.X; Value (Integer): 1 */ { "outlet.%i.status", 0, 1, ".1.3.6.1.4.1.534.1.12.2.1.2.%i", NULL, SU_OUTLET, &pw_outlet_status_info[0] }, /* Ambient collection */ /* EMP001 (legacy) mapping */ /* XUPS-MIB::xupsEnvRemoteTemp.0 */ { "ambient.temperature", 0, 1.0, "1.3.6.1.4.1.534.1.6.5.0", "", 0, NULL }, /* XUPS-MIB::xupsEnvRemoteTempLowerLimit.0 */ { "ambient.temperature.low", ST_FLAG_RW, 1.0, "1.3.6.1.4.1.534.1.6.9.0", "", 0, NULL }, /* XUPS-MIB::xupsEnvRemoteTempUpperLimit.0 */ { "ambient.temperature.high", ST_FLAG_RW, 1.0, "1.3.6.1.4.1.534.1.6.10.0", "", 0, NULL }, /* XUPS-MIB::xupsEnvRemoteHumidity.0 */ { "ambient.humidity", 0, 1.0, "1.3.6.1.4.1.534.1.6.6.0", "", 0, NULL }, /* XUPS-MIB::xupsEnvRemoteHumidityLowerLimit.0 */ { "ambient.humidity.low", ST_FLAG_RW, 1.0, "1.3.6.1.4.1.534.1.6.11.0", "", 0, NULL }, /* XUPS-MIB::xupsEnvRemoteHumidityUpperLimit.0 */ { "ambient.humidity.high", ST_FLAG_RW, 1.0, "1.3.6.1.4.1.534.1.6.12.0", "", 0, NULL }, /* XUPS-MIB::xupsContactDescr.n */ { "ambient.contacts.1.name", ST_FLAG_STRING, 1.0, ".1.3.6.1.4.1.534.1.6.8.1.4.1", "", 0, NULL }, { "ambient.contacts.2.name", ST_FLAG_STRING, 1.0, ".1.3.6.1.4.1.534.1.6.8.1.4.2", "", 0, NULL }, /* XUPS-MIB::xupsContactState.n */ { "ambient.contacts.1.status", ST_FLAG_STRING, 1.0, ".1.3.6.1.4.1.534.1.6.8.1.3.1", "", 0, &pw_ambient_drycontacts_info[0] }, { "ambient.contacts.2.status", ST_FLAG_STRING, 1.0, ".1.3.6.1.4.1.534.1.6.8.1.3.2", "", 0, &pw_ambient_drycontacts_info[0] }, /* EMP002 (EATON EMP MIB) mapping, including daisychain support */ /* Warning: indexes start at '1' not '0'! */ /* sensorCount.0 */ { "ambient.count", ST_FLAG_RW, 1.0, ".1.3.6.1.4.1.534.6.8.1.1.1.0", "", 0, NULL }, /* CommunicationStatus.n */ { "ambient.%i.present", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.534.6.8.1.1.4.1.1.%i", NULL, SU_AMBIENT_TEMPLATE, &pw_emp002_ambient_presence_info[0] }, /* sensorName.n: OctetString EMPDT1H1C2 @1 */ { "ambient.%i.name", ST_FLAG_STRING, 1.0, ".1.3.6.1.4.1.534.6.8.1.1.3.1.1.%i", "", SU_AMBIENT_TEMPLATE, NULL }, /* sensorManufacturer.n */ { "ambient.%i.mfr", ST_FLAG_STRING, 1.0, ".1.3.6.1.4.1.534.6.8.1.1.2.1.6.%i", "", SU_AMBIENT_TEMPLATE, NULL }, /* sensorModel.n */ { "ambient.%i.model", ST_FLAG_STRING, 1.0, ".1.3.6.1.4.1.534.6.8.1.1.2.1.7.%i", "", SU_AMBIENT_TEMPLATE, NULL }, /* sensorSerialNumber.n */ { "ambient.%i.serial", ST_FLAG_STRING, 1.0, ".1.3.6.1.4.1.534.6.8.1.1.2.1.9.%i", "", SU_AMBIENT_TEMPLATE, NULL }, /* sensorUuid.n */ { "ambient.%i.id", ST_FLAG_STRING, 1.0, ".1.3.6.1.4.1.534.6.8.1.1.2.1.2.%i", "", SU_AMBIENT_TEMPLATE, NULL }, /* sensorAddress.n */ { "ambient.%i.address", 0, 1, ".1.3.6.1.4.1.534.6.8.1.1.2.1.4.%i", "", SU_AMBIENT_TEMPLATE, NULL }, /* sensorFirmwareVersion.n */ { "ambient.%i.firmware", ST_FLAG_STRING, 1.0, ".1.3.6.1.4.1.534.6.8.1.1.2.1.10.%i", "", SU_AMBIENT_TEMPLATE, NULL }, /* temperatureUnit.1 * MUST be before the temperature data reading! */ { "ambient.%i.temperature.unit", 0, 1.0, ".1.3.6.1.4.1.534.6.8.1.2.5.0", "", SU_AMBIENT_TEMPLATE, &pw_sensor_temperature_unit_info[0] }, /* temperatureValue.n.1 */ { "ambient.%i.temperature", 0, 0.1, ".1.3.6.1.4.1.534.6.8.1.2.3.1.3.%i.1", "", SU_AMBIENT_TEMPLATE, #if WITH_SNMP_LKP_FUN &pw_sensor_temperature_read_info[0] #else NULL #endif }, { "ambient.%i.temperature.status", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.534.6.8.1.2.3.1.1.%i.1", NULL, SU_AMBIENT_TEMPLATE, &pw_threshold_status_info[0] }, { "ups.alarm", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.534.6.8.1.2.3.1.1.%i.1", NULL, SU_AMBIENT_TEMPLATE, &pw_threshold_temperature_alarms_info[0] }, /* FIXME: ambient.n.temperature.{minimum,maximum} */ /* temperatureThresholdLowCritical.n.1 */ { "ambient.%i.temperature.low.critical", ST_FLAG_RW, 0.1, ".1.3.6.1.4.1.534.6.8.1.2.2.1.6.%i.1", "", SU_AMBIENT_TEMPLATE, NULL }, /* temperatureThresholdLowWarning.n.1 */ { "ambient.%i.temperature.low.warning", ST_FLAG_RW, 0.1, ".1.3.6.1.4.1.534.6.8.1.2.2.1.5.%i.1", "", SU_AMBIENT_TEMPLATE, NULL }, /* temperatureThresholdHighWarning.n.1 */ { "ambient.%i.temperature.high.warning", ST_FLAG_RW, 0.1, ".1.3.6.1.4.1.534.6.8.1.2.2.1.7.%i.1", "", SU_AMBIENT_TEMPLATE, NULL }, /* temperatureThresholdHighCritical.n.1 */ { "ambient.%i.temperature.high.critical", ST_FLAG_RW, 0.1, ".1.3.6.1.4.1.534.6.8.1.2.2.1.8.%i.1", "", SU_AMBIENT_TEMPLATE, NULL }, /* humidityValue.n.1 */ { "ambient.%i.humidity", 0, 0.1, ".1.3.6.1.4.1.534.6.8.1.3.3.1.3.%i.1", "", SU_AMBIENT_TEMPLATE, NULL }, { "ambient.%i.humidity.status", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.534.6.8.1.3.3.1.1.%i.1", NULL, SU_AMBIENT_TEMPLATE, &pw_threshold_status_info[0] }, { "ups.alarm", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.534.6.8.1.3.3.1.1.%i.1", NULL, SU_AMBIENT_TEMPLATE, &pw_threshold_humidity_alarms_info[0] }, /* FIXME: consider ambient.n.humidity.{minimum,maximum} */ /* humidityThresholdLowCritical.n.1 */ { "ambient.%i.humidity.low.critical", ST_FLAG_RW, 0.1, ".1.3.6.1.4.1.534.6.8.1.3.2.1.6.%i.1", "", SU_AMBIENT_TEMPLATE, NULL }, /* humidityThresholdLowWarning.n.1 */ { "ambient.%i.humidity.low.warning", ST_FLAG_RW, 0.1, ".1.3.6.1.4.1.534.6.8.1.3.2.1.5.%i.1", "", SU_AMBIENT_TEMPLATE, NULL }, /* humidityThresholdHighWarning.n.1 */ { "ambient.%i.humidity.high.warning", ST_FLAG_RW, 0.1, ".1.3.6.1.4.1.534.6.8.1.3.2.1.7.%i.1", "", SU_AMBIENT_TEMPLATE, NULL }, /* humidityThresholdHighCritical.n.1 */ { "ambient.%i.humidity.high.critical", ST_FLAG_RW, 0.1, ".1.3.6.1.4.1.534.6.8.1.3.2.1.8.%i.1", "", SU_AMBIENT_TEMPLATE, NULL }, /* digitalInputName.n.{1,2} */ { "ambient.%i.contacts.1.name", ST_FLAG_STRING, 1.0, ".1.3.6.1.4.1.534.6.8.1.4.2.1.1.%i.1", "", SU_AMBIENT_TEMPLATE, NULL }, { "ambient.%i.contacts.2.name", ST_FLAG_STRING, 1.0, ".1.3.6.1.4.1.534.6.8.1.4.2.1.1.%i.2", "", SU_AMBIENT_TEMPLATE, NULL }, /* digitalInputPolarity.n */ { "ambient.%i.contacts.1.config", ST_FLAG_RW | ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.534.6.8.1.4.2.1.3.%i.1", "", SU_AMBIENT_TEMPLATE, &pw_ambient_drycontacts_polarity_info[0] }, { "ambient.%i.contacts.2.config", ST_FLAG_RW | ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.534.6.8.1.4.2.1.3.%i.2", "", SU_AMBIENT_TEMPLATE, &pw_ambient_drycontacts_polarity_info[0] }, /* XUPS-MIB::xupsContactState.n */ { "ambient.%i.contacts.1.status", ST_FLAG_STRING, 1.0, ".1.3.6.1.4.1.534.6.8.1.4.3.1.3.%i.1", "", SU_AMBIENT_TEMPLATE, &pw_ambient_drycontacts_state_info[0] }, { "ambient.%i.contacts.2.status", ST_FLAG_STRING, 1.0, ".1.3.6.1.4.1.534.6.8.1.4.3.1.3.%i.2", "", SU_AMBIENT_TEMPLATE, &pw_ambient_drycontacts_state_info[0] }, /* instant commands */ { "test.battery.start.quick", 0, 1, PW_OID_BATTEST_START, "", SU_TYPE_CMD | SU_FLAG_OK, NULL }, /* Shed load and restart when line power back on; cannot be canceled */ { "shutdown.return", 0, DEFAULT_SHUTDOWNDELAY, PW_OID_CONT_LOAD_SHED_AND_RESTART, "", SU_TYPE_CMD | SU_FLAG_OK, NULL }, /* Cancel output off, by writing 0 to xupsControlOutputOffDelay */ { "shutdown.stop", 0, 0, PW_OID_CONT_OFFDELAY, "", SU_TYPE_CMD | SU_FLAG_OK, NULL }, /* XUPS-MIB::xupsControlOutputOffDelay */ /* load off after 1 sec, shortest possible delay; 0 cancels */ { "load.off", 0, 1, PW_OID_CONT_OFFDELAY, "1", SU_TYPE_CMD | SU_FLAG_OK, NULL }, /* Delayed version, parameter is mandatory (so dfl is NULL)! */ { "load.off.delay", 0, 1, PW_OID_CONT_OFFDELAY, NULL, SU_TYPE_CMD | SU_FLAG_OK, NULL }, /* XUPS-MIB::xupsControlOutputOnDelay */ /* load on after 1 sec, shortest possible delay; 0 cancels */ { "load.on", 0, 1, PW_OID_CONT_ONDELAY, "1", SU_TYPE_CMD | SU_FLAG_OK, NULL }, /* Delayed version, parameter is mandatory (so dfl is NULL)! */ { "load.on.delay", 0, 1, PW_OID_CONT_ONDELAY, NULL, SU_TYPE_CMD | SU_FLAG_OK, NULL }, /* Delays handling: * 0-n :Time in seconds until the command is issued * -1:Cancel a pending Off/On command */ /* XUPS-MIB::xupsRecepOffDelaySecs.n */ { "outlet.%i.load.off", 0, 1, ".1.3.6.1.4.1.534.1.12.2.1.3.%i", "0", SU_TYPE_CMD | SU_OUTLET, NULL }, /* XUPS-MIB::xupsRecepOnDelaySecs.n */ { "outlet.%i.load.on", 0, 1, ".1.3.6.1.4.1.534.1.12.2.1.4.%i", "0", SU_TYPE_CMD | SU_OUTLET, NULL }, /* Delayed version, parameter is mandatory (so dfl is NULL)! */ { "outlet.%i.load.off.delay", 0, 1, ".1.3.6.1.4.1.534.1.12.2.1.3.%i", NULL, SU_TYPE_CMD | SU_OUTLET, NULL }, /* XUPS-MIB::xupsRecepOnDelaySecs.n */ { "outlet.%i.load.on.delay", 0, 1, ".1.3.6.1.4.1.534.1.12.2.1.4.%i", NULL, SU_TYPE_CMD | SU_OUTLET, NULL }, { "ups.alarms", 0, 1.0, PW_OID_ALARMS, "", 0, NULL }, /* end of structure. */ { NULL, 0, 0, NULL, NULL, 0, NULL } } ; static alarms_info_t eaton_pxg_alarms[] = { /* xupsLowBattery */ { PW_OID_ALARM_LB, "LB", NULL }, /* xupsOutputOverload */ { ".1.3.6.1.4.1.534.1.7.7", "OVER", "Output overload!" }, /* xupsInternalFailure */ { ".1.3.6.1.4.1.534.1.7.8", NULL, "Internal failure!" }, /* xupsBatteryDischarged */ { ".1.3.6.1.4.1.534.1.7.9", NULL, "Battery discharged!" }, /* xupsInverterFailure */ { ".1.3.6.1.4.1.534.1.7.10", NULL, "Inverter failure!" }, /* xupsOnBypass * FIXME: informational (not an alarm), * to RFC'ed for device.event? */ { ".1.3.6.1.4.1.534.1.7.11", "BYPASS", "On bypass!" }, /* xupsBypassNotAvailable * FIXME: informational (not an alarm), * to RFC'ed for device.event? */ { ".1.3.6.1.4.1.534.1.7.12", NULL, "Bypass not available!" }, /* xupsOutputOff * FIXME: informational (not an alarm), * to RFC'ed for device.event? */ { ".1.3.6.1.4.1.534.1.7.13", "OFF", "Output off!" }, /* xupsInputFailure * FIXME: informational (not an alarm), * to RFC'ed for device.event? */ { ".1.3.6.1.4.1.534.1.7.14", NULL, "Input failure!" }, /* xupsBuildingAlarm * FIXME: informational (not an alarm), * to RFC'ed for device.event? */ { ".1.3.6.1.4.1.534.1.7.15", NULL, "Building alarm!" }, /* xupsShutdownImminent */ { ".1.3.6.1.4.1.534.1.7.16", NULL, "Shutdown imminent!" }, /* xupsOnInverter * FIXME: informational (not an alarm), * to RFC'ed for device.event? */ { ".1.3.6.1.4.1.534.1.7.17", NULL, "On inverter!" }, /* xupsBreakerOpen * FIXME: informational (not an alarm), * to RFC'ed for device.event? */ { ".1.3.6.1.4.1.534.1.7.20", NULL, "Breaker open!" }, /* xupsAlarmBatteryBad */ { ".1.3.6.1.4.1.534.1.7.23", "RB", "Battery bad!" }, /* xupsOutputOffAsRequested * FIXME: informational (not an alarm), * to RFC'ed for device.event? */ { ".1.3.6.1.4.1.534.1.7.24", "OFF", "Output off as requested!" }, /* xupsDiagnosticTestFailed * FIXME: informational (not an alarm), * to RFC'ed for device.event? */ { ".1.3.6.1.4.1.534.1.7.25", NULL, "Diagnostic test failure!" }, /* xupsCommunicationsLost */ { ".1.3.6.1.4.1.534.1.7.26", NULL, "Communication with UPS lost!" }, /* xupsUpsShutdownPending */ { ".1.3.6.1.4.1.534.1.7.27", NULL, "Shutdown pending!" }, /* xupsAmbientTempBad */ { ".1.3.6.1.4.1.534.1.7.29", NULL, "Bad ambient temperature!" }, /* xupsLossOfRedundancy */ { ".1.3.6.1.4.1.534.1.7.30", NULL, "Redundancy lost!" }, /* xupsAlarmTempBad */ { ".1.3.6.1.4.1.534.1.7.31", NULL, "Bad temperature!" }, /* xupsAlarmChargerFailed */ { ".1.3.6.1.4.1.534.1.7.32", NULL, "Charger failure!" }, /* xupsAlarmFanFailure */ { ".1.3.6.1.4.1.534.1.7.33", NULL, "Fan failure!" }, /* xupsAlarmFuseFailure */ { ".1.3.6.1.4.1.534.1.7.34", NULL, "Fuse failure!" }, /* xupsPowerSwitchBad */ { ".1.3.6.1.4.1.534.1.7.35", NULL, "Powerswitch failure!" }, /* xupsModuleFailure */ { ".1.3.6.1.4.1.534.1.7.36", NULL, "Parallel or composite module failure!" }, /* xupsOnAlternatePowerSource * FIXME: informational (not an alarm), * to RFC'ed for device.event? */ { ".1.3.6.1.4.1.534.1.7.37", NULL, "Using alternative power source!" }, /* xupsAltPowerNotAvailable * FIXME: informational (not an alarm), * to RFC'ed for device.event? */ { ".1.3.6.1.4.1.534.1.7.38", NULL, "Alternative power source unavailable!" }, /* xupsRemoteTempBad */ { ".1.3.6.1.4.1.534.1.7.40", NULL, "Bad remote temperature!" }, /* xupsRemoteHumidityBad */ { ".1.3.6.1.4.1.534.1.7.41", NULL, "Bad remote humidity!" }, /* xupsAlarmOutputBad */ { ".1.3.6.1.4.1.534.1.7.42", NULL, "Bad output condition!" }, /* xupsAlarmAwaitingPower * FIXME: informational (not an alarm), * to RFC'ed for device.event? */ { ".1.3.6.1.4.1.534.1.7.43", NULL, "Awaiting power!" }, /* xupsOnMaintenanceBypass * FIXME: informational (not an alarm), * to RFC'ed for device.event? * FIXME: NUT currently doesn't distinguish between Maintenance and * Automatic Bypass (both published as "ups.alarm: BYPASS) * Should we make the distinction? */ { ".1.3.6.1.4.1.534.1.7.44", "BYPASS", "On maintenance bypass!" }, /* end of structure. */ { NULL, NULL, NULL } } ; mib2nut_info_t eaton_pxg_ups = { "eaton_pxg_ups", EATON_PXG_MIB_VERSION, NULL, PW_OID_MODEL_NAME, eaton_pxg_mib, EATON_PXGX_SYSOID , eaton_pxg_alarms }; nut-2.8.1/drivers/macosx-ups.c0000644000175000017500000003254114501607135013201 00000000000000/* Bridge driver to read Mac OS X UPS status (as displayed in Energy Saver control panel) * * Copyright (C) 2011-2012, 2015 Charles Lepple * * 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 2 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, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #include "config.h" #include "main.h" #include "attribute.h" #include #include "CoreFoundation/CoreFoundation.h" #include "IOKit/ps/IOPowerSources.h" #include "IOKit/ps/IOPSKeys.h" #define DRIVER_NAME "Mac OS X UPS meta-driver" #define DRIVER_VERSION "1.40" /* driver description structure */ upsdrv_info_t upsdrv_info = { DRIVER_NAME, DRIVER_VERSION, "Charles Lepple ", DRV_EXPERIMENTAL, { NULL } }; #if 0 #define CFRelease(ref) do { upsdebugx(3, "%s:%d: CFRelease(%p)", __FILE__, __LINE__, ref); CFRelease(ref); } while(0) #endif static CFStringRef g_power_source_name = NULL; static double max_capacity_value = 100.0; /*! Copy the current power dictionary. * * Caller must release power dictionary when finished with it. */ static CFDictionaryRef copy_power_dictionary(CFStringRef power_source_name) { CFTypeRef power_sources_info, power_source; CFArrayRef sources_list; CFDictionaryRef this_power_dictionary, power_dictionary = NULL; CFStringRef this_power_source_name; CFIndex num_keys, index; power_sources_info = IOPSCopyPowerSourcesInfo(); assert(power_sources_info); upsdebugx(6, "%s: Got power_sources_info:", __func__); if(nut_debug_level >= 6) CFShow(power_sources_info); upsdebugx(5, "power_source_name = "); if(nut_debug_level >= 5) CFShow(power_source_name); upsdebugx(6, "end power_source_name"); sources_list = IOPSCopyPowerSourcesList(power_sources_info); num_keys = CFArrayGetCount(sources_list); for(index=0; index < num_keys; index++) { upsdebugx(6, "%s: Getting power source %ld/%ld...", __func__, index+1, num_keys); power_source = CFArrayGetValueAtIndex(sources_list, index); assert(power_source); upsdebugx(6, "%s: power source %ld = ", __func__, index+1); if(nut_debug_level >= 6) CFShow(power_source); this_power_dictionary = IOPSGetPowerSourceDescription(power_sources_info, power_source); assert(this_power_dictionary); this_power_source_name = CFDictionaryGetValue(this_power_dictionary, CFSTR(kIOPSNameKey)); assert(this_power_source_name); if(!CFStringCompare(this_power_source_name, power_source_name, 0)) { power_dictionary = this_power_dictionary; CFRetain(power_dictionary); break; } } if(power_dictionary) { upsdebugx(5, "CFShowing 'power_dictionary'"); if(nut_debug_level >= 5) CFShow(power_dictionary); } /* Get a new power_sources_info next time: */ CFRelease(power_sources_info); CFRelease(sources_list); return power_dictionary; } void upsdrv_initinfo(void) { /* try to detect the UPS here - call fatal_with_errno(EXIT_FAILURE, ) if it fails */ char device_name_buf[80] = ""; CFStringRef device_type_cfstr, device_name_cfstr; CFPropertyListRef power_dictionary; CFNumberRef max_capacity; upsdebugx(1, "upsdrv_initinfo()"); dstate_setinfo("device.mfr", "(unknown)"); dstate_setinfo("ups.mfr", "(unknown)"); power_dictionary = copy_power_dictionary(g_power_source_name); device_type_cfstr = CFDictionaryGetValue(power_dictionary, CFSTR(kIOPSTypeKey)); if(device_type_cfstr && !CFStringCompare(device_type_cfstr, CFSTR(kIOPSInternalBatteryType), 0)) { dstate_setinfo("device.type", "battery"); } upsdebugx(2, "Getting 'Name' key"); device_name_cfstr = CFDictionaryGetValue(power_dictionary, CFSTR(kIOPSNameKey)); if (!device_name_cfstr) { fatalx(EXIT_FAILURE, "Couldn't retrieve 'Name' key from power dictionary."); } CFRetain(device_name_cfstr); CFStringGetCString(device_name_cfstr, device_name_buf, sizeof(device_name_buf), kCFStringEncodingUTF8); upsdebugx(2, "Got name: %s", device_name_buf); CFRelease(device_name_cfstr); dstate_setinfo("device.model", "%s", device_name_buf); dstate_setinfo("ups.model", "%s", device_name_buf); max_capacity = CFDictionaryGetValue(power_dictionary, CFSTR(kIOPSMaxCapacityKey)); if(max_capacity) { CFRetain(max_capacity); CFNumberGetValue(max_capacity, kCFNumberDoubleType, &max_capacity_value); CFRelease(max_capacity); upsdebugx(3, "Max Capacity = %.f units (usually 100)", max_capacity_value); if(max_capacity_value != 100.0) { upsdebugx(1, "Max Capacity: %f != 100", max_capacity_value); } } /* upsh.instcmd = instcmd; */ CFRelease(power_dictionary); } void upsdrv_updateinfo(void) { CFPropertyListRef power_dictionary; CFStringRef power_source_state; CFNumberRef battery_voltage, battery_runtime; CFNumberRef current_capacity; CFBooleanRef is_charging; /* double max_capacity_value = 100.0; */ double current_capacity_value; upsdebugx(1, "upsdrv_updateinfo()"); power_dictionary = copy_power_dictionary( g_power_source_name ); if(!power_dictionary) { dstate_datastale(); return; } status_init(); /* Retrieve OL/OB state */ power_source_state = CFDictionaryGetValue(power_dictionary, CFSTR(kIOPSPowerSourceStateKey)); assert(power_source_state); CFRetain(power_source_state); upsdebugx(3, "Power Source State:"); if(nut_debug_level >= 3) CFShow(power_source_state); if(!CFStringCompare(power_source_state, CFSTR(kIOPSACPowerValue), 0)) { status_set("OL"); } else { status_set("OB"); } CFRelease(power_source_state); /* Retrieve CHRG state */ is_charging = CFDictionaryGetValue(power_dictionary, CFSTR(kIOPSIsChargingKey)); if(is_charging) { Boolean is_charging_value; is_charging_value = CFBooleanGetValue(is_charging); if(is_charging_value) { status_set("CHRG"); } } status_commit(); /* Retrieve battery voltage */ battery_voltage = CFDictionaryGetValue(power_dictionary, CFSTR(kIOPSVoltageKey)); if(battery_voltage) { int battery_voltage_value; CFNumberGetValue(battery_voltage, kCFNumberIntType, &battery_voltage_value); upsdebugx(2, "battery_voltage = %d mV", battery_voltage_value); dstate_setinfo("battery.voltage", "%.3f", battery_voltage_value/1000.0); } /* Retrieve battery runtime */ battery_runtime = CFDictionaryGetValue(power_dictionary, CFSTR(kIOPSTimeToEmptyKey)); if(battery_runtime) { double battery_runtime_value; CFNumberGetValue(battery_runtime, kCFNumberDoubleType, &battery_runtime_value); upsdebugx(2, "battery_runtime = %.f minutes", battery_runtime_value); if(battery_runtime_value > 0) { dstate_setinfo("battery.runtime", "%d", (int)(battery_runtime_value*60)); } else { dstate_delinfo("battery.runtime"); } } else { dstate_delinfo("battery.runtime"); } /* Retrieve current capacity */ current_capacity = CFDictionaryGetValue(power_dictionary, CFSTR(kIOPSCurrentCapacityKey)); if(current_capacity) { CFNumberGetValue(current_capacity, kCFNumberDoubleType, ¤t_capacity_value); upsdebugx(2, "Current Capacity = %.f/%.f units", current_capacity_value, max_capacity_value); if(max_capacity_value > 0) { dstate_setinfo("battery.charge", "%.f", 100.0 * current_capacity_value / max_capacity_value); } } /* TODO: it should be possible to set poll_interval (and maxage in the * server) to an absurdly large value, and use notify(3) to get * updates. */ /* * poll_interval = 2; */ dstate_dataok(); CFRelease(power_dictionary); } void upsdrv_shutdown(void) { /* tell the UPS to shut down, then return - DO NOT SLEEP HERE */ /* maybe try to detect the UPS here, but try a shutdown even if it doesn't respond at first if possible */ /* NOTE: Mac OS X already has shutdown routines - this driver is more for monitoring and notification purposes. Still, there is a key that might be useful to set in SystemConfiguration land. */ upslogx(LOG_ERR, "shutdown not supported"); set_exit_flag(-1); /* you may have to check the line status since the commands for toggling power are frequently different for OL vs. OB */ /* OL: this must power cycle the load if possible */ /* OB: the load must remain off until the power returns */ } /* static int instcmd(const char *cmdname, const char *extra) { if (!strcasecmp(cmdname, "test.battery.stop")) { ser_send_buf(upsfd, ...); return STAT_INSTCMD_HANDLED; } upslogx(LOG_NOTICE, "instcmd: unknown command [%s]", cmdname); return STAT_INSTCMD_UNKNOWN; } */ /* TODO: There is a configuration file here: /Library/Preferences/SystemConfiguration/com.apple.PowerManagement.plist with several keys under UPSDefaultThresholds: * UPSShutdownAfterMinutes * UPSShutdownAtLevel * UPSShutdownAtMinutesLeft It is not likely that these keys can be written, but they might be good values for NUT variables. In conjunction with 'ignorelb' and a delta, this could be used to synthesize a LB status right before the computer shuts down. */ /* static int setvar(const char *varname, const char *val) { if (!strcasecmp(varname, "ups.test.interval")) { ser_send_buf(upsfd, ...); return STAT_SET_HANDLED; } upslogx(LOG_NOTICE, "setvar: unknown variable [%s]", varname); return STAT_SET_UNKNOWN; } */ void upsdrv_help(void) { } /* list flags and values that you want to receive via -x */ void upsdrv_makevartable(void) { /* allow '-x xyzzy' */ /* addvar(VAR_FLAG, "xyzzy", "Enable xyzzy mode"); */ /* allow '-x foo=' */ /* addvar(VAR_VALUE, "foo", "Override foo setting"); */ addvar(VAR_VALUE, "model", "Regular Expression to match power source model name"); } void upsdrv_initups(void) { CFArrayRef power_source_key_list; CFIndex num_keys, index; CFDictionaryRef power_dictionary; CFTypeRef power_blob; CFStringRef potential_key, potential_model = NULL; char *model_name; /* regex(3) */ char potential_model_name[256]; regex_t model_regex; int ret = 0; upsdebugx(3, "upsdrv_initups(): Power Sources blob:"); /* upsfd = ser_open(device_path); */ /* ser_set_speed(upsfd, device_path, B1200); */ power_blob = IOPSCopyPowerSourcesInfo(); if(!power_blob) { fatalx(EXIT_FAILURE, "Couldn't retrieve Power Sources blob"); } if(nut_debug_level >= 3) CFShow(power_blob); /* The CFDictionary through 10.9 has changed to a CFArray, * so this part is no longer applicable: */ #if 0 /* Note: original value of device_name is derived from * device_path (value of port parameter) in main.c */ if(!strcmp(device_name, "auto")) { device_name = "/UPS"; } upsdebugx(2, "Matching power supply key names against regex '%s'", device_name); ret = regcomp(&name_regex, device_name, REG_EXTENDED|REG_NOSUB|REG_ICASE); if(ret) { fatalx(EXIT_FAILURE, "Failed to compile regex from 'port' parameter: '%s'.", device_name); } #endif if((model_name = getval("model"))) { upsdebugx(2, "Matching power supply model names against regex '%s'", model_name); ret = regcomp(&model_regex, model_name, REG_EXTENDED|REG_NOSUB|REG_ICASE); if(ret) { fatalx(EXIT_FAILURE, "Failed to compile regex from 'model' parameter: '%s'.", model_name); } } power_source_key_list = IOPSCopyPowerSourcesList(power_blob); num_keys = CFArrayGetCount(power_source_key_list); upsdebugx(1, "Number of power supplies found: %d", (int)num_keys); if(nut_debug_level >= 3) CFShow(power_source_key_list); if(num_keys < 1) { /* bail */ fatalx(EXIT_FAILURE, "Couldn't find any UPS or battery. Is your UPS shown in the 'Energy Saver' control panel?"); } for(index=0; index < num_keys; index++) { upsdebugx(2, "Retrieving power source #%ld", index+1); potential_key = CFArrayGetValueAtIndex(power_source_key_list, index); upsdebugx(3, "Power source key/index:"); if(nut_debug_level >= 3) CFShow(potential_key); power_dictionary = IOPSGetPowerSourceDescription(power_blob, potential_key); assert(power_dictionary); CFRetain(power_dictionary); upsdebugx(2, "Getting 'Name' key (UPS model)"); potential_model = CFDictionaryGetValue(power_dictionary, CFSTR(kIOPSNameKey)); CFRetain(potential_model); if(CFStringGetCString(potential_model, potential_model_name, sizeof(potential_model_name), kCFStringEncodingUTF8)) { upsdebugx(1, " model name: %s", potential_model_name); } else { upsdebugx(1, " (failed to retrieve 'Name')"); } CFRelease(power_dictionary); if(model_name) { ret = regexec(&model_regex, potential_model_name, 0,0,0); if(!ret) { upsdebugx(2, "Matched model name"); break; } } CFRelease(potential_model); } if(model_name) { regfree(&model_regex); } if(ret) { if(model_name) { fatalx(EXIT_FAILURE, "Couldn't find UPS or battery matching 'model' (%s)", model_name); } else { fatalx(EXIT_FAILURE, "Couldn't find an UPS or battery."); } } g_power_source_name = potential_model; /* the upsh handlers can't be done here, as they get initialized * shortly after upsdrv_initups returns to main. */ /* don't try to detect the UPS here */ /* do stuff */ } void upsdrv_cleanup(void) { upsdebugx(1, "Cleanup: release references"); CFRelease(g_power_source_name); /* free(dynamic_mem); */ /* ser_close(upsfd, device_path); */ } nut-2.8.1/drivers/apcupsd-ups.h0000644000175000017500000001575014500336654013362 00000000000000/* apcupsd-ups.h - NUT client driver to apcupsd Copyright (C) 2005 - 2010 Arnaud Quette 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 2 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, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef NUT_APCUPSD_UPS_H_SEEN #define NUT_APCUPSD_UPS_H_SEEN 1 /* from usbhid-ups.h */ /* --------------------------------------------------------------- */ /* Struct & data for ups.status processing */ /* --------------------------------------------------------------- */ typedef struct { const char *status_str; /* ups.status string */ int status_value; /* ups.status value */ } status_lkp_t; #define STATUS_CAL 1 /* calibration */ #define STATUS_TRIM 2 /* SmartTrim */ #define STATUS_BOOST 4 /* SmartBoost */ #define STATUS_OL 8 /* on line */ #define STATUS_OB 16 /* on battery */ #define STATUS_OVER 32 /* overload */ #define STATUS_LB 64 /* low battery */ #define STATUS_RB 128 /* replace battery */ #define STATUS_BYPASS 256 /* on bypass */ #define STATUS_OFF 512 /* ups is off */ #define STATUS_CHRG 1024 /* charging */ #define STATUS_DISCHRG 2048 /* discharging */ /* static status_lkp_t status_info[] = { { "CAL", STATUS_CAL }, { "TRIM", STATUS_TRIM }, { "BOOST", STATUS_BOOST }, { "OL", STATUS_OL }, { "OB", STATUS_OB }, { "OVER", STATUS_OVER }, { "LB", STATUS_LB }, { "RB", STATUS_RB }, { "BYPASS", STATUS_BYPASS }, { "OFF", STATUS_OFF }, { "CHRG", STATUS_CHRG }, { "DISCHRG", STATUS_DISCHRG }, { "NULL", 0 }, }; */ /* from usbhid-ups.h */ typedef struct { char hid_value; /* HID value */ char *nut_value; /* NUT value */ } info_enum_t; /* --------------------------------------------------------------- */ /* Structure containing information about how to get/set data */ /* from/to the UPS and convert these to/from NUT standard */ /* --------------------------------------------------------------- */ typedef struct { const char *apcupsd_item; const char *info_type; /* NUT variable name */ int info_flags; /* NUT flags (to set in addinfo) */ float info_len; /* if ST_FLAG_STRING: length of the string */ /* if HU_TYPE_CMD: command value ; multiplier (or max len) otherwise */ const char *default_value; /* if HU_FLAG_ABSENT: default value ; format otherwise */ int drv_flags; /* */ char **var_values; /* all possible values for this variable (allows to check data...) */ /* FIXME: "void *" so we can have bound or enum */ /* interpreter interpret; */ /* FFE: interpreter fct, NULL if not needed */ } apcuspd_info_t; /* data flags */ #define DU_FLAG_NONE 0 #define DU_FLAG_INIT 1 /* intialy show element to upsd */ #define DU_FLAG_STATUS 2 #define DU_FLAG_DATE 4 #define DU_FLAG_TIME 8 #define DU_FLAG_FW1 16 #define DU_FLAG_FW2 32 #define DU_FLAG_PRESERVE 64 /* ------------ */ /* Data table */ /* ------------ */ static apcuspd_info_t nut_data[] = { { NULL, "ups.mfr", ST_FLAG_STRING | ST_FLAG_RW, 32, "APC", DU_FLAG_INIT, NULL }, { "MODEL", "ups.model", ST_FLAG_STRING | ST_FLAG_RW, 32, "Unknown UPS", DU_FLAG_INIT, NULL }, { "STATUS", "ups.status", ST_FLAG_STRING | ST_FLAG_RW, 32, "OFF", DU_FLAG_INIT|DU_FLAG_STATUS, NULL }, { "SERIALNO", "ups.serial", ST_FLAG_STRING | ST_FLAG_RW, 32, NULL, DU_FLAG_NONE, NULL }, { "LOADPCT", "ups.load", ST_FLAG_RW, 1, "%1.1f", DU_FLAG_NONE, NULL }, { "DATE", "ups.time", ST_FLAG_STRING | ST_FLAG_RW, 16, NULL, DU_FLAG_TIME, NULL }, { "DATE", "ups.date", ST_FLAG_STRING | ST_FLAG_RW, 16, NULL, DU_FLAG_DATE, NULL }, { "MANDATE", "ups.mfr.date", ST_FLAG_STRING | ST_FLAG_RW, 16, NULL, DU_FLAG_NONE, NULL }, { "FIRMWARE", "ups.firmware", ST_FLAG_STRING | ST_FLAG_RW, 16, NULL, DU_FLAG_FW1, NULL }, { "FIRMWARE", "ups.firmware.aux", ST_FLAG_STRING | ST_FLAG_RW, 16, NULL, DU_FLAG_FW2, NULL }, { "ITEMP", "ups.temperature", ST_FLAG_RW, 1, "%1.1f", DU_FLAG_NONE, NULL }, { "UPSNAME", "ups.id", ST_FLAG_STRING | ST_FLAG_RW, 16, NULL, DU_FLAG_NONE, NULL }, { "DWAKE", "ups.delay.start", ST_FLAG_RW, 1, "%.0f", DU_FLAG_NONE, NULL }, { "DSHUTD", "ups.delay.shutdown", ST_FLAG_RW, 1, "%.0f", DU_FLAG_NONE, NULL }, { "STESTI", "ups.test.interval", ST_FLAG_RW, 1, "%.0f", DU_FLAG_NONE, NULL }, { "SELFTEST", "ups.test.result", ST_FLAG_STRING | ST_FLAG_RW, 16, NULL, DU_FLAG_NONE, NULL }, { "LINEV", "input.voltage", ST_FLAG_RW, 1, "%1.1f", DU_FLAG_NONE, NULL }, { "MAXLINEV", "input.voltage.maximum", ST_FLAG_RW, 1, "%1.1f", DU_FLAG_NONE, NULL }, { "MINLINEV", "input.voltage.minimum", ST_FLAG_RW, 1, "%1.1f", DU_FLAG_NONE, NULL }, { "NOMINV", "input.voltage.nominal", 0, 1, "%.0f", DU_FLAG_NONE, NULL }, { "NOMOUTV", "output.voltage.nominal", 0, 1, "%.0f", DU_FLAG_NONE, NULL }, { "LASTXFER", "input.transfer.reason", ST_FLAG_STRING | ST_FLAG_RW, 32, NULL, DU_FLAG_NONE, NULL }, { "LOTRANS", "input.transfer.low", ST_FLAG_RW, 1, "%1.1f", DU_FLAG_NONE, NULL }, { "HITRANS", "input.transfer.high", ST_FLAG_RW, 1, "%1.1f", DU_FLAG_NONE, NULL }, { "SENSE", "input.sensitivity", ST_FLAG_STRING | ST_FLAG_RW, 1, NULL, DU_FLAG_NONE, NULL }, { "LINEFREQ", "input.frequency", ST_FLAG_RW, 1, "%1.1f", DU_FLAG_NONE, NULL }, { "OUTPUTV", "output.voltage", ST_FLAG_RW, 1, "%1.1f", DU_FLAG_NONE, NULL }, { "LINEFREQ", "output.frequency", ST_FLAG_RW, 1, "%1.1f", DU_FLAG_NONE, NULL }, { "BCHARGE", "battery.charge", ST_FLAG_RW, 1, "%1.1f", DU_FLAG_PRESERVE, NULL }, { "MBATTCHG", "battery.charge.low", ST_FLAG_RW, 1, "%.0f", DU_FLAG_NONE, NULL }, { "BATTDATE", "battery.date", ST_FLAG_STRING /* | ST_FLAG_RW */, 16, NULL, DU_FLAG_DATE, NULL }, { "BATTV", "battery.voltage", 0, 1, "%1.1f", DU_FLAG_NONE, NULL }, { "NOMBATTV", "battery.voltage.nominal", 0, 1, "%1.1f", DU_FLAG_NONE, NULL }, { "TIMELEFT", "battery.runtime", ST_FLAG_RW, 60, "%1.1f", DU_FLAG_PRESERVE, NULL }, { "MINTIMEL", "battery.runtime.low", ST_FLAG_RW, 60, "%.0f", DU_FLAG_NONE, NULL }, { "RETPCT", "battery.charge.restart", ST_FLAG_RW, 1, "%1.1f", DU_FLAG_NONE, NULL }, { "NOMPOWER", "ups.realpower.nominal", 0, 1, "%1.1f", DU_FLAG_INIT, NULL }, { "LOAD_W", "ups.realpower", 0, 1, "%1.1f", DU_FLAG_NONE, NULL }, { "LOADAPNT", "power.percent", ST_FLAG_RW, 1, "%1.1f", DU_FLAG_NONE, NULL }, { "OUTCURNT", "output.current", 0, 1, "%1.2f", DU_FLAG_NONE, NULL }, { "LOAD_VA", "ups.power", 0, 1, "%1.1f", DU_FLAG_NONE, NULL }, { "NOMAPNT", "ups.power.nominal", 0, 1, "%.0f", DU_FLAG_INIT, NULL }, { NULL, NULL, 0, 0, NULL, DU_FLAG_NONE, NULL } }; #endif /* NUT_APCUPSD_UPS_H_SEEN */ nut-2.8.1/drivers/legrand-hid.c0000644000175000017500000002257514500336654013272 00000000000000/* legrand-hid.c - subdriver to monitor Legrand USB/HID devices with NUT * * Copyright (C) * 2003 - 2012 Arnaud Quette * 2005 - 2006 Peter Selinger * 2008 - 2009 Arjen de Korte * 2013 Charles Lepple * 2018 Gabriele Taormina , for Legrand * * 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 2 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, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "common.h" #include "usbhid-ups.h" #include "legrand-hid.h" #include "main.h" #include "usb-common.h" #define LEGRAND_HID_VERSION "Legrand HID 0.2" /* Legrand VendorID and ProductID */ #define LEGRAND_VID 0x1cb0 /* Legrand */ #define LEGRAND_PID_PDU 0x0038 /* Keor PDU model (800VA) */ #define LEGRAND_PID_SP 0x0032 /* Keor SP model (600, 800, 1000, 1500, 2000VA version) */ static void *disable_interrupt_pipe(USBDevice_t *device) { NUT_UNUSED_VARIABLE(device); if (!use_interrupt_pipe) return NULL; use_interrupt_pipe = FALSE; upslogx(LOG_INFO, "interrupt pipe disabled (add 'pollonly' flag to 'ups.conf' to get rid of this message)"); return NULL; } /* USB IDs device table */ static usb_device_id_t legrand_usb_device_table[] = { { USB_DEVICE(LEGRAND_VID, LEGRAND_PID_PDU), disable_interrupt_pipe }, /* Legrand Keor PDU */ { USB_DEVICE(LEGRAND_VID, LEGRAND_PID_SP), disable_interrupt_pipe }, /* Legrand Keor SP */ /* Terminating entry */ { 0, 0, NULL } }; /* --------------------------------------------------------------- */ /* Vendor-specific usage table */ /* --------------------------------------------------------------- */ /* LEGRAND usage table */ static usage_lkp_t legrand_usage_lkp[] = { { NULL, 0 } }; static usage_tables_t legrand_utab[] = { legrand_usage_lkp, hid_usage_lkp, NULL, }; static const char *legrand_times10(double value) { static char buf[20]; snprintf(buf, sizeof(buf), "%0.1f", value * 10); return buf; } static info_lkp_t legrand_times10_info[] = { { 0, NULL, legrand_times10, NULL }, { 0, NULL, NULL, NULL } }; static const char *legrand_times100k(double value) { static char buf[20]; snprintf(buf, sizeof(buf), "%0.1f", value * 100000); return buf; } static info_lkp_t legrand_times100k_info[] = { { 0, NULL, legrand_times100k, NULL }, { 0, NULL, NULL, NULL } }; static const char *legrand_times1M(double value) { static char buf[20]; snprintf(buf, sizeof(buf), "%0.1f", value * 1000000); return buf; } static info_lkp_t legrand_times1M_info[] = { { 0, NULL, legrand_times1M, NULL }, { 0, NULL, NULL, NULL } }; static const char *legrand_times10M(double value) { static char buf[20]; snprintf(buf, sizeof(buf), "%0.1f", value * 10000000); return buf; } static info_lkp_t legrand_times10M_info[] = { { 0, NULL, legrand_times10M, NULL }, { 0, NULL, NULL, NULL } }; /* --------------------------------------------------------------- */ /* HID2NUT lookup table */ /* --------------------------------------------------------------- */ static hid_info_t legrand_hid2nut[] = { /* Input Data */ { "input.voltage", 0, 0, "UPS.Input.Voltage", NULL, "%.0f", 0, NULL }, { "input.voltage", 0, 0, "UPS.PowerConverter.Input.Voltage", NULL, "%.0f", 0, legrand_times1M_info }, { "input.transfer.high", 0, 0, "UPS.Input.HighVoltageTransfer", NULL, "%.0f", HU_FLAG_STATIC, NULL }, { "input.transfer.high", 0, 0, "UPS.PowerConverter.Output.HighVoltageTransfer", NULL, "%.0f", HU_FLAG_STATIC, legrand_times10_info }, { "input.transfer.low", 0, 0, "UPS.Input.LowVoltageTransfer", NULL, "%.0f", HU_FLAG_STATIC, NULL }, { "input.transfer.low", 0, 0, "UPS.PowerConverter.Output.LowVoltageTransfer", NULL, "%.0f", HU_FLAG_STATIC, NULL }, { "input.voltage.nominal", 0, 0, "UPS.Input.ConfigVoltage", NULL, "%.0f", HU_FLAG_STATIC, NULL }, { "input.voltage.nominal", 0, 0, "UPS.Flow.ConfigVoltage", NULL, "%.0f", HU_FLAG_STATIC, NULL }, /* Battery Data */ { "battery.voltage.nominal", 0, 0, "UPS.PowerSummary.ConfigVoltage", NULL, "%.0f", HU_FLAG_STATIC, divide_by_10_conversion }, { "battery.voltage.nominal", 0, 0, "UPS.BatterySystem.Battery.ConfigVoltage", NULL, "%.0f", HU_FLAG_STATIC, NULL }, { "battery.voltage", 0, 0, "UPS.PowerSummary.Voltage", NULL, "%.0f", 0, divide_by_10_conversion }, { "battery.voltage", 0, 0, "UPS.BatterySystem.Battery.Voltage", NULL, "%.0f", 0, legrand_times100k_info }, { "battery.charge", 0, 0, "UPS.PowerSummary.RemainingCapacity", NULL, "%.0f", 0, NULL }, { "battery.runtime", 0, 0, "UPS.PowerSummary.RuntimeToEmpty", NULL, "%.0f", 0, NULL }, { "battery.charge.warning", 0, 0, "UPS.PowerSummary.WarningCapacityLimit", NULL, "%.0f", HU_FLAG_STATIC, NULL }, { "battery.charge.low", 0, 0, "UPS.PowerSummary.RemainingCapacityLimit", NULL, "%.0f", HU_FLAG_STATIC, NULL }, /* Output Data */ { "output.voltage", 0, 0, "UPS.Output.Voltage", NULL, "%.0f", 0, NULL }, { "output.voltage", 0, 0, "UPS.PowerConverter.Output.Voltage", NULL, "%.0f", 0, legrand_times10M_info }, { "output.frequency", 0, 0, "UPS.Output.Frequency", NULL, "%.0f", 0, NULL }, { "ups.load", 0, 0, "UPS.Output.PercentLoad", NULL, "%.0f", 0, NULL }, { "ups.load", 0, 0, "UPS.OutletSystem.Outlet.PercentLoad", NULL, "%.0f", 0, NULL }, { "ups.realpower.nominal", 0, 0, "UPS.Output.ConfigActivePower", NULL, "%.0f", HU_FLAG_STATIC, NULL }, { "ups.realpower.nominal", 0, 0, "UPS.Flow.ConfigApparentPower", NULL, "%.0f", HU_FLAG_STATIC, NULL }, /* UPS Status */ { "BOOL", 0, 0, "UPS.PowerSummary.PresentStatus.ACPresent", NULL, NULL, HU_FLAG_QUICK_POLL, online_info }, { "BOOL", 0, 0, "UPS.PowerSummary.PresentStatus.BelowRemainingCapacityLimit", NULL, NULL, HU_FLAG_QUICK_POLL, lowbatt_info }, { "BOOL", 0, 0, "UPS.PowerSummary.PresentStatus.Charging", NULL, NULL, HU_FLAG_QUICK_POLL, charging_info }, { "BOOL", 0, 0, "UPS.PowerSummary.PresentStatus.Discharging", NULL, NULL, HU_FLAG_QUICK_POLL, discharging_info }, { "BOOL", 0, 0, "UPS.Output.Overload", NULL, NULL, HU_FLAG_QUICK_POLL, overload_info }, /* Delays */ { "ups.delay.shutdown", ST_FLAG_RW | ST_FLAG_STRING, 10, "UPS.OutletSystem.Outlet.DelayBeforeShutdown", NULL, DEFAULT_OFFDELAY, HU_FLAG_ABSENT, NULL }, { "ups.delay.start", ST_FLAG_RW | ST_FLAG_STRING, 10, "UPS.OutletSystem.Outlet.DelayBeforeStartup", NULL, DEFAULT_ONDELAY, HU_FLAG_ABSENT, NULL }, { "ups.delay.shutdown", ST_FLAG_RW | ST_FLAG_STRING, 10, "UPS.Output.DelayBeforeShutdown", NULL, DEFAULT_OFFDELAY, HU_FLAG_ABSENT, NULL }, { "ups.delay.start", ST_FLAG_RW | ST_FLAG_STRING, 10, "UPS.Output.DelayBeforeStartup", NULL, DEFAULT_ONDELAY, HU_FLAG_ABSENT, NULL }, { "load.off.delay", 0, 0, "UPS.OutletSystem.Outlet.DelayBeforeShutdown", NULL, DEFAULT_OFFDELAY, HU_TYPE_CMD, NULL }, { "load.on.delay", 0, 0, "UPS.OutletSystem.Outlet.DelayBeforeStartup", NULL, DEFAULT_ONDELAY, HU_TYPE_CMD, NULL }, { "load.off.delay", 0, 0, "UPS.Output.DelayBeforeShutdown", NULL, DEFAULT_OFFDELAY, HU_TYPE_CMD, NULL }, { "load.on.delay", 0, 0, "UPS.Output.DelayBeforeStartup", NULL, DEFAULT_ONDELAY, HU_TYPE_CMD, NULL }, /* Battery Testing */ { "test.battery.start.quick", 0, 0, "UPS.BatterySystem.Battery.Test", NULL, "1", HU_TYPE_CMD, NULL }, { "test.battery.start.deep", 0, 0, "UPS.BatterySystem.Battery.Test", NULL, "2", HU_TYPE_CMD, NULL }, { "test.battery.stop", 0, 0, "UPS.BatterySystem.Battery.Test", NULL, "3", HU_TYPE_CMD, NULL }, { "test.battery.start.quick", 0, 0, "UPS.Output.Test", NULL, "1", HU_TYPE_CMD, NULL }, { "test.battery.start.deep", 0, 0, "UPS.Output.Test", NULL, "2", HU_TYPE_CMD, NULL }, { "test.battery.stop", 0, 0, "UPS.Output.Test", NULL, "3", HU_TYPE_CMD, NULL }, /* Buzzer */ { "beeper.enable", 0, 0, "UPS.PowerSummary.AudibleAlarmControl", NULL, "2", HU_TYPE_CMD, NULL }, { "beeper.disable", 0, 0, "UPS.PowerSummary.AudibleAlarmControl", NULL, "3", HU_TYPE_CMD, NULL }, /* end of structure. */ { NULL, 0, 0, NULL, NULL, NULL, 0, NULL } }; static const char *legrand_format_model(HIDDevice_t *hd) { return hd->Product; } static const char *legrand_format_mfr(HIDDevice_t *hd) { return hd->Vendor ? hd->Vendor : "Legrand"; } static const char *legrand_format_serial(HIDDevice_t *hd) { return hd->Serial; } /* this function allows the subdriver to "claim" a device: return 1 if * the device is supported by this subdriver, else 0. */ static int legrand_claim(HIDDevice_t *hd) { int status = is_usb_device_supported(legrand_usb_device_table, hd); switch (status) { case POSSIBLY_SUPPORTED: /* by default, reject, unless the productid option is given */ if (getval("productid")) return 1; possibly_supported("Legrand", hd); return 0; case SUPPORTED: return 1; case NOT_SUPPORTED: default: return 0; } } subdriver_t legrand_subdriver = { LEGRAND_HID_VERSION, legrand_claim, legrand_utab, legrand_hid2nut, legrand_format_model, legrand_format_mfr, legrand_format_serial, fix_report_desc, }; nut-2.8.1/drivers/tripplite-hid.h0000644000175000017500000000221014500336654013657 00000000000000/* tripplite-hid.h - data to monitor Tripp Lite USB/HID devices with NUT * * Copyright (C) * 2003 - 2005 Arnaud Quette * 2005 Peter Selinger * * Sponsored by MGE UPS SYSTEMS * * 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 2 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, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #ifndef TRIPPLITE_HID_H #define TRIPPLITE_HID_H #include "usbhid-ups.h" extern subdriver_t tripplite_subdriver; #endif /* TRIPPLITE_HID_H */ nut-2.8.1/drivers/powerp-bin.c0000644000175000017500000004072214501607135013164 00000000000000/* * powerp-bin.c - Model specific routines for CyberPower binary * protocol UPSes * * Copyright (C) * 2007 Doug Reynolds * 2007-2009 Arjen de Korte * * 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 2 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, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ /* * Throughout this driver, READ and WRITE comments are shown. These are * the typical commands to and replies from the UPS that was used for * decoding the protocol (with a serial logger). */ #include "main.h" #include "serial.h" #include "powerp-bin.h" #include "nut_stdint.h" #include #define POWERPANEL_BIN_VERSION "Powerpanel-Binary 0.5" typedef struct { unsigned char start; unsigned char i_volt; unsigned char o_volt; unsigned char o_load; unsigned char fill_4; unsigned char b_chrg; unsigned char u_temp; unsigned char i_freq; unsigned char fill_8; unsigned char flags[4]; unsigned char stop; } status_t; typedef struct { const char *val; const char command; } valtab_t; static enum { PR = 0, OP = 1 } type = PR; static unsigned char powpan_answer[SMALLBUF]; /* PR series */ static const valtab_t tran_high_pr[] = { { "138", -9 }, { "139", -8 }, { "140", -7 }, { "141", -6 }, { "142", -5 }, { "143", -4 }, { "144", -3 }, { "145", -2 }, { "146", -1 }, { "147", 0 }, { NULL, 0 } }; /* OP series */ static const valtab_t tran_high_op[] = { { "140", -5 }, { "141", -4 }, { "142", -3 }, { "143", -2 }, { "144", -1 }, { "145", 0 }, { "146", +1 }, { "147", +2 }, { "148", +3 }, { "149", +4 }, { "150", +5 }, { NULL, 0 } }; /* PR series */ static const valtab_t tran_low_pr[] = { { "88", 0 }, { "89", +1 }, { "90", +2 }, { "91", +3 }, { "92", +4 }, { "93", +5 }, { "94", +6 }, { "95", +7 }, { "96", +8 }, { "97", +9 }, { NULL, 0 } }; /* OP series */ static const valtab_t tran_low_op[] = { { "85", -5 }, { "86", -4 }, { "87", -3 }, { "88", -2 }, { "89", -1 }, { "90", 0 }, { "91", +1 }, { "92", +2 }, { "93", +3 }, { "94", +4 }, { "95", +5 }, { NULL, 0 } }; /* PR series */ static const valtab_t batt_low_pr[] = { { "25", -6 }, { "30", -5 }, { "35", -3 }, { "40", -1 }, { "45", 0 }, { "50", +2 }, { "55", +4 }, { "60", +6 }, { NULL, 0 } }; /* OP series */ static const valtab_t batt_low_op[] = { { "15", -8 }, { "18", -7 }, { "19", -6 }, { "20", -5 }, { "22", -4 }, { "24", -3 }, { "25", -2 }, { "26", -1 }, { "28", 0 }, { "30", +1 }, { "32", +2 }, { "34", +3 }, { "35", +4 }, { "36", +5 }, { "38", +6 }, { "40", +7 }, { NULL, 0 } }; /* PR series */ static const valtab_t out_volt_pr[] = { { "110", -10 }, { "120", 0 }, { "130", +10 }, { NULL, 0 } }; /* OP series */ static const valtab_t out_volt_op[] = { { "110", -2 }, { "115", -1 }, { "120", 0 }, { "124", +1 }, { "128", +2 }, { "130", +3 }, { NULL, 0 } }; static const valtab_t yes_no_info[] = { { "yes", 2 }, { "no", 0 }, { NULL, 0 } }; /* Older models report the model in a numeric format 'rOnn' */ static const struct { const char *val; const char *model; } modeltab[] = { { "rO10", "OP1000AVR" }, { "rO27", "OP320AVR" }, { "rO29", "OP500AVR" }, { "rO31", "OP800AVR" }, { "rO33", "OP850AVR" }, { "rO37", "OP900AVR" }, { "rO39", "OP650AVR" }, { "rO41", "OP700AVR" }, { "rO43", "OP1250AVR" }, { "rO45", "OP1500AVR" }, { NULL, NULL } }; static const struct { const char *var; const char *get; const char *set; const valtab_t *map[2]; } vartab[] = { { "input.transfer.high", "R\x02\r", "Q\x02%c\r", { tran_high_pr, tran_high_op } }, { "input.transfer.low", "R\x04\r", "Q\x04%c\r", { tran_low_pr, tran_low_op } }, { "battery.charge.low", "R\x08\r", "Q\x08%c\r", { batt_low_pr, batt_low_op } }, { "ups.start.battery", "R\x0F\r", "Q\x0F%c\r", { yes_no_info, yes_no_info } }, { "output.voltage.nominal", "R\x18\r", "Q\x18%c\r", { out_volt_pr, out_volt_op } }, { NULL, NULL, NULL, { NULL, 0 } } }; static const struct { const char *cmd; const char *command; const size_t len; } cmdtab[] = { { "test.battery.start.quick", "T\230\r", 3 }, /* 20 seconds test */ { "test.battery.stop", "CT\r", 3 }, { "beeper.toggle", "B\r", 2 }, { "shutdown.reboot", "S\0\0R\0\1W\r", 8}, /* the shutdown.stayoff command behaves * as shutdown.return when on battery */ { "shutdown.stayoff", "S\0\0W\r", 5 }, { "shutdown.stop", "C\r", 2 }, { NULL, NULL, 0 } }; /* map UPS data to (approximated) input/output voltage */ static int op_volt(unsigned char in) { if (in < 26) { return 0; } return (((float)in * 200 / 230) + 6); } /* map UPS data to (approximated) load */ static int op_load(unsigned char in) { if (in > 108) { return 200; } return (in * 200) / 108; } /* map UPS data to (approximated) charge percentage */ static int op_chrg(unsigned char in) { if (in > 197) { return 100; } if (in < 151) { return 0; } return ((in - 151) * 100) / 46; } /* map UPS data to (approximated) temperature */ static float op_temp(unsigned char in) { return (pow((float)in / 32, 2) + 10); } /* map UPS data to (approximated) frequency */ static float op_freq(unsigned char in) { return (12600.0 / (in + 32)); } static ssize_t powpan_command(const char *buf, size_t bufsize) { ssize_t ret; ser_flush_io(upsfd); ret = ser_send_buf_pace(upsfd, UPSDELAY, buf, bufsize); if (ret < 0) { upsdebug_with_errno(3, "send"); return -1; } if (ret == 0) { upsdebug_with_errno(3, "send: timeout"); return -1; } upsdebug_hex(3, "send", buf, bufsize); usleep(100000); ret = ser_get_buf_len(upsfd, powpan_answer, bufsize-1, SER_WAIT_SEC, SER_WAIT_USEC); if (ret < 0) { upsdebug_with_errno(3, "read"); upsdebug_hex(4, " \\_", buf, bufsize-1); return -1; } if (ret == 0) { upsdebugx(3, "read: timeout"); upsdebug_hex(4, " \\_", buf, bufsize-1); return -1; } upsdebug_hex(3, "read", powpan_answer, (size_t)ret); return ret; } static int powpan_instcmd(const char *cmdname, const char *extra) { int i; for (i = 0; cmdtab[i].cmd != NULL; i++) { ssize_t ret; if (strcasecmp(cmdname, cmdtab[i].cmd)) { continue; } ret = powpan_command(cmdtab[i].command, cmdtab[i].len); assert(cmdtab[i].len < SSIZE_MAX); if (ret >= 0 && (ret == (ssize_t)(cmdtab[i].len - 1)) && (!memcmp(powpan_answer, cmdtab[i].command, cmdtab[i].len - 1)) ) { return STAT_INSTCMD_HANDLED; } upslogx(LOG_ERR, "%s: command [%s] [%s] failed", __func__, cmdname, extra); return STAT_INSTCMD_FAILED; } upslogx(LOG_ERR, "%s: command [%s] not found", __func__, cmdname); return STAT_INSTCMD_UNKNOWN; } static int powpan_setvar(const char *varname, const char *val) { char command[SMALLBUF]; int i, j; for (i = 0; vartab[i].var != NULL; i++) { if (strcasecmp(varname, vartab[i].var)) { continue; } if (!strcasecmp(val, dstate_getinfo(varname))) { upslogx(LOG_INFO, "powpan_setvar: [%s] no change for variable [%s]", val, varname); return STAT_SET_HANDLED; } for (j = 0; vartab[i].map[type][j].val != NULL; j++) { if (strcasecmp(val, vartab[i].map[type][j].val)) { continue; } #ifdef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL #pragma GCC diagnostic push #endif #ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL #pragma GCC diagnostic ignored "-Wformat-nonliteral" #endif #ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_FORMAT_SECURITY #pragma GCC diagnostic ignored "-Wformat-security" #endif snprintf(command, sizeof(command), vartab[i].set, vartab[i].map[type][j].command); #ifdef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL #pragma GCC diagnostic pop #endif if ((powpan_command(command, 4) == 3) && (!memcmp(powpan_answer, command, 3))) { dstate_setinfo(varname, "%s", val); return STAT_SET_HANDLED; } upslogx(LOG_ERR, "powpan_setvar: setting variable [%s] to [%s] failed", varname, val); return STAT_SET_UNKNOWN; } upslogx(LOG_ERR, "powpan_setvar: [%s] is not valid for variable [%s]", val, varname); return STAT_SET_UNKNOWN; } upslogx(LOG_ERR, "powpan_setvar: variable [%s] not found", varname); return STAT_SET_UNKNOWN; } static void powpan_initinfo(void) { int i, j; char *s; dstate_setinfo("ups.delay.start", "%d", 45); dstate_setinfo("ups.delay.shutdown", "%d", 0); /* almost immediate */ /* * NOTE: The reply is already in the buffer, since the F\r command * was used for autodetection of the UPS. No need to do it again. */ if ((s = strtok((char *)&powpan_answer[1], ".")) != NULL) { for (i = 0; modeltab[i].val != NULL; i++) { if (!strncmp(s, modeltab[i].val, strlen(modeltab[i].val))) { break; } } if (modeltab[i].model) { /* model found in table */ dstate_setinfo("ups.model", "%s", modeltab[i].model); } else { /* report model value as is */ dstate_setinfo("ups.model", "%s", str_rtrim(s, ' ')); } } if ((s = strtok(NULL, ".")) != NULL) { dstate_setinfo("input.voltage.nominal", "%d", (unsigned char)s[0]); } if ((s = strtok(NULL, ".")) != NULL) { dstate_setinfo("input.frequency.nominal", "%d", (unsigned char)s[0]); } if ((s = strtok(NULL, ".")) != NULL) { dstate_setinfo("ups.firmware", "%c.%c%c%c", s[0], s[1], s[2], s[3]); } for (i = 0; cmdtab[i].cmd != NULL; i++) { dstate_addcmd(cmdtab[i].cmd); } for (i = 0; vartab[i].var != NULL; i++) { if (powpan_command(vartab[i].get, 3) < 2) { continue; } for (j = 0; vartab[i].map[type][j].val != NULL; j++) { if (vartab[i].map[type][j].command != powpan_answer[1]) { continue; } dstate_setinfo(vartab[i].var, "%s", vartab[i].map[type][j].val); break; } if (dstate_getinfo(vartab[i].var) == NULL) { upslogx(LOG_WARNING, "warning: [%d] unknown value for [%s]!", powpan_answer[1], vartab[i].var); continue; } dstate_setflags(vartab[i].var, ST_FLAG_RW); for (j = 0; vartab[i].map[type][j].val != NULL; j++) { dstate_addenum(vartab[i].var, "%s", vartab[i].map[type][j].val); } } /* * FIXME: The following commands need to be reverse engineered. It * looks like they are used in detecting the UPS model. To rule out * any incompatibilities, only use them when running in debug mode. */ if (nut_debug_level > 2) { powpan_command("R\x29\r", 3); powpan_command("R\x2B\r", 3); powpan_command("R\x3D\r", 3); } dstate_addcmd("shutdown.stayoff"); dstate_addcmd("shutdown.reboot"); } static ssize_t powpan_status(status_t *status) { ssize_t ret; ser_flush_io(upsfd); /* * WRITE D\r * READ #VVL.CTF.....\r * 01234567890123 */ ret = ser_send_pace(upsfd, UPSDELAY, "D\r"); if (ret < 0) { upsdebug_with_errno(3, "send"); return -1; } if (ret == 0) { upsdebug_with_errno(3, "send: timeout"); return -1; } upsdebug_hex(3, "send", "D\r", 2); usleep(200000); ret = ser_get_buf_len(upsfd, status, sizeof(*status), SER_WAIT_SEC, SER_WAIT_USEC); if (ret < 0) { upsdebug_with_errno(3, "read"); upsdebug_hex(4, " \\_", status, sizeof(*status)); return -1; } if (ret == 0) { upsdebugx(3, "read: timeout"); upsdebug_hex(4, " \\_", status, sizeof(*status)); return -1; } upsdebug_hex(3, "read", status, (size_t)ret); if ((status->flags[0] + status->flags[1]) != 255) { upsdebugx(4, " \\_ : checksum flags[0..1] failed"); return -1; } if ((status->flags[2] + status->flags[3]) != 255) { upsdebugx(4, " \\_ : checksum flags[2..3] failed"); return -1; } return 0; } static int powpan_updateinfo(void) { status_t status; if (powpan_status(&status)) { return -1; } switch (type) { case OP: dstate_setinfo("input.voltage", "%d", op_volt(status.i_volt)); if (status.flags[0] & 0x84) { dstate_setinfo("output.voltage", "%s", dstate_getinfo("output.voltage.nominal")); } else { dstate_setinfo("output.voltage", "%d", op_volt(status.i_volt)); } dstate_setinfo("ups.load", "%d", op_load(status.o_load)); dstate_setinfo("battery.charge", "%d", op_chrg(status.b_chrg)); dstate_setinfo("ups.temperature", "%.1f", op_temp(status.u_temp)); dstate_setinfo("input.frequency", "%.1f", op_freq(status.i_freq)); break; case PR: #if (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_PUSH_POP) && (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_COVERED_SWITCH_DEFAULT) # pragma GCC diagnostic push # pragma GCC diagnostic ignored "-Wcovered-switch-default" #endif /* All enum cases defined as of the time of coding * have been covered above. Handle later definitions, * memory corruptions and buggy inputs below... */ default: #if (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_PUSH_POP) && (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_COVERED_SWITCH_DEFAULT) # pragma GCC diagnostic pop #endif dstate_setinfo("input.voltage", "%d", status.i_volt); if (status.flags[0] & 0x84) { dstate_setinfo("output.voltage", "%s", dstate_getinfo("output.voltage.nominal")); } else { dstate_setinfo("output.voltage", "%d", status.o_volt); } dstate_setinfo("ups.load", "%d", status.o_load); dstate_setinfo("battery.charge", "%d", status.b_chrg); dstate_setinfo("ups.temperature", "%d", status.u_temp); dstate_setinfo("input.frequency", "%.1f", (status.i_freq == 0) ? 0.0 : 45.0 + (float)status.i_freq / 10.0); break; } if (status.flags[0] & 0x01) { dstate_setinfo("ups.beeper.status", "enabled"); } else { dstate_setinfo("ups.beeper.status", "disabled"); } status_init(); if (status.flags[0] & 0x80) { status_set("OB"); } else { status_set("OL"); } if (status.flags[0] & 0x40) { status_set("LB"); } /* !OB && !TEST */ if (!(status.flags[0] & 0x84)) { if (status.o_volt < 0.5 * status.i_volt) { upsdebugx(2, "%s: output voltage too low", __func__); } else if (status.o_volt < 0.95 * status.i_volt) { status_set("TRIM"); } else if (status.o_volt < 1.05 * status.i_volt) { upsdebugx(2, "%s: appears to be in BYPASS state", __func__); } else if (status.o_volt < 1.5 * status.i_volt) { status_set("BOOST"); } else { upsdebugx(2, "%s: output voltage too high", __func__); } } if (status.flags[0] & 0x04) { status_set("TEST"); } if (status.flags[0] == 0) { status_set("OFF"); } status_commit(); return (status.flags[0] & 0x80) ? 1 : 0; } static ssize_t powpan_initups(void) { ssize_t ret; int i; upsdebugx(1, "Trying %s protocol...", powpan_binary.version); ser_set_speed(upsfd, device_path, B1200); /* This fails for many devices, so don't bother to complain */ ser_send_pace(upsfd, UPSDELAY, "\r\r"); for (i = 0; i < MAXTRIES; i++) { ser_flush_io(upsfd); /* * WRITE F\r * READ .PR2200 .x.<.1100 * 01234567890123456789 */ ret = ser_send_pace(upsfd, UPSDELAY, "F\r"); if (ret < 0) { upsdebug_with_errno(3, "send"); continue; } if (ret == 0) { upsdebug_with_errno(3, "send: timeout"); continue; } upsdebug_hex(3, "send", "F\r", 2); usleep(200000); ret = ser_get_line(upsfd, powpan_answer, sizeof(powpan_answer), ENDCHAR, IGNCHAR, SER_WAIT_SEC, SER_WAIT_USEC); if (ret < 0) { upsdebug_with_errno(3, "read"); upsdebug_hex(4, " \\_", powpan_answer, strlen((char *)powpan_answer)); continue; } if (ret == 0) { upsdebugx(3, "read: timeout"); upsdebug_hex(4, " \\_", powpan_answer, strlen((char *)powpan_answer)); continue; } upsdebug_hex(3, "read", powpan_answer, (size_t)ret); if (ret < 20) { upsdebugx(2, "Expected 20 bytes but only got %" PRIiSIZE, ret); continue; } if (powpan_answer[0] != '.') { upsdebugx(2, "Expected start character '.' but got '%c'", (char)powpan_answer[0]); continue; } /* See if we need to use the 'old' protocol for the OP series */ if (!strncmp((char *)&powpan_answer[1], "OP", 2)) { type = OP; } /* This is for an older model series, that reports the model numerically */ if (!strncmp((char *)&powpan_answer[1], "rO", 2)) { type = OP; } if (getval("ondelay")) { fatalx(EXIT_FAILURE, "Setting 'ondelay' not supported by %s driver", powpan_binary.version); } if (getval("offdelay")) { fatalx(EXIT_FAILURE, "Setting 'offdelay' not supported by %s driver", powpan_binary.version); } return ret; } return -1; } subdriver_t powpan_binary = { "binary", POWERPANEL_BIN_VERSION, powpan_instcmd, powpan_setvar, powpan_initups, powpan_initinfo, powpan_updateinfo }; nut-2.8.1/drivers/eaton-pdu-nlogic-mib.h0000644000175000017500000000217014501607135015014 00000000000000/* eaton-pdu-nlogic-mib.h - subdriver to monitor eaton-pdu-nlogic SNMP devices with NUT * * Copyright (C) * 2011 - 2016 Arnaud Quette * 2022 Eaton (author: Arnaud Quette ) * * 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 2 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, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef EATON_PDU_NLOGIC_MIB_H #define EATON_PDU_NLOGIC_MIB_H #include "main.h" #include "snmp-ups.h" extern mib2nut_info_t eaton_pdu_nlogic; #endif /* EATON_PDU_NLOGIC_MIB_H */ nut-2.8.1/drivers/huawei-mib.c0000644000175000017500000002573114501607135013134 00000000000000/* huawei-mib.c - subdriver to monitor Huawei SNMP devices with NUT * * Copyright (C) * 2011 - 2012 Arnaud Quette * 2015 Stuart Henderson * * 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 2 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, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "huawei-mib.h" #define HUAWEI_MIB_VERSION "0.4" #define HUAWEI_SYSOID ".1.3.6.1.4.1.8072.3.2.10" #define HUAWEI_UPSMIB ".1.3.6.1.4.1.2011" #define HUAWEI_OID_MODEL_NAME ".1.3.6.1.4.1.2011.6.174.1.2.100.1.2.1" /* To create a value lookup structure (as needed on the 2nd line of the example * below), use the following kind of declaration, outside of the present snmp_info_t[]: * static info_lkp_t huawei_onbatt_info[] = { * { 1, "OB", NULL, NULL }, * { 2, "OL", NULL, NULL }, * { 0, NULL, NULL, NULL } * }; */ static info_lkp_t huawei_supplymethod_info[] = { { 1, "", NULL, NULL }, /* no supply */ { 2, "OL BYPASS", NULL, NULL }, { 3, "OL", NULL, NULL }, { 4, "OB", NULL, NULL }, { 5, "", NULL, NULL }, /* combined */ { 6, "OL ECO", NULL, NULL }, { 7, "OB ECO", NULL, NULL }, { 0, NULL, NULL, NULL } }; static info_lkp_t huawei_battstate_info[] = { { 1, "", NULL, NULL }, /* not connected */ { 2, "", NULL, NULL }, /* not charging or discharging */ { 3, "", NULL, NULL }, /* hibernation */ { 4, "", NULL, NULL }, /* float */ { 5, "CHRG", NULL, NULL }, /* equalized charging */ { 6, "DISCHRG", NULL, NULL }, { 0, NULL, NULL, NULL } }; static info_lkp_t huawei_phase_info[] = { { 1, "1", NULL, NULL }, { 2, "3", NULL, NULL }, { 0, NULL, NULL, NULL } }; static info_lkp_t huawei_voltrating_info[] = { { 1, "200", NULL, NULL }, { 2, "208", NULL, NULL }, { 3, "220", NULL, NULL }, { 4, "380", NULL, NULL }, { 5, "400", NULL, NULL }, { 6, "415", NULL, NULL }, { 7, "480", NULL, NULL }, { 8, "600", NULL, NULL }, { 9, "690", NULL, NULL }, { 0, NULL, NULL, NULL } }; static info_lkp_t huawei_freqrating_info[] = { { 1, "50", NULL, NULL }, { 2, "60", NULL, NULL }, { 0, NULL, NULL, NULL } }; static info_lkp_t huawei_pwrrating_info[] = { { 1, "80000", NULL, NULL }, { 2, "100000", NULL, NULL }, { 3, "120000", NULL, NULL }, { 4, "160000", NULL, NULL }, { 5, "200000", NULL, NULL }, { 6, "30000", NULL, NULL }, { 7, "40000", NULL, NULL }, { 8, "60000", NULL, NULL }, { 9, "2400000", NULL, NULL }, { 10, "2500000", NULL, NULL }, { 11, "2800000", NULL, NULL }, { 12, "3000000", NULL, NULL }, { 0, NULL, NULL, NULL } }; /* Note: This is currently identical to ietf_test_result_info from IETF MIB * We rename it here to a) allow evolution that may become incompatible; * b) avoid namespace conflicts, especially with DMF loader of named objects */ static info_lkp_t huawei_test_result_info[] = { { 1, "done and passed", NULL, NULL }, { 2, "done and warning", NULL, NULL }, { 3, "done and error", NULL, NULL }, { 4, "aborted", NULL, NULL }, { 5, "in progress", NULL, NULL }, { 6, "no test initiated", NULL, NULL }, { 0, NULL, NULL, NULL } }; /* HUAWEI Snmp2NUT lookup table */ static snmp_info_t huawei_mib[] = { /* Data format: * { info_type, info_flags, info_len, OID, dfl, flags, oid2info, setvar }, * * info_type: NUT INFO_ or CMD_ element name * info_flags: flags to set in addinfo * info_len: length of strings if STR * cmd value if CMD, multiplier otherwise * OID: SNMP OID or NULL * dfl: default value * flags: snmp-ups internal flags (FIXME: ...) * oid2info: lookup table between OID and NUT values * * Example: * { "input.voltage", 0, 0.1, ".1.3.6.1.4.1.705.1.6.2.1.2.1", "", SU_INPUT_1, NULL }, * { "ups.status", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.705.1.7.3.0", "", SU_FLAG_OK | SU_STATUS_BATT, huawei_onbatt_info }, * * To create a value lookup structure (as needed on the 2nd line), use the * following kind of declaration, outside of the present snmp_info_t[]: * static info_lkp_t huawei_onbatt_info[] = { * { 1, "OB" }, * { 2, "OL" }, * { 0, NULL } * }; */ /* standard MIB items */ { "device.description", ST_FLAG_STRING | ST_FLAG_RW, SU_INFOSIZE, ".1.3.6.1.2.1.1.1.0", NULL, SU_FLAG_OK, NULL }, { "device.contact", ST_FLAG_STRING | ST_FLAG_RW, SU_INFOSIZE, ".1.3.6.1.2.1.1.4.0", NULL, SU_FLAG_OK, NULL }, { "device.location", ST_FLAG_STRING | ST_FLAG_RW, SU_INFOSIZE, ".1.3.6.1.2.1.1.6.0", NULL, SU_FLAG_OK, NULL }, /* UPS page */ { "ups.mfr", ST_FLAG_STRING, SU_INFOSIZE, NULL, "Huawei", SU_FLAG_ABSENT | SU_FLAG_OK, NULL }, { "ups.model", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.2011.6.174.1.2.100.1.2.1", "Generic SNMP UPS", SU_FLAG_STATIC | SU_FLAG_OK, NULL }, { "ups.id", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.2011.6.174.1.1.1.2.0", NULL, SU_FLAG_STATIC | SU_FLAG_OK, NULL }, { "ups.time", 0, 1, ".1.3.6.1.4.1.2011.6.174.1.11.1.0", NULL, SU_FLAG_OK, NULL }, /* seconds since epoch */ { "ups.firmware", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.2011.6.174.1.2.100.1.3.1", NULL, SU_FLAG_STATIC | SU_FLAG_OK, NULL }, { "ups.serial", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.2011.6.174.1.2.100.1.5.1", NULL, SU_FLAG_STATIC | SU_FLAG_OK, NULL }, { "ups.status", 0, 1, ".1.3.6.1.4.1.2011.6.174.1.2.101.1.1.1", NULL, SU_FLAG_OK, huawei_supplymethod_info }, { "ups.status", 0, 1, ".1.3.6.1.4.1.2011.6.174.1.2.101.1.3.1", NULL, SU_STATUS_BATT | SU_FLAG_OK, huawei_battstate_info }, { "ups.test.result", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.2.1.33.1.7.3.0", "", 0, huawei_test_result_info }, /* Input page */ /* hwUpsCtrlInputStandard listed in MIB but not present on tested UPS5000-E */ { "input.phases", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.2011.6.174.1.102.100.1.8", "3", SU_FLAG_ABSENT | SU_FLAG_OK, huawei_phase_info }, { "input.L1-N.voltage", 0, 0.1, ".1.3.6.1.4.1.2011.6.174.1.3.100.1.1.1", NULL, SU_FLAG_OK, NULL }, { "input.L2-N.voltage", 0, 0.1, ".1.3.6.1.4.1.2011.6.174.1.3.100.1.2.1", NULL, SU_FLAG_OK, NULL }, { "input.L3-N.voltage", 0, 0.1, ".1.3.6.1.4.1.2011.6.174.1.3.100.1.3.1", NULL, SU_FLAG_OK, NULL }, { "input.frequency", 0, 0.01, ".1.3.6.1.4.1.2011.6.174.1.3.100.1.4.1", NULL, SU_FLAG_OK, NULL }, { "input.L1.current", 0, 0.1, ".1.3.6.1.4.1.2011.6.174.1.3.100.1.5.1", NULL, SU_FLAG_OK, NULL }, { "input.L2.current", 0, 0.1, ".1.3.6.1.4.1.2011.6.174.1.3.100.1.6.1", NULL, SU_FLAG_OK, NULL }, { "input.L3.current", 0, 0.1, ".1.3.6.1.4.1.2011.6.174.1.3.100.1.7.1", NULL, SU_FLAG_OK, NULL }, { "input.L1.powerfactor", 0, 0.01, ".1.3.6.1.4.1.2011.6.174.1.3.100.1.8.1", NULL, SU_FLAG_OK, NULL }, { "input.L2.powerfactor", 0, 0.01, ".1.3.6.1.4.1.2011.6.174.1.3.100.1.9.1", NULL, SU_FLAG_OK, NULL }, { "input.L3.powerfactor", 0, 0.01, ".1.3.6.1.4.1.2011.6.174.1.3.100.1.10.1", NULL, SU_FLAG_OK, NULL }, { "input.bypass.L1-N.voltage", 0, 0.1, ".1.3.6.1.4.1.2011.6.174.1.5.100.1.1.1", NULL, SU_FLAG_OK, NULL }, { "input.bypass.L2-N.voltage", 0, 0.1, ".1.3.6.1.4.1.2011.6.174.1.5.100.1.2.1", NULL, SU_FLAG_OK, NULL }, { "input.bypass.L3-N.voltage", 0, 0.1, ".1.3.6.1.4.1.2011.6.174.1.5.100.1.3.1", NULL, SU_FLAG_OK, NULL }, { "input.bypass.frequency", 0, 0.01, ".1.3.6.1.4.1.2011.6.174.1.5.100.1.4.1", NULL, SU_FLAG_OK, NULL }, /* Output page */ /* hwUpsCtrlOutputStandard listed in MIB but not present on tested UPS5000-E */ { "output.phases", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.2011.6.174.1.102.100.1.9", "3", SU_FLAG_ABSENT | SU_FLAG_OK, huawei_phase_info }, { "output.L1-N.voltage", 0, 0.1, ".1.3.6.1.4.1.2011.6.174.1.4.100.1.1.1", NULL, SU_FLAG_OK, NULL }, { "output.L2-N.voltage", 0, 0.1, ".1.3.6.1.4.1.2011.6.174.1.4.100.1.2.1", NULL, SU_FLAG_OK, NULL }, { "output.L3-N.voltage", 0, 0.1, ".1.3.6.1.4.1.2011.6.174.1.4.100.1.3.1", NULL, SU_FLAG_OK, NULL }, { "output.L1.current", 0, 0.1, ".1.3.6.1.4.1.2011.6.174.1.4.100.1.4.1", NULL, SU_FLAG_OK, NULL }, { "output.L2.current", 0, 0.1, ".1.3.6.1.4.1.2011.6.174.1.4.100.1.5.1", NULL, SU_FLAG_OK, NULL }, { "output.L3.current", 0, 0.1, ".1.3.6.1.4.1.2011.6.174.1.4.100.1.6.1", NULL, SU_FLAG_OK, NULL }, { "output.frequency", 0, 0.01, ".1.3.6.1.4.1.2011.6.174.1.4.100.1.7.1", NULL, SU_FLAG_OK, NULL }, { "output.L1.realpower", 0, 0.1, ".1.3.6.1.4.1.2011.6.174.1.4.100.1.8.1", NULL, SU_FLAG_OK, NULL }, { "output.L1.realpower", 0, 0.1, ".1.3.6.1.4.1.2011.6.174.1.4.100.1.9.1", NULL, SU_FLAG_OK, NULL }, { "output.L1.realpower", 0, 0.1, ".1.3.6.1.4.1.2011.6.174.1.4.100.1.10.1", NULL, SU_FLAG_OK, NULL }, { "output.L1.power", 0, 0.1, ".1.3.6.1.4.1.2011.6.174.1.4.100.1.11.1", NULL, SU_FLAG_OK, NULL }, { "output.L2.power", 0, 0.1, ".1.3.6.1.4.1.2011.6.174.1.4.100.1.12.1", NULL, SU_FLAG_OK, NULL }, { "output.L3.power", 0, 0.1, ".1.3.6.1.4.1.2011.6.174.1.4.100.1.13.1", NULL, SU_FLAG_OK, NULL }, { "output.L1.power.percent", 0, 0.1, ".1.3.6.1.4.1.2011.6.174.1.4.100.1.14.1", NULL, SU_FLAG_OK, NULL }, { "output.L2.power.percent", 0, 0.1, ".1.3.6.1.4.1.2011.6.174.1.4.100.1.15.1", NULL, SU_FLAG_OK, NULL }, { "output.L3.power.percent", 0, 0.1, ".1.3.6.1.4.1.2011.6.174.1.4.100.1.16.1", NULL, SU_FLAG_OK, NULL }, { "output.voltage.nominal", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.2011.6.174.1.4.100.1.17.1", NULL, SU_FLAG_STATIC | SU_FLAG_OK, huawei_voltrating_info }, { "output.frequency.nominal", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.2011.6.174.1.4.100.1.18.1", NULL, SU_FLAG_STATIC | SU_FLAG_OK, huawei_freqrating_info }, { "output.power.nominal", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.2011.6.174.1.2.100.1.6.1", NULL, SU_FLAG_STATIC | SU_FLAG_OK, huawei_pwrrating_info }, { "output.L1.powerfactor", 0, 0.01, ".1.3.6.1.4.1.2011.6.174.1.4.100.1.19.1", NULL, SU_FLAG_OK, NULL }, { "output.L2.powerfactor", 0, 0.01, ".1.3.6.1.4.1.2011.6.174.1.4.100.1.20.1", NULL, SU_FLAG_OK, NULL }, { "output.L2.powerfactor", 0, 0.01, ".1.3.6.1.4.1.2011.6.174.1.4.100.1.21.1", NULL, SU_FLAG_OK, NULL }, /* Battery page */ { "battery.voltage", 0, 0.1, ".1.3.6.1.4.1.2011.6.174.1.6.100.1.1.1", NULL, SU_FLAG_OK, NULL }, { "battery.current", 0, 0.1, ".1.3.6.1.4.1.2011.6.174.1.6.100.1.2.1", NULL, SU_FLAG_OK, NULL }, { "battery.charge", 0, 1, ".1.3.6.1.4.1.2011.6.174.1.6.100.1.3.1", NULL, SU_FLAG_OK, NULL }, { "battery.runtime", 0, 1, ".1.3.6.1.4.1.2011.6.174.1.6.100.1.4.1", NULL, SU_FLAG_OK, NULL }, #if WITH_UNMAPPED_DATA_POINTS { "unmapped.hwUpsBattTest", 0, 1, ".1.3.6.1.4.1.2011.6.174.1.103.101.1.6.1", NULL, SU_FLAG_OK, NULL }, #endif /* if WITH_UNMAPPED_DATA_POINTS */ /* end of structure. */ { NULL, 0, 0, NULL, NULL, 0, NULL } }; mib2nut_info_t huawei = { "huawei", HUAWEI_MIB_VERSION, NULL, HUAWEI_OID_MODEL_NAME, huawei_mib, HUAWEI_SYSOID, NULL }; nut-2.8.1/drivers/eaton-ats16-nmc-mib.c0000644000175000017500000003745614501607135014476 00000000000000/* eaton-ats16-nmc-mib.c - subdriver to monitor Eaton ATS16 NMC SNMP devices with NUT * using legacy NMC cards * * Copyright (C) * 2011-2012 Arnaud Quette * 2016-2020 Eaton (author: Arnaud Quette ) * * Note: this subdriver was initially generated as a "stub" by the * gen-snmp-subdriver script. It must be customized! * * 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 2 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, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "eaton-ats16-nmc-mib.h" #define EATON_ATS16_NMC_MIB_VERSION "0.21" #define EATON_ATS16_NMC_SYSOID ".1.3.6.1.4.1.705.1" /* legacy NMC */ #define EATON_ATS16_NMC_MODEL ".1.3.6.1.4.1.534.10.2.1.2.0" static info_lkp_t eaton_ats16_nmc_source_info[] = { { 1, "init", NULL, NULL }, { 2, "diagnosis", NULL, NULL }, { 3, "off", NULL, NULL }, { 4, "1", NULL, NULL }, { 5, "2", NULL, NULL }, { 6, "safe", NULL, NULL }, { 7, "fault", NULL, NULL }, { 0, NULL, NULL, NULL } }; static info_lkp_t eaton_ats16_nmc_sensitivity_info[] = { { 1, "normal", NULL, NULL }, { 2, "high", NULL, NULL }, { 3, "low", NULL, NULL }, { 0, NULL, NULL, NULL } }; static info_lkp_t eaton_ats16_nmc_input_frequency_status_info[] = { { 1, "good", NULL, NULL }, /* No threshold triggered */ { 2, "out-of-range", NULL, NULL }, /* Frequency out of range triggered */ { 0, NULL, NULL, NULL } }; static info_lkp_t eaton_ats16_nmc_input_voltage_status_info[] = { { 1, "good", NULL, NULL }, /* No threshold triggered */ { 2, "derated-range", NULL, NULL }, /* Voltage derated */ { 3, "out-of-range", NULL, NULL }, /* Voltage out of range triggered */ { 4, "unknown", NULL, NULL }, /* "missing" */ { 0, NULL, NULL, NULL } }; static info_lkp_t eaton_ats16_nmc_test_result_info[] = { { 1, "done and passed", NULL, NULL }, { 2, "done and warning", NULL, NULL }, { 3, "done and error", NULL, NULL }, { 4, "aborted", NULL, NULL }, { 5, "in progress", NULL, NULL }, { 6, "no test initiated", NULL, NULL }, { 0, NULL, NULL, NULL } }; static info_lkp_t eaton_ats16_nmc_output_status_info[] = { { 1, "OFF", NULL, NULL }, /* Output not powered */ { 2, "OL", NULL, NULL }, /* Output powered */ { 0, NULL, NULL, NULL } }; static info_lkp_t eaton_ats16_ambient_drycontacts_info[] = { { -1, "unknown", NULL, NULL }, { 1, "opened", NULL, NULL }, { 2, "closed", NULL, NULL }, { 3, "opened", NULL, NULL }, /* openWithNotice */ { 4, "closed", NULL, NULL }, /* closedWithNotice */ { 0, NULL, NULL, NULL } }; /* EATON_ATS_NMC Snmp2NUT lookup table */ static snmp_info_t eaton_ats16_nmc_mib[] = { /* standard MIB items */ { "device.description", ST_FLAG_STRING | ST_FLAG_RW, SU_INFOSIZE, ".1.3.6.1.2.1.1.1.0", NULL, SU_FLAG_OK, NULL }, { "device.contact", ST_FLAG_STRING | ST_FLAG_RW, SU_INFOSIZE, ".1.3.6.1.2.1.1.4.0", NULL, SU_FLAG_OK, NULL }, { "device.location", ST_FLAG_STRING | ST_FLAG_RW, SU_INFOSIZE, ".1.3.6.1.2.1.1.6.0", NULL, SU_FLAG_OK, NULL }, /* Device collection */ { "device.type", ST_FLAG_STRING, SU_INFOSIZE, NULL, "ats", SU_FLAG_STATIC | SU_FLAG_ABSENT | SU_FLAG_OK, NULL }, /* ats2IdentManufacturer.0 = STRING: EATON */ { "device.mfr", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.534.10.2.1.1.0", "Eaton", SU_FLAG_STATIC | SU_FLAG_OK, NULL }, /* ats2IdentModel.0 = STRING: Eaton ATS */ { "device.model", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.534.10.2.1.2.0", "ATS", SU_FLAG_STATIC | SU_FLAG_OK, NULL }, /* FIXME: RFC for device.firmware! */ /* FIXME: the 2 "firmware" entries below should be SU_FLAG_SEMI_STATIC */ /* ats2IdentFWVersion.0 = STRING: 00.00.0009 */ { "ups.firmware", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.534.10.2.1.3.0", NULL, SU_FLAG_OK, NULL }, /* FIXME: RFC for device.firmware.aux! */ /* ats2IdentRelease.0 = STRING: JF */ { "ups.firmware.aux", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.534.10.2.1.4.0", NULL, SU_FLAG_OK, NULL }, /* ats2IdentSerialNumber.0 = STRING: GA04F23009 */ { "device.serial", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.534.10.2.1.5.0", NULL, SU_FLAG_STATIC | SU_FLAG_OK, NULL }, /* ats2IdentPartNumber.0 = STRING: EATS16N */ { "device.part", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.534.10.2.1.6.0", NULL, SU_FLAG_STATIC | SU_FLAG_OK, NULL }, /* ats2IdentAgentVersion.0 = STRING: 301F23C28 */ /* { "unmapped.ats2IdentAgentVersion", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.534.10.2.1.7.0", NULL, SU_FLAG_OK, NULL, NULL }, */ /* ats2InputDephasing.0 = INTEGER: 2 degrees */ /* { "unmapped.ats2InputDephasing", 0, 1, ".1.3.6.1.4.1.534.10.2.2.1.1.0", NULL, SU_FLAG_OK, NULL, NULL }, */ /* Input collection */ /* ats2InputIndex.source1 = INTEGER: source1(1) */ { "input.1.id", 0, 1, ".1.3.6.1.4.1.534.10.2.2.2.1.1.1", NULL, SU_FLAG_STATIC | SU_FLAG_OK, NULL }, /* ats2InputIndex.source2 = INTEGER: source2(2) */ { "input.2.id", 0, 1, ".1.3.6.1.4.1.534.10.2.2.2.1.1.2", NULL, SU_FLAG_STATIC | SU_FLAG_OK, NULL }, /* ats2InputVoltage.source1 = INTEGER: 2292 0.1 V */ { "input.1.voltage", 0, 0.1, ".1.3.6.1.4.1.534.10.2.2.2.1.2.1", NULL, SU_FLAG_OK, NULL }, /* ats2InputVoltage.source2 = INTEGER: 2432 0.1 V */ { "input.2.voltage", 0, 0.1, ".1.3.6.1.4.1.534.10.2.2.2.1.2.2", NULL, SU_FLAG_OK, NULL }, /* ats2InputStatusVoltage.source1 = INTEGER: normalRange(1) */ { "input.1.voltage.status", ST_FLAG_STRING, 1, ".1.3.6.1.4.1.534.10.2.3.2.1.5.1", NULL, SU_FLAG_OK, eaton_ats16_nmc_input_voltage_status_info }, /* ats2InputStatusVoltage.source2 = INTEGER: normalRange(1) */ { "input.2.voltage.status", ST_FLAG_STRING, 1, ".1.3.6.1.4.1.534.10.2.3.2.1.5.2", NULL, SU_FLAG_OK, eaton_ats16_nmc_input_voltage_status_info }, /* ats2InputFrequency.source1 = INTEGER: 500 0.1 Hz */ { "input.1.frequency", 0, 0.1, ".1.3.6.1.4.1.534.10.2.2.2.1.3.1", NULL, SU_FLAG_OK, NULL }, /* ats2InputFrequency.source2 = INTEGER: 500 0.1 Hz */ { "input.2.frequency", 0, 0.1, ".1.3.6.1.4.1.534.10.2.2.2.1.3.2", NULL, SU_FLAG_OK, NULL }, /* ats2InputStatusFrequency.source1 = INTEGER: good(1) */ { "input.1.frequency.status", ST_FLAG_STRING, 1, ".1.3.6.1.4.1.534.10.2.3.2.1.2.1", NULL, SU_FLAG_OK, eaton_ats16_nmc_input_frequency_status_info }, /* ats2InputStatusFrequency.source2 = INTEGER: good(1) */ { "input.2.frequency.status", ST_FLAG_STRING, 1, ".1.3.6.1.4.1.534.10.2.3.2.1.2.2", NULL, SU_FLAG_OK, eaton_ats16_nmc_input_frequency_status_info }, /* ats2ConfigSensitivity.0 = INTEGER: normal(1) */ { "input.sensitivity", ST_FLAG_RW, SU_INFOSIZE, ".1.3.6.1.4.1.534.10.2.4.6.0", NULL, SU_FLAG_OK, &eaton_ats16_nmc_sensitivity_info[0] }, /* ats2OperationMode.0 = INTEGER: source1(4) */ { "input.source", ST_FLAG_STRING, 1, ".1.3.6.1.4.1.534.10.2.2.4.0", NULL, SU_FLAG_OK, eaton_ats16_nmc_source_info }, /* ats2ConfigPreferred.0 = INTEGER: source1(1) */ { "input.source.preferred", ST_FLAG_RW, 1, ".1.3.6.1.4.1.534.10.2.4.5.0", NULL, SU_FLAG_OK, NULL }, /* ats2InputDephasing = INTEGER: 181 */ { "input.phase.shift", 0, 1, ".1.3.6.1.4.1.534.10.2.2.1.1.0", NULL, SU_FLAG_OK, NULL }, /* Output collection */ /* ats2OutputVoltage.0 = INTEGER: 2304 0.1 V */ { "output.voltage", 0, 0.1, ".1.3.6.1.4.1.534.10.2.2.3.1.0", NULL, SU_FLAG_OK, NULL }, /* ats2ConfigOutputVoltage.0 = INTEGER: 230 1 V */ { "output.voltage.nominal", ST_FLAG_RW, 1, ".1.3.6.1.4.1.534.10.2.4.4.0", NULL, SU_FLAG_OK, NULL }, /* ats2OutputCurrent.0 = INTEGER: 5 0.1 A */ { "output.current", 0, 0.1, ".1.3.6.1.4.1.534.10.2.2.3.2.0", NULL, SU_FLAG_OK, NULL }, /* UPS collection */ /* FIXME: RFC for device.test.result! */ /* ats2ConfigTransferTest.0 = INTEGER: noTestInitiated(6) */ { "ups.test.result", 0, 1, ".1.3.6.1.4.1.534.10.2.4.8.0", NULL, SU_FLAG_OK, eaton_ats16_nmc_test_result_info }, /* FIXME: RFC for device.status! */ /* ats2StatusOutput.0 = INTEGER: outputPowered(2) */ { "ups.status", 0, 1, ".1.3.6.1.4.1.534.10.2.3.3.2.0", NULL, SU_FLAG_OK, eaton_ats16_nmc_output_status_info }, /* Ambient collection */ /* ats2EnvRemoteTemp.0 = INTEGER: 0 degrees Centigrade */ { "ambient.temperature", 0, 0.1, ".1.3.6.1.4.1.534.10.2.5.1.0", NULL, SU_FLAG_OK, NULL }, /* ats2EnvRemoteTempLowerLimit.0 = INTEGER: 5 degrees Centigrade */ { "ambient.temperature.low", ST_FLAG_RW, 1, ".1.3.6.1.4.1.534.10.2.5.5.0", NULL, SU_FLAG_OK, NULL }, /* ats2EnvRemoteTempUpperLimit.0 = INTEGER: 40 degrees Centigrade */ { "ambient.temperature.high", ST_FLAG_RW, 1, ".1.3.6.1.4.1.534.10.2.5.6.0", NULL, SU_FLAG_OK, NULL }, /* ats2EnvRemoteHumidity.0 = INTEGER: 0 percent */ { "ambient.humidity", 0, 0.1, ".1.3.6.1.4.1.534.10.2.5.2.0", NULL, SU_FLAG_OK, NULL }, /* ats2EnvRemoteHumidityLowerLimit.0 = INTEGER: 5 percent */ { "ambient.humidity.low", ST_FLAG_RW, 1, ".1.3.6.1.4.1.534.10.2.5.7.0", NULL, SU_FLAG_OK, NULL }, /* ats2EnvRemoteHumidityUpperLimit.0 = INTEGER: 90 percent */ { "ambient.humidity.high", ST_FLAG_RW, 1, ".1.3.6.1.4.1.534.10.2.5.8.0", NULL, SU_FLAG_OK, NULL }, /* Dry contacts on EMP001 TH module */ /* ats2ContactState.1 = INTEGER: open(1) */ { "ambient.contacts.1.status", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.534.10.2.5.4.1.3.1", NULL, SU_FLAG_OK, &eaton_ats16_ambient_drycontacts_info[0] }, /* ats2ContactState.2 = INTEGER: open(1) */ { "ambient.contacts.2.status", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.534.10.2.5.4.1.3.2", NULL, SU_FLAG_OK, &eaton_ats16_ambient_drycontacts_info[0]}, #if WITH_UNMAPPED_DATA_POINTS /* FIXME: Remaining data to be processed */ /* ats2InputStatusDephasing.0 = INTEGER: normal(1) */ { "unmapped.ats2InputStatusDephasing", 0, 1, ".1.3.6.1.4.1.534.10.2.3.1.1.0", NULL, SU_FLAG_OK, NULL }, /* ats2InputStatusIndex.source1 = INTEGER: source1(1) */ { "unmapped.ats2InputStatusIndex", 0, 1, ".1.3.6.1.4.1.534.10.2.3.2.1.1.1", NULL, SU_FLAG_OK, NULL }, /* ats2InputStatusIndex.source2 = INTEGER: source2(2) */ { "unmapped.ats2InputStatusIndex", 0, 1, ".1.3.6.1.4.1.534.10.2.3.2.1.1.2", NULL, SU_FLAG_OK, NULL }, /* ats2InputStatusGood.source1 = INTEGER: voltageAndFreqNormalRange(2) */ { "unmapped.ats2InputStatusGood", 0, 1, ".1.3.6.1.4.1.534.10.2.3.2.1.3.1", NULL, SU_FLAG_OK, NULL }, /* ats2InputStatusGood.source2 = INTEGER: voltageAndFreqNormalRange(2) */ { "unmapped.ats2InputStatusGood", 0, 1, ".1.3.6.1.4.1.534.10.2.3.2.1.3.2", NULL, SU_FLAG_OK, NULL }, /* ats2InputStatusInternalFailure.source1 = INTEGER: good(1) */ { "unmapped.ats2InputStatusInternalFailure", 0, 1, ".1.3.6.1.4.1.534.10.2.3.2.1.4.1", NULL, SU_FLAG_OK, NULL }, /* ats2InputStatusInternalFailure.source2 = INTEGER: good(1) */ { "unmapped.ats2InputStatusInternalFailure", 0, 1, ".1.3.6.1.4.1.534.10.2.3.2.1.4.2", NULL, SU_FLAG_OK, NULL }, /* ats2InputStatusUsed.source1 = INTEGER: poweringLoad(2) */ { "unmapped.ats2InputStatusUsed", 0, 1, ".1.3.6.1.4.1.534.10.2.3.2.1.6.1", NULL, SU_FLAG_OK, NULL }, /* ats2InputStatusUsed.source2 = INTEGER: notPoweringLoad(1) */ { "unmapped.ats2InputStatusUsed", 0, 1, ".1.3.6.1.4.1.534.10.2.3.2.1.6.2", NULL, SU_FLAG_OK, NULL }, /* ats2StatusInternalFailure.0 = INTEGER: good(1) */ { "unmapped.ats2StatusInternalFailure", 0, 1, ".1.3.6.1.4.1.534.10.2.3.3.1.0", NULL, SU_FLAG_OK, NULL }, /* ats2StatusOverload.0 = INTEGER: noOverload(1) */ { "unmapped.ats2StatusOverload", 0, 1, ".1.3.6.1.4.1.534.10.2.3.3.3.0", NULL, SU_FLAG_OK, NULL }, /* ats2StatusOverTemperature.0 = INTEGER: noOverTemperature(1) */ { "unmapped.ats2StatusOverTemperature", 0, 1, ".1.3.6.1.4.1.534.10.2.3.3.4.0", NULL, SU_FLAG_OK, NULL }, /* ats2StatusShortCircuit.0 = INTEGER: noShortCircuit(1) */ { "unmapped.ats2StatusShortCircuit", 0, 1, ".1.3.6.1.4.1.534.10.2.3.3.5.0", NULL, SU_FLAG_OK, NULL }, /* ats2StatusCommunicationLost.0 = INTEGER: good(1) */ { "unmapped.ats2StatusCommunicationLost", 0, 1, ".1.3.6.1.4.1.534.10.2.3.3.6.0", NULL, SU_FLAG_OK, NULL }, /* ats2StatusConfigurationFailure.0 = INTEGER: good(1) */ { "unmapped.ats2StatusConfigurationFailure", 0, 1, ".1.3.6.1.4.1.534.10.2.3.3.7.0", NULL, SU_FLAG_OK, NULL }, /* ats2ConfigTimeRTC.0 = Wrong Type (should be Counter32): Gauge32: 19191036 */ { "unmapped.ats2ConfigTimeRTC", 0, 1, ".1.3.6.1.4.1.534.10.2.4.1.1.0", NULL, SU_FLAG_OK, NULL }, /* ats2ConfigTimeTextDate.0 = STRING: 08/11/1970 */ { "unmapped.ats2ConfigTimeTextDate", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.534.10.2.4.1.2.0", NULL, SU_FLAG_OK, NULL }, /* ats2ConfigTimeTextTime.0 = STRING: 02/50/36 */ { "unmapped.ats2ConfigTimeTextTime", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.534.10.2.4.1.3.0", NULL, SU_FLAG_OK, NULL }, /* ats2ConfigInputVoltageRating.0 = INTEGER: 1 1 V */ { "unmapped.ats2ConfigInputVoltageRating", 0, 1, ".1.3.6.1.4.1.534.10.2.4.2.0", NULL, SU_FLAG_OK, NULL }, /* ats2ConfigInputFrequencyRating.0 = INTEGER: 50 Hz */ { "unmapped.ats2ConfigInputFrequencyRating", 0, 1, ".1.3.6.1.4.1.534.10.2.4.3.0", NULL, SU_FLAG_OK, NULL }, /* ats2ConfigTransferMode.0 = INTEGER: standard(1) */ { "unmapped.ats2ConfigTransferMode", 0, 1, ".1.3.6.1.4.1.534.10.2.4.7.0", NULL, SU_FLAG_OK, NULL }, /* ats2ConfigBrownoutLow.0 = INTEGER: 202 1 V */ { "unmapped.ats2ConfigBrownoutLow", 0, 1, ".1.3.6.1.4.1.534.10.2.4.9.0", NULL, SU_FLAG_OK, NULL }, /* ats2ConfigBrownoutLowDerated.0 = INTEGER: 189 1 V */ { "unmapped.ats2ConfigBrownoutLowDerated", 0, 1, ".1.3.6.1.4.1.534.10.2.4.10.0", NULL, SU_FLAG_OK, NULL }, /* ats2ConfigBrownoutHigh.0 = INTEGER: 258 1 V */ { "unmapped.ats2ConfigBrownoutHigh", 0, 1, ".1.3.6.1.4.1.534.10.2.4.11.0", NULL, SU_FLAG_OK, NULL }, /* ats2ConfigHysteresisVoltage.0 = INTEGER: 5 1 V */ { "unmapped.ats2ConfigHysteresisVoltage", 0, 1, ".1.3.6.1.4.1.534.10.2.4.12.0", NULL, SU_FLAG_OK, NULL }, /* Ambient collection */ /* ats2EnvNumContacts.0 = INTEGER: 2 */ { "unmapped.ats2EnvNumContacts", 0, 1, ".1.3.6.1.4.1.534.10.2.5.3.0", NULL, SU_FLAG_OK, NULL }, /* ats2ContactIndex.1 = INTEGER: 1 */ { "unmapped.ats2ContactIndex", 0, 1, ".1.3.6.1.4.1.534.10.2.5.4.1.1.1", NULL, SU_FLAG_OK, NULL }, /* ats2ContactIndex.2 = INTEGER: 2 */ { "unmapped.ats2ContactIndex", 0, 1, ".1.3.6.1.4.1.534.10.2.5.4.1.1.2", NULL, SU_FLAG_OK, NULL }, /* ats2ContactType.1 = INTEGER: notUsed(4) */ { "unmapped.ats2ContactType", 0, 1, ".1.3.6.1.4.1.534.10.2.5.4.1.2.1", NULL, SU_FLAG_OK, NULL }, /* ats2ContactType.2 = INTEGER: notUsed(4) */ { "unmapped.ats2ContactType", 0, 1, ".1.3.6.1.4.1.534.10.2.5.4.1.2.2", NULL, SU_FLAG_OK, NULL }, /* ats2ContactDescr.1 = STRING: Input #1 */ { "unmapped.ats2ContactDescr", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.534.10.2.5.4.1.4.1", NULL, SU_FLAG_OK, NULL }, /* ats2ContactDescr.2 = STRING: Input #2 */ { "unmapped.ats2ContactDescr", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.534.10.2.5.4.1.4.2", NULL, SU_FLAG_OK, NULL }, #endif /* if WITH_UNMAPPED_DATA_POINTS */ /* end of structure. */ { NULL, 0, 0, NULL, NULL, 0, NULL } }; /* Note: keep the legacy definition intact, to avoid breaking compatibility */ /* FIXME: The lines below are duplicated to fix an issue with the code generator (nut-snmpinfo.py -> line is discarding) */ /* Note: * due to a bug in tools/nut-snmpinfo.py, prepending a 2nd mib2nut_info_t * declaration with a comment line results in data extraction not being * done for all entries in the file. Hence the above comment line being * after its belonging declaration! */ /*mib2nut_info_t eaton_ats16_nmc = { "eaton_ats16_nmc", EATON_ATS16_NMC_MIB_VERSION, NULL, EATON_ATS16_NMC_MODEL, EATON_ATS16_NMC_mib, EATON_ATS16_NMC_SYSOID, NULL }; */ mib2nut_info_t eaton_ats16_nmc = { "eaton_ats16_nmc", EATON_ATS16_NMC_MIB_VERSION, NULL, EATON_ATS16_NMC_MODEL, eaton_ats16_nmc_mib, EATON_ATS16_NMC_SYSOID, NULL }; nut-2.8.1/drivers/nutdrv_qx_voltronic.h0000644000175000017500000000176314273170601015241 00000000000000/* nutdrv_qx_voltronic.h - Subdriver for Voltronic Power UPSes * * Copyright (C) * 2013 Daniele Pezzini * * 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 2 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, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #ifndef NUTDRV_QX_VOLTRONIC_H #define NUTDRV_QX_VOLTRONIC_H #include "nutdrv_qx.h" extern subdriver_t voltronic_subdriver; #endif /* NUTDRV_QX_VOLTRONIC_H */ nut-2.8.1/drivers/netxml-ups.h0000644000175000017500000000521014501607135013214 00000000000000/* netxml-ups.h Driver data/defines for network XML UPS units Copyright (C) 2008-2009 Arjen de Korte 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 2 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, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef NETXML_UPS_H #define NETXML_UPS_H #include "nut_stdint.h" typedef struct { const char *version; /* name of this subdriver */ const char *initups; const char *initinfo; char *configure; /* central configuration */ char *subscribe; /* alarm subscriptions */ char *summary; /* used for quick updates */ char *getobject; char *setobject; int (*startelm_cb)(void *userdata, int parent, const char *nspace, const char *name, const char **atts); int (*cdata_cb)(void *userdata, int state, const char *cdata, size_t len); int (*endelm_cb)(void *userdata, int state, const char *nspace, const char *name); } subdriver_t; /* ---------------------------------------------------------------------- */ /* data for processing boolean values from UPS */ #define STATUS_BIT(x) (ups_status & (uint32_t)1< * (C) 2000 Nigel Metheringham * (C) 2011+ Michal Soltys * * 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 2 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, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef NUT_APCSMART_H_SEEN #define NUT_APCSMART_H_SEEN 1 #define ALT_CABLE_1 "940-0095B" /* * alerts and other stuff for quick reference: * * $ OL * ! OB * % LB * + not LB anymore * # RB * ? OVER * = not OVER anymore * * powering down now (only older models ?), handled by upsread() * otherwise ignored (it doesn't have to be in ignore sets) * * | eeprom change * & check alarm register for fail * ~ ??? */ /* * old ones for reference: * #define IGNCHARS "\015+$|!~%?=#&" * #define POLL_IGNORE "\015&|" * #define POLL_ALERT "$!%+#?=" * #define MINIGNCHARS "\015+$|!" * notice ~ that was present in IGNCHARS, but not in POLL_IGNORE - this kinda * didn't make sense (?); new versions doesn't filter ~, but keep that in mind * in case something obscure surfaces * due to switch to ICANON tty mode, we removed \015 from ignored characters, * as it's handled by IGNCR at read() level */ /* * about CR: * apparently windows is unable to ignore CRs by means of IGNCR flag (or * perhaps there is something else involved); so despite IGNCR we re-aad \015 * to ignore sets for now; see: * http://article.gmane.org/gmane.comp.monitoring.nut.user/7762 * * furthermore, since the canonical/non-canonical mode is user selectable now, * we have to ignore this character explicitly */ #ifndef WIN32 #include #endif /* Basic UPS reply line structure */ #define ENDCHAR 10 /* APC ends responses with LF (and CR, but it's IGNCRed) */ /* what to ignore during alert aware serial reads */ #define IGN_AACHARS "\015|&" /* what alert_handler() should care about */ #define ALERT_CHARS "$!%+#?=" /* characters ignored by alertless reads */ #define IGN_CHARS IGN_AACHARS ALERT_CHARS /* * these ones are used only during Capability Check read, due to ^Z sending * certain characters such as #; it seems it could be equal to just IGN_CHARS * w/o # old: #define IGN_CCCHARS "|$!+" */ #define IGN_CCCHARS "\015|&$!%+?=" /* capability check ignore set */ /* * Command Set 'a' reports everything - protocol number, alerts and supported * commands */ #define IGN_CSCHARS "" /* command set ignore set */ /* dangerous instant commands must be reconfirmed within a 12 second window */ #define MINCMDTIME 3 #define MAXCMDTIME 15 /* it only does two strings, and they're both the same length */ #define APC_STRLEN 8 #define SER_D0 0x001 /* 0 sec., for flushes */ #define SER_DX 0x002 /* 200 ms for long/repeated cmds, in case of unexpected NAs */ #define SER_D1 0x004 /* 1.5 sec. */ #define SER_D3 0x008 /* 3 sec. (default) */ #define SER_AA 0x010 /* Alert Aware set */ #define SER_CC 0x020 /* Capability Check ign set */ #define SER_CS 0x040 /* Command Set ign set */ #define SER_TO 0x080 /* timeout allowed */ #define SER_HA 0x100 /* handle asterisk */ /* sets of the above (don't test against them, obviously */ /* * Some cmd codes to ignore (nut doesn't expose those, though the driver might * use them internally (e.g. [a]). If you decide to support them at some * point, remember about removing them from here ! */ #define APC_UNR_CMDS "\032\177~')-+8QRYayz" /* --------------- */ /* status bits */ #define APC_STAT_CAL (1L << 0) /* calibration */ #define APC_STAT_TRIM (1L << 1) /* SmartTrim */ #define APC_STAT_BOOST (1L << 2) /* SmartBoost */ #define APC_STAT_OL (1L << 3) /* on line */ #define APC_STAT_OB (1L << 4) /* on battery */ #define APC_STAT_OVER (1L << 5) /* overload */ #define APC_STAT_LB (1L << 6) /* low battery */ #define APC_STAT_RB (1L << 7) /* replace battery */ /* * serial protocol: special commands - initialization and such * these are not exposed as instant commands */ #define APC_STATUS 'Q' #define APC_GOSMART 'Y' #define APC_GODUMB 'R' #define APC_CMDSET 'a' #define APC_CMDSET_FMT "^[0-9]\\.[^.]*\\.[^.]+(\\.[^.]+)?$" #define APC_CAPS '\032' /* ^Z */ #define APC_NEXTVAL '-' #define APC_FW_OLD 'V' #define APC_FW_NEW 'b' #define APC_LBUF 512 #define APC_SBUF 32 /* default a.w.d. value / regex format for command '@' */ #define APC_AWDFMT "^[0-9]{1,3}$" /* sdtype method regex format*/ #define APC_SDFMT "^[0-5]$" /* advorder method regex format*/ #define APC_ADVFMT "^([0-4]{1,5}|[Nn][Oo])$" /* cshdelay format */ #define APC_CSHDFMT "^([0-9]\\.?|[0-9]?\\.[0-9])$" #endif /* NUT_APCSMART_H_SEEN */ nut-2.8.1/drivers/clone-outlet.c0000644000175000017500000002553114501607135013515 00000000000000/* * clone-outlet.c: clone outlet UPS driver * * Copyright (C) 2009 - Arjen de Korte * * 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 2 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, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "main.h" #include "parseconf.h" #include "nut_stdint.h" #include #ifndef WIN32 #include #include #endif #define DRIVER_NAME "clone outlet UPS Driver" #define DRIVER_VERSION "0.03" /* driver description structure */ upsdrv_info_t upsdrv_info = { DRIVER_NAME, DRIVER_VERSION, "Arjen de Korte ", DRV_EXPERIMENTAL, { NULL } }; static struct { struct { char *shutdown; } delay; struct { char *shutdown; } timer; char *status; } prefix = { { NULL }, { NULL }, NULL }; static struct { struct { long shutdown; } delay; struct { long shutdown; } timer; int status; } outlet = { { -1 }, { -1 }, 1 }; static struct { char status[LARGEBUF]; } ups = { "WAIT" }; static int dumpdone = 0; static PCONF_CTX_t sock_ctx; static time_t last_heard = 0, last_ping = 0; #ifdef WIN32 static char read_buf[SMALLBUF]; static OVERLAPPED read_overlapped; #else /* TODO: Why not built in WIN32? */ static time_t last_connfail = 0; #endif static int parse_args(size_t numargs, char **arg) { if (numargs < 1) { return 0; } if (!strcasecmp(arg[0], "PONG")) { upsdebugx(3, "Got PONG from UPS"); return 1; } if (!strcasecmp(arg[0], "DUMPDONE")) { upsdebugx(3, "UPS: dump is done"); dumpdone = 1; return 1; } if (!strcasecmp(arg[0], "DATASTALE")) { dstate_datastale(); return 1; } if (!strcasecmp(arg[0], "DATAOK")) { dstate_dataok(); return 1; } if (numargs < 2) { return 0; } /* DELINFO */ if (!strcasecmp(arg[0], "DELINFO")) { dstate_delinfo(arg[1]); return 1; } if (numargs < 3) { return 0; } /* SETINFO */ if (!strcasecmp(arg[0], "SETINFO")) { if (!strncasecmp(arg[1], "driver.", 7)) { /* don't pass on upstream driver settings */ return 1; } if (!strcasecmp(arg[1], prefix.delay.shutdown)) { outlet.delay.shutdown = strtol(arg[2], NULL, 10); } if (!strcasecmp(arg[1], prefix.timer.shutdown)) { outlet.timer.shutdown = strtol(arg[2], NULL, 10); } if (!strcasecmp(arg[1], prefix.status)) { outlet.status = strcasecmp(arg[2], "off"); } if (!strcasecmp(arg[1], "ups.status")) { snprintf(ups.status, sizeof(ups.status), "%s", arg[2]); return 1; } dstate_setinfo(arg[1], "%s", arg[2]); return 1; } return 0; } static TYPE_FD sstate_connect(void) { TYPE_FD fd; #ifndef WIN32 ssize_t ret; int len; const char *dumpcmd = "DUMPALL\n"; struct sockaddr_un sa; memset(&sa, '\0', sizeof(sa)); sa.sun_family = AF_UNIX; len = snprintf(sa.sun_path, sizeof(sa.sun_path), "%s/%s", dflt_statepath(), device_path); if (len < 0) { fatalx(EXIT_FAILURE, "Can't create a unix domain socket: " "failed to prepare the pathname"); } if ((uintmax_t)len >= (uintmax_t)sizeof(sa.sun_path)) { fatalx(EXIT_FAILURE, "Can't create a unix domain socket: pathname '%s/%s' " "is too long (%" PRIuSIZE ") for 'struct sockaddr_un->sun_path' " "on this system (%" PRIuSIZE ")", dflt_statepath(), device_path, strlen(dflt_statepath()) + 1 + strlen(device_path), sizeof(sa.sun_path)); } fd = socket(AF_UNIX, SOCK_STREAM, 0); if (INVALID_FD(fd)) { upslog_with_errno(LOG_ERR, "Can't create socket for UPS [%s]", device_path); return ERROR_FD; } ret = connect(fd, (struct sockaddr *) &sa, sizeof(sa)); if (ret < 0) { time_t now; close(fd); /* rate-limit complaints - don't spam the syslog */ time(&now); if (difftime(now, last_connfail) < 60) { return ERROR_FD; } last_connfail = now; upslog_with_errno(LOG_ERR, "Can't connect to UPS [%s]", device_path); return ERROR_FD; } ret = fcntl(fd, F_GETFL, 0); if (ret < 0) { upslog_with_errno(LOG_ERR, "fcntl get on UPS [%s] failed", device_path); close(fd); return ERROR_FD; } ret = fcntl(fd, F_SETFL, ret | O_NDELAY); if (ret < 0) { upslog_with_errno(LOG_ERR, "fcntl set O_NDELAY on UPS [%s] failed", device_path); close(fd); return ERROR_FD; } /* get a dump started so we have a fresh set of data */ ret = write(fd, dumpcmd, strlen(dumpcmd)); if (ret != (int)strlen(dumpcmd)) { upslog_with_errno(LOG_ERR, "Initial write to UPS [%s] failed", device_path); close(fd); return ERROR_FD; } /* continued below... */ #else /* WIN32 */ char pipename[SMALLBUF]; const char *dumpcmd = "DUMPALL\n"; BOOL result = FALSE; snprintf(pipename, sizeof(pipename), "\\\\.\\pipe\\%s/%s", dflt_statepath(), device_path); result = WaitNamedPipe(pipename,NMPWAIT_USE_DEFAULT_WAIT); if (result == FALSE) { return ERROR_FD; } fd = CreateFile( pipename, /* pipe name */ GENERIC_READ | /* read and write access */ GENERIC_WRITE, 0, /* no sharing */ NULL, /* default security attributes FIXME */ OPEN_EXISTING, /* opens existing pipe */ FILE_FLAG_OVERLAPPED, /* enable async IO */ NULL); /* no template file */ if (fd == INVALID_HANDLE_VALUE) { upslog_with_errno(LOG_ERR, "Can't connect to UPS [%s]", device_path); return ERROR_FD; } /* get a dump started so we have a fresh set of data */ DWORD bytesWritten = 0; result = WriteFile (fd,dumpcmd,strlen(dumpcmd),&bytesWritten,NULL); if (result == 0 || bytesWritten != strlen(dumpcmd)) { upslog_with_errno(LOG_ERR, "Initial write to UPS [%s] failed", device_path); CloseHandle(fd); return ERROR_FD; } /* Start a read IO so we could wait on the event associated with it */ ReadFile(fd, read_buf, sizeof(read_buf) - 1, /*-1 to be sure to have a trailling 0 */ NULL, &(read_overlapped)); #endif /* sstate_connect() continued for both platforms: */ pconf_init(&sock_ctx, NULL); time(&last_heard); dumpdone = 0; /* set ups.status to "WAIT" while waiting for the driver response to dumpcmd */ dstate_setinfo("ups.status", "WAIT"); upslogx(LOG_INFO, "Connected to UPS [%s]", device_path); return fd; } static void sstate_disconnect(void) { if (INVALID_FD(upsfd)) { /* Already disconnected... or not yet? ;) */ return; } pconf_finish(&sock_ctx); #ifndef WIN32 close(upsfd); #else CloseHandle(upsfd); #endif upsfd = ERROR_FD; } static int sstate_sendline(const char *buf) { ssize_t ret; if (INVALID_FD(upsfd)) { return -1; /* failed */ } #ifndef WIN32 ret = write(upsfd, buf, strlen(buf)); #else DWORD bytesWritten = 0; BOOL result = FALSE; result = WriteFile (upsfd,buf,strlen(buf),&bytesWritten,NULL); if( result == 0 ) { ret = 0; } else { ret = (int)bytesWritten; } #endif if (ret == (int)strlen(buf)) { return 0; } upslog_with_errno(LOG_NOTICE, "Send to UPS [%s] failed", device_path); return -1; /* failed */ } static int sstate_readline(void) { int i; ssize_t ret; #ifndef WIN32 char buf[SMALLBUF]; if (INVALID_FD(upsfd)) { return -1; /* failed */ } ret = read(upsfd, buf, sizeof(buf)); if (ret < 0) { switch(errno) { case EINTR: case EAGAIN: return 0; default: upslog_with_errno(LOG_WARNING, "Read from UPS [%s] failed", device_path); return -1; } } #else if (INVALID_FD(upsfd)) { return -1; /* failed */ } /* FIXME? I do not see this buf or read_buf filled below */ char *buf = read_buf; DWORD bytesRead; GetOverlappedResult(upsfd, &read_overlapped, &bytesRead, FALSE); ret = bytesRead; #endif for (i = 0; i < ret; i++) { switch (pconf_char(&sock_ctx, buf[i])) { case 1: if (parse_args(sock_ctx.numargs, sock_ctx.arglist)) { time(&last_heard); } continue; case 0: continue; /* haven't gotten a line yet */ default: /* parse error */ upslogx(LOG_NOTICE, "Parse error on sock: %s", sock_ctx.errmsg); return -1; } } return 0; } static int sstate_dead(int maxage) { time_t now; double elapsed; /* an unconnected ups is always dead */ if (INVALID_FD(upsfd)) { upsdebugx(3, "sstate_dead: connection to driver socket for UPS [%s] lost", device_path); return -1; /* dead */ } time(&now); /* ignore DATAOK/DATASTALE unless the dump is done */ if (dumpdone && dstate_is_stale()) { upsdebugx(3, "sstate_dead: driver for UPS [%s] says data is stale", device_path); return -1; /* dead */ } elapsed = difftime(now, last_heard); /* somewhere beyond a third of the maximum time - prod it to make it talk */ if ((elapsed > (maxage / 3)) && (difftime(now, last_ping) > (maxage / 3))) { upsdebugx(3, "Send PING to UPS"); sstate_sendline("PING\n"); last_ping = now; } if (elapsed > maxage) { upsdebugx(3, "sstate_dead: didn't hear from driver for UPS [%s] for %g seconds (max %d)", device_path, elapsed, maxage); return -1; /* dead */ } return 0; } void upsdrv_initinfo(void) { } void upsdrv_updateinfo(void) { if (sstate_dead(15)) { sstate_disconnect(); extrafd = upsfd = sstate_connect(); return; } if (sstate_readline()) { sstate_disconnect(); return; } if (outlet.status == 0) { upsdebugx(2, "OFF flag set (%s: switched off)", prefix.status); dstate_setinfo("ups.status", "%s OFF", ups.status); return; } if ((outlet.timer.shutdown > -1) && (outlet.timer.shutdown <= outlet.delay.shutdown)) { upsdebugx(2, "FSD flag set (%s: -1 < [%ld] <= %ld)", prefix.timer.shutdown, outlet.timer.shutdown, outlet.delay.shutdown); dstate_setinfo("ups.status", "FSD %s", ups.status); return; } upsdebugx(3, "%s: power state not critical", getval("prefix")); dstate_setinfo("ups.status", "%s", ups.status); } void upsdrv_shutdown(void) { /* replace with a proper shutdown function */ /* upslogx(LOG_ERR, "shutdown not supported"); set_exit_flag(-1); */ } void upsdrv_help(void) { } void upsdrv_makevartable(void) { addvar(VAR_VALUE, "prefix", "Outlet prefix (mandatory)"); } void upsdrv_initups(void) { char buf[SMALLBUF]; const char *val; val = getval("prefix"); if (!val) { fatalx(EXIT_FAILURE, "Outlet prefix is mandatory for this driver!"); } snprintf(buf, sizeof(buf), "%s.delay.shutdown", val); prefix.delay.shutdown = xstrdup(buf); snprintf(buf, sizeof(buf), "%s.timer.shutdown", val); prefix.timer.shutdown = xstrdup(buf); snprintf(buf, sizeof(buf), "%s.status", val); prefix.status = xstrdup(buf); extrafd = upsfd = sstate_connect(); } void upsdrv_cleanup(void) { free(prefix.delay.shutdown); free(prefix.timer.shutdown); free(prefix.status); sstate_disconnect(); } nut-2.8.1/drivers/generic_gpio_libgpiod.c0000644000175000017500000002021114501607135015374 00000000000000/* generic_gpio_libgpiod.c - gpiod based NUT driver code for GPIO attached UPS devices * * Copyright (C) * 2023 Modris Berzonis * * 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 2 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, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #include "config.h" #include "main.h" #include "attribute.h" #include "generic_gpio_common.h" #include "generic_gpio_libgpiod.h" #define DRIVER_NAME "GPIO UPS driver" #define DRIVER_VERSION "1.01" /* driver description structure */ upsdrv_info_t upsdrv_info = { DRIVER_NAME, DRIVER_VERSION, "ModrisB ", DRV_STABLE, { NULL } }; static void reserve_lines_libgpiod(struct gpioups_t *gpioupsfd, int inner); /* CyberPower 12V open collector state definitions 0 ON BATTERY Low when operating from utility line Open when operating from battery 1 REPLACE BATTERY Low when battery is charged Open when battery fails the Self Test 6 BATTERY MISSING Low when battery is present Open when battery is missing 3 LOW BATTERY Low when battery is near full charge capacity Open when operating from a battery with < 20% capacity NUT supported states OL On line (mains is present) OB On battery (mains is not present) LB Low battery HB High battery RB The battery needs to be replaced CHRG The battery is charging DISCHRG The battery is discharging (inverter is providing load power) BYPASS UPS bypass circuit is active -- no battery protection is available CAL UPS is currently performing runtime calibration (on battery) OFF UPS is offline and is not supplying power to the load OVER UPS is overloaded TRIM UPS is trimming incoming voltage (called "buck" in some hardware) BOOST UPS is boosting incoming voltage FSD Forced Shutdown (restricted use, see the note below) CyberPower rules setting OL=^0;OB=0;LB=3;HB=^3;RB=1;DISCHRG=0&^3;BYPASS=6; */ /* * reserve GPIO lines as per run options and inner parameter: do reservation once * or per each status read */ static void reserve_lines_libgpiod(struct gpioups_t *gpioupsfdlocal, int inner) { struct libgpiod_data_t *libgpiod_data = (struct libgpiod_data_t *)(gpioupsfdlocal->lib_data); upsdebugx(5, "reserve_lines_libgpiod runOptions 0x%x, inner %d", gpioupsfdlocal->runOptions, inner); if(((gpioupsfdlocal->runOptions&ROPT_REQRES) != 0) == inner) { struct gpiod_line_request_config config; int gpioRc; config.consumer=upsdrv_info.name; if(gpioupsfdlocal->runOptions&ROPT_EVMODE) { config.request_type = GPIOD_LINE_REQUEST_EVENT_BOTH_EDGES; upsdebugx(5, "reserve_lines_libgpiod GPIOD_LINE_REQUEST_EVENT_BOTH_EDGES"); } else { config.request_type = GPIOD_LINE_REQUEST_DIRECTION_INPUT; upsdebugx(5, "reserve_lines_libgpiod GPIOD_LINE_REQUEST_DIRECTION_INPUT"); } config.flags = 0; /* GPIOD_LINE_REQUEST_FLAG_OPEN_DRAIN; */ gpioRc = gpiod_line_request_bulk(&libgpiod_data->gpioLines, &config, NULL); if(gpioRc) fatal_with_errno( LOG_ERR, "GPIO gpiod_line_request_bulk call failed, check for other applications that may have reserved GPIO lines" ); upsdebugx(5, "GPIO gpiod_line_request_bulk with type %d return code %d", config.request_type, gpioRc ); } } /* * allocate memeory for libary, open gpiochip * and check lines numbers validity - consistency with h/w chip */ void gpio_open(struct gpioups_t *gpioupsfdlocal) { struct libgpiod_data_t *libgpiod_data = xcalloc(sizeof(struct libgpiod_data_t),1); gpioupsfdlocal->lib_data = libgpiod_data; libgpiod_data->gpioChipHandle = gpiod_chip_open_by_name(gpioupsfdlocal->chipName); if(!libgpiod_data->gpioChipHandle) fatal_with_errno( LOG_ERR, "Could not open GPIO chip [%s], check chips presence and/or access rights", gpioupsfdlocal->chipName ); else { int gpioRc; upslogx(LOG_NOTICE, "GPIO chip [%s] opened", gpioupsfdlocal->chipName); gpioupsfdlocal->chipLinesCount = gpiod_chip_num_lines(libgpiod_data->gpioChipHandle); upslogx(LOG_NOTICE, "Find %d lines on GPIO chip [%s]", gpioupsfdlocal->chipLinesCount, gpioupsfdlocal->chipName); if(gpioupsfdlocal->chipLinesCountupsMaxLine) { gpiod_chip_close(libgpiod_data->gpioChipHandle); fatalx( LOG_ERR, "GPIO chip lines count %d smaller than UPS line number used (%d)", gpioupsfdlocal->chipLinesCount, gpioupsfdlocal->upsMaxLine ); } gpiod_line_bulk_init(&libgpiod_data->gpioLines); gpiod_line_bulk_init(&libgpiod_data->gpioEventLines); gpioRc = gpiod_chip_get_lines( libgpiod_data->gpioChipHandle, (unsigned int *)gpioupsfdlocal->upsLines, gpioupsfdlocal->upsLinesCount, &libgpiod_data->gpioLines ); if(gpioRc) fatal_with_errno( LOG_ERR, "GPIO line reservation (gpiod_chip_get_lines call) failed with code %d, check for possible issue in rules parameter", gpioRc ); upsdebugx(5, "GPIO gpiod_chip_get_lines return code %d", gpioRc); reserve_lines_libgpiod(gpioupsfdlocal, 0); } } /* * close gpiochip and release allocated memory */ void gpio_close(struct gpioups_t *gpioupsfdlocal) { if(gpioupsfdlocal) { struct libgpiod_data_t *libgpiod_data = (struct libgpiod_data_t *)(gpioupsfdlocal->lib_data); if(libgpiod_data) { if(libgpiod_data->gpioChipHandle) { gpiod_chip_close(libgpiod_data->gpioChipHandle); } free(gpioupsfdlocal->lib_data); gpioupsfdlocal->lib_data = NULL; } } } /* * get GPIO line states for all needed lines */ void gpio_get_lines_states(struct gpioups_t *gpioupsfdlocal) { int i; int gpioRc; struct libgpiod_data_t *libgpiod_data = (struct libgpiod_data_t *)(gpioupsfdlocal->lib_data); reserve_lines_libgpiod(gpioupsfdlocal, 1); if(gpioupsfdlocal->runOptions&ROPT_EVMODE) { struct timespec timeoutLong = {1,0}; struct gpiod_line_event event; int monRes; upsdebugx(5, "gpio_get_lines_states_libgpiod initial %d, timeout %ld", gpioupsfdlocal->initial, timeoutLong.tv_sec ); if(gpioupsfdlocal->initial) { timeoutLong.tv_sec = 35; } else { gpioupsfdlocal->initial = 1; } upsdebugx(5, "gpio_get_lines_states_libgpiod initial %d, timeout %ld", gpioupsfdlocal->initial, timeoutLong.tv_sec ); gpiod_line_bulk_init(&libgpiod_data->gpioEventLines); monRes=gpiod_line_event_wait_bulk( &libgpiod_data->gpioLines, &timeoutLong, &libgpiod_data->gpioEventLines ); upsdebugx(5, "gpiod_line_event_wait_bulk completed with %d return code and timeout %ld s", monRes, timeoutLong.tv_sec ); if(monRes==1) { int num_lines_local = (int)gpiod_line_bulk_num_lines(&libgpiod_data->gpioEventLines); int j; for(j=0; jgpioEventLines, j ); int eventRc=gpiod_line_event_read(eLine, &event); unsigned int lineOffset = gpiod_line_offset(eLine); event.event_type=0; upsdebugx(5, "Event read return code %d and event type %d for line %d", eventRc, event.event_type, lineOffset ); } } } for(i=0; i < gpioupsfdlocal->upsLinesCount; i++) { gpioupsfdlocal->upsLinesStates[i] = -1; } gpioRc=gpiod_line_get_value_bulk( &libgpiod_data->gpioLines, gpioupsfdlocal->upsLinesStates ); if (gpioRc < 0) fatal_with_errno(LOG_ERR, "GPIO line status read call failed"); upsdebugx(5, "GPIO gpiod_line_get_value_bulk completed with %d return code, status values:", gpioRc ); for(i=0; i < gpioupsfdlocal->upsLinesCount; i++) { upsdebugx(5, "Line%d state = %d", i, gpioupsfdlocal->upsLinesStates[i] ); } if(gpioupsfdlocal->runOptions&ROPT_REQRES) { gpiod_line_release_bulk(&libgpiod_data->gpioLines); } } nut-2.8.1/drivers/oneac.c0000644000175000017500000006743014501607135012174 00000000000000/*vim ts=4*/ /* oneac.c - Driver for Oneac UPS using the Advanced Interface. * * Supported Oneac UPS families in this driver: * EG (late 80s, early 90s, plug-in serial interface card) * ON (early and mid-90s, plug-in serial interface card) * OZ (mid-90s on, DB-25 std., interface slot) * OB (early 2000's on, big cabinet, DB-25 std., interface slot) * * Copyright (C) * 2003 by Eric Lawson * 2012 by Bill Elliot * * This program was sponsored by MGE UPS SYSTEMS, and now Eaton * * 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 2 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, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * History: * - 7 February 2012. Bill Elliot * Enhancing the driver for additional capabilities and later units. * * - 28 November 2003. Eric Lawson * More or less complete re-write for NUT 1.5.9 * This was somewhat easier than trying to beat the old driver code * into submission * */ #include "main.h" #include "serial.h" #include "oneac.h" #include "nut_stdint.h" /* Prototypes to allow setting pointer before function is defined */ int setcmd(const char* varname, const char* setvalue); int instcmd(const char *cmdname, const char *extra); #define DRIVER_NAME "Oneac EG/ON/OZ/OB UPS driver" #define DRIVER_VERSION "0.82" /* driver description structure */ upsdrv_info_t upsdrv_info = { DRIVER_NAME, DRIVER_VERSION, "Bill Elliot \n" "Eric Lawson ", DRV_STABLE, { NULL } }; #define SECS 0 /* Serial function wait time*/ #define USEC 500000 /* Rest of serial function wait time*/ #define COMM_TRIES 3 /* Serial retries before "stale" */ static char UpsFamily [3]; /**************************************************************** * Below are functions used only in this oneac driver * ***************************************************************/ /* Since an installed network card may delay responses from the UPS * allow for a repeat of the get request. Also confirm that * the correct number of characters are returned. */ static ssize_t OneacGetResponse (char* chBuff, const size_t BuffSize, int ExpectedCount) { int Retries = 10; /* x/2 seconds max with 500000 USEC */ ssize_t return_val; do { return_val = ser_get_line(upsfd, chBuff, BuffSize, ENDCHAR, IGNCHARS, SECS, USEC); if (return_val == ExpectedCount) break; upsdebugx (3, "!OneacGetResponse retry (%" PRIiSIZE ", %d)...", return_val, Retries); } while (--Retries > 0); upsdebugx (4,"OneacGetResponse buffer: %s",chBuff); if (Retries == 0) { upsdebugx (2,"!!OneacGetResponse timeout..."); return_val = 1; /* Comms error */ } else { if (Retries < 10) upsdebugx (2,"OneacGetResponse recovered (%d)...", Retries); return_val = 0; /* Good comms */ } return return_val; } static void do_battery_test(void) { char buffer[32]; if (getval("testtime") == NULL) snprintf(buffer, 3, "%s", DEFAULT_BAT_TEST_TIME); else { snprintf(buffer, 3, "%s", getval("testtime")); /*the UPS wants this value to always be two characters long*/ /*so put a zero in front of the string, if needed.... */ if (strlen(buffer) < 2) { buffer[2] = '\0'; buffer[1] = buffer[0]; buffer[0] = '0'; } } ser_send(upsfd,"%s%s%s",BAT_TEST_PREFIX,buffer,COMMAND_END); } static int SetOutputAllow(const char* lowval, const char* highval) { char buffer[32]; snprintf(buffer, 4, "%.3s", lowval); /*the UPS wants this value to always be three characters long*/ /*so put a zero in front of the string, if needed.... */ if (strlen(buffer) < 3) { buffer[3] = '\0'; buffer[2] = buffer[1]; buffer[1] = buffer[0]; buffer[0] = '0'; } upsdebugx (2,"SetOutputAllow sending %s%.3s,%.3s...", SETX_OUT_ALLOW, buffer, highval); ser_send(upsfd,"%s%.3s,%.3s%s", SETX_OUT_ALLOW, buffer, highval, COMMAND_END); ser_get_line(upsfd,buffer,sizeof(buffer), ENDCHAR, IGNCHARS,SECS,USEC); if(buffer[0] == DONT_UNDERSTAND) { upsdebugx (2,"SetOutputAllow got asterisk back..."); return 1; /* Invalid command */ } return 0; /* Valid command */ } static void EliminateLeadingZeroes (const char* buff1, int StringSize, char* buff2, const size_t buff2size) { int i = 0; int j = 0; memset(buff2, '\0', buff2size); /* Fill with nulls */ /* Find first non-'0' */ while ((i < (StringSize - 1) && (buff1[i] == '0'))) { i++; } while (i < StringSize) /* Move rest of string */ { buff2[j++] = buff1[i++]; } } /**************************************************************** * Below are the commands that are called by main * ***************************************************************/ void upsdrv_initups(void) { upsfd = ser_open(device_path); ser_set_speed(upsfd, device_path, B9600); /*get the UPS in the right frame of mind*/ ser_send_pace(upsfd, 100, "%s", COMMAND_END); ser_send_pace(upsfd, 100, "%s", COMMAND_END); sleep (1); } void upsdrv_initinfo(void) { int i,j, k; int VRange=0; int timevalue; ssize_t RetValue; char buffer[256], buffer2[32]; /* All families should reply to this request so we can confirm that it is * an ONEAC UPS */ ser_flush_in(upsfd,"",0); ser_send(upsfd,"%c%s",GET_FAMILY,COMMAND_END); if(OneacGetResponse (buffer, sizeof(buffer), 2)) { fatalx(EXIT_FAILURE, "Serial timeout with ONEAC UPS on %s\n", device_path); } else { if (strncmp(buffer,FAMILY_ON,FAMILY_SIZE) != 0 && strncmp(buffer,FAMILY_OZ,FAMILY_SIZE) != 0 && strncmp(buffer,FAMILY_OB,FAMILY_SIZE) != 0 && strncmp(buffer,FAMILY_EG,FAMILY_SIZE) != 0) { fatalx(EXIT_FAILURE, "Did not find an ONEAC UPS on %s\n", device_path); } } /* UPS Model (either EG, ON, OZ or OB series of UPS) */ strncpy(UpsFamily, buffer, FAMILY_SIZE); UpsFamily[2] = '\0'; dstate_setinfo("device.model", "%s",UpsFamily); printf("Found %s family of Oneac UPS\n", UpsFamily); dstate_setinfo("ups.type", "%s", "Line Interactive"); dstate_addcmd("test.battery.start.quick"); dstate_addcmd("test.battery.stop"); dstate_addcmd("test.failure.start"); dstate_addcmd("shutdown.return"); dstate_addcmd("shutdown.stop"); dstate_addcmd("shutdown.reboot"); upsh.setvar = setcmd; upsh.instcmd = instcmd; /* set some stuff that shouldn't change after initialization */ /* this stuff is common to all families of UPS */ ser_send(upsfd,"%c%s",GET_ALL,COMMAND_END); if (strncmp(UpsFamily, FAMILY_EG, FAMILY_SIZE) == 0) { RetValue = OneacGetResponse (buffer, sizeof(buffer), GETALL_EG_RESP_SIZE); } else { RetValue = OneacGetResponse (buffer, sizeof(buffer), GETALL_RESP_SIZE); } if(RetValue) { fatalx(EXIT_FAILURE, "Serial timeout(2) with ONEAC UPS on %s\n", device_path); } /* Manufacturer */ dstate_setinfo("device.mfr", "%.5s", buffer); /*firmware revision*/ dstate_setinfo("ups.firmware", "%.3s",buffer+7); /*nominal AC frequency setting --either 50 or 60*/ dstate_setinfo("input.frequency.nominal", "%.2s", buffer+20); dstate_setinfo("output.frequency.nominal", "%.2s", buffer+20); /* Shutdown delay in seconds...can be changed by user */ if (getval("offdelay") == NULL) dstate_setinfo("ups.delay.shutdown", "0"); else dstate_setinfo("ups.delay.shutdown", "%s", getval("offdelay")); dstate_setflags("ups.delay.shutdown", ST_FLAG_STRING | ST_FLAG_RW); dstate_setaux("ups.delay.shutdown", GET_SHUTDOWN_RESP_SIZE); /* Setup some ON/OZ/OB only stuff ... i.e. not EG */ if (strncmp(UpsFamily, FAMILY_EG, FAMILY_SIZE) != 0) { dstate_addcmd("reset.input.minmax"); /*nominal input voltage*/ VRange = buffer[26]; /* Keep for later use also */ switch (VRange) /* Will be '1' or '2' */ { case V120AC: dstate_setinfo("input.voltage.nominal", "120"); dstate_setinfo("output.voltage.nominal", "120"); break; case V230AC: dstate_setinfo("input.voltage.nominal", "230"); dstate_setinfo("output.voltage.nominal", "230"); break; default: upslogx(LOG_INFO,"Oneac: " "Invalid nom voltage parameter from UPS [%c]", VRange); } } /* Setup some OZ/OB only stuff */ if ((strncmp (UpsFamily, FAMILY_OZ, FAMILY_SIZE) == 0) || (strncmp (UpsFamily, FAMILY_OB, FAMILY_SIZE) == 0)) { dstate_addcmd("test.panel.start"); dstate_addcmd("test.battery.start.deep"); dstate_addcmd("beeper.enable"); dstate_addcmd("beeper.disable"); dstate_addcmd("beeper.mute"); dstate_setaux("ups.delay.shutdown", GETX_SHUTDOWN_RESP_SIZE); ser_flush_in(upsfd,"",0); ser_send(upsfd,"%c%s",GETX_ALL_2,COMMAND_END); if(OneacGetResponse (buffer, sizeof(buffer), GETX_ALL2_RESP_SIZE)) { fatalx(EXIT_FAILURE, "Serial timeout(3) with ONEAC UPS on %s\n", device_path); } /* Low and high output trip points */ EliminateLeadingZeroes (buffer+73, 3, buffer2, sizeof(buffer2)); dstate_setinfo("input.transfer.low", "%s", buffer2); dstate_setflags("input.transfer.low", ST_FLAG_STRING | ST_FLAG_RW ); dstate_setaux("input.transfer.low", 3); EliminateLeadingZeroes (buffer+76, 3, buffer2, sizeof(buffer2)); dstate_setinfo("input.transfer.high", "%s", buffer2); dstate_setflags("input.transfer.high", ST_FLAG_STRING | ST_FLAG_RW); dstate_setaux("input.transfer.high", 3); /* Restart delay */ EliminateLeadingZeroes (buffer+84, 4, buffer2, sizeof(buffer2)); dstate_setinfo("ups.delay.start", "%s", buffer2); dstate_setflags("ups.delay.start", ST_FLAG_STRING | ST_FLAG_RW); dstate_setaux("ups.delay.start", 4); /* Low Batt at time */ strncpy(buffer2, buffer+82, 2); buffer2[2]='\0'; timevalue = atoi(buffer2) * 60; /* Change minutes to seconds */ dstate_setinfo("battery.runtime.low", "%d",timevalue); dstate_setflags("battery.runtime.low", ST_FLAG_STRING | ST_FLAG_RW); dstate_setaux("battery.runtime.low", 2); /*Get the actual model string for ON UPS reported as OZ/OB family*/ /*UPS Model (full string)*/ memset(buffer2, '\0', 32); #ifdef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_FORMAT_TRUNCATION #pragma GCC diagnostic push #endif #ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_FORMAT_TRUNCATION #pragma GCC diagnostic ignored "-Wformat-truncation" #endif #ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_STRINGOP_TRUNCATION #pragma GCC diagnostic ignored "-Wstringop-truncation" #endif strncpy(buffer2, buffer + 5, 10); #ifdef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_FORMAT_TRUNCATION #pragma GCC diagnostic pop #endif for (i = 9; i >= 0 && buffer2[i] == ' '; --i) { buffer2[i] = '\0'; } dstate_setinfo("device.model", "%s", buffer2); /* Serial number */ dstate_setinfo("device.serial", "%.4s-%.4s", buffer+18, buffer+22); printf("Found %.10s UPS with serial number %.4s-%.4s\n", buffer2, buffer+18, buffer+22); /* Manufacture Date */ dstate_setinfo("ups.mfr.date", "%.6s (yymmdd)", buffer+38); /* Battery Replace Date */ dstate_setinfo("battery.date", "%.6s (yymmdd)", buffer+44); dstate_setflags("battery.date", ST_FLAG_STRING | ST_FLAG_RW); dstate_setaux("battery.date", 6); /* Real power nominal */ EliminateLeadingZeroes (buffer+55, 5, buffer2, sizeof(buffer2)); dstate_setinfo("ups.realpower.nominal", "%s", buffer2); /* Set up ups.start.auto to be writable */ dstate_setinfo("ups.start.auto", "yes"); dstate_setflags("ups.start.auto", ST_FLAG_STRING | ST_FLAG_RW); dstate_setaux("ups.start.auto", 3); /* Get output window min/max points from OB or OZ v1.9 or later */ if ((strncmp (UpsFamily, FAMILY_OB, FAMILY_SIZE) == 0) || (strcmp (dstate_getinfo("ups.firmware"), MIN_ALLOW_FW) >= 0 )) { upsdebugx (2,"Can get output window min/max! (%s)", dstate_getinfo("ups.firmware")); ser_send(upsfd,"%s%s",GETX_ALLOW_RANGE,COMMAND_END); if(OneacGetResponse (buffer, sizeof(buffer), GETX_RANGE_RESP_SIZE)) { fatalx(EXIT_FAILURE, "Serial timeout(4) with ONEAC UPS on %s\n",device_path); } strncpy(buffer2, buffer, 3); buffer2[3]='\0'; i = atoi(buffer2); /* Minimum voltage */ #ifdef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_FORMAT_TRUNCATION #pragma GCC diagnostic push #endif #ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_FORMAT_TRUNCATION #pragma GCC diagnostic ignored "-Wformat-truncation" #endif #ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_STRINGOP_TRUNCATION #pragma GCC diagnostic ignored "-Wstringop-truncation" #endif strncpy(buffer2, buffer + 4, 3); #ifdef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_FORMAT_TRUNCATION #pragma GCC diagnostic pop #endif j = atoi(buffer2); /* Maximum voltage */ strncpy(buffer2, buffer+8, 2); buffer2[2]='\0'; k = atoi(buffer2); /* Spread between */ dstate_setinfo("input.transfer.low.min", "%3d", i); dstate_setinfo("input.transfer.low.max", "%3d", j-k); dstate_setinfo("input.transfer.high.min", "%3d", i+k); dstate_setinfo("input.transfer.high.max", "%3d", j); } else { /* Use default values from firmware */ upsdebugx (2,"Using trip defaults (%s)...", dstate_getinfo("ups.firmware")); switch (VRange) /* Held from initial use */ { case V120AC: dstate_setinfo("input.transfer.low.min", "90"); dstate_setinfo("input.transfer.low.max", "120"); dstate_setinfo("input.transfer.high.min", "110"); dstate_setinfo("input.transfer.high.max", "140"); break; case V230AC: dstate_setinfo("input.transfer.low.min", "172"); dstate_setinfo("input.transfer.low.max", "228"); dstate_setinfo("input.transfer.high.min", "212"); dstate_setinfo("input.transfer.high.max", "268"); break; default: ; } } } } void upsdrv_updateinfo(void) { static int CommTry = COMM_TRIES; /* Comm loss counter */ char buffer[256]; /* Main response buffer */ char buffer2[32]; /* Conversion buffer */ char s; ssize_t RetValue; int timevalue; /* Start with EG/ON information */ ser_flush_in(upsfd,"",0); /*just in case*/ ser_send (upsfd,"%c%s", GET_ALL, COMMAND_END); if (strncmp(UpsFamily, FAMILY_EG, FAMILY_SIZE) == 0) { RetValue = OneacGetResponse (buffer,sizeof(buffer),GETALL_EG_RESP_SIZE); } else { RetValue = OneacGetResponse (buffer, sizeof(buffer), GETALL_RESP_SIZE); } if ((RetValue != 0) && (CommTry == 0)) { ser_comm_fail("Oneac UPS Comm failure continues on port %s", device_path); } else if (RetValue != 0) { if (--CommTry == 0) { ser_comm_fail("Oneac UPS Comm failure on port %s",device_path); dstate_datastale(); } upsdebugx(2,"Oneac: Update serial comm retry value: %d", CommTry); return; } else { CommTry = COMM_TRIES; /* Reset serial retries */ s = buffer[12]; status_init(); alarm_init(); /*take care of the UPS status information*/ if (s == '@') { status_set("OL"); } else { if (s & 0x01) /* On Battery */ { status_set("OB"); } else { status_set("OL"); } if (s & 0x02) /* Low Battery */ status_set("LB"); if (s & 0x04) /* General fault */ { dstate_setinfo("ups.test.result","UPS Internal Failure"); } else { dstate_setinfo("ups.test.result","Normal"); } if (s & 0x08) /* Replace Battery */ status_set("RB"); /* if (s & 0x10) */ /* High Line */ if (s & 0x20) /* Unit is hot */ alarm_set("OVERHEAT"); } /*take care of the reason why the UPS last transferred to battery*/ switch (buffer[13]) { case XFER_BLACKOUT : dstate_setinfo("input.transfer.reason", "Blackout"); break; case XFER_LOW_VOLT : dstate_setinfo("input.transfer.reason", "Low Input Voltage"); break; case XFER_HI_VOLT : dstate_setinfo("input.transfer.reason", "High Input Voltage"); break; case NO_VALUE_YET : dstate_setinfo("input.transfer.reason", "No transfer yet."); break; default : upslogx(LOG_INFO,"Oneac: Unknown reason for UPS battery" " transfer [%c]", buffer[13]); } /* now update info for only the non-EG families of UPS*/ if (strncmp(UpsFamily, FAMILY_EG, FAMILY_SIZE) != 0) { dstate_setinfo("ups.load", "0%.2s",buffer+31); /* Output ON or OFF? */ if(buffer[27] == NO_VALUE_YET) status_set("OFF"); /*battery charge*/ if(buffer[10] == YES) dstate_setinfo("battery.charge", "0%.2s",buffer+33); else dstate_setinfo("battery.charge", "100"); EliminateLeadingZeroes (buffer+35, 3, buffer2, sizeof(buffer2)); dstate_setinfo("input.voltage", "%s",buffer2); EliminateLeadingZeroes (buffer+38, 3, buffer2, sizeof(buffer2)); dstate_setinfo("input.voltage.minimum", "%s",buffer2); EliminateLeadingZeroes (buffer+41, 3, buffer2, sizeof(buffer2)); dstate_setinfo("input.voltage.maximum", "%s",buffer2); EliminateLeadingZeroes (buffer+44, 3, buffer2, sizeof(buffer2)); dstate_setinfo("output.voltage", "%s",buffer2); if (buffer[15] == NO_VALUE_YET) { dstate_delinfo("ups.timer.shutdown"); } else { /* A shutdown is underway! */ status_set("FSD"); if(buffer[15] != HIGH_COUNT) { EliminateLeadingZeroes (buffer+15, 3, buffer2, sizeof(buffer2)); dstate_setinfo("ups.timer.shutdown", "%s", buffer2); } else { dstate_setinfo("ups.timer.shutdown", "999"); } } if (buffer[47] == YES) status_set("BOOST"); } /* Now update info for only the OZ/OB families of UPS */ if ((strncmp(UpsFamily, FAMILY_OZ, FAMILY_SIZE) == 0) || (strncmp(UpsFamily, FAMILY_OB, FAMILY_SIZE) == 0)) { ser_flush_in(upsfd,"",0); /*just in case*/ ser_send (upsfd,"%c%s",GETX_ALL_1,COMMAND_END); RetValue = OneacGetResponse (buffer, sizeof(buffer), GETX_ALL1_RESP_SIZE); if(RetValue) { if (--CommTry == 0) { ser_comm_fail("Oneac (OZ) UPS Comm failure on port %s", device_path); dstate_datastale(); } upsdebugx(2,"Oneac: " "Update (OZ) serial comm retry value: %d", CommTry); } else { CommTry = COMM_TRIES; /* Reset count */ EliminateLeadingZeroes (buffer+57, 5, buffer2, sizeof(buffer2)); dstate_setinfo("ups.realpower", "%s",buffer2); dstate_setinfo("input.frequency", "%.2s.%c", buffer+42,buffer[44]); dstate_setinfo("output.frequency", "%.2s.%c", buffer+76, buffer[78]); EliminateLeadingZeroes (buffer+29, 3, buffer2, sizeof(buffer2)); dstate_setinfo("battery.voltage", "%s.%c",buffer2, buffer[32]); dstate_setinfo("ups.temperature", "%.2s",buffer+13); dstate_setinfo("ups.load", "%.3s",buffer+73); strncpy(buffer2, buffer+19, 4); buffer2[4]='\0'; timevalue = atoi(buffer2) * 60; /* Change mins to secs */ dstate_setinfo("battery.runtime", "%d",timevalue); /* Now some individual requests... */ /* Battery replace date */ ser_send (upsfd,"%c%s",GETX_BATT_REPLACED,COMMAND_END); if(!OneacGetResponse (buffer, sizeof(buffer), GETX_DATE_RESP_SIZE)) dstate_setinfo("battery.date", "%.6s (yymmdd)", buffer); /* Low and high output trip points */ ser_send (upsfd,"%c%s",GETX_LOW_OUT_ALLOW,COMMAND_END); if(!OneacGetResponse (buffer, sizeof(buffer), GETX_ALLOW_RESP_SIZE)) { EliminateLeadingZeroes (buffer, 3, buffer2,sizeof(buffer2)); dstate_setinfo("input.transfer.low", "%s", buffer2); } ser_send (upsfd,"%c%s",GETX_HI_OUT_ALLOW,COMMAND_END); if(!OneacGetResponse (buffer, sizeof(buffer), GETX_ALLOW_RESP_SIZE)) dstate_setinfo("input.transfer.high", "%s", buffer); /* Restart delay */ ser_send (upsfd,"%c%s",GETX_RESTART_DLY,COMMAND_END); if(!OneacGetResponse (buffer, sizeof(buffer), GETX_RSTRT_RESP_SIZE)) { EliminateLeadingZeroes (buffer, 4, buffer2, sizeof(buffer2)); dstate_setinfo("ups.delay.start", "%s", buffer2); } /* Buzzer state */ ser_send (upsfd,"%s%s",GETX_BUZZER_WHAT,COMMAND_END); if(!OneacGetResponse (buffer, sizeof(buffer), 1)) { switch (buffer[0]) { case BUZZER_ENABLED : dstate_setinfo("ups.beeper.status", "enabled"); break; case BUZZER_DISABLED : dstate_setinfo("ups.beeper.status", "disabled"); break; case BUZZER_MUTED : dstate_setinfo("ups.beeper.status", "muted"); break; default : dstate_setinfo("ups.beeper.status", "enabled"); } } /* Auto start setting */ ser_send (upsfd,"%s%s",GETX_AUTO_START,COMMAND_END); if(!OneacGetResponse (buffer, sizeof(buffer), 1)) { if (buffer[0] == '0') dstate_setinfo("ups.start.auto", "yes"); else dstate_setinfo("ups.start.auto", "no"); } /* Low Batt at time */ ser_send (upsfd,"%c%s",GETX_LOW_BATT_TIME,COMMAND_END); if(!OneacGetResponse (buffer, sizeof(buffer), 2)) { strncpy(buffer2, buffer, 2); buffer2[2]='\0'; timevalue = atoi(buffer2) * 60; /* Mins to secs */ dstate_setinfo("battery.runtime.low", "%d",timevalue); } /* Shutdown timer */ ser_send (upsfd,"%c%s",GETX_SHUTDOWN,COMMAND_END); if(!OneacGetResponse (buffer, sizeof(buffer), GETX_SHUTDOWN_RESP_SIZE)) { /* ON would have handled NO_VALUE_YET and setting FSD * above so only deal with counter value here. */ if (buffer[0] != NO_VALUE_YET) { EliminateLeadingZeroes (buffer, 5, buffer2, sizeof(buffer2)); dstate_setinfo("ups.timer.shutdown", "%s", buffer2); } } /* Restart timer */ ser_send (upsfd,"%s%s",GETX_RESTART_COUNT,COMMAND_END); if(!OneacGetResponse (buffer, sizeof(buffer), GETX_RSTRT_RESP_SIZE)) { if (atoi(buffer) == 0) { dstate_delinfo("ups.timer.start"); } else { EliminateLeadingZeroes (buffer, 4, buffer2, sizeof(buffer2)); dstate_setinfo("ups.timer.start", "%s", buffer2); } } } } alarm_commit(); status_commit(); /* If the comm retry counter is zero then datastale has been set. * We don't want to set dataok or ser_comm_good if that is the case. */ if (CommTry != 0) { dstate_dataok(); ser_comm_good(); } } } void upsdrv_shutdown(void) { ser_send(upsfd,"%s",SHUTDOWN); } void upsdrv_help(void) { printf("\n---------\nNOTE:\n"); printf("You must set the UPS interface card DIP switch to 9600 BPS\n"); } void upsdrv_cleanup(void) { ser_close(upsfd, device_path); } void upsdrv_makevartable(void) { addvar(VAR_VALUE,"testtime", "Change battery test time from the 2 minute default."); addvar(VAR_VALUE,"offdelay", "Change shutdown delay time from 0 second default."); } int instcmd(const char *cmdname, const char *extra) { int i; upsdebugx(2, "In instcmd with %s and extra %s.", cmdname, extra); if (!strcasecmp(cmdname, "test.failure.start")) { ser_send(upsfd,"%s%s",SIM_PWR_FAIL,COMMAND_END); return STAT_INSTCMD_HANDLED; } if (!strcasecmp(cmdname, "shutdown.return")) { i = atoi(dstate_getinfo("ups.delay.shutdown")); if ((strncmp (UpsFamily, FAMILY_OZ, FAMILY_SIZE) == 0) || (strncmp (UpsFamily, FAMILY_OB, FAMILY_SIZE) == 0)) { upsdebugx(3, "Shutdown using %c%d...", DELAYED_SHUTDOWN_PREFIX, i); ser_send(upsfd,"%c%d%s",DELAYED_SHUTDOWN_PREFIX, i, COMMAND_END); } else { upsdebugx(3, "Shutdown using %c%03d...",DELAYED_SHUTDOWN_PREFIX, i); ser_send(upsfd,"%c%03d%s",DELAYED_SHUTDOWN_PREFIX, i, COMMAND_END); } return STAT_INSTCMD_HANDLED; } if(!strcasecmp(cmdname, "shutdown.reboot")) { ser_send(upsfd, "%s", SHUTDOWN); return STAT_INSTCMD_HANDLED; } if (!strcasecmp(cmdname, "shutdown.stop")) { ser_send(upsfd,"%c%s",DELAYED_SHUTDOWN_PREFIX,COMMAND_END); return STAT_INSTCMD_HANDLED; } if (!strcasecmp(cmdname, "test.battery.start.quick")) { do_battery_test(); return STAT_INSTCMD_HANDLED; } if (!strcasecmp(cmdname, "test.battery.start.deep")) { ser_send(upsfd, "%s%s", TEST_BATT_DEEP, COMMAND_END); return STAT_INSTCMD_HANDLED; } if (!strcasecmp(cmdname, "test.battery.stop")) { if ((strncmp (UpsFamily, FAMILY_EG, FAMILY_SIZE) == 0) || (strncmp (UpsFamily, FAMILY_ON, FAMILY_SIZE) == 0)) { ser_send(upsfd,"%s00%s",BAT_TEST_PREFIX,COMMAND_END); } else { ser_send(upsfd,"%c%s",TEST_ABORT,COMMAND_END); } return STAT_INSTCMD_HANDLED; } if (!strcasecmp(cmdname, "reset.input.minmax")) { ser_send(upsfd,"%c%s",RESET_MIN_MAX, COMMAND_END); return STAT_INSTCMD_HANDLED; } if (!strcasecmp(cmdname, "beeper.enable")) { ser_send(upsfd,"%c%c%s",SETX_BUZZER_PREFIX, BUZZER_ENABLED,COMMAND_END); return STAT_INSTCMD_HANDLED; } if (!strcasecmp(cmdname, "beeper.disable")) { ser_send(upsfd,"%c%c%s",SETX_BUZZER_PREFIX,BUZZER_DISABLED,COMMAND_END); return STAT_INSTCMD_HANDLED; } if (!strcasecmp(cmdname, "beeper.mute")) { ser_send(upsfd,"%c%c%s",SETX_BUZZER_PREFIX, BUZZER_MUTED, COMMAND_END); return STAT_INSTCMD_HANDLED; } if (!strcasecmp(cmdname, "test.panel.start")) { ser_send(upsfd,"%s%s",TEST_INDICATORS, COMMAND_END); return STAT_INSTCMD_HANDLED; } upslogx(LOG_NOTICE, "instcmd: unknown command [%s]", cmdname); return STAT_INSTCMD_UNKNOWN; } int setcmd(const char* varname, const char* setvalue) { upsdebugx(2, "In setcmd for %s with %s...", varname, setvalue); if (!strcasecmp(varname, "ups.delay.shutdown")) { if ((strncmp (UpsFamily, FAMILY_OZ, FAMILY_SIZE) == 0) || (strncmp (UpsFamily, FAMILY_OB, FAMILY_SIZE) == 0)) { if (atoi(setvalue) > 65535) { upsdebugx(2, "Too big for OZ/OB (>65535)...(%s)", setvalue); return STAT_SET_UNKNOWN; } } else { if (atoi(setvalue) > 999) { upsdebugx(2, "Too big for EG/ON (>999)...(%s)", setvalue); return STAT_SET_UNKNOWN; } } dstate_setinfo("ups.delay.shutdown", "%s", setvalue); return STAT_SET_HANDLED; } if (!strcasecmp(varname, "input.transfer.low")) { if (SetOutputAllow(setvalue, dstate_getinfo("input.transfer.high"))) { return STAT_SET_UNKNOWN; } else { dstate_setinfo("input.transfer.low" , "%s", setvalue); return STAT_SET_HANDLED; } } if (!strcasecmp(varname, "input.transfer.high")) { if (SetOutputAllow(dstate_getinfo("input.transfer.low"), setvalue)) { return STAT_SET_UNKNOWN; } else { dstate_setinfo("input.transfer.high" , "%s", setvalue); return STAT_SET_HANDLED; } } if (!strcasecmp(varname, "battery.date")) { if(strlen(setvalue) == GETX_DATE_RESP_SIZE) /* yymmdd (6 chars) */ { ser_send(upsfd, "%s%s%s", SETX_BATTERY_DATE, setvalue, COMMAND_END); dstate_setinfo("battery.date", "%s (yymmdd)", setvalue); return STAT_SET_HANDLED; } else { return STAT_SET_UNKNOWN; } } if (!strcasecmp(varname, "ups.delay.start")) { if (atoi(setvalue) <= 9999) { ser_send(upsfd,"%s%s%s",SETX_RESTART_DELAY, setvalue, COMMAND_END); dstate_setinfo("ups.delay.start", "%s", setvalue); return STAT_SET_HANDLED; } else { return STAT_SET_UNKNOWN; } } if (!strcasecmp(varname, "battery.runtime.low")) { if (atoi(setvalue) <= 99) { ser_send(upsfd,"%s%s%s",SETX_LOWBATT_AT, setvalue, COMMAND_END); dstate_setinfo("battery.runtime.low", "%s", setvalue); return STAT_SET_HANDLED; } else { return STAT_SET_UNKNOWN; } } if (!strcasecmp(varname, "ups.start.auto")) { if (!strcasecmp(setvalue, "yes")) { ser_send(upsfd,"%c0%s",SETX_AUTO_START, COMMAND_END); dstate_setinfo("ups.start.auto", "yes"); return STAT_SET_HANDLED; } else if (!strcasecmp(setvalue, "no")) { ser_send(upsfd,"%c1%s",SETX_AUTO_START, COMMAND_END); dstate_setinfo("ups.start.auto", "no"); return STAT_SET_HANDLED; } return STAT_SET_UNKNOWN; } upslogx(LOG_NOTICE, "setcmd: unknown command [%s]", varname); return STAT_SET_UNKNOWN; } nut-2.8.1/drivers/powercom-hid.c0000644000175000017500000006060514501607135013501 00000000000000/* powercom-hid.c - subdriver to monitor PowerCOM USB/HID devices with NUT * * Copyright (C) * 2003 - 2009 Arnaud Quette * 2005 - 2006 Peter Selinger * 2008 - 2009 Arjen de Korte * 2020 - 2022 Jim Klimov * * 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 2 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, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "main.h" /* for getval() */ #include "usbhid-ups.h" #include "powercom-hid.h" #include "usb-common.h" #define POWERCOM_HID_VERSION "PowerCOM HID 0.7" /* FIXME: experimental flag to be put in upsdrv_info */ /* PowerCOM */ #define POWERCOM_VENDORID 0x0d9f /* USB IDs device table */ static usb_device_id_t powercom_usb_device_table[] = { /* PowerCOM IMP - IMPERIAL Series */ { USB_DEVICE(POWERCOM_VENDORID, 0x00a2), NULL }, /* PowerCOM SKP - Smart KING Pro (all Smart series) */ { USB_DEVICE(POWERCOM_VENDORID, 0x00a3), NULL }, /* PowerCOM WOW */ { USB_DEVICE(POWERCOM_VENDORID, 0x00a4), NULL }, /* PowerCOM VGD - Vanguard */ { USB_DEVICE(POWERCOM_VENDORID, 0x00a5), NULL }, /* PowerCOM BNT - Black Knight Pro */ { USB_DEVICE(POWERCOM_VENDORID, 0x00a6), NULL }, /* PowerCOM Vanguard and BNT-xxxAP */ { USB_DEVICE(POWERCOM_VENDORID, 0x0004), NULL }, { USB_DEVICE(POWERCOM_VENDORID, 0x0001), NULL }, /* Terminating entry */ { 0, 0, NULL } }; static char powercom_scratch_buf[32]; static const char *powercom_startup_fun(double value) { uint16_t i = value; snprintf(powercom_scratch_buf, sizeof(powercom_scratch_buf), "%d", 60 * (((i & 0x00FF) << 8) + (i >> 8))); upsdebugx(3, "%s: value = %.0f, buf = %s", __func__, value, powercom_scratch_buf); return powercom_scratch_buf; } static double powercom_startup_nuf(const char *value) { const char *s = dstate_getinfo("ups.delay.start"); uint16_t val, command; int iv; iv = atoi(value ? value : s) / 60; if (iv < 0 || (intmax_t)iv > (intmax_t)UINT16_MAX) { upsdebugx(0, "%s: value = %d is not in uint16_t range", __func__, iv); return 0; } /* COMMENTME: What are we doing here, a byte-swap in the word? */ val = (uint16_t)iv; command = (uint16_t)(val << 8); command += (uint16_t)(val >> 8); upsdebugx(3, "%s: value = %s, command = %04X", __func__, value, command); return command; } static info_lkp_t powercom_startup_info[] = { { 0, NULL, powercom_startup_fun, powercom_startup_nuf } }; static const char *powercom_shutdown_fun(double value) { uint16_t i = value; snprintf(powercom_scratch_buf, sizeof(powercom_scratch_buf), "%d", 60 * (i & 0x00FF) + (i >> 8)); upsdebugx(3, "%s: value = %.0f, buf = %s", __func__, value, powercom_scratch_buf); return powercom_scratch_buf; } static double powercom_shutdown_nuf(const char *value) { const char *s = dstate_getinfo("ups.delay.shutdown"); uint16_t val, command; int iv; iv = atoi(value ? value : s); if (iv < 0 || (intmax_t)iv > (intmax_t)UINT16_MAX) { upsdebugx(0, "%s: value = %d is not in uint16_t range", __func__, iv); return 0; } val = (uint16_t)iv; val = val ? val : 1; /* 0 sets the maximum delay */ command = ((uint16_t)((val % 60) << 8)) + (uint16_t)(val / 60); command |= 0x4000; /* AC RESTART NORMAL ENABLE */ upsdebugx(3, "%s: value = %s, command = %04X", __func__, value, command); return command; } static info_lkp_t powercom_shutdown_info[] = { { 0, NULL, powercom_shutdown_fun, powercom_shutdown_nuf } }; static double powercom_stayoff_nuf(const char *value) { const char *s = dstate_getinfo("ups.delay.shutdown"); uint16_t val, command; int iv; iv = atoi(value ? value : s); if (iv < 0 || (intmax_t)iv > (intmax_t)UINT16_MAX) { upsdebugx(0, "%s: value = %d is not in uint16_t range", __func__, iv); return 0; } val = (uint16_t)iv; val = val ? val : 1; /* 0 sets the maximum delay */ command = ((uint16_t)((val % 60) << 8)) + (uint16_t)(val / 60); command |= 0x8000; /* AC RESTART NORMAL DISABLE */ upsdebugx(3, "%s: value = %s, command = %04X", __func__, value, command); return command; } static info_lkp_t powercom_stayoff_info[] = { { 0, NULL, NULL, powercom_stayoff_nuf } }; static info_lkp_t powercom_beeper_info[] = { { 1, "enabled", NULL, NULL }, { 2, "disabled", NULL, NULL }, /* muted? */ { 0, NULL, NULL, NULL } }; static const char *powercom_voltage_conversion_fun(double value) { static char buf[20]; snprintf(buf, sizeof(buf), "%0.0f", value * 4); return buf; } static info_lkp_t powercom_voltage_conversion[] = { { 0, NULL, powercom_voltage_conversion_fun, NULL } }; static const char *powercom_upsfail_conversion_fun(double value) { if ((long)value & 0x0001) { return "fanfail"; } else { return "!fanfail"; } } static info_lkp_t powercom_upsfail_conversion[] = { { 0, NULL, powercom_upsfail_conversion_fun, NULL } }; static const char *powercom_replacebatt_conversion_fun(double value) { if ((long)value & 0x0002) { return "replacebatt"; } else { return "!replacebatt"; } } static info_lkp_t powercom_replacebatt_conversion[] = { { 0, NULL, powercom_replacebatt_conversion_fun, NULL } }; static const char *powercom_test_conversion_fun(double value) { if ((long)value & 0x0004) { return "cal"; } else { return "!cal"; } } static info_lkp_t powercom_test_conversion[] = { { 0, NULL, powercom_test_conversion_fun, NULL } }; static const char *powercom_shutdownimm_conversion_fun(double value) { if ((long)value & 0x0010) { return "shutdownimm"; } else { return "!shutdownimm"; } } static info_lkp_t powercom_shutdownimm_conversion[] = { { 0, NULL, powercom_shutdownimm_conversion_fun, NULL } }; static const char *powercom_online_conversion_fun(double value) { if ((long)value & 0x0001) { return "!online"; } else { return "online"; } } static info_lkp_t powercom_online_conversion[] = { { 0, NULL, powercom_online_conversion_fun, NULL } }; static const char *powercom_lowbatt_conversion_fun(double value) { if ((long)value & 0x0002) { return "lowbatt"; } else { return "!lowbatt"; } } static info_lkp_t powercom_lowbatt_conversion[] = { { 0, NULL, powercom_lowbatt_conversion_fun, NULL } }; static const char *powercom_trim_conversion_fun(double value) { if (((long)value & 0x0018) == 0x0008) { return "trim"; } else { return "!trim"; } } static info_lkp_t powercom_trim_conversion[] = { { 0, NULL, powercom_trim_conversion_fun, NULL } }; static const char *powercom_boost_conversion_fun(double value) { if (((long)value & 0x0018) == 0x0018) { return "boost"; } else { return "!boost"; } } static info_lkp_t powercom_boost_conversion[] = { { 0, NULL, powercom_boost_conversion_fun, NULL } }; static const char *powercom_overload_conversion_fun(double value) { if ((long)value & 0x0020) { return "overload"; } else { return "!overload"; } } static info_lkp_t powercom_overload_conversion[] = { { 0, NULL, powercom_overload_conversion_fun, NULL } }; /* --------------------------------------------------------------- */ /* Vendor-specific usage table */ /* --------------------------------------------------------------- */ /* POWERCOM usage table */ static usage_lkp_t powercom_usage_lkp[] = { { "PowercomUPS", 0x00020004 }, { "PowercomBatterySystem", 0x00020010 }, { "PowercomPowerConverter", 0x00020016 }, { "PowercomInput", 0x0002001a }, { "PowercomOutput", 0x0002001c }, { "PowercomVoltage", 0x00020030 }, { "PowercomFrequency", 0x00020032 }, { "PowercomPercentLoad", 0x00020035 }, { "PowercomTemperature", 0x00020036 }, { "PowercomDelayBeforeStartup", 0x00020056 }, { "PowercomDelayBeforeShutdown", 0x00020057 }, { "PowercomTest", 0x00020058 }, { "PowercomShutdownRequested", 0x00020068 }, { "PowercomInternalChargeController", 0x00020081 }, { "PowercomPrimaryBatterySupport", 0x00020082 }, { "PowercomDesignCapacity", 0x00020083 }, { "PowercomSpecificationInfo", 0x00020084 }, { "PowercomManufacturerDate", 0x00020085 }, { "PowercomSerialNumber", 0x00020086 }, { "PowercomManufacturerName", 0x00020087 }, { "POWERCOM1", 0x0084002f }, { "POWERCOM2", 0xff860060 }, { "POWERCOM3", 0xff860080 }, { "PCMDelayBeforeStartup", 0x00ff0056 }, { "PCMDelayBeforeShutdown", 0x00ff0057 }, { NULL, 0 } }; static usage_tables_t powercom_utab[] = { powercom_usage_lkp, hid_usage_lkp, NULL, }; /* --------------------------------------------------------------- */ /* HID2NUT lookup table */ /* --------------------------------------------------------------- */ static hid_info_t powercom_hid2nut[] = { { "BOOL", 0, 0, "UPS.PowerSummary.PresentStatus.ACPresent", NULL, NULL, 0, online_info }, { "BOOL", 0, 0, "UPS.PowerSummary.PresentStatus.BatteryPresent", NULL, NULL, 0, nobattery_info }, { "BOOL", 0, 0, "UPS.PowerSummary.PresentStatus.BelowRemainingCapacityLimit", NULL, NULL, 0, lowbatt_info }, { "BOOL", 0, 0, "UPS.PowerSummary.PresentStatus.Charging", NULL, NULL, 0, charging_info }, { "BOOL", 0, 0, "UPS.PowerSummary.PresentStatus.CommunicationLost", NULL, NULL, 0, commfault_info }, { "BOOL", 0, 0, "UPS.PowerSummary.PresentStatus.Discharging", NULL, NULL, 0, discharging_info }, { "BOOL", 0, 0, "UPS.PowerSummary.PresentStatus.NeedReplacement", NULL, NULL, 0, replacebatt_info }, { "BOOL", 0, 0, "UPS.PowerSummary.PresentStatus.Overload", NULL, NULL, 0, overload_info }, { "BOOL", 0, 0, "UPS.PowerSummary.PresentStatus.RemainingTimeLimitExpired", NULL, NULL, 0, timelimitexpired_info }, { "BOOL", 0, 0, "UPS.PowerSummary.PresentStatus.ShutdownImminent", NULL, NULL, 0, shutdownimm_info }, /* { "BOOL", 0, 0, "UPS.PowerSummary.PresentStatus.POWERCOM3", NULL, "%.0f", 0, NULL }, */ /* { "BOOL", 0, 0, "UPS.PowerSummary.PresentStatus.ShutdownRequested", NULL, "%.0f", 0, NULL }, */ /* { "BOOL", 0, 0, "UPS.PowerSummary.PresentStatus.VoltageNotRegulated", NULL, "%.0f", 0, NULL }, */ { "BOOL", 0, 0, "UPS.PresentStatus.ACPresent", NULL, NULL, 0, online_info }, { "BOOL", 0, 0, "UPS.PresentStatus.BatteryPresent", NULL, NULL, 0, nobattery_info }, { "BOOL", 0, 0, "UPS.PresentStatus.BelowRemainingCapacityLimit", NULL, NULL, 0, lowbatt_info }, { "BOOL", 0, 0, "UPS.PresentStatus.Boost", NULL, NULL, 0, boost_info }, { "BOOL", 0, 0, "UPS.PresentStatus.Buck", NULL, NULL, 0, trim_info }, { "BOOL", 0, 0, "UPS.PresentStatus.Charging", NULL, NULL, 0, charging_info }, { "BOOL", 0, 0, "UPS.PresentStatus.CommunicationLost", NULL, NULL, 0, commfault_info }, { "BOOL", 0, 0, "UPS.PresentStatus.Discharging", NULL, NULL, 0, discharging_info }, { "BOOL", 0, 0, "UPS.PresentStatus.NeedReplacement", NULL, NULL, 0, replacebatt_info }, { "BOOL", 0, 0, "UPS.PresentStatus.Overload", NULL, NULL, 0, overload_info }, { "BOOL", 0, 0, "UPS.PresentStatus.RemainingTimeLimitExpired", NULL, NULL, 0, timelimitexpired_info }, { "BOOL", 0, 0, "UPS.PresentStatus.ShutdownImminent", NULL, NULL, 0, shutdownimm_info }, /* { "BOOL", 0, 0, "UPS.PresentStatus.POWERCOM3", NULL, "%.0f", 0, NULL }, */ /* { "BOOL", 0, 0, "UPS.PresentStatus.ShutdownRequested", NULL, "%.0f", 0, NULL }, */ /* { "BOOL", 0, 0, "UPS.PresentStatus.Tested", NULL, "%.0f", 0, NULL }, */ /* { "BOOL", 0, 0, "UPS.PresentStatus.VoltageNotRegulated", NULL, "%.0f", 0, NULL }, */ /* * According to the HID PDC specifications, the below values should report battery.voltage(.nominal) * PowerCOM duplicates the output.voltage(.nominal) here, so we ignore them * { "battery.voltage", 0, 0, "UPS.PowerSummary.Voltage", NULL, "%.2f", 0, NULL }, * { "battery.voltage", 0, 0, "UPS.Battery.Voltage", NULL, "%.2f", 0, NULL }, * { "battery.voltage.nominal", 0, 0, "UPS.PowerSummary.ConfigVoltage", NULL, "%.0f", HU_FLAG_STATIC, NULL }, * { "battery.voltage.nominal", 0, 0, "UPS.Battery.ConfigVoltage", NULL, "%.0f", HU_FLAG_STATIC, NULL }, */ { "battery.charge", 0, 0, "UPS.PowerSummary.RemainingCapacity", NULL, "%.0f", 0, NULL }, { "battery.charge", 0, 0, "UPS.Battery.RemainingCapacity", NULL, "%.0f", 0, NULL }, { "battery.charge.low", 0, 0, "UPS.PowerSummary.RemainingCapacityLimit", NULL, "%.0f", 0, NULL }, { "battery.charge.warning", 0, 0, "UPS.PowerSummary.WarningCapacityLimit", NULL, "%.0f", 0, NULL }, { "battery.runtime", 0, 0, "UPS.PowerSummary.RunTimeToEmpty", NULL, "%.0f", 0, NULL }, { "battery.mfr.date", 0, 0, "UPS.Battery.ManufacturerDate", NULL, "%s", HU_FLAG_STATIC, date_conversion }, { "battery.type", 0, 0, "UPS.PowerSummary.iDeviceChemistry", NULL, "%s", HU_FLAG_STATIC, stringid_conversion }, #if WITH_UNMAPPED_DATA_POINTS { "unmapped.ups.battery.delaybeforestartup", 0, 0, "UPS.Battery.DelayBeforeStartup", NULL, "%.0f", 0, NULL }, { "unmapped.ups.battery.initialized", 0, 0, "UPS.Battery.Initialized", NULL, "%.0f", 0, NULL }, #endif /* if WITH_UNMAPPED_DATA_POINTS */ { "ups.beeper.status", 0, 0, "UPS.PowerSummary.AudibleAlarmControl", NULL, "%s", 0, powercom_beeper_info }, { "ups.beeper.status", 0, 0, "UPS.AudibleAlarmControl", NULL, "%s", 0, powercom_beeper_info }, { "ups.load", 0, 0, "UPS.Output.PercentLoad", NULL, "%.0f", 0, NULL }, { "ups.date", 0, 0, "UPS.PowerSummary.ManufacturerDate", NULL, "%s", HU_FLAG_STATIC, date_conversion }, { "ups.test.result", 0, 0, "UPS.Battery.Test", NULL, "%s", 0, test_read_info }, #if WITH_UNMAPPED_DATA_POINTS { "unmapped.ups.powersummary.imanufacturer", 0, 0, "UPS.PowerSummary.iManufacturer", NULL, "%s", HU_FLAG_STATIC, stringid_conversion }, { "unmapped.ups.powersummary.iproduct", 0, 0, "UPS.PowerSummary.iProduct", NULL, "%s", HU_FLAG_STATIC, stringid_conversion }, { "unmapped.ups.powersummary.iserialnumber", 0, 0, "UPS.PowerSummary.iSerialNumber", NULL, "%s", HU_FLAG_STATIC, stringid_conversion }, { "unmapped.ups.iname", 0, 0, "UPS.iName", NULL, "%s", HU_FLAG_STATIC, stringid_conversion }, { "unmapped.ups.powersummary.ioeminformation", 0, 0, "UPS.PowerSummary.iOEMInformation", NULL, "%s", HU_FLAG_STATIC, stringid_conversion }, #endif /* if WITH_UNMAPPED_DATA_POINTS */ /* The implementation of the HID path UPS.PowerSummary.DelayBeforeStartup is unconventional: * Read: * Byte 7, byte 8 (min) * Write: * Command 4, high byte min, low byte min */ { "ups.delay.start", ST_FLAG_RW | ST_FLAG_STRING, 8, "UPS.PowerSummary.DelayBeforeStartup", NULL, "60", HU_FLAG_ABSENT, NULL }, { "ups.timer.start", 0, 0, "UPS.PowerSummary.DelayBeforeStartup", NULL, "%.0f", 0, powercom_startup_info }, /* The implementation of the HID path UPS.PowerSummary.DelayBeforeShutdown is unconventional: * Read: * Byte 13, Byte 14 (min, sec) * Write: * If Byte(sec), bit7=0 and bit6=0 Then * If Byte 9, bit0=1 Then command 185, 188, min, sec (OL -> shutdown.return) * If Byte 9, bit0=0 Then command 186, 188, min, sec (OB -> shutdown.stayoff) * If Byte(sec), bit7=0 and bit6=1 * Then command 185, 188, min, sec (shutdown.return) * If Byte(sec), bit7=1 and bit6=0 Then * Then command 186, 188, min, sec (shutdown.stayoff) * If Byte(sec), bit7=1 and bit6=1 Then * No actions */ { "ups.delay.shutdown", ST_FLAG_RW | ST_FLAG_STRING, 8, "UPS.PowerSummary.DelayBeforeShutdown", NULL, DEFAULT_OFFDELAY, HU_FLAG_ABSENT, NULL }, { "ups.timer.shutdown", 0, 0, "UPS.PowerSummary.DelayBeforeShutdown", NULL, "%.0f", HU_FLAG_QUICK_POLL, powercom_shutdown_info }, { "ups.delay.shutdown", ST_FLAG_RW | ST_FLAG_STRING, 8, "UPS.PowerSummary.PCMDelayBeforeShutdown", NULL, DEFAULT_OFFDELAY, HU_FLAG_ABSENT, NULL }, { "ups.timer.shutdown", 0, 0, "UPS.PowerSummary.PCMDelayBeforeShutdown", NULL, "%.0f", HU_FLAG_QUICK_POLL, powercom_shutdown_info }, { "input.voltage", 0, 0, "UPS.Input.Voltage", NULL, "%.1f", 0, NULL }, { "input.voltage.nominal", 0, 0, "UPS.Input.ConfigVoltage", NULL, "%.0f", HU_FLAG_STATIC, NULL }, { "input.frequency", 0, 0, "UPS.Input.Frequency", NULL, "%.1f", 0, NULL }, { "output.voltage", 0, 0, "UPS.Output.Voltage", NULL, "%.1f", 0, NULL }, { "output.voltage.nominal", 0, 0, "UPS.Output.ConfigVoltage", NULL, "%.0f", HU_FLAG_STATIC, NULL }, { "output.frequency", 0, 0, "UPS.Output.Frequency", NULL, "%.1f", 0, NULL }, #if WITH_UNMAPPED_DATA_POINTS { "unmapped.ups.powercom1", 0, 0, "UPS.POWERCOM1", NULL, "%.0f", 0, NULL }, /* broken pipe */ { "unmapped.ups.powercom2", 0, 0, "UPS.POWERCOM2", NULL, "%.0f", 0, NULL }, /* broken pipe */ { "unmapped.ups.powersummary.rechargeable", 0, 0, "UPS.PowerSummary.Rechargeable", NULL, "%.0f", 0, NULL }, { "unmapped.ups.shutdownimminent", 0, 0, "UPS.ShutdownImminent", NULL, "%.0f", 0, NULL }, #endif /* if WITH_UNMAPPED_DATA_POINTS */ /* instcmds */ { "beeper.toggle", 0, 0, "UPS.PowerSummary.AudibleAlarmControl", NULL, "1", HU_TYPE_CMD, NULL }, { "beeper.enable", 0, 0, "UPS.PowerSummary.AudibleAlarmControl", NULL, "1", HU_TYPE_CMD, NULL }, { "beeper.disable", 0, 0, "UPS.PowerSummary.AudibleAlarmControl", NULL, "0", HU_TYPE_CMD, NULL }, { "test.battery.start.quick", 0, 0, "UPS.Battery.Test", NULL, "1", HU_TYPE_CMD, NULL }, { "load.on.delay", 0, 0, "UPS.PowerSummary.DelayBeforeStartup", NULL, NULL, HU_TYPE_CMD, powercom_startup_info }, { "shutdown.return", 0, 0, "UPS.PowerSummary.DelayBeforeShutdown", NULL, NULL, HU_TYPE_CMD, powercom_shutdown_info }, { "shutdown.stayoff", 0, 0, "UPS.PowerSummary.DelayBeforeShutdown", NULL, NULL, HU_TYPE_CMD, powercom_stayoff_info }, { "load.on", 0, 0, "UPS.PowerSummary.PCMDelayBeforeStartup", NULL, "0", HU_TYPE_CMD, powercom_startup_info }, { "load.off", 0, 0, "UPS.PowerSummary.PCMDelayBeforeShutdown", NULL, "0", HU_TYPE_CMD, powercom_stayoff_info }, { "shutdown.return", 0, 0, "UPS.PowerSummary.PCMDelayBeforeShutdown", NULL, NULL, HU_TYPE_CMD, powercom_shutdown_info }, { "shutdown.stayoff", 0, 0, "UPS.PowerSummary.PCMDelayBeforeShutdown", NULL, NULL, HU_TYPE_CMD, powercom_stayoff_info }, { "ups.serial", 0, 0, "PowercomUPS.PowercomSerialNumber", NULL, "%s", 0, stringid_conversion }, { "ups.mfr", 0, 0, "PowercomUPS.PowercomManufacturerName", NULL, "%s", 0, stringid_conversion }, #if WITH_UNMAPPED_DATA_POINTS { "UPS.DesignCapacity", 0, 0, "PowercomUPS.PowercomDesignCapacity", NULL, "%.0f", 0, NULL }, /* is always 255 */ #endif /* if WITH_UNMAPPED_DATA_POINTS */ { "ups.mfr.date", 0, 0, "PowercomUPS.PowercomManufacturerDate", NULL, "%s", 0, date_conversion }, { "battery.temperature", 0, 0, "PowercomUPS.PowercomBatterySystem.PowercomTemperature", NULL, "%.0f", 0, NULL }, { "battery.temperature", 0, 0, "UPS.Battery.Temperature", NULL, "%.1f", 0, NULL }, { "battery.charge", 0, 0, "PowercomUPS.PowercomBatterySystem.PowercomVoltage", NULL, "%.0f", 0, NULL }, #if WITH_UNMAPPED_DATA_POINTS { "UPS.BatterySystem.SpecificationInfo", 0, 0, "PowercomUPS.PowercomBatterySystem.PowercomSpecificationInfo", NULL, "%.0f", 0, NULL }, #endif /* if WITH_UNMAPPED_DATA_POINTS */ { "input.frequency", 0, 0, "PowercomUPS.PowercomPowerConverter.PowercomInput.PowercomFrequency", NULL, "%.0f", 0, NULL }, { "input.voltage", 0, 0, "PowercomUPS.PowercomPowerConverter.PowercomInput.PowercomVoltage", NULL, "%.0f", 0, powercom_voltage_conversion }, { "output.voltage", 0, 0, "PowercomUPS.PowercomPowerConverter.PowercomOutput.PowercomVoltage", NULL, "%.0f", 0, powercom_voltage_conversion }, { "ups.load", 0, 0, "PowercomUPS.PowercomPowerConverter.PowercomOutput.PowercomPercentLoad", NULL, "%.0f", 0, NULL }, /* flags: 4 - Testing, 8 - Probably mute (it's set on battery with muted beeper and sometimes during ups test) * bit 0 UPS fault (1 = FAILT) * bit 1 Battery status (1 = BAD, 0 = NORMAL) * bit 2 Test mode (1 = TEST, 0 = NORMAL) * bit 3 X * bit 4 Pre-SD count mode (1 = ACTIVE) * bit 5 Schedule count mode (1 = ACTIVE) * bit 6 Disable NO LOAD SHUTDOWN (1 = ACTIVE) * bit 7 0 */ #if WITH_UNMAPPED_DATA_POINTS { "UPS.PowerConverter.Output.InternalChargeController", 0, 0, "PowercomUPS.PowercomPowerConverter.PowercomOutput.PowercomInternalChargeController", NULL, "%.0f", 0, NULL }, #endif /* if WITH_UNMAPPED_DATA_POINTS */ { "BOOL", 0, 0, "PowercomUPS.PowercomPowerConverter.PowercomOutput.PowercomInternalChargeController", NULL, NULL, HU_FLAG_QUICK_POLL, powercom_upsfail_conversion }, { "BOOL", 0, 0, "PowercomUPS.PowercomPowerConverter.PowercomOutput.PowercomInternalChargeController", NULL, NULL, HU_FLAG_QUICK_POLL, powercom_replacebatt_conversion }, { "BOOL", 0, 0, "PowercomUPS.PowercomPowerConverter.PowercomOutput.PowercomInternalChargeController", NULL, NULL, HU_FLAG_QUICK_POLL, powercom_test_conversion }, { "BOOL", 0, 0, "PowercomUPS.PowercomPowerConverter.PowercomOutput.PowercomInternalChargeController", NULL, NULL, HU_FLAG_QUICK_POLL, powercom_shutdownimm_conversion }, /* flags: 1 - On battery, 2 - Low Battery, 8 - Trim, 8+16 - Boost * bit 0 is line fail (1 = INV, 0 = LINE) * bit 1 is low battery (1 = BAT_ LOW, 0 = NORMAL) * bit 2 X * bit 3 AVR status (1 = AVR, 0 = NO_AVR) * bit 4 AVR mode (1 = BOOST, 0 = BUCK) * bit 5 Load status (1 = OVER LOAD, 0 = NORMAL) * bit 6 X * bit 7 SD mode display */ #if WITH_UNMAPPED_DATA_POINTS { "UPS.PowerConverter.Output.PrimaryBatterySupport", 0, 0, "PowercomUPS.PowercomPowerConverter.PowercomOutput.PowercomPrimaryBatterySupport", NULL, "%.0f", 0, NULL }, #endif /* if WITH_UNMAPPED_DATA_POINTS */ { "BOOL", 0, 0, "PowercomUPS.PowercomPowerConverter.PowercomOutput.PowercomPrimaryBatterySupport", NULL, NULL, HU_FLAG_QUICK_POLL, powercom_online_conversion }, /* Low battery status may not work */ { "BOOL", 0, 0, "PowercomUPS.PowercomPowerConverter.PowercomOutput.PowercomPrimaryBatterySupport", NULL, NULL, HU_FLAG_QUICK_POLL, powercom_lowbatt_conversion }, { "BOOL", 0, 0, "PowercomUPS.PowercomPowerConverter.PowercomOutput.PowercomPrimaryBatterySupport", NULL, NULL, HU_FLAG_QUICK_POLL, powercom_trim_conversion }, { "BOOL", 0, 0, "PowercomUPS.PowercomPowerConverter.PowercomOutput.PowercomPrimaryBatterySupport", NULL, NULL, HU_FLAG_QUICK_POLL, powercom_boost_conversion }, { "BOOL", 0, 0, "PowercomUPS.PowercomPowerConverter.PowercomOutput.PowercomPrimaryBatterySupport", NULL, NULL, HU_FLAG_QUICK_POLL, powercom_overload_conversion }, { "output.frequency", 0, 0, "PowercomUPS.PowercomPowerConverter.PowercomOutput.PowercomFrequency", NULL, "%.0f", 0, NULL }, { "ups.test.result", 0, 0, "PowercomUPS.PowercomPowerConverter.PowercomTest", NULL, "%s", 0, test_read_info }, #if WITH_UNMAPPED_DATA_POINTS { "UPS.PowerConverter.ShutdownRequested", 0, 0, "PowercomUPS.PowercomPowerConverter.PowercomShutdownRequested", NULL, "%.0f", 0, NULL }, #endif /* if WITH_UNMAPPED_DATA_POINTS */ { "ups.delay.shutdown", 0, 0, "PowercomUPS.PowercomPowerConverter.PowercomDelayBeforeShutdown", NULL, "%.0f", 0, NULL }, { "ups.delay.start", 0, 0, "PowercomUPS.PowercomPowerConverter.PowercomDelayBeforeStartup", NULL, "%.0f", 0, NULL }, { "load.off", 0, 0, "PowercomUPS.PowercomPowerConverter.PowercomDelayBeforeShutdown", NULL, "0", HU_TYPE_CMD, NULL }, /* end of structure. */ { NULL, 0, 0, NULL, NULL, NULL, 0, NULL } }; static const char *powercom_format_model(HIDDevice_t *hd) { return hd->Product; } static const char *powercom_format_mfr(HIDDevice_t *hd) { return hd->Vendor ? hd->Vendor : "PowerCOM"; } static const char *powercom_format_serial(HIDDevice_t *hd) { return hd->Serial; } /* this function allows the subdriver to "claim" a device: return 1 if * the device is supported by this subdriver, else 0. */ static int powercom_claim(HIDDevice_t *hd) { int status = is_usb_device_supported(powercom_usb_device_table, hd); switch (status) { case POSSIBLY_SUPPORTED: if (hd->ProductID == 0x0002) { upsdebugx(0, "This Powercom device (%04x/%04x) is not supported by usbhid-ups.\n" "Please use the 'powercom' driver instead.\n", hd->VendorID, hd->ProductID); return 0; } /* by default, reject, unless the productid option is given */ if (getval("productid")) { return 1; } possibly_supported("PowerCOM", hd); return 0; case SUPPORTED: if (hd->ProductID == 0x0001) { interrupt_only = 1; interrupt_size = 8; } return 1; case NOT_SUPPORTED: default: return 0; } } subdriver_t powercom_subdriver = { POWERCOM_HID_VERSION, powercom_claim, powercom_utab, powercom_hid2nut, powercom_format_model, powercom_format_mfr, powercom_format_serial, fix_report_desc, }; nut-2.8.1/drivers/nutdrv_qx_masterguard.h0000644000175000017500000000203414500336654015535 00000000000000/* nutdrv_qx_masterguard.h - Subdriver for Masterguard A/E Series * * Copyright (C) * 2020-2021 Edgar Fuß * * 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 2 of the License, or * (at your option) any later version, or a 2-clause BSD License. * * 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, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #ifndef NUTDRV_QX_MASTERGUARD_H #define NUTDRV_QX_MASTERGUARD_H #include "nutdrv_qx.h" extern subdriver_t masterguard_subdriver; #endif /* NUTDRV_QX_MASTERGUARD_H */ nut-2.8.1/drivers/dstate.c0000644000175000017500000014101414502253356012365 00000000000000/* dstate.c - Network UPS Tools driver-side state management Copyright (C) 2003 Russell Kroll 2008 Arjen de Korte 2012 - 2017 Arnaud Quette 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 2 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, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "config.h" /* must be the first header */ #include #ifndef WIN32 #include #include #include #include #include #include #else #include #include "wincompat.h" #endif #include "common.h" #include "dstate.h" #include "state.h" #include "parseconf.h" #include "attribute.h" #include "nut_stdint.h" static TYPE_FD sockfd = ERROR_FD; #ifndef WIN32 static char *sockfn = NULL; #else static OVERLAPPED connect_overlapped; static char *pipename = NULL; #endif static int stale = 1, alarm_active = 0, ignorelb = 0; static char status_buf[ST_MAX_VALUE_LEN], alarm_buf[ST_MAX_VALUE_LEN]; static st_tree_t *dtree_root = NULL; static conn_t *connhead = NULL; static cmdlist_t *cmdhead = NULL; struct ups_handler upsh; #ifndef WIN32 /* this may be a frequent stumbling point for new users, so be verbose here */ static void sock_fail(const char *fn) __attribute__((noreturn)); static void sock_fail(const char *fn) { int sockerr; struct passwd *pwuser; /* save this so it doesn't get overwritten */ sockerr = errno; /* dispense with the usual upslog stuff since we have stderr here */ printf("\nFatal error: unable to create listener socket\n\n"); printf("bind %s failed: %s\n", fn, strerror(sockerr)); pwuser = getpwuid(getuid()); if (!pwuser) { fatal_with_errno(EXIT_FAILURE, "getpwuid"); } /* deal with some common problems */ switch (errno) { case EACCES: printf("\nCurrent user: %s (UID %d)\n\n", pwuser->pw_name, (int)pwuser->pw_uid); printf("Things to try:\n\n"); printf(" - set different owners or permissions on %s\n\n", dflt_statepath()); printf(" - run this as some other user " "(try -u )\n"); break; case ENOENT: printf("\nThings to try:\n\n"); printf(" - mkdir %s\n", dflt_statepath()); break; case ENOTDIR: printf("\nThings to try:\n\n"); printf(" - rm %s\n\n", dflt_statepath()); printf(" - mkdir %s\n", dflt_statepath()); break; } /* * there - that wasn't so bad. every helpful line of code here * prevents one more "help me" mail to the list a year from now */ printf("\n"); fatalx(EXIT_FAILURE, "Exiting."); } #endif static TYPE_FD sock_open(const char *fn) { TYPE_FD fd; #ifndef WIN32 int ret; struct sockaddr_un ssaddr; check_unix_socket_filename(fn); fd = socket(AF_UNIX, SOCK_STREAM, 0); if (INVALID_FD(fd)) { fatal_with_errno(EXIT_FAILURE, "Can't create a unix domain socket"); } /* keep this around for the unlink() when exiting */ sockfn = xstrdup(fn); ssaddr.sun_family = AF_UNIX; snprintf(ssaddr.sun_path, sizeof(ssaddr.sun_path), "%s", sockfn); unlink(sockfn); /* group gets access so upsd can be a different user but same group */ umask(0007); ret = bind(fd, (struct sockaddr *) &ssaddr, sizeof ssaddr); if (ret < 0) { sock_fail(sockfn); } ret = chmod(sockfn, 0660); if (ret < 0) { fatal_with_errno(EXIT_FAILURE, "chmod(%s, 0660) failed", sockfn); } ret = listen(fd, DS_LISTEN_BACKLOG); if (ret < 0) { fatal_with_errno(EXIT_FAILURE, "listen(%d, %d) failed", fd, DS_LISTEN_BACKLOG); } #else /* WIN32 */ fd = CreateNamedPipe( fn, // pipe name PIPE_ACCESS_DUPLEX | // read/write access FILE_FLAG_OVERLAPPED, // async IO PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_WAIT, PIPE_UNLIMITED_INSTANCES, // max. instances ST_SOCK_BUF_LEN, // output buffer size ST_SOCK_BUF_LEN, // input buffer size 0, // client time-out NULL); // FIXME: default security attribute if (INVALID_FD(fd)) { fatal_with_errno(EXIT_FAILURE, "Can't create a state socket (windows named pipe)"); } /* Prepare an async wait on a connection on the pipe */ memset(&connect_overlapped,0,sizeof(connect_overlapped)); connect_overlapped.hEvent = CreateEvent(NULL, /*Security*/ FALSE, /* auto-reset*/ FALSE, /* inital state = non signaled*/ NULL /* no name*/); if(connect_overlapped.hEvent == NULL ) { fatal_with_errno(EXIT_FAILURE, "Can't create event"); } /* Wait for a connection */ ConnectNamedPipe(fd,&connect_overlapped); #endif return fd; } static void sock_disconnect(conn_t *conn) { #ifndef WIN32 close(conn->fd); #else /* FIXME not sure if this is the right way to close a connection */ if( conn->read_overlapped.hEvent != INVALID_HANDLE_VALUE) { CloseHandle(conn->read_overlapped.hEvent); conn->read_overlapped.hEvent = INVALID_HANDLE_VALUE; } DisconnectNamedPipe(conn->fd); #endif pconf_finish(&conn->ctx); if (conn->prev) { conn->prev->next = conn->next; } else { connhead = conn->next; } if (conn->next) { conn->next->prev = conn->prev; } else { /* conntail = conn->prev; */ } free(conn); } static void send_to_all(const char *fmt, ...) { ssize_t ret; char buf[ST_SOCK_BUF_LEN]; size_t buflen; va_list ap; conn_t *conn, *cnext; va_start(ap, fmt); #ifdef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL #pragma GCC diagnostic push #endif #ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL #pragma GCC diagnostic ignored "-Wformat-nonliteral" #endif #ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_FORMAT_SECURITY #pragma GCC diagnostic ignored "-Wformat-security" #endif ret = vsnprintf(buf, sizeof(buf), fmt, ap); #ifdef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL #pragma GCC diagnostic pop #endif va_end(ap); if (ret < 1) { upsdebugx(2, "%s: nothing to write", __func__); return; } if (ret <= INT_MAX) upsdebugx(5, "%s: %.*s", __func__, (int)(ret-1), buf); buflen = strlen(buf); if (buflen >= SSIZE_MAX) { /* Can't compare buflen to ret... though should not happen with ST_SOCK_BUF_LEN */ upslog_with_errno(LOG_NOTICE, "%s failed: buffered message too large", __func__); return; } for (conn = connhead; conn; conn = cnext) { cnext = conn->next; if (conn->nobroadcast) continue; #ifndef WIN32 ret = write(conn->fd, buf, buflen); #else DWORD bytesWritten = 0; BOOL result = FALSE; result = WriteFile (conn->fd, buf, buflen, &bytesWritten, NULL); if( result == 0 ) { upsdebugx(2, "write failed on handle %p, disconnecting", conn->fd); sock_disconnect(conn); continue; } else { ret = (ssize_t)bytesWritten; } #endif if ((ret < 1) || (ret != (ssize_t)buflen)) { #ifndef WIN32 upsdebugx(0, "WARNING: %s: write %" PRIiSIZE " bytes to " "socket %d failed (ret=%" PRIiSIZE "), disconnecting: %s", __func__, buflen, (int)conn->fd, ret, strerror(errno)); #else upsdebugx(0, "WARNING: %s: write %" PRIiSIZE " bytes to " "handle %p failed (ret=%" PRIiSIZE "), disconnecting: %s", __func__, buflen, conn->fd, ret, strerror(errno)); #endif upsdebugx(6, "failed write: %s", buf); sock_disconnect(conn); /* TOTHINK: Maybe fallback elsewhere in other cases? */ if (ret < 0 && errno == EAGAIN && do_synchronous == -1) { upsdebugx(0, "%s: synchronous mode was 'auto', " "will try 'on' for next connections", __func__); do_synchronous = 1; } dstate_setinfo("driver.parameter.synchronous", "%s", (do_synchronous==1)?"yes":((do_synchronous==0)?"no":"auto")); } else { upsdebugx(6, "%s: write %" PRIiSIZE " bytes to socket %d succeeded " "(ret=%" PRIiSIZE "): %s", __func__, buflen, conn->fd, ret, buf); } } } static int send_to_one(conn_t *conn, const char *fmt, ...) { ssize_t ret; va_list ap; char buf[ST_SOCK_BUF_LEN]; size_t buflen; #ifdef WIN32 DWORD bytesWritten = 0; BOOL result = FALSE; #endif va_start(ap, fmt); #ifdef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL #pragma GCC diagnostic push #endif #ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL #pragma GCC diagnostic ignored "-Wformat-nonliteral" #endif #ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_FORMAT_SECURITY #pragma GCC diagnostic ignored "-Wformat-security" #endif ret = vsnprintf(buf, sizeof(buf), fmt, ap); #ifdef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL #pragma GCC diagnostic pop #endif va_end(ap); upsdebugx(2, "%s: sending %.*s", __func__, (int)strcspn(buf, "\n"), buf); if (ret < 1) { upsdebugx(2, "%s: nothing to write", __func__); return 1; } buflen = strlen(buf); if (buflen >= SSIZE_MAX) { /* Can't compare buflen to ret... though should not happen with ST_SOCK_BUF_LEN */ upslog_with_errno(LOG_NOTICE, "%s failed: buffered message too large", __func__); return 0; /* failed */ } if (ret <= INT_MAX) upsdebugx(5, "%s: %.*s", __func__, (int)(ret-1), buf); /* upsdebugx(0, "%s: writing %" PRIiSIZE " bytes to socket %d: %s", __func__, buflen, conn->fd, buf); */ #ifndef WIN32 ret = write(conn->fd, buf, buflen); #else result = WriteFile (conn->fd, buf, buflen, &bytesWritten, NULL); if( result == 0 ) { ret = 0; } else { ret = (ssize_t)bytesWritten; } #endif if (ret < 0) { /* Hacky bugfix: throttle down for upsd to read that */ #ifndef WIN32 upsdebugx(1, "%s: had to throttle down to retry " "writing %" PRIiSIZE " bytes to socket %d " "(ret=%" PRIiSIZE ", errno=%d, strerror=%s): %s", __func__, buflen, (int)conn->fd, ret, errno, strerror(errno), buf); #else upsdebugx(1, "%s: had to throttle down to retry " "writing %" PRIiSIZE " bytes to handle %p " "(ret=%" PRIiSIZE ", errno=%d, strerror=%s): %s", __func__, buflen, conn->fd, ret, errno, strerror(errno), buf); #endif usleep(200); #ifndef WIN32 ret = write(conn->fd, buf, buflen); #else result = WriteFile (conn->fd, buf, buflen, &bytesWritten, NULL); if( result == 0 ) { ret = 0; } else { ret = (ssize_t)bytesWritten; } #endif if (ret == (ssize_t)buflen) { upsdebugx(1, "%s: throttling down helped", __func__); } } if ((ret < 1) || (ret != (ssize_t)buflen)) { #ifndef WIN32 upsdebugx(0, "WARNING: %s: write %" PRIiSIZE " bytes to " "socket %d failed (ret=%" PRIiSIZE "), disconnecting: %s", __func__, buflen, (int)conn->fd, ret, strerror(errno)); #else upsdebugx(0, "WARNING: %s: write %" PRIiSIZE " bytes to " "handle %p failed (ret=%" PRIiSIZE "), disconnecting: %s", __func__, buflen, conn->fd, ret, strerror(errno)); #endif upsdebugx(6, "failed write: %s", buf); sock_disconnect(conn); /* TOTHINK: Maybe fallback elsewhere in other cases? */ if (ret < 0 && errno == EAGAIN && do_synchronous == -1) { upsdebugx(0, "%s: synchronous mode was 'auto', " "will try 'on' for next connections", __func__); do_synchronous = 1; } dstate_setinfo("driver.parameter.synchronous", "%s", (do_synchronous==1)?"yes":((do_synchronous==0)?"no":"auto")); return 0; /* failed */ } else { #ifndef WIN32 upsdebugx(6, "%s: write %" PRIiSIZE " bytes to socket %d succeeded " "(ret=%" PRIiSIZE "): %s", __func__, buflen, conn->fd, ret, buf); #else upsdebugx(6, "%s: write %" PRIiSIZE " bytes to handle %p succeeded " "(ret=%" PRIiSIZE "): %s", __func__, buflen, conn->fd, ret, buf); #endif } return 1; /* OK */ } static void sock_connect(TYPE_FD sock) { conn_t *conn; #ifndef WIN32 int ret; int fd; struct sockaddr_un sa; #if defined(__hpux) && !defined(_XOPEN_SOURCE_EXTENDED) int salen; #else socklen_t salen; #endif salen = sizeof(sa); fd = accept(sock, (struct sockaddr *) &sa, &salen); if (INVALID_FD(fd)) { upslog_with_errno(LOG_ERR, "accept on unix fd failed"); return; } /* enable nonblocking I/O? * -1 = auto (try async, allow fallback to sync) * 0 = async * 1 = sync */ if (do_synchronous < 1) { upsdebugx(0, "%s: enabling asynchronous mode (%s)", __func__, (do_synchronous<0)?"auto":"fixed"); ret = fcntl(fd, F_GETFL, 0); if (ret < 0) { upslog_with_errno(LOG_ERR, "fcntl get on unix fd failed"); close(fd); return; } ret = fcntl(fd, F_SETFL, ret | O_NDELAY); if (ret < 0) { upslog_with_errno(LOG_ERR, "fcntl set O_NDELAY on unix fd failed"); close(fd); return; } } else { upsdebugx(0, "%s: keeping default synchronous mode", __func__); } conn = xcalloc(1, sizeof(*conn)); conn->fd = fd; #else /* WIN32 */ /* We have detected a connection on the opened pipe. * So we start by saving its handle and creating * a new pipe for future connection */ conn = xcalloc(1, sizeof(*conn)); conn->fd = sock; /* sockfd is the handle of the connection pending pipe */ sockfd = CreateNamedPipe( pipename, // pipe name PIPE_ACCESS_DUPLEX | // read/write access FILE_FLAG_OVERLAPPED, // async IO PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_WAIT, PIPE_UNLIMITED_INSTANCES, // max. instances ST_SOCK_BUF_LEN, // output buffer size ST_SOCK_BUF_LEN, // input buffer size 0, // client time-out NULL); // FIXME: default security attribute if (INVALID_FD(sockfd)) { fatal_with_errno(EXIT_FAILURE, "Can't create a state socket (windows named pipe)"); } /* Prepare a new async wait for a connection on the pipe */ CloseHandle(connect_overlapped.hEvent); memset(&connect_overlapped,0,sizeof(connect_overlapped)); connect_overlapped.hEvent = CreateEvent(NULL, /*Security*/ FALSE, /* auto-reset*/ FALSE, /* inital state = non signaled*/ NULL /* no name*/); if(connect_overlapped.hEvent == NULL ) { fatal_with_errno(EXIT_FAILURE, "Can't create event"); } /* Wait for a connection */ ConnectNamedPipe(sockfd,&connect_overlapped); /* A new pipe waiting for new client connection has been created. We could manage the current connection now */ /* Start a read operation on the newly connected pipe so we could wait on the event associated to this IO */ memset(&conn->read_overlapped,0,sizeof(conn->read_overlapped)); memset(conn->buf,0,sizeof(conn->buf)); conn->read_overlapped.hEvent = CreateEvent(NULL, /*Security*/ FALSE, /* auto-reset*/ FALSE, /* inital state = non signaled*/ NULL /* no name*/); if(conn->read_overlapped.hEvent == NULL ) { fatal_with_errno(EXIT_FAILURE, "Can't create event"); } ReadFile (conn->fd, conn->buf, sizeof(conn->buf) - 1, /* -1 to be sure to have a trailling 0 */ NULL, &(conn->read_overlapped)); #endif conn->nobroadcast = 0; pconf_init(&conn->ctx, NULL); if (connhead) { conn->next = connhead; connhead->prev = conn; } connhead = conn; #ifndef WIN32 upsdebugx(3, "new connection on fd %d", fd); #else upsdebugx(3, "new connection on handle %p", sock); #endif } static int st_tree_dump_conn(st_tree_t *node, conn_t *conn) { int ret; enum_t *etmp; range_t *rtmp; if (!node) { return 1; /* not an error */ } if (node->left) { ret = st_tree_dump_conn(node->left, conn); if (!ret) { return 0; /* write failed in the child */ } } if (!send_to_one(conn, "SETINFO %s \"%s\"\n", node->var, node->val)) { return 0; /* write failed, bail out */ } /* send any enums */ for (etmp = node->enum_list; etmp; etmp = etmp->next) { if (!send_to_one(conn, "ADDENUM %s \"%s\"\n", node->var, etmp->val)) { return 0; } } /* send any ranges */ for (rtmp = node->range_list; rtmp; rtmp = rtmp->next) { if (!send_to_one(conn, "ADDRANGE %s %i %i\n", node->var, rtmp->min, rtmp->max)) { return 0; } } /* provide any auxiliary data */ if (node->aux) { if (!send_to_one(conn, "SETAUX %s %ld\n", node->var, node->aux)) { return 0; } } /* finally report any flags */ if (node->flags) { char flist[SMALLBUF]; /* build the list */ snprintf(flist, sizeof(flist), "%s", node->var); if (node->flags & ST_FLAG_RW) { snprintfcat(flist, sizeof(flist), " RW"); } if (node->flags & ST_FLAG_STRING) { snprintfcat(flist, sizeof(flist), " STRING"); } if (node->flags & ST_FLAG_NUMBER) { snprintfcat(flist, sizeof(flist), " NUMBER"); } if (!send_to_one(conn, "SETFLAGS %s\n", flist)) { return 0; } } if (node->right) { return st_tree_dump_conn(node->right, conn); } return 1; /* everything's OK here ... */ } static int cmd_dump_conn(conn_t *conn) { cmdlist_t *cmd; for (cmd = cmdhead; cmd; cmd = cmd->next) { if (!send_to_one(conn, "ADDCMD %s\n", cmd->name)) { return 0; } } return 1; } static void send_tracking(conn_t *conn, const char *id, int value) { send_to_one(conn, "TRACKING %s %i\n", id, value); } static int sock_arg(conn_t *conn, size_t numarg, char **arg) { #ifdef WIN32 char *sockfn = pipename; /* Just for the report below; not a global var in WIN32 builds */ #endif upsdebugx(6, "Driver on %s is now handling %s with %" PRIuSIZE " args", sockfn, numarg ? arg[0] : "", numarg); if (numarg < 1) { return 0; } if (!strcasecmp(arg[0], "DUMPALL")) { /* first thing: the staleness flag (see also below) */ if ((stale == 1) && !send_to_one(conn, "DATASTALE\n")) { return 1; } if (!st_tree_dump_conn(dtree_root, conn)) { return 1; } if (!cmd_dump_conn(conn)) { return 1; } if ((stale == 0) && !send_to_one(conn, "DATAOK\n")) { return 1; } send_to_one(conn, "DUMPDONE\n"); return 1; } if (!strcasecmp(arg[0], "PING")) { send_to_one(conn, "PONG\n"); return 1; } if (!strcasecmp(arg[0], "NOBROADCAST")) { char buf[SMALLBUF]; conn->nobroadcast = 1; #ifndef WIN32 snprintf(buf, sizeof(buf), "socket %d", conn->fd); #else snprintf(buf, sizeof(buf), "handle %p", conn->fd); #endif upsdebugx(1, "%s: %s requested NOBROADCAST mode", __func__, buf); return 1; } /* BROADCAST <0|1> */ if (!strcasecmp(arg[0], "BROADCAST")) { int i; char buf[SMALLBUF]; conn->nobroadcast = 0; if (numarg > 1 && str_to_int(arg[1], &i, 10)) { if (i < 1) conn->nobroadcast = 1; } #ifndef WIN32 snprintf(buf, sizeof(buf), "socket %d", conn->fd); #else snprintf(buf, sizeof(buf), "handle %p", conn->fd); #endif upsdebugx(1, "%s: %s requested %sBROADCAST mode", __func__, buf, conn->nobroadcast ? "NO" : ""); return 1; } if (numarg < 2) { return 0; } /* INSTCMD [] [TRACKING ] */ if (!strcasecmp(arg[0], "INSTCMD")) { int ret; char *cmdname = arg[1]; char *cmdparam = NULL; char *cmdid = NULL; /* Check if and TRACKING were provided */ if (numarg == 3) { cmdparam = arg[2]; } else if (numarg == 4 && !strcasecmp(arg[2], "TRACKING")) { cmdid = arg[3]; } else if (numarg == 5 && !strcasecmp(arg[3], "TRACKING")) { cmdparam = arg[2]; cmdid = arg[4]; } else if (numarg != 2) { upslogx(LOG_NOTICE, "Malformed INSTCMD request"); return 0; } if (cmdid) upsdebugx(3, "%s: TRACKING = %s", __func__, cmdid); /* try the handler shared by all drivers first */ ret = main_instcmd(arg[1], arg[2], conn); if (ret != STAT_INSTCMD_UNKNOWN) { /* The command was acknowledged by shared handler, and * either handled successfully, or failed, or was not * valid in current circumstances - in any case, we do * not pass to driver-provided logic. */ /* send back execution result if requested */ if (cmdid) send_tracking(conn, cmdid, ret); /* The command was handled, status is a separate consideration */ return 1; } /* else try other handler(s) */ /* try the driver-provided handler if present */ if (upsh.instcmd) { ret = upsh.instcmd(cmdname, cmdparam); /* send back execution result if requested */ if (cmdid) send_tracking(conn, cmdid, ret); /* The command was handled, status is a separate consideration */ return 1; } upslogx(LOG_NOTICE, "Got INSTCMD, but driver lacks a handler"); return 1; } if (numarg < 3) { return 0; } /* SET [TRACKING ] */ if (!strcasecmp(arg[0], "SET")) { int ret; char *setid = NULL; /* Check if TRACKING was provided */ if (numarg == 5) { if (!strcasecmp(arg[3], "TRACKING")) { setid = arg[4]; } else { upslogx(LOG_NOTICE, "Got SET with unsupported parameters (%s/%s)", arg[3], arg[4]); return 0; } upsdebugx(3, "%s: TRACKING = %s", __func__, setid); } /* try the handler shared by all drivers first */ ret = main_setvar(arg[1], arg[2], conn); if (ret != STAT_SET_UNKNOWN) { /* The command was acknowledged by shared handler, and * either handled successfully, or failed, or was not * valid in current circumstances - in any case, we do * not pass to driver-provided logic. */ /* send back execution result if requested */ if (setid) send_tracking(conn, setid, ret); /* The command was handled, status is a separate consideration */ return 1; } /* else try other handler(s) */ /* try the driver-provided handler if present */ if (upsh.setvar) { ret = upsh.setvar(arg[1], arg[2]); /* send back execution result if requested */ if (setid) send_tracking(conn, setid, ret); /* The command was handled, status is a separate consideration */ return 1; } upslogx(LOG_NOTICE, "Got SET, but driver lacks a handler"); return 1; } /* unknown */ return 0; } static void sock_read(conn_t *conn) { ssize_t ret, i; #ifndef WIN32 char buf[SMALLBUF]; ret = read(conn->fd, buf, sizeof(buf)); if (ret < 0) { switch(errno) { case EINTR: case EAGAIN: return; default: sock_disconnect(conn); return; } } #else char *buf = conn->buf; DWORD bytesRead; BOOL res; res = GetOverlappedResult(conn->fd, &conn->read_overlapped, &bytesRead, FALSE); if( res == 0 ) { upslogx(LOG_INFO, "Read error : %d",(int)GetLastError()); sock_disconnect(conn); return; } ret = bytesRead; /* Special case for signals */ if (!strncmp(conn->buf, COMMAND_STOP, sizeof(COMMAND_STOP))) { set_exit_flag(1); return; } #endif for (i = 0; i < ret; i++) { switch(pconf_char(&conn->ctx, buf[i])) { case 0: /* nothing to parse yet */ continue; case 1: /* try to use it, and complain about unknown commands */ if (!sock_arg(conn, conn->ctx.numargs, conn->ctx.arglist)) { size_t arg; upslogx(LOG_INFO, "Unknown command on socket: "); for (arg = 0; arg < conn->ctx.numargs && arg < INT_MAX; arg++) { upslogx(LOG_INFO, "arg %d: %s", (int)arg, conn->ctx.arglist[arg]); } } continue; default: /* nothing parsed */ upslogx(LOG_NOTICE, "Parse error on sock: %s", conn->ctx.errmsg); return; } } #ifdef WIN32 /* Restart async read */ memset(conn->buf,0,sizeof(conn->buf)); ReadFile(conn->fd,conn->buf,sizeof(conn->buf)-1,NULL,&(conn->read_overlapped)); /* -1 to be sure to have a trailling 0 */ #endif } static void sock_close(void) { conn_t *conn, *cnext; if (VALID_FD(sockfd)) { #ifndef WIN32 close(sockfd); if (sockfn) { unlink(sockfn); free(sockfn); sockfn = NULL; } #else FlushFileBuffers(sockfd); CloseHandle(sockfd); #endif sockfd = ERROR_FD; } for (conn = connhead; conn; conn = cnext) { cnext = conn->next; sock_disconnect(conn); } connhead = NULL; /* conntail = NULL; */ } /* interface */ char * dstate_init(const char *prog, const char *devname) { char sockname[SMALLBUF]; #ifndef WIN32 /* do this here for now */ #if (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_PUSH_POP) && (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_STRICT_PROTOTYPES) # pragma GCC diagnostic push # pragma GCC diagnostic ignored "-Wstrict-prototypes" #endif signal(SIGPIPE, SIG_IGN); #if (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_PUSH_POP) && (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_STRICT_PROTOTYPES) # pragma GCC diagnostic pop #endif if (devname) { snprintf(sockname, sizeof(sockname), "%s/%s-%s", dflt_statepath(), prog, devname); } else { snprintf(sockname, sizeof(sockname), "%s/%s", dflt_statepath(), prog); } #else /* upsname (and so devname) is now mandatory so no need to test it */ snprintf(sockname, sizeof(sockname), "\\\\.\\pipe\\%s-%s", prog, devname); pipename = xstrdup(sockname); #endif sockfd = sock_open(sockname); #ifndef WIN32 upsdebugx(2, "dstate_init: sock %s open on fd %d", sockname, sockfd); #else upsdebugx(2, "dstate_init: sock %s open on handle %p", sockname, sockfd); #endif /* NOTE: Caller must free this string */ return xstrdup(sockname); } /* returns 1 if timeout expired or data is available on UPS fd, 0 otherwise */ int dstate_poll_fds(struct timeval timeout, TYPE_FD arg_extrafd) { int maxfd = 0; /* Unidiomatic use vs. "sockfd" below, which is "int" on non-WIN32 */ int overrun = 0; conn_t *conn; struct timeval now; #ifndef WIN32 int ret; fd_set rfds; conn_t *cnext; FD_ZERO(&rfds); FD_SET(sockfd, &rfds); maxfd = sockfd; if (VALID_FD(arg_extrafd)) { FD_SET(arg_extrafd, &rfds); if (arg_extrafd > maxfd) { maxfd = arg_extrafd; } } for (conn = connhead; conn; conn = conn->next) { FD_SET(conn->fd, &rfds); if (conn->fd > maxfd) { maxfd = conn->fd; } } gettimeofday(&now, NULL); /* number of microseconds should always be positive */ if (timeout.tv_usec < now.tv_usec) { timeout.tv_sec -= 1; timeout.tv_usec += 1000000; } if (timeout.tv_sec < now.tv_sec) { timeout.tv_sec = 0; timeout.tv_usec = 0; overrun = 1; /* no time left */ } else { timeout.tv_sec -= now.tv_sec; timeout.tv_usec -= now.tv_usec; } ret = select(maxfd + 1, &rfds, NULL, NULL, &timeout); if (ret == 0) { return 1; /* timer expired */ } if (ret < 0) { switch (errno) { case EINTR: case EAGAIN: /* ignore interruptions from signals */ break; default: upslog_with_errno(LOG_ERR, "select unix sockets failed"); } return overrun; } if (FD_ISSET(sockfd, &rfds)) { sock_connect(sockfd); } for (conn = connhead; conn; conn = cnext) { cnext = conn->next; if (FD_ISSET(conn->fd, &rfds)) { sock_read(conn); } } /* tell the caller if that fd woke up */ if (VALID_FD(arg_extrafd) && (FD_ISSET(arg_extrafd, &rfds))) { return 1; } #else /* WIN32 */ DWORD ret; HANDLE rfds[32]; DWORD timeout_ms; /* FIXME: Should such table (and limit) be used in reality? */ NUT_UNUSED_VARIABLE(arg_extrafd); /* if (VALID_FD(arg_extrafd)) { rfds[maxfd] = arg_extrafd; maxfd++; } */ gettimeofday(&now, NULL); /* number of microseconds should always be positive */ if (timeout.tv_usec < now.tv_usec) { timeout.tv_sec -= 1; timeout.tv_usec += 1000000; } if (timeout.tv_sec < now.tv_sec) { timeout.tv_sec = 0; timeout.tv_usec = 0; overrun = 1; /* no time left */ } else { timeout.tv_sec -= now.tv_sec; timeout.tv_usec -= now.tv_usec; } timeout_ms = (timeout.tv_sec * 1000) + (timeout.tv_usec / 1000); /* Wait on the read IO of each connections */ for (conn = connhead; conn; conn = conn->next) { rfds[maxfd] = conn->read_overlapped.hEvent; maxfd++; } /* Add the connect event */ rfds[maxfd] = connect_overlapped.hEvent; maxfd++; ret = WaitForMultipleObjects( maxfd, /* number of objects in array */ rfds, /* array of objects */ FALSE, /* wait for any object */ timeout_ms); /* timeout in millisecond */ if (ret == WAIT_TIMEOUT) { return 1; /* timer expired */ } if (ret == WAIT_FAILED) { upslog_with_errno(LOG_ERR, "waitfor failed"); return overrun; } /* Retrieve the signaled connection */ for (conn = connhead; conn != NULL; conn = conn->next) { if( conn->read_overlapped.hEvent == rfds[ret-WAIT_OBJECT_0]) { break; } } /* the connection event handle has been signaled */ if (rfds[ret] == connect_overlapped.hEvent) { sock_connect(sockfd); } /* one of the read event handle has been signaled */ else { if (conn != NULL) { sock_read(conn); } } /* tell the caller if that fd woke up */ /* if (VALID_FD(arg_extrafd) && (ret == arg_extrafd)) { return 1; } */ #endif return overrun; } /****************************************************************** * COMMON ******************************************************************/ int dstate_setinfo(const char *var, const char *fmt, ...) { int ret; char value[ST_MAX_VALUE_LEN]; va_list ap; va_start(ap, fmt); #ifdef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL #pragma GCC diagnostic push #endif #ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL #pragma GCC diagnostic ignored "-Wformat-nonliteral" #endif #ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_FORMAT_SECURITY #pragma GCC diagnostic ignored "-Wformat-security" #endif vsnprintf(value, sizeof(value), fmt, ap); #ifdef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL #pragma GCC diagnostic pop #endif va_end(ap); ret = state_setinfo(&dtree_root, var, value); if (ret == 1) { send_to_all("SETINFO %s \"%s\"\n", var, value); } return ret; } int dstate_addenum(const char *var, const char *fmt, ...) { int ret; char value[ST_MAX_VALUE_LEN]; va_list ap; va_start(ap, fmt); #ifdef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL #pragma GCC diagnostic push #endif #ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL #pragma GCC diagnostic ignored "-Wformat-nonliteral" #endif #ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_FORMAT_SECURITY #pragma GCC diagnostic ignored "-Wformat-security" #endif vsnprintf(value, sizeof(value), fmt, ap); #ifdef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL #pragma GCC diagnostic pop #endif va_end(ap); ret = state_addenum(dtree_root, var, value); if (ret == 1) { send_to_all("ADDENUM %s \"%s\"\n", var, value); } return ret; } int dstate_addrange(const char *var, const int min, const int max) { int ret; ret = state_addrange(dtree_root, var, min, max); if (ret == 1) { send_to_all("ADDRANGE %s %i %i\n", var, min, max); /* Also add the "NUMBER" flag for ranges */ dstate_addflags(var, ST_FLAG_NUMBER); } return ret; } void dstate_setflags(const char *var, int flags) { st_tree_t *sttmp; char flist[SMALLBUF]; /* find the dtree node for var */ sttmp = state_tree_find(dtree_root, var); if (!sttmp) { upslogx(LOG_ERR, "%s: base variable (%s) does not exist", __func__, var); return; } if (sttmp->flags & ST_FLAG_IMMUTABLE) { upslogx(LOG_WARNING, "%s: base variable (%s) is immutable", __func__, var); return; } if (sttmp->flags == flags) { return; /* no change */ } sttmp->flags = flags; /* build the list */ snprintf(flist, sizeof(flist), "%s", var); if (flags & ST_FLAG_RW) { snprintfcat(flist, sizeof(flist), " RW"); } if (flags & ST_FLAG_STRING) { snprintfcat(flist, sizeof(flist), " STRING"); } if (flags & ST_FLAG_NUMBER) { snprintfcat(flist, sizeof(flist), " NUMBER"); } /* update listeners */ send_to_all("SETFLAGS %s\n", flist); } void dstate_addflags(const char *var, const int addflags) { int flags = state_getflags(dtree_root, var); if (flags == -1) { upslogx(LOG_ERR, "%s: cannot get flags of '%s'", __func__, var); return; } /* Already set */ if ((flags & addflags) == addflags) return; flags |= addflags; dstate_setflags(var, flags); } void dstate_delflags(const char *var, const int delflags) { int flags = state_getflags(dtree_root, var); if (flags == -1) { upslogx(LOG_ERR, "%s: cannot get flags of '%s'", __func__, var); return; } /* Already not set */ if (!(flags & delflags)) return; flags &= ~delflags; dstate_setflags(var, flags); } void dstate_setaux(const char *var, long aux) { st_tree_t *sttmp; /* find the dtree node for var */ sttmp = state_tree_find(dtree_root, var); if (!sttmp) { upslogx(LOG_ERR, "dstate_setaux: base variable (%s) does not exist", var); return; } if (sttmp->aux == aux) { return; /* no change */ } sttmp->aux = aux; /* update listeners */ send_to_all("SETAUX %s %ld\n", var, aux); } const char *dstate_getinfo(const char *var) { return state_getinfo(dtree_root, var); } void dstate_addcmd(const char *cmdname) { int ret; ret = state_addcmd(&cmdhead, cmdname); /* update listeners */ if (ret == 1) { send_to_all("ADDCMD %s\n", cmdname); } } int dstate_delinfo(const char *var) { int ret; ret = state_delinfo(&dtree_root, var); /* update listeners */ if (ret == 1) { send_to_all("DELINFO %s\n", var); } return ret; } int dstate_delinfo_olderthan(const char *var, const st_tree_timespec_t *cutoff) { int ret; ret = state_delinfo_olderthan(&dtree_root, var, cutoff); /* update listeners */ if (ret == 1) { send_to_all("DELINFO %s\n", var); } return ret; } int dstate_delenum(const char *var, const char *val) { int ret; ret = state_delenum(dtree_root, var, val); /* update listeners */ if (ret == 1) { send_to_all("DELENUM %s \"%s\"\n", var, val); } return ret; } int dstate_delrange(const char *var, const int min, const int max) { int ret; ret = state_delrange(dtree_root, var, min, max); /* update listeners */ if (ret == 1) { send_to_all("DELRANGE %s %i %i\n", var, min, max); } return ret; } int dstate_delcmd(const char *cmd) { int ret; ret = state_delcmd(&cmdhead, cmd); /* update listeners */ if (ret == 1) { send_to_all("DELCMD %s\n", cmd); } return ret; } void dstate_free(void) { state_infofree(dtree_root); dtree_root = NULL; state_cmdfree(cmdhead); cmdhead = NULL; sock_close(); } const st_tree_t *dstate_getroot(void) { return dtree_root; } const cmdlist_t *dstate_getcmdlist(void) { return cmdhead; } void dstate_dataok(void) { if (stale == 1) { stale = 0; send_to_all("DATAOK\n"); } } void dstate_datastale(void) { if (stale == 0) { stale = 1; send_to_all("DATASTALE\n"); } } int dstate_is_stale(void) { return stale; } /* ups.status management functions - reducing duplication in the drivers */ /* clean out the temp space for a new pass */ void status_init(void) { if (dstate_getinfo("driver.flag.ignorelb")) { ignorelb = 1; } memset(status_buf, 0, sizeof(status_buf)); } /* add a status element */ void status_set(const char *buf) { if (ignorelb && !strcasecmp(buf, "LB")) { upsdebugx(2, "%s: ignoring LB flag from device", __func__); return; } /* separate with a space if multiple elements are present */ if (strlen(status_buf) > 0) { snprintfcat(status_buf, sizeof(status_buf), " %s", buf); } else { snprintfcat(status_buf, sizeof(status_buf), "%s", buf); } } /* write the status_buf into the externally visible dstate storage */ void status_commit(void) { while (ignorelb) { const char *val, *low; val = dstate_getinfo("battery.charge"); low = dstate_getinfo("battery.charge.low"); if (val && low && (strtol(val, NULL, 10) < strtol(low, NULL, 10))) { snprintfcat(status_buf, sizeof(status_buf), " LB"); upsdebugx(2, "%s: appending LB flag [charge '%s' below '%s']", __func__, val, low); break; } val = dstate_getinfo("battery.runtime"); low = dstate_getinfo("battery.runtime.low"); if (val && low && (strtol(val, NULL, 10) < strtol(low, NULL, 10))) { snprintfcat(status_buf, sizeof(status_buf), " LB"); upsdebugx(2, "%s: appending LB flag [runtime '%s' below '%s']", __func__, val, low); break; } /* LB condition not detected */ break; } if (alarm_active) { dstate_setinfo("ups.status", "ALARM %s", status_buf); } else { dstate_setinfo("ups.status", "%s", status_buf); } } /* similar handlers for ups.alarm */ void alarm_init(void) { /* reinit global counter */ alarm_active = 0; device_alarm_init(); } #if (!defined HAVE_PRAGMA_GCC_DIAGNOSTIC_PUSH_POP_INSIDEFUNC) && (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_TYPE_LIMITS_BESIDEFUNC) # pragma GCC diagnostic ignored "-Wtype-limits" #endif #if (!defined HAVE_PRAGMA_GCC_DIAGNOSTIC_PUSH_POP_INSIDEFUNC) && (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_TAUTOLOGICAL_CONSTANT_OUT_OF_RANGE_COMPARE_BESIDEFUNC) # pragma GCC diagnostic ignored "-Wtautological-constant-out-of-range-compare" #endif void alarm_set(const char *buf) { int ret; if (strlen(alarm_buf) > 0) { ret = snprintfcat(alarm_buf, sizeof(alarm_buf), " %s", buf); } else { ret = snprintfcat(alarm_buf, sizeof(alarm_buf), "%s", buf); } if (ret < 0) { /* Should we also try to print the potentially unusable buf? * Generally - likely not. But if it is short enough... * Note: LARGEBUF was the original limit mismatched vs alarm_buf * size before PR #986. */ char alarm_tmp[LARGEBUF]; int ibuflen; size_t buflen; memset(alarm_tmp, 0, sizeof(alarm_tmp)); /* A bit of complexity to keep both (int)snprintf(...) and (size_t)sizeof(...) happy */ ibuflen = snprintf(alarm_tmp, sizeof(alarm_tmp), "%s", buf); if (ibuflen < 0) { alarm_tmp[0] = 'N'; alarm_tmp[1] = '/'; alarm_tmp[2] = 'A'; alarm_tmp[3] = '\0'; buflen = strlen(alarm_tmp); } else { #if (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_PUSH_POP) && ( (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_TYPE_LIMITS) || (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_TAUTOLOGICAL_CONSTANT_OUT_OF_RANGE_COMPARE) ) /* Note for gating macros above: unsuffixed HAVE_PRAGMA_GCC_DIAGNOSTIC_PUSH_POP * means support of contexts both inside and outside function body, so the push * above and pop below (outside this finction) are not used. */ # pragma GCC diagnostic push #endif #ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_TYPE_LIMITS /* Note that the individual warning pragmas for use inside function bodies * are named without a _INSIDEFUNC suffix, for simplicity and legacy reasons */ # pragma GCC diagnostic ignored "-Wtype-limits" #endif #ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_TAUTOLOGICAL_CONSTANT_OUT_OF_RANGE_COMPARE # pragma GCC diagnostic ignored "-Wtautological-constant-out-of-range-compare" #endif if ((unsigned long long int)ibuflen < SIZE_MAX) { #if (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_PUSH_POP) && ( (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_TYPE_LIMITS) || (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_TAUTOLOGICAL_CONSTANT_OUT_OF_RANGE_COMPARE) ) # pragma GCC diagnostic pop #endif buflen = (size_t)ibuflen; } else { buflen = SIZE_MAX; } } upslogx(LOG_ERR, "%s: error setting alarm_buf to: %s%s", __func__, alarm_tmp, ( (buflen < sizeof(alarm_tmp)) ? "" : "..." ) ); } else if ((size_t)ret > sizeof(alarm_buf)) { char alarm_tmp[LARGEBUF]; int ibuflen; size_t buflen; memset(alarm_tmp, 0, sizeof(alarm_tmp)); ibuflen = snprintf(alarm_tmp, sizeof(alarm_tmp), "%s", buf); if (ibuflen < 0) { alarm_tmp[0] = 'N'; alarm_tmp[1] = '/'; alarm_tmp[2] = 'A'; alarm_tmp[3] = '\0'; buflen = strlen(alarm_tmp); } else { #if (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_PUSH_POP) && ( (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_TYPE_LIMITS) || (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_TAUTOLOGICAL_CONSTANT_OUT_OF_RANGE_COMPARE) ) # pragma GCC diagnostic push #endif #ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_TYPE_LIMITS # pragma GCC diagnostic ignored "-Wtype-limits" #endif #ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_TAUTOLOGICAL_CONSTANT_OUT_OF_RANGE_COMPARE # pragma GCC diagnostic ignored "-Wtautological-constant-out-of-range-compare" #endif if ((unsigned long long int)ibuflen < SIZE_MAX) { #if (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_PUSH_POP) && ( (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_TYPE_LIMITS) || (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_TAUTOLOGICAL_CONSTANT_OUT_OF_RANGE_COMPARE) ) # pragma GCC diagnostic pop #endif buflen = (size_t)ibuflen; } else { buflen = SIZE_MAX; } } upslogx(LOG_WARNING, "%s: result was truncated while setting or appending " "alarm_buf (limited to %" PRIuSIZE " bytes), with message: %s%s", __func__, sizeof(alarm_buf), alarm_tmp, ( (buflen < sizeof(alarm_tmp)) ? "" : "..." )); } } #if (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_PUSH_POP_BESIDEFUNC) && (!defined HAVE_PRAGMA_GCC_DIAGNOSTIC_PUSH_POP_INSIDEFUNC) && ( (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_TYPE_LIMITS_BESIDEFUNC) || (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_TAUTOLOGICAL_CONSTANT_OUT_OF_RANGE_COMPARE_BESIDEFUNC) ) # pragma GCC diagnostic pop #endif /* write the status_buf into the info array */ void alarm_commit(void) { if (strlen(alarm_buf) > 0) { dstate_setinfo("ups.alarm", "%s", alarm_buf); alarm_active = 1; } else { dstate_delinfo("ups.alarm"); alarm_active = 0; } } void device_alarm_init(void) { /* only clear the buffer, don't touch the alarms counter */ memset(alarm_buf, 0, sizeof(alarm_buf)); } /* same as above, but writes to "device.X.ups.alarm" or "ups.alarm" */ void device_alarm_commit(const int device_number) { char info_name[20]; memset(info_name, 0, 20); if (device_number != 0) /* would then go into "device.%i.alarm" */ snprintf(info_name, 20, "device.%i.ups.alarm", device_number); else /* would then go into "device.alarm" */ snprintf(info_name, 20, "ups.alarm"); /* Daisychain subdevices note: * increase the counter when alarms are present on a subdevice, but * don't decrease the count. Otherwise, we may not get the ALARM flag * in ups.status, while there are some alarms present on device.X */ if (strlen(alarm_buf) > 0) { dstate_setinfo(info_name, "%s", alarm_buf); alarm_active++; } else { dstate_delinfo(info_name); } } /* For devices where we do not have phase-count info (no mapping provided * in the tables), nor in the device data/protocol, we can still guesstimate * and report a value. This routine may also replace an existing value, e.g. * if we've found new data disproving old one (e.g. if the 3-phase UPS was * disbalanced when the driver was started, so we thought it is 1-phase in * practice, and then the additional lines came up loaded, hence the bools * "may_reevaluate" and the readonly flag "may_change_dstate" (so the caller * can query the current apparent situation, without changing any dstates). * It is up to callers to decide if they already have data they want to keep. * The "xput_prefix" is e.g. "input." or "input.bypass." or "output." with * the trailing dot where applicable - we use this string verbatim below. * The "inited_phaseinfo" and "num_phases" are addresses of caller's own * variables to store the flag (if we have successfully inited) and the * discovered amount of phases, or NULL if caller does not want to track it. * * NOTE: The code below can detect if the device is 1, 2 (split phase) or 3 * phases. * * Returns: * -1 Runtime/input error (non fatal, but routine was skipped) * 0 Nothing changed: could not determine a value * 1 A phase value was just determined (and set, if not read-only mode) * 2 Nothing changed: already inited (and may_reevaluate==false) * 3 Nothing changed: detected a value but it is already published * as a dstate; populated inited_phaseinfo and num_phases though */ int dstate_detect_phasecount( const char *xput_prefix, const int may_change_dstate, int *inited_phaseinfo, int *num_phases, const int may_reevaluate ) { /* If caller does not want either of these back - loopback the values below */ int local_inited_phaseinfo = 0, local_num_phases = -1; /* Temporary local value storage */ int old_num_phases = -1, detected_phaseinfo = 0; if (!inited_phaseinfo) inited_phaseinfo = &local_inited_phaseinfo; if (!num_phases) num_phases = &local_num_phases; old_num_phases = *num_phases; upsdebugx(3, "Entering %s('%s', %i, %i, %i, %i)", __func__, xput_prefix, may_change_dstate, *inited_phaseinfo, *num_phases, may_reevaluate); if (!(*inited_phaseinfo) || may_reevaluate) { const char *v1, *v2, *v3, *v0, *v1n, *v2n, *v3n, *v12, *v23, *v31, *c1, *c2, *c3, *c0; char buf[MAX_STRING_SIZE]; /* For concatenation of "xput_prefix" with items we want to query */ size_t xput_prefix_len; size_t bufrw_max; char *bufrw_ptr = NULL; if (!xput_prefix) { upsdebugx(0, "%s(): Bad xput_prefix was passed: it is NULL - function skipped", __func__); return -1; } xput_prefix_len = strlen(xput_prefix); if (xput_prefix_len < 1) { upsdebugx(0, "%s(): Bad xput_prefix was passed: it is empty - function skipped", __func__); return -1; } bufrw_max = sizeof(buf) - xput_prefix_len; if (bufrw_max <= 15) { /* We need to append max ~13 chars per below, so far */ upsdebugx(0, "%s(): Bad xput_prefix was passed: it is too long - function skipped", __func__); return -1; } memset(buf, 0, sizeof(buf)); strncpy(buf, xput_prefix, sizeof(buf)); bufrw_ptr = buf + xput_prefix_len ; /* We either have defined and non-zero (numeric) values below, or NULLs. * Note that as "zero" we should expect any valid numeric representation * of a zero value as some drivers may save strangely formatted values. * For now, we limit the level of paranoia with missing dstate entries, * empty entries, and actual single zero character as contents of the * string. Other obscure cases (string of multiple zeroes, a floating * point zero, surrounding whitespace etc. may be solved if the need * does arise in the future. Arguably, drivers' translation/mapping * tables should take care of this with converion routine and numeric * data type flags. */ #define dstate_getinfo_nonzero(var, suffix) \ do { strncpy(bufrw_ptr, suffix, bufrw_max); \ if ( (var = dstate_getinfo(buf)) ) { \ if ( (var[0] == '0' && var[1] == '\0') || \ (var[0] == '\0') ) { \ var = NULL; \ } \ } \ } while(0) dstate_getinfo_nonzero(v1, "L1.voltage"); dstate_getinfo_nonzero(v2, "L2.voltage"); dstate_getinfo_nonzero(v3, "L3.voltage"); dstate_getinfo_nonzero(v1n, "L1-N.voltage"); dstate_getinfo_nonzero(v2n, "L2-N.voltage"); dstate_getinfo_nonzero(v3n, "L3-N.voltage"); dstate_getinfo_nonzero(v1n, "L1-N.voltage"); dstate_getinfo_nonzero(v12, "L1-L2.voltage"); dstate_getinfo_nonzero(v23, "L2-L3.voltage"); dstate_getinfo_nonzero(v31, "L3-L1.voltage"); dstate_getinfo_nonzero(c1, "L1.current"); dstate_getinfo_nonzero(c2, "L2.current"); dstate_getinfo_nonzero(c3, "L3.current"); dstate_getinfo_nonzero(v0, "voltage"); dstate_getinfo_nonzero(c0, "current"); if ( (v1 && v2 && !v3) || (v1n && v2n && !v3n) || (c1 && c2 && !c3) || (v12 && !v23 && !v31) ) { upsdebugx(5, "%s(): determined a 2-phase case", __func__); *num_phases = 2; *inited_phaseinfo = 1; detected_phaseinfo = 1; } else if ( (v1 && v2 && v3) || (v1n && v2n && v3n) || (c1 && (c2 || c3)) || (c2 && (c1 || c3)) || (c3 && (c1 || c2)) || v12 || v23 || v31 ) { upsdebugx(5, "%s(): determined a 3-phase case", __func__); *num_phases = 3; *inited_phaseinfo = 1; detected_phaseinfo = 1; } else if ( /* We definitely have only one non-zero line */ !v12 && !v23 && !v31 && ( (c0 && !c1 && !c2 && !c3) || (v0 && !v1 && !v2 && !v3) || (c1 && !c2 && !c3) || (!c1 && c2 && !c3) || (!c1 && !c2 && c3) || (v1 && !v2 && !v3) || (!v1 && v2 && !v3) || (!v1 && !v2 && v3) || (v1n && !v2n && !v3n) || (!v1n && v2n && !v3n) || (!v1n && !v2n && v3n) ) ) { *num_phases = 1; *inited_phaseinfo = 1; detected_phaseinfo = 1; upsdebugx(5, "%s(): determined a 1-phase case", __func__); } else { upsdebugx(5, "%s(): could not determine the phase case", __func__); } if (detected_phaseinfo) { const char *oldphases; strncpy(bufrw_ptr, "phases", bufrw_max); oldphases = dstate_getinfo(buf); if (oldphases) { if (atoi(oldphases) == *num_phases) { /* Technically, a bit has changed: we have set the flag which may have been missing before */ upsdebugx(5, "%s(): Nothing changed, with a valid reason; dstate already published with the same value: %s=%s (detected %d)", __func__, buf, oldphases, *num_phases); return 3; } } if ( (*num_phases != old_num_phases) || (!oldphases) ) { if (may_change_dstate) { dstate_setinfo(buf, "%d", *num_phases); upsdebugx(3, "%s(): calculated non-XML value for NUT variable %s was set to %d", __func__, buf, *num_phases); } else { upsdebugx(3, "%s(): calculated non-XML value for NUT variable %s=%d but did not set its dstate (read-only request)", __func__, buf, *num_phases); } return 1; } } upsdebugx(5, "%s(): Nothing changed: could not determine a value", __func__); return 0; } upsdebugx(5, "%s(): Nothing changed, with a valid reason; already inited", __func__); return 2; } /* Dump the data tree (in upsc-like format) to stdout */ /* Actual implementation */ static int dstate_tree_dump(const st_tree_t *node) { int ret; if (!node) { return 1; /* not an error */ } if (node->left) { ret = dstate_tree_dump(node->left); if (!ret) { return 0; /* write failed in the child */ } } printf("%s: %s\n", node->var, node->val); if (node->right) { return dstate_tree_dump(node->right); } return 1; /* everything's OK here ... */ } /* Dump the data tree (in upsc-like format) to stdout */ /* Public interface */ void dstate_dump(void) { const st_tree_t *node; upsdebugx(3, "Entering %s", __func__); node = (const st_tree_t *)dstate_getroot(); dstate_tree_dump(node); } nut-2.8.1/drivers/serial.c0000644000175000017500000003320114501607135012353 00000000000000/* serial.c - common serial port functions for Network UPS Tools drivers Copyright (C) 2003 Russell Kroll 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 2 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, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "common.h" #include "timehead.h" #include "serial.h" #include "main.h" #include "attribute.h" #ifndef WIN32 #include #include #include #endif #include #include #include #include #ifdef HAVE_UU_LOCK #include #endif #include "nut_stdint.h" static unsigned int comm_failures = 0; static void ser_open_error(const char *port) __attribute__((noreturn)); static void ser_open_error(const char *port) { struct stat fs; #ifndef WIN32 struct passwd *user; struct group *group; #endif printf("\n"); printf("Unable to open %s: %s\n\n", port, strerror(errno)); /* check for bad port definitions first */ if (stat(port, &fs)) { printf("Things to try:\n\n"); printf(" - Check 'port=' in ups.conf\n\n"); printf(" - Check owner/permissions of all parts of path\n\n"); fatalx(EXIT_FAILURE, "Fatal error: unusable configuration"); } /* TODO */ #ifndef WIN32 user = getpwuid(getuid()); if (user) printf(" Current user id: %s (%d)\n", user->pw_name, (int) user->pw_uid); user = getpwuid(fs.st_uid); if (user) printf("Serial port owner: %s (%d)\n", user->pw_name, (int) fs.st_uid); group = getgrgid(fs.st_gid); if (group) printf("Serial port group: %s (%d)\n", group->gr_name, (int) fs.st_gid); #endif printf(" Mode of port: %04o\n\n", (int) fs.st_mode & 07777); printf("Things to try:\n\n"); printf(" - Use another port (with the right permissions)\n\n"); printf(" - Fix the port owner/group or permissions on this port\n\n"); printf(" - Run this driver as another user (upsdrvctl -u or 'user=...' in ups.conf).\n"); printf(" See upsdrvctl(8) and ups.conf(5).\n\n"); fatalx(EXIT_FAILURE, "Fatal error: unusable configuration"); } static void lock_set(TYPE_FD_SER fd, const char *port) { int ret; if (INVALID_FD_SER(fd)) { #ifndef WIN32 fatal_with_errno(EXIT_FAILURE, "lock_set: programming error: fd = %d", fd); #else fatal_with_errno(EXIT_FAILURE, "lock_set: programming error: struct = %p", fd); #endif } if (do_lock_port == 0) return; #ifdef HAVE_UU_LOCK ret = uu_lock(xbasename(port)); if (ret != 0) fatalx(EXIT_FAILURE, "Can't uu_lock %s: %s", xbasename(port), uu_lockerr(ret)); #elif defined(HAVE_FLOCK) ret = flock(fd, LOCK_EX | LOCK_NB); if (ret != 0) fatalx(EXIT_FAILURE, "%s is locked by another process", port); #elif defined(HAVE_LOCKF) lseek(fd, 0L, SEEK_SET); ret = lockf(fd, F_TLOCK, 0L); if (ret != 0) fatalx(EXIT_FAILURE, "%s is locked by another process", port); #else NUT_UNUSED_VARIABLE(port); ret = 0; /* Make compiler happy */ ret = ret; upslog_with_errno(LOG_WARNING, "Warning: no locking method is available"); #endif } /* Non fatal version of ser_open */ TYPE_FD_SER ser_open_nf(const char *port) { TYPE_FD_SER fd; fd = open(port, O_RDWR | O_NOCTTY | O_EXCL | O_NONBLOCK); if (INVALID_FD_SER(fd)) { return ERROR_FD_SER; } lock_set(fd, port); return fd; } TYPE_FD_SER ser_open(const char *port) { TYPE_FD_SER res; res = ser_open_nf(port); if (INVALID_FD_SER(res)) { ser_open_error(port); } return res; } int ser_set_speed_nf(TYPE_FD_SER fd, const char *port, speed_t speed) { struct termios tio; NUT_UNUSED_VARIABLE(port); if (tcgetattr(fd, &tio) != 0) { return -1; } tio.c_cflag = CS8 | CLOCAL | CREAD; tio.c_iflag = IGNPAR; tio.c_oflag = 0; tio.c_lflag = 0; tio.c_cc[VMIN] = 1; tio.c_cc[VTIME] = 0; #ifdef HAVE_CFSETISPEED cfsetispeed(&tio, speed); cfsetospeed(&tio, speed); #else #error This system lacks cfsetispeed() and has no other means to set the speed #endif tcflush(fd, TCIFLUSH); tcsetattr(fd, TCSANOW, &tio); return 0; } int ser_set_speed(TYPE_FD_SER fd, const char *port, speed_t speed) { int res; res = ser_set_speed_nf(fd,port,speed); if(res == -1) { fatal_with_errno(EXIT_FAILURE, "tcgetattr(%s)", port); } return 0; } #ifndef WIN32 static int ser_set_control(TYPE_FD_SER fd, int line, int state) { if (state) { return ioctl(fd, TIOCMBIS, &line); } else { return ioctl(fd, TIOCMBIC, &line); } } #endif int ser_set_dtr(TYPE_FD_SER fd, int state) { #ifndef WIN32 return ser_set_control(fd, TIOCM_DTR, state); #else DWORD action; if (state == 0) { action = CLRDTR; } else { action = SETDTR; } /* Success */ if (EscapeCommFunction(fd->handle,action) != 0) { return 0; } return -1; #endif } int ser_set_rts(TYPE_FD_SER fd, int state) { #ifndef WIN32 return ser_set_control(fd, TIOCM_RTS, state); #else DWORD action; if(state == 0) { action = CLRRTS; } else { action = SETRTS; } /* Success */ if( EscapeCommFunction(fd->handle,action) != 0) { return 0; } return -1; #endif } #ifndef WIN32 static int ser_get_control(TYPE_FD_SER fd, int line) { int flags; ioctl(fd, TIOCMGET, &flags); return (flags & line); } #endif int ser_get_dsr(TYPE_FD_SER fd) { #ifndef WIN32 return ser_get_control(fd, TIOCM_DSR); #else int flags; w32_getcomm(fd->handle, &flags); return (flags & TIOCM_DSR); #endif } int ser_get_cts(TYPE_FD_SER fd) { #ifndef WIN32 return ser_get_control(fd, TIOCM_CTS); #else int flags; w32_getcomm(fd->handle, &flags); return (flags & TIOCM_CTS); #endif } int ser_get_dcd(TYPE_FD_SER fd) { #ifndef WIN32 return ser_get_control(fd, TIOCM_CD); #else int flags; w32_getcomm(fd->handle, &flags); return (flags & TIOCM_CD); #endif } int ser_close(TYPE_FD_SER fd, const char *port) { if (INVALID_FD_SER(fd)) { #ifndef WIN32 fatal_with_errno(EXIT_FAILURE, "ser_close: programming error: fd=%d port=%s", fd, port); #else fatal_with_errno(EXIT_FAILURE, "ser_close: programming error: struct=%p port=%s", fd, port); #endif } if (close(fd) != 0) return -1; #ifdef HAVE_UU_LOCK if (do_lock_port) uu_unlock(xbasename(port)); #endif return 0; } ssize_t ser_send_char(TYPE_FD_SER fd, unsigned char ch) { return ser_send_buf_pace(fd, 0, &ch, 1); } static ssize_t send_formatted(TYPE_FD_SER fd, const char *fmt, va_list va, useconds_t d_usec) { int ret; char buf[LARGEBUF]; #ifdef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL #pragma GCC diagnostic push #endif #ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL #pragma GCC diagnostic ignored "-Wformat-nonliteral" #endif #ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_FORMAT_SECURITY #pragma GCC diagnostic ignored "-Wformat-security" #endif ret = vsnprintf(buf, sizeof(buf), fmt, va); #ifdef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL #pragma GCC diagnostic pop #endif if (ret >= (int)sizeof(buf)) { upslogx(LOG_WARNING, "vsnprintf needed more than %d bytes", (int)sizeof(buf)); } return ser_send_buf_pace(fd, d_usec, buf, strlen(buf)); } /* send the results of the format string with d_usec delay after each char */ ssize_t ser_send_pace(TYPE_FD_SER fd, useconds_t d_usec, const char *fmt, ...) { ssize_t ret; va_list ap; va_start(ap, fmt); #ifdef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL #pragma GCC diagnostic push #endif #ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL #pragma GCC diagnostic ignored "-Wformat-nonliteral" #endif #ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_FORMAT_SECURITY #pragma GCC diagnostic ignored "-Wformat-security" #endif ret = send_formatted(fd, fmt, ap, d_usec); #ifdef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL #pragma GCC diagnostic pop #endif va_end(ap); return ret; } /* send the results of the format string with no delay */ ssize_t ser_send(TYPE_FD_SER fd, const char *fmt, ...) { ssize_t ret; va_list ap; va_start(ap, fmt); #ifdef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL #pragma GCC diagnostic push #endif #ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL #pragma GCC diagnostic ignored "-Wformat-nonliteral" #endif #ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_FORMAT_SECURITY #pragma GCC diagnostic ignored "-Wformat-security" #endif ret = send_formatted(fd, fmt, ap, 0); #ifdef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL #pragma GCC diagnostic pop #endif va_end(ap); return ret; } /* send buflen bytes from buf with no delay */ ssize_t ser_send_buf(TYPE_FD_SER fd, const void *buf, size_t buflen) { return ser_send_buf_pace(fd, 0, buf, buflen); } /* send buflen bytes from buf with d_usec delay after each char */ ssize_t ser_send_buf_pace(TYPE_FD_SER fd, useconds_t d_usec, const void *buf, size_t buflen) { ssize_t ret = 0; ssize_t sent; const char *data = buf; assert(buflen < SSIZE_MAX); for (sent = 0; sent < (ssize_t)buflen; sent += ret) { /* Conditions above ensure that (buflen - sent) > 0 below */ ret = write(fd, &data[sent], (d_usec == 0) ? (size_t)((ssize_t)buflen - sent) : 1); if (ret < 1) { return ret; } usleep(d_usec); } return sent; } ssize_t ser_get_char(TYPE_FD_SER fd, void *ch, time_t d_sec, useconds_t d_usec) { /* Per standard below, we can cast here, because required ranges are * effectively the same (and signed -1 for suseconds_t), and at most long: * https://pubs.opengroup.org/onlinepubs/009604599/basedefs/sys/types.h.html */ return select_read(fd, ch, 1, d_sec, (suseconds_t)d_usec); } ssize_t ser_get_buf(TYPE_FD_SER fd, void *buf, size_t buflen, time_t d_sec, useconds_t d_usec) { memset(buf, '\0', buflen); return select_read(fd, buf, buflen, d_sec, (suseconds_t)d_usec); } /* keep reading until buflen bytes are received or a timeout occurs */ ssize_t ser_get_buf_len(TYPE_FD_SER fd, void *buf, size_t buflen, time_t d_sec, useconds_t d_usec) { ssize_t ret; ssize_t recv; char *data = buf; assert(buflen < SSIZE_MAX); memset(buf, '\0', buflen); for (recv = 0; recv < (ssize_t)buflen; recv += ret) { ret = select_read(fd, &data[recv], (size_t)((ssize_t)buflen - recv), d_sec, (suseconds_t)d_usec); if (ret < 1) { return ret; } } return recv; } /* reads a line up to , discarding anything else that may follow, with callouts to the handler if anything matches the alertset */ ssize_t ser_get_line_alert(TYPE_FD_SER fd, void *buf, size_t buflen, char endchar, const char *ignset, const char *alertset, void handler(char ch), time_t d_sec, useconds_t d_usec) { ssize_t i, ret; char tmp[64]; char *data = buf; ssize_t count = 0, maxcount; assert(buflen < SSIZE_MAX && buflen > 0); memset(buf, '\0', buflen); maxcount = (ssize_t)buflen - 1; /* for trailing \0 */ while (count < maxcount) { ret = select_read(fd, tmp, sizeof(tmp), d_sec, (suseconds_t)d_usec); if (ret < 1) { return ret; } for (i = 0; i < ret; i++) { if ((count == maxcount) || (tmp[i] == endchar)) { return count; } if (strchr(ignset, tmp[i])) continue; if (strchr(alertset, tmp[i])) { if (handler) handler(tmp[i]); continue; } data[count++] = tmp[i]; } } return count; } /* as above, only with no alertset handling (just a wrapper) */ ssize_t ser_get_line(TYPE_FD_SER fd, void *buf, size_t buflen, char endchar, const char *ignset, time_t d_sec, useconds_t d_usec) { return ser_get_line_alert(fd, buf, buflen, endchar, ignset, "", NULL, d_sec, d_usec); } ssize_t ser_flush_in(TYPE_FD_SER fd, const char *ignset, int verbose) { ssize_t ret, extra = 0; char ch; while ((ret = ser_get_char(fd, &ch, 0, 0)) > 0) { if (strchr(ignset, ch)) continue; extra++; if (verbose == 0) continue; if (isprint((unsigned char)ch & 0xFF)) upslogx(LOG_INFO, "ser_flush_in: read char %c", ch); else upslogx(LOG_INFO, "ser_flush_in: read char 0x%02x", ch); } return extra; } int ser_flush_io(TYPE_FD_SER fd) { return tcflush(fd, TCIOFLUSH); } void ser_comm_fail(const char *fmt, ...) { int ret; char why[SMALLBUF]; va_list ap; /* this means we're probably here because select was interrupted */ if (exit_flag != 0) return; /* ignored, since we're about to exit anyway */ comm_failures++; if ((comm_failures == SER_ERR_LIMIT) || ((comm_failures % SER_ERR_RATE) == 0)) { upslogx(LOG_WARNING, "Warning: excessive comm failures, " "limiting error reporting"); } /* once it's past the limit, only log once every SER_ERR_LIMIT calls */ if ((comm_failures > SER_ERR_LIMIT) && ((comm_failures % SER_ERR_LIMIT) != 0)) return; va_start(ap, fmt); #ifdef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL #pragma GCC diagnostic push #endif #ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL #pragma GCC diagnostic ignored "-Wformat-nonliteral" #endif #ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_FORMAT_SECURITY #pragma GCC diagnostic ignored "-Wformat-security" #endif ret = vsnprintf(why, sizeof(why), fmt, ap); #ifdef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL #pragma GCC diagnostic pop #endif va_end(ap); if ((ret < 1) || (ret >= (int) sizeof(why))) upslogx(LOG_WARNING, "ser_comm_fail: vsnprintf needed " "more than %d bytes", (int)sizeof(why)); upslogx(LOG_WARNING, "Communications with UPS lost: %s", why); } void ser_comm_good(void) { if (comm_failures == 0) return; upslogx(LOG_NOTICE, "Communications with UPS re-established"); comm_failures = 0; } nut-2.8.1/drivers/netvision-mib.c0000644000175000017500000002455114500336654013673 00000000000000/* netvision-mib.c - data to monitor Socomec Sicon UPS equipped * with Netvision WEB/SNMP card/external box with NUT * * Copyright (C) * 2004 Thanos Chatziathanassiou * 2012 Manuel Bouyer * 2015 Arnaud Quette * * 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 2 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, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #include "netvision-mib.h" #define NETVISION_MIB_VERSION "0.44" #define NETVISION_SYSOID ".1.3.6.1.4.1.4555.1.1.1" /* SNMP OIDs set */ #define NETVISION_OID_UPS_MIB ".1.3.6.1.4.1.4555.1.1.1.1" #define NETVISION_OID_UPSIDENTMODEL ".1.3.6.1.4.1.4555.1.1.1.1.1.1.0" #define NETVISION_OID_UPSIDENTFWVERSION ".1.3.6.1.4.1.4555.1.1.1.1.1.2.0" #define NETVISION_OID_UPSIDENTAGENTSWVERSION ".1.3.6.1.4.1.4555.1.1.1.1.1.3.0" #define NETVISION_OID_UPSIDENTUPSSERIALNUMBER ".1.3.6.1.4.1.4555.1.1.1.1.1.4.0" /* UPS Battery */ #define NETVISION_OID_BATTERYSTATUS ".1.3.6.1.4.1.4555.1.1.1.1.2.1.0" static info_lkp_t netvision_batt_info[] = { { 2, "", NULL, NULL }, /* battery normal */ { 3, "LB", NULL, NULL }, /* battery low */ { 4, "LB", NULL, NULL }, /* battery depleted */ { 5, "DISCHRG", NULL, NULL }, /* battery discharging */ { 6, "RB", NULL, NULL }, /* battery failure */ { 0, NULL, NULL, NULL } }; /* Battery status: upsAlarmOnBattery */ static info_lkp_t netvision_onbatt_info[] = { { 0, "OL", NULL, NULL }, /* Online */ { 1, "OB", NULL, NULL }, /* On battery */ { 0, NULL, NULL, NULL } }; #define NETVISION_OID_SECONDSONBATTERY ".1.3.6.1.4.1.4555.1.1.1.1.2.2.0" #define NETVISION_OID_BATT_RUNTIME_REMAINING ".1.3.6.1.4.1.4555.1.1.1.1.2.3.0" #define NETVISION_OID_BATT_CHARGE ".1.3.6.1.4.1.4555.1.1.1.1.2.4.0" #define NETVISION_OID_BATT_VOLTS ".1.3.6.1.4.1.4555.1.1.1.1.2.5.0" #define NETVISION_OID_INPUT_NUM_LINES ".1.3.6.1.4.1.4555.1.1.1.1.3.1.0" /* 1phase or 3phase UPS input */ #define NETVISION_OID_INPUT_FREQ ".1.3.6.1.4.1.4555.1.1.1.1.3.2.0" #define NETVISION_OID_OUTPUT_NUM_LINES ".1.3.6.1.4.1.4555.1.1.1.1.4.3.0" /* 1phase or 3phase UPS output */ #define NETVISION_OID_OUTPUT_FREQ ".1.3.6.1.4.1.4555.1.1.1.1.4.2.0" #define NETVISION_OID_BYPASS_FREQ ".1.3.6.1.4.1.4555.1.1.1.1.5.1.0" #define NETVISION_OID_BYPASS_NUM_LINES ".1.3.6.1.4.1.4555.1.1.1.1.5.2.0" /* 1phase or 3phase UPS input */ /* three phase ups provide input/output/load for each phase in case of one-phase output, only _P1 should be used */ #define NETVISION_OID_OUT_VOLTAGE_P1 ".1.3.6.1.4.1.4555.1.1.1.1.4.4.1.2.1" #define NETVISION_OID_OUT_CURRENT_P1 ".1.3.6.1.4.1.4555.1.1.1.1.4.4.1.3.1" #define NETVISION_OID_OUT_LOAD_PCT_P1 ".1.3.6.1.4.1.4555.1.1.1.1.4.4.1.4.1" #define NETVISION_OID_IN_VOLTAGE_P1 ".1.3.6.1.4.1.4555.1.1.1.1.3.3.1.5.1" #define NETVISION_OID_IN_CURRENT_P1 ".1.3.6.1.4.1.4555.1.1.1.1.3.3.1.3.1" #define NETVISION_OID_BY_VOLTAGE_P1 ".1.3.6.1.4.1.4555.1.1.1.1.5.3.1.2.1" #define NETVISION_OID_BY_CURRENT_P1 ".1.3.6.1.4.1.4555.1.1.1.1.5.3.1.3.1" #define NETVISION_OID_OUT_VOLTAGE_P2 ".1.3.6.1.4.1.4555.1.1.1.1.4.4.1.2.2" #define NETVISION_OID_OUT_CURRENT_P2 ".1.3.6.1.4.1.4555.1.1.1.1.4.4.1.3.2" #define NETVISION_OID_OUT_LOAD_PCT_P2 ".1.3.6.1.4.1.4555.1.1.1.1.4.4.1.4.2" #define NETVISION_OID_IN_VOLTAGE_P2 ".1.3.6.1.4.1.4555.1.1.1.1.3.3.1.5.2" #define NETVISION_OID_IN_CURRENT_P2 ".1.3.6.1.4.1.4555.1.1.1.1.3.3.1.3.2" #define NETVISION_OID_BY_VOLTAGE_P2 ".1.3.6.1.4.1.4555.1.1.1.1.5.3.1.2.2" #define NETVISION_OID_BY_CURRENT_P2 ".1.3.6.1.4.1.4555.1.1.1.1.5.3.1.3.2" #define NETVISION_OID_OUT_VOLTAGE_P3 ".1.3.6.1.4.1.4555.1.1.1.1.4.4.1.2.3" #define NETVISION_OID_OUT_CURRENT_P3 ".1.3.6.1.4.1.4555.1.1.1.1.4.4.1.3.3" #define NETVISION_OID_OUT_LOAD_PCT_P3 ".1.3.6.1.4.1.4555.1.1.1.1.4.4.1.4.3" #define NETVISION_OID_IN_VOLTAGE_P3 ".1.3.6.1.4.1.4555.1.1.1.1.3.3.1.5.3" #define NETVISION_OID_IN_CURRENT_P3 ".1.3.6.1.4.1.4555.1.1.1.1.3.3.1.3.3" #define NETVISION_OID_BY_VOLTAGE_P3 ".1.3.6.1.4.1.4555.1.1.1.1.5.3.1.2.3" #define NETVISION_OID_BY_CURRENT_P3 ".1.3.6.1.4.1.4555.1.1.1.1.5.3.1.3.3" #define NETVISION_OID_OUTPUT_SOURCE ".1.3.6.1.4.1.4555.1.1.1.1.4.1.0" #define NETVISION_OID_CONTROL_STATUS ".1.3.6.1.4.1.4555.1.1.1.1.8.1" #define NETVISION_OID_CONTROL_SHUTDOWN_DELAY ".1.3.6.1.4.1.4555.1.1.1.1.8.2" static info_lkp_t netvision_output_info[] = { { 1, "", NULL, NULL }, /* output source other */ { 2, "", NULL, NULL }, /* output source none */ { 3, "OL", NULL, NULL }, /* output source normal */ { 4, "OL BYPASS", NULL, NULL }, /* output source bypass */ { 5, "OB", NULL, NULL }, /* output source battery */ { 6, "OL BOOST", NULL, NULL }, /* output source booster */ { 7, "OL TRIM", NULL, NULL }, /* output source reducer */ { 8, "OL", NULL, NULL }, /* output source standby */ { 9, "", NULL, NULL }, /* output source ecomode */ { 0, NULL, NULL, NULL } }; /* Snmp2NUT lookup table */ static snmp_info_t netvision_mib[] = { /* standard MIB items */ { "device.description", ST_FLAG_STRING | ST_FLAG_RW, SU_INFOSIZE, ".1.3.6.1.2.1.1.1.0", NULL, SU_FLAG_OK, NULL }, { "device.contact", ST_FLAG_STRING | ST_FLAG_RW, SU_INFOSIZE, ".1.3.6.1.2.1.1.4.0", NULL, SU_FLAG_OK, NULL }, { "device.location", ST_FLAG_STRING | ST_FLAG_RW, SU_INFOSIZE, ".1.3.6.1.2.1.1.6.0", NULL, SU_FLAG_OK, NULL }, { "ups.mfr", ST_FLAG_STRING, SU_INFOSIZE, NETVISION_OID_UPSIDENTAGENTSWVERSION, "SOCOMEC SICON UPS", SU_FLAG_STATIC | SU_FLAG_OK, NULL }, { "ups.model", ST_FLAG_STRING, SU_INFOSIZE, NETVISION_OID_UPSIDENTMODEL, "Generic SNMP UPS", SU_FLAG_STATIC | SU_FLAG_OK, NULL }, { "ups.serial", ST_FLAG_STRING, SU_INFOSIZE, NETVISION_OID_UPSIDENTUPSSERIALNUMBER, "", SU_FLAG_STATIC | SU_FLAG_OK, NULL }, { "ups.firmware.aux", ST_FLAG_STRING, SU_INFOSIZE, NETVISION_OID_UPSIDENTFWVERSION, "", SU_FLAG_STATIC | SU_FLAG_OK, NULL }, { "ups.status", ST_FLAG_STRING, SU_INFOSIZE, NETVISION_OID_BATTERYSTATUS, "", SU_FLAG_OK | SU_STATUS_BATT, &netvision_batt_info[0] }, { "ups.status", ST_FLAG_STRING, SU_INFOSIZE, NETVISION_OID_OUTPUT_SOURCE, "", SU_FLAG_OK | SU_STATUS_PWR, &netvision_output_info[0] }, /* upsAlarmOnBattery */ { "ups.status", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.4555.1.1.1.1.6.3.2.0", "", SU_FLAG_OK | SU_STATUS_PWR, &netvision_onbatt_info[0] }, /* ups load */ { "ups.load", 0, 1, NETVISION_OID_OUT_LOAD_PCT_P1, 0, SU_INPUT_1, NULL }, /*ups input,output voltage, output frquency phase 1 */ { "input.phases", 0, 1.0, NETVISION_OID_INPUT_NUM_LINES, NULL, 0, NULL }, { "input.frequency", 0, 0.1, NETVISION_OID_INPUT_FREQ, NULL, SU_FLAG_OK, NULL }, { "input.voltage", 0, 0.1, NETVISION_OID_IN_VOLTAGE_P1, NULL, SU_INPUT_1, NULL }, { "input.current", 0, 0.1, NETVISION_OID_IN_CURRENT_P1, NULL, SU_INPUT_1, NULL }, { "input.L1-N.voltage", 0, 0.1, NETVISION_OID_IN_VOLTAGE_P1, NULL, SU_INPUT_3, NULL }, { "input.L1.current", 0, 0.1, NETVISION_OID_IN_CURRENT_P1, NULL, SU_INPUT_3, NULL }, { "input.L2-N.voltage", 0, 0.1, NETVISION_OID_IN_VOLTAGE_P2, NULL, SU_INPUT_3, NULL }, { "input.L2.current", 0, 0.1, NETVISION_OID_IN_CURRENT_P2, NULL, SU_INPUT_3, NULL }, { "input.L3-N.voltage", 0, 0.1, NETVISION_OID_IN_VOLTAGE_P3, NULL, SU_INPUT_3, NULL }, { "input.L3.current", 0, 0.1, NETVISION_OID_IN_CURRENT_P3, NULL, SU_INPUT_3, NULL }, { "output.phases", 0, 1.0, NETVISION_OID_OUTPUT_NUM_LINES, NULL, 0, NULL }, { "output.frequency", 0, 0.1, NETVISION_OID_OUTPUT_FREQ, NULL, SU_FLAG_OK, NULL }, { "output.voltage", 0, 0.1, NETVISION_OID_OUT_VOLTAGE_P1, NULL, SU_OUTPUT_1, NULL }, { "output.current", 0, 0.1, NETVISION_OID_OUT_CURRENT_P1, NULL, SU_OUTPUT_1, NULL }, { "output.load", 0, 1.0, NETVISION_OID_OUT_LOAD_PCT_P1, NULL, SU_OUTPUT_1, NULL }, { "output.L1-N.voltage", 0, 0.1, NETVISION_OID_OUT_VOLTAGE_P1, NULL, SU_OUTPUT_3, NULL }, { "output.L1.current", 0, 0.1, NETVISION_OID_OUT_CURRENT_P1, NULL, SU_OUTPUT_3, NULL }, { "output.L1.power.percent", 0, 1.0, NETVISION_OID_OUT_LOAD_PCT_P1, NULL, SU_OUTPUT_3, NULL }, { "output.L2-N.voltage", 0, 0.1, NETVISION_OID_OUT_VOLTAGE_P2, NULL, SU_OUTPUT_3, NULL }, { "output.L2.current", 0, 0.1, NETVISION_OID_OUT_CURRENT_P2, NULL, SU_OUTPUT_3, NULL }, { "output.L2.power.percent", 0, 1.0, NETVISION_OID_OUT_LOAD_PCT_P2, NULL, SU_OUTPUT_3, NULL }, { "output.L3-N.voltage", 0, 0.1, NETVISION_OID_OUT_VOLTAGE_P3, NULL, SU_OUTPUT_3, NULL }, { "output.L3.current", 0, 0.1, NETVISION_OID_OUT_CURRENT_P3, NULL, SU_OUTPUT_3, NULL }, { "output.L3.power.percent", 0, 1.0, NETVISION_OID_OUT_LOAD_PCT_P3, NULL, SU_OUTPUT_3, NULL }, { "input.bypass.phases", 0, 1.0, NETVISION_OID_BYPASS_NUM_LINES, NULL, 0, NULL }, { "input.bypass.frequency", 0, 0.1, NETVISION_OID_BYPASS_FREQ, NULL, SU_FLAG_OK, NULL }, { "input.bypass.voltage", 0, 0.1, NETVISION_OID_BY_VOLTAGE_P1, NULL, SU_BYPASS_1, NULL }, { "input.bypass.current", 0, 0.1, NETVISION_OID_BY_CURRENT_P1, NULL, SU_BYPASS_1, NULL }, { "input.bypass.L1-N.voltage", 0, 0.1, NETVISION_OID_BY_VOLTAGE_P1, NULL, SU_BYPASS_3, NULL }, { "input.bypass.L1.current", 0, 0.1, NETVISION_OID_BY_CURRENT_P1, NULL, SU_BYPASS_3, NULL }, { "input.bypass.L2-N.voltage", 0, 0.1, NETVISION_OID_BY_VOLTAGE_P2, NULL, SU_BYPASS_3, NULL }, { "input.bypass.L2.current", 0, 0.1, NETVISION_OID_BY_CURRENT_P2, NULL, SU_BYPASS_3, NULL }, { "input.bypass.L3-N.voltage", 0, 0.1, NETVISION_OID_BY_VOLTAGE_P3, NULL, SU_BYPASS_3, NULL }, { "input.bypass.L3.current", 0, 0.1, NETVISION_OID_BY_CURRENT_P3, NULL, SU_BYPASS_3, NULL }, /* battery info */ { "battery.charge", 0, 1, NETVISION_OID_BATT_CHARGE, "", SU_FLAG_OK, NULL }, { "battery.voltage", 0, 0.1, NETVISION_OID_BATT_VOLTS, "", SU_FLAG_OK, NULL }, { "battery.runtime", 0, 60, NETVISION_OID_BATT_RUNTIME_REMAINING, "", SU_FLAG_OK, NULL }, /* end of structure. */ { NULL, 0, 0, NULL, NULL, 0, NULL } }; mib2nut_info_t netvision = { "netvision", NETVISION_MIB_VERSION, NULL, NETVISION_OID_UPSIDENTMODEL, netvision_mib, NETVISION_SYSOID, NULL }; nut-2.8.1/drivers/rhino.c0000644000175000017500000004613114501607135012221 00000000000000/* rhino.c - driver for Microsol Rhino UPS hardware Copyright (C) 2004 Silvino B. Magalhães 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 2 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, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 2004/11/13 - Version 0.10 - Initial release 2005/07/07 - Version 0.20 - Initial rhino commands tests 2005/10/25 - Version 0.30 - Operational-1 release 2005/10/26 - Version 0.40 - Operational-2 release 2005/11/29 - Version 0.50 - rhino commands release http://www.microsol.com.br */ #include "config.h" /* must be the first header */ #include #include "main.h" #include "serial.h" #include "nut_float.h" #include "nut_stdint.h" #include "timehead.h" #define DRIVER_NAME "Microsol Rhino UPS driver" #define DRIVER_VERSION "0.53" /* driver description structure */ upsdrv_info_t upsdrv_info = { DRIVER_NAME, DRIVER_VERSION, "Silvino B. Magalhaes ", DRV_STABLE, { NULL } }; #define UPSDELAY 500 /* 0.5 ms delay */ typedef int bool_t; #define false 0 #define true 1 /* rhino commands */ #define CMD_INON 0x0001 #define CMD_INOFF 0x0002 #define CMD_SHUT 0x0004 #define CMD_OUTON 0x0003 #define CMD_OUTOFF 0x0004 #define CMD_PASSON 0x0005 #define CMD_PASSOFF 0x0006 #define CMD_UPSCONT 0x0053 /* xoff - xon protocol */ #define _SOH = 0x01; /* start of header */ #define _EOT = 0x04; /* end of transmission */ #define _ACK = 0x06; /* acknoledge (positive) */ #define _DLE = 0x10; /* data link escape */ #define _XOn = 0x11; /* transmit on */ #define _XOff = 0x13; /* transmit off */ #define _NAK = 0x15; /* negative acknoledge */ #define _SYN = 0x16; /* synchronous idle */ #define _CAN = 0x18; /* cancel */ static int const pacsize = 37; /* size of receive data package */ /* autonomy calcule */ static double const AmpH = 40; /* Amperes-hora da bateria */ static double const VbatMin = 126; /* Tensão mínina das baterias */ static double const VbatNom = 144; /* Tensão nominal das baterias */ static double const FM = 0.32; /* Fator multiplicativo de correção da autonomia */ static double const FA = -2; /* Fator aditivo de correção da autonomia */ static double const ConstInt = 250; /* Consumo interno sem o carregador */ static double const Vin = 220; /* Tensão de entrada */ static int Day, Month, Year; static int dian=0, mesn=0, anon=0, weekn=0; static int ihour,imin, isec; /* unsigned char DaysOnWeek; */ /* char seman[4]; */ /* int FExpansaoBateria; */ /* internal variables */ /* package handshake variables */ /* int ContadorEstouro; */ static bool_t detected; static bool_t SourceFail, Out110, RedeAnterior, OcorrenciaDeFalha; static bool_t RetornoDaRede, SuperAquecimento, SuperAquecimentoAnterior; static bool_t OverCharge, OldOverCharge, CriticBatt, OldCritBatt; static bool_t Flag_inversor, BypassOn, InputOn, OutputOn; static bool_t LowBatt, oldInversorOn; /* data vetor from received and configuration data package - not used yet unsigned char Dados[ 161 ]; */ /* identification group */ static int RhinoModel; /*, imodel; */ static int PotenciaNominal, PowerFactor; /* input group */ static double AppPowerIn, UtilPowerIn, InFreq, InCurrent; static double LimInfEntrada, LimSupEntrada, ValorNominalEntrada; static int FatorPotEntrada; /* output group */ static double OutVoltage, InVoltage, OutCurrent, AppPowerOut; static double UtilPowerOut, OutFreq, LimInfSaida, LimSupSaida, ValorNominalSaida; static int FatorPotSaida; /* battery group */ static int Autonomy, Waiting; static double BattVoltage, Temperature, LimInfBattSrc, LimSupBattSrc; static double LimInfBattInv, LimSupBattInv, BattNonValue; /* general group */ static int BoostVolt, Rendimento; /* status group */ static unsigned char StatusEntrada, StatusSaida, StatusBateria; /* events group */ static unsigned char EventosRede, EventosSaida, EventosBateria; /* Grupo de Programação */ /* Methods */ static void ScanReceivePack(void); static int AutonomyCalc( int ); static void CommReceive(const unsigned char*, ssize_t); static void getbaseinfo(void); static void getupdateinfo(void); static unsigned char RecPack[37]; /* comment on english language */ /* #define PORTUGUESE */ /* The following Portuguese strings are in UTF-8. */ #ifdef PORTUGUESE #define M_UNKN "Modêlo rhino desconhecido\n" #define NO_RHINO "Rhino não detectado! abortando ...\n" #define UPS_DATE "Data no UPS %4d/%02d/%02d\n" #define SYS_DATE "Data do Sistema %4d/%02d/%02d dia da semana %s\n" #define ERR_PACK "Pacote errado\n" #define NO_EVENT "Não há eventos\n" #define UPS_TIME "Hora interna UPS %0d:%02d:%02d\n" #else #define M_UNKN "Unknown rhino model\n" #define NO_RHINO "Rhino not detected! aborting ...\n" #define UPS_DATE "UPS Date %4d/%02d/%02d\n" #define SYS_DATE "System Date %4d/%02d/%02d day of week %s\n" #define ERR_PACK "Wrong package\n" #define NO_EVENT "No events\n" #define UPS_TIME "UPS internal Time %0d:%02d:%02d\n" #endif static int AutonomyCalc( int ia ) /* all models */ { int result = 0; double auton, calc, currin; if( ia ) { if( d_equal(BattVoltage, 0) ) result = 0; else { calc = ( OutVoltage * OutCurrent )* 1.0 / ( 0.08 * BattVoltage ); auton = pow( calc, 1.18 ); if( d_equal(auton, 0) ) result = 0; else { auton = 1.0 / auton; auton = auton * 11.07; calc = ( BattVoltage * 1.0 / 10 ) - 168; result = (int) ( auton * calc * 2.5 ); } } } else { currin = ( UtilPowerOut + ConstInt ) *1.0 / Vin; auton = ( ( ( AmpH *1.0 / currin ) * 60 * ( ( BattVoltage - VbatMin ) * 1.0 /( VbatNom - VbatMin ) ) * FM ) + FA ); if( ( BattVoltage > 129 ) && ( BattVoltage < 144 ) ) result = 133; else result = (int) auton; } return result; } /* Treat received package */ static void ScanReceivePack( void ) { /* model independent data */ Year = RecPack[31] + ( RecPack[32] * 100 ); Month = RecPack[30]; Day = RecPack[29]; /* UPS internal time */ ihour = RecPack[26]; imin = RecPack[27]; isec = RecPack[28]; /* Flag1 */ /* SobreTemp = ( ( 0x01 & RecPack[33]) = 0x01 ); */ /* OutputOn = ( ( 0x02 & RecPack[33]) = 0x02 ); OutputOn */ /* InputOn = ( ( 0x04 & RecPack[33]) = 0x04 ); InputOn */ /* ByPassOn = ( ( 0x08 & RecPack[33]) = 0x08 ); BypassOn */ /* Auto_HAB = ( ( 0x10 & RecPack[33]) = 0x10 ); */ /* Timer_HAB = ( ( 0x20 & RecPack[33]) = 0x20 ); */ /* Boost_Ligado = ( ( 0x40 & RecPack[33]) = 0x40 ); */ /* Bateria_Desc = ( ( 0x80 & RecPack[33]) = 0x80 ); */ /* Flag2 */ /* Quad_Ant_Ent = ( ( 0x01 & RecPack[34]) = 0x01 ); */ /* Quadratura = ( ( 0x02 & RecPack[34]) = 0x02 ); */ /* Termino_XMODEM = ( ( 0x04 & RecPack[34]) = 0x04 ); */ /* Em_Sincronismo = ( ( 0x08 & RecPack[34]) = 0x08 ); */ /* Out110 = ( ( 0x10 & RecPack[34]) = 0x10 ); Out110 */ /* Exec_Beep = ( ( 0x20 & RecPack[34]) = 0x20 ); */ /* LowBatt = ( ( 0x40 & RecPack[34]) = 0x40 ); LowBatt */ /* Boost_Sobre = ( ( 0x80 & RecPack[34]) = 0x80 ); */ /* Flag3 */ /* OverCharge = ( ( 0x01 & RecPack[35]) = 0x01 ); OverCharge */ /* SourceFail = ( ( 0x02 & RecPack[35]) = 0x02 ); SourceFail */ /* RedeAnterior = ( ( 0x04 & RecPack[35]) = 0x04 ); */ /* Cmd_Executado = ( ( 0x08 & RecPack[35]) = 0x08 ); */ /* Exec_Autoteste = ( ( 0x10 & RecPack[35]) = 0x10 ); */ /* Quad_Ant_Sai = ( ( 0x20 & RecPack[35]) = 0x20 ); */ /* ComandoSerial = ( ( 0x40 & RecPack[35]) = 0x40 ); */ /* SobreTensao = ( ( 0x80 & RecPack[35]) = 0x80 ); */ OutputOn = ( ( 0x02 & RecPack[33] ) == 0x02 ); InputOn = ( ( 0x04 & RecPack[33] ) == 0x04 ); BypassOn = ( ( 0x08 & RecPack[33] ) == 0x08 ); Out110 = ( ( 0x10 & RecPack[34] ) == 0x10 ); LowBatt = ( ( 0x40 & RecPack[34] ) == 0x40 ); OverCharge = ( ( 0x01 & RecPack[35] ) == 0x01 ); SourceFail = ( ( 0x02 & RecPack[35] ) == 0x02 ); /* model dependent data read */ PowerFactor = 800; if( RecPack[0] == 0xC2 ) { LimInfBattSrc = 174; LimSupBattSrc = 192;/* 180????? carregador eh 180 (SCOPOS) */ LimInfBattInv = 174; LimSupBattInv = 192;/* 170????? (SCOPOS) */ } else { LimInfBattSrc = 138; LimSupBattSrc = 162;/* 180????? carregador eh 180 (SCOPOS) */ LimInfBattInv = 126; LimSupBattInv = 156;/* 170????? (SCOPOS) */ } BattNonValue = 144; /* VersaoInterna = "R10" + IntToStr( RecPack[1] ); */ InVoltage = RecPack[2]; InCurrent = RecPack[3]; UtilPowerIn = RecPack[4] + RecPack[5] * 256; AppPowerIn = RecPack[6] + RecPack[7] * 256; FatorPotEntrada = RecPack[8]; InFreq = ( RecPack[9] + RecPack[10] * 256 ) * 1.0 / 10; OutVoltage = RecPack[11]; OutCurrent = RecPack[12]; UtilPowerOut = RecPack[13] + RecPack[14] * 256; AppPowerOut = RecPack[15] + RecPack[16] * 256; FatorPotSaida = RecPack[17]; OutFreq = ( RecPack[18] + RecPack[19] * 256 ) * 1.0 / 10; BattVoltage = RecPack[20]; BoostVolt = RecPack[21] + RecPack[22] * 256; Temperature = ( 0x7F & RecPack[23] ); Rendimento = RecPack[24]; /* model independent data */ if( ( BattVoltage < LimInfBattInv ) ) CriticBatt = true; if( BypassOn ) OutVoltage = ( InVoltage * 1.0 / 2 ) + 5; if( SourceFail && RedeAnterior ) /* falha pela primeira vez */ OcorrenciaDeFalha = true; if( !( SourceFail ) && !( RedeAnterior ) ) /* retorno da rede */ RetornoDaRede = true; if( RedeAnterior == !( SourceFail ) ) { RetornoDaRede = false; OcorrenciaDeFalha = false; } RedeAnterior = !( SourceFail ); LimInfSaida = 75; LimSupSaida = 150; ValorNominalSaida = 110; LimInfEntrada = 190; LimSupEntrada = 250; ValorNominalEntrada = 220; if( SourceFail ) { StatusEntrada = 2; RecPack[8] = 200; /* ?????????????????????????????????? */ } else { StatusEntrada = 1; RecPack[8] = 99; /* ??????????????????????????????????? */ } if( OutputOn ) /* Output Status */ StatusSaida = 2; else StatusSaida = 1; if( OverCharge ) StatusSaida = 3; if( CriticBatt ) /* Battery Status */ StatusBateria = 4; else StatusBateria = 1; EventosRede = 0; if( OcorrenciaDeFalha ) EventosRede = 1; if( RetornoDaRede ) EventosRede = 2; /* verify InversorOn */ if( Flag_inversor ) { oldInversorOn = InputOn; Flag_inversor = false; } EventosSaida = 0; if( InputOn && !( oldInversorOn ) ) EventosSaida = 26; if( oldInversorOn && !( InputOn ) ) EventosSaida = 27; oldInversorOn = InputOn; if( SuperAquecimento && !( SuperAquecimentoAnterior ) ) EventosSaida = 12; if( SuperAquecimentoAnterior && !( SuperAquecimento ) ) EventosSaida = 13; SuperAquecimentoAnterior = SuperAquecimento; EventosBateria = 0; OldCritBatt = CriticBatt; if( OverCharge && !( OldOverCharge ) ) EventosSaida = 10; if( OldOverCharge && !( OverCharge ) ) EventosSaida = 11; OldOverCharge = OverCharge; /* autonomy calc. */ if( RecPack[ 0 ] == 0xC2 ) Autonomy = AutonomyCalc( 1 ); else Autonomy = AutonomyCalc( 0 ); } static void CommReceive(const unsigned char *bufptr, ssize_t size) { int i, i_end, CheckSum, chk; if( size == 37 ) Waiting = 0; printf("CommReceive size = %" PRIiSIZE " waiting = %d\n", size, Waiting ); switch( Waiting ) { /* normal package */ case 0: { if( size == 37 ) { i_end = 37; for( i = 0 ; i < i_end ; ++i ) { RecPack[i] = *bufptr; bufptr++; } /* CheckSum verify */ CheckSum = 0; i_end = 36; for( i = 0 ; i < i_end ; ++i ) { chk = RecPack[ i ]; CheckSum = CheckSum + chk; } CheckSum = CheckSum % 256; ser_flush_in(upsfd,"",0); /* clean port */ /* correct package */ if( ( RecPack[0] == 0xC0 || RecPack[0] == 0xC1 || RecPack[0] == 0xC2 || RecPack[0] == 0xC3 ) && ( RecPack[ 36 ] == CheckSum ) ) { if(!(detected)) { RhinoModel = RecPack[0]; detected = true; } switch( RhinoModel ) { case 0xC0: case 0xC1: case 0xC2: case 0xC3: { ScanReceivePack(); break; } default: { printf( M_UNKN ); break; } } } } break; } case 1: { /* dumping package, nothing to do yet */ Waiting = 0; break; } } Waiting = 0; } static ssize_t send_command( unsigned char cmd ) { static const size_t sizes = 19, iend = 18; size_t i, kount; /*, j, uc; */ unsigned char chk, checksum = 0; ssize_t ret = -1; unsigned char ch, *psend = NULL; if ( !(psend = xmalloc(sizeof(char) * sizes)) ) { upslogx(LOG_ERR, "send_command() failed to allocate buffer"); return -1; } /* mounting buffer to send */ for(i = 0; i < iend; i++ ) { if ( i == 0 ) chk = 0x01; else { if( i == 1 ) chk = cmd; else chk = 0x00; /* 0x20; */ } ch = chk; psend[i] = ch; /* psend[0 - 17] */ if( i > 0 ) /* psend[0] not computed */ checksum = checksum + chk; } ch = checksum; ch = (~( ch) ); /* not ch */ psend[iend] = ch; /* send five times the command */ kount = 0; while ( kount < 5 ) { /* ret = ser_send_buf_pace(upsfd, UPSDELAY, psend, sizes ); */ /* optional delay */ for(i = 0 ; i < sizes ; i++) { ret = ser_send_char( upsfd, psend[i] ); /* usleep ( UPSDELAY ); sending without delay */ } usleep( UPSDELAY ); /* delay between sent command */ kount++; } free (psend); return ret; } static void sendshut( void ) { int i; for(i=0; i < 30000; i++) usleep( UPSDELAY ); /* 15 seconds delay */ if ( send_command( CMD_SHUT ) < 1 ) upslogx(LOG_ERR, "Ups shutdown command sending failed"); else upslogx(LOG_NOTICE, "Ups shutdown command sent"); printf("Ups shutdown command sent\n"); } static void getbaseinfo(void) { unsigned char temp[256]; unsigned char Pacote[37]; ssize_t tam, i, j=0; time_t tmt; struct tm *now; struct tm tmbuf; const char *Model; time( &tmt ); now = localtime_r( &tmt, &tmbuf ); dian = now->tm_mday; mesn = now->tm_mon+1; anon = now->tm_year+1900; weekn = now->tm_wday; /* trying detect rhino model */ while ( ( !detected ) && ( j < 10 ) ) { temp[0] = 0; /* flush temp buffer */ tam = ser_get_buf_len(upsfd, temp, pacsize, 3, 0); if( tam == 37 ) { for( i = 0 ; i < tam ; i++ ) { Pacote[i] = temp[i]; } } j++; if( tam == 37) CommReceive(Pacote, tam); else CommReceive(temp, tam); } if( (!detected) ) { fatalx(EXIT_FAILURE, NO_RHINO ); } switch( RhinoModel ) { case 0xC0: { Model = "Rhino 20.0 kVA"; PotenciaNominal = 20000; break; } case 0xC1: { Model = "Rhino 10.0 kVA"; PotenciaNominal = 10000; break; } case 0xC2: { Model = "Rhino 6.0 kVA"; PotenciaNominal = 6000; break; } case 0xC3: { Model = "Rhino 7.5 kVA"; PotenciaNominal = 7500; break; } default: { Model = "Rhino unknown model"; PotenciaNominal = 0; break; } } /* manufacturer and model */ dstate_setinfo("ups.mfr", "%s", "Microsol"); dstate_setinfo("ups.model", "%s", Model); /* dstate_setinfo("input.transfer.low", "%03.1f", InDownLim); LimInfBattInv ? dstate_setinfo("input.transfer.high", "%03.1f", InUpLim); LimSupBattInv ? */ dstate_addcmd("shutdown.stayoff"); /* CMD_SHUT */ /* there is no reserved words for CMD_INON and CMD_INOFF yet */ /* dstate_addcmd("input.on"); */ /* CMD_INON = 1 */ /* dstate_addcmd("input.off"); */ /* CMD_INOFF = 2 */ dstate_addcmd("load.on"); /* CMD_OUTON = 3 */ dstate_addcmd("load.off"); /* CMD_OUTOFF = 4 */ dstate_addcmd("bypass.start"); /* CMD_PASSON = 5 */ dstate_addcmd("bypass.stop"); /* CMD_PASSOFF = 6 */ printf("Detected %s on %s\n", dstate_getinfo("ups.model"), device_path); } static void getupdateinfo(void) { unsigned char temp[256]; ssize_t tam; temp[0] = 0; /* flush temp buffer */ tam = ser_get_buf_len(upsfd, temp, pacsize, 3, 0); CommReceive(temp, tam); } static int instcmd(const char *cmdname, const char *extra) { ssize_t ret = 0; if (!strcasecmp(cmdname, "shutdown.stayoff")) { /* shutdown now (one way) */ /* send_command( CMD_SHUT ); */ sendshut(); return STAT_INSTCMD_HANDLED; } if (!strcasecmp(cmdname, "load.on")) { /* liga Saida */ ret = send_command( 3 ); if ( ret < 1 ) upslogx(LOG_ERR, "send_command 3 failed"); return STAT_INSTCMD_HANDLED; } if (!strcasecmp(cmdname, "load.off")) { /* desliga Saida */ ret = send_command( 4 ); if ( ret < 1 ) upslogx(LOG_ERR, "send_command 4 failed"); return STAT_INSTCMD_HANDLED; } if (!strcasecmp(cmdname, "bypass.start")) { /* liga Bypass */ ret = send_command( 5 ); if ( ret < 1 ) upslogx(LOG_ERR, "send_command 5 failed"); return STAT_INSTCMD_HANDLED; } if (!strcasecmp(cmdname, "bypass.stop")) { /* desliga Bypass */ ret = send_command( 6 ); if ( ret < 1 ) upslogx(LOG_ERR, "send_command 6 failed"); return STAT_INSTCMD_HANDLED; } upslogx(LOG_NOTICE, "instcmd: unknown command [%s] [%s]", cmdname, extra); return STAT_INSTCMD_UNKNOWN; } void upsdrv_initinfo(void) { getbaseinfo(); upsh.instcmd = instcmd; } void upsdrv_updateinfo(void) { getupdateinfo(); /* new package for updates */ dstate_setinfo("output.voltage", "%03.1f", OutVoltage); dstate_setinfo("input.voltage", "%03.1f", InVoltage); dstate_setinfo("battery.voltage", "%02.1f", BattVoltage); /* output and bypass tests */ if( OutputOn ) dstate_setinfo("outlet.switchable", "%s", "yes"); else dstate_setinfo("outlet.switchable", "%s", "no"); if( BypassOn ) dstate_setinfo("outlet.1.switchable", "%s", "yes"); else dstate_setinfo("outlet.1.switchable", "%s", "no"); status_init(); if (!SourceFail ) status_set("OL"); /* on line */ else status_set("OB"); /* on battery */ if (Autonomy < 5 ) status_set("LB"); /* low battery */ status_commit(); dstate_setinfo("ups.temperature", "%2.2f", Temperature); dstate_setinfo("input.frequency", "%2.1f", InFreq); dstate_dataok(); } /* power down the attached load immediately */ void upsdrv_shutdown(void) { /* basic idea: find out line status and send appropriate command */ /* on line: send normal shutdown, ups will return by itself on utility */ /* on battery: send shutdown+return, ups will cycle and return soon */ if (!SourceFail) /* on line */ { /* FIXME: Both legs of the if-clause send CMD_SHUT, where is the "forcing"? */ printf("On line, forcing shutdown command...\n"); /* send_command( CMD_SHUT ); */ sendshut(); } else { printf("On battery, sending normal shutdown command...\n"); /* send_command( CMD_SHUT ); */ sendshut(); } } void upsdrv_help(void) { } void upsdrv_makevartable(void) { addvar(VAR_VALUE, "battext", "Battery Extension (0-80)min"); } void upsdrv_initups(void) { upsfd = ser_open(device_path); ser_set_speed(upsfd, device_path, B19200); /* dtr and rts setting */ ser_set_dtr(upsfd, 1); ser_set_rts(upsfd, 0); } void upsdrv_cleanup(void) { ser_close(upsfd, device_path); } nut-2.8.1/drivers/eaton-ats16-nm2-mib.h0000644000175000017500000000216314500336654014411 00000000000000/* eaton_ats16-nm2-mib.h - subdriver to monitor Eaton ATS16 NM2 SNMP devices with NUT * * Copyright (C) * 2011-2012 Arnaud Quette * 2016-2017 Eaton (author: Arnaud Quette ) * * 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 2 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, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef EATON_ATS16_NM2_MIB_H #define EATON_ATS16_NM2_MIB_H #include "main.h" #include "snmp-ups.h" extern mib2nut_info_t eaton_ats16_nm2; #endif /* EATON_ATS16_NM2_MIB_H */ nut-2.8.1/drivers/safenet.h0000644000175000017500000000440014500336654012531 00000000000000/* * safenet.h - defines/macros for the safenet driver * * Copyright (C) 2003 Arjen de Korte * * 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 2 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, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef NUT_SAFENET_H_SEEN #define NUT_SAFENET_H_SEEN 1 /* * The following commands where traced on the serial port. From these, the * COM_POLL_STAT command is just an example of how this command looks. * Inside the driver, we'll overwrite the default with specially crafted * 'random' data (see the comments). */ #define COM_INITIALIZE "ZCADLIOPERJD\r" #define COM_MAINS_TEST "ZFSDERBTRFGY\r" #define COM_BATT_TEST "ZAVLEJFICOPR\r" #define COM_STOP_TEST "ZGWLEJFICOPR\r" #define COM_TOGGLE_BEEP "ZELWSABPMBEQ\r" #define COM_POLL_STAT "ZHDGFGDJELBC\r" /* * The following command is "ZBASdddWLPGE\r", where 'ddd' equals the number of * seconds delay before the UPS switches off. Value must be greater than or * equal to 1. Mapping of the numerals is 0=A, 1=B, 2=C, etc. */ #define SHUTDOWN_RETURN "ZBASAAAWLPGE\r" /* shutdown in 1 second */ /* * The following commands are "ZAFdddRrrrrO\r", where 'ddd' equals the number * of seconds delay before the UPS switches off and 'rrrr' the number of * minutes before it restarts. Both values must be greater than or equal to 1. * Mapping of the numerals is 0=A, 1=B, 2=C, etc. */ #define SHUTDOWN_REBOOT "ZAFAAARAAAAO\r" /* shutdown in 1 second, return after 1 minute */ struct safenet { char onbattery; char dunno_02; char batterylow; char overload; char dunno_05; char silenced; char batteryfail; char systemfail; char systemtest; char dunno_10; }; #endif /* NUT_SAFENET_H_SEEN */ nut-2.8.1/drivers/belkinunv.c0000644000175000017500000010764114515702041013100 00000000000000/* belkinunv.c - driver for newer Belkin models, such as "Belkin Universal UPS" (ca. 2003) Copyright (C) 2003 Peter Selinger 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 2 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, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ /* SOFT SHUTDOWN WORKAROUND One problem with the Belkin Universal UPS is that it cannot enter a soft shutdown (shut down until AC power returns) unless the batteries are completely depleted. Thus, one cannot just shut off the UPS after operating system shutdown; it will not come back on when the power comes back on. The belkinunv driver should never be used with the -k option. Instead, we provide a "standalone" mode for this driver via some -x options, which is intended to be used in startup and shutdown scripts. Please see the belkinunv(8) man page for details. VARIABLES: battery.charge battery.runtime battery.voltage battery.voltage.nominal input.frequency input.frequency.nominal e.g. 60 for 60Hz input.sensitivity (RW) normal/medium/low input.transfer.high (RW) input.transfer.low (RW) input.voltage input.voltage.maximum input.voltage.minimum input.voltage.nominal output.frequency output.voltage ups.beeper.status (RW) enabled/disabled/muted ups.firmware ups.load ups.model ups.power.nominal e.g. 800 for an 800VA system ups.status ups.temperature ups.test.result ups.delay.restart read-only: time to restart ups.delay.shutdown read-only: time to shutdown ups.type ONLINE/OFFLINE/LINEINT COMMANDS: beeper.disable beeper.enable beeper.mute reset.input.minmax shutdown.reboot shut down load immediately for 1-2 minutes shutdown.reboot.graceful shut down load after 40 seconds for 1-2 minutes shutdown.stayoff shut down load immediately and stay off test.battery.start start 10-second battery test test.battery.stop test.failure.start start "deep" battery test test.failure.stop STATUS FLAGS: OB load is on battery, including during tests OFF load is off OL load is online ACFAIL AC failure OVER overload OVERHEAT overheat COMMFAULT UPS Fault LB low battery CHRG charging DEPLETED battery depleted RB replace battery */ #include "main.h" #include "serial.h" #define DRIVER_NAME "Belkin 'Universal UPS' driver" #define DRIVER_VERSION "0.09" /* driver description structure */ upsdrv_info_t upsdrv_info = { DRIVER_NAME, DRIVER_VERSION, "Peter Selinger ", DRV_STABLE, { NULL } }; /* somewhat arbitrary buffer size - the longest actually occuring message is 18 bytes for the F6C800-UNV. But since message length is arbitrary in principle, we allow for some extra bytes. */ #define MAXMSGSIZE 25 /* definitions of register numbers for Belkin UPS */ #define REG_VOLTRATING 0x01 #define REG_FREQRATING 0x02 #define REG_POWERRATING 0x03 #define REG_BATVOLTRATING 0x04 #define REG_XFER_LO 0x06 #define REG_XFER_LO_MAX 0x07 #define REG_XFER_LO_MIN 0x08 #define REG_XFER_HI 0x09 #define REG_XFER_HI_MAX 0x0a #define REG_XFER_HI_MIN 0x0b #define REG_VOLTSENS 0x0c #define REG_UPSMODEL 0x0d #define REG_UPSMODEL2 0x0e #define REG_FIRMWARE 0x0f #define REG_TESTSTATUS 0x10 #define REG_ALARMSTATUS 0x11 #define REG_SHUTDOWNTIMER 0x15 #define REG_RESTARTTIMER 0x16 #define REG_INPUTVOLT 0x18 #define REG_INPUTFREQ 0x19 #define REG_TEMPERATURE 0x1a #define REG_OUTPUTVOLT 0x1b #define REG_OUTPUTFREQ 0x1c #define REG_LOAD 0x1e #define REG_BATSTAT2 0x1f #define REG_BATVOLT 0x20 #define REG_BATLEVEL 0x21 #define REG_UPSSTATUS 0x22 #define REG_BATSTATUS 0x23 #define REG_TIMELEFT 0x3f /* flags for REG_UPSSTATUS */ #define US_ACFAILURE 0x0001 #define US_OVERLOAD 0x0010 #define US_OFF 0x0020 #define US_OVERHEAT 0x0040 #define US_UPSFAULT 0x0080 #define US_WAITING 0x2000 #define US_BUZZER 0x8000 /* flags for REG_BATSTATUS */ #define BS_LOW 0x04 #define BS_CHARGING 0x10 #define BS_ONBATTERY 0x20 #define BS_DEPLETED 0x40 #define BS_REPLACE 0x80 /* size of an array */ #define asize(x) ((int)(SIZEOF_ARRAY(x))) static const char *upstype[3] = { "ONLINE", "OFFLINE", "LINEINT" }; static const char *voltsens[3] = { "normal", "medium", "low" }; static const char *teststatus[6] = { "no test performed", "test passed", "test failed", "test failed", "test aborted", "test in progress" }; #define ST_OFF 0 #define ST_ONLINE 1 #define ST_BATTERY 2 static const char *status[] = { "UPS is off", /* ST_OFF */ "UPS is on AC power", /* ST_ONLINE */ "UPS is on battery" /* ST_BATTERY */ }; /* some useful strings */ #define ESC "\033" #define COL0 ESC "[G" ESC "[K" /* terminal control: clear line */ static int minutil = -1; static int maxutil = -1; static int xfer_lo_min = -1; static int xfer_lo_max = -1; static int xfer_hi_min = -1; static int xfer_hi_max = -1; int instcmd(const char *cmdname, const char *extra); static int setvar(const char *varname, const char *val); /* ---------------------------------------------------------------------- */ /* a general purpose Belkin-specific function: */ /* calculate a Belkin checksum, i.e., add buf[0]...buf[n-1] */ static unsigned char belkin_checksum(unsigned char *buf, int n) { int i, res; res = 0; for (i=0; i bufsize) { return -1; } r = ser_get_buf_len(upsfd, &buf[0], 1, 3, 0); if (r<0) { upslog_with_errno(LOG_ERR, "Error reading from UPS"); return -1; } else if (r==0) { upslogx(LOG_ERR, "No response from UPS"); return -1; } else if (buf[0]!=0x7e) { upslogx(LOG_ERR, "Garbage read from UPS"); return -1; } n+=r; /* read instruction, size, and register */ if (n+3 > bufsize) { return -1; } r = ser_get_buf_len(upsfd, &buf[1], 3, 3, 0); if (r!=3) { upslogx(LOG_ERR, "Short read from UPS"); return -1; } n+=r; len = buf[2]; /* read data and checksum */ if (n+len > bufsize) { return -1; } /* Casting is okay, len is range-limited to unsigned char */ r = ser_get_buf_len(upsfd, &buf[4], (size_t)len, 3, 0); if (r!=len) { upslogx(LOG_ERR, "Short read from UPS"); return -1; } n+=r; /* check checksum */ if (belkin_checksum(buf, len+3) != buf[len+3]) { upslogx(LOG_ERR, "Bad checksum from UPS"); return -1; } return n; } /* read the value of a string register from UPS. Return NULL on failure, else an allocated string. */ static char *belkin_nut_read_str(unsigned char reg) { unsigned char buf[MAXMSGSIZE]; ssize_t r; size_t len; char *str; /* send the request */ buf[0] = 0x7e; buf[1] = 0x03; buf[2] = 0x02; buf[3] = reg; buf[4] = 0; buf[5] = belkin_checksum(buf, 5); r = ser_send_buf(upsfd, buf, 6); if (r<0) { upslogx(LOG_ERR, "Failed write to UPS"); return NULL; } /* receive the answer */ r = belkin_nut_receive(buf, MAXMSGSIZE); if (r<0) { return NULL; } if ((buf[1]!=0x05 && buf[1]!=0x01) || buf[3] != reg) { upslogx(LOG_ERR, "Invalid response from UPS"); return NULL; } if (buf[1]==0x01) { return NULL; } /* convert the answer to a string */ if (buf[2] < 1) { upslogx(LOG_ERR, "Invalid response from UPS: string too short to be true"); return NULL; } len = buf[2]-1; str = (char *)xmalloc(len+1); memcpy(str, &buf[4], len); str[len]=0; return str; } /* read the value of an integer register from UPS. Return -1 on failure. */ static int belkin_nut_read_int(unsigned char reg) { unsigned char buf[MAXMSGSIZE]; int len; ssize_t r; /* send the request */ buf[0] = 0x7e; buf[1] = 0x03; buf[2] = 0x02; buf[3] = reg; buf[4] = 0; buf[5] = belkin_checksum(buf, 5); r = ser_send_buf(upsfd, buf, 6); if (r<0) { upslogx(LOG_ERR, "Failed write to UPS"); return -1; } /* receive the answer */ r = belkin_nut_receive(buf, MAXMSGSIZE); if (r<0) { return -1; } if ((buf[1]!=0x05 && buf[1]!=0x01) || buf[3] != reg) { upslogx(LOG_ERR, "Invalid response from UPS"); return -1; } if (buf[1]==0x01) { return -1; } /* convert the answer to an integer */ len = buf[2]-1; if (len==1) { return buf[4]; } else if (len==2) { return buf[4] + 256*buf[5]; } else { upslogx(LOG_ERR, "Invalid response from UPS"); return -1; } } /* write the value of an integer register to UPS. Return -1 on failure, else 0 */ static int belkin_nut_write_int(unsigned char reg, int val) { unsigned char buf[MAXMSGSIZE]; ssize_t r; /* send the request */ buf[0] = 0x7e; buf[1] = 0x04; buf[2] = 0x03; buf[3] = reg; buf[4] = val & 0xff; buf[5] = (val>>8) & 0xff; buf[6] = belkin_checksum(buf, 6); r = ser_send_buf(upsfd, buf, 7); if (r<0) { upslogx(LOG_ERR, "Failed write to UPS"); return -1; } /* receive the acknowledgement */ r = belkin_nut_receive(buf, MAXMSGSIZE); if (r<0) { return -1; } if ((buf[1]!=0x02 && buf[1]!=0x01) || buf[3] != reg) { upslogx(LOG_ERR, "Invalid response from UPS"); return -1; } if (buf[1]==0x01) { return -1; } return 0; } /* ---------------------------------------------------------------------- */ /* some private functions for talking to the UPS - "standalone" versions. The functions in this section have _std_ in their name, and they do not use default NUT error handling (this would not be desirable during standalone operation, i.e., when the -x wait option is given). These functions also take an additional file descriptor argument. */ /* Open and prepare a serial port for communication with a Belkin Universal UPS. DEVICE is the name of the serial port. It will be opened in non-blocking read/write mode, and the appropriate communications parameters will be set. The device will also be sent a special signal (clear DTR, set RTS) to cause the UPS to switch from "dumb" to "smart" mode, and any pending data (=garbage) will be discarded. After this call, the device is ready for reading and writing via read(2) and write(2). Return a valid file descriptor on success, or else -1 with errno set. */ static TYPE_FD_SER belkin_std_open_tty(const char *device) { TYPE_FD_SER fd; struct termios tios; #ifndef WIN32 struct flock flock; #endif char buf[128]; ssize_t r; /* open the device */ fd = open(device, O_RDWR | O_NONBLOCK); if (INVALID_FD_SER(fd)) { return ERROR_FD_SER; } /* set communications parameters: 2400 baud, 8 bits, 1 stop bit, no parity, enable reading, hang up when done, ignore modem control lines. */ memset(&tios, 0, sizeof(tios)); tios.c_cflag = B2400 | CS8 | CREAD | HUPCL | CLOCAL; tios.c_cc[VMIN] = 1; tios.c_cc[VTIME] = 0; r = tcsetattr(fd, TCSANOW, &tios); if (r == -1) { close(fd); return ERROR_FD_SER; } /* signal the UPS to enter "smart" mode. This is done by setting RTS and dropping DTR for at least 0.25 seconds. RTS and DTR refer to two specific pins in the 9-pin serial connector. Note: this must be done for at least 0.25 seconds for the UPS to react. Ignore any errors, as this probably means we are not on a "real" serial port. */ ser_set_dtr(upsfd, 0); ser_set_rts(upsfd, 1); /* flush both directions of serial port: throw away all data in transit */ r = ser_flush_io(fd); if (r == -1) { close(fd); return ERROR_FD_SER; } /* TODO: port to WIN32 */ #ifndef WIN32 /* lock the port */ memset(&flock, 0, sizeof(flock)); flock.l_type = F_RDLCK; r = fcntl(fd, F_SETLK, &flock); if (r == -1) { close(fd); return ERROR_FD_SER; } #endif /* sleep at least 0.25 seconds for the UPS to wake up. Belkin's own software sleeps 1 second, so that's what we do, too. */ usleep(1000000); /* flush incoming data again, and read any remaining garbage bytes. There should not be any. */ r = tcflush(fd, TCIFLUSH); if (r == -1) { close(fd); return ERROR_FD_SER; } #ifndef WIN32 r = read(fd, buf, 127); #else /* WIN32 : w32_serial_read is blocking, using select_read with 0ms timeout * is non-blocking */ r = select_read(fd, buf, 127, 0, 0); #endif if (r == -1 && errno != EAGAIN) { close(fd); return ERROR_FD_SER; } /* leave port in non-blocking state */ return fd; } /* blocking read with 1-second timeout (use non-blocking i/o) */ static int belkin_std_upsread(TYPE_FD_SER fd, unsigned char *buf, int n) { int count = 0; ssize_t r; int tries = 0; while (count < n) { #ifndef WIN32 r = read(fd, &buf[count], (size_t)(n-count)); #else /* WIN32 : w32_serial_read is blocking, using select_read * with 0ms timeout is non-blocking */ r = select_read(fd, buf, (size_t)(n-count), 0, 0); #endif if (r==-1 && errno==EAGAIN) { /* non-blocking i/o, no data available */ usleep(100000); tries++; } else if (r == -1) { return -1; } else { count += r; } if (tries > 10) { return -1; } } return count; } /* blocking write with 1-second timeout (use non-blocking i/o) */ static int belkin_std_upswrite(TYPE_FD_SER fd, unsigned char *buf, int n) { int count = 0; ssize_t r; int tries = 0; while (count < n) { r = write(fd, &buf[count], (size_t)(n-count)); if (r==-1 && errno==EAGAIN) { /* non-blocking i/o, no data available */ usleep(100000); tries++; } else if (r == -1) { return -1; } else { count += r; } if (tries > 10) { return -1; } } return count; } /* receive Belkin message from UPS, check for well-formedness (leading byte, checksum). Return length of message, or -1 if not well-formed */ static int belkin_std_receive(TYPE_FD_SER fd, unsigned char *buf, int bufsize) { int r; int n=0; int len; /* read 0x7e */ if (n+1 > bufsize) { return -1; } r = belkin_std_upsread(fd, &buf[0], 1); if (r==-1 || buf[0]!=0x7e) { return -1; } n+=r; /* read instruction, size, and register */ if (n+3 > bufsize) { return -1; } r = belkin_std_upsread(fd, &buf[1], 3); if (r!=3) { return -1; } n+=r; len = buf[2]; /* read data and checksum */ if (n+len > bufsize) { return -1; } r = belkin_std_upsread(fd, &buf[4], len); if (r!=len) { return -1; } n+=r; /* check checksum */ if (belkin_checksum(buf, len+3) != buf[len+3]) { return -1; } return n; } /* read the value of an integer register from UPS. Return -1 on failure. */ static int belkin_std_read_int(TYPE_FD_SER fd, unsigned char reg) { unsigned char buf[MAXMSGSIZE]; int len, r; /* send the request */ buf[0] = 0x7e; buf[1] = 0x03; buf[2] = 0x02; buf[3] = reg; buf[4] = 0; buf[5] = belkin_checksum(buf, 5); r = belkin_std_upswrite(fd, buf, 6); if (r<0) { return -1; } /* receive the answer */ r = belkin_std_receive(fd, buf, MAXMSGSIZE); if (r<0) { return -1; } if ((buf[1]!=0x05 && buf[1]!=0x01) || buf[3] != reg) { return -1; } if (buf[1]==0x01) { return -1; } /* convert the answer to an integer */ len = buf[2]-1; if (len==1) { return buf[4]; } else if (len==2) { return buf[4] + 256*buf[5]; } else { return -1; } } /* write the value of an integer register to UPS. Return -1 on failure, else 0 */ static int belkin_std_write_int(TYPE_FD_SER fd, unsigned char reg, int val) { unsigned char buf[MAXMSGSIZE]; int r; /* send the request */ buf[0] = 0x7e; buf[1] = 0x04; buf[2] = 0x03; buf[3] = reg; buf[4] = val & 0xff; buf[5] = (val>>8) & 0xff; buf[6] = belkin_checksum(buf, 6); r = belkin_std_upswrite(fd, buf, 7); if (r<0) { return -1; } /* receive the acknowledgement */ r = belkin_std_receive(fd, buf, MAXMSGSIZE); if (r<0) { return -1; } if ((buf[1]!=0x02 && buf[1]!=0x01) || buf[3] != reg) { return -1; } if (buf[1]==0x01) { return -1; } return 0; } /* ---------------------------------------------------------------------- */ /* "standalone" program executed when driver is called with the '-x wait' or '-x wait=' flag or option */ /* this function updates the status line, as specified by the smode parameter (0=silent, 1=normal, 2=dumbterminal). This is only done if the status has not changed from the previous call */ static void updatestatus(int smode, const char *fmt, ...) { char buf[1024]; /* static string limit is OK */ static char oldbuf[1024] = { 0 }; static int init = 1; va_list ap; if (smode==0) { return; } if (init) { init = 0; oldbuf[0] = 0; } /* read formatted argument string */ va_start(ap, fmt); #ifdef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL #pragma GCC diagnostic push #endif #ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL #pragma GCC diagnostic ignored "-Wformat-nonliteral" #endif #ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_FORMAT_SECURITY #pragma GCC diagnostic ignored "-Wformat-security" #endif vsnprintf(buf, sizeof(buf), fmt, ap); #ifdef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL #pragma GCC diagnostic pop #endif buf[sizeof(buf)-1] = 0; va_end(ap); if (strcmp(oldbuf, buf)==0) { return; } strcpy(oldbuf, buf); if (smode==2) { /* "dumbterm" version just prints a new line each time */ printf("%s\n", buf); } else { /* "normal" version overwrites same line each time */ printf(COL0 "%s", buf); } fflush(stdout); } /* switch from status line display to normal output mode */ static void endstatus(int smode) { if (smode==1) { fprintf(stdout, "\n"); fflush(stdout); } } static int belkin_wait(void) { int level = 0; /* battery level to wait for */ int smode = 1; /* statusline mode: 0=silent, 1=normal, 2=dumbterm */ int nohang = 0; /* nohang flag */ int flash = 0; /* flash flag */ char *val; int failcount = 0; /* count consecutive failed connection attempts */ int failerrno = 0; TYPE_FD_SER fd; int r; int bs, ov, bl, st; /* read command line '-x' options */ val = getval("wait"); if (val) { level = atoi(val); } if (dstate_getinfo("driver.flag.nohang")) { nohang = 1; } if (dstate_getinfo("driver.flag.flash")) { flash = 1; } if (dstate_getinfo("driver.flag.silent")) { smode = 0; } else if (dstate_getinfo("driver.flag.dumbterm")) { smode = 2; } updatestatus(smode, "Connecting to UPS..."); failcount = 0; fd = ERROR_FD_SER; while (1) { if (failcount >= 3 && nohang) { endstatus(smode); printf("UPS is not responding: %s\n", strerror(failerrno)); return 1; } else if (failcount >= 3) { updatestatus(smode, "UPS is not responding, will keep trying: %s", strerror(failerrno)); } if (INVALID_FD_SER(fd)) { fd = belkin_std_open_tty(device_path); } if (INVALID_FD_SER(fd)) { failcount++; failerrno = errno; sleep(1); continue; } /* wait until the UPS is online and the battery level is >= level */ bs = belkin_std_read_int(fd, REG_BATSTATUS); /* battery status */ if (bs==-1) { failcount++; failerrno = errno; close(fd); fd = ERROR_FD_SER; sleep(1); continue; } ov = belkin_std_read_int(fd, REG_OUTPUTVOLT); /* output voltage */ if (ov==-1) { failcount++; failerrno = errno; close(fd); fd = ERROR_FD_SER; sleep(1); continue; } bl = belkin_std_read_int(fd, REG_BATLEVEL); /* battery level */ if (bl==-1) { failcount++; failerrno = errno; close(fd); fd = ERROR_FD_SER; sleep(1); continue; } /* successfully got data from UPS */ failcount = 0; if (bs & BS_ONBATTERY) { st = ST_BATTERY; } else if (ov>0) { st = ST_ONLINE; } else { st = ST_OFF; } updatestatus(smode, "%s, battery level: %d%%", status[st], bl); if (st == ST_ONLINE && bl >= level) { break; } sleep(1); } /* termination condition reached */ endstatus(smode); if (flash) { printf("Interrupting UPS load for ca. 2 minutes.\n"); r = belkin_std_write_int(fd, REG_RESTARTTIMER, 2); if (r==0) { r = belkin_std_write_int(fd, REG_SHUTDOWNTIMER, 1); } if (r) { printf("Timed shutdown operation failed.\n"); close(fd); return 2; } } close(fd); return 0; } /* ---------------------------------------------------------------------- */ /* functions which interface with main.c */ /* read all hardcoded info about this UPS */ void upsdrv_initinfo(void) { char *str; int val; int i; /* read hard-wired values */ val = belkin_nut_read_int(REG_VOLTRATING); if (val!=-1) { dstate_setinfo("input.voltage.nominal", "%d", val); } val = belkin_nut_read_int(REG_FREQRATING); if (val!=-1) { dstate_setinfo("input.frequency.nominal", "%d", val); } val = belkin_nut_read_int(REG_POWERRATING); if (val!=-1) { dstate_setinfo("ups.power.nominal", "%d", val); } val = belkin_nut_read_int(REG_BATVOLTRATING); if (val!=-1) { dstate_setinfo("battery.voltage.nominal", "%d", val); } xfer_lo_max = belkin_nut_read_int(REG_XFER_LO_MAX); xfer_lo_min = belkin_nut_read_int(REG_XFER_LO_MIN); xfer_hi_max = belkin_nut_read_int(REG_XFER_HI_MAX); xfer_hi_min = belkin_nut_read_int(REG_XFER_HI_MIN); str = belkin_nut_read_str(REG_UPSMODEL); if (str) { dstate_setinfo("ups.model", "%s", str); free(str); } val = belkin_nut_read_int(REG_FIRMWARE); if (val!=-1) { dstate_setinfo("ups.firmware", "%d", (val>>4) & 0xf); dstate_setinfo("ups.type", "%s", upstype[(val & 0x0f) % 3]); } /* read writable values and declare them writable */ val = belkin_nut_read_int(REG_VOLTSENS); if (val!=-1) { dstate_setinfo("input.sensitivity", "%s", (val>=0 && val 0) { status_set("OL"); /* online */ } else { status_set("OFF"); /* off */ } if (us & US_ACFAILURE) { status_set("ACFAIL"); /* AC failure, self-invented */ /* Note: this is not the same as "on battery", because this flag makes sense even during a test, or when the load is off. It simply reflects the status of utility power. A "critical" situation should be OB && BL && ACFAIL. */ } if (us & US_OVERLOAD) { status_set("OVER"); /* overload */ } if (us & US_OVERHEAT) { status_set("OVERHEAT"); /* overheat, self-invented */ } if (us & US_UPSFAULT) { status_set("COMMFAULT"); /* UPS Fault */ } if (bs & BS_LOW) { status_set("LB"); /* low battery */ } if (bs & BS_CHARGING) { status_set("CHRG"); /* charging */ } if (bs & BS_DEPLETED) { status_set("DEPLETED"); /* battery depleted, self-invented */ } if (bs & BS_REPLACE) { status_set("RB"); /* replace battery */ } status_commit(); /* new read everything else */ val = belkin_nut_read_int(REG_XFER_LO); if (val!=-1) { dstate_setinfo("input.transfer.low", "%d", val); } val = belkin_nut_read_int(REG_XFER_HI); if (val!=-1) { dstate_setinfo("input.transfer.high", "%d", val); } val = belkin_nut_read_int(REG_VOLTSENS); if (val!=-1) { dstate_setinfo("input.sensitivity", "%s", (val>=0 && val=0 && val0 && (maxutil==-1 || val>maxutil)) { maxutil = val; } if (val>0 && (minutil==-1 || val' */ addvar(VAR_FLAG, "wait", "Wait for AC power "); addvar(VAR_VALUE, "wait", "Wait for AC power and battery level"); /* allow '-x nohang' */ addvar(VAR_FLAG, "nohang", "In wait mode: quit if UPS dead "); /* allow '-x flash' */ addvar(VAR_FLAG, "flash", "In wait mode: do brief shutdown "); /* allow '-x silent' */ addvar(VAR_FLAG, "silent", "In wait mode: suppress status line "); /* allow '-x dumbterm' */ addvar(VAR_FLAG, "dumbterm", "In wait mode: simpler status line "); } /* prep the serial port */ void upsdrv_initups(void) { /* If '-x wait' or '-x wait=' option given, branch into standalone behavior. */ if (getval("wait") || dstate_getinfo("driver.flag.wait")) { exit(belkin_wait()); } belkin_nut_open_tty(); } void upsdrv_cleanup(void) { ser_close(upsfd, device_path); } nut-2.8.1/drivers/apc-epdu-mib.h0000644000175000017500000000200314501607135013340 00000000000000/* apc-epdu-mib.h - subdriver to monitor apc SNMP easy pdu with NUT * * Copyright (C) * 2011 - 2022 Eric Clappier * * 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 2 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, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef APC_EPDU_MIB_H #define APC_EPDU_MIB_H #include "main.h" #include "snmp-ups.h" extern mib2nut_info_t apc_pdu_epdu; #endif /* APC_EPDU_MIB_H */ nut-2.8.1/drivers/belkin-hid.c0000644000175000017500000006217214501607135013113 00000000000000/* belkin-hid.c - data to monitor Belkin UPS Systems USB/HID devices with NUT * * Copyright (C) * 2003 - 2008 Arnaud Quette * 2005 Peter Selinger * 2011, 2014 Charles Lepple * * Sponsored by MGE UPS SYSTEMS * * 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 2 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, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #include "main.h" /* for getval() */ #include "usbhid-ups.h" #include "belkin-hid.h" #include "usb-common.h" #include /* for fabs() */ #define BELKIN_HID_VERSION "Belkin/Liebert HID 0.18" /* Belkin */ #define BELKIN_VENDORID 0x050d /* Liebert */ #define LIEBERT_VENDORID 0x10af /*! USB IDs device table. * Note that there are at least two Liebert firmware types which both report * a VID:PID of 10af:0001. The newer ones tend not to have the Belkin broken * Usage Pages (and therefore use standard HID PDC paths) but they have * incorrect exponents for some fields. */ static usb_device_id_t belkin_usb_device_table[] = { /* F6C800-UNV */ { USB_DEVICE(BELKIN_VENDORID, 0x0980), NULL }, /* F6C900-UNV */ { USB_DEVICE(BELKIN_VENDORID, 0x0900), NULL }, /* F6C100-UNV */ { USB_DEVICE(BELKIN_VENDORID, 0x0910), NULL }, /* F6C120-UNV */ { USB_DEVICE(BELKIN_VENDORID, 0x0912), NULL }, /* F6C550-AVR */ { USB_DEVICE(BELKIN_VENDORID, 0x0551), NULL }, /* F6C1250-TW-RK */ { USB_DEVICE(BELKIN_VENDORID, 0x0750), NULL }, /* F6C1500-TW-RK */ { USB_DEVICE(BELKIN_VENDORID, 0x0751), NULL }, /* F6H375-USB */ { USB_DEVICE(BELKIN_VENDORID, 0x0375), NULL }, /* Regulator PRO-USB */ { USB_DEVICE(BELKIN_VENDORID, 0x0f51), NULL }, /* F6C1100-UNV, F6C1200-UNV */ { USB_DEVICE(BELKIN_VENDORID, 0x1100), NULL }, /* Liebert GXT4 UPS */ { USB_DEVICE(LIEBERT_VENDORID, 0x0004), NULL }, /* Liebert PowerSure PSA UPS */ { USB_DEVICE(LIEBERT_VENDORID, 0x0001), NULL }, /* Liebert PowerSure PSI 1440 */ { USB_DEVICE(LIEBERT_VENDORID, 0x0004), NULL }, /* Liebert GXT3 */ { USB_DEVICE(LIEBERT_VENDORID, 0x0008), NULL }, /* Terminating entry */ { 0, 0, NULL } }; static const char *liebert_online_fun(double value); static const char *liebert_discharging_fun(double value); static const char *liebert_charging_fun(double value); static const char *liebert_lowbatt_fun(double value); static const char *liebert_replacebatt_fun(double value); static const char *liebert_shutdownimm_fun(double value); static const char *liebert_config_voltage_fun(double value); static const char *liebert_line_voltage_fun(double value); static info_lkp_t liebert_online_info[] = { { 0, NULL, liebert_online_fun, NULL } }; static info_lkp_t liebert_discharging_info[] = { { 0, NULL, liebert_discharging_fun, NULL } }; static info_lkp_t liebert_charging_info[] = { { 0, NULL, liebert_charging_fun, NULL } }; static info_lkp_t liebert_lowbatt_info[] = { { 0, NULL, liebert_lowbatt_fun, NULL } }; static info_lkp_t liebert_replacebatt_info[] = { { 0, NULL, liebert_replacebatt_fun, NULL } }; static info_lkp_t liebert_shutdownimm_info[] = { { 0, NULL, liebert_shutdownimm_fun, NULL } }; static info_lkp_t liebert_config_voltage_info[] = { { 0, NULL, liebert_config_voltage_fun, NULL }, }; static info_lkp_t liebert_line_voltage_info[] = { { 0, NULL, liebert_line_voltage_fun, NULL }, }; static double liebert_config_voltage_mult = 1.0; static double liebert_line_voltage_mult = 1.0; static char liebert_conversion_buf[10]; /* These lookup functions also cover the 1e-7 factor which seems to be due to a * broken report descriptor in certain Liebert units. */ static const char *liebert_online_fun(double value) { return value ? "online" : "!online"; } static const char *liebert_discharging_fun(double value) { return value ? "dischrg" : "!dischrg"; } static const char *liebert_charging_fun(double value) { return value ? "chrg" : "!chrg"; } static const char *liebert_lowbatt_fun(double value) { return value ? "lowbatt" : "!lowbatt"; } static const char *liebert_replacebatt_fun(double value) { return value ? "replacebatt" : "!replacebatt"; } static const char *liebert_shutdownimm_fun(double value) { return value ? "shutdownimm" : "!shutdownimm"; } /*! Apply heuristics to Liebert ConfigVoltage for correction of other values. * Logic is weird since the ConfigVoltage item comes after InputVoltage and * OutputVoltage. */ static const char *liebert_config_voltage_fun(double value) { if( value < 1 ) { if( fabs(value - 1e-7) < 1e-9 ) { liebert_config_voltage_mult = 1e8; liebert_line_voltage_mult = 1e7; /* stomp this in case input voltage was low */ upsdebugx(2, "ConfigVoltage = %g -> assuming correction factor = %g", value, liebert_config_voltage_mult); } else { upslogx(LOG_NOTICE, "ConfigVoltage exponent looks wrong, but not correcting."); } } snprintf(liebert_conversion_buf, sizeof(liebert_conversion_buf), "%.1f", value * liebert_config_voltage_mult); return liebert_conversion_buf; } static const char *liebert_line_voltage_fun(double value) { if( value < 1 ) { if( fabs(value - 1e-7) < 1e-9 ) { liebert_line_voltage_mult = 1e7; upsdebugx(2, "Input/OutputVoltage = %g -> assuming correction factor = %g", value, liebert_line_voltage_mult); } else { upslogx(LOG_NOTICE, "LineVoltage exponent looks wrong, but not correcting."); } } snprintf(liebert_conversion_buf, sizeof(liebert_conversion_buf), "%.1f", value * liebert_line_voltage_mult); return liebert_conversion_buf; } /* some conversion functions specific to Belkin */ /* returns statically allocated string - must not use it again before done with result! */ static const char *belkin_firmware_conversion_fun(double value) { static char buf[20]; snprintf(buf, sizeof(buf), "%ld", (long)value >> 4); return buf; } static info_lkp_t belkin_firmware_conversion[] = { { 0, NULL, belkin_firmware_conversion_fun, NULL } }; static const char *belkin_upstype_conversion_fun(double value) { switch ((long)value & 0x0f) { case 1: return "offline"; case 2: return "line-interactive"; case 3: return "simple online"; case 4: return "simple offline"; case 5: return "simple line-interactive"; default: return "online"; } } static info_lkp_t belkin_upstype_conversion[] = { { 0, NULL, belkin_upstype_conversion_fun, NULL } }; static const char *belkin_sensitivity_conversion_fun(double value) { switch ((long)value) { case 1: return "reduced"; case 2: return "low"; default: return "normal"; } } static info_lkp_t belkin_sensitivity_conversion[] = { { 0, NULL, belkin_sensitivity_conversion_fun, NULL } }; static info_lkp_t belkin_test_info[] = { { 0, "No test initiated", NULL, NULL }, { 1, "Done and passed", NULL, NULL }, { 2, "Done and warning", NULL, NULL }, { 3, "Done and error", NULL, NULL }, { 4, "Aborted", NULL, NULL }, { 5, "In progress", NULL, NULL }, { 0, NULL, NULL, NULL } }; static const char *belkin_overload_conversion_fun(double value) { if ((long)value & 0x0010) { return "overload"; } else { return "!overload"; } } static info_lkp_t belkin_overload_conversion[] = { { 0, NULL, belkin_overload_conversion_fun, NULL } }; static const char *belkin_overheat_conversion_fun(double value) { if ((long)value & 0x0040) { return "overheat"; } else { return "!overheat"; } } static info_lkp_t belkin_overheat_conversion[] = { { 0, NULL, belkin_overheat_conversion_fun, NULL } }; static const char *belkin_commfault_conversion_fun(double value) { if ((long)value & 0x0080) { return "commfault"; } else { return "!commfault"; } } static info_lkp_t belkin_commfault_conversion[] = { { 0, NULL, belkin_commfault_conversion_fun, NULL } }; static const char *belkin_awaitingpower_conversion_fun(double value) { if ((long)value & 0x2000) { return "awaitingpower"; } else { return "!awaitingpower"; } } static info_lkp_t belkin_awaitingpower_conversion[] = { { 0, NULL, belkin_awaitingpower_conversion_fun, NULL } }; static const char *belkin_online_conversion_fun(double value) { if ((long)value & 0x0001) { return "!online"; } else { return "online"; } } static info_lkp_t belkin_online_conversion[] = { { 0, NULL, belkin_online_conversion_fun, NULL } }; static const char *belkin_lowbatt_conversion_fun(double value) { if ((long)value & 0x0004) { return "lowbatt"; } else { return "!lowbatt"; } } static info_lkp_t belkin_lowbatt_conversion[] = { { 0, NULL, belkin_lowbatt_conversion_fun, NULL } }; static const char *belkin_depleted_conversion_fun(double value) { if ((long)value & 0x0040) { return "depleted"; } else { return "!depleted"; } } static info_lkp_t belkin_depleted_conversion[] = { { 0, NULL, belkin_depleted_conversion_fun, NULL } }; static const char *belkin_replacebatt_conversion_fun(double value) { if ((long)value & 0x0080) { return "replacebatt"; } else { return "!replacebatt"; } } static info_lkp_t belkin_replacebatt_conversion[] = { { 0, NULL, belkin_replacebatt_conversion_fun, NULL } }; /* --------------------------------------------------------------- */ /* Vendor-specific usage table */ /* --------------------------------------------------------------- */ /* BELKIN usage table */ /* Note: these seem to have been wrongly encoded by Belkin */ /* Pages 84 to 88 are reserved for official HID definition! */ static usage_lkp_t belkin_usage_lkp[] = { { "BELKINConfig", 0x00860026 }, { "BELKINConfigVoltage", 0x00860040 }, /* (V) */ { "BELKINConfigFrequency", 0x00860042 }, /* (Hz) */ { "BELKINConfigApparentPower", 0x00860043 }, /* (VA) */ { "BELKINConfigBatteryVoltage", 0x00860044 }, /* (V) */ { "BELKINConfigOverloadTransfer", 0x00860045 }, /* (%) */ { "BELKINLowVoltageTransfer", 0x00860053 }, /* R/W (V) */ { "BELKINHighVoltageTransfer", 0x00860054 }, /* R/W (V)*/ { "BELKINLowVoltageTransferMax", 0x0086005b }, /* (V) */ { "BELKINLowVoltageTransferMin", 0x0086005c }, /* (V) */ { "BELKINHighVoltageTransferMax", 0x0086005d }, /* (V) */ { "BELKINHighVoltageTransferMin", 0x0086005e }, /* (V) */ { "BELKINControls", 0x00860027 }, { "BELKINLoadOn", 0x00860050 }, /* R/W: write: 1=do action. Read: 0=none, 1=started, 2=in progress, 3=complete */ { "BELKINLoadOff", 0x00860051 }, /* R/W: ditto */ { "BELKINLoadToggle", 0x00860052 }, /* R/W: ditto */ { "BELKINDelayBeforeReboot", 0x00860055 }, /* R/W: write: 0=start shutdown using default delay. */ { "BELKINDelayBeforeStartup", 0x00860056 }, /* R/W (minutes) */ { "BELKINDelayBeforeShutdown", 0x00860057 }, /* R/W (seconds) */ { "BELKINTest", 0x00860058 }, /* R/W: write: 0=no test, 1=quick test, 2=deep test, 3=abort test. Read: 0=no test, 1=passed, 2=warning, 3=error, 4=abort, 5=in progress */ { "BELKINAudibleAlarmControl", 0x0086005a }, /* R/W: 1=disabled, 2=enabled, 3=muted */ { "BELKINDevice", 0x00860029 }, { "BELKINVoltageSensitivity", 0x00860074 }, /* R/W: 0=normal, 1=reduced, 2=low */ { "BELKINModelString", 0x00860075 }, { "BELKINModelStringOffset", 0x00860076 }, /* offset of Model name in Model String */ { "BELKINUPSType", 0x0086007c }, /* high nibble: firmware version. Low nibble: 0=online, 1=offline, 2=line-interactive, 3=simple online, 4=simple offline, 5=simple line-interactive */ { "BELKINPowerState", 0x0086002a }, { "BELKINInput", 0x0086001a }, { "BELKINOutput", 0x0086001c }, { "BELKINBatterySystem", 0x00860010 }, { "BELKINVoltage", 0x00860030 }, /* (0.1 Volt) */ { "BELKINFrequency", 0x00860032 }, /* (0.1 Hz) */ { "BELKINPower", 0x00860034 }, /* (Watt) */ { "BELKINPercentLoad", 0x00860035 }, /* (%) */ { "BELKINTemperature", 0x00860036 }, /* (Celsius) */ { "BELKINCharge", 0x00860039 }, /* (%) */ { "BELKINRunTimeToEmpty", 0x0086006c }, /* (minutes) */ { "BELKINStatus", 0x00860028 }, { "BELKINBatteryStatus", 0x00860022 }, /* 1 byte: bit2=low battery, bit4=charging, bit5=discharging, bit6=battery empty, bit7=replace battery */ { "BELKINPowerStatus", 0x00860021 }, /* 2 bytes: bit0=ac failure, bit4=overload, bit5=load is off, bit6=overheat, bit7=UPS fault, bit13=awaiting power, bit15=alarm status */ { NULL, 0 } }; static usage_tables_t belkin_utab[] = { belkin_usage_lkp, hid_usage_lkp, NULL, }; /* --------------------------------------------------------------- */ /* HID2NUT lookup table */ /* --------------------------------------------------------------- */ static hid_info_t belkin_hid2nut[] = { /* interpreted Belkin variables */ { "battery.charge", 0, 0, "UPS.BELKINBatterySystem.BELKINCharge", NULL, "%.0f", 0, NULL }, /* { "battery.charge.broken", 0, 0, "UPS.PowerSummary.RemainingCapacity", NULL, "%.0f", 0, NULL }, */ { "battery.charge.low", 0, 0, "UPS.PowerSummary.RemainingCapacityLimit", NULL, "%.0f", 0, NULL }, { "battery.charge.warning", 0, 0, "UPS.PowerSummary.WarningCapacityLimit", NULL, "%.0f", 0, NULL }, /* Read only */ { "battery.runtime", 0, 0, "UPS.PowerSummary.RunTimeToEmpty", NULL, "%.0f", 0, NULL }, { "battery.type", 0, 0, "UPS.PowerSummary.iDeviceChemistry", NULL, "%s", 0, stringid_conversion }, { "battery.voltage", 0, 0, "UPS.BELKINBatterySystem.BELKINVoltage", NULL, "%s", 0, divide_by_10_conversion }, { "battery.voltage.nominal", 0, 0, "UPS.BELKINConfig.BELKINConfigBatteryVoltage", NULL, "%.0f", 0, NULL }, { "input.frequency", 0, 0, "UPS.BELKINPowerState.BELKINInput.BELKINFrequency", NULL, "%s", 0, divide_by_10_conversion }, { "input.frequency.nominal", 0, 0, "UPS.BELKINConfig.BELKINConfigFrequency", NULL, "%.0f", 0, NULL }, { "input.sensitivity", ST_FLAG_RW | ST_FLAG_STRING, 10, "UPS.BELKINDevice.BELKINVoltageSensitivity", NULL, "%s", 0, belkin_sensitivity_conversion }, { "input.transfer.high", ST_FLAG_RW | ST_FLAG_STRING, 10, "UPS.BELKINConfig.BELKINHighVoltageTransfer", NULL, "%.0f", 0, NULL }, { "input.transfer.high.max", 0, 0, "UPS.BELKINConfig.BELKINHighVoltageTransferMax", NULL, "%.0f", 0, NULL }, { "input.transfer.high.min", 0, 0, "UPS.BELKINConfig.BELKINHighVoltageTransferMin", NULL, "%.0f", 0, NULL }, { "input.transfer.low", ST_FLAG_RW | ST_FLAG_STRING, 10, "UPS.BELKINConfig.BELKINLowVoltageTransfer", NULL, "%.0f", 0, NULL }, { "input.transfer.low.max", 0, 0, "UPS.BELKINConfig.BELKINLowVoltageTransferMax", NULL, "%.0f", 0, NULL }, { "input.transfer.low.min", 0, 0, "UPS.BELKINConfig.BELKINLowVoltageTransferMin", NULL, "%.0f", 0, NULL }, { "input.voltage", 0, 0, "UPS.BELKINPowerState.BELKINInput.BELKINVoltage", NULL, "%s", 0, divide_by_10_conversion }, { "input.voltage.nominal", 0, 0, "UPS.BELKINConfig.BELKINConfigVoltage", NULL, "%.0f", 0, NULL }, { "output.frequency", 0, 0, "UPS.BELKINPowerState.BELKINOutput.BELKINFrequency", NULL, "%s", 0, divide_by_10_conversion }, { "output.voltage", 0, 0, "UPS.BELKINPowerState.BELKINOutput.BELKINVoltage", NULL, "%s", 0, divide_by_10_conversion }, { "ups.beeper.status", 0, 0, "UPS.BELKINControls.BELKINAudibleAlarmControl", NULL, "%s", 0, beeper_info }, { "ups.delay.start", ST_FLAG_RW | ST_FLAG_STRING, 10, "UPS.BELKINControls.BELKINDelayBeforeStartup", NULL, DEFAULT_ONDELAY, HU_FLAG_ABSENT, NULL }, { "ups.delay.shutdown", ST_FLAG_RW | ST_FLAG_STRING, 10, "UPS.BELKINControls.BELKINDelayBeforeShutdown", NULL, DEFAULT_OFFDELAY, HU_FLAG_ABSENT, NULL }, { "ups.timer.start", 0, 0, "UPS.BELKINControls.BELKINDelayBeforeStartup", NULL, "%.0f", HU_FLAG_QUICK_POLL, NULL }, { "ups.timer.shutdown", 0, 0, "UPS.BELKINControls.BELKINDelayBeforeShutdown", NULL, "%.0f", HU_FLAG_QUICK_POLL, NULL }, { "ups.timer.reboot", 0, 0, "UPS.BELKINControls.BELKINDelayBeforeReboot", NULL, "%.0f", HU_FLAG_QUICK_POLL, NULL }, { "ups.firmware", 0, 0, "UPS.BELKINDevice.BELKINUPSType", NULL, "%s", 0, belkin_firmware_conversion }, { "ups.load", 0, 0, "UPS.BELKINPowerState.BELKINOutput.BELKINPercentLoad", NULL, "%.0f", 0, NULL }, { "ups.load.high", 0, 0, "UPS.BELKINConfig.BELKINConfigOverloadTransfer", NULL, "%.0f", 0, NULL }, { "ups.mfr.date", 0, 0, "UPS.PowerSummary.ManufacturerDate", NULL, "%s", 0, date_conversion }, { "ups.power.nominal", 0, 0, "UPS.BELKINConfig.BELKINConfigApparentPower", NULL, "%.0f", 0, NULL }, { "ups.serial", 0, 0, "UPS.PowerSummary.iSerialNumber", NULL, "%s", 0, stringid_conversion }, { "ups.test.result", 0, 0, "UPS.BELKINControls.BELKINTest", NULL, "%s", 0, belkin_test_info }, { "ups.type", 0, 0, "UPS.BELKINDevice.BELKINUPSType", NULL, "%s", 0, belkin_upstype_conversion }, /* Liebert PSA: */ { "battery.charge", 0, 0, "UPS.PowerSummary.RemainingCapacity", NULL, "%.0f", HU_FLAG_QUICK_POLL, NULL }, /* why .broken above? */ { "input.frequency", 0, 0, "UPS.Input.Frequency", NULL, "%s", 0, divide_by_10_conversion }, { "input.voltage", 0, 0, "UPS.Input.Voltage", NULL, "%s", 0, liebert_line_voltage_info }, { "output.voltage", 0, 0, "UPS.Output.Voltage", NULL, "%s", 0, liebert_line_voltage_info }, /* You would think these next two would be off by the same factor. You'd be wrong. */ { "battery.voltage", 0, 0, "UPS.PowerSummary.Voltage", NULL, "%s", 0, liebert_line_voltage_info }, { "battery.voltage.nominal", 0, 0, "UPS.PowerSummary.ConfigVoltage", NULL, "%s", HU_FLAG_STATIC, liebert_config_voltage_info }, { "ups.load", 0, 0, "UPS.Output.PercentLoad", NULL, "%.0f", 0, NULL }, /* status */ { "BOOL", 0, 0, "UPS.PowerSummary.Discharging", NULL, NULL, HU_FLAG_QUICK_POLL, liebert_discharging_info }, /* might not need to be liebert_* version */ { "BOOL", 0, 0, "UPS.PowerSummary.Charging", NULL, NULL, HU_FLAG_QUICK_POLL, liebert_charging_info }, { "BOOL", 0, 0, "UPS.PowerSummary.ShutdownImminent", NULL, NULL, 0, liebert_shutdownimm_info }, { "BOOL", 0, 0, "UPS.PowerSummary.ACPresent", NULL, NULL, HU_FLAG_QUICK_POLL, liebert_online_info }, { "BOOL", 0, 0, "UPS.PowerSummary.PresentStatus.Discharging", NULL, NULL, HU_FLAG_QUICK_POLL, liebert_discharging_info }, { "BOOL", 0, 0, "UPS.PowerSummary.PresentStatus.Charging", NULL, NULL, HU_FLAG_QUICK_POLL, liebert_charging_info }, { "BOOL", 0, 0, "UPS.PowerSummary.PresentStatus.ShutdownImminent", NULL, NULL, 0, liebert_shutdownimm_info }, { "BOOL", 0, 0, "UPS.PowerSummary.PresentStatus.ACPresent", NULL, NULL, HU_FLAG_QUICK_POLL, liebert_online_info }, { "BOOL", 0, 0, "UPS.PowerSummary.PresentStatus.NeedReplacement", NULL, NULL, HU_FLAG_QUICK_POLL, liebert_replacebatt_info }, { "BOOL", 0, 0, "UPS.PowerSummary.PresentStatus.BelowRemainingCapacityLimit", NULL, NULL, HU_FLAG_QUICK_POLL, liebert_lowbatt_info }, /* { "BOOL", 0, 0, "UPS.PowerSummary.BelowRemainingCapacityLimit", NULL, "%s", 0, lowbatt_info }, broken! */ { "BOOL", 0, 0, "UPS.BELKINStatus.BELKINPowerStatus", NULL, NULL, 0, belkin_overload_conversion }, { "BOOL", 0, 0, "UPS.BELKINStatus.BELKINPowerStatus", NULL, NULL, 0, belkin_overheat_conversion }, { "BOOL", 0, 0, "UPS.BELKINStatus.BELKINPowerStatus", NULL, NULL, 0, belkin_commfault_conversion }, { "BOOL", 0, 0, "UPS.BELKINStatus.BELKINPowerStatus", NULL, NULL, 0, belkin_awaitingpower_conversion }, { "BOOL", 0, 0, "UPS.BELKINStatus.BELKINPowerStatus", NULL, NULL, HU_FLAG_QUICK_POLL, belkin_online_conversion }, { "BOOL", 0, 0, "UPS.BELKINStatus.BELKINBatteryStatus", NULL, NULL, HU_FLAG_QUICK_POLL, belkin_depleted_conversion }, { "BOOL", 0, 0, "UPS.BELKINStatus.BELKINBatteryStatus", NULL, NULL, 0, belkin_replacebatt_conversion }, { "BOOL", 0, 0, "UPS.BELKINStatus.BELKINBatteryStatus", NULL, NULL, HU_FLAG_QUICK_POLL, belkin_lowbatt_conversion }, /* instant commands. */ /* split into subsets while waiting for extradata support * ie: test.battery.start quick */ { "test.battery.start.quick", 0, 0, "UPS.BELKINControls.BELKINTest", NULL, "1", HU_TYPE_CMD, NULL }, { "test.battery.start.deep", 0, 0, "UPS.BELKINControls.BELKINTest", NULL, "2", HU_TYPE_CMD, NULL }, { "test.battery.stop", 0, 0, "UPS.BELKINControls.BELKINTest", NULL, "3", HU_TYPE_CMD, NULL }, { "beeper.on", 0, 0, "UPS.BELKINControls.BELKINAudibleAlarmControl", NULL, "2", HU_TYPE_CMD, NULL }, { "beeper.off", 0, 0, "UPS.BELKINControls.BELKINAudibleAlarmControl", NULL, "3", HU_TYPE_CMD, NULL }, { "beeper.disable", 0, 0, "UPS.BELKINControls.BELKINAudibleAlarmControl", NULL, "1", HU_TYPE_CMD, NULL }, { "beeper.enable", 0, 0, "UPS.BELKINControls.BELKINAudibleAlarmControl", NULL, "2", HU_TYPE_CMD, NULL }, { "beeper.mute", 0, 0, "UPS.BELKINControls.BELKINAudibleAlarmControl", NULL, "3", HU_TYPE_CMD, NULL }, { "load.off", 0, 0, "UPS.BELKINControls.BELKINDelayBeforeShutdown", NULL, "1", HU_TYPE_CMD, NULL }, { "load.on", 0, 0, "UPS.BELKINControls.BELKINDelayBeforeStartup", NULL, "1", HU_TYPE_CMD, NULL }, { "load.off.delay", 0, 0, "UPS.BELKINControls.BELKINDelayBeforeShutdown", NULL, DEFAULT_OFFDELAY, HU_TYPE_CMD, NULL }, { "load.on.delay", 0, 0, "UPS.BELKINControls.BELKINDelayBeforeStartup", NULL, DEFAULT_ONDELAY, HU_TYPE_CMD, NULL }, { "shutdown.stop", 0, 0, "UPS.BELKINControls.BELKINDelayBeforeShutdown", NULL, "-1", HU_TYPE_CMD, NULL }, { "shutdown.reboot", 0, 0, "UPS.BELKINControls.BELKINDelayBeforeReboot", NULL, "10", HU_TYPE_CMD, NULL }, /* Note: on my Belkin UPS, there is no way to implement shutdown.return or load.on, even though they should exist in principle. Hopefully other Belkin models will be better designed. Fixme: fill in the appropriate instant commands. For a more detailed description of the problem and a possible (but not yet implemented) workaround, see the belkinunv(8) man page. -PS 2005/08/28 */ #if WITH_UNMAPPED_DATA_POINTS /* added for debugging Liebert GXT3 : */ { "unmapped.ups.powersummary.iserialnumber", 0, 0, "UPS.PowerSummary.iSerialNumber", NULL, "%.0f", 0, NULL }, { "unmapped.ups.powersummary.imanufacturer", 0, 0, "UPS.PowerSummary.iManufacturer", NULL, "%.0f", 0, NULL }, { "unmapped.ups.powersummary.ioeminformation", 0, 0, "UPS.PowerSummary.iOEMInformation", NULL, "%s", 0, stringid_conversion }, { "unmapped.ups.powersummary.designcapacity", 0, 0, "UPS.PowerSummary.DesignCapacity", NULL, "%.0f", 0, NULL }, { "unmapped.ups.powersummary.remainingtimelimit", 0, 0, "UPS.PowerSummary.RemainingTimeLimit", NULL, "%.0f", 0, NULL }, { "unmapped.ups.powersummary.capacitymode", 0, 0, "UPS.PowerSummary.CapacityMode", NULL, "%.0f", 0, NULL }, { "unmapped.ups.powersummary.rechargeable", 0, 0, "UPS.PowerSummary.Rechargeable", NULL, "%.0f", 0, NULL }, { "unmapped.ups.powersummary.batterypresent", 0, 0, "UPS.PowerSummary.BatteryPresent", NULL, "%.0f", 0, NULL }, { "unmapped.ups.powersummary.fullchargecapacity", 0, 0, "UPS.PowerSummary.FullChargeCapacity", NULL, "%.0f", 0, NULL }, { "unmapped.ups.powersummary.capacitygranularity1", 0, 0, "UPS.PowerSummary.CapacityGranularity1", NULL, "%.0f", 0, NULL }, { "unmapped.ups.powersummary.capacitygranularity2", 0, 0, "UPS.PowerSummary.CapacityGranularity2", NULL, "%.0f", 0, NULL }, { "unmapped.ups.powersummary.iproduct", 0, 0, "UPS.PowerSummary.iProduct", NULL, "%.0f", 0, NULL }, #endif /* if WITH_UNMAPPED_DATA_POINTS */ /* end of structure. */ { NULL, 0, 0, NULL, NULL, NULL, 0, NULL } }; static const char *belkin_format_model(HIDDevice_t *hd) { if ((hd->Product) && (strlen(hd->Product) > 0)) { return hd->Product; } return "unknown"; } static const char *belkin_format_mfr(HIDDevice_t *hd) { const char *mfr; mfr = hd->Vendor ? hd->Vendor : "Belkin"; /* trim leading whitespace */ while (*mfr == ' ') { mfr++; } if (strlen(mfr) == 0) { mfr = "Belkin"; } return mfr; } static const char *belkin_format_serial(HIDDevice_t *hd) { char serial[64]; if (hd->Serial) { return hd->Serial; } /* try UPS.PowerSummary.iSerialNumber */ HIDGetItemString(udev, "UPS.PowerSummary.iSerialNumber", serial, sizeof(serial), belkin_utab); if (strlen(serial) < 1) { return NULL; } /* free(hd->Serial); not needed, we already know it is NULL */ hd->Serial = strdup(serial); return hd->Serial; } /* this function allows the subdriver to "claim" a device: return 1 if * the device is supported by this subdriver, else 0. */ static int belkin_claim(HIDDevice_t *hd) { int status = is_usb_device_supported(belkin_usb_device_table, hd); switch (status) { case POSSIBLY_SUPPORTED: switch (hd->VendorID) { case BELKIN_VENDORID: /* reject any known non-UPS */ if (hd->ProductID == 0x0218) /* F5U218-MOB 4-Port USB Hub */ return 0; /* by default, reject, unless the productid option is given */ if (getval("productid")) { return 1; } possibly_supported("Belkin", hd); return 0; case LIEBERT_VENDORID: /* by default, reject, unless the productid option is given */ if (getval("productid")) { return 1; } possibly_supported("Liebert", hd); return 0; } return 0; case SUPPORTED: return 1; case NOT_SUPPORTED: default: return 0; } } subdriver_t belkin_subdriver = { BELKIN_HID_VERSION, belkin_claim, belkin_utab, belkin_hid2nut, belkin_format_model, belkin_format_mfr, belkin_format_serial, fix_report_desc, }; nut-2.8.1/drivers/apc-iem-mib.h0000644000175000017500000000126614500336654013173 00000000000000#ifndef APC_IEM_MIB_H #define APC_IEM_MIB_H /* * FIXME: The below is needed because the main driver body uses this to determine * whether a conversion from Fahrenheit to Celsius is needed (which really should * be solved in subdriver specific formatting functions, like we do in usbhid-ups * This is used in both snmp-ups.c and apc.c logics. */ /* IEM ambient variables */ /* IEM: integrated environment monitor probe */ #define APCC_OID_IEM_TEMP ".1.3.6.1.4.1.318.1.1.10.2.3.2.1.4.1" #define APCC_OID_IEM_TEMP_UNIT ".1.3.6.1.4.1.318.1.1.10.2.3.2.1.5.1" #define APCC_IEM_FAHRENHEIT 2 #define APCC_OID_IEM_HUMID ".1.3.6.1.4.1.318.1.1.10.2.3.2.1.6.1" #endif /* APC_IEM_MIB_H */ nut-2.8.1/drivers/nutdrv_qx_hunnox.c0000644000175000017500000001515514501607135014535 00000000000000/* nutdrv_qx_hunnox.c - Subdriver for Hunnox protocol based UPSes * * Copyright (C) * 2013 Daniele Pezzini * 2020 Mariano Jan https://marianojan.com * * 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 2 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, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #include "main.h" #include "nutdrv_qx.h" #include "nutdrv_qx_blazer-common.h" #include "nutdrv_qx_hunnox.h" #define HUNNOX_VERSION "Hunnox 0.02" /* qx2nut lookup table */ static item_t hunnox_qx2nut[] = { /* * > [Q1\r] * < [(226.0 195.0 226.0 014 49.0 27.5 30.0 00001000\r] * 01234567890123456789012345678901234567890123456 * 0 1 2 3 4 */ { "input.voltage", 0, NULL, "Q1\r", "", 47, '(', "", 1, 5, "%.1f", QX_FLAG_QUICK_POLL, NULL, NULL, NULL }, { "input.voltage.fault", 0, NULL, "Q1\r", "", 47, '(', "", 7, 11, "%.1f", QX_FLAG_QUICK_POLL, NULL, NULL, NULL }, { "output.voltage", 0, NULL, "Q1\r", "", 47, '(', "", 13, 17, "%.1f", QX_FLAG_QUICK_POLL, NULL, NULL, NULL }, { "ups.load", 0, NULL, "Q1\r", "", 47, '(', "", 19, 21, "%.0f", QX_FLAG_QUICK_POLL, NULL, NULL, NULL }, { "input.frequency", 0, NULL, "Q1\r", "", 47, '(', "", 23, 26, "%.1f", QX_FLAG_QUICK_POLL, NULL, NULL, NULL }, { "battery.voltage", 0, NULL, "Q1\r", "", 47, '(', "", 28, 31, "%.2f", QX_FLAG_QUICK_POLL, NULL, NULL, qx_multiply_battvolt }, { "ups.temperature", 0, NULL, "Q1\r", "", 47, '(', "", 33, 36, "%.1f", QX_FLAG_QUICK_POLL, NULL, NULL, NULL }, /* Status bits */ { "ups.status", 0, NULL, "Q1\r", "", 47, '(', "", 38, 38, NULL, QX_FLAG_QUICK_POLL, NULL, NULL, blazer_process_status_bits }, /* Utility Fail (Immediate) */ { "ups.status", 0, NULL, "Q1\r", "", 47, '(', "", 39, 39, NULL, QX_FLAG_QUICK_POLL, NULL, NULL, blazer_process_status_bits }, /* Battery Low */ { "ups.status", 0, NULL, "Q1\r", "", 47, '(', "", 40, 40, NULL, QX_FLAG_QUICK_POLL, NULL, NULL, blazer_process_status_bits }, /* Bypass/Boost or Buck Active */ { "ups.alarm", 0, NULL, "Q1\r", "", 47, '(', "", 41, 41, NULL, 0, NULL, NULL, blazer_process_status_bits }, /* UPS Failed */ { "ups.type", 0, NULL, "Q1\r", "", 47, '(', "", 42, 42, "%s", QX_FLAG_STATIC, NULL, NULL, blazer_process_status_bits }, /* UPS Type */ { "ups.status", 0, NULL, "Q1\r", "", 47, '(', "", 43, 43, NULL, QX_FLAG_QUICK_POLL, NULL, NULL, blazer_process_status_bits }, /* Test in Progress */ { "ups.status", 0, NULL, "Q1\r", "", 47, '(', "", 44, 44, NULL, QX_FLAG_QUICK_POLL, NULL, NULL, blazer_process_status_bits }, /* Shutdown Active */ { "ups.beeper.status", 0, NULL, "Q1\r", "", 47, '(', "", 45, 45, "%s", 0, NULL, NULL, blazer_process_status_bits }, /* Beeper status */ /* * > [F\r] * < [#220.0 000 024.0 50.0\r] * 0123456789012345678901 * 0 1 2 */ { "input.voltage.nominal", 0, NULL, "F\r", "", 22, '#', "", 1, 5, "%.0f", QX_FLAG_STATIC, NULL, NULL, NULL }, { "input.current.nominal", 0, NULL, "F\r", "", 22, '#', "", 7, 9, "%.1f", QX_FLAG_STATIC, NULL, NULL, NULL }, { "battery.voltage.nominal", 0, NULL, "F\r", "", 22, '#', "", 11, 15, "%.1f", QX_FLAG_STATIC, NULL, NULL, NULL }, { "input.frequency.nominal", 0, NULL, "F\r", "", 22, '#', "", 17, 20, "%.0f", QX_FLAG_STATIC, NULL, NULL, NULL }, /* * > [FW?\r] * < [#------------- ------ VT12046Q \r] * 012345678901234567890123456789012345678 * 0 1 2 3 */ { "device.mfr", 0, NULL, "FW?\r", "", 39, '#', "", 1, 15, "%s", QX_FLAG_STATIC | QX_FLAG_TRIM, NULL, NULL, NULL }, { "device.model", 0, NULL, "FW?\r", "", 39, '#', "", 17, 26, "%s", QX_FLAG_STATIC | QX_FLAG_TRIM, NULL, NULL, NULL }, { "ups.firmware", 0, NULL, "FW?\r", "", 39, '#', "", 28, 37, "%s", QX_FLAG_STATIC | QX_FLAG_TRIM, NULL, NULL, NULL }, /* Instant commands */ { "beeper.toggle", 0, NULL, "Q\r", "", 0, 0, "", 0, 0, NULL, QX_FLAG_CMD, NULL, NULL, NULL }, { "load.off", 0, NULL, "S00R0000\r", "", 0, 0, "", 0, 0, NULL, QX_FLAG_CMD, NULL, NULL, NULL }, { "load.on", 0, NULL, "C\r", "", 0, 0, "", 0, 0, NULL, QX_FLAG_CMD, NULL, NULL, NULL }, { "shutdown.return", 0, NULL, "S%s\r", "", 0, 0, "", 0, 0, NULL, QX_FLAG_CMD, NULL, NULL, blazer_process_command }, { "shutdown.stayoff", 0, NULL, "S%sR0000\r", "", 0, 0, "", 0, 0, NULL, QX_FLAG_CMD, NULL, NULL, blazer_process_command }, { "shutdown.stop", 0, NULL, "C\r", "", 0, 0, "", 0, 0, NULL, QX_FLAG_CMD, NULL, NULL, NULL }, { "test.battery.start", 0, NULL, "T%02d\r", "", 0, 0, "", 0, 0, NULL, QX_FLAG_CMD, NULL, NULL, blazer_process_command }, { "test.battery.start.deep", 0, NULL, "TL\r", "", 0, 0, "", 0, 0, NULL, QX_FLAG_CMD, NULL, NULL, NULL }, { "test.battery.start.quick", 0, NULL, "T\r", "", 0, 0, "", 0, 0, NULL, QX_FLAG_CMD, NULL, NULL, NULL }, { "test.battery.stop", 0, NULL, "CT\r", "", 0, 0, "", 0, 0, NULL, QX_FLAG_CMD, NULL, NULL, NULL }, /* Server-side settable vars */ { "ups.delay.start", ST_FLAG_RW, blazer_r_ondelay, NULL, "", 0, 0, "", 0, 0, "0", QX_FLAG_ABSENT | QX_FLAG_SETVAR | QX_FLAG_RANGE, NULL, NULL, blazer_process_setvar }, { "ups.delay.shutdown", ST_FLAG_RW, blazer_r_offdelay, NULL, "", 0, 0, "", 0, 0, "60", QX_FLAG_ABSENT | QX_FLAG_SETVAR | QX_FLAG_RANGE, NULL, NULL, blazer_process_setvar }, /* End of structure. */ { NULL, 0, NULL, NULL, "", 0, 0, "", 0, 0, NULL, 0, NULL, NULL, NULL } }; /* Testing table */ #ifdef TESTING static testing_t hunnox_testing[] = { { "Q1\r", "(215.0 195.0 230.0 014 49.0 22.7 30.0 00000000\r", -1 }, { "F\r", "#230.0 000 024.0 50.0\r", -1 }, { "FW?\r", "#NOT_A_LIVE_UPS TESTING TESTING \r", -1 }, { "Q\r", "", -1 }, { "S03\r", "", -1 }, { "C\r", "", -1 }, { "S02R0005\r", "", -1 }, { "S.5R0000\r", "", -1 }, { "T04\r", "", -1 }, { "TL\r", "", -1 }, { "T\r", "", -1 }, { "CT\r", "", -1 }, { NULL } }; #endif /* TESTING */ /* Subdriver-specific initups */ static void hunnox_initups(void) { blazer_initups(hunnox_qx2nut); } /* Subdriver interface */ subdriver_t hunnox_subdriver = { HUNNOX_VERSION, blazer_claim, hunnox_qx2nut, hunnox_initups, NULL, blazer_makevartable, "UPS No Ack", NULL, #ifdef TESTING hunnox_testing, #endif /* TESTING */ }; nut-2.8.1/drivers/emerson-avocent-pdu-mib.h0000644000175000017500000000223714377374134015561 00000000000000/* emerson-avocent-pdu-mib.h - subdriver to monitor Emerson Avocent PDUs with NUT * * Copyright (C) * 2008-2018 Arnaud Quette * 2009 Opengear * 2018 Eaton (Arnaud Quette ) * * 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 2 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, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef EMERSON_AVOCENT_PDU_MIB_H #define EMERSON_AVOCENT_PDU_MIB_H #include "main.h" #include "snmp-ups.h" extern mib2nut_info_t emerson_avocent_pdu; #endif /* EMERSON_AVOCENT_PDU_MIB_H */ nut-2.8.1/drivers/cps-hid.c0000644000175000017500000003367114501607135012436 00000000000000/* cps-hid.c - subdriver to monitor CPS USB/HID devices with NUT * * Copyright (C) * 2003 - 2008 Arnaud Quette * 2005 - 2006 Peter Selinger * 2020 - 2022 Jim Klimov * * Note: this subdriver was initially generated as a "stub" by the * gen-usbhid-subdriver script. It must be customized. * * 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 2 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, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #include "main.h" /* for getval() */ #include "nut_float.h" #include "hidparser.h" /* for FindObject_with_ID_Node() */ #include "usbhid-ups.h" #include "cps-hid.h" #include "usb-common.h" #define CPS_HID_VERSION "CyberPower HID 0.8" /* Cyber Power Systems */ #define CPS_VENDORID 0x0764 /* Values for correcting the HID on some models * where LogMin and LogMax are set incorrectly in the HID. */ #define CPS_VOLTAGE_LOGMIN 0 #define CPS_VOLTAGE_LOGMAX 511 /* Includes safety margin. */ /*! Battery voltage scale factor. * For some devices, the reported battery voltage is off by factor * of 1.5 so we need to apply a scale factor to it to get the real * battery voltage. By default, the factor is 1 (no scaling). */ static double battery_scale = 1; static int might_need_battery_scale = 0; static int battery_scale_checked = 0; /*! If the ratio of the battery voltage to the nominal battery voltage exceeds * this factor, we assume that the battery voltage needs to be scaled by 2/3. */ static const double battery_voltage_sanity_check = 1.4; static void *cps_battery_scale(USBDevice_t *device) { NUT_UNUSED_VARIABLE(device); might_need_battery_scale = 1; return NULL; } /* USB IDs device table */ static usb_device_id_t cps_usb_device_table[] = { /* 900AVR/BC900D */ { USB_DEVICE(CPS_VENDORID, 0x0005), NULL }, /* Dynex DX-800U?, CP1200AVR/BC1200D, CP825AVR-G, CP1000AVRLCD, CP1000PFCLCD, CP1500C, CP550HG, etc. */ { USB_DEVICE(CPS_VENDORID, 0x0501), &cps_battery_scale }, /* OR2200LCDRM2U, OR700LCDRM1U, PR6000LCDRTXL5U */ { USB_DEVICE(CPS_VENDORID, 0x0601), NULL }, /* Terminating entry */ { 0, 0, NULL } }; /*! Adjusts @a battery_scale if voltage is well above nominal. */ static void cps_adjust_battery_scale(double batt_volt) { const char *batt_volt_nom_str; double batt_volt_nom; if(battery_scale_checked) { return; } batt_volt_nom_str = dstate_getinfo("battery.voltage.nominal"); if(!batt_volt_nom_str) { upsdebugx(2, "%s: 'battery.voltage.nominal' not available yet; skipping scale determination", __func__); return; } batt_volt_nom = strtod(batt_volt_nom_str, NULL); if(d_equal(batt_volt_nom, 0)) { upsdebugx(3, "%s: 'battery.voltage.nominal' is %s", __func__, batt_volt_nom_str); return; } if( (batt_volt / batt_volt_nom) > battery_voltage_sanity_check ) { upslogx(LOG_INFO, "%s: battery readings will be scaled by 2/3", __func__); battery_scale = 2.0/3; } battery_scale_checked = 1; } /* returns statically allocated string - must not use it again before done with result! */ static const char *cps_battvolt_fun(double value) { static char buf[8]; if(might_need_battery_scale) { cps_adjust_battery_scale(value); } upsdebugx(5, "%s: battery_scale = %.3f", __func__, battery_scale); snprintf(buf, sizeof(buf), "%.1f", battery_scale * value); return buf; } static info_lkp_t cps_battvolt[] = { { 0, NULL, &cps_battvolt_fun, NULL } }; /* returns statically allocated string - must not use it again before done with result! */ static const char *cps_battcharge_fun(double value) { static char buf[8]; /* clamp battery charge to 100% */ snprintf(buf, sizeof(buf), "%.0f", value < 100.0 ? value : 100.0); return buf; } static info_lkp_t cps_battcharge[] = { { 0, NULL, &cps_battcharge_fun, NULL } }; /* --------------------------------------------------------------- */ /* Vendor-specific usage table */ /* --------------------------------------------------------------- */ /* CPS usage table */ static usage_lkp_t cps_usage_lkp[] = { { NULL, 0x0 } }; static usage_tables_t cps_utab[] = { cps_usage_lkp, hid_usage_lkp, NULL, }; /* --------------------------------------------------------------- */ /* HID2NUT lookup table */ /* --------------------------------------------------------------- */ static hid_info_t cps_hid2nut[] = { #if WITH_UNMAPPED_DATA_POINTS { "unmapped.ups.powersummary.rechargeable", 0, 0, "UPS.PowerSummary.Rechargeable", NULL, "%.0f", 0, NULL }, { "unmapped.ups.powersummary.capacitymode", 0, 0, "UPS.PowerSummary.CapacityMode", NULL, "%.0f", 0, NULL }, { "unmapped.ups.powersummary.designcapacity", 0, 0, "UPS.PowerSummary.DesignCapacity", NULL, "%.0f", 0, NULL }, { "unmapped.ups.powersummary.capacitygranularity1", 0, 0, "UPS.PowerSummary.CapacityGranularity1", NULL, "%.0f", 0, NULL }, { "unmapped.ups.powersummary.capacitygranularity2", 0, 0, "UPS.PowerSummary.CapacityGranularity2", NULL, "%.0f", 0, NULL }, { "unmapped.ups.powersummary.fullchargecapacity", 0, 0, "UPS.PowerSummary.FullChargeCapacity", NULL, "%.0f", 0, NULL }, #endif /* if WITH_UNMAPPED_DATA_POINTS */ /* Battery page */ { "battery.type", 0, 0, "UPS.PowerSummary.iDeviceChemistry", NULL, "%s", 0, stringid_conversion }, { "battery.mfr.date", ST_FLAG_RW | ST_FLAG_STRING, 10, "UPS.Battery.ManufacturerDate", NULL, "%s", HU_FLAG_SEMI_STATIC, date_conversion }, { "battery.mfr.date", 0, 0, "UPS.PowerSummary.iOEMInformation", NULL, "%s", 0, stringid_conversion }, { "battery.charge.warning", 0, 0, "UPS.PowerSummary.WarningCapacityLimit", NULL, "%.0f", 0, NULL }, { "battery.charge.low", ST_FLAG_RW | ST_FLAG_STRING, 10, "UPS.PowerSummary.RemainingCapacityLimit", NULL, "%.0f", HU_FLAG_SEMI_STATIC, NULL }, { "battery.charge", 0, 0, "UPS.PowerSummary.RemainingCapacity", NULL, "%s", 0, cps_battcharge }, { "battery.runtime", 0, 0, "UPS.PowerSummary.RunTimeToEmpty", NULL, "%.0f", 0, NULL }, { "battery.runtime.low", ST_FLAG_RW | ST_FLAG_STRING, 10, "UPS.PowerSummary.RemainingTimeLimit", NULL, "%.0f", HU_FLAG_SEMI_STATIC, NULL }, { "battery.voltage.nominal", 0, 0, "UPS.PowerSummary.ConfigVoltage", NULL, "%.0f", 0, NULL }, { "battery.voltage", 0, 0, "UPS.PowerSummary.Voltage", NULL, "%s", 0, cps_battvolt }, /* UPS page */ { "ups.load", 0, 0, "UPS.Output.PercentLoad", NULL, "%.0f", 0, NULL }, { "ups.beeper.status", 0, 0, "UPS.PowerSummary.AudibleAlarmControl", NULL, "%s", 0, beeper_info }, { "ups.test.result", 0, 0, "UPS.Output.Test", NULL, "%s", 0, test_read_info }, { "ups.realpower.nominal", 0, 0, "UPS.Output.ConfigActivePower", NULL, "%.0f", 0, NULL }, { "ups.delay.start", ST_FLAG_RW | ST_FLAG_STRING, 10, "UPS.Output.DelayBeforeStartup", NULL, DEFAULT_ONDELAY, HU_FLAG_ABSENT, NULL}, { "ups.delay.shutdown", ST_FLAG_RW | ST_FLAG_STRING, 10, "UPS.Output.DelayBeforeShutdown", NULL, DEFAULT_OFFDELAY, HU_FLAG_ABSENT, NULL}, { "ups.timer.start", 0, 0, "UPS.Output.DelayBeforeStartup", NULL, "%.0f", HU_FLAG_QUICK_POLL, NULL}, { "ups.timer.shutdown", 0, 0, "UPS.Output.DelayBeforeShutdown", NULL, "%.0f", HU_FLAG_QUICK_POLL, NULL}, { "ups.timer.reboot", 0, 0, "UPS.Output.DelayBeforeReboot", NULL, "%.0f", HU_FLAG_QUICK_POLL, NULL}, /* Special case: ups.status & ups.alarm */ { "BOOL", 0, 0, "UPS.PowerSummary.PresentStatus.ACPresent", NULL, NULL, HU_FLAG_QUICK_POLL, online_info }, { "BOOL", 0, 0, "UPS.PowerSummary.PresentStatus.Charging", NULL, NULL, HU_FLAG_QUICK_POLL, charging_info }, { "BOOL", 0, 0, "UPS.PowerSummary.PresentStatus.Discharging", NULL, NULL, HU_FLAG_QUICK_POLL, discharging_info }, { "BOOL", 0, 0, "UPS.PowerSummary.PresentStatus.BelowRemainingCapacityLimit", NULL, NULL, HU_FLAG_QUICK_POLL, lowbatt_info }, { "BOOL", 0, 0, "UPS.PowerSummary.PresentStatus.FullyCharged", NULL, NULL, 0, fullycharged_info }, { "BOOL", 0, 0, "UPS.PowerSummary.PresentStatus.RemainingTimeLimitExpired", NULL, NULL, 0, timelimitexpired_info }, { "BOOL", 0, 0, "UPS.Output.Boost", NULL, NULL, 0, boost_info }, { "BOOL", 0, 0, "UPS.Output.Overload", NULL, NULL, 0, overload_info }, /* Input page */ { "input.frequency", 0, 0, "UPS.Input.Frequency", NULL, "%.1f", 0, NULL }, { "input.voltage.nominal", 0, 0, "UPS.Input.ConfigVoltage", NULL, "%.0f", 0, NULL }, { "input.voltage", 0, 0, "UPS.Input.Voltage", NULL, "%.1f", 0, NULL }, { "input.transfer.low", ST_FLAG_RW | ST_FLAG_STRING, 10, "UPS.Input.LowVoltageTransfer", NULL, "%.0f", HU_FLAG_SEMI_STATIC, NULL }, { "input.transfer.high", ST_FLAG_RW | ST_FLAG_STRING, 10, "UPS.Input.HighVoltageTransfer", NULL, "%.0f", HU_FLAG_SEMI_STATIC, NULL }, /* Output page */ { "output.frequency", 0, 0, "UPS.Output.Frequency", NULL, "%.1f", 0, NULL }, { "output.voltage", 0, 0, "UPS.Output.Voltage", NULL, "%.1f", 0, NULL }, { "output.voltage.nominal", 0, 0, "UPS.Output.ConfigVoltage", NULL, "%.0f", 0, NULL }, /* instant commands. */ { "test.battery.start.quick", 0, 0, "UPS.Output.Test", NULL, "1", HU_TYPE_CMD, NULL }, { "test.battery.start.deep", 0, 0, "UPS.Output.Test", NULL, "2", HU_TYPE_CMD, NULL }, { "test.battery.stop", 0, 0, "UPS.Output.Test", NULL, "3", HU_TYPE_CMD, NULL }, { "load.off.delay", 0, 0, "UPS.Output.DelayBeforeShutdown", NULL, DEFAULT_OFFDELAY, HU_TYPE_CMD, NULL }, { "load.on.delay", 0, 0, "UPS.Output.DelayBeforeStartup", NULL, DEFAULT_ONDELAY, HU_TYPE_CMD, NULL }, { "shutdown.stop", 0, 0, "UPS.Output.DelayBeforeShutdown", NULL, "-1", HU_TYPE_CMD, NULL }, { "shutdown.reboot", 0, 0, "UPS.Output.DelayBeforeReboot", NULL, "10", HU_TYPE_CMD, NULL }, { "beeper.on", 0, 0, "UPS.PowerSummary.AudibleAlarmControl", NULL, "2", HU_TYPE_CMD, NULL }, { "beeper.off", 0, 0, "UPS.PowerSummary.AudibleAlarmControl", NULL, "3", HU_TYPE_CMD, NULL }, { "beeper.enable", 0, 0, "UPS.PowerSummary.AudibleAlarmControl", NULL, "2", HU_TYPE_CMD, NULL }, { "beeper.disable", 0, 0, "UPS.PowerSummary.AudibleAlarmControl", NULL, "1", HU_TYPE_CMD, NULL }, { "beeper.mute", 0, 0, "UPS.PowerSummary.AudibleAlarmControl", NULL, "3", HU_TYPE_CMD, NULL }, /* end of structure. */ { NULL, 0, 0, NULL, NULL, NULL, 0, NULL } }; static const char *cps_format_model(HIDDevice_t *hd) { return hd->Product; } static const char *cps_format_mfr(HIDDevice_t *hd) { return hd->Vendor ? hd->Vendor : "CPS"; } static const char *cps_format_serial(HIDDevice_t *hd) { return hd->Serial; } /* this function allows the subdriver to "claim" a device: return 1 if * the device is supported by this subdriver, else 0. */ static int cps_claim(HIDDevice_t *hd) { int status = is_usb_device_supported(cps_usb_device_table, hd); switch (status) { case POSSIBLY_SUPPORTED: /* by default, reject, unless the productid option is given */ if (getval("productid")) { return 1; } possibly_supported("CyberPower", hd); return 0; case SUPPORTED: return 1; case NOT_SUPPORTED: default: return 0; } } /* CPS Models like CP900EPFCLCD/CP1500PFCLCDa return a syntactically legal but incorrect * Report Descriptor whereby the Input High Transfer Max/Min values * are used for the Output Voltage Usage Item limits. * Additionally the Input Voltage LogMax is set incorrectly for EU models. * This corrects them by finding and applying fixed * voltage limits as being more appropriate. */ static int cps_fix_report_desc(HIDDevice_t *pDev, HIDDesc_t *pDesc_arg) { HIDData_t *pData; int vendorID = pDev->VendorID; int productID = pDev->ProductID; if (vendorID != CPS_VENDORID || (productID != 0x0501 && productID != 0x0601)) { return 0; } if (disable_fix_report_desc) { upsdebugx(3, "NOT Attempting Report Descriptor fix for UPS: " "Vendor: %04x, Product: %04x " "(got disable_fix_report_desc in config)", vendorID, productID); return 0; } upsdebugx(3, "Attempting Report Descriptor fix for UPS: Vendor: %04x, Product: %04x", vendorID, productID); /* Apply the fix cautiously by looking for input voltage, high voltage transfer and output voltage report usages. * If the output voltage log min/max equals high voltage transfer log min/max then the bug is present. * To fix it Set both the input and output voltages to pre-defined settings. */ if ((pData=FindObject_with_ID_Node(pDesc_arg, 16, USAGE_POW_HIGH_VOLTAGE_TRANSFER))) { long hvt_logmin = pData->LogMin; long hvt_logmax = pData->LogMax; upsdebugx(4, "Report Descriptor: hvt input LogMin: %ld LogMax: %ld", hvt_logmin, hvt_logmax); if ((pData=FindObject_with_ID_Node(pDesc_arg, 18, USAGE_POW_VOLTAGE))) { long output_logmin = pData->LogMin; long output_logmax = pData->LogMax; upsdebugx(4, "Report Descriptor: output LogMin: %ld LogMax: %ld", output_logmin, output_logmax); if (hvt_logmin == output_logmin && hvt_logmax == output_logmax) { pData->LogMin = CPS_VOLTAGE_LOGMIN; pData->LogMax = CPS_VOLTAGE_LOGMAX; upsdebugx(3, "Fixing Report Descriptor. Set Output Voltage LogMin = %d, LogMax = %d", CPS_VOLTAGE_LOGMIN , CPS_VOLTAGE_LOGMAX); if ((pData=FindObject_with_ID_Node(pDesc_arg, 15, USAGE_POW_VOLTAGE))) { long input_logmin = pData->LogMin; long input_logmax = pData->LogMax; upsdebugx(4, "Report Descriptor: input LogMin: %ld LogMax: %ld", input_logmin, input_logmax); upsdebugx(3, "Fixing Report Descriptor. Set Input Voltage LogMin = %d, LogMax = %d", CPS_VOLTAGE_LOGMIN , CPS_VOLTAGE_LOGMAX); } return 1; } } } return 0; } subdriver_t cps_subdriver = { CPS_HID_VERSION, cps_claim, cps_utab, cps_hid2nut, cps_format_model, cps_format_mfr, cps_format_serial, cps_fix_report_desc, }; nut-2.8.1/drivers/hpe-pdu3-cis-mib.h0000644000175000017500000000213114501607135014045 00000000000000/* hpe_pdu_cis-mib.h - subdriver to monitor HPE_PDU_CIS SNMP devices with NUT * * Copyright (C) * 2011 - 2016 Arnaud Quette * 2022 Eaton (author: Arnaud Quette ) * * 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 2 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, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef HPE_PDU3_CIS_MIB_H #define HPE_PDU3_CIS_MIB_H #include "main.h" #include "snmp-ups.h" extern mib2nut_info_t hpe_pdu3_cis; #endif /* HPE_PDU3_CIS_MIB_H */ nut-2.8.1/drivers/libusb1.c0000644000175000017500000011100714514200703012430 00000000000000/*! * @file libusb1.c * @brief Generic USB communication backend (using libusb 1.0) * * @author Copyright (C) 2016 Eaton * Copyright (C) 2016 Arnaud Quette * Copyright (C) 2021 Jim Klimov * * The logic of this file is ripped from mge-shut driver (also from * Arnaud Quette), which is a "HID over serial link" UPS driver for * Network UPS Tools * * 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 2 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, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * * -------------------------------------------------------------------------- */ #include "config.h" /* for HAVE_LIBUSB_DETACH_KERNEL_DRIVER flag */ #include "common.h" /* for xmalloc, upsdebugx prototypes */ #include "usb-common.h" #include "nut_libusb.h" #include "nut_stdint.h" #define USB_DRIVER_NAME "USB communication driver (libusb 1.0)" #define USB_DRIVER_VERSION "0.46" /* driver description structure */ upsdrv_info_t comm_upsdrv_info = { USB_DRIVER_NAME, USB_DRIVER_VERSION, NULL, 0, { NULL } }; #define MAX_REPORT_SIZE 0x1800 #define MAX_RETRY 3 static void nut_libusb_close(libusb_device_handle *udev); /*! Add USB-related driver variables with addvar() and dstate_setinfo(). * This removes some code duplication across the USB drivers. */ void nut_usb_addvars(void) { const struct libusb_version *v = libusb_get_version(); /* allow -x vendor=X, vendorid=X, product=X, productid=X, serial=X */ addvar(VAR_VALUE, "vendor", "Regular expression to match UPS Manufacturer string"); addvar(VAR_VALUE, "product", "Regular expression to match UPS Product string"); addvar(VAR_VALUE, "serial", "Regular expression to match UPS Serial number"); addvar(VAR_VALUE, "vendorid", "Regular expression to match UPS Manufacturer numerical ID (4 digits hexadecimal)"); addvar(VAR_VALUE, "productid", "Regular expression to match UPS Product numerical ID (4 digits hexadecimal)"); addvar(VAR_VALUE, "bus", "Regular expression to match USB bus name"); addvar(VAR_VALUE, "device", "Regular expression to match USB device name"); addvar(VAR_VALUE, "busport", "Regular expression to match USB bus port name" #if (!defined WITH_USB_BUSPORT) || (!WITH_USB_BUSPORT) /* Not supported by this version of libusb1, * but let's not crash config parsing on * unknown keywords due to such nuances! :) */ " (tolerated but ignored in this build)" #endif ); /* Warning: this feature is inherently non-deterministic! * If you only care to know that at least one of your no-name UPSes is online, * this option can help. If you must really know which one, it will not! */ addvar(VAR_FLAG, "allow_duplicates", "If you have several UPS devices which may not be uniquely " "identified by options above, allow each driver instance with this " "option to take the first match if available, or try another " "(association of driver to device may vary between runs)"); addvar(VAR_VALUE, "usb_set_altinterface", "Force redundant call to usb_set_altinterface() (value=bAlternateSetting; default=0)"); #ifdef LIBUSB_API_VERSION dstate_setinfo("driver.version.usb", "libusb-%u.%u.%u (API: 0x%x)", v->major, v->minor, v->micro, LIBUSB_API_VERSION); #else /* no LIBUSB_API_VERSION */ dstate_setinfo("driver.version.usb", "libusb-%u.%u.%u", v->major, v->minor, v->micro); #endif /* LIBUSB_API_VERSION */ } /* invoke matcher against device */ static inline int matches(USBDeviceMatcher_t *matcher, USBDevice_t *device) { if (!matcher) { return 1; } return matcher->match_function(device, matcher->privdata); } /*! If needed, set the USB alternate interface. * * In NUT 2.7.2 and earlier, the following call was made unconditionally: * usb_set_altinterface(udev, 0); * * Although harmless on Linux and *BSD, this extra call prevents old Tripp Lite * devices from working on Mac OS X (presumably the OS is already setting * altinterface to 0). */ static int nut_usb_set_altinterface(libusb_device_handle *udev) { int altinterface = 0, ret = 0; char *alt_string, *endp = NULL; if(testvar("usb_set_altinterface")) { alt_string = getval("usb_set_altinterface"); if(alt_string) { altinterface = (int)strtol(alt_string, &endp, 10); if(endp && !(endp[0] == 0)) { upslogx(LOG_WARNING, "%s: '%s' is not a valid number", __func__, alt_string); } if(altinterface < 0 || altinterface > 255) { upslogx(LOG_WARNING, "%s: setting bAlternateInterface to %d will probably not work", __func__, altinterface); } } /* set default interface */ upsdebugx(2, "%s: calling libusb_set_interface_alt_setting(udev, %d, %d)", __func__, usb_subdriver.hid_rep_index, altinterface); ret = libusb_set_interface_alt_setting(udev, usb_subdriver.hid_rep_index, altinterface); if(ret != 0) { upslogx(LOG_WARNING, "%s: libusb_set_interface_alt_setting(udev, %d, %d) returned %d (%s)", __func__, usb_subdriver.hid_rep_index, altinterface, ret, libusb_strerror((enum libusb_error)ret) ); } upslogx(LOG_NOTICE, "%s: libusb_set_interface_alt_setting() should not be necessary - " "please email the nut-upsdev list with information about your UPS.", __func__); } else { upsdebugx(3, "%s: skipped libusb_set_interface_alt_setting(udev, %d, 0)", __func__, usb_subdriver.hid_rep_index); } return ret; } /* On success, fill in the curDevice structure and return the report * descriptor length. On failure, return -1. * Note: When callback is not NULL, the report descriptor will be * passed to this function together with the udev and USBDevice_t * information. This callback should return a value > 0 if the device * is accepted, or < 1 if not. If it isn't accepted, the next device * (if any) will be tried, until there are no more devices left. */ static int nut_libusb_open(libusb_device_handle **udevp, USBDevice_t *curDevice, USBDeviceMatcher_t *matcher, int (*callback)(libusb_device_handle *udev, USBDevice_t *hd, usb_ctrl_charbuf rdbuf, usb_ctrl_charbufsize rdlen) ) { int retries; /* libusb-1.0 usb_ctrl_charbufsize is uint16_t and we * want the rdlen vars signed - so taking a wider type */ int32_t rdlen1, rdlen2; /* report descriptor length, method 1+2 */ USBDeviceMatcher_t *m; libusb_device **devlist; ssize_t devcount = 0; size_t devnum; struct libusb_device_descriptor dev_desc; struct libusb_config_descriptor *conf_desc = NULL; const struct libusb_interface_descriptor *if_desc; libusb_device_handle *udev; uint8_t bus_num, device_addr; #if (defined WITH_USB_BUSPORT) && (WITH_USB_BUSPORT) uint8_t bus_port; #endif int ret, res; unsigned char buf[20]; const unsigned char *p; char string[256]; int i; int count_open_EACCESS = 0; int count_open_errors = 0; /* report descriptor */ unsigned char rdbuf[MAX_REPORT_SIZE]; int32_t rdlen; /* libusb base init */ if (libusb_init(NULL) < 0) { libusb_exit(NULL); fatal_with_errno(EXIT_FAILURE, "Failed to init libusb 1.0"); } /* TODO: Find a place for this, from Windows branch made for libusb0.c */ /* #ifdef WIN32 struct usb_bus *busses; busses = usb_get_busses(); #endif */ #ifndef __linux__ /* SUN_LIBUSB (confirmed to work on Solaris and FreeBSD) */ /* Causes a double free corruption in linux if device is detached! */ /* nut_libusb_close(*udevp); */ if (*udevp) libusb_close(*udevp); #endif devcount = libusb_get_device_list(NULL, &devlist); /* devcount may be < 0, loop will get skipped; * its SSIZE_MAX < SIZE_MAX for devnum */ for (devnum = 0; (ssize_t)devnum < devcount; devnum++) { /* int if_claimed = 0; */ libusb_device *device = devlist[devnum]; libusb_get_device_descriptor(device, &dev_desc); upsdebugx(2, "Checking device %" PRIuSIZE " of %" PRIuSIZE " (%04X/%04X)", devnum + 1, devcount, dev_desc.idVendor, dev_desc.idProduct); /* supported vendors are now checked by the supplied matcher */ /* open the device */ ret = libusb_open(device, udevp); if (ret != 0) { upsdebugx(1, "Failed to open device (%04X/%04X), skipping: %s", dev_desc.idVendor, dev_desc.idProduct, libusb_strerror((enum libusb_error)ret)); count_open_errors++; if (ret == LIBUSB_ERROR_ACCESS) { count_open_EACCESS++; } continue; } udev = *udevp; /* collect the identifying information of this device. Note that this is safe, because there's no need to claim an interface for this (and therefore we do not yet need to detach any kernel drivers). */ free(curDevice->Vendor); free(curDevice->Product); free(curDevice->Serial); free(curDevice->Bus); free(curDevice->Device); #if (defined WITH_USB_BUSPORT) && (WITH_USB_BUSPORT) free(curDevice->BusPort); #endif memset(curDevice, '\0', sizeof(*curDevice)); /* Keep the list of items in sync with those matched by * drivers/libusb0.c and tools/nut-scanner/scan_usb.c: */ bus_num = libusb_get_bus_number(device); curDevice->Bus = (char *)malloc(4); if (curDevice->Bus == NULL) { libusb_free_device_list(devlist, 1); fatal_with_errno(EXIT_FAILURE, "Out of memory"); } if (bus_num > 0) { sprintf(curDevice->Bus, "%03d", bus_num); } else { upsdebugx(1, "%s: invalid libusb bus number %i", __func__, bus_num); free(curDevice->Bus); curDevice->Bus = NULL; } device_addr = libusb_get_device_address(device); curDevice->Device = (char *)malloc(4); if (curDevice->Device == NULL) { libusb_free_device_list(devlist, 1); fatal_with_errno(EXIT_FAILURE, "Out of memory"); } if (device_addr > 0) { /* 0 means not available, e.g. lack of platform support */ sprintf(curDevice->Device, "%03d", device_addr); } else { if (devnum <= 999) { /* Log visibly so users know their number discovered * from `lsusb` or `dmesg` (if any) was ignored */ upsdebugx(0, "%s: invalid libusb device address %" PRIu8 ", " "falling back to enumeration order counter %" PRIuSIZE, __func__, device_addr, devnum); sprintf(curDevice->Device, "%03d", (int)devnum); } else { upsdebugx(1, "%s: invalid libusb device address %" PRIu8, __func__, device_addr); free(curDevice->Device); curDevice->Device = NULL; } } #if (defined WITH_USB_BUSPORT) && (WITH_USB_BUSPORT) bus_port = libusb_get_port_number(device); curDevice->BusPort = (char *)malloc(4); if (curDevice->BusPort == NULL) { libusb_free_device_list(devlist, 1); fatal_with_errno(EXIT_FAILURE, "Out of memory"); } if (bus_port > 0) { sprintf(curDevice->BusPort, "%03d", bus_port); } else { upsdebugx(1, "%s: invalid libusb bus number %i", __func__, bus_port); free(curDevice->BusPort); curDevice->BusPort = NULL; } #endif curDevice->VendorID = dev_desc.idVendor; curDevice->ProductID = dev_desc.idProduct; curDevice->bcdDevice = dev_desc.bcdDevice; if (dev_desc.iManufacturer) { retries = MAX_RETRY; while (retries > 0) { ret = libusb_get_string_descriptor_ascii(udev, dev_desc.iManufacturer, (unsigned char*)string, sizeof(string)); if (ret > 0) { curDevice->Vendor = strdup(string); if (curDevice->Vendor == NULL) { libusb_free_device_list(devlist, 1); fatal_with_errno(EXIT_FAILURE, "Out of memory"); } break; } retries--; upsdebugx(1, "%s get iManufacturer failed, retrying...", __func__); } } if (dev_desc.iProduct) { retries = MAX_RETRY; while (retries > 0) { ret = libusb_get_string_descriptor_ascii(udev, dev_desc.iProduct, (unsigned char*)string, sizeof(string)); if (ret > 0) { curDevice->Product = strdup(string); if (curDevice->Product == NULL) { libusb_free_device_list(devlist, 1); fatal_with_errno(EXIT_FAILURE, "Out of memory"); } break; } retries--; upsdebugx(1, "%s get iProduct failed, retrying...", __func__); } } if (dev_desc.iSerialNumber) { retries = MAX_RETRY; while (retries > 0) { ret = libusb_get_string_descriptor_ascii(udev, dev_desc.iSerialNumber, (unsigned char*)string, sizeof(string)); if (ret > 0) { curDevice->Serial = strdup(string); if (curDevice->Serial == NULL) { libusb_free_device_list(devlist, 1); fatal_with_errno(EXIT_FAILURE, "Out of memory"); } break; } retries--; upsdebugx(1, "%s get iSerialNumber failed, retrying...", __func__); } } upsdebugx(2, "- VendorID: %04x", curDevice->VendorID); upsdebugx(2, "- ProductID: %04x", curDevice->ProductID); upsdebugx(2, "- Manufacturer: %s", curDevice->Vendor ? curDevice->Vendor : "unknown"); upsdebugx(2, "- Product: %s", curDevice->Product ? curDevice->Product : "unknown"); upsdebugx(2, "- Serial Number: %s", curDevice->Serial ? curDevice->Serial : "unknown"); upsdebugx(2, "- Bus: %s", curDevice->Bus ? curDevice->Bus : "unknown"); #if (defined WITH_USB_BUSPORT) && (WITH_USB_BUSPORT) upsdebugx(2, "- Bus Port: %s", curDevice->BusPort ? curDevice->BusPort : "unknown"); #endif upsdebugx(2, "- Device: %s", curDevice->Device ? curDevice->Device : "unknown"); upsdebugx(2, "- Device release number: %04x", curDevice->bcdDevice); /* FIXME: extend to Eaton OEMs (HP, IBM, ...) */ if ((curDevice->VendorID == 0x463) && (curDevice->bcdDevice == 0x0202)) { usb_subdriver.hid_desc_index = 1; } upsdebugx(2, "Trying to match device"); for (m = matcher; m; m=m->next) { ret = matches(m, curDevice); if (ret==0) { upsdebugx(2, "Device does not match - skipping"); goto next_device; } else if (ret==-1) { libusb_free_device_list(devlist, 1); fatal_with_errno(EXIT_FAILURE, "matcher"); #ifndef HAVE___ATTRIBUTE__NORETURN # if (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_PUSH_POP) && (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_UNREACHABLE_CODE) # pragma GCC diagnostic push # pragma GCC diagnostic ignored "-Wunreachable-code" # endif goto next_device; # if (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_PUSH_POP) && (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_UNREACHABLE_CODE) # pragma GCC diagnostic pop # endif #endif } else if (ret==-2) { upsdebugx(2, "matcher: unspecified error"); goto next_device; } } /* If we got here, none of the matchers said * that the device is not what we want. */ upsdebugx(2, "Device matches"); upsdebugx(2, "Reading first configuration descriptor"); ret = libusb_get_config_descriptor(device, (uint8_t)usb_subdriver.hid_rep_index, &conf_desc); /*ret = libusb_get_active_config_descriptor(device, &conf_desc);*/ if (ret < 0) upsdebugx(2, "result: %i (%s)", ret, libusb_strerror((enum libusb_error)ret)); /* Now we have matched the device we wanted. Claim it. */ #if defined(HAVE_LIBUSB_KERNEL_DRIVER_ACTIVE) && defined(HAVE_LIBUSB_SET_AUTO_DETACH_KERNEL_DRIVER) /* Due to the way FreeBSD implements libusb_set_auto_detach_kernel_driver(), * check to see if the kernel driver is active before setting * the auto-detach flag. Otherwise, libusb_claim_interface() * with the auto-detach flag only works if the driver is * running as root. * * Is the kernel driver active? Consider the unimplemented * return code to be equivalent to inactive here. */ if((ret = libusb_kernel_driver_active(udev, usb_subdriver.hid_rep_index)) == 1) { upsdebugx(3, "libusb_kernel_driver_active() returned 1 (driver active)"); /* Try the auto-detach kernel driver method. * This function is not available on FreeBSD 10.1-10.3 */ if ((ret = libusb_set_auto_detach_kernel_driver (udev, 1)) != LIBUSB_SUCCESS) { upsdebugx(1, "failed to set kernel driver auto-detach " "driver flag for USB device: %s", libusb_strerror((enum libusb_error)ret)); } else { upsdebugx(2, "successfully set kernel driver auto-detach flag"); } } else { upsdebugx(3, "libusb_kernel_driver_active() returned %d: %s", ret, libusb_strerror((enum libusb_error)ret)); } #endif #if (defined HAVE_LIBUSB_DETACH_KERNEL_DRIVER) || (defined HAVE_LIBUSB_DETACH_KERNEL_DRIVER_NP) /* Then, try the explicit detach method. * This function is available on FreeBSD 10.1-10.3 */ retries = MAX_RETRY; #ifdef WIN32 /* TODO: Align with libusb1 - initially from Windows branch made against libusb0 */ libusb_set_configuration(udev, 1); #endif while ((ret = libusb_claim_interface(udev, usb_subdriver.hid_rep_index)) != LIBUSB_SUCCESS) { upsdebugx(2, "failed to claim USB device: %s", libusb_strerror((enum libusb_error)ret)); if (ret == LIBUSB_ERROR_BUSY && testvar("allow_duplicates")) { upsdebugx(2, "Configured to allow_duplicates so looking for another similar device"); goto next_device; } # ifdef HAVE_LIBUSB_DETACH_KERNEL_DRIVER if ((ret = libusb_detach_kernel_driver(udev, usb_subdriver.hid_rep_index)) != LIBUSB_SUCCESS) { # else /* if defined HAVE_LIBUSB_DETACH_KERNEL_DRIVER_NP) */ if ((ret = libusb_detach_kernel_driver_np(udev, usb_subdriver.hid_rep_index)) != LIBUSB_SUCCESS) { # endif if (ret == LIBUSB_ERROR_NOT_FOUND) { /* logged as "Entity not found" if this persists */ upsdebugx(2, "Kernel driver already detached"); } else { upsdebugx(1, "failed to detach kernel driver from USB device: %s", libusb_strerror((enum libusb_error)ret)); } } else { upsdebugx(2, "detached kernel driver from USB device..."); } if (retries-- > 0) { continue; } libusb_free_config_descriptor(conf_desc); libusb_free_device_list(devlist, 1); fatalx(EXIT_FAILURE, "Can't claim USB device [%04x:%04x]@%d/%d: %s", curDevice->VendorID, curDevice->ProductID, usb_subdriver.hid_rep_index, usb_subdriver.hid_desc_index, libusb_strerror((enum libusb_error)ret)); } #else if ((ret = libusb_claim_interface(udev, usb_subdriver.hid_rep_index)) != LIBUSB_SUCCESS ) { if (ret == LIBUSB_ERROR_BUSY && testvar("allow_duplicates")) { upsdebugx(2, "Configured to allow_duplicates so looking for another similar device"); goto next_device; } libusb_free_config_descriptor(conf_desc); libusb_free_device_list(devlist, 1); fatalx(EXIT_FAILURE, "Can't claim USB device [%04x:%04x]@%d/%d: %s", curDevice->VendorID, curDevice->ProductID, usb_subdriver.hid_rep_index, usb_subdriver.hid_desc_index, libusb_strerror((enum libusb_error)ret)); } #endif /* if_claimed = 1; */ upsdebugx(2, "Claimed interface %d successfully", usb_subdriver.hid_rep_index); nut_usb_set_altinterface(udev); if (!callback) { libusb_free_config_descriptor(conf_desc); libusb_free_device_list(devlist, 1); return 1; } if (!conf_desc) { /* ?? this should never happen */ upsdebugx(2, " Couldn't retrieve descriptors"); goto next_device; } rdlen1 = -1; rdlen2 = -1; /* Get HID descriptor */ /* FIRST METHOD: ask for HID descriptor directly. */ /* libusb0: USB_ENDPOINT_IN + 1 */ res = libusb_control_transfer(udev, LIBUSB_ENDPOINT_IN|LIBUSB_REQUEST_TYPE_STANDARD|LIBUSB_RECIPIENT_INTERFACE, LIBUSB_REQUEST_GET_DESCRIPTOR, (LIBUSB_DT_HID << 8) + usb_subdriver.hid_desc_index, usb_subdriver.hid_rep_index, buf, 0x9, USB_TIMEOUT); if (res < 0) { upsdebugx(2, "Unable to get HID descriptor (%s)", libusb_strerror((enum libusb_error)res)); } else if (res < 9) { upsdebugx(2, "HID descriptor too short (expected %d, got %d)", 9, res); } else { upsdebugx(2, "Retrieved HID descriptor (expected %d, got %d)", 9, res); upsdebug_hex(3, "HID descriptor, method 1", buf, 9); rdlen1 = ((uint8_t)buf[7]) | (((uint8_t)buf[8]) << 8); } if (rdlen1 < -1) { upsdebugx(2, "Warning: HID descriptor, method 1 failed"); } upsdebugx(3, "HID descriptor length (method 1) %d", rdlen1); /* SECOND METHOD: find HID descriptor among "extra" bytes of interface descriptor, i.e., bytes tucked onto the end of descriptor 2. */ /* Note: on some broken UPS's (e.g. Tripp Lite Smart1000LCD), only this second method gives the correct result */ /* for now, we always assume configuration 0, interface 0, altsetting 0, as above. */ if_desc = &(conf_desc->interface[usb_subdriver.hid_rep_index].altsetting[0]); for (i = 0; i < if_desc->extra_length; i += if_desc->extra[i]) { upsdebugx(4, "i=%d, extra[i]=%02x, extra[i+1]=%02x", i, if_desc->extra[i], if_desc->extra[i+1]); if (i+9 <= if_desc->extra_length && if_desc->extra[i] >= 9 && if_desc->extra[i+1] == 0x21) { p = &if_desc->extra[i]; upsdebug_hex(3, "HID descriptor, method 2", p, 9); rdlen2 = ((uint8_t)p[7]) | (((uint8_t)p[8]) << 8); break; } } /* we can now free the config descriptor */ libusb_free_config_descriptor(conf_desc); if (rdlen2 < -1) { upsdebugx(2, "Warning: HID descriptor, method 2 failed"); } upsdebugx(3, "HID descriptor length (method 2) %d", rdlen2); /* when available, always choose the second value, as it seems to be more reliable (it is the one reported e.g. by lsusb). Note: if the need arises, can change this to use the maximum of the two values instead. */ if ((curDevice->VendorID == 0x463) && (curDevice->bcdDevice == 0x0202)) { upsdebugx(1, "Eaton device v2.02. Using full report descriptor"); rdlen = rdlen1; } else { rdlen = rdlen2 >= 0 ? rdlen2 : rdlen1; } if (rdlen < 0) { upsdebugx(2, "Unable to retrieve any HID descriptor"); goto next_device; } if (rdlen1 >= 0 && rdlen2 >= 0 && rdlen1 != rdlen2) { upsdebugx(2, "Warning: two different HID descriptors retrieved " "(Reportlen = %d vs. %d)", rdlen1, rdlen2); } upsdebugx(2, "HID descriptor length %d", rdlen); if (rdlen > (int)sizeof(rdbuf)) { upsdebugx(2, "HID descriptor too long %d (max %d)", rdlen, (int)sizeof(rdbuf)); goto next_device; } #if (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_PUSH_POP) && ( (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_TYPE_LIMITS) || (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_TAUTOLOGICAL_CONSTANT_OUT_OF_RANGE_COMPARE) || (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_TAUTOLOGICAL_UNSIGNED_ZERO_COMPARE) ) # pragma GCC diagnostic push #endif #ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_TYPE_LIMITS # pragma GCC diagnostic ignored "-Wtype-limits" #endif #ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_TAUTOLOGICAL_CONSTANT_OUT_OF_RANGE_COMPARE # pragma GCC diagnostic ignored "-Wtautological-constant-out-of-range-compare" #endif #ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_TAUTOLOGICAL_UNSIGNED_ZERO_COMPARE # pragma GCC diagnostic ignored "-Wtautological-unsigned-zero-compare" #endif if ((uintmax_t)rdlen > UINT16_MAX) { #if (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_PUSH_POP) && ( (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_TYPE_LIMITS) || (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_TAUTOLOGICAL_CONSTANT_OUT_OF_RANGE_COMPARE) || (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_TAUTOLOGICAL_UNSIGNED_ZERO_COMPARE) ) # pragma GCC diagnostic pop #endif upsdebugx(2, "HID descriptor too long %d (max %u)", rdlen, UINT16_MAX); goto next_device; } /* libusb0: USB_ENDPOINT_IN + 1 */ res = libusb_control_transfer(udev, LIBUSB_ENDPOINT_IN|LIBUSB_REQUEST_TYPE_STANDARD|LIBUSB_RECIPIENT_INTERFACE, LIBUSB_REQUEST_GET_DESCRIPTOR, (LIBUSB_DT_REPORT << 8) + usb_subdriver.hid_desc_index, usb_subdriver.hid_rep_index, rdbuf, (uint16_t)rdlen, USB_TIMEOUT); if (res < 0) { upsdebug_with_errno(2, "Unable to get Report descriptor"); goto next_device; } if (res < rdlen) { #ifndef WIN32 upsdebugx(2, "Warning: report descriptor too short " "(expected %d, got %d)", rdlen, res); #else /* https://github.com/networkupstools/nut/issues/1690#issuecomment-1455206002 */ upsdebugx(0, "Warning: report descriptor too short " "(expected %d, got %d)", rdlen, res); upsdebugx(0, "Please check your Windows Device Manager: " "perhaps the UPS was recognized by default OS\n" "driver such as HID UPS Battery (hidbatt.sys, " "hidusb.sys or similar). It could have been\n" "\"restored\" by Windows Update. You can try " "https://zadig.akeo.ie/ to handle it with\n" "either WinUSB, libusb0.sys or libusbK.sys."); #endif /* WIN32 */ rdlen = res; /* correct rdlen if necessary */ } if (rdlen < USB_CTRL_CHARBUFSIZE_MIN || (uintmax_t)rdlen > (uintmax_t)USB_CTRL_CHARBUFSIZE_MAX ) { upsdebugx(2, "Report descriptor length is out of range on this device: " "should be %" PRIdMAX " < %d < %" PRIuMAX, (intmax_t)USB_CTRL_CHARBUFSIZE_MIN, rdlen, (uintmax_t)USB_CTRL_CHARBUFSIZE_MAX); goto next_device; } res = callback(udev, curDevice, rdbuf, (usb_ctrl_charbufsize)rdlen); if (res < 1) { upsdebugx(2, "Caller doesn't like this device"); goto next_device; } upsdebugx(2, "Report descriptor retrieved (Reportlen = %d)", rdlen); upsdebugx(2, "Found HID device"); fflush(stdout); libusb_free_device_list(devlist, 1); return rdlen; next_device: /* usb_release_interface() sometimes blocks and goes into uninterruptible sleep. So don't do it. */ /* if (if_claimed) libusb_release_interface(udev, usb_subdriver.hid_rep_index); */ libusb_close(udev); } *udevp = NULL; libusb_free_device_list(devlist, 1); upsdebugx(2, "libusb1: No appropriate HID device found"); fflush(stdout); if (devcount < 1) { upslogx(LOG_WARNING, "libusb1: Could not open any HID devices: " "no USB buses found"); } else if (count_open_errors > 0 || count_open_errors == count_open_EACCESS ) { upslogx(LOG_WARNING, "libusb1: Could not open any HID devices: " "insufficient permissions on everything"); } return -1; } /* * Error handler for usb_get/set_* functions. Return value > 0 success, * 0 unknown or temporary failure (ignored), < 0 permanent failure (reconnect) */ static int nut_libusb_strerror(const int ret, const char *desc) { if (ret > 0) { return ret; } switch(ret) { #if 0 /* FIXME: not sure how to map these ones! */ case LIBUSB_ERROR_INVALID_PARAM: /** Invalid parameter */ /** System call interrupted (perhaps due to signal) */ case LIBUSB_ERROR_INTERRUPTED: /** Insufficient memory */ case LIBUSB_ERROR_NO_MEM: #endif case LIBUSB_ERROR_BUSY: /** Resource busy */ case LIBUSB_ERROR_NO_DEVICE: /** No such device (it may have been disconnected) */ case LIBUSB_ERROR_ACCESS: /** Access denied (insufficient permissions) */ case LIBUSB_ERROR_IO: /** Input/output error */ case LIBUSB_ERROR_NOT_FOUND: /** Entity not found */ case LIBUSB_ERROR_PIPE: /** Pipe error */ /** Operation not supported or unimplemented on this platform */ case LIBUSB_ERROR_NOT_SUPPORTED: upslogx(LOG_DEBUG, "%s: %s", desc, libusb_strerror((enum libusb_error)ret)); return ret; case LIBUSB_ERROR_TIMEOUT: /** Operation timed out */ upsdebugx(2, "%s: Connection timed out", desc); return 0; #ifndef WIN32 case LIBUSB_ERROR_OVERFLOW: /** Overflow */ # ifdef EPROTO /* FIXME: not sure how to map this one! */ case -EPROTO: /* Protocol error */ # endif upsdebugx(2, "%s: %s", desc, libusb_strerror((enum libusb_error)ret)); return 0; #endif /* WIN32 */ case LIBUSB_ERROR_OTHER: /** Other error */ default: /** Undetermined, log only */ upslogx(LOG_DEBUG, "%s: %s", desc, libusb_strerror((enum libusb_error)ret)); return 0; } } /* return the report of ID=type in report * return -1 on failure, report length on success */ /* Expected evaluated types for the API: * static int nut_libusb_get_report(libusb_device_handle *udev, * int ReportId, unsigned char *raw_buf, int ReportSize) */ static int nut_libusb_get_report( libusb_device_handle *udev, usb_ctrl_repindex ReportId, usb_ctrl_charbuf raw_buf, usb_ctrl_charbufsize ReportSize) { int ret; upsdebugx(4, "Entering libusb_get_report"); #if (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_PUSH_POP) && ( (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_TYPE_LIMITS) || (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_TAUTOLOGICAL_CONSTANT_OUT_OF_RANGE_COMPARE) || (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_TAUTOLOGICAL_UNSIGNED_ZERO_COMPARE) ) # pragma GCC diagnostic push #endif #ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_TYPE_LIMITS # pragma GCC diagnostic ignored "-Wtype-limits" #endif #ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_TAUTOLOGICAL_CONSTANT_OUT_OF_RANGE_COMPARE # pragma GCC diagnostic ignored "-Wtautological-constant-out-of-range-compare" #endif #ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_TAUTOLOGICAL_UNSIGNED_ZERO_COMPARE # pragma GCC diagnostic ignored "-Wtautological-unsigned-zero-compare" #endif if (!udev || ReportId < 0 || (uintmax_t)ReportId > UINT16_MAX || ReportSize < 0 || (uintmax_t)ReportSize > UINT16_MAX ) { #if (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_PUSH_POP) && ( (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_TYPE_LIMITS) || (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_TAUTOLOGICAL_CONSTANT_OUT_OF_RANGE_COMPARE) || (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_TAUTOLOGICAL_UNSIGNED_ZERO_COMPARE) ) # pragma GCC diagnostic pop #endif return 0; } /* libusb0: USB_ENDPOINT_IN + USB_TYPE_CLASS + USB_RECIP_INTERFACE */ ret = libusb_control_transfer(udev, LIBUSB_ENDPOINT_IN|LIBUSB_REQUEST_TYPE_CLASS|LIBUSB_RECIPIENT_INTERFACE, 0x01, /* HID_REPORT_GET */ (uint16_t)ReportId + (0x03<<8), /* HID_REPORT_TYPE_FEATURE */ usb_subdriver.hid_rep_index, raw_buf, (uint16_t)ReportSize, USB_TIMEOUT); /* Ignore "protocol stall" (for unsupported request) on control endpoint */ if (ret == LIBUSB_ERROR_PIPE) { return 0; } return nut_libusb_strerror(ret, __func__); } /* Expected evaluated types for the API: * static int nut_libusb_set_report(libusb_device_handle *udev, * int ReportId, unsigned char *raw_buf, int ReportSize) */ static int nut_libusb_set_report( libusb_device_handle *udev, usb_ctrl_repindex ReportId, usb_ctrl_charbuf raw_buf, usb_ctrl_charbufsize ReportSize) { int ret; #if (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_PUSH_POP) && ( (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_TYPE_LIMITS) || (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_TAUTOLOGICAL_CONSTANT_OUT_OF_RANGE_COMPARE) || (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_TAUTOLOGICAL_UNSIGNED_ZERO_COMPARE) ) # pragma GCC diagnostic push #endif #ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_TYPE_LIMITS # pragma GCC diagnostic ignored "-Wtype-limits" #endif #ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_TAUTOLOGICAL_CONSTANT_OUT_OF_RANGE_COMPARE # pragma GCC diagnostic ignored "-Wtautological-constant-out-of-range-compare" #endif #ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_TAUTOLOGICAL_UNSIGNED_ZERO_COMPARE # pragma GCC diagnostic ignored "-Wtautological-unsigned-zero-compare" #endif if (!udev || ReportId < 0 || (uintmax_t)ReportId > UINT16_MAX || ReportSize < 0 || (uintmax_t)ReportSize > UINT16_MAX ) { #if (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_PUSH_POP) && ( (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_TYPE_LIMITS) || (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_TAUTOLOGICAL_CONSTANT_OUT_OF_RANGE_COMPARE) || (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_TAUTOLOGICAL_UNSIGNED_ZERO_COMPARE) ) # pragma GCC diagnostic pop #endif return 0; } /* libusb0: USB_ENDPOINT_OUT + USB_TYPE_CLASS + USB_RECIP_INTERFACE */ ret = libusb_control_transfer(udev, LIBUSB_ENDPOINT_OUT|LIBUSB_REQUEST_TYPE_CLASS|LIBUSB_RECIPIENT_INTERFACE, 0x09, /* HID_REPORT_SET = 0x09*/ (uint16_t)ReportId + (0x03<<8), /* HID_REPORT_TYPE_FEATURE */ usb_subdriver.hid_rep_index, raw_buf, (uint16_t)ReportSize, USB_TIMEOUT); /* Ignore "protocol stall" (for unsupported request) on control endpoint */ if (ret == LIBUSB_ERROR_PIPE) { return 0; } return nut_libusb_strerror(ret, __func__); } /* Expected evaluated types for the API: * static int nut_libusb_get_string(libusb_device_handle *udev, * int StringIdx, char *buf, int buflen) */ static int nut_libusb_get_string( libusb_device_handle *udev, usb_ctrl_strindex StringIdx, char *buf, usb_ctrl_charbufsize buflen) { int ret; #if (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_PUSH_POP) && ( (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_TYPE_LIMITS) || (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_TAUTOLOGICAL_CONSTANT_OUT_OF_RANGE_COMPARE) || (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_TAUTOLOGICAL_UNSIGNED_ZERO_COMPARE) ) # pragma GCC diagnostic push #endif #ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_TYPE_LIMITS # pragma GCC diagnostic ignored "-Wtype-limits" #endif #ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_TAUTOLOGICAL_CONSTANT_OUT_OF_RANGE_COMPARE # pragma GCC diagnostic ignored "-Wtautological-constant-out-of-range-compare" #endif #ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_TAUTOLOGICAL_UNSIGNED_ZERO_COMPARE # pragma GCC diagnostic ignored "-Wtautological-unsigned-zero-compare" #endif if (!udev || StringIdx < 0 || (uintmax_t)StringIdx > UINT8_MAX || buflen < 0 || (uintmax_t)buflen > (uintmax_t)INT_MAX ) { #if (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_PUSH_POP) && ( (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_TYPE_LIMITS) || (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_TAUTOLOGICAL_CONSTANT_OUT_OF_RANGE_COMPARE) || (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_TAUTOLOGICAL_UNSIGNED_ZERO_COMPARE) ) # pragma GCC diagnostic pop #endif return -1; } ret = libusb_get_string_descriptor_ascii(udev, (uint8_t)StringIdx, (unsigned char*)buf, (int)buflen); return nut_libusb_strerror(ret, __func__); } /* Expected evaluated types for the API: * static int nut_libusb_get_interrupt(libusb_device_handle *udev, * unsigned char *buf, int bufsize, int timeout) */ static int nut_libusb_get_interrupt( libusb_device_handle *udev, usb_ctrl_charbuf buf, usb_ctrl_charbufsize bufsize, usb_ctrl_timeout_msec timeout) { int ret, tmpbufsize; #if (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_PUSH_POP) && ( (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_TYPE_LIMITS) || (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_TAUTOLOGICAL_CONSTANT_OUT_OF_RANGE_COMPARE) || (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_TAUTOLOGICAL_UNSIGNED_ZERO_COMPARE) ) # pragma GCC diagnostic push #endif #ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_TYPE_LIMITS # pragma GCC diagnostic ignored "-Wtype-limits" #endif #ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_TAUTOLOGICAL_CONSTANT_OUT_OF_RANGE_COMPARE # pragma GCC diagnostic ignored "-Wtautological-constant-out-of-range-compare" #endif #ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_TAUTOLOGICAL_UNSIGNED_ZERO_COMPARE # pragma GCC diagnostic ignored "-Wtautological-unsigned-zero-compare" #endif if (!udev || bufsize < 0 || (uintmax_t)bufsize > (uintmax_t)INT_MAX ) { #if (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_PUSH_POP) && ( (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_TYPE_LIMITS) || (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_TAUTOLOGICAL_CONSTANT_OUT_OF_RANGE_COMPARE) || (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_TAUTOLOGICAL_UNSIGNED_ZERO_COMPARE) ) # pragma GCC diagnostic pop #endif return -1; } /* NOTE: With all the fuss about word sized arguments, * the libusb_interrupt_transfer() lengths are about ints: * int LIBUSB_CALL libusb_interrupt_transfer(libusb_device_handle *dev_handle, * unsigned char endpoint, unsigned char *data, int length, * int *actual_length, unsigned int timeout); */ tmpbufsize = (int)bufsize; /* FIXME: hardcoded interrupt EP => need to get EP descr for IF descr */ /* ret = libusb_interrupt_transfer(udev, 0x81, buf, bufsize, &bufsize, timeout); */ /* libusb0: ret = usb_interrupt_read(udev, USB_ENDPOINT_IN + usb_subdriver.hid_ep_in, (char *)buf, bufsize, timeout); */ /* Interrupt EP is LIBUSB_ENDPOINT_IN with offset defined in hid_ep_in, which is 0 by default, unless overridden in subdriver. */ ret = libusb_interrupt_transfer(udev, LIBUSB_ENDPOINT_IN + usb_subdriver.hid_ep_in, (unsigned char *)buf, tmpbufsize, &tmpbufsize, timeout); /* Clear stall condition */ if (ret == LIBUSB_ERROR_PIPE) { ret = libusb_clear_halt(udev, 0x81); } /* In case of success, return the operation size, as done with libusb 0.1 */ if (ret == LIBUSB_SUCCESS) { if (tmpbufsize < 0 || (uintmax_t)tmpbufsize > (uintmax_t)USB_CTRL_CHARBUFSIZE_MAX ) { return -1; } ret = (usb_ctrl_charbufsize)bufsize; } return nut_libusb_strerror(ret, __func__); } static void nut_libusb_close(libusb_device_handle *udev) { if (!udev) { return; } /* usb_release_interface() sometimes blocks and goes * into uninterruptible sleep. So don't do it. */ /* libusb_release_interface(udev, usb_subdriver.hid_rep_index); */ libusb_close(udev); libusb_exit(NULL); } usb_communication_subdriver_t usb_subdriver = { USB_DRIVER_NAME, USB_DRIVER_VERSION, nut_libusb_open, nut_libusb_close, nut_libusb_get_report, nut_libusb_set_report, nut_libusb_get_string, nut_libusb_get_interrupt, LIBUSB_DEFAULT_INTERFACE, LIBUSB_DEFAULT_DESC_INDEX, LIBUSB_DEFAULT_HID_EP_IN, LIBUSB_DEFAULT_HID_EP_OUT }; nut-2.8.1/drivers/mge-hid.c0000644000175000017500000020467114502253356012424 00000000000000/* mge-hid.c - data to monitor Eaton / MGE HID (USB and serial) devices * * Copyright (C) * 2003 - 2015 Arnaud Quette * 2015 - 2016 Eaton / Arnaud Quette * * Sponsored by MGE UPS SYSTEMS * * 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 2 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, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /* TODO list: * - better processing of FW info: * * some models (HP R5000) include firmware.aux (00.01.0021;00.01.00) * * other (9130) need more processing (0128 => 1.28) * ... * - better handling of input.transfer.* (need dstate_addrange) * - outlet management logic (Ie, for outlet.X.load.{on,off}.delay * => use outlet.X.delay.{start,stop} */ #include "main.h" /* for getval() */ #include "usbhid-ups.h" #include "mge-hid.h" #include "nut_float.h" #include "timehead.h" #define MGE_HID_VERSION "MGE HID 1.46" /* (prev. MGE Office Protection Systems, prev. MGE UPS SYSTEMS) */ /* Eaton */ #define MGE_VENDORID 0x0463 /* Dell */ #define DELL_VENDORID 0x047c /* Powerware */ #define POWERWARE_VENDORID 0x0592 /* Hewlett Packard */ #define HP_VENDORID 0x03f0 /* AEG */ #define AEG_VENDORID 0x2b2d /* Note that normally this VID is handled by Liebert/Phoenixtec HID mapping, * here it is just for for AEG PROTECT NAS devices: */ /* Phoenixtec Power Co., Ltd */ #define PHOENIXTEC 0x06da /* IBM */ #define IBM_VENDORID 0x04b3 #if !((defined SHUT_MODE) && SHUT_MODE) #include "usb-common.h" /* USB IDs device table */ static usb_device_id_t mge_usb_device_table[] = { /* various models */ { USB_DEVICE(MGE_VENDORID, 0x0001), NULL }, { USB_DEVICE(MGE_VENDORID, 0xffff), NULL }, /* various models */ { USB_DEVICE(DELL_VENDORID, 0xffff), NULL }, /* PW 9140 */ { USB_DEVICE(POWERWARE_VENDORID, 0x0004), NULL }, /* R/T3000 */ { USB_DEVICE(HP_VENDORID, 0x1fe5), NULL }, /* R/T3000 */ { USB_DEVICE(HP_VENDORID, 0x1fe6), NULL }, /* various models */ { USB_DEVICE(HP_VENDORID, 0x1fe7), NULL }, { USB_DEVICE(HP_VENDORID, 0x1fe8), NULL }, /* PROTECT B / NAS */ { USB_DEVICE(AEG_VENDORID, 0xffff), NULL }, { USB_DEVICE(PHOENIXTEC, 0xffff), NULL }, /* 6000 VA LCD 4U Rack UPS; 5396-1Kx */ { USB_DEVICE(IBM_VENDORID, 0x0001), NULL }, /* Terminating entry */ { 0, 0, NULL } }; #endif /* !SHUT_MODE => USB */ typedef enum { MGE_DEFAULT_OFFLINE = 0, MGE_PEGASUS = 0x100, MGE_3S = 0x110, /* All offline models have type value < 200! */ MGE_DEFAULT = 0x200, /* for line-interactive and online models */ MGE_EVOLUTION = 0x300, /* MGE Evolution series */ MGE_EVOLUTION_650, MGE_EVOLUTION_850, MGE_EVOLUTION_1150, MGE_EVOLUTION_S_1250, MGE_EVOLUTION_1550, MGE_EVOLUTION_S_1750, MGE_EVOLUTION_2000, MGE_EVOLUTION_S_2500, MGE_EVOLUTION_S_3000, MGE_PULSAR_M = 0x400, /* MGE Pulsar M series */ MGE_PULSAR_M_2200, MGE_PULSAR_M_3000, MGE_PULSAR_M_3000_XL, EATON_5P = 0x500 /* Eaton 5P / 5PX series */ } models_type_t; /* Default to line-interactive or online (ie, not offline). * This is then overridden for offline, through mge_model_names */ static models_type_t mge_type = MGE_DEFAULT; /* Countries definition, for region specific settings and features */ typedef enum { COUNTRY_UNKNOWN = -1, COUNTRY_EUROPE = 0, COUNTRY_US, /* Special European models, which also supports 200 / 208 V */ COUNTRY_EUROPE_208, COUNTRY_WORLDWIDE, COUNTRY_AUSTRALIA, } country_code_t; static int country_code = COUNTRY_UNKNOWN; static char mge_scratch_buf[20]; /* ABM - Advanced Battery Monitoring *********************************** * Synthesis table * HID data | Charger in ABM mode | Charger in Constant mode * UPS.BatterySystem.Charger.ABMEnable | 1 | 0 * UPS.PowerSummary.PresentStatus.ACPresent | On utility | On battery | On utility | On battery * Charger ABM mode | Charging | Floating | Resting | Discharging | Disabled | Disabled * UPS.BatterySystem.Charger.Mode | 1 | 3 | 4 | 2 | 6 | 6 * UPS.PowerSummary.PresentStatus.Charging | 1 | 1 | 1 | 0 | 1 | 0 * UPS.PowerSummary.PresentStatus.Discharging | 0 |  0 |  0 | 1 | 0 | 1 * * Notes (from David G. Miller) to understand ABM status: * When supporting ABM, when a UPS powers up or returns from battery, or * ends the ABM rest mode, it enters charge mode. * Some UPSs run a different charger reference voltage during charge mode * but all the newer models should not be doing that, but basically once * the battery voltage reaches the charger reference level (should be 2.3 * volts/cell), the charger is considered in float mode. Some UPSs will not * annunciate float mode until the charger power starts falling from the maximum * level indicating the battery is truly at the float voltage or in float mode. * The %charge level is based on battery voltage and the charge mode timer * (should be 48 hours) and some UPSs add in a value that's related to charger * power output. So you can have UPS that enters float mode with anywhere * from 80% or greater battery capacity. * float mode is not important from the software's perspective, it's there to * help determine if the charger is advancing correctly. * So in float mode, the charger is charging the battery, so by definition you * can assert the CHRG flag in NUT when in "float" mode or "charge" mode. * When in "rest" mode the charger is not delivering anything to the battery, * but it will when the ABM cycle(28 days) ends, or a battery discharge occurs * and utility returns. This is when the ABM status should be "resting". * If a battery failure is detected that disables the charger, it should be * reporting "off" in the ABM charger status. * Of course when delivering load power from the battery, the ABM status is * discharging. */ #define ABM_UNKNOWN -1 #define ABM_DISABLED 0 #define ABM_ENABLED 1 /* Internal flag to process battery status (CHRG/DISCHRG) and ABM */ static int advanced_battery_monitoring = ABM_UNKNOWN; /* TODO: Lifted from strptime.c... maybe should externalize the fallback? * NOTE: HAVE_DECL_* are always defined, 0 or 1. Many other flags are not. */ #if ! HAVE_DECL_ROUND # ifndef WIN32 static long round (double value) # else static long round (LDOUBLE value) # endif { long intpart; intpart = (long)value; value = value - intpart; if (value >= 0.5) intpart++; return intpart; } #endif /* HAVE_DECL_ROUND */ /* Used to store internally if ABM is enabled or not */ static const char *eaton_abm_enabled_fun(double value) { advanced_battery_monitoring = value; upsdebugx(2, "ABM is %s", (advanced_battery_monitoring==1)?"enabled":"disabled"); /* Return NULL, not to get the value published! */ return NULL; } static info_lkp_t eaton_abm_enabled_info[] = { { 0, "dummy", eaton_abm_enabled_fun, NULL }, { 0, NULL, NULL, NULL } }; /* Note 1: This point will need more clarification! */ # if 0 /* Used to store internally if ABM is enabled or not (for legacy units) */ static const char *eaton_abm_enabled_legacy_fun(double value) { advanced_battery_monitoring = value; upsdebugx(2, "ABM is %s (legacy data)", (advanced_battery_monitoring==1)?"enabled":"disabled"); /* Return NULL, not to get the value published! */ return NULL; } static info_lkp_t eaton_abm_enabled_legacy_info[] = { { 0, "dummy", eaton_abm_enabled_legacy_fun, NULL }, { 0, NULL, NULL, NULL } }; #endif /* if 0 */ /* Used to process ABM flags, for battery.charger.status */ static const char *eaton_abm_status_fun(double value) { /* Don't process if ABM is disabled */ if (advanced_battery_monitoring == ABM_DISABLED) { /* Clear any previously published data, in case * the user has switched off ABM */ dstate_delinfo("battery.charger.status"); return NULL; } upsdebugx(2, "ABM numeric status: %i", (int)value); switch ((long)value) { case 1: snprintf(mge_scratch_buf, sizeof(mge_scratch_buf), "%s", "charging"); break; case 2: snprintf(mge_scratch_buf, sizeof(mge_scratch_buf), "%s", "discharging"); break; case 3: snprintf(mge_scratch_buf, sizeof(mge_scratch_buf), "%s", "floating"); break; case 4: snprintf(mge_scratch_buf, sizeof(mge_scratch_buf), "%s", "resting"); break; case 6: /* ABM Charger Disabled */ snprintf(mge_scratch_buf, sizeof(mge_scratch_buf), "%s", "off"); break; case 5: /* Undefined - ABM is not activated */ default: /* Return NULL, not to get the value published! */ return NULL; } upsdebugx(2, "ABM string status: %s", mge_scratch_buf); return mge_scratch_buf; } static info_lkp_t eaton_abm_status_info[] = { { 1, "dummy", eaton_abm_status_fun, NULL }, { 0, NULL, NULL, NULL } }; /* Used to process ABM flags, for ups.status (CHRG/DISCHRG/RB) */ static const char *eaton_abm_chrg_dischrg_fun(double value) { /* Don't process if ABM is disabled */ if (advanced_battery_monitoring == ABM_DISABLED) return NULL; switch ((long)value) { case 1: /* charging status */ case 3: /* floating status */ snprintf(mge_scratch_buf, sizeof(mge_scratch_buf), "%s", "chrg"); break; case 2: snprintf(mge_scratch_buf, sizeof(mge_scratch_buf), "%s", "dischrg"); break; case 6: /* ABM Charger Disabled */ case 4: /* resting, nothing to publish! (?) */ case 5: /* Undefined - ABM is not activated */ default: /* Return NULL, not to get the value published! */ return NULL; } upsdebugx(2, "ABM CHRG/DISCHRG legacy string status (ups.status): %s", mge_scratch_buf); return mge_scratch_buf; } static info_lkp_t eaton_abm_chrg_dischrg_info[] = { { 1, "dummy", eaton_abm_chrg_dischrg_fun, NULL }, { 0, NULL, NULL, NULL } }; /* ABM also implies that standard CHRG/DISCHRG are processed according * to weither ABM is enabled or not... * If ABM is disabled, we publish these legacy status * Otherwise, we don't publish on ups.status, but only battery.charger.status */ /* FIXME: we may prefer to publish the CHRG/DISCHRG status * on battery.charger.status?! */ static const char *eaton_abm_check_dischrg_fun(double value) { if (advanced_battery_monitoring == ABM_DISABLED) { if (d_equal(value, 1)) { snprintf(mge_scratch_buf, sizeof(mge_scratch_buf), "%s", "dischrg"); } else { snprintf(mge_scratch_buf, sizeof(mge_scratch_buf), "%s", "!dischrg"); } } else { /* Else, ABM is enabled, we should return NULL, * not to get the value published! * However, clear flags that would persist in case of prior * publication in ABM-disabled mode */ snprintf(mge_scratch_buf, sizeof(mge_scratch_buf), "%s", "!dischrg"); } return mge_scratch_buf; } static info_lkp_t eaton_discharging_info[] = { { 1, "dummy", eaton_abm_check_dischrg_fun, NULL }, { 0, NULL, NULL, NULL } }; static const char *eaton_abm_check_chrg_fun(double value) { if (advanced_battery_monitoring == ABM_DISABLED) { if (d_equal(value, 1)) { snprintf(mge_scratch_buf, sizeof(mge_scratch_buf), "%s", "chrg"); } else { snprintf(mge_scratch_buf, sizeof(mge_scratch_buf), "%s", "!chrg"); } } else { /* Else, ABM is enabled, we should return NULL, * not to get the value published! * However, clear flags that would persist in case of prior * publication in ABM-disabled mode */ snprintf(mge_scratch_buf, sizeof(mge_scratch_buf), "%s", "!chrg"); } return mge_scratch_buf; } static info_lkp_t eaton_charging_info[] = { { 1, "dummy", eaton_abm_check_chrg_fun, NULL }, { 0, NULL, NULL, NULL } }; /* The HID path 'UPS.PowerSummary.Time' reports Unix time (ie the number of * seconds since 1970-01-01 00:00:00. This has to be split between ups.date and * ups.time */ static const char *mge_date_conversion_fun(double value) { time_t sec = value; struct tm tmbuf; if (strftime(mge_scratch_buf, sizeof(mge_scratch_buf), "%Y/%m/%d", localtime_r(&sec, &tmbuf)) == 10) { return mge_scratch_buf; } upsdebugx(3, "%s: can't compute date %g", __func__, value); return NULL; } static const char *mge_time_conversion_fun(double value) { time_t sec = value; struct tm tmbuf; if (strftime(mge_scratch_buf, sizeof(mge_scratch_buf), "%H:%M:%S", localtime_r(&sec, &tmbuf)) == 8) { return mge_scratch_buf; } upsdebugx(3, "%s: can't compute time %g", __func__, value); return NULL; } #ifdef HAVE_STRPTIME /* Conversion back retrieve ups.time to build the full unix time */ static double mge_date_conversion_nuf(const char *value) { struct tm mge_tm; /* build a full value (date) + time string */ snprintf(mge_scratch_buf, sizeof(mge_scratch_buf), "%s %s", value, dstate_getinfo("ups.time")); if (strptime(mge_scratch_buf, "%Y/%m/%d %H:%M:%S", &mge_tm) != NULL) { return mktime(&mge_tm); } upsdebugx(3, "%s: can't compute date %s", __func__, value); return 0; } /* Conversion back retrieve ups.date to build the full unix time */ static double mge_time_conversion_nuf(const char *value) { struct tm mge_tm; /* build a full date + value (time) string */ snprintf(mge_scratch_buf, sizeof(mge_scratch_buf), "%s %s", dstate_getinfo("ups.date"), value); if (strptime(mge_scratch_buf, "%Y/%m/%d %H:%M:%S", &mge_tm) != NULL) { return mktime(&mge_tm); } upsdebugx(3, "%s: can't compute time %s", __func__, value); return 0; } static info_lkp_t mge_date_conversion[] = { { 0, NULL, mge_date_conversion_fun, mge_date_conversion_nuf }, { 0, NULL, NULL, NULL } }; static info_lkp_t mge_time_conversion[] = { { 0, NULL, mge_time_conversion_fun, mge_time_conversion_nuf }, { 0, NULL, NULL, NULL } }; #else static info_lkp_t mge_date_conversion[] = { { 0, NULL, mge_date_conversion_fun, NULL }, { 0, NULL, NULL, NULL } }; static info_lkp_t mge_time_conversion[] = { { 0, NULL, mge_time_conversion_fun, NULL }, { 0, NULL, NULL, NULL } }; #endif /* HAVE_STRPTIME */ /* The HID path 'UPS.PowerSummary.ConfigVoltage' only reports 'battery.voltage.nominal' for specific UPS series. Ignore the value for other series (default behavior). */ static const char *mge_battery_voltage_nominal_fun(double value) { switch (mge_type & 0xFF00) /* Ignore model byte */ { case MGE_EVOLUTION: if (mge_type == MGE_EVOLUTION_650) { value = 12.0; } break; case MGE_PULSAR_M: case EATON_5P: break; default: return NULL; } snprintf(mge_scratch_buf, sizeof(mge_scratch_buf), "%.0f", value); return mge_scratch_buf; } static info_lkp_t mge_battery_voltage_nominal[] = { { 0, NULL, mge_battery_voltage_nominal_fun, NULL }, { 0, NULL, NULL, NULL } }; /* The HID path 'UPS.PowerSummary.Voltage' only reports 'battery.voltage' for specific UPS series. Ignore the value for other series (default behavior). */ static const char *mge_battery_voltage_fun(double value) { switch (mge_type & 0xFF00) /* Ignore model byte */ { case MGE_EVOLUTION: case MGE_PULSAR_M: case EATON_5P: break; default: return NULL; } snprintf(mge_scratch_buf, sizeof(mge_scratch_buf), "%.1f", value); return mge_scratch_buf; } static info_lkp_t mge_battery_voltage[] = { { 0, NULL, mge_battery_voltage_fun, NULL }, { 0, NULL, NULL, NULL } }; static const char *mge_powerfactor_conversion_fun(double value) { snprintf(mge_scratch_buf, sizeof(mge_scratch_buf), "%.2f", value / 100); return mge_scratch_buf; } static info_lkp_t mge_powerfactor_conversion[] = { { 0, NULL, mge_powerfactor_conversion_fun, NULL }, { 0, NULL, NULL, NULL } }; static const char *mge_battery_capacity_fun(double value) { snprintf(mge_scratch_buf, sizeof(mge_scratch_buf), "%.2f", value / 3600); return mge_scratch_buf; } static info_lkp_t mge_battery_capacity[] = { { 0, NULL, mge_battery_capacity_fun, NULL }, { 0, NULL, NULL, NULL } }; static info_lkp_t eaton_enable_disable_info[] = { { 0, "disabled", NULL, NULL }, { 1, "enabled", NULL, NULL }, { 0, NULL, NULL, NULL } }; static info_lkp_t mge_upstype_conversion[] = { { 1, "offline / line interactive", NULL, NULL }, { 2, "online", NULL, NULL }, { 3, "online - unitary/parallel", NULL, NULL }, { 4, "online - parallel with hot standy", NULL, NULL }, { 5, "online - hot standby redundancy", NULL, NULL }, { 0, NULL, NULL, NULL } }; static info_lkp_t mge_sensitivity_info[] = { { 0, "normal", NULL, NULL }, { 1, "high", NULL, NULL }, { 2, "low", NULL, NULL }, { 0, NULL, NULL, NULL } }; static info_lkp_t mge_emergency_stop[] = { { 1, "Emergency stop!", NULL, NULL }, { 0, NULL, NULL, NULL } }; static info_lkp_t mge_wiring_fault[] = { { 1, "Wiring fault!", NULL, NULL }, { 0, NULL, NULL, NULL } }; static info_lkp_t mge_config_failure[] = { { 1, "Fatal EEPROM fault!", NULL, NULL }, { 0, NULL, NULL, NULL } }; static info_lkp_t mge_inverter_volthi[] = { { 1, "Inverter AC voltage too high!", NULL, NULL }, { 0, NULL, NULL, NULL } }; static info_lkp_t mge_inverter_voltlo[] = { { 1, "Inverter AC voltage too low!", NULL, NULL }, { 0, NULL, NULL, NULL } }; static info_lkp_t mge_short_circuit[] = { { 1, "Output short circuit!", NULL, NULL }, { 0, NULL, NULL, NULL } }; static info_lkp_t mge_onbatt_info[] = { { 1, "!online", NULL, NULL }, { 0, "online", NULL, NULL }, { 0, NULL, NULL, NULL } }; /* allow limiting to ups.model = Protection Station, Ellipse Eco * and 3S (US 750 and AUS 700 only!) */ static const char *eaton_check_pegasus_fun(double value) { switch (mge_type & 0xFF00) /* Ignore model byte */ { case MGE_PEGASUS: break; case MGE_3S: /* Only consider non European models */ if (country_code != COUNTRY_EUROPE) break; return NULL; default: return NULL; } snprintf(mge_scratch_buf, sizeof(mge_scratch_buf), "%.0f", value); return mge_scratch_buf; } static info_lkp_t pegasus_threshold_info[] = { { 10, "10", eaton_check_pegasus_fun, NULL }, { 25, "25", eaton_check_pegasus_fun, NULL }, { 60, "60", eaton_check_pegasus_fun, NULL }, { 0, NULL, NULL, NULL } }; /* allow limiting standard yes/no info (here, to enable ECO mode) to * ups.model = Protection Station, Ellipse Eco and 3S (US 750 and AUS 700 only!) * this allows to enable special flags used in hid_info_t entries (Ie RW) */ static const char *pegasus_yes_no_info_fun(double value) { switch (mge_type & 0xFF00) /* Ignore model byte */ { case MGE_PEGASUS: break; case MGE_3S: /* Only consider non European models */ if (country_code != COUNTRY_EUROPE) break; return NULL; default: return NULL; } return (d_equal(value, 0)) ? "no" : "yes"; } /* Conversion back of yes/no info */ static double pegasus_yes_no_info_nuf(const char *value) { switch (mge_type & 0xFF00) /* Ignore model byte */ { case MGE_PEGASUS: break; case MGE_3S: /* Only consider non European models */ if (country_code != COUNTRY_EUROPE) break; return 0; default: return 0; } if (!strncmp(value, "yes", 3)) return 1; else return 0; } static info_lkp_t pegasus_yes_no_info[] = { { 0, "no", pegasus_yes_no_info_fun, pegasus_yes_no_info_nuf }, { 1, "yes", pegasus_yes_no_info_fun, pegasus_yes_no_info_nuf }, { 0, NULL, NULL, NULL } }; /* Determine country using UPS.PowerSummary.Country. * If not present: * if PowerConverter.Output.Voltage >= 200 => "Europe" * else default to "US" */ static const char *eaton_check_country_fun(double value) { country_code = value; /* Return NULL, not to get the value published! */ return NULL; } static info_lkp_t eaton_check_country_info[] = { { 0, "dummy", eaton_check_country_fun, NULL }, { 0, NULL, NULL, NULL } }; /* When UPS.PowerConverter.Output.ActivePower is not present, * compute a realpower approximation using available data */ static const char *eaton_compute_realpower_fun(double value) { const char *str_ups_load = dstate_getinfo("ups.load"); const char *str_power_nominal = dstate_getinfo("ups.power.nominal"); const char *str_powerfactor = dstate_getinfo("output.powerfactor"); float powerfactor = 0.80; int power_nominal = 0; int ups_load = 0; double realpower = 0; NUT_UNUSED_VARIABLE(value); if (str_power_nominal && str_ups_load) { /* Extract needed values */ ups_load = atoi(str_ups_load); power_nominal = atoi(str_power_nominal); if (str_powerfactor) powerfactor = atof(str_powerfactor); /* Compute the value */ realpower = round(ups_load * 0.01 * power_nominal * powerfactor); snprintf(mge_scratch_buf, sizeof(mge_scratch_buf), "%.0f", realpower); upsdebugx(1, "eaton_compute_realpower_fun(%s)", mge_scratch_buf); return mge_scratch_buf; } /* else can't process */ /* Return NULL, not to get the value published! */ return NULL; } static info_lkp_t eaton_compute_realpower_info[] = { { 0, "dummy", eaton_compute_realpower_fun, NULL }, { 0, NULL, NULL, NULL } }; /* Limit nominal output voltage according to HV or LV models */ static const char *nominal_output_voltage_fun(double value) { static long nominal = -1; if (nominal < 0) { nominal = value; } switch ((long)nominal) { /* LV models */ case 100: case 110: case 120: case 127: switch ((long)value) { case 100: case 110: case 120: case 127: break; default: return NULL; } break; /* line-interactive and online support 200/208 and 220/230/240*/ /* HV models */ /* 208V */ case 200: case 208: switch ((long)value) { case 200: case 208: break; /* 230V */ case 220: case 230: case 240: if ((mge_type & 0xFF00) >= MGE_DEFAULT) break; return NULL; default: return NULL; } break; /* HV models */ /* 230V */ case 220: case 230: case 240: switch ((long)value) { case 200: case 208: /* line-interactive and online also support 200 / 208 V * So break on offline models */ if ((mge_type & 0xFF00) < MGE_DEFAULT) return NULL; /* FIXME: Some European models ("5130 RT 3000") also * support both HV values */ if (country_code == COUNTRY_EUROPE_208) break; /* explicit fallthrough: */ goto fallthrough_value; case 220: case 230: case 240: fallthrough_value: break; default: return NULL; } break; default: upsdebugx(3, "%s: can't autodetect settable voltages from %g", __func__, value); } snprintf(mge_scratch_buf, sizeof(mge_scratch_buf), "%.0f", value); return mge_scratch_buf; } static info_lkp_t nominal_output_voltage_info[] = { /* line-interactive, starting with Evolution, support both HV values */ /* HV models */ /* 208V */ { 200, "200", nominal_output_voltage_fun, NULL }, { 208, "208", nominal_output_voltage_fun, NULL }, /* HV models */ /* 230V */ { 220, "220", nominal_output_voltage_fun, NULL }, { 230, "230", nominal_output_voltage_fun, NULL }, { 240, "240", nominal_output_voltage_fun, NULL }, /* LV models */ { 100, "100", nominal_output_voltage_fun, NULL }, { 110, "110", nominal_output_voltage_fun, NULL }, { 120, "120", nominal_output_voltage_fun, NULL }, { 127, "127", nominal_output_voltage_fun, NULL }, { 0, NULL, NULL, NULL } }; /* Limit reporting "online / !online" to when "!off" */ static const char *eaton_converter_online_fun(double value) { unsigned ups_status = ups_status_get(); if (ups_status & STATUS(OFF)) return NULL; else return (d_equal(value, 0)) ? "!online" : "online"; } static info_lkp_t eaton_converter_online_info[] = { { 0, "dummy", eaton_converter_online_fun, NULL }, { 0, NULL, NULL, NULL } }; /* --------------------------------------------------------------- */ /* Vendor-specific usage table */ /* --------------------------------------------------------------- */ /* Eaton / MGE HID usage table */ static usage_lkp_t mge_usage_lkp[] = { { "Undefined", 0xffff0000 }, { "STS", 0xffff0001 }, { "Environment", 0xffff0002 }, { "Statistic", 0xffff0003 }, { "StatisticSystem", 0xffff0004 }, /* 0xffff0005-0xffff000f => Reserved */ { "Phase", 0xffff0010 }, { "PhaseID", 0xffff0011 }, { "Chopper", 0xffff0012 }, { "ChopperID", 0xffff0013 }, { "Inverter", 0xffff0014 }, { "InverterID", 0xffff0015 }, { "Rectifier", 0xffff0016 }, { "RectifierID", 0xffff0017 }, { "LCMSystem", 0xffff0018 }, { "LCMSystemID", 0xffff0019 }, { "LCMAlarm", 0xffff001a }, { "LCMAlarmID", 0xffff001b }, { "HistorySystem", 0xffff001c }, { "HistorySystemID", 0xffff001d }, { "Event", 0xffff001e }, { "EventID", 0xffff001f }, { "CircuitBreaker", 0xffff0020 }, { "TransferForbidden", 0xffff0021 }, { "OverallAlarm", 0xffff0022 }, /* renamed to Alarm in Eaton SW! */ { "Dephasing", 0xffff0023 }, { "BypassBreaker", 0xffff0024 }, { "PowerModule", 0xffff0025 }, { "PowerRate", 0xffff0026 }, { "PowerSource", 0xffff0027 }, { "CurrentPowerSource", 0xffff0028 }, { "RedundancyLevel", 0xffff0029 }, { "RedundancyLost", 0xffff002a }, { "NotificationStatus", 0xffff002b }, { "ProtectionLost", 0xffff002c }, { "ConfigurationFailure", 0xffff002d }, { "CompatibilityFailure", 0xffff002e }, /* 0xffff002e-0xffff003f => Reserved */ { "SwitchType", 0xffff0040 }, /* renamed to Type in Eaton SW! */ { "ConverterType", 0xffff0041 }, { "FrequencyConverterMode", 0xffff0042 }, { "AutomaticRestart", 0xffff0043 }, { "ForcedReboot", 0xffff0044 }, { "TestPeriod", 0xffff0045 }, { "EnergySaving", 0xffff0046 }, { "StartOnBattery", 0xffff0047 }, { "Schedule", 0xffff0048 }, { "DeepDischargeProtection", 0xffff0049 }, { "ShortCircuit", 0xffff004a }, { "ExtendedVoltageMode", 0xffff004b }, { "SensitivityMode", 0xffff004c }, { "RemainingCapacityLimitSetting", 0xffff004d }, { "ExtendedFrequencyMode", 0xffff004e }, { "FrequencyConverterModeSetting", 0xffff004f }, { "LowVoltageBoostTransfer", 0xffff0050 }, { "HighVoltageBoostTransfer", 0xffff0051 }, { "LowVoltageBuckTransfer", 0xffff0052 }, { "HighVoltageBuckTransfer", 0xffff0053 }, { "OverloadTransferEnable", 0xffff0054 }, { "OutOfToleranceTransferEnable", 0xffff0055 }, { "ForcedTransferEnable", 0xffff0056 }, { "LowVoltageBypassTransfer", 0xffff0057 }, { "HighVoltageBypassTransfer", 0xffff0058 }, { "FrequencyRangeBypassTransfer", 0xffff0059 }, { "LowVoltageEcoTransfer", 0xffff005a }, { "HighVoltageEcoTransfer", 0xffff005b }, { "FrequencyRangeEcoTransfer", 0xffff005c }, { "ShutdownTimer", 0xffff005d }, { "StartupTimer", 0xffff005e }, { "RestartLevel", 0xffff005f }, { "PhaseOutOfRange", 0xffff0060 }, { "CurrentLimitation", 0xffff0061 }, { "ThermalOverload", 0xffff0062 }, { "SynchroSource", 0xffff0063 }, { "FuseFault", 0xffff0064 }, { "ExternalProtectedTransfert", 0xffff0065 }, { "ExternalForcedTransfert", 0xffff0066 }, { "Compensation", 0xffff0067 }, { "EmergencyStop", 0xffff0068 }, { "PowerFactor", 0xffff0069 }, { "PeakFactor", 0xffff006a }, { "ChargerType", 0xffff006b }, { "HighPositiveDCBusVoltage", 0xffff006c }, { "LowPositiveDCBusVoltage", 0xffff006d }, { "HighNegativeDCBusVoltage", 0xffff006e }, { "LowNegativeDCBusVoltage", 0xffff006f }, { "FrequencyRangeTransfer", 0xffff0070 }, { "WiringFaultDetection", 0xffff0071 }, { "ControlStandby", 0xffff0072 }, { "ShortCircuitTolerance", 0xffff0073 }, { "VoltageTooHigh", 0xffff0074 }, { "VoltageTooLow", 0xffff0075 }, { "DCBusUnbalanced", 0xffff0076 }, { "FanFailure", 0xffff0077 }, { "WiringFault", 0xffff0078 }, { "Floating", 0xffff0079 }, { "OverCurrent", 0xffff007a }, { "RemainingActivePower", 0xffff007b }, { "Energy", 0xffff007c }, { "Threshold", 0xffff007d }, { "OverThreshold", 0xffff007e }, /* 0xffff007f => Reserved */ { "Sensor", 0xffff0080 }, { "LowHumidity", 0xffff0081 }, { "HighHumidity", 0xffff0082 }, { "LowTemperature", 0xffff0083 }, { "HighTemperature", 0xffff0084 }, { "ECOControl", 0xffff0085 }, { "Efficiency", 0xffff0086 }, { "ABMEnable", 0xffff0087 }, { "NegativeCurrent", 0xffff0088 }, { "AutomaticStart", 0xffff0089 }, /* 0xffff008a-0xffff008f => Reserved */ { "Count", 0xffff0090 }, { "Timer", 0xffff0091 }, { "Interval", 0xffff0092 }, { "TimerExpired", 0xffff0093 }, { "Mode", 0xffff0094 }, { "Country", 0xffff0095 }, { "State", 0xffff0096 }, { "Time", 0xffff0097 }, { "Code", 0xffff0098 }, { "DataValid", 0xffff0099 }, { "ToggleTimer", 0xffff009a }, { "BypassTransferDelay", 0xffff009b }, { "HysteresysVoltageTransfer", 0xffff009c }, { "SlewRate", 0xffff009d }, /* 0xffff009e-0xffff009f => Reserved */ { "PDU", 0xffff00a0 }, { "Breaker", 0xffff00a1 }, { "BreakerID", 0xffff00a2 }, { "OverVoltage", 0xffff00a3 }, { "Tripped", 0xffff00a4 }, { "OverEnergy", 0xffff00a5 }, { "OverHumidity", 0xffff00a6 }, { "ConfigurationReset", 0xffff00a7 }, /* renamed from LCDControl in Eaton SW! */ { "Level", 0xffff00a8 }, { "PDUType", 0xffff00a9 }, { "ReactivePower", 0xffff00aa }, { "Pole", 0xffff00ab }, { "PoleID", 0xffff00ac }, { "Reset", 0xffff00ad }, { "WatchdogReset", 0xffff00ae }, /* 0xffff00af-0xffff00df => Reserved */ { "COPIBridge", 0xffff00e0 }, /* 0xffff00e1-0xffff00ef => Reserved */ { "iModel", 0xffff00f0 }, { "iVersion", 0xffff00f1 }, { "iTechnicalLevel", 0xffff00f2 }, { "iPartNumber", 0xffff00f3 }, { "iReferenceNumber", 0xffff00f4 }, { "iGang", 0xffff00f5 }, /* 0xffff00f6-0xffff00ff => Reserved */ /* end of table */ { NULL, 0 } }; static usage_tables_t mge_utab[] = { mge_usage_lkp, hid_usage_lkp, NULL, }; /* --------------------------------------------------------------- */ /* Model Name formating entries */ /* --------------------------------------------------------------- */ typedef struct { const char *iProduct; const char *iModel; models_type_t type; /* enumerated model type */ const char *name; /* optional (defaults to " " if NULL) */ } models_name_t; /* * Do not remove models from this list, but instead comment them * out if not needed. This allows us to quickly add overrides for * specific models only, should this be needed. */ static models_name_t mge_model_names [] = { /* Ellipse models */ { "ELLIPSE", "300", MGE_DEFAULT_OFFLINE, "ellipse 300" }, { "ELLIPSE", "500", MGE_DEFAULT_OFFLINE, "ellipse 500" }, { "ELLIPSE", "650", MGE_DEFAULT_OFFLINE, "ellipse 650" }, { "ELLIPSE", "800", MGE_DEFAULT_OFFLINE, "ellipse 800" }, { "ELLIPSE", "1200", MGE_DEFAULT_OFFLINE, "ellipse 1200" }, /* Ellipse Premium models */ { "ellipse", "PR500", MGE_DEFAULT_OFFLINE, "ellipse premium 500" }, { "ellipse", "PR650", MGE_DEFAULT_OFFLINE, "ellipse premium 650" }, { "ellipse", "PR800", MGE_DEFAULT_OFFLINE, "ellipse premium 800" }, { "ellipse", "PR1200", MGE_DEFAULT_OFFLINE, "ellipse premium 1200" }, /* Ellipse "Pro" */ { "ELLIPSE", "600", MGE_DEFAULT_OFFLINE, "Ellipse 600" }, { "ELLIPSE", "750", MGE_DEFAULT_OFFLINE, "Ellipse 750" }, { "ELLIPSE", "1000", MGE_DEFAULT_OFFLINE, "Ellipse 1000" }, { "ELLIPSE", "1500", MGE_DEFAULT_OFFLINE, "Ellipse 1500" }, /* Ellipse MAX */ { "Ellipse MAX", "600", MGE_DEFAULT_OFFLINE, NULL }, { "Ellipse MAX", "850", MGE_DEFAULT_OFFLINE, NULL }, { "Ellipse MAX", "1100", MGE_DEFAULT_OFFLINE, NULL }, { "Ellipse MAX", "1500", MGE_DEFAULT_OFFLINE, NULL }, /* Protection Center */ { "PROTECTIONCENTER", "420", MGE_DEFAULT_OFFLINE, "Protection Center 420" }, { "PROTECTIONCENTER", "500", MGE_DEFAULT_OFFLINE, "Protection Center 500" }, { "PROTECTIONCENTER", "675", MGE_DEFAULT_OFFLINE, "Protection Center 675" }, /* Protection Station, supports Eco control */ { "Protection Station", "500", MGE_PEGASUS, NULL }, { "Protection Station", "650", MGE_PEGASUS, NULL }, { "Protection Station", "800", MGE_PEGASUS, NULL }, /* Ellipse ECO, also supports Eco control */ { "Ellipse ECO", "650", MGE_PEGASUS, NULL }, { "Ellipse ECO", "800", MGE_PEGASUS, NULL }, { "Ellipse ECO", "1200", MGE_PEGASUS, NULL }, { "Ellipse ECO", "1600", MGE_PEGASUS, NULL }, /* 3S, also supports Eco control on some models (AUS 700 and US 750)*/ { "3S", "450", MGE_DEFAULT_OFFLINE, NULL }, /* US only */ { "3S", "550", MGE_DEFAULT_OFFLINE, NULL }, /* US 120V + EU 230V + AUS 240V */ { "3S", "700", MGE_3S, NULL }, /* EU 230V + AUS 240V (w/ eco control) */ { "3S", "750", MGE_3S, NULL }, /* US 120V (w/ eco control) */ /* Evolution models */ { "Evolution", "500", MGE_DEFAULT, "Pulsar Evolution 500" }, { "Evolution", "800", MGE_DEFAULT, "Pulsar Evolution 800" }, { "Evolution", "1100", MGE_DEFAULT, "Pulsar Evolution 1100" }, { "Evolution", "1500", MGE_DEFAULT, "Pulsar Evolution 1500" }, { "Evolution", "2200", MGE_DEFAULT, "Pulsar Evolution 2200" }, { "Evolution", "3000", MGE_DEFAULT, "Pulsar Evolution 3000" }, { "Evolution", "3000XL", MGE_DEFAULT, "Pulsar Evolution 3000 XL" }, /* Newer Evolution models */ { "Evolution", "650", MGE_EVOLUTION_650, NULL }, { "Evolution", "850", MGE_EVOLUTION_850, NULL }, { "Evolution", "1150", MGE_EVOLUTION_1150, NULL }, { "Evolution", "S 1250", MGE_EVOLUTION_S_1250, NULL }, { "Evolution", "1550", MGE_EVOLUTION_1550, NULL }, { "Evolution", "S 1750", MGE_EVOLUTION_S_1750, NULL }, { "Evolution", "2000", MGE_EVOLUTION_2000, NULL }, { "Evolution", "S 2500", MGE_EVOLUTION_S_2500, NULL }, { "Evolution", "S 3000", MGE_EVOLUTION_S_3000, NULL }, /* Eaton 5P */ { "Eaton 5P", "650", EATON_5P, "5P 650" }, { "Eaton 5P", "850", EATON_5P, "5P 850" }, { "Eaton 5P", "1150", EATON_5P, "5P 1150" }, { "Eaton 5P", "1550", EATON_5P, "5P 1550" }, /* Pulsar M models */ { "PULSAR M", "2200", MGE_PULSAR_M_2200, NULL }, { "PULSAR M", "3000", MGE_PULSAR_M_3000, NULL }, { "PULSAR M", "3000 XL", MGE_PULSAR_M_3000_XL, NULL }, /* Eaton'ified names */ { "EX", "2200", MGE_PULSAR_M_2200, NULL }, { "EX", "3000", MGE_PULSAR_M_3000, NULL }, { "EX", "3000 XL", MGE_PULSAR_M_3000, NULL }, /* Pulsar models (TBR) */ /* { "Pulsar", "700", MGE_DEFAULT, NULL }, */ /* { "Pulsar", "1000", MGE_DEFAULT, NULL }, */ /* { "Pulsar", "1500", MGE_DEFAULT, NULL }, */ /* { "Pulsar", "1000 RT2U", MGE_DEFAULT, NULL }, */ /* { "Pulsar", "1500 RT2U", MGE_DEFAULT, NULL }, */ /* Eaton'ified names (TBR) */ /* { "EX", "700", MGE_DEFAULT, NULL }, */ /* { "EX", "1000", MGE_DEFAULT, NULL }, */ /* { "EX", "1500", MGE_DEFAULT, NULL }, */ /* { "EX", "1000 RT2U", MGE_DEFAULT, NULL }, */ /* { "EX", "1500 RT2U", MGE_DEFAULT, NULL }, */ /* Pulsar MX models */ { "PULSAR", "MX4000", MGE_DEFAULT, "Pulsar MX 4000 RT" }, { "PULSAR", "MX5000", MGE_DEFAULT, "Pulsar MX 5000 RT" }, /* NOVA models */ { "NOVA AVR", "500", MGE_DEFAULT, "Nova 500 AVR" }, { "NOVA AVR", "600", MGE_DEFAULT, "Nova 600 AVR" }, { "NOVA AVR", "625", MGE_DEFAULT, "Nova 625 AVR" }, { "NOVA AVR", "1100", MGE_DEFAULT, "Nova 1100 AVR" }, { "NOVA AVR", "1250", MGE_DEFAULT, "Nova 1250 AVR" }, /* EXtreme C (EMEA) */ { "EXtreme", "700C", MGE_DEFAULT, "Pulsar EXtreme 700C" }, { "EXtreme", "1000C", MGE_DEFAULT, "Pulsar EXtreme 1000C" }, { "EXtreme", "1500C", MGE_DEFAULT, "Pulsar EXtreme 1500C" }, { "EXtreme", "1500CCLA", MGE_DEFAULT, "Pulsar EXtreme 1500C CLA" }, { "EXtreme", "2200C", MGE_DEFAULT, "Pulsar EXtreme 2200C" }, { "EXtreme", "3200C", MGE_DEFAULT, "Pulsar EXtreme 3200C" }, /* EXtreme C (USA, aka "EX RT") */ { "EX", "700RT", MGE_DEFAULT, "Pulsar EX 700 RT" }, { "EX", "1000RT", MGE_DEFAULT, "Pulsar EX 1000 RT" }, { "EX", "1500RT", MGE_DEFAULT, "Pulsar EX 1500 RT" }, { "EX", "2200RT", MGE_DEFAULT, "Pulsar EX 2200 RT" }, { "EX", "3200RT", MGE_DEFAULT, "Pulsar EX 3200 RT" }, /* Comet EX RT three phased */ { "EX", "5RT31", MGE_DEFAULT, "EX 5 RT 3:1" }, { "EX", "7RT31", MGE_DEFAULT, "EX 7 RT 3:1" }, { "EX", "11RT31", MGE_DEFAULT, "EX 11 RT 3:1" }, /* Comet EX RT mono phased */ { "EX", "5RT", MGE_DEFAULT, "EX 5 RT" }, { "EX", "7RT", MGE_DEFAULT, "EX 7 RT" }, { "EX", "11RT", MGE_DEFAULT, "EX 11 RT" }, /* Galaxy 3000 */ { "GALAXY", "3000_10", MGE_DEFAULT, "Galaxy 3000 10 kVA" }, { "GALAXY", "3000_15", MGE_DEFAULT, "Galaxy 3000 15 kVA" }, { "GALAXY", "3000_20", MGE_DEFAULT, "Galaxy 3000 20 kVA" }, { "GALAXY", "3000_30", MGE_DEFAULT, "Galaxy 3000 30 kVA" }, /* end of structure. */ { NULL, NULL, 0, NULL } }; /* --------------------------------------------------------------- */ /* Data lookup table (HID <-> NUT) */ /* --------------------------------------------------------------- */ static hid_info_t mge_hid2nut[] = { /* Device collection */ /* Just declared to call *hid2info */ { "device.country", ST_FLAG_STRING, 20, "UPS.PowerSummary.Country", NULL, "Europe", HU_FLAG_STATIC, eaton_check_country_info }, /* Battery page */ { "battery.charge", 0, 0, "UPS.PowerSummary.RemainingCapacity", NULL, "%.0f", 0, NULL }, { "battery.charge.low", ST_FLAG_RW | ST_FLAG_STRING, 5, "UPS.PowerSummary.RemainingCapacityLimitSetting", NULL, "%.0f", HU_FLAG_SEMI_STATIC, NULL }, { "battery.charge.low", 0, 0, "UPS.PowerSummary.RemainingCapacityLimit", NULL, "%.0f", HU_FLAG_STATIC , NULL }, /* Read only */ { "battery.charge.restart", ST_FLAG_RW | ST_FLAG_STRING, 3, "UPS.PowerSummary.RestartLevel", NULL, "%.0f", HU_FLAG_SEMI_STATIC, NULL }, { "battery.capacity", 0, 0, "UPS.BatterySystem.Battery.DesignCapacity", NULL, "%s", HU_FLAG_STATIC, mge_battery_capacity }, /* conversion needed from As to Ah */ { "battery.runtime", 0, 0, "UPS.PowerSummary.RunTimeToEmpty", NULL, "%.0f", 0, NULL }, { "battery.runtime.low", ST_FLAG_RW | ST_FLAG_STRING, 10, "UPS.PowerSummary.RemainingTimeLimit", NULL, "%.0f", 0, NULL }, { "battery.runtime.elapsed", 0, 0, "UPS.StatisticSystem.Input.[1].Statistic.[1].Time", NULL, "%.0f", HU_FLAG_QUICK_POLL, NULL }, { "battery.runtime.low", ST_FLAG_RW | ST_FLAG_STRING, 10, "UPS.PowerSummary.RemainingTimeLimit", NULL, "%.0f", 0, NULL }, { "battery.temperature", 0, 0, "UPS.BatterySystem.Battery.Temperature", NULL, "%s", 0, kelvin_celsius_conversion }, { "battery.type", 0, 0, "UPS.PowerSummary.iDeviceChemistry", NULL, "%s", HU_FLAG_STATIC, stringid_conversion }, { "battery.voltage", 0, 0, "UPS.BatterySystem.Voltage", NULL, "%.1f", 0, NULL }, { "battery.voltage", 0, 0, "UPS.PowerSummary.Voltage", NULL, "%s", 0, mge_battery_voltage }, { "battery.voltage.nominal", 0, 0, "UPS.BatterySystem.ConfigVoltage", NULL, "%.0f", HU_FLAG_STATIC, NULL }, { "battery.voltage.nominal", 0, 0, "UPS.PowerSummary.ConfigVoltage", NULL, "%s", HU_FLAG_STATIC, mge_battery_voltage_nominal }, { "battery.protection", ST_FLAG_RW | ST_FLAG_STRING, 5, "UPS.BatterySystem.Battery.DeepDischargeProtection", NULL, "%s", HU_FLAG_SEMI_STATIC, yes_no_info }, { "battery.energysave", ST_FLAG_RW | ST_FLAG_STRING, 5, "UPS.PowerConverter.Input.[3].EnergySaving", NULL, "%s", HU_FLAG_SEMI_STATIC, yes_no_info }, { "battery.energysave.load", ST_FLAG_RW | ST_FLAG_STRING, 5, "UPS.PowerConverter.Input.[3].ConfigPercentLoad", NULL, "%.0f", HU_FLAG_SEMI_STATIC, NULL }, /* Current implementation */ { "battery.energysave.delay", ST_FLAG_RW | ST_FLAG_STRING, 5, "UPS.PowerConverter.Input.[3].EnergySaving.ShutdownTimer", NULL, "%.0f", HU_FLAG_SEMI_STATIC, NULL }, /* Newer implementation */ { "battery.energysave.delay", ST_FLAG_RW | ST_FLAG_STRING, 5, "UPS.PowerConverter.Input.[3].ShutdownTimer", NULL, "%.0f", HU_FLAG_SEMI_STATIC, NULL }, { "battery.energysave.realpower", ST_FLAG_RW | ST_FLAG_STRING, 5, "UPS.PowerConverter.Input.[3].ConfigActivePower", NULL, "%.0f", HU_FLAG_SEMI_STATIC, NULL }, /* ABM (Advanced Battery Monitoring) processing * Must be processed before the BOOL status */ /* Not published, just to store in internal var. advanced_battery_monitoring */ { "battery.charger.status", 0, 0, "UPS.BatterySystem.Charger.ABMEnable", NULL, "%.0f", HU_FLAG_QUICK_POLL, eaton_abm_enabled_info }, /* Same as the one above, but for legacy units */ /* Refer to Note 1 (This point will need more clarification!) { "battery.charger.status", 0, 0, "UPS.BatterySystem.Charger.PresentStatus.Used", NULL, "%.0f", HU_FLAG_QUICK_POLL, eaton_abm_enabled_legacy_info }, */ /* This data is the actual ABM status information */ { "battery.charger.status", 0, 0, "UPS.BatterySystem.Charger.Mode", NULL, "%.0f", HU_FLAG_QUICK_POLL, eaton_abm_status_info }, /* UPS page */ { "ups.efficiency", 0, 0, "UPS.PowerConverter.Output.Efficiency", NULL, "%.0f", 0, NULL }, { "ups.firmware", 0, 0, "UPS.PowerSummary.iVersion", NULL, "%s", HU_FLAG_STATIC, stringid_conversion }, { "ups.load", 0, 0, "UPS.PowerSummary.PercentLoad", NULL, "%.0f", 0, NULL }, { "ups.load.high", ST_FLAG_RW | ST_FLAG_STRING, 5, "UPS.Flow.[4].ConfigPercentLoad", NULL, "%.0f", HU_FLAG_SEMI_STATIC, NULL }, { "ups.delay.start", ST_FLAG_RW | ST_FLAG_STRING, 10, "UPS.PowerSummary.DelayBeforeStartup", NULL, DEFAULT_ONDELAY, HU_FLAG_ABSENT, NULL}, { "ups.delay.shutdown", ST_FLAG_RW | ST_FLAG_STRING, 10, "UPS.PowerSummary.DelayBeforeShutdown", NULL, DEFAULT_OFFDELAY, HU_FLAG_ABSENT, NULL}, { "ups.timer.start", 0, 0, "UPS.PowerSummary.DelayBeforeStartup", NULL, "%.0f", HU_FLAG_QUICK_POLL, NULL}, { "ups.timer.shutdown", 0, 0, "UPS.PowerSummary.DelayBeforeShutdown", NULL, "%.0f", HU_FLAG_QUICK_POLL, NULL}, { "ups.timer.reboot", 0, 0, "UPS.PowerSummary.DelayBeforeReboot", NULL, "%.0f", HU_FLAG_QUICK_POLL, NULL}, { "ups.test.result", 0, 0, "UPS.BatterySystem.Battery.Test", NULL, "%s", 0, test_read_info }, { "ups.test.interval", ST_FLAG_RW | ST_FLAG_STRING, 8, "UPS.BatterySystem.Battery.TestPeriod", NULL, "%.0f", HU_FLAG_SEMI_STATIC, NULL }, /* Duplicate data for some units (such as 3S) that use a different path * Only the first valid one will be used */ { "ups.beeper.status", 0 ,0, "UPS.BatterySystem.Battery.AudibleAlarmControl", NULL, "%s", HU_FLAG_SEMI_STATIC, beeper_info }, { "ups.beeper.status", 0 ,0, "UPS.PowerSummary.AudibleAlarmControl", NULL, "%s", HU_FLAG_SEMI_STATIC, beeper_info }, { "ups.temperature", 0, 0, "UPS.PowerSummary.Temperature", NULL, "%s", 0, kelvin_celsius_conversion }, { "ups.power", 0, 0, "UPS.PowerConverter.Output.ApparentPower", NULL, "%.0f", 0, NULL }, { "ups.L1.power", 0, 0, "UPS.PowerConverter.Output.Phase.[1].ApparentPower", NULL, "%.0f", 0, NULL }, { "ups.L2.power", 0, 0, "UPS.PowerConverter.Output.Phase.[2].ApparentPower", NULL, "%.0f", 0, NULL }, { "ups.L3.power", 0, 0, "UPS.PowerConverter.Output.Phase.[3].ApparentPower", NULL, "%.0f", 0, NULL }, { "ups.power.nominal", 0, 0, "UPS.Flow.[4].ConfigApparentPower", NULL, "%.0f", HU_FLAG_STATIC, NULL }, { "ups.realpower", 0, 0, "UPS.PowerConverter.Output.ActivePower", NULL, "%.0f", 0, NULL }, /* When not available, process an approximation from other data, * but map to apparent power to be called */ { "ups.realpower", 0, 0, "UPS.Flow.[4].ConfigApparentPower", NULL, "-1", 0, eaton_compute_realpower_info }, { "ups.L1.realpower", 0, 0, "UPS.PowerConverter.Output.Phase.[1].ActivePower", NULL, "%.0f", 0, NULL }, { "ups.L2.realpower", 0, 0, "UPS.PowerConverter.Output.Phase.[2].ActivePower", NULL, "%.0f", 0, NULL }, { "ups.L3.realpower", 0, 0, "UPS.PowerConverter.Output.Phase.[3].ActivePower", NULL, "%.0f", 0, NULL }, { "ups.realpower.nominal", 0, 0, "UPS.Flow.[4].ConfigActivePower", NULL, "%.0f", HU_FLAG_STATIC, NULL }, { "ups.start.auto", ST_FLAG_RW | ST_FLAG_STRING, 5, "UPS.PowerConverter.Input.[1].AutomaticRestart", NULL, "%s", HU_FLAG_SEMI_STATIC, yes_no_info }, { "ups.start.battery", ST_FLAG_RW | ST_FLAG_STRING, 5, "UPS.PowerConverter.Input.[3].StartOnBattery", NULL, "%s", HU_FLAG_SEMI_STATIC, yes_no_info }, { "ups.start.reboot", ST_FLAG_RW | ST_FLAG_STRING, 5, "UPS.PowerConverter.Output.ForcedReboot", NULL, "%s", HU_FLAG_SEMI_STATIC, yes_no_info }, { "ups.shutdown", ST_FLAG_RW | ST_FLAG_STRING, 10, "UPS.PowerSummary.PresentStatus.Switchable", NULL, "%s", HU_FLAG_SEMI_STATIC | HU_FLAG_ENUM, eaton_enable_disable_info }, #ifdef HAVE_STRPTIME { "ups.date", ST_FLAG_RW | ST_FLAG_STRING, 10, "UPS.PowerSummary.Time", NULL, "%s", 0, mge_date_conversion }, { "ups.time", ST_FLAG_RW | ST_FLAG_STRING, 10, "UPS.PowerSummary.Time", NULL, "%s", 0, mge_time_conversion }, #else { "ups.date", 0, 0, "UPS.PowerSummary.Time", NULL, "%s", 0, mge_date_conversion }, { "ups.time", 0, 0, "UPS.PowerSummary.Time", NULL, "%s", 0, mge_time_conversion }, #endif /* HAVE_STRPTIME */ { "ups.type", 0, 0, "UPS.PowerConverter.ConverterType", NULL, "%s", HU_FLAG_STATIC, mge_upstype_conversion }, /* Special case: boolean values that are mapped to ups.status and ups.alarm */ { "BOOL", 0, 0, "UPS.PowerSummary.PresentStatus.ACPresent", NULL, NULL, HU_FLAG_QUICK_POLL, online_info }, { "BOOL", 0, 0, "UPS.PowerConverter.Input.[3].PresentStatus.Used", NULL, NULL, 0, mge_onbatt_info }, #if 0 /* NOTE: see entry with eaton_converter_online_info below now */ { "BOOL", 0, 0, "UPS.PowerConverter.Input.[1].PresentStatus.Used", NULL, NULL, 0, online_info }, #endif /* These 2 ones are used when ABM is disabled */ { "BOOL", 0, 0, "UPS.PowerSummary.PresentStatus.Discharging", NULL, NULL, HU_FLAG_QUICK_POLL, eaton_discharging_info }, { "BOOL", 0, 0, "UPS.PowerSummary.PresentStatus.Charging", NULL, NULL, HU_FLAG_QUICK_POLL, eaton_charging_info }, /* And this one when ABM is enabled (same as battery.charger.status) */ { "BOOL", 0, 0, "UPS.BatterySystem.Charger.Mode", NULL, "%.0f", HU_FLAG_QUICK_POLL, eaton_abm_chrg_dischrg_info }, /* FIXME: on Dell, the above requires an "AND" with "UPS.BatterySystem.Charger.Mode = 1" */ { "BOOL", 0, 0, "UPS.PowerSummary.PresentStatus.BelowRemainingCapacityLimit", NULL, NULL, HU_FLAG_QUICK_POLL, lowbatt_info }, /* Output overload, Level 1 (FIXME: add the level?) */ { "BOOL", 0, 0, "UPS.PowerConverter.Output.Overload.[1].PresentStatus.OverThreshold", NULL, NULL, 0, overload_info }, /* Output overload, Level 2 (FIXME: add the level?) */ { "BOOL", 0, 0, "UPS.PowerConverter.Output.Overload.[2].PresentStatus.OverThreshold", NULL, NULL, 0, overload_info }, /* Output overload, Level 3 (FIXME: add the level?) */ { "BOOL", 0, 0, "UPS.PowerSummary.PresentStatus.Overload", NULL, NULL, 0, overload_info }, { "BOOL", 0, 0, "UPS.PowerSummary.PresentStatus.NeedReplacement", NULL, NULL, 0, replacebatt_info }, /* FIXME: on Dell, the above requires an "AND" with "UPS.BatterySystem.Battery.Test = 3 " */ { "BOOL", 0, 0, "UPS.LCMSystem.LCMAlarm.[2].PresentStatus.TimerExpired", NULL, NULL, 0, replacebatt_info }, { "BOOL", 0, 0, "UPS.PowerConverter.Input.[1].PresentStatus.Buck", NULL, NULL, 0, trim_info }, { "BOOL", 0, 0, "UPS.PowerConverter.Input.[1].PresentStatus.Boost", NULL, NULL, 0, boost_info }, { "BOOL", 0, 0, "UPS.PowerConverter.Input.[1].PresentStatus.VoltageOutOfRange", NULL, NULL, 0, vrange_info }, { "BOOL", 0, 0, "UPS.PowerConverter.Input.[1].PresentStatus.FrequencyOutOfRange", NULL, NULL, 0, frange_info }, { "BOOL", 0, 0, "UPS.PowerSummary.PresentStatus.Good", NULL, NULL, 0, off_info }, /* NOTE: UPS.PowerConverter.Input.[1].PresentStatus.Used" must only be considered when not "OFF", * and must hence be after "UPS.PowerSummary.PresentStatus.Good" */ { "BOOL", 0, 0, "UPS.PowerConverter.Input.[1].PresentStatus.Used", NULL, NULL, 0, eaton_converter_online_info }, { "BOOL", 0, 0, "UPS.PowerConverter.Input.[2].PresentStatus.Used", NULL, NULL, 0, bypass_auto_info }, /* Automatic bypass */ /* NOTE: entry [3] is above as mge_onbatt_info */ { "BOOL", 0, 0, "UPS.PowerConverter.Input.[4].PresentStatus.Used", NULL, NULL, 0, bypass_manual_info }, /* Manual bypass */ { "BOOL", 0, 0, "UPS.PowerSummary.PresentStatus.FanFailure", NULL, NULL, 0, fanfail_info }, { "BOOL", 0, 0, "UPS.BatterySystem.Battery.PresentStatus.Present", NULL, NULL, 0, nobattery_info }, { "BOOL", 0, 0, "UPS.BatterySystem.Charger.PresentStatus.InternalFailure", NULL, NULL, 0, chargerfail_info }, { "BOOL", 0, 0, "UPS.BatterySystem.Charger.PresentStatus.VoltageTooHigh", NULL, NULL, 0, battvolthi_info }, { "BOOL", 0, 0, "UPS.PowerConverter.Input.[1].PresentStatus.VoltageTooHigh", NULL, NULL, 0, battvolthi_info }, /* Battery DC voltage too high! */ { "BOOL", 0, 0, "UPS.BatterySystem.Battery.PresentStatus.VoltageTooHigh", NULL, NULL, 0, battvolthi_info }, { "BOOL", 0, 0, "UPS.BatterySystem.Charger.PresentStatus.VoltageTooLow", NULL, NULL, 0, battvoltlo_info }, { "BOOL", 0, 0, "UPS.PowerConverter.Input.[1].PresentStatus.VoltageTooLow", NULL, NULL, 0, mge_onbatt_info }, { "BOOL", 0, 0, "UPS.PowerSummary.PresentStatus.InternalFailure", NULL, NULL, 0, commfault_info }, { "BOOL", 0, 0, "UPS.PowerSummary.PresentStatus.OverTemperature", NULL, NULL, 0, overheat_info }, { "BOOL", 0, 0, "UPS.PowerSummary.PresentStatus.ShutdownImminent", NULL, NULL, 0, shutdownimm_info }, /* Vendor specific ups.alarm */ { "ups.alarm", 0, 0, "UPS.PowerSummary.PresentStatus.EmergencyStop", NULL, NULL, 0, mge_emergency_stop }, { "ups.alarm", 0, 0, "UPS.PowerConverter.Input.[1].PresentStatus.WiringFault", NULL, NULL, 0, mge_wiring_fault }, { "ups.alarm", 0, 0, "UPS.PowerSummary.PresentStatus.ConfigurationFailure", NULL, NULL, 0, mge_config_failure }, { "ups.alarm", 0, 0, "UPS.PowerConverter.Inverter.PresentStatus.VoltageTooHigh", NULL, NULL, 0, mge_inverter_volthi }, { "ups.alarm", 0, 0, "UPS.PowerConverter.Inverter.PresentStatus.VoltageTooLow", NULL, NULL, 0, mge_inverter_voltlo }, { "ups.alarm", 0, 0, "UPS.PowerConverter.Output.PresentStatus.ShortCircuit", NULL, NULL, 0, mge_short_circuit }, /* Input page */ { "input.voltage", 0, 0, "UPS.PowerConverter.Input.[1].Voltage", NULL, "%.1f", 0, NULL }, { "input.L1-N.voltage", 0, 0, "UPS.PowerConverter.Input.[1].Phase.[1].Voltage", NULL, "%.1f", 0, NULL }, { "input.L2-N.voltage", 0, 0, "UPS.PowerConverter.Input.[1].Phase.[2].Voltage", NULL, "%.1f", 0, NULL }, { "input.L3-N.voltage", 0, 0, "UPS.PowerConverter.Input.[1].Phase.[3].Voltage", NULL, "%.1f", 0, NULL }, { "input.L1-L2.voltage", 0, 0, "UPS.PowerConverter.Input.[1].Phase.[12].Voltage", NULL, "%.1f", 0, NULL }, { "input.L2-L3.voltage", 0, 0, "UPS.PowerConverter.Input.[1].Phase.[23].Voltage", NULL, "%.1f", 0, NULL }, { "input.L3-L1.voltage", 0, 0, "UPS.PowerConverter.Input.[1].Phase.[31].Voltage", NULL, "%.1f", 0, NULL }, { "input.voltage.nominal", 0, 0, "UPS.Flow.[1].ConfigVoltage", NULL, "%.0f", HU_FLAG_STATIC, NULL }, { "input.current", 0, 0, "UPS.PowerConverter.Input.[1].Current", NULL, "%.2f", 0, NULL }, { "input.L1.current", 0, 0, "UPS.PowerConverter.Input.[1].Phase.[1].Current", NULL, "%.1f", 0, NULL }, { "input.L2.current", 0, 0, "UPS.PowerConverter.Input.[1].Phase.[2].Current", NULL, "%.1f", 0, NULL }, { "input.L3.current", 0, 0, "UPS.PowerConverter.Input.[1].Phase.[3].Current", NULL, "%.1f", 0, NULL }, { "input.current.nominal", 0, 0, "UPS.Flow.[1].ConfigCurrent", NULL, "%.2f", HU_FLAG_STATIC, NULL }, { "input.frequency", 0, 0, "UPS.PowerConverter.Input.[1].Frequency", NULL, "%.1f", 0, NULL }, { "input.frequency.nominal", 0, 0, "UPS.Flow.[1].ConfigFrequency", NULL, "%.0f", HU_FLAG_STATIC, NULL }, /* same as "input.transfer.boost.low" */ { "input.transfer.low", ST_FLAG_RW | ST_FLAG_STRING, 5, "UPS.PowerConverter.Output.LowVoltageTransfer", NULL, "%.0f", HU_FLAG_SEMI_STATIC, NULL }, { "input.transfer.boost.low", ST_FLAG_RW | ST_FLAG_STRING, 5, "UPS.PowerConverter.Output.LowVoltageBoostTransfer", NULL, "%.0f", HU_FLAG_SEMI_STATIC, NULL }, { "input.transfer.boost.high", ST_FLAG_RW | ST_FLAG_STRING, 5, "UPS.PowerConverter.Output.HighVoltageBoostTransfer", NULL, "%.0f", HU_FLAG_SEMI_STATIC, NULL }, { "input.transfer.trim.low", ST_FLAG_RW | ST_FLAG_STRING, 5, "UPS.PowerConverter.Output.LowVoltageBuckTransfer", NULL, "%.0f", HU_FLAG_SEMI_STATIC, NULL }, /* same as "input.transfer.trim.high" */ { "input.transfer.high", ST_FLAG_RW | ST_FLAG_STRING, 5, "UPS.PowerConverter.Output.HighVoltageTransfer", NULL, "%.0f", HU_FLAG_SEMI_STATIC, NULL }, { "input.transfer.trim.high", ST_FLAG_RW | ST_FLAG_STRING, 5, "UPS.PowerConverter.Output.HighVoltageBuckTransfer", NULL, "%.0f", HU_FLAG_SEMI_STATIC, NULL }, { "input.sensitivity", ST_FLAG_RW | ST_FLAG_STRING, 10, "UPS.PowerConverter.Output.SensitivityMode", NULL, "%s", HU_FLAG_SEMI_STATIC, mge_sensitivity_info }, { "input.voltage.extended", ST_FLAG_RW | ST_FLAG_STRING, 5, "UPS.PowerConverter.Output.ExtendedVoltageMode", NULL, "%s", HU_FLAG_SEMI_STATIC, yes_no_info }, { "input.frequency.extended", ST_FLAG_RW | ST_FLAG_STRING, 5, "UPS.PowerConverter.Output.ExtendedFrequencyMode", NULL, "%s", HU_FLAG_SEMI_STATIC, yes_no_info }, /* Bypass page */ { "input.bypass.voltage", 0, 0, "UPS.PowerConverter.Input.[2].Voltage", NULL, "%.1f", 0, NULL }, { "input.bypass.L1-N.voltage", 0, 0, "UPS.PowerConverter.Input.[2].Phase.[1].Voltage", NULL, "%.1f", 0, NULL }, { "input.bypass.L2-N.voltage", 0, 0, "UPS.PowerConverter.Input.[2].Phase.[2].Voltage", NULL, "%.1f", 0, NULL }, { "input.bypass.L3-N.voltage", 0, 0, "UPS.PowerConverter.Input.[2].Phase.[3].Voltage", NULL, "%.1f", 0, NULL }, { "input.bypass.L1-L2.voltage", 0, 0, "UPS.PowerConverter.Input.[2].Phase.[12].Voltage", NULL, "%.1f", 0, NULL }, { "input.bypass.L2-L3.voltage", 0, 0, "UPS.PowerConverter.Input.[2].Phase.[23].Voltage", NULL, "%.1f", 0, NULL }, { "input.bypass.L3-L1.voltage", 0, 0, "UPS.PowerConverter.Input.[2].Phase.[31].Voltage", NULL, "%.1f", 0, NULL }, { "input.bypass.voltage.nominal", 0, 0, "UPS.Flow.[2].ConfigVoltage", NULL, "%.0f", HU_FLAG_STATIC, NULL }, { "input.bypass.current", 0, 0, "UPS.PowerConverter.Input.[2].Current", NULL, "%.2f", 0, NULL }, { "input.bypass.L1.current", 0, 0, "UPS.PowerConverter.Input.[2].Phase.[1].Current", NULL, "%.1f", 0, NULL }, { "input.bypass.L2.current", 0, 0, "UPS.PowerConverter.Input.[2].Phase.[2].Current", NULL, "%.1f", 0, NULL }, { "input.bypass.L3.current", 0, 0, "UPS.PowerConverter.Input.[2].Phase.[3].Current", NULL, "%.1f", 0, NULL }, { "input.bypass.current.nominal", 0, 0, "UPS.Flow.[2].ConfigCurrent", NULL, "%.2f", HU_FLAG_STATIC, NULL }, { "input.bypass.frequency", 0, 0, "UPS.PowerConverter.Input.[2].Frequency", NULL, "%.1f", 0, NULL }, { "input.bypass.frequency.nominal", 0, 0, "UPS.Flow.[2].ConfigFrequency", NULL, "%.0f", HU_FLAG_STATIC, NULL }, /* Output page */ { "output.voltage", 0, 0, "UPS.PowerConverter.Output.Voltage", NULL, "%.1f", 0, NULL }, { "output.L1-N.voltage", 0, 0, "UPS.PowerConverter.Output.Phase.[1].Voltage", NULL, "%.1f", 0, NULL }, { "output.L2-N.voltage", 0, 0, "UPS.PowerConverter.Output.Phase.[2].Voltage", NULL, "%.1f", 0, NULL }, { "output.L3-N.voltage", 0, 0, "UPS.PowerConverter.Output.Phase.[3].Voltage", NULL, "%.1f", 0, NULL }, { "output.L1-L2.voltage", 0, 0, "UPS.PowerConverter.Output.Phase.[12].Voltage", NULL, "%.1f", 0, NULL }, { "output.L2-L3.voltage", 0, 0, "UPS.PowerConverter.Output.Phase.[23].Voltage", NULL, "%.1f", 0, NULL }, { "output.L3-L1.voltage", 0, 0, "UPS.PowerConverter.Output.Phase.[31].Voltage", NULL, "%.1f", 0, NULL }, { "output.voltage.nominal", ST_FLAG_RW | ST_FLAG_STRING, 3, "UPS.Flow.[4].ConfigVoltage", NULL, "%.0f", HU_FLAG_SEMI_STATIC | HU_FLAG_ENUM, nominal_output_voltage_info }, { "output.current", 0, 0, "UPS.PowerConverter.Output.Current", NULL, "%.2f", 0, NULL }, { "output.L1.current", 0, 0, "UPS.PowerConverter.Output.Phase.[1].Current", NULL, "%.1f", 0, NULL }, { "output.L2.current", 0, 0, "UPS.PowerConverter.Output.Phase.[2].Current", NULL, "%.1f", 0, NULL }, { "output.L3.current", 0, 0, "UPS.PowerConverter.Output.Phase.[3].Current", NULL, "%.1f", 0, NULL }, { "output.current.nominal", 0, 0, "UPS.Flow.[4].ConfigCurrent", NULL, "%.2f", 0, NULL }, { "output.frequency", 0, 0, "UPS.PowerConverter.Output.Frequency", NULL, "%.1f", 0, NULL }, /* FIXME: can be RW (50/60) (or on .nominal)? */ { "output.frequency.nominal", 0, 0, "UPS.Flow.[4].ConfigFrequency", NULL, "%.0f", HU_FLAG_STATIC, NULL }, { "output.powerfactor", 0, 0, "UPS.PowerConverter.Output.PowerFactor", NULL, "%s", 0, mge_powerfactor_conversion }, /* Outlet page (using MGE UPS SYSTEMS - PowerShare technology) */ { "outlet.id", 0, 0, "UPS.OutletSystem.Outlet.[1].OutletID", NULL, "%.0f", HU_FLAG_STATIC, NULL }, { "outlet.desc", ST_FLAG_RW | ST_FLAG_STRING, 20, "UPS.OutletSystem.Outlet.[1].OutletID", NULL, "Main Outlet", HU_FLAG_ABSENT, NULL }, { "outlet.switchable", 0, 0, "UPS.OutletSystem.Outlet.[1].PresentStatus.Switchable", NULL, "%s", HU_FLAG_STATIC, yes_no_info }, /* On Protection Station, the line below is the power consumption threshold * on the master outlet used to automatically power off the slave outlets. * Values: 10, 25 (default) or 60 VA. */ { "outlet.power", ST_FLAG_RW | ST_FLAG_STRING, 6, "UPS.OutletSystem.Outlet.[1].ConfigApparentPower", NULL, "%s", HU_FLAG_SEMI_STATIC | HU_FLAG_ENUM, pegasus_threshold_info }, { "outlet.power", 0, 0, "UPS.OutletSystem.Outlet.[1].ApparentPower", NULL, "%.0f", 0, NULL }, { "outlet.realpower", 0, 0, "UPS.OutletSystem.Outlet.[1].ActivePower", NULL, "%.0f", 0, NULL }, { "outlet.current", 0, 0, "UPS.OutletSystem.Outlet.[1].Current", NULL, "%.2f", 0, NULL }, { "outlet.powerfactor", 0, 0, "UPS.OutletSystem.Outlet.[1].PowerFactor", NULL, "%.2f", 0, NULL }, /* "%s", 0, mge_powerfactor_conversion }, */ /* First outlet */ { "outlet.1.id", 0, 0, "UPS.OutletSystem.Outlet.[2].OutletID", NULL, "%.0f", HU_FLAG_STATIC, NULL }, { "outlet.1.desc", ST_FLAG_RW | ST_FLAG_STRING, 20, "UPS.OutletSystem.Outlet.[2].OutletID", NULL, "PowerShare Outlet 1", HU_FLAG_ABSENT, NULL }, { "outlet.1.switchable", 0, 0, "UPS.OutletSystem.Outlet.[2].PresentStatus.Switchable", NULL, "%s", HU_FLAG_STATIC, yes_no_info }, { "outlet.1.status", 0, 0, "UPS.OutletSystem.Outlet.[2].PresentStatus.SwitchOn/Off", NULL, "%s", 0, on_off_info }, /* For low end models, with 1 non backup'ed outlet */ { "outlet.1.status", 0, 0, "UPS.PowerSummary.PresentStatus.ACPresent", NULL, "%s", 0, on_off_info }, /* FIXME: change to outlet.1.battery.charge.low, as in mge-xml.c?! */ { "outlet.1.autoswitch.charge.low", ST_FLAG_RW | ST_FLAG_STRING, 3, "UPS.OutletSystem.Outlet.[2].RemainingCapacityLimit", NULL, "%.0f", HU_FLAG_SEMI_STATIC, NULL }, { "outlet.1.delay.shutdown", ST_FLAG_RW | ST_FLAG_STRING, 5, "UPS.OutletSystem.Outlet.[2].ShutdownTimer", NULL, "%.0f", HU_FLAG_SEMI_STATIC, NULL }, { "outlet.1.delay.start", ST_FLAG_RW | ST_FLAG_STRING, 5, "UPS.OutletSystem.Outlet.[2].StartupTimer", NULL, "%.0f", HU_FLAG_SEMI_STATIC, NULL }, { "outlet.1.power", 0, 0, "UPS.OutletSystem.Outlet.[2].ApparentPower", NULL, "%.0f", 0, NULL }, { "outlet.1.realpower", 0, 0, "UPS.OutletSystem.Outlet.[2].ActivePower", NULL, "%.0f", 0, NULL }, { "outlet.1.current", 0, 0, "UPS.OutletSystem.Outlet.[2].Current", NULL, "%.2f", 0, NULL }, { "outlet.1.powerfactor", 0, 0, "UPS.OutletSystem.Outlet.[2].PowerFactor", NULL, "%.2f", 0, NULL }, /* "%s", 0, mge_powerfactor_conversion }, */ /* Second outlet */ { "outlet.2.id", 0, 0, "UPS.OutletSystem.Outlet.[3].OutletID", NULL, "%.0f", HU_FLAG_STATIC, NULL }, { "outlet.2.desc", ST_FLAG_RW | ST_FLAG_STRING, 20, "UPS.OutletSystem.Outlet.[3].OutletID", NULL, "PowerShare Outlet 2", HU_FLAG_ABSENT, NULL }, /* needed for Pegasus to enable master/slave mode: * FIXME: rename to something more suitable (outlet.?) */ { "outlet.2.switchable", ST_FLAG_RW | ST_FLAG_STRING, 3, "UPS.OutletSystem.Outlet.[3].PresentStatus.Switchable", NULL, "%s", HU_FLAG_SEMI_STATIC, pegasus_yes_no_info }, /* Generic version (RO) for other models */ { "outlet.2.switchable", 0, 0, "UPS.OutletSystem.Outlet.[3].PresentStatus.Switchable", NULL, "%s", 0, yes_no_info }, { "outlet.2.status", 0, 0, "UPS.OutletSystem.Outlet.[3].PresentStatus.SwitchOn/Off", NULL, "%s", 0, on_off_info }, { "outlet.2.autoswitch.charge.low", ST_FLAG_RW | ST_FLAG_STRING, 3, "UPS.OutletSystem.Outlet.[3].RemainingCapacityLimit", NULL, "%.0f", HU_FLAG_SEMI_STATIC, NULL }, { "outlet.2.delay.shutdown", ST_FLAG_RW | ST_FLAG_STRING, 5, "UPS.OutletSystem.Outlet.[3].ShutdownTimer", NULL, "%.0f", HU_FLAG_SEMI_STATIC, NULL }, { "outlet.2.delay.start", ST_FLAG_RW | ST_FLAG_STRING, 5, "UPS.OutletSystem.Outlet.[3].StartupTimer", NULL, "%.0f", HU_FLAG_SEMI_STATIC, NULL }, { "outlet.2.power", 0, 0, "UPS.OutletSystem.Outlet.[3].ApparentPower", NULL, "%.0f", 0, NULL }, { "outlet.2.realpower", 0, 0, "UPS.OutletSystem.Outlet.[3].ActivePower", NULL, "%.0f", 0, NULL }, { "outlet.2.current", 0, 0, "UPS.OutletSystem.Outlet.[3].Current", NULL, "%.2f", 0, NULL }, { "outlet.2.powerfactor", 0, 0, "UPS.OutletSystem.Outlet.[3].PowerFactor", NULL, "%.2f", 0, NULL }, /* "%s", 0, mge_powerfactor_conversion }, */ /* instant commands. */ /* splited into subset while waiting for extradata support * ie: test.battery.start quick */ { "test.battery.start.quick", 0, 0, "UPS.BatterySystem.Battery.Test", NULL, "1", HU_TYPE_CMD, NULL }, { "test.battery.start.deep", 0, 0, "UPS.BatterySystem.Battery.Test", NULL, "2", HU_TYPE_CMD, NULL }, { "test.battery.stop", 0, 0, "UPS.BatterySystem.Battery.Test", NULL, "3", HU_TYPE_CMD, NULL }, { "load.off.delay", 0, 0, "UPS.PowerSummary.DelayBeforeShutdown", NULL, DEFAULT_OFFDELAY, HU_TYPE_CMD, NULL }, { "load.on.delay", 0, 0, "UPS.PowerSummary.DelayBeforeStartup", NULL, DEFAULT_ONDELAY, HU_TYPE_CMD, NULL }, { "shutdown.stop", 0, 0, "UPS.PowerSummary.DelayBeforeShutdown", NULL, "-1", HU_TYPE_CMD, NULL }, { "shutdown.reboot", 0, 0, "UPS.PowerSummary.DelayBeforeReboot", NULL, "10", HU_TYPE_CMD, NULL}, { "beeper.off", 0, 0, "UPS.PowerSummary.AudibleAlarmControl", NULL, "1", HU_TYPE_CMD, NULL }, { "beeper.on", 0, 0, "UPS.PowerSummary.AudibleAlarmControl", NULL, "2", HU_TYPE_CMD, NULL }, /* Duplicate commands for some units (such as 3S) that use a different path * Only the first valid one will be used */ { "beeper.mute", 0, 0, "UPS.BatterySystem.Battery.AudibleAlarmControl", NULL, "3", HU_TYPE_CMD, NULL }, { "beeper.mute", 0, 0, "UPS.PowerSummary.AudibleAlarmControl", NULL, "3", HU_TYPE_CMD, NULL }, { "beeper.disable", 0, 0, "UPS.BatterySystem.Battery.AudibleAlarmControl", NULL, "1", HU_TYPE_CMD, NULL }, { "beeper.disable", 0, 0, "UPS.PowerSummary.AudibleAlarmControl", NULL, "1", HU_TYPE_CMD, NULL }, { "beeper.enable", 0, 0, "UPS.BatterySystem.Battery.AudibleAlarmControl", NULL, "2", HU_TYPE_CMD, NULL }, { "beeper.enable", 0, 0, "UPS.PowerSummary.AudibleAlarmControl", NULL, "2", HU_TYPE_CMD, NULL }, /* Command for the outlet collection */ { "outlet.1.load.off", 0, 0, "UPS.OutletSystem.Outlet.[2].DelayBeforeShutdown", NULL, "0", HU_TYPE_CMD, NULL }, { "outlet.1.load.on", 0, 0, "UPS.OutletSystem.Outlet.[2].DelayBeforeStartup", NULL, "0", HU_TYPE_CMD, NULL }, { "outlet.2.load.off", 0, 0, "UPS.OutletSystem.Outlet.[3].DelayBeforeShutdown", NULL, "0", HU_TYPE_CMD, NULL }, { "outlet.2.load.on", 0, 0, "UPS.OutletSystem.Outlet.[3].DelayBeforeStartup", NULL, "0", HU_TYPE_CMD, NULL }, /* end of structure. */ { NULL, 0, 0, NULL, NULL, NULL, 0, NULL } }; /* * All the logic for finely formatting the MGE model name and device * type matching (used for device specific values or corrections). * Returns pointer to (dynamically allocated) model name. */ static char *get_model_name(const char *iProduct, const char *iModel) { models_name_t *model = NULL; upsdebugx(2, "get_model_name(%s, %s)\n", iProduct, iModel); /* Search for device type and formatting rules */ for (model = mge_model_names; model->iProduct; model++) { if(model->name) { upsdebugx(2, "comparing with: %s", model->name); } else { upsdebugx(2, "comparing with: %s %s", model->iProduct, model->iModel); } if (strcmp(iProduct, model->iProduct)) { continue; } if (strcmp(iModel, model->iModel)) { continue; } mge_type = model->type; break; } if (!model->name) { /* * Model not found or NULL (use default) so construct * model name by concatenation of iProduct and iModel */ char buf[SMALLBUF]; #ifdef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_FORMAT_TRUNCATION #pragma GCC diagnostic push #endif #ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_FORMAT_TRUNCATION #pragma GCC diagnostic ignored "-Wformat-truncation" #endif /* NOTE: We intentionally limit the amount of bytes reported */ int len = snprintf(buf, sizeof(buf), "%s %s", iProduct, iModel); if (len < 0) { upsdebugx(1, "%s: got an error while extracting iProduct+iModel value", __func__); } /* NOTE: SMALLBUF here comes from mge_format_model() * buffer definitions below */ if ((intmax_t)len > (intmax_t)sizeof(buf) || (intmax_t)(strnlen(iProduct, SMALLBUF) + strnlen(iModel, SMALLBUF) + 1 + 1) > (intmax_t)sizeof(buf) ) { upsdebugx(1, "%s: extracted iProduct+iModel value was truncated", __func__); } #ifdef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_FORMAT_TRUNCATION #pragma GCC diagnostic pop #endif return strdup(buf); } return strdup(model->name); } static const char *mge_format_model(HIDDevice_t *hd) { char product[SMALLBUF]; char model[SMALLBUF]; double value; /* Dell has already a fully formatted name in iProduct */ if (hd->VendorID == DELL_VENDORID) { return hd->Product; } /* Get iProduct and iModel strings */ snprintf(product, sizeof(product), "%s", hd->Product ? hd->Product : "unknown"); HIDGetItemString(udev, "UPS.PowerSummary.iModel", model, sizeof(model), mge_utab); /* Fallback to ConfigApparentPower */ if ((strlen(model) < 1) && (HIDGetItemValue(udev, "UPS.Flow.[4].ConfigApparentPower", &value, mge_utab) == 1 )) { snprintf(model, sizeof(model), "%i", (int)value); } if (strlen(model) > 0) { free(hd->Product); hd->Product = get_model_name(product, model); } return hd->Product; } static const char *mge_format_mfr(HIDDevice_t *hd) { return hd->Vendor ? hd->Vendor : "Eaton"; } static const char *mge_format_serial(HIDDevice_t *hd) { return hd->Serial; } /* this function allows the subdriver to "claim" a device: return 1 if * the device is supported by this subdriver, else 0. */ static int mge_claim(HIDDevice_t *hd) { #if (defined SHUT_MODE) && SHUT_MODE NUT_UNUSED_VARIABLE(hd); return 1; #else /* !SHUT_MODE => USB */ int status = is_usb_device_supported(mge_usb_device_table, hd); switch (status) { case POSSIBLY_SUPPORTED: switch (hd->VendorID) { case HP_VENDORID: case DELL_VENDORID: /* by default, reject, unless the productid option is given */ if (getval("productid")) { return 1; } /* * this vendor makes lots of USB devices that are * not a UPS, so don't use possibly_supported here */ return 0; case PHOENIXTEC: /* The vendorid 0x06da is primarily handled by * liebert-hid, except for (maybe) AEG PROTECT NAS * branded devices */ if (hd->Vendor && strstr(hd->Vendor, "AEG")) { return 1; } if (hd->Product && strstr(hd->Product, "AEG")) { return 1; } /* Let liebert-hid grab this */ return 0; default: /* Valid for Eaton */ /* by default, reject, unless the productid option is given */ if (getval("productid")) { return 1; } possibly_supported("Eaton / MGE", hd); return 0; } case SUPPORTED: switch (hd->VendorID) { case PHOENIXTEC: /* see comments above */ if (hd->Vendor && strstr(hd->Vendor, "AEG")) { return 1; } if (hd->Product && strstr(hd->Product, "AEG")) { return 1; } /* Let liebert-hid grab this */ return 0; } return 1; case NOT_SUPPORTED: default: return 0; } #endif /* SHUT_MODE / USB */ } subdriver_t mge_subdriver = { MGE_HID_VERSION, mge_claim, mge_utab, mge_hid2nut, mge_format_model, mge_format_mfr, mge_format_serial, fix_report_desc, }; nut-2.8.1/drivers/baytech-mib.h0000644000175000017500000000022114273170601013260 00000000000000#ifndef BAYTECH_MIB_H #define BAYTECH_MIB_H #include "main.h" #include "snmp-ups.h" extern mib2nut_info_t baytech; #endif /* BAYTECH_MIB_H */ nut-2.8.1/drivers/oneac.h0000644000175000017500000001503014500336654012172 00000000000000/* oneac.h - Driver for Oneac UPS using the Advanced Interface. * * Copyright (C) * 2003 by Eric Lawson * 2012 by Bill Elliot * * This program was sponsored by MGE UPS SYSTEMS, and now Eaton * * 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 2 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, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #ifndef NUT_ONEAC_H_SEEN #define NUT_ONEAC_H_SEEN 1 /*misc stuff*/ #define ENDCHAR '\r' #define IGNCHARS "\n" #define COMMAND_END "\r\n" #define DEFAULT_BAT_TEST_TIME "02" /*Information requests -- EG level */ #define GET_ALL '%' #define GETALL_EG_RESP_SIZE 22 #define GETALL_RESP_SIZE 48 #define GET_MFR 'M' #define GET_FAMILY 'F' #define GET_VERSION 'N' #define GET_ON_INVERTER 'G' #define GET_BATLOW 'K' #define GET_STATUS 'X' #define GET_LAST_XFER 'W' #define GET_INVERTER_RDY 'I' #define GET_SHUTDOWN 'O' #define GET_TEST_TIME 'Q' #define GET_NOM_FREQ 'H' /*Information requests -- ON level (EG plus these) */ #define GET_NOM_VOLTAGE 'V' #define GET_DISPLAY_CODE 'D' #define GET_CONDITION_CODE 'C' #define GET_PERCENT_LOAD 'P' #define GET_PERCENT_BAT_REM 'T' #define GET_INPUT_LINE_VOLT 'L' #define GET_MIN_INPUT_VOLT 'A' #define GET_MAX_INPUT_VOLT 'E' #define GET_OUTPUT_VOLT 'S' #define GET_BOOSTING 'B' #define GET_SHUTDOWN_RESP_SIZE 3 /*Information requests -- OZ/OB level (ON plus these) */ #define GETX_ALL_1 '&' #define GETX_ALL1_RESP_SIZE 79 #define GETX_OUTSOURCE 'a' #define GETX_FRONTDISP 'b' #define GETX_INT_TEMP 'g' /* Degrees C */ #define GETX_BATT_STAT 'h' /* Unknown(1), Normal, Low, Depleted */ #define GETX_BATT_CHG_PERC 'i' /* 0 - 100 */ #define GETX_EST_MIN_REM 'j' #define GETX_ONBATT_TIME 'k' /* In seconds */ #define GETX_BATT_VOLTS 'l' /* Read as xxx.x */ #define GETX_INP_FREQ 'p' #define GETX_MIN_IN_VOLTS 'q' #define GETX_MAX_IN_VOLTS 'r' #define GETX_IN_VOLTS 's' #define GETX_IN_WATTS 'u' #define GETX_OUT_VOLTS 'v' #define GETX_OUT_WATTS 'x' #define GETX_OUT_LOAD_PERC 'y' #define GETX_OUT_FREQ 'z' #define GETX_ALL_2 '^' #define GETX_ALL2_RESP_SIZE 92 #define GETX_MODEL 'J' #define GETX_FW_REV 'U' /* Read as xx.x */ #define GETX_SERIAL_NUM 'Y' #define GETX_MAN_DATE '$' /* yymmdd */ #define GETX_BATT_REPLACED '+' /* yymmdd */ #define GETX_DATE_RESP_SIZE 6 /* FIXME: Both of the following constants are unused, and the first is not * valid C syntax (breaks LLVM). */ #if 0 #define GETX_UNIT_KVA '''' /* Read as xxx.xx */ #define GETX_UNIT_WATTS "''" /* 2-character string request */ #endif #define GETX_LOW_OUT_ALLOW '[' /* Tap up or inverter at this point */ #define GETX_HI_OUT_ALLOW ']' /* Tap down or inverter at this point */ #define GETX_NOTIFY_DELAY ',' /* Secs of delay for power fail alert */ #define GETX_ALLOW_RESP_SIZE 3 #define GETX_LOW_BATT_TIME '"' /* Low batt alarm at xx minutes */ #define GETX_RESTART_DLY '_' /* Restart delay */ #define GETX_RESTART_COUNT "_?" /* Returns actual counter value */ #define GETX_RSTRT_RESP_SIZE 4 /*Other requests */ #define GETX_SHUTDOWN '}' /* Shutdown counter (..... for none) */ #define GETX_SHUTDOWN_RESP_SIZE 5 #define GETX_BATT_TEST_DAYS "\x02\x1A" /* Days between battery tests */ #define GETX_BUZZER_WHAT "\x07?" /* What is buzzer state */ #define GETX_AUTO_START " 999 on OZ */ #define MIN_ALLOW_FW "1.9" /* At or above provides output allow range */ /*responses*/ #define FAMILY_EG "EG" /* 3 tri-color LEDs and big ON/OFF on front */ #define FAMILY_ON "ON" /* Serial port avail only on interface card */ #define FAMILY_OZ "OZ" /* DB-25 std., plus interface slot */ #define FAMILY_OB "OB" /* Lg. cab with removable modules */ #define FAMILY_SIZE 2 #define YES 'Y' #define NO 'N' #define V230AC '2' #define V120AC '1' #define XFER_BLACKOUT 'B' #define XFER_LOW_VOLT 'L' #define XFER_HI_VOLT 'H' #define BUZZER_ENABLED '1' #define BUZZER_DISABLED '0' #define BUZZER_MUTED '2' /*front panel alarm codes*/ #define CODE_BREAKER_OPEN "c1" /*input circuit breaker open*/ #define CODE_BAT_FUSE_OPEN "c2" /*battery not connected. Open fuse?*/ #define CODE_TOO_HOT "c3" /*UPS too hot*/ #define CODE_CHARGING "c4" /*recharging battery pack*/ #define CODE_LOW_BAT_CAP "c5" /*batteries getting too old*/ #define CODE_OVERLOAD "c8" /*"slight" overload*/ #define CODE_GROSS_OVLE "c9" /*gross overload 1 minute to power off*/ #define CODE_CHRGR_FUSE_OPEN "u1" /*battery charger fuse probably open*/ #endif /* NUT_ONEAC_H_SEEN */ nut-2.8.1/drivers/apcsmart_tabs.h0000644000175000017500000000702014500336654013730 00000000000000/* * apcsmart_tabs.h - tables for apcsmart driver * * Copyright (C) 1999 Russell Kroll * (C) 2000 Nigel Metheringham * (C) 2011+ Michal Soltys * * 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 2 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, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef NUT_APCSMART_TABS_H_SEEN #define NUT_APCSMART_TABS_H_SEEN 1 #include "main.h" #define APC_TABLE_VERSION "version 3.1" /* common flags */ #define APC_PRESENT 0x00000001 /* capability seen on this UPS */ /* instant commands' flags */ #define APC_NASTY 0x00000002 /* Nasty command - must be reconfirmed */ #define APC_REPEAT 0x00000004 /* Command needs sending twice */ /* variables' flags */ #define APC_POLL 0x00000100 /* poll this variable regularly */ #define APC_RW 0x00000200 /* read-write variable */ #define APC_ENUM 0x00000400 /* enumerated type variable */ #define APC_STRING 0x00000800 /* string variable */ #define APC_MULTI 0x00001000 /* there're other vars like that */ #define APC_PACK 0x00002000 /* packed variable */ #define APC_PACK_MAX 4 /* max count of subfields in packed var */ /* variables' format */ #define APC_F_MASK 0xFF000000 /* Mask for apc data formats */ #define APC_F_LEAVE 0x00000000 /* Just pass this through */ #define APC_F_PERCENT 0x01000000 /* Data in a percent format */ #define APC_F_VOLT 0x02000000 /* Data in a voltage format */ #define APC_F_AMP 0x03000000 /* Data in a current/amp format */ #define APC_F_CELSIUS 0x04000000 /* Data in a temp/C format */ #define APC_F_HEX 0x05000000 /* Data in a hex number format */ #define APC_F_DEC 0x06000000 /* Data in a decimal format */ #define APC_F_SECONDS 0x07000000 /* Time in seconds */ #define APC_F_MINUTES 0x08000000 /* Time in minutes */ #define APC_F_HOURS 0x09000000 /* Time in hours */ #define APC_F_REASON 0x0A000000 /* Reason of transfer */ /* instant commands */ #define APC_CMD_CUSTOM 0 /* command uses separate function */ #define APC_CMD_OFF 'Z' #define APC_CMD_ON '\016' /* ^N */ #define APC_CMD_FPTEST 'A' #define APC_CMD_SIMPWF 'U' #define APC_CMD_BTESTTOGGLE 'W' #define APC_CMD_GRACEDOWN '@' #define APC_CMD_SOFTDOWN 'S' #define APC_CMD_SHUTDOWN 'K' #define APC_CMD_CALTOGGLE 'D' #define APC_CMD_BYPTOGGLE '^' typedef struct { const char *name; /* the variable name */ char cmd; /* variable character */ unsigned int flags; /* various flags */ const char *regex; /* variable must match this regex */ size_t nlen0; /* var name + null len */ int cnt; /* curr. count of subs */ } apc_vartab_t; typedef struct { const char *name, *ext; char cmd; int flags; } apc_cmdtab_t; typedef struct { const char *firmware; const char *cmdchars; int flags; } apc_compattab_t; extern apc_vartab_t apc_vartab[]; extern apc_cmdtab_t apc_cmdtab[]; extern apc_compattab_t apc_compattab[]; extern upsdrv_info_t apc_tab_info; #endif /* NUT_APCSMART_TABS_H_SEEN */ nut-2.8.1/drivers/upshandler.h0000644000175000017500000000300214500336654013246 00000000000000/* upshandler.h - function callbacks used by the drivers Copyright (C) 2003 Russell Kroll 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 2 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, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef NUT_UPSHANDLER_H #define NUT_UPSHANDLER_H /* return values for instcmd */ enum { STAT_INSTCMD_HANDLED = 0, /* completed successfully */ STAT_INSTCMD_UNKNOWN, /* unspecified error */ STAT_INSTCMD_INVALID, /* invalid command */ STAT_INSTCMD_FAILED /* command failed */ }; /* return values for setvar */ enum { STAT_SET_HANDLED = 0, /* completed successfully */ STAT_SET_UNKNOWN, /* unspecified error */ STAT_SET_INVALID, /* not writeable */ STAT_SET_FAILED /* writing failed */ }; /* structure for funcs that get called by msg parse routine */ struct ups_handler { int (*setvar)(const char *, const char *); int (*instcmd)(const char *, const char *); }; #endif /* NUT_UPSHANDLER_H */ nut-2.8.1/drivers/delta_ups-mib.h0000644000175000017500000000201014273170601013617 00000000000000/* delta_ups-mib.h - subdriver to monitor delta_ups SNMP devices with NUT * * Copyright (C) * 2011 - 2012 Arnaud Quette * * 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 2 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, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef DELTA_UPS_MIB_H #define DELTA_UPS_MIB_H #include "main.h" #include "snmp-ups.h" extern mib2nut_info_t delta_ups; #endif /* DELTA_UPS_MIB_H */ nut-2.8.1/drivers/eaton-pdu-marlin-helpers.c0000644000175000017500000000546114501607135015717 00000000000000/* eaton-pdu-marlin-helpers.c - helper routines for eaton-pdu-marlin-mib.c * to monitor Eaton ePDUs branded as: * G2 Marlin SW / MI / MO / MA * G3 Shark SW / MI / MO / MA * * Copyright (C) 2017-2019 * Arnaud Quette * Copyright (C) 2017 * Jim Klimov * * Supported by Eaton * and previously MGE Office Protection Systems * * 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 2 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, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #include "config.h" /* must be the first header */ #include #include #include "nut_stdint.h" #include "eaton-pdu-marlin-helpers.h" #include "dstate.h" #include "common.h" /* Allow access to temperature_unit */ #include "snmp-ups.h" /* Take string "unitsPresent" (ex: "0,3,4,5"), and count the amount * of "," separators+1 using an inline function */ long marlin_device_count_fun(const char *daisy_dev_list) { long count = 0, i; for (i = 0; daisy_dev_list[i] != '\0'; i++) { if (daisy_dev_list[i] == ',') { /* Each comma means a new device in the list */ count ++; } } if (i > 0 && (daisy_dev_list[i - 1] != ',') ) { /* Non-empty string => at least one device, and no trailing commas */ count ++; } upsdebugx(3, "%s: counted devices in '%s', got %ld", __func__, daisy_dev_list, count); return count; } /* Temperature unit consideration: * only store the device unit, for converting to Celsius. * Don't publish the device unit, since NUT will publish * as Celsius in all cases */ const char *eaton_sensor_temperature_unit_fun(void *raw_snmp_value) { long snmp_value = *((long*)raw_snmp_value); switch (snmp_value) { case 0: /* store the value, for temperature processing */ temperature_unit = TEMPERATURE_KELVIN; break; case 1: /* store the value, for temperature processing */ temperature_unit = TEMPERATURE_CELSIUS; break; case 2: /* store the value, for temperature processing */ temperature_unit = TEMPERATURE_FAHRENHEIT; break; default: /* store the value, for temperature processing */ temperature_unit = TEMPERATURE_UNKNOWN; break; } return "celsius"; } nut-2.8.1/drivers/arduino-hid.h0000644000175000017500000000225114500336654013311 00000000000000/* arduino-hid.h - subdriver to monitor Arduino USB/HID devices with NUT * * Copyright (C) * 2003 - 2009 Arnaud Quette * 2005 - 2006 Peter Selinger * 2008 - 2009 Arjen de Korte * 2021 Alex Bratchik * * 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 2 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, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef ARDUINO_HID_H #define ARDUINO_HID_H #include "usbhid-ups.h" extern subdriver_t arduino_subdriver; #endif /* ARDUINO_HID_H */ nut-2.8.1/drivers/powervar-hid.c0000755000175000017500000001237214500336654013520 00000000000000/* powervar-hid.c - subdriver to monitor Powervar USB/HID devices with NUT * * Copyright (C) * 2003 - 2012 Arnaud Quette * 2005 - 2006 Peter Selinger * 2008 - 2009 Arjen de Korte * 2013 Charles Lepple * 2019 AMETEK Powervar - Andrew McCartney * * Note: this subdriver was initially generated as a "stub" by the * gen-usbhid-subdriver script. It must be customized. * * 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 2 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, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "config.h" /* must be first */ #include "usbhid-ups.h" #include "powervar-hid.h" #include "main.h" /* for getval() */ #include "usb-common.h" #define POWERVAR_HID_VERSION "Powervar HID 0.20" /* FIXME: experimental flag to be put in upsdrv_info */ /* Powervar */ #define POWERVAR_VENDORID 0x4234 /* USB IDs device table */ static usb_device_id_t powervar_usb_device_table[] = { /* Powervar */ { USB_DEVICE(POWERVAR_VENDORID, 0x0002), NULL }, /* Terminating entry */ { 0, 0, NULL } }; static usb_communication_subdriver_t *usb = &usb_subdriver; /* --------------------------------------------------------------- */ /* Vendor-specific usage table */ /* --------------------------------------------------------------- */ /* POWERVAR usage table */ static usage_lkp_t powervar_usage_lkp[] = { { "POWERVAR1", 0xff000001 }, { NULL, 0 } }; static usage_tables_t powervar_utab[] = { powervar_usage_lkp, hid_usage_lkp, NULL, }; /* --------------------------------------------------------------- */ /* HID2NUT lookup table */ /* --------------------------------------------------------------- */ static hid_info_t powervar_hid2nut[] = { /* Battery page */ { "battery.type", 0, 0, "UPS.PowerSummary.iDeviceChemistry", NULL, "%s", 0, stringid_conversion }, { "battery.charge", 0, 0, "UPS.PowerSummary.RemainingCapacity", NULL, "%.0f", 0, NULL }, { "battery.capacity", 0, 0, "UPS.PowerSummary.FullChargeCapacity", NULL, "%.0f", 0, NULL }, { "battery.runtime", 0, 0, "UPS.PowerSummary.RuntimeToEmpty", NULL, "%.0f", 0, NULL }, /* Special case: ups.status & ups.alarm */ { "BOOL", 0, 0, "UPS.PowerSummary.PresentStatus.ACPresent", NULL, NULL, HU_FLAG_QUICK_POLL, online_info }, { "BOOL", 0, 0, "UPS.PowerSummary.PresentStatus.Discharging", NULL, NULL, HU_FLAG_QUICK_POLL, discharging_info }, { "BOOL", 0, 0, "UPS.PowerSummary.PresentStatus.Charging", NULL, NULL, HU_FLAG_QUICK_POLL, charging_info }, { "BOOL", 0, 0, "UPS.PowerSummary.PresentStatus.ShutdownImminent", NULL, NULL, 0, shutdownimm_info }, { "BOOL", 0, 0, "UPS.PowerSummary.PresentStatus.BelowRemainingCapacityLimit", NULL, NULL, 0, lowbatt_info }, { "BOOL", 0, 0, "UPS.PowerSummary.PresentStatus.Overload", NULL, NULL, 0, overload_info }, { "BOOL", 0, 0, "UPS.PowerSummary.PresentStatus.NeedReplacement", NULL, NULL, 0, replacebatt_info }, { "BOOL", 0, 0, "UPS.PowerSummary.PresentStatus.RemainingTimeLimitExpired", NULL, NULL, 0, timelimitexpired_info }, { "BOOL", 0, 0, "UPS.PowerSummary.PresentStatus.InternalFailure", NULL, NULL, 0, yes_no_info }, { "BOOL", 0, 0, "UPS.PowerSummary.PresentStatus.Good", NULL, NULL, 0, yes_no_info }, { "BOOL", 0, 0, "UPS.PowerSummary.PresentStatus.OverTemperature", NULL, NULL, 0, overheat_info }, { "BOOL", 0, 0, "UPS.PowerSummary.PresentStatus.FullyCharged", NULL, NULL, 0, fullycharged_info }, { "BOOL", 0, 0, "UPS.PowerSummary.PresentStatus.FullyDischarged", NULL, NULL, 0, depleted_info }, /* end of structure. */ { NULL, 0, 0, NULL, NULL, NULL, 0, NULL } }; static const char *powervar_format_model(HIDDevice_t *hd) { return hd->Product; } static const char *powervar_format_mfr(HIDDevice_t *hd) { return hd->Vendor ? hd->Vendor : "Powervar"; } static const char *powervar_format_serial(HIDDevice_t *hd) { return hd->Serial; } /* this function allows the subdriver to "claim" a device: return 1 if * the device is supported by this subdriver, else 0. */ static int powervar_claim(HIDDevice_t *hd) { int status = is_usb_device_supported(powervar_usb_device_table, hd); switch (status) { case POSSIBLY_SUPPORTED: /* by default, reject, unless the productid option is given */ if (getval("productid")) { usb->hid_rep_index = 1; return 1; } possibly_supported("Powervar", hd); return 0; case SUPPORTED: usb->hid_rep_index = 1; return 1; case NOT_SUPPORTED: default: return 0; } } subdriver_t powervar_subdriver = { POWERVAR_HID_VERSION, powervar_claim, powervar_utab, powervar_hid2nut, powervar_format_model, powervar_format_mfr, powervar_format_serial, fix_report_desc, }; nut-2.8.1/drivers/tripplitesu.c0000644000175000017500000005720314515702041013465 00000000000000/* tripplitesu.c - model specific routines for Tripp Lite SmartOnline (SU*) models Copyright (C) 2003 Allan N. Hessenflow 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 2 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, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ /* Notes: The map for commands_available isn't clear. All of the information I have on the Tripp Lite SmartOnline protocol comes from the files TUN.tlp and TUNRT.tlp from their drivers, and some experimentation. One of those files told me what one bit was for in the AVL response, out of 18 that the SU1000RT2U sends or 21 that some other model sends. Later I found a description of the Belkin protocol, which is the same. Unfortunately it gives a definition of the AVL response that conflicts with the one bit I found from TUNRT.tlp, and in fact the response my SU1000RT2U gives, compared to the commands I have found it supports, does not match the Belkin description. So I'm treating the whole field as unknown. It would be nice to be able to use it to determine what variables to make RW. As a workaround, I'm assuming any value I query successfully which also can be set on at least one model, can in fact be set on the one I'm talking to. I didn't just add Tripp Lite support to the existing Belkin driver because I didn't discover that they were the same protocol until after I had put more features in this driver than the Belkin driver has. I'm not calling this a unified Belkin/Tripp Lite driver for a couple of reasons. One is that I don't have a Belkin to test with (and so I explicitly check for Tripp Lite in this drivers initialization - it *may* work fine with a Belkin by simply removing that test). The other reason is that I'd have to come up with a name - I don't know a name for the protocol, and I don't know which company (if either) originated the protocol. Picking one of the companies arbitrarily to name it after just seems wrong. There are a few things still to add. Primarily there's control of individual outlet banks, using (I presume) outlet.n.x variables. I'll probably wait for an example of that to show up in some other driver before adding that, to try to make sure I do it in the way that Russell Kroll envisioned. It also might be nice to give the user control over the delays before shutdown and restart, probably with additional driver parameters. Letting the user turn the buzzer off might be nice too; for that I'd have to investigate whether the command to do that disables it entirely, or just turns it off during the existing alarm condition, to determine whether it would be better implemented through variables or instant commands, and then of course request that those get added to the list of known names. Finally, there are a number of other alarm conditions that can be reported that would be nice to pass on to the user; these would require new variables or new status values. The following parameters (ups.conf) are supported: lowbatt The following variables are supported (RW = read/write): ambient.humidity (1) ambient.temperature (1) battery.charge battery.current (1) battery.temperature battery.voltage battery.voltage.nominal input.frequency input.sensitivity (RW) (1) input.transfer.high (RW) input.transfer.low (RW) input.voltage input.voltage.nominal output.current (1) output.frequency output.voltage output.voltage.nominal ups.firmware ups.id (RW) (1) ups.load ups.mfr ups.model ups.status ups.test.result ups.contacts (1) The following instant commands are supported: load.off load.on shutdown.reboot shutdown.reboot.graceful shutdown.return shutdown.stop test.battery.start test.battery.stop The following ups.status values are supported: BOOST (1) BYPASS LB OB OFF OL OVER (2) RB (2) TRIM (1) (1) these items have not been tested because they are not supported by my SU1000RT2U. (2) these items have not been tested because I haven't tested them. */ #include "main.h" #include "serial.h" #include "nut_stdint.h" #define DRIVER_NAME "Tripp Lite SmartOnline driver" #define DRIVER_VERSION "0.07" /* driver description structure */ upsdrv_info_t upsdrv_info = { DRIVER_NAME, DRIVER_VERSION, "Allan N. Hessenflow ", DRV_EXPERIMENTAL, { NULL } }; #define MAX_RESPONSE_LENGTH 256 static const char *test_result_names[] = { "No test performed", "Passed", "In progress", "General test failed", "Battery failed", "Deep battery test failed", "Aborted" }; static struct { int code; const char *name; } sensitivity[] = { {0, "Normal"}, {1, "Reduced"}, {2, "Low"} }; static struct { int outlet_banks; unsigned long commands_available; } ups; /* bits in commands_available */ #define WDG_AVAILABLE (1UL << 1) /* message types */ #define POLL 'P' #define SET 'S' #define ACCEPT 'A' #define REJECT 'R' #define DATA 'D' /* commands */ #define AUTO_REBOOT "ARB" /* poll/set */ #define AUTO_TEST "ATT" /* poll/set */ #define ATX_REBOOT "ATX" /* poll/set */ #define AVAILABLE "AVL" /* poll */ #define BATTERY_REPLACEMENT_DATE "BRD" /* poll/set */ #define BUZZER_TEST "BTT" /* set */ #define BATTERY_TEST "BTV" /* poll/set */ #define BUZZER "BUZ" /* set */ #define ECONOMIC_MODE "ECO" /* set */ #define ENABLE_BUZZER "EDB" /* set */ #define ENVIRONMENT_INFORMATION "ENV" /* poll */ #define OUTLET_RELAYS "LET" /* poll */ #define MANUFACTURER "MNU" /* poll */ #define MODEL "MOD" /* poll */ #define RATINGS "RAT" /* poll */ #define RELAY_CYCLE "RNF" /* set */ #define RELAY_OFF "ROF" /* set */ #define RELAY_ON "RON" /* set */ #define ATX_RESUME "RSM" /* set */ #define TSU_SHUTDOWN_ACTION "SDA" /* set */ #define TSU_SHUTDOWN_RESTART "SDR" /* set */ #define TSU_SHUTDOWN_TYPE "SDT" /* poll/set */ #define RELAY_STATUS "SOL" /* poll/set */ #define SELECT_OUTPUT_VOLTAGE "SOV" /* poll/set */ #define STATUS_ALARM "STA" /* poll */ #define STATUS_BATTERY "STB" /* poll */ #define STATUS_INPUT "STI" /* poll */ #define STATUS_OUTPUT "STO" /* poll */ #define STATUS_BYPASS "STP" /* poll */ #define TELEPHONE "TEL" /* poll/set */ #define TEST_RESULT "TSR" /* poll */ #define TEST "TST" /* set */ #define TRANSFER_FREQUENCY "TXF" /* poll/set */ #define TRANSFER_VOLTAGE "TXV" /* poll/set */ #define BOOT_DELAY "UBD" /* poll/set */ #define BAUD_RATE "UBR" /* poll/set */ #define IDENTIFICATION "UID" /* poll/set */ #define VERSION_CMD "VER" /* poll */ #define VOLTAGE_SENSITIVITY "VSN" /* poll/set */ #define WATCHDOG "WDG" /* poll/set */ static ssize_t do_command(char type, const char *command, const char *parameters, char *response) { char buffer[SMALLBUF]; size_t count; ssize_t ret; ser_flush_io(upsfd); if (response) { *response = '\0'; } snprintf(buffer, sizeof(buffer), "~00%c%03d%s%s", type, (int)(strlen(command) + strlen(parameters)), command, parameters); ret = ser_send_pace(upsfd, 10000, "%s", buffer); if (ret <= 0) { upsdebug_with_errno(3, "do_command: send [%s]", buffer); return -1; } upsdebugx(3, "do_command: %" PRIiSIZE " bytes sent [%s] -> OK", ret, buffer); ret = ser_get_buf_len(upsfd, (unsigned char *)buffer, 4, 3, 0); if (ret < 0) { upsdebug_with_errno(3, "do_command: read"); return -1; } if (ret == 0) { upsdebugx(3, "do_command: read -> TIMEOUT"); return -1; } buffer[ret] = '\0'; upsdebugx(3, "do_command: %" PRIiSIZE " byted read [%s]", ret, buffer); if (!strcmp(buffer, "~00D")) { int c; ret = ser_get_buf_len(upsfd, (unsigned char *)buffer, 3, 3, 0); if (ret < 0) { upsdebug_with_errno(3, "do_command: read"); return -1; } if (ret == 0) { upsdebugx(3, "do_command: read -> TIMEOUT"); return -1; } buffer[ret] = '\0'; upsdebugx(3, "do_command: %" PRIiSIZE " bytes read [%s]", ret, buffer); c = atoi(buffer); if (c < 0) { upsdebugx(3, "do_command: response not expected to be a negative count!"); return -1; } count = (size_t)c; if (count >= MAX_RESPONSE_LENGTH) { upsdebugx(3, "do_command: response exceeds expected size!"); return -1; } if (count && !response) { upsdebugx(3, "do_command: response not expected!"); return -1; } if (count == 0) { return 0; } ret = ser_get_buf_len(upsfd, (unsigned char *)response, count, 3, 0); if (ret < 0) { upsdebug_with_errno(3, "do_command: read"); return -1; } if (ret == 0) { upsdebugx(3, "do_command: read -> TIMEOUT"); return -1; } response[ret] = '\0'; upsdebugx(3, "do_command: %" PRIiSIZE " bytes read [%s]", ret, response); /* Tripp Lite pads their string responses with spaces. I don't like that, so I remove them. This is safe to do with all responses for this protocol, so I just do that here. */ str_rtrim(response, ' '); return ret; } if (!strcmp(buffer, "~00A")) { return 0; } return -1; } static char *field(char *str, int fieldnum) { while (str && fieldnum--) { str = strchr(str, ';'); if (str) str++; } if (str && *str == ';') return NULL; return str; } static int get_identification(void) { char response[MAX_RESPONSE_LENGTH]; if (do_command(POLL, IDENTIFICATION, "", response) >= 0) { dstate_setinfo("ups.id", "%s", response); return 1; } return 0; } static void set_identification(const char *val) { char response[MAX_RESPONSE_LENGTH]; if (do_command(POLL, IDENTIFICATION, "", response) < 0) return; if (strcmp(val, response)) { strncpy(response, val, MAX_RESPONSE_LENGTH); response[MAX_RESPONSE_LENGTH - 1] = '\0'; do_command(SET, IDENTIFICATION, response, NULL); } } static int get_transfer_voltage_low(void) { char response[MAX_RESPONSE_LENGTH]; char *ptr; if (do_command(POLL, TRANSFER_VOLTAGE, "", response) > 0) { ptr = field(response, 0); if (ptr) dstate_setinfo("input.transfer.low", "%d", atoi(ptr)); return 1; } return 0; } static void set_transfer_voltage_low(int val) { char response[MAX_RESPONSE_LENGTH]; char *ptr; int high; if (do_command(POLL, TRANSFER_VOLTAGE, "", response) <= 0) return; ptr = field(response, 0); if (!ptr || val == atoi(ptr)) return; ptr = field(response, 1); if (!ptr) return; high = atoi(ptr); snprintf(response, sizeof(response), "%d;%d", val, high); do_command(SET, TRANSFER_VOLTAGE, response, NULL); } static int get_transfer_voltage_high(void) { char response[MAX_RESPONSE_LENGTH]; char *ptr; if (do_command(POLL, TRANSFER_VOLTAGE, "", response) > 0) { ptr = field(response, 1); if (ptr) dstate_setinfo("input.transfer.high", "%d", atoi(ptr)); return 1; } return 0; } static void set_transfer_voltage_high(int val) { char response[MAX_RESPONSE_LENGTH]; char *ptr; int low; if (do_command(POLL, TRANSFER_VOLTAGE, "", response) <= 0) return; ptr = field(response, 0); if (!ptr) return; low = atoi(ptr); ptr = field(response, 1); if (!ptr || val == atoi(ptr)) return; snprintf(response, sizeof(response), "%d;%d", low, val); do_command(SET, TRANSFER_VOLTAGE, response, NULL); } static int get_sensitivity(void) { char response[MAX_RESPONSE_LENGTH]; unsigned int i; if (do_command(POLL, VOLTAGE_SENSITIVITY, "", response) <= 0) return 0; for (i = 0; i < SIZEOF_ARRAY(sensitivity); i++) { if (sensitivity[i].code == atoi(response)) { dstate_setinfo("input.sensitivity", "%s", sensitivity[i].name); return 1; } } return 0; } static void set_sensitivity(const char *val) { char parm[20]; unsigned int i; for (i = 0; i < SIZEOF_ARRAY(sensitivity); i++) { if (!strcasecmp(val, sensitivity[i].name)) { snprintf(parm, sizeof(parm), "%u", i); do_command(SET, VOLTAGE_SENSITIVITY, parm, NULL); break; } } } static void auto_reboot(int enable) { char parm[20]; char response[MAX_RESPONSE_LENGTH]; char *ptr; int mode; if (enable) mode = 1; else mode = 2; if (do_command(POLL, AUTO_REBOOT, "", response) <= 0) return; ptr = field(response, 0); if (!ptr || atoi(ptr) != mode) { snprintf(parm, sizeof(parm), "%d", mode); do_command(SET, AUTO_REBOOT, parm, NULL); } } static int instcmd(const char *cmdname, const char *extra) { int i; char parm[20]; if (!strcasecmp(cmdname, "load.off")) { for (i = 0; i < ups.outlet_banks; i++) { snprintf(parm, sizeof(parm), "%d;1", i + 1); do_command(SET, RELAY_OFF, parm, NULL); } return STAT_INSTCMD_HANDLED; } if (!strcasecmp(cmdname, "load.on")) { for (i = 0; i < ups.outlet_banks; i++) { snprintf(parm, sizeof(parm), "%d;1", i + 1); do_command(SET, RELAY_ON, parm, NULL); } return STAT_INSTCMD_HANDLED; } if (!strcasecmp(cmdname, "shutdown.reboot")) { auto_reboot(1); do_command(SET, TSU_SHUTDOWN_RESTART, "1", NULL); do_command(SET, TSU_SHUTDOWN_ACTION, "10", NULL); return STAT_INSTCMD_HANDLED; } if (!strcasecmp(cmdname, "shutdown.reboot.graceful")) { auto_reboot(1); do_command(SET, TSU_SHUTDOWN_RESTART, "1", NULL); do_command(SET, TSU_SHUTDOWN_ACTION, "60", NULL); return STAT_INSTCMD_HANDLED; } if (!strcasecmp(cmdname, "shutdown.return")) { auto_reboot(1); do_command(SET, TSU_SHUTDOWN_RESTART, "1", NULL); do_command(SET, TSU_SHUTDOWN_ACTION, "10", NULL); return STAT_INSTCMD_HANDLED; } #if 0 /* doesn't seem to work */ if (!strcasecmp(cmdname, "shutdown.stayoff")) { auto_reboot(0); do_command(SET, TSU_SHUTDOWN_ACTION, "10", NULL); return STAT_INSTCMD_HANDLED; } #endif if (!strcasecmp(cmdname, "shutdown.stop")) { do_command(SET, TSU_SHUTDOWN_ACTION, "0", NULL); return STAT_INSTCMD_HANDLED; } if (!strcasecmp(cmdname, "test.battery.start")) { do_command(SET, TEST, "3", NULL); return STAT_INSTCMD_HANDLED; } if (!strcasecmp(cmdname, "test.battery.stop")) { do_command(SET, TEST, "0", NULL); return STAT_INSTCMD_HANDLED; } upslogx(LOG_NOTICE, "instcmd: unknown command [%s] [%s]", cmdname, extra); return STAT_INSTCMD_UNKNOWN; } static int setvar(const char *varname, const char *val) { if (!strcasecmp(varname, "ups.id")) { set_identification(val); get_identification(); return STAT_SET_HANDLED; } if (!strcasecmp(varname, "input.transfer.low")) { set_transfer_voltage_low(atoi(val)); get_transfer_voltage_low(); return STAT_SET_HANDLED; } if (!strcasecmp(varname, "input.transfer.high")) { set_transfer_voltage_high(atoi(val)); get_transfer_voltage_high(); return STAT_SET_HANDLED; } if (!strcasecmp(varname, "input.sensitivity")) { set_sensitivity(val); get_sensitivity(); return STAT_SET_HANDLED; } upslogx(LOG_NOTICE, "setvar: unknown var [%s]", varname); return STAT_SET_UNKNOWN; } static int init_comm(void) { size_t i, bit; char response[MAX_RESPONSE_LENGTH]; ups.commands_available = 0; /* Repeat enumerate command 2x, firmware bug on some units garbles 1st response */ if (do_command(POLL, AVAILABLE, "", response) <= 0){ upslogx(LOG_NOTICE, "init_comm: Initial response malformed, retrying in 300ms"); usleep(3E5); } if (do_command(POLL, AVAILABLE, "", response) <= 0) return 0; i = strlen(response); for (bit = 0; bit < i; bit++) if (response[i - bit - 1] == '1') ups.commands_available |= (1UL << bit); if (do_command(POLL, MANUFACTURER, "", response) <= 0) return 0; if (strcmp(response, "Tripp Lite")) return 0; return 1; } void upsdrv_initinfo(void) { char response[MAX_RESPONSE_LENGTH]; unsigned int min_low_transfer, max_low_transfer; unsigned int min_high_transfer, max_high_transfer; unsigned int i; char *ptr; if (!init_comm()) fatalx(EXIT_FAILURE, "Unable to detect Tripp Lite SmartOnline UPS on port %s\n", device_path); min_low_transfer = max_low_transfer = 0; min_high_transfer = max_high_transfer = 0; /* get all the read-only fields here */ if (do_command(POLL, MANUFACTURER, "", response) > 0) dstate_setinfo("ups.mfr", "%s", response); if (do_command(POLL, MODEL, "", response) > 0) dstate_setinfo("ups.model", "%s", response); if (do_command(POLL, VERSION_CMD, "", response) > 0) dstate_setinfo("ups.firmware", "%s", response); if (do_command(POLL, RATINGS, "", response) > 0) { ptr = field(response, 0); if (ptr) dstate_setinfo("input.voltage.nominal", "%d", atoi(ptr)); ptr = field(response, 2); if (ptr) { dstate_setinfo("output.voltage.nominal", "%d", atoi(ptr)); } ptr = field(response, 14); if (ptr) dstate_setinfo("battery.voltage.nominal", "%d", atoi(ptr)); ptr = field(response, 10); if (ptr) { int ipv = atoi(ptr); if (ipv >= 0) min_low_transfer = (unsigned int)ipv; } ptr = field(response, 9); if (ptr) { int ipv = atoi(ptr); if (ipv >= 0) max_low_transfer = (unsigned int)ipv; } ptr = field(response, 12); if (ptr) { int ipv = atoi(ptr); if (ipv >= 0) min_high_transfer = (unsigned int)ipv; } ptr = field(response, 11); if (ptr) { int ipv = atoi(ptr); if (ipv >= 0) max_high_transfer = (unsigned int)ipv; } } if (do_command(POLL, OUTLET_RELAYS, "", response) > 0) ups.outlet_banks = atoi(response); /* define things that are settable */ if (get_identification()) { dstate_setflags("ups.id", ST_FLAG_RW | ST_FLAG_STRING); dstate_setaux("ups.id", 100); } if (get_transfer_voltage_low() && max_low_transfer) { dstate_setflags("input.transfer.low", ST_FLAG_RW); for (i = min_low_transfer; i <= max_low_transfer; i++) dstate_addenum("input.transfer.low", "%d", i); } if (get_transfer_voltage_high() && max_low_transfer) { dstate_setflags("input.transfer.high", ST_FLAG_RW); for (i = min_high_transfer; i <= max_high_transfer; i++) dstate_addenum("input.transfer.high", "%d", i); } if (get_sensitivity()) { dstate_setflags("input.sensitivity", ST_FLAG_RW); for (i = 0; i < SIZEOF_ARRAY(sensitivity); i++) dstate_addenum("input.sensitivity", "%s", sensitivity[i].name); } if (ups.outlet_banks) { dstate_addcmd("load.off"); dstate_addcmd("load.on"); } dstate_addcmd("shutdown.reboot"); dstate_addcmd("shutdown.reboot.graceful"); dstate_addcmd("shutdown.return"); #if 0 /* doesn't work */ dstate_addcmd("shutdown.stayoff"); #endif dstate_addcmd("shutdown.stop"); dstate_addcmd("test.battery.start"); dstate_addcmd("test.battery.stop"); /* add all the variables that change regularly */ upsdrv_updateinfo(); upsh.instcmd = instcmd; upsh.setvar = setvar; printf("Detected %s %s on %s\n", dstate_getinfo("ups.mfr"), dstate_getinfo("ups.model"), device_path); } void upsdrv_updateinfo(void) { char response[MAX_RESPONSE_LENGTH]; char *ptr, *ptr2; int i; int flags; int contacts_set; int low_battery; status_init(); if (do_command(POLL, STATUS_OUTPUT, "", response) <= 0) { dstate_datastale(); return; } ptr = field(response, 0); /* require output status field to exist */ if (!ptr) { dstate_datastale(); return; } switch (atoi(ptr)) { case 0: status_set("OL"); break; case 1: status_set("OB"); break; case 2: status_set("BYPASS"); break; case 3: status_set("OL"); status_set("TRIM"); break; case 4: status_set("OL"); status_set("BOOST"); break; case 5: status_set("BYPASS"); break; case 6: break; case 7: status_set("OFF"); break; default: break; } ptr = field(response, 6); if (ptr) dstate_setinfo("ups.load", "%d", atoi(ptr)); ptr = field(response, 3); if (ptr) dstate_setinfo("output.voltage", "%03.1f", (double) (atoi(ptr)) / 10.0); ptr = field(response, 1); if (ptr) dstate_setinfo("output.frequency", "%03.1f", (double) (atoi(ptr)) / 10.0); ptr = field(response, 4); if (ptr) dstate_setinfo("output.current", "%03.1f", (double) (atoi(ptr)) / 10.0); low_battery = 0; if (do_command(POLL, STATUS_BATTERY, "", response) <= 0) { dstate_datastale(); return; } ptr = field(response, 0); if (ptr && atoi(ptr) == 2) status_set("RB"); ptr = field(response, 1); if (ptr && atoi(ptr)) low_battery = 1; ptr = field(response, 8); if (ptr) dstate_setinfo("battery.temperature", "%d", atoi(ptr)); ptr = field(response, 9); if (ptr) { dstate_setinfo("battery.charge", "%d", atoi(ptr)); ptr2 = getval("lowbatt"); if (ptr2 && atoi(ptr2) > 0 && atoi(ptr2) <= 99 && atoi(ptr) <= atoi(ptr2)) low_battery = 1; } ptr = field(response, 6); if (ptr) dstate_setinfo("battery.voltage", "%03.1f", (double) (atoi(ptr)) / 10.0); ptr = field(response, 7); if (ptr) dstate_setinfo("battery.current", "%03.1f", (double) (atoi(ptr)) / 10.0); if (low_battery) status_set("LB"); if (do_command(POLL, STATUS_ALARM, "", response) <= 0) { dstate_datastale(); return; } ptr = field(response, 3); if (ptr && atoi(ptr)) status_set("OVER"); if (do_command(POLL, STATUS_INPUT, "", response) > 0) { ptr = field(response, 2); if (ptr) dstate_setinfo("input.voltage", "%03.1f", (double) (atoi(ptr)) / 10.0); ptr = field(response, 1); if (ptr) dstate_setinfo("input.frequency", "%03.1f", (double) (atoi(ptr)) / 10.0); } if (do_command(POLL, TEST_RESULT, "", response) > 0) { int r; size_t trsize; r = atoi(response); trsize = SIZEOF_ARRAY(test_result_names); if ((r < 0) || (r >= (int) trsize)) r = 0; dstate_setinfo("ups.test.result", "%s", test_result_names[r]); } if (do_command(POLL, ENVIRONMENT_INFORMATION, "", response) > 0) { ptr = field(response, 0); if (ptr) dstate_setinfo("ambient.temperature", "%d", atoi(ptr)); ptr = field(response, 1); if (ptr) dstate_setinfo("ambient.humidity", "%d", atoi(ptr)); flags = 0; contacts_set = 0; for (i = 0; i < 4; i++) { ptr = field(response, 2 + i); if (ptr) { contacts_set = 1; if (*ptr == '1') flags |= 1 << i; } } if (contacts_set) dstate_setinfo("ups.contacts", "%02X", flags); } /* if we are here, status is valid */ status_commit(); dstate_dataok(); } void upsdrv_shutdown(void) { char parm[20]; if (!init_comm()) printf("Status failed. Assuming it's on battery and trying a shutdown anyway.\n"); auto_reboot(1); /* in case the power is on, tell it to automatically reboot. if it is off, this has no effect. */ snprintf(parm, sizeof(parm), "%d", 1); /* delay before reboot, in minutes */ do_command(SET, TSU_SHUTDOWN_RESTART, parm, NULL); snprintf(parm, sizeof(parm), "%d", 5); /* delay before shutdown, in seconds */ do_command(SET, TSU_SHUTDOWN_ACTION, parm, NULL); } void upsdrv_help(void) { } /* list flags and values that you want to receive via -x or ups.conf */ void upsdrv_makevartable(void) { addvar(VAR_VALUE, "lowbatt", "Set low battery level, in percent"); } void upsdrv_initups(void) { upsfd = ser_open(device_path); ser_set_speed(upsfd, device_path, B2400); } void upsdrv_cleanup(void) { ser_close(upsfd, device_path); } nut-2.8.1/drivers/bcmxcp_ser.c0000644000175000017500000002750714502253356013240 00000000000000#include "main.h" #include "bcmxcp.h" #include "bcmxcp_io.h" #include "bcmxcp_ser.h" #include "serial.h" #include "nut_stdint.h" #define SUBDRIVER_NAME "RS-232 communication subdriver" #define SUBDRIVER_VERSION "0.22" /* communication driver description structure */ upsdrv_info_t comm_upsdrv_info = { SUBDRIVER_NAME, SUBDRIVER_VERSION, NULL, 0, { NULL } }; #define PW_MAX_BAUD 5 /* NOT static: also used from nut-scanner, so extern'ed via bcmxcp_ser.h */ pw_baud_rate_t pw_baud_rates[] = { { B19200, 19200 }, { B9600, 9600 }, { B4800, 4800 }, { B2400, 2400 }, { B1200, 1200 }, /* end of structure. */ { 0, 0 } }; /* NOT static: also used from nut-scanner, so extern'ed via bcmxcp_ser.h */ unsigned char BCMXCP_AUTHCMD[4] = {0xCF, 0x69, 0xE8, 0xD5}; /* Authorisation command */ static void send_command(unsigned char *command, size_t command_length) { int retry = 0; ssize_t sent; unsigned char sbuf[1024]; if (command_length > UCHAR_MAX) { upsdebugx (3, "%s: ERROR: command_length too long for the character protocol", __func__); return; } /* Prepare the send buffer */ sbuf[0] = PW_COMMAND_START_BYTE; sbuf[1] = (unsigned char)(command_length); memcpy(sbuf+2, command, command_length); command_length += 2; /* Add checksum */ sbuf[command_length] = calc_checksum(sbuf); command_length += 1; upsdebug_hex (3, "send_command", sbuf, command_length); while (retry++ < PW_MAX_TRY) { if (retry == PW_MAX_TRY) { ser_send_char(upsfd, 0x1d); /* last retry is preceded by a ESC.*/ usleep(250000); } sent = ser_send_buf(upsfd, sbuf, command_length); if (sent < 0) { upslogx(LOG_ERR, "%s(): error reading from ser_send_buf()", __func__); return; } if ((size_t)sent == command_length) { return; } } } void send_read_command(unsigned char command) { send_command(&command, 1); } void send_write_command(unsigned char *command, size_t command_length) { send_command(command, command_length); } /* get the answer of a command from the ups. And check that the answer is for this command */ ssize_t get_answer(unsigned char *data, unsigned char command) { unsigned char my_buf[128]; /* packet has a maximum length of 121+5 bytes */ ssize_t res; size_t length, end_length = 0, endblock = 0, start = 0; unsigned char block_number, sequence, pre_sequence = 0; while (endblock != 1) { do { /* Read PW_COMMAND_START_BYTE byte */ res = ser_get_char(upsfd, my_buf, 1, 0); if (res != 1) { upsdebugx(1, "Receive error (PW_COMMAND_START_BYTE): %" PRIiSIZE ", cmd=%x!!!\n", res, command); return -1; } start++; } while ((my_buf[0] != PW_COMMAND_START_BYTE) && (start < 128)); if (start == 128) { ser_comm_fail("Receive error (PW_COMMAND_START_BYTE): packet not on start!!%x\n", my_buf[0]); return -1; } /* Read block number byte */ res = ser_get_char(upsfd, my_buf + 1, 1, 0); if (res != 1) { ser_comm_fail("Receive error (Block number): %" PRIiSIZE "!!!\n", res); return -1; } block_number = (unsigned char)my_buf[1]; if (command <= 0x43) { if ((command - 0x30) != block_number) { ser_comm_fail("Receive error (Request command): %x!!!\n", block_number); return -1; } } if (command >= 0x89) { if ((command == 0xA0) && (block_number != 0x01)) { ser_comm_fail("Receive error (Requested only mode command): %x!!!\n", block_number); return -1; } if ((command != 0xA0) && (block_number != 0x09)) { ser_comm_fail("Receive error (Control command): %x!!!\n", block_number); return -1; } } /* Read data length byte */ res = ser_get_char(upsfd, my_buf + 2, 1, 0); if (res != 1) { ser_comm_fail("Receive error (length): %" PRIiSIZE "!!!\n", res); return -1; } length = (unsigned char)my_buf[2]; if (length < 1) { ser_comm_fail("Receive error (length): packet length %" PRIxSIZE "!!!\n", length); return -1; } /* Read sequence byte */ res = ser_get_char(upsfd, my_buf + 3, 1, 0); if (res != 1) { ser_comm_fail("Receive error (sequence): %" PRIiSIZE "!!!\n", res); return -1; } sequence = (unsigned char)my_buf[3]; if ((sequence & 0x80) == 0x80) { endblock = 1; } if ((sequence & 0x07) != (pre_sequence + 1)) { ser_comm_fail("Not the right sequence received %x!!!\n", sequence); return -1; } pre_sequence = sequence; /* Try to read all the remaining bytes */ res = ser_get_buf_len(upsfd, my_buf + 4, length, 1, 0); if (res < 0) { ser_comm_fail("%s(): ser_get_buf_len() returned error code %" PRIiSIZE, __func__, res); return res; } if ((size_t)res != length) { ser_comm_fail("Receive error (data): got %" PRIiSIZE " bytes instead of %" PRIuSIZE "!!!\n", res, length); return -1; } /* Get the checksum byte */ res = ser_get_char(upsfd, my_buf + (4 + length), 1, 0); if (res != 1) { ser_comm_fail("Receive error (checksum): %" PRIxSIZE "!!!\n", res); return -1; } /* now we have the whole answer from the ups, we can checksum it */ if (!checksum_test(my_buf)) { ser_comm_fail("checksum error! "); return -1; } memcpy(data+end_length, my_buf + 4, length); end_length += length; } upsdebug_hex (5, "get_answer", data, end_length); ser_comm_good(); assert(end_length < SSIZE_MAX); return (ssize_t)end_length; } static ssize_t command_sequence(unsigned char *command, size_t command_length, unsigned char *answer) { ssize_t bytes_read; int retry = 0; while (retry++ < PW_MAX_TRY) { if (retry == PW_MAX_TRY) { ser_flush_in(upsfd, "", 0); } send_write_command(command, command_length); bytes_read = get_answer(answer, *command); if (bytes_read > 0) { return bytes_read; } } return -1; } /* Sends a single command (length=1). and get the answer */ ssize_t command_read_sequence(unsigned char command, unsigned char *answer) { ssize_t bytes_read; bytes_read = command_sequence(&command, 1, answer); if (bytes_read < 1) { ser_comm_fail("Error executing command"); } return bytes_read; } /* Sends a setup command (length > 1) */ ssize_t command_write_sequence(unsigned char *command, size_t command_length, unsigned char *answer) { ssize_t bytes_read; bytes_read = command_sequence(command, command_length, answer); if (bytes_read < 1) { ser_comm_fail("Error executing command"); } return bytes_read; } void upsdrv_comm_good(void) { ser_comm_good(); } #if (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_PUSH_POP_BESIDEFUNC) && (!defined HAVE_PRAGMA_GCC_DIAGNOSTIC_PUSH_POP_INSIDEFUNC) && ( (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_TYPE_LIMITS_BESIDEFUNC) || (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_TAUTOLOGICAL_CONSTANT_OUT_OF_RANGE_COMPARE_BESIDEFUNC) ) # pragma GCC diagnostic push #endif #if (!defined HAVE_PRAGMA_GCC_DIAGNOSTIC_PUSH_POP_INSIDEFUNC) && (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_TYPE_LIMITS_BESIDEFUNC) # pragma GCC diagnostic ignored "-Wtype-limits" #endif #if (!defined HAVE_PRAGMA_GCC_DIAGNOSTIC_PUSH_POP_INSIDEFUNC) && (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_TAUTOLOGICAL_CONSTANT_OUT_OF_RANGE_COMPARE_BESIDEFUNC) # pragma GCC diagnostic ignored "-Wtautological-constant-out-of-range-compare" #endif static void pw_comm_setup(const char *port) { unsigned char command = PW_SET_REQ_ONLY_MODE; unsigned char id_command = PW_ID_BLOCK_REQ; unsigned char answer[256]; int i = 0; ssize_t ret = -1; speed_t mybaud = 0, baud; if (getval("baud_rate") != NULL) { int br = atoi(getval("baud_rate")); /* Note that atoi() behavior on erroneous input is undefined */ if (br < 0) { upslogx(LOG_ERR, "baud_rate option is invalid"); return; } /* FIXME: speed_t does not define a SPEED_MAX value nor * guarantee that it is an int (just a typedef from * termios.h happens to say that on some systems)... * But since we convert this setting from int, we assume... */ #if (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_PUSH_POP) && ( (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_TYPE_LIMITS) || (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_TAUTOLOGICAL_CONSTANT_OUT_OF_RANGE_COMPARE) || (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_UNREACHABLE_CODE) ) /* Note for gating macros above: unsuffixed HAVE_PRAGMA_GCC_DIAGNOSTIC_PUSH_POP * means support of contexts both inside and outside function body, so the push * above and pop below (outside this finction) are not used. */ # pragma GCC diagnostic push #endif #ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_TYPE_LIMITS /* Note that the individual warning pragmas for use inside function bodies * are named without a _INSIDEFUNC suffix, for simplicity and legacy reasons */ # pragma GCC diagnostic ignored "-Wtype-limits" #endif #ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_UNREACHABLE_CODE #pragma GCC diagnostic ignored "-Wunreachable-code" #endif #ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_TAUTOLOGICAL_CONSTANT_OUT_OF_RANGE_COMPARE # pragma GCC diagnostic ignored "-Wtautological-constant-out-of-range-compare" #endif /* Older CLANG (e.g. clang-3.4) seems to not support the GCC pragmas above */ #ifdef __clang__ #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wunreachable-code" #pragma clang diagnostic ignored "-Wtautological-compare" #pragma clang diagnostic ignored "-Wtautological-constant-out-of-range-compare" #endif switch(sizeof(speed_t)) { case 8: assert (br < INT64_MAX); break; case 4: assert (br < INT32_MAX); break; case 2: assert (br < INT16_MAX); break; default: assert (br < INT_MAX); } #ifdef __clang__ #pragma clang diagnostic pop #endif #if (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_PUSH_POP) && ( (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_TYPE_LIMITS) || (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_TAUTOLOGICAL_CONSTANT_OUT_OF_RANGE_COMPARE) || (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_UNREACHABLE_CODE) ) # pragma GCC diagnostic pop #endif baud = (speed_t)br; for (i = 0; i < PW_MAX_BAUD; i++) { if (baud == pw_baud_rates[i].name) { mybaud = pw_baud_rates[i].rate; break; } } if (mybaud == 0) { fatalx(EXIT_FAILURE, "Specified baudrate \"%s\" is invalid!", getval("baud_rate")); } ser_set_speed(upsfd, device_path, mybaud); ser_send_char(upsfd, 0x1d); /* send ESC to take it out of menu */ usleep(90000); send_write_command(BCMXCP_AUTHCMD, 4); usleep(500000); ret = command_sequence(&command, 1, answer); if (ret <= 0) { usleep(500000); ret = command_sequence(&id_command, 1, answer); } if (ret > 0) { /* Cast baud into max length unsigned, despite the POSIX * standard some systems vary in definition of this type */ upslogx(LOG_INFO, "Connected to UPS on %s with baudrate %llu", port, (unsigned long long int)baud); return; } upslogx(LOG_ERR, "No response from UPS on %s with baudrate %llu", port, (unsigned long long int)baud); } upslogx(LOG_INFO, "Attempting to autodect baudrate"); for (i=0; i 0) { upslogx(LOG_INFO, "Connected to UPS on %s with baudrate %" PRIuSIZE, port, pw_baud_rates[i].name); return; } upsdebugx(2, "No response from UPS on %s with baudrate %" PRIuSIZE, port, pw_baud_rates[i].name); } fatalx(EXIT_FAILURE, "Can't connect to the UPS on port %s!\n", port); } #if (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_PUSH_POP_BESIDEFUNC) && (!defined HAVE_PRAGMA_GCC_DIAGNOSTIC_PUSH_POP_INSIDEFUNC) && ( (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_TYPE_LIMITS_BESIDEFUNC) || (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_TAUTOLOGICAL_CONSTANT_OUT_OF_RANGE_COMPARE_BESIDEFUNC) ) # pragma GCC diagnostic pop #endif void upsdrv_initups(void) { upsfd = ser_open(device_path); pw_comm_setup(device_path); } void upsdrv_cleanup(void) { /* free(dynamic_mem); */ ser_close(upsfd, device_path); } void upsdrv_reconnect(void) { } nut-2.8.1/drivers/blazer.c0000644000175000017500000005377514501607135012375 00000000000000/* * blazer.c: driver core for Megatec/Q1 protocol based UPSes * * OBSOLETION WARNING: Please to not base new development on this * codebase, instead create a new subdriver for nutdrv_qx which * generally covers all Megatec/Qx protocol family and aggregates * device support from such legacy drivers over time. * * A document describing the protocol implemented by this driver can be * found online at https://www.networkupstools.org/ups-protocols/megatec.html * * Copyright (C) * 2008,2009 - Arjen de Korte * 2012 - Arnaud Quette * * 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 2 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, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "main.h" #include "blazer.h" #include "nut_float.h" static long ondelay = 3; /* minutes */ static long offdelay = 30; /* seconds */ static int proto; static int online = 1; static struct { double packs; /* battery voltage multiplier */ struct { double nom; /* nominal runtime on battery (full load) */ double est; /* estimated runtime remaining (full load) */ double exp; /* load exponent */ } runt; struct { double act; /* actual battery voltage */ double high; /* battery float voltage */ double nom; /* nominal battery voltage */ double low; /* battery low voltage */ } volt; struct { double act; /* actual battery charge */ long time; /* recharge time from empty to full */ } chrg; } batt = { 1, { -1, 0, 0 }, { -1, -1, -1, -1 }, { -1, 43200 } }; static struct { double act; /* actual load (reported by UPS) */ double low; /* idle load */ double eff; /* effective load */ } load = { 0, 0.1, 1 }; static time_t lastpoll = 0; /* * This little structure defines the various flavors of the Megatec protocol. * Only the .name and .status are mandatory, .rating and .vendor elements are * optional. If only some models support the last two, fill them in anyway * and tell people to use the 'norating' and 'novendor' options to bypass * getting them. */ static const struct { const char *name; const char *status; const char *rating; const char *vendor; } command[] = { { "megatec", "Q1\r", "F\r", "I\r" }, { "mustek", "QS\r", "F\r", "I\r" }, { "megatec/old", "D\r", "F\r", "I\r" }, { "zinto", "Q1\r", "F\r", "FW?\r" }, { NULL, NULL, NULL, NULL } }; /* * Do whatever we think is needed when we read a battery voltage from the UPS. * Basically all it does now, is guesstimating the battery charge, but this * could be extended. */ static double blazer_battery(const char *ptr, char **endptr) { batt.volt.act = batt.packs * strtod(ptr, endptr); if ((!getval("runtimecal") || !dstate_getinfo("battery.charge")) && (batt.volt.low > 0) && (batt.volt.high > batt.volt.low)) { batt.chrg.act = 100 * (batt.volt.act - batt.volt.low) / (batt.volt.high - batt.volt.low); if (batt.chrg.act < 0) { batt.chrg.act = 0; } if (batt.chrg.act > 100) { batt.chrg.act = 100; } dstate_setinfo("battery.charge", "%.0f", batt.chrg.act); } return batt.volt.act; } /* * Do whatever we think is needed when we read the load from the UPS. */ static double blazer_load(const char *ptr, char **endptr) { load.act = strtod(ptr, endptr); load.eff = pow(load.act / 100, batt.runt.exp); if (load.eff < load.low) { load.eff = load.low; } return load.act; } /* * The battery voltage will quickly return to at least the nominal value after * discharging them. For overlapping battery.voltage.low/high ranges therefore * choose the one with the highest multiplier. */ static double blazer_packs(const char *ptr, char **endptr) { const double packs[] = { 120, 100, 80, 60, 48, 36, 30, 24, 18, 12, 8, 6, 4, 3, 2, 1, 0.5, -1 }; const char *val; int i; val = dstate_getinfo("battery.voltage.nominal"); batt.volt.nom = strtod(val ? val : ptr, endptr); for (i = 0; packs[i] > 0; i++) { if (packs[i] * batt.volt.act > 1.25 * batt.volt.nom) { continue; } if (packs[i] * batt.volt.act < 0.8 * batt.volt.nom) { upslogx(LOG_INFO, "Can't autodetect number of battery packs [%.0f/%.2f]", batt.volt.nom, batt.volt.act); break; } batt.packs = packs[i]; break; } return batt.volt.nom; } static int blazer_status(const char *cmd) { const struct { const char *var; const char *fmt; double (*conv)(const char *, char **); } status[] = { { "input.voltage", "%.1f", strtod }, { "input.voltage.fault", "%.1f", strtod }, { "output.voltage", "%.1f", strtod }, { "ups.load", "%.0f", blazer_load }, { "input.frequency", "%.1f", strtod }, { "battery.voltage", "%.2f", blazer_battery }, { "ups.temperature", "%.1f", strtod }, { NULL, NULL, NULL } }; char buf[SMALLBUF], *val, *last = NULL; int i; /* * > [Q1\r] * < [(226.0 195.0 226.0 014 49.0 27.5 30.0 00001000\r] * 01234567890123456789012345678901234567890123456 * 0 1 2 3 4 */ if (blazer_command(cmd, buf, sizeof(buf)) < 46) { upsdebugx(2, "%s: short reply", __func__); return -1; } if (buf[0] != '(') { upsdebugx(2, "%s: invalid start character [%02x]", __func__, buf[0]); return -1; } for (i = 0, val = strtok_r(buf+1, " ", &last); status[i].var; i++, val = strtok_r(NULL, " \r\n", &last)) { if (!val) { upsdebugx(2, "%s: parsing failed", __func__); return -1; } if (strspn(val, "0123456789.") != strlen(val)) { upsdebugx(2, "%s: non numerical value [%s]", __func__, val); continue; } #ifdef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL #pragma GCC diagnostic push #endif #ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL #pragma GCC diagnostic ignored "-Wformat-nonliteral" #endif #ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_FORMAT_SECURITY #pragma GCC diagnostic ignored "-Wformat-security" #endif dstate_setinfo(status[i].var, status[i].fmt, status[i].conv(val, NULL)); #ifdef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL #pragma GCC diagnostic pop #endif } if (!val) { upsdebugx(2, "%s: parsing failed", __func__); return -1; } if (strspn(val, "01") != 8) { upsdebugx(2, "Invalid status [%s]", val); return -1; } if (val[7] == '1') { /* Beeper On */ dstate_setinfo("ups.beeper.status", "enabled"); } else { dstate_setinfo("ups.beeper.status", "disabled"); } if (val[4] == '1') { /* UPS Type is Standby (0 is On_line) */ dstate_setinfo("ups.type", "offline / line interactive"); } else { dstate_setinfo("ups.type", "online"); } status_init(); if (val[0] == '1') { /* Utility Fail (Immediate) */ status_set("OB"); online = 0; } else { status_set("OL"); online = 1; } if (val[1] == '1') { /* Battery Low */ status_set("LB"); } if (val[2] == '1') { /* Bypass/Boost or Buck Active */ double vi, vo; vi = strtod(dstate_getinfo("input.voltage"), NULL); vo = strtod(dstate_getinfo("output.voltage"), NULL); if (vo < 0.5 * vi) { upsdebugx(2, "%s: output voltage too low", __func__); } else if (vo < 0.95 * vi) { status_set("TRIM"); } else if (vo < 1.05 * vi) { status_set("BYPASS"); } else if (vo < 1.5 * vi) { status_set("BOOST"); } else { upsdebugx(2, "%s: output voltage too high", __func__); } } if (val[5] == '1') { /* Test in Progress */ status_set("CAL"); } alarm_init(); if (val[3] == '1') { /* UPS Failed */ alarm_set("UPS selftest failed!"); } if (val[6] == '1') { /* Shutdown Active */ alarm_set("Shutdown imminent!"); status_set("FSD"); } alarm_commit(); status_commit(); return 0; } static int blazer_rating(const char *cmd) { const struct { const char *var; const char *fmt; double (*conv)(const char *, char **); } rating[] = { { "input.voltage.nominal", "%.0f", strtod }, { "input.current.nominal", "%.1f", strtod }, { "battery.voltage.nominal", "%.1f", blazer_packs }, { "input.frequency.nominal", "%.0f", strtod }, { NULL, NULL, NULL } }; char buf[SMALLBUF], *val, *last = NULL; int i; /* * > [F\r] * < [#220.0 000 024.0 50.0\r] * 0123456789012345678901 * 0 1 2 */ if (blazer_command(cmd, buf, sizeof(buf)) < 22) { upsdebugx(2, "%s: short reply", __func__); return -1; } if (buf[0] != '#') { upsdebugx(2, "%s: invalid start character [%02x]", __func__, buf[0]); return -1; } for (i = 0, val = strtok_r(buf+1, " ", &last); rating[i].var; i++, val = strtok_r(NULL, " \r\n", &last)) { if (!val) { upsdebugx(2, "%s: parsing failed", __func__); return -1; } if (strspn(val, "0123456789.") != strlen(val)) { upsdebugx(2, "%s: non numerical value [%s]", __func__, val); continue; } #ifdef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL #pragma GCC diagnostic push #endif #ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL #pragma GCC diagnostic ignored "-Wformat-nonliteral" #endif #ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_FORMAT_SECURITY #pragma GCC diagnostic ignored "-Wformat-security" #endif dstate_setinfo(rating[i].var, rating[i].fmt, rating[i].conv(val, NULL)); #ifdef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL #pragma GCC diagnostic pop #endif } return 0; } static int blazer_vendor(const char *cmd) { const struct { const char *var; const int len; } information[] = { { "ups.mfr", 15 }, { "ups.model", 10 }, { "ups.firmware", 10 }, { NULL, 0 } }; char buf[SMALLBUF]; int i, index; /* * > [I\r] * < [#------------- ------ VT12046Q \r] * 012345678901234567890123456789012345678 * 0 1 2 3 */ if (blazer_command(cmd, buf, sizeof(buf)) < 39) { upsdebugx(2, "%s: short reply", __func__); return -1; } if (buf[0] != '#') { upsdebugx(2, "%s: invalid start character [%02x]", __func__, buf[0]); return -1; } for (i = 0, index = 1; information[i].var; index += information[i++].len+1) { char val[SMALLBUF]; snprintf(val, sizeof(val), "%.*s", information[i].len, &buf[index]); dstate_setinfo(information[i].var, "%s", str_rtrim(val, ' ')); } return 0; } static int blazer_instcmd(const char *cmdname, const char *extra) { const struct { const char *cmd; const char *ups; } instcmd[] = { { "beeper.toggle", "Q\r" }, { "load.off", "S00R0000\r" }, { "load.on", "C\r" }, { "shutdown.stop", "C\r" }, { "test.battery.start.deep", "TL\r" }, { "test.battery.start.quick", "T\r" }, { "test.battery.stop", "CT\r" }, { NULL, NULL } }; char buf[SMALLBUF] = ""; int i; upslogx(LOG_INFO, "instcmd(%s, %s)", cmdname, extra ? extra : "[NULL]"); for (i = 0; instcmd[i].cmd; i++) { if (strcasecmp(cmdname, instcmd[i].cmd)) { continue; } snprintf(buf, sizeof(buf), "%s", instcmd[i].ups); /* * If a command is invalid, it will be echoed back * As an exception, Best UPS units will report "ACK" in case of success! * Other UPSes will reply "(ACK" in case of success. */ if (blazer_command(buf, buf, sizeof(buf)) > 0) { if (strncmp(buf, "ACK", 3) && strncmp(buf, "(ACK", 4)) { upslogx(LOG_ERR, "instcmd: command [%s] failed", cmdname); return STAT_INSTCMD_FAILED; } } upslogx(LOG_INFO, "instcmd: command [%s] handled", cmdname); return STAT_INSTCMD_HANDLED; } if (!strcasecmp(cmdname, "shutdown.return")) { /* * Sn: Shutdown after n minutes and then turn on when mains is back * SnRm: Shutdown after n minutes and then turn on after m minutes * Accepted values for n: .2 -> .9 , 01 -> 10 * Accepted values for m: 0001 -> 9999 * Note: "S01R0001" and "S01R0002" may not work on early (GE) * firmware versions. The failure mode is that the UPS turns * off and never returns. The fix is to push the return value * up by 2, i.e. S01R0003, and it will return online properly. * (thus the default of ondelay=3 mins) */ if (ondelay == 0) { if (offdelay < 60) { snprintf(buf, sizeof(buf), "S.%ld\r", offdelay / 6); } else { snprintf(buf, sizeof(buf), "S%02ld\r", offdelay / 60); } } else if (offdelay < 60) { snprintf(buf, sizeof(buf), "S.%ldR%04ld\r", offdelay / 6, ondelay); } else { snprintf(buf, sizeof(buf), "S%02ldR%04ld\r", offdelay / 60, ondelay); } } else if (!strcasecmp(cmdname, "shutdown.stayoff")) { /* * SnR0000 * Shutdown after n minutes and stay off * Accepted values for n: .2 -> .9 , 01 -> 10 */ if (offdelay < 60) { snprintf(buf, sizeof(buf), "S.%ldR0000\r", offdelay / 6); } else { snprintf(buf, sizeof(buf), "S%02ldR0000\r", offdelay / 60); } } else if (!strcasecmp(cmdname, "test.battery.start")) { long delay = extra ? strtol(extra, NULL, 10) : 10; if ((delay < 1) || (delay > 99)) { upslogx(LOG_ERR, "instcmd: command [%s] failed, delay [%s] out of range", cmdname, extra); return STAT_INSTCMD_FAILED; } snprintf(buf, sizeof(buf), "T%02ld\r", delay); } else { upslogx(LOG_ERR, "instcmd: command [%s] not found", cmdname); return STAT_INSTCMD_UNKNOWN; } /* * If a command is invalid, it will be echoed back. * As an exception, Best UPS units will report "ACK" in case of success! * Other UPSes will reply "(ACK" in case of success. */ if (blazer_command(buf, buf, sizeof(buf)) > 0) { if (strncmp(buf, "ACK", 3) && strncmp(buf, "(ACK", 4)) { upslogx(LOG_ERR, "instcmd: command [%s] failed", cmdname); return STAT_INSTCMD_FAILED; } } upslogx(LOG_INFO, "instcmd: command [%s] handled", cmdname); return STAT_INSTCMD_HANDLED; } void blazer_makevartable(void) { addvar(VAR_VALUE, "ondelay", "Delay before UPS startup (minutes)"); addvar(VAR_VALUE, "offdelay", "Delay before UPS shutdown (seconds)"); addvar(VAR_VALUE, "runtimecal", "Parameters used for runtime calculation"); addvar(VAR_VALUE, "chargetime", "Nominal charge time for UPS battery"); addvar(VAR_VALUE, "idleload", "Minimum load to be used for runtime calculation"); addvar(VAR_FLAG, "norating", "Skip reading rating information from UPS"); addvar(VAR_FLAG, "novendor", "Skip reading vendor information from UPS"); addvar(VAR_FLAG, "protocol", "Preselect communication protocol (skip autodetection)"); } void blazer_initups(void) { const char *val; val = getval("ondelay"); if (val) { ondelay = strtol(val, NULL, 10); } if ((ondelay < 0) || (ondelay > 9999)) { fatalx(EXIT_FAILURE, "Start delay '%ld' out of range [0..9999]", ondelay); } val = getval("offdelay"); if (val) { offdelay = strtol(val, NULL, 10); } if ((offdelay < 12) || (offdelay > 600)) { fatalx(EXIT_FAILURE, "Shutdown delay '%ld' out of range [12..600]", offdelay); } /* Truncate to nearest setable value */ if (offdelay < 60) { offdelay -= (offdelay % 6); } else { offdelay -= (offdelay % 60); } val = dstate_getinfo("battery.voltage.high"); if (val) { batt.volt.high = strtod(val, NULL); } val = dstate_getinfo("battery.voltage.low"); if (val) { batt.volt.low = strtod(val, NULL); } } static void blazer_initbattery(void) { const char *val; /* If no values were provided by the user in ups.conf, try to guesstimate * battery.charge, but announce it! */ if ( (!d_equal(batt.volt.nom, 1)) && ((d_equal(batt.volt.high, -1)) || (d_equal(batt.volt.low, -1)))) { upslogx(LOG_INFO, "No values provided for battery high/low voltages in ups.conf\n"); /* Basic formula, which should cover most cases */ batt.volt.low = 104 * batt.volt.nom / 120; batt.volt.high = 130 * batt.volt.nom / 120; /* Publish these data too */ dstate_setinfo("battery.voltage.low", "%.2f", batt.volt.low); dstate_setinfo("battery.voltage.high", "%.2f", batt.volt.high); upslogx(LOG_INFO, "Using 'guesstimation' (low: %f, high: %f)!", batt.volt.low, batt.volt.high); } val = getval("runtimecal"); if (val) { double rh, lh, rl, ll; time(&lastpoll); if (sscanf(val, "%lf,%lf,%lf,%lf", &rh, &lh, &rl, &ll) < 4) { fatalx(EXIT_FAILURE, "Insufficient parameters for runtimecal"); } if ((rl < rh) || (rh <= 0)) { fatalx(EXIT_FAILURE, "Parameter out of range (runtime)"); } if ((lh > 100) || (ll > lh) || (ll <= 0)) { fatalx(EXIT_FAILURE, "Parameter out of range (load)"); } batt.runt.exp = log(rl / rh) / log(lh / ll); upsdebugx(2, "battery runtime exponent : %.3f", batt.runt.exp); batt.runt.nom = rh * pow(lh / 100, batt.runt.exp); upsdebugx(2, "battery runtime nominal : %.1f", batt.runt.nom); } else { upslogx(LOG_INFO, "Battery runtime will not be calculated (runtimecal not set)"); return; } if (batt.chrg.act < 0) { batt.volt.low = batt.volt.nom; batt.volt.high = 1.15 * batt.volt.nom; blazer_battery(dstate_getinfo("battery.voltage"), NULL); } val = dstate_getinfo("battery.charge"); if (val) { batt.runt.est = batt.runt.nom * strtod(val, NULL) / 100; upsdebugx(2, "battery runtime estimate : %.1f", batt.runt.est); } else { fatalx(EXIT_FAILURE, "Initial battery charge undetermined"); } val = getval("chargetime"); if (val) { batt.chrg.time = strtol(val, NULL, 10); if (batt.chrg.time <= 0) { fatalx(EXIT_FAILURE, "Charge time out of range [1..s]"); } upsdebugx(2, "battery charge time : %ld", batt.chrg.time); } else { upslogx(LOG_INFO, "No charge time specified, using built in default [%ld seconds]", batt.chrg.time); } val = getval("idleload"); if (val) { load.low = strtod(val, NULL) / 100; if ((load.low < 0) || (load.low > 1)) { fatalx(EXIT_FAILURE, "Idle load out of range [0..100]"); } upsdebugx(2, "minimum load used (idle) : %.3f", load.low); } else { upslogx(LOG_INFO, "No idle load specified, using built in default [%.1f %%]", 100 * load.low); } } void blazer_initinfo(void) { const char *protocol = getval("protocol"); int retry; upsdebugx(0, "Please note that this driver is deprecated and will not receive\n" "new development. If it works for managing your devices - fine,\n" "but if you are running it to try setting up a new device, please\n" "consider the newer nutdrv_qx instead, which should handle all 'Qx'\n" "protocol variants for NUT. (Please also report if your device works\n" "with this driver, but nutdrv_qx would not actually support it with\n" "any subdriver!)\n"); for (proto = 0; command[proto].status; proto++) { int ret = -1; if (protocol && strcasecmp(protocol, command[proto].name)) { upsdebugx(2, "Skipping %s protocol...", command[proto].name); continue; } upsdebugx(2, "Trying %s protocol...", command[proto].name); for (retry = 1; retry <= MAXTRIES; retry++) { ret = blazer_status(command[proto].status); if (ret < 0) { upsdebugx(2, "Status read %d failed", retry); continue; } upsdebugx(2, "Status read in %d tries", retry); break; } if (!ret) { upslogx(LOG_INFO, "Supported UPS detected with %s protocol", command[proto].name); break; } } if (!command[proto].status) { fatalx(EXIT_FAILURE, "No supported UPS detected"); } if (command[proto].rating && !testvar("norating")) { int ret = -1; for (retry = 1; retry <= MAXTRIES; retry++) { ret = blazer_rating(command[proto].rating); if (ret < 0) { upsdebugx(1, "Rating read %d failed", retry); continue; } upsdebugx(2, "Ratings read in %d tries", retry); break; } if (ret) { upslogx(LOG_DEBUG, "Rating information unavailable"); } } if (command[proto].vendor && !testvar("novendor")) { int ret = -1; for (retry = 1; retry <= MAXTRIES; retry++) { ret = blazer_vendor(command[proto].vendor); if (ret < 0) { upsdebugx(1, "Vendor information read %d failed", retry); continue; } upslogx(LOG_INFO, "Vendor information read in %d tries", retry); break; } if (ret) { upslogx(LOG_DEBUG, "Vendor information unavailable"); } } blazer_initbattery(); dstate_setinfo("ups.delay.start", "%ld", 60 * ondelay); dstate_setinfo("ups.delay.shutdown", "%ld", offdelay); dstate_addcmd("beeper.toggle"); dstate_addcmd("load.off"); dstate_addcmd("load.on"); dstate_addcmd("shutdown.return"); dstate_addcmd("shutdown.stayoff"); dstate_addcmd("shutdown.stop"); dstate_addcmd("test.battery.start"); dstate_addcmd("test.battery.start.deep"); dstate_addcmd("test.battery.start.quick"); dstate_addcmd("test.battery.stop"); upsh.instcmd = blazer_instcmd; } void upsdrv_updateinfo(void) { static int retry = 0; if (blazer_status(command[proto].status)) { if (retry < MAXTRIES) { upsdebugx(1, "Communications with UPS lost: status read failed!"); retry++; } else if (retry == MAXTRIES) { upslogx(LOG_WARNING, "Communications with UPS lost: status read failed!"); retry++; } else { dstate_datastale(); } return; } if (getval("runtimecal")) { time_t now; time(&now); if (online) { /* OL */ batt.runt.est += batt.runt.nom * difftime(now, lastpoll) / batt.chrg.time; if (batt.runt.est > batt.runt.nom) { batt.runt.est = batt.runt.nom; } } else { /* OB */ batt.runt.est -= load.eff * difftime(now, lastpoll); if (batt.runt.est < 0) { batt.runt.est = 0; } } dstate_setinfo("battery.charge", "%.0f", 100 * batt.runt.est / batt.runt.nom); dstate_setinfo("battery.runtime", "%.0f", batt.runt.est / load.eff); lastpoll = now; } if (retry > MAXTRIES) { upslogx(LOG_NOTICE, "Communications with UPS re-established"); } retry = 0; dstate_dataok(); } void upsdrv_shutdown(void) { int retry; /* Stop pending shutdowns */ for (retry = 1; retry <= MAXTRIES; retry++) { if (blazer_instcmd("shutdown.stop", NULL) != STAT_INSTCMD_HANDLED) { continue; } break; } if (retry > MAXTRIES) { upslogx(LOG_NOTICE, "No shutdown pending"); } /* Shutdown */ for (retry = 1; retry <= MAXTRIES; retry++) { if (blazer_instcmd("shutdown.return", NULL) != STAT_INSTCMD_HANDLED) { continue; } upslogx(LOG_ERR, "Shutting down in %ld seconds", offdelay); set_exit_flag(-2); /* EXIT_SUCCESS */ return; } upslogx(LOG_ERR, "Shutdown failed!"); set_exit_flag(-1); } nut-2.8.1/drivers/Makefile.in0000644000175000017500000070620514520274662013016 00000000000000# Makefile.in generated by automake 1.16.5 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2021 Free Software Foundation, Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. @SET_MAKE@ # Network UPS Tools: drivers VPATH = @srcdir@ am__is_gnu_make = { \ if test -z '$(MAKELEVEL)'; then \ false; \ elif test -n '$(MAKE_HOST)'; then \ true; \ elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \ true; \ else \ false; \ fi; \ } am__make_running_with_option = \ case $${target_option-} in \ ?) ;; \ *) echo "am__make_running_with_option: internal error: invalid" \ "target option '$${target_option-}' specified" >&2; \ exit 1;; \ esac; \ has_opt=no; \ sane_makeflags=$$MAKEFLAGS; \ if $(am__is_gnu_make); then \ sane_makeflags=$$MFLAGS; \ else \ case $$MAKEFLAGS in \ *\\[\ \ ]*) \ bs=\\; \ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ esac; \ fi; \ skip_next=no; \ strip_trailopt () \ { \ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ }; \ for flg in $$sane_makeflags; do \ test $$skip_next = yes && { skip_next=no; continue; }; \ case $$flg in \ *=*|--*) continue;; \ -*I) strip_trailopt 'I'; skip_next=yes;; \ -*I?*) strip_trailopt 'I';; \ -*O) strip_trailopt 'O'; skip_next=yes;; \ -*O?*) strip_trailopt 'O';; \ -*l) strip_trailopt 'l'; skip_next=yes;; \ -*l?*) strip_trailopt 'l';; \ -[dEDm]) skip_next=yes;; \ -[JT]) skip_next=yes;; \ esac; \ case $$flg in \ *$$target_option*) has_opt=yes; break;; \ esac; \ done; \ test $$has_opt = yes am__make_dryrun = (target_option=n; $(am__make_running_with_option)) am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkglibexecdir = $(libexecdir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ target_triplet = @target@ @WITH_USB_TRUE@am__append_1 = $(LIBUSB_CFLAGS) @WITH_NEON_TRUE@am__append_2 = $(LIBNEON_CFLAGS) @WITH_LIBPOWERMAN_TRUE@am__append_3 = $(LIBPOWERMAN_CFLAGS) @WITH_IPMI_TRUE@am__append_4 = $(LIBIPMI_CFLAGS) @WITH_GPIO_TRUE@am__append_5 = $(LIBGPIO_CFLAGS) @WITH_MODBUS_TRUE@am__append_6 = $(LIBMODBUS_CFLAGS) @HAVE_LIBREGEX_TRUE@am__append_7 = $(LIBREGEX_CFLAGS) EXTRA_PROGRAMS = $(am__EXEEXT_1) $(am__EXEEXT_3) $(am__EXEEXT_4) \ $(am__EXEEXT_5) $(am__EXEEXT_6) $(am__EXEEXT_7) \ $(am__EXEEXT_8) $(am__EXEEXT_9) $(am__EXEEXT_10) @SOME_DRIVERS_FALSE@driverexec_PROGRAMS = $(am__EXEEXT_9) \ @SOME_DRIVERS_FALSE@ $(am__EXEEXT_11) $(am__EXEEXT_12) \ @SOME_DRIVERS_FALSE@ $(am__EXEEXT_13) $(am__EXEEXT_14) \ @SOME_DRIVERS_FALSE@ $(am__EXEEXT_15) $(am__EXEEXT_17) \ @SOME_DRIVERS_FALSE@ $(am__EXEEXT_19) $(am__EXEEXT_20) \ @SOME_DRIVERS_FALSE@ $(am__EXEEXT_21) $(am__EXEEXT_22) \ @SOME_DRIVERS_FALSE@ $(am__EXEEXT_24) @SOME_DRIVERS_TRUE@driverexec_PROGRAMS = $(DRIVER_BUILD_LIST) \ @SOME_DRIVERS_TRUE@ $(am__EXEEXT_11) $(am__EXEEXT_12) \ @SOME_DRIVERS_TRUE@ $(am__EXEEXT_13) $(am__EXEEXT_14) \ @SOME_DRIVERS_TRUE@ $(am__EXEEXT_15) $(am__EXEEXT_17) \ @SOME_DRIVERS_TRUE@ $(am__EXEEXT_19) $(am__EXEEXT_20) \ @SOME_DRIVERS_TRUE@ $(am__EXEEXT_21) $(am__EXEEXT_22) \ @SOME_DRIVERS_TRUE@ $(am__EXEEXT_24) skel$(EXEEXT) @SOME_DRIVERS_FALSE@@WITH_SERIAL_TRUE@am__append_8 = $(SERIAL_DRIVERLIST) $(SERIAL_USB_DRIVERLIST) @SOME_DRIVERS_FALSE@@WITH_SERIAL_FALSE@@WITH_USB_TRUE@am__append_9 = $(SERIAL_USB_DRIVERLIST) @SOME_DRIVERS_FALSE@@WITH_SNMP_TRUE@am__append_10 = $(SNMP_DRIVERLIST) @SOME_DRIVERS_FALSE@@WITH_USB_TRUE@am__append_11 = $(USB_LIBUSB_DRIVERLIST) @SOME_DRIVERS_FALSE@@WITH_NEON_TRUE@am__append_12 = $(NEONXML_DRIVERLIST) @SOME_DRIVERS_FALSE@@WITH_LIBPOWERMAN_TRUE@am__append_13 = $(POWERMAN_DRIVERLIST) @SOME_DRIVERS_FALSE@@WITH_IPMI_TRUE@am__append_14 = $(IPMI_DRIVERLIST) @SOME_DRIVERS_FALSE@@WITH_GPIO_TRUE@am__append_15 = $(GPIO_DRIVERLIST) @SOME_DRIVERS_FALSE@@WITH_MACOSX_TRUE@am__append_16 = $(MACOSX_DRIVERLIST) @SOME_DRIVERS_FALSE@@WITH_LINUX_I2C_TRUE@am__append_17 = $(LINUX_I2C_DRIVERLIST) @SOME_DRIVERS_FALSE@@WITH_MODBUS_TRUE@am__append_18 = $(MODBUS_DRIVERLIST) sbin_PROGRAMS = upsdrvctl$(EXEEXT) @WITH_SSL_TRUE@am__append_19 = $(LIBSSL_CFLAGS) @WITH_SSL_TRUE@am__append_20 = $(LIBSSL_LIBS) @WITH_FREEIPMI_TRUE@am__append_21 = nut-libfreeipmi.c @WITH_SERIAL_TRUE@am__append_22 = -DQX_SERIAL @WITH_SERIAL_TRUE@am__append_23 = libdummy_serial.la $(SERLIBS) @WITH_USB_TRUE@am__append_24 = -DQX_USB @WITH_USB_TRUE@am__append_25 = $(LIBUSB_IMPL) usb-common.c @WITH_USB_TRUE@am__append_26 = $(LIBUSB_LIBS) subdir = drivers ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/m4/ax_c___attribute__.m4 \ $(top_srcdir)/m4/ax_c_pragmas.m4 \ $(top_srcdir)/m4/ax_check_compile_flag.m4 \ $(top_srcdir)/m4/ax_compare_version.m4 \ $(top_srcdir)/m4/ax_realpath.m4 \ $(top_srcdir)/m4/ax_run_or_link_ifelse.m4 \ $(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \ $(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \ $(top_srcdir)/m4/lt~obsolete.m4 \ $(top_srcdir)/m4/nut_arg_with.m4 \ $(top_srcdir)/m4/nut_check_asciidoc.m4 \ $(top_srcdir)/m4/nut_check_aspell.m4 \ $(top_srcdir)/m4/nut_check_cppcheck.m4 \ $(top_srcdir)/m4/nut_check_headers_windows.m4 \ $(top_srcdir)/m4/nut_check_libavahi.m4 \ $(top_srcdir)/m4/nut_check_libfreeipmi.m4 \ $(top_srcdir)/m4/nut_check_libgd.m4 \ $(top_srcdir)/m4/nut_check_libgpiod.m4 \ $(top_srcdir)/m4/nut_check_libltdl.m4 \ $(top_srcdir)/m4/nut_check_libmodbus.m4 \ $(top_srcdir)/m4/nut_check_libneon.m4 \ $(top_srcdir)/m4/nut_check_libnetsnmp.m4 \ $(top_srcdir)/m4/nut_check_libnss.m4 \ $(top_srcdir)/m4/nut_check_libopenssl.m4 \ $(top_srcdir)/m4/nut_check_libpowerman.m4 \ $(top_srcdir)/m4/nut_check_libregex.m4 \ $(top_srcdir)/m4/nut_check_libsystemd.m4 \ $(top_srcdir)/m4/nut_check_libusb.m4 \ $(top_srcdir)/m4/nut_check_libwrap.m4 \ $(top_srcdir)/m4/nut_check_os.m4 \ $(top_srcdir)/m4/nut_check_pkgconfig.m4 \ $(top_srcdir)/m4/nut_check_python.m4 \ $(top_srcdir)/m4/nut_check_socketlib.m4 \ $(top_srcdir)/m4/nut_compiler_family.m4 \ $(top_srcdir)/m4/nut_func_getnameinfo_argtypes.m4 \ $(top_srcdir)/m4/nut_report_feature.m4 \ $(top_srcdir)/m4/nut_stash_warnings.m4 \ $(top_srcdir)/m4/nut_type_socklen_t.m4 \ $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) DIST_COMMON = $(srcdir)/Makefile.am $(dist_noinst_HEADERS) \ $(am__DIST_COMMON) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/include/config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = am__EXEEXT_1 = al175$(EXEEXT) bcmxcp$(EXEEXT) belkin$(EXEEXT) \ belkinunv$(EXEEXT) bestfcom$(EXEEXT) bestfortress$(EXEEXT) \ bestuferrups$(EXEEXT) bestups$(EXEEXT) etapro$(EXEEXT) \ everups$(EXEEXT) gamatronic$(EXEEXT) genericups$(EXEEXT) \ isbmex$(EXEEXT) liebert$(EXEEXT) liebert-esp2$(EXEEXT) \ masterguard$(EXEEXT) metasys$(EXEEXT) mge-utalk$(EXEEXT) \ microdowell$(EXEEXT) microsol-apc$(EXEEXT) mge-shut$(EXEEXT) \ oneac$(EXEEXT) optiups$(EXEEXT) powercom$(EXEEXT) \ rhino$(EXEEXT) safenet$(EXEEXT) nutdrv_siemens-sitop$(EXEEXT) \ solis$(EXEEXT) tripplite$(EXEEXT) tripplitesu$(EXEEXT) \ upscode2$(EXEEXT) victronups$(EXEEXT) powerpanel$(EXEEXT) \ blazer_ser$(EXEEXT) ivtscd$(EXEEXT) apcsmart$(EXEEXT) \ apcsmart-old$(EXEEXT) riello_ser$(EXEEXT) sms_ser$(EXEEXT) am__EXEEXT_2 = usbhid-ups$(EXEEXT) bcmxcp_usb$(EXEEXT) \ tripplite_usb$(EXEEXT) blazer_usb$(EXEEXT) \ richcomm_usb$(EXEEXT) riello_usb$(EXEEXT) \ nutdrv_atcl_usb$(EXEEXT) am__EXEEXT_3 = $(am__EXEEXT_2) am__EXEEXT_4 = nutdrv_qx$(EXEEXT) am__EXEEXT_5 = snmp-ups$(EXEEXT) am__EXEEXT_6 = netxml-ups$(EXEEXT) am__EXEEXT_7 = macosx-ups$(EXEEXT) am__EXEEXT_8 = asem$(EXEEXT) pijuice$(EXEEXT) am__EXEEXT_9 = dummy-ups$(EXEEXT) clone$(EXEEXT) clone-outlet$(EXEEXT) \ apcupsd-ups$(EXEEXT) skel$(EXEEXT) am__EXEEXT_10 = generic_gpio_libgpiod$(EXEEXT) @SOME_DRIVERS_FALSE@@WITH_SERIAL_TRUE@am__EXEEXT_11 = $(am__EXEEXT_1) \ @SOME_DRIVERS_FALSE@@WITH_SERIAL_TRUE@ $(am__EXEEXT_4) @SOME_DRIVERS_FALSE@@WITH_SERIAL_FALSE@@WITH_USB_TRUE@am__EXEEXT_12 = $(am__EXEEXT_4) @SOME_DRIVERS_FALSE@@WITH_SNMP_TRUE@am__EXEEXT_13 = $(am__EXEEXT_5) @SOME_DRIVERS_FALSE@@WITH_USB_TRUE@am__EXEEXT_14 = $(am__EXEEXT_2) @SOME_DRIVERS_FALSE@@WITH_NEON_TRUE@am__EXEEXT_15 = $(am__EXEEXT_6) am__EXEEXT_16 = powerman-pdu$(EXEEXT) @SOME_DRIVERS_FALSE@@WITH_LIBPOWERMAN_TRUE@am__EXEEXT_17 = \ @SOME_DRIVERS_FALSE@@WITH_LIBPOWERMAN_TRUE@ $(am__EXEEXT_16) am__EXEEXT_18 = nut-ipmipsu$(EXEEXT) @SOME_DRIVERS_FALSE@@WITH_IPMI_TRUE@am__EXEEXT_19 = $(am__EXEEXT_18) @SOME_DRIVERS_FALSE@@WITH_GPIO_TRUE@am__EXEEXT_20 = $(am__EXEEXT_10) @SOME_DRIVERS_FALSE@@WITH_MACOSX_TRUE@am__EXEEXT_21 = $(am__EXEEXT_7) @SOME_DRIVERS_FALSE@@WITH_LINUX_I2C_TRUE@am__EXEEXT_22 = \ @SOME_DRIVERS_FALSE@@WITH_LINUX_I2C_TRUE@ $(am__EXEEXT_8) am__EXEEXT_23 = phoenixcontact_modbus$(EXEEXT) generic_modbus$(EXEEXT) \ huawei-ups2000$(EXEEXT) socomec_jbus$(EXEEXT) \ adelsystem_cbi$(EXEEXT) apc_modbus$(EXEEXT) @SOME_DRIVERS_FALSE@@WITH_MODBUS_TRUE@am__EXEEXT_24 = \ @SOME_DRIVERS_FALSE@@WITH_MODBUS_TRUE@ $(am__EXEEXT_23) am__installdirs = "$(DESTDIR)$(driverexecdir)" "$(DESTDIR)$(sbindir)" PROGRAMS = $(driverexec_PROGRAMS) $(sbin_PROGRAMS) libdummy_la_LIBADD = am_libdummy_la_OBJECTS = main.lo dstate.lo libdummy_la_OBJECTS = $(am_libdummy_la_OBJECTS) AM_V_lt = $(am__v_lt_@AM_V@) am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@) am__v_lt_0 = --silent am__v_lt_1 = libdummy_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ $(libdummy_la_LDFLAGS) $(LDFLAGS) -o $@ libdummy_mockdrv_la_LIBADD = am_libdummy_mockdrv_la_OBJECTS = libdummy_mockdrv_la-main.lo \ libdummy_mockdrv_la-dstate.lo libdummy_mockdrv_la_OBJECTS = $(am_libdummy_mockdrv_la_OBJECTS) libdummy_mockdrv_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \ $(libdummy_mockdrv_la_CFLAGS) $(CFLAGS) \ $(libdummy_mockdrv_la_LDFLAGS) $(LDFLAGS) -o $@ libdummy_serial_la_LIBADD = am_libdummy_serial_la_OBJECTS = serial.lo libdummy_serial_la_OBJECTS = $(am_libdummy_serial_la_OBJECTS) libdummy_serial_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \ $(AM_CFLAGS) $(CFLAGS) $(libdummy_serial_la_LDFLAGS) \ $(LDFLAGS) -o $@ libdummy_upsdrvquery_la_LIBADD = am_libdummy_upsdrvquery_la_OBJECTS = upsdrvquery.lo libdummy_upsdrvquery_la_OBJECTS = \ $(am_libdummy_upsdrvquery_la_OBJECTS) libdummy_upsdrvquery_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \ $(AM_CFLAGS) $(CFLAGS) $(libdummy_upsdrvquery_la_LDFLAGS) \ $(LDFLAGS) -o $@ am_adelsystem_cbi_OBJECTS = adelsystem_cbi.$(OBJEXT) adelsystem_cbi_OBJECTS = $(am_adelsystem_cbi_OBJECTS) am__DEPENDENCIES_1 = adelsystem_cbi_DEPENDENCIES = $(LDADD_DRIVERS) $(am__DEPENDENCIES_1) am_al175_OBJECTS = al175.$(OBJEXT) al175_OBJECTS = $(am_al175_OBJECTS) al175_LDADD = $(LDADD) am__DEPENDENCIES_2 = libdummy_serial.la $(LDADD_DRIVERS) \ $(am__DEPENDENCIES_1) al175_DEPENDENCIES = $(am__DEPENDENCIES_2) am__apc_modbus_SOURCES_DIST = apc_modbus.c libusb0.c libusb1.c \ hidparser.c usb-common.c @WITH_LIBUSB_0_1_FALSE@@WITH_LIBUSB_1_0_TRUE@am__objects_1 = libusb1.$(OBJEXT) @WITH_LIBUSB_0_1_TRUE@am__objects_1 = libusb0.$(OBJEXT) am_apc_modbus_OBJECTS = apc_modbus.$(OBJEXT) $(am__objects_1) \ hidparser.$(OBJEXT) usb-common.$(OBJEXT) apc_modbus_OBJECTS = $(am_apc_modbus_OBJECTS) apc_modbus_DEPENDENCIES = $(LDADD_DRIVERS) $(am__DEPENDENCIES_1) \ $(am__DEPENDENCIES_1) am_apcsmart_OBJECTS = apcsmart.$(OBJEXT) apcsmart_tabs.$(OBJEXT) apcsmart_OBJECTS = $(am_apcsmart_OBJECTS) am__DEPENDENCIES_3 = $(am__DEPENDENCIES_2) apcsmart_DEPENDENCIES = $(am__DEPENDENCIES_3) $(am__DEPENDENCIES_1) am_apcsmart_old_OBJECTS = apcsmart-old.$(OBJEXT) apcsmart_old_OBJECTS = $(am_apcsmart_old_OBJECTS) apcsmart_old_LDADD = $(LDADD) apcsmart_old_DEPENDENCIES = $(am__DEPENDENCIES_2) am_apcupsd_ups_OBJECTS = apcupsd_ups-apcupsd-ups.$(OBJEXT) apcupsd_ups_OBJECTS = $(am_apcupsd_ups_OBJECTS) apcupsd_ups_DEPENDENCIES = $(LDADD_DRIVERS) apcupsd_ups_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(apcupsd_ups_CFLAGS) \ $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@ am_asem_OBJECTS = asem.$(OBJEXT) asem_OBJECTS = $(am_asem_OBJECTS) asem_DEPENDENCIES = $(LDADD_DRIVERS) $(am__DEPENDENCIES_1) am_bcmxcp_OBJECTS = bcmxcp.$(OBJEXT) bcmxcp_ser.$(OBJEXT) bcmxcp_OBJECTS = $(am_bcmxcp_OBJECTS) bcmxcp_DEPENDENCIES = $(am__DEPENDENCIES_3) am_bcmxcp_usb_OBJECTS = bcmxcp_usb.$(OBJEXT) bcmxcp.$(OBJEXT) \ usb-common.$(OBJEXT) bcmxcp_usb_OBJECTS = $(am_bcmxcp_usb_OBJECTS) bcmxcp_usb_DEPENDENCIES = $(LDADD_DRIVERS) $(am__DEPENDENCIES_1) am_belkin_OBJECTS = belkin.$(OBJEXT) belkin_OBJECTS = $(am_belkin_OBJECTS) belkin_LDADD = $(LDADD) belkin_DEPENDENCIES = $(am__DEPENDENCIES_2) am_belkinunv_OBJECTS = belkinunv.$(OBJEXT) belkinunv_OBJECTS = $(am_belkinunv_OBJECTS) belkinunv_LDADD = $(LDADD) belkinunv_DEPENDENCIES = $(am__DEPENDENCIES_2) am_bestfcom_OBJECTS = bestfcom.$(OBJEXT) bestfcom_OBJECTS = $(am_bestfcom_OBJECTS) bestfcom_LDADD = $(LDADD) bestfcom_DEPENDENCIES = $(am__DEPENDENCIES_2) am_bestfortress_OBJECTS = bestfortress.$(OBJEXT) bestfortress_OBJECTS = $(am_bestfortress_OBJECTS) bestfortress_LDADD = $(LDADD) bestfortress_DEPENDENCIES = $(am__DEPENDENCIES_2) am_bestuferrups_OBJECTS = bestuferrups.$(OBJEXT) bestuferrups_OBJECTS = $(am_bestuferrups_OBJECTS) bestuferrups_LDADD = $(LDADD) bestuferrups_DEPENDENCIES = $(am__DEPENDENCIES_2) am_bestups_OBJECTS = bestups.$(OBJEXT) bestups_OBJECTS = $(am_bestups_OBJECTS) bestups_LDADD = $(LDADD) bestups_DEPENDENCIES = $(am__DEPENDENCIES_2) am_blazer_ser_OBJECTS = blazer.$(OBJEXT) blazer_ser.$(OBJEXT) blazer_ser_OBJECTS = $(am_blazer_ser_OBJECTS) blazer_ser_DEPENDENCIES = $(am__DEPENDENCIES_3) am__blazer_usb_SOURCES_DIST = blazer.c blazer_usb.c libusb0.c \ libusb1.c usb-common.c am_blazer_usb_OBJECTS = blazer.$(OBJEXT) blazer_usb.$(OBJEXT) \ $(am__objects_1) usb-common.$(OBJEXT) blazer_usb_OBJECTS = $(am_blazer_usb_OBJECTS) blazer_usb_DEPENDENCIES = $(LDADD_DRIVERS) $(am__DEPENDENCIES_1) am_clone_OBJECTS = clone.$(OBJEXT) clone_OBJECTS = $(am_clone_OBJECTS) clone_LDADD = $(LDADD) clone_DEPENDENCIES = $(am__DEPENDENCIES_2) am_clone_outlet_OBJECTS = clone-outlet.$(OBJEXT) clone_outlet_OBJECTS = $(am_clone_outlet_OBJECTS) clone_outlet_LDADD = $(LDADD) clone_outlet_DEPENDENCIES = $(am__DEPENDENCIES_2) am_dummy_ups_OBJECTS = dummy_ups-dummy-ups.$(OBJEXT) dummy_ups_OBJECTS = $(am_dummy_ups_OBJECTS) @WITH_SSL_TRUE@am__DEPENDENCIES_4 = $(am__DEPENDENCIES_1) dummy_ups_DEPENDENCIES = $(LDADD_DRIVERS) \ $(top_builddir)/clients/libupsclient.la $(am__DEPENDENCIES_4) dummy_ups_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(dummy_ups_CFLAGS) \ $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@ am_etapro_OBJECTS = etapro.$(OBJEXT) etapro_OBJECTS = $(am_etapro_OBJECTS) etapro_LDADD = $(LDADD) etapro_DEPENDENCIES = $(am__DEPENDENCIES_2) am_everups_OBJECTS = everups.$(OBJEXT) everups_OBJECTS = $(am_everups_OBJECTS) everups_LDADD = $(LDADD) everups_DEPENDENCIES = $(am__DEPENDENCIES_2) am_gamatronic_OBJECTS = gamatronic.$(OBJEXT) gamatronic_OBJECTS = $(am_gamatronic_OBJECTS) gamatronic_LDADD = $(LDADD) gamatronic_DEPENDENCIES = $(am__DEPENDENCIES_2) am_generic_gpio_libgpiod_OBJECTS = generic_gpio_common.$(OBJEXT) \ generic_gpio_libgpiod.$(OBJEXT) generic_gpio_libgpiod_OBJECTS = $(am_generic_gpio_libgpiod_OBJECTS) generic_gpio_libgpiod_DEPENDENCIES = $(LDADD_DRIVERS) \ $(am__DEPENDENCIES_1) am_generic_modbus_OBJECTS = generic_modbus.$(OBJEXT) generic_modbus_OBJECTS = $(am_generic_modbus_OBJECTS) generic_modbus_DEPENDENCIES = $(LDADD_DRIVERS) $(am__DEPENDENCIES_1) am_genericups_OBJECTS = genericups.$(OBJEXT) genericups_OBJECTS = $(am_genericups_OBJECTS) genericups_LDADD = $(LDADD) genericups_DEPENDENCIES = $(am__DEPENDENCIES_2) am_huawei_ups2000_OBJECTS = huawei-ups2000.$(OBJEXT) huawei_ups2000_OBJECTS = $(am_huawei_ups2000_OBJECTS) huawei_ups2000_DEPENDENCIES = $(am__DEPENDENCIES_2) \ $(am__DEPENDENCIES_1) am_isbmex_OBJECTS = isbmex.$(OBJEXT) isbmex_OBJECTS = $(am_isbmex_OBJECTS) isbmex_DEPENDENCIES = $(am__DEPENDENCIES_3) am_ivtscd_OBJECTS = ivtscd.$(OBJEXT) ivtscd_OBJECTS = $(am_ivtscd_OBJECTS) ivtscd_LDADD = $(LDADD) ivtscd_DEPENDENCIES = $(am__DEPENDENCIES_2) am_liebert_OBJECTS = liebert.$(OBJEXT) liebert_OBJECTS = $(am_liebert_OBJECTS) liebert_LDADD = $(LDADD) liebert_DEPENDENCIES = $(am__DEPENDENCIES_2) am_liebert_esp2_OBJECTS = liebert-esp2.$(OBJEXT) liebert_esp2_OBJECTS = $(am_liebert_esp2_OBJECTS) liebert_esp2_LDADD = $(LDADD) liebert_esp2_DEPENDENCIES = $(am__DEPENDENCIES_2) am_macosx_ups_OBJECTS = macosx-ups.$(OBJEXT) macosx_ups_OBJECTS = $(am_macosx_ups_OBJECTS) macosx_ups_DEPENDENCIES = $(LDADD_DRIVERS) macosx_ups_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ $(macosx_ups_LDFLAGS) $(LDFLAGS) -o $@ am_masterguard_OBJECTS = masterguard.$(OBJEXT) masterguard_OBJECTS = $(am_masterguard_OBJECTS) masterguard_LDADD = $(LDADD) masterguard_DEPENDENCIES = $(am__DEPENDENCIES_2) am_metasys_OBJECTS = metasys.$(OBJEXT) metasys_OBJECTS = $(am_metasys_OBJECTS) metasys_DEPENDENCIES = $(am__DEPENDENCIES_3) am_mge_shut_OBJECTS = mge_shut-usbhid-ups.$(OBJEXT) \ mge_shut-libshut.$(OBJEXT) mge_shut-libhid.$(OBJEXT) \ mge_shut-hidparser.$(OBJEXT) mge_shut-mge-hid.$(OBJEXT) mge_shut_OBJECTS = $(am_mge_shut_OBJECTS) mge_shut_DEPENDENCIES = $(am__DEPENDENCIES_3) mge_shut_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(mge_shut_CFLAGS) \ $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@ am_mge_utalk_OBJECTS = mge-utalk.$(OBJEXT) mge_utalk_OBJECTS = $(am_mge_utalk_OBJECTS) mge_utalk_LDADD = $(LDADD) mge_utalk_DEPENDENCIES = $(am__DEPENDENCIES_2) am_microdowell_OBJECTS = microdowell.$(OBJEXT) microdowell_OBJECTS = $(am_microdowell_OBJECTS) microdowell_LDADD = $(LDADD) microdowell_DEPENDENCIES = $(am__DEPENDENCIES_2) am_microsol_apc_OBJECTS = microsol-apc.$(OBJEXT) \ microsol-common.$(OBJEXT) microsol_apc_OBJECTS = $(am_microsol_apc_OBJECTS) microsol_apc_DEPENDENCIES = $(am__DEPENDENCIES_3) am_netxml_ups_OBJECTS = netxml-ups.$(OBJEXT) mge-xml.$(OBJEXT) netxml_ups_OBJECTS = $(am_netxml_ups_OBJECTS) netxml_ups_DEPENDENCIES = $(LDADD_DRIVERS) $(am__DEPENDENCIES_1) am__nut_ipmipsu_SOURCES_DIST = nut-ipmipsu.c nut-libfreeipmi.c @WITH_FREEIPMI_TRUE@am__objects_2 = nut-libfreeipmi.$(OBJEXT) am_nut_ipmipsu_OBJECTS = nut-ipmipsu.$(OBJEXT) $(am__objects_2) nut_ipmipsu_OBJECTS = $(am_nut_ipmipsu_OBJECTS) nut_ipmipsu_DEPENDENCIES = $(am__DEPENDENCIES_3) $(am__DEPENDENCIES_1) am_nutdrv_atcl_usb_OBJECTS = nutdrv_atcl_usb.$(OBJEXT) \ usb-common.$(OBJEXT) nutdrv_atcl_usb_OBJECTS = $(am_nutdrv_atcl_usb_OBJECTS) nutdrv_atcl_usb_DEPENDENCIES = $(LDADD_DRIVERS) $(am__DEPENDENCIES_1) am__nutdrv_qx_SOURCES_DIST = nutdrv_qx.c libusb0.c libusb1.c \ usb-common.c nutdrv_qx_bestups.c nutdrv_qx_blazer-common.c \ nutdrv_qx_masterguard.c nutdrv_qx_mecer.c nutdrv_qx_megatec.c \ nutdrv_qx_megatec-old.c nutdrv_qx_mustek.c nutdrv_qx_q1.c \ nutdrv_qx_voltronic.c nutdrv_qx_voltronic-qs.c \ nutdrv_qx_voltronic-qs-hex.c nutdrv_qx_zinto.c \ nutdrv_qx_hunnox.c nutdrv_qx_ablerex.c @WITH_LIBUSB_0_1_FALSE@@WITH_LIBUSB_1_0_TRUE@am__objects_3 = nutdrv_qx-libusb1.$(OBJEXT) @WITH_LIBUSB_0_1_TRUE@am__objects_3 = nutdrv_qx-libusb0.$(OBJEXT) @WITH_USB_TRUE@am__objects_4 = $(am__objects_3) \ @WITH_USB_TRUE@ nutdrv_qx-usb-common.$(OBJEXT) am__objects_5 = nutdrv_qx-nutdrv_qx_bestups.$(OBJEXT) \ nutdrv_qx-nutdrv_qx_blazer-common.$(OBJEXT) \ nutdrv_qx-nutdrv_qx_masterguard.$(OBJEXT) \ nutdrv_qx-nutdrv_qx_mecer.$(OBJEXT) \ nutdrv_qx-nutdrv_qx_megatec.$(OBJEXT) \ nutdrv_qx-nutdrv_qx_megatec-old.$(OBJEXT) \ nutdrv_qx-nutdrv_qx_mustek.$(OBJEXT) \ nutdrv_qx-nutdrv_qx_q1.$(OBJEXT) \ nutdrv_qx-nutdrv_qx_voltronic.$(OBJEXT) \ nutdrv_qx-nutdrv_qx_voltronic-qs.$(OBJEXT) \ nutdrv_qx-nutdrv_qx_voltronic-qs-hex.$(OBJEXT) \ nutdrv_qx-nutdrv_qx_zinto.$(OBJEXT) \ nutdrv_qx-nutdrv_qx_hunnox.$(OBJEXT) \ nutdrv_qx-nutdrv_qx_ablerex.$(OBJEXT) am_nutdrv_qx_OBJECTS = nutdrv_qx-nutdrv_qx.$(OBJEXT) $(am__objects_4) \ $(am__objects_5) nutdrv_qx_OBJECTS = $(am_nutdrv_qx_OBJECTS) @WITH_SERIAL_TRUE@am__DEPENDENCIES_5 = libdummy_serial.la \ @WITH_SERIAL_TRUE@ $(am__DEPENDENCIES_1) @WITH_USB_TRUE@am__DEPENDENCIES_6 = $(am__DEPENDENCIES_1) nutdrv_qx_DEPENDENCIES = $(LDADD_DRIVERS) $(am__DEPENDENCIES_5) \ $(am__DEPENDENCIES_6) nutdrv_qx_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(nutdrv_qx_CFLAGS) \ $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@ am_nutdrv_siemens_sitop_OBJECTS = nutdrv_siemens_sitop.$(OBJEXT) nutdrv_siemens_sitop_OBJECTS = $(am_nutdrv_siemens_sitop_OBJECTS) nutdrv_siemens_sitop_LDADD = $(LDADD) nutdrv_siemens_sitop_DEPENDENCIES = $(am__DEPENDENCIES_2) am_oneac_OBJECTS = oneac.$(OBJEXT) oneac_OBJECTS = $(am_oneac_OBJECTS) oneac_LDADD = $(LDADD) oneac_DEPENDENCIES = $(am__DEPENDENCIES_2) am_optiups_OBJECTS = optiups.$(OBJEXT) optiups_OBJECTS = $(am_optiups_OBJECTS) optiups_LDADD = $(LDADD) optiups_DEPENDENCIES = $(am__DEPENDENCIES_2) am_phoenixcontact_modbus_OBJECTS = phoenixcontact_modbus.$(OBJEXT) phoenixcontact_modbus_OBJECTS = $(am_phoenixcontact_modbus_OBJECTS) phoenixcontact_modbus_DEPENDENCIES = $(LDADD_DRIVERS) \ $(am__DEPENDENCIES_1) am_pijuice_OBJECTS = pijuice.$(OBJEXT) pijuice_OBJECTS = $(am_pijuice_OBJECTS) pijuice_DEPENDENCIES = $(LDADD_DRIVERS) $(am__DEPENDENCIES_1) am_powercom_OBJECTS = powercom.$(OBJEXT) powercom_OBJECTS = $(am_powercom_OBJECTS) powercom_DEPENDENCIES = $(am__DEPENDENCIES_3) am_powerman_pdu_OBJECTS = powerman-pdu.$(OBJEXT) powerman_pdu_OBJECTS = $(am_powerman_pdu_OBJECTS) powerman_pdu_DEPENDENCIES = $(am__DEPENDENCIES_3) \ $(am__DEPENDENCIES_1) am_powerpanel_OBJECTS = powerpanel.$(OBJEXT) powerp-bin.$(OBJEXT) \ powerp-txt.$(OBJEXT) powerpanel_OBJECTS = $(am_powerpanel_OBJECTS) powerpanel_DEPENDENCIES = $(am__DEPENDENCIES_3) am_rhino_OBJECTS = rhino.$(OBJEXT) rhino_OBJECTS = $(am_rhino_OBJECTS) rhino_DEPENDENCIES = $(am__DEPENDENCIES_3) am__richcomm_usb_SOURCES_DIST = richcomm_usb.c libusb0.c libusb1.c \ usb-common.c am_richcomm_usb_OBJECTS = richcomm_usb.$(OBJEXT) $(am__objects_1) \ usb-common.$(OBJEXT) richcomm_usb_OBJECTS = $(am_richcomm_usb_OBJECTS) richcomm_usb_DEPENDENCIES = $(LDADD_DRIVERS) $(am__DEPENDENCIES_1) am_riello_ser_OBJECTS = riello.$(OBJEXT) riello_ser.$(OBJEXT) riello_ser_OBJECTS = $(am_riello_ser_OBJECTS) riello_ser_DEPENDENCIES = $(am__DEPENDENCIES_3) am__riello_usb_SOURCES_DIST = riello.c riello_usb.c libusb0.c \ libusb1.c usb-common.c am_riello_usb_OBJECTS = riello.$(OBJEXT) riello_usb.$(OBJEXT) \ $(am__objects_1) usb-common.$(OBJEXT) riello_usb_OBJECTS = $(am_riello_usb_OBJECTS) riello_usb_DEPENDENCIES = $(LDADD_DRIVERS) $(am__DEPENDENCIES_1) am_safenet_OBJECTS = safenet.$(OBJEXT) safenet_OBJECTS = $(am_safenet_OBJECTS) safenet_LDADD = $(LDADD) safenet_DEPENDENCIES = $(am__DEPENDENCIES_2) am_skel_OBJECTS = skel.$(OBJEXT) skel_OBJECTS = $(am_skel_OBJECTS) skel_DEPENDENCIES = $(LDADD_DRIVERS) am_sms_ser_OBJECTS = sms_ser.$(OBJEXT) sms_ser_OBJECTS = $(am_sms_ser_OBJECTS) sms_ser_DEPENDENCIES = $(am__DEPENDENCIES_3) am_snmp_ups_OBJECTS = snmp_ups-snmp-ups.$(OBJEXT) \ snmp_ups-snmp-ups-helpers.$(OBJEXT) snmp_ups-apc-mib.$(OBJEXT) \ snmp_ups-apc-pdu-mib.$(OBJEXT) snmp_ups-apc-epdu-mib.$(OBJEXT) \ snmp_ups-baytech-mib.$(OBJEXT) \ snmp_ups-bestpower-mib.$(OBJEXT) snmp_ups-compaq-mib.$(OBJEXT) \ snmp_ups-cyberpower-mib.$(OBJEXT) \ snmp_ups-delta_ups-mib.$(OBJEXT) \ snmp_ups-eaton-pdu-genesis2-mib.$(OBJEXT) \ snmp_ups-eaton-pdu-marlin-mib.$(OBJEXT) \ snmp_ups-eaton-pdu-marlin-helpers.$(OBJEXT) \ snmp_ups-eaton-pdu-pulizzi-mib.$(OBJEXT) \ snmp_ups-eaton-pdu-revelation-mib.$(OBJEXT) \ snmp_ups-eaton-pdu-nlogic-mib.$(OBJEXT) \ snmp_ups-eaton-ats16-nmc-mib.$(OBJEXT) \ snmp_ups-eaton-ats16-nm2-mib.$(OBJEXT) \ snmp_ups-apc-ats-mib.$(OBJEXT) \ snmp_ups-eaton-ats30-mib.$(OBJEXT) \ snmp_ups-eaton-ups-pwnm2-mib.$(OBJEXT) \ snmp_ups-eaton-ups-pxg-mib.$(OBJEXT) \ snmp_ups-emerson-avocent-pdu-mib.$(OBJEXT) \ snmp_ups-hpe-pdu-mib.$(OBJEXT) \ snmp_ups-hpe-pdu3-cis-mib.$(OBJEXT) \ snmp_ups-huawei-mib.$(OBJEXT) snmp_ups-ietf-mib.$(OBJEXT) \ snmp_ups-mge-mib.$(OBJEXT) snmp_ups-netvision-mib.$(OBJEXT) \ snmp_ups-raritan-pdu-mib.$(OBJEXT) \ snmp_ups-raritan-px2-mib.$(OBJEXT) snmp_ups-xppc-mib.$(OBJEXT) snmp_ups_OBJECTS = $(am_snmp_ups_OBJECTS) snmp_ups_DEPENDENCIES = $(LDADD_DRIVERS) $(am__DEPENDENCIES_1) snmp_ups_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(snmp_ups_CFLAGS) \ $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@ am_socomec_jbus_OBJECTS = socomec_jbus.$(OBJEXT) socomec_jbus_OBJECTS = $(am_socomec_jbus_OBJECTS) socomec_jbus_DEPENDENCIES = $(am__DEPENDENCIES_2) \ $(am__DEPENDENCIES_1) am_solis_OBJECTS = solis.$(OBJEXT) solis_OBJECTS = $(am_solis_OBJECTS) solis_DEPENDENCIES = $(am__DEPENDENCIES_3) am_tripplite_OBJECTS = tripplite.$(OBJEXT) tripplite_OBJECTS = $(am_tripplite_OBJECTS) tripplite_DEPENDENCIES = $(am__DEPENDENCIES_3) am__tripplite_usb_SOURCES_DIST = tripplite_usb.c libusb0.c libusb1.c \ usb-common.c am_tripplite_usb_OBJECTS = tripplite_usb.$(OBJEXT) $(am__objects_1) \ usb-common.$(OBJEXT) tripplite_usb_OBJECTS = $(am_tripplite_usb_OBJECTS) tripplite_usb_DEPENDENCIES = $(LDADD_DRIVERS) $(am__DEPENDENCIES_1) am_tripplitesu_OBJECTS = tripplitesu.$(OBJEXT) tripplitesu_OBJECTS = $(am_tripplitesu_OBJECTS) tripplitesu_LDADD = $(LDADD) tripplitesu_DEPENDENCIES = $(am__DEPENDENCIES_2) am_upscode2_OBJECTS = upscode2.$(OBJEXT) upscode2_OBJECTS = $(am_upscode2_OBJECTS) upscode2_DEPENDENCIES = $(am__DEPENDENCIES_3) am_upsdrvctl_OBJECTS = upsdrvctl.$(OBJEXT) upsdrvctl_OBJECTS = $(am_upsdrvctl_OBJECTS) upsdrvctl_DEPENDENCIES = $(LDADD_COMMON) libdummy_upsdrvquery.la am__usbhid_ups_SOURCES_DIST = usbhid-ups.c libhid.c libusb0.c \ libusb1.c hidparser.c usb-common.c apc-hid.c arduino-hid.c \ belkin-hid.c cps-hid.c explore-hid.c liebert-hid.c mge-hid.c \ powercom-hid.c tripplite-hid.c idowell-hid.c openups-hid.c \ powervar-hid.c delta_ups-hid.c ever-hid.c legrand-hid.c \ salicru-hid.c am__objects_6 = apc-hid.$(OBJEXT) arduino-hid.$(OBJEXT) \ belkin-hid.$(OBJEXT) cps-hid.$(OBJEXT) explore-hid.$(OBJEXT) \ liebert-hid.$(OBJEXT) mge-hid.$(OBJEXT) powercom-hid.$(OBJEXT) \ tripplite-hid.$(OBJEXT) idowell-hid.$(OBJEXT) \ openups-hid.$(OBJEXT) powervar-hid.$(OBJEXT) \ delta_ups-hid.$(OBJEXT) ever-hid.$(OBJEXT) \ legrand-hid.$(OBJEXT) salicru-hid.$(OBJEXT) am_usbhid_ups_OBJECTS = usbhid-ups.$(OBJEXT) libhid.$(OBJEXT) \ $(am__objects_1) hidparser.$(OBJEXT) usb-common.$(OBJEXT) \ $(am__objects_6) usbhid_ups_OBJECTS = $(am_usbhid_ups_OBJECTS) usbhid_ups_DEPENDENCIES = $(LDADD_DRIVERS) $(am__DEPENDENCIES_1) am_victronups_OBJECTS = victronups.$(OBJEXT) victronups_OBJECTS = $(am_victronups_OBJECTS) victronups_LDADD = $(LDADD) victronups_DEPENDENCIES = $(am__DEPENDENCIES_2) AM_V_P = $(am__v_P_@AM_V@) am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) am__v_P_0 = false am__v_P_1 = : AM_V_GEN = $(am__v_GEN_@AM_V@) am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) am__v_GEN_0 = @echo " GEN " $@; am__v_GEN_1 = AM_V_at = $(am__v_at_@AM_V@) am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) am__v_at_0 = @ am__v_at_1 = DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)/include depcomp = $(SHELL) $(top_srcdir)/depcomp am__maybe_remake_depfiles = depfiles am__depfiles_remade = ./$(DEPDIR)/adelsystem_cbi.Po \ ./$(DEPDIR)/al175.Po ./$(DEPDIR)/apc-hid.Po \ ./$(DEPDIR)/apc_modbus.Po ./$(DEPDIR)/apcsmart-old.Po \ ./$(DEPDIR)/apcsmart.Po ./$(DEPDIR)/apcsmart_tabs.Po \ ./$(DEPDIR)/apcupsd_ups-apcupsd-ups.Po \ ./$(DEPDIR)/arduino-hid.Po ./$(DEPDIR)/asem.Po \ ./$(DEPDIR)/bcmxcp.Po ./$(DEPDIR)/bcmxcp_ser.Po \ ./$(DEPDIR)/bcmxcp_usb.Po ./$(DEPDIR)/belkin-hid.Po \ ./$(DEPDIR)/belkin.Po ./$(DEPDIR)/belkinunv.Po \ ./$(DEPDIR)/bestfcom.Po ./$(DEPDIR)/bestfortress.Po \ ./$(DEPDIR)/bestuferrups.Po ./$(DEPDIR)/bestups.Po \ ./$(DEPDIR)/blazer.Po ./$(DEPDIR)/blazer_ser.Po \ ./$(DEPDIR)/blazer_usb.Po ./$(DEPDIR)/clone-outlet.Po \ ./$(DEPDIR)/clone.Po ./$(DEPDIR)/cps-hid.Po \ ./$(DEPDIR)/delta_ups-hid.Po ./$(DEPDIR)/dstate.Plo \ ./$(DEPDIR)/dummy_ups-dummy-ups.Po ./$(DEPDIR)/etapro.Po \ ./$(DEPDIR)/ever-hid.Po ./$(DEPDIR)/everups.Po \ ./$(DEPDIR)/explore-hid.Po ./$(DEPDIR)/gamatronic.Po \ ./$(DEPDIR)/generic_gpio_common.Po \ ./$(DEPDIR)/generic_gpio_libgpiod.Po \ ./$(DEPDIR)/generic_modbus.Po ./$(DEPDIR)/genericups.Po \ ./$(DEPDIR)/hidparser.Po ./$(DEPDIR)/huawei-ups2000.Po \ ./$(DEPDIR)/idowell-hid.Po ./$(DEPDIR)/isbmex.Po \ ./$(DEPDIR)/ivtscd.Po ./$(DEPDIR)/legrand-hid.Po \ ./$(DEPDIR)/libdummy_mockdrv_la-dstate.Plo \ ./$(DEPDIR)/libdummy_mockdrv_la-main.Plo ./$(DEPDIR)/libhid.Po \ ./$(DEPDIR)/libusb0.Po ./$(DEPDIR)/libusb1.Po \ ./$(DEPDIR)/liebert-esp2.Po ./$(DEPDIR)/liebert-hid.Po \ ./$(DEPDIR)/liebert.Po ./$(DEPDIR)/macosx-ups.Po \ ./$(DEPDIR)/main.Plo ./$(DEPDIR)/masterguard.Po \ ./$(DEPDIR)/metasys.Po ./$(DEPDIR)/mge-hid.Po \ ./$(DEPDIR)/mge-utalk.Po ./$(DEPDIR)/mge-xml.Po \ ./$(DEPDIR)/mge_shut-hidparser.Po \ ./$(DEPDIR)/mge_shut-libhid.Po ./$(DEPDIR)/mge_shut-libshut.Po \ ./$(DEPDIR)/mge_shut-mge-hid.Po \ ./$(DEPDIR)/mge_shut-usbhid-ups.Po ./$(DEPDIR)/microdowell.Po \ ./$(DEPDIR)/microsol-apc.Po ./$(DEPDIR)/microsol-common.Po \ ./$(DEPDIR)/netxml-ups.Po ./$(DEPDIR)/nut-ipmipsu.Po \ ./$(DEPDIR)/nut-libfreeipmi.Po ./$(DEPDIR)/nutdrv_atcl_usb.Po \ ./$(DEPDIR)/nutdrv_qx-libusb0.Po \ ./$(DEPDIR)/nutdrv_qx-libusb1.Po \ ./$(DEPDIR)/nutdrv_qx-nutdrv_qx.Po \ ./$(DEPDIR)/nutdrv_qx-nutdrv_qx_ablerex.Po \ ./$(DEPDIR)/nutdrv_qx-nutdrv_qx_bestups.Po \ ./$(DEPDIR)/nutdrv_qx-nutdrv_qx_blazer-common.Po \ ./$(DEPDIR)/nutdrv_qx-nutdrv_qx_hunnox.Po \ ./$(DEPDIR)/nutdrv_qx-nutdrv_qx_masterguard.Po \ ./$(DEPDIR)/nutdrv_qx-nutdrv_qx_mecer.Po \ ./$(DEPDIR)/nutdrv_qx-nutdrv_qx_megatec-old.Po \ ./$(DEPDIR)/nutdrv_qx-nutdrv_qx_megatec.Po \ ./$(DEPDIR)/nutdrv_qx-nutdrv_qx_mustek.Po \ ./$(DEPDIR)/nutdrv_qx-nutdrv_qx_q1.Po \ ./$(DEPDIR)/nutdrv_qx-nutdrv_qx_voltronic-qs-hex.Po \ ./$(DEPDIR)/nutdrv_qx-nutdrv_qx_voltronic-qs.Po \ ./$(DEPDIR)/nutdrv_qx-nutdrv_qx_voltronic.Po \ ./$(DEPDIR)/nutdrv_qx-nutdrv_qx_zinto.Po \ ./$(DEPDIR)/nutdrv_qx-usb-common.Po \ ./$(DEPDIR)/nutdrv_siemens_sitop.Po ./$(DEPDIR)/oneac.Po \ ./$(DEPDIR)/openups-hid.Po ./$(DEPDIR)/optiups.Po \ ./$(DEPDIR)/phoenixcontact_modbus.Po ./$(DEPDIR)/pijuice.Po \ ./$(DEPDIR)/powercom-hid.Po ./$(DEPDIR)/powercom.Po \ ./$(DEPDIR)/powerman-pdu.Po ./$(DEPDIR)/powerp-bin.Po \ ./$(DEPDIR)/powerp-txt.Po ./$(DEPDIR)/powerpanel.Po \ ./$(DEPDIR)/powervar-hid.Po ./$(DEPDIR)/rhino.Po \ ./$(DEPDIR)/richcomm_usb.Po ./$(DEPDIR)/riello.Po \ ./$(DEPDIR)/riello_ser.Po ./$(DEPDIR)/riello_usb.Po \ ./$(DEPDIR)/safenet.Po ./$(DEPDIR)/salicru-hid.Po \ ./$(DEPDIR)/serial.Plo ./$(DEPDIR)/skel.Po \ ./$(DEPDIR)/sms_ser.Po ./$(DEPDIR)/snmp_ups-apc-ats-mib.Po \ ./$(DEPDIR)/snmp_ups-apc-epdu-mib.Po \ ./$(DEPDIR)/snmp_ups-apc-mib.Po \ ./$(DEPDIR)/snmp_ups-apc-pdu-mib.Po \ ./$(DEPDIR)/snmp_ups-baytech-mib.Po \ ./$(DEPDIR)/snmp_ups-bestpower-mib.Po \ ./$(DEPDIR)/snmp_ups-compaq-mib.Po \ ./$(DEPDIR)/snmp_ups-cyberpower-mib.Po \ ./$(DEPDIR)/snmp_ups-delta_ups-mib.Po \ ./$(DEPDIR)/snmp_ups-eaton-ats16-nm2-mib.Po \ ./$(DEPDIR)/snmp_ups-eaton-ats16-nmc-mib.Po \ ./$(DEPDIR)/snmp_ups-eaton-ats30-mib.Po \ ./$(DEPDIR)/snmp_ups-eaton-pdu-genesis2-mib.Po \ ./$(DEPDIR)/snmp_ups-eaton-pdu-marlin-helpers.Po \ ./$(DEPDIR)/snmp_ups-eaton-pdu-marlin-mib.Po \ ./$(DEPDIR)/snmp_ups-eaton-pdu-nlogic-mib.Po \ ./$(DEPDIR)/snmp_ups-eaton-pdu-pulizzi-mib.Po \ ./$(DEPDIR)/snmp_ups-eaton-pdu-revelation-mib.Po \ ./$(DEPDIR)/snmp_ups-eaton-ups-pwnm2-mib.Po \ ./$(DEPDIR)/snmp_ups-eaton-ups-pxg-mib.Po \ ./$(DEPDIR)/snmp_ups-emerson-avocent-pdu-mib.Po \ ./$(DEPDIR)/snmp_ups-hpe-pdu-mib.Po \ ./$(DEPDIR)/snmp_ups-hpe-pdu3-cis-mib.Po \ ./$(DEPDIR)/snmp_ups-huawei-mib.Po \ ./$(DEPDIR)/snmp_ups-ietf-mib.Po \ ./$(DEPDIR)/snmp_ups-mge-mib.Po \ ./$(DEPDIR)/snmp_ups-netvision-mib.Po \ ./$(DEPDIR)/snmp_ups-raritan-pdu-mib.Po \ ./$(DEPDIR)/snmp_ups-raritan-px2-mib.Po \ ./$(DEPDIR)/snmp_ups-snmp-ups-helpers.Po \ ./$(DEPDIR)/snmp_ups-snmp-ups.Po \ ./$(DEPDIR)/snmp_ups-xppc-mib.Po ./$(DEPDIR)/socomec_jbus.Po \ ./$(DEPDIR)/solis.Po ./$(DEPDIR)/tripplite-hid.Po \ ./$(DEPDIR)/tripplite.Po ./$(DEPDIR)/tripplite_usb.Po \ ./$(DEPDIR)/tripplitesu.Po ./$(DEPDIR)/upscode2.Po \ ./$(DEPDIR)/upsdrvctl.Po ./$(DEPDIR)/upsdrvquery.Plo \ ./$(DEPDIR)/usb-common.Po ./$(DEPDIR)/usbhid-ups.Po \ ./$(DEPDIR)/victronups.Po am__mv = mv -f COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ $(AM_CFLAGS) $(CFLAGS) AM_V_CC = $(am__v_CC_@AM_V@) am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@) am__v_CC_0 = @echo " CC " $@; am__v_CC_1 = CCLD = $(CC) LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ $(AM_LDFLAGS) $(LDFLAGS) -o $@ AM_V_CCLD = $(am__v_CCLD_@AM_V@) am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@) am__v_CCLD_0 = @echo " CCLD " $@; am__v_CCLD_1 = SOURCES = $(libdummy_la_SOURCES) $(libdummy_mockdrv_la_SOURCES) \ $(libdummy_serial_la_SOURCES) \ $(libdummy_upsdrvquery_la_SOURCES) $(adelsystem_cbi_SOURCES) \ $(al175_SOURCES) $(apc_modbus_SOURCES) $(apcsmart_SOURCES) \ $(apcsmart_old_SOURCES) $(apcupsd_ups_SOURCES) $(asem_SOURCES) \ $(bcmxcp_SOURCES) $(bcmxcp_usb_SOURCES) $(belkin_SOURCES) \ $(belkinunv_SOURCES) $(bestfcom_SOURCES) \ $(bestfortress_SOURCES) $(bestuferrups_SOURCES) \ $(bestups_SOURCES) $(blazer_ser_SOURCES) $(blazer_usb_SOURCES) \ $(clone_SOURCES) $(clone_outlet_SOURCES) $(dummy_ups_SOURCES) \ $(etapro_SOURCES) $(everups_SOURCES) $(gamatronic_SOURCES) \ $(generic_gpio_libgpiod_SOURCES) $(generic_modbus_SOURCES) \ $(genericups_SOURCES) $(huawei_ups2000_SOURCES) \ $(isbmex_SOURCES) $(ivtscd_SOURCES) $(liebert_SOURCES) \ $(liebert_esp2_SOURCES) $(macosx_ups_SOURCES) \ $(masterguard_SOURCES) $(metasys_SOURCES) $(mge_shut_SOURCES) \ $(mge_utalk_SOURCES) $(microdowell_SOURCES) \ $(microsol_apc_SOURCES) $(netxml_ups_SOURCES) \ $(nut_ipmipsu_SOURCES) $(nutdrv_atcl_usb_SOURCES) \ $(nutdrv_qx_SOURCES) $(nutdrv_siemens_sitop_SOURCES) \ $(oneac_SOURCES) $(optiups_SOURCES) \ $(phoenixcontact_modbus_SOURCES) $(pijuice_SOURCES) \ $(powercom_SOURCES) $(powerman_pdu_SOURCES) \ $(powerpanel_SOURCES) $(rhino_SOURCES) $(richcomm_usb_SOURCES) \ $(riello_ser_SOURCES) $(riello_usb_SOURCES) $(safenet_SOURCES) \ $(skel_SOURCES) $(sms_ser_SOURCES) $(snmp_ups_SOURCES) \ $(socomec_jbus_SOURCES) $(solis_SOURCES) $(tripplite_SOURCES) \ $(tripplite_usb_SOURCES) $(tripplitesu_SOURCES) \ $(upscode2_SOURCES) $(upsdrvctl_SOURCES) $(usbhid_ups_SOURCES) \ $(victronups_SOURCES) DIST_SOURCES = $(libdummy_la_SOURCES) $(libdummy_mockdrv_la_SOURCES) \ $(libdummy_serial_la_SOURCES) \ $(libdummy_upsdrvquery_la_SOURCES) $(adelsystem_cbi_SOURCES) \ $(al175_SOURCES) $(am__apc_modbus_SOURCES_DIST) \ $(apcsmart_SOURCES) $(apcsmart_old_SOURCES) \ $(apcupsd_ups_SOURCES) $(asem_SOURCES) $(bcmxcp_SOURCES) \ $(bcmxcp_usb_SOURCES) $(belkin_SOURCES) $(belkinunv_SOURCES) \ $(bestfcom_SOURCES) $(bestfortress_SOURCES) \ $(bestuferrups_SOURCES) $(bestups_SOURCES) \ $(blazer_ser_SOURCES) $(am__blazer_usb_SOURCES_DIST) \ $(clone_SOURCES) $(clone_outlet_SOURCES) $(dummy_ups_SOURCES) \ $(etapro_SOURCES) $(everups_SOURCES) $(gamatronic_SOURCES) \ $(generic_gpio_libgpiod_SOURCES) $(generic_modbus_SOURCES) \ $(genericups_SOURCES) $(huawei_ups2000_SOURCES) \ $(isbmex_SOURCES) $(ivtscd_SOURCES) $(liebert_SOURCES) \ $(liebert_esp2_SOURCES) $(macosx_ups_SOURCES) \ $(masterguard_SOURCES) $(metasys_SOURCES) $(mge_shut_SOURCES) \ $(mge_utalk_SOURCES) $(microdowell_SOURCES) \ $(microsol_apc_SOURCES) $(netxml_ups_SOURCES) \ $(am__nut_ipmipsu_SOURCES_DIST) $(nutdrv_atcl_usb_SOURCES) \ $(am__nutdrv_qx_SOURCES_DIST) $(nutdrv_siemens_sitop_SOURCES) \ $(oneac_SOURCES) $(optiups_SOURCES) \ $(phoenixcontact_modbus_SOURCES) $(pijuice_SOURCES) \ $(powercom_SOURCES) $(powerman_pdu_SOURCES) \ $(powerpanel_SOURCES) $(rhino_SOURCES) \ $(am__richcomm_usb_SOURCES_DIST) $(riello_ser_SOURCES) \ $(am__riello_usb_SOURCES_DIST) $(safenet_SOURCES) \ $(skel_SOURCES) $(sms_ser_SOURCES) $(snmp_ups_SOURCES) \ $(socomec_jbus_SOURCES) $(solis_SOURCES) $(tripplite_SOURCES) \ $(am__tripplite_usb_SOURCES_DIST) $(tripplitesu_SOURCES) \ $(upscode2_SOURCES) $(upsdrvctl_SOURCES) \ $(am__usbhid_ups_SOURCES_DIST) $(victronups_SOURCES) am__can_run_installinfo = \ case $$AM_UPDATE_INFO_DIR in \ n|no|NO) false;; \ *) (install-info --version) >/dev/null 2>&1;; \ esac HEADERS = $(dist_noinst_HEADERS) am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) # Read a list of newline-separated strings from the standard input, # and print each of them once, without duplicates. Input order is # *not* preserved. am__uniquify_input = $(AWK) '\ BEGIN { nonempty = 0; } \ { items[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in items) print i; }; } \ ' # Make sure the list of sources is unique. This is necessary because, # e.g., the same source file might be shared among _SOURCES variables # for different programs/libraries. am__define_uniq_tagged_files = \ list='$(am__tagged_files)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | $(am__uniquify_input)` am__DIST_COMMON = $(srcdir)/Makefile.in $(top_srcdir)/depcomp DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) A2X = @A2X@ ACLOCAL = @ACLOCAL@ ALTPIDPATH = @ALTPIDPATH@ AMTAR = @AMTAR@ AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ AR = @AR@ ASCIIDOC = @ASCIIDOC@ ASPELL = @ASPELL@ ASPELL_FILTER_LIB_PATH = @ASPELL_FILTER_LIB_PATH@ ASPELL_FILTER_SHARE_PATH = @ASPELL_FILTER_SHARE_PATH@ ASPELL_FILTER_TEX_PATH = @ASPELL_FILTER_TEX_PATH@ AUGPARSE = @AUGPARSE@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ BINDIR = @BINDIR@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CONFIG_FLAGS = @CONFIG_FLAGS@ CONFPATH = @CONFPATH@ CPP = @CPP@ CPPCHECK = @CPPCHECK@ CPPFLAGS = @CPPFLAGS@ CPPUNIT_CFLAGS = @CPPUNIT_CFLAGS@ CPPUNIT_LIBS = @CPPUNIT_LIBS@ CSCOPE = @CSCOPE@ CTAGS = @CTAGS@ CXX = @CXX@ CXXCPP = @CXXCPP@ CXXDEPMODE = @CXXDEPMODE@ CXXFLAGS = @CXXFLAGS@ CYGPATH_W = @CYGPATH_W@ DBLATEX = @DBLATEX@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ DEPLOYED_UPSC = @DEPLOYED_UPSC@ DEPLOYED_UPSD = @DEPLOYED_UPSD@ DLLTOOL = @DLLTOOL@ DOC_BUILD_LIST = @DOC_BUILD_LIST@ DOC_CHECK_LIST = @DOC_CHECK_LIST@ DRIVER_BUILD_LIST = @DRIVER_BUILD_LIST@ DRIVER_INSTALL_TARGET = @DRIVER_INSTALL_TARGET@ DRIVER_MAN_LIST = @DRIVER_MAN_LIST@ DRIVER_MAN_LIST_PAGES = @DRIVER_MAN_LIST_PAGES@ DRVPATH = @DRVPATH@ DSYMUTIL = @DSYMUTIL@ DUMPBIN = @DUMPBIN@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ ETAGS = @ETAGS@ EXEEXT = @EXEEXT@ FGREP = @FGREP@ FORCE_NUT_VERSION = @FORCE_NUT_VERSION@ GDLIB_CONFIG = @GDLIB_CONFIG@ GREP = @GREP@ HAVE_SYS_SOCKET_H = @HAVE_SYS_SOCKET_H@ HAVE_WINSOCK2_H = @HAVE_WINSOCK2_H@ HAVE_WS2TCPIP_H = @HAVE_WS2TCPIP_H@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ LD = @LD@ LDFLAGS = @LDFLAGS@ LIBAVAHI_CFLAGS = @LIBAVAHI_CFLAGS@ LIBAVAHI_LIBS = @LIBAVAHI_LIBS@ LIBDIR = @LIBDIR@ LIBGD_CFLAGS = @LIBGD_CFLAGS@ LIBGD_LDFLAGS = @LIBGD_LDFLAGS@ LIBGPIO_CFLAGS = @LIBGPIO_CFLAGS@ LIBGPIO_LIBS = @LIBGPIO_LIBS@ LIBI2C_LIBS = @LIBI2C_LIBS@ LIBIPMI_CFLAGS = @LIBIPMI_CFLAGS@ LIBIPMI_LIBS = @LIBIPMI_LIBS@ LIBLTDL_CFLAGS = @LIBLTDL_CFLAGS@ LIBLTDL_LIBS = @LIBLTDL_LIBS@ LIBMODBUS_CFLAGS = @LIBMODBUS_CFLAGS@ LIBMODBUS_LIBS = @LIBMODBUS_LIBS@ LIBNEON_CFLAGS = @LIBNEON_CFLAGS@ LIBNEON_LIBS = @LIBNEON_LIBS@ LIBNETSNMP_CFLAGS = @LIBNETSNMP_CFLAGS@ LIBNETSNMP_LIBS = @LIBNETSNMP_LIBS@ LIBOBJS = @LIBOBJS@ LIBPOWERMAN_CFLAGS = @LIBPOWERMAN_CFLAGS@ LIBPOWERMAN_LIBS = @LIBPOWERMAN_LIBS@ LIBREGEX_LIBS = @LIBREGEX_LIBS@ LIBS = @LIBS@ LIBSSL_CFLAGS = @LIBSSL_CFLAGS@ LIBSSL_LIBS = @LIBSSL_LIBS@ LIBSSL_REQUIRES = @LIBSSL_REQUIRES@ LIBSYSTEMD_CFLAGS = @LIBSYSTEMD_CFLAGS@ LIBSYSTEMD_LIBS = @LIBSYSTEMD_LIBS@ LIBTOOL = @LIBTOOL@ LIBTOOL_DEPS = @LIBTOOL_DEPS@ LIBUSB_CFLAGS = @LIBUSB_CFLAGS@ LIBUSB_CONFIG = @LIBUSB_CONFIG@ LIBUSB_LIBS = @LIBUSB_LIBS@ LIBWRAP_CFLAGS = @LIBWRAP_CFLAGS@ LIBWRAP_LIBS = @LIBWRAP_LIBS@ LIPO = @LIPO@ LN_S = @LN_S@ LN_S_R = @LN_S_R@ LTLIBOBJS = @LTLIBOBJS@ LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@ MAINT = @MAINT@ MAKEINFO = @MAKEINFO@ MANIFEST_TOOL = @MANIFEST_TOOL@ MKDIR_P = @MKDIR_P@ MSGFMT = @MSGFMT@ NETLIBS = @NETLIBS@ NET_SNMP_CONFIG = @NET_SNMP_CONFIG@ NM = @NM@ NMEDIT = @NMEDIT@ NUT_DATADIR = @NUT_DATADIR@ NUT_LIBEXECDIR = @NUT_LIBEXECDIR@ NUT_NETVERSION = @NUT_NETVERSION@ NUT_SOURCE_GITREV = @NUT_SOURCE_GITREV@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ OS_NAME = @OS_NAME@ OTOOL = @OTOOL@ OTOOL64 = @OTOOL64@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_SEPARATOR = @PATH_SEPARATOR@ PIDPATH = @PIDPATH@ PKGCONFIGDIR = @PKGCONFIGDIR@ PKG_CONFIG = @PKG_CONFIG@ PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@ PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ PORT = @PORT@ POWERDOWNFLAG = @POWERDOWNFLAG@ PREFIX = @PREFIX@ PYTHON = @PYTHON@ PYTHON2 = @PYTHON2@ PYTHON2_SITE_PACKAGES = @PYTHON2_SITE_PACKAGES@ PYTHON3 = @PYTHON3@ PYTHON3_SITE_PACKAGES = @PYTHON3_SITE_PACKAGES@ PYTHON_SITE_PACKAGES = @PYTHON_SITE_PACKAGES@ RANLIB = @RANLIB@ REALPATH = @REALPATH@ RUN_AS_GROUP = @RUN_AS_GROUP@ RUN_AS_USER = @RUN_AS_USER@ SBINDIR = @SBINDIR@ SED = @SED@ SEMLIBS = @SEMLIBS@ SERLIBS = @SERLIBS@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ SOURCE_HIGHLIGHT = @SOURCE_HIGHLIGHT@ STATEPATH = @STATEPATH@ STRIP = @STRIP@ SUN_LIBUSB = @SUN_LIBUSB@ SYSTEMD_ANALYZE_PROGRAM = @SYSTEMD_ANALYZE_PROGRAM@ SYSTEMD_DAEMON_ARGS_DRIVER = @SYSTEMD_DAEMON_ARGS_DRIVER@ SYSTEMD_DAEMON_ARGS_UPSD = @SYSTEMD_DAEMON_ARGS_UPSD@ SYSTEMD_DAEMON_ARGS_UPSMON = @SYSTEMD_DAEMON_ARGS_UPSMON@ SYSTEMD_DAEMON_NOTIFYACCESS_DRIVER = @SYSTEMD_DAEMON_NOTIFYACCESS_DRIVER@ SYSTEMD_DAEMON_NOTIFYACCESS_UPSD = @SYSTEMD_DAEMON_NOTIFYACCESS_UPSD@ SYSTEMD_DAEMON_NOTIFYACCESS_UPSMON = @SYSTEMD_DAEMON_NOTIFYACCESS_UPSMON@ SYSTEMD_DAEMON_TYPE_DRIVER = @SYSTEMD_DAEMON_TYPE_DRIVER@ SYSTEMD_DAEMON_TYPE_UPSD = @SYSTEMD_DAEMON_TYPE_UPSD@ SYSTEMD_DAEMON_TYPE_UPSMON = @SYSTEMD_DAEMON_TYPE_UPSMON@ SYSTEMD_DAEMON_WATCHDOG_DRIVER = @SYSTEMD_DAEMON_WATCHDOG_DRIVER@ SYSTEMD_DAEMON_WATCHDOG_UPSD = @SYSTEMD_DAEMON_WATCHDOG_UPSD@ SYSTEMD_DAEMON_WATCHDOG_UPSMON = @SYSTEMD_DAEMON_WATCHDOG_UPSMON@ SYSTEMD_TMPFILES_PROGRAM = @SYSTEMD_TMPFILES_PROGRAM@ TREE_VERSION = @TREE_VERSION@ VALGRIND = @VALGRIND@ VERSION = @VERSION@ WINDMC = @WINDMC@ WINDRES = @WINDRES@ WORDS_BIGENDIAN = @WORDS_BIGENDIAN@ XMLLINT = @XMLLINT@ XSLTPROC = @XSLTPROC@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_AR = @ac_ct_AR@ ac_ct_CC = @ac_ct_CC@ ac_ct_CXX = @ac_ct_CXX@ ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__tar = @am__tar@ am__untar = @am__untar@ auglensdir = @auglensdir@ bindir = @bindir@ build = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ cgiexecdir = @cgiexecdir@ datadir = @datadir@ datarootdir = @datarootdir@ devddir = @devddir@ docdir = @docdir@ driverexecdir = @driverexecdir@ dummy_PKG_CONFIG = @dummy_PKG_CONFIG@ dummy_PKG_CONFIG_CFLAGS = @dummy_PKG_CONFIG_CFLAGS@ dummy_PKG_CONFIG_LIBS = @dummy_PKG_CONFIG_LIBS@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ hotplugdir = @hotplugdir@ htmldir = @htmldir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libdir = @libdir@ libexecdir = @libexecdir@ localedir = @localedir@ localstatedir = @localstatedir@ mandir = @mandir@ mkdir_p = @mkdir_p@ now = @now@ nut_with_nut_monitor = @nut_with_nut_monitor@ nut_with_nut_monitor_desktop = @nut_with_nut_monitor_desktop@ nut_with_nut_monitor_dir = @nut_with_nut_monitor_dir@ nut_with_nut_monitor_py2gtk2 = @nut_with_nut_monitor_py2gtk2@ nut_with_nut_monitor_py3qt5 = @nut_with_nut_monitor_py3qt5@ nut_with_pynut = @nut_with_pynut@ nut_with_pynut_py = @nut_with_pynut_py@ nut_with_pynut_py2 = @nut_with_pynut_py2@ nut_with_pynut_py3 = @nut_with_pynut_py3@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ pkgconfigdir = @pkgconfigdir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ runstatedir = @runstatedir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ sysconfdir = @sysconfdir@ systemdshutdowndir = @systemdshutdowndir@ systemdsystemunitdir = @systemdsystemunitdir@ systemdtmpfilesdir = @systemdtmpfilesdir@ target = @target@ target_alias = @target_alias@ target_cpu = @target_cpu@ target_os = @target_os@ target_vendor = @target_vendor@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ udevdir = @udevdir@ # by default, link programs in this directory with libcommon.la # (libtool version of the static lib, in order to access LTLIBOBJS) #FIXME: SERLIBS is only useful for LDADD_DRIVERS_SERIAL not for LDADD_COMMON LDADD_COMMON = $(top_builddir)/common/libcommon.la $(top_builddir)/common/libparseconf.la LDADD_DRIVERS = libdummy.la libdummy_upsdrvquery.la $(LDADD_COMMON) LDADD_DRIVERS_SERIAL = libdummy_serial.la $(LDADD_DRIVERS) $(SERLIBS) # most targets are serial drivers, so make this the default LDADD = $(LDADD_DRIVERS_SERIAL) # Avoid per-target CFLAGS, because this will prevent re-use of object # files. In any case, CFLAGS are only -I options, so there is no harm, # but only add them if we really use the target. AM_CFLAGS = -I$(top_srcdir)/include $(am__append_1) $(am__append_2) \ $(am__append_3) $(am__append_4) $(am__append_5) \ $(am__append_6) $(am__append_7) NUTSW_DRIVERLIST = dummy-ups clone clone-outlet apcupsd-ups skel SERIAL_DRIVERLIST = al175 bcmxcp belkin belkinunv bestfcom \ bestfortress bestuferrups bestups etapro everups \ gamatronic genericups isbmex liebert liebert-esp2 masterguard metasys \ mge-utalk microdowell microsol-apc mge-shut oneac optiups powercom rhino \ safenet nutdrv_siemens-sitop solis tripplite tripplitesu upscode2 victronups powerpanel \ blazer_ser ivtscd apcsmart apcsmart-old riello_ser sms_ser SNMP_DRIVERLIST = snmp-ups USB_LIBUSB_DRIVERLIST = usbhid-ups bcmxcp_usb tripplite_usb \ blazer_usb richcomm_usb riello_usb \ nutdrv_atcl_usb USB_DRIVERLIST = $(USB_LIBUSB_DRIVERLIST) SERIAL_USB_DRIVERLIST = \ nutdrv_qx NEONXML_DRIVERLIST = netxml-ups MACOSX_DRIVERLIST = macosx-ups MODBUS_DRIVERLIST = phoenixcontact_modbus generic_modbus huawei-ups2000 socomec_jbus adelsystem_cbi apc_modbus LINUX_I2C_DRIVERLIST = asem pijuice POWERMAN_DRIVERLIST = powerman-pdu IPMI_DRIVERLIST = nut-ipmipsu GPIO_DRIVERLIST = generic_gpio_libgpiod # ========================================================================== # Driver build details # upsdrvctl: the all-singing all-dancing driver control program upsdrvctl_SOURCES = upsdrvctl.c upsdrvctl_LDADD = $(LDADD_COMMON) libdummy_upsdrvquery.la # serial drivers: all of them use standard LDADD and CFLAGS al175_SOURCES = al175.c apcsmart_SOURCES = apcsmart.c apcsmart_tabs.c apcsmart_LDADD = $(LDADD) $(LIBREGEX_LIBS) apcsmart_old_SOURCES = apcsmart-old.c bcmxcp_SOURCES = bcmxcp.c bcmxcp_ser.c bcmxcp_LDADD = $(LDADD) -lm belkin_SOURCES = belkin.c belkinunv_SOURCES = belkinunv.c bestfcom_SOURCES = bestfcom.c bestfortress_SOURCES = bestfortress.c bestuferrups_SOURCES = bestuferrups.c bestups_SOURCES = bestups.c blazer_ser_SOURCES = blazer.c blazer_ser.c blazer_ser_LDADD = $(LDADD) -lm etapro_SOURCES = etapro.c everups_SOURCES = everups.c gamatronic_SOURCES = gamatronic.c genericups_SOURCES = genericups.c isbmex_SOURCES = isbmex.c isbmex_LDADD = $(LDADD) -lm ivtscd_SOURCES = ivtscd.c liebert_SOURCES = liebert.c liebert_esp2_SOURCES = liebert-esp2.c masterguard_SOURCES = masterguard.c metasys_SOURCES = metasys.c metasys_LDADD = $(LDADD) -lm mge_utalk_SOURCES = mge-utalk.c microdowell_SOURCES = microdowell.c microsol_apc_SOURCES = microsol-apc.c microsol-common.c microsol_apc_LDADD = $(LDADD) -lm oneac_SOURCES = oneac.c optiups_SOURCES = optiups.c powercom_SOURCES = powercom.c powercom_LDADD = $(LDADD) -lm powerpanel_SOURCES = powerpanel.c powerp-bin.c powerp-txt.c powerpanel_LDADD = $(LDADD) -lm rhino_SOURCES = rhino.c rhino_LDADD = $(LDADD) -lm safenet_SOURCES = safenet.c nutdrv_siemens_sitop_SOURCES = nutdrv_siemens_sitop.c solis_SOURCES = solis.c solis_LDADD = $(LDADD) -lm tripplite_SOURCES = tripplite.c tripplite_LDADD = $(LDADD) -lm tripplitesu_SOURCES = tripplitesu.c upscode2_SOURCES = upscode2.c upscode2_LDADD = $(LDADD) -lm victronups_SOURCES = victronups.c riello_ser_SOURCES = riello.c riello_ser.c riello_ser_LDADD = $(LDADD) -lm sms_ser_SOURCES = sms_ser.c sms_ser_LDADD = $(LDADD) -lm # non-serial drivers: these use custom LDADD and/or CFLAGS # dummy (in NUTSW_DRIVERLIST) dummy_ups_SOURCES = dummy-ups.c dummy_ups_CFLAGS = $(AM_CFLAGS) -I$(top_srcdir)/clients \ $(am__append_19) dummy_ups_LDADD = $(LDADD_DRIVERS) \ $(top_builddir)/clients/libupsclient.la $(am__append_20) # Clone drivers (in NUTSW_DRIVERLIST) clone_SOURCES = clone.c clone_outlet_SOURCES = clone-outlet.c # apcupsd client driver (in NUTSW_DRIVERLIST) apcupsd_ups_SOURCES = apcupsd-ups.c apcupsd_ups_CFLAGS = $(AM_CFLAGS) apcupsd_ups_LDADD = $(LDADD_DRIVERS) # sample skeleton driver (in NUTSW_DRIVERLIST) skel_SOURCES = skel.c skel_LDADD = $(LDADD_DRIVERS) # USB @WITH_LIBUSB_0_1_TRUE@LIBUSB_IMPL = libusb0.c @WITH_LIBUSB_1_0_TRUE@LIBUSB_IMPL = libusb1.c USBHID_UPS_SUBDRIVERS = apc-hid.c arduino-hid.c belkin-hid.c cps-hid.c explore-hid.c \ liebert-hid.c mge-hid.c powercom-hid.c tripplite-hid.c idowell-hid.c \ openups-hid.c powervar-hid.c delta_ups-hid.c ever-hid.c legrand-hid.c salicru-hid.c usbhid_ups_SOURCES = usbhid-ups.c libhid.c $(LIBUSB_IMPL) hidparser.c \ usb-common.c $(USBHID_UPS_SUBDRIVERS) usbhid_ups_LDADD = $(LDADD_DRIVERS) $(LIBUSB_LIBS) -lm tripplite_usb_SOURCES = tripplite_usb.c $(LIBUSB_IMPL) usb-common.c tripplite_usb_LDADD = $(LDADD_DRIVERS) $(LIBUSB_LIBS) -lm bcmxcp_usb_SOURCES = bcmxcp_usb.c bcmxcp.c usb-common.c bcmxcp_usb_LDADD = $(LDADD_DRIVERS) $(LIBUSB_LIBS) -lm blazer_usb_SOURCES = blazer.c blazer_usb.c $(LIBUSB_IMPL) usb-common.c blazer_usb_LDADD = $(LDADD_DRIVERS) $(LIBUSB_LIBS) -lm nutdrv_atcl_usb_SOURCES = nutdrv_atcl_usb.c usb-common.c nutdrv_atcl_usb_LDADD = $(LDADD_DRIVERS) $(LIBUSB_LIBS) richcomm_usb_SOURCES = richcomm_usb.c $(LIBUSB_IMPL) usb-common.c richcomm_usb_LDADD = $(LDADD_DRIVERS) $(LIBUSB_LIBS) riello_usb_SOURCES = riello.c riello_usb.c $(LIBUSB_IMPL) usb-common.c riello_usb_LDADD = $(LDADD_DRIVERS) $(LIBUSB_LIBS) -lm # HID-over-serial mge_shut_SOURCES = usbhid-ups.c libshut.c libhid.c hidparser.c mge-hid.c # per-target CFLAGS are necessary here mge_shut_CFLAGS = $(AM_CFLAGS) -DSHUT_MODE=1 mge_shut_LDADD = $(LDADD) -lm # SNMP # Please keep the MIB table below sorted roughly alphabetically (incidentally # by vendor too) to ease maintenance and codebase fork resynchronisations snmp_ups_SOURCES = snmp-ups.c snmp-ups-helpers.c \ apc-mib.c apc-pdu-mib.c apc-epdu-mib.c \ baytech-mib.c bestpower-mib.c \ compaq-mib.c cyberpower-mib.c \ delta_ups-mib.c \ eaton-pdu-genesis2-mib.c eaton-pdu-marlin-mib.c eaton-pdu-marlin-helpers.c \ eaton-pdu-pulizzi-mib.c eaton-pdu-revelation-mib.c eaton-pdu-nlogic-mib.c \ eaton-ats16-nmc-mib.c eaton-ats16-nm2-mib.c apc-ats-mib.c eaton-ats30-mib.c \ eaton-ups-pwnm2-mib.c eaton-ups-pxg-mib.c \ emerson-avocent-pdu-mib.c \ hpe-pdu-mib.c hpe-pdu3-cis-mib.c huawei-mib.c \ ietf-mib.c \ mge-mib.c \ netvision-mib.c \ raritan-pdu-mib.c raritan-px2-mib.c \ xppc-mib.c snmp_ups_CFLAGS = $(AM_CFLAGS) $(LIBNETSNMP_CFLAGS) snmp_ups_LDADD = $(LDADD_DRIVERS) $(LIBNETSNMP_LIBS) -lm # NEON XML/HTTP netxml_ups_SOURCES = netxml-ups.c mge-xml.c netxml_ups_LDADD = $(LDADD_DRIVERS) $(LIBNEON_LIBS) # Powerman powerman_pdu_SOURCES = powerman-pdu.c powerman_pdu_LDADD = $(LDADD) $(LIBPOWERMAN_LIBS) # IPMI PSU nut_ipmipsu_SOURCES = nut-ipmipsu.c $(am__append_21) # FIXME: Hacky hot-fix for build agents of varying OS generations: # Different versions of IPMI libs requested 'unsigned int *' or 'int *' args: #nut_ipmipsu_CFLAGS = $(AM_CFLAGS) -Wno-pointer-sign nut_ipmipsu_LDADD = $(LDADD) $(LIBIPMI_LIBS) # Mac OS X metadriver macosx_ups_LDADD = $(LDADD_DRIVERS) macosx_ups_LDFLAGS = $(LDFLAGS) -framework IOKit -framework CoreFoundation macosx_ups_SOURCES = macosx-ups.c # Modbus drivers phoenixcontact_modbus_SOURCES = phoenixcontact_modbus.c phoenixcontact_modbus_LDADD = $(LDADD_DRIVERS) $(LIBMODBUS_LIBS) generic_modbus_SOURCES = generic_modbus.c generic_modbus_LDADD = $(LDADD_DRIVERS) $(LIBMODBUS_LIBS) adelsystem_cbi_SOURCES = adelsystem_cbi.c adelsystem_cbi_LDADD = $(LDADD_DRIVERS) $(LIBMODBUS_LIBS) apc_modbus_SOURCES = apc_modbus.c $(LIBUSB_IMPL) hidparser.c usb-common.c apc_modbus_LDADD = $(LDADD_DRIVERS) $(LIBMODBUS_LIBS) $(LIBUSB_LIBS) # Huawei UPS2000 driver # (this is both a Modbus and a serial driver) huawei_ups2000_SOURCES = huawei-ups2000.c huawei_ups2000_LDADD = $(LDADD_DRIVERS_SERIAL) $(LIBMODBUS_LIBS) # Socomec JBUS driver # (this is a Modbus driver) socomec_jbus_SOURCES = socomec_jbus.c socomec_jbus_LDADD = $(LDADD_DRIVERS_SERIAL) $(LIBMODBUS_LIBS) # Linux I2C drivers asem_LDADD = $(LDADD_DRIVERS) $(LIBI2C_LIBS) asem_SOURCES = asem.c pijuice_LDADD = $(LDADD_DRIVERS) $(LIBI2C_LIBS) pijuice_SOURCES = pijuice.c # GPIO drivers generic_gpio_libgpiod_SOURCES = generic_gpio_common.c generic_gpio_libgpiod.c generic_gpio_libgpiod_LDADD = $(LDADD_DRIVERS) $(LIBGPIO_LIBS) # nutdrv_qx USB/Serial nutdrv_qx_SOURCES = nutdrv_qx.c $(am__append_25) \ $(NUTDRV_QX_SUBDRIVERS) nutdrv_qx_LDADD = $(LDADD_DRIVERS) -lm $(am__append_23) \ $(am__append_26) nutdrv_qx_CFLAGS = $(AM_CFLAGS) $(am__append_22) $(am__append_24) NUTDRV_QX_SUBDRIVERS = nutdrv_qx_bestups.c nutdrv_qx_blazer-common.c \ nutdrv_qx_masterguard.c \ nutdrv_qx_mecer.c nutdrv_qx_megatec.c nutdrv_qx_megatec-old.c \ nutdrv_qx_mustek.c nutdrv_qx_q1.c nutdrv_qx_voltronic.c \ nutdrv_qx_voltronic-qs.c nutdrv_qx_voltronic-qs-hex.c nutdrv_qx_zinto.c \ nutdrv_qx_hunnox.c nutdrv_qx_ablerex.c # ---------------------------------------------------------------------- # List of header files. The purpose of this list is not dependency # tracking (which is automatic), but to ensure these files are # distributed by "make dist". dist_noinst_HEADERS = apc-mib.h apc-iem-mib.h apc-hid.h arduino-hid.h baytech-mib.h bcmxcp.h bcmxcp_ser.h \ bcmxcp_io.h belkin.h belkin-hid.h bestpower-mib.h blazer.h cps-hid.h dstate.h \ dummy-ups.h explore-hid.h gamatronic.h genericups.h \ generic_gpio_common.h generic_gpio_libgpiod.h \ hidparser.h hidtypes.h ietf-mib.h libhid.h libshut.h nut_libusb.h liebert-hid.h \ main.h mge-hid.h mge-mib.h mge-utalk.h \ mge-xml.h microdowell.h microsol-apc.h microsol-common.h netvision-mib.h netxml-ups.h nut-ipmi.h oneac.h \ powercom.h powerpanel.h powerp-bin.h powerp-txt.h raritan-pdu-mib.h \ safenet.h serial.h sms_ser.h snmp-ups.h solis.h tripplite.h tripplite-hid.h \ upshandler.h usb-common.h usbhid-ups.h powercom-hid.h compaq-mib.h idowell-hid.h \ apcsmart.h apcsmart_tabs.h apcsmart-old.h apcupsd-ups.h cyberpower-mib.h riello.h openups-hid.h \ delta_ups-mib.h nutdrv_qx.h nutdrv_qx_bestups.h nutdrv_qx_blazer-common.h \ nutdrv_qx_masterguard.h \ nutdrv_qx_mecer.h nutdrv_qx_ablerex.h \ nutdrv_qx_megatec.h nutdrv_qx_megatec-old.h nutdrv_qx_mustek.h nutdrv_qx_q1.h nutdrv_qx_hunnox.h \ nutdrv_qx_voltronic.h nutdrv_qx_voltronic-qs.h nutdrv_qx_voltronic-qs-hex.h nutdrv_qx_zinto.h \ upsdrvquery.h \ xppc-mib.h huawei-mib.h eaton-ats16-nmc-mib.h eaton-ats16-nm2-mib.h apc-ats-mib.h raritan-px2-mib.h eaton-ats30-mib.h \ apc-pdu-mib.h apc-epdu-mib.h ever-hid.h eaton-pdu-genesis2-mib.h eaton-pdu-marlin-mib.h eaton-pdu-marlin-helpers.h \ eaton-pdu-pulizzi-mib.h eaton-pdu-revelation-mib.h emerson-avocent-pdu-mib.h eaton-ups-pwnm2-mib.h eaton-ups-pxg-mib.h legrand-hid.h \ hpe-pdu-mib.h hpe-pdu3-cis-mib.h powervar-hid.h delta_ups-hid.h generic_modbus.h salicru-hid.h adelsystem_cbi.h eaton-pdu-nlogic-mib.h # Define a dummy library so that Automake builds rules for the # corresponding object files. This library is not actually built, # as a final product. It was necessary for Automake-technical reasons, # because per-object CFLAGS can only be specified for libraries, not # for object files. This library is used during the build process, # and is not meant to be installed. # The libdummy_mockdrv.la is used for unit-tests to mock a driver # with near-production codebase but without its standard main(). # Otherwise, also not meant to be installed. EXTRA_LTLIBRARIES = libdummy.la libdummy_serial.la \ libdummy_upsdrvquery.la libdummy_mockdrv.la libdummy_la_SOURCES = main.c dstate.c libdummy_la_LDFLAGS = -no-undefined -static libdummy_serial_la_SOURCES = serial.c libdummy_serial_la_LDFLAGS = -no-undefined -static libdummy_upsdrvquery_la_SOURCES = upsdrvquery.c libdummy_upsdrvquery_la_LDFLAGS = -no-undefined -static libdummy_mockdrv_la_SOURCES = main.c dstate.c libdummy_mockdrv_la_CFLAGS = $(AM_CFLAGS) -DDRIVERS_MAIN_WITHOUT_MAIN=1 libdummy_mockdrv_la_LDFLAGS = -static $(top_builddir)/common/libcommon.la $(top_builddir)/common/libparseconf.la CLEANFILES = $(EXTRA_LTLIBRARIES) $(EXTRA_PROGRAMS) MAINTAINERCLEANFILES = Makefile.in .dirstamp all: all-am .SUFFIXES: .SUFFIXES: .c .lo .o .obj $(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu drivers/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --gnu drivers/Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): install-driverexecPROGRAMS: $(driverexec_PROGRAMS) @$(NORMAL_INSTALL) @list='$(driverexec_PROGRAMS)'; test -n "$(driverexecdir)" || list=; \ if test -n "$$list"; then \ echo " $(MKDIR_P) '$(DESTDIR)$(driverexecdir)'"; \ $(MKDIR_P) "$(DESTDIR)$(driverexecdir)" || exit 1; \ fi; \ for p in $$list; do echo "$$p $$p"; done | \ sed 's/$(EXEEXT)$$//' | \ while read p p1; do if test -f $$p \ || test -f $$p1 \ ; then echo "$$p"; echo "$$p"; else :; fi; \ done | \ sed -e 'p;s,.*/,,;n;h' \ -e 's|.*|.|' \ -e 'p;x;s,.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/' | \ sed 'N;N;N;s,\n, ,g' | \ $(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1 } \ { d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \ if ($$2 == $$4) files[d] = files[d] " " $$1; \ else { print "f", $$3 "/" $$4, $$1; } } \ END { for (d in files) print "f", d, files[d] }' | \ while read type dir files; do \ if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \ test -z "$$files" || { \ echo " $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files '$(DESTDIR)$(driverexecdir)$$dir'"; \ $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files "$(DESTDIR)$(driverexecdir)$$dir" || exit $$?; \ } \ ; done uninstall-driverexecPROGRAMS: @$(NORMAL_UNINSTALL) @list='$(driverexec_PROGRAMS)'; test -n "$(driverexecdir)" || list=; \ files=`for p in $$list; do echo "$$p"; done | \ sed -e 'h;s,^.*/,,;s/$(EXEEXT)$$//;$(transform)' \ -e 's/$$/$(EXEEXT)/' \ `; \ test -n "$$list" || exit 0; \ echo " ( cd '$(DESTDIR)$(driverexecdir)' && rm -f" $$files ")"; \ cd "$(DESTDIR)$(driverexecdir)" && rm -f $$files clean-driverexecPROGRAMS: @list='$(driverexec_PROGRAMS)'; test -n "$$list" || exit 0; \ echo " rm -f" $$list; \ rm -f $$list || exit $$?; \ test -n "$(EXEEXT)" || exit 0; \ list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \ echo " rm -f" $$list; \ rm -f $$list install-sbinPROGRAMS: $(sbin_PROGRAMS) @$(NORMAL_INSTALL) @list='$(sbin_PROGRAMS)'; test -n "$(sbindir)" || list=; \ if test -n "$$list"; then \ echo " $(MKDIR_P) '$(DESTDIR)$(sbindir)'"; \ $(MKDIR_P) "$(DESTDIR)$(sbindir)" || exit 1; \ fi; \ for p in $$list; do echo "$$p $$p"; done | \ sed 's/$(EXEEXT)$$//' | \ while read p p1; do if test -f $$p \ || test -f $$p1 \ ; then echo "$$p"; echo "$$p"; else :; fi; \ done | \ sed -e 'p;s,.*/,,;n;h' \ -e 's|.*|.|' \ -e 'p;x;s,.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/' | \ sed 'N;N;N;s,\n, ,g' | \ $(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1 } \ { d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \ if ($$2 == $$4) files[d] = files[d] " " $$1; \ else { print "f", $$3 "/" $$4, $$1; } } \ END { for (d in files) print "f", d, files[d] }' | \ while read type dir files; do \ if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \ test -z "$$files" || { \ echo " $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files '$(DESTDIR)$(sbindir)$$dir'"; \ $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files "$(DESTDIR)$(sbindir)$$dir" || exit $$?; \ } \ ; done uninstall-sbinPROGRAMS: @$(NORMAL_UNINSTALL) @list='$(sbin_PROGRAMS)'; test -n "$(sbindir)" || list=; \ files=`for p in $$list; do echo "$$p"; done | \ sed -e 'h;s,^.*/,,;s/$(EXEEXT)$$//;$(transform)' \ -e 's/$$/$(EXEEXT)/' \ `; \ test -n "$$list" || exit 0; \ echo " ( cd '$(DESTDIR)$(sbindir)' && rm -f" $$files ")"; \ cd "$(DESTDIR)$(sbindir)" && rm -f $$files clean-sbinPROGRAMS: @list='$(sbin_PROGRAMS)'; test -n "$$list" || exit 0; \ echo " rm -f" $$list; \ rm -f $$list || exit $$?; \ test -n "$(EXEEXT)" || exit 0; \ list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \ echo " rm -f" $$list; \ rm -f $$list libdummy.la: $(libdummy_la_OBJECTS) $(libdummy_la_DEPENDENCIES) $(EXTRA_libdummy_la_DEPENDENCIES) $(AM_V_CCLD)$(libdummy_la_LINK) $(libdummy_la_OBJECTS) $(libdummy_la_LIBADD) $(LIBS) libdummy_mockdrv.la: $(libdummy_mockdrv_la_OBJECTS) $(libdummy_mockdrv_la_DEPENDENCIES) $(EXTRA_libdummy_mockdrv_la_DEPENDENCIES) $(AM_V_CCLD)$(libdummy_mockdrv_la_LINK) $(libdummy_mockdrv_la_OBJECTS) $(libdummy_mockdrv_la_LIBADD) $(LIBS) libdummy_serial.la: $(libdummy_serial_la_OBJECTS) $(libdummy_serial_la_DEPENDENCIES) $(EXTRA_libdummy_serial_la_DEPENDENCIES) $(AM_V_CCLD)$(libdummy_serial_la_LINK) $(libdummy_serial_la_OBJECTS) $(libdummy_serial_la_LIBADD) $(LIBS) libdummy_upsdrvquery.la: $(libdummy_upsdrvquery_la_OBJECTS) $(libdummy_upsdrvquery_la_DEPENDENCIES) $(EXTRA_libdummy_upsdrvquery_la_DEPENDENCIES) $(AM_V_CCLD)$(libdummy_upsdrvquery_la_LINK) $(libdummy_upsdrvquery_la_OBJECTS) $(libdummy_upsdrvquery_la_LIBADD) $(LIBS) adelsystem_cbi$(EXEEXT): $(adelsystem_cbi_OBJECTS) $(adelsystem_cbi_DEPENDENCIES) $(EXTRA_adelsystem_cbi_DEPENDENCIES) @rm -f adelsystem_cbi$(EXEEXT) $(AM_V_CCLD)$(LINK) $(adelsystem_cbi_OBJECTS) $(adelsystem_cbi_LDADD) $(LIBS) al175$(EXEEXT): $(al175_OBJECTS) $(al175_DEPENDENCIES) $(EXTRA_al175_DEPENDENCIES) @rm -f al175$(EXEEXT) $(AM_V_CCLD)$(LINK) $(al175_OBJECTS) $(al175_LDADD) $(LIBS) apc_modbus$(EXEEXT): $(apc_modbus_OBJECTS) $(apc_modbus_DEPENDENCIES) $(EXTRA_apc_modbus_DEPENDENCIES) @rm -f apc_modbus$(EXEEXT) $(AM_V_CCLD)$(LINK) $(apc_modbus_OBJECTS) $(apc_modbus_LDADD) $(LIBS) apcsmart$(EXEEXT): $(apcsmart_OBJECTS) $(apcsmart_DEPENDENCIES) $(EXTRA_apcsmart_DEPENDENCIES) @rm -f apcsmart$(EXEEXT) $(AM_V_CCLD)$(LINK) $(apcsmart_OBJECTS) $(apcsmart_LDADD) $(LIBS) apcsmart-old$(EXEEXT): $(apcsmart_old_OBJECTS) $(apcsmart_old_DEPENDENCIES) $(EXTRA_apcsmart_old_DEPENDENCIES) @rm -f apcsmart-old$(EXEEXT) $(AM_V_CCLD)$(LINK) $(apcsmart_old_OBJECTS) $(apcsmart_old_LDADD) $(LIBS) apcupsd-ups$(EXEEXT): $(apcupsd_ups_OBJECTS) $(apcupsd_ups_DEPENDENCIES) $(EXTRA_apcupsd_ups_DEPENDENCIES) @rm -f apcupsd-ups$(EXEEXT) $(AM_V_CCLD)$(apcupsd_ups_LINK) $(apcupsd_ups_OBJECTS) $(apcupsd_ups_LDADD) $(LIBS) asem$(EXEEXT): $(asem_OBJECTS) $(asem_DEPENDENCIES) $(EXTRA_asem_DEPENDENCIES) @rm -f asem$(EXEEXT) $(AM_V_CCLD)$(LINK) $(asem_OBJECTS) $(asem_LDADD) $(LIBS) bcmxcp$(EXEEXT): $(bcmxcp_OBJECTS) $(bcmxcp_DEPENDENCIES) $(EXTRA_bcmxcp_DEPENDENCIES) @rm -f bcmxcp$(EXEEXT) $(AM_V_CCLD)$(LINK) $(bcmxcp_OBJECTS) $(bcmxcp_LDADD) $(LIBS) bcmxcp_usb$(EXEEXT): $(bcmxcp_usb_OBJECTS) $(bcmxcp_usb_DEPENDENCIES) $(EXTRA_bcmxcp_usb_DEPENDENCIES) @rm -f bcmxcp_usb$(EXEEXT) $(AM_V_CCLD)$(LINK) $(bcmxcp_usb_OBJECTS) $(bcmxcp_usb_LDADD) $(LIBS) belkin$(EXEEXT): $(belkin_OBJECTS) $(belkin_DEPENDENCIES) $(EXTRA_belkin_DEPENDENCIES) @rm -f belkin$(EXEEXT) $(AM_V_CCLD)$(LINK) $(belkin_OBJECTS) $(belkin_LDADD) $(LIBS) belkinunv$(EXEEXT): $(belkinunv_OBJECTS) $(belkinunv_DEPENDENCIES) $(EXTRA_belkinunv_DEPENDENCIES) @rm -f belkinunv$(EXEEXT) $(AM_V_CCLD)$(LINK) $(belkinunv_OBJECTS) $(belkinunv_LDADD) $(LIBS) bestfcom$(EXEEXT): $(bestfcom_OBJECTS) $(bestfcom_DEPENDENCIES) $(EXTRA_bestfcom_DEPENDENCIES) @rm -f bestfcom$(EXEEXT) $(AM_V_CCLD)$(LINK) $(bestfcom_OBJECTS) $(bestfcom_LDADD) $(LIBS) bestfortress$(EXEEXT): $(bestfortress_OBJECTS) $(bestfortress_DEPENDENCIES) $(EXTRA_bestfortress_DEPENDENCIES) @rm -f bestfortress$(EXEEXT) $(AM_V_CCLD)$(LINK) $(bestfortress_OBJECTS) $(bestfortress_LDADD) $(LIBS) bestuferrups$(EXEEXT): $(bestuferrups_OBJECTS) $(bestuferrups_DEPENDENCIES) $(EXTRA_bestuferrups_DEPENDENCIES) @rm -f bestuferrups$(EXEEXT) $(AM_V_CCLD)$(LINK) $(bestuferrups_OBJECTS) $(bestuferrups_LDADD) $(LIBS) bestups$(EXEEXT): $(bestups_OBJECTS) $(bestups_DEPENDENCIES) $(EXTRA_bestups_DEPENDENCIES) @rm -f bestups$(EXEEXT) $(AM_V_CCLD)$(LINK) $(bestups_OBJECTS) $(bestups_LDADD) $(LIBS) blazer_ser$(EXEEXT): $(blazer_ser_OBJECTS) $(blazer_ser_DEPENDENCIES) $(EXTRA_blazer_ser_DEPENDENCIES) @rm -f blazer_ser$(EXEEXT) $(AM_V_CCLD)$(LINK) $(blazer_ser_OBJECTS) $(blazer_ser_LDADD) $(LIBS) blazer_usb$(EXEEXT): $(blazer_usb_OBJECTS) $(blazer_usb_DEPENDENCIES) $(EXTRA_blazer_usb_DEPENDENCIES) @rm -f blazer_usb$(EXEEXT) $(AM_V_CCLD)$(LINK) $(blazer_usb_OBJECTS) $(blazer_usb_LDADD) $(LIBS) clone$(EXEEXT): $(clone_OBJECTS) $(clone_DEPENDENCIES) $(EXTRA_clone_DEPENDENCIES) @rm -f clone$(EXEEXT) $(AM_V_CCLD)$(LINK) $(clone_OBJECTS) $(clone_LDADD) $(LIBS) clone-outlet$(EXEEXT): $(clone_outlet_OBJECTS) $(clone_outlet_DEPENDENCIES) $(EXTRA_clone_outlet_DEPENDENCIES) @rm -f clone-outlet$(EXEEXT) $(AM_V_CCLD)$(LINK) $(clone_outlet_OBJECTS) $(clone_outlet_LDADD) $(LIBS) dummy-ups$(EXEEXT): $(dummy_ups_OBJECTS) $(dummy_ups_DEPENDENCIES) $(EXTRA_dummy_ups_DEPENDENCIES) @rm -f dummy-ups$(EXEEXT) $(AM_V_CCLD)$(dummy_ups_LINK) $(dummy_ups_OBJECTS) $(dummy_ups_LDADD) $(LIBS) etapro$(EXEEXT): $(etapro_OBJECTS) $(etapro_DEPENDENCIES) $(EXTRA_etapro_DEPENDENCIES) @rm -f etapro$(EXEEXT) $(AM_V_CCLD)$(LINK) $(etapro_OBJECTS) $(etapro_LDADD) $(LIBS) everups$(EXEEXT): $(everups_OBJECTS) $(everups_DEPENDENCIES) $(EXTRA_everups_DEPENDENCIES) @rm -f everups$(EXEEXT) $(AM_V_CCLD)$(LINK) $(everups_OBJECTS) $(everups_LDADD) $(LIBS) gamatronic$(EXEEXT): $(gamatronic_OBJECTS) $(gamatronic_DEPENDENCIES) $(EXTRA_gamatronic_DEPENDENCIES) @rm -f gamatronic$(EXEEXT) $(AM_V_CCLD)$(LINK) $(gamatronic_OBJECTS) $(gamatronic_LDADD) $(LIBS) generic_gpio_libgpiod$(EXEEXT): $(generic_gpio_libgpiod_OBJECTS) $(generic_gpio_libgpiod_DEPENDENCIES) $(EXTRA_generic_gpio_libgpiod_DEPENDENCIES) @rm -f generic_gpio_libgpiod$(EXEEXT) $(AM_V_CCLD)$(LINK) $(generic_gpio_libgpiod_OBJECTS) $(generic_gpio_libgpiod_LDADD) $(LIBS) generic_modbus$(EXEEXT): $(generic_modbus_OBJECTS) $(generic_modbus_DEPENDENCIES) $(EXTRA_generic_modbus_DEPENDENCIES) @rm -f generic_modbus$(EXEEXT) $(AM_V_CCLD)$(LINK) $(generic_modbus_OBJECTS) $(generic_modbus_LDADD) $(LIBS) genericups$(EXEEXT): $(genericups_OBJECTS) $(genericups_DEPENDENCIES) $(EXTRA_genericups_DEPENDENCIES) @rm -f genericups$(EXEEXT) $(AM_V_CCLD)$(LINK) $(genericups_OBJECTS) $(genericups_LDADD) $(LIBS) huawei-ups2000$(EXEEXT): $(huawei_ups2000_OBJECTS) $(huawei_ups2000_DEPENDENCIES) $(EXTRA_huawei_ups2000_DEPENDENCIES) @rm -f huawei-ups2000$(EXEEXT) $(AM_V_CCLD)$(LINK) $(huawei_ups2000_OBJECTS) $(huawei_ups2000_LDADD) $(LIBS) isbmex$(EXEEXT): $(isbmex_OBJECTS) $(isbmex_DEPENDENCIES) $(EXTRA_isbmex_DEPENDENCIES) @rm -f isbmex$(EXEEXT) $(AM_V_CCLD)$(LINK) $(isbmex_OBJECTS) $(isbmex_LDADD) $(LIBS) ivtscd$(EXEEXT): $(ivtscd_OBJECTS) $(ivtscd_DEPENDENCIES) $(EXTRA_ivtscd_DEPENDENCIES) @rm -f ivtscd$(EXEEXT) $(AM_V_CCLD)$(LINK) $(ivtscd_OBJECTS) $(ivtscd_LDADD) $(LIBS) liebert$(EXEEXT): $(liebert_OBJECTS) $(liebert_DEPENDENCIES) $(EXTRA_liebert_DEPENDENCIES) @rm -f liebert$(EXEEXT) $(AM_V_CCLD)$(LINK) $(liebert_OBJECTS) $(liebert_LDADD) $(LIBS) liebert-esp2$(EXEEXT): $(liebert_esp2_OBJECTS) $(liebert_esp2_DEPENDENCIES) $(EXTRA_liebert_esp2_DEPENDENCIES) @rm -f liebert-esp2$(EXEEXT) $(AM_V_CCLD)$(LINK) $(liebert_esp2_OBJECTS) $(liebert_esp2_LDADD) $(LIBS) macosx-ups$(EXEEXT): $(macosx_ups_OBJECTS) $(macosx_ups_DEPENDENCIES) $(EXTRA_macosx_ups_DEPENDENCIES) @rm -f macosx-ups$(EXEEXT) $(AM_V_CCLD)$(macosx_ups_LINK) $(macosx_ups_OBJECTS) $(macosx_ups_LDADD) $(LIBS) masterguard$(EXEEXT): $(masterguard_OBJECTS) $(masterguard_DEPENDENCIES) $(EXTRA_masterguard_DEPENDENCIES) @rm -f masterguard$(EXEEXT) $(AM_V_CCLD)$(LINK) $(masterguard_OBJECTS) $(masterguard_LDADD) $(LIBS) metasys$(EXEEXT): $(metasys_OBJECTS) $(metasys_DEPENDENCIES) $(EXTRA_metasys_DEPENDENCIES) @rm -f metasys$(EXEEXT) $(AM_V_CCLD)$(LINK) $(metasys_OBJECTS) $(metasys_LDADD) $(LIBS) mge-shut$(EXEEXT): $(mge_shut_OBJECTS) $(mge_shut_DEPENDENCIES) $(EXTRA_mge_shut_DEPENDENCIES) @rm -f mge-shut$(EXEEXT) $(AM_V_CCLD)$(mge_shut_LINK) $(mge_shut_OBJECTS) $(mge_shut_LDADD) $(LIBS) mge-utalk$(EXEEXT): $(mge_utalk_OBJECTS) $(mge_utalk_DEPENDENCIES) $(EXTRA_mge_utalk_DEPENDENCIES) @rm -f mge-utalk$(EXEEXT) $(AM_V_CCLD)$(LINK) $(mge_utalk_OBJECTS) $(mge_utalk_LDADD) $(LIBS) microdowell$(EXEEXT): $(microdowell_OBJECTS) $(microdowell_DEPENDENCIES) $(EXTRA_microdowell_DEPENDENCIES) @rm -f microdowell$(EXEEXT) $(AM_V_CCLD)$(LINK) $(microdowell_OBJECTS) $(microdowell_LDADD) $(LIBS) microsol-apc$(EXEEXT): $(microsol_apc_OBJECTS) $(microsol_apc_DEPENDENCIES) $(EXTRA_microsol_apc_DEPENDENCIES) @rm -f microsol-apc$(EXEEXT) $(AM_V_CCLD)$(LINK) $(microsol_apc_OBJECTS) $(microsol_apc_LDADD) $(LIBS) netxml-ups$(EXEEXT): $(netxml_ups_OBJECTS) $(netxml_ups_DEPENDENCIES) $(EXTRA_netxml_ups_DEPENDENCIES) @rm -f netxml-ups$(EXEEXT) $(AM_V_CCLD)$(LINK) $(netxml_ups_OBJECTS) $(netxml_ups_LDADD) $(LIBS) nut-ipmipsu$(EXEEXT): $(nut_ipmipsu_OBJECTS) $(nut_ipmipsu_DEPENDENCIES) $(EXTRA_nut_ipmipsu_DEPENDENCIES) @rm -f nut-ipmipsu$(EXEEXT) $(AM_V_CCLD)$(LINK) $(nut_ipmipsu_OBJECTS) $(nut_ipmipsu_LDADD) $(LIBS) nutdrv_atcl_usb$(EXEEXT): $(nutdrv_atcl_usb_OBJECTS) $(nutdrv_atcl_usb_DEPENDENCIES) $(EXTRA_nutdrv_atcl_usb_DEPENDENCIES) @rm -f nutdrv_atcl_usb$(EXEEXT) $(AM_V_CCLD)$(LINK) $(nutdrv_atcl_usb_OBJECTS) $(nutdrv_atcl_usb_LDADD) $(LIBS) nutdrv_qx$(EXEEXT): $(nutdrv_qx_OBJECTS) $(nutdrv_qx_DEPENDENCIES) $(EXTRA_nutdrv_qx_DEPENDENCIES) @rm -f nutdrv_qx$(EXEEXT) $(AM_V_CCLD)$(nutdrv_qx_LINK) $(nutdrv_qx_OBJECTS) $(nutdrv_qx_LDADD) $(LIBS) nutdrv_siemens-sitop$(EXEEXT): $(nutdrv_siemens_sitop_OBJECTS) $(nutdrv_siemens_sitop_DEPENDENCIES) $(EXTRA_nutdrv_siemens_sitop_DEPENDENCIES) @rm -f nutdrv_siemens-sitop$(EXEEXT) $(AM_V_CCLD)$(LINK) $(nutdrv_siemens_sitop_OBJECTS) $(nutdrv_siemens_sitop_LDADD) $(LIBS) oneac$(EXEEXT): $(oneac_OBJECTS) $(oneac_DEPENDENCIES) $(EXTRA_oneac_DEPENDENCIES) @rm -f oneac$(EXEEXT) $(AM_V_CCLD)$(LINK) $(oneac_OBJECTS) $(oneac_LDADD) $(LIBS) optiups$(EXEEXT): $(optiups_OBJECTS) $(optiups_DEPENDENCIES) $(EXTRA_optiups_DEPENDENCIES) @rm -f optiups$(EXEEXT) $(AM_V_CCLD)$(LINK) $(optiups_OBJECTS) $(optiups_LDADD) $(LIBS) phoenixcontact_modbus$(EXEEXT): $(phoenixcontact_modbus_OBJECTS) $(phoenixcontact_modbus_DEPENDENCIES) $(EXTRA_phoenixcontact_modbus_DEPENDENCIES) @rm -f phoenixcontact_modbus$(EXEEXT) $(AM_V_CCLD)$(LINK) $(phoenixcontact_modbus_OBJECTS) $(phoenixcontact_modbus_LDADD) $(LIBS) pijuice$(EXEEXT): $(pijuice_OBJECTS) $(pijuice_DEPENDENCIES) $(EXTRA_pijuice_DEPENDENCIES) @rm -f pijuice$(EXEEXT) $(AM_V_CCLD)$(LINK) $(pijuice_OBJECTS) $(pijuice_LDADD) $(LIBS) powercom$(EXEEXT): $(powercom_OBJECTS) $(powercom_DEPENDENCIES) $(EXTRA_powercom_DEPENDENCIES) @rm -f powercom$(EXEEXT) $(AM_V_CCLD)$(LINK) $(powercom_OBJECTS) $(powercom_LDADD) $(LIBS) powerman-pdu$(EXEEXT): $(powerman_pdu_OBJECTS) $(powerman_pdu_DEPENDENCIES) $(EXTRA_powerman_pdu_DEPENDENCIES) @rm -f powerman-pdu$(EXEEXT) $(AM_V_CCLD)$(LINK) $(powerman_pdu_OBJECTS) $(powerman_pdu_LDADD) $(LIBS) powerpanel$(EXEEXT): $(powerpanel_OBJECTS) $(powerpanel_DEPENDENCIES) $(EXTRA_powerpanel_DEPENDENCIES) @rm -f powerpanel$(EXEEXT) $(AM_V_CCLD)$(LINK) $(powerpanel_OBJECTS) $(powerpanel_LDADD) $(LIBS) rhino$(EXEEXT): $(rhino_OBJECTS) $(rhino_DEPENDENCIES) $(EXTRA_rhino_DEPENDENCIES) @rm -f rhino$(EXEEXT) $(AM_V_CCLD)$(LINK) $(rhino_OBJECTS) $(rhino_LDADD) $(LIBS) richcomm_usb$(EXEEXT): $(richcomm_usb_OBJECTS) $(richcomm_usb_DEPENDENCIES) $(EXTRA_richcomm_usb_DEPENDENCIES) @rm -f richcomm_usb$(EXEEXT) $(AM_V_CCLD)$(LINK) $(richcomm_usb_OBJECTS) $(richcomm_usb_LDADD) $(LIBS) riello_ser$(EXEEXT): $(riello_ser_OBJECTS) $(riello_ser_DEPENDENCIES) $(EXTRA_riello_ser_DEPENDENCIES) @rm -f riello_ser$(EXEEXT) $(AM_V_CCLD)$(LINK) $(riello_ser_OBJECTS) $(riello_ser_LDADD) $(LIBS) riello_usb$(EXEEXT): $(riello_usb_OBJECTS) $(riello_usb_DEPENDENCIES) $(EXTRA_riello_usb_DEPENDENCIES) @rm -f riello_usb$(EXEEXT) $(AM_V_CCLD)$(LINK) $(riello_usb_OBJECTS) $(riello_usb_LDADD) $(LIBS) safenet$(EXEEXT): $(safenet_OBJECTS) $(safenet_DEPENDENCIES) $(EXTRA_safenet_DEPENDENCIES) @rm -f safenet$(EXEEXT) $(AM_V_CCLD)$(LINK) $(safenet_OBJECTS) $(safenet_LDADD) $(LIBS) skel$(EXEEXT): $(skel_OBJECTS) $(skel_DEPENDENCIES) $(EXTRA_skel_DEPENDENCIES) @rm -f skel$(EXEEXT) $(AM_V_CCLD)$(LINK) $(skel_OBJECTS) $(skel_LDADD) $(LIBS) sms_ser$(EXEEXT): $(sms_ser_OBJECTS) $(sms_ser_DEPENDENCIES) $(EXTRA_sms_ser_DEPENDENCIES) @rm -f sms_ser$(EXEEXT) $(AM_V_CCLD)$(LINK) $(sms_ser_OBJECTS) $(sms_ser_LDADD) $(LIBS) snmp-ups$(EXEEXT): $(snmp_ups_OBJECTS) $(snmp_ups_DEPENDENCIES) $(EXTRA_snmp_ups_DEPENDENCIES) @rm -f snmp-ups$(EXEEXT) $(AM_V_CCLD)$(snmp_ups_LINK) $(snmp_ups_OBJECTS) $(snmp_ups_LDADD) $(LIBS) socomec_jbus$(EXEEXT): $(socomec_jbus_OBJECTS) $(socomec_jbus_DEPENDENCIES) $(EXTRA_socomec_jbus_DEPENDENCIES) @rm -f socomec_jbus$(EXEEXT) $(AM_V_CCLD)$(LINK) $(socomec_jbus_OBJECTS) $(socomec_jbus_LDADD) $(LIBS) solis$(EXEEXT): $(solis_OBJECTS) $(solis_DEPENDENCIES) $(EXTRA_solis_DEPENDENCIES) @rm -f solis$(EXEEXT) $(AM_V_CCLD)$(LINK) $(solis_OBJECTS) $(solis_LDADD) $(LIBS) tripplite$(EXEEXT): $(tripplite_OBJECTS) $(tripplite_DEPENDENCIES) $(EXTRA_tripplite_DEPENDENCIES) @rm -f tripplite$(EXEEXT) $(AM_V_CCLD)$(LINK) $(tripplite_OBJECTS) $(tripplite_LDADD) $(LIBS) tripplite_usb$(EXEEXT): $(tripplite_usb_OBJECTS) $(tripplite_usb_DEPENDENCIES) $(EXTRA_tripplite_usb_DEPENDENCIES) @rm -f tripplite_usb$(EXEEXT) $(AM_V_CCLD)$(LINK) $(tripplite_usb_OBJECTS) $(tripplite_usb_LDADD) $(LIBS) tripplitesu$(EXEEXT): $(tripplitesu_OBJECTS) $(tripplitesu_DEPENDENCIES) $(EXTRA_tripplitesu_DEPENDENCIES) @rm -f tripplitesu$(EXEEXT) $(AM_V_CCLD)$(LINK) $(tripplitesu_OBJECTS) $(tripplitesu_LDADD) $(LIBS) upscode2$(EXEEXT): $(upscode2_OBJECTS) $(upscode2_DEPENDENCIES) $(EXTRA_upscode2_DEPENDENCIES) @rm -f upscode2$(EXEEXT) $(AM_V_CCLD)$(LINK) $(upscode2_OBJECTS) $(upscode2_LDADD) $(LIBS) upsdrvctl$(EXEEXT): $(upsdrvctl_OBJECTS) $(upsdrvctl_DEPENDENCIES) $(EXTRA_upsdrvctl_DEPENDENCIES) @rm -f upsdrvctl$(EXEEXT) $(AM_V_CCLD)$(LINK) $(upsdrvctl_OBJECTS) $(upsdrvctl_LDADD) $(LIBS) usbhid-ups$(EXEEXT): $(usbhid_ups_OBJECTS) $(usbhid_ups_DEPENDENCIES) $(EXTRA_usbhid_ups_DEPENDENCIES) @rm -f usbhid-ups$(EXEEXT) $(AM_V_CCLD)$(LINK) $(usbhid_ups_OBJECTS) $(usbhid_ups_LDADD) $(LIBS) victronups$(EXEEXT): $(victronups_OBJECTS) $(victronups_DEPENDENCIES) $(EXTRA_victronups_DEPENDENCIES) @rm -f victronups$(EXEEXT) $(AM_V_CCLD)$(LINK) $(victronups_OBJECTS) $(victronups_LDADD) $(LIBS) mostlyclean-compile: -rm -f *.$(OBJEXT) distclean-compile: -rm -f *.tab.c @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/adelsystem_cbi.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/al175.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/apc-hid.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/apc_modbus.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/apcsmart-old.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/apcsmart.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/apcsmart_tabs.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/apcupsd_ups-apcupsd-ups.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/arduino-hid.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/asem.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/bcmxcp.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/bcmxcp_ser.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/bcmxcp_usb.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/belkin-hid.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/belkin.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/belkinunv.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/bestfcom.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/bestfortress.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/bestuferrups.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/bestups.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/blazer.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/blazer_ser.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/blazer_usb.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/clone-outlet.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/clone.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cps-hid.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/delta_ups-hid.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dstate.Plo@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dummy_ups-dummy-ups.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/etapro.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ever-hid.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/everups.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/explore-hid.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gamatronic.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/generic_gpio_common.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/generic_gpio_libgpiod.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/generic_modbus.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/genericups.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/hidparser.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/huawei-ups2000.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/idowell-hid.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/isbmex.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ivtscd.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/legrand-hid.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libdummy_mockdrv_la-dstate.Plo@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libdummy_mockdrv_la-main.Plo@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libhid.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libusb0.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libusb1.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/liebert-esp2.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/liebert-hid.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/liebert.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/macosx-ups.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/main.Plo@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/masterguard.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/metasys.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mge-hid.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mge-utalk.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mge-xml.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mge_shut-hidparser.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mge_shut-libhid.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mge_shut-libshut.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mge_shut-mge-hid.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mge_shut-usbhid-ups.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/microdowell.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/microsol-apc.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/microsol-common.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/netxml-ups.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nut-ipmipsu.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nut-libfreeipmi.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nutdrv_atcl_usb.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nutdrv_qx-libusb0.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nutdrv_qx-libusb1.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nutdrv_qx-nutdrv_qx.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nutdrv_qx-nutdrv_qx_ablerex.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nutdrv_qx-nutdrv_qx_bestups.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nutdrv_qx-nutdrv_qx_blazer-common.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nutdrv_qx-nutdrv_qx_hunnox.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nutdrv_qx-nutdrv_qx_masterguard.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nutdrv_qx-nutdrv_qx_mecer.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nutdrv_qx-nutdrv_qx_megatec-old.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nutdrv_qx-nutdrv_qx_megatec.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nutdrv_qx-nutdrv_qx_mustek.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nutdrv_qx-nutdrv_qx_q1.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nutdrv_qx-nutdrv_qx_voltronic-qs-hex.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nutdrv_qx-nutdrv_qx_voltronic-qs.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nutdrv_qx-nutdrv_qx_voltronic.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nutdrv_qx-nutdrv_qx_zinto.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nutdrv_qx-usb-common.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nutdrv_siemens_sitop.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/oneac.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/openups-hid.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/optiups.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/phoenixcontact_modbus.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pijuice.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/powercom-hid.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/powercom.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/powerman-pdu.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/powerp-bin.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/powerp-txt.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/powerpanel.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/powervar-hid.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/rhino.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/richcomm_usb.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/riello.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/riello_ser.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/riello_usb.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/safenet.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/salicru-hid.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/serial.Plo@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/skel.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sms_ser.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/snmp_ups-apc-ats-mib.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/snmp_ups-apc-epdu-mib.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/snmp_ups-apc-mib.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/snmp_ups-apc-pdu-mib.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/snmp_ups-baytech-mib.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/snmp_ups-bestpower-mib.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/snmp_ups-compaq-mib.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/snmp_ups-cyberpower-mib.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/snmp_ups-delta_ups-mib.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/snmp_ups-eaton-ats16-nm2-mib.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/snmp_ups-eaton-ats16-nmc-mib.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/snmp_ups-eaton-ats30-mib.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/snmp_ups-eaton-pdu-genesis2-mib.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/snmp_ups-eaton-pdu-marlin-helpers.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/snmp_ups-eaton-pdu-marlin-mib.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/snmp_ups-eaton-pdu-nlogic-mib.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/snmp_ups-eaton-pdu-pulizzi-mib.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/snmp_ups-eaton-pdu-revelation-mib.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/snmp_ups-eaton-ups-pwnm2-mib.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/snmp_ups-eaton-ups-pxg-mib.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/snmp_ups-emerson-avocent-pdu-mib.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/snmp_ups-hpe-pdu-mib.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/snmp_ups-hpe-pdu3-cis-mib.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/snmp_ups-huawei-mib.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/snmp_ups-ietf-mib.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/snmp_ups-mge-mib.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/snmp_ups-netvision-mib.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/snmp_ups-raritan-pdu-mib.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/snmp_ups-raritan-px2-mib.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/snmp_ups-snmp-ups-helpers.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/snmp_ups-snmp-ups.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/snmp_ups-xppc-mib.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/socomec_jbus.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/solis.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tripplite-hid.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tripplite.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tripplite_usb.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tripplitesu.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/upscode2.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/upsdrvctl.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/upsdrvquery.Plo@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/usb-common.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/usbhid-ups.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/victronups.Po@am__quote@ # am--include-marker $(am__depfiles_remade): @$(MKDIR_P) $(@D) @echo '# dummy' >$@-t && $(am__mv) $@-t $@ am--depfiles: $(am__depfiles_remade) .c.o: @am__fastdepCC_TRUE@ $(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.o$$||'`;\ @am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\ @am__fastdepCC_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ $< .c.obj: @am__fastdepCC_TRUE@ $(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.obj$$||'`;\ @am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ `$(CYGPATH_W) '$<'` &&\ @am__fastdepCC_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'` .c.lo: @am__fastdepCC_TRUE@ $(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.lo$$||'`;\ @am__fastdepCC_TRUE@ $(LTCOMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\ @am__fastdepCC_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LTCOMPILE) -c -o $@ $< libdummy_mockdrv_la-main.lo: main.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libdummy_mockdrv_la_CFLAGS) $(CFLAGS) -MT libdummy_mockdrv_la-main.lo -MD -MP -MF $(DEPDIR)/libdummy_mockdrv_la-main.Tpo -c -o libdummy_mockdrv_la-main.lo `test -f 'main.c' || echo '$(srcdir)/'`main.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libdummy_mockdrv_la-main.Tpo $(DEPDIR)/libdummy_mockdrv_la-main.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='main.c' object='libdummy_mockdrv_la-main.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libdummy_mockdrv_la_CFLAGS) $(CFLAGS) -c -o libdummy_mockdrv_la-main.lo `test -f 'main.c' || echo '$(srcdir)/'`main.c libdummy_mockdrv_la-dstate.lo: dstate.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libdummy_mockdrv_la_CFLAGS) $(CFLAGS) -MT libdummy_mockdrv_la-dstate.lo -MD -MP -MF $(DEPDIR)/libdummy_mockdrv_la-dstate.Tpo -c -o libdummy_mockdrv_la-dstate.lo `test -f 'dstate.c' || echo '$(srcdir)/'`dstate.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libdummy_mockdrv_la-dstate.Tpo $(DEPDIR)/libdummy_mockdrv_la-dstate.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='dstate.c' object='libdummy_mockdrv_la-dstate.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libdummy_mockdrv_la_CFLAGS) $(CFLAGS) -c -o libdummy_mockdrv_la-dstate.lo `test -f 'dstate.c' || echo '$(srcdir)/'`dstate.c apcupsd_ups-apcupsd-ups.o: apcupsd-ups.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(apcupsd_ups_CFLAGS) $(CFLAGS) -MT apcupsd_ups-apcupsd-ups.o -MD -MP -MF $(DEPDIR)/apcupsd_ups-apcupsd-ups.Tpo -c -o apcupsd_ups-apcupsd-ups.o `test -f 'apcupsd-ups.c' || echo '$(srcdir)/'`apcupsd-ups.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/apcupsd_ups-apcupsd-ups.Tpo $(DEPDIR)/apcupsd_ups-apcupsd-ups.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='apcupsd-ups.c' object='apcupsd_ups-apcupsd-ups.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(apcupsd_ups_CFLAGS) $(CFLAGS) -c -o apcupsd_ups-apcupsd-ups.o `test -f 'apcupsd-ups.c' || echo '$(srcdir)/'`apcupsd-ups.c apcupsd_ups-apcupsd-ups.obj: apcupsd-ups.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(apcupsd_ups_CFLAGS) $(CFLAGS) -MT apcupsd_ups-apcupsd-ups.obj -MD -MP -MF $(DEPDIR)/apcupsd_ups-apcupsd-ups.Tpo -c -o apcupsd_ups-apcupsd-ups.obj `if test -f 'apcupsd-ups.c'; then $(CYGPATH_W) 'apcupsd-ups.c'; else $(CYGPATH_W) '$(srcdir)/apcupsd-ups.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/apcupsd_ups-apcupsd-ups.Tpo $(DEPDIR)/apcupsd_ups-apcupsd-ups.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='apcupsd-ups.c' object='apcupsd_ups-apcupsd-ups.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(apcupsd_ups_CFLAGS) $(CFLAGS) -c -o apcupsd_ups-apcupsd-ups.obj `if test -f 'apcupsd-ups.c'; then $(CYGPATH_W) 'apcupsd-ups.c'; else $(CYGPATH_W) '$(srcdir)/apcupsd-ups.c'; fi` dummy_ups-dummy-ups.o: dummy-ups.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(dummy_ups_CFLAGS) $(CFLAGS) -MT dummy_ups-dummy-ups.o -MD -MP -MF $(DEPDIR)/dummy_ups-dummy-ups.Tpo -c -o dummy_ups-dummy-ups.o `test -f 'dummy-ups.c' || echo '$(srcdir)/'`dummy-ups.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/dummy_ups-dummy-ups.Tpo $(DEPDIR)/dummy_ups-dummy-ups.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='dummy-ups.c' object='dummy_ups-dummy-ups.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(dummy_ups_CFLAGS) $(CFLAGS) -c -o dummy_ups-dummy-ups.o `test -f 'dummy-ups.c' || echo '$(srcdir)/'`dummy-ups.c dummy_ups-dummy-ups.obj: dummy-ups.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(dummy_ups_CFLAGS) $(CFLAGS) -MT dummy_ups-dummy-ups.obj -MD -MP -MF $(DEPDIR)/dummy_ups-dummy-ups.Tpo -c -o dummy_ups-dummy-ups.obj `if test -f 'dummy-ups.c'; then $(CYGPATH_W) 'dummy-ups.c'; else $(CYGPATH_W) '$(srcdir)/dummy-ups.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/dummy_ups-dummy-ups.Tpo $(DEPDIR)/dummy_ups-dummy-ups.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='dummy-ups.c' object='dummy_ups-dummy-ups.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(dummy_ups_CFLAGS) $(CFLAGS) -c -o dummy_ups-dummy-ups.obj `if test -f 'dummy-ups.c'; then $(CYGPATH_W) 'dummy-ups.c'; else $(CYGPATH_W) '$(srcdir)/dummy-ups.c'; fi` mge_shut-usbhid-ups.o: usbhid-ups.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(mge_shut_CFLAGS) $(CFLAGS) -MT mge_shut-usbhid-ups.o -MD -MP -MF $(DEPDIR)/mge_shut-usbhid-ups.Tpo -c -o mge_shut-usbhid-ups.o `test -f 'usbhid-ups.c' || echo '$(srcdir)/'`usbhid-ups.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/mge_shut-usbhid-ups.Tpo $(DEPDIR)/mge_shut-usbhid-ups.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='usbhid-ups.c' object='mge_shut-usbhid-ups.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(mge_shut_CFLAGS) $(CFLAGS) -c -o mge_shut-usbhid-ups.o `test -f 'usbhid-ups.c' || echo '$(srcdir)/'`usbhid-ups.c mge_shut-usbhid-ups.obj: usbhid-ups.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(mge_shut_CFLAGS) $(CFLAGS) -MT mge_shut-usbhid-ups.obj -MD -MP -MF $(DEPDIR)/mge_shut-usbhid-ups.Tpo -c -o mge_shut-usbhid-ups.obj `if test -f 'usbhid-ups.c'; then $(CYGPATH_W) 'usbhid-ups.c'; else $(CYGPATH_W) '$(srcdir)/usbhid-ups.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/mge_shut-usbhid-ups.Tpo $(DEPDIR)/mge_shut-usbhid-ups.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='usbhid-ups.c' object='mge_shut-usbhid-ups.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(mge_shut_CFLAGS) $(CFLAGS) -c -o mge_shut-usbhid-ups.obj `if test -f 'usbhid-ups.c'; then $(CYGPATH_W) 'usbhid-ups.c'; else $(CYGPATH_W) '$(srcdir)/usbhid-ups.c'; fi` mge_shut-libshut.o: libshut.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(mge_shut_CFLAGS) $(CFLAGS) -MT mge_shut-libshut.o -MD -MP -MF $(DEPDIR)/mge_shut-libshut.Tpo -c -o mge_shut-libshut.o `test -f 'libshut.c' || echo '$(srcdir)/'`libshut.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/mge_shut-libshut.Tpo $(DEPDIR)/mge_shut-libshut.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='libshut.c' object='mge_shut-libshut.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(mge_shut_CFLAGS) $(CFLAGS) -c -o mge_shut-libshut.o `test -f 'libshut.c' || echo '$(srcdir)/'`libshut.c mge_shut-libshut.obj: libshut.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(mge_shut_CFLAGS) $(CFLAGS) -MT mge_shut-libshut.obj -MD -MP -MF $(DEPDIR)/mge_shut-libshut.Tpo -c -o mge_shut-libshut.obj `if test -f 'libshut.c'; then $(CYGPATH_W) 'libshut.c'; else $(CYGPATH_W) '$(srcdir)/libshut.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/mge_shut-libshut.Tpo $(DEPDIR)/mge_shut-libshut.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='libshut.c' object='mge_shut-libshut.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(mge_shut_CFLAGS) $(CFLAGS) -c -o mge_shut-libshut.obj `if test -f 'libshut.c'; then $(CYGPATH_W) 'libshut.c'; else $(CYGPATH_W) '$(srcdir)/libshut.c'; fi` mge_shut-libhid.o: libhid.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(mge_shut_CFLAGS) $(CFLAGS) -MT mge_shut-libhid.o -MD -MP -MF $(DEPDIR)/mge_shut-libhid.Tpo -c -o mge_shut-libhid.o `test -f 'libhid.c' || echo '$(srcdir)/'`libhid.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/mge_shut-libhid.Tpo $(DEPDIR)/mge_shut-libhid.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='libhid.c' object='mge_shut-libhid.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(mge_shut_CFLAGS) $(CFLAGS) -c -o mge_shut-libhid.o `test -f 'libhid.c' || echo '$(srcdir)/'`libhid.c mge_shut-libhid.obj: libhid.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(mge_shut_CFLAGS) $(CFLAGS) -MT mge_shut-libhid.obj -MD -MP -MF $(DEPDIR)/mge_shut-libhid.Tpo -c -o mge_shut-libhid.obj `if test -f 'libhid.c'; then $(CYGPATH_W) 'libhid.c'; else $(CYGPATH_W) '$(srcdir)/libhid.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/mge_shut-libhid.Tpo $(DEPDIR)/mge_shut-libhid.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='libhid.c' object='mge_shut-libhid.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(mge_shut_CFLAGS) $(CFLAGS) -c -o mge_shut-libhid.obj `if test -f 'libhid.c'; then $(CYGPATH_W) 'libhid.c'; else $(CYGPATH_W) '$(srcdir)/libhid.c'; fi` mge_shut-hidparser.o: hidparser.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(mge_shut_CFLAGS) $(CFLAGS) -MT mge_shut-hidparser.o -MD -MP -MF $(DEPDIR)/mge_shut-hidparser.Tpo -c -o mge_shut-hidparser.o `test -f 'hidparser.c' || echo '$(srcdir)/'`hidparser.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/mge_shut-hidparser.Tpo $(DEPDIR)/mge_shut-hidparser.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='hidparser.c' object='mge_shut-hidparser.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(mge_shut_CFLAGS) $(CFLAGS) -c -o mge_shut-hidparser.o `test -f 'hidparser.c' || echo '$(srcdir)/'`hidparser.c mge_shut-hidparser.obj: hidparser.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(mge_shut_CFLAGS) $(CFLAGS) -MT mge_shut-hidparser.obj -MD -MP -MF $(DEPDIR)/mge_shut-hidparser.Tpo -c -o mge_shut-hidparser.obj `if test -f 'hidparser.c'; then $(CYGPATH_W) 'hidparser.c'; else $(CYGPATH_W) '$(srcdir)/hidparser.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/mge_shut-hidparser.Tpo $(DEPDIR)/mge_shut-hidparser.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='hidparser.c' object='mge_shut-hidparser.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(mge_shut_CFLAGS) $(CFLAGS) -c -o mge_shut-hidparser.obj `if test -f 'hidparser.c'; then $(CYGPATH_W) 'hidparser.c'; else $(CYGPATH_W) '$(srcdir)/hidparser.c'; fi` mge_shut-mge-hid.o: mge-hid.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(mge_shut_CFLAGS) $(CFLAGS) -MT mge_shut-mge-hid.o -MD -MP -MF $(DEPDIR)/mge_shut-mge-hid.Tpo -c -o mge_shut-mge-hid.o `test -f 'mge-hid.c' || echo '$(srcdir)/'`mge-hid.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/mge_shut-mge-hid.Tpo $(DEPDIR)/mge_shut-mge-hid.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='mge-hid.c' object='mge_shut-mge-hid.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(mge_shut_CFLAGS) $(CFLAGS) -c -o mge_shut-mge-hid.o `test -f 'mge-hid.c' || echo '$(srcdir)/'`mge-hid.c mge_shut-mge-hid.obj: mge-hid.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(mge_shut_CFLAGS) $(CFLAGS) -MT mge_shut-mge-hid.obj -MD -MP -MF $(DEPDIR)/mge_shut-mge-hid.Tpo -c -o mge_shut-mge-hid.obj `if test -f 'mge-hid.c'; then $(CYGPATH_W) 'mge-hid.c'; else $(CYGPATH_W) '$(srcdir)/mge-hid.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/mge_shut-mge-hid.Tpo $(DEPDIR)/mge_shut-mge-hid.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='mge-hid.c' object='mge_shut-mge-hid.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(mge_shut_CFLAGS) $(CFLAGS) -c -o mge_shut-mge-hid.obj `if test -f 'mge-hid.c'; then $(CYGPATH_W) 'mge-hid.c'; else $(CYGPATH_W) '$(srcdir)/mge-hid.c'; fi` nutdrv_qx-nutdrv_qx.o: nutdrv_qx.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nutdrv_qx_CFLAGS) $(CFLAGS) -MT nutdrv_qx-nutdrv_qx.o -MD -MP -MF $(DEPDIR)/nutdrv_qx-nutdrv_qx.Tpo -c -o nutdrv_qx-nutdrv_qx.o `test -f 'nutdrv_qx.c' || echo '$(srcdir)/'`nutdrv_qx.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/nutdrv_qx-nutdrv_qx.Tpo $(DEPDIR)/nutdrv_qx-nutdrv_qx.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='nutdrv_qx.c' object='nutdrv_qx-nutdrv_qx.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nutdrv_qx_CFLAGS) $(CFLAGS) -c -o nutdrv_qx-nutdrv_qx.o `test -f 'nutdrv_qx.c' || echo '$(srcdir)/'`nutdrv_qx.c nutdrv_qx-nutdrv_qx.obj: nutdrv_qx.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nutdrv_qx_CFLAGS) $(CFLAGS) -MT nutdrv_qx-nutdrv_qx.obj -MD -MP -MF $(DEPDIR)/nutdrv_qx-nutdrv_qx.Tpo -c -o nutdrv_qx-nutdrv_qx.obj `if test -f 'nutdrv_qx.c'; then $(CYGPATH_W) 'nutdrv_qx.c'; else $(CYGPATH_W) '$(srcdir)/nutdrv_qx.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/nutdrv_qx-nutdrv_qx.Tpo $(DEPDIR)/nutdrv_qx-nutdrv_qx.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='nutdrv_qx.c' object='nutdrv_qx-nutdrv_qx.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nutdrv_qx_CFLAGS) $(CFLAGS) -c -o nutdrv_qx-nutdrv_qx.obj `if test -f 'nutdrv_qx.c'; then $(CYGPATH_W) 'nutdrv_qx.c'; else $(CYGPATH_W) '$(srcdir)/nutdrv_qx.c'; fi` nutdrv_qx-libusb0.o: libusb0.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nutdrv_qx_CFLAGS) $(CFLAGS) -MT nutdrv_qx-libusb0.o -MD -MP -MF $(DEPDIR)/nutdrv_qx-libusb0.Tpo -c -o nutdrv_qx-libusb0.o `test -f 'libusb0.c' || echo '$(srcdir)/'`libusb0.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/nutdrv_qx-libusb0.Tpo $(DEPDIR)/nutdrv_qx-libusb0.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='libusb0.c' object='nutdrv_qx-libusb0.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nutdrv_qx_CFLAGS) $(CFLAGS) -c -o nutdrv_qx-libusb0.o `test -f 'libusb0.c' || echo '$(srcdir)/'`libusb0.c nutdrv_qx-libusb0.obj: libusb0.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nutdrv_qx_CFLAGS) $(CFLAGS) -MT nutdrv_qx-libusb0.obj -MD -MP -MF $(DEPDIR)/nutdrv_qx-libusb0.Tpo -c -o nutdrv_qx-libusb0.obj `if test -f 'libusb0.c'; then $(CYGPATH_W) 'libusb0.c'; else $(CYGPATH_W) '$(srcdir)/libusb0.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/nutdrv_qx-libusb0.Tpo $(DEPDIR)/nutdrv_qx-libusb0.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='libusb0.c' object='nutdrv_qx-libusb0.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nutdrv_qx_CFLAGS) $(CFLAGS) -c -o nutdrv_qx-libusb0.obj `if test -f 'libusb0.c'; then $(CYGPATH_W) 'libusb0.c'; else $(CYGPATH_W) '$(srcdir)/libusb0.c'; fi` nutdrv_qx-libusb1.o: libusb1.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nutdrv_qx_CFLAGS) $(CFLAGS) -MT nutdrv_qx-libusb1.o -MD -MP -MF $(DEPDIR)/nutdrv_qx-libusb1.Tpo -c -o nutdrv_qx-libusb1.o `test -f 'libusb1.c' || echo '$(srcdir)/'`libusb1.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/nutdrv_qx-libusb1.Tpo $(DEPDIR)/nutdrv_qx-libusb1.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='libusb1.c' object='nutdrv_qx-libusb1.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nutdrv_qx_CFLAGS) $(CFLAGS) -c -o nutdrv_qx-libusb1.o `test -f 'libusb1.c' || echo '$(srcdir)/'`libusb1.c nutdrv_qx-libusb1.obj: libusb1.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nutdrv_qx_CFLAGS) $(CFLAGS) -MT nutdrv_qx-libusb1.obj -MD -MP -MF $(DEPDIR)/nutdrv_qx-libusb1.Tpo -c -o nutdrv_qx-libusb1.obj `if test -f 'libusb1.c'; then $(CYGPATH_W) 'libusb1.c'; else $(CYGPATH_W) '$(srcdir)/libusb1.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/nutdrv_qx-libusb1.Tpo $(DEPDIR)/nutdrv_qx-libusb1.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='libusb1.c' object='nutdrv_qx-libusb1.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nutdrv_qx_CFLAGS) $(CFLAGS) -c -o nutdrv_qx-libusb1.obj `if test -f 'libusb1.c'; then $(CYGPATH_W) 'libusb1.c'; else $(CYGPATH_W) '$(srcdir)/libusb1.c'; fi` nutdrv_qx-usb-common.o: usb-common.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nutdrv_qx_CFLAGS) $(CFLAGS) -MT nutdrv_qx-usb-common.o -MD -MP -MF $(DEPDIR)/nutdrv_qx-usb-common.Tpo -c -o nutdrv_qx-usb-common.o `test -f 'usb-common.c' || echo '$(srcdir)/'`usb-common.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/nutdrv_qx-usb-common.Tpo $(DEPDIR)/nutdrv_qx-usb-common.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='usb-common.c' object='nutdrv_qx-usb-common.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nutdrv_qx_CFLAGS) $(CFLAGS) -c -o nutdrv_qx-usb-common.o `test -f 'usb-common.c' || echo '$(srcdir)/'`usb-common.c nutdrv_qx-usb-common.obj: usb-common.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nutdrv_qx_CFLAGS) $(CFLAGS) -MT nutdrv_qx-usb-common.obj -MD -MP -MF $(DEPDIR)/nutdrv_qx-usb-common.Tpo -c -o nutdrv_qx-usb-common.obj `if test -f 'usb-common.c'; then $(CYGPATH_W) 'usb-common.c'; else $(CYGPATH_W) '$(srcdir)/usb-common.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/nutdrv_qx-usb-common.Tpo $(DEPDIR)/nutdrv_qx-usb-common.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='usb-common.c' object='nutdrv_qx-usb-common.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nutdrv_qx_CFLAGS) $(CFLAGS) -c -o nutdrv_qx-usb-common.obj `if test -f 'usb-common.c'; then $(CYGPATH_W) 'usb-common.c'; else $(CYGPATH_W) '$(srcdir)/usb-common.c'; fi` nutdrv_qx-nutdrv_qx_bestups.o: nutdrv_qx_bestups.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nutdrv_qx_CFLAGS) $(CFLAGS) -MT nutdrv_qx-nutdrv_qx_bestups.o -MD -MP -MF $(DEPDIR)/nutdrv_qx-nutdrv_qx_bestups.Tpo -c -o nutdrv_qx-nutdrv_qx_bestups.o `test -f 'nutdrv_qx_bestups.c' || echo '$(srcdir)/'`nutdrv_qx_bestups.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/nutdrv_qx-nutdrv_qx_bestups.Tpo $(DEPDIR)/nutdrv_qx-nutdrv_qx_bestups.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='nutdrv_qx_bestups.c' object='nutdrv_qx-nutdrv_qx_bestups.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nutdrv_qx_CFLAGS) $(CFLAGS) -c -o nutdrv_qx-nutdrv_qx_bestups.o `test -f 'nutdrv_qx_bestups.c' || echo '$(srcdir)/'`nutdrv_qx_bestups.c nutdrv_qx-nutdrv_qx_bestups.obj: nutdrv_qx_bestups.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nutdrv_qx_CFLAGS) $(CFLAGS) -MT nutdrv_qx-nutdrv_qx_bestups.obj -MD -MP -MF $(DEPDIR)/nutdrv_qx-nutdrv_qx_bestups.Tpo -c -o nutdrv_qx-nutdrv_qx_bestups.obj `if test -f 'nutdrv_qx_bestups.c'; then $(CYGPATH_W) 'nutdrv_qx_bestups.c'; else $(CYGPATH_W) '$(srcdir)/nutdrv_qx_bestups.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/nutdrv_qx-nutdrv_qx_bestups.Tpo $(DEPDIR)/nutdrv_qx-nutdrv_qx_bestups.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='nutdrv_qx_bestups.c' object='nutdrv_qx-nutdrv_qx_bestups.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nutdrv_qx_CFLAGS) $(CFLAGS) -c -o nutdrv_qx-nutdrv_qx_bestups.obj `if test -f 'nutdrv_qx_bestups.c'; then $(CYGPATH_W) 'nutdrv_qx_bestups.c'; else $(CYGPATH_W) '$(srcdir)/nutdrv_qx_bestups.c'; fi` nutdrv_qx-nutdrv_qx_blazer-common.o: nutdrv_qx_blazer-common.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nutdrv_qx_CFLAGS) $(CFLAGS) -MT nutdrv_qx-nutdrv_qx_blazer-common.o -MD -MP -MF $(DEPDIR)/nutdrv_qx-nutdrv_qx_blazer-common.Tpo -c -o nutdrv_qx-nutdrv_qx_blazer-common.o `test -f 'nutdrv_qx_blazer-common.c' || echo '$(srcdir)/'`nutdrv_qx_blazer-common.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/nutdrv_qx-nutdrv_qx_blazer-common.Tpo $(DEPDIR)/nutdrv_qx-nutdrv_qx_blazer-common.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='nutdrv_qx_blazer-common.c' object='nutdrv_qx-nutdrv_qx_blazer-common.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nutdrv_qx_CFLAGS) $(CFLAGS) -c -o nutdrv_qx-nutdrv_qx_blazer-common.o `test -f 'nutdrv_qx_blazer-common.c' || echo '$(srcdir)/'`nutdrv_qx_blazer-common.c nutdrv_qx-nutdrv_qx_blazer-common.obj: nutdrv_qx_blazer-common.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nutdrv_qx_CFLAGS) $(CFLAGS) -MT nutdrv_qx-nutdrv_qx_blazer-common.obj -MD -MP -MF $(DEPDIR)/nutdrv_qx-nutdrv_qx_blazer-common.Tpo -c -o nutdrv_qx-nutdrv_qx_blazer-common.obj `if test -f 'nutdrv_qx_blazer-common.c'; then $(CYGPATH_W) 'nutdrv_qx_blazer-common.c'; else $(CYGPATH_W) '$(srcdir)/nutdrv_qx_blazer-common.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/nutdrv_qx-nutdrv_qx_blazer-common.Tpo $(DEPDIR)/nutdrv_qx-nutdrv_qx_blazer-common.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='nutdrv_qx_blazer-common.c' object='nutdrv_qx-nutdrv_qx_blazer-common.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nutdrv_qx_CFLAGS) $(CFLAGS) -c -o nutdrv_qx-nutdrv_qx_blazer-common.obj `if test -f 'nutdrv_qx_blazer-common.c'; then $(CYGPATH_W) 'nutdrv_qx_blazer-common.c'; else $(CYGPATH_W) '$(srcdir)/nutdrv_qx_blazer-common.c'; fi` nutdrv_qx-nutdrv_qx_masterguard.o: nutdrv_qx_masterguard.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nutdrv_qx_CFLAGS) $(CFLAGS) -MT nutdrv_qx-nutdrv_qx_masterguard.o -MD -MP -MF $(DEPDIR)/nutdrv_qx-nutdrv_qx_masterguard.Tpo -c -o nutdrv_qx-nutdrv_qx_masterguard.o `test -f 'nutdrv_qx_masterguard.c' || echo '$(srcdir)/'`nutdrv_qx_masterguard.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/nutdrv_qx-nutdrv_qx_masterguard.Tpo $(DEPDIR)/nutdrv_qx-nutdrv_qx_masterguard.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='nutdrv_qx_masterguard.c' object='nutdrv_qx-nutdrv_qx_masterguard.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nutdrv_qx_CFLAGS) $(CFLAGS) -c -o nutdrv_qx-nutdrv_qx_masterguard.o `test -f 'nutdrv_qx_masterguard.c' || echo '$(srcdir)/'`nutdrv_qx_masterguard.c nutdrv_qx-nutdrv_qx_masterguard.obj: nutdrv_qx_masterguard.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nutdrv_qx_CFLAGS) $(CFLAGS) -MT nutdrv_qx-nutdrv_qx_masterguard.obj -MD -MP -MF $(DEPDIR)/nutdrv_qx-nutdrv_qx_masterguard.Tpo -c -o nutdrv_qx-nutdrv_qx_masterguard.obj `if test -f 'nutdrv_qx_masterguard.c'; then $(CYGPATH_W) 'nutdrv_qx_masterguard.c'; else $(CYGPATH_W) '$(srcdir)/nutdrv_qx_masterguard.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/nutdrv_qx-nutdrv_qx_masterguard.Tpo $(DEPDIR)/nutdrv_qx-nutdrv_qx_masterguard.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='nutdrv_qx_masterguard.c' object='nutdrv_qx-nutdrv_qx_masterguard.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nutdrv_qx_CFLAGS) $(CFLAGS) -c -o nutdrv_qx-nutdrv_qx_masterguard.obj `if test -f 'nutdrv_qx_masterguard.c'; then $(CYGPATH_W) 'nutdrv_qx_masterguard.c'; else $(CYGPATH_W) '$(srcdir)/nutdrv_qx_masterguard.c'; fi` nutdrv_qx-nutdrv_qx_mecer.o: nutdrv_qx_mecer.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nutdrv_qx_CFLAGS) $(CFLAGS) -MT nutdrv_qx-nutdrv_qx_mecer.o -MD -MP -MF $(DEPDIR)/nutdrv_qx-nutdrv_qx_mecer.Tpo -c -o nutdrv_qx-nutdrv_qx_mecer.o `test -f 'nutdrv_qx_mecer.c' || echo '$(srcdir)/'`nutdrv_qx_mecer.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/nutdrv_qx-nutdrv_qx_mecer.Tpo $(DEPDIR)/nutdrv_qx-nutdrv_qx_mecer.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='nutdrv_qx_mecer.c' object='nutdrv_qx-nutdrv_qx_mecer.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nutdrv_qx_CFLAGS) $(CFLAGS) -c -o nutdrv_qx-nutdrv_qx_mecer.o `test -f 'nutdrv_qx_mecer.c' || echo '$(srcdir)/'`nutdrv_qx_mecer.c nutdrv_qx-nutdrv_qx_mecer.obj: nutdrv_qx_mecer.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nutdrv_qx_CFLAGS) $(CFLAGS) -MT nutdrv_qx-nutdrv_qx_mecer.obj -MD -MP -MF $(DEPDIR)/nutdrv_qx-nutdrv_qx_mecer.Tpo -c -o nutdrv_qx-nutdrv_qx_mecer.obj `if test -f 'nutdrv_qx_mecer.c'; then $(CYGPATH_W) 'nutdrv_qx_mecer.c'; else $(CYGPATH_W) '$(srcdir)/nutdrv_qx_mecer.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/nutdrv_qx-nutdrv_qx_mecer.Tpo $(DEPDIR)/nutdrv_qx-nutdrv_qx_mecer.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='nutdrv_qx_mecer.c' object='nutdrv_qx-nutdrv_qx_mecer.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nutdrv_qx_CFLAGS) $(CFLAGS) -c -o nutdrv_qx-nutdrv_qx_mecer.obj `if test -f 'nutdrv_qx_mecer.c'; then $(CYGPATH_W) 'nutdrv_qx_mecer.c'; else $(CYGPATH_W) '$(srcdir)/nutdrv_qx_mecer.c'; fi` nutdrv_qx-nutdrv_qx_megatec.o: nutdrv_qx_megatec.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nutdrv_qx_CFLAGS) $(CFLAGS) -MT nutdrv_qx-nutdrv_qx_megatec.o -MD -MP -MF $(DEPDIR)/nutdrv_qx-nutdrv_qx_megatec.Tpo -c -o nutdrv_qx-nutdrv_qx_megatec.o `test -f 'nutdrv_qx_megatec.c' || echo '$(srcdir)/'`nutdrv_qx_megatec.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/nutdrv_qx-nutdrv_qx_megatec.Tpo $(DEPDIR)/nutdrv_qx-nutdrv_qx_megatec.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='nutdrv_qx_megatec.c' object='nutdrv_qx-nutdrv_qx_megatec.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nutdrv_qx_CFLAGS) $(CFLAGS) -c -o nutdrv_qx-nutdrv_qx_megatec.o `test -f 'nutdrv_qx_megatec.c' || echo '$(srcdir)/'`nutdrv_qx_megatec.c nutdrv_qx-nutdrv_qx_megatec.obj: nutdrv_qx_megatec.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nutdrv_qx_CFLAGS) $(CFLAGS) -MT nutdrv_qx-nutdrv_qx_megatec.obj -MD -MP -MF $(DEPDIR)/nutdrv_qx-nutdrv_qx_megatec.Tpo -c -o nutdrv_qx-nutdrv_qx_megatec.obj `if test -f 'nutdrv_qx_megatec.c'; then $(CYGPATH_W) 'nutdrv_qx_megatec.c'; else $(CYGPATH_W) '$(srcdir)/nutdrv_qx_megatec.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/nutdrv_qx-nutdrv_qx_megatec.Tpo $(DEPDIR)/nutdrv_qx-nutdrv_qx_megatec.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='nutdrv_qx_megatec.c' object='nutdrv_qx-nutdrv_qx_megatec.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nutdrv_qx_CFLAGS) $(CFLAGS) -c -o nutdrv_qx-nutdrv_qx_megatec.obj `if test -f 'nutdrv_qx_megatec.c'; then $(CYGPATH_W) 'nutdrv_qx_megatec.c'; else $(CYGPATH_W) '$(srcdir)/nutdrv_qx_megatec.c'; fi` nutdrv_qx-nutdrv_qx_megatec-old.o: nutdrv_qx_megatec-old.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nutdrv_qx_CFLAGS) $(CFLAGS) -MT nutdrv_qx-nutdrv_qx_megatec-old.o -MD -MP -MF $(DEPDIR)/nutdrv_qx-nutdrv_qx_megatec-old.Tpo -c -o nutdrv_qx-nutdrv_qx_megatec-old.o `test -f 'nutdrv_qx_megatec-old.c' || echo '$(srcdir)/'`nutdrv_qx_megatec-old.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/nutdrv_qx-nutdrv_qx_megatec-old.Tpo $(DEPDIR)/nutdrv_qx-nutdrv_qx_megatec-old.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='nutdrv_qx_megatec-old.c' object='nutdrv_qx-nutdrv_qx_megatec-old.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nutdrv_qx_CFLAGS) $(CFLAGS) -c -o nutdrv_qx-nutdrv_qx_megatec-old.o `test -f 'nutdrv_qx_megatec-old.c' || echo '$(srcdir)/'`nutdrv_qx_megatec-old.c nutdrv_qx-nutdrv_qx_megatec-old.obj: nutdrv_qx_megatec-old.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nutdrv_qx_CFLAGS) $(CFLAGS) -MT nutdrv_qx-nutdrv_qx_megatec-old.obj -MD -MP -MF $(DEPDIR)/nutdrv_qx-nutdrv_qx_megatec-old.Tpo -c -o nutdrv_qx-nutdrv_qx_megatec-old.obj `if test -f 'nutdrv_qx_megatec-old.c'; then $(CYGPATH_W) 'nutdrv_qx_megatec-old.c'; else $(CYGPATH_W) '$(srcdir)/nutdrv_qx_megatec-old.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/nutdrv_qx-nutdrv_qx_megatec-old.Tpo $(DEPDIR)/nutdrv_qx-nutdrv_qx_megatec-old.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='nutdrv_qx_megatec-old.c' object='nutdrv_qx-nutdrv_qx_megatec-old.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nutdrv_qx_CFLAGS) $(CFLAGS) -c -o nutdrv_qx-nutdrv_qx_megatec-old.obj `if test -f 'nutdrv_qx_megatec-old.c'; then $(CYGPATH_W) 'nutdrv_qx_megatec-old.c'; else $(CYGPATH_W) '$(srcdir)/nutdrv_qx_megatec-old.c'; fi` nutdrv_qx-nutdrv_qx_mustek.o: nutdrv_qx_mustek.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nutdrv_qx_CFLAGS) $(CFLAGS) -MT nutdrv_qx-nutdrv_qx_mustek.o -MD -MP -MF $(DEPDIR)/nutdrv_qx-nutdrv_qx_mustek.Tpo -c -o nutdrv_qx-nutdrv_qx_mustek.o `test -f 'nutdrv_qx_mustek.c' || echo '$(srcdir)/'`nutdrv_qx_mustek.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/nutdrv_qx-nutdrv_qx_mustek.Tpo $(DEPDIR)/nutdrv_qx-nutdrv_qx_mustek.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='nutdrv_qx_mustek.c' object='nutdrv_qx-nutdrv_qx_mustek.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nutdrv_qx_CFLAGS) $(CFLAGS) -c -o nutdrv_qx-nutdrv_qx_mustek.o `test -f 'nutdrv_qx_mustek.c' || echo '$(srcdir)/'`nutdrv_qx_mustek.c nutdrv_qx-nutdrv_qx_mustek.obj: nutdrv_qx_mustek.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nutdrv_qx_CFLAGS) $(CFLAGS) -MT nutdrv_qx-nutdrv_qx_mustek.obj -MD -MP -MF $(DEPDIR)/nutdrv_qx-nutdrv_qx_mustek.Tpo -c -o nutdrv_qx-nutdrv_qx_mustek.obj `if test -f 'nutdrv_qx_mustek.c'; then $(CYGPATH_W) 'nutdrv_qx_mustek.c'; else $(CYGPATH_W) '$(srcdir)/nutdrv_qx_mustek.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/nutdrv_qx-nutdrv_qx_mustek.Tpo $(DEPDIR)/nutdrv_qx-nutdrv_qx_mustek.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='nutdrv_qx_mustek.c' object='nutdrv_qx-nutdrv_qx_mustek.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nutdrv_qx_CFLAGS) $(CFLAGS) -c -o nutdrv_qx-nutdrv_qx_mustek.obj `if test -f 'nutdrv_qx_mustek.c'; then $(CYGPATH_W) 'nutdrv_qx_mustek.c'; else $(CYGPATH_W) '$(srcdir)/nutdrv_qx_mustek.c'; fi` nutdrv_qx-nutdrv_qx_q1.o: nutdrv_qx_q1.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nutdrv_qx_CFLAGS) $(CFLAGS) -MT nutdrv_qx-nutdrv_qx_q1.o -MD -MP -MF $(DEPDIR)/nutdrv_qx-nutdrv_qx_q1.Tpo -c -o nutdrv_qx-nutdrv_qx_q1.o `test -f 'nutdrv_qx_q1.c' || echo '$(srcdir)/'`nutdrv_qx_q1.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/nutdrv_qx-nutdrv_qx_q1.Tpo $(DEPDIR)/nutdrv_qx-nutdrv_qx_q1.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='nutdrv_qx_q1.c' object='nutdrv_qx-nutdrv_qx_q1.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nutdrv_qx_CFLAGS) $(CFLAGS) -c -o nutdrv_qx-nutdrv_qx_q1.o `test -f 'nutdrv_qx_q1.c' || echo '$(srcdir)/'`nutdrv_qx_q1.c nutdrv_qx-nutdrv_qx_q1.obj: nutdrv_qx_q1.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nutdrv_qx_CFLAGS) $(CFLAGS) -MT nutdrv_qx-nutdrv_qx_q1.obj -MD -MP -MF $(DEPDIR)/nutdrv_qx-nutdrv_qx_q1.Tpo -c -o nutdrv_qx-nutdrv_qx_q1.obj `if test -f 'nutdrv_qx_q1.c'; then $(CYGPATH_W) 'nutdrv_qx_q1.c'; else $(CYGPATH_W) '$(srcdir)/nutdrv_qx_q1.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/nutdrv_qx-nutdrv_qx_q1.Tpo $(DEPDIR)/nutdrv_qx-nutdrv_qx_q1.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='nutdrv_qx_q1.c' object='nutdrv_qx-nutdrv_qx_q1.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nutdrv_qx_CFLAGS) $(CFLAGS) -c -o nutdrv_qx-nutdrv_qx_q1.obj `if test -f 'nutdrv_qx_q1.c'; then $(CYGPATH_W) 'nutdrv_qx_q1.c'; else $(CYGPATH_W) '$(srcdir)/nutdrv_qx_q1.c'; fi` nutdrv_qx-nutdrv_qx_voltronic.o: nutdrv_qx_voltronic.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nutdrv_qx_CFLAGS) $(CFLAGS) -MT nutdrv_qx-nutdrv_qx_voltronic.o -MD -MP -MF $(DEPDIR)/nutdrv_qx-nutdrv_qx_voltronic.Tpo -c -o nutdrv_qx-nutdrv_qx_voltronic.o `test -f 'nutdrv_qx_voltronic.c' || echo '$(srcdir)/'`nutdrv_qx_voltronic.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/nutdrv_qx-nutdrv_qx_voltronic.Tpo $(DEPDIR)/nutdrv_qx-nutdrv_qx_voltronic.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='nutdrv_qx_voltronic.c' object='nutdrv_qx-nutdrv_qx_voltronic.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nutdrv_qx_CFLAGS) $(CFLAGS) -c -o nutdrv_qx-nutdrv_qx_voltronic.o `test -f 'nutdrv_qx_voltronic.c' || echo '$(srcdir)/'`nutdrv_qx_voltronic.c nutdrv_qx-nutdrv_qx_voltronic.obj: nutdrv_qx_voltronic.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nutdrv_qx_CFLAGS) $(CFLAGS) -MT nutdrv_qx-nutdrv_qx_voltronic.obj -MD -MP -MF $(DEPDIR)/nutdrv_qx-nutdrv_qx_voltronic.Tpo -c -o nutdrv_qx-nutdrv_qx_voltronic.obj `if test -f 'nutdrv_qx_voltronic.c'; then $(CYGPATH_W) 'nutdrv_qx_voltronic.c'; else $(CYGPATH_W) '$(srcdir)/nutdrv_qx_voltronic.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/nutdrv_qx-nutdrv_qx_voltronic.Tpo $(DEPDIR)/nutdrv_qx-nutdrv_qx_voltronic.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='nutdrv_qx_voltronic.c' object='nutdrv_qx-nutdrv_qx_voltronic.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nutdrv_qx_CFLAGS) $(CFLAGS) -c -o nutdrv_qx-nutdrv_qx_voltronic.obj `if test -f 'nutdrv_qx_voltronic.c'; then $(CYGPATH_W) 'nutdrv_qx_voltronic.c'; else $(CYGPATH_W) '$(srcdir)/nutdrv_qx_voltronic.c'; fi` nutdrv_qx-nutdrv_qx_voltronic-qs.o: nutdrv_qx_voltronic-qs.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nutdrv_qx_CFLAGS) $(CFLAGS) -MT nutdrv_qx-nutdrv_qx_voltronic-qs.o -MD -MP -MF $(DEPDIR)/nutdrv_qx-nutdrv_qx_voltronic-qs.Tpo -c -o nutdrv_qx-nutdrv_qx_voltronic-qs.o `test -f 'nutdrv_qx_voltronic-qs.c' || echo '$(srcdir)/'`nutdrv_qx_voltronic-qs.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/nutdrv_qx-nutdrv_qx_voltronic-qs.Tpo $(DEPDIR)/nutdrv_qx-nutdrv_qx_voltronic-qs.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='nutdrv_qx_voltronic-qs.c' object='nutdrv_qx-nutdrv_qx_voltronic-qs.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nutdrv_qx_CFLAGS) $(CFLAGS) -c -o nutdrv_qx-nutdrv_qx_voltronic-qs.o `test -f 'nutdrv_qx_voltronic-qs.c' || echo '$(srcdir)/'`nutdrv_qx_voltronic-qs.c nutdrv_qx-nutdrv_qx_voltronic-qs.obj: nutdrv_qx_voltronic-qs.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nutdrv_qx_CFLAGS) $(CFLAGS) -MT nutdrv_qx-nutdrv_qx_voltronic-qs.obj -MD -MP -MF $(DEPDIR)/nutdrv_qx-nutdrv_qx_voltronic-qs.Tpo -c -o nutdrv_qx-nutdrv_qx_voltronic-qs.obj `if test -f 'nutdrv_qx_voltronic-qs.c'; then $(CYGPATH_W) 'nutdrv_qx_voltronic-qs.c'; else $(CYGPATH_W) '$(srcdir)/nutdrv_qx_voltronic-qs.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/nutdrv_qx-nutdrv_qx_voltronic-qs.Tpo $(DEPDIR)/nutdrv_qx-nutdrv_qx_voltronic-qs.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='nutdrv_qx_voltronic-qs.c' object='nutdrv_qx-nutdrv_qx_voltronic-qs.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nutdrv_qx_CFLAGS) $(CFLAGS) -c -o nutdrv_qx-nutdrv_qx_voltronic-qs.obj `if test -f 'nutdrv_qx_voltronic-qs.c'; then $(CYGPATH_W) 'nutdrv_qx_voltronic-qs.c'; else $(CYGPATH_W) '$(srcdir)/nutdrv_qx_voltronic-qs.c'; fi` nutdrv_qx-nutdrv_qx_voltronic-qs-hex.o: nutdrv_qx_voltronic-qs-hex.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nutdrv_qx_CFLAGS) $(CFLAGS) -MT nutdrv_qx-nutdrv_qx_voltronic-qs-hex.o -MD -MP -MF $(DEPDIR)/nutdrv_qx-nutdrv_qx_voltronic-qs-hex.Tpo -c -o nutdrv_qx-nutdrv_qx_voltronic-qs-hex.o `test -f 'nutdrv_qx_voltronic-qs-hex.c' || echo '$(srcdir)/'`nutdrv_qx_voltronic-qs-hex.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/nutdrv_qx-nutdrv_qx_voltronic-qs-hex.Tpo $(DEPDIR)/nutdrv_qx-nutdrv_qx_voltronic-qs-hex.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='nutdrv_qx_voltronic-qs-hex.c' object='nutdrv_qx-nutdrv_qx_voltronic-qs-hex.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nutdrv_qx_CFLAGS) $(CFLAGS) -c -o nutdrv_qx-nutdrv_qx_voltronic-qs-hex.o `test -f 'nutdrv_qx_voltronic-qs-hex.c' || echo '$(srcdir)/'`nutdrv_qx_voltronic-qs-hex.c nutdrv_qx-nutdrv_qx_voltronic-qs-hex.obj: nutdrv_qx_voltronic-qs-hex.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nutdrv_qx_CFLAGS) $(CFLAGS) -MT nutdrv_qx-nutdrv_qx_voltronic-qs-hex.obj -MD -MP -MF $(DEPDIR)/nutdrv_qx-nutdrv_qx_voltronic-qs-hex.Tpo -c -o nutdrv_qx-nutdrv_qx_voltronic-qs-hex.obj `if test -f 'nutdrv_qx_voltronic-qs-hex.c'; then $(CYGPATH_W) 'nutdrv_qx_voltronic-qs-hex.c'; else $(CYGPATH_W) '$(srcdir)/nutdrv_qx_voltronic-qs-hex.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/nutdrv_qx-nutdrv_qx_voltronic-qs-hex.Tpo $(DEPDIR)/nutdrv_qx-nutdrv_qx_voltronic-qs-hex.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='nutdrv_qx_voltronic-qs-hex.c' object='nutdrv_qx-nutdrv_qx_voltronic-qs-hex.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nutdrv_qx_CFLAGS) $(CFLAGS) -c -o nutdrv_qx-nutdrv_qx_voltronic-qs-hex.obj `if test -f 'nutdrv_qx_voltronic-qs-hex.c'; then $(CYGPATH_W) 'nutdrv_qx_voltronic-qs-hex.c'; else $(CYGPATH_W) '$(srcdir)/nutdrv_qx_voltronic-qs-hex.c'; fi` nutdrv_qx-nutdrv_qx_zinto.o: nutdrv_qx_zinto.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nutdrv_qx_CFLAGS) $(CFLAGS) -MT nutdrv_qx-nutdrv_qx_zinto.o -MD -MP -MF $(DEPDIR)/nutdrv_qx-nutdrv_qx_zinto.Tpo -c -o nutdrv_qx-nutdrv_qx_zinto.o `test -f 'nutdrv_qx_zinto.c' || echo '$(srcdir)/'`nutdrv_qx_zinto.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/nutdrv_qx-nutdrv_qx_zinto.Tpo $(DEPDIR)/nutdrv_qx-nutdrv_qx_zinto.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='nutdrv_qx_zinto.c' object='nutdrv_qx-nutdrv_qx_zinto.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nutdrv_qx_CFLAGS) $(CFLAGS) -c -o nutdrv_qx-nutdrv_qx_zinto.o `test -f 'nutdrv_qx_zinto.c' || echo '$(srcdir)/'`nutdrv_qx_zinto.c nutdrv_qx-nutdrv_qx_zinto.obj: nutdrv_qx_zinto.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nutdrv_qx_CFLAGS) $(CFLAGS) -MT nutdrv_qx-nutdrv_qx_zinto.obj -MD -MP -MF $(DEPDIR)/nutdrv_qx-nutdrv_qx_zinto.Tpo -c -o nutdrv_qx-nutdrv_qx_zinto.obj `if test -f 'nutdrv_qx_zinto.c'; then $(CYGPATH_W) 'nutdrv_qx_zinto.c'; else $(CYGPATH_W) '$(srcdir)/nutdrv_qx_zinto.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/nutdrv_qx-nutdrv_qx_zinto.Tpo $(DEPDIR)/nutdrv_qx-nutdrv_qx_zinto.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='nutdrv_qx_zinto.c' object='nutdrv_qx-nutdrv_qx_zinto.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nutdrv_qx_CFLAGS) $(CFLAGS) -c -o nutdrv_qx-nutdrv_qx_zinto.obj `if test -f 'nutdrv_qx_zinto.c'; then $(CYGPATH_W) 'nutdrv_qx_zinto.c'; else $(CYGPATH_W) '$(srcdir)/nutdrv_qx_zinto.c'; fi` nutdrv_qx-nutdrv_qx_hunnox.o: nutdrv_qx_hunnox.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nutdrv_qx_CFLAGS) $(CFLAGS) -MT nutdrv_qx-nutdrv_qx_hunnox.o -MD -MP -MF $(DEPDIR)/nutdrv_qx-nutdrv_qx_hunnox.Tpo -c -o nutdrv_qx-nutdrv_qx_hunnox.o `test -f 'nutdrv_qx_hunnox.c' || echo '$(srcdir)/'`nutdrv_qx_hunnox.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/nutdrv_qx-nutdrv_qx_hunnox.Tpo $(DEPDIR)/nutdrv_qx-nutdrv_qx_hunnox.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='nutdrv_qx_hunnox.c' object='nutdrv_qx-nutdrv_qx_hunnox.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nutdrv_qx_CFLAGS) $(CFLAGS) -c -o nutdrv_qx-nutdrv_qx_hunnox.o `test -f 'nutdrv_qx_hunnox.c' || echo '$(srcdir)/'`nutdrv_qx_hunnox.c nutdrv_qx-nutdrv_qx_hunnox.obj: nutdrv_qx_hunnox.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nutdrv_qx_CFLAGS) $(CFLAGS) -MT nutdrv_qx-nutdrv_qx_hunnox.obj -MD -MP -MF $(DEPDIR)/nutdrv_qx-nutdrv_qx_hunnox.Tpo -c -o nutdrv_qx-nutdrv_qx_hunnox.obj `if test -f 'nutdrv_qx_hunnox.c'; then $(CYGPATH_W) 'nutdrv_qx_hunnox.c'; else $(CYGPATH_W) '$(srcdir)/nutdrv_qx_hunnox.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/nutdrv_qx-nutdrv_qx_hunnox.Tpo $(DEPDIR)/nutdrv_qx-nutdrv_qx_hunnox.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='nutdrv_qx_hunnox.c' object='nutdrv_qx-nutdrv_qx_hunnox.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nutdrv_qx_CFLAGS) $(CFLAGS) -c -o nutdrv_qx-nutdrv_qx_hunnox.obj `if test -f 'nutdrv_qx_hunnox.c'; then $(CYGPATH_W) 'nutdrv_qx_hunnox.c'; else $(CYGPATH_W) '$(srcdir)/nutdrv_qx_hunnox.c'; fi` nutdrv_qx-nutdrv_qx_ablerex.o: nutdrv_qx_ablerex.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nutdrv_qx_CFLAGS) $(CFLAGS) -MT nutdrv_qx-nutdrv_qx_ablerex.o -MD -MP -MF $(DEPDIR)/nutdrv_qx-nutdrv_qx_ablerex.Tpo -c -o nutdrv_qx-nutdrv_qx_ablerex.o `test -f 'nutdrv_qx_ablerex.c' || echo '$(srcdir)/'`nutdrv_qx_ablerex.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/nutdrv_qx-nutdrv_qx_ablerex.Tpo $(DEPDIR)/nutdrv_qx-nutdrv_qx_ablerex.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='nutdrv_qx_ablerex.c' object='nutdrv_qx-nutdrv_qx_ablerex.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nutdrv_qx_CFLAGS) $(CFLAGS) -c -o nutdrv_qx-nutdrv_qx_ablerex.o `test -f 'nutdrv_qx_ablerex.c' || echo '$(srcdir)/'`nutdrv_qx_ablerex.c nutdrv_qx-nutdrv_qx_ablerex.obj: nutdrv_qx_ablerex.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nutdrv_qx_CFLAGS) $(CFLAGS) -MT nutdrv_qx-nutdrv_qx_ablerex.obj -MD -MP -MF $(DEPDIR)/nutdrv_qx-nutdrv_qx_ablerex.Tpo -c -o nutdrv_qx-nutdrv_qx_ablerex.obj `if test -f 'nutdrv_qx_ablerex.c'; then $(CYGPATH_W) 'nutdrv_qx_ablerex.c'; else $(CYGPATH_W) '$(srcdir)/nutdrv_qx_ablerex.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/nutdrv_qx-nutdrv_qx_ablerex.Tpo $(DEPDIR)/nutdrv_qx-nutdrv_qx_ablerex.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='nutdrv_qx_ablerex.c' object='nutdrv_qx-nutdrv_qx_ablerex.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nutdrv_qx_CFLAGS) $(CFLAGS) -c -o nutdrv_qx-nutdrv_qx_ablerex.obj `if test -f 'nutdrv_qx_ablerex.c'; then $(CYGPATH_W) 'nutdrv_qx_ablerex.c'; else $(CYGPATH_W) '$(srcdir)/nutdrv_qx_ablerex.c'; fi` snmp_ups-snmp-ups.o: snmp-ups.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(snmp_ups_CFLAGS) $(CFLAGS) -MT snmp_ups-snmp-ups.o -MD -MP -MF $(DEPDIR)/snmp_ups-snmp-ups.Tpo -c -o snmp_ups-snmp-ups.o `test -f 'snmp-ups.c' || echo '$(srcdir)/'`snmp-ups.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/snmp_ups-snmp-ups.Tpo $(DEPDIR)/snmp_ups-snmp-ups.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='snmp-ups.c' object='snmp_ups-snmp-ups.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(snmp_ups_CFLAGS) $(CFLAGS) -c -o snmp_ups-snmp-ups.o `test -f 'snmp-ups.c' || echo '$(srcdir)/'`snmp-ups.c snmp_ups-snmp-ups.obj: snmp-ups.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(snmp_ups_CFLAGS) $(CFLAGS) -MT snmp_ups-snmp-ups.obj -MD -MP -MF $(DEPDIR)/snmp_ups-snmp-ups.Tpo -c -o snmp_ups-snmp-ups.obj `if test -f 'snmp-ups.c'; then $(CYGPATH_W) 'snmp-ups.c'; else $(CYGPATH_W) '$(srcdir)/snmp-ups.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/snmp_ups-snmp-ups.Tpo $(DEPDIR)/snmp_ups-snmp-ups.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='snmp-ups.c' object='snmp_ups-snmp-ups.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(snmp_ups_CFLAGS) $(CFLAGS) -c -o snmp_ups-snmp-ups.obj `if test -f 'snmp-ups.c'; then $(CYGPATH_W) 'snmp-ups.c'; else $(CYGPATH_W) '$(srcdir)/snmp-ups.c'; fi` snmp_ups-snmp-ups-helpers.o: snmp-ups-helpers.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(snmp_ups_CFLAGS) $(CFLAGS) -MT snmp_ups-snmp-ups-helpers.o -MD -MP -MF $(DEPDIR)/snmp_ups-snmp-ups-helpers.Tpo -c -o snmp_ups-snmp-ups-helpers.o `test -f 'snmp-ups-helpers.c' || echo '$(srcdir)/'`snmp-ups-helpers.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/snmp_ups-snmp-ups-helpers.Tpo $(DEPDIR)/snmp_ups-snmp-ups-helpers.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='snmp-ups-helpers.c' object='snmp_ups-snmp-ups-helpers.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(snmp_ups_CFLAGS) $(CFLAGS) -c -o snmp_ups-snmp-ups-helpers.o `test -f 'snmp-ups-helpers.c' || echo '$(srcdir)/'`snmp-ups-helpers.c snmp_ups-snmp-ups-helpers.obj: snmp-ups-helpers.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(snmp_ups_CFLAGS) $(CFLAGS) -MT snmp_ups-snmp-ups-helpers.obj -MD -MP -MF $(DEPDIR)/snmp_ups-snmp-ups-helpers.Tpo -c -o snmp_ups-snmp-ups-helpers.obj `if test -f 'snmp-ups-helpers.c'; then $(CYGPATH_W) 'snmp-ups-helpers.c'; else $(CYGPATH_W) '$(srcdir)/snmp-ups-helpers.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/snmp_ups-snmp-ups-helpers.Tpo $(DEPDIR)/snmp_ups-snmp-ups-helpers.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='snmp-ups-helpers.c' object='snmp_ups-snmp-ups-helpers.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(snmp_ups_CFLAGS) $(CFLAGS) -c -o snmp_ups-snmp-ups-helpers.obj `if test -f 'snmp-ups-helpers.c'; then $(CYGPATH_W) 'snmp-ups-helpers.c'; else $(CYGPATH_W) '$(srcdir)/snmp-ups-helpers.c'; fi` snmp_ups-apc-mib.o: apc-mib.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(snmp_ups_CFLAGS) $(CFLAGS) -MT snmp_ups-apc-mib.o -MD -MP -MF $(DEPDIR)/snmp_ups-apc-mib.Tpo -c -o snmp_ups-apc-mib.o `test -f 'apc-mib.c' || echo '$(srcdir)/'`apc-mib.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/snmp_ups-apc-mib.Tpo $(DEPDIR)/snmp_ups-apc-mib.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='apc-mib.c' object='snmp_ups-apc-mib.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(snmp_ups_CFLAGS) $(CFLAGS) -c -o snmp_ups-apc-mib.o `test -f 'apc-mib.c' || echo '$(srcdir)/'`apc-mib.c snmp_ups-apc-mib.obj: apc-mib.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(snmp_ups_CFLAGS) $(CFLAGS) -MT snmp_ups-apc-mib.obj -MD -MP -MF $(DEPDIR)/snmp_ups-apc-mib.Tpo -c -o snmp_ups-apc-mib.obj `if test -f 'apc-mib.c'; then $(CYGPATH_W) 'apc-mib.c'; else $(CYGPATH_W) '$(srcdir)/apc-mib.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/snmp_ups-apc-mib.Tpo $(DEPDIR)/snmp_ups-apc-mib.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='apc-mib.c' object='snmp_ups-apc-mib.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(snmp_ups_CFLAGS) $(CFLAGS) -c -o snmp_ups-apc-mib.obj `if test -f 'apc-mib.c'; then $(CYGPATH_W) 'apc-mib.c'; else $(CYGPATH_W) '$(srcdir)/apc-mib.c'; fi` snmp_ups-apc-pdu-mib.o: apc-pdu-mib.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(snmp_ups_CFLAGS) $(CFLAGS) -MT snmp_ups-apc-pdu-mib.o -MD -MP -MF $(DEPDIR)/snmp_ups-apc-pdu-mib.Tpo -c -o snmp_ups-apc-pdu-mib.o `test -f 'apc-pdu-mib.c' || echo '$(srcdir)/'`apc-pdu-mib.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/snmp_ups-apc-pdu-mib.Tpo $(DEPDIR)/snmp_ups-apc-pdu-mib.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='apc-pdu-mib.c' object='snmp_ups-apc-pdu-mib.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(snmp_ups_CFLAGS) $(CFLAGS) -c -o snmp_ups-apc-pdu-mib.o `test -f 'apc-pdu-mib.c' || echo '$(srcdir)/'`apc-pdu-mib.c snmp_ups-apc-pdu-mib.obj: apc-pdu-mib.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(snmp_ups_CFLAGS) $(CFLAGS) -MT snmp_ups-apc-pdu-mib.obj -MD -MP -MF $(DEPDIR)/snmp_ups-apc-pdu-mib.Tpo -c -o snmp_ups-apc-pdu-mib.obj `if test -f 'apc-pdu-mib.c'; then $(CYGPATH_W) 'apc-pdu-mib.c'; else $(CYGPATH_W) '$(srcdir)/apc-pdu-mib.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/snmp_ups-apc-pdu-mib.Tpo $(DEPDIR)/snmp_ups-apc-pdu-mib.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='apc-pdu-mib.c' object='snmp_ups-apc-pdu-mib.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(snmp_ups_CFLAGS) $(CFLAGS) -c -o snmp_ups-apc-pdu-mib.obj `if test -f 'apc-pdu-mib.c'; then $(CYGPATH_W) 'apc-pdu-mib.c'; else $(CYGPATH_W) '$(srcdir)/apc-pdu-mib.c'; fi` snmp_ups-apc-epdu-mib.o: apc-epdu-mib.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(snmp_ups_CFLAGS) $(CFLAGS) -MT snmp_ups-apc-epdu-mib.o -MD -MP -MF $(DEPDIR)/snmp_ups-apc-epdu-mib.Tpo -c -o snmp_ups-apc-epdu-mib.o `test -f 'apc-epdu-mib.c' || echo '$(srcdir)/'`apc-epdu-mib.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/snmp_ups-apc-epdu-mib.Tpo $(DEPDIR)/snmp_ups-apc-epdu-mib.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='apc-epdu-mib.c' object='snmp_ups-apc-epdu-mib.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(snmp_ups_CFLAGS) $(CFLAGS) -c -o snmp_ups-apc-epdu-mib.o `test -f 'apc-epdu-mib.c' || echo '$(srcdir)/'`apc-epdu-mib.c snmp_ups-apc-epdu-mib.obj: apc-epdu-mib.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(snmp_ups_CFLAGS) $(CFLAGS) -MT snmp_ups-apc-epdu-mib.obj -MD -MP -MF $(DEPDIR)/snmp_ups-apc-epdu-mib.Tpo -c -o snmp_ups-apc-epdu-mib.obj `if test -f 'apc-epdu-mib.c'; then $(CYGPATH_W) 'apc-epdu-mib.c'; else $(CYGPATH_W) '$(srcdir)/apc-epdu-mib.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/snmp_ups-apc-epdu-mib.Tpo $(DEPDIR)/snmp_ups-apc-epdu-mib.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='apc-epdu-mib.c' object='snmp_ups-apc-epdu-mib.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(snmp_ups_CFLAGS) $(CFLAGS) -c -o snmp_ups-apc-epdu-mib.obj `if test -f 'apc-epdu-mib.c'; then $(CYGPATH_W) 'apc-epdu-mib.c'; else $(CYGPATH_W) '$(srcdir)/apc-epdu-mib.c'; fi` snmp_ups-baytech-mib.o: baytech-mib.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(snmp_ups_CFLAGS) $(CFLAGS) -MT snmp_ups-baytech-mib.o -MD -MP -MF $(DEPDIR)/snmp_ups-baytech-mib.Tpo -c -o snmp_ups-baytech-mib.o `test -f 'baytech-mib.c' || echo '$(srcdir)/'`baytech-mib.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/snmp_ups-baytech-mib.Tpo $(DEPDIR)/snmp_ups-baytech-mib.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='baytech-mib.c' object='snmp_ups-baytech-mib.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(snmp_ups_CFLAGS) $(CFLAGS) -c -o snmp_ups-baytech-mib.o `test -f 'baytech-mib.c' || echo '$(srcdir)/'`baytech-mib.c snmp_ups-baytech-mib.obj: baytech-mib.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(snmp_ups_CFLAGS) $(CFLAGS) -MT snmp_ups-baytech-mib.obj -MD -MP -MF $(DEPDIR)/snmp_ups-baytech-mib.Tpo -c -o snmp_ups-baytech-mib.obj `if test -f 'baytech-mib.c'; then $(CYGPATH_W) 'baytech-mib.c'; else $(CYGPATH_W) '$(srcdir)/baytech-mib.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/snmp_ups-baytech-mib.Tpo $(DEPDIR)/snmp_ups-baytech-mib.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='baytech-mib.c' object='snmp_ups-baytech-mib.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(snmp_ups_CFLAGS) $(CFLAGS) -c -o snmp_ups-baytech-mib.obj `if test -f 'baytech-mib.c'; then $(CYGPATH_W) 'baytech-mib.c'; else $(CYGPATH_W) '$(srcdir)/baytech-mib.c'; fi` snmp_ups-bestpower-mib.o: bestpower-mib.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(snmp_ups_CFLAGS) $(CFLAGS) -MT snmp_ups-bestpower-mib.o -MD -MP -MF $(DEPDIR)/snmp_ups-bestpower-mib.Tpo -c -o snmp_ups-bestpower-mib.o `test -f 'bestpower-mib.c' || echo '$(srcdir)/'`bestpower-mib.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/snmp_ups-bestpower-mib.Tpo $(DEPDIR)/snmp_ups-bestpower-mib.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='bestpower-mib.c' object='snmp_ups-bestpower-mib.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(snmp_ups_CFLAGS) $(CFLAGS) -c -o snmp_ups-bestpower-mib.o `test -f 'bestpower-mib.c' || echo '$(srcdir)/'`bestpower-mib.c snmp_ups-bestpower-mib.obj: bestpower-mib.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(snmp_ups_CFLAGS) $(CFLAGS) -MT snmp_ups-bestpower-mib.obj -MD -MP -MF $(DEPDIR)/snmp_ups-bestpower-mib.Tpo -c -o snmp_ups-bestpower-mib.obj `if test -f 'bestpower-mib.c'; then $(CYGPATH_W) 'bestpower-mib.c'; else $(CYGPATH_W) '$(srcdir)/bestpower-mib.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/snmp_ups-bestpower-mib.Tpo $(DEPDIR)/snmp_ups-bestpower-mib.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='bestpower-mib.c' object='snmp_ups-bestpower-mib.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(snmp_ups_CFLAGS) $(CFLAGS) -c -o snmp_ups-bestpower-mib.obj `if test -f 'bestpower-mib.c'; then $(CYGPATH_W) 'bestpower-mib.c'; else $(CYGPATH_W) '$(srcdir)/bestpower-mib.c'; fi` snmp_ups-compaq-mib.o: compaq-mib.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(snmp_ups_CFLAGS) $(CFLAGS) -MT snmp_ups-compaq-mib.o -MD -MP -MF $(DEPDIR)/snmp_ups-compaq-mib.Tpo -c -o snmp_ups-compaq-mib.o `test -f 'compaq-mib.c' || echo '$(srcdir)/'`compaq-mib.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/snmp_ups-compaq-mib.Tpo $(DEPDIR)/snmp_ups-compaq-mib.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='compaq-mib.c' object='snmp_ups-compaq-mib.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(snmp_ups_CFLAGS) $(CFLAGS) -c -o snmp_ups-compaq-mib.o `test -f 'compaq-mib.c' || echo '$(srcdir)/'`compaq-mib.c snmp_ups-compaq-mib.obj: compaq-mib.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(snmp_ups_CFLAGS) $(CFLAGS) -MT snmp_ups-compaq-mib.obj -MD -MP -MF $(DEPDIR)/snmp_ups-compaq-mib.Tpo -c -o snmp_ups-compaq-mib.obj `if test -f 'compaq-mib.c'; then $(CYGPATH_W) 'compaq-mib.c'; else $(CYGPATH_W) '$(srcdir)/compaq-mib.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/snmp_ups-compaq-mib.Tpo $(DEPDIR)/snmp_ups-compaq-mib.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='compaq-mib.c' object='snmp_ups-compaq-mib.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(snmp_ups_CFLAGS) $(CFLAGS) -c -o snmp_ups-compaq-mib.obj `if test -f 'compaq-mib.c'; then $(CYGPATH_W) 'compaq-mib.c'; else $(CYGPATH_W) '$(srcdir)/compaq-mib.c'; fi` snmp_ups-cyberpower-mib.o: cyberpower-mib.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(snmp_ups_CFLAGS) $(CFLAGS) -MT snmp_ups-cyberpower-mib.o -MD -MP -MF $(DEPDIR)/snmp_ups-cyberpower-mib.Tpo -c -o snmp_ups-cyberpower-mib.o `test -f 'cyberpower-mib.c' || echo '$(srcdir)/'`cyberpower-mib.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/snmp_ups-cyberpower-mib.Tpo $(DEPDIR)/snmp_ups-cyberpower-mib.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='cyberpower-mib.c' object='snmp_ups-cyberpower-mib.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(snmp_ups_CFLAGS) $(CFLAGS) -c -o snmp_ups-cyberpower-mib.o `test -f 'cyberpower-mib.c' || echo '$(srcdir)/'`cyberpower-mib.c snmp_ups-cyberpower-mib.obj: cyberpower-mib.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(snmp_ups_CFLAGS) $(CFLAGS) -MT snmp_ups-cyberpower-mib.obj -MD -MP -MF $(DEPDIR)/snmp_ups-cyberpower-mib.Tpo -c -o snmp_ups-cyberpower-mib.obj `if test -f 'cyberpower-mib.c'; then $(CYGPATH_W) 'cyberpower-mib.c'; else $(CYGPATH_W) '$(srcdir)/cyberpower-mib.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/snmp_ups-cyberpower-mib.Tpo $(DEPDIR)/snmp_ups-cyberpower-mib.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='cyberpower-mib.c' object='snmp_ups-cyberpower-mib.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(snmp_ups_CFLAGS) $(CFLAGS) -c -o snmp_ups-cyberpower-mib.obj `if test -f 'cyberpower-mib.c'; then $(CYGPATH_W) 'cyberpower-mib.c'; else $(CYGPATH_W) '$(srcdir)/cyberpower-mib.c'; fi` snmp_ups-delta_ups-mib.o: delta_ups-mib.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(snmp_ups_CFLAGS) $(CFLAGS) -MT snmp_ups-delta_ups-mib.o -MD -MP -MF $(DEPDIR)/snmp_ups-delta_ups-mib.Tpo -c -o snmp_ups-delta_ups-mib.o `test -f 'delta_ups-mib.c' || echo '$(srcdir)/'`delta_ups-mib.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/snmp_ups-delta_ups-mib.Tpo $(DEPDIR)/snmp_ups-delta_ups-mib.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='delta_ups-mib.c' object='snmp_ups-delta_ups-mib.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(snmp_ups_CFLAGS) $(CFLAGS) -c -o snmp_ups-delta_ups-mib.o `test -f 'delta_ups-mib.c' || echo '$(srcdir)/'`delta_ups-mib.c snmp_ups-delta_ups-mib.obj: delta_ups-mib.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(snmp_ups_CFLAGS) $(CFLAGS) -MT snmp_ups-delta_ups-mib.obj -MD -MP -MF $(DEPDIR)/snmp_ups-delta_ups-mib.Tpo -c -o snmp_ups-delta_ups-mib.obj `if test -f 'delta_ups-mib.c'; then $(CYGPATH_W) 'delta_ups-mib.c'; else $(CYGPATH_W) '$(srcdir)/delta_ups-mib.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/snmp_ups-delta_ups-mib.Tpo $(DEPDIR)/snmp_ups-delta_ups-mib.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='delta_ups-mib.c' object='snmp_ups-delta_ups-mib.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(snmp_ups_CFLAGS) $(CFLAGS) -c -o snmp_ups-delta_ups-mib.obj `if test -f 'delta_ups-mib.c'; then $(CYGPATH_W) 'delta_ups-mib.c'; else $(CYGPATH_W) '$(srcdir)/delta_ups-mib.c'; fi` snmp_ups-eaton-pdu-genesis2-mib.o: eaton-pdu-genesis2-mib.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(snmp_ups_CFLAGS) $(CFLAGS) -MT snmp_ups-eaton-pdu-genesis2-mib.o -MD -MP -MF $(DEPDIR)/snmp_ups-eaton-pdu-genesis2-mib.Tpo -c -o snmp_ups-eaton-pdu-genesis2-mib.o `test -f 'eaton-pdu-genesis2-mib.c' || echo '$(srcdir)/'`eaton-pdu-genesis2-mib.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/snmp_ups-eaton-pdu-genesis2-mib.Tpo $(DEPDIR)/snmp_ups-eaton-pdu-genesis2-mib.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='eaton-pdu-genesis2-mib.c' object='snmp_ups-eaton-pdu-genesis2-mib.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(snmp_ups_CFLAGS) $(CFLAGS) -c -o snmp_ups-eaton-pdu-genesis2-mib.o `test -f 'eaton-pdu-genesis2-mib.c' || echo '$(srcdir)/'`eaton-pdu-genesis2-mib.c snmp_ups-eaton-pdu-genesis2-mib.obj: eaton-pdu-genesis2-mib.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(snmp_ups_CFLAGS) $(CFLAGS) -MT snmp_ups-eaton-pdu-genesis2-mib.obj -MD -MP -MF $(DEPDIR)/snmp_ups-eaton-pdu-genesis2-mib.Tpo -c -o snmp_ups-eaton-pdu-genesis2-mib.obj `if test -f 'eaton-pdu-genesis2-mib.c'; then $(CYGPATH_W) 'eaton-pdu-genesis2-mib.c'; else $(CYGPATH_W) '$(srcdir)/eaton-pdu-genesis2-mib.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/snmp_ups-eaton-pdu-genesis2-mib.Tpo $(DEPDIR)/snmp_ups-eaton-pdu-genesis2-mib.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='eaton-pdu-genesis2-mib.c' object='snmp_ups-eaton-pdu-genesis2-mib.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(snmp_ups_CFLAGS) $(CFLAGS) -c -o snmp_ups-eaton-pdu-genesis2-mib.obj `if test -f 'eaton-pdu-genesis2-mib.c'; then $(CYGPATH_W) 'eaton-pdu-genesis2-mib.c'; else $(CYGPATH_W) '$(srcdir)/eaton-pdu-genesis2-mib.c'; fi` snmp_ups-eaton-pdu-marlin-mib.o: eaton-pdu-marlin-mib.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(snmp_ups_CFLAGS) $(CFLAGS) -MT snmp_ups-eaton-pdu-marlin-mib.o -MD -MP -MF $(DEPDIR)/snmp_ups-eaton-pdu-marlin-mib.Tpo -c -o snmp_ups-eaton-pdu-marlin-mib.o `test -f 'eaton-pdu-marlin-mib.c' || echo '$(srcdir)/'`eaton-pdu-marlin-mib.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/snmp_ups-eaton-pdu-marlin-mib.Tpo $(DEPDIR)/snmp_ups-eaton-pdu-marlin-mib.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='eaton-pdu-marlin-mib.c' object='snmp_ups-eaton-pdu-marlin-mib.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(snmp_ups_CFLAGS) $(CFLAGS) -c -o snmp_ups-eaton-pdu-marlin-mib.o `test -f 'eaton-pdu-marlin-mib.c' || echo '$(srcdir)/'`eaton-pdu-marlin-mib.c snmp_ups-eaton-pdu-marlin-mib.obj: eaton-pdu-marlin-mib.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(snmp_ups_CFLAGS) $(CFLAGS) -MT snmp_ups-eaton-pdu-marlin-mib.obj -MD -MP -MF $(DEPDIR)/snmp_ups-eaton-pdu-marlin-mib.Tpo -c -o snmp_ups-eaton-pdu-marlin-mib.obj `if test -f 'eaton-pdu-marlin-mib.c'; then $(CYGPATH_W) 'eaton-pdu-marlin-mib.c'; else $(CYGPATH_W) '$(srcdir)/eaton-pdu-marlin-mib.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/snmp_ups-eaton-pdu-marlin-mib.Tpo $(DEPDIR)/snmp_ups-eaton-pdu-marlin-mib.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='eaton-pdu-marlin-mib.c' object='snmp_ups-eaton-pdu-marlin-mib.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(snmp_ups_CFLAGS) $(CFLAGS) -c -o snmp_ups-eaton-pdu-marlin-mib.obj `if test -f 'eaton-pdu-marlin-mib.c'; then $(CYGPATH_W) 'eaton-pdu-marlin-mib.c'; else $(CYGPATH_W) '$(srcdir)/eaton-pdu-marlin-mib.c'; fi` snmp_ups-eaton-pdu-marlin-helpers.o: eaton-pdu-marlin-helpers.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(snmp_ups_CFLAGS) $(CFLAGS) -MT snmp_ups-eaton-pdu-marlin-helpers.o -MD -MP -MF $(DEPDIR)/snmp_ups-eaton-pdu-marlin-helpers.Tpo -c -o snmp_ups-eaton-pdu-marlin-helpers.o `test -f 'eaton-pdu-marlin-helpers.c' || echo '$(srcdir)/'`eaton-pdu-marlin-helpers.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/snmp_ups-eaton-pdu-marlin-helpers.Tpo $(DEPDIR)/snmp_ups-eaton-pdu-marlin-helpers.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='eaton-pdu-marlin-helpers.c' object='snmp_ups-eaton-pdu-marlin-helpers.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(snmp_ups_CFLAGS) $(CFLAGS) -c -o snmp_ups-eaton-pdu-marlin-helpers.o `test -f 'eaton-pdu-marlin-helpers.c' || echo '$(srcdir)/'`eaton-pdu-marlin-helpers.c snmp_ups-eaton-pdu-marlin-helpers.obj: eaton-pdu-marlin-helpers.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(snmp_ups_CFLAGS) $(CFLAGS) -MT snmp_ups-eaton-pdu-marlin-helpers.obj -MD -MP -MF $(DEPDIR)/snmp_ups-eaton-pdu-marlin-helpers.Tpo -c -o snmp_ups-eaton-pdu-marlin-helpers.obj `if test -f 'eaton-pdu-marlin-helpers.c'; then $(CYGPATH_W) 'eaton-pdu-marlin-helpers.c'; else $(CYGPATH_W) '$(srcdir)/eaton-pdu-marlin-helpers.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/snmp_ups-eaton-pdu-marlin-helpers.Tpo $(DEPDIR)/snmp_ups-eaton-pdu-marlin-helpers.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='eaton-pdu-marlin-helpers.c' object='snmp_ups-eaton-pdu-marlin-helpers.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(snmp_ups_CFLAGS) $(CFLAGS) -c -o snmp_ups-eaton-pdu-marlin-helpers.obj `if test -f 'eaton-pdu-marlin-helpers.c'; then $(CYGPATH_W) 'eaton-pdu-marlin-helpers.c'; else $(CYGPATH_W) '$(srcdir)/eaton-pdu-marlin-helpers.c'; fi` snmp_ups-eaton-pdu-pulizzi-mib.o: eaton-pdu-pulizzi-mib.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(snmp_ups_CFLAGS) $(CFLAGS) -MT snmp_ups-eaton-pdu-pulizzi-mib.o -MD -MP -MF $(DEPDIR)/snmp_ups-eaton-pdu-pulizzi-mib.Tpo -c -o snmp_ups-eaton-pdu-pulizzi-mib.o `test -f 'eaton-pdu-pulizzi-mib.c' || echo '$(srcdir)/'`eaton-pdu-pulizzi-mib.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/snmp_ups-eaton-pdu-pulizzi-mib.Tpo $(DEPDIR)/snmp_ups-eaton-pdu-pulizzi-mib.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='eaton-pdu-pulizzi-mib.c' object='snmp_ups-eaton-pdu-pulizzi-mib.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(snmp_ups_CFLAGS) $(CFLAGS) -c -o snmp_ups-eaton-pdu-pulizzi-mib.o `test -f 'eaton-pdu-pulizzi-mib.c' || echo '$(srcdir)/'`eaton-pdu-pulizzi-mib.c snmp_ups-eaton-pdu-pulizzi-mib.obj: eaton-pdu-pulizzi-mib.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(snmp_ups_CFLAGS) $(CFLAGS) -MT snmp_ups-eaton-pdu-pulizzi-mib.obj -MD -MP -MF $(DEPDIR)/snmp_ups-eaton-pdu-pulizzi-mib.Tpo -c -o snmp_ups-eaton-pdu-pulizzi-mib.obj `if test -f 'eaton-pdu-pulizzi-mib.c'; then $(CYGPATH_W) 'eaton-pdu-pulizzi-mib.c'; else $(CYGPATH_W) '$(srcdir)/eaton-pdu-pulizzi-mib.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/snmp_ups-eaton-pdu-pulizzi-mib.Tpo $(DEPDIR)/snmp_ups-eaton-pdu-pulizzi-mib.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='eaton-pdu-pulizzi-mib.c' object='snmp_ups-eaton-pdu-pulizzi-mib.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(snmp_ups_CFLAGS) $(CFLAGS) -c -o snmp_ups-eaton-pdu-pulizzi-mib.obj `if test -f 'eaton-pdu-pulizzi-mib.c'; then $(CYGPATH_W) 'eaton-pdu-pulizzi-mib.c'; else $(CYGPATH_W) '$(srcdir)/eaton-pdu-pulizzi-mib.c'; fi` snmp_ups-eaton-pdu-revelation-mib.o: eaton-pdu-revelation-mib.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(snmp_ups_CFLAGS) $(CFLAGS) -MT snmp_ups-eaton-pdu-revelation-mib.o -MD -MP -MF $(DEPDIR)/snmp_ups-eaton-pdu-revelation-mib.Tpo -c -o snmp_ups-eaton-pdu-revelation-mib.o `test -f 'eaton-pdu-revelation-mib.c' || echo '$(srcdir)/'`eaton-pdu-revelation-mib.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/snmp_ups-eaton-pdu-revelation-mib.Tpo $(DEPDIR)/snmp_ups-eaton-pdu-revelation-mib.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='eaton-pdu-revelation-mib.c' object='snmp_ups-eaton-pdu-revelation-mib.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(snmp_ups_CFLAGS) $(CFLAGS) -c -o snmp_ups-eaton-pdu-revelation-mib.o `test -f 'eaton-pdu-revelation-mib.c' || echo '$(srcdir)/'`eaton-pdu-revelation-mib.c snmp_ups-eaton-pdu-revelation-mib.obj: eaton-pdu-revelation-mib.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(snmp_ups_CFLAGS) $(CFLAGS) -MT snmp_ups-eaton-pdu-revelation-mib.obj -MD -MP -MF $(DEPDIR)/snmp_ups-eaton-pdu-revelation-mib.Tpo -c -o snmp_ups-eaton-pdu-revelation-mib.obj `if test -f 'eaton-pdu-revelation-mib.c'; then $(CYGPATH_W) 'eaton-pdu-revelation-mib.c'; else $(CYGPATH_W) '$(srcdir)/eaton-pdu-revelation-mib.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/snmp_ups-eaton-pdu-revelation-mib.Tpo $(DEPDIR)/snmp_ups-eaton-pdu-revelation-mib.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='eaton-pdu-revelation-mib.c' object='snmp_ups-eaton-pdu-revelation-mib.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(snmp_ups_CFLAGS) $(CFLAGS) -c -o snmp_ups-eaton-pdu-revelation-mib.obj `if test -f 'eaton-pdu-revelation-mib.c'; then $(CYGPATH_W) 'eaton-pdu-revelation-mib.c'; else $(CYGPATH_W) '$(srcdir)/eaton-pdu-revelation-mib.c'; fi` snmp_ups-eaton-pdu-nlogic-mib.o: eaton-pdu-nlogic-mib.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(snmp_ups_CFLAGS) $(CFLAGS) -MT snmp_ups-eaton-pdu-nlogic-mib.o -MD -MP -MF $(DEPDIR)/snmp_ups-eaton-pdu-nlogic-mib.Tpo -c -o snmp_ups-eaton-pdu-nlogic-mib.o `test -f 'eaton-pdu-nlogic-mib.c' || echo '$(srcdir)/'`eaton-pdu-nlogic-mib.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/snmp_ups-eaton-pdu-nlogic-mib.Tpo $(DEPDIR)/snmp_ups-eaton-pdu-nlogic-mib.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='eaton-pdu-nlogic-mib.c' object='snmp_ups-eaton-pdu-nlogic-mib.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(snmp_ups_CFLAGS) $(CFLAGS) -c -o snmp_ups-eaton-pdu-nlogic-mib.o `test -f 'eaton-pdu-nlogic-mib.c' || echo '$(srcdir)/'`eaton-pdu-nlogic-mib.c snmp_ups-eaton-pdu-nlogic-mib.obj: eaton-pdu-nlogic-mib.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(snmp_ups_CFLAGS) $(CFLAGS) -MT snmp_ups-eaton-pdu-nlogic-mib.obj -MD -MP -MF $(DEPDIR)/snmp_ups-eaton-pdu-nlogic-mib.Tpo -c -o snmp_ups-eaton-pdu-nlogic-mib.obj `if test -f 'eaton-pdu-nlogic-mib.c'; then $(CYGPATH_W) 'eaton-pdu-nlogic-mib.c'; else $(CYGPATH_W) '$(srcdir)/eaton-pdu-nlogic-mib.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/snmp_ups-eaton-pdu-nlogic-mib.Tpo $(DEPDIR)/snmp_ups-eaton-pdu-nlogic-mib.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='eaton-pdu-nlogic-mib.c' object='snmp_ups-eaton-pdu-nlogic-mib.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(snmp_ups_CFLAGS) $(CFLAGS) -c -o snmp_ups-eaton-pdu-nlogic-mib.obj `if test -f 'eaton-pdu-nlogic-mib.c'; then $(CYGPATH_W) 'eaton-pdu-nlogic-mib.c'; else $(CYGPATH_W) '$(srcdir)/eaton-pdu-nlogic-mib.c'; fi` snmp_ups-eaton-ats16-nmc-mib.o: eaton-ats16-nmc-mib.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(snmp_ups_CFLAGS) $(CFLAGS) -MT snmp_ups-eaton-ats16-nmc-mib.o -MD -MP -MF $(DEPDIR)/snmp_ups-eaton-ats16-nmc-mib.Tpo -c -o snmp_ups-eaton-ats16-nmc-mib.o `test -f 'eaton-ats16-nmc-mib.c' || echo '$(srcdir)/'`eaton-ats16-nmc-mib.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/snmp_ups-eaton-ats16-nmc-mib.Tpo $(DEPDIR)/snmp_ups-eaton-ats16-nmc-mib.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='eaton-ats16-nmc-mib.c' object='snmp_ups-eaton-ats16-nmc-mib.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(snmp_ups_CFLAGS) $(CFLAGS) -c -o snmp_ups-eaton-ats16-nmc-mib.o `test -f 'eaton-ats16-nmc-mib.c' || echo '$(srcdir)/'`eaton-ats16-nmc-mib.c snmp_ups-eaton-ats16-nmc-mib.obj: eaton-ats16-nmc-mib.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(snmp_ups_CFLAGS) $(CFLAGS) -MT snmp_ups-eaton-ats16-nmc-mib.obj -MD -MP -MF $(DEPDIR)/snmp_ups-eaton-ats16-nmc-mib.Tpo -c -o snmp_ups-eaton-ats16-nmc-mib.obj `if test -f 'eaton-ats16-nmc-mib.c'; then $(CYGPATH_W) 'eaton-ats16-nmc-mib.c'; else $(CYGPATH_W) '$(srcdir)/eaton-ats16-nmc-mib.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/snmp_ups-eaton-ats16-nmc-mib.Tpo $(DEPDIR)/snmp_ups-eaton-ats16-nmc-mib.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='eaton-ats16-nmc-mib.c' object='snmp_ups-eaton-ats16-nmc-mib.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(snmp_ups_CFLAGS) $(CFLAGS) -c -o snmp_ups-eaton-ats16-nmc-mib.obj `if test -f 'eaton-ats16-nmc-mib.c'; then $(CYGPATH_W) 'eaton-ats16-nmc-mib.c'; else $(CYGPATH_W) '$(srcdir)/eaton-ats16-nmc-mib.c'; fi` snmp_ups-eaton-ats16-nm2-mib.o: eaton-ats16-nm2-mib.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(snmp_ups_CFLAGS) $(CFLAGS) -MT snmp_ups-eaton-ats16-nm2-mib.o -MD -MP -MF $(DEPDIR)/snmp_ups-eaton-ats16-nm2-mib.Tpo -c -o snmp_ups-eaton-ats16-nm2-mib.o `test -f 'eaton-ats16-nm2-mib.c' || echo '$(srcdir)/'`eaton-ats16-nm2-mib.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/snmp_ups-eaton-ats16-nm2-mib.Tpo $(DEPDIR)/snmp_ups-eaton-ats16-nm2-mib.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='eaton-ats16-nm2-mib.c' object='snmp_ups-eaton-ats16-nm2-mib.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(snmp_ups_CFLAGS) $(CFLAGS) -c -o snmp_ups-eaton-ats16-nm2-mib.o `test -f 'eaton-ats16-nm2-mib.c' || echo '$(srcdir)/'`eaton-ats16-nm2-mib.c snmp_ups-eaton-ats16-nm2-mib.obj: eaton-ats16-nm2-mib.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(snmp_ups_CFLAGS) $(CFLAGS) -MT snmp_ups-eaton-ats16-nm2-mib.obj -MD -MP -MF $(DEPDIR)/snmp_ups-eaton-ats16-nm2-mib.Tpo -c -o snmp_ups-eaton-ats16-nm2-mib.obj `if test -f 'eaton-ats16-nm2-mib.c'; then $(CYGPATH_W) 'eaton-ats16-nm2-mib.c'; else $(CYGPATH_W) '$(srcdir)/eaton-ats16-nm2-mib.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/snmp_ups-eaton-ats16-nm2-mib.Tpo $(DEPDIR)/snmp_ups-eaton-ats16-nm2-mib.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='eaton-ats16-nm2-mib.c' object='snmp_ups-eaton-ats16-nm2-mib.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(snmp_ups_CFLAGS) $(CFLAGS) -c -o snmp_ups-eaton-ats16-nm2-mib.obj `if test -f 'eaton-ats16-nm2-mib.c'; then $(CYGPATH_W) 'eaton-ats16-nm2-mib.c'; else $(CYGPATH_W) '$(srcdir)/eaton-ats16-nm2-mib.c'; fi` snmp_ups-apc-ats-mib.o: apc-ats-mib.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(snmp_ups_CFLAGS) $(CFLAGS) -MT snmp_ups-apc-ats-mib.o -MD -MP -MF $(DEPDIR)/snmp_ups-apc-ats-mib.Tpo -c -o snmp_ups-apc-ats-mib.o `test -f 'apc-ats-mib.c' || echo '$(srcdir)/'`apc-ats-mib.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/snmp_ups-apc-ats-mib.Tpo $(DEPDIR)/snmp_ups-apc-ats-mib.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='apc-ats-mib.c' object='snmp_ups-apc-ats-mib.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(snmp_ups_CFLAGS) $(CFLAGS) -c -o snmp_ups-apc-ats-mib.o `test -f 'apc-ats-mib.c' || echo '$(srcdir)/'`apc-ats-mib.c snmp_ups-apc-ats-mib.obj: apc-ats-mib.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(snmp_ups_CFLAGS) $(CFLAGS) -MT snmp_ups-apc-ats-mib.obj -MD -MP -MF $(DEPDIR)/snmp_ups-apc-ats-mib.Tpo -c -o snmp_ups-apc-ats-mib.obj `if test -f 'apc-ats-mib.c'; then $(CYGPATH_W) 'apc-ats-mib.c'; else $(CYGPATH_W) '$(srcdir)/apc-ats-mib.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/snmp_ups-apc-ats-mib.Tpo $(DEPDIR)/snmp_ups-apc-ats-mib.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='apc-ats-mib.c' object='snmp_ups-apc-ats-mib.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(snmp_ups_CFLAGS) $(CFLAGS) -c -o snmp_ups-apc-ats-mib.obj `if test -f 'apc-ats-mib.c'; then $(CYGPATH_W) 'apc-ats-mib.c'; else $(CYGPATH_W) '$(srcdir)/apc-ats-mib.c'; fi` snmp_ups-eaton-ats30-mib.o: eaton-ats30-mib.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(snmp_ups_CFLAGS) $(CFLAGS) -MT snmp_ups-eaton-ats30-mib.o -MD -MP -MF $(DEPDIR)/snmp_ups-eaton-ats30-mib.Tpo -c -o snmp_ups-eaton-ats30-mib.o `test -f 'eaton-ats30-mib.c' || echo '$(srcdir)/'`eaton-ats30-mib.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/snmp_ups-eaton-ats30-mib.Tpo $(DEPDIR)/snmp_ups-eaton-ats30-mib.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='eaton-ats30-mib.c' object='snmp_ups-eaton-ats30-mib.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(snmp_ups_CFLAGS) $(CFLAGS) -c -o snmp_ups-eaton-ats30-mib.o `test -f 'eaton-ats30-mib.c' || echo '$(srcdir)/'`eaton-ats30-mib.c snmp_ups-eaton-ats30-mib.obj: eaton-ats30-mib.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(snmp_ups_CFLAGS) $(CFLAGS) -MT snmp_ups-eaton-ats30-mib.obj -MD -MP -MF $(DEPDIR)/snmp_ups-eaton-ats30-mib.Tpo -c -o snmp_ups-eaton-ats30-mib.obj `if test -f 'eaton-ats30-mib.c'; then $(CYGPATH_W) 'eaton-ats30-mib.c'; else $(CYGPATH_W) '$(srcdir)/eaton-ats30-mib.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/snmp_ups-eaton-ats30-mib.Tpo $(DEPDIR)/snmp_ups-eaton-ats30-mib.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='eaton-ats30-mib.c' object='snmp_ups-eaton-ats30-mib.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(snmp_ups_CFLAGS) $(CFLAGS) -c -o snmp_ups-eaton-ats30-mib.obj `if test -f 'eaton-ats30-mib.c'; then $(CYGPATH_W) 'eaton-ats30-mib.c'; else $(CYGPATH_W) '$(srcdir)/eaton-ats30-mib.c'; fi` snmp_ups-eaton-ups-pwnm2-mib.o: eaton-ups-pwnm2-mib.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(snmp_ups_CFLAGS) $(CFLAGS) -MT snmp_ups-eaton-ups-pwnm2-mib.o -MD -MP -MF $(DEPDIR)/snmp_ups-eaton-ups-pwnm2-mib.Tpo -c -o snmp_ups-eaton-ups-pwnm2-mib.o `test -f 'eaton-ups-pwnm2-mib.c' || echo '$(srcdir)/'`eaton-ups-pwnm2-mib.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/snmp_ups-eaton-ups-pwnm2-mib.Tpo $(DEPDIR)/snmp_ups-eaton-ups-pwnm2-mib.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='eaton-ups-pwnm2-mib.c' object='snmp_ups-eaton-ups-pwnm2-mib.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(snmp_ups_CFLAGS) $(CFLAGS) -c -o snmp_ups-eaton-ups-pwnm2-mib.o `test -f 'eaton-ups-pwnm2-mib.c' || echo '$(srcdir)/'`eaton-ups-pwnm2-mib.c snmp_ups-eaton-ups-pwnm2-mib.obj: eaton-ups-pwnm2-mib.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(snmp_ups_CFLAGS) $(CFLAGS) -MT snmp_ups-eaton-ups-pwnm2-mib.obj -MD -MP -MF $(DEPDIR)/snmp_ups-eaton-ups-pwnm2-mib.Tpo -c -o snmp_ups-eaton-ups-pwnm2-mib.obj `if test -f 'eaton-ups-pwnm2-mib.c'; then $(CYGPATH_W) 'eaton-ups-pwnm2-mib.c'; else $(CYGPATH_W) '$(srcdir)/eaton-ups-pwnm2-mib.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/snmp_ups-eaton-ups-pwnm2-mib.Tpo $(DEPDIR)/snmp_ups-eaton-ups-pwnm2-mib.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='eaton-ups-pwnm2-mib.c' object='snmp_ups-eaton-ups-pwnm2-mib.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(snmp_ups_CFLAGS) $(CFLAGS) -c -o snmp_ups-eaton-ups-pwnm2-mib.obj `if test -f 'eaton-ups-pwnm2-mib.c'; then $(CYGPATH_W) 'eaton-ups-pwnm2-mib.c'; else $(CYGPATH_W) '$(srcdir)/eaton-ups-pwnm2-mib.c'; fi` snmp_ups-eaton-ups-pxg-mib.o: eaton-ups-pxg-mib.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(snmp_ups_CFLAGS) $(CFLAGS) -MT snmp_ups-eaton-ups-pxg-mib.o -MD -MP -MF $(DEPDIR)/snmp_ups-eaton-ups-pxg-mib.Tpo -c -o snmp_ups-eaton-ups-pxg-mib.o `test -f 'eaton-ups-pxg-mib.c' || echo '$(srcdir)/'`eaton-ups-pxg-mib.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/snmp_ups-eaton-ups-pxg-mib.Tpo $(DEPDIR)/snmp_ups-eaton-ups-pxg-mib.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='eaton-ups-pxg-mib.c' object='snmp_ups-eaton-ups-pxg-mib.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(snmp_ups_CFLAGS) $(CFLAGS) -c -o snmp_ups-eaton-ups-pxg-mib.o `test -f 'eaton-ups-pxg-mib.c' || echo '$(srcdir)/'`eaton-ups-pxg-mib.c snmp_ups-eaton-ups-pxg-mib.obj: eaton-ups-pxg-mib.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(snmp_ups_CFLAGS) $(CFLAGS) -MT snmp_ups-eaton-ups-pxg-mib.obj -MD -MP -MF $(DEPDIR)/snmp_ups-eaton-ups-pxg-mib.Tpo -c -o snmp_ups-eaton-ups-pxg-mib.obj `if test -f 'eaton-ups-pxg-mib.c'; then $(CYGPATH_W) 'eaton-ups-pxg-mib.c'; else $(CYGPATH_W) '$(srcdir)/eaton-ups-pxg-mib.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/snmp_ups-eaton-ups-pxg-mib.Tpo $(DEPDIR)/snmp_ups-eaton-ups-pxg-mib.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='eaton-ups-pxg-mib.c' object='snmp_ups-eaton-ups-pxg-mib.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(snmp_ups_CFLAGS) $(CFLAGS) -c -o snmp_ups-eaton-ups-pxg-mib.obj `if test -f 'eaton-ups-pxg-mib.c'; then $(CYGPATH_W) 'eaton-ups-pxg-mib.c'; else $(CYGPATH_W) '$(srcdir)/eaton-ups-pxg-mib.c'; fi` snmp_ups-emerson-avocent-pdu-mib.o: emerson-avocent-pdu-mib.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(snmp_ups_CFLAGS) $(CFLAGS) -MT snmp_ups-emerson-avocent-pdu-mib.o -MD -MP -MF $(DEPDIR)/snmp_ups-emerson-avocent-pdu-mib.Tpo -c -o snmp_ups-emerson-avocent-pdu-mib.o `test -f 'emerson-avocent-pdu-mib.c' || echo '$(srcdir)/'`emerson-avocent-pdu-mib.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/snmp_ups-emerson-avocent-pdu-mib.Tpo $(DEPDIR)/snmp_ups-emerson-avocent-pdu-mib.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='emerson-avocent-pdu-mib.c' object='snmp_ups-emerson-avocent-pdu-mib.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(snmp_ups_CFLAGS) $(CFLAGS) -c -o snmp_ups-emerson-avocent-pdu-mib.o `test -f 'emerson-avocent-pdu-mib.c' || echo '$(srcdir)/'`emerson-avocent-pdu-mib.c snmp_ups-emerson-avocent-pdu-mib.obj: emerson-avocent-pdu-mib.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(snmp_ups_CFLAGS) $(CFLAGS) -MT snmp_ups-emerson-avocent-pdu-mib.obj -MD -MP -MF $(DEPDIR)/snmp_ups-emerson-avocent-pdu-mib.Tpo -c -o snmp_ups-emerson-avocent-pdu-mib.obj `if test -f 'emerson-avocent-pdu-mib.c'; then $(CYGPATH_W) 'emerson-avocent-pdu-mib.c'; else $(CYGPATH_W) '$(srcdir)/emerson-avocent-pdu-mib.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/snmp_ups-emerson-avocent-pdu-mib.Tpo $(DEPDIR)/snmp_ups-emerson-avocent-pdu-mib.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='emerson-avocent-pdu-mib.c' object='snmp_ups-emerson-avocent-pdu-mib.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(snmp_ups_CFLAGS) $(CFLAGS) -c -o snmp_ups-emerson-avocent-pdu-mib.obj `if test -f 'emerson-avocent-pdu-mib.c'; then $(CYGPATH_W) 'emerson-avocent-pdu-mib.c'; else $(CYGPATH_W) '$(srcdir)/emerson-avocent-pdu-mib.c'; fi` snmp_ups-hpe-pdu-mib.o: hpe-pdu-mib.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(snmp_ups_CFLAGS) $(CFLAGS) -MT snmp_ups-hpe-pdu-mib.o -MD -MP -MF $(DEPDIR)/snmp_ups-hpe-pdu-mib.Tpo -c -o snmp_ups-hpe-pdu-mib.o `test -f 'hpe-pdu-mib.c' || echo '$(srcdir)/'`hpe-pdu-mib.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/snmp_ups-hpe-pdu-mib.Tpo $(DEPDIR)/snmp_ups-hpe-pdu-mib.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='hpe-pdu-mib.c' object='snmp_ups-hpe-pdu-mib.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(snmp_ups_CFLAGS) $(CFLAGS) -c -o snmp_ups-hpe-pdu-mib.o `test -f 'hpe-pdu-mib.c' || echo '$(srcdir)/'`hpe-pdu-mib.c snmp_ups-hpe-pdu-mib.obj: hpe-pdu-mib.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(snmp_ups_CFLAGS) $(CFLAGS) -MT snmp_ups-hpe-pdu-mib.obj -MD -MP -MF $(DEPDIR)/snmp_ups-hpe-pdu-mib.Tpo -c -o snmp_ups-hpe-pdu-mib.obj `if test -f 'hpe-pdu-mib.c'; then $(CYGPATH_W) 'hpe-pdu-mib.c'; else $(CYGPATH_W) '$(srcdir)/hpe-pdu-mib.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/snmp_ups-hpe-pdu-mib.Tpo $(DEPDIR)/snmp_ups-hpe-pdu-mib.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='hpe-pdu-mib.c' object='snmp_ups-hpe-pdu-mib.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(snmp_ups_CFLAGS) $(CFLAGS) -c -o snmp_ups-hpe-pdu-mib.obj `if test -f 'hpe-pdu-mib.c'; then $(CYGPATH_W) 'hpe-pdu-mib.c'; else $(CYGPATH_W) '$(srcdir)/hpe-pdu-mib.c'; fi` snmp_ups-hpe-pdu3-cis-mib.o: hpe-pdu3-cis-mib.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(snmp_ups_CFLAGS) $(CFLAGS) -MT snmp_ups-hpe-pdu3-cis-mib.o -MD -MP -MF $(DEPDIR)/snmp_ups-hpe-pdu3-cis-mib.Tpo -c -o snmp_ups-hpe-pdu3-cis-mib.o `test -f 'hpe-pdu3-cis-mib.c' || echo '$(srcdir)/'`hpe-pdu3-cis-mib.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/snmp_ups-hpe-pdu3-cis-mib.Tpo $(DEPDIR)/snmp_ups-hpe-pdu3-cis-mib.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='hpe-pdu3-cis-mib.c' object='snmp_ups-hpe-pdu3-cis-mib.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(snmp_ups_CFLAGS) $(CFLAGS) -c -o snmp_ups-hpe-pdu3-cis-mib.o `test -f 'hpe-pdu3-cis-mib.c' || echo '$(srcdir)/'`hpe-pdu3-cis-mib.c snmp_ups-hpe-pdu3-cis-mib.obj: hpe-pdu3-cis-mib.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(snmp_ups_CFLAGS) $(CFLAGS) -MT snmp_ups-hpe-pdu3-cis-mib.obj -MD -MP -MF $(DEPDIR)/snmp_ups-hpe-pdu3-cis-mib.Tpo -c -o snmp_ups-hpe-pdu3-cis-mib.obj `if test -f 'hpe-pdu3-cis-mib.c'; then $(CYGPATH_W) 'hpe-pdu3-cis-mib.c'; else $(CYGPATH_W) '$(srcdir)/hpe-pdu3-cis-mib.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/snmp_ups-hpe-pdu3-cis-mib.Tpo $(DEPDIR)/snmp_ups-hpe-pdu3-cis-mib.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='hpe-pdu3-cis-mib.c' object='snmp_ups-hpe-pdu3-cis-mib.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(snmp_ups_CFLAGS) $(CFLAGS) -c -o snmp_ups-hpe-pdu3-cis-mib.obj `if test -f 'hpe-pdu3-cis-mib.c'; then $(CYGPATH_W) 'hpe-pdu3-cis-mib.c'; else $(CYGPATH_W) '$(srcdir)/hpe-pdu3-cis-mib.c'; fi` snmp_ups-huawei-mib.o: huawei-mib.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(snmp_ups_CFLAGS) $(CFLAGS) -MT snmp_ups-huawei-mib.o -MD -MP -MF $(DEPDIR)/snmp_ups-huawei-mib.Tpo -c -o snmp_ups-huawei-mib.o `test -f 'huawei-mib.c' || echo '$(srcdir)/'`huawei-mib.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/snmp_ups-huawei-mib.Tpo $(DEPDIR)/snmp_ups-huawei-mib.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='huawei-mib.c' object='snmp_ups-huawei-mib.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(snmp_ups_CFLAGS) $(CFLAGS) -c -o snmp_ups-huawei-mib.o `test -f 'huawei-mib.c' || echo '$(srcdir)/'`huawei-mib.c snmp_ups-huawei-mib.obj: huawei-mib.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(snmp_ups_CFLAGS) $(CFLAGS) -MT snmp_ups-huawei-mib.obj -MD -MP -MF $(DEPDIR)/snmp_ups-huawei-mib.Tpo -c -o snmp_ups-huawei-mib.obj `if test -f 'huawei-mib.c'; then $(CYGPATH_W) 'huawei-mib.c'; else $(CYGPATH_W) '$(srcdir)/huawei-mib.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/snmp_ups-huawei-mib.Tpo $(DEPDIR)/snmp_ups-huawei-mib.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='huawei-mib.c' object='snmp_ups-huawei-mib.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(snmp_ups_CFLAGS) $(CFLAGS) -c -o snmp_ups-huawei-mib.obj `if test -f 'huawei-mib.c'; then $(CYGPATH_W) 'huawei-mib.c'; else $(CYGPATH_W) '$(srcdir)/huawei-mib.c'; fi` snmp_ups-ietf-mib.o: ietf-mib.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(snmp_ups_CFLAGS) $(CFLAGS) -MT snmp_ups-ietf-mib.o -MD -MP -MF $(DEPDIR)/snmp_ups-ietf-mib.Tpo -c -o snmp_ups-ietf-mib.o `test -f 'ietf-mib.c' || echo '$(srcdir)/'`ietf-mib.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/snmp_ups-ietf-mib.Tpo $(DEPDIR)/snmp_ups-ietf-mib.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='ietf-mib.c' object='snmp_ups-ietf-mib.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(snmp_ups_CFLAGS) $(CFLAGS) -c -o snmp_ups-ietf-mib.o `test -f 'ietf-mib.c' || echo '$(srcdir)/'`ietf-mib.c snmp_ups-ietf-mib.obj: ietf-mib.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(snmp_ups_CFLAGS) $(CFLAGS) -MT snmp_ups-ietf-mib.obj -MD -MP -MF $(DEPDIR)/snmp_ups-ietf-mib.Tpo -c -o snmp_ups-ietf-mib.obj `if test -f 'ietf-mib.c'; then $(CYGPATH_W) 'ietf-mib.c'; else $(CYGPATH_W) '$(srcdir)/ietf-mib.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/snmp_ups-ietf-mib.Tpo $(DEPDIR)/snmp_ups-ietf-mib.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='ietf-mib.c' object='snmp_ups-ietf-mib.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(snmp_ups_CFLAGS) $(CFLAGS) -c -o snmp_ups-ietf-mib.obj `if test -f 'ietf-mib.c'; then $(CYGPATH_W) 'ietf-mib.c'; else $(CYGPATH_W) '$(srcdir)/ietf-mib.c'; fi` snmp_ups-mge-mib.o: mge-mib.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(snmp_ups_CFLAGS) $(CFLAGS) -MT snmp_ups-mge-mib.o -MD -MP -MF $(DEPDIR)/snmp_ups-mge-mib.Tpo -c -o snmp_ups-mge-mib.o `test -f 'mge-mib.c' || echo '$(srcdir)/'`mge-mib.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/snmp_ups-mge-mib.Tpo $(DEPDIR)/snmp_ups-mge-mib.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='mge-mib.c' object='snmp_ups-mge-mib.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(snmp_ups_CFLAGS) $(CFLAGS) -c -o snmp_ups-mge-mib.o `test -f 'mge-mib.c' || echo '$(srcdir)/'`mge-mib.c snmp_ups-mge-mib.obj: mge-mib.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(snmp_ups_CFLAGS) $(CFLAGS) -MT snmp_ups-mge-mib.obj -MD -MP -MF $(DEPDIR)/snmp_ups-mge-mib.Tpo -c -o snmp_ups-mge-mib.obj `if test -f 'mge-mib.c'; then $(CYGPATH_W) 'mge-mib.c'; else $(CYGPATH_W) '$(srcdir)/mge-mib.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/snmp_ups-mge-mib.Tpo $(DEPDIR)/snmp_ups-mge-mib.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='mge-mib.c' object='snmp_ups-mge-mib.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(snmp_ups_CFLAGS) $(CFLAGS) -c -o snmp_ups-mge-mib.obj `if test -f 'mge-mib.c'; then $(CYGPATH_W) 'mge-mib.c'; else $(CYGPATH_W) '$(srcdir)/mge-mib.c'; fi` snmp_ups-netvision-mib.o: netvision-mib.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(snmp_ups_CFLAGS) $(CFLAGS) -MT snmp_ups-netvision-mib.o -MD -MP -MF $(DEPDIR)/snmp_ups-netvision-mib.Tpo -c -o snmp_ups-netvision-mib.o `test -f 'netvision-mib.c' || echo '$(srcdir)/'`netvision-mib.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/snmp_ups-netvision-mib.Tpo $(DEPDIR)/snmp_ups-netvision-mib.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='netvision-mib.c' object='snmp_ups-netvision-mib.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(snmp_ups_CFLAGS) $(CFLAGS) -c -o snmp_ups-netvision-mib.o `test -f 'netvision-mib.c' || echo '$(srcdir)/'`netvision-mib.c snmp_ups-netvision-mib.obj: netvision-mib.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(snmp_ups_CFLAGS) $(CFLAGS) -MT snmp_ups-netvision-mib.obj -MD -MP -MF $(DEPDIR)/snmp_ups-netvision-mib.Tpo -c -o snmp_ups-netvision-mib.obj `if test -f 'netvision-mib.c'; then $(CYGPATH_W) 'netvision-mib.c'; else $(CYGPATH_W) '$(srcdir)/netvision-mib.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/snmp_ups-netvision-mib.Tpo $(DEPDIR)/snmp_ups-netvision-mib.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='netvision-mib.c' object='snmp_ups-netvision-mib.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(snmp_ups_CFLAGS) $(CFLAGS) -c -o snmp_ups-netvision-mib.obj `if test -f 'netvision-mib.c'; then $(CYGPATH_W) 'netvision-mib.c'; else $(CYGPATH_W) '$(srcdir)/netvision-mib.c'; fi` snmp_ups-raritan-pdu-mib.o: raritan-pdu-mib.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(snmp_ups_CFLAGS) $(CFLAGS) -MT snmp_ups-raritan-pdu-mib.o -MD -MP -MF $(DEPDIR)/snmp_ups-raritan-pdu-mib.Tpo -c -o snmp_ups-raritan-pdu-mib.o `test -f 'raritan-pdu-mib.c' || echo '$(srcdir)/'`raritan-pdu-mib.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/snmp_ups-raritan-pdu-mib.Tpo $(DEPDIR)/snmp_ups-raritan-pdu-mib.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='raritan-pdu-mib.c' object='snmp_ups-raritan-pdu-mib.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(snmp_ups_CFLAGS) $(CFLAGS) -c -o snmp_ups-raritan-pdu-mib.o `test -f 'raritan-pdu-mib.c' || echo '$(srcdir)/'`raritan-pdu-mib.c snmp_ups-raritan-pdu-mib.obj: raritan-pdu-mib.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(snmp_ups_CFLAGS) $(CFLAGS) -MT snmp_ups-raritan-pdu-mib.obj -MD -MP -MF $(DEPDIR)/snmp_ups-raritan-pdu-mib.Tpo -c -o snmp_ups-raritan-pdu-mib.obj `if test -f 'raritan-pdu-mib.c'; then $(CYGPATH_W) 'raritan-pdu-mib.c'; else $(CYGPATH_W) '$(srcdir)/raritan-pdu-mib.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/snmp_ups-raritan-pdu-mib.Tpo $(DEPDIR)/snmp_ups-raritan-pdu-mib.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='raritan-pdu-mib.c' object='snmp_ups-raritan-pdu-mib.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(snmp_ups_CFLAGS) $(CFLAGS) -c -o snmp_ups-raritan-pdu-mib.obj `if test -f 'raritan-pdu-mib.c'; then $(CYGPATH_W) 'raritan-pdu-mib.c'; else $(CYGPATH_W) '$(srcdir)/raritan-pdu-mib.c'; fi` snmp_ups-raritan-px2-mib.o: raritan-px2-mib.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(snmp_ups_CFLAGS) $(CFLAGS) -MT snmp_ups-raritan-px2-mib.o -MD -MP -MF $(DEPDIR)/snmp_ups-raritan-px2-mib.Tpo -c -o snmp_ups-raritan-px2-mib.o `test -f 'raritan-px2-mib.c' || echo '$(srcdir)/'`raritan-px2-mib.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/snmp_ups-raritan-px2-mib.Tpo $(DEPDIR)/snmp_ups-raritan-px2-mib.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='raritan-px2-mib.c' object='snmp_ups-raritan-px2-mib.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(snmp_ups_CFLAGS) $(CFLAGS) -c -o snmp_ups-raritan-px2-mib.o `test -f 'raritan-px2-mib.c' || echo '$(srcdir)/'`raritan-px2-mib.c snmp_ups-raritan-px2-mib.obj: raritan-px2-mib.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(snmp_ups_CFLAGS) $(CFLAGS) -MT snmp_ups-raritan-px2-mib.obj -MD -MP -MF $(DEPDIR)/snmp_ups-raritan-px2-mib.Tpo -c -o snmp_ups-raritan-px2-mib.obj `if test -f 'raritan-px2-mib.c'; then $(CYGPATH_W) 'raritan-px2-mib.c'; else $(CYGPATH_W) '$(srcdir)/raritan-px2-mib.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/snmp_ups-raritan-px2-mib.Tpo $(DEPDIR)/snmp_ups-raritan-px2-mib.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='raritan-px2-mib.c' object='snmp_ups-raritan-px2-mib.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(snmp_ups_CFLAGS) $(CFLAGS) -c -o snmp_ups-raritan-px2-mib.obj `if test -f 'raritan-px2-mib.c'; then $(CYGPATH_W) 'raritan-px2-mib.c'; else $(CYGPATH_W) '$(srcdir)/raritan-px2-mib.c'; fi` snmp_ups-xppc-mib.o: xppc-mib.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(snmp_ups_CFLAGS) $(CFLAGS) -MT snmp_ups-xppc-mib.o -MD -MP -MF $(DEPDIR)/snmp_ups-xppc-mib.Tpo -c -o snmp_ups-xppc-mib.o `test -f 'xppc-mib.c' || echo '$(srcdir)/'`xppc-mib.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/snmp_ups-xppc-mib.Tpo $(DEPDIR)/snmp_ups-xppc-mib.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='xppc-mib.c' object='snmp_ups-xppc-mib.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(snmp_ups_CFLAGS) $(CFLAGS) -c -o snmp_ups-xppc-mib.o `test -f 'xppc-mib.c' || echo '$(srcdir)/'`xppc-mib.c snmp_ups-xppc-mib.obj: xppc-mib.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(snmp_ups_CFLAGS) $(CFLAGS) -MT snmp_ups-xppc-mib.obj -MD -MP -MF $(DEPDIR)/snmp_ups-xppc-mib.Tpo -c -o snmp_ups-xppc-mib.obj `if test -f 'xppc-mib.c'; then $(CYGPATH_W) 'xppc-mib.c'; else $(CYGPATH_W) '$(srcdir)/xppc-mib.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/snmp_ups-xppc-mib.Tpo $(DEPDIR)/snmp_ups-xppc-mib.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='xppc-mib.c' object='snmp_ups-xppc-mib.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(snmp_ups_CFLAGS) $(CFLAGS) -c -o snmp_ups-xppc-mib.obj `if test -f 'xppc-mib.c'; then $(CYGPATH_W) 'xppc-mib.c'; else $(CYGPATH_W) '$(srcdir)/xppc-mib.c'; fi` mostlyclean-libtool: -rm -f *.lo clean-libtool: -rm -rf .libs _libs ID: $(am__tagged_files) $(am__define_uniq_tagged_files); mkid -fID $$unique tags: tags-am TAGS: tags tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) set x; \ here=`pwd`; \ $(am__define_uniq_tagged_files); \ shift; \ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ test -n "$$unique" || unique=$$empty_fix; \ if test $$# -gt 0; then \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ "$$@" $$unique; \ else \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ $$unique; \ fi; \ fi ctags: ctags-am CTAGS: ctags ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) $(am__define_uniq_tagged_files); \ test -z "$(CTAGS_ARGS)$$unique" \ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ $$unique GTAGS: here=`$(am__cd) $(top_builddir) && pwd` \ && $(am__cd) $(top_srcdir) \ && gtags -i $(GTAGS_ARGS) "$$here" cscopelist: cscopelist-am cscopelist-am: $(am__tagged_files) list='$(am__tagged_files)'; \ case "$(srcdir)" in \ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \ *) sdir=$(subdir)/$(srcdir) ;; \ esac; \ for i in $$list; do \ if test -f "$$i"; then \ echo "$(subdir)/$$i"; \ else \ echo "$$sdir/$$i"; \ fi; \ done >> $(top_builddir)/cscope.files distclean-tags: -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags distdir: $(BUILT_SOURCES) $(MAKE) $(AM_MAKEFLAGS) distdir-am distdir-am: $(DISTFILES) @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ dist_files=`for file in $$list; do echo $$file; done | \ sed -e "s|^$$srcdirstrip/||;t" \ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ case $$dist_files in \ */*) $(MKDIR_P) `echo "$$dist_files" | \ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ sort -u` ;; \ esac; \ for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d "$(distdir)/$$file"; then \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ else \ test -f "$(distdir)/$$file" \ || cp -p $$d/$$file "$(distdir)/$$file" \ || exit 1; \ fi; \ done check-am: all-am check: check-am all-am: Makefile $(PROGRAMS) $(HEADERS) installdirs: for dir in "$(DESTDIR)$(driverexecdir)" "$(DESTDIR)$(sbindir)"; do \ test -z "$$dir" || $(MKDIR_P) "$$dir"; \ done install: install-am install-exec: install-exec-am install-data: install-data-am uninstall: uninstall-am install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-am install-strip: if test -z '$(STRIP)'; then \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ install; \ else \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ fi mostlyclean-generic: clean-generic: -test -z "$(CLEANFILES)" || rm -f $(CLEANFILES) distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." -test -z "$(MAINTAINERCLEANFILES)" || rm -f $(MAINTAINERCLEANFILES) clean: clean-am clean-am: clean-driverexecPROGRAMS clean-generic clean-libtool \ clean-sbinPROGRAMS mostlyclean-am distclean: distclean-am -rm -f ./$(DEPDIR)/adelsystem_cbi.Po -rm -f ./$(DEPDIR)/al175.Po -rm -f ./$(DEPDIR)/apc-hid.Po -rm -f ./$(DEPDIR)/apc_modbus.Po -rm -f ./$(DEPDIR)/apcsmart-old.Po -rm -f ./$(DEPDIR)/apcsmart.Po -rm -f ./$(DEPDIR)/apcsmart_tabs.Po -rm -f ./$(DEPDIR)/apcupsd_ups-apcupsd-ups.Po -rm -f ./$(DEPDIR)/arduino-hid.Po -rm -f ./$(DEPDIR)/asem.Po -rm -f ./$(DEPDIR)/bcmxcp.Po -rm -f ./$(DEPDIR)/bcmxcp_ser.Po -rm -f ./$(DEPDIR)/bcmxcp_usb.Po -rm -f ./$(DEPDIR)/belkin-hid.Po -rm -f ./$(DEPDIR)/belkin.Po -rm -f ./$(DEPDIR)/belkinunv.Po -rm -f ./$(DEPDIR)/bestfcom.Po -rm -f ./$(DEPDIR)/bestfortress.Po -rm -f ./$(DEPDIR)/bestuferrups.Po -rm -f ./$(DEPDIR)/bestups.Po -rm -f ./$(DEPDIR)/blazer.Po -rm -f ./$(DEPDIR)/blazer_ser.Po -rm -f ./$(DEPDIR)/blazer_usb.Po -rm -f ./$(DEPDIR)/clone-outlet.Po -rm -f ./$(DEPDIR)/clone.Po -rm -f ./$(DEPDIR)/cps-hid.Po -rm -f ./$(DEPDIR)/delta_ups-hid.Po -rm -f ./$(DEPDIR)/dstate.Plo -rm -f ./$(DEPDIR)/dummy_ups-dummy-ups.Po -rm -f ./$(DEPDIR)/etapro.Po -rm -f ./$(DEPDIR)/ever-hid.Po -rm -f ./$(DEPDIR)/everups.Po -rm -f ./$(DEPDIR)/explore-hid.Po -rm -f ./$(DEPDIR)/gamatronic.Po -rm -f ./$(DEPDIR)/generic_gpio_common.Po -rm -f ./$(DEPDIR)/generic_gpio_libgpiod.Po -rm -f ./$(DEPDIR)/generic_modbus.Po -rm -f ./$(DEPDIR)/genericups.Po -rm -f ./$(DEPDIR)/hidparser.Po -rm -f ./$(DEPDIR)/huawei-ups2000.Po -rm -f ./$(DEPDIR)/idowell-hid.Po -rm -f ./$(DEPDIR)/isbmex.Po -rm -f ./$(DEPDIR)/ivtscd.Po -rm -f ./$(DEPDIR)/legrand-hid.Po -rm -f ./$(DEPDIR)/libdummy_mockdrv_la-dstate.Plo -rm -f ./$(DEPDIR)/libdummy_mockdrv_la-main.Plo -rm -f ./$(DEPDIR)/libhid.Po -rm -f ./$(DEPDIR)/libusb0.Po -rm -f ./$(DEPDIR)/libusb1.Po -rm -f ./$(DEPDIR)/liebert-esp2.Po -rm -f ./$(DEPDIR)/liebert-hid.Po -rm -f ./$(DEPDIR)/liebert.Po -rm -f ./$(DEPDIR)/macosx-ups.Po -rm -f ./$(DEPDIR)/main.Plo -rm -f ./$(DEPDIR)/masterguard.Po -rm -f ./$(DEPDIR)/metasys.Po -rm -f ./$(DEPDIR)/mge-hid.Po -rm -f ./$(DEPDIR)/mge-utalk.Po -rm -f ./$(DEPDIR)/mge-xml.Po -rm -f ./$(DEPDIR)/mge_shut-hidparser.Po -rm -f ./$(DEPDIR)/mge_shut-libhid.Po -rm -f ./$(DEPDIR)/mge_shut-libshut.Po -rm -f ./$(DEPDIR)/mge_shut-mge-hid.Po -rm -f ./$(DEPDIR)/mge_shut-usbhid-ups.Po -rm -f ./$(DEPDIR)/microdowell.Po -rm -f ./$(DEPDIR)/microsol-apc.Po -rm -f ./$(DEPDIR)/microsol-common.Po -rm -f ./$(DEPDIR)/netxml-ups.Po -rm -f ./$(DEPDIR)/nut-ipmipsu.Po -rm -f ./$(DEPDIR)/nut-libfreeipmi.Po -rm -f ./$(DEPDIR)/nutdrv_atcl_usb.Po -rm -f ./$(DEPDIR)/nutdrv_qx-libusb0.Po -rm -f ./$(DEPDIR)/nutdrv_qx-libusb1.Po -rm -f ./$(DEPDIR)/nutdrv_qx-nutdrv_qx.Po -rm -f ./$(DEPDIR)/nutdrv_qx-nutdrv_qx_ablerex.Po -rm -f ./$(DEPDIR)/nutdrv_qx-nutdrv_qx_bestups.Po -rm -f ./$(DEPDIR)/nutdrv_qx-nutdrv_qx_blazer-common.Po -rm -f ./$(DEPDIR)/nutdrv_qx-nutdrv_qx_hunnox.Po -rm -f ./$(DEPDIR)/nutdrv_qx-nutdrv_qx_masterguard.Po -rm -f ./$(DEPDIR)/nutdrv_qx-nutdrv_qx_mecer.Po -rm -f ./$(DEPDIR)/nutdrv_qx-nutdrv_qx_megatec-old.Po -rm -f ./$(DEPDIR)/nutdrv_qx-nutdrv_qx_megatec.Po -rm -f ./$(DEPDIR)/nutdrv_qx-nutdrv_qx_mustek.Po -rm -f ./$(DEPDIR)/nutdrv_qx-nutdrv_qx_q1.Po -rm -f ./$(DEPDIR)/nutdrv_qx-nutdrv_qx_voltronic-qs-hex.Po -rm -f ./$(DEPDIR)/nutdrv_qx-nutdrv_qx_voltronic-qs.Po -rm -f ./$(DEPDIR)/nutdrv_qx-nutdrv_qx_voltronic.Po -rm -f ./$(DEPDIR)/nutdrv_qx-nutdrv_qx_zinto.Po -rm -f ./$(DEPDIR)/nutdrv_qx-usb-common.Po -rm -f ./$(DEPDIR)/nutdrv_siemens_sitop.Po -rm -f ./$(DEPDIR)/oneac.Po -rm -f ./$(DEPDIR)/openups-hid.Po -rm -f ./$(DEPDIR)/optiups.Po -rm -f ./$(DEPDIR)/phoenixcontact_modbus.Po -rm -f ./$(DEPDIR)/pijuice.Po -rm -f ./$(DEPDIR)/powercom-hid.Po -rm -f ./$(DEPDIR)/powercom.Po -rm -f ./$(DEPDIR)/powerman-pdu.Po -rm -f ./$(DEPDIR)/powerp-bin.Po -rm -f ./$(DEPDIR)/powerp-txt.Po -rm -f ./$(DEPDIR)/powerpanel.Po -rm -f ./$(DEPDIR)/powervar-hid.Po -rm -f ./$(DEPDIR)/rhino.Po -rm -f ./$(DEPDIR)/richcomm_usb.Po -rm -f ./$(DEPDIR)/riello.Po -rm -f ./$(DEPDIR)/riello_ser.Po -rm -f ./$(DEPDIR)/riello_usb.Po -rm -f ./$(DEPDIR)/safenet.Po -rm -f ./$(DEPDIR)/salicru-hid.Po -rm -f ./$(DEPDIR)/serial.Plo -rm -f ./$(DEPDIR)/skel.Po -rm -f ./$(DEPDIR)/sms_ser.Po -rm -f ./$(DEPDIR)/snmp_ups-apc-ats-mib.Po -rm -f ./$(DEPDIR)/snmp_ups-apc-epdu-mib.Po -rm -f ./$(DEPDIR)/snmp_ups-apc-mib.Po -rm -f ./$(DEPDIR)/snmp_ups-apc-pdu-mib.Po -rm -f ./$(DEPDIR)/snmp_ups-baytech-mib.Po -rm -f ./$(DEPDIR)/snmp_ups-bestpower-mib.Po -rm -f ./$(DEPDIR)/snmp_ups-compaq-mib.Po -rm -f ./$(DEPDIR)/snmp_ups-cyberpower-mib.Po -rm -f ./$(DEPDIR)/snmp_ups-delta_ups-mib.Po -rm -f ./$(DEPDIR)/snmp_ups-eaton-ats16-nm2-mib.Po -rm -f ./$(DEPDIR)/snmp_ups-eaton-ats16-nmc-mib.Po -rm -f ./$(DEPDIR)/snmp_ups-eaton-ats30-mib.Po -rm -f ./$(DEPDIR)/snmp_ups-eaton-pdu-genesis2-mib.Po -rm -f ./$(DEPDIR)/snmp_ups-eaton-pdu-marlin-helpers.Po -rm -f ./$(DEPDIR)/snmp_ups-eaton-pdu-marlin-mib.Po -rm -f ./$(DEPDIR)/snmp_ups-eaton-pdu-nlogic-mib.Po -rm -f ./$(DEPDIR)/snmp_ups-eaton-pdu-pulizzi-mib.Po -rm -f ./$(DEPDIR)/snmp_ups-eaton-pdu-revelation-mib.Po -rm -f ./$(DEPDIR)/snmp_ups-eaton-ups-pwnm2-mib.Po -rm -f ./$(DEPDIR)/snmp_ups-eaton-ups-pxg-mib.Po -rm -f ./$(DEPDIR)/snmp_ups-emerson-avocent-pdu-mib.Po -rm -f ./$(DEPDIR)/snmp_ups-hpe-pdu-mib.Po -rm -f ./$(DEPDIR)/snmp_ups-hpe-pdu3-cis-mib.Po -rm -f ./$(DEPDIR)/snmp_ups-huawei-mib.Po -rm -f ./$(DEPDIR)/snmp_ups-ietf-mib.Po -rm -f ./$(DEPDIR)/snmp_ups-mge-mib.Po -rm -f ./$(DEPDIR)/snmp_ups-netvision-mib.Po -rm -f ./$(DEPDIR)/snmp_ups-raritan-pdu-mib.Po -rm -f ./$(DEPDIR)/snmp_ups-raritan-px2-mib.Po -rm -f ./$(DEPDIR)/snmp_ups-snmp-ups-helpers.Po -rm -f ./$(DEPDIR)/snmp_ups-snmp-ups.Po -rm -f ./$(DEPDIR)/snmp_ups-xppc-mib.Po -rm -f ./$(DEPDIR)/socomec_jbus.Po -rm -f ./$(DEPDIR)/solis.Po -rm -f ./$(DEPDIR)/tripplite-hid.Po -rm -f ./$(DEPDIR)/tripplite.Po -rm -f ./$(DEPDIR)/tripplite_usb.Po -rm -f ./$(DEPDIR)/tripplitesu.Po -rm -f ./$(DEPDIR)/upscode2.Po -rm -f ./$(DEPDIR)/upsdrvctl.Po -rm -f ./$(DEPDIR)/upsdrvquery.Plo -rm -f ./$(DEPDIR)/usb-common.Po -rm -f ./$(DEPDIR)/usbhid-ups.Po -rm -f ./$(DEPDIR)/victronups.Po -rm -f Makefile distclean-am: clean-am distclean-compile distclean-generic \ distclean-tags dvi: dvi-am dvi-am: html: html-am html-am: info: info-am info-am: install-data-am: install-dvi: install-dvi-am install-dvi-am: install-exec-am: install-driverexecPROGRAMS install-sbinPROGRAMS install-html: install-html-am install-html-am: install-info: install-info-am install-info-am: install-man: install-pdf: install-pdf-am install-pdf-am: install-ps: install-ps-am install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-am -rm -f ./$(DEPDIR)/adelsystem_cbi.Po -rm -f ./$(DEPDIR)/al175.Po -rm -f ./$(DEPDIR)/apc-hid.Po -rm -f ./$(DEPDIR)/apc_modbus.Po -rm -f ./$(DEPDIR)/apcsmart-old.Po -rm -f ./$(DEPDIR)/apcsmart.Po -rm -f ./$(DEPDIR)/apcsmart_tabs.Po -rm -f ./$(DEPDIR)/apcupsd_ups-apcupsd-ups.Po -rm -f ./$(DEPDIR)/arduino-hid.Po -rm -f ./$(DEPDIR)/asem.Po -rm -f ./$(DEPDIR)/bcmxcp.Po -rm -f ./$(DEPDIR)/bcmxcp_ser.Po -rm -f ./$(DEPDIR)/bcmxcp_usb.Po -rm -f ./$(DEPDIR)/belkin-hid.Po -rm -f ./$(DEPDIR)/belkin.Po -rm -f ./$(DEPDIR)/belkinunv.Po -rm -f ./$(DEPDIR)/bestfcom.Po -rm -f ./$(DEPDIR)/bestfortress.Po -rm -f ./$(DEPDIR)/bestuferrups.Po -rm -f ./$(DEPDIR)/bestups.Po -rm -f ./$(DEPDIR)/blazer.Po -rm -f ./$(DEPDIR)/blazer_ser.Po -rm -f ./$(DEPDIR)/blazer_usb.Po -rm -f ./$(DEPDIR)/clone-outlet.Po -rm -f ./$(DEPDIR)/clone.Po -rm -f ./$(DEPDIR)/cps-hid.Po -rm -f ./$(DEPDIR)/delta_ups-hid.Po -rm -f ./$(DEPDIR)/dstate.Plo -rm -f ./$(DEPDIR)/dummy_ups-dummy-ups.Po -rm -f ./$(DEPDIR)/etapro.Po -rm -f ./$(DEPDIR)/ever-hid.Po -rm -f ./$(DEPDIR)/everups.Po -rm -f ./$(DEPDIR)/explore-hid.Po -rm -f ./$(DEPDIR)/gamatronic.Po -rm -f ./$(DEPDIR)/generic_gpio_common.Po -rm -f ./$(DEPDIR)/generic_gpio_libgpiod.Po -rm -f ./$(DEPDIR)/generic_modbus.Po -rm -f ./$(DEPDIR)/genericups.Po -rm -f ./$(DEPDIR)/hidparser.Po -rm -f ./$(DEPDIR)/huawei-ups2000.Po -rm -f ./$(DEPDIR)/idowell-hid.Po -rm -f ./$(DEPDIR)/isbmex.Po -rm -f ./$(DEPDIR)/ivtscd.Po -rm -f ./$(DEPDIR)/legrand-hid.Po -rm -f ./$(DEPDIR)/libdummy_mockdrv_la-dstate.Plo -rm -f ./$(DEPDIR)/libdummy_mockdrv_la-main.Plo -rm -f ./$(DEPDIR)/libhid.Po -rm -f ./$(DEPDIR)/libusb0.Po -rm -f ./$(DEPDIR)/libusb1.Po -rm -f ./$(DEPDIR)/liebert-esp2.Po -rm -f ./$(DEPDIR)/liebert-hid.Po -rm -f ./$(DEPDIR)/liebert.Po -rm -f ./$(DEPDIR)/macosx-ups.Po -rm -f ./$(DEPDIR)/main.Plo -rm -f ./$(DEPDIR)/masterguard.Po -rm -f ./$(DEPDIR)/metasys.Po -rm -f ./$(DEPDIR)/mge-hid.Po -rm -f ./$(DEPDIR)/mge-utalk.Po -rm -f ./$(DEPDIR)/mge-xml.Po -rm -f ./$(DEPDIR)/mge_shut-hidparser.Po -rm -f ./$(DEPDIR)/mge_shut-libhid.Po -rm -f ./$(DEPDIR)/mge_shut-libshut.Po -rm -f ./$(DEPDIR)/mge_shut-mge-hid.Po -rm -f ./$(DEPDIR)/mge_shut-usbhid-ups.Po -rm -f ./$(DEPDIR)/microdowell.Po -rm -f ./$(DEPDIR)/microsol-apc.Po -rm -f ./$(DEPDIR)/microsol-common.Po -rm -f ./$(DEPDIR)/netxml-ups.Po -rm -f ./$(DEPDIR)/nut-ipmipsu.Po -rm -f ./$(DEPDIR)/nut-libfreeipmi.Po -rm -f ./$(DEPDIR)/nutdrv_atcl_usb.Po -rm -f ./$(DEPDIR)/nutdrv_qx-libusb0.Po -rm -f ./$(DEPDIR)/nutdrv_qx-libusb1.Po -rm -f ./$(DEPDIR)/nutdrv_qx-nutdrv_qx.Po -rm -f ./$(DEPDIR)/nutdrv_qx-nutdrv_qx_ablerex.Po -rm -f ./$(DEPDIR)/nutdrv_qx-nutdrv_qx_bestups.Po -rm -f ./$(DEPDIR)/nutdrv_qx-nutdrv_qx_blazer-common.Po -rm -f ./$(DEPDIR)/nutdrv_qx-nutdrv_qx_hunnox.Po -rm -f ./$(DEPDIR)/nutdrv_qx-nutdrv_qx_masterguard.Po -rm -f ./$(DEPDIR)/nutdrv_qx-nutdrv_qx_mecer.Po -rm -f ./$(DEPDIR)/nutdrv_qx-nutdrv_qx_megatec-old.Po -rm -f ./$(DEPDIR)/nutdrv_qx-nutdrv_qx_megatec.Po -rm -f ./$(DEPDIR)/nutdrv_qx-nutdrv_qx_mustek.Po -rm -f ./$(DEPDIR)/nutdrv_qx-nutdrv_qx_q1.Po -rm -f ./$(DEPDIR)/nutdrv_qx-nutdrv_qx_voltronic-qs-hex.Po -rm -f ./$(DEPDIR)/nutdrv_qx-nutdrv_qx_voltronic-qs.Po -rm -f ./$(DEPDIR)/nutdrv_qx-nutdrv_qx_voltronic.Po -rm -f ./$(DEPDIR)/nutdrv_qx-nutdrv_qx_zinto.Po -rm -f ./$(DEPDIR)/nutdrv_qx-usb-common.Po -rm -f ./$(DEPDIR)/nutdrv_siemens_sitop.Po -rm -f ./$(DEPDIR)/oneac.Po -rm -f ./$(DEPDIR)/openups-hid.Po -rm -f ./$(DEPDIR)/optiups.Po -rm -f ./$(DEPDIR)/phoenixcontact_modbus.Po -rm -f ./$(DEPDIR)/pijuice.Po -rm -f ./$(DEPDIR)/powercom-hid.Po -rm -f ./$(DEPDIR)/powercom.Po -rm -f ./$(DEPDIR)/powerman-pdu.Po -rm -f ./$(DEPDIR)/powerp-bin.Po -rm -f ./$(DEPDIR)/powerp-txt.Po -rm -f ./$(DEPDIR)/powerpanel.Po -rm -f ./$(DEPDIR)/powervar-hid.Po -rm -f ./$(DEPDIR)/rhino.Po -rm -f ./$(DEPDIR)/richcomm_usb.Po -rm -f ./$(DEPDIR)/riello.Po -rm -f ./$(DEPDIR)/riello_ser.Po -rm -f ./$(DEPDIR)/riello_usb.Po -rm -f ./$(DEPDIR)/safenet.Po -rm -f ./$(DEPDIR)/salicru-hid.Po -rm -f ./$(DEPDIR)/serial.Plo -rm -f ./$(DEPDIR)/skel.Po -rm -f ./$(DEPDIR)/sms_ser.Po -rm -f ./$(DEPDIR)/snmp_ups-apc-ats-mib.Po -rm -f ./$(DEPDIR)/snmp_ups-apc-epdu-mib.Po -rm -f ./$(DEPDIR)/snmp_ups-apc-mib.Po -rm -f ./$(DEPDIR)/snmp_ups-apc-pdu-mib.Po -rm -f ./$(DEPDIR)/snmp_ups-baytech-mib.Po -rm -f ./$(DEPDIR)/snmp_ups-bestpower-mib.Po -rm -f ./$(DEPDIR)/snmp_ups-compaq-mib.Po -rm -f ./$(DEPDIR)/snmp_ups-cyberpower-mib.Po -rm -f ./$(DEPDIR)/snmp_ups-delta_ups-mib.Po -rm -f ./$(DEPDIR)/snmp_ups-eaton-ats16-nm2-mib.Po -rm -f ./$(DEPDIR)/snmp_ups-eaton-ats16-nmc-mib.Po -rm -f ./$(DEPDIR)/snmp_ups-eaton-ats30-mib.Po -rm -f ./$(DEPDIR)/snmp_ups-eaton-pdu-genesis2-mib.Po -rm -f ./$(DEPDIR)/snmp_ups-eaton-pdu-marlin-helpers.Po -rm -f ./$(DEPDIR)/snmp_ups-eaton-pdu-marlin-mib.Po -rm -f ./$(DEPDIR)/snmp_ups-eaton-pdu-nlogic-mib.Po -rm -f ./$(DEPDIR)/snmp_ups-eaton-pdu-pulizzi-mib.Po -rm -f ./$(DEPDIR)/snmp_ups-eaton-pdu-revelation-mib.Po -rm -f ./$(DEPDIR)/snmp_ups-eaton-ups-pwnm2-mib.Po -rm -f ./$(DEPDIR)/snmp_ups-eaton-ups-pxg-mib.Po -rm -f ./$(DEPDIR)/snmp_ups-emerson-avocent-pdu-mib.Po -rm -f ./$(DEPDIR)/snmp_ups-hpe-pdu-mib.Po -rm -f ./$(DEPDIR)/snmp_ups-hpe-pdu3-cis-mib.Po -rm -f ./$(DEPDIR)/snmp_ups-huawei-mib.Po -rm -f ./$(DEPDIR)/snmp_ups-ietf-mib.Po -rm -f ./$(DEPDIR)/snmp_ups-mge-mib.Po -rm -f ./$(DEPDIR)/snmp_ups-netvision-mib.Po -rm -f ./$(DEPDIR)/snmp_ups-raritan-pdu-mib.Po -rm -f ./$(DEPDIR)/snmp_ups-raritan-px2-mib.Po -rm -f ./$(DEPDIR)/snmp_ups-snmp-ups-helpers.Po -rm -f ./$(DEPDIR)/snmp_ups-snmp-ups.Po -rm -f ./$(DEPDIR)/snmp_ups-xppc-mib.Po -rm -f ./$(DEPDIR)/socomec_jbus.Po -rm -f ./$(DEPDIR)/solis.Po -rm -f ./$(DEPDIR)/tripplite-hid.Po -rm -f ./$(DEPDIR)/tripplite.Po -rm -f ./$(DEPDIR)/tripplite_usb.Po -rm -f ./$(DEPDIR)/tripplitesu.Po -rm -f ./$(DEPDIR)/upscode2.Po -rm -f ./$(DEPDIR)/upsdrvctl.Po -rm -f ./$(DEPDIR)/upsdrvquery.Plo -rm -f ./$(DEPDIR)/usb-common.Po -rm -f ./$(DEPDIR)/usbhid-ups.Po -rm -f ./$(DEPDIR)/victronups.Po -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-am mostlyclean-am: mostlyclean-compile mostlyclean-generic \ mostlyclean-libtool pdf: pdf-am pdf-am: ps: ps-am ps-am: uninstall-am: uninstall-driverexecPROGRAMS uninstall-sbinPROGRAMS .MAKE: install-am install-strip .PHONY: CTAGS GTAGS TAGS all all-am am--depfiles check check-am clean \ clean-driverexecPROGRAMS clean-generic clean-libtool \ clean-sbinPROGRAMS cscopelist-am ctags ctags-am distclean \ distclean-compile distclean-generic distclean-libtool \ distclean-tags distdir dvi dvi-am html html-am info info-am \ install install-am install-data install-data-am \ install-driverexecPROGRAMS install-dvi install-dvi-am \ install-exec install-exec-am install-html install-html-am \ install-info install-info-am install-man install-pdf \ install-pdf-am install-ps install-ps-am install-sbinPROGRAMS \ install-strip installcheck installcheck-am installdirs \ maintainer-clean maintainer-clean-generic mostlyclean \ mostlyclean-compile mostlyclean-generic mostlyclean-libtool \ pdf pdf-am ps ps-am tags tags-am uninstall uninstall-am \ uninstall-driverexecPROGRAMS uninstall-sbinPROGRAMS .PRECIOUS: Makefile # Make sure out-of-dir dependencies exist (especially when dev-building parts): $(top_builddir)/common/libcommon.la \ $(top_builddir)/common/libparseconf.la \ $(top_builddir)/clients/libupsclient.la: dummy @cd $(@D) && $(MAKE) $(AM_MAKEFLAGS) $(@F) dummy: # NOTE: Do not clean ".deps" in SUBDIRS of the main project, # the root Makefile.am takes care of that! #clean-local: # $(AM_V_at)rm -rf $(builddir)/.deps # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: nut-2.8.1/drivers/ever-hid.c0000644000175000017500000007747714502413017012621 00000000000000/* ever-hid.c - subdriver to monitor EVER USB/HID devices with NUT * * Copyright (C) * 2003 - 2012 Arnaud Quette * 2005 - 2006 Peter Selinger * 2008 - 2009 Arjen de Korte * 2013 Charles Lepple * 2017 EVER Power Systems [https://ever.eu/] * 2020 - 2022 Jim Klimov * * Note: this subdriver was initially generated as a "stub" by the * gen-usbhid-subdriver script. It must be customized. * * 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 2 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, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "config.h" /* must be first */ #include "usbhid-ups.h" #include "ever-hid.h" #include "main.h" /* for getval() */ #include "usb-common.h" #define EVER_HID_VERSION "Ever HID 0.10" /* FIXME: experimental flag to be put in upsdrv_info */ /* Ever */ #define EVER_VENDORID 0x2e51 /* ST Microelectronics */ #define STMICRO_VENDORID 0x0483 /* USB IDs device table */ static usb_device_id_t ever_usb_device_table[] = { { USB_DEVICE(STMICRO_VENDORID, 0xa113), NULL }, { USB_DEVICE(EVER_VENDORID, 0xffff), NULL}, { USB_DEVICE(EVER_VENDORID, 0x0000), NULL}, /* Terminating entry */ { 0, 0, NULL } }; /* --------------------------------------------------------------- */ /* Vendor-specific usage table */ /* --------------------------------------------------------------- */ static const char *ever_format_hardware_fun(double value) { /* TODO - add exception handling for v1.0b0B */ const char* hard_rev[27] = {"0", "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z"}; static char model[10]; snprintf(model, sizeof(model), "rev.%sv%02u", (&hard_rev[ ((unsigned int)value & 0xFF00)>>8 ])[0], (unsigned int)value & 0xFF ); return model; } static const char *ever_format_version_fun(double value) { static char model[10]; /*upsdebugx(1, "UPS ups_firmware_conversion_fun VALUE: %d", (long)value);*/ snprintf(model, sizeof(model), "v%X.%Xb%02d", ((unsigned int)value & 0xF000)>>12, ((unsigned int)value & 0xF00)>>8, ((int)value & 0xFF) ); return model; } static const char *ever_mac_address_fun(double value) { int mac_adress_report_id = 210; int len = reportbuf->len[mac_adress_report_id]; int n = 0; /* number of characters currently in line */ int i; /* number of bytes output from buffer */ const void *buf = reportbuf->data[mac_adress_report_id]; static char line[100]; NUT_UNUSED_VARIABLE(value); line[0] = '\0'; /* skip first element which is a report id */ for (i = 1; i < len; i++) { n = snprintfcat(line, sizeof(line), n ? ":%02x" : "%02x", ((unsigned char *)buf)[i]); } return line; } static const char *ever_ip_address_fun(double value) { static int report_counter = 1; int report_id = 211, len; int n = 0; /* number of characters currently in line */ int i; /* number of bytes output from buffer */ const void *buf; static char line[100]; NUT_UNUSED_VARIABLE(value); if(report_counter == 1) report_id = 211; /* notification dest ip */ else if(report_counter == 2) report_id = 230; /* ip address */ else if(report_counter == 3) report_id = 231; /* network mask */ else if(report_counter == 4) report_id = 232; /* default gateway */ report_counter== 4 ? report_counter=1 : report_counter++; len = reportbuf->len[report_id]; buf = reportbuf->data[report_id]; line[0] = '\0'; /* skip first element which is a report id */ for (i = 1; i < len; i++) { n = snprintfcat(line, sizeof(line), n ? ".%d" : "%d", ((unsigned char *)buf)[i]); } return line; } static const char *ever_packets_fun(double value) { static int report_counter = 1; int report_id = 215, len, res; const unsigned char *buf; static char line[200]; NUT_UNUSED_VARIABLE(value); if(report_counter == 1 ) report_id = 215; else if(report_counter == 2 ) report_id = 216; else if(report_counter == 3 ) report_id = 217; else if(report_counter == 4 ) report_id = 218; report_counter== 4 ? report_counter=1 : report_counter++; len = reportbuf->len[report_id]; buf = reportbuf->data[report_id]; line[0] = '\0'; /* skip first element which is a report id */ if(len < 5) return ""; res = (int)buf[1]; res |= (int)buf[2] << 8; res |= (int)buf[3] << 16; res |= (int)buf[4] << 24; snprintf(line, sizeof(line), "%d", res); return line; } static const char* ever_workmode_fun(double value) { int workmode_report_id = 74; int workmode = -1; const unsigned char *buf = reportbuf->data[workmode_report_id]; static char line[200]; NUT_UNUSED_VARIABLE(value); line[0] = '\0'; /* skip first element which is a report id */ snprintfcat(line, sizeof(line), "%d", buf[1]); workmode = atoi(line); switch(workmode) { case 1: return "UNKNOWN"; case 2: return "STOP"; case 4: return "ONLINE"; case 8: return "ONBATTERY"; case 16: return "WATCH"; case 32: return "WAITING"; case 64: return "EMERGENCY"; default: return "UNKNOWN"; } } static const char* ever_messages_fun(double value) { int messages_report_id = 75, messages; int n = 0; /* number of characters currently in line */ const unsigned char *buf = reportbuf->data[messages_report_id]; static char line[200]; NUT_UNUSED_VARIABLE(value); line[0] = '\0'; /* skip first element which is a report id */ messages = (int)buf[1]; messages |= (int)buf[2] << 8; /* duplicate of ups.status: OB LB */ /* if(messages & 0x01) n = snprintfcat(line, sizeof(line), n ? " %s" : "%s", "OVERLOAD"); if(messages & 0x02) n = snprintfcat(line, sizeof(line), n ? " %s" : "%s", "BATTERY_LOW"); */ if(messages & 0x04) n = snprintfcat(line, sizeof(line), n ? " %s" : "%s", "BOOST"); if(messages & 0x08) n = snprintfcat(line, sizeof(line), n ? " %s" : "%s", "BUCK"); if(messages & 0x10) n = snprintfcat(line, sizeof(line), n ? " %s" : "%s", "BOOST_BLOCKED"); if(messages & 0x20) n = snprintfcat(line, sizeof(line), n ? " %s" : "%s", "BUCK_BLOCKED"); if(messages & 0x40) n = snprintfcat(line, sizeof(line), n ? " %s" : "%s", "CHARGING"); if(messages & 0x80) n = snprintfcat(line, sizeof(line), n ? " %s" : "%s", "FAN_ON"); if(messages & 0x100) n = snprintfcat(line, sizeof(line), n ? " %s" : "%s", "EPO_BLOCKED"); if(messages & 0x200) n = snprintfcat(line, sizeof(line), n ? " %s" : "%s", "NEED_REPLACMENT"); if(messages & 0x400 || messages & 0x800) n = snprintfcat(line, sizeof(line), n ? " %s" : "%s", "OVERHEAT"); if(messages & 0x1000) n = snprintfcat(line, sizeof(line), n ? " %s" : "%s", "WAITING_FOR_MIN_CHARGE"); if(messages & 0x2000) n = snprintfcat(line, sizeof(line), n ? " %s" : "%s", "MAINS_OUT_OF_RANGE"); return line; } static const char* ever_alarms_fun(double value) { int alarms_report_id = 76, alarms; int n = 0; /* number of characters currently in line */ const unsigned char *buf = reportbuf->data[alarms_report_id]; static char line[200]; NUT_UNUSED_VARIABLE(value); line[0] = '\0'; /* skip first element which is a report id */ alarms = (int)buf[1]; alarms |= (int)buf[2] << 8; if(alarms & 0x01) n = snprintfcat(line, sizeof(line), n ? " %s" : "%s", "OVERLOAD"); if(alarms & 0x02) n = snprintfcat(line, sizeof(line), n ? " %s" : "%s", "SHORT-CIRCUIT"); if(alarms & 0x04 || alarms & 0x08) n = snprintfcat(line, sizeof(line), n ? " %s" : "%s", "OVERHEAT"); if(alarms & 0x10) n = snprintfcat(line, sizeof(line), n ? " %s" : "%s", "EPO"); if(alarms & 0x20) n = snprintfcat(line, sizeof(line), n ? " %s" : "%s", "INERNAL_ERROR"); if(alarms & 0x40) n = snprintfcat(line, sizeof(line), n ? " %s" : "%s", "REVERSE_POWER_SUPPLY"); if(alarms & 0x80) n = snprintfcat(line, sizeof(line), n ? " %s" : "%s", "NO_INETERNAL_COMM"); if(alarms & 0x100) n = snprintfcat(line, sizeof(line), n ? " %s" : "%s", "CRITICAL_BATT_VOLTAGE"); return line; } static const char* ever_on_off_fun(double value) { int workmode_report_id = 74; int workmode = -1; const unsigned char *buf = reportbuf->data[workmode_report_id]; static char line[200]; NUT_UNUSED_VARIABLE(value); line[0] = '\0'; /* skip first element which is a report id */ snprintfcat(line, sizeof(line), "%d", buf[1]); workmode = atoi(line); if(workmode != 0x04 && workmode != 0x08) return "off"; return "!off"; } static info_lkp_t ever_format_hardware[] = { { 0, NULL, ever_format_hardware_fun, NULL }, { 0, NULL, NULL, NULL } }; static info_lkp_t ever_format_version[] = { { 0, NULL, ever_format_version_fun, NULL }, { 0, NULL, NULL, NULL } }; static info_lkp_t ever_mac_address[] = { { 0, NULL, ever_mac_address_fun, NULL }, { 0, NULL, NULL, NULL } }; static info_lkp_t ever_ip_address[] = { { 0, NULL, ever_ip_address_fun, NULL }, { 0, NULL, NULL, NULL } }; static info_lkp_t ever_packets[] = { { 0, NULL, ever_packets_fun, NULL }, { 0, NULL, NULL, NULL } }; static info_lkp_t ever_workmode[] = { { 0, NULL, ever_workmode_fun, NULL }, { 0, NULL, NULL, NULL } }; static info_lkp_t ever_messages[] = { { 0, NULL, ever_messages_fun, NULL }, { 0, NULL, NULL, NULL } }; static info_lkp_t ever_alarms[] = { { 0, NULL, ever_alarms_fun, NULL }, { 0, NULL, NULL, NULL } }; static info_lkp_t ever_on_off_info[] = { { 0, NULL, ever_on_off_fun, NULL }, { 0, NULL, NULL, NULL } }; /* EVER usage table */ static usage_lkp_t ever_usage_lkp[] = { { "EVER1", 0x00000000 }, { "EVER2", 0xff000000 }, { "EVER3", 0xff000001 }, { "EVER4", 0xff000002 }, { "EVER5", 0xff000003 }, { "EVER6", 0xff000004 }, { "EVER7", 0xff000005 }, { "EVER8", 0xff000006 }, { "EVER9", 0xff000007 }, { "EVER10", 0xff000008 }, { "EVER11", 0xff000009 }, { "EVER12", 0xff000010 }, { "EVER13", 0xff000011 }, { "EVER14", 0xff000012 }, { "EVER15", 0xff000013 }, { "EVER16", 0xff000014 }, { "EVER17", 0xff000015 }, { "EVER18", 0xff000016 }, { "EVER19", 0xff000017 }, { "EVER20", 0xff000018 }, { "EVER21", 0xff000019 }, { "EVER22", 0xff00001a }, { "EVER23", 0xff00001b }, { "EVER24", 0xff00001c }, { "EVER25", 0xff00001d }, { "EVER26", 0xff00001e }, { "EVER27", 0xff00001f }, { "EVER28", 0xff000020 }, { "EVER29", 0xff000021 }, { "EVER30", 0xff000022 }, { "EVER31", 0xff000023 }, { "EVER32", 0xff000030 }, { "EVER33", 0xff000031 }, { "EVER34", 0xff000032 }, { "EVER35", 0xff000033 }, { "EVER36", 0xff000034 }, { "EVER37", 0xff000035 }, { "EVER38", 0xff000036 }, { "EVER39", 0xff000037 }, { "EVER40", 0xff000038 }, { "EVER41", 0xff000039 }, { "EVER42", 0xff000040 }, { "EVER43", 0xff000041 }, { "EVER44", 0xff000042 }, { "EVER45", 0xff000043 }, { "EVER46", 0xff000044 }, { "EVER47", 0xff000045 }, { "EVER48", 0xff000046 }, { "EVER49", 0xff000050 }, { "EVER50", 0xff000051 }, { "EVER51", 0xff000052 }, { "EVER52", 0xff000053 }, { "EVER53", 0xff000054 }, { "EVER54", 0xff000060 }, { "EVER55", 0xff000061 }, { "EVER56", 0xff000062 }, { "EVER57", 0xff000063 }, { "EVER58", 0xff000064 }, { "EVER59", 0xff000066 }, { "EVER60", 0xff000067 }, { "EVER61", 0xff000068 }, { "EVER62", 0xff000069 }, { "EVER63", 0xff00006a }, { "EVER64", 0xff00006b }, { "EVER65", 0xff00006c }, { "EVER66", 0xff00006d }, { "EVER67", 0xff00006e }, { "EVER68", 0xff00006f }, { "EVER69", 0xff000070 }, { "EVER70", 0xff000071 }, { "EVER71", 0xff000072 }, { "EVER72", 0xff000073 }, { "EVER73", 0xff000074 }, { "EVER74", 0xff000075 }, { "EVER75", 0xff000076 }, { "EVER76", 0xff000077 }, { "EVER77", 0xff000078 }, { "EVER78", 0xff000079 }, { "EVER79", 0xff00007a }, { "EVER80", 0xff00007b }, { "EVER81", 0xff00007c }, { "EVER82", 0xff00007d }, { "EVER83", 0xff00007e }, { "EVER84", 0xff00007f }, { "EVER85", 0xff000080 }, { "EVER86", 0xff000081 }, { "EVER87", 0xff000082 }, { "EVER88", 0xff000083 }, { "EVER89", 0xff000084 }, { "EVER90", 0xff000085 }, { "EVER91", 0xff000086 }, { "EVER92", 0xff000087 }, { "EVER93", 0xff000088 }, { "EVER94", 0xff000089 }, { "EVER95", 0xff00008a }, { "EVER96", 0xff00008b }, { "EVER97", 0xff000090 }, { "EVER98", 0xff000091 }, { "EVER99", 0xff000092 }, { "EVER100", 0xff000093 }, { "EVER101", 0xff000094 }, { "EVER102", 0xff000095 }, { "EVER103", 0xff000096 }, { "EVER104", 0xff000097 }, { NULL, 0 } }; static usage_tables_t ever_utab[] = { ever_usage_lkp, hid_usage_lkp, NULL, }; /* --------------------------------------------------------------- */ /* HID2NUT lookup table */ /* --------------------------------------------------------------- */ static hid_info_t ever_hid2nut[] = { /* Note: fields marked with "experimental." prefix were proposed without * an exact match vs. docs/nut-names.txt definitions. PRs are welcome to * analyze and map those values into standard NUT variable names, or to * raise discussion on mailing lists and define new names via consensus. * There is a lot of interesting info listed below. * * Note: mappings that were applied below (as committed 2022-02-09) may * be wrong and are based mostly on cursory reading of original names. * In particular, not sure if the skipped "id.*" fields were identifiers * or some "internal device" etc. */ /* experimental: "NUT variable names" do not currently have * any battery.*id data points: */ { "experimental.battery.batteryid", 0, 0, "UPS.BatterySystem.Battery.BatteryID", NULL, "%.0f", 0, NULL }, { "experimental.battery.systemid", 0, 0, "UPS.BatterySystem.BatterySystemID", NULL, "%.0f", 0, NULL }, { "experimental.battery.chargerid", 0, 0, "UPS.BatterySystem.Charger.ChargerID", NULL, "%.0f", 0, NULL }, { "experimental.battery.input_flowid", 0, 0, "UPS.BatterySystem.Input.FlowID", NULL, "%.0f", 0, NULL }, { "experimental.battery.input_id", 0, 0, "UPS.BatterySystem.Input.InputID", NULL, "%.0f", 0, NULL }, { "experimental.battery.output_flowid", 0, 0, "UPS.BatterySystem.Output.FlowID", NULL, "%.0f", 0, NULL }, { "experimental.battery.output_id", 0, 0, "UPS.BatterySystem.Output.OutputID", NULL, "%.0f", 0, NULL }, /* experimental: "NUT variable names" do not currently have * any id (nor version) data points for FW/HW of components: */ /* not implemented*/ /* { "experimental.id.ups_type", 0, 0, "UPS.EVER1.EVER12", NULL, "%s", 0, ever_format_model }, */ { "experimental.id.firmware_version_inverter", 0, 0, "UPS.EVER1.EVER13", NULL, "%s", 0, ever_format_version }, { "experimental.id.firmware_version_interfaces", 0, 0, "UPS.EVER1.EVER14", NULL, "%s", 0, ever_format_version }, { "experimental.id.hardware_version", 0, 0, "UPS.EVER1.EVER15", NULL, "%s", 0, ever_format_hardware }, { "experimental.id.protocol_version_inverter", 0, 0, "UPS.EVER1.EVER16", NULL, "%s", 0, ever_format_version }, { "experimental.id.protocol_version_interfaces", 0, 0, "UPS.EVER1.EVER17", NULL, "%s", 0, ever_format_version }, /* WAS: "experimental.inverter_info.heatsink_temperature" */ { "ups.temperature", 0, 0, "UPS.EVER1.EVER42", NULL, "%s", 0, kelvin_celsius_conversion }, /* WAS: "experimental.inverter_info.battery_temperature" */ { "battery.temperature", 0, 0, "UPS.EVER1.EVER43", NULL, "%s", 0, kelvin_celsius_conversion }, /* WAS: "experimental.ups_info.output_powerfactor" */ { "output.powerfactor", 0, 0, "UPS.EVER1.EVER44", NULL, "%.0f", 0, NULL }, /* experimental: Should these be HU_TYPE_CMD entries? * Or are they really settings? */ { "experimental.control.ups_on", ST_FLAG_RW | ST_FLAG_NUMBER, 0, "UPS.EVER1.EVER45.EVER46", NULL, "%.0f", 0, NULL }, { "experimental.control.clear_fault", ST_FLAG_RW | ST_FLAG_NUMBER, 0, "UPS.EVER1.EVER45.EVER47", NULL, "%.0f", 0, NULL }, { "experimental.control.clear_battery_fault", ST_FLAG_RW | ST_FLAG_NUMBER, 0, "UPS.EVER1.EVER45.EVER48", NULL, "%.0f", 0, NULL }, { "experimental.control.epo_blocked", ST_FLAG_RW | ST_FLAG_NUMBER, 0, "UPS.EVER1.EVER49.EVER50", NULL, "%.0f", 0, NULL }, { "experimental.control.green_mode", ST_FLAG_RW | ST_FLAG_NUMBER, 0, "UPS.EVER1.EVER49.EVER51", NULL, "%.0f", 0, NULL }, { "experimental.control.button_sound", ST_FLAG_RW | ST_FLAG_NUMBER, 0, "UPS.EVER1.EVER49.EVER52", NULL, "%.0f", 0, NULL }, { "experimental.control.audible_alarm", ST_FLAG_RW | ST_FLAG_NUMBER, 0, "UPS.EVER1.EVER49.EVER53", NULL, "%.0f", 0, NULL }, /* WAS: "experimental.config.output_voltage" */ { "output.voltage", ST_FLAG_RW | ST_FLAG_STRING, 3, "UPS.EVER1.EVER54", NULL, "%.0f", 0, NULL }, /* not implemented*/ /* { "experimental.config.min_output_voltage", ST_FLAG_RW | ST_FLAG_STRING, 3, "UPS.EVER1.EVER55", NULL, "%.0f", 0, NULL }, { "experimental.config.max_output_voltage", ST_FLAG_RW | ST_FLAG_STRING, 3, "UPS.EVER1.EVER56", NULL, "%.0f", 0, NULL }, { "experimental.config.min_output_frequency", ST_FLAG_RW | ST_FLAG_NUMBER, 0, "UPS.EVER1.EVER57", NULL, "%.1f", 0, NULL }, { "experimental.config.max_output_frequency", ST_FLAG_RW | ST_FLAG_NUMBER, 0, "UPS.EVER1.EVER58", NULL, "%.1f", 0, NULL }, */ /* experimental: what units is this counted in? * is "ups.load.high" a suitable mapping here? or "battery.voltage.high"? */ { "experimental.config.overload_clearance_threshold", ST_FLAG_RW | ST_FLAG_STRING, 2, "UPS.EVER1.EVER59", NULL, "%.0f", 0, NULL }, { "experimental.config.stb_charge", ST_FLAG_RW | ST_FLAG_STRING, 2, "UPS.EVER1.EVER60", NULL, "%.0f", 0, NULL }, /* WAS: "experimental.config.number_of_ebms" * Should this be a string? rw? */ { "battery.packs.external", ST_FLAG_RW | ST_FLAG_STRING, 1, "UPS.EVER1.EVER61", NULL, "%.0f", 0, NULL }, { "experimental.statistics.mains_loss_counter", 0, 0, "UPS.EVER1.EVER62", NULL, "%.0f", 0, NULL }, { "experimental.statistics.lowering_AVR_trigger_counter", 0, 0, "UPS.EVER1.EVER63", NULL, "%.0f", 0, NULL }, { "experimental.statistics.rising_AVR_trigger_counter", 0, 0, "UPS.EVER1.EVER64", NULL, "%.0f", 0, NULL }, { "experimental.statistics.overload_counter", 0, 0, "UPS.EVER1.EVER65", NULL, "%.0f", 0, NULL }, { "experimental.statistics.short_circuit_counter", 0, 0, "UPS.EVER1.EVER66", NULL, "%.0f", 0, NULL }, { "experimental.statistics.discharge_counter", 0, 0, "UPS.EVER1.EVER67", NULL, "%.0f", 0, NULL }, { "experimental.statistics.overheat_counter", 0, 0, "UPS.EVER1.EVER68", NULL, "%.0f", 0, NULL }, { "experimental.statistics.mains_operation_time", 0, 0, "UPS.EVER1.EVER69", NULL, "%.0f", 0, NULL }, { "experimental.statistics.autonomous_operation_time", 0, 0, "UPS.EVER1.EVER70", NULL, "%.0f", 0, NULL }, { "experimental.statistics.overload_operation_time", 0, 0, "UPS.EVER1.EVER71", NULL, "%.0f", 0, NULL }, { "experimental.networkcard.mac_address", 0, 0, "UPS.EVER1.EVER72", NULL, "%s", 0, ever_mac_address }, { "experimental.networkcard.notification_destination_ip", 0, 0, "UPS.EVER1.EVER73", NULL, "%s", 0, ever_ip_address }, { "experimental.networkcard.send_packets", 0, 0, "UPS.EVER1.EVER77", NULL, "%s", 0, ever_packets }, { "experimental.networkcard.received_packets", 0, 0, "UPS.EVER1.EVER78", NULL, "%s", 0, ever_packets }, { "experimental.networkcard.send_packets_err", 0, 0, "UPS.EVER1.EVER79", NULL, "%s", 0, ever_packets }, { "experimental.networkcard.received_packets_err", 0, 0, "UPS.EVER1.EVER80", NULL, "%s", 0, ever_packets }, { "experimental.networkcard.config_dhcp_enabled", 0, 0, "UPS.EVER1.EVER85.EVER86", NULL, "%.0f", 0, NULL }, { "experimental.networkcard.config_ethernet_enabled", 0, 0, "UPS.EVER1.EVER85.EVER87", NULL, "%.0f", 0, NULL }, { "experimental.networkcard.config_http_enabled", 0, 0, "UPS.EVER1.EVER85.EVER88", NULL, "%.0f", 0, NULL }, { "experimental.networkcard.config_snmp_enabled", 0, 0, "UPS.EVER1.EVER85.EVER89", NULL, "%.0f", 0, NULL }, { "experimental.networkcard.config_snmp_trap_enabled", 0, 0, "UPS.EVER1.EVER85.EVER90", NULL, "%.0f", 0, NULL }, { "experimental.networkcard.config_readonly", 0, 0, "UPS.EVER1.EVER85.EVER91", NULL, "%.0f", 0, NULL }, { "experimental.networkcard.config_restart_eth", 0, 0, "UPS.EVER1.EVER85.EVER96", NULL, "%.0f", 0, NULL }, { "experimental.networkcard.ip_address", 0, 0, "UPS.EVER1.EVER93", NULL, "%s", 0, ever_ip_address }, { "experimental.networkcard.network_mask", 0, 0, "UPS.EVER1.EVER94", NULL, "%s", 0, ever_ip_address }, { "experimental.networkcard.default_gateway", 0, 0, "UPS.EVER1.EVER95", NULL, "%s", 0, ever_ip_address }, /* WAS: "experimental.id.config_active_power" */ { "ups.realpower.nominal", 0, 0, "UPS.Flow.ConfigActivePower", NULL, "%.0f", 0, NULL }, /* WAS: "experimental.id.config_apparent_power" * Other HID subdrivers use "ups.power.nominal" mostly (often HU_FLAG_STATIC); * once of each: "ups.realpower.nominal", "ups.realpower". * Is this even a run-time value or a hardware property? */ { "ups.power.nominal", 0, 0, "UPS.Flow.ConfigApparentPower", NULL, "%.0f", 0, NULL }, /* WAS: "experimental.ups.config_frequency" * Here and next: is this about input or output?.. * Other drivers have "input.frequency.nominal" on numbered Flows * As a "nominal", should it be HU_FLAG_SEMI_STATIC or HU_FLAG_STATIC maybe? * Note there are non-nominal values in "powerconverter" below, * so the questions here may be somewhat irrelevant... */ { "output.frequency.nominal", 0, 0, "UPS.Flow.ConfigFrequency", NULL, "%.0f", 0, NULL }, /* WAS: "experimental.ups.config_voltage" */ { "output.voltage.nominal", 0, 0, "UPS.Flow.ConfigVoltage", NULL, "%.0f", 0, NULL }, { "experimental.ups.flow_id", 0, 0, "UPS.Flow.FlowID", NULL, "%.0f", 0, NULL }, /* NOTE: NUT variable names define "outlet.n.*" names for numbering all * separately manageable outlets; the numberless value (or outlet.0.*) * is reserved to represent common properties of all outlets, if there * are more than one outlet (group). * Mapping below arbitrarily assigns n=1 but really this should be tied * to actual outlet counts (see %i mappings in other drivers). */ /* WAS: experimental.outlet.outlet_id */ { "outlet.1.id", 0, 0, "UPS.OutletSystem.Outlet.OutletID", NULL, "%.0f", 0, NULL }, /* WAS: */ { "experimental.outlet.1.present", 0, 0, "UPS.OutletSystem.Outlet.PresentStatus.Present", NULL, "%.0f", 0, yes_no_info }, { "outlet.1.switchable", 0, 0, "UPS.OutletSystem.Outlet.PresentStatus.Switchable", NULL, "%.0f", 0, yes_no_info }, /* WAS: experimental.outlet.switch_on_off */ { "outlet.1.status", 0, 0, "UPS.OutletSystem.Outlet.PresentStatus.SwitchOn/Off", NULL, "%.0f", 0, NULL }, { "experimental.outlet.1.undefined", 0, 0, "UPS.OutletSystem.Outlet.PresentStatus.Undefined", NULL, "%.0f", 0, NULL }, { "experimental.outlet.1.system_id", 0, 0, "UPS.OutletSystem.OutletSystemID", NULL, "%.0f", 0, NULL }, /* experimental: Should these be HU_TYPE_CMD entries? * Or are they really settings? */ { "experimental.outlet.1.switch_off_control", ST_FLAG_RW | ST_FLAG_NUMBER, 0, "UPS.OutletSystem.Outlet.SwitchOffControl", NULL, "%.0f", 0, NULL }, { "experimental.outlet.1.switch_on_control", ST_FLAG_RW | ST_FLAG_NUMBER, 0, "UPS.OutletSystem.Outlet.SwitchOnControl", NULL, "%.0f", 0, NULL }, { "experimental.powerconverter.input_flow_id", 0, 0, "UPS.PowerConverter.Input.FlowID", NULL, "%.0f", 0, NULL }, /* WAS: experimental.powerconverter.input_frequency */ { "input.frequency", 0, 0, "UPS.PowerConverter.Input.Frequency", NULL, "%.0f", 0, NULL }, { "experimental.powerconverter.input_id", 0, 0, "UPS.PowerConverter.Input.InputID", NULL, "%.0f", 0, NULL }, /* WAS: experimental.powerconverter.input_voltage */ { "input.voltage", 0, 0, "UPS.PowerConverter.Input.Voltage", NULL, "%.0f", 0, NULL }, /* WAS: experimental.powerconverter.output_active_power */ { "ups.realpower", 0, 0, "UPS.PowerConverter.Output.ActivePower", NULL, "%.0f", 0, NULL }, /* WAS: experimental.powerconverter.output_apparent_power */ { "ups.power", 0, 0, "UPS.PowerConverter.Output.ApparentPower", NULL, "%.0f", 0, NULL }, /* WAS: experimental.powerconverter.output_current */ { "output.current", 0, 0, "UPS.PowerConverter.Output.Current", NULL, "%.0f", 0, NULL }, { "experimental.powerconverter.output_flowid", 0, 0, "UPS.PowerConverter.Output.FlowID", NULL, "%.0f", 0, NULL }, /* WAS: experimental.powerconverter.output_frequency */ { "output.frequency", 0, 0, "UPS.PowerConverter.Output.Frequency", NULL, "%.0f", 0, NULL }, { "experimental.powerconverter.output_id", 0, 0, "UPS.PowerConverter.Output.OutputID", NULL, "%.0f", 0, NULL }, /* WAS: experimental.powerconverter.output_percent_load * Note: several original readings map into "ups.load", first served wins */ { "ups.load", 0, 0, "UPS.PowerConverter.Output.PercentLoad", NULL, "%.0f", 0, NULL }, /* WAS: experimental.powerconverter.output_voltage */ { "output.voltage", 0, 0, "UPS.PowerConverter.Output.Voltage", NULL, "%.0f", 0, NULL }, { "experimental.powerconverter.powerconverterid", 0, 0, "UPS.PowerConverter.PowerConverterID", NULL, "%.0f", 0, NULL }, { "experimental.powersummary.capacity_granularity_1", 0, 0, "UPS.PowerSummary.CapacityGranularity1", NULL, "%.0f", 0, NULL }, { "experimental.powersummary.capacity_granularity_2", 0, 0, "UPS.PowerSummary.CapacityGranularity2", NULL, "%.0f", 0, NULL }, /* WAS: */ { "experimental.powersummary.capacity_mode", 0, 0, "UPS.PowerSummary.CapacityMode", NULL, "%.0f", 0, NULL }, /* WAS: experimental.powersummary.delay_before_shutdown */ { "ups.delay.shutdown", ST_FLAG_RW | ST_FLAG_STRING, 10, "UPS.PowerSummary.DelayBeforeShutdown", NULL, DEFAULT_OFFDELAY, HU_FLAG_ABSENT, NULL }, /* WAS: experimental.powersummary.design_capacity */ { "battery.capacity", 0, 0, "UPS.PowerSummary.DesignCapacity", NULL, "%.0f", 0, NULL }, { "experimental.powersummary.flow_id", 0, 0, "UPS.PowerSummary.FlowID", NULL, "%.0f", 0, NULL }, /* WAS: experimental.powersummary.full_charge_capacity */ { "battery.capacity", 0, 0, "UPS.PowerSummary.FullChargeCapacity", NULL, "%.0f", 0, NULL }, /* WAS: experimental.powersummary.idevice_chemistry */ { "battery.type", 0, 0, "UPS.PowerSummary.iDeviceChemistry", NULL, "%.0f", 0, NULL }, /* WAS: experimental.powersummary.percent_load * Note: several original readings map into "ups.load", first served wins */ { "ups.load", 0, 0, "UPS.PowerSummary.PercentLoad", NULL, "%.0f", 0, NULL }, { "experimental.powersummary.rechargeable", 0, 0, "UPS.PowerSummary.Rechargeable", NULL, "%.0f", 0, NULL }, /* WAS: experimental.powersummary.remaining_capacity */ { "battery.charge", 0, 0, "UPS.PowerSummary.RemainingCapacity", NULL, "%.0f", 0, NULL }, /* WAS: experimental.powersummary.remaining_time_limit */ { "battery.runtime.low", ST_FLAG_RW | ST_FLAG_NUMBER, 0, "UPS.PowerSummary.RemainingTimeLimit", NULL, "%.0f", 0, NULL }, /* WAS: experimental.powersummary.run_time_to_empty */ { "battery.runtime", 0, 0, "UPS.PowerSummary.RunTimeToEmpty", NULL, "%.0f", 0, NULL }, /* WAS: experimental.powersummary.voltage */ { "battery.voltage", 0, 0, "UPS.PowerSummary.Voltage", NULL, "%.0f", 0, NULL }, /* WAS: experimental.powersummary.delay_before_shutdown */ { "ups.timer.shutdown", 0, 0, "UPS.PowerSummary.DelayBeforeShutdown", NULL, "%.0f", HU_FLAG_QUICK_POLL, NULL }, #if WITH_UNMAPPED_DATA_POINTS /* not implemented*/ { "unmapped.ups.powersummary.powersummaryid", 0, 0, "UPS.PowerSummary.PowerSummaryID", NULL, "%.0f", 0, NULL }, #endif /* if WITH_UNMAPPED_DATA_POINTS */ { "BOOL", 0, 0, "UPS.PowerSummary.PresentStatus.ACPresent", NULL, NULL, HU_FLAG_QUICK_POLL, online_info }, { "BOOL", 0, 0, "UPS.PowerSummary.PresentStatus.AwaitingPower", NULL, NULL, HU_FLAG_QUICK_POLL, awaitingpower_info }, { "BOOL", 0, 0, "UPS.PowerSummary.PresentStatus.BatteryPresent", NULL, NULL, 0, nobattery_info }, /* not implemented*/ /* { "experimental.ups.presentstatus.belowremainingcapacitylimit", 0, 0, "UPS.PowerSummary.PresentStatus.BelowRemainingCapacityLimit", NULL, "%.0f", 0, NULL }, */ /* { "BOOL", 0, 0, "UPS.PowerSummary.PresentStatus.Boost", NULL, NULL, 0, boost_info }, */ /* { "BOOL", 0, 0, "UPS.PowerSummary.PresentStatus.Buck", NULL, NULL, 0, trim_info }, */ /* { "BOOL", 0, 0, "UPS.PowerSummary.PresentStatus.Charging", NULL, NULL, HU_FLAG_QUICK_POLL, charging_info }, */ { "BOOL", 0, 0, "UPS.PowerSummary.PresentStatus.CommunicationLost", NULL, NULL, 0, commfault_info }, { "BOOL", 0, 0, "UPS.PowerSummary.PresentStatus.Discharging", NULL, NULL, HU_FLAG_QUICK_POLL, discharging_info }, /* not implemented*/ /* { "experimental.ups.powersummary.presentstatus.good", 0, 0, "UPS.PowerSummary.PresentStatus.Good", NULL, "%.0f", 0, NULL }, */ /* { "experimental.ups.powersummary.presentstatus.internalfailure", 0, 0, "UPS.PowerSummary.PresentStatus.InternalFailure", NULL, "%.0f", 0, NULL }, */ { "BOOL", 0, 0, "UPS.PowerSummary.PresentStatus.NeedReplacement", NULL, NULL, 0, replacebatt_info }, { "BOOL", 0, 0, "UPS.PowerSummary.PresentStatus.Overload", NULL, NULL, HU_FLAG_QUICK_POLL, overload_info }, { "BOOL", 0, 0, "UPS.PowerSummary.PresentStatus.OverTemperature", NULL, NULL, 0, overheat_info }, /* not implemented*/ /* { "BOOL", 0, 0, "UPS.PowerSummary.PresentStatus.RemainingTimeLimitExpired", NULL, NULL, 0, lowbatt_info }, */ { "BOOL", 0, 0, "UPS.PowerSummary.PresentStatus.ShutdownImminent", NULL, NULL, 0, shutdownimm_info }, { "BOOL", 0, 0, "UPS.EVER1.EVER18.EVER19", NULL, NULL, 0, overload_info }, { "BOOL", 0, 0, "UPS.EVER1.EVER18.EVER20", NULL, NULL, 0, lowbatt_info }, { "BOOL", 0, 0, "UPS.EVER1.EVER18.EVER21", NULL, NULL, 0, boost_info }, { "BOOL", 0, 0, "UPS.EVER1.EVER18.EVER22", NULL, NULL, 0, trim_info }, { "BOOL", 0, 0, "UPS.EVER1.EVER18.EVER25", NULL, NULL, 0, charging_info }, { "BOOL", 0, 0, "UPS.EVER1.EVER18.EVER28", NULL, NULL, 0, replacebatt_info }, { "BOOL", 0, 0, "UPS.EVER1.EVER32.EVER33", NULL, NULL, 0, overload_info }, { "BOOL", 0, 0, "UPS.EVER1.EVER32.EVER40", NULL, "%.0f", 0, commfault_info }, { "BOOL", 0, 0, "UPS.EVER1.EVER97.EVER102", NULL, "%s", 0, ever_on_off_info }, /* ever workmodes, messages & alarms */ { "experimental.status.workmode", 0, 0, "UPS.EVER1.EVER97.EVER98", NULL, "%s", 0, ever_workmode }, { "experimental.status.messages", 0, 0, "UPS.EVER1.EVER18.EVER28", NULL, NULL, 0, ever_messages }, { "experimental.status.alarms", 0, 0, "UPS.EVER1.EVER32.EVER33", NULL, NULL, 0, ever_alarms }, /* instant commands */ /* experimental: With the same fields here, are the commands different? * Per NUT command names, should be: documented load.off stays off, like * shutdown.stayoff, but shutdown.return may return if wall power comes back! * In many drivers, similar command with "-1" instead of DEFAULT_OFFDELAY * serves as a shutdown.stop (to abort a pending shutdown). */ { "load.off.delay", 0, 0, "UPS.PowerSummary.DelayBeforeShutdown", NULL, DEFAULT_OFFDELAY, HU_TYPE_CMD, NULL }, { "shutdown.return", 0, 0, "UPS.PowerSummary.DelayBeforeShutdown", NULL, DEFAULT_OFFDELAY, HU_TYPE_CMD, NULL }, /* end of structure. */ { NULL, 0, 0, NULL, NULL, NULL, 0, NULL } }; static const char *ever_format_model(HIDDevice_t *hd) { return hd->Product; } static const char *ever_format_mfr(HIDDevice_t *hd) { return hd->Vendor ? hd->Vendor : "Ever"; } static const char *ever_format_serial(HIDDevice_t *hd) { return hd->Serial; } /* this function allows the subdriver to "claim" a device: return 1 if the device is supported by this subdriver, else 0. */ static int ever_claim(HIDDevice_t *hd) { int status = is_usb_device_supported(ever_usb_device_table, hd); switch (status) { case POSSIBLY_SUPPORTED: /* by default, reject, unless the productid option is given */ if (getval("productid")) { return 1; } possibly_supported("Ever", hd); return 0; case SUPPORTED: return 1; case NOT_SUPPORTED: default: return 0; } } subdriver_t ever_subdriver = { EVER_HID_VERSION, ever_claim, ever_utab, ever_hid2nut, ever_format_model, ever_format_mfr, ever_format_serial, fix_report_desc, }; nut-2.8.1/drivers/apcsmart.c0000644000175000017500000015313714516530040012715 00000000000000/* * apcsmart.c - driver for APC smart protocol units (originally "newapc") * * Copyright (C) 1999 Russell Kroll * (C) 2000 Nigel Metheringham * (C) 2011+ Michal Soltys * * 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 2 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, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "main.h" /* Must be first, includes "config.h" */ #include #include #include #include #include /* strcasecmp() */ #include "serial.h" #include "timehead.h" #include "nut_stdint.h" #include "apcsmart.h" #include "apcsmart_tabs.h" #define DRIVER_NAME "APC Smart protocol driver" #define DRIVER_VERSION "3.32" #ifdef WIN32 # ifndef ECANCELED # define ECANCELED ERROR_CANCELLED # endif #endif /* driver description structure */ upsdrv_info_t upsdrv_info = { DRIVER_NAME, DRIVER_VERSION, "Russell Kroll \n" "Nigel Metheringham \n" "Michal Soltys ", DRV_STABLE, { &apc_tab_info, NULL } }; static long ups_status = 0; /* some forwards */ static int sdcmd_S(const void *); static int sdcmd_AT(const void *); static int sdcmd_K(const void *); static int sdcmd_Z(const void *); static int sdcmd_CS(const void *); /* * following table *must* match order defined in the man page, namely: * 0:: soft hibernate (*S*) * 1:: hard hibernate (*@*) * 2:: delayed poweroff (*K*) * 3:: instant poweroff (*Z*) * 4:: "force OB hack" (*CS*) */ static int (*sdlist[])(const void *) = { sdcmd_S, sdcmd_AT, sdcmd_K, sdcmd_Z, sdcmd_CS, }; #define SDIDX_AT 1 /* * note: both lookup functions MUST be used after variable detection is * completed - that is after deprecate_vars() call; the general reason for this * is 1:n and n:1 nut <-> apc mappings, which are not determined prior to the * detection */ static apc_vartab_t *vt_lookup_char(char cmdchar) { int i; for (i = 0; apc_vartab[i].name != NULL; i++) if ((apc_vartab[i].flags & APC_PRESENT) && apc_vartab[i].cmd == cmdchar) return &apc_vartab[i]; return NULL; } static apc_vartab_t *vt_lookup_name(const char *var) { int i; for (i = 0; apc_vartab[i].name != NULL; i++) if ((apc_vartab[i].flags & APC_PRESENT) && !strcasecmp(apc_vartab[i].name, var)) return &apc_vartab[i]; return NULL; } static const char *prtchr(char x) { static size_t curr = 24; static char info[32]; curr = (curr + 8) & 0x1F; snprintf(info + curr, 8, isprint((size_t)x) ? "%c" : "0x%02x", x); return info + curr; } static int rexhlp(const char *rex, const char *val) { static const char *empty = ""; int ret; regex_t mbuf; if (!rex || !*rex) return 1; if (!val) val = empty; regcomp(&mbuf, rex, REG_EXTENDED|REG_NOSUB); ret = regexec(&mbuf, val, 0, 0, 0); regfree(&mbuf); return !ret; } /* convert APC formatting to NUT formatting */ /* TODO: handle errors better */ static const char *convert_data(apc_vartab_t *vt, const char *upsval) { static char temp[APC_LBUF]; long tval; /* this should never happen */ if (strlen(upsval) >= sizeof(temp)) { upslogx(LOG_CRIT, "%s: the length of [%s] is too big", __func__, vt->name); memcpy(temp, upsval, sizeof(temp) - 1); temp[sizeof(temp) - 1] = '\0'; return temp; } switch (vt->flags & APC_F_MASK) { case APC_F_PERCENT: case APC_F_VOLT: case APC_F_AMP: case APC_F_CELSIUS: case APC_F_HEX: case APC_F_DEC: case APC_F_SECONDS: case APC_F_LEAVE: /* no conversion for any of these */ strcpy(temp, upsval); return temp; case APC_F_HOURS: /* convert to seconds */ tval = 60 * 60 * strtol(upsval, NULL, 10); snprintf(temp, sizeof(temp), "%ld", tval); return temp; case APC_F_MINUTES: /* Convert to seconds - NUT standard time measurement */ tval = 60 * strtol(upsval, NULL, 10); /* Ignore errors - there's not much we can do */ snprintf(temp, sizeof(temp), "%ld", tval); return temp; case APC_F_REASON: switch (upsval[0]) { case 'R': return "unacceptable utility voltage rate of change"; case 'H': return "high utility voltage"; case 'L': return "low utility voltage"; case 'T': return "line voltage notch or spike"; case 'O': return "no transfers yet since turnon"; case 'S': return "simulated power failure or UPS test"; default: strcpy(temp, upsval); return temp; } } /* this should never happen */ upslogx(LOG_CRIT, "%s: unable to convert [%s]", __func__, vt->name); strcpy(temp, upsval); return temp; } /* report differences if tcsetattr != tcgetattr, return otherwise */ /* * Aix compatible names */ #if defined(VWERSE) && !defined(VWERASE) #define VWERASE VWERSE #endif /* VWERSE && !VWERASE */ #if defined(VDISCRD) && !defined(VDISCARD) #define VDISCARD VDISCRD #endif /* VDISCRD && !VDISCARD */ static void apc_ser_diff(struct termios *tioset, struct termios *tioget) { size_t i; const char dir[] = { 's', 'g' }; struct termios *tio[] = { tioset, tioget }; struct cchar { const char *name; unsigned int sub; }; const struct cchar cchars1[] = { #ifdef VDISCARD { "discard", VDISCARD }, #endif #ifdef VDSUSP { "dsusp", VDSUSP }, #endif { "eof", VEOF }, { "eol", VEOL }, { "eol2", VEOL2 }, { "erase", VERASE }, #ifdef VINTR { "intr", VINTR }, #endif { "kill", VKILL }, { "lnext", VLNEXT }, { "min", VMIN }, { "quit", VQUIT }, #ifdef VREPRINT { "reprint", VREPRINT }, #endif { "start", VSTART }, #ifdef VSTATUS { "status", VSTATUS }, #endif { "stop", VSTOP }, { "susp", VSUSP }, { "time", VTIME }, { "werase", VWERASE }, { NULL, 0 }, }, *cp; /* clear status flags so that they don't affect our binary compare */ #if defined(PENDIN) || defined(FLUSHO) for (i = 0; i < SIZEOF_ARRAY(tio); i++) { #ifdef PENDIN tio[i]->c_lflag &= ~(unsigned int)PENDIN; #endif #ifdef FLUSHO tio[i]->c_lflag &= ~(unsigned int)FLUSHO; #endif } #endif /* defined(PENDIN) || defined(FLUSHO) */ if (!memcmp(tio[0], tio[1], sizeof(*tio[0]))) return; upslogx(LOG_NOTICE, "%s: device reports different attributes than requested", device_path); /* * According to the manual the most common problem is mis-matched * combinations of input and output baud rates. If the combination is * not supported then neither are changed. This should not be a * problem here since we set them both to the same extremely common * rate of 2400. */ for (i = 0; i < SIZEOF_ARRAY(tio); i++) { upsdebugx(1, "tc%cetattr(): gfmt1:cflag=%x:iflag=%x:lflag=%x:oflag=%x:", dir[i], (unsigned int) tio[i]->c_cflag, (unsigned int) tio[i]->c_iflag, (unsigned int) tio[i]->c_lflag, (unsigned int) tio[i]->c_oflag); for (cp = cchars1; cp->name; ++cp) upsdebugx(1, "\t%s=%x:", cp->name, tio[i]->c_cc[cp->sub]); upsdebugx(1, "\tispeed=%d:ospeed=%d", (int) cfgetispeed(tio[i]), (int) cfgetospeed(tio[i])); } } static void apc_ser_set(void) { struct termios tio, tio_chk; char *val; /* * this must be called before the rest, as ser_set_speed() performs * early initialization of the port, apart from changing speed */ ser_set_speed(upsfd, device_path, B2400); val = getval("cable"); if (val && !strcasecmp(val, ALT_CABLE_1)) { if (ser_set_dtr(upsfd, 1) == -1) fatalx(EXIT_FAILURE, "%s: ser_set_dtr(%s) failed", __func__, device_path); if (ser_set_rts(upsfd, 0) == -1) fatalx(EXIT_FAILURE, "%s: ser_set_rts(%s) failed", __func__, device_path); } /* * that's all if we want simple non canonical mode; this is meant as a * compatibility measure for windows systems and perhaps some * problematic serial cards/converters */ if ((val = getval("ttymode")) && !strcmp(val, "raw")) return; memset(&tio, 0, sizeof(tio)); errno = 0; if (tcgetattr(upsfd, &tio)) fatal_with_errno(EXIT_FAILURE, "%s: tcgetattr(%s)", __func__, device_path); /* set port mode: common stuff, canonical processing */ tio.c_cflag |= (CS8 | CLOCAL | CREAD); tio.c_lflag |= ICANON; #ifdef NOKERNINFO tio.c_lflag |= NOKERNINFO; #endif tio.c_lflag &= ~(unsigned int)(ISIG | IEXTEN); tio.c_iflag |= (IGNCR | IGNPAR); tio.c_iflag &= ~(unsigned int)(IXON | IXOFF); tio.c_cc[VEOL] = '*'; /* specially handled in apc_read() */ #ifdef _POSIX_VDISABLE tio.c_cc[VERASE] = _POSIX_VDISABLE; tio.c_cc[VKILL] = _POSIX_VDISABLE; tio.c_cc[VEOF] = _POSIX_VDISABLE; tio.c_cc[VEOL2] = _POSIX_VDISABLE; #endif if (tcflush(upsfd, TCIOFLUSH)) fatal_with_errno(EXIT_FAILURE, "%s: tcflush(%s)", __func__, device_path); /* * warn: * Note, that tcsetattr() returns success if /any/ of the requested * changes could be successfully carried out. Thus the more complicated * test. */ if (tcsetattr(upsfd, TCSANOW, &tio)) fatal_with_errno(EXIT_FAILURE, "%s: tcsetattr(%s)", __func__, device_path); memset(&tio_chk, 0, sizeof(tio_chk)); if (tcgetattr(upsfd, &tio_chk)) fatal_with_errno(EXIT_FAILURE, "%s: tcgetattr(%s)", __func__, device_path); apc_ser_diff(&tio, &tio_chk); } static void ups_status_set(void) { status_init(); if (ups_status & APC_STAT_CAL) status_set("CAL"); /* calibration */ if (ups_status & APC_STAT_TRIM) status_set("TRIM"); /* SmartTrim */ if (ups_status & APC_STAT_BOOST) status_set("BOOST"); /* SmartBoost */ if (ups_status & APC_STAT_OL) status_set("OL"); /* on line */ if (ups_status & APC_STAT_OB) status_set("OB"); /* on battery */ if (ups_status & APC_STAT_OVER) status_set("OVER"); /* overload */ if (ups_status & APC_STAT_LB) status_set("LB"); /* low battery */ if (ups_status & APC_STAT_RB) status_set("RB"); /* replace batt */ if (ups_status == 0) status_set("OFF"); status_commit(); } static void alert_handler(char ch) { switch (ch) { case '!': /* clear OL, set OB */ upsdebugx(1, "%s: %s", __func__, "OB"); ups_status &= ~APC_STAT_OL; ups_status |= APC_STAT_OB; break; case '$': /* clear OB, set OL */ upsdebugx(1, "%s: %s", __func__, "OL"); ups_status &= ~APC_STAT_OB; ups_status |= APC_STAT_OL; break; case '%': /* set LB */ upsdebugx(1, "%s: %s", __func__, "LB"); ups_status |= APC_STAT_LB; break; case '+': /* clear LB */ upsdebugx(1, "%s: %s", __func__, "not LB"); ups_status &= ~APC_STAT_LB; break; case '#': /* set RB */ upsdebugx(1, "%s: %s", __func__, "RB"); ups_status |= APC_STAT_RB; break; case '?': /* set OVER */ upsdebugx(1, "%s: %s", __func__, "OVER"); ups_status |= APC_STAT_OVER; break; case '=': /* clear OVER */ upsdebugx(1, "%s: %s", __func__, "not OVER"); ups_status &= ~APC_STAT_OVER; break; default: upsdebugx(1, "%s: got 0x%02x (unhandled)", __func__, ch); break; } ups_status_set(); } /* * we need a tiny bit different processing due to '*' and canonical mode; the * function is subtly different from generic ser_get_line_alert() */ #define apc_read(b, l, f) apc_read_i(b, l, f, __func__, __LINE__) static ssize_t apc_read_i(char *buf, size_t buflen, int flags, const char *fn, unsigned int ln) { const char *iset = IGN_CHARS, *aset = ""; size_t count = 0; ssize_t i, ret; int sec = 3, usec = 0; char temp[APC_LBUF]; if (buflen > (size_t)SSIZE_MAX) { fatalx (EXIT_FAILURE, "Error: apc_read_i called with buflen too large"); } if (INVALID_FD(upsfd)) return 0; if (flags & SER_D0) { sec = 0; usec = 0; } if (flags & SER_DX) { sec = 0; usec = 200000; } if (flags & SER_D1) { sec = 1; usec = 500000; } if (flags & SER_D3) { sec = 3; usec = 0; } if (flags & SER_AA) { iset = IGN_AACHARS; aset = ALERT_CHARS; } if (flags & SER_CC) { iset = IGN_CCCHARS; aset = ""; sec = 6; usec = 0; } if (flags & SER_CS) { iset = IGN_CSCHARS; aset = ""; sec = 6; usec = 0; } memset(buf, '\0', buflen); while (count < buflen - 1) { errno = 0; ret = select_read(upsfd, temp, sizeof(temp), sec, usec); /* partial timeout (non-canon only paranoid check) */ if (ret == 0 && count) { ser_comm_fail("serial port partial timeout: %u(%s)", ln, fn); return -1; } /* error or no timeout allowed */ if (ret < 0 || (ret == 0 && !(flags & SER_TO))) { if (ret) ser_comm_fail("serial port read error: %u(%s): %s", ln, fn, strerror(errno)); else ser_comm_fail("serial port read timeout: %u(%s)", ln, fn); return ret; } /* ok, timeout is acceptable */ if (ret == 0 && (flags & SER_TO)) { /* * but it doesn't imply ser_comm_good * * for example we might be in comm_fail condition, * trying to "nudge" the UPS with some command * obviously expecting timeout if the comm is still * lost. This would result with filling logs with * confusing comm lost/comm re-established pairs due to * successful serial writes */ return 0; } /* parse input */ for (i = 0; i < ret; i++) { /* overflow read */ if (count == buflen - 1) { ser_comm_fail("serial port read overflow: %u(%s)", ln, fn); tcflush(upsfd, TCIFLUSH); return -1; } /* standard "line received" condition */ if (temp[i] == ENDCHAR) { ser_comm_good(); return (ssize_t)count; } /* * '*' is set as a secondary EOL; convert to 'OK' only as a * reply to shutdown command in sdok(); otherwise next * select_read() will continue normally */ if ((flags & SER_HA) && temp[i] == '*') { /* * a bit paranoid, but remember '*' is not real EOL; * there could be some firmware in existence, that * would send both string: 'OK\n' and alert: '*'. * Just in case, try to flush the input with small 1 sec. * timeout */ memset(buf, '\0', buflen); errno = 0; ret = select_read(upsfd, temp, sizeof(temp), 1, 0); if (ret < 0) { ser_comm_fail("serial port read error: %u(%s): %s", ln, fn, strerror(errno)); return ret; } buf[0] = 'O'; buf[1] = 'K'; ser_comm_good(); return 2; } /* ignore set */ if (strchr(iset, temp[i]) || temp[i] == '*') { continue; } /* alert set */ if (strchr(aset, temp[i])) { alert_handler(temp[i]); continue; } buf[count++] = temp[i]; } } ser_comm_good(); /* buflen range limited above */ return (ssize_t)count; } #define apc_write(code) apc_write_i(code, __func__, __LINE__) static ssize_t apc_write_i(unsigned char code, const char *fn, unsigned int ln) { ssize_t ret; errno = 0; if (INVALID_FD(upsfd)) return 0; ret = ser_send_char(upsfd, code); /* * Formally any write() sould never return 0, if the count != 0. For * the sake of handling any obscure nonsense, we consider such return * as a failure - thus <= condition; either way, LE is pretty hard * condition hardly ever happening; */ if (ret <= 0) ser_comm_fail("serial port write error: %u(%s): %s", ln, fn, strerror(errno)); return ret; } /* * We have to watch out for NA, here; * This is generally safe, as otherwise we will just timeout. The reason we do * it, is that under certain conditions an ups might respond with NA for * something it would normally handle (e.g. calling @ while being in powered * off or hibernated state. If we keep sending the "arguments" after getting * NA, they will be interpreted as commands, which is quite a bug :) * Furthermore later flushes might not work properly, if the reply to those * commands are generated with some delay. * * We also set errno to something usable, so outside upslog calls don't output * confusing "success". */ #define apc_write_long(code) apc_write_long_i(code, __func__, __LINE__) static ssize_t apc_write_long_i(const char *code, const char *fn, unsigned int ln) { char temp[APC_LBUF]; ssize_t ret; ret = apc_write_i((const unsigned char)(*code), fn, ln); if (ret != 1) return ret; /* peek for the answer - anything at this point is failure */ ret = apc_read(temp, sizeof(temp), SER_DX|SER_TO); if (ret) { errno = ECANCELED; return -1; } ret = ser_send_pace(upsfd, 50000, "%s", code + 1); if (ret >= 0) ret++; /* see remark in plain apc_write() */ if (ret != (int)strlen(code)) ser_comm_fail("serial port write error: %u(%s): %s", ln, fn, strerror(errno)); return ret; } #define apc_write_rep(code) apc_write_rep_i(code, __func__, __LINE__) static ssize_t apc_write_rep_i(unsigned char code, const char *fn, unsigned int ln) { char temp[APC_LBUF]; ssize_t ret; ret = apc_write_i(code, fn, ln); if (ret != 1) return ret; /* peek for the answer - anything at this point is failure */ ret = apc_read(temp, sizeof(temp), SER_DX|SER_TO); if (ret) { errno = ECANCELED; return -1; } usleep(1300000); ret = apc_write_i(code, fn, ln); if (ret >= 0) ret++; return ret; } /* all flags other than SER_AA are ignored */ static void apc_flush(int flags) { char temp[APC_LBUF]; if (flags & SER_AA) { tcflush(upsfd, TCOFLUSH); /* TODO */ while(apc_read(temp, sizeof(temp), SER_D0|SER_TO|SER_AA) > 0); } else { tcflush(upsfd, TCIOFLUSH); /* tcflush(upsfd, TCIFLUSH); */ /* while(apc_read(temp, sizeof(temp), SER_D0|SER_TO)); */ } } /* apc specific wrappers around set/del info - to handle "packed" variables */ static void apc_dstate_delinfo(apc_vartab_t *vt, int skip) { char *name, *nidx; int c; /* standard not packed var */ if (!(vt->flags & APC_PACK)) { dstate_delinfo(vt->name); return; } if ( !(name = xmalloc(sizeof(char) * vt->nlen0)) ) { upslogx(LOG_ERR, "apc_dstate_delinfo() failed to allocate buffer"); return; } strcpy(name, vt->name); nidx = strstr(name,".0.") + 1; for (c = skip; c < vt->cnt; c++) { *nidx = (char)('1' + c); dstate_delinfo(name); } vt->cnt = 0; free(name); } static void apc_dstate_setinfo(apc_vartab_t *vt, const char *upsval) { char *name, *nidx; char *temp, *vidx[APC_PACK_MAX], *com, *curr; int c; /* standard not packed var */ if (!(vt->flags & APC_PACK)) { dstate_setinfo(vt->name, "%s", convert_data(vt, upsval)); return; } if ( !(name = xmalloc(sizeof(char) * vt->nlen0)) ) { upslogx(LOG_ERR, "apc_dstate_setinfo() failed to allocate buffer"); return; } if ( !(temp = xmalloc(sizeof(char) * (strlen(upsval) + 1))) ) { upslogx(LOG_ERR, "apc_dstate_setinfo() failed to allocate buffer"); free(name); return; } /* we have to set proper name for dstate_setinfo() calls */ strcpy(name, vt->name); nidx = strstr(name,".0.") + 1; /* split the value string */ strcpy(temp, upsval); curr = temp; c = 0; do { vidx[c] = curr; com = strchr(curr, ','); if (com) { curr = com + 1; *com = '\0'; } } while(++c < APC_PACK_MAX && com); /* * unlikely, but keep things tidy - remove leftover values, if * subsequent read returns less */ if (vt->cnt > c) apc_dstate_delinfo(vt, c); /* unlikely - warn user if we have more than APC_PACK_MAX fields */ if (c == APC_PACK_MAX && com) upslogx(LOG_WARNING, "packed variable %s [%s] longer than %d fields,\n" "ignoring remaining fields", vt->name, prtchr(vt->cmd), c); vt->cnt = c; while (c-- > 0) { *nidx = (char)('1' + c); if (*vidx[c]) dstate_setinfo(name, "%s", convert_data(vt, vidx[c])); else dstate_setinfo(name, "N/A"); } free(name); free(temp); } static const char *preread_data(apc_vartab_t *vt) { ssize_t ret; static char temp[APC_LBUF]; upsdebugx(1, "%s: %s [%s]", __func__, vt->name, prtchr(vt->cmd)); apc_flush(0); ret = apc_write((const unsigned char)vt->cmd); if (ret != 1) return 0; ret = apc_read(temp, sizeof(temp), SER_TO); if (ret < 1 || !strcmp(temp, "NA")) { if (ret >= 0) upslogx(LOG_ERR, "%s: %s [%s] timed out or not supported", __func__, vt->name, prtchr(vt->cmd)); return 0; } return temp; } static int poll_data(apc_vartab_t *vt) { char temp[APC_LBUF]; if (!(vt->flags & APC_PRESENT)) return 1; upsdebugx(1, "%s: %s [%s]", __func__, vt->name, prtchr(vt->cmd)); apc_flush(SER_AA); if (apc_write((const unsigned char)vt->cmd) != 1) return 0; if (apc_read(temp, sizeof(temp), SER_AA) < 1) return 0; /* automagically no longer supported by the hardware somehow */ if (!strcmp(temp, "NA")) { upslogx(LOG_WARNING, "%s: verified variable %s [%s] returned NA, removing", __func__, vt->name, prtchr(vt->cmd)); vt->flags &= ~(unsigned int)APC_PRESENT; apc_dstate_delinfo(vt, 0); } else apc_dstate_setinfo(vt, temp); return 1; } static int update_status(void) { ssize_t ret; char buf[APC_LBUF]; upsdebugx(1, "%s: [%s]", __func__, prtchr(APC_STATUS)); apc_flush(SER_AA); if (apc_write(APC_STATUS) != 1) return 0; ret = apc_read(buf, sizeof(buf), SER_AA); if ((ret < 1) || (!strcmp(buf, "NA"))) { if (ret >= 0) upslogx(LOG_WARNING, "%s: %s", __func__, "failed"); return 0; } ups_status = strtol(buf, 0, 16) & 0xff; ups_status_set(); return 1; } /* * two informative functions, to not redo the same thing in few places */ static inline void confirm_cv(unsigned char cmd, const char *tag, const char *name) { upsdebugx(1, "%s [%s] - %s supported", name, prtchr((char)cmd), tag); } static inline void warn_cv(unsigned char cmd, const char *tag, const char *name) { if (tag && name) upslogx(LOG_WARNING, "%s [%s] - %s invalid", name, prtchr((char)cmd), tag); else upslogx(LOG_WARNING, "[%s] unrecognized", prtchr((char)cmd)); } static void var_string_setup(apc_vartab_t *vt) { /* * handle special data for our two strings; note - STRING variables * cannot be PACK at the same time */ if (vt->flags & APC_STRING) { dstate_setflags(vt->name, ST_FLAG_RW | ST_FLAG_STRING); dstate_setaux(vt->name, APC_STRLEN); vt->flags |= APC_RW; } } static int var_verify(apc_vartab_t *vt) { const char *temp; if (vt->flags & APC_MULTI) { /* APC_MULTI are handled by deprecate_vars() */ vt->flags |= APC_PRESENT; return -1; } temp = preread_data(vt); /* no conversion here, validator should operate on raw values */ if (!temp || !rexhlp(vt->regex, temp)) { warn_cv((const unsigned char)vt->cmd, "variable", vt->name); return 0; } vt->flags |= APC_PRESENT; apc_dstate_setinfo(vt, temp); var_string_setup(vt); confirm_cv((const unsigned char)vt->cmd, "variable", vt->name); return 1; } /* * This function iterates over vartab, deprecating nut<->apc 1:n and n:1 * variables. We prefer earliest present variable. All the other ones must be * marked as not present (which implies deprecation). * This pass is requried after completion of all protocol_verify() and/or * legacy_verify() calls. */ static void deprecate_vars(void) { int i, j; const char *temp; apc_vartab_t *vt, *vtn; for (i = 0; apc_vartab[i].name != NULL; i++) { vt = &apc_vartab[i]; if (!(vt->flags & APC_MULTI) || !(vt->flags & APC_PRESENT)) { /* * a) not interesting, or * b) not marked as present earlier, or already handled */ continue; } /* pre-read data, we have to verify it */ temp = preread_data(vt); /* no conversion here, validator should operate on raw values */ if (!temp || !rexhlp(vt->regex, temp)) { vt->flags &= ~(unsigned int)APC_PRESENT; warn_cv((const unsigned char)vt->cmd, "variable combination", vt->name); continue; } /* multi & present, deprecate all the remaining ones */ for (j = i + 1; apc_vartab[j].name != NULL; j++) { vtn = &apc_vartab[j]; if (strcmp(vtn->name, vt->name) && vtn->cmd != vt->cmd) continue; vtn->flags &= ~(unsigned int)APC_PRESENT; } apc_dstate_setinfo(vt, temp); var_string_setup(vt); confirm_cv((const unsigned char)vt->cmd, "variable combination", vt->name); } } static void apc_getcaps(int qco) { const char *ptr, *entptr; char upsloc, temp[APC_LBUF], cmd, loc, etmp[APC_SBUF], *endtemp; int matrix, valid; size_t nument, entlen, i; ssize_t ret; apc_vartab_t *vt; /* * If we can do caps, then we need the Firmware revision which has the * locale descriptor as the last character (ugh); this is valid for * both 'V' and 'b' commands. */ ptr = dstate_getinfo("ups.firmware"); if (ptr) upsloc = ptr[strlen(ptr) - 1]; else upsloc = 0; /* get capability string */ apc_flush(0); if (apc_write(APC_CAPS) != 1) return; /* * note - apc_read() needs larger timeout grace (not a problem w.r.t. * to nut's timing, as it's done only during setup) and different * ignore set due to certain characters like '#' being received */ ret = apc_read(temp, sizeof(temp), SER_CC|SER_TO); if ((ret < 1) || (!strcmp(temp, "NA"))) { /* * Early Smart-UPS not as smart as the later ones ... * this should never happen on properly functioning hardware - * as capability support was reported earlier */ if (ret >= 0) upslogx(LOG_WARNING, "%s", "APC cannot do capabilities but said it could !"); return; } /* recv always puts a \0 at the end, so this is safe */ /* however it assumes a zero byte cannot be embedded */ endtemp = &temp[0] + strlen(temp); if (temp[0] != '#') { upslogx(LOG_WARNING, "unknown capability start char [%c] !", temp[0]); upsdebugx(1, "please report this caps string: %s", temp); return; } if (temp[1] == '#') { /* Matrix-UPS */ ptr = &temp[0]; matrix = 1; } else { ptr = &temp[1]; matrix = 0; } /* command char, location, # of entries, entry length */ while (ptr[0] != '\0') { if (matrix) ptr += 2; /* jump over repeating ## */ /* check for idiocy */ if (ptr >= endtemp) { /* if we expected this, just ignore it */ if (qco) return; fatalx(EXIT_FAILURE, "capability string has overflowed, " "please report this error with device details!"); } entptr = &ptr[4]; cmd = ptr[0]; loc = ptr[1]; if (ptr[2] < 48 || ptr[3] < 48) { upsdebugx(3, "%s: SKIP: nument (%d) or entlen (%d) " "out of range for cmd %d at loc %d", __func__, (ptr[2] - 48), (ptr[3] - 48), cmd, loc); /* just ignore it as we did for ages see e.g. v2.7.4 * (note the next loop cycle was and still would be * no-op anyway, if "nument <= 0"). */ nument = 0; entlen = 0; /* NOT a full skip: Gotta handle "vt" to act like before */ /*ptr = entptr;*/ /*continue;*/ } else { nument = (size_t)ptr[2] - 48; entlen = (size_t)ptr[3] - 48; } vt = vt_lookup_char(cmd); valid = vt && ((loc == upsloc) || (loc == '4')) && !(vt->flags & APC_PACK); /* mark this as writable */ if (valid) { upsdebugx(1, "%s [%s(%c)] - capability supported", vt->name, prtchr(cmd), loc); dstate_setflags(vt->name, ST_FLAG_RW); /* make sure setvar knows what this is */ vt->flags |= APC_RW | APC_ENUM; } else if (vt && (vt->flags & APC_PACK)) /* * Currently we assume - basing on the following * feedback: * http://www.mail-archive.com/nut-upsdev@lists.alioth.debian.org/msg03398.html * - that "packed" variables are not enumerable; if at * some point in the future it turns out to be false, * the handling will have to be a bit more complex */ upslogx(LOG_WARNING, "WARN: packed APC variable %s [%s] reported as enumerable,\n" "please report it on the mailing list", vt->name, prtchr(cmd)); for (i = 0; i < nument; i++) { if (valid) { snprintf(etmp, entlen + 1, "%s", entptr); dstate_addenum(vt->name, "%s", convert_data(vt, etmp)); } entptr += entlen; } ptr = entptr; } } static void legacy_verify(const char *var) { int i; /* * note: some NUT variables map onto multiple APC ones, e.g. firmware: * V,b -> ups.firmware; that's why we keep the loop, as it's over NUT * names */ for (i = 0; apc_vartab[i].name != NULL; i++) { if (strcmp(apc_vartab[i].name, var)) continue; var_verify(&apc_vartab[i]); } } static void protocol_verify(unsigned char cmd) { int i, found; apc_vartab_t *vt; apc_cmdtab_t *ct; /* don't bother with cmd/var we don't care about */ if (strchr(APC_UNR_CMDS, cmd)) return; /* * loop necessary for apc:nut 1:n cases (e.g. T -> device.uptime, * ambient.0.temperature) */ found = 0; for (i = 0; apc_vartab[i].name != NULL; i++) { vt = &apc_vartab[i]; if (vt->cmd != cmd) continue; var_verify(vt); found = 1; } if (found) return; /* * see if it's a command * loop necessary for apc:nut 1:n cases (e.g. D -> calibrate.start, * calibrate.stop) */ found = 0; for (i = 0; apc_cmdtab[i].name != NULL; i++) { ct = &apc_cmdtab[i]; if (ct->cmd != cmd) continue; ct->flags |= APC_PRESENT; dstate_addcmd(ct->name); confirm_cv(cmd, "command", ct->name); found = 1; } if (found) return; /* * epilogue - unrecognized command / variable not included * in APC_UNR_CMDS */ warn_cv(cmd, NULL, NULL); } static void oldapcsetup(void) { /* * note: battery.date and ups.id make little sense here, as * that would imply writability and this is an *old* apc psu */ legacy_verify("ups.temperature"); legacy_verify("ups.load"); legacy_verify("input.voltage"); legacy_verify("output.voltage"); legacy_verify("battery.charge"); legacy_verify("battery.voltage"); /* these will usually timeout */ legacy_verify("ups.model"); legacy_verify("ups.serial"); legacy_verify("ups.firmware"); legacy_verify("output.current"); deprecate_vars(); /* see if this might be an old Matrix-UPS instead */ if (vt_lookup_name("output.current")) dstate_setinfo("ups.model", "Matrix-UPS"); else { /* really old models don't support ups.model (apc: 0x01) */ if (!vt_lookup_name("ups.model")) /* force the model name */ dstate_setinfo("ups.model", "Smart-UPS"); } /* * If we have come down this path then we dont do capabilities and * other shiny features. */ } /* some hardware is a special case - hotwire the list of cmdchars */ static int firmware_table_lookup(void) { ssize_t ret; unsigned int i, j; char buf[APC_LBUF]; upsdebugx(1, "attempting firmware lookup using [%s]", prtchr(APC_FW_OLD)); apc_flush(0); if (apc_write(APC_FW_OLD) != 1) return 0; if ((ret = apc_read(buf, sizeof(buf), SER_TO)) < 0) return 0; /* * Some UPSes support both 'V' and 'b'. As 'b' doesn't always return * firmware version, we attempt that only if 'V' doesn't work. */ if (!ret || !strcmp(buf, "NA")) { upsdebugx(1, "attempting firmware lookup using [%s]", prtchr(APC_FW_NEW)); if (apc_write(APC_FW_NEW) != 1) return 0; if (apc_read(buf, sizeof(buf), SER_TO) < 1) return 0; } upsdebugx(1, "detected firmware version: %s", buf); /* this will be reworked if we get a lot of these things */ if (!strcmp(buf, "451.2.I")) { /* quirk_capability_overflow */ upsdebugx(1, "WARN: quirky firmware !"); return 2; } if (rexhlp("^[a-fA-F0-9]{2}$", buf)) { /* * certain old set of UPSes that return voltage above 255V * through 'b'; see: * http://article.gmane.org/gmane.comp.monitoring.nut.user/7762 */ strcpy(buf, "set\1"); } for (i = 0; apc_compattab[i].firmware != NULL; i++) { if (!strcmp(apc_compattab[i].firmware, buf)) { upsdebugx(1, "matched firmware: %s", apc_compattab[i].firmware); /* magic ? */ if (strspn(apc_compattab[i].firmware, "05")) { dstate_setinfo("ups.model", "Matrix-UPS"); } else { dstate_setinfo("ups.model", "Smart-UPS"); } /* matched - run the cmdchars from the table */ upsdebugx(1, "parsing out supported cmds and vars"); for (j = 0; j < strlen(apc_compattab[i].cmdchars); j++) protocol_verify((const unsigned char)(apc_compattab[i].cmdchars[j])); deprecate_vars(); return 1; /* matched */ } } return 0; } static int getbaseinfo(void) { unsigned int i; ssize_t ret; int qco; char *cmds, *tail, temp[APC_LBUF]; /* * try firmware lookup first; we could start with 'a', but older models * sometimes return other things than a command set */ qco = firmware_table_lookup(); if (qco == 1) /* found compat */ return 1; upsdebugx(1, "attempting var/cmdset lookup using [%s]", prtchr(APC_CMDSET)); /* * Initially we ask the UPS what commands it takes. If this fails we are * going to need an alternate strategy - we can deal with that if it * happens */ apc_flush(0); if (apc_write(APC_CMDSET) != 1) return 0; if ((ret = apc_read(temp, sizeof(temp), SER_CS|SER_TO)) < 0) return 0; if (!ret || !strcmp(temp, "NA") || !rexhlp(APC_CMDSET_FMT, temp)) { /* We have an old dumb UPS - go to specific code for old stuff */ upslogx(LOG_NOTICE, "very old or unknown APC model, support will be limited"); oldapcsetup(); return 1; } upsdebugx(1, "parsing out supported cmds/vars"); /* * returned set is verified for validity above, so just extract * what's interesting for us * * the known format is: * ver.alerts.commands[.stuff] */ cmds = strchr(temp, '.'); cmds = strchr(cmds + 1, '.'); tail = strchr(++cmds, '.'); if (tail) *tail = 0; for (i = 0; i < strlen(cmds); i++) protocol_verify((const unsigned char)cmds[i]); deprecate_vars(); /* if capabilities are supported, add them here */ if (strchr(cmds, APC_CAPS)) { upsdebugx(1, "parsing out caps"); apc_getcaps(qco); } return 1; } /* check for calibration status and either start or stop */ static int do_cal(int start) { char temp[APC_LBUF]; long tval; ssize_t ret; apc_flush(SER_AA); ret = apc_write(APC_STATUS); if (ret != 1) { return STAT_INSTCMD_HANDLED; /* FUTURE: failure */ } ret = apc_read(temp, sizeof(temp), SER_AA); /* if we can't check the current calibration status, bail out */ if ((ret < 1) || (!strcmp(temp, "NA"))) { upslogx(LOG_WARNING, "%s", "runtime calibration state undeterminable"); return STAT_INSTCMD_HANDLED; /* FUTURE: failure */ } tval = strtol(temp, 0, 16); if (tval & APC_STAT_CAL) { /* calibration currently happening */ if (start == 1) { /* requested start while calibration still running */ upslogx(LOG_NOTICE, "%s", "runtime calibration already in progress"); return STAT_INSTCMD_HANDLED; /* FUTURE: failure */ } /* stop requested */ upslogx(LOG_NOTICE, "%s", "stopping runtime calibration"); ret = apc_write(APC_CMD_CALTOGGLE); if (ret != 1) { return STAT_INSTCMD_HANDLED; /* FUTURE: failure */ } ret = apc_read(temp, sizeof(temp), SER_AA); if ((ret < 1) || (!strcmp(temp, "NA")) || (!strcmp(temp, "NO"))) { upslogx(LOG_WARNING, "stop calibration failed, cmd returned: %s", temp); return STAT_INSTCMD_HANDLED; /* FUTURE: failure */ } return STAT_INSTCMD_HANDLED; /* FUTURE: success */ } /* calibration not happening */ if (start == 0) { /* stop requested */ upslogx(LOG_NOTICE, "%s", "runtime calibration not occurring"); return STAT_INSTCMD_HANDLED; /* FUTURE: failure */ } upslogx(LOG_NOTICE, "%s", "starting runtime calibration"); ret = apc_write(APC_CMD_CALTOGGLE); if (ret != 1) { return STAT_INSTCMD_HANDLED; /* FUTURE: failure */ } ret = apc_read(temp, sizeof(temp), SER_AA); if ((ret < 1) || (!strcmp(temp, "NA")) || (!strcmp(temp, "NO"))) { upslogx(LOG_WARNING, "start calibration failed, cmd returned: %s", temp); return STAT_INSTCMD_HANDLED; /* FUTURE: failure */ } return STAT_INSTCMD_HANDLED; /* FUTURE: success */ } #if 0 /* get the UPS talking to us in smart mode */ static int smartmode(void) { int ret; char temp[APC_LBUF]; apc_flush(0); ret = apc_write(APC_GOSMART); if (ret != 1) { return 0; } ret = apc_read(temp, sizeof(temp), 0); if ((ret < 1) || (!strcmp(temp, "NA")) || (!strcmp(temp, "NO"))) { upslogx(LOG_CRIT, "%s", "enabling smartmode failed !"); return 0; } return 1; } #endif /* * get the UPS talking to us in smart mode * note: this is weird overkill, but possibly excused due to some obscure * hardware/firmware combinations; simpler version commmented out above, for * now let's keep minimally adjusted old one */ static int smartmode(int cnt) { ssize_t ret; int tries; char temp[APC_LBUF]; for (tries = 0; tries < cnt; tries++) { apc_flush(0); if (apc_write(APC_GOSMART) != 1) return 0; /* timeout here is intented */ ret = apc_read(temp, sizeof(temp), SER_TO|SER_D1); if (ret > 0 && !strcmp(temp, "SM")) return 1; /* success */ if (ret < 0) /* error, so we didn't timeout - wait a bit before retry */ sleep(1); if (apc_write(27) != 1) /* ESC */ return 0; /* eat the response (might be NA, might be something else) */ apc_read(temp, sizeof(temp), SER_TO|SER_D1); } return 0; /* failure */ } /* * all shutdown commands should respond with 'OK' or '*' * apc_read() handles conversion to 'OK' so we care only about that one * ign allows for timeout without assuming an error */ static int sdok(int ign) { ssize_t ret; char temp[APC_SBUF]; /* * older upses on failed commands might just timeout, we cut down * timeout grace though * furthermore, command 'Z' will not reply with anything */ ret = apc_read(temp, sizeof(temp), SER_HA|SER_D1|SER_TO); if (ret < 0) return STAT_INSTCMD_FAILED; upsdebugx(1, "%s: got \"%s\"", __func__, temp); if ((!ret && ign) || !strcmp(temp, "OK")) { upsdebugx(1, "%s: %s", __func__, "last shutdown cmd succeeded"); return STAT_INSTCMD_HANDLED; } upsdebugx(1, "%s: %s", __func__, "last shutdown cmd failed"); return STAT_INSTCMD_FAILED; } /* soft hibernate: S - working only when OB, otherwise ignored */ static int sdcmd_S(const void *foo) { apc_flush(0); if (!foo) upsdebugx(1, "%s: issuing [%s]", __func__, prtchr(APC_CMD_SOFTDOWN)); if (apc_write(APC_CMD_SOFTDOWN) != 1) return STAT_INSTCMD_FAILED; return sdok(0); } /* soft hibernate, hack version for CS 350 & co. */ static int sdcmd_CS(const void *foo) { ssize_t ret; useconds_t cshd = 3500000; char temp[APC_SBUF]; const char *val; NUT_UNUSED_VARIABLE(foo); /* TODO: Catch overflows? * Let compilers complain about (non-)casting on systems * where useconds_t is not a good target for strtod() output */ if ((val = getval("cshdelay"))) cshd = (strtod(val, NULL) * 1000000); upsdebugx(1, "%s: issuing CS 'hack' [%s+%s] with %2.1f sec delay", __func__, prtchr(APC_CMD_SIMPWF), prtchr(APC_CMD_SOFTDOWN), (double)cshd / 1000000); if (ups_status & APC_STAT_OL) { apc_flush(0); upsdebugx(1, "%s: issuing [%s]", __func__, prtchr(APC_CMD_SIMPWF)); ret = apc_write(APC_CMD_SIMPWF); if (ret != 1) { return STAT_INSTCMD_FAILED; } /* eat response, allow timeout */ ret = apc_read(temp, sizeof(temp), SER_D1|SER_TO); if (ret < 0) { return STAT_INSTCMD_FAILED; } usleep(cshd); } /* continue with regular soft hibernate */ return sdcmd_S((void *)1); } /* * hard hibernate: @nnn / @nn * note: works differently for older and new models, see manual page for * thorough explanation */ static int sdcmd_AT(const void *str) { ssize_t ret; size_t cnt, padto, i; const char *awd = str; char temp[APC_SBUF], *ptr; if (!awd) awd = "000"; cnt = strlen(awd); padto = cnt == 2 ? 2 : 3; temp[0] = APC_CMD_GRACEDOWN; ptr = temp + 1; for (i = cnt; i < padto ; i++) { *ptr++ = '0'; } strcpy(ptr, awd); upsdebugx(1, "%s: issuing [%s] with %ld minutes of additional wakeup delay", __func__, prtchr(APC_CMD_GRACEDOWN), strtol(awd, NULL, 10)*6); apc_flush(0); ret = apc_write_long(temp); /* Range-check: padto is 2 or 3 per above */ if (ret != (ssize_t)padto + 1) { upslogx(LOG_ERR, "issuing [%s] with %" PRIuSIZE " digits failed", prtchr(APC_CMD_GRACEDOWN), padto); return STAT_INSTCMD_FAILED; } ret = sdok(0); if (ret == STAT_INSTCMD_HANDLED || padto == 3) return (int)ret; upslogx(LOG_ERR, "command [%s] with 2 digits doesn't work - try 3 digits", prtchr(APC_CMD_GRACEDOWN)); /* * "tricky" part - we tried @nn variation and it (unsurprisingly) * failed; we have to abort the sequence with something bogus to have * the clean state; newer upses will respond with 'NO', older will be * silent (YMMV); */ apc_write(APC_GOSMART); /* eat response, allow it to timeout */ apc_read(temp, sizeof(temp), SER_D1|SER_TO); return STAT_INSTCMD_FAILED; } /* shutdown: K - delayed poweroff */ static int sdcmd_K(const void *foo) { ssize_t ret; NUT_UNUSED_VARIABLE(foo); upsdebugx(1, "%s: issuing [%s]", __func__, prtchr(APC_CMD_SHUTDOWN)); apc_flush(0); ret = apc_write_rep(APC_CMD_SHUTDOWN); if (ret != 2) return STAT_INSTCMD_FAILED; return sdok(0); } /* shutdown: Z - immediate poweroff */ static int sdcmd_Z(const void *foo) { ssize_t ret; NUT_UNUSED_VARIABLE(foo); upsdebugx(1, "%s: issuing [%s]", __func__, prtchr(APC_CMD_OFF)); apc_flush(0); ret = apc_write_rep(APC_CMD_OFF); if (ret != 2) { return STAT_INSTCMD_FAILED; } /* note: ups will not reply anything after this command */ return sdok(1); } static void upsdrv_shutdown_simple(void) { long sdtype = 0; const char *val; if ((val = getval("sdtype"))) sdtype = strtol(val, NULL, 10); upsdebugx(1, "%s: currently: %s, sdtype: %ld", __func__, (ups_status & APC_STAT_OL) ? "on-line" : "on battery", sdtype); switch (sdtype) { case 5: /* hard hibernate */ sdcmd_AT(getval("awd")); break; case 4: /* special hack for CS 350 and similar models */ sdcmd_CS(0); break; case 3: /* delayed poweroff */ sdcmd_K(0); break; case 2: /* instant poweroff */ sdcmd_Z(0); break; case 1: /* * Send a combined set of shutdown commands which can work * better if the UPS gets power during shutdown process * Specifically it sends both the soft shutdown 'S' and the * hard hibernate '@nnn' commands */ /* S works only when OB */ if (!(ups_status & APC_STAT_OB) || sdcmd_S(0) != STAT_INSTCMD_HANDLED) sdcmd_AT(getval("awd")); break; default: /* * Send @nnn or S, depending on OB / OL status */ if (ups_status & APC_STAT_OL) /* on line */ sdcmd_AT(getval("awd")); else sdcmd_S(0); } } static void upsdrv_shutdown_advanced(void) { const void *arg; const char *val; size_t i, len; val = getval("advorder"); len = strlen(val); upsdebugx(1, "%s: currently: %s, advorder: %s", __func__, (ups_status & APC_STAT_OL) ? "on-line" : "on battery", val); /* * try each method in the list with a little bit of handling in certain * cases */ for (i = 0; i < len; i++) { switch (val[i] - '0') { case SDIDX_AT: arg = getval("awd"); break; default: arg = NULL; } if (sdlist[val[i] - '0'](arg) == STAT_INSTCMD_HANDLED) break; /* finish if command succeeded */ } } /* power down the attached load immediately */ void upsdrv_shutdown(void) { char temp[APC_LBUF]; if (!smartmode(1)) upslogx(LOG_WARNING, "%s: %s", __func__, "setting SmartMode failed !"); /* check the line status */ if (apc_write(APC_STATUS) == 1) { if (apc_read(temp, sizeof(temp), SER_D1) == 1) { ups_status = strtol(temp, 0, 16); } else { upslogx(LOG_WARNING, "%s: %s", __func__, "status read failed, assuming LB+OB"); ups_status = APC_STAT_LB | APC_STAT_OB; } } else { upslogx(LOG_WARNING, "%s: %s", __func__, "status write failed, assuming LB+OB"); ups_status = APC_STAT_LB | APC_STAT_OB; } if (testvar("advorder") && toupper((size_t)*getval("advorder")) != 'N') upsdrv_shutdown_advanced(); else upsdrv_shutdown_simple(); } static int update_info(int all) { int i; upsdebugx(1, "%s: starting scan%s", __func__, all ? " (all vars)" : ""); for (i = 0; apc_vartab[i].name != NULL; i++) { if (!all && (apc_vartab[i].flags & APC_POLL) == 0) continue; if (!poll_data(&apc_vartab[i])) { upsdebugx(1, "%s: %s", __func__, "aborting scan"); return 0; } } upsdebugx(1, "%s: %s", __func__, "scan completed"); return 1; } static int setvar_enum(apc_vartab_t *vt, const char *val) { int i; ssize_t ret; char orig[APC_LBUF], temp[APC_LBUF]; const char *ptr; apc_flush(SER_AA); if (apc_write((const unsigned char)vt->cmd) != 1) return STAT_SET_FAILED; ret = apc_read(orig, sizeof(orig), SER_AA); if ((ret < 1) || (!strcmp(orig, "NA"))) return STAT_SET_FAILED; ptr = convert_data(vt, orig); /* suppress redundant changes - easier on the eeprom */ if (!strcmp(ptr, val)) { upslogx(LOG_INFO, "%s: ignoring SET %s='%s' (unchanged value)", __func__, vt->name, val); return STAT_SET_HANDLED; /* FUTURE: no change */ } for (i = 0; i < 32; i++) { if (apc_write(APC_NEXTVAL) != 1) return STAT_SET_FAILED; /* this should return either OK (if rotated) or NO (if not) */ ret = apc_read(temp, sizeof(temp), SER_AA); if ((ret < 1) || (!strcmp(temp, "NA"))) return STAT_SET_FAILED; /* sanity checks */ if (!strcmp(temp, "NO")) return STAT_SET_FAILED; if (strcmp(temp, "OK")) return STAT_SET_FAILED; /* see what it rotated onto */ if (apc_write((const unsigned char)vt->cmd) != 1) return STAT_SET_FAILED; ret = apc_read(temp, sizeof(temp), SER_AA); if ((ret < 1) || (!strcmp(temp, "NA"))) return STAT_SET_FAILED; ptr = convert_data(vt, temp); upsdebugx(1, "%s: rotate - got [%s], want [%s]", __func__, ptr, val); if (!strcmp(ptr, val)) { /* got it */ upslogx(LOG_INFO, "%s: SET %s='%s'", __func__, vt->name, val); /* refresh data from the hardware */ poll_data(vt); return STAT_SET_HANDLED; /* FUTURE: success */ } /* check for wraparound */ if (!strcmp(ptr, orig)) { upslogx(LOG_ERR, "%s: variable %s wrapped", __func__, vt->name); return STAT_SET_FAILED; } } upslogx(LOG_ERR, "%s: gave up after 6 tries for %s", __func__, vt->name); /* refresh data from the hardware */ poll_data(vt); return STAT_SET_FAILED; } static int setvar_string(apc_vartab_t *vt, const char *val) { size_t i; ssize_t ret; char temp[APC_LBUF], *ptr; /* sanitize length */ if (strlen(val) > APC_STRLEN) { upslogx(LOG_ERR, "%s: value (%s) too long", __func__, val); return STAT_SET_FAILED; } apc_flush(SER_AA); if (apc_write((const unsigned char)vt->cmd) != 1) return STAT_SET_FAILED; ret = apc_read(temp, sizeof(temp), SER_AA); if ((ret < 1) || (!strcmp(temp, "NA"))) return STAT_SET_FAILED; /* suppress redundant changes - easier on the eeprom */ if (!strcmp(temp, val)) { upslogx(LOG_INFO, "%s: ignoring SET %s='%s' (unchanged value)", __func__, vt->name, val); return STAT_SET_HANDLED; /* FUTURE: no change */ } /* length sanitized above */ temp[0] = APC_NEXTVAL; strcpy(temp + 1, val); ptr = temp + strlen(temp); for (i = strlen(val); i < APC_STRLEN; i++) *ptr++ = '\015'; /* pad with CRs */ *ptr = 0; if (apc_write_long(temp) != APC_STRLEN + 1) return STAT_SET_FAILED; ret = apc_read(temp, sizeof(temp), SER_AA); if (ret < 1) { upslogx(LOG_ERR, "%s: %s", __func__, "short final read"); return STAT_SET_FAILED; } if (!strcmp(temp, "NO")) { upslogx(LOG_ERR, "%s: %s", __func__, "got NO at final read"); return STAT_SET_FAILED; } /* refresh data from the hardware */ poll_data(vt); upslogx(LOG_INFO, "%s: SET %s='%s'", __func__, vt->name, val); return STAT_SET_HANDLED; /* FUTURE: success */ } static int setvar(const char *varname, const char *val) { apc_vartab_t *vt; vt = vt_lookup_name(varname); if (!vt) return STAT_SET_UNKNOWN; if ((vt->flags & APC_RW) == 0) { upslogx(LOG_WARNING, "%s: [%s] is not writable", __func__, varname); return STAT_SET_UNKNOWN; } if (vt->flags & APC_ENUM) return setvar_enum(vt, val); if (vt->flags & APC_STRING) return setvar_string(vt, val); upslogx(LOG_WARNING, "%s: unknown type for [%s]", __func__, varname); return STAT_SET_UNKNOWN; } /* load on */ static int do_loadon(void) { apc_flush(0); upsdebugx(1, "%s: issuing [%s]", __func__, prtchr(APC_CMD_ON)); if (apc_write_rep(APC_CMD_ON) != 2) return STAT_INSTCMD_FAILED; /* * ups will not reply anything after this command, but might * generate brief OVER condition (which will be corrected on * the next status update) */ upsdebugx(1, "%s: [%s] completed", __func__, prtchr(APC_CMD_ON)); return STAT_INSTCMD_HANDLED; } /* actually send the instcmd's char to the ups */ static int do_cmd(const apc_cmdtab_t *ct) { ssize_t ret; int c; char temp[APC_LBUF]; apc_flush(SER_AA); if (ct->flags & APC_REPEAT) { ret = apc_write_rep((const unsigned char)ct->cmd); c = 2; } else { ret = apc_write((const unsigned char)ct->cmd); c = 1; } if (ret != c) { return STAT_INSTCMD_FAILED; } ret = apc_read(temp, sizeof(temp), SER_AA); if (ret < 1) return STAT_INSTCMD_FAILED; if (strcmp(temp, "OK")) { upslogx(LOG_WARNING, "%s: got [%s] after command [%s]", __func__, temp, ct->name); return STAT_INSTCMD_FAILED; } upslogx(LOG_INFO, "%s: %s completed", __func__, ct->name); return STAT_INSTCMD_HANDLED; } /* some commands must be repeated in a window to execute */ static int instcmd_chktime(apc_cmdtab_t *ct, const char *ext) { double elapsed; time_t now; static time_t last = 0; time(&now); elapsed = difftime(now, last); last = now; /* you have to hit this in a small window or it fails */ if ((elapsed < MINCMDTIME) || (elapsed > MAXCMDTIME)) { upsdebugx(1, "%s: outside window for [%s %s] (%2.0f)", __func__, ct->name, ext ? ext : "\b", elapsed); return 0; } return 1; } static int instcmd(const char *cmd, const char *ext) { int i; apc_cmdtab_t *ct = NULL; for (i = 0; apc_cmdtab[i].name != NULL; i++) { /* cmd must match */ if (strcasecmp(apc_cmdtab[i].name, cmd)) continue; /* if cmd specifies regex, ext must match */ if (apc_cmdtab[i].ext) { if (!rexhlp(apc_cmdtab[i].ext, ext)) continue; /* if cmd doesn't specify regex, ext must be NULL */ } else { if (ext) continue; } ct = &apc_cmdtab[i]; break; } if (!ct) { upslogx(LOG_WARNING, "%s: unknown command [%s %s]", __func__, cmd, ext ? ext : "\b"); return STAT_INSTCMD_INVALID; } if (!(ct->flags & APC_PRESENT)) { upslogx(LOG_WARNING, "%s: command [%s %s] recognized, but" " not supported by your UPS model", __func__, cmd, ext ? ext : "\b"); return STAT_INSTCMD_INVALID; } /* first verify if the command is "nasty" */ if ((ct->flags & APC_NASTY) && !instcmd_chktime(ct, ext)) return STAT_INSTCMD_HANDLED; /* future: again */ /* we're good to go, handle special stuff first, then generic cmd */ if (!strcasecmp(cmd, "calibrate.start")) return do_cal(1); if (!strcasecmp(cmd, "calibrate.stop")) return do_cal(0); if (!strcasecmp(cmd, "load.on")) return do_loadon(); if (!strcasecmp(cmd, "load.off")) return sdcmd_Z(0); if (!strcasecmp(cmd, "shutdown.stayoff")) return sdcmd_K(0); if (!strcasecmp(cmd, "shutdown.return")) { if (!ext || !*ext) return sdcmd_S(0); if (toupper((size_t)*ext) == 'A') return sdcmd_AT(ext + 3); if (toupper((size_t)*ext) == 'C') return sdcmd_CS(0); } /* nothing special here */ return do_cmd(ct); } /* install pointers to functions for msg handlers called from msgparse */ static void setuphandlers(void) { upsh.setvar = setvar; upsh.instcmd = instcmd; } /* ---- functions that interface with main.c ------------------------------- */ void upsdrv_makevartable(void) { addvar(VAR_VALUE, "ttymode", "tty discipline selection"); addvar(VAR_VALUE, "cable", "alternate cable (940-0095B) selection"); addvar(VAR_VALUE, "awd", "hard hibernate's additional wakeup delay"); addvar(VAR_VALUE, "sdtype", "simple shutdown method"); addvar(VAR_VALUE, "advorder", "advanced shutdown control"); addvar(VAR_VALUE, "cshdelay", "CS hack delay"); } void upsdrv_help(void) { printf( "\nFor detailed information, please refer to:\n" " - apcsmart(8)\n" " - https://www.networkupstools.org/docs/man/apcsmart.html\n" ); } void upsdrv_initups(void) { char *val; apc_vartab_t *ptr; /* sanitize awd (additional waekup delay of '@' command) */ if ((val = getval("awd")) && !rexhlp(APC_AWDFMT, val)) { fatalx(EXIT_FAILURE, "invalid value (%s) for option 'awd'", val); } /* sanitize sdtype */ if ((val = getval("sdtype")) && !rexhlp(APC_SDFMT, val)) { fatalx(EXIT_FAILURE, "invalid value (%s) for option 'sdtype'", val); } /* sanitize advorder */ if ((val = getval("advorder")) && !rexhlp(APC_ADVFMT, val)) { fatalx(EXIT_FAILURE, "invalid value (%s) for option 'advorder'", val); } /* sanitize cshdelay */ if ((val = getval("cshdelay")) && !rexhlp(APC_CSHDFMT, val)) { fatalx(EXIT_FAILURE, "invalid value (%s) for option 'cshdelay'", val); } upsfd = extrafd = ser_open(device_path); apc_ser_set(); /* fill length values */ for (ptr = apc_vartab; ptr->name; ptr++) ptr->nlen0 = strlen(ptr->name) + 1; } void upsdrv_cleanup(void) { char temp[APC_LBUF]; if (INVALID_FD(upsfd)) return; apc_flush(0); /* try to bring the UPS out of smart mode */ apc_write(APC_GODUMB); apc_read(temp, sizeof(temp), SER_TO); ser_close(upsfd, device_path); } void upsdrv_initinfo(void) { const char *pmod, *pser; if (!smartmode(5)) { fatalx(EXIT_FAILURE, "unable to detect an APC Smart protocol UPS on port %s\n" "check the cabling, port name or model name and try again", device_path ); } if (!getbaseinfo()) { fatalx(EXIT_FAILURE, "Problems with communicating APC UPS on port %s\n", device_path ); } /* manufacturer ID - hardcoded in this particular module */ dstate_setinfo("ups.mfr", "APC"); if (!(pmod = dstate_getinfo("ups.model"))) pmod = "\"unknown model\""; if (!(pser = dstate_getinfo("ups.serial"))) pser = "unknown serial"; upsdebugx(1, "detected %s [%s] on %s", pmod, pser, device_path); setuphandlers(); /* * seems to be ok so far, it must be set so initial call of * upsdrv_updateinfo() doesn't begin with stale condition */ dstate_dataok(); } void upsdrv_updateinfo(void) { static int last_worked = 0; static time_t last_full = 0; int all; time_t now; /* try to wake up a dead ups once in awhile */ if (dstate_is_stale()) { if (!last_worked) upsdebugx(1, "%s: %s", __func__, "comm lost"); /* reset this so a full update runs when the UPS returns */ last_full = 0; if (++last_worked < 10) return; /* become aggressive after a few tries */ upsdebugx(1, "%s: nudging ups with 'Y', iteration #%d ...", __func__, last_worked); if (!smartmode(1)) return; last_worked = 0; } if (!update_status()) { dstate_datastale(); return; } time(&now); /* refresh all variables hourly */ /* does not catch measure-ups II insertion/removal */ if (difftime(now, last_full) > 3600) { last_full = now; all = 1; } else all = 0; if (update_info(all)) { dstate_dataok(); } else { dstate_datastale(); } } nut-2.8.1/drivers/libshut.c0000644000175000017500000012014314501607135012550 00000000000000/*! * @file libshut.c * @brief HID Library - SHUT communication sub driver * * @author Copyright (C) * 2006 - 2009 Arnaud Quette * * 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 2 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, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * * -------------------------------------------------------------------------- */ /* TODO list * - cleanup, cleanup, cleanup * - manage interrupt and complete libshut_get_interrupt / shut_control_msg routing * - baudrate negotiation * - complete shut_strerror * - validate / complete commands and data table in mge-hid from mge-shut */ #include "config.h" /* must be the first header */ #include #include #include #include #include "nut_stdint.h" /* for uint8_t, uint16_t, uint32_t */ #include "serial.h" #include "libshut.h" #include "common.h" /* for xmalloc, upsdebugx prototypes */ #define SHUT_DRIVER_NAME "SHUT communication driver" #define SHUT_DRIVER_VERSION "0.88" /* communication driver description structure */ upsdrv_info_t comm_upsdrv_info = { SHUT_DRIVER_NAME, SHUT_DRIVER_VERSION, NULL, 0, { NULL } }; #define MAX_TRY 4 #define MAX_STRING_SIZE 128 /*! * HID descriptor, completed with desc{type,len} */ struct my_hid_descriptor { uint8_t bLength; uint8_t bDescriptorType; uint16_t bcdHID; uint8_t bCountryCode; uint8_t bNumDescriptors; uint8_t bReportDescriptorType; uint16_t wDescriptorLength; }; /*!******************************************************** * USB spec information, synchronised with (ripped from) libusb */ /* * Device and/or Interface Class codes */ #define USB_CLASS_PER_INTERFACE 0 /* for DeviceClass */ #define USB_CLASS_AUDIO 1 #define USB_CLASS_COMM 2 #define USB_CLASS_HID 3 #define USB_CLASS_PRINTER 7 #define USB_CLASS_MASS_STORAGE 8 #define USB_CLASS_HUB 9 #define USB_CLASS_DATA 10 #define USB_CLASS_VENDOR_SPEC 0xff /* * Descriptor types */ #define USB_DT_DEVICE 0x01 #define USB_DT_CONFIG 0x02 #define USB_DT_STRING 0x03 #define USB_DT_INTERFACE 0x04 #define USB_DT_ENDPOINT 0x05 #define USB_DT_HID 0x21 #define USB_DT_REPORT 0x22 #define USB_DT_PHYSICAL 0x23 #define USB_DT_HUB 0x29 /* * Descriptor sizes per descriptor type */ #define USB_DT_DEVICE_SIZE 18 #define USB_DT_CONFIG_SIZE 9 #define USB_DT_INTERFACE_SIZE 9 #define USB_DT_ENDPOINT_SIZE 7 #define USB_DT_ENDPOINT_AUDIO_SIZE 9 /* Audio extension */ #define USB_DT_HUB_NONVAR_SIZE 7 /* * Standard requests */ #define USB_REQ_GET_STATUS 0x00 #define USB_REQ_CLEAR_FEATURE 0x01 /* 0x02 is reserved */ #define USB_REQ_SET_FEATURE 0x03 /* 0x04 is reserved */ #define USB_REQ_SET_ADDRESS 0x05 #define USB_REQ_GET_DESCRIPTOR 0x06 #define USB_REQ_SET_DESCRIPTOR 0x07 #define USB_REQ_GET_CONFIGURATION 0x08 #define USB_REQ_SET_CONFIGURATION 0x09 #define USB_REQ_GET_INTERFACE 0x0A #define USB_REQ_SET_INTERFACE 0x0B #define USB_REQ_SYNCH_FRAME 0x0C #define USB_TYPE_STANDARD (0x00 << 5) #define USB_TYPE_CLASS (0x01 << 5) #define USB_TYPE_VENDOR (0x02 << 5) #define USB_TYPE_RESERVED (0x03 << 5) #define USB_RECIP_DEVICE 0x00 #define USB_RECIP_INTERFACE 0x01 #define USB_RECIP_ENDPOINT 0x02 #define USB_RECIP_OTHER 0x03 /* * Various libusb API related stuff */ #define USB_ENDPOINT_IN 0x80 #define USB_ENDPOINT_OUT 0x00 /*! * end of USB spec information *********************************************************/ /*! * HID definitions */ #define HID_REPORT_TYPE_INPUT 0x01 #define HID_REPORT_TYPE_OUTPUT 0x02 #define HID_REPORT_TYPE_FEATURE 0x03 #define REQUEST_TYPE_USB 0x80 #define REQUEST_TYPE_HID 0x81 #define REQUEST_TYPE_GET_REPORT 0xa1 #define REQUEST_TYPE_SET_REPORT 0x21 #define MAX_REPORT_SIZE 0x1800 /*! * SHUT definitions - From Simplified SHUT spec */ #define SHUT_TYPE_REQUEST 0x01 #define SHUT_TYPE_RESPONSE 0x04 #define SHUT_TYPE_NOTIFY 0x05 #define SHUT_OK 0x06 #define SHUT_NOK 0x15 /* sync signals are also used to set the notification level */ #define SHUT_SYNC 0x16 /* complete notifications - not yet managed */ /* but needed for some early Ellipse models */ #define SHUT_SYNC_LIGHT 0x17 /* partial notifications */ #define SHUT_SYNC_OFF 0x18 /* disable notifications - only do polling */ #define SHUT_PKT_LAST 0x80 #define SHUT_TIMEOUT 3000 /*! * SHUT functions for HID marshalling */ /* Expected evaluated types for the API after typedefs: * static int shut_get_descriptor(int upsfd, unsigned char type, * unsigned char index, void *buf, int size); * static int shut_get_string_simple(int upsfd, int index, * char *buf, size_t buflen); * static int libshut_get_report(int upsfd, int ReportId, * unsigned char *raw_buf, int ReportSize ); * static int libshut_set_report(int upsfd, int id, unsigned char *pkt, * int reportlen); * static int libshut_get_interrupt(int upsfd, unsigned char *buf, * int bufsize, int timeout); * static void libshut_close(int upsfd); */ static int shut_get_descriptor( usb_dev_handle upsfd, usb_ctrl_requesttype type, usb_ctrl_descindex index, void *buf, usb_ctrl_charbufsize size); static int shut_get_string_simple( usb_dev_handle upsfd, usb_ctrl_strindex index, char *buf, usb_ctrl_charbufsize buflen); static int libshut_get_report( usb_dev_handle upsfd, usb_ctrl_repindex ReportId, usb_ctrl_charbuf raw_buf, usb_ctrl_charbufsize ReportSize); static int libshut_set_report( usb_dev_handle upsfd, usb_ctrl_repindex id, usb_ctrl_charbuf pkt, usb_ctrl_charbufsize reportlen); static int libshut_get_interrupt( usb_dev_handle upsfd, usb_ctrl_charbuf buf, usb_ctrl_charbufsize bufsize, usb_ctrl_timeout_msec timeout); static void libshut_close(usb_dev_handle upsfd); /* FIXME */ static const char * shut_strerror(void) { return ""; } /*! * From SHUT specifications * sync'ed with libusb */ typedef struct shut_ctrltransfer_s { uint8_t bRequestType; uint8_t bRequest; uint16_t wValue; uint16_t wIndex; uint16_t wLength; uint32_t timeout; /* in milliseconds */ /* pointer to data */ void *data; /* uint8_t padding[8]; for use with shut_set_report?! */ } shut_ctrltransfer_t; typedef union hid_data_t { shut_ctrltransfer_t hid_pkt; uint8_t raw_pkt[8]; /* max report lengh, was 8 */ } hid_data_t; typedef struct shut_packet_s { uint8_t bType; uint8_t bLength; hid_data_t data; uint8_t bChecksum; } shut_packet_t; typedef union shut_data_t { shut_packet_t shut_pkt; uint8_t raw_pkt[11]; } shut_data_t; typedef union hid_desc_data_t { struct my_hid_descriptor hid_desc; uint8_t raw_desc[9]; /* max report lengh, aws 9 */ } hid_desc_data_t; /* Device descriptor */ typedef struct device_descriptor_s { uint8_t bLength; uint8_t bDescriptorType; uint16_t bcdUSB; uint8_t bDeviceClass; uint8_t bDeviceSubClass; uint8_t bDeviceProtocol; uint8_t bMaxPacketSize0; uint16_t idVendor; uint16_t idProduct; uint16_t bcdDevice; uint8_t iManufacturer; uint8_t iProduct; uint8_t iSerialNumber; uint8_t bNumConfigurations; } device_descriptor_t; #if 0 typedef union device_desc_data_t { device_descriptor_t dev_desc; uint8_t raw_desc[18]; } device_desc_data_t; #endif /* Low level SHUT (Serial HID UPS Transfer) routines */ /* Expected evaluated types for the API after typedefs: static void setline(int upsfd, int set); static int shut_synchronise(int upsfd); static int shut_wait_ack(int upsfd); static int shut_interrupt_read(int upsfd, int ep, unsigned char *bytes, int size, int timeout); static int shut_control_msg(int upsfd, int requesttype, int request, int value, int index, unsigned char *bytes, int size, int timeout); */ static void setline( usb_dev_handle upsfd, int set); static int shut_synchronise(usb_dev_handle upsfd); static int shut_wait_ack(usb_dev_handle upsfd); static int shut_interrupt_read( usb_dev_handle upsfd, usb_ctrl_endpoint ep, usb_ctrl_charbuf bytes, usb_ctrl_charbufsize size, usb_ctrl_timeout_msec timeout); static int shut_control_msg( usb_dev_handle upsfd, usb_ctrl_requesttype requesttype, usb_ctrl_request request, usb_ctrl_msgvalue value, usb_ctrl_repindex index, usb_ctrl_charbuf bytes, usb_ctrl_charbufsize size, usb_ctrl_timeout_msec timeout); /* Data portability */ /* realign packet data according to Endianess */ #define BYTESWAP(in) ((((uint16_t)in & 0x00FF) << 8) + (((uint16_t)in & 0xFF00) >> 8)) static void align_request(struct shut_ctrltransfer_s *ctrl) { #if (defined (WORDS_BIGENDIAN)) && (WORDS_BIGENDIAN) /* Sparc/Mips/... are big endian, USB/SHUT little endian */ (*ctrl).wValue = BYTESWAP((*ctrl).wValue); (*ctrl).wIndex = BYTESWAP((*ctrl).wIndex); (*ctrl).wLength = BYTESWAP((*ctrl).wLength); #else NUT_UNUSED_VARIABLE(ctrl); #endif } #if (!defined HAVE_PRAGMA_GCC_DIAGNOSTIC_PUSH_POP_INSIDEFUNC) && (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_TYPE_LIMITS_BESIDEFUNC) # pragma GCC diagnostic ignored "-Wtype-limits" #endif #if (!defined HAVE_PRAGMA_GCC_DIAGNOSTIC_PUSH_POP_INSIDEFUNC) && (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_TAUTOLOGICAL_CONSTANT_OUT_OF_RANGE_COMPARE_BESIDEFUNC) # pragma GCC diagnostic ignored "-Wtautological-constant-out-of-range-compare" #endif /* On success, fill in the curDevice structure and return the report * descriptor length. On failure, return -1. * Note: When callback is not NULL, the report descriptor will be * passed to this function together with the upsfd and SHUTDevice_t * information. This callback should return a value > 0 if the device * is accepted, or < 1 if not. */ /* Expected evaluated types for the API after typedefs: * static int libshut_open(int *arg_upsfd, SHUTDevice_t *curDevice, char *arg_device_path, * int (*callback)(int arg_upsfd, SHUTDevice_t *hd, * unsigned char *rdbuf, int rdlen)) */ static int libshut_open( usb_dev_handle *arg_upsfd, SHUTDevice_t *curDevice, char *arg_device_path, int (*callback)(usb_dev_handle arg_upsfd, SHUTDevice_t *hd, usb_ctrl_charbuf rdbuf, usb_ctrl_charbufsize rdlen)) { int ret, res; /* Below we cast this buffer as sometimes containing entried of type * "struct device_descriptor_s" or "struct my_hid_descriptor". * Currently both of these are sized "2", and I don't see a way * to require a "max()" of such sizes to align for generally. */ usb_ctrl_char buf[20] __attribute__((aligned(4))); char string[MAX_STRING_SIZE]; struct my_hid_descriptor *desc; struct device_descriptor_s *dev_descriptor; /* report descriptor */ usb_ctrl_char rdbuf[MAX_REPORT_SIZE]; usb_ctrl_charbufsize rdlen; /* All devices use HID descriptor at index 0. However, some newer * Eaton units have a light HID descriptor at index 0, and the full * version is at index 1 (in which case, bcdDevice == 0x0202) */ usb_ctrl_descindex hid_desc_index = 0; if (!arg_device_path) { fatalx(EXIT_FAILURE, "%s: arg_device_path=null", __func__); } upsdebugx(2, "libshut_open: using port %s", arg_device_path); /* If device is still open, close it */ if (VALID_FD_SER(*arg_upsfd)) { ser_close(*arg_upsfd, arg_device_path); } /* initialize serial port */ /* FIXME: add variable baudrate detection */ *arg_upsfd = ser_open(arg_device_path); ser_set_speed(*arg_upsfd, arg_device_path, B2400); setline(*arg_upsfd, 1); /* initialise communication */ if (!shut_synchronise(*arg_upsfd)) { upsdebugx(2, "No communication with UPS"); return -1; } upsdebugx(2, "Communication with UPS established"); /* we can skip the rest due to serial bus specifics! */ if (!callback) { return 1; } /* Get DEVICE descriptor */ #if (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_PUSH_POP) && (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_CAST_ALIGN) # pragma GCC diagnostic push # pragma GCC diagnostic ignored "-Wcast-align" #endif #ifdef __clang__ # pragma clang diagnostic push # pragma clang diagnostic ignored "-Wcast-align" #endif dev_descriptor = (struct device_descriptor_s *)buf; #ifdef __clang__ # pragma clang diagnostic pop #endif #if (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_PUSH_POP) && (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_CAST_ALIGN) # pragma GCC diagnostic pop #endif res = shut_get_descriptor(*arg_upsfd, USB_DT_DEVICE, 0, buf, USB_DT_DEVICE_SIZE); /* res = shut_control_msg(devp, USB_ENDPOINT_IN+1, USB_REQ_GET_DESCRIPTOR, (USB_DT_DEVICE << 8) + 0, 0, buf, 0x9, SHUT_TIMEOUT); */ if (res < 0) { upsdebugx(2, "Unable to get DEVICE descriptor (%s)", shut_strerror()); return -1; } if (res < 9) { upsdebugx(2, "DEVICE descriptor too short (expected %d, got %d)", USB_DT_DEVICE_SIZE, res); return -1; } /* collect the identifying information of this device. Note that this is safe, because there's no need to claim an interface for this (and therefore we do not yet need to detach any kernel drivers). */ free(curDevice->Vendor); free(curDevice->Product); free(curDevice->Serial); free(curDevice->Bus); free(curDevice->Device); #if (defined WITH_USB_BUSPORT) && (WITH_USB_BUSPORT) free(curDevice->BusPort); #endif memset(curDevice, '\0', sizeof(*curDevice)); curDevice->VendorID = dev_descriptor->idVendor; curDevice->ProductID = dev_descriptor->idProduct; curDevice->Bus = strdup("serial"); curDevice->Device = strdup(arg_device_path); #if (defined WITH_USB_BUSPORT) && (WITH_USB_BUSPORT) curDevice->BusPort = (char *)malloc(4); if (curDevice->BusPort == NULL) { fatal_with_errno(EXIT_FAILURE, "Out of memory"); } upsdebugx(2, "%s: NOTE: BusPort is always zero with libshut", __func__); sprintf(curDevice->BusPort, "%03d", 0); #endif curDevice->bcdDevice = dev_descriptor->bcdDevice; curDevice->Vendor = NULL; if (dev_descriptor->iManufacturer) { ret = shut_get_string_simple(*arg_upsfd, dev_descriptor->iManufacturer, string, MAX_STRING_SIZE); if (ret > 0) { curDevice->Vendor = strdup(string); } } if (curDevice->Vendor == NULL) { curDevice->Vendor = strdup("Eaton"); } /* ensure iProduct retrieval */ if (dev_descriptor->iProduct) { ret = shut_get_string_simple(*arg_upsfd, dev_descriptor->iProduct, string, MAX_STRING_SIZE); } else { ret = 0; } if (ret > 0) { curDevice->Product = strdup(string); } else { curDevice->Product = strdup("unknown"); } if (dev_descriptor->iSerialNumber) { ret = shut_get_string_simple(*arg_upsfd, dev_descriptor->iSerialNumber, string, 0x25); } else { ret = 0; } if (ret > 0) { curDevice->Serial = strdup(string); } else { curDevice->Serial = strdup("unknown"); } upsdebugx(2, "- VendorID: %04x", curDevice->VendorID); upsdebugx(2, "- ProductID: %04x", curDevice->ProductID); upsdebugx(2, "- Manufacturer: %s", curDevice->Vendor); upsdebugx(2, "- Product: %s", curDevice->Product); upsdebugx(2, "- Serial Number: %s", curDevice->Serial); upsdebugx(2, "- Bus: %s", curDevice->Bus); #if (defined WITH_USB_BUSPORT) && (WITH_USB_BUSPORT) upsdebugx(2, "- Bus Port: %s", curDevice->BusPort ? curDevice->BusPort : "unknown"); #endif upsdebugx(2, "- Device: %s", curDevice->Device ? curDevice->Device : "unknown"); upsdebugx(2, "- Device release number: %04x", curDevice->bcdDevice); upsdebugx(2, "Device matches"); if ((curDevice->VendorID == 0x463) && (curDevice->bcdDevice == 0x0202)) { upsdebugx(1, "Eaton device v2.02. Using full report descriptor"); hid_desc_index = 1; } /* Get HID descriptor */ #if (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_PUSH_POP) && (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_CAST_ALIGN) # pragma GCC diagnostic push # pragma GCC diagnostic ignored "-Wcast-align" #endif #ifdef __clang__ # pragma clang diagnostic push # pragma clang diagnostic ignored "-Wcast-align" #endif desc = (struct my_hid_descriptor *)buf; #ifdef __clang__ # pragma clang diagnostic pop #endif #if (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_PUSH_POP) && (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_CAST_ALIGN) # pragma GCC diagnostic pop #endif res = shut_get_descriptor(*arg_upsfd, USB_DT_HID, hid_desc_index, buf, 0x9); /* res = shut_control_msg(devp, USB_ENDPOINT_IN+1, USB_REQ_GET_DESCRIPTOR, (USB_DT_HID << 8) + 0, 0, buf, 0x9, SHUT_TIMEOUT); */ if (res < 0) { upsdebugx(2, "Unable to get HID descriptor (%s)", shut_strerror()); return -1; } if (res < 9) { upsdebugx(2, "HID descriptor too short (expected %d, got %d)", 8, res); return -1; } /* USB_LE16_TO_CPU(desc->wDescriptorLength); */ desc->wDescriptorLength = (0x00FF & (uint8_t)buf[7]) | ((0x00FF & (uint8_t)buf[8]) << 8); upsdebugx(2, "HID descriptor retrieved (Reportlen = %u)", desc->wDescriptorLength); /* if (!dev->config) { upsdebugx(2, " Couldn't retrieve descriptors"); return -1; } */ rdlen = desc->wDescriptorLength; #if (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_PUSH_POP) && ( (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_TYPE_LIMITS) || (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_TAUTOLOGICAL_CONSTANT_OUT_OF_RANGE_COMPARE) ) # pragma GCC diagnostic push #endif #ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_TYPE_LIMITS # pragma GCC diagnostic ignored "-Wtype-limits" #endif #ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_TAUTOLOGICAL_CONSTANT_OUT_OF_RANGE_COMPARE # pragma GCC diagnostic ignored "-Wtautological-constant-out-of-range-compare" #endif /* Older CLANG (e.g. clang-3.4) seems to not support the GCC pragmas above */ #ifdef __clang__ #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wtautological-compare" #pragma clang diagnostic ignored "-Wtautological-constant-out-of-range-compare" #endif if (rdlen > sizeof(rdbuf) || rdlen > INT_MAX) { #ifdef __clang__ #pragma clang diagnostic pop #endif #if (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_PUSH_POP) && ( (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_TYPE_LIMITS) || (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_TAUTOLOGICAL_CONSTANT_OUT_OF_RANGE_COMPARE) ) # pragma GCC diagnostic pop #endif upsdebugx(2, "HID descriptor too long %" PRI_NUT_USB_CTRL_CHARBUFSIZE " (max %" PRIuSIZE ")", rdlen, sizeof(rdbuf)); return -1; } /* Get REPORT descriptor */ res = shut_get_descriptor(*arg_upsfd, USB_DT_REPORT, hid_desc_index, rdbuf, rdlen); /* res = shut_control_msg(devp, USB_ENDPOINT_IN+1, USB_REQ_GET_DESCRIPTOR, (USB_DT_REPORT << 8) + 0, 0, ReportDesc, desc->wDescriptorLength, SHUT_TIMEOUT); */ #if (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_PUSH_POP) && ( (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_TYPE_LIMITS) || (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_TAUTOLOGICAL_CONSTANT_OUT_OF_RANGE_COMPARE) ) # pragma GCC diagnostic push #endif #ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_TYPE_LIMITS # pragma GCC diagnostic ignored "-Wtype-limits" #endif #ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_TAUTOLOGICAL_CONSTANT_OUT_OF_RANGE_COMPARE # pragma GCC diagnostic ignored "-Wtautological-constant-out-of-range-compare" #endif /* Older CLANG (e.g. clang-3.4) seems to not support the GCC pragmas above */ #ifdef __clang__ #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wtautological-compare" #pragma clang diagnostic ignored "-Wtautological-constant-out-of-range-compare" #endif if (res >= 0 && (uintmax_t)res < (uintmax_t)SIZE_MAX && (size_t)res == rdlen) #ifdef __clang__ #pragma clang diagnostic pop #endif #if (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_PUSH_POP) && ( (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_TYPE_LIMITS) || (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_TAUTOLOGICAL_CONSTANT_OUT_OF_RANGE_COMPARE) ) # pragma GCC diagnostic pop #endif { res = callback(*arg_upsfd, curDevice, rdbuf, rdlen); if (res < 1) { upsdebugx(2, "Caller doesn't like this device"); return -1; } upsdebugx(2, "Report descriptor retrieved (Reportlen = %" PRI_NUT_USB_CTRL_CHARBUFSIZE ")", rdlen); upsdebugx(2, "Found HID device"); fflush(stdout); return (int)rdlen; } if (res < 0) { upsdebugx(2, "Unable to get Report descriptor (%d)", res); } else { upsdebugx(2, "Report descriptor too short (expected %" PRI_NUT_USB_CTRL_CHARBUFSIZE ", got %d)", rdlen, res); } upsdebugx(2, "libshut: No appropriate HID device found"); fflush(stdout); return -1; } #if (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_PUSH_POP_BESIDEFUNC) && (!defined HAVE_PRAGMA_GCC_DIAGNOSTIC_PUSH_POP_INSIDEFUNC) && ( (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_TYPE_LIMITS_BESIDEFUNC) || (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_TAUTOLOGICAL_CONSTANT_OUT_OF_RANGE_COMPARE_BESIDEFUNC) ) # pragma GCC diagnostic pop #endif /* Expected evaluated types for the API after typedefs: * static void libshut_close(int arg_upsfd) */ static void libshut_close(usb_dev_handle arg_upsfd) { if (INVALID_FD_SER(arg_upsfd)) { return; } ser_close(arg_upsfd, NULL); } /* return the report of ID=type in report * return -1 on failure, report length on success */ /* Expected evaluated types for the API after typedefs: * static int libshut_get_report(int arg_upsfd, int ReportId, * unsigned char *raw_buf, int ReportSize) */ static int libshut_get_report( usb_dev_handle arg_upsfd, usb_ctrl_repindex ReportId, usb_ctrl_charbuf raw_buf, usb_ctrl_charbufsize ReportSize) { if (INVALID_FD_SER(arg_upsfd)) { return 0; } upsdebugx(4, "Entering libshut_get_report"); return shut_control_msg(arg_upsfd, REQUEST_TYPE_GET_REPORT, /* == USB_ENDPOINT_IN + USB_TYPE_CLASS + USB_RECIP_INTERFACE, */ 0x01, ReportId+(0x03<<8), /* HID_REPORT_TYPE_FEATURE */ 0, raw_buf, ReportSize, SHUT_TIMEOUT); } /* return ReportSize upon success ; -1 otherwise */ /* Expected evaluated types for the API after typedefs: * static int libshut_set_report(int arg_upsfd, int ReportId, * unsigned char *raw_buf, int ReportSize) */ static int libshut_set_report( usb_dev_handle arg_upsfd, usb_ctrl_repindex ReportId, usb_ctrl_charbuf raw_buf, usb_ctrl_charbufsize ReportSize) { int ret; if (INVALID_FD_SER(arg_upsfd)) { return 0; } upsdebugx(1, "Entering libshut_set_report (report %x, " "len %" PRI_NUT_USB_CTRL_CHARBUFSIZE ")", ReportId, ReportSize); if ((uintmax_t)ReportSize > (uintmax_t)INT_MAX) { upsdebugx(1, "%s: ReportSize exceeds INT_MAX", __func__); return -1; } upsdebug_hex (4, "==> Report after set", raw_buf, ReportSize); ret = shut_control_msg(arg_upsfd, REQUEST_TYPE_SET_REPORT, /* == USB_ENDPOINT_OUT + USB_TYPE_CLASS + USB_RECIP_INTERFACE, */ 0x09, ReportId+(0x03<<8), /* HID_REPORT_TYPE_FEATURE */ 0, raw_buf, ReportSize, SHUT_TIMEOUT); return ((ret == 0) ? (int)ReportSize : ret); } /* Expected evaluated types for the API after typedefs: * static int libshut_get_string(int arg_upsfd, * int StringIdx, char *buf, size_t buflen) */ static int libshut_get_string( usb_dev_handle arg_upsfd, usb_ctrl_strindex StringIdx, char *buf, usb_ctrl_charbufsize buflen) { int ret; if (INVALID_FD_SER(arg_upsfd)) { return -1; } ret = shut_get_string_simple(arg_upsfd, StringIdx, buf, buflen); if (ret > 0) upsdebugx(2, "-> String: %s (len = %i/%i)", buf, ret, (int)buflen); else upsdebugx(2, "- Unable to fetch buf"); return ret; } /* Expected evaluated types for the API after typedefs: * static int libshut_get_interrupt(int arg_upsfd, unsigned char *buf, * int bufsize, int timeout) */ static int libshut_get_interrupt( usb_dev_handle arg_upsfd, usb_ctrl_charbuf buf, usb_ctrl_charbufsize bufsize, usb_ctrl_timeout_msec timeout) { int ret; if (INVALID_FD_SER(arg_upsfd)) { return -1; } /* FIXME: hardcoded interrupt EP => need to get EP descr for IF descr */ ret = shut_interrupt_read(arg_upsfd, 0x81, buf, bufsize, timeout); if (ret > 0) upsdebugx(6, " ok"); else upsdebugx(6, " none (%i)", ret); return ret; } shut_communication_subdriver_t shut_subdriver = { SHUT_DRIVER_NAME, SHUT_DRIVER_VERSION, libshut_open, libshut_close, libshut_get_report, libshut_set_report, libshut_get_string, libshut_get_interrupt }; /***********************************************************************/ /********** Low level SHUT (Serial HID UPS Transfer) routines **********/ /***********************************************************************/ /* * set RTS to on and DTR to off * * set : 1 to set comm * set : 0 to stop commupsh. */ /* Expected evaluated types for the API after typedefs: * void setline(int arg_upsfd, int set) */ void setline(usb_dev_handle arg_upsfd, int set) { if (INVALID_FD_SER(arg_upsfd)) { return; } upsdebugx(3, "entering setline(%i)", set); if (set == 1) { ser_set_dtr(arg_upsfd, 0); ser_set_rts(arg_upsfd, 1); } else { ser_set_dtr(arg_upsfd, 1); ser_set_rts(arg_upsfd, 0); } } /***************************************************************************** * shut_synchronise () * * initiate communication with the UPS * * return TRUE on success, FALSE on failure * *****************************************************************************/ /* Expected evaluated types for the API after typedefs: * int shut_synchronise(int arg_upsfd) */ int shut_synchronise(usb_dev_handle arg_upsfd) { int retCode = 0; unsigned char c = SHUT_SYNC_OFF, reply; int try; upsdebugx (2, "entering shut_synchronise()"); reply = '\0'; /* FIXME: re enable notification support? switch (notification) { case OFF_NOTIFICATION: c = SHUT_SYNC_OFF; break; case LIGHT_NOTIFICATION: c = SHUT_SYNC_LIGHT; break; default: case COMPLETE_NOTIFICATION: c = SHUT_SYNC; break; } */ /* Sync with the UPS according to notification */ for (try = 0; try < MAX_TRY; try++) { upsdebugx (3, "Syncing communication (try %i)", try); if ((ser_send_char(arg_upsfd, c)) == -1) { upsdebugx (3, "Communication error while writing to port"); continue; } ser_get_char(arg_upsfd, &reply, 1, 0); if (reply == c) { upsdebugx (3, "Syncing and notification setting done"); return 1; } } return retCode; } /*! * Compute a SHUT checksum for the packet "buf" */ /* Expected evaluated types for the API after typedefs: * static unsigned char shut_checksum(const unsigned char *buf, int bufsize) */ static unsigned char shut_checksum( const usb_ctrl_charbuf buf, usb_ctrl_charbufsize bufsize) { usb_ctrl_charbufsize i; unsigned char chk=0; for(i=0; i0 && Retry<3) { /* if(serial_read (SHUT_TIMEOUT, &Start[0]) > 0) */ if(ser_get_char(arg_upsfd, &Start[0], SHUT_TIMEOUT/1000, 0) > 0) { /* sdata.shut_pkt.bType = Start[0]; */ if(Start[0]==SHUT_SYNC) { upsdebugx (4, "received SYNC token"); memcpy(Buf, Start, 1); return 1; } else if(Start[0]==SHUT_SYNC_OFF) { upsdebugx (4, "received SYNC_OFF token"); memcpy(Buf, Start, 1); return 1; } else { /* if((serial_read (SHUT_TIMEOUT, &Start[1]) > 0) && */ if( (ser_get_char(arg_upsfd, &Start[1], SHUT_TIMEOUT/1000, 0) > 0) && ((Start[1]>>4)==(Start[1]&0x0F))) { upsdebug_hex(4, "Receive", Start, 2); Size=Start[1]&0x0F; if( Size > 8 ) { upsdebugx (4, "shut_packet_recv: invalid frame size = %d", Size); ser_send_char(arg_upsfd, SHUT_NOK); Retry++; break; } /* sdata.shut_pkt.bLength = Size; */ for(recv=0;recv OK", Chk[0]); memcpy(Buf, Frame, Size); datalen-=Size; Buf+=Size; Pos+=Size; Retry=0; ser_send_char(arg_upsfd, SHUT_OK); /* shut_token_send(SHUT_OK); */ /* Check if there are more data to receive */ if((Start[0] & 0xf0) == SHUT_PKT_LAST) { /* Check if it's a notification */ if ((Start[0] & 0x0f) == SHUT_TYPE_NOTIFY) { /* TODO: process notification (dropped for now) */ upsdebugx (4, "=> notification"); datalen+=Pos; Pos=0; } else { return Pos; } } else upsdebugx (4, "need more data (%" PRI_NUT_USB_CTRL_CHARBUFSIZE ")!", datalen); } else { upsdebugx (4, "shut_checksum: %02x => NOK", Chk[0]); ser_send_char(arg_upsfd, SHUT_NOK); /* shut_token_send(SHUT_NOK); */ Retry++; } } else { return 0; } } } else { Retry++; } } /* while */ return 0; } /**********************************************************************/ /* Expected evaluated types for the API after typedefs: * static int shut_interrupt_read(int arg_upsfd, int ep, * unsigned char *bytes, int size, * int timeout) */ static int shut_interrupt_read( usb_dev_handle arg_upsfd, usb_ctrl_endpoint ep, usb_ctrl_charbuf bytes, usb_ctrl_charbufsize size, usb_ctrl_timeout_msec timeout) { /* usleep(timeout * 1000); */ /* FIXME: to be written */ NUT_UNUSED_VARIABLE(arg_upsfd); NUT_UNUSED_VARIABLE(ep); NUT_UNUSED_VARIABLE(bytes); NUT_UNUSED_VARIABLE(size); NUT_UNUSED_VARIABLE(timeout); return 0; } /**********************************************************************/ /* Expected evaluated types for the API after typedefs: * static int shut_get_string_simple(int arg_upsfd, int index, * char *buf, size_t buflen) */ static int shut_get_string_simple( usb_dev_handle arg_upsfd, usb_ctrl_strindex index, char *buf, usb_ctrl_charbufsize buflen) { usb_ctrl_char tbuf[255]; /* Some devices choke on size > 255 */ int ret, si, di; ret = shut_control_msg(arg_upsfd, USB_ENDPOINT_IN, USB_REQ_GET_DESCRIPTOR, (USB_DT_STRING << 8) + index, 0x0, tbuf, buflen, SHUT_TIMEOUT); if (ret < 0) return ret; if (tbuf[1] != USB_DT_STRING) return -EIO; if (tbuf[0] > ret) return -EFBIG; /* skip the UTF8 zero'ed high bytes */ for (di = 0, si = 2; si < tbuf[0]; si += 2) { if (di >= (int)(buflen - 1)) break; if (tbuf[si + 1]) /* high byte */ buf[di++] = '?'; else buf[di++] = (char)tbuf[si]; } buf[di] = 0; return di; } /* * Human Interface Device (HID) functions *********************************************************************/ /********************************************************************** * shut_get_descriptor(int desctype, usb_ctrl_charbuf pkt) * * get descriptor specified by DescType and return it in Buf * * desctype - from shutdataType * pkt - where to store the report received * * return 0 on success, -1 on failure, -2 on NACK * *********************************************************************/ /* Expected evaluated types for the API after typedefs: * static int shut_get_descriptor(int arg_upsfd, unsigned char type, * unsigned char index, void *buf, int size) */ static int shut_get_descriptor( usb_dev_handle arg_upsfd, usb_ctrl_requesttype type, usb_ctrl_descindex index, void *buf, usb_ctrl_charbufsize size) { memset(buf, 0, size); upsdebugx (2, "entering shut_get_descriptor(n %02x, %" PRI_NUT_USB_CTRL_CHARBUFSIZE ")", type, size); return shut_control_msg(arg_upsfd, USB_ENDPOINT_IN+(type>=USB_DT_HID?1:0), USB_REQ_GET_DESCRIPTOR, (type << 8) + index, 0, buf, size, SHUT_TIMEOUT); } /* Take care of a SHUT transfer (sending and receiving data) */ /* Expected evaluated types for the API after typedefs: * static int shut_control_msg(int arg_upsfd, int requesttype, int request, * int value, int index, unsigned char *bytes, int size, * int timeout) */ static int shut_control_msg( usb_dev_handle arg_upsfd, usb_ctrl_requesttype requesttype, usb_ctrl_request request, usb_ctrl_msgvalue value, usb_ctrl_repindex index, usb_ctrl_charbuf bytes, usb_ctrl_charbufsize size, usb_ctrl_timeout_msec timeout) { unsigned char shut_pkt[11]; short Retry=1, set_pass = -1; usb_ctrl_charbufsize data_size, remaining_size = size; int i; struct shut_ctrltransfer_s ctrl; int ret = 0; upsdebugx (3, "entering shut_control_msg"); /* deal for set requests */ if (requesttype == REQUEST_TYPE_SET_REPORT) { set_pass = 1; /* add 8 for the first frame that declares a coming set */ remaining_size+= 8; } #if (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_PUSH_POP) && ( (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_TYPE_LIMITS) || (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_TAUTOLOGICAL_CONSTANT_OUT_OF_RANGE_COMPARE) || (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_TAUTOLOGICAL_UNSIGNED_ZERO_COMPARE) ) # pragma GCC diagnostic push #endif #ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_TYPE_LIMITS # pragma GCC diagnostic ignored "-Wtype-limits" #endif #ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_TAUTOLOGICAL_CONSTANT_OUT_OF_RANGE_COMPARE # pragma GCC diagnostic ignored "-Wtautological-constant-out-of-range-compare" #endif #ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_TAUTOLOGICAL_UNSIGNED_ZERO_COMPARE # pragma GCC diagnostic ignored "-Wtautological-unsigned-zero-compare" #endif /* Note: checking against limits of protocol struct fields, * not against USB_CTRL_REQUEST_MAX et al, which are mostly int */ if (requesttype < 0 || (uintmax_t)requesttype > UINT8_MAX || request < 0 || (uintmax_t)request > UINT8_MAX || value < 0 || (uintmax_t)value > UINT16_MAX || index < 0 || (uintmax_t)index > UINT16_MAX || (uintmax_t)size > UINT16_MAX || (uintmax_t)timeout > UINT32_MAX ) { #if (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_PUSH_POP) && ( (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_TYPE_LIMITS) || (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_TAUTOLOGICAL_CONSTANT_OUT_OF_RANGE_COMPARE) || (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_TAUTOLOGICAL_UNSIGNED_ZERO_COMPARE) ) # pragma GCC diagnostic pop #endif upsdebugx (1, "%s: input values out of range", __func__); return -1; } /* build the control request */ ctrl.bRequestType = (uint8_t)requesttype; ctrl.bRequest = (uint8_t)request; ctrl.wValue = (uint16_t)value; ctrl.wIndex = (uint16_t)index; ctrl.wLength = (uint16_t)size; ctrl.data = bytes; ctrl.timeout = (uint32_t)timeout; /* in milliseconds */ align_request(&ctrl); /* Send all data */ while(remaining_size > 0 && Retry > 0) { if (requesttype == REQUEST_TYPE_SET_REPORT) { if (set_pass == 1) { data_size = 8; set_pass++; /* prepare for the next step */ } else { data_size = size; upsdebug_hex(4, "data", bytes, data_size); } } else { /* Always 8 bytes payload for GET_REPORT with SHUT */ data_size = 8; } /* Forge the SHUT Frame */ shut_pkt[0] = SHUT_TYPE_REQUEST + ( ((requesttype == REQUEST_TYPE_SET_REPORT) && (remaining_size>8))? 0 : SHUT_PKT_LAST); #if (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_PUSH_POP) && ( (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_TYPE_LIMITS) || (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_TAUTOLOGICAL_CONSTANT_OUT_OF_RANGE_COMPARE) || (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_TAUTOLOGICAL_UNSIGNED_ZERO_COMPARE) ) # pragma GCC diagnostic push #endif #ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_TYPE_LIMITS # pragma GCC diagnostic ignored "-Wtype-limits" #endif #ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_TAUTOLOGICAL_CONSTANT_OUT_OF_RANGE_COMPARE # pragma GCC diagnostic ignored "-Wtautological-constant-out-of-range-compare" #endif #ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_TAUTOLOGICAL_UNSIGNED_ZERO_COMPARE # pragma GCC diagnostic ignored "-Wtautological-unsigned-zero-compare" #endif /* Older CLANG (e.g. clang-3.4) seems to not support the GCC pragmas above */ #ifdef __clang__ #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wtautological-compare" #pragma clang diagnostic ignored "-Wtautological-constant-out-of-range-compare" #endif if (data_size < 0 || data_size > UCHAR_MAX) { #ifdef __clang__ #pragma clang diagnostic pop #endif #if (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_PUSH_POP) && ( (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_TYPE_LIMITS) || (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_TAUTOLOGICAL_CONSTANT_OUT_OF_RANGE_COMPARE) || (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_TAUTOLOGICAL_UNSIGNED_ZERO_COMPARE) ) # pragma GCC diagnostic pop #endif upsdebugx(1, "%s: ERROR: data_size %" PRI_NUT_USB_CTRL_CHARBUFSIZE " is out of range for SHUT packet", __func__, data_size); return -1; } if (data_size > 0x0F) { upsdebugx(1, "%s: WARNING: data_size %" PRI_NUT_USB_CTRL_CHARBUFSIZE " may be too large for SHUT packet?", __func__, data_size); /* Do not abort here - maybe there is intentional maths * in the protocol with overlapping/shifted-away numbers? */ } shut_pkt[1] = (unsigned char)(data_size<<4) + (unsigned char)data_size; if ( (requesttype == REQUEST_TYPE_SET_REPORT) && (remaining_size < 8) ) memcpy(&shut_pkt[2], bytes, data_size); /* we need to send ctrl.data */ else memcpy(&shut_pkt[2], &ctrl, 8); shut_pkt[(data_size+3) - 1] = shut_checksum(&shut_pkt[2], (unsigned char)data_size); /* Packets need only to be sent once * NACK handling should take care of the rest */ if (Retry == 1) { ser_send_buf(arg_upsfd, shut_pkt, data_size+3); upsdebug_hex(3, "shut_control_msg", shut_pkt, data_size+3); /* serial_send (shut_pkt, data_size+3); */ } i = shut_wait_ack (arg_upsfd); switch (i) { case 0: if (requesttype == REQUEST_TYPE_SET_REPORT) remaining_size-=data_size; else remaining_size = 0; Retry=1; break; case -1: if (Retry >= MAX_TRY) { upsdebugx(2, "Max tries reached while waiting for ACK, still getting errors"); /* try to resync, and give one more try */ Retry--; shut_synchronise(arg_upsfd); return i; } else { upsdebugx(4, "Retry = %i", Retry); /* Send a NACK to get a resend from the UPS */ ser_send_char(arg_upsfd, SHUT_NOK); Retry++; } break; case -3: /* FIXME: notification caught => to be processed */ /* Send a NACK for the moment, to get a resend from the UPS */ ser_send_char(arg_upsfd, SHUT_NOK); Retry++; goto fallthrough_default; default: fallthrough_default: break; } } if (remaining_size != 0) return -1; /* now receive data, except for SET_REPORT */ if (requesttype != REQUEST_TYPE_SET_REPORT) ret = shut_packet_recv (arg_upsfd, bytes, size); return ret; } /********************************************************************** * shut_wait_ack() * * wait for an ACK packet * * returns 0 on success, -1 on error, -2 on NACK, -3 on NOTIFICATION * *********************************************************************/ /* Expected evaluated types for the API after typedefs: * int shut_wait_ack(int arg_upsfd) */ int shut_wait_ack(usb_dev_handle arg_upsfd) { int retCode = -1; unsigned char c = '\0'; ser_get_char(arg_upsfd, &c, SHUT_TIMEOUT/1000, 0); if (c == SHUT_OK) { upsdebugx (2, "shut_wait_ack(): ACK received"); retCode = 0; } else if (c == SHUT_NOK) { upsdebugx (2, "shut_wait_ack(): NACK received"); retCode = -2; } else if ((c & 0x0f) == SHUT_TYPE_NOTIFY) { upsdebugx (2, "shut_wait_ack(): NOTIFY received"); retCode = -3; } else if (c == '\0') upsdebugx (2, "shut_wait_ack(): Nothing received"); return retCode; } nut-2.8.1/drivers/tripplite.c0000644000175000017500000004103514502253356013117 00000000000000/* tripplite.c - model specific routines for Tripp Lite SmartUPS models (tested with: "SMART 700" [on back -- "SmartPro UPS" on front], "SMART700SER") tripplite.c was derived from Russell Kroll's bestups.c by Rik Faith. Copyright (C) 1999 Russell Kroll Copyright (C) 2001 Rickard E. (Rik) Faith Copyright (C) 2004,2008 Nicholas J. Kain 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 2 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, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ /* REFERENCE 1 A few magic numbers were derived from the GPL'd file opensrc_server/upscmd.cpp, formerly (but not longer) available from Tripp Lite at http://www.tripplite.com/linux/. */ /* REFERENCE 2 Other hints on commands were found on these web pages: http://www.kursknet.ru/~boa/ups/stinfo_command.html http://www.kursknet.ru/~boa/ups/rtinfo_command.html These pages confirm the information in the Tripp Lite source code referenced above and add more details. The first page tells how to derive the VA rating from w_value and l_value. It's a confusing explanation because shifts are used to mask out bits. Here is an example starting with the formula on the web page and proceeding to a formula that uses C syntax. I have a SMART 700 (700VA, 450W) w_value = 0x84 [available from upsc as REG1] l_value=- 0x60 [available from upsc as REG2] Unit Type: bit 6 of w_value is 0 so I have a Smart (vs. a Unison) VA Rating: ((([V:W Result]<<2)*8)+([V:L Result]>>3))*5 = (((w_value<<2)*8)+([l_value]>>3)) * 5 = ((w_value & 0x3f)*32 + (l_value >> 3)) * 5 = (4 * 32 + 12) * 5 = 700 */ /* Known UPS Commands: * * :N%02X -- delay the UPS for provided time (hex seconds) * :H%06X -- reboot the UPS. UPS will restart after provided time (hex s) * :A -- begins a self-test * :C -- fetches result of a self-test * :K1 -- turns on power receptacles * :K0 -- turns off power receptacles * :K3 -- turns on bank 1 receptacle(s) * :K2 -- turns off bank 1 receptacle(s) * :K5 -- turns on bank 2 receptacle(s) * :K4 -- turns off bank 2 receptacle(s) * :G -- unconfirmed: shuts down UPS until power returns * :Q1 -- enable "Remote Reboot" * :Q0 -- disable "Remote Reboot" * :W -- returns 'W' data * :L -- returns 'L' data * :V -- returns 'V' data (firmware revision) * :X -- returns 'X' data (firmware checksum) * :D -- returns general status data * :B -- returns battery voltage (hexadecimal decivolts) * :I -- returns minimum input voltage (hexadecimal hertz) * :M -- returns maximum input voltage (hexadecimal hertz) * :P -- returns power rating * :Z -- unknown * :U -- unknown * :O -- unknown * :E -- unknown * :Y -- returns mains frequency (':D' is preferred) * :T -- returns ups temperature (':D' is preferred) * :R -- returns input voltage (':D' is preferred) * :F -- returns load percentage (':D' is preferred) * :S -- enables remote reboot/remote power on */ /* Returned value from ':D' looks like: * * 0123456789abcdef01234 * ABCCDEFFGGGGHHIIIIJJJ * A 0=LB 1=OK * B 0=OVER 1=OK * CC INFO_UTILITY * D 0=normal 1=TRIM 2=BOOST 3="EXTRA BOOST" * E 0=OFF 1=OB 2=OL 3=OB (1 and 3 are the same?) * FF f(INFO_UPSTEMP) * GG ? INFO_BATTPCT (00 when OB, values don't match table we use) * HH ? (always 00) * II INFO_LOADPCT * JJJJ ? (e.g., 5B82 5B82 5982 037B 0082) * KKK INFO_ACFREQ * 10 */ #include "main.h" #include "serial.h" #include "tripplite.h" #include "nut_stdint.h" #include #include #define DRIVER_NAME "Tripp-Lite SmartUPS driver" #define DRIVER_VERSION "0.94" /* driver description structure */ upsdrv_info_t upsdrv_info = { DRIVER_NAME, DRIVER_VERSION, "Russell Kroll \n" \ "Rickard E. (Rik) Faith \n" \ "Nicholas J. Kain ", DRV_STABLE, { NULL } }; /* Time in seconds to delay before shutting down. */ static unsigned int offdelay = DEFAULT_OFFDELAY; static unsigned int startdelay = DEFAULT_STARTDELAY; static unsigned int bootdelay = DEFAULT_BOOTDELAY; static long hex2d(char *start, unsigned int len) { char buf[32]; snprintf(buf, sizeof buf, "%.*s", len, start); return strtol(buf, NULL, 16); } /* The UPS that I'm using (SMART700SER) has the bizarre characteristic * of innately echoing back commands. Therefore, we cannot use * ser_get_line and must manually discard our echoed command. * * All UPS commands are challenge-response, so this function makes things * very clean. * * return: # of chars in buf, excluding terminating \0 */ static ssize_t send_cmd(const char *str, char *buf, size_t len) { char c; ssize_t ret = 0; ssize_t i = 0; ser_flush_io(upsfd); ser_send(upsfd, "%s", str); if (!len || !buf || len > SSIZE_MAX) return -1; for (;;) { ret = ser_get_char(upsfd, &c, SER_WAIT_SEC, SER_WAIT_USEC); if (ret < 1) return -1; if (c == ENDCHAR) break; } do { ret = ser_get_char(upsfd, &c, SER_WAIT_SEC, SER_WAIT_USEC); if (ret < 1) return -1; if (c == IGNCHAR || c == ENDCHAR) continue; buf[i++] = c; } while (c != ENDCHAR && i < (int)len); buf[i] = '\0'; return i; } static void get_letter_cmd(const char *str, char *buf, size_t len) { int tries; ssize_t ret; for (tries = 0; tries < MAXTRIES; ++tries) { ret = send_cmd(str, buf, len); if ((ret > 0) && isalnum((unsigned char)buf[0])) return; } fatalx(EXIT_FAILURE, "\nFailed to find UPS - giving up..."); } static ssize_t do_reboot_now(void) { char buf[256], cmd[16]; snprintf(cmd, sizeof cmd, ":H%06X\r", startdelay); return send_cmd(cmd, buf, sizeof buf); } static void do_reboot(void) { char buf[256], cmd[16]; snprintf(cmd, sizeof cmd, ":N%02X\r", bootdelay); send_cmd(cmd, buf, sizeof buf); do_reboot_now(); } static ssize_t soft_shutdown(void) { char buf[256], cmd[16]; snprintf(cmd, sizeof cmd, ":N%02X\r", offdelay); send_cmd(cmd, buf, sizeof buf); return send_cmd(":G\r", buf, sizeof buf); } static ssize_t hard_shutdown(void) { char buf[256], cmd[16]; snprintf(cmd, sizeof cmd, ":N%02X\r", offdelay); send_cmd(cmd, buf, sizeof buf); return send_cmd(":K0\r", buf, sizeof buf); } static int instcmd(const char *cmdname, const char *extra) { char buf[256]; if (!strcasecmp(cmdname, "test.battery.start")) { send_cmd(":A\r", buf, sizeof buf); return STAT_INSTCMD_HANDLED; } if (!strcasecmp(cmdname, "load.off")) { send_cmd(":K0\r", buf, sizeof buf); return STAT_INSTCMD_HANDLED; } if (!strcasecmp(cmdname, "load.on")) { send_cmd(":K1\r", buf, sizeof buf); return STAT_INSTCMD_HANDLED; } if (!strcasecmp(cmdname, "outlet.1.load.off")) { send_cmd(":K2\r", buf, sizeof buf); return STAT_INSTCMD_HANDLED; } if (!strcasecmp(cmdname, "outlet.1.load.on")) { send_cmd(":K3\r", buf, sizeof buf); return STAT_INSTCMD_HANDLED; } if (!strcasecmp(cmdname, "outlet.2.load.off")) { send_cmd(":K4\r", buf, sizeof buf); return STAT_INSTCMD_HANDLED; } if (!strcasecmp(cmdname, "outlet.2.load.on")) { send_cmd(":K5\r", buf, sizeof buf); return STAT_INSTCMD_HANDLED; } if (!strcasecmp(cmdname, "shutdown.reboot")) { do_reboot_now(); return STAT_INSTCMD_HANDLED; } if (!strcasecmp(cmdname, "shutdown.reboot.graceful")) { do_reboot(); return STAT_INSTCMD_HANDLED; } if (!strcasecmp(cmdname, "shutdown.return")) { soft_shutdown(); return STAT_INSTCMD_HANDLED; } if (!strcasecmp(cmdname, "shutdown.stayoff")) { hard_shutdown(); return STAT_INSTCMD_HANDLED; } upslogx(LOG_NOTICE, "instcmd: unknown command [%s] [%s]", cmdname, extra); return STAT_INSTCMD_UNKNOWN; } static int setvar(const char *varname, const char *val) { if (!strcasecmp(varname, "ups.delay.shutdown")) { int ipv = atoi(val); if (ipv >= 0) offdelay = (unsigned int)ipv; dstate_setinfo("ups.delay.shutdown", "%u", offdelay); return STAT_SET_HANDLED; } if (!strcasecmp(varname, "ups.delay.start")) { int ipv = atoi(val); if (ipv >= 0) startdelay = (unsigned int)ipv; dstate_setinfo("ups.delay.start", "%u", startdelay); return STAT_SET_HANDLED; } if (!strcasecmp(varname, "ups.delay.reboot")) { int ipv = atoi(val); if (ipv >= 0) bootdelay = (unsigned int)ipv; dstate_setinfo("ups.delay.reboot", "%u", bootdelay); return STAT_SET_HANDLED; } return STAT_SET_UNKNOWN; } void upsdrv_initinfo(void) { const char *model; char w_value[16], l_value[16], v_value[16], x_value[16]; int gen, plugs; long w, l, va; get_letter_cmd(":W\r", w_value, sizeof w_value); get_letter_cmd(":L\r", l_value, sizeof l_value); get_letter_cmd(":V\r", v_value, sizeof v_value); get_letter_cmd(":X\r", x_value, sizeof x_value); dstate_setinfo("ups.mfr", "%s", "Tripp Lite"); w = hex2d(w_value, 2); l = hex2d(l_value, 2); model = "Smart"; if (w & 0x40) model = "Unison"; va = ((w & 0x3f) * 32 + (l >> 3)) * 5; /* New formula */ if (!(w & 0x80)) va = l / 2; /* Old formula */ gen = 1 + (!(x_value[0] & 0x07) * !(x_value[1] & 0x07)); plugs = x_value[0] - !!(x_value[1] >> 3) * 8; dstate_setinfo("ups.model", "%s %ld", model, va); dstate_setinfo("ups.firmware", "%c%c (Gen %d)", 'A'+v_value[0]-'0', 'A'+v_value[1]-'0', gen); dstate_setinfo("ups.delay.shutdown", "%d", offdelay); dstate_setflags("ups.delay.shutdown", ST_FLAG_RW | ST_FLAG_STRING); dstate_setaux("ups.delay.shutdown", 3); dstate_setinfo("ups.delay.start", "%d", startdelay); dstate_setflags("ups.delay.start", ST_FLAG_RW | ST_FLAG_STRING); dstate_setaux("ups.delay.start", 8); dstate_setinfo("ups.delay.reboot", "%d", bootdelay); dstate_setflags("ups.delay.reboot", ST_FLAG_RW | ST_FLAG_STRING); dstate_setaux("ups.delay.reboot", 3); dstate_addcmd("test.battery.start"); /* Turns off automatically */ dstate_addcmd("load.off"); dstate_addcmd("load.on"); dstate_addcmd("shutdown.reboot"); dstate_addcmd("shutdown.reboot.graceful"); dstate_addcmd("shutdown.return"); dstate_addcmd("shutdown.stayoff"); if (plugs > 1) { dstate_addcmd("outlet.1.load.off"); dstate_addcmd("outlet.1.load.on"); if (plugs > 2) { dstate_addcmd("outlet.2.load.off"); dstate_addcmd("outlet.2.load.on"); } } upsh.instcmd = instcmd; upsh.setvar = setvar; printf("Detected %s %s on %s\n", dstate_getinfo("ups.mfr"), dstate_getinfo("ups.model"), device_path); } void upsdrv_shutdown(void) { soft_shutdown(); } void upsdrv_updateinfo(void) { static int numfails; char buf[256]; int bp, temp; ssize_t len; long volt, load, vmax, vmin, stest; int bcond, lstate, tstate, mode; float bv, freq; len = send_cmd(":D\r", buf, sizeof buf); if (len != 21) { ++numfails; if (numfails > MAXTRIES) { ser_comm_fail("Data command failed: [%" PRIiSIZE "] bytes != 21 bytes.", len); dstate_datastale(); } return; } volt = hex2d(buf + 2, 2); temp = (int)(hex2d(buf + 6, 2)*0.3636 - 21.0); load = hex2d(buf + 12, 2); freq = hex2d(buf + 18, 3) / 10.0; bcond = buf[0]; lstate = buf[1]; tstate = buf[4]; mode = buf[5]; if (volt > INVOLT_MAX || volt < INVOLT_MIN || temp > TEMP_MAX || temp < TEMP_MIN || load > LOAD_MAX || load < LOAD_MIN || freq > FREQ_MAX || freq < FREQ_MIN) { ++numfails; if (numfails > MAXTRIES) { ser_comm_fail("Data out of bounds: [%0ld,%3d,%3ld,%02.2f]", volt, temp, load, freq); dstate_datastale(); } return; } send_cmd(":B\r", buf, sizeof buf); bv = (float)(hex2d(buf, 2)) / 10.0; if (bv > 50.0 || bv < 0.0) { ++numfails; if (numfails > MAXTRIES) { ser_comm_fail("Battery voltage out of bounds: [%02.1f]", bv); dstate_datastale(); } return; } send_cmd(":M\r", buf, sizeof buf); vmax = hex2d(buf, 2); if (vmax > INVOLT_MAX || vmax < INVOLT_MIN) { ++numfails; if (numfails > MAXTRIES) { ser_comm_fail("InVoltMax out of bounds: [%ld]", vmax); dstate_datastale(); } return; } send_cmd(":I\r", buf, sizeof buf); vmin = hex2d(buf, 2); if (vmin > INVOLT_MAX || vmin < INVOLT_MIN) { ++numfails; if (numfails > MAXTRIES) { ser_comm_fail("InVoltMin out of bounds: [%ld]", vmin); dstate_datastale(); } return; } send_cmd(":C\r", buf, sizeof buf); errno = 0; stest = strtol(buf, 0, 10); if (errno == ERANGE) { ++numfails; if (numfails > MAXTRIES) { ser_comm_fail("Self test is out of range: [%ld]", stest); dstate_datastale(); } return; } if (errno == EINVAL) { ++numfails; if (numfails > MAXTRIES) { ser_comm_fail("Self test returned non-numeric data."); dstate_datastale(); } return; } if (stest > 3 || stest < 0) { ++numfails; if (numfails > MAXTRIES) { ser_comm_fail("Self test out of bounds: [%ld]", stest); dstate_datastale(); } return; } /* We've successfully gathered all the data for an update. */ numfails = 0; dstate_setinfo("input.voltage", "%0ld", volt); dstate_setinfo("ups.temperature", "%3d", temp); dstate_setinfo("ups.load", "%3ld", load); dstate_setinfo("input.frequency", "%02.2f", freq); status_init(); /* Battery Voltage Condition */ switch (bcond) { case '0': /* Low Battery */ status_set("LB"); break; case '1': /* Normal */ break; default: /* Unknown */ upslogx(LOG_ERR, "Unknown battery state: %c", bcond); break; } /* Load State */ switch (lstate) { case '0': /* Overload */ status_set("OVER"); break; case '1': /* Normal */ break; default: /* Unknown */ upslogx(LOG_ERR, "Unknown load state: %c", lstate); break; } /* Tap State */ switch (tstate) { case '0': /* Normal */ break; case '1': /* Reducing */ status_set("TRIM"); break; case '2': /* Boost */ case '3': /* Extra Boost */ status_set("BOOST"); break; default: /* Unknown */ upslogx(LOG_ERR, "Unknown tap state: %c", tstate); break; } /* Mode */ switch (mode) { case '0': /* Off */ status_set("OFF"); break; case '1': /* On Battery */ status_set("OB"); break; case '2': /* On Line */ status_set("OL"); break; case '3': /* On Battery */ status_set("OB"); break; default: /* Unknown */ upslogx(LOG_ERR, "Unknown mode state: %c", mode); break; } status_commit(); /* dq ~= sqrt(dV) is a reasonable approximation * Results fit well against the discrete function used in the Tripp Lite * source, but give a continuous result. */ if (bv >= MAX_VOLT) bp = 100; else if (bv <= MIN_VOLT) bp = 10; else bp = (int)(100*sqrt((bv - MIN_VOLT) / (MAX_VOLT - MIN_VOLT))); dstate_setinfo("battery.voltage", "%.1f", bv); dstate_setinfo("battery.charge", "%3d", bp); dstate_setinfo("input.voltage.maximum", "%ld", vmax); dstate_setinfo("input.voltage.minimum", "%ld", vmin); switch (stest) { case 0: dstate_setinfo("ups.test.result", "%s", "OK"); break; case 1: dstate_setinfo("ups.test.result", "%s", "Battery Bad (Replace)"); break; case 2: dstate_setinfo("ups.test.result", "%s", "In Progress"); break; case 3: dstate_setinfo("ups.test.result", "%s", "Bad Inverter"); break; default: dstate_setinfo("ups.test.result", "Unknown (%s)", buf); break; } dstate_dataok(); ser_comm_good(); } void upsdrv_help(void) { } void upsdrv_makevartable(void) { char msg[256]; snprintf(msg, sizeof msg, "Set shutdown delay, in seconds (default=%d).", DEFAULT_OFFDELAY); addvar(VAR_VALUE, "offdelay", msg); snprintf(msg, sizeof msg, "Set start delay, in seconds (default=%d).", DEFAULT_STARTDELAY); addvar(VAR_VALUE, "startdelay", msg); snprintf(msg, sizeof msg, "Set reboot delay, in seconds (default=%d).", DEFAULT_BOOTDELAY); addvar(VAR_VALUE, "rebootdelay", msg); } void upsdrv_initups(void) { char *val; upsfd = ser_open(device_path); ser_set_speed(upsfd, device_path, B2400); if ((val = getval("offdelay"))) { int ipv = atoi(val); if (ipv >= 0) offdelay = (unsigned int)ipv; } if ((val = getval("startdelay"))) { int ipv = atoi(val); if (ipv >= 0) startdelay = (unsigned int)ipv; } if ((val = getval("rebootdelay"))) { int ipv = atoi(val); if (ipv >= 0) bootdelay = (unsigned int)ipv; } } void upsdrv_cleanup(void) { ser_close(upsfd, device_path); } nut-2.8.1/drivers/microsol-common.h0000644000175000017500000000441014500336654014222 00000000000000/* microsol-common.h - common framework for Microsol Solis-based UPS hardware Copyright (C) 2004 Silvino B. Magalhaes 2019 Roberto Panerai Velloso 2021 Ygor A. S. Regados 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 2 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, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 2021/03/19 - Version 0.70 - Initial release, based on solis driver */ #ifndef INCLUDED_MICROSOL_COMMON_H #define INCLUDED_MICROSOL_COMMON_H typedef unsigned int bool_t; #define PACKET_SIZE 25 /* buffers */ extern unsigned char received_packet[PACKET_SIZE]; /* Identification */ extern const char *model_name; extern unsigned int ups_model; extern bool_t input_220v, output_220v; /* logical */ extern bool_t detected; extern bool_t line_unpowered, overheat, overload; extern bool_t critical_battery, inverter_working; /*extern bool_t recharging;*/ /* microsol-apc.c has its own copy */ /* Input group */ extern double input_voltage, input_current, input_frequency; extern double input_minimum_voltage, input_maximum_voltage, input_nominal_voltage; extern double input_low_limit, input_high_limit; /* Output group */ extern double output_voltage, output_current, output_frequency; /* Battery group */ extern int battery_extension; extern double battery_voltage, battery_charge; extern double temperature; /* Power group */ extern double apparent_power, real_power, ups_load; extern int load_power_factor, nominal_power, ups_power_factor; extern void scan_received_pack_model_specific(void); extern void set_ups_model(void); extern bool_t ups_model_defined(void); #endif /* INCLUDED_MICROSOL_COMMON_H */ nut-2.8.1/drivers/powerpanel.c0000644000175000017500000001123014501607135013246 00000000000000/* * powerpanel.c - Model specific routines for CyberPower text/binary * protocol UPSes * * Copyright (C) * 2007 Doug Reynolds * 2007-2008 Arjen de Korte * * 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 2 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, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "main.h" #include "serial.h" #include "powerp-bin.h" #include "powerp-txt.h" static int mode = 0; static subdriver_t *subdriver[] = { &powpan_binary, &powpan_text, NULL }; #define DRIVER_NAME "CyberPower text/binary protocol UPS driver" #define DRIVER_VERSION "0.29" /* driver description structure */ upsdrv_info_t upsdrv_info = { DRIVER_NAME, DRIVER_VERSION, "Doug Reynolds \n" \ "Arjen de Korte \n" \ "Timothy Pearson ", DRV_EXPERIMENTAL, { NULL } }; /* FIXME: add a sub version for binary and text subdrivers? */ void upsdrv_initinfo(void) { char *s; dstate_setinfo("ups.mfr", "CyberPower"); dstate_setinfo("ups.model", "[unknown]"); dstate_setinfo("ups.serial", "[unknown]"); subdriver[mode]->initinfo(); /* * Allow to override the following parameters */ if ((s = getval("manufacturer")) != NULL) { dstate_setinfo("ups.mfr", "%s", s); } if ((s = getval("model")) != NULL) { dstate_setinfo("ups.model", "%s", s); } if ((s = getval("serial")) != NULL) { dstate_setinfo("ups.serial", "%s", s); } upsh.instcmd = subdriver[mode]->instcmd; upsh.setvar = subdriver[mode]->setvar; } void upsdrv_updateinfo(void) { static int retry = 0; if (subdriver[mode]->updateinfo() < 0) { ser_comm_fail("Status read failed!"); if (retry < 3) { retry++; } else { dstate_datastale(); } return; } retry = 0; ser_comm_good(); dstate_dataok(); } void upsdrv_shutdown(void) { int i, ret = -1; /* * Try to shutdown with delay and automatic reboot if the power * returned in the mean time (newer models support this). */ if (subdriver[mode]->instcmd("shutdown.return", NULL) == STAT_INSTCMD_HANDLED) { /* Shutdown successful */ return; } /* * Looks like an older type. Assume we're still on battery if * we can't read status or it is telling us we're on battery. */ for (i = 0; i < MAXTRIES; i++) { ret = subdriver[mode]->updateinfo(); if (ret >= 0) { break; } } if (ret > 0) { /* * When on battery, the 'shutdown.stayoff' command will make * the UPS switch back on when the power returns. */ if (subdriver[mode]->instcmd("shutdown.stayoff", NULL) == STAT_INSTCMD_HANDLED) { upslogx(LOG_INFO, "Waiting for power to return..."); return; } } else if (ret == 0) { /* * Apparently, the power came back already, so we just need to reboot. */ if (subdriver[mode]->instcmd("shutdown.reboot", NULL) == STAT_INSTCMD_HANDLED) { upslogx(LOG_INFO, "Rebooting now..."); return; } } upslogx(LOG_ERR, "Shutdown command failed!"); } void upsdrv_initups(void) { char *version; version = getval("protocol"); upsfd = ser_open(device_path); ser_set_rts(upsfd, 0); /* * Try to autodetect which UPS is connected. */ for (mode = 0; subdriver[mode] != NULL; mode++) { if ((version != NULL) && strcasecmp(version, subdriver[mode]->version)) { continue; } ser_set_dtr(upsfd, 1); usleep(10000); if (subdriver[mode]->initups() > 0) { upslogx(LOG_INFO, "CyberPower UPS with %s protocol on %s detected", subdriver[mode]->version, device_path); return; } ser_set_dtr(upsfd, 0); usleep(10000); } fatalx(EXIT_FAILURE, "CyberPower UPS not found on %s", device_path); } void upsdrv_help(void) { } void upsdrv_makevartable(void) { addvar(VAR_VALUE, "ondelay", "Delay before UPS startup"); addvar(VAR_VALUE, "offdelay", "Delay before UPS shutdown"); addvar(VAR_VALUE, "manufacturer", "manufacturer"); addvar(VAR_VALUE, "model", "modelname"); addvar(VAR_VALUE, "serial", "serialnumber"); addvar(VAR_VALUE, "protocol", "protocol to use [text|binary] (default: autodection)"); } void upsdrv_cleanup(void) { ser_set_dtr(upsfd, 0); ser_close(upsfd, device_path); } nut-2.8.1/drivers/legrand-hid.h0000644000175000017500000000217014500336654013264 00000000000000/* legrand-hid.h - subdriver to monitor Legrand USB/HID devices with NUT * * Copyright (C) * 2003 - 2009 Arnaud Quette * 2005 - 2006 Peter Selinger * 2008 - 2009 Arjen de Korte * * 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 2 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, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef LEGRAND_HID_H #define LEGRAND_HID_H #include "usbhid-ups.h" extern subdriver_t legrand_subdriver; #endif /* LEGRAND_HID_H */ nut-2.8.1/drivers/nutdrv_qx_megatec.c0000644000175000017500000001473714501607135014630 00000000000000/* nutdrv_qx_megatec.c - Subdriver for Megatec protocol based UPSes * * Copyright (C) * 2013 Daniele Pezzini * * 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 2 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, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #include "main.h" #include "nutdrv_qx.h" #include "nutdrv_qx_blazer-common.h" #include "nutdrv_qx_megatec.h" #define MEGATEC_VERSION "Megatec 0.07" /* qx2nut lookup table */ static item_t megatec_qx2nut[] = { /* * > [Q1\r] * < [(226.0 195.0 226.0 014 49.0 27.5 30.0 00001000\r] * 01234567890123456789012345678901234567890123456 * 0 1 2 3 4 */ { "input.voltage", 0, NULL, "Q1\r", "", 47, '(', "", 1, 5, "%.1f", 0, NULL, NULL, NULL }, { "input.voltage.fault", 0, NULL, "Q1\r", "", 47, '(', "", 7, 11, "%.1f", 0, NULL, NULL, NULL }, { "output.voltage", 0, NULL, "Q1\r", "", 47, '(', "", 13, 17, "%.1f", 0, NULL, NULL, NULL }, { "ups.load", 0, NULL, "Q1\r", "", 47, '(', "", 19, 21, "%.0f", 0, NULL, NULL, NULL }, { "input.frequency", 0, NULL, "Q1\r", "", 47, '(', "", 23, 26, "%.1f", 0, NULL, NULL, NULL }, { "battery.voltage", 0, NULL, "Q1\r", "", 47, '(', "", 28, 31, "%.2f", 0, NULL, NULL, qx_multiply_battvolt }, { "ups.temperature", 0, NULL, "Q1\r", "", 47, '(', "", 33, 36, "%.1f", 0, NULL, NULL, NULL }, /* Status bits */ { "ups.status", 0, NULL, "Q1\r", "", 47, '(', "", 38, 38, NULL, QX_FLAG_QUICK_POLL, NULL, NULL, blazer_process_status_bits }, /* Utility Fail (Immediate) */ { "ups.status", 0, NULL, "Q1\r", "", 47, '(', "", 39, 39, NULL, QX_FLAG_QUICK_POLL, NULL, NULL, blazer_process_status_bits }, /* Battery Low */ { "ups.status", 0, NULL, "Q1\r", "", 47, '(', "", 40, 40, NULL, QX_FLAG_QUICK_POLL, NULL, NULL, blazer_process_status_bits }, /* Bypass/Boost or Buck Active */ { "ups.alarm", 0, NULL, "Q1\r", "", 47, '(', "", 41, 41, NULL, 0, NULL, NULL, blazer_process_status_bits }, /* UPS Failed */ { "ups.type", 0, NULL, "Q1\r", "", 47, '(', "", 42, 42, "%s", QX_FLAG_STATIC, NULL, NULL, blazer_process_status_bits }, /* UPS Type */ { "ups.status", 0, NULL, "Q1\r", "", 47, '(', "", 43, 43, NULL, QX_FLAG_QUICK_POLL, NULL, NULL, blazer_process_status_bits }, /* Test in Progress */ { "ups.status", 0, NULL, "Q1\r", "", 47, '(', "", 44, 44, NULL, QX_FLAG_QUICK_POLL, NULL, NULL, blazer_process_status_bits }, /* Shutdown Active */ { "ups.beeper.status", 0, NULL, "Q1\r", "", 47, '(', "", 45, 45, "%s", 0, NULL, NULL, blazer_process_status_bits }, /* Beeper status */ /* * > [F\r] * < [#220.0 000 024.0 50.0\r] * 0123456789012345678901 * 0 1 2 */ { "input.voltage.nominal", 0, NULL, "F\r", "", 22, '#', "", 1, 5, "%.0f", QX_FLAG_STATIC, NULL, NULL, NULL }, { "input.current.nominal", 0, NULL, "F\r", "", 22, '#', "", 7, 9, "%.1f", QX_FLAG_STATIC, NULL, NULL, NULL }, { "battery.voltage.nominal", 0, NULL, "F\r", "", 22, '#', "", 11, 15, "%.1f", QX_FLAG_STATIC, NULL, NULL, NULL }, { "input.frequency.nominal", 0, NULL, "F\r", "", 22, '#', "", 17, 20, "%.0f", QX_FLAG_STATIC, NULL, NULL, NULL }, /* * > [I\r] * < [#------------- ------ VT12046Q \r] * 012345678901234567890123456789012345678 * 0 1 2 3 */ { "device.mfr", 0, NULL, "I\r", "", 39, '#', "", 1, 15, "%s", QX_FLAG_STATIC | QX_FLAG_TRIM, NULL, NULL, NULL }, { "device.model", 0, NULL, "I\r", "", 39, '#', "", 17, 26, "%s", QX_FLAG_STATIC | QX_FLAG_TRIM, NULL, NULL, NULL }, { "ups.firmware", 0, NULL, "I\r", "", 39, '#', "", 28, 37, "%s", QX_FLAG_STATIC | QX_FLAG_TRIM, NULL, NULL, NULL }, /* Instant commands */ { "beeper.toggle", 0, NULL, "Q\r", "", 0, 0, "", 0, 0, NULL, QX_FLAG_CMD, NULL, NULL, NULL }, { "load.off", 0, NULL, "S00R0000\r", "", 0, 0, "", 0, 0, NULL, QX_FLAG_CMD, NULL, NULL, NULL }, { "load.on", 0, NULL, "C\r", "", 0, 0, "", 0, 0, NULL, QX_FLAG_CMD, NULL, NULL, NULL }, { "shutdown.return", 0, NULL, "S%s\r", "", 0, 0, "", 0, 0, NULL, QX_FLAG_CMD, NULL, NULL, blazer_process_command }, { "shutdown.stayoff", 0, NULL, "S%sR0000\r", "", 0, 0, "", 0, 0, NULL, QX_FLAG_CMD, NULL, NULL, blazer_process_command }, { "shutdown.stop", 0, NULL, "C\r", "", 0, 0, "", 0, 0, NULL, QX_FLAG_CMD, NULL, NULL, NULL }, { "test.battery.start", 0, NULL, "T%02d\r", "", 0, 0, "", 0, 0, NULL, QX_FLAG_CMD, NULL, NULL, blazer_process_command }, { "test.battery.start.deep", 0, NULL, "TL\r", "", 0, 0, "", 0, 0, NULL, QX_FLAG_CMD, NULL, NULL, NULL }, { "test.battery.start.quick", 0, NULL, "T\r", "", 0, 0, "", 0, 0, NULL, QX_FLAG_CMD, NULL, NULL, NULL }, { "test.battery.stop", 0, NULL, "CT\r", "", 0, 0, "", 0, 0, NULL, QX_FLAG_CMD, NULL, NULL, NULL }, /* Server-side settable vars */ { "ups.delay.start", ST_FLAG_RW, blazer_r_ondelay, NULL, "", 0, 0, "", 0, 0, DEFAULT_ONDELAY, QX_FLAG_ABSENT | QX_FLAG_SETVAR | QX_FLAG_RANGE, NULL, NULL, blazer_process_setvar }, { "ups.delay.shutdown", ST_FLAG_RW, blazer_r_offdelay, NULL, "", 0, 0, "", 0, 0, DEFAULT_OFFDELAY, QX_FLAG_ABSENT | QX_FLAG_SETVAR | QX_FLAG_RANGE, NULL, NULL, blazer_process_setvar }, /* End of structure. */ { NULL, 0, NULL, NULL, "", 0, 0, "", 0, 0, NULL, 0, NULL, NULL, NULL } }; /* Testing table */ #ifdef TESTING static testing_t megatec_testing[] = { { "Q1\r", "(215.0 195.0 230.0 014 49.0 22.7 30.0 00000000\r", -1 }, { "F\r", "#230.0 000 024.0 50.0\r", -1 }, { "I\r", "#NOT_A_LIVE_UPS TESTING TESTING \r", -1 }, { "Q\r", "", -1 }, { "S03\r", "", -1 }, { "C\r", "", -1 }, { "S02R0005\r", "", -1 }, { "S.5R0000\r", "", -1 }, { "T04\r", "", -1 }, { "TL\r", "", -1 }, { "T\r", "", -1 }, { "CT\r", "", -1 }, { NULL } }; #endif /* TESTING */ /* Subdriver-specific initups */ static void megatec_initups(void) { blazer_initups(megatec_qx2nut); } /* Subdriver interface */ subdriver_t megatec_subdriver = { MEGATEC_VERSION, blazer_claim, megatec_qx2nut, megatec_initups, NULL, blazer_makevartable, "ACK", NULL, #ifdef TESTING megatec_testing, #endif /* TESTING */ }; nut-2.8.1/drivers/powercom.c0000644000175000017500000012140714501607135012735 00000000000000/* * powercom.c - model specific routines for following units: * -Trust 425/625 * -Powercom * -Advice Partner/King PR750 * See http://www.advice.co.il/product/inter/ups.html for its specifications. * This model is based on PowerCom (www.powercom.com) models. * -Socomec Sicon Egys 420 * -OptiUPS VS 575C * * Copyrights: * (C) 2015 Arnaud Quette * (C) 2013 Florian Bruhin * (C) 2002 Simon Rozman * (C) 1999 Peter Bieringer * * 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 2 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, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * rev 0.7: Alexey Sidorov * - add Powercom's Black Knight Pro model support ( BNT-400/500/600/800/801/1000/1200/1500/2000AP 220-240V ) * * rev 0.8: Alexey Sidorov * - add Powercom's King Pro model support ( KIN-425/525/625/800/1000/1200/1500/1600/2200/3000/5000AP[-RM] 100-120,200-240 V) * * rev 0.9: Alexey Sidorov * - add Powercom's Imperial model support ( IMP-xxxAP, IMD-xxxAP ) * * rev 0.10: Alexey Sidorov * - fix wrong detection KIN-2200AP * - use ser_set_dtr/ser_set_rts * * rev 0.11: Alexey Sidorov * - move variables from .h to .c file (thanks Michael Tokarev for bugreport) * - fix string comparison (thanks Michael Tokarev for bugreport & Charles Lepple for patch) * - added BNT-other, for BNT 100-120V models (I havn't specs for it) * * Tested on: BNT-1200AP * * Known bugs: * - strange battery level on BNT1200AP in online mode( & may be on other models) * - i don't know how connect to IMP|IMD USB * - i havn't specs for BNT 100-120V models. Add BNT-other type for it * * rev 0.13: Keven Ates * - Modified functions to work for BNT-other 100-120V models. * - Modified BNT-other type defaults to work for the BNT 1500A 120VA model. * - Documented the type[] values purpose in a condensed format. * - BNT-other can be used to perform a complete user override of values for all PowerCom models, detected or not. * * Tested on: BNT-1500A * * rev 0.14: Florian Bruhin (The Compiler) * - Added support for OptiUPS VS 575C * This probably also works with others, but I don't have their model numbers. * * rev 0.15: VSE NN * - Fixed UPS type assignment for Powercom Imperial USB series manufactured since 2009. * * Tested on: IMP-625AP * * rev 0.16: Arnaud Quette * - Fixed the processing of input/output voltages for KIN models * (https://github.com/networkupstools/nut/issues/187) * * rev 0.18: Rouben Tchakhmakhtchian * - Added nobt flag to config that skips UPS battery check on startup/init * (https://github.com/networkupstools/nut/issues/546) * */ #include "main.h" #include "serial.h" #include "powercom.h" #include "math.h" #define DRIVER_NAME "PowerCom protocol UPS driver" #define DRIVER_VERSION "0.21" /* driver description structure */ upsdrv_info_t upsdrv_info = { DRIVER_NAME, DRIVER_VERSION, "Simon Rozman \n" \ "Peter Bieringer \n" \ "Alexey Sidorov \n" \ "Florian Bruhin \n" \ "Arnaud Quette \n" \ "Rouben Tchakhmakhtchian ", DRV_STABLE, { NULL } }; #define NUM_OF_SUBTYPES (sizeof (types) / sizeof (*types)) /* general constants */ enum general { MAX_NUM_OF_BYTES_FROM_UPS = 16 }; /* variables used by module */ static unsigned char raw_data[MAX_NUM_OF_BYTES_FROM_UPS]; /* raw data reveived from UPS */ static unsigned int linevoltage = 230U; /* line voltage, can be defined via command line option */ static const char *manufacturer = "PowerCom"; static const char *modelname = "Unknown"; static const char *serialnumber = "Unknown"; static unsigned int type = 0; /* forward declaration of functions used to setup flow control */ static void dtr0rts1 (void); static void no_flow_control (void); /* struct defining types * --------------------- * See powercom.h for detailed information and functions. * * The following type defaults use this definition: * * "TypeID", * ByteCount, * { "FlowControlString", FlowControlFuncPtr }, * { { ValidationIndex, ValidationValue }, * { ValidationIndex, ValidationValue }, * { ValidationIndex, ValidationValue } }, * { { DelayShutdownMinutes, DelayShutdownSeconds }, * UseMinutesChar'y''n' }, * { FrequencyFactor, FrequencyConstant }, * { OfflineLoadFactor, OfflineLoadConstant, * OnlineLoadFactor, OnlineLoadConstant }, * { OfflineBatteryFactor, OfflineLoad%Factor, OfflineBatteryConstant, * OnlineBatteryFactor, OnlineBatteryConstant }, * { 240VoltageFactor, 240VoltageConstant, * 120VoltageFactor, 120VoltageConstant }, */ static struct type types[] = { { "Trust", 11, { "dtr0rts1", dtr0rts1 }, { { 5U, 0U }, { 7U, 0U }, { 8U, 0U } }, { { 0U, 10U }, 'n' }, { 0.00020997, 0.00020928 }, { 6.1343, -0.3808, 4.3110, 0.1811 }, { 5.0000, 0.3268, -825.00, 4.5639, -835.82 }, { 1.9216, -0.0977, 0.9545, 0.0000 }, }, { "Egys", 16, { "no_flow_control", no_flow_control }, { { 5U, 0x80U }, { 7U, 0U }, { 8U, 0U } }, { { 0U, 10U }, 'n' }, { 0.00020997, 0.00020928 }, { 6.1343, -0.3808, 1.3333, 0.6667 }, { 5.0000, 0.3268, -825.00, 2.2105, -355.37 }, { 1.9216, -0.0977, 0.9545, 0.0000 }, }, { "KP625AP", 16, { "dtr0rts1", dtr0rts1 }, { { 5U, 0x80U }, { 7U, 0U }, { 8U, 0U } }, { { 0U, 10U }, 'n' }, { 0.00020997, 0.00020928 }, { 6.1343, -0.3808, 4.3110, 0.1811 }, { 5.0000, 0.3268, -825.00, 4.5639, -835.82 }, { 1.9216, -0.0977, 0.9545, 0.0000 }, }, { "IMP", 16, { "no_flow_control", no_flow_control }, { { 5U, 0xFFU }, { 7U, 0U }, { 8U, 0U } }, { { 1U, 30U }, 'y' }, { 0.00020997, 0.00020928 }, { 6.1343, -0.3808, 4.3110, 0.1811 }, { 5.0000, 0.3268, -825.00, 4.5639, -835.82 }, { 1.9216, -0.0977, 0.9545, 0.0000 }, }, { "KIN", 16, { "no_flow_control", no_flow_control }, { { 11U, 0x4bU }, { 8U, 0U }, { 8U, 0U } }, { { 1U, 30U }, 'y' }, { 0.00020997, 0.0 }, { 6.1343, -0.3808, 1.075, 0.1811 }, { 5.0000, 0.3268, -825.00, 0.46511, 0 }, { 1.9216, -0.0977, 0.82857, 0.0000 }, }, { "BNT", 16, { "no_flow_control", no_flow_control }, { { 11U, 0x42U }, { 8U, 0U }, { 8U, 0U } }, { { 1U, 30U }, 'y' }, { 0.00020803, 0.0 }, { 1.4474, 0.0, 0.8594, 0.0 }, { 5.0000, 0.3268, -825.00, 0.46511, 0 }, { 1.9216, -0.0977, 0.82857, 0.0000 }, }, { "BNT-other", 16, { "no_flow_control", no_flow_control }, { { 8U, 0U }, { 8U, 0U }, { 8U, 0U } }, { { 1U, 30U }, 'y' }, { 0.00027778, 0.0000 }, { 1.0000, 0.0000, 1.0000, 0.0000 }, { 1.0000, 0.0000, 0.0000, 1.0000, 0.0000 }, { 2.0000, 0.0000, 2.0000, 0.0000 }, }, { "OPTI", 16, { "no_flow_control", no_flow_control }, { { 5U, 0xFFU }, { 7U, 0U }, { 8U, 0U } }, { { 1U, 30U }, 'y' }, { 0.0000, 0.0000 }, { 1.0000, 0.0000, 1.0000, 0.0000 }, { 1.0000, 0.0000, 0.0000, 1.0000, 0.0000 }, { 2.0000, 0.0000, 2.0000, 0.0000 }, }, }; /* values for sending to UPS */ enum commands { SEND_DATA = '\x01', BATTERY_TEST = '\x03', WAKEUP_TIME = '\x04', RESTART = '\xb9', SHUTDOWN = '\xba', COUNTER = '\xbc' }; /* location of data in received string */ enum data { UPS_LOAD = 0U, BATTERY_CHARGE = 1U, INPUT_VOLTAGE = 2U, OUTPUT_VOLTAGE = 3U, INPUT_FREQUENCY = 4U, UPSVERSION = 5U, OUTPUT_FREQUENCY = 6U, STATUS_A = 9U, STATUS_B = 10U, MODELNAME = 11U, MODELNUMBER = 12U }; /* status bits */ enum status { SUMMARY = 0U, MAINS_FAILURE = 1U, ONLINE = 1U, FAULT = 1U, LOW_BAT = 2U, BAD_BAT = 2U, TEST = 4U, AVR_ON = 8U, AVR_MODE = 16U, SD_COUNTER = 16U, OVERLOAD = 32U, SHED_COUNTER = 32U, DIS_NOLOAD = 64U, SD_DISPLAY = 128U, OFF = 128U }; static unsigned int voltages[] = {100,110,115,120,0,0,0,200,220,230,240,0,0,0,0,0}; static unsigned int BNTmodels[] = {0,400,500,600,800,801,1000,1200,1500,2000,0,0,0,0,0,0}; static unsigned int KINmodels[] = {0,425,500,525,625,800,1000,1200,1500,1600,2200,2200,2500,3000,5000,0}; static unsigned int IMPmodels[] = {0,425,525,625,825,1025,1200,1500,2000,0,0,0,0,0,0,0}; static unsigned int OPTImodels[] = {0,0,0,575,0,0,0,0,0,0,0,0,0,0,0,0}; /* * local used functions */ static void shutdown_halt(void) { ser_send_char (upsfd, (unsigned char)SHUTDOWN); if (types[type].shutdown_arguments.minutesShouldBeUsed != 'n') ser_send_char (upsfd, types[type].shutdown_arguments.delay[0]); ser_send_char (upsfd, types[type].shutdown_arguments.delay[1]); upslogx(LOG_INFO, "Shutdown (stayoff) initiated."); set_exit_flag(-2); /* EXIT_SUCCESS */ } static void shutdown_ret(void) { ser_send_char (upsfd, (unsigned char)RESTART); ser_send_char (upsfd, (unsigned char)COUNTER); if (types[type].shutdown_arguments.minutesShouldBeUsed != 'n') ser_send_char (upsfd, types[type].shutdown_arguments.delay[0]); ser_send_char (upsfd, types[type].shutdown_arguments.delay[1]); upslogx(LOG_INFO, "Shutdown (return) initiated."); set_exit_flag(-2); /* EXIT_SUCCESS */ } /* registered instant commands */ static int instcmd (const char *cmdname, const char *extra) { if (!strcasecmp(cmdname, "test.battery.start")) { ser_send_char (upsfd, BATTERY_TEST); return STAT_INSTCMD_HANDLED; } if (!strcasecmp(cmdname, "shutdown.return")) { /* NOTE: In this context, "return" is UPS behavior after the * wall-power gets restored. The routine exits the driver anyway. */ shutdown_ret(); #ifndef HAVE___ATTRIBUTE__NORETURN return STAT_INSTCMD_HANDLED; #endif } if (!strcasecmp(cmdname, "shutdown.stayoff")) { shutdown_halt(); #ifndef HAVE___ATTRIBUTE__NORETURN return STAT_INSTCMD_HANDLED; #endif } upslogx(LOG_NOTICE, "instcmd: unknown command [%s] [%s]", cmdname, extra); return STAT_INSTCMD_UNKNOWN; } /* set DTR and RTS lines on a serial port to supply a passive * serial interface: DTR to 0 (-V), RTS to 1 (+V) */ static void dtr0rts1 (void) { ser_set_dtr(upsfd, 0); ser_set_rts(upsfd, 1); upsdebugx(2, "DTR => 0, RTS => 1"); } /* clear any flow control */ static void no_flow_control (void) { struct termios tio; tcgetattr (upsfd, &tio); tio.c_iflag &= ~ ((tcflag_t)IXON | (tcflag_t)IXOFF); tio.c_cc[VSTART] = _POSIX_VDISABLE; tio.c_cc[VSTOP] = _POSIX_VDISABLE; upsdebugx(2, "Flow control disable"); /* disable any flow control */ tcsetattr(upsfd, TCSANOW, &tio); } /* sane check for returned buffer */ static int validate_raw_data (void) { int i = 0, num_of_tests = sizeof types[0].validation / sizeof types[0].validation[0]; for (i = 0; i < num_of_tests && raw_data[ types[type].validation[i].index_of_byte] == types[type].validation[i].required_value; i++) ; return (i < num_of_tests) ? 1 : 0; } /* get info from ups */ static int ups_getinfo(void) { size_t i; ssize_t c; /* send trigger char to UPS */ if (ser_send_char (upsfd, SEND_DATA) != 1) { upslogx(LOG_NOTICE, "writing error"); dstate_datastale(); return 0; } else { upsdebugx(5, "Num of bytes requested for reading from UPS: %d", types[type].num_of_bytes_from_ups); /* Note: num_of_bytes_from_ups is (unsigned char) so comparable * to ssize_t without more range checks */ c = ser_get_buf_len(upsfd, raw_data, types[type].num_of_bytes_from_ups, 3, 0); if (c != (ssize_t)types[type].num_of_bytes_from_ups) { upslogx(LOG_NOTICE, "data receiving error (%" PRIiSIZE " instead of %d bytes)", c, types[type].num_of_bytes_from_ups); dstate_datastale(); return 0; } else upsdebugx(5, "Num of bytes received from UPS: %" PRIiSIZE, c); } /* optional dump of raw data */ if (nut_debug_level > 4) { /* FIXME: use upsdebug_hex() ? */ printf("Raw data from UPS:\n"); for (i = 0; i < types[type].num_of_bytes_from_ups; i++) { printf("%2zu 0x%02x (%c)\n", i, raw_data[i], raw_data[i]>=0x20 ? raw_data[i] : ' '); } } /* validate raw data for correctness */ if (validate_raw_data() != 0) { upslogx(LOG_NOTICE, "data receiving error (validation check)"); dstate_datastale(); return 0; } return 1; } static float input_voltage(void) { unsigned int model; float tmp=0.0; if ( !strcmp(types[type].name, "BNT") && raw_data[MODELNUMBER]%16 > 7 ) { tmp=2.2*raw_data[INPUT_VOLTAGE]-24; } else if ( !strcmp(types[type].name, "KIN")) { model=KINmodels[raw_data[MODELNUMBER]/16]; /* Process input voltage, according to line voltage and model rating */ if (linevoltage < 200) { if (model <= 625) { tmp = 0.89 * raw_data[INPUT_VOLTAGE] + 6.18; } else if ((model >= 800) && (model < 2000)) { tmp = 1.61 * raw_data[INPUT_VOLTAGE] / 2.0; } else { tmp = 1.625 * raw_data[INPUT_VOLTAGE] / 2.0; } } if (linevoltage >= 200) { if (model <= 625) { tmp = 1.79 * raw_data[INPUT_VOLTAGE] + 3.35; } else if ((model >= 800) && (model < 2000)) { tmp = 1.61 * raw_data[INPUT_VOLTAGE]; } else { tmp = 1.625 * raw_data[INPUT_VOLTAGE]; } } } else if ( !strcmp(types[type].name, "IMP") || !strcmp(types[type].name, "OPTI")) { tmp=raw_data[INPUT_VOLTAGE]*2.0; } else { tmp=linevoltage >= 220 ? types[type].voltage[0] * raw_data[INPUT_VOLTAGE] + types[type].voltage[1] : types[type].voltage[2] * raw_data[INPUT_VOLTAGE] + types[type].voltage[3]; } if (tmp<0) tmp=0.0; return tmp; } static float output_voltage(void) { float tmp,rdatax,rdatay,rdataz,boostdata; unsigned int statINV = 0,statAVR = 0,statAVRMode = 0,model,t; static float datax1[]={0,1.0,1.0,1.0,1.0,0.945,0.945,0.945,0.127,0.127,0.945,0.945,0.945,0.256}; static float datay1[]={0,0.85,0.85,0.85,0.88,0.9,0.9,0.9,6.6,6.6,0.87,0.87,0.87,3.29}; static float dataz1[]={0,1.03,0.78,0.78,0.72,0.55,0.55,0.55,0.5,0.5,0.43,0.43,0.43,0.3}; static float datax2[]={0,1.0,1.0,1.0,1.0,1.89,1.89,1.89,0.127,0.127,1.89,1.89,1.89,0.256}; static float datay2[]={0,1.73,1.74,1.74,1.77,0.9,0.9,0.9,13.204,13.204,0.88,0.88,0.88,6.645}; static float dataz2[]={0,1.15,0.9,0.9,0.75,1.1,1.1,1.1,0.8,0.8,0.86,0.86,0.86,0.7}; if ( !strcmp(types[type].name, "BNT") || !strcmp(types[type].name, "KIN")) { statINV=raw_data[STATUS_A] & ONLINE; statAVR=raw_data[STATUS_A] & AVR_ON; statAVRMode=raw_data[STATUS_A] & AVR_MODE; } if ( !strcmp(types[type].name, "BNT") && raw_data[MODELNUMBER]%16 > 7 ) { if (statINV==0) { if (statAVR==0){ tmp=2.2*raw_data[OUTPUT_VOLTAGE]-24; } else { if (statAVRMode > 0) tmp=(2.2*raw_data[OUTPUT_VOLTAGE]-24)*31/27; else tmp=(2.22*raw_data[OUTPUT_VOLTAGE]-24)*27/31; } } else { t=raw_data[OUTPUT_FREQUENCY]/2; tmp=(1.965*raw_data[15])*(1.965*raw_data[15])*(t-raw_data[OUTPUT_VOLTAGE])/t; if (tmp>0) tmp=sqrt(tmp); else tmp=0.0; } } else if ( !strcmp(types[type].name, "KIN")) { model=KINmodels[raw_data[MODELNUMBER]/16]; if (statINV == 0) { if (statAVR == 0) { /* FIXME: miss test "if (iUPS == 1) {" */ if (linevoltage >= 200) { if (model <= 625) tmp = 1.79*raw_data[OUTPUT_VOLTAGE] + 3.35; else if (model<2000) tmp = 1.61*raw_data[OUTPUT_VOLTAGE]; else tmp = 1.625*raw_data[OUTPUT_VOLTAGE]; } else { if (model <= 625) tmp = 0.89 * raw_data[OUTPUT_VOLTAGE] + 6.18; else if (model<2000) tmp = 1.61 * raw_data[OUTPUT_VOLTAGE] / 2.0; else tmp = 1.625 * raw_data[OUTPUT_VOLTAGE] / 2.0; } } else if (statAVR == 1) { /* FIXME: miss test "if ((iUPS == 1) || (iUPS == 13)) {" */ if (linevoltage >= 200) { if (model <= 525) tmp = 2.07 * raw_data[OUTPUT_VOLTAGE]; else if (model == 625) tmp = 2.07 * raw_data[OUTPUT_VOLTAGE]+5; else if (model < 2000) tmp = 1.87 * raw_data[OUTPUT_VOLTAGE]; else tmp = 1.87 * raw_data[OUTPUT_VOLTAGE]; } else { if (model <= 625) tmp = 2.158 * raw_data[OUTPUT_VOLTAGE] / 2.0; else if (model < 2000) tmp = 1.842 * raw_data[OUTPUT_VOLTAGE] / 2.0; else tmp = 1.875 * raw_data[OUTPUT_VOLTAGE] / 2.0; } } else { /* FIXME: miss test "if ((iUPS == 1) || (iUPS == 13)) {" */ if (linevoltage >= 200) { if (model == 625) tmp = 1.571 * raw_data[OUTPUT_VOLTAGE]; else if (model < 2000) tmp = 1.37 * raw_data[OUTPUT_VOLTAGE]; else tmp = 1.4 * raw_data[OUTPUT_VOLTAGE]; } else { if (model <= 625) tmp = 1.635 * raw_data[OUTPUT_VOLTAGE] / 2.0; else if (model < 2000) tmp = 1.392 * raw_data[OUTPUT_VOLTAGE] / 2.0; else tmp = 1.392 * raw_data[OUTPUT_VOLTAGE] / 2.0; } } } else { /* FIXME: miss test "if ((iUPS == 1) && (T != 0))" */ if (linevoltage < 200) { rdatax = datax1[raw_data[MODELNUMBER]/16]; rdatay = datay1[raw_data[MODELNUMBER]/16]; rdataz = dataz1[raw_data[MODELNUMBER]/16]; } else { rdatax = datax2[raw_data[MODELNUMBER]/16]; rdatay = datay2[raw_data[MODELNUMBER]/16]; rdataz = dataz2[raw_data[MODELNUMBER]/16+1]; } boostdata = 1.0 + statAVR * 20.0 / 135.0; t = raw_data[OUTPUT_FREQUENCY]/2; tmp = 0; if (model > 625){ tmp=(raw_data[BATTERY_CHARGE]*rdatax)*(raw_data[BATTERY_CHARGE]*rdatax)* (t-raw_data[OUTPUT_VOLTAGE])/t; if (tmp>0) /* Casts below try to avoid potential multiplication overflow */ tmp=(float)( (double)sqrt(tmp)*rdatay*boostdata - (double)raw_data[UPS_LOAD]*rdataz*boostdata ); } else { tmp=(raw_data[BATTERY_CHARGE]*rdatax-raw_data[UPS_LOAD]*rdataz)* (raw_data[BATTERY_CHARGE]*rdatax-raw_data[UPS_LOAD]*rdataz)* (t-raw_data[OUTPUT_VOLTAGE])/t; if (tmp>0) tmp=sqrt(tmp)*rdatay; } /* FIXME: may miss a last processing with ErrorVal = 5 | 10 */ } } else if ( !strcmp(types[type].name, "IMP") || !strcmp(types[type].name, "OPTI")) { tmp=raw_data[OUTPUT_VOLTAGE]*2.0; } else { tmp= linevoltage >= 220 ? types[type].voltage[0] * raw_data[OUTPUT_VOLTAGE] + types[type].voltage[1] : types[type].voltage[2] * raw_data[OUTPUT_VOLTAGE] + types[type].voltage[3]; } if (tmp<0) tmp=0.0; return tmp; } static float input_freq(void) { if ( !strcmp(types[type].name, "BNT") || !strcmp(types[type].name, "KIN")) return 4807.0/raw_data[INPUT_FREQUENCY]; else if ( !strcmp(types[type].name, "IMP") || !strcmp(types[type].name, "OPTI")) return raw_data[INPUT_FREQUENCY]; return raw_data[INPUT_FREQUENCY] ? 1.0 / (types[type].freq[0] * raw_data[INPUT_FREQUENCY] + types[type].freq[1]) : 0; } static float output_freq(void) { if ( !strcmp(types[type].name, "BNT") || !strcmp(types[type].name, "KIN")) return 4807.0/raw_data[OUTPUT_FREQUENCY]; else if ( !strcmp(types[type].name, "IMP") || !strcmp(types[type].name, "OPTI")) return raw_data[OUTPUT_FREQUENCY]; return raw_data[OUTPUT_FREQUENCY] ? 1.0 / (types[type].freq[0] * raw_data[OUTPUT_FREQUENCY] + types[type].freq[1]) : 0; } static float load_level(void) { unsigned int statINV,model,voltage; int load425[]={99,88,84,80,84,84,84,86,86,81,76}; int load525[]={127,113,106,100,106,106,106,109,109,103,97}; int load625[]={131,115,107,103,107,107,107,110,110,105,99}; int load2k[] ={94,94,94,94,94,94,94,120,120,115,110}; int load425i[]={60,54,51,48,51,51,51,53,53,50,48}; int load525i[]={81,72,67,62,67,67,67,65,65,62,59}; int load625i[]={79,70,67,64,67,67,67,65,65,61,58}; int load2ki[] ={84,77,74,70,74,74,74,77,77,74,70}; int load400[]={1,1,1,1,1,1,1,1,88,83,87}; int load500[]={1,1,1,1,1,1,1,1,108,103,98}; int load600[]={1,1,1,1,1,1,1,1,128,123,118}; int load400i[]={1,1,1,1,1,1,1,1,54,52,49}; int load500i[]={1,1,1,1,1,1,1,1,66,64,61}; int load600i[]={1,1,1,1,1,1,1,1,86,84,81}; int load801i[]={1,1,1,1,1,1,1,1,44,42,40}; int load1000i[]={1,1,1,1,1,1,1,1,56,54,52}; int load1200i[]={1,1,1,1,1,1,1,1,76,74,72}; if ( !strcmp(types[type].name, "BNT") && raw_data[MODELNUMBER]%16 > 7 ) { statINV=raw_data[STATUS_A] & ONLINE; voltage=raw_data[MODELNUMBER]%16; model=BNTmodels[raw_data[MODELNUMBER]/16]; if (statINV==0){ if (model==400 || model==801) return raw_data[UPS_LOAD]*110.0/load400[voltage]; else if (model==600 || model==1200) return raw_data[UPS_LOAD]*110.0/load600[voltage]; else return raw_data[UPS_LOAD]*110.0/load500[voltage]; } else { switch (model) { case 400: return raw_data[UPS_LOAD]*110.0/load400i[voltage]; case 500: case 800: return raw_data[UPS_LOAD]*110.0/load500i[voltage]; case 600: return raw_data[UPS_LOAD]*110.0/load600i[voltage]; case 801: return raw_data[UPS_LOAD]*110.0/load801i[voltage]; case 1200: return raw_data[UPS_LOAD]*110.0/load1200i[voltage]; case 1000: case 1500: case 2000: return raw_data[UPS_LOAD]*110.0/load1000i[voltage]; } } } else if (!strcmp(types[type].name, "KIN")) { statINV=raw_data[STATUS_A] & ONLINE; voltage=raw_data[MODELNUMBER]%16; model=KINmodels[raw_data[MODELNUMBER]/16]; if (statINV==0){ if (model==425) return raw_data[UPS_LOAD]*110.0/load425[voltage]; if (model==525) return raw_data[UPS_LOAD]*110.0/load525[voltage]; if (model==625) return raw_data[UPS_LOAD]*110.0/load625[voltage]; if (model<2000) return raw_data[UPS_LOAD]*1.13; return raw_data[UPS_LOAD]*110.0/load2k[voltage]; } else { if (model==425) return raw_data[UPS_LOAD]*110.0/load425i[voltage]; if (model==525) return raw_data[UPS_LOAD]*110.0/load525i[voltage]; if (model==625) return raw_data[UPS_LOAD]*110.0/load625i[voltage]; if (model<2000) return raw_data[UPS_LOAD]*1.66; return raw_data[UPS_LOAD]*110.0/load2ki[voltage]; } } else if ( !strcmp(types[type].name, "IMP") || !strcmp(types[type].name, "OPTI")) { return raw_data[UPS_LOAD]; } return (raw_data[STATUS_A] & MAINS_FAILURE) ? types[type].loadpct[0] * raw_data[UPS_LOAD] + types[type].loadpct[1] : types[type].loadpct[2] * raw_data[UPS_LOAD] + types[type].loadpct[3]; } static float batt_level(void) { int bat0,bat29,bat100; unsigned int model; float battval; if ( !strcmp(types[type].name, "BNT") ) { bat0=157; bat29=165; bat100=193; battval=(raw_data[UPS_LOAD])/4+raw_data[BATTERY_CHARGE]; if (battval<=bat0) return 0.0; if (battval<=bat29) return (battval-bat0)*30.0/(bat29-bat0); if (battval<=bat100) return 30.0+(battval-bat29)*70.0/(bat100-bat29); return 100.0; } if ( !strcmp(types[type].name, "KIN")) { model=KINmodels[raw_data[MODELNUMBER]/16]; if (model>=800 && model<=2000){ battval=(raw_data[BATTERY_CHARGE]-165.0)*2.6; if (raw_data[STATUS_A] & ONLINE) return battval+raw_data[UPS_LOAD]; if (battval>7) return battval-6; return battval; } else if (model<=625){ battval=raw_data[UPS_LOAD]/4.0+raw_data[BATTERY_CHARGE]; bat0=169; bat29=176; bat100=204; } else { battval=raw_data[UPS_LOAD]/4.0-raw_data[UPS_LOAD]/32.0+raw_data[BATTERY_CHARGE]; bat0=175; bat29=182; bat100=209; } if (battval<=bat0) return 0; if (battval>bat0 && battval<=bat29) return (battval-bat0)*30.0/(bat29-bat0); if (battval>bat29 && battval<=bat100) return 30.0+(battval-bat29)*70.0/(bat100-bat29); return 100; } if ( !strcmp(types[type].name, "IMP") || !strcmp(types[type].name, "OPTI")) return raw_data[BATTERY_CHARGE]; return (raw_data[STATUS_A] & ONLINE) ? /* Are we on battery power? */ /* Yes */ types[type].battpct[0] * raw_data[BATTERY_CHARGE] + types[type].battpct[1] * load_level() + types[type].battpct[2] : /* No */ types[type].battpct[3] * raw_data[BATTERY_CHARGE] + types[type].battpct[4]; } /* * global used functions */ /* update information */ void upsdrv_updateinfo(void) { char val[32]; if (!ups_getinfo()) { /* https://github.com/networkupstools/nut/issues/356 */ upsdebugx(1, "%s: failed to ups_getinfo() once, retrying for slower devices", __func__); if (!ups_getinfo()) { return; } } /* input.frequency */ upsdebugx(3, "input.frequency (raw data): [raw: %u]", raw_data[INPUT_FREQUENCY]); dstate_setinfo("input.frequency", "%02.2f", input_freq()); upsdebugx(2, "input.frequency: %s", dstate_getinfo("input.frequency")); /* output.frequency */ upsdebugx(3, "output.frequency (raw data): [raw: %u]", raw_data[OUTPUT_FREQUENCY]); dstate_setinfo("output.frequency", "%02.2f", output_freq()); upsdebugx(2, "output.frequency: %s", dstate_getinfo("output.frequency")); /* ups.load */ upsdebugx(3, "ups.load (raw data): [raw: %u]", raw_data[UPS_LOAD]); dstate_setinfo("ups.load", "%03.1f", load_level()); upsdebugx(2, "ups.load: %s", dstate_getinfo("ups.load")); /* battery.charge */ upsdebugx(3, "battery.charge (raw data): [raw: %u]", raw_data[BATTERY_CHARGE]); dstate_setinfo("battery.charge", "%03.1f", batt_level()); upsdebugx(2, "battery.charge: %s", dstate_getinfo("battery.charge")); /* input.voltage */ upsdebugx(3, "input.voltage (raw data): [raw: %u]", raw_data[INPUT_VOLTAGE]); dstate_setinfo("input.voltage", "%03.1f",input_voltage()); upsdebugx(2, "input.voltage: %s", dstate_getinfo("input.voltage")); /* output.voltage */ upsdebugx(3, "output.voltage (raw data): [raw: %u]", raw_data[OUTPUT_VOLTAGE]); dstate_setinfo("output.voltage", "%03.1f",output_voltage()); upsdebugx(2, "output.voltage: %s", dstate_getinfo("output.voltage")); status_init(); *val = 0; if (!(raw_data[STATUS_A] & MAINS_FAILURE)) { !(raw_data[STATUS_A] & OFF) ? status_set("OL") : status_set("OFF"); } else { status_set("OB"); } if (raw_data[STATUS_A] & LOW_BAT) status_set("LB"); if (raw_data[STATUS_A] & AVR_ON) { input_voltage() < linevoltage ? status_set("BOOST") : status_set("TRIM"); } if (raw_data[STATUS_A] & OVERLOAD) status_set("OVER"); if (raw_data[STATUS_B] & BAD_BAT) status_set("RB"); if (raw_data[STATUS_B] & TEST) status_set("TEST"); status_commit(); upsdebugx(2, "STATUS: %s", dstate_getinfo("ups.status")); dstate_dataok(); } /* shutdown UPS */ void upsdrv_shutdown(void) { /* power down the attached load immediately */ printf("Forced UPS shutdown (and wait for power)...\n"); shutdown_ret(); } /* initialize UPS */ void upsdrv_initups(void) { int tmp; unsigned int model = 0; unsigned int i; static char buf[20]; /* check manufacturer name from arguments */ if (testvar("manufacturer")) manufacturer = getval("manufacturer"); /* check model name from arguments */ if (testvar("modelname")) modelname = getval("modelname"); /* check serial number from arguments */ if (testvar("serialnumber")) serialnumber = getval("serialnumber"); /* get and check type */ if (testvar("type")) { for (i = 0; i < NUM_OF_SUBTYPES && strcmp(types[i].name, getval("type")); i++) ; if (i >= NUM_OF_SUBTYPES) { printf("Given UPS type '%s' isn't valid!\n", getval("type")); exit (1); } type = i; } /* check line voltage from arguments */ if (testvar("linevoltage")) { tmp = atoi(getval("linevoltage")); if (! ( (tmp >= 200 && tmp <= 240) || (tmp >= 100 && tmp <= 120) ) ) { printf("Given line voltage '%d' is out of range (100-120 or 200-240 V)\n", tmp); exit (1); } linevoltage = (unsigned int) tmp; } if (testvar("numOfBytesFromUPS")) { tmp = atoi(getval("numOfBytesFromUPS")); if (! (tmp > 0 && tmp <= MAX_NUM_OF_BYTES_FROM_UPS) ) { printf("Given numOfBytesFromUPS '%d' is out of range (1 to %d)\n", tmp, MAX_NUM_OF_BYTES_FROM_UPS); exit (1); } types[type].num_of_bytes_from_ups = (unsigned char) tmp; } if (testvar("methodOfFlowControl")) { for (i = 0; i < NUM_OF_SUBTYPES && strcmp(types[i].flowControl.name, getval("methodOfFlowControl")); i++) ; if (i >= NUM_OF_SUBTYPES) { printf("Given methodOfFlowControl '%s' isn't valid!\n", getval("methodOfFlowControl")); exit (1); } types[type].flowControl = types[i].flowControl; } if (testvar("validationSequence") && sscanf(getval("validationSequence"), "{{%u,%x},{%u,%x},{%u,%x}}", &types[type].validation[0].index_of_byte, &types[type].validation[0].required_value, &types[type].validation[1].index_of_byte, &types[type].validation[1].required_value, &types[type].validation[2].index_of_byte, &types[type].validation[2].required_value ) < 6 ) { printf("Given validationSequence '%s' isn't valid!\n", getval("validationSequence")); exit (1); } /* NOTE: %hhu is not supported before C99; that would need reading * arguments into an uint as %u, checking range and casting */ if (testvar("shutdownArguments") && sscanf(getval("shutdownArguments"), "{{%hhu,%hhu},%c}", &types[type].shutdown_arguments.delay[0], &types[type].shutdown_arguments.delay[1], &types[type].shutdown_arguments.minutesShouldBeUsed ) < 3 ) { printf("Given shutdownArguments '%s' isn't valid!\n", getval("shutdownArguments")); exit (1); } if (testvar("frequency") && sscanf(getval("frequency"), "{%f,%f}", &types[type].freq[0], &types[type].freq[1] ) < 2 ) { printf("Given frequency '%s' isn't valid!\n", getval("frequency")); exit (1); } if (testvar("loadPercentage") && sscanf(getval("loadPercentage"), "{%f,%f,%f,%f}", &types[type].loadpct[0], &types[type].loadpct[1], &types[type].loadpct[2], &types[type].loadpct[3] ) < 4 ) { printf("Given loadPercentage '%s' isn't valid!\n", getval("loadPercentage")); exit (1); } if (testvar("batteryPercentage") && sscanf(getval("batteryPercentage"), "{%f,%f,%f,%f,%f}", &types[type].battpct[0], &types[type].battpct[1], &types[type].battpct[2], &types[type].battpct[3], &types[type].battpct[4] ) < 5 ) { printf("Given batteryPercentage '%s' isn't valid!\n", getval("batteryPercentage")); exit (1); } if (testvar("voltage") && sscanf(getval("voltage"), "{%f,%f,%f,%f}", &types[type].voltage[0], &types[type].voltage[1], &types[type].voltage[2], &types[type].voltage[3] ) < 4 ) { printf("Given voltage '%s' isn't valid!\n", getval("voltage")); exit (1); } /* open serial port */ upsfd = ser_open(device_path); ser_set_speed(upsfd, device_path, B1200); /* setup flow control */ types[type].flowControl.setup_flow_control(); /* Setup Model and LineVoltage */ if (!strncmp(types[type].name, "BNT",3) || !strcmp(types[type].name, "KIN") || !strcmp(types[type].name, "IMP") || !strcmp(types[type].name, "OPTI")) { if (!ups_getinfo()) return; /* Give "BNT-other" a chance! */ if (raw_data[MODELNAME]==0x42 || raw_data[MODELNAME]==0x4B || raw_data[MODELNAME]==0x4F){ /* Give "IMP" a chance also! */ if (raw_data[UPSVERSION]==0xFF){ types[type].name="IMP"; model=IMPmodels[raw_data[MODELNUMBER]/16]; } else { model=BNTmodels[raw_data[MODELNUMBER]/16]; if (!strcmp(types[type].name, "BNT-other")) types[type].name="BNT-other"; else if (raw_data[MODELNAME]==0x42) types[type].name="BNT"; else if (raw_data[MODELNAME]==0x4B){ types[type].name="KIN"; model=KINmodels[raw_data[MODELNUMBER]/16]; } else if (raw_data[MODELNAME]==0x4F){ types[type].name="OPTI"; model=OPTImodels[raw_data[MODELNUMBER]/16]; } } } else if (raw_data[UPSVERSION]==0xFF){ types[type].name="IMP"; model=IMPmodels[raw_data[MODELNUMBER]/16]; } linevoltage=voltages[raw_data[MODELNUMBER]%16]; if (!strcmp(types[type].name, "OPTI")) { snprintf(buf,sizeof(buf),"%s-%u",types[type].name, model); } else { snprintf(buf,sizeof(buf),"%s-%uAP",types[type].name, model); } if (!strcmp(modelname, "Unknown")) modelname=buf; upsdebugx(1,"Detected: %s , %dV",buf,linevoltage); if (testvar("nobt") || dstate_getinfo("driver.flag.nobt")) { upslogx(LOG_NOTICE, "nobt flag set, skipping battery test as requested"); } else { upslogx(LOG_NOTICE, "nobt flag not set, performing battery test as requested"); if (ser_send_char (upsfd, BATTERY_TEST) != 1) { upslogx(LOG_NOTICE, "Write error: failed to send battery test command to UPS!"); dstate_datastale(); return; } } } upsdebugx(1, "Values of arguments:"); upsdebugx(1, " manufacturer : '%s'", manufacturer); upsdebugx(1, " model name : '%s'", modelname); upsdebugx(1, " serial number : '%s'", serialnumber); upsdebugx(1, " line voltage : '%u'", linevoltage); upsdebugx(1, " type : '%s'", types[type].name); upsdebugx(1, " number of bytes from UPS: '%u'", types[type].num_of_bytes_from_ups); upsdebugx(1, " method of flow control : '%s'", types[type].flowControl.name); upsdebugx(1, " validation sequence: '{{%u,%#x},{%u,%#x},{%u,%#x}}'", types[type].validation[0].index_of_byte, types[type].validation[0].required_value, types[type].validation[1].index_of_byte, types[type].validation[1].required_value, types[type].validation[2].index_of_byte, types[type].validation[2].required_value); upsdebugx(1, " shutdown arguments: '{{%u,%u},%c}'", types[type].shutdown_arguments.delay[0], types[type].shutdown_arguments.delay[1], types[type].shutdown_arguments.minutesShouldBeUsed); if ( strcmp(types[type].name, "KIN") && strcmp(types[type].name, "BNT") && strcmp(types[type].name, "IMP")) { upsdebugx(1, " frequency calculation coefficients: '{%f,%f}'", types[type].freq[0], types[type].freq[1]); upsdebugx(1, " load percentage calculation coefficients: " "'{%f,%f,%f,%f}'", types[type].loadpct[0], types[type].loadpct[1], types[type].loadpct[2], types[type].loadpct[3]); upsdebugx(1, " battery percentage calculation coefficients: " "'{%f,%f,%f,%f,%f}'", types[type].battpct[0], types[type].battpct[1], types[type].battpct[2], types[type].battpct[3], types[type].battpct[4]); upsdebugx(1, " voltage calculation coefficients: '{%f,%f}'", types[type].voltage[2], types[type].voltage[3]); } } /* display help */ void upsdrv_help(void) { /* 1 2 3 4 5 6 7 8 */ /* 12345678901234567890123456789012345678901234567890123456789012345678901234567890 MAX */ printf("\n"); printf("Specify UPS information in the ups.conf file.\n"); printf(" type: Type of UPS: 'Trust','Egys','KP625AP','IMP','KIN','BNT',\n"); printf(" 'BNT-other', 'OPTI' (default: 'Trust')\n"); printf(" 'BNT-other' is a special type intended for BNT 100-120V models,\n"); printf(" but can be used to override ALL models.\n"); printf("You can additional specify these variables:\n"); printf(" manufacturer: Manufacturer name (default: 'PowerCom')\n"); printf(" modelname: Model name (default: 'Unknown' or autodetected)\n"); printf(" serialnumber: Serial number (default: Unknown)\n"); printf(" shutdownArguments: 3 delay arguments for the shutdown operation:\n"); printf(" {{Minutes,Seconds},UseMinutes?}\n"); printf(" where Minutes and Seconds are integer, UseMinutes? is either\n"); printf(" 'y' or 'n'.\n"); printf("You can specify these variables if not automagically detected for types\n"); printf(" 'IMP','KIN','BNT'\n"); printf(" linevoltage: Line voltage: 110-120 or 220-240 (default: 230)\n"); printf(" numOfBytesFromUPS: Number of bytes in a UPS frame: 16 is common, 11 for 'Trust'\n"); printf(" methodOfFlowControl: Flow control method for UPS:\n"); printf(" 'dtr0rts1', 'dtr1' or 'no_flow_control'\n"); printf(" validationSequence: 3 pairs of validation values: {{I,V},{I,V},{I,V}}\n"); printf(" where I is the index into BytesFromUPS (see numOfBytesFromUPS)\n"); printf(" and V is the value for the ByteIndex to match.\n"); printf(" frequency: Input & Output Frequency conversion values: {A, B}\n"); printf(" used in function: 1/(A*x+B)\n"); printf(" If the raw value x IS the frequency, then A=1/(x^2), B=0\n"); printf(" loadPercentage: Load conversion values for Battery and Line load: {BA,BB,LA,LB}\n"); printf(" used in function: A*x+B\n"); printf(" If the raw value x IS the Load Percent, then A=1, B=0\n"); printf(" batteryPercentage: Battery conversion values for Battery and Line power:\n"); printf(" {A,B,C,D,E}\n"); printf(" used in functions: (Battery) A*x+B*y+C, (Line) D*x+E\n"); printf(" If the raw value x IS the Battery Percent, then\n"); printf(" A=1, B=0, C=0, D=1, E=0\n"); printf(" voltage: Voltage conversion values for 240 and 120 voltage:\n"); printf(" {240A,240B,120A,120B}\n"); printf(" used in function: A*x+B\n"); printf(" If the raw value x IS HALF the Voltage, then A=2, B=0\n"); printf(" nobt: Flag to skip battery check on init/startup.\n\n"); printf("Example for BNT1500AP in ups.conf:\n"); printf("[BNT1500AP]\n"); printf(" driver = powercom\n"); printf(" port = /dev/ttyS0\n"); printf(" desc = \"PowerCom BNT 1500 AP\"\n"); printf(" manufacturer = PowerCom\n"); printf(" modelname = BNT1500AP\n"); printf(" serialnumber = 13245678900\n"); printf(" type = BNT-other\n"); printf("# linevoltage = 120\n"); printf("# numOfBytesFromUPS = 16\n"); printf("# methodOfFlowControl = no_flow_control\n"); printf("# validationSequence = {{8,0},{8,0},{8,0}}\n"); printf("# shutdownArguments = {{1,30},y}\n"); printf("# frequency = {0.00027778,0.0000}\n"); printf("# loadPercentage = {1.0000,0.0,1.0000,0.0}\n"); printf("# batteryPercentage = {1.0000,0.0000,0.0000,1.0000,0.0000}\n"); printf("# voltage = {2.0000,0.0000,2.0000,0.0000}\n"); printf(" nobt\n"); return; } /* initialize information */ void upsdrv_initinfo(void) { /* write constant data for this model */ dstate_setinfo ("ups.mfr", "%s", manufacturer); dstate_setinfo ("ups.model", "%s", modelname); dstate_setinfo ("ups.serial", "%s", serialnumber); dstate_setinfo ("ups.model.type", "%s", types[type].name); dstate_setinfo ("input.voltage.nominal", "%u", linevoltage); /* now add the instant commands */ dstate_addcmd ("test.battery.start"); dstate_addcmd ("shutdown.return"); dstate_addcmd ("shutdown.stayoff"); upsh.instcmd = instcmd; } /* define possible arguments */ void upsdrv_makevartable(void) { /* 1 2 3 4 5 6 7 8 */ /*2345678901234567890123456789012345678901234567890123456789012345678901234567890 MAX */ addvar(VAR_VALUE, "type", "Type of UPS: 'Trust','Egys','KP625AP','IMP','KIN','BNT','BNT-other','OPTI'\n" " (default: 'Trust')"); addvar(VAR_VALUE, "manufacturer", "Manufacturer name (default: 'PowerCom')"); addvar(VAR_VALUE, "modelname", "Model name [cannot be detected] (default: Unknown)"); addvar(VAR_VALUE, "serialnumber", "Serial number [cannot be detected] (default: Unknown)"); addvar(VAR_VALUE, "shutdownArguments", "Delay values for shutdown: Minutes, Seconds, UseMinutes?'y'or'n'"); addvar(VAR_VALUE, "linevoltage", "Line voltage 110-120 or 220-240 V (default: 230)"); addvar(VAR_VALUE, "numOfBytesFromUPS", "The number of bytes in a UPS frame"); addvar(VAR_VALUE, "methodOfFlowControl", "Flow control method for UPS: 'dtr0rts1' or 'no_flow_control'"); addvar(VAR_VALUE, "validationSequence", "Validation values: ByteIndex, ByteValue x 3"); if ( strcmp(types[type].name, "KIN") && strcmp(types[type].name, "BNT") && strcmp(types[type].name, "IMP")) { addvar(VAR_VALUE, "frequency", "Frequency conversion values: FreqFactor, FreqConst"); addvar(VAR_VALUE, "loadPercentage", "Load conversion values: OffFactor, OffConst, OnFactor, OnConst"); addvar(VAR_VALUE, "batteryPercentage", "Battery conversion values: OffFactor, LoadFactor, OffConst, OnFactor, OnConst"); addvar(VAR_VALUE, "voltage", "Voltage conversion values: 240VFactor, 240VConst, 120VFactor, 120VConst"); addvar(VAR_FLAG, "nobt", "Disable battery test at driver init/startup"); } } void upsdrv_cleanup(void) { ser_close(upsfd, device_path); } nut-2.8.1/drivers/riello.h0000644000175000017500000001241714501607135012375 00000000000000/* * riello.h: defines/macros for Riello protocol based UPSes * * Documents describing the protocol implemented by this driver can be * found online at: * * https://www.networkupstools.org/protocols/riello/PSGPSER-0104.pdf * https://www.networkupstools.org/protocols/riello/PSSENTR-0100.pdf * * Copyright (C) 2012 - Elio Parisi * * 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 2 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, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * Reference of the derivative work: blazer driver */ #ifndef NUT_RIELLO_H_SEEN #define NUT_RIELLO_H_SEEN 1 #include "nut_stdint.h" #define CTRL_RETRIES 50 #define CTRL_TIMEOUT 100 #define MAX_READ_WRITE (16 * 1024) #define USB_WRITE_DELAY 200 #define MAXTRIES 3 #define COUNTLOST 10 #define DEV_RIELLOSENTRY 14 #define DEV_RIELLOGPSER 21 #define LENGTH_GI 68 #define LENGTH_GN 34 #define LENGTH_RS_MM 42 #define LENGTH_RS_TM 48 #define LENGTH_RS_TT 64 #define LENGTH_RE 70 #define LENGTH_RC 56 #define LENGTH_DEF 12 #define SENTR_EXT176 176 #define SENTR_ALSO240 240 #define SENTR_ONLY192 192 #define BUFFER_SIZE 220 typedef struct { uint16_t SWversion; uint16_t Model; uint16_t Uinp1; uint16_t Uinp2; uint16_t Uinp3; uint16_t Iinp1; uint16_t Iinp2; uint16_t Iinp3; uint16_t Finp; uint16_t Uout1; uint16_t Uout2; uint16_t Uout3; uint16_t Iout1; uint16_t Iout2; uint16_t Iout3; uint16_t Pout1; uint16_t Pout2; uint16_t Pout3; uint16_t Ipout1; uint16_t Ipout2; uint16_t Ipout3; uint16_t Fout; uint16_t BatTime; uint16_t BatCap; uint16_t Ubat; uint16_t Ibat; uint16_t Tsystem; uint16_t NomBatCap; uint16_t Ubypass1; uint16_t Ubypass2; uint16_t Ubypass3; uint16_t Fbypass; uint16_t LockUPS; uint8_t AlarmCode[4]; char AlarmCodeT[12]; uint8_t StatusCode[12]; char StatusCodeT[42]; char Identification[18]; char ModelStr[18]; char Version[14]; uint16_t NomPowerKVA; uint16_t NomPowerKW; uint16_t NomUbat; uint16_t NumBat; uint16_t UbatPerc; uint16_t NominalUout; uint16_t Boost; uint16_t Buck; uint8_t Identif_bytes[12]; uint16_t NomFout; uint32_t Pout1VA; uint32_t Pout2VA; uint32_t Pout3VA; uint32_t Pout1W; uint32_t Pout2W; uint32_t Pout3W; } TRielloData; /* CRC and Checksum functions */ uint16_t riello_calc_CRC(uint8_t type, uint8_t *buff, uint16_t size, uint8_t checksum); void riello_create_crc(uint8_t type, uint8_t *buff, uint16_t size, uint8_t checksum); uint8_t riello_test_crc(uint8_t type, uint8_t *buff, uint16_t size, uint8_t chacksum); uint8_t riello_test_bit(uint8_t *basic_address, uint8_t bit); /* send GPSER command functions */ uint8_t riello_prepare_gi(uint8_t* buffer); uint8_t riello_prepare_gn(uint8_t* buffer, uint8_t gpser_error_control); uint8_t riello_prepare_rs(uint8_t* buffer, uint8_t gpser_error_control); uint8_t riello_prepare_re(uint8_t* buffer, uint8_t gpser_error_control); uint8_t riello_prepare_rc(uint8_t* buffer, uint8_t gpser_error_control); uint8_t riello_prepare_cs(uint8_t* buffer, uint8_t gpser_error_control, uint16_t delay); uint8_t riello_prepare_cr(uint8_t* buffer, uint8_t gpser_error_control, uint16_t delay); uint8_t riello_prepare_cd(uint8_t* buffer, uint8_t gpser_error_control); uint8_t riello_prepare_tp(uint8_t* buffer, uint8_t gpser_error_control); uint8_t riello_prepare_tb(uint8_t* buffer, uint8_t gpser_error_control); /* send SENTR command functions */ uint8_t riello_prepare_shutsentr(uint8_t* buffer, uint16_t delay); uint8_t riello_prepare_cancelsentr(uint8_t* buffer); uint8_t riello_prepare_setrebsentr(uint8_t* buffer, uint16_t delay); uint8_t riello_prepare_rebsentr(uint8_t* buffer, uint16_t delay); uint8_t riello_prepare_tbsentr(uint8_t* buffer); /* parse GPSER ups responses */ void riello_parse_gi(uint8_t* buffer, TRielloData* data); void riello_parse_gn(uint8_t* buffer, TRielloData* data); void riello_parse_rs(uint8_t* buffer, TRielloData* data, uint8_t numread); void riello_parse_re(uint8_t* buffer, TRielloData* data); void riello_parse_rc(uint8_t* buffer, TRielloData* data); /* parse SENTR ups responses */ void riello_parse_sentr(uint8_t* buffer, TRielloData* data); /* communication functions */ void riello_init_serial(void); uint8_t riello_header(uint8_t type, uint8_t a, uint8_t* length); uint8_t riello_tail(uint8_t type, uint8_t length); uint8_t riello_test_nak(uint8_t type, uint8_t* buffer); void riello_parse_serialport(uint8_t typedev, uint8_t* buffer, uint8_t checksum); void riello_comm_setup(const char *port); int get_ups_statuscode(void); /* Shared global variables for driver subtypes */ /* extern uint8_t foundheader; */ extern uint16_t buf_ptr_length; extern uint8_t wait_packet; extern uint8_t foundnak; extern uint8_t foundbadcrc; extern uint8_t commbyte; extern uint8_t requestSENTR; #endif /* NUT_RIELLO_H_SEEN */ nut-2.8.1/drivers/explore-hid.c0000644000175000017500000000416414500336654013326 00000000000000/* explore-hid.c - this is a "stub" subdriver used to collect data * about HID UPS systems that are not yet supported. * * This subdriver will match any UPS, but only if the "-x explore" option * is given. * * 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 2 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, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #include "main.h" #include "usbhid-ups.h" #include "explore-hid.h" #define EXPLORE_HID_VERSION "EXPLORE HID 0.2" static usage_tables_t explore_utab[] = { hid_usage_lkp, NULL, }; /* --------------------------------------------------------------- */ /* Data lookup table (HID <-> NUT) */ /* --------------------------------------------------------------- */ static hid_info_t explore_hid2nut[] = { /* end of structure. */ { NULL, 0, 0, NULL, NULL, NULL, 0, NULL } }; static const char *explore_format_model(HIDDevice_t *hd) { return hd->Product; } static const char *explore_format_mfr(HIDDevice_t *hd) { return hd->Vendor; } static const char *explore_format_serial(HIDDevice_t *hd) { return hd->Serial; } /* this function allows the subdriver to "claim" a device: return 1 if * the device is supported by this subdriver, else 0. */ static int explore_claim(HIDDevice_t *hd) { NUT_UNUSED_VARIABLE(hd); if (testvar("explore")) { return 1; } else { return 0; } } subdriver_t explore_subdriver = { EXPLORE_HID_VERSION, explore_claim, explore_utab, explore_hid2nut, explore_format_model, explore_format_mfr, explore_format_serial, fix_report_desc, }; nut-2.8.1/drivers/nutdrv_qx_mecer.h0000644000175000017500000000175114273170601014312 00000000000000/* nutdrv_qx_mecer.h - Subdriver for Mecer/Voltronic Power P98 UPSes * * Copyright (C) * 2013 Daniele Pezzini * * 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 2 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, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #ifndef NUTDRV_QX_MECER_H #define NUTDRV_QX_MECER_H #include "nutdrv_qx.h" extern subdriver_t mecer_subdriver; #endif /* NUTDRV_QX_MECER_H */ nut-2.8.1/drivers/eaton-pdu-genesis2-mib.c0000644000175000017500000001075314500336654015265 00000000000000/* eaton-pdu-genesis2-mib.c - data to monitor Eaton ePDUs branded as: * G1 Aphel based ePDUs (Basic) - GenesisII * * Copyright (C) 2008 - 2019 * Arnaud Quette * Arnaud Quette * Copyright (C) 2015 - 2017 * Jim Klimov * * Supported by Eaton * and previously MGE Office Protection Systems * * 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 2 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, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #include "eaton-pdu-genesis2-mib.h" #define EATON_APHEL_GENESIS2_MIB_VERSION "0.52" /* APHEL-GENESIS-II-MIB (monitored ePDU) * ************************************* * Note: There is also a basic XML interface, but not worth * implementing in netxml-ups! */ #define APHEL1_OID_MIB ".1.3.6.1.4.1.17373" #define APHEL1_SYSOID APHEL1_OID_MIB #define APHEL1_OID_MODEL_NAME ".1.3.6.1.4.1.17373.3.1.1.0" #define APHEL1_OID_FIRMREV ".1.3.6.1.4.1.17373.3.1.2.0" #define APHEL1_OID_DEVICE_NAME ".1.3.6.1.4.1.17373.3.1.3.0" #define APHEL1_OID_UNIT_MACADDR ".1.3.6.1.4.1.17373.3.1.4.0" /* needs concat ..0 */ #define APHEL1_OID_OUTLET_CURRENT ".1.3.6.1.4.1.17373.3.2" /* Snmp2NUT lookup table for GenesisII MIB */ static snmp_info_t eaton_aphel_genesisII_mib[] = { /* standard MIB items */ { "device.description", ST_FLAG_STRING | ST_FLAG_RW, SU_INFOSIZE, ".1.3.6.1.2.1.1.1.0", NULL, SU_FLAG_OK, NULL }, { "device.contact", ST_FLAG_STRING | ST_FLAG_RW, SU_INFOSIZE, ".1.3.6.1.2.1.1.4.0", NULL, SU_FLAG_OK, NULL }, { "device.location", ST_FLAG_STRING | ST_FLAG_RW, SU_INFOSIZE, ".1.3.6.1.2.1.1.6.0", NULL, SU_FLAG_OK, NULL }, /* Device page */ { "device.mfr", ST_FLAG_STRING, SU_INFOSIZE, NULL, "EATON | Powerware", SU_FLAG_STATIC | SU_FLAG_ABSENT | SU_FLAG_OK, NULL }, { "device.model", ST_FLAG_STRING, SU_INFOSIZE, APHEL1_OID_MODEL_NAME, "Eaton Powerware ePDU Monitored", SU_FLAG_STATIC | SU_FLAG_OK, NULL }, { "device.type", ST_FLAG_STRING, SU_INFOSIZE, NULL, "pdu", SU_FLAG_STATIC | SU_FLAG_ABSENT | SU_FLAG_OK, NULL }, { "device.macaddr", ST_FLAG_STRING, SU_INFOSIZE, APHEL1_OID_UNIT_MACADDR, "unknown", 0, NULL }, /* UPS page */ { "ups.mfr", ST_FLAG_STRING, SU_INFOSIZE, NULL, "EATON | Powerware", SU_FLAG_STATIC | SU_FLAG_ABSENT | SU_FLAG_OK, NULL }, { "ups.model", ST_FLAG_STRING, SU_INFOSIZE, APHEL1_OID_MODEL_NAME, "Generic SNMP PDU", SU_FLAG_STATIC | SU_FLAG_OK, NULL }, { "ups.id", ST_FLAG_STRING, SU_INFOSIZE, APHEL1_OID_DEVICE_NAME, "unknown", SU_FLAG_STATIC | SU_FLAG_OK, NULL }, { "ups.firmware", ST_FLAG_STRING, SU_INFOSIZE, APHEL1_OID_FIRMREV, "", SU_FLAG_STATIC | SU_FLAG_OK, NULL }, { "ups.type", ST_FLAG_STRING, SU_INFOSIZE, NULL, "pdu", SU_FLAG_STATIC | SU_FLAG_ABSENT | SU_FLAG_OK, NULL }, /* Outlet page */ /* we can't use template since there is no counterpart to outlet.count */ { "outlet.1.current", 0, 0.1, APHEL1_OID_OUTLET_CURRENT ".1.0", NULL, SU_FLAG_NEGINVALID, NULL }, { "outlet.2.current", 0, 0.1, APHEL1_OID_OUTLET_CURRENT ".2.0", NULL, SU_FLAG_NEGINVALID, NULL }, { "outlet.3.current", 0, 0.1, APHEL1_OID_OUTLET_CURRENT ".3.0", NULL, SU_FLAG_NEGINVALID, NULL }, { "outlet.4.current", 0, 0.1, APHEL1_OID_OUTLET_CURRENT ".4.0", NULL, SU_FLAG_NEGINVALID, NULL }, { "outlet.5.current", 0, 0.1, APHEL1_OID_OUTLET_CURRENT ".5.0", NULL, SU_FLAG_NEGINVALID, NULL }, { "outlet.6.current", 0, 0.1, APHEL1_OID_OUTLET_CURRENT ".6.0", NULL, SU_FLAG_NEGINVALID, NULL }, { "outlet.7.current", 0, 0.1, APHEL1_OID_OUTLET_CURRENT ".7.0", NULL, SU_FLAG_NEGINVALID, NULL }, { "outlet.8.current", 0, 0.1, APHEL1_OID_OUTLET_CURRENT ".8.0", NULL, SU_FLAG_NEGINVALID, NULL }, /* end of structure. */ { NULL, 0, 0, NULL, NULL, 0, NULL } }; mib2nut_info_t aphel_genesisII = { "aphel_genesisII", EATON_APHEL_GENESIS2_MIB_VERSION, NULL, APHEL1_OID_MODEL_NAME, eaton_aphel_genesisII_mib, APHEL1_SYSOID, NULL }; nut-2.8.1/drivers/emerson-avocent-pdu-mib.c0000644000175000017500000002245014501607135015540 00000000000000/* emerson-avocent-pdu-mib.c - subdriver to monitor Emerson Avocent PDUs with NUT * * Copyright (C) * 2008-2018 Arnaud Quette * 2009 Opengear * 2017-2019 Eaton (Arnaud Quette ) * * 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 2 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, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #define OPENGEAR_MULTIPLE_BANKS 1 #include "emerson-avocent-pdu-mib.h" #define EMERSON_AVOCENT_MIB_VERSION "1.3" #define EMERSON_AVOCENT_SYSOID ".1.3.6.1.4.1.10418.17.1.7" #define EMERSON_AVOCENT_OID_MODEL_NAME ".1.3.6.1.4.1.10418.17.2.1.2.0" /* FIXME: Avocent PM's seem to have 3 temperature sensors (index 1, 2, 3) * for the embedded temperature (equivalent to ups.temperature) */ #define AVOCENT_OID_UNIT_TEMPERATURE ".1.3.6.1.4.1.10418.17.2.5.3.1.17.1.1" /* Same as above for humidity... */ #define AVOCENT_OID_UNIT_HUMIDITY ".1.3.6.1.4.1.10418.17.2.5.3.1.24.1" #define AVOCENT_OID_OUTLET_COUNT ".1.3.6.1.4.1.10418.17.2.5.3.1.8.%i.%i" /* FIXME: This is actually pmPowerMgmtPDUTableCurrent1Value */ #define AVOCENT_OID_UNIT_CURRENT ".1.3.6.1.4.1.10418.17.2.5.3.1.10.1.1" /* FIXME: This is actually pmPowerMgmtPDUTableVoltage1Value */ #define AVOCENT_OID_UNIT_VOLTAGE ".1.3.6.1.4.1.10418.17.2.5.3.1.31.1.1" #define AVOCENT_OID_UNIT_MACADDR ".1.3.6.1.2.1.2.2.1.6.1" #ifdef OPENGEAR_MULTIPLE_BANKS #define AVOCENT_OID_OUTLET_ID ".1.3.6.1.4.1.10418.17.2.5.5.1.3" #define AVOCENT_OID_OUTLET_NAME ".1.3.6.1.4.1.10418.17.2.5.5.1.4" #define AVOCENT_OID_OUTLET_STATUS ".1.3.6.1.4.1.10418.17.2.5.5.1.5" /* This the actual value for the Current of the sensor. */ #define AVOCENT_OID_OUTLET_LOAD ".1.3.6.1.4.1.10418.17.2.5.5.1.50" #define AVOCENT_OID_OUTLET_CONTROL ".1.3.6.1.4.1.10418.17.2.5.5.1.6" #else #define AVOCENT_OID_OUTLET_ID ".1.3.6.1.4.1.10418.17.2.5.5.1.3.1.1" #define AVOCENT_OID_OUTLET_NAME ".1.3.6.1.4.1.10418.17.2.5.5.1.4.1.1" #define AVOCENT_OID_OUTLET_STATUS ".1.3.6.1.4.1.10418.17.2.5.5.1.5.1.1" #define AVOCENT_OID_OUTLET_LOAD ".1.3.6.1.4.1.10418.17.2.5.5.1.50.1.1" #define AVOCENT_OID_OUTLET_CONTROL ".1.3.6.1.4.1.10418.17.2.5.5.1.6.1.1" #endif static info_lkp_t avocent_outlet_status_info[] = { { 1, "off", NULL, NULL }, { 2, "on", NULL, NULL }, /* { 3, "offLocked", NULL, NULL }, { 4, "onLocked", NULL, NULL }, { 5, "offCycle", NULL, NULL }, { 6, "onPendingOff", NULL, NULL }, { 7, "offPendingOn", NULL, NULL }, { 8, "onPendingCycle", NULL, NULL }, { 9, "notSet", NULL, NULL }, { 10, "onFixed", NULL, NULL }, { 11, "offShutdown", NULL, NULL }, { 12, "tripped", NULL, NULL }, */ { 0, NULL, NULL, NULL } }; static snmp_info_t emerson_avocent_pdu_mib[] = { /* standard MIB items */ { "device.description", ST_FLAG_STRING | ST_FLAG_RW, SU_INFOSIZE, ".1.3.6.1.2.1.1.1.0", NULL, SU_FLAG_OK, NULL }, { "device.contact", ST_FLAG_STRING | ST_FLAG_RW, SU_INFOSIZE, ".1.3.6.1.2.1.1.4.0", NULL, SU_FLAG_OK, NULL }, { "device.location", ST_FLAG_STRING | ST_FLAG_RW, SU_INFOSIZE, ".1.3.6.1.2.1.1.6.0", NULL, SU_FLAG_OK, NULL }, /* Device page */ { "device.mfr", ST_FLAG_STRING, SU_INFOSIZE, NULL, "Avocent", SU_FLAG_STATIC | SU_FLAG_ABSENT | SU_FLAG_OK, NULL }, { "device.model", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.10418.17.2.5.3.1.5.1.%i", /* EMERSON_AVOCENT_OID_MODEL_NAME */ "Avocent SNMP PDU", SU_FLAG_ABSENT | SU_FLAG_OK | SU_FLAG_NAINVALID, NULL }, { "device.serial", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.10418.17.2.1.4.0", "", SU_FLAG_STATIC | SU_FLAG_OK, NULL }, { "device.type", ST_FLAG_STRING, SU_INFOSIZE, NULL, "pdu", SU_FLAG_STATIC | SU_FLAG_ABSENT | SU_FLAG_OK, NULL }, /* Daisychained devices support * Notes: this definition is used to: * - estimate the number of devices, based on the below OID iteration capabilities * - determine the base index of the SNMP OID (ie 0 or 1) */ { "device.count", 0, 1, ".1.3.6.1.4.1.10418.17.2.5.2.1.4.1", "1", SU_FLAG_STATIC, NULL }, /* UPS page */ { "ups.mfr", ST_FLAG_STRING, SU_INFOSIZE, NULL, "Avocent", SU_FLAG_STATIC | SU_FLAG_ABSENT | SU_FLAG_OK, NULL }, { "ups.model", ST_FLAG_STRING, SU_INFOSIZE, EMERSON_AVOCENT_OID_MODEL_NAME, "Avocent SNMP PDU", SU_FLAG_STATIC | SU_FLAG_OK, NULL }, { "ups.id", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.10418.17.2.1.1.0", "unknown", SU_FLAG_STATIC | SU_FLAG_OK, NULL }, { "ups.serial", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.10418.17.2.1.4.0", "", SU_FLAG_STATIC | SU_FLAG_OK, NULL }, { "ups.firmware", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.10418.17.2.1.7.0", "", SU_FLAG_STATIC | SU_FLAG_OK, NULL }, { "ups.type", ST_FLAG_STRING, SU_INFOSIZE, NULL, "pdu", SU_FLAG_STATIC | SU_FLAG_ABSENT | SU_FLAG_OK, NULL }, { "ups.macaddr", ST_FLAG_STRING, SU_INFOSIZE, AVOCENT_OID_UNIT_MACADDR, "", SU_FLAG_STATIC | SU_FLAG_OK, NULL }, /* Outlet page */ { "outlet.id", 0, 1, NULL, "0", SU_FLAG_STATIC | SU_FLAG_ABSENT | SU_FLAG_OK, NULL }, { "outlet.desc", ST_FLAG_RW | ST_FLAG_STRING, 20, NULL, "All outlets", SU_FLAG_STATIC | SU_FLAG_ABSENT | SU_FLAG_OK, NULL }, { "outlet.count", 0, 1, ".1.3.6.1.4.1.10418.17.2.5.3.1.8.1.%i", "0", SU_FLAG_STATIC | SU_FLAG_ZEROINVALID | SU_FLAG_OK, NULL }, /* outlets */ /* NOTE: there is a bug in Avocent FW: * index '0' should not respond (and is not in subtree mode) but answers * to unitary get, since OIDs start at index '1'. *Use the status data below to test since '0' is not a supported value */ { "outlet.%i.status", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.10418.17.2.5.5.1.5.1.%i.%i", NULL, SU_OUTLET | SU_TYPE_DAISY_1 | SU_FLAG_ZEROINVALID, &avocent_outlet_status_info[0] }, { "outlet.%i.id", 0, 1, ".1.3.6.1.4.1.10418.17.2.5.5.1.3.1.%i.%i", NULL, SU_FLAG_STATIC | SU_FLAG_ABSENT | SU_FLAG_OK | SU_OUTLET | SU_TYPE_DAISY_1, NULL }, { "outlet.%i.desc", ST_FLAG_RW | ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.10418.17.2.5.5.1.4.1.%i.%i", NULL, SU_OUTLET | SU_TYPE_DAISY_1 | SU_FLAG_NAINVALID, NULL }, /* pmPowerMgmtOutletsTableCurrentValue.1.1.1; Value (Integer): 0 */ { "outlet.%i.current", 0, 0.1, ".1.3.6.1.4.1.10418.17.2.5.5.1.50.1.%i.%i", NULL, SU_OUTLET | SU_TYPE_DAISY_1, NULL }, /* pmPowerMgmtOutletsTableCurrentHighCritical.1.1.1; Value (Integer): 160 */ { "outlet.%i.current.high.critical", ST_FLAG_RW, 0.1, ".1.3.6.1.4.1.10418.17.2.5.5.1.100.1.%i.%i", NULL, SU_OUTLET | SU_TYPE_DAISY_1, NULL }, /* pmPowerMgmtOutletsTableCurrentHighWarning.1.1.1; Value (Integer): 120 */ { "outlet.%i.current.high.warning", ST_FLAG_RW, 0.1, ".1.3.6.1.4.1.10418.17.2.5.5.1.101.1.%i.%i", NULL, SU_OUTLET | SU_TYPE_DAISY_1, NULL }, /* pmPowerMgmtOutletsTableCurrentLowWarning.1.1.1; Value (Integer): 0 */ { "outlet.%i.current.low.warning", ST_FLAG_RW, 0.1, ".1.3.6.1.4.1.10418.17.2.5.5.1.102.1.%i.%i", NULL, SU_OUTLET | SU_TYPE_DAISY_1, NULL }, /* pmPowerMgmtOutletsTableCurrentLowCritical.1.1.1; Value (Integer): 0 */ { "outlet.%i.current.low.critical", ST_FLAG_RW, 0.1, ".1.3.6.1.4.1.10418.17.2.5.5.1.103.1.%i.%i", NULL, SU_OUTLET | SU_TYPE_DAISY_1, NULL }, /* pmPowerMgmtOutletsTablePowerValue.1.1.1; Value (Integer): 0 */ { "outlet.%i.realpower", 0, 0.1, ".1.3.6.1.4.1.10418.17.2.5.5.1.60.1.%i.%i", NULL, SU_OUTLET | SU_TYPE_DAISY_1, NULL }, /* pmPowerMgmtOutletsTableVoltageValue.1.1.1; Value (Integer): 238 */ { "outlet.%i.voltage", 0, 1, ".1.3.6.1.4.1.10418.17.2.5.5.1.70.1.%i.%i", NULL, SU_OUTLET | SU_TYPE_DAISY_1, NULL }, /* TODO: handle statistics * pmPowerMgmtOutletsTableEnergyValue.1.1.1; Value (Integer): 0 (Wh) * pmPowerMgmtOutletsTableEnergyStartTime.1.1.1; Value (OctetString): 2018-02-13 10:40:09 * pmPowerMgmtOutletsTableEnergyReset.1.1.1; Value (Integer): noAction (1) */ /* Outlet groups collection */ /* pmPowerMgmtNumberOfOutletGroup.0; Value (Integer): 0 */ { "outlet.group.count", 0, 1, ".1.3.6.1.4.1.10418.17.2.5.6.%i", "0", SU_FLAG_STATIC | SU_TYPE_DAISY_1, NULL }, /* TODO: support for "Banks" (not sure to understand what is this?!) * pmPowerMgmtTotalNumberOfBanks.0; Value (Integer): 6 * pmPowerMgmtBanksTableName.1.1.1; Value (OctetString): 18-bf-ffP0_1_A */ /* According to MIB Power Control values are: * noAction(1), * powerOn(2), * powerOff(3), * powerCycle(4), * powerLock(5), * powerUnlock(6) */ { "outlet.%i.load.cycle", 0, 1, ".1.3.6.1.4.1.10418.17.2.5.5.1.6.1.%i.%i", "4", SU_TYPE_CMD | SU_OUTLET | SU_TYPE_DAISY_1, NULL }, { "outlet.%i.load.off", 0, 1, ".1.3.6.1.4.1.10418.17.2.5.5.1.6.1.%i.%i", "3", SU_TYPE_CMD | SU_OUTLET | SU_TYPE_DAISY_1, NULL }, { "outlet.%i.load.on", 0, 1, ".1.3.6.1.4.1.10418.17.2.5.5.1.6.1.%i.%i", "2", SU_TYPE_CMD | SU_OUTLET | SU_TYPE_DAISY_1, NULL }, /* end of structure. */ { NULL, 0, 0, NULL, NULL, 0, NULL } }; mib2nut_info_t emerson_avocent_pdu = { "emerson_avocent_pdu", EMERSON_AVOCENT_MIB_VERSION, NULL, EMERSON_AVOCENT_OID_MODEL_NAME, emerson_avocent_pdu_mib, EMERSON_AVOCENT_SYSOID, NULL }; nut-2.8.1/drivers/nutdrv_qx_hunnox.h0000644000175000017500000000202714500336654014540 00000000000000/* nutdrv_qx_hunnox.h - Subdriver for Hunnox protocol based UPSes * * Copyright (C) * 2013 Daniele Pezzini * 2020 Mariano Jan https://marianojan.com * * 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 2 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, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #ifndef NUTDRV_QX_HUNNOX_H #define NUTDRV_QX_HUNNOX_H #include "nutdrv_qx.h" extern subdriver_t hunnox_subdriver; #endif /* NUTDRV_QX_HUNNOX_H */ nut-2.8.1/drivers/powerp-txt.h0000644000175000017500000000205214500336654013236 00000000000000/* * powerp-txt.h - Model specific data/definitions for CyberPower text * protocol UPSes * * Copyright (C) * 2007 Doug Reynolds * 2007-2008 Arjen de Korte * * 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 2 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, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef POWERP_TXT_H #define POWERP_TXT_H #include "powerpanel.h" extern subdriver_t powpan_text; #endif nut-2.8.1/drivers/phoenixcontact_modbus.c0000644000175000017500000001156114502253356015503 00000000000000/* phoenixcontact_modbus.c - Driver for PhoenixContact-QUINT UPS * * Copyright (C) * 2017 Spiros Ioannou * * 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 2 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, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #include "main.h" #include #define DRIVER_NAME "NUT PhoenixContact Modbus driver" #define DRIVER_VERSION "0.03" #define CHECK_BIT(var,pos) ((var) & (1<<(pos))) #define MODBUS_SLAVE_ID 192 /* Variables */ static modbus_t *modbus_ctx = NULL; static int errcount = 0; static int mrir(modbus_t * arg_ctx, int addr, int nb, uint16_t * dest); /* driver description structure */ upsdrv_info_t upsdrv_info = { DRIVER_NAME, DRIVER_VERSION, "Spiros Ioannou \n", DRV_BETA, {NULL} }; void upsdrv_initinfo(void) { upsdebugx(2, "upsdrv_initinfo"); dstate_setinfo("device.mfr", "Phoenix Contact"); dstate_setinfo("device.model", "QUINT-UPS/24DC"); /* upsh.instcmd = instcmd; */ /* upsh.setvar = setvar; */ } void upsdrv_updateinfo(void) { uint16_t tab_reg[64]; errcount = 0; upsdebugx(2, "upsdrv_updateinfo"); mrir(modbus_ctx, 29697, 3, tab_reg); status_init(); if (tab_reg[0]) status_set("OB"); else status_set("OL"); if (tab_reg[2]) { status_set("CHRG"); } if (tab_reg[1]) { status_set("LB"); /* LB is actually called "shutdown event" on this ups */ } mrir(modbus_ctx, 29745, 1, tab_reg); dstate_setinfo("output.voltage", "%d", (int) (tab_reg[0] / 1000)); mrir(modbus_ctx, 29749, 5, tab_reg); dstate_setinfo("battery.charge", "%d", tab_reg[0]); /* dstate_setinfo("battery.runtime",tab_reg[1]*60); */ /* also reported on this address, but less accurately */ mrir(modbus_ctx, 29792, 10, tab_reg); dstate_setinfo("battery.voltage", "%f", (double) (tab_reg[0]) / 1000.0); dstate_setinfo("battery.temperature", "%d", tab_reg[1] - 273); dstate_setinfo("battery.runtime", "%d", tab_reg[3]); dstate_setinfo("battery.capacity", "%d", tab_reg[8] * 10); dstate_setinfo("output.current", "%f", (double) (tab_reg[6]) / 1000.0); /* ALARMS */ mrir(modbus_ctx, 29840, 1, tab_reg); alarm_init(); if (CHECK_BIT(tab_reg[0], 4) && CHECK_BIT(tab_reg[0], 5)) alarm_set("End of life (Resistance)"); if (CHECK_BIT(tab_reg[0], 6)) alarm_set("End of life (Time)"); if (CHECK_BIT(tab_reg[0], 7)) alarm_set("End of life (Voltage)"); if (CHECK_BIT(tab_reg[0], 9)) alarm_set("No Battery"); if (CHECK_BIT(tab_reg[0], 10)) alarm_set("Inconsistent technology"); if (CHECK_BIT(tab_reg[0], 11)) alarm_set("Overload Cutoff"); /* We don't use those low-battery indicators below. * No info or configuration exists for those alarm low-bat */ if (CHECK_BIT(tab_reg[0], 12)) alarm_set("Low Battery (Voltage)"); if (CHECK_BIT(tab_reg[0], 13)) alarm_set("Low Battery (Charge)"); if (CHECK_BIT(tab_reg[0], 14)) alarm_set("Low Battery (Time)"); if (CHECK_BIT(tab_reg[0], 16)) alarm_set("Low Battery (Service)"); if (errcount == 0) { alarm_commit(); status_commit(); dstate_dataok(); } else dstate_datastale(); } void upsdrv_shutdown(void) { /* replace with a proper shutdown function */ upslogx(LOG_ERR, "shutdown not supported"); set_exit_flag(-1); } void upsdrv_help(void) { } /* list flags and values that you want to receive via -x */ void upsdrv_makevartable(void) { } void upsdrv_initups(void) { int r; upsdebugx(2, "upsdrv_initups"); modbus_ctx = modbus_new_rtu(device_path, 115200, 'E', 8, 1); if (modbus_ctx == NULL) fatalx(EXIT_FAILURE, "Unable to create the libmodbus context"); r = modbus_set_slave(modbus_ctx, MODBUS_SLAVE_ID); /* slave ID */ if (r < 0) { modbus_free(modbus_ctx); fatalx(EXIT_FAILURE, "Invalid modbus slave ID %d",MODBUS_SLAVE_ID); } if (modbus_connect(modbus_ctx) == -1) { modbus_free(modbus_ctx); fatalx(EXIT_FAILURE, "modbus_connect: unable to connect: %s", modbus_strerror(errno)); } } void upsdrv_cleanup(void) { if (modbus_ctx != NULL) { modbus_close(modbus_ctx); modbus_free(modbus_ctx); } } /* Modbus Read Input Registers */ static int mrir(modbus_t * arg_ctx, int addr, int nb, uint16_t * dest) { int r; r = modbus_read_input_registers(arg_ctx, addr, nb, dest); if (r == -1) { upslogx(LOG_ERR, "mrir: modbus_read_input_registers(addr:%d, count:%d): %s (%s)", addr, nb, modbus_strerror(errno), device_path); errcount++; } return r; } nut-2.8.1/drivers/apcsmart-old.c0000644000175000017500000010524314516530040013464 00000000000000/* apcsmart.c - driver for APC smart protocol units (originally "newapc") Copyright (C) 1999 Russell Kroll (C) 2000 Nigel Metheringham 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 2 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, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "main.h" #include "serial.h" #include "apcsmart-old.h" #include "nut_stdint.h" #define DRIVER_NAME "APC Smart protocol driver (old)" #define DRIVER_VERSION "2.32" static upsdrv_info_t table_info = { "APC command table", APC_TABLE_VERSION, NULL, 0, { NULL } }; /* driver description structure */ upsdrv_info_t upsdrv_info = { DRIVER_NAME, DRIVER_VERSION, "Russell Kroll \n" "Nigel Metheringham \n" "Michal Soltys ", DRV_STABLE, { &table_info, NULL } }; #define ALT_CABLE_1 "940-0095B" static int ups_status = 0, quirk_capability_overflow = 0; static apc_vartab_t *vartab_lookup_char(char cmdchar) { int i; for (i = 0; apc_vartab[i].name != NULL; i++) if (apc_vartab[i].cmd == cmdchar) return &apc_vartab[i]; return NULL; } static apc_vartab_t *vartab_lookup_name(const char *var) { int i; for (i = 0; apc_vartab[i].name != NULL; i++) if (!strcasecmp(apc_vartab[i].name, var)) return &apc_vartab[i]; return NULL; } /* FUTURE: change to use function pointers */ /* convert APC formatting to NUT formatting */ static const char *convert_data(apc_vartab_t *cmd_entry, const char *upsval) { static char tmp[128]; long tval; switch(cmd_entry->flags & APC_FORMATMASK) { case APC_F_PERCENT: case APC_F_VOLT: case APC_F_AMP: case APC_F_CELSIUS: case APC_F_HEX: case APC_F_DEC: case APC_F_SECONDS: case APC_F_LEAVE: /* no conversion for any of these */ return upsval; case APC_F_HOURS: /* convert to seconds */ tval = 60 * 60 * strtol(upsval, NULL, 10); snprintf(tmp, sizeof(tmp), "%ld", tval); return tmp; case APC_F_MINUTES: /* Convert to seconds - NUT standard time measurement */ tval = 60 * strtol(upsval, NULL, 10); /* Ignore errors - Theres not much we can do */ snprintf(tmp, sizeof(tmp), "%ld", tval); return tmp; case APC_F_REASON: switch (upsval[0]) { case 'R': return "unacceptable utility voltage rate of change"; case 'H': return "high utility voltage"; case 'L': return "low utility voltage"; case 'T': return "line voltage notch or spike"; case 'O': return "no transfers yet since turnon"; case 'S': return "simulated power failure or UPS test"; default: return upsval; } } upslogx(LOG_NOTICE, "Unable to handle conversion of %s", cmd_entry->name); return upsval; } static void ups_status_set(void) { status_init(); if (ups_status & APC_STAT_CAL) status_set("CAL"); /* calibration */ if (ups_status & APC_STAT_TRIM) status_set("TRIM"); /* SmartTrim */ if (ups_status & APC_STAT_BOOST) status_set("BOOST"); /* SmartBoost */ if (ups_status & APC_STAT_OL) status_set("OL"); /* on line */ if (ups_status & APC_STAT_OB) status_set("OB"); /* on battery */ if (ups_status & APC_STAT_OVER) status_set("OVER"); /* overload */ if (ups_status & APC_STAT_LB) status_set("LB"); /* low battery */ if (ups_status & APC_STAT_RB) status_set("RB"); /* replace batt */ if (ups_status == 0) status_set("OFF"); status_commit(); } static void alert_handler(char ch) { switch (ch) { case '!': /* clear OL, set OB */ upsdebugx(4, "alert_handler: OB"); ups_status &= ~APC_STAT_OL; ups_status |= APC_STAT_OB; break; case '$': /* clear OB, set OL */ upsdebugx(4, "alert_handler: OL"); ups_status &= ~APC_STAT_OB; ups_status |= APC_STAT_OL; break; case '%': /* set LB */ upsdebugx(4, "alert_handler: LB"); ups_status |= APC_STAT_LB; break; case '+': /* clear LB */ upsdebugx(4, "alert_handler: not LB"); ups_status &= ~APC_STAT_LB; break; case '#': /* set RB */ upsdebugx(4, "alert_handler: RB"); ups_status |= APC_STAT_RB; break; case '?': /* set OVER */ upsdebugx(4, "alert_handler: OVER"); ups_status |= APC_STAT_OVER; break; case '=': /* clear OVER */ upsdebugx(4, "alert_handler: not OVER"); ups_status &= ~APC_STAT_OVER; break; default: upsdebugx(4, "alert_handler got 0x%02x (unhandled)", ch); break; } ups_status_set(); } static ssize_t read_buf(char *buf, size_t buflen) { ssize_t ret; ret = ser_get_line_alert(upsfd, buf, buflen, ENDCHAR, POLL_IGNORE, POLL_ALERT, alert_handler, SER_WAIT_SEC, SER_WAIT_USEC); if (ret < 1) { ser_comm_fail("%s", ret ? strerror(errno) : "timeout"); return ret; } ser_comm_good(); return ret; } static ssize_t poll_data(apc_vartab_t *vt) { ssize_t ret; char tmp[SMALLBUF]; if ((vt->flags & APC_PRESENT) == 0) return 1; upsdebugx(4, "poll_data: %s", vt->name); ret = ser_send_char(upsfd, vt->cmd); if (ret != 1) { upslogx(LOG_ERR, "poll_data: ser_send_char failed"); dstate_datastale(); return 0; } if (read_buf(tmp, sizeof(tmp)) < 1) { dstate_datastale(); return 0; } /* no longer supported by the hardware somehow */ if (!strcmp(tmp, "NA")) { dstate_delinfo(vt->name); return 1; } dstate_setinfo(vt->name, "%s", convert_data(vt, tmp)); dstate_dataok(); return 1; } /* check for support or just update a named variable */ static int query_ups(const char *var, int first) { ssize_t ret; char temp[256]; const char *ptr; apc_vartab_t *vt; vt = vartab_lookup_name(var); if (!vt) { upsdebugx(1, "query_ups: unknown variable %s", var); return 0; } /* * not first run and already known to not be supported ? */ if (!first && !(vt->flags & APC_PRESENT)) return 0; /* empty the input buffer (while allowing the alert handler to run) */ ret = ser_get_line_alert(upsfd, temp, sizeof(temp), ENDCHAR, POLL_IGNORE, POLL_ALERT, alert_handler, 0, 0); ret = ser_send_char(upsfd, vt->cmd); if (ret != 1) { upslog_with_errno(LOG_ERR, "query_ups: ser_send_char failed"); return 0; } ret = ser_get_line_alert(upsfd, temp, sizeof(temp), ENDCHAR, POLL_IGNORE, POLL_ALERT, alert_handler, SER_WAIT_SEC, SER_WAIT_USEC); if ((ret < 1) && (first == 0)) { ser_comm_fail("%s", ret ? strerror(errno) : "timeout"); return 0; } ser_comm_good(); if ((ret < 1) || (!strcmp(temp, "NA"))) /* not supported */ return 0; vt->flags |= APC_PRESENT; ptr = convert_data(vt, temp); dstate_setinfo(vt->name, "%s", ptr); return 1; /* success */ } static void do_capabilities(void) { const char *ptr, *entptr; char upsloc, temp[512], cmd, loc, etmp[16], *endtemp; int matrix, valid; size_t i, nument, entlen; ssize_t ret; apc_vartab_t *vt; upsdebugx(1, "APC - About to get capabilities string"); /* If we can do caps, then we need the Firmware revision which has the locale descriptor as the last character (ugh) */ ptr = dstate_getinfo("ups.firmware"); if (ptr) upsloc = ptr[strlen(ptr) - 1]; else upsloc = 0; /* get capability string */ ret = ser_send_char(upsfd, APC_CAPABILITY); /* ^Z */ if (ret != 1) { upslog_with_errno(LOG_ERR, "do_capabilities: ser_send_char failed"); return; } /* note different IGN set since ^Z returns things like # */ ret = ser_get_line(upsfd, temp, sizeof(temp), ENDCHAR, MINIGNCHARS, SER_WAIT_SEC, SER_WAIT_USEC); if ((ret < 1) || (!strcmp(temp, "NA"))) { /* Early Smart-UPS, not as smart as later ones */ /* This should never happen since we only call this if the REQ_CAPABILITIES command is supported */ upslogx(LOG_ERR, "ERROR: APC cannot do capabilities but said it could!"); return; } /* recv always puts a \0 at the end, so this is safe */ /* however it assumes a zero byte cannot be embedded */ endtemp = &temp[0] + strlen(temp); if (temp[0] != '#') { upsdebugx(1, "Unrecognized capability start char %c", temp[0]); upsdebugx(1, "Please report this error [%s]", temp); upslogx(LOG_ERR, "ERROR: unknown capability start char %c!", temp[0]); return; } if (temp[1] == '#') { /* Matrix-UPS */ matrix = 1; ptr = &temp[0]; } else { ptr = &temp[1]; matrix = 0; } /* command char, location, # of entries, entry length */ while (ptr[0] != '\0') { if (matrix) ptr += 2; /* jump over repeating ## */ /* check for idiocy */ if (ptr >= endtemp) { /* if we expected this, just ignore it */ if (quirk_capability_overflow) return; fatalx(EXIT_FAILURE, "Capability string has overflowed\n" "Please report this error with device details\n" "ERROR: capability overflow!" ); } entptr = &ptr[4]; cmd = ptr[0]; loc = ptr[1]; if (ptr[2] < 48 || ptr[3] < 48) { upsdebugx(3, "%s: SKIP: nument (%d) or entlen (%d) " "out of range for cmd %d at loc %d", __func__, (ptr[2] - 48), (ptr[3] - 48), cmd, loc); /* just ignore it as we did for ages see e.g. v2.7.4 * (note the next loop cycle was and still would be * no-op anyway, if "nument <= 0"). */ nument = 0; entlen = 0; /* NOT a full skip: Gotta handle "vt" to act like before */ /*ptr = entptr;*/ /*continue;*/ } else { nument = (size_t)ptr[2] - 48; entlen = (size_t)ptr[3] - 48; } vt = vartab_lookup_char(cmd); valid = vt && ((loc == upsloc) || (loc == '4')); /* mark this as writable */ if (valid) { upsdebugx(1, "Supported capability: %02x (%c) - %s", cmd, loc, vt->name); dstate_setflags(vt->name, ST_FLAG_RW); /* make sure setvar knows what this is */ vt->flags |= APC_RW | APC_ENUM; } for (i = 0; i < nument; i++) { if (valid) { snprintf(etmp, entlen + 1, "%s", entptr); dstate_addenum(vt->name, "%s", convert_data(vt, etmp)); } entptr += entlen; } ptr = entptr; } } static int update_status(void) { ssize_t ret; char buf[SMALLBUF]; upsdebugx(4, "update_status"); ser_flush_in(upsfd, IGNCHARS, nut_debug_level); ret = ser_send_char(upsfd, APC_STATUS); if (ret != 1) { upslog_with_errno(LOG_ERR, "update_status: ser_send_char failed"); dstate_datastale(); return 0; } ret = read_buf(buf, sizeof(buf)); if ((ret < 1) || (!strcmp(buf, "NA"))) { dstate_datastale(); return 0; } ups_status = strtol(buf, 0, 16) & 0xff; ups_status_set(); dstate_dataok(); return 1; } static void oldapcsetup(void) { ssize_t ret = 0; /* really old models ignore REQ_MODEL, so find them first */ ret = query_ups("ups.model", 1); if (ret != 1) { /* force the model name */ dstate_setinfo("ups.model", "Smart-UPS"); } /* see if this might be an old Matrix-UPS instead */ if (query_ups("output.current", 1)) dstate_setinfo("ups.model", "Matrix-UPS"); query_ups("ups.serial", 1); query_ups("input.voltage", 1); /* This one may fail... no problem */ update_status(); /* If we have come down this path then we dont do capabilities and other shiny features */ } static void protocol_verify(unsigned char cmd) { int i, found; /* see if it's a variable */ for (i = 0; apc_vartab[i].name != NULL; i++) { /* 1:1 here, so the first match is the only match */ if (apc_vartab[i].cmd == cmd) { upsdebugx(3, "UPS supports variable [%s]", apc_vartab[i].name); /* load initial data */ apc_vartab[i].flags |= APC_PRESENT; poll_data(&apc_vartab[i]); /* handle special data for our two strings */ if (apc_vartab[i].flags & APC_STRING) { dstate_setflags(apc_vartab[i].name, ST_FLAG_RW | ST_FLAG_STRING); dstate_setaux(apc_vartab[i].name, APC_STRLEN); apc_vartab[i].flags |= APC_RW; } return; } } /* check the command list */ /* some cmdchars map onto multiple commands (start and stop) */ found = 0; for (i = 0; apc_cmdtab[i].name != NULL; i++) { if (apc_cmdtab[i].cmd == cmd) { upsdebugx(2, "UPS supports command [%s]", apc_cmdtab[i].name); dstate_addcmd(apc_cmdtab[i].name); apc_cmdtab[i].flags |= APC_PRESENT; found = 1; } } if (found) return; if (isprint((size_t)cmd)) upsdebugx(1, "protocol_verify: 0x%02x [%c] unrecognized", cmd, cmd); else upsdebugx(1, "protocol_verify: 0x%02x unrecognized", cmd); } /* some hardware is a special case - hotwire the list of cmdchars */ static int firmware_table_lookup(void) { ssize_t ret; unsigned int i, j; char buf[SMALLBUF]; upsdebugx(1, "Attempting firmware lookup using command 'V'"); ret = ser_send_char(upsfd, 'V'); if (ret != 1) { upslog_with_errno(LOG_ERR, "firmware_table_lookup: ser_send_char failed"); return 0; } ret = ser_get_line(upsfd, buf, sizeof(buf), ENDCHAR, IGNCHARS, SER_WAIT_SEC, SER_WAIT_USEC); /* * Some UPSes support both 'V' and 'b'. As 'b' doesn't always return * firmware version, we attempt that only if 'V' doesn't work. */ if ((ret < 1) || (!strcmp(buf, "NA"))) { upsdebugx(1, "Attempting firmware lookup using command 'b'"); ret = ser_send_char(upsfd, 'b'); if (ret != 1) { upslog_with_errno(LOG_ERR, "firmware_table_lookup: ser_send_char failed"); return 0; } ret = ser_get_line(upsfd, buf, sizeof(buf), ENDCHAR, IGNCHARS, SER_WAIT_SEC, SER_WAIT_USEC); if (ret < 1) { upslog_with_errno(LOG_ERR, "firmware_table_lookup: ser_get_line failed"); return 0; } } upsdebugx(2, "Firmware: [%s]", buf); /* this will be reworked if we get a lot of these things */ if (!strcmp(buf, "451.2.I")) { quirk_capability_overflow = 1; return 0; } for (i = 0; compat_tab[i].firmware != NULL; i++) { if (!strcmp(compat_tab[i].firmware, buf)) { upsdebugx(2, "Matched - cmdchars: %s", compat_tab[i].cmdchars); if (strspn(compat_tab[i].firmware, "05")) { dstate_setinfo("ups.model", "Matrix-UPS"); } else { dstate_setinfo("ups.model", "Smart-UPS"); } /* matched - run the cmdchars from the table */ for (j = 0; j < strlen(compat_tab[i].cmdchars); j++) protocol_verify((const unsigned char)(compat_tab[i].cmdchars[j])); return 1; /* matched */ } } upsdebugx(2, "Not found in table - trying normal method"); return 0; } static void getbaseinfo(void) { unsigned int i; ssize_t ret = 0; char *alrts, temp[512]; unsigned char *cmds; /* * try firmware lookup first; we could start with 'a', but older models * sometimes return other things than a command set */ if (firmware_table_lookup() == 1) return; upsdebugx(1, "APC - Attempting to find command set"); /* Initially we ask the UPS what commands it takes If this fails we are going to need an alternate strategy - we can deal with that if it happens */ ret = ser_send_char(upsfd, APC_CMDSET); if (ret != 1) { upslog_with_errno(LOG_ERR, "getbaseinfo: ser_send_char failed"); return; } ret = ser_get_line(upsfd, temp, sizeof(temp), ENDCHAR, IGNCHARS, SER_WAIT_SEC, SER_WAIT_USEC); if ((ret < 1) || (!strcmp(temp, "NA"))) { /* We have an old dumb UPS - go to specific code for old stuff */ oldapcsetup(); return; } upsdebugx(1, "APC - Parsing out command set"); /* We have the version.alert.cmdchars string NB the alert chars are normally in IGNCHARS so will have been pretty much edited out. You will need to change the ser_get_line above if you want to check those out too.... */ alrts = strchr(temp, '.'); if (alrts == NULL) { fatalx(EXIT_FAILURE, "Unable to split APC version string"); } *alrts++ = 0; cmds = (unsigned char*)strchr(alrts, '.'); if (cmds == NULL) { fatalx(EXIT_FAILURE, "Unable to find APC command string"); } *cmds++ = 0; for (i = 0; i < strlen((char *)cmds); i++) protocol_verify(cmds[i]); /* if capabilities are supported, add them here */ if (strchr((char *)cmds, APC_CAPABILITY)) do_capabilities(); upsdebugx(1, "APC - UPS capabilities determined"); } /* check for calibration status and either start or stop */ static int do_cal(int start) { char temp[256]; long tval; ssize_t ret; ret = ser_send_char(upsfd, APC_STATUS); if (ret != 1) { upslog_with_errno(LOG_ERR, "do_cal: ser_send_char failed"); return STAT_INSTCMD_HANDLED; /* FUTURE: failure */ } ret = read_buf(temp, sizeof(temp)); /* if we can't check the current calibration status, bail out */ if ((ret < 1) || (!strcmp(temp, "NA"))) return STAT_INSTCMD_HANDLED; /* FUTURE: failure */ tval = strtol(temp, 0, 16); if (tval & APC_STAT_CAL) { /* calibration currently happening */ if (start == 1) { /* requested start while calibration still running */ upslogx(LOG_INFO, "Runtime calibration already in progress"); return STAT_INSTCMD_HANDLED; /* FUTURE: failure */ } /* stop requested */ upslogx(LOG_INFO, "Stopping runtime calibration"); ret = ser_send_char(upsfd, APC_CMD_CALTOGGLE); if (ret != 1) { upslog_with_errno(LOG_ERR, "do_cal: ser_send_char failed"); return STAT_INSTCMD_HANDLED; /* FUTURE: failure */ } ret = read_buf(temp, sizeof(temp)); if ((ret < 1) || (!strcmp(temp, "NA")) || (!strcmp(temp, "NO"))) { upslogx(LOG_WARNING, "Stop calibration failed: %s", temp); return STAT_INSTCMD_HANDLED; /* FUTURE: failure */ } return STAT_INSTCMD_HANDLED; /* FUTURE: success */ } /* calibration not happening */ if (start == 0) { /* stop requested */ upslogx(LOG_INFO, "Runtime calibration not occurring"); return STAT_INSTCMD_HANDLED; /* FUTURE: failure */ } upslogx(LOG_INFO, "Starting runtime calibration"); ret = ser_send_char(upsfd, APC_CMD_CALTOGGLE); if (ret != 1) { upslog_with_errno(LOG_ERR, "do_cal: ser_send_char failed"); return STAT_INSTCMD_HANDLED; /* FUTURE: failure */ } ret = read_buf(temp, sizeof(temp)); if ((ret < 1) || (!strcmp(temp, "NA")) || (!strcmp(temp, "NO"))) { upslogx(LOG_WARNING, "Start calibration failed: %s", temp); return STAT_INSTCMD_HANDLED; /* FUTURE: failure */ } return STAT_INSTCMD_HANDLED; /* FUTURE: success */ } /* get the UPS talking to us in smart mode */ static int smartmode(void) { ssize_t ret; int tries; char temp[256]; for (tries = 0; tries < 5; tries++) { ret = ser_send_char(upsfd, APC_GOSMART); if (ret != 1) { upslog_with_errno(LOG_ERR, "smartmode: ser_send_char failed"); return 0; } ret = ser_get_line(upsfd, temp, sizeof(temp), ENDCHAR, IGNCHARS, SER_WAIT_SEC, SER_WAIT_USEC); if (ret > 0) if (!strcmp(temp, "SM")) return 1; /* success */ sleep(1); /* wait before trying again */ /* it failed, so try to bail out of menus on newer units */ ret = ser_send_char(upsfd, 27); /* ESC */ if (ret != 1) { upslog_with_errno(LOG_ERR, "smartmode: ser_send_char failed"); return 0; } /* eat the response (might be NA, might be something else) */ ret = ser_get_line(upsfd, temp, sizeof(temp), ENDCHAR, IGNCHARS, SER_WAIT_SEC, SER_WAIT_USEC); } return 0; /* failure */ } /* * all shutdown commands should respond with 'OK' or '*' */ static long sdok(void) { char temp[16]; ser_get_line(upsfd, temp, sizeof(temp), ENDCHAR, IGNCHARS, SER_WAIT_SEC, SER_WAIT_USEC); upsdebugx(4, "sdok: got \"%s\"", temp); if (!strcmp(temp, "*") || !strcmp(temp, "OK")) { upsdebugx(4, "Last issued shutdown command succeeded"); return 1; } upsdebugx(1, "Last issued shutdown command failed"); return 0; } /* soft hibernate: S - working only when OB, otherwise ignored */ static long sdcmd_S(long dummy) { NUT_UNUSED_VARIABLE(dummy); ser_flush_in(upsfd, IGNCHARS, nut_debug_level); upsdebugx(1, "Issuing soft hibernate"); ser_send_char(upsfd, APC_CMD_SOFTDOWN); return sdok(); } /* soft hibernate, hack version for CS 350 */ static long sdcmd_CS(long tval) { upsdebugx(1, "Using CS 350 'force OB' shutdown method"); if (tval & APC_STAT_OL) { upsdebugx(1, "On-line - forcing OB temporarily"); ser_send_char(upsfd, 'U'); usleep(UPSDELAY); } return sdcmd_S(tval); } /* * hard hibernate: @nnn / @nn * note: works differently for older and new models, see help function for * detailed info */ static long sdcmd_ATn(long cnt) { long n = 0; long mmax, ret; const char *strval; char timer[4]; mmax = cnt == 2 ? 99 : 999; if ((strval = getval("wugrace"))) { errno = 0; n = strtol(strval, NULL, 10); if (errno || n < 0 || n > mmax) n = 0; } if (cnt > INT_MAX || cnt < 0) { fatalx(EXIT_FAILURE, "Error: %s: cnt (%ld) is out of range", __func__, cnt); } snprintf(timer, sizeof(timer), "%.*ld", (int)cnt, n); ser_flush_in(upsfd, IGNCHARS, nut_debug_level); upsdebugx(1, "Issuing hard hibernate with %ld minutes additional wakeup delay", n*6); ser_send_char(upsfd, APC_CMD_GRACEDOWN); usleep(CMDLONGDELAY); ser_send_pace(upsfd, UPSDELAY, "%s", timer); ret = sdok(); if (ret || cnt == 3) return ret; /* * "tricky" part - we tried @nn variation and it (unsurprisingly) * failed; we have to abort the sequence with something bogus to have * the clean state; newer upses will respond with 'NO', older will be * silent (YMMV); */ ser_send_char(upsfd, APC_CMD_GRACEDOWN); usleep(UPSDELAY); ser_flush_in(upsfd, IGNCHARS, nut_debug_level); return 0; } /* shutdown: K - delayed poweroff */ static long sdcmd_K(long dummy) { NUT_UNUSED_VARIABLE(dummy); ser_flush_in(upsfd, IGNCHARS, nut_debug_level); upsdebugx(1, "Issuing delayed poweroff"); ser_send_char(upsfd, APC_CMD_SHUTDOWN); usleep(CMDLONGDELAY); ser_send_char(upsfd, APC_CMD_SHUTDOWN); return sdok(); } /* shutdown: Z - immediate poweroff */ static long sdcmd_Z(long dummy) { NUT_UNUSED_VARIABLE(dummy); ser_flush_in(upsfd, IGNCHARS, nut_debug_level); upsdebugx(1, "Issuing immediate poweroff"); ser_send_char(upsfd, APC_CMD_OFF); usleep(CMDLONGDELAY); ser_send_char(upsfd, APC_CMD_OFF); return sdok(); } static long (*sdlist[])(long) = { sdcmd_S, sdcmd_ATn, /* for @nnn version */ sdcmd_K, sdcmd_Z, sdcmd_CS, sdcmd_ATn, /* for @nn version */ }; #define SDIDX_S 0 #define SDIDX_AT3N 1 #define SDIDX_K 2 #define SDIDX_Z 3 #define SDIDX_CS 4 #define SDIDX_AT2N 5 #define SDCNT 6 static void upsdrv_shutdown_simple(long status) { long sdtype = 0; char *strval; if ((strval = getval("sdtype"))) { errno = 0; sdtype = strtol(strval, NULL, 10); if (errno || sdtype < 0 || sdtype > 6) sdtype = 0; } switch (sdtype) { case 6: /* hard hibernate */ sdcmd_ATn(3); break; case 5: /* "hack nn" hard hibernate */ sdcmd_ATn(2); break; case 4: /* special hack for CS 350 and similar models */ sdcmd_CS(status); break; case 3: /* delayed poweroff */ sdcmd_K(0); break; case 2: /* instant poweroff */ sdcmd_Z(0); break; case 1: /* * Send a combined set of shutdown commands which can work * better if the UPS gets power during shutdown process * Specifically it sends both the soft shutdown 'S' and the * hard hibernate '@nnn' commands */ upsdebugx(1, "UPS - currently %s - sending soft/hard hibernate commands", (status & APC_STAT_OL) ? "on-line" : "on battery"); /* S works only when OB */ if ((status & APC_STAT_OB) && sdcmd_S(0)) break; sdcmd_ATn(3); break; default: /* * Send @nnn or S, depending on OB / OL status */ if (status & APC_STAT_OL) /* on line */ sdcmd_ATn(3); else sdcmd_S(0); } } static void upsdrv_shutdown_advanced(long status) { const char *strval; const char deforder[] = {48 + SDIDX_S, 48 + SDIDX_AT3N, 48 + SDIDX_K, 48 + SDIDX_Z, 0}; size_t i; long n; strval = getval("advorder"); /* sanitize advorder */ if (!strval || !strlen(strval) || strlen(strval) > SDCNT) strval = deforder; for (i = 0; i < strlen(strval); i++) { if (strval[i] - 48 < 0 || strval[i] - 48 >= SDCNT) { strval = deforder; break; } } /* * try each method in the list with a little bit of handling in certain * cases */ for (i = 0; i < strlen(strval); i++) { switch (strval[i] - 48) { case SDIDX_CS: n = status; break; case SDIDX_AT3N: n = 3; break; case SDIDX_AT2N: default: n = 2; } if (sdlist[strval[i] - 48](n)) break; /* finish if command succeeded */ } } /* power down the attached load immediately */ void upsdrv_shutdown(void) { char temp[32]; ssize_t ret; long status; if (!smartmode()) upsdebugx(1, "SM detection failed. Trying a shutdown command anyway"); /* check the line status */ ret = ser_send_char(upsfd, APC_STATUS); if (ret == 1) { ret = ser_get_line(upsfd, temp, sizeof(temp), ENDCHAR, IGNCHARS, SER_WAIT_SEC, SER_WAIT_USEC); if (ret < 1) { upsdebugx(1, "Status read failed ! Assuming on battery state"); status = APC_STAT_LB | APC_STAT_OB; } else { status = strtol(temp, 0, 16); } } else { upsdebugx(1, "Status request failed; assuming on battery state"); status = APC_STAT_LB | APC_STAT_OB; } if (testvar("advorder") && strcasecmp(getval("advorder"), "no")) upsdrv_shutdown_advanced(status); else upsdrv_shutdown_simple(status); } /* 940-0095B support: set DTR, lower RTS */ static void init_serial_0095B(void) { ser_set_dtr(upsfd, 1); ser_set_rts(upsfd, 0); } static void update_info_normal(void) { size_t i; upsdebugx(3, "update_info_normal: starting"); for (i = 0; apc_vartab[i].name != NULL; i++) { if ((apc_vartab[i].flags & APC_POLL) == 0) continue; if (!poll_data(&apc_vartab[i])) { upsdebugx(3, "update_info_normal: poll_data (%s) failed - " "aborting scan", apc_vartab[i].name); return; } } upsdebugx(3, "update_info_normal: done"); } static void update_info_all(void) { size_t i; upsdebugx(3, "update_info_all: starting"); for (i = 0; apc_vartab[i].name != NULL; i++) { if (!poll_data(&apc_vartab[i])) { upsdebugx(3, "update_info_all: poll_data (%s) failed - " "aborting scan", apc_vartab[i].name); return; } } upsdebugx(3, "update_info_all: done"); } static int setvar_enum(apc_vartab_t *vt, const char *val) { int i; ssize_t ret; char orig[256], temp[256]; const char *ptr; ser_flush_in(upsfd, IGNCHARS, nut_debug_level); ret = ser_send_char(upsfd, vt->cmd); if (ret != 1) { upslog_with_errno(LOG_ERR, "setvar_enum: ser_send_char failed"); return STAT_SET_HANDLED; /* FUTURE: failed */ } ret = read_buf(orig, sizeof(orig)); if ((ret < 1) || (!strcmp(orig, "NA"))) return STAT_SET_HANDLED; /* FUTURE: failed */ ptr = convert_data(vt, orig); /* suppress redundant changes - easier on the eeprom */ if (!strcmp(ptr, val)) { upslogx(LOG_INFO, "Ignoring enum SET %s='%s' (unchanged value)", vt->name, val); return STAT_SET_HANDLED; /* FUTURE: no change */ } for (i = 0; i < 6; i++) { ret = ser_send_char(upsfd, APC_NEXTVAL); if (ret != 1) { upslog_with_errno(LOG_ERR, "setvar_enum: ser_send_char failed"); return STAT_SET_HANDLED; /* FUTURE: failed */ } /* this should return either OK (if rotated) or NO (if not) */ ret = read_buf(temp, sizeof(temp)); if ((ret < 1) || (!strcmp(temp, "NA"))) return STAT_SET_HANDLED; /* FUTURE: failed */ /* sanity checks */ if (!strcmp(temp, "NO")) return STAT_SET_HANDLED; /* FUTURE: failed */ if (strcmp(temp, "OK") != 0) return STAT_SET_HANDLED; /* FUTURE: failed */ /* see what it rotated onto */ ret = ser_send_char(upsfd, vt->cmd); if (ret != 1) { upslog_with_errno(LOG_ERR, "setvar_enum: ser_send_char failed"); return STAT_SET_HANDLED; /* FUTURE: failed */ } ret = read_buf(temp, sizeof(temp)); if ((ret < 1) || (!strcmp(temp, "NA"))) return STAT_SET_HANDLED; /* FUTURE: failed */ ptr = convert_data(vt, temp); upsdebugx(1, "Rotate value: got [%s], want [%s]", ptr, val); if (!strcmp(ptr, val)) { /* got it */ upslogx(LOG_INFO, "SET %s='%s'", vt->name, val); /* refresh data from the hardware */ query_ups(vt->name, 0); return STAT_SET_HANDLED; /* FUTURE: success */ } /* check for wraparound */ if (!strcmp(ptr, orig)) { upslogx(LOG_ERR, "setvar: variable %s wrapped", vt->name); return STAT_SET_HANDLED; /* FUTURE: failed */ } } upslogx(LOG_ERR, "setvar: gave up after 6 tries for %s", vt->name); /* refresh data from the hardware */ query_ups(vt->name, 0); return STAT_SET_HANDLED; } static int setvar_string(apc_vartab_t *vt, const char *val) { size_t i; ssize_t ret; char temp[256]; ser_flush_in(upsfd, IGNCHARS, nut_debug_level); ret = ser_send_char(upsfd, vt->cmd); if (ret != 1) { upslog_with_errno(LOG_ERR, "setvar_string: ser_send_char failed"); return STAT_SET_HANDLED; /* FUTURE: failed */ } ret = read_buf(temp, sizeof(temp)); if ((ret < 1) || (!strcmp(temp, "NA"))) return STAT_SET_HANDLED; /* FUTURE: failed */ /* suppress redundant changes - easier on the eeprom */ if (!strcmp(temp, val)) { upslogx(LOG_INFO, "Ignoring string SET %s='%s' (unchanged value)", vt->name, val); return STAT_SET_HANDLED; /* FUTURE: no change */ } ret = ser_send_char(upsfd, APC_NEXTVAL); if (ret != 1) { upslog_with_errno(LOG_ERR, "setvar_string: ser_send_char failed"); return STAT_SET_HANDLED; /* FUTURE: failed */ } usleep(UPSDELAY); for (i = 0; i < strlen(val); i++) { ret = ser_send_char(upsfd, (const unsigned char)(val[i])); if (ret != 1) { upslog_with_errno(LOG_ERR, "setvar_string: ser_send_char failed"); return STAT_SET_HANDLED; /* FUTURE: failed */ } usleep(UPSDELAY); } /* pad to 8 chars with CRs */ for (i = strlen(val); i < APC_STRLEN; i++) { ret = ser_send_char(upsfd, 13); if (ret != 1) { upslog_with_errno(LOG_ERR, "setvar_string: ser_send_char failed"); return STAT_SET_HANDLED; /* FUTURE: failed */ } usleep(UPSDELAY); } ret = read_buf(temp, sizeof(temp)); if (ret < 1) { upslogx(LOG_ERR, "setvar_string: short final read"); return STAT_SET_HANDLED; /* FUTURE: failed */ } if (!strcmp(temp, "NO")) { upslogx(LOG_ERR, "setvar_string: got NO at final read"); return STAT_SET_HANDLED; /* FUTURE: failed */ } /* refresh data from the hardware */ query_ups(vt->name, 0); upslogx(LOG_INFO, "SET %s='%s'", vt->name, val); return STAT_SET_HANDLED; /* FUTURE: failed */ } static int setvar(const char *varname, const char *val) { apc_vartab_t *vt; vt = vartab_lookup_name(varname); if (!vt) return STAT_SET_UNKNOWN; if ((vt->flags & APC_RW) == 0) { upslogx(LOG_WARNING, "setvar: [%s] is not writable", varname); return STAT_SET_UNKNOWN; } if (vt->flags & APC_ENUM) return setvar_enum(vt, val); if (vt->flags & APC_STRING) return setvar_string(vt, val); upslogx(LOG_WARNING, "setvar: Unknown type for [%s]", varname); return STAT_SET_UNKNOWN; } /* actually send the instcmd's char to the ups */ static int do_cmd(apc_cmdtab_t *ct) { ssize_t ret; char buf[SMALLBUF]; ser_flush_in(upsfd, IGNCHARS, nut_debug_level); ret = ser_send_char(upsfd, ct->cmd); if (ret != 1) { upslog_with_errno(LOG_ERR, "do_cmd: ser_send_char failed"); return STAT_INSTCMD_HANDLED; /* FUTURE: failed */ } /* some commands have to be sent twice with a 1.5s gap */ if (ct->flags & APC_REPEAT) { usleep(CMDLONGDELAY); ret = ser_send_char(upsfd, ct->cmd); if (ret != 1) { upslog_with_errno(LOG_ERR, "do_cmd: ser_send_char failed"); return STAT_INSTCMD_HANDLED; /* FUTURE: failed */ } } ret = read_buf(buf, sizeof(buf)); if (ret < 1) return STAT_INSTCMD_HANDLED; /* FUTURE: failed */ if (strcmp(buf, "OK") != 0) { upslogx(LOG_WARNING, "Got [%s] after command [%s]", buf, ct->name); return STAT_INSTCMD_HANDLED; /* FUTURE: failed */ } upslogx(LOG_INFO, "Command: %s", ct->name); return STAT_INSTCMD_HANDLED; /* FUTURE: success */ } /* some commands must be repeated in a window to execute */ static int instcmd_chktime(apc_cmdtab_t *ct) { double elapsed; time_t now; static time_t last = 0; time(&now); elapsed = difftime(now, last); last = now; /* you have to hit this in a small window or it fails */ if ((elapsed < MINCMDTIME) || (elapsed > MAXCMDTIME)) { upsdebugx(1, "instcmd_chktime: outside window for %s (%2.0f)", ct->name, elapsed); return STAT_INSTCMD_HANDLED; /* FUTURE: again */ } return do_cmd(ct); } static int instcmd(const char *cmdname, const char *extra) { int i; apc_cmdtab_t *ct; ct = NULL; for (i = 0; apc_cmdtab[i].name != NULL; i++) if (!strcasecmp(apc_cmdtab[i].name, cmdname)) ct = &apc_cmdtab[i]; if (!ct) { upslogx(LOG_WARNING, "instcmd: unknown command [%s] [%s]", cmdname, extra); return STAT_INSTCMD_UNKNOWN; } if ((ct->flags & APC_PRESENT) == 0) { upslogx(LOG_WARNING, "instcmd: command [%s] [%s] is not supported", cmdname, extra); return STAT_INSTCMD_UNKNOWN; } if (!strcasecmp(cmdname, "calibrate.start")) return do_cal(1); if (!strcasecmp(cmdname, "calibrate.stop")) return do_cal(0); if (ct->flags & APC_NASTY) return instcmd_chktime(ct); /* nothing special here */ return do_cmd(ct); } /* install pointers to functions for msg handlers called from msgparse */ static void setuphandlers(void) { upsh.setvar = setvar; upsh.instcmd = instcmd; } /* functions that interface with main.c */ void upsdrv_makevartable(void) { addvar(VAR_VALUE, "cable", "Specify alternate cable (940-0095B)"); addvar(VAR_VALUE, "wugrace", "Hard hibernate's wakeup grace"); addvar(VAR_VALUE, "sdtype", "Specify simple shutdown method (0-6)"); addvar(VAR_VALUE, "advorder", "Enable advanced shutdown control"); } void upsdrv_initups(void) { char *cable; upsfd = ser_open(device_path); ser_set_speed(upsfd, device_path, B2400); cable = getval("cable"); if (cable && !strcasecmp(cable, ALT_CABLE_1)) init_serial_0095B(); /* make sure we wake up if the UPS sends alert chars to us */ extrafd = upsfd; } void upsdrv_help(void) { } void upsdrv_initinfo(void) { const char *pmod, *pser; if (!smartmode()) { fatalx(EXIT_FAILURE, "Unable to detect an APC Smart protocol UPS on port %s\n" "Check the cabling, port name or model name and try again", device_path ); } /* manufacturer ID - hardcoded in this particular module */ dstate_setinfo("ups.mfr", "APC"); getbaseinfo(); if (!(pmod = dstate_getinfo("ups.model"))) pmod = "\"unknown model\""; if (!(pser = dstate_getinfo("ups.serial"))) pser = "unknown serial"; upsdebugx(1, "Detected %s [%s] on %s", pmod, pser, device_path); setuphandlers(); } void upsdrv_updateinfo(void) { static time_t last_full = 0; time_t now; /* try to wake up a dead ups once in awhile */ if ((dstate_is_stale()) && (!smartmode())) { ser_comm_fail("Communications with UPS lost - check cabling"); /* reset this so a full update runs when the UPS returns */ last_full = 0; return; } ser_comm_good(); if (!update_status()) return; time(&now); /* refresh all variables hourly */ /* does not catch measure-ups II insertion/removal */ if (difftime(now, last_full) > 3600) { last_full = now; update_info_all(); return; } update_info_normal(); } void upsdrv_cleanup(void) { /* try to bring the UPS out of smart mode */ ser_send_char(upsfd, APC_GODUMB); ser_close(upsfd, device_path); } nut-2.8.1/drivers/sms_ser.h0000644000175000017500000000664514514200703012562 00000000000000/* * sms_ser.h: defines/macros protocol for SMS Brazil UPSes * * Copyright (C) 2023 - Alex W. Baule * * 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 2 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, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * Reference of the derivative work: riello driver */ #ifndef NUT_SMS_SER_H_SEEN #define NUT_SMS_SER_H_SEEN 1 #include /* bool type */ #include "nut_stdint.h" #define DEFAULT_BOOTDELAY 64 /* seconds (max 0xFF) */ #define MAXTRIES 3 typedef struct { char model[25]; /* device.model */ char version[7]; /* ups.firmware */ char voltageRange[15]; /* garbage from sms (it's a string with some strange items) */ char currentRange[7]; /* garbage from sms (it's 000) maybe with some cleanup on string input.voltage.nominal */ uint8_t voltageBattery; /* battery.voltage.nominal (DeviceData.voltageBattery / 12 = battery.packs) */ uint8_t frequency; /* output.frequency.nominal */ bool beepon; /* ups.beeper.status */ bool shutdown; /* ups.status = FSD (the shutdown has started by another via) */ bool test; /* the UPS is testing the battery, need a status ? */ bool upsok; /* ups.status or battery.status ? (Maybe RB if is False ?) */ bool boost; /* ups.status = BOOST */ bool bypass; /* ups.status = BYPASS */ bool lowbattery; /* ups.status = LB (OL + LB or OB + LB ?) */ bool onbattery; /* ups.status = OB + battery.charger.status = discharging */ float lastinputVac; /* garbage ? always 000 */ float inputVac; /* input.voltage */ float outputVac; /* output.voltage */ float outputpower; /* ups.load */ float outputHz; /* output.frequency */ float batterylevel; /* battery.charge (batterylevel < 100 ? battery.charger.status = charging if onacpower/discharging if onbattery : resting) * battery.voltage = (voltageBattery * batterylevel) / 100) */ float temperatureC; /* ups.temperature */ } SmsData; void sms_parse_features(uint8_t *rawvalues, SmsData *results); void sms_parse_information(uint8_t *rawvalues, SmsData *results); void sms_parse_results(uint8_t* rawvalues, SmsData* results); uint8_t sms_prepare_get_status(uint8_t* buffer); uint8_t sms_prepare_get_information(uint8_t* buffer); uint8_t sms_prepare_get_features(uint8_t* buffer); uint8_t sms_prepare_set_beep(uint8_t* buffer); uint8_t sms_prepare_test_battery_low(uint8_t* buffer); uint8_t sms_prepare_test_battery_nsec(uint8_t* buffer, uint16_t delay); uint8_t sms_prepare_shutdown_nsec(uint8_t* buffer, uint16_t delay); uint8_t sms_prepare_shutdown_restore(uint8_t* buffer); uint8_t sms_prepare_cancel_test(uint8_t* buffer); uint8_t sms_prepare_cancel_shutdown(uint8_t* buffer); #endif /* NUT_SMS_SER_H_SEEN */ nut-2.8.1/drivers/eaton-ats30-mib.h0000644000175000017500000000203214377374134013715 00000000000000/* eaton_ats30-mib.h - subdriver to monitor eaton_ats30 SNMP devices with NUT * * Copyright (C) 2017 Eaton * Author: Tomas Halman * * 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 2 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, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef EATON_ATS30_MIB_H #define EATON_ATS30_MIB_H #include "main.h" #include "snmp-ups.h" extern mib2nut_info_t eaton_ats30; #endif /* EATON_ATS30_MIB_H */ nut-2.8.1/drivers/salicru-hid.c0000644000175000017500000004020114501607135013276 00000000000000/* salicru-hid.c - subdriver to monitor Salicru USB/HID devices with NUT * * Copyright (C) * 2003 - 2012 Arnaud Quette * 2005 - 2006 Peter Selinger * 2008 - 2009 Arjen de Korte * 2013 Charles Lepple * 2021 Francois Lacroix * 2022 Abel Gomez * * Note: this subdriver was initially generated as a "stub" by the * gen-usbhid-subdriver script. It must be customized. * * 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 2 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, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "config.h" /* must be first */ #include "usbhid-ups.h" #include "salicru-hid.h" #include "main.h" /* for getval() */ #include "usb-common.h" #define SALICRU_HID_VERSION "Salicru HID 0.4" /* FIXME: experimental flag to be put in upsdrv_info */ /* Salicru */ #define SALICRU_VENDORID 0x2e66 /* USB IDs device table */ static usb_device_id_t salicru_usb_device_table[] = { /* Salicru SPS 3000 ADV RT2 */ /* https://www.salicru.com/sps-3000-adv-rt2.html */ { USB_DEVICE(SALICRU_VENDORID, 0x0101), NULL }, /* TWINPRO3/TWINRT3 (SLC-1500-TWIN PRO3) per https://github.com/networkupstools/nut/issues/1142 */ /* SLC TWIN PRO2<=3KVA per https://github.com/networkupstools/nut/issues/450 */ { USB_DEVICE(SALICRU_VENDORID, 0x0201), NULL }, { USB_DEVICE(SALICRU_VENDORID, 0x0202), NULL }, { USB_DEVICE(SALICRU_VENDORID, 0x0203), NULL }, /* Salicru SPS 850 HOME per https://github.com/networkupstools/nut/pull/1199 */ /* https://www.salicru.com/sps-home.html */ { USB_DEVICE(SALICRU_VENDORID, 0x0300), NULL }, /* Salicru SPS 850 ADV T, see https://github.com/networkupstools/nut/issues/1416 */ /* https://www.salicru.com/sps-850-adv-t.html */ { USB_DEVICE(SALICRU_VENDORID, 0x0302), NULL }, /* Terminating entry */ { 0, 0, NULL } }; /* --------------------------------------------------------------- */ /* Vendor-specific usage table */ /* --------------------------------------------------------------- */ /* SALICRU usage table */ static usage_lkp_t salicru_usage_lkp[] = { { NULL, 0 } }; static usage_tables_t salicru_utab[] = { salicru_usage_lkp, hid_usage_lkp, NULL, }; /* --------------------------------------------------------------- */ /* HID2NUT lookup table */ /* --------------------------------------------------------------- */ static hid_info_t salicru_hid2nut[] = { #ifdef DEBUG { "experimental.ups.powersummary.imanufacturer", 0, 0, "UPS.PowerSummary.iManufacturer", NULL, "%.0f", 0, NULL }, { "experimental.ups.powersummary.iproduct", 0, 0, "UPS.PowerSummary.CapacityMode", NULL, "%.0f", 0, NULL }, { "experimental.ups.powersummary.iserialnumber", 0, 0, "UPS.PowerSummary.iSerialNumber", NULL, "%.0f", 0, NULL }, { "experimental.ups.powersummary.capacitymode", 0, 0, "UPS.PowerSummary.CapacityMode", NULL, "%.0f", 0, NULL }, { "experimental.ups.powersummary.rechargeable", 0, 0, "UPS.PowerSummary.Rechargeable", NULL, "%.0f", 0, NULL }, { "experimental.ups.powersummary.designcapacity", 0, 0, "UPS.PowerSummary.DesignCapacity", NULL, "%.0f", 0, NULL }, { "experimental.ups.powersummary.fullchargecapacity", 0, 0, "UPS.PowerSummary.FullChargeCapacity", NULL, "%.0f", 0, NULL }, #endif /* DEBUG */ /* A few more unknown fields 0.043266 [D1] Path: UPS.ff010004.ff010024.ff0100d0, Type: Feature, ReportID: 0x19, Offset: 0, Size: 8, Value: 0.1 0.043766 [D1] Path: UPS.ff010004.ff010024.ff0100d1, Type: Feature, ReportID: 0x1a, Offset: 0, Size: 8, Value: 0 0.044308 [D1] Path: UPS.ff01001d.ff010019.ff010020, Type: Feature, ReportID: 0x25, Offset: 0, Size: 1, Value: 0 0.044762 [D1] Path: UPS.ff01001d.ff010019.ff010021, Type: Feature, ReportID: 0x2c, Offset: 0, Size: 1, Value: 0 0.044891 [D1] Path: UPS.ff01001d.ff010019.ff010021, Type: Input, ReportID: 0x2c, Offset: 0, Size: 1, Value: 0 0.045386 [D1] Path: UPS.ff01001d.ff01001a.ff010001, Type: Feature, ReportID: 0x26, Offset: 0, Size: 1, Value: 0 0.045888 [D1] Path: UPS.ff01001d.ff01001a.ff010002, Type: Feature, ReportID: 0x27, Offset: 0, Size: 8, Value: 1 0.047553 [D2] libusb_get_report: error sending control message: Value too large for defined data type 0.047659 [D1] Can't retrieve Report 28: Value too large for defined data type 0.047796 [D1] Path: UPS.ff01001d.ff01001b.ff010040, Type: Feature, ReportID: 0x28, Offset: 0, Size: 8 0.048272 [D2] libusb_get_report: error sending control message: Value too large for defined data type 0.048403 [D1] Can't retrieve Report 28: Value too large for defined data type 0.048537 [D1] Path: UPS.ff01001d.ff01001b.ff010016, Type: Input, ReportID: 0x28, Offset: 0, Size: 8 0.049017 [D2] libusb_get_report: error sending control message: Value too large for defined data type 0.049147 [D1] Can't retrieve Report 28: Value too large for defined data type 0.049280 [D1] Path: UPS.ff01001d.ff01001b.ff010018, Type: Feature, ReportID: 0x28, Offset: 8, Size: 8 0.050944 [D2] libusb_get_report: error sending control message: Value too large for defined data type 0.051124 [D1] Can't retrieve Report 28: Value too large for defined data type 0.051264 [D1] Path: UPS.ff01001d.ff01001b.ff010018, Type: Input, ReportID: 0x28, Offset: 8, Size: 8 0.052965 [D2] libusb_get_report: error sending control message: Value too large for defined data type 0.053137 [D1] Can't retrieve Report 29: Value too large for defined data type 0.053277 [D1] Path: UPS.ff01001d.ff01001b.ff010015, Type: Feature, ReportID: 0x29, Offset: 0, Size: 8 0.053804 [D2] libusb_get_report: error sending control message: Value too large for defined data type 0.053954 [D1] Can't retrieve Report 29: Value too large for defined data type 0.054091 [D1] Path: UPS.ff01001d.ff01001b.ff010015, Type: Output, ReportID: 0x29, Offset: 0, Size: 8 0.054530 [D2] libusb_get_report: error sending control message: Value too large for defined data type 0.054664 [D1] Can't retrieve Report 29: Value too large for defined data type 0.054799 [D1] Path: UPS.ff01001d.ff01001b.ff010017, Type: Feature, ReportID: 0x29, Offset: 8, Size: 8 0.055285 [D2] libusb_get_report: error sending control message: Value too large for defined data type 0.055421 [D1] Can't retrieve Report 29: Value too large for defined data type 0.055557 [D1] Path: UPS.ff01001d.ff01001b.ff010017, Type: Output, ReportID: 0x29, Offset: 8, Size: 8 0.056130 [D2] libusb_get_report: error sending control message: Value too large for defined data type 0.056273 [D1] Can't retrieve Report 2d: Value too large for defined data type 0.056409 [D1] Path: UPS.ff01001d.ff01001b.ff010010, Type: Feature, ReportID: 0x2d, Offset: 0, Size: 1 0.056927 [D2] libusb_get_report: error sending control message: Value too large for defined data type 0.057074 [D1] Can't retrieve Report 2d: Value too large for defined data type 0.057211 [D1] Path: UPS.ff01001d.ff01001b.ff01001e, Type: Feature, ReportID: 0x2d, Offset: 1, Size: 1 0.057676 [D2] libusb_get_report: error sending control message: Value too large for defined data type 0.057825 [D1] Can't retrieve Report 2d: Value too large for defined data type 0.057962 [D1] Path: UPS.ff01001d.ff01001b.ff01001f, Type: Feature, ReportID: 0x2d, Offset: 2, Size: 1 0.058416 [D2] libusb_get_report: error sending control message: Value too large for defined data type 0.058551 [D1] Can't retrieve Report 2d: Value too large for defined data type 0.058685 [D1] Path: UPS.ff01001d.ff01001b.ff010010, Type: Input, ReportID: 0x2d, Offset: 0, Size: 1 0.059156 [D2] libusb_get_report: error sending control message: Value too large for defined data type 0.059291 [D1] Can't retrieve Report 2d: Value too large for defined data type 0.059426 [D1] Path: UPS.ff01001d.ff01001b.ff01001e, Type: Input, ReportID: 0x2d, Offset: 1, Size: 1 0.059957 [D2] libusb_get_report: error sending control message: Value too large for defined data type 0.060112 [D1] Can't retrieve Report 2d: Value too large for defined data type 0.060248 [D1] Path: UPS.ff01001d.ff01001b.ff01001f, Type: Input, ReportID: 0x2d, Offset: 2, Size: 1 0.061944 [D2] libusb_get_report: error sending control message: Value too large for defined data type 0.062117 [D1] Can't retrieve Report 2a: Value too large for defined data type 0.062256 [D1] Path: UPS.ff01001d.ff01001b.ff010013, Type: Feature, ReportID: 0x2a, Offset: 0, Size: 1 0.063941 [D2] libusb_get_report: error sending control message: Value too large for defined data type 0.064104 [D1] Can't retrieve Report 2b: Value too large for defined data type 0.064242 [D1] Path: UPS.ff01001d.ff01001b.ff010014, Type: Feature, ReportID: 0x2b, Offset: 0, Size: 1 */ /* Battery page */ { "battery.type", 0, 0, "UPS.PowerSummary.iDeviceChemistry", NULL, "%s", 0, stringid_conversion }, { "battery.charge", 0, 0, "UPS.PowerSummary.RemainingCapacity", NULL, "%.0f", 0, NULL }, { "battery.charge.warning", 0, 0, "UPS.PowerSummary.WarningCapacityLimit", NULL, "%.0f", 0, NULL }, { "battery.charge.low", ST_FLAG_RW | ST_FLAG_STRING, 10, "UPS.PowerSummary.RemainingCapacityLimit", NULL, "%.0f", HU_FLAG_SEMI_STATIC, NULL }, { "battery.runtime", 0, 0, "UPS.PowerSummary.RunTimeToEmpty", NULL, "%.0f", 0, NULL }, { "battery.runtime.low", ST_FLAG_RW | ST_FLAG_STRING, 10, "UPS.PowerSummary.RemainingTimeLimit", NULL, "%.0f", HU_FLAG_SEMI_STATIC, NULL }, { "battery.voltage.nominal", 0, 0, "UPS.PowerSummary.ConfigVoltage", NULL, "%.0f", 0, NULL }, { "battery.voltage", 0, 0, "UPS.PowerSummary.Voltage", NULL, "%.2f", 0, NULL }, /* UPS page */ { "ups.load", 0, 0, "UPS.Output.PercentLoad", NULL, "%.0f", 0, NULL }, { "ups.beeper.status", 0, 0, "UPS.PowerSummary.AudibleAlarmControl", NULL, "%s", 0, beeper_info }, { "ups.test.result", 0, 0, "UPS.Output.Test", NULL, "%s", 0, test_read_info }, { "ups.realpower.nominal", 0, 0, "UPS.Output.ConfigActivePower", NULL, "%.0f", 0, NULL }, /* Boolean value */ { "BOOL", 0, 0, "UPS.PowerSummary.PresentStatus.ACPresent", NULL, NULL, HU_FLAG_QUICK_POLL, online_info }, { "BOOL", 0, 0, "UPS.PowerSummary.PresentStatus.Charging", NULL, NULL, HU_FLAG_QUICK_POLL, charging_info }, { "BOOL", 0, 0, "UPS.PowerSummary.PresentStatus.Discharging", NULL, NULL, HU_FLAG_QUICK_POLL, discharging_info }, { "BOOL", 0, 0, "UPS.PowerSummary.PresentStatus.BelowRemainingCapacityLimit", NULL, NULL, HU_FLAG_QUICK_POLL, lowbatt_info }, { "BOOL", 0, 0, "UPS.PowerSummary.PresentStatus.FullyCharged", NULL, NULL, 0, fullycharged_info }, { "BOOL", 0, 0, "UPS.PowerSummary.PresentStatus.RemainingTimeLimitExpired", NULL, NULL, 0, timelimitexpired_info }, { "BOOL", 0, 0, "UPS.Output.CommunicationLost", NULL, NULL, 0, commfault_info }, { "BOOL", 0, 0, "UPS.Output.Boost", NULL, NULL, 0, boost_info }, { "BOOL", 0, 0, "UPS.Output.Overload", NULL, NULL, 0, overload_info }, /* Input page */ { "input.frequency", 0, 0, "UPS.Input.Frequency", NULL, "%.1f", 0, NULL }, { "input.voltage.nominal", 0, 0, "UPS.Input.ConfigVoltage", NULL, "%.0f", 0, NULL }, { "input.voltage", 0, 0, "UPS.Input.Voltage", NULL, "%.1f", 0, NULL }, /* read-only on this model but probably R/W in other models */ /* { "input.transfer.low", ST_FLAG_RW | ST_FLAG_STRING, 10, "UPS.Input.LowVoltageTransfer", NULL, "%.0f", HU_FLAG_SEMI_STATIC, NULL }, { "input.transfer.high", ST_FLAG_RW | ST_FLAG_STRING, 10, "UPS.Input.HighVoltageTransfer", NULL, "%.0f", HU_FLAG_SEMI_STATIC, NULL }, */ { "input.transfer.high", 0, 0, "UPS.PowerConverter.Output.HighVoltageTransfer", NULL, "%.0f", HU_FLAG_STATIC, NULL }, { "input.transfer.low", 0, 0, "UPS.PowerConverter.Output.LowVoltageTransfer", NULL, "%.0f", HU_FLAG_STATIC, NULL }, /* Output page */ { "output.frequency", 0, 0, "UPS.Output.Frequency", NULL, "%.1f", 0, NULL }, { "output.voltage", 0, 0, "UPS.Output.Voltage", NULL, "%.1f", 0, NULL }, { "output.voltage.nominal", 0, 0, "UPS.Output.ConfigVoltage", NULL, "%.0f", 0, NULL }, /* instant commands. */ /* Need testing { "test.battery.start.quick", 0, 0, "UPS.Output.Test", NULL, "1", HU_TYPE_CMD, NULL }, { "test.battery.start.deep", 0, 0, "UPS.Output.Test", NULL, "2", HU_TYPE_CMD, NULL }, { "test.battery.stop", 0, 0, "UPS.Output.Test", NULL, "3", HU_TYPE_CMD, NULL }, { "load.off.delay", 0, 0, "UPS.Output.DelayBeforeShutdown", NULL, DEFAULT_OFFDELAY, HU_TYPE_CMD, NULL }, { "load.on.delay", 0, 0, "UPS.Output.DelayBeforeStartup", NULL, DEFAULT_ONDELAY, HU_TYPE_CMD, NULL }, { "shutdown.stop", 0, 0, "UPS.Output.DelayBeforeShutdown", NULL, "-1", HU_TYPE_CMD, NULL }, { "shutdown.reboot", 0, 0, "UPS.Output.DelayBeforeReboot", NULL, "10", HU_TYPE_CMD, NULL }, { "beeper.on", 0, 0, "UPS.PowerSummary.AudibleAlarmControl", NULL, "2", HU_TYPE_CMD, NULL }, { "beeper.off", 0, 0, "UPS.PowerSummary.AudibleAlarmControl", NULL, "3", HU_TYPE_CMD, NULL }, { "beeper.enable", 0, 0, "UPS.PowerSummary.AudibleAlarmControl", NULL, "2", HU_TYPE_CMD, NULL }, { "beeper.disable", 0, 0, "UPS.PowerSummary.AudibleAlarmControl", NULL, "1", HU_TYPE_CMD, NULL }, { "beeper.mute", 0, 0, "UPS.PowerSummary.AudibleAlarmControl", NULL, "3", HU_TYPE_CMD, NULL }, */ /* Salicru Twin Pro 2 Descriptors: Sensors */ { "ups.load", 0, 0, "UPS.PowerSummary.PercentLoad", NULL, "%.0f", 0, NULL }, { "ups.test.result", 0, 0, "UPS.BatterySystem.Battery.Test", NULL, "%s", 0, test_read_info }, { "ups.realpower.nominal", 0, 0, "UPS.Flow.[4].ConfigActivePower", NULL, "%.0f", 0, NULL }, { "ups.realpower", 0, 0, "UPS.PowerConverter.Output.ActivePower", NULL, "%.0f", 0, NULL }, { "BOOL", 0, 0, "UPS.PowerSummary.PresentStatus.Overload", NULL, NULL, 0, overload_info }, { "BOOL", 0, 0, "UPS.PowerSummary.PresentStatus.OverTemperature", NULL, NULL, 0, overheat_info }, { "input.frequency", 0, 0, "UPS.PowerConverter.Input.[1].Frequency", NULL, "%.1f", 0, NULL }, { "input.voltage", 0, 0, "UPS.PowerConverter.Input.[1].Voltage", NULL, "%.1f", 0, NULL }, { "output.frequency", 0, 0, "UPS.PowerConverter.Output.Frequency", NULL, "%.1f", 0, NULL }, { "output.voltage", 0, 0, "UPS.PowerConverter.Output.Voltage", NULL, "%.1f", 0, NULL }, { "output.voltage.nominal", 0, 0, "UPS.PowerSummary.ConfigVoltage", NULL, "%.0f", 0, NULL }, { "ups.test.result", 0, 0, "UPS.BatterySystem.Battery.Test", NULL, "%s", 0, test_read_info }, /* Salicru Twin Pro 2 Descriptors: Instant commands */ { "test.battery.start.quick", 0, 0, "UPS.BatterySystem.Battery.Test", NULL, "1", HU_TYPE_CMD, NULL }, { "test.battery.start.deep", 0, 0, "UPS.BatterySystem.Battery.Test", NULL, "2", HU_TYPE_CMD, NULL }, { "test.battery.stop", 0, 0, "UPS.BatterySystem.Battery.Test", NULL, "3", HU_TYPE_CMD, NULL }, /* end of structure. */ { NULL, 0, 0, NULL, NULL, NULL, 0, NULL } }; static const char *salicru_format_model(HIDDevice_t *hd) { return hd->Product; } static const char *salicru_format_mfr(HIDDevice_t *hd) { return hd->Vendor ? hd->Vendor : "Salicru"; } static const char *salicru_format_serial(HIDDevice_t *hd) { return hd->Serial; } /* this function allows the subdriver to "claim" a device: return 1 if * the device is supported by this subdriver, else 0. */ static int salicru_claim(HIDDevice_t *hd) { int status = is_usb_device_supported(salicru_usb_device_table, hd); switch (status) { case POSSIBLY_SUPPORTED: /* by default, reject, unless the productid option is given */ if (getval("productid")) { return 1; } possibly_supported("Salicru", hd); return 0; case SUPPORTED: return 1; case NOT_SUPPORTED: default: return 0; } } subdriver_t salicru_subdriver = { SALICRU_HID_VERSION, salicru_claim, salicru_utab, salicru_hid2nut, salicru_format_model, salicru_format_mfr, salicru_format_serial, fix_report_desc, }; nut-2.8.1/drivers/metasys.c0000644000175000017500000010543214501607135012567 00000000000000/* metasys.c - driver for Meta System UPS Copyright (C) 2004 Fabio Di Niro 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 2 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, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ /* Uncomment if you want to read additional Meta System UPS data */ /* #define EXTRADATA */ #include "main.h" #include "serial.h" #include "nut_float.h" #include "nut_stdint.h" #define DRIVER_NAME "Metasystem UPS driver" #define DRIVER_VERSION "0.09" /* driver description structure */ upsdrv_info_t upsdrv_info = { DRIVER_NAME, DRIVER_VERSION, "Fabio Di Niro ", DRV_STABLE, { NULL } }; /* Autorestart flag */ static int autorestart = 0; static int nominal_power = 0; /* ups commands */ #define UPS_INFO 0x00 #define UPS_OUTPUT_DATA 0x01 #define UPS_INPUT_DATA 0x02 #define UPS_STATUS 0x03 #define UPS_BATTERY_DATA 0x04 #define UPS_HISTORY_DATA 0x05 #define UPS_GET_SCHEDULING 0x06 #define UPS_EVENT_LIST 0x07 #define UPS_GET_TIMES_ON_BATTERY 0x08 #define UPS_GET_NEUTRAL_SENSE 0x09 #define UPS_SET_SCHEDULING 0x0a #define UPS_SET_NEUTRAL_SENSE 0x0b #define UPS_SET_TIMES_ON_BATTERY 0x0c #define UPS_SET_BUZZER_MUTE 0x0d #define UPS_SET_BATTERY_TEST 0x0e static int instcmd(const char *cmdname, const char *extra); /* Metasystem UPS data transfer are made with packet of the format: STX DATA_LENGTH DATA CHECKSUM where: STX is 0x02 and is the start of transmission byte DATA_LENGTH is number of data bytes + the checksum byte DATA ...... CHECKSUM is the sum modulus 256 of all DATA bytes + DATA_LENGTH The answer from the UPS have the same packet format and the first data byte is equal to the command that the ups is answering to */ static uint16_t get_word(unsigned char *buffer) { /* return an integer reading a word in the supplied buffer */ unsigned char a, b; uint16_t result; a = buffer[0]; b = buffer[1]; result = b*256 + a; return result; } static uint32_t get_long(unsigned char *buffer) { /* return a long integer reading 4 bytes in the supplied buffer */ unsigned char a, b, c, d; uint32_t result; a=buffer[0]; b=buffer[1]; c=buffer[2]; d=buffer[3]; result = (256*256*256*d) + (256*256*c) + (256*b) + a; return result; } static float get_word_float(unsigned char *buffer) { /* return a float converted after reading a word in the supplied buffer */ /* NOTE: This started as a wrapper for legacy logic that directly assigned * float_num = get_word(...) * in code below. No idea if the protocol really sends 16-bit floats. * FWIW, bcmxcp.c copied get_word() and get_long() from metasys.c but did * implement a get_float() for IEEE-754 32-bit values. */ return (float)(int16_t)get_word(buffer); } static void send_zeros(void) { /* send 100 times the value 0x00.....it seems to be used for resetting */ unsigned char buf[100]; /* the ups serial port */ memset(buf, '\0', sizeof(buf)); ser_send_buf(upsfd, buf, sizeof(buf)); return; } /* was used just for the debug process */ static void dump_buffer(unsigned char *buffer, int buf_len) { int i; for (i = 0; i < buf_len; i++) { printf("byte %d: %x\n", i, buffer[i]); } return; } /* send a read command to the UPS, it retries 5 times before give up it's a 4 byte request (STX, LENGTH, COMMAND and CHECKSUM) */ static void send_read_command(unsigned char command) { int retry; ssize_t sent; unsigned char buf[4]; retry = 0; sent = 0; while ((sent != 4) && (retry < 5)) { buf[0]=0x02; /* STX Start of Transmission */ buf[1]=0x02; /* data length(data + checksum byte) */ buf[2]=command; /* command to send */ buf[3]=buf[1] + buf[2]; /* checksum (sum modulus 256 of data bytes + length) */ if (retry == 4) send_zeros(); /* last retry is preceded by a serial reset...*/ sent = ser_send_buf(upsfd, buf, 4); retry += 1; } } /* send a write command to the UPS, the write command and the value to be written are passed with a char* buffer it retries 5 times before give up */ static void send_write_command(unsigned char *command, size_t command_length) { int retry, checksum; ssize_t sent; size_t i; unsigned char raw_buf[255]; /* prepares the raw data */ raw_buf[0] = 0x02; /* STX byte */ raw_buf[1] = (unsigned char)(command_length + 1); /* data length + checksum */ memcpy(raw_buf+2, command, command_length); command_length += 2; /* calculate checksum */ checksum = 0; for (i = 1; i < command_length; i++) checksum += raw_buf[i]; checksum = checksum % 256; raw_buf[command_length] = (unsigned char)checksum; command_length +=1; assert (command_length < INT_MAX); retry = 0; sent = 0; while ((sent != (int)(command_length)) && (retry < 5)) { if (retry == 4) send_zeros(); /* last retry is preceded by a serial reset... */ sent = ser_send_buf(upsfd, raw_buf, (command_length)); if (sent < 0) ser_comm_fail("Error sending command %d\n", raw_buf[2]); if (sent != (int)(command_length)) printf("Error sending command %d\n", raw_buf[2]); retry += 1; } } /* get the answer of a command from the ups */ static int get_answer(unsigned char *data) { unsigned char my_buf[255]; /* packet has a maximum length of 256 bytes */ unsigned char packet_length, checksum, i; ssize_t res; /* Read STX byte */ res = ser_get_char(upsfd, my_buf, 1, 0); if (res < 1) { ser_comm_fail("Receive error (STX): %" PRIiSIZE "!!!\n", res); return -1; } if (my_buf[0] != 0x02) { ser_comm_fail("Receive error (STX): packet not on start!!\n"); return -1; } /* Read data length byte */ res = ser_get_char(upsfd, my_buf, 1, 0); if (res < 1) { ser_comm_fail("Receive error (length): %" PRIiSIZE "!!!\n", res); return -1; } packet_length = my_buf[0]; if (packet_length < 2) { ser_comm_fail("Receive error (length): packet length %d!!!\n", packet_length); return -1; } /* Try to read all the remainig bytes (packet_length) */ res = ser_get_buf_len(upsfd, my_buf, packet_length, 1, 0); if (res != packet_length) { ser_comm_fail("Receive error (data): got %" PRIiSIZE " bytes instead of %d!!!\n", res, packet_length); return -1; } /* now we have the whole answer from the ups, we can checksum it checksum byte is equal to the sum modulus 256 of all the data bytes + packet_length (no STX no checksum byte itself) */ checksum = packet_length; for (i = 0; i < (packet_length - 1); i++) checksum += my_buf[i]; checksum = checksum % 256; if (my_buf[packet_length-1] != checksum) { ser_comm_fail("checksum error! got %x instead of %x, received %d bytes \n", my_buf[packet_length - 1], checksum, packet_length); dump_buffer(my_buf, packet_length); return -1; } packet_length-=1; /* get rid of the checksum byte */ memcpy(data, my_buf, packet_length); return packet_length; } /* send a read command and try get the answer, if something fails, it retries (5 times max) if it is on the 4th or 5th retry, it will flush the serial before sending commands it returns the length of the received answer or -1 in case of failure */ static int command_read_sequence(unsigned char command, unsigned char *data) { int bytes_read = 0; int retry = 0; while ((bytes_read < 1) && (retry < 5)) { send_read_command(command); bytes_read = get_answer(data); if (retry > 2) ser_flush_in(upsfd, "", 0); retry += 1; } if ((data[0] != command) || (retry == 5)) { ser_comm_fail("Error executing command %d\n", command); dstate_datastale(); return -1; } ser_comm_good(); return bytes_read; } /* send a write command and try get the answer, if something fails, it retries (5 times max) if it is on the 4th or 5th retry, it will flush the serial before sending commands it returns the length of the received answer or -1 in case of failure */ static int command_write_sequence(unsigned char *command, size_t command_length, unsigned char *answer) { int bytes_read = 0; int retry = 0; while ((bytes_read < 1) && (retry < 5)) { send_write_command(command, command_length); bytes_read = get_answer(answer); if (retry > 2) ser_flush_in(upsfd, "", 0); retry += 1; } if ((answer[0] != command[0]) || (retry == 5)) { ser_comm_fail("Error executing command N.%d\n", command[0]); dstate_datastale(); return -1; } ser_comm_good(); return bytes_read; } #if (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_PUSH_POP_BESIDEFUNC) && (!defined HAVE_PRAGMA_GCC_DIAGNOSTIC_PUSH_POP_INSIDEFUNC) && ( (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_TYPE_LIMITS_BESIDEFUNC) || (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_TAUTOLOGICAL_CONSTANT_OUT_OF_RANGE_COMPARE_BESIDEFUNC) ) # pragma GCC diagnostic push #endif #if (!defined HAVE_PRAGMA_GCC_DIAGNOSTIC_PUSH_POP_INSIDEFUNC) && (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_TYPE_LIMITS_BESIDEFUNC) # pragma GCC diagnostic ignored "-Wtype-limits" #endif #if (!defined HAVE_PRAGMA_GCC_DIAGNOSTIC_PUSH_POP_INSIDEFUNC) && (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_TAUTOLOGICAL_CONSTANT_OUT_OF_RANGE_COMPARE_BESIDEFUNC) # pragma GCC diagnostic ignored "-Wtautological-constant-out-of-range-compare" #endif void upsdrv_initinfo(void) { unsigned char my_answer[255]; char serial[13]; int res, i; /* Initial setup of variables */ #ifdef EXTRADATA dstate_setinfo("output.power", "%d", -1); dstate_setflags("output.power", ST_FLAG_RW); #endif dstate_setinfo("output.voltage", "%d", -1); dstate_setflags("output.voltage", ST_FLAG_RW); dstate_setinfo("output.current", "%d", -1); dstate_setflags("output.current", ST_FLAG_RW); #ifdef EXTRADATA dstate_setinfo("output.current.peak", "%2.2f", -1); dstate_setflags("output.current.peak", ST_FLAG_RW); dstate_setinfo("input.power", "%d", -1); dstate_setflags("input.power", ST_FLAG_RW); #endif dstate_setinfo("input.voltage", "%d", -1); dstate_setflags("input.voltage", ST_FLAG_RW); #ifdef EXTRADATA dstate_setinfo("input.current", "%2.2f", -1); dstate_setflags("input.current", ST_FLAG_RW); dstate_setinfo("input.current.peak", "%2.2f", -1); dstate_setflags("input.current.peak", ST_FLAG_RW); #endif dstate_setinfo("battery.voltage", "%d", -1); dstate_setflags("battery.voltage", ST_FLAG_RW); #ifdef EXTRADATA dstate_setinfo("battery.voltage.low", "%2.2f", -1); dstate_setflags("battery.voltage.low", ST_FLAG_RW); dstate_setinfo("battery.voltage.exhaust", "%2.2f", -1); dstate_setflags("battery.voltage.exhaust", ST_FLAG_RW); dstate_setinfo("ups.total.runtime", "retrieving..."); dstate_setflags("ups.total.runtime", ST_FLAG_STRING | ST_FLAG_RW); dstate_setaux("ups.total.runtime", 20); dstate_setinfo("ups.inverter.runtime", "retrieving..."); dstate_setflags("ups.inverter.runtime", ST_FLAG_STRING | ST_FLAG_RW); dstate_setaux("ups.inverter.runtime", 20); dstate_setinfo("ups.inverter.interventions", "%d", -1); dstate_setflags("ups.inverter.interventions", ST_FLAG_RW); dstate_setinfo("battery.full.discharges", "%d", -1); dstate_setflags("battery.full.discharges", ST_FLAG_RW); dstate_setinfo("ups.bypass.interventions", "%d", -1); dstate_setflags("ups.bypass.interventions", ST_FLAG_RW); dstate_setinfo("ups.overheatings", "%d", -1); dstate_setflags("ups.overheatings", ST_FLAG_RW); #endif dstate_setinfo("ups.load", "%d", -1); dstate_setflags("ups.load", ST_FLAG_RW); dstate_setinfo("ups.delay.shutdown", "%d", -1); dstate_setflags("ups.delay.shutdown", ST_FLAG_RW); dstate_setinfo("ups.delay.start", "%d", -1); dstate_setflags("ups.delay.start", ST_FLAG_RW); dstate_setinfo("ups.temperature", "%d", -1); dstate_setflags("ups.temperature", ST_FLAG_RW); dstate_setinfo("ups.test.result", "not yet done..."); dstate_setflags("ups.test.result", ST_FLAG_STRING | ST_FLAG_RW); dstate_setaux("ups.test.result", 20); /* UPS INFO READ */ res = command_read_sequence(UPS_INFO, my_answer); if (res < 0) fatal_with_errno(EXIT_FAILURE, "Could not communicate with the ups"); /* the manufacturer is hard coded into the driver, the model type is in the second byte of the answer, the third byte identifies the model version */ dstate_setinfo("ups.mfr", "Meta System"); i = my_answer[1] * 10 + my_answer[2]; switch (i) { case 11: dstate_setinfo("ups.model", "%s", "HF Line (1 board)"); nominal_power = 630; break; case 12: dstate_setinfo("ups.model", "%s", "HF Line (2 boards)"); nominal_power = 1260; break; case 13: dstate_setinfo("ups.model", "%s", "HF Line (3 boards)"); nominal_power = 1890; break; case 14: dstate_setinfo("ups.model", "%s", "HF Line (4 boards)"); nominal_power = 2520; break; case 21: dstate_setinfo("ups.model", "%s", "ECO Network 750/1000"); nominal_power = 500; break; case 22: dstate_setinfo("ups.model", "%s", "ECO Network 1050/1500"); nominal_power = 700; break; case 23: dstate_setinfo("ups.model", "%s", "ECO Network 1500/2000"); nominal_power = 1000; break; case 24: dstate_setinfo("ups.model", "%s", "ECO Network 1800/2500"); nominal_power = 1200; break; case 25: dstate_setinfo("ups.model", "%s", "ECO Network 2100/3000"); nominal_power = 1400; break; case 31: dstate_setinfo("ups.model", "%s", "ECO 308"); nominal_power = 500; break; case 32: dstate_setinfo("ups.model", "%s", "ECO 311"); nominal_power = 700; break; case 44: dstate_setinfo("ups.model", "%s", "HF Line (4 boards)/2"); nominal_power = 2520; break; case 45: dstate_setinfo("ups.model", "%s", "HF Line (5 boards)/2"); nominal_power = 3150; break; case 46: dstate_setinfo("ups.model", "%s", "HF Line (6 boards)/2"); nominal_power = 3780; break; case 47: dstate_setinfo("ups.model", "%s", "HF Line (7 boards)/2"); nominal_power = 4410; break; case 48: dstate_setinfo("ups.model", "%s", "HF Line (8 boards)/2"); nominal_power = 5040; break; case 51: dstate_setinfo("ups.model", "%s", "HF Millennium 810"); nominal_power = 700; break; case 52: dstate_setinfo("ups.model", "%s", "HF Millennium 820"); nominal_power = 1400; break; case 61: dstate_setinfo("ups.model", "%s", "HF TOP Line 910"); nominal_power = 700; break; case 62: dstate_setinfo("ups.model", "%s", "HF TOP Line 920"); nominal_power = 1400; break; case 63: dstate_setinfo("ups.model", "%s", "HF TOP Line 930"); nominal_power = 2100; break; case 64: dstate_setinfo("ups.model", "%s", "HF TOP Line 940"); nominal_power = 2800; break; case 74: dstate_setinfo("ups.model", "%s", "HF TOP Line 940/2"); nominal_power = 2800; break; case 75: dstate_setinfo("ups.model", "%s", "HF TOP Line 950/2"); nominal_power = 3500; break; case 76: dstate_setinfo("ups.model", "%s", "HF TOP Line 960/2"); nominal_power = 4200; break; case 77: dstate_setinfo("ups.model", "%s", "HF TOP Line 970/2"); nominal_power = 4900; break; case 78: dstate_setinfo("ups.model", "%s", "HF TOP Line 980/2"); nominal_power = 5600; break; case 81: dstate_setinfo("ups.model", "%s", "ECO 508"); nominal_power = 500; break; case 82: dstate_setinfo("ups.model", "%s", "ECO 511"); nominal_power = 700; break; case 83: dstate_setinfo("ups.model", "%s", "ECO 516"); nominal_power = 1000; break; case 84: dstate_setinfo("ups.model", "%s", "ECO 519"); nominal_power = 1200; break; case 85: dstate_setinfo("ups.model", "%s", "ECO 522"); nominal_power = 1400; break; case 91: dstate_setinfo("ups.model", "%s", "ECO 305 / Harviot 530 SX"); nominal_power = 330; break; case 92: dstate_setinfo("ups.model", "%s", "ORDINATORE 2"); nominal_power = 330; break; case 93: dstate_setinfo("ups.model", "%s", "Harviot 730 SX"); nominal_power = 430; break; case 101: dstate_setinfo("ups.model", "%s", "ECO 308 SX / SX Interactive / Ordinatore"); nominal_power = 500; break; case 102: dstate_setinfo("ups.model", "%s", "ECO 311 SX / SX Interactive"); nominal_power = 700; break; case 111: dstate_setinfo("ups.model", "%s", "ally HF 800 / BI-TWICE 800"); nominal_power = 560; break; case 112: dstate_setinfo("ups.model", "%s", "ally HF 1600"); nominal_power = 1120; break; case 121: dstate_setinfo("ups.model", "%s", "ally HF 1000 / BI-TWICE 1000"); nominal_power = 700; break; case 122: dstate_setinfo("ups.model", "%s", "ally HF 2000"); nominal_power = 1400; break; case 131: dstate_setinfo("ups.model", "%s", "ally HF 1250 / BI-TWICE 1250"); nominal_power = 875; break; case 132: dstate_setinfo("ups.model", "%s", "ally HF 2500"); nominal_power = 1750; break; case 141: dstate_setinfo("ups.model", "%s", "Megaline 1250"); nominal_power = 875; break; case 142: dstate_setinfo("ups.model", "%s", "Megaline 2500"); nominal_power = 1750; break; case 143: dstate_setinfo("ups.model", "%s", "Megaline 3750"); nominal_power = 2625; break; case 144: dstate_setinfo("ups.model", "%s", "Megaline 5000"); nominal_power = 3500; break; case 154: dstate_setinfo("ups.model", "%s", "Megaline 5000 / 2"); nominal_power = 3500; break; case 155: dstate_setinfo("ups.model", "%s", "Megaline 6250 / 2"); nominal_power = 4375; break; case 156: dstate_setinfo("ups.model", "%s", "Megaline 7500 / 2"); nominal_power = 5250; break; case 157: dstate_setinfo("ups.model", "%s", "Megaline 8750 / 2"); nominal_power = 6125; break; case 158: dstate_setinfo("ups.model", "%s", "Megaline 10000 / 2"); nominal_power = 7000; break; default: fatal_with_errno(EXIT_FAILURE, "Unknown UPS"); } /* Get the serial number; res >=0 per check above */ #if (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_PUSH_POP) && ( (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_TYPE_LIMITS) || (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_TAUTOLOGICAL_CONSTANT_OUT_OF_RANGE_COMPARE) ) /* Note for gating macros above: unsuffixed HAVE_PRAGMA_GCC_DIAGNOSTIC_PUSH_POP * means support of contexts both inside and outside function body, so the push * above and pop below (outside this finction) are not used. */ # pragma GCC diagnostic push #endif #ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_TYPE_LIMITS /* Note that the individual warning pragmas for use inside function bodies * are named without a _INSIDEFUNC suffix, for simplicity and legacy reasons */ # pragma GCC diagnostic ignored "-Wtype-limits" #endif #ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_TAUTOLOGICAL_CONSTANT_OUT_OF_RANGE_COMPARE # pragma GCC diagnostic ignored "-Wtautological-constant-out-of-range-compare" #endif if (res < 7 || (unsigned long long int)res >= SIZE_MAX) #if (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_PUSH_POP) && ( (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_TYPE_LIMITS) || (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_TAUTOLOGICAL_CONSTANT_OUT_OF_RANGE_COMPARE) ) # pragma GCC diagnostic pop #endif fatal_with_errno(EXIT_FAILURE, "Could not communicate with the ups"); memcpy(serial, my_answer + 7, (size_t)(res - 7)); /* serial number start from the 8th byte */ serial[12]='\0'; /* terminate string */ dstate_setinfo("ups.serial", "%s", serial); /* get the ups firmware. The major number is in the 5th byte, the minor is in the 6th */ dstate_setinfo("ups.firmware", "%u.%u", my_answer[5], my_answer[6]); printf("Detected %s [%s] v.%s on %s\n", dstate_getinfo("ups.model"), dstate_getinfo("ups.serial"), dstate_getinfo("ups.firmware"), device_path); /* Add instant commands */ dstate_addcmd("shutdown.return"); dstate_addcmd("shutdown.stayoff"); dstate_addcmd("shutdown.stop"); dstate_addcmd("test.failure.start"); dstate_addcmd("test.failure.stop"); dstate_addcmd("test.battery.start"); dstate_addcmd("beeper.enable"); dstate_addcmd("beeper.mute"); dstate_addcmd("beeper.on"); dstate_addcmd("beeper.off"); upsh.instcmd = instcmd; return; } #if (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_PUSH_POP_BESIDEFUNC) && (!defined HAVE_PRAGMA_GCC_DIAGNOSTIC_PUSH_POP_INSIDEFUNC) && ( (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_TYPE_LIMITS_BESIDEFUNC) || (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_TAUTOLOGICAL_CONSTANT_OUT_OF_RANGE_COMPARE_BESIDEFUNC) ) # pragma GCC diagnostic pop #endif void upsdrv_updateinfo(void) { int res; uint16_t int_num; #ifdef EXTRADATA int day, hour, minute; #endif float float_num; uint32_t long_num; unsigned char my_answer[255]; /* GET Output data */ res = command_read_sequence(UPS_OUTPUT_DATA, my_answer); if (res < 0) { printf("Could not communicate with the ups"); dstate_datastale(); } else { /* Active power */ int_num = get_word(&my_answer[1]); if (nominal_power != 0) { float_num = (float)((int_num * 100)/nominal_power); dstate_setinfo("ups.load", "%2.1f", float_num); } else { dstate_setinfo("ups.load", "%s", "not available"); } #ifdef EXTRADATA dstate_setinfo("output.power", "%u", int_num); #endif /* voltage */ int_num = get_word(&my_answer[3]); if ((int16_t)int_num > 0) dstate_setinfo("output.voltage", "%u", int_num); if ((int16_t)int_num == -1) dstate_setinfo("output.voltage", "%s", "overrange"); if ((int16_t)int_num == -2) dstate_setinfo("output.voltage", "%s", "not available"); /* current */ float_num = get_word_float(&my_answer[5]); if (f_equal(float_num, -1.0)) dstate_setinfo("output.current", "%s", "overrange"); if (f_equal(float_num, -2.0)) dstate_setinfo("output.current", "%s", "not available"); if (float_num > 0) { float_num = (float)(float_num/10); dstate_setinfo("output.current", "%2.2f", float_num); } #ifdef EXTRADATA /* peak current */ float_num = get_word_float(&my_answer[7]); if (f_equal(float_num, -1.0)) dstate_setinfo("output.current.peak", "%s", "overrange"); if (f_equal(float_num, -2.0)) dstate_setinfo("output.current.peak", "%s", "not available"); if (float_num > 0) { float_num = (float)(float_num/10); dstate_setinfo("output.current.peak", "%2.2f", float_num); } #endif } /* GET Input data */ res = command_read_sequence(UPS_INPUT_DATA, my_answer); if (res < 0){ printf("Could not communicate with the ups"); dstate_datastale(); } else { #ifdef EXTRADATA /* Active power */ int_num = get_word(&my_answer[1]); if ((int16_t)int_num > 0) dstate_setinfo("input.power", "%u", int_num); if ((int16_t)int_num == -1) dstate_setinfo("input.power", "%s", "overrange"); if ((int16_t)int_num == -2) dstate_setinfo("input.power", "%s", "not available"); #endif /* voltage */ int_num = get_word(&my_answer[3]); if ((int16_t)int_num > 0) dstate_setinfo("input.voltage", "%u", int_num); if ((int16_t)int_num == -1) dstate_setinfo("input.voltage", "%s", "overrange"); if ((int16_t)int_num == -2) dstate_setinfo("input.voltage", "%s", "not available"); #ifdef EXTRADATA /* current */ float_num = get_word_float(&my_answer[5]); if (float_num == -1) dstate_setinfo("input.current", "%s", "overrange"); if (float_num == -2) dstate_setinfo("input.current", "%s", "not available"); if (float_num > 0) { float_num = (float)(float_num/10); dstate_setinfo("input.current", "%2.2f", float_num); } /* peak current */ float_num = get_word_float(&my_answer[7]); if (float_num == -1) dstate_setinfo("input.current.peak", "%s", "overrange"); if (float_num == -2) dstate_setinfo("input.current.peak", "%s", "not available"); if (float_num > 0) { float_num = (float)(float_num/10); dstate_setinfo("input.current.peak", "%2.2f", float_num); } #endif } /* GET Battery data */ res = command_read_sequence(UPS_BATTERY_DATA, my_answer); if (res < 0) { printf("Could not communicate with the ups"); dstate_datastale(); } else { /* Actual value */ float_num = get_word_float(&my_answer[1]); float_num = (float)(float_num/10); dstate_setinfo("battery.voltage", "%2.2f", float_num); #ifdef EXTRADATA /* reserve threshold */ float_num = get_word_float(&my_answer[3]); float_num = (float)(float_num/10); dstate_setinfo("battery.voltage.low", "%2.2f", float_num); /* exhaust threshold */ float_num = get_word_float(&my_answer[5]); float_num = (float)(float_num/10); dstate_setinfo("battery.voltage.exhaust", "%2.2f", float_num); #endif } #ifdef EXTRADATA /* GET history data */ res = command_read_sequence(UPS_HISTORY_DATA, my_answer); if (res < 0) { printf("Could not communicate with the ups"); dstate_datastale(); } else { /* ups total runtime */ long_num = get_long(&my_answer[1]); day = (int)(long_num / 86400); long_num -= (long)(day*86400); hour = (int)(long_num / 3600); long_num -= (long)(hour*3600); minute = (int)(long_num / 60); long_num -= (minute*60); dstate_setinfo("ups.total.runtime", "%d days %dh %dm %lus", day, hour, minute, long_num); /* ups inverter runtime */ long_num = get_long(&my_answer[5]); day = (int)(long_num / 86400); long_num -= (long)(day*86400); hour = (int)(long_num / 3600); long_num -= (long)(hour*3600); minute = (int)(long_num / 60); long_num -= (minute*60); dstate_setinfo("ups.inverter.runtime", "%d days %dh %dm %lus", day, hour, minute, long_num); /* ups inverter interventions */ dstate_setinfo("ups.inverter.interventions", "%u", get_word(&my_answer[9])); /* battery full discharges */ dstate_setinfo("battery.full.discharges", "%u", get_word(&my_answer[11])); /* ups bypass / stabilizer interventions */ int_num = get_word(&my_answer[13]); if ((int16_t)int_num == -2) dstate_setinfo("ups.bypass.interventions", "%s", "not avaliable"); if ((int16_t)int_num >= 0) dstate_setinfo("ups.bypass.interventions", "%u", int_num); /* ups overheatings */ int_num = get_word(&my_answer[15]); if ((int16_t)int_num == -2) dstate_setinfo("ups.overheatings", "%s", "not avalilable"); if ((int16_t)int_num >= 0) dstate_setinfo("ups.overheatings", "%u", int_num); } #endif /* GET times on battery */ res = command_read_sequence(UPS_GET_TIMES_ON_BATTERY, my_answer); if (res < 0) { printf("Could not communicate with the ups"); dstate_datastale(); } else { autorestart = my_answer[5]; } /* GET schedule */ res = command_read_sequence(UPS_GET_SCHEDULING, my_answer); if (res < 0) { printf("Could not communicate with the ups"); dstate_datastale(); } else { /* time remaining to shutdown */ long_num = get_long(&my_answer[1]); if ((int32_t)long_num == -1) { dstate_setinfo("ups.delay.shutdown", "%d", 120); } else { dstate_setinfo("ups.delay.shutdown", "%lu", (unsigned long)long_num); } /* time remaining to restart */ long_num = get_long(&my_answer[5]); if ((int32_t)long_num == -1) { dstate_setinfo("ups.delay.start", "%d", 0); } else { dstate_setinfo("ups.delay.start", "%lu", (unsigned long)long_num); } } /* GET ups status */ res = command_read_sequence(UPS_STATUS, my_answer); if (res < 0) { printf("Could not communicate with the ups"); dstate_datastale(); } else { /* ups temperature */ my_answer[3] -=128; if (my_answer[3] > 0) { dstate_setinfo("ups.temperature", "%d", my_answer[3]); } else { dstate_setinfo("ups.temperature", "%s", "not available"); } /* Status */ status_init(); switch (my_answer[1]) { /* byte 1 = STATUS */ case 0x00: status_set("OL"); /* running on mains power */ break; case 0x01: status_set("OB"); /* running on battery power */ break; case 0x02: status_set("LB"); /* battery reserve */ break; case 0x03: /* bypass engaged */ case 0x04: /* manual bypass engaged */ status_set("BY"); break; default: printf("status unknown \n"); break; } switch (my_answer[2]) { /* byte 2 = FAULTS */ case 0x00: /* all right */ break; case 0x01: /* overload */ status_set("OVER"); break; case 0x02: /* overheat */ break; case 0x03: /* hardware fault */ break; case 0x04: /* battery charger failure (overcharging) */ break; case 0x05: /* replace batteries */ status_set("RB"); break; default: printf("status unknown \n"); break; } status_commit(); dstate_dataok(); } return; } void upsdrv_shutdown(void) { unsigned char command[10], answer[10]; /* Ensure that the ups is configured for automatically restart after a complete battery discharge and when the power comes back after a shutdown */ if (! autorestart) { command[0]=UPS_SET_TIMES_ON_BATTERY; command[1]=0x00; /* max time on */ command[2]=0x00; /* battery */ command[3]=0x00; /* max time after */ command[4]=0x00; /* battery reserve */ command[5]=0x01; /* autorestart after battery depleted enabled */ command_write_sequence(command, 6, answer); } /* shedule a shutdown in 120 seconds */ command[0]=UPS_SET_SCHEDULING; command[1]=0x96; /* remaining */ command[2]=0x00; /* time */ command[3]=0x00; /* to */ command[4]=0x00; /* shutdown 150 secs */ /* restart time has been set to 1 instead of 0 for avoiding a bug in some ups firmware */ command[5]=0x01; /* programmed */ command[6]=0x00; /* time */ command[7]=0x00; /* to */ command[8]=0x00; /* restart 1 sec */ command_write_sequence(command, 9, answer); /* you may have to check the line status since the commands for toggling power are frequently different for OL vs. OB */ /* OL: this must power cycle the load if possible */ /* OB: the load must remain off until the power returns */ } static int instcmd(const char *cmdname, const char *extra) { unsigned char command[10], answer[10]; int res; if (!strcasecmp(cmdname, "beeper.off")) { /* compatibility mode for old command */ upslogx(LOG_WARNING, "The 'beeper.off' command has been renamed to 'beeper.mute' for this driver"); return instcmd("beeper.mute", NULL); } if (!strcasecmp(cmdname, "beeper.on")) { /* compatibility mode for old command */ upslogx(LOG_WARNING, "The 'beeper.on' command has been renamed to 'beeper.enable'"); return instcmd("beeper.enable", NULL); } if (!strcasecmp(cmdname, "shutdown.return")) { /* Same stuff as upsdrv_shutdown() */ if (! autorestart) { command[0]=UPS_SET_TIMES_ON_BATTERY; command[1]=0x00; /* max time on */ command[2]=0x00; /* battery */ command[3]=0x00; /* max time after */ command[4]=0x00; /* battery reserve */ command[5]=0x01; /* autorestart after battery depleted enabled */ command_write_sequence(command, 6, answer); } /* shedule a shutdown in 30 seconds */ command[0]=UPS_SET_SCHEDULING; command[1]=0x1e; /* remaining */ command[2]=0x00; /* time */ command[3]=0x00; /* to */ command[4]=0x00; /* shutdown 30 secs */ command[5]=0x01; /* programmed */ command[6]=0x00; /* time */ command[7]=0x00; /* to */ command[8]=0x00; /* restart 1 sec */ command_write_sequence(command, 9, answer); return STAT_INSTCMD_HANDLED; } if (!strcasecmp(cmdname, "shutdown.stayoff")) { /* shedule a shutdown in 30 seconds with no restart (-1) */ command[0]=UPS_SET_SCHEDULING; command[1]=0x1e; /* remaining */ command[2]=0x00; /* time */ command[3]=0x00; /* to */ command[4]=0x00; /* shutdown 150 secs */ command[5]=0xff; /* programmed */ command[6]=0xff; /* time */ command[7]=0xff; /* to */ command[8]=0xff; /* restart -1 no restart*/ command_write_sequence(command, 9, answer); return STAT_INSTCMD_HANDLED; } if (!strcasecmp(cmdname, "shutdown.stop")) { /* set shutdown and restart time to -1 (no shutdown, no restart) */ command[0]=UPS_SET_SCHEDULING; command[1]=0xff; /* remaining */ command[2]=0xff; /* time */ command[3]=0xff; /* to */ command[4]=0xff; /* shutdown -1 (no shutdown) */ command[5]=0xff; /* programmed */ command[6]=0xff; /* time */ command[7]=0xff; /* to */ command[8]=0xff; /* restart -1 no restart */ command_write_sequence(command, 9, answer); return STAT_INSTCMD_HANDLED; } if (!strcasecmp(cmdname, "test.failure.start")) { /* force ups on battery power */ command[0]=UPS_SET_BATTERY_TEST; command[1]=0x01; /* 0 = perform battery test 1 = force UPS on battery power 2 = restore standard mode (mains power) */ command_write_sequence(command, 2, answer); return STAT_INSTCMD_HANDLED; } if (!strcasecmp(cmdname, "test.failure.stop")) { /* restore standard mode (mains power) */ command[0]=UPS_SET_BATTERY_TEST; command[1]=0x02; /* 0 = perform battery test 1 = force UPS on battery power 2 = restore standard mode (mains power) */ command_write_sequence(command, 2, answer); return STAT_INSTCMD_HANDLED; } if (!strcasecmp(cmdname, "test.battery.start")) { /* launch battery test */ command[0]=UPS_SET_BATTERY_TEST; command[1]=0x00; /* 0 = perform battery test 1 = force UPS on battery power 2 = restore standard mode (mains power) */ send_write_command(command, 2); sleep(15); res = get_answer(answer); switch (answer[1]) { /* byte 1 = Test result */ case 0x00: /* all right */ dstate_setinfo("ups.test.result", "OK"); break; case 0x01: dstate_setinfo("ups.test.result", "Battery charge: 20%%"); break; case 0x02: dstate_setinfo("ups.test.result", "Battery charge: 40%%"); break; case 0x03: dstate_setinfo("ups.test.result", "Battery charge: 60%%"); break; case 0x04: dstate_setinfo("ups.test.result", "Battery charge: 80%%"); break; case 0x05: dstate_setinfo("ups.test.result", "Battery charge: 100%%"); break; case 0xfe: dstate_setinfo("ups.test.result", "Bad battery pack: replace"); break; default: dstate_setinfo("ups.test.result", "Impossible to test"); break; } dstate_dataok(); upslogx(LOG_NOTICE, "instcmd: test battery returned with %d bytes", res); upslogx(LOG_NOTICE, "test battery byte 1 = %x", answer[1]); return STAT_INSTCMD_HANDLED; } if (!strcasecmp(cmdname, "beeper.enable")) { /* set buzzer to not muted */ command[0]=UPS_SET_BUZZER_MUTE; command[1]=0x00; /* 0 = not muted 1 = muted 2 = read current status */ command_write_sequence(command, 2, answer); return STAT_INSTCMD_HANDLED; } if (!strcasecmp(cmdname, "beeper.mute")) { /* set buzzer to muted */ command[0]=UPS_SET_BUZZER_MUTE; command[1]=0x01; /* 0 = not muted 1 = muted 2 = read current status */ command_write_sequence(command, 2, answer); return STAT_INSTCMD_HANDLED; } upslogx(LOG_NOTICE, "instcmd: unknown command [%s] [%s]", cmdname, extra); return STAT_INSTCMD_UNKNOWN; } void upsdrv_help(void) { } /* list flags and values that you want to receive via -x */ void upsdrv_makevartable(void) { /* allow '-x xyzzy' */ /* addvar(VAR_FLAG, "xyzzy", "Enable xyzzy mode"); */ /* allow '-x foo=' */ /* addvar(VAR_VALUE, "foo", "Override foo setting"); */ } void upsdrv_initups(void) { upsfd = ser_open(device_path); ser_set_speed(upsfd, device_path, B2400); send_zeros(); } void upsdrv_cleanup(void) { ser_close(upsfd, device_path); } nut-2.8.1/drivers/tripplite-hid.c0000644000175000017500000006632314501607135013665 00000000000000/* tripplite-hid.c - data to monitor Tripp Lite USB/HID devices with NUT * * Copyright (C) * 2003 - 2012 Arnaud Quette * 2005 - 2006 Peter Selinger * 2008 - 2009 Arjen de Korte * * Sponsored by MGE UPS SYSTEMS * * 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 2 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, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #include "main.h" #include "usbhid-ups.h" #include "tripplite-hid.h" #include "usb-common.h" #define TRIPPLITE_HID_VERSION "TrippLite HID 0.85" /* FIXME: experimental flag to be put in upsdrv_info */ /* For some devices, the reported battery voltage is off by * factor of 10 (due to an error in the report descriptor), * so we need to apply a scale factor to it to get the actual * battery voltage. By default, the factor is 1 (no scaling). */ static double battery_scale = 1.0; static double io_voltage_scale = 1.0; static double io_frequency_scale = 1.0; static double io_current_scale = 1.0; /* Specific handlers for USB device matching */ static void *battery_scale_1dot0(USBDevice_t *device) { NUT_UNUSED_VARIABLE(device); /* FIXME: we could remove this one since it's the default! */ battery_scale = 1.0; return NULL; } static void *battery_scale_0dot1(USBDevice_t *device) { NUT_UNUSED_VARIABLE(device); battery_scale = 0.1; return NULL; } static void *smart1500lcdt_scale(USBDevice_t *device) { NUT_UNUSED_VARIABLE(device); battery_scale = 100000.0; io_voltage_scale = 100000.0; io_frequency_scale = 0.01; io_current_scale = 0.01; return NULL; } /* TrippLite */ #define TRIPPLITE_VENDORID 0x09ae /* Hewlett Packard */ #define HP_VENDORID 0x03f0 /* Delta/Minuteman */ #define DELTA_VENDORID 0x05dd /* USB IDs device table */ static usb_device_id_t tripplite_usb_device_table[] = { /* e.g. TrippLite AVR550U */ { USB_DEVICE(TRIPPLITE_VENDORID, 0x1003), battery_scale_0dot1 }, /* e.g. TrippLite AVR750U */ { USB_DEVICE(TRIPPLITE_VENDORID, 0x1007), battery_scale_0dot1 }, /* e.g. TrippLite ECO550UPS */ { USB_DEVICE(TRIPPLITE_VENDORID, 0x1008), battery_scale_0dot1 }, { USB_DEVICE(TRIPPLITE_VENDORID, 0x1009), battery_scale_0dot1 }, { USB_DEVICE(TRIPPLITE_VENDORID, 0x1010), battery_scale_0dot1 }, /* e.g. TrippLite SU3000LCD2UHV */ { USB_DEVICE(TRIPPLITE_VENDORID, 0x1330), battery_scale_1dot0 }, /* e.g. TrippLite OMNI1000LCD */ { USB_DEVICE(TRIPPLITE_VENDORID, 0x2005), battery_scale_0dot1 }, /* e.g. TrippLite OMNI900LCD */ { USB_DEVICE(TRIPPLITE_VENDORID, 0x2007), battery_scale_0dot1 }, /* e.g. ? */ { USB_DEVICE(TRIPPLITE_VENDORID, 0x2008), battery_scale_0dot1 }, /* e.g. TrippLite Smart1000LCD */ { USB_DEVICE(TRIPPLITE_VENDORID, 0x2009), battery_scale_0dot1 }, /* e.g. ? */ { USB_DEVICE(TRIPPLITE_VENDORID, 0x2010), battery_scale_0dot1 }, { USB_DEVICE(TRIPPLITE_VENDORID, 0x2011), battery_scale_0dot1 }, { USB_DEVICE(TRIPPLITE_VENDORID, 0x2012), battery_scale_0dot1 }, { USB_DEVICE(TRIPPLITE_VENDORID, 0x2013), battery_scale_0dot1 }, { USB_DEVICE(TRIPPLITE_VENDORID, 0x2014), battery_scale_0dot1 }, { USB_DEVICE(TRIPPLITE_VENDORID, 0x3008), battery_scale_1dot0 }, { USB_DEVICE(TRIPPLITE_VENDORID, 0x3009), battery_scale_1dot0 }, { USB_DEVICE(TRIPPLITE_VENDORID, 0x3010), battery_scale_1dot0 }, { USB_DEVICE(TRIPPLITE_VENDORID, 0x3011), battery_scale_1dot0 }, /* e.g. TrippLite smart2200RMXL2U */ { USB_DEVICE(TRIPPLITE_VENDORID, 0x3012), battery_scale_1dot0 }, /* e.g. ? */ { USB_DEVICE(TRIPPLITE_VENDORID, 0x3013), battery_scale_1dot0 }, /* e.g. ? */ { USB_DEVICE(TRIPPLITE_VENDORID, 0x3014), battery_scale_1dot0 }, /* e.g. ? */ { USB_DEVICE(TRIPPLITE_VENDORID, 0x3015), battery_scale_1dot0 }, /* e.g. TrippLite Smart1500LCD (newer unit) */ { USB_DEVICE(TRIPPLITE_VENDORID, 0x3016), smart1500lcdt_scale }, /* e.g. TrippLite AVR750U (newer unit) */ { USB_DEVICE(TRIPPLITE_VENDORID, 0x3024), smart1500lcdt_scale }, /* e.g. TrippLite SmartOnline SU1500RTXL2UA (older unit?) */ { USB_DEVICE(TRIPPLITE_VENDORID, 0x4001), battery_scale_1dot0 }, /* e.g. TrippLite SmartOnline SU6000RT4U? */ { USB_DEVICE(TRIPPLITE_VENDORID, 0x4002), battery_scale_1dot0 }, /* e.g. TrippLite SmartOnline SU1500RTXL2ua */ { USB_DEVICE(TRIPPLITE_VENDORID, 0x4003), battery_scale_1dot0 }, /* e.g. TrippLite SmartOnline SU1000XLA */ { USB_DEVICE(TRIPPLITE_VENDORID, 0x4004), battery_scale_1dot0 }, /* e.g. ? */ { USB_DEVICE(TRIPPLITE_VENDORID, 0x4005), battery_scale_1dot0 }, { USB_DEVICE(TRIPPLITE_VENDORID, 0x4006), battery_scale_1dot0 }, { USB_DEVICE(TRIPPLITE_VENDORID, 0x4007), battery_scale_1dot0 }, { USB_DEVICE(TRIPPLITE_VENDORID, 0x4008), battery_scale_1dot0 }, /* e.g. ? */ { USB_DEVICE(HP_VENDORID, 0x0001), battery_scale_1dot0 }, /* HP R1500 G2 and G3 INTL */ { USB_DEVICE(HP_VENDORID, 0x1fe0), battery_scale_1dot0 }, /* HP T750 G2 */ { USB_DEVICE(HP_VENDORID, 0x1fe1), battery_scale_1dot0 }, /* e.g. ? */ { USB_DEVICE(HP_VENDORID, 0x1fe2), battery_scale_1dot0 }, /* HP T1500 G3 */ { USB_DEVICE(HP_VENDORID, 0x1fe3), battery_scale_1dot0 }, /* HP T750 INTL */ { USB_DEVICE(HP_VENDORID, 0x1f06), battery_scale_1dot0 }, /* HP T1000 INTL */ { USB_DEVICE(HP_VENDORID, 0x1f08), battery_scale_1dot0 }, /* HP T1500 INTL */ { USB_DEVICE(HP_VENDORID, 0x1f09), battery_scale_1dot0 }, /* HP R/T 2200 INTL (like SMART2200RMXL2U) */ { USB_DEVICE(HP_VENDORID, 0x1f0a), battery_scale_1dot0 }, /* Delta/Minuteman Enterprise Plus E1500RM2U */ { USB_DEVICE(DELTA_VENDORID, 0xa011), battery_scale_1dot0 }, /* Delta/Minuteman PRO1500RT2U */ { USB_DEVICE(DELTA_VENDORID, 0xa0a0), battery_scale_1dot0 }, /* Terminating entry */ { 0, 0, NULL } }; /* returns statically allocated string - must not use it again before done with result! */ static const char *tripplite_chemistry_fun(double value) { static char buf[20]; const char *model; model = dstate_getinfo("ups.productid"); /* Workaround for AVR 550U firmware bug */ if (!strcmp(model, "1003")) { return "unknown"; } /* Workaround for OMNI1000LCD firmware bug */ if (!strcmp(model, "2005")) { return "unknown"; } return HIDGetIndexString(udev, (int)value, buf, sizeof(buf)); } static info_lkp_t tripplite_chemistry[] = { { 0, NULL, tripplite_chemistry_fun, NULL } }; /* returns statically allocated string - must not use it again before done with result! */ static const char *tripplite_battvolt_fun(double value) { static char buf[8]; snprintf(buf, sizeof(buf), "%.1f", battery_scale * value); return buf; } static info_lkp_t tripplite_battvolt[] = { { 0, NULL, tripplite_battvolt_fun, NULL } }; static const char *tripplite_iovolt_fun(double value) { static char buf[8]; snprintf(buf, sizeof(buf), "%.1f", io_voltage_scale * value); return buf; } static info_lkp_t tripplite_iovolt[] = { { 0, NULL, tripplite_iovolt_fun, NULL } }; static const char *tripplite_iofreq_fun(double value) { static char buf[8]; snprintf(buf, sizeof(buf), "%.1f", io_frequency_scale * value); return buf; } static info_lkp_t tripplite_iofreq[] = { { 0, NULL, tripplite_iofreq_fun, NULL } }; static const char *tripplite_ioamp_fun(double value) { static char buf[8]; snprintf(buf, sizeof(buf), "%.1f", io_current_scale * value); return buf; } static info_lkp_t tripplite_ioamp[] = { { 0, NULL, tripplite_ioamp_fun, NULL } }; /* --------------------------------------------------------------- */ /* Vendor-specific usage table */ /* --------------------------------------------------------------- */ /* TRIPPLITE usage table */ static usage_lkp_t tripplite_usage_lkp[] = { /* currently unknown: 00ff0001, ffff007d, ffff00c0, ffff00c1, ffff00c2, ffff00c3, ffff00c4, ffff00c5, ffff00d2, ffff0091, ffff00c7 */ { "TLCustom", 0xffff0010 }, { "TLDelayBeforeStartup", 0xffff0056 }, /* in minutes */ { "TLLowVoltageTransferMax", 0xffff0057 }, { "TLLowVoltageTransferMin", 0xffff0058 }, { "TLHighVoltageTransferMax", 0xffff0059 }, { "TLHighVoltageTransferMin", 0xffff005a }, /* Outlet state: * 1- On/Closed * 2- Off/Open * 3- On with pending off * 4- Off with pending on * 5- Unknown * 6- Resolved/Unknown * 7- Failed and Closed * 8- Failed and Open */ { "OutletState", 0xffff007a }, { "OutletCount", 0xffff007b }, /* Number of load segments */ { "UPSFirmwareVersion", 0xffff007c }, { "CommunicationProtocolVersion", 0xffff007d }, /* HID protocol version */ { "CommunicationVersion", 0xffff007e }, /* USB firmware version */ { "iUPSPartNumber", 0xffff007f }, /* String index to Part Number */ { "AutoOnDelay", 0xffff0080 }, /* '0' (no delay) to 'n' (delay in seconds) */ { "TLWatchdog", 0xffff0092 }, { "TLOutletsAvailableMask", 0xffff0095 }, { "TLOutletsStatusMask", 0xffff0096 }, /* it looks like Tripp Lite confused pages 0x84 and 0x85 for the following 4 items, on some OMNI1000LCD devices. */ { "TLCharging", 0x00840044 }, /* conflicts with HID spec! */ /* conflicts with HID spec (and HP implementation) for TrippLite! * Refer to tripplite_discharging_info */ { "TLDischarging", 0x00840045 }, { "TLNeedReplacement", 0x0084004b }, { "TLACPresent", 0x008400d0 }, { NULL, 0 } }; static usage_tables_t tripplite_utab[] = { tripplite_usage_lkp, /* tripplite lookup table; make sure this is first */ hid_usage_lkp, /* generic lookup table */ NULL, }; /* --------------------------------------------------------------- */ /* HID2NUT lookup table */ /* --------------------------------------------------------------- */ /* HID2NUT lookup table */ static hid_info_t tripplite_hid2nut[] = { #if WITH_UNMAPPED_DATA_POINTS || (defined USBHID_UPS_TRIPPLITE_DEBUG) /* unmapped variables - meaning unknown */ { "UPS.Flow.0xffff0097", 0, 0, "UPS.Flow.0xffff0097", NULL, "%.0f", 0, NULL }, { "UPS.TLCustom.[1].0xffff0075", 0, 0, "UPS.TLCustom.[1].0xffff0075", NULL, "%.0f", 0, NULL }, { "UPS.TLCustom.[1].0xffff0076", 0, 0, "UPS.TLCustom.[1].0xffff0076", NULL, "%.0f", 0, NULL }, { "UPS.TLCustom.[1].0xffff007c", 0, 0, "UPS.TLCustom.[1].0xffff007c", NULL, "%.0f", 0, NULL }, { "UPS.TLCustom.[1].0xffff007d", 0, 0, "UPS.TLCustom.[1].0xffff007d", NULL, "%.0f", 0, NULL }, { "UPS.TLCustom.[1].0xffff00e0", 0, 0, "UPS.TLCustom.[1].0xffff00e0", NULL, "%.0f", 0, NULL }, { "UPS.TLCustom.[1].0xffff00e1", 0, 0, "UPS.TLCustom.[1].0xffff00e1", NULL, "%.0f", 0, NULL }, { "UPS.TLCustom.[1].0xffff00e2", 0, 0, "UPS.TLCustom.[1].0xffff00e2", NULL, "%.0f", 0, NULL }, { "UPS.TLCustom.[1].0xffff00e3", 0, 0, "UPS.TLCustom.[1].0xffff00e3", NULL, "%.0f", 0, NULL }, { "UPS.TLCustom.[1].0xffff00e4", 0, 0, "UPS.TLCustom.[1].0xffff00e4", NULL, "%.0f", 0, NULL }, { "UPS.TLCustom.[1].0xffff00e5", 0, 0, "UPS.TLCustom.[1].0xffff00e5", NULL, "%.0f", 0, NULL }, { "UPS.TLCustom.[1].0xffff00e6", 0, 0, "UPS.TLCustom.[1].0xffff00e6", NULL, "%.0f", 0, NULL }, { "UPS.TLCustom.[1].0xffff00e7", 0, 0, "UPS.TLCustom.[1].0xffff00e7", NULL, "%.0f", 0, NULL }, { "UPS.TLCustom.[1].0xffff00e8", 0, 0, "UPS.TLCustom.[1].0xffff00e8", NULL, "%.0f", 0, NULL }, { "UPS.0xffff0015.[1].0xffff00c0", 0, 0, "UPS.0xffff0015.[1].0xffff00c0", NULL, "%.0f", 0, NULL }, { "UPS.0xffff0015.[1].0xffff00c1", 0, 0, "UPS.0xffff0015.[1].0xffff00c1", NULL, "%.0f", 0, NULL }, { "UPS.0xffff0015.[1].0xffff00c2", 0, 0, "UPS.0xffff0015.[1].0xffff00c2", NULL, "%.0f", 0, NULL }, { "UPS.0xffff0015.[1].0xffff00c3", 0, 0, "UPS.0xffff0015.[1].0xffff00c3", NULL, "%.0f", 0, NULL }, { "UPS.0xffff0015.[1].0xffff00c4", 0, 0, "UPS.0xffff0015.[1].0xffff00c4", NULL, "%.0f", 0, NULL }, { "UPS.0xffff0015.[1].0xffff00c5", 0, 0, "UPS.0xffff0015.[1].0xffff00c5", NULL, "%.0f", 0, NULL }, { "UPS.0xffff0015.[1].0xffff00d2", 0, 0, "UPS.0xffff0015.[1].0xffff00d2", NULL, "%.0f", 0, NULL }, { "UPS.0xffff0015.[1].0xffff00d3", 0, 0, "UPS.0xffff0015.[1].0xffff00d3", NULL, "%.0f", 0, NULL }, { "UPS.0xffff0015.[1].0xffff00d6", 0, 0, "UPS.0xffff0015.[1].0xffff00d6", NULL, "%.0f", 0, NULL }, { "UPS.OutletSystem.Outlet.0xffff0081", 0, 0, "UPS.OutletSystem.Outlet.0xffff0081", NULL, "%.0f", 0, NULL }, { "UPS.OutletSystem.Outlet.0xffff0091", 0, 0, "UPS.OutletSystem.Outlet.0xffff0091", NULL, "%.0f", 0, NULL }, { "UPS.OutletSystem.Outlet.0xffff0093", 0, 0, "UPS.OutletSystem.Outlet.0xffff0093", NULL, "%.0f", 0, NULL }, { "UPS.OutletSystem.Outlet.0xffff0095", 0, 0, "UPS.OutletSystem.Outlet.0xffff0095", NULL, "%.0f", 0, NULL }, { "UPS.OutletSystem.Outlet.0xffff0096", 0, 0, "UPS.OutletSystem.Outlet.0xffff0096", NULL, "%.0f", 0, NULL }, { "UPS.OutletSystem.Outlet.0xffff0098", 0, 0, "UPS.OutletSystem.Outlet.0xffff0098", NULL, "%.0f", 0, NULL }, { "UPS.OutletSystem.Outlet.0xffff00a2", 0, 0, "UPS.OutletSystem.Outlet.0xffff00a2", NULL, "%.0f", 0, NULL }, { "UPS.OutletSystem.Outlet.0xffff00a4", 0, 0, "UPS.OutletSystem.Outlet.0xffff00a4", NULL, "%.0f", 0, NULL }, { "UPS.OutletSystem.Outlet.0xffff00a7", 0, 0, "UPS.OutletSystem.Outlet.0xffff00a7", NULL, "%.0f", 0, NULL }, { "UPS.OutletSystem.Outlet.0xffff00a9", 0, 0, "UPS.OutletSystem.Outlet.0xffff00a9", NULL, "%.0f", 0, NULL }, { "UPS.OutletSystem.Outlet.0xffff00aa", 0, 0, "UPS.OutletSystem.Outlet.0xffff00aa", NULL, "%.0f", 0, NULL }, { "UPS.OutletSystem.Outlet.0xffff00ab", 0, 0, "UPS.OutletSystem.Outlet.0xffff00ab", NULL, "%.0f", 0, NULL }, { "UPS.OutletSystem.Outlet.0xffff00ac", 0, 0, "UPS.OutletSystem.Outlet.0xffff00ac", NULL, "%.0f", 0, NULL }, { "UPS.PowerSummary.iOEMInformation", 0, 0, "UPS.PowerSummary.iOEMInformation", NULL, "%s", HU_FLAG_STATIC, stringid_conversion }, #endif /* if WITH_UNMAPPED_DATA_POINTS || USBHID_UPS_TRIPPLITE_DEBUG */ /* Device page */ { "device.part", 0, 0, "UPS.TLCustom.[1].iUPSPartNumber", NULL, "%s", HU_FLAG_STATIC, stringid_conversion }, /* Battery page */ { "battery.charge", 0, 0, "UPS.PowerSummary.RemainingCapacity", NULL, "%.0f", 0, NULL }, { "battery.charge", 0, 0, "UPS.BatterySystem.Battery.RemainingCapacity", NULL, "%.0f", 0, NULL }, { "battery.charge.low", ST_FLAG_RW | ST_FLAG_STRING, 5, "UPS.PowerSummary.RemainingCapacityLimit", NULL, "%.0f", HU_FLAG_SEMI_STATIC, NULL }, { "battery.charge.warning", 0, 0, "UPS.PowerSummary.WarningCapacityLimit", NULL, "%.0f", 0, NULL }, { "battery.runtime", 0, 0, "UPS.PowerSummary.RunTimeToEmpty", NULL, "%.0f", 0, NULL }, { "battery.voltage.nominal", 0, 0, "UPS.BatterySystem.Battery.ConfigVoltage", NULL, "%.1f", HU_FLAG_STATIC, NULL }, { "battery.voltage", 0, 0, "UPS.BatterySystem.Battery.Voltage", NULL, "%s", 0, tripplite_battvolt }, { "battery.type", 0, 0, "UPS.PowerSummary.iDeviceChemistry", NULL, "%s", HU_FLAG_STATIC, tripplite_chemistry }, { "battery.temperature", 0, 0, "UPS.BatterySystem.Temperature", NULL, "%s", 0, kelvin_celsius_conversion }, /* UPS page */ { "ups.delay.start", ST_FLAG_RW | ST_FLAG_STRING, 10, "UPS.OutletSystem.Outlet.DelayBeforeStartup", NULL, DEFAULT_ONDELAY, HU_FLAG_ABSENT, NULL}, { "ups.delay.start", ST_FLAG_RW | ST_FLAG_STRING, 10, "UPS.OutletSystem.Outlet.TLDelayBeforeStartup", NULL, DEFAULT_ONDELAY, HU_FLAG_ABSENT, NULL}, /* FIXME { "ups.delay.start", ST_FLAG_RW | ST_FLAG_STRING, 6, "UPS.TLCustom.[1].TLDelayBeforeStartup", NULL, DEFAULT_ONDELAY, HU_FLAG_ABSENT, NULL}, { "ups.timer.start", 0, 0, "UPS.TLCustom.[1].DelayBeforeStartup", NULL, "%.0f", HU_FLAG_QUICK_POLL, NULL}, - what's the right notion behind this one? { "ups.delay.start", ST_FLAG_RW | ST_FLAG_STRING, 6, "UPS.TLCustom.[1].AutoOnDelay", NULL, DEFAULT_ONDELAY, 0, NULL}, */ { "ups.delay.shutdown", ST_FLAG_RW | ST_FLAG_STRING, 10, "UPS.OutletSystem.Outlet.DelayBeforeShutdown", NULL, DEFAULT_OFFDELAY, HU_FLAG_ABSENT, NULL}, { "ups.timer.start", 0, 0, "UPS.OutletSystem.Outlet.DelayBeforeStartup", NULL, "%.0f", HU_FLAG_QUICK_POLL, NULL}, { "ups.timer.start", 0, 0, "UPS.OutletSystem.Outlet.TLDelayBeforeStartup", NULL, "%.0f", HU_FLAG_QUICK_POLL, NULL}, { "ups.timer.shutdown", 0, 0, "UPS.OutletSystem.Outlet.DelayBeforeShutdown", NULL, "%.0f", HU_FLAG_QUICK_POLL, NULL}, { "ups.timer.reboot", 0, 0, "UPS.OutletSystem.Outlet.DelayBeforeReboot", NULL, "%.0f", HU_FLAG_QUICK_POLL, NULL }, { "ups.test.result", 0, 0, "UPS.BatterySystem.Test", NULL, "%s", 0, test_read_info }, { "ups.beeper.status", 0, 0, "UPS.PowerSummary.AudibleAlarmControl", NULL, "%s", 0, beeper_info }, { "ups.power.nominal", 0, 0, "UPS.Flow.ConfigApparentPower", NULL, "%.0f", HU_FLAG_STATIC, NULL }, { "ups.power", 0, 0, "UPS.OutletSystem.Outlet.ActivePower", NULL, "%.1f", 0, NULL }, { "ups.power", 0, 0, "UPS.PowerConverter.Output.ActivePower", NULL, "%.1f", 0, NULL }, { "ups.load", 0, 0, "UPS.OutletSystem.Outlet.PercentLoad", NULL, "%.0f", 0, NULL }, /* FIXME: what is the conversion format for this one? * Example on HP T1500 G3 * UPS.TLCustom.[1].UPSFirmwareVersion, Type: Feature, ReportID: 0x0f, Offset: 0, Size: 16, Value: 262 */ { "ups.firmware", 0, 0, "UPS.TLCustom.[1].UPSFirmwareVersion", NULL, "%.0f", HU_FLAG_STATIC, NULL }, /* Number of seconds left before the watchdog reboots the UPS (0 = disabled) */ { "ups.watchdog.status", 0, 0, "UPS.OutletSystem.Outlet.TLWatchdog", NULL, "%.0f", 0, NULL }, /* Special case: ups.status */ { "BOOL", 0, 0, "UPS.PowerSummary.PresentStatus.InternalFailure", NULL, NULL, 0, commfault_info }, { "BOOL", 0, 0, "UPS.PowerSummary.PresentStatus.ShutdownImminent", NULL, NULL, 0, shutdownimm_info }, { "BOOL", 0, 0, "UPS.PowerSummary.PresentStatus.ACPresent", NULL, NULL, HU_FLAG_QUICK_POLL, online_info }, { "BOOL", 0, 0, "UPS.PowerSummary.PresentStatus.BelowRemainingCapacityLimit", NULL, NULL, HU_FLAG_QUICK_POLL, lowbatt_info }, { "BOOL", 0, 0, "UPS.PowerSummary.PresentStatus.FullyCharged", NULL, NULL, HU_FLAG_QUICK_POLL, fullycharged_info }, { "BOOL", 0, 0, "UPS.PowerSummary.PresentStatus.Charging", NULL, NULL, HU_FLAG_QUICK_POLL, charging_info }, { "BOOL", 0, 0, "UPS.PowerSummary.PresentStatus.Discharging", NULL, NULL, HU_FLAG_QUICK_POLL, discharging_info }, { "BOOL", 0, 0, "UPS.PowerSummary.PresentStatus.FullyDischarged", NULL, NULL, HU_FLAG_QUICK_POLL, depleted_info }, { "BOOL", 0, 0, "UPS.PowerSummary.PresentStatus.NeedReplacement", NULL, NULL, 0, replacebatt_info }, /* repeat some of the above for faulty usage codes (seen on OMNI1000LCD, untested) */ { "BOOL", 0, 0, "UPS.PowerSummary.PresentStatus.TLACPresent", NULL, NULL, HU_FLAG_QUICK_POLL, online_info }, /* "Redundant" definition to deal with the conflict between * TrippLite units, wrongly defining 0x00840045 as "TLDischarging" * and HP which uses the standard 0x00840045 (as ConfigPercentLoad). * Note that this path should not exist on HP devices. */ { "BOOL", 0, 0, "UPS.PowerSummary.PresentStatus.TLDischarging", NULL, NULL, HU_FLAG_QUICK_POLL, discharging_info }, /* Otherwise, define the version for HP devices */ { "ups.load.nominal", 0, 0, "UPS.Flow.ConfigPercentLoad", NULL, "%.0f", 0, NULL }, { "BOOL", 0, 0, "UPS.PowerSummary.PresentStatus.TLCharging", NULL, NULL, HU_FLAG_QUICK_POLL, charging_info }, { "BOOL", 0, 0, "UPS.PowerSummary.PresentStatus.TLNeedReplacement", NULL, NULL, 0, replacebatt_info }, { "BOOL", 0, 0, "UPS.PowerConverter.PresentStatus.VoltageOutOfRange", NULL, NULL, 0, vrange_info }, { "BOOL", 0, 0, "UPS.PowerConverter.PresentStatus.Buck", NULL, NULL, 0, trim_info }, { "BOOL", 0, 0, "UPS.PowerConverter.PresentStatus.Boost", NULL, NULL, 0, boost_info }, { "BOOL", 0, 0, "UPS.PowerConverter.PresentStatus.Overload", NULL, NULL, 0, overload_info }, /* This is probably not the correct mapping for all models */ /* { "BOOL", 0, 0, "UPS.PowerConverter.PresentStatus.Used", NULL, NULL, 0, nobattery_info }, */ { "BOOL", 0, 0, "UPS.PowerConverter.PresentStatus.OverTemperature", NULL, NULL, 0, overheat_info }, { "BOOL", 0, 0, "UPS.PowerConverter.PresentStatus.InternalFailure", NULL, NULL, 0, commfault_info }, { "BOOL", 0, 0, "UPS.PowerConverter.PresentStatus.AwaitingPower", NULL, NULL, 0, awaitingpower_info }, /* Duplicated values { "BOOL", 0, 0, "UPS.BatterySystem.Battery.PresentStatus.BelowRemainingCapacityLimit", NULL, NULL, HU_FLAG_QUICK_POLL, lowbatt_info }, { "BOOL", 0, 0, "UPS.BatterySystem.Battery.PresentStatus.FullyCharged", NULL, NULL, HU_FLAG_QUICK_POLL, fullycharged_info }, { "BOOL", 0, 0, "UPS.BatterySystem.Battery.PresentStatus.Charging", NULL, NULL, HU_FLAG_QUICK_POLL, charging_info }, { "BOOL", 0, 0, "UPS.BatterySystem.Battery.PresentStatus.Discharging", NULL, NULL, HU_FLAG_QUICK_POLL, discharging_info }, { "BOOL", 0, 0, "UPS.BatterySystem.Battery.PresentStatus.FullyDischarged", NULL, NULL, HU_FLAG_QUICK_POLL, depleted_info }, { "BOOL", 0, 0, "UPS.BatterySystem.Battery.PresentStatus.NeedReplacement", NULL, NULL, 0, replacebatt_info }, */ /* Input page */ { "input.voltage.nominal", 0, 0, "UPS.PowerSummary.Input.ConfigVoltage", NULL, "%.0f", HU_FLAG_STATIC, NULL }, { "input.voltage", 0, 0, "UPS.PowerSummary.Input.Voltage", NULL, "%s", 0, tripplite_iovolt }, { "input.voltage", 0, 0, "UPS.PowerConverter.Input.Voltage", NULL, "%s", 0, tripplite_iovolt }, { "input.frequency", 0, 0, "UPS.PowerConverter.Input.Frequency", NULL, "%s", 0, tripplite_iofreq }, { "input.transfer.low", ST_FLAG_RW | ST_FLAG_STRING, 5, "UPS.PowerConverter.Output.LowVoltageTransfer", NULL, "%.1f", HU_FLAG_SEMI_STATIC, NULL }, { "input.transfer.low.max", 0, 0, "UPS.PowerConverter.Output.TLLowVoltageTransferMax", NULL, "%.0f", HU_FLAG_STATIC, NULL }, { "input.transfer.low.min", 0, 0, "UPS.PowerConverter.Output.TLLowVoltageTransferMin", NULL, "%.0f", HU_FLAG_STATIC, NULL }, { "input.transfer.high", ST_FLAG_RW | ST_FLAG_STRING, 5, "UPS.PowerConverter.Output.HighVoltageTransfer", NULL, "%.1f", HU_FLAG_SEMI_STATIC, NULL }, { "input.transfer.high.max", 0, 0, "UPS.PowerConverter.Output.TLHighVoltageTransferMax", NULL, "%.0f", HU_FLAG_STATIC, NULL }, { "input.transfer.high.min", 0, 0, "UPS.PowerConverter.Output.TLHighVoltageTransferMin", NULL, "%.0f", HU_FLAG_STATIC, NULL }, /* Output page */ { "output.voltage.nominal", 0, 0, "UPS.Flow.ConfigVoltage", NULL, "%.0f", HU_FLAG_STATIC, NULL }, { "output.voltage", 0, 0, "UPS.PowerConverter.Output.Voltage", NULL, "%s", 0, tripplite_iovolt }, { "output.voltage", 0, 0, "UPS.PowerSummary.Voltage", NULL, "%s", 0, tripplite_iovolt }, { "output.current", 0, 0, "UPS.PowerConverter.Output.Current", NULL, "%s", 0, tripplite_ioamp }, { "output.frequency.nominal", 0, 0, "UPS.Flow.ConfigFrequency", NULL, "%.0f", HU_FLAG_STATIC, NULL }, { "output.frequency", 0, 0, "UPS.PowerConverter.Output.Frequency", NULL, "%s", 0, tripplite_iofreq }, /* instant commands. */ { "test.battery.start.quick", 0, 0, "UPS.BatterySystem.Test", NULL, "1", HU_TYPE_CMD, NULL }, /* reported to work on OMNI1000 */ { "test.battery.start.deep", 0, 0, "UPS.BatterySystem.Test", NULL, "2", HU_TYPE_CMD, NULL }, /* reported not to work */ { "test.battery.stop", 0, 0, "UPS.BatterySystem.Test", NULL, "3", HU_TYPE_CMD, NULL }, /* reported not to work */ { "load.off.delay", 0, 0, "UPS.OutletSystem.Outlet.DelayBeforeShutdown", NULL, DEFAULT_OFFDELAY, HU_TYPE_CMD, NULL }, { "load.on.delay", 0, 0, "UPS.OutletSystem.Outlet.DelayBeforeStartup", NULL, DEFAULT_ONDELAY, HU_TYPE_CMD, NULL }, { "load.on.delay", 0, 0, "UPS.OutletSystem.Outlet.TLDelayBeforeStartup", NULL, DEFAULT_ONDELAY, HU_TYPE_CMD, NULL }, { "shutdown.stop", 0, 0, "UPS.OutletSystem.Outlet.DelayBeforeShutdown", NULL, "-1", HU_TYPE_CMD, NULL }, { "shutdown.reboot", 0, 0, "UPS.OutletSystem.Outlet.DelayBeforeReboot", NULL, "10", HU_TYPE_CMD, NULL }, /* NOTE: the ECO550UPS doesn't support DelayBeforeStartup, so we use the watchdog to trigger a reboot */ { "shutdown.reboot", 0, 0, "UPS.OutletSystem.Outlet.TLWatchdog", NULL, "10", HU_TYPE_CMD, NULL }, /* WARNING: if this timer expires, the UPS will reboot! Defaults to 60 seconds */ { "reset.watchdog", 0, 0, "UPS.OutletSystem.Outlet.TLWatchdog", NULL, "60", HU_TYPE_CMD, NULL }, { "beeper.on", 0, 0, "UPS.PowerSummary.AudibleAlarmControl", NULL, "2", HU_TYPE_CMD, NULL }, { "beeper.off", 0, 0, "UPS.PowerSummary.AudibleAlarmControl", NULL, "3", HU_TYPE_CMD, NULL }, { "beeper.disable", 0, 0, "UPS.PowerSummary.AudibleAlarmControl", NULL, "1", HU_TYPE_CMD, NULL }, { "beeper.enable", 0, 0, "UPS.PowerSummary.AudibleAlarmControl", NULL, "2", HU_TYPE_CMD, NULL }, { "beeper.mute", 0, 0, "UPS.PowerSummary.AudibleAlarmControl", NULL, "3", HU_TYPE_CMD, NULL }, /* FIXME (to be tested): HP specific (may conflict or differ from TL implementation!) * { "outlet.count", 0, 0, "UPS.TLCustom.[1].OutletCount", NULL, "%.0f", HU_FLAG_STATIC, NULL }, * { "outlet.status", 0, 0, "UPS.TLCustom.[1].OutletState", NULL, "%.0f", HU_FLAG_STATIC, NULL }, 0.284486 Path: UPS.TLCustom.[1].ffff00ff, Type: Feature, ReportID: 0xff, Offset: 0, Size: 8, Value: 255 0.285276 Path: UPS.TLCustom.[1].OutletCount, Type: Feature, ReportID: 0x6d, Offset: 0, Size: 8, Value: 1 0.286260 Path: UPS.TLCustom.[1].OutletState, Type: Feature, ReportID: 0x70, Offset: 0, Size: 8, Value: 1 0.287248 Path: UPS.TLCustom.[1].CommunicationVersion, Type: Feature, ReportID: 0x0e, Offset: 0, Size: 16, Value: 262 0.288901 Path: UPS.TLCustom.[1].CommunicationProtocolVersion, Type: Feature, ReportID: 0x6c, Offset: 0, Size: 16, Value: 2560 0.289903 Path: UPS.TLCustom.[1].TLDelayBeforeStartup, Type: Feature, ReportID: 0x71, Offset: 0, Size: 16, Value: 65535 0.290854 Path: UPS.TLCustom.[1].AutoOnDelay, Type: Feature, ReportID: 0x72, Offset: 0, Size: 16, Value: 65535 */ /* end of structure. */ { NULL, 0, 0, NULL, NULL, NULL, 0, NULL } }; static const char *tripplite_format_model(HIDDevice_t *hd) { return hd->Product; } static const char *tripplite_format_mfr(HIDDevice_t *hd) { return hd->Vendor; } static const char *tripplite_format_serial(HIDDevice_t *hd) { return hd->Serial; } /* this function allows the subdriver to "claim" a device: return 1 if * the device is supported by this subdriver, else 0. */ static int tripplite_claim(HIDDevice_t *hd) { int status = is_usb_device_supported(tripplite_usb_device_table, hd); switch (status) { case POSSIBLY_SUPPORTED: switch (hd->VendorID) { case HP_VENDORID: /* by default, reject, unless the productid option is given */ if (getval("productid")) { return 1; } /* * this vendor makes lots of USB devices that are * not a UPS, so don't use possibly_supported here */ return 0; case TRIPPLITE_VENDORID: /* reject known non-HID devices */ /* not all Tripp Lite products are HID, some are "serial over USB". */ if (hd->ProductID == 0x0001) { /* e.g. SMART550USB, SMART3000RM2U */ upsdebugx(0, "This Tripp Lite device (%04x/%04x) is not supported by usbhid-ups.\n" "Please use the tripplite_usb driver instead.\n", hd->VendorID, hd->ProductID); return 0; } /* by default, reject, unless the productid option is given */ if (getval("productid")) { return 1; } possibly_supported("TrippLite", hd); return 0; /* catch all (not really needed) */ default: return 0; } case SUPPORTED: return 1; case NOT_SUPPORTED: default: return 0; } } subdriver_t tripplite_subdriver = { TRIPPLITE_HID_VERSION, tripplite_claim, tripplite_utab, tripplite_hid2nut, tripplite_format_model, tripplite_format_mfr, tripplite_format_serial, fix_report_desc, }; nut-2.8.1/drivers/solis.h0000644000175000017500000004673114500336654012252 00000000000000/* solis.h - Microsol Solis UPS hardware Copyright (C) 2004 Silvino B. Magalhaes 2019 Roberto Panerai Velloso 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 2 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, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 2004/10/10 - Version 0.10 - Initial release 2004/10/20 - Version 0.20 - add Battery information in driver 2004/10/26 - Version 0.30 - add commands and test shutdown 2004/10/30 - Version 0.40 - add model data structs 2004/11/22 - Version 0.50 - add internal e external shutdown programming 2005/06/16 - Version 0.60 - save external shutdown programming to ups, support new cables and Solaris compilation 2015/09/19 - Version 0.63 - patch for correct reading for Microsol Back-Ups BZ1200-BR */ #ifndef INCLUDED_SOLIS_H #define INCLUDED_SOLIS_H #include "nut_stdint.h" /* General FIXMEs: * * "static" declarations belong in some one single C source; * headers should use "extern" to refer linker to look for * vars in other object files * * use a common definition of bool_t */ typedef int bool_t; /* autonomy constants */ static const int bext[5] = {14,18,28,18,1}; static const int nompow[5] = { 1000,1500,2000,3000,1200 }; static const int inds[6] = { 0,0,1,2,3,4 }; static const double InVolt_offset = 30.; #define PACKET_SIZE 25 static const size_t packet_size = PACKET_SIZE; static const struct { int maxi; /* power internals */ int minc[21]; /* power minimal index */ int maxc[21]; /* power maximus index */ int mm[21][39]; /* autonomy time [minutes] */ } auton[5] = {{ 7, { 139,139,142,141,141,141,141,0,0,0,0,0,0,0,0,0,0,0,0,0,0 } , { 176,174,172,172,170,170,170,0,0,0,0,0,0,0,0,0,0,0,0,0,0 } , { { 1,1,1,1,2,2,2,2,3,3,3,3,4,4,5,5,6,7,8,10,11,12,15,17,19,22,25,28,31,35,40,43,47,52,59,64,68,75,75 }, { 1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,5,5,6,7,8,9,10,11,12,13,15,18,20,21,24,28,30,32,33,33,34,34,34,34 }, { 1,1,1,1,1,1,1,1,1,1,2,2,2,2,3,3,4,4,5,5,6,7,8,9,10,11,12,13,15,17,19,21,22,23,23,23,23,23,23 }, { 1,1,1,1,1,1,1,1,1,1,1,1,2,2,2,3,3,4,4,4,5,6,7,7,8,9,19,11,12,13,14,16,18,20,20,20,20,20,20 }, { 1,1,1,1,1,1,1,1,1,1,2,2,2,2,3,3,3,4,5,5,6,6,6,7,7,8,8,10,11,12,13,14,14,14,14,14,14,14,14 }, { 1,1,1,1,1,1,1,1,1,1,2,2,2,3,3,3,3,4,4,5,6,6,6,7,7,8,9,10,11,12,12,12,12,12,12,12,12,12,12 }, { 1,1,1,1,1,1,1,2,2,2,2,2,3,3,3,4,4,5,5,6,6,6,7,7,8,9,10,10,10,10,10,10,10,10,10,10,10,10,10 }, { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 }, { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 }, { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 }, { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 }, { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 }, { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 }, { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 }, { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 }, { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 }, { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 }, { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 }, { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 }, { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 }, { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 }, },}, { 10, { 141,141,141,141,141,141,141,141,141,141,0,0,0,0,0,0,0,0,0,0,0 } , { 177,177,177,172,173,172,172,172,172,172,0,0,0,0,0,0,0,0,0,0,0 } , { { 1,1,1,1,1,1,1,1,1,2,2,3,3,5,6,7,9,10,12,15,16,18,22,25,27,30,36,42,45,48,55,60,64,70,78, 84,90,97,104 }, { 1,1,1,1,1,1,1,1,1,2,2,2,3,2,3,4,5,6,7,8,10,12,13,14,16,19,22,25,28,30,35,38,42,46,52,55, 58,60,62 }, { 1,1,1,1,1,1,1,1,1,1,2,2,2,3,3,4,4,4,5,7,9,10,12,13,16,20,21,23,26,28,30,34,35,37,38,39,40 ,40,40 }, { 1,1,1,1,1,1,1,1,1,1,1,2,2,2,3,3,4,4,4,5,6,7,8,9,10,11,13,14,16,18,21,22,24,27,27,27,27,27,27 }, { 1,1,1,1,1,1,1,1,1,2,2,2,2,3,3,4,4,4,4,4,5,6,7,8,9,10,11,12,14,15,16,19,20,22,23,23,23,23,23 }, { 1,1,1,1,1,1,1,1,1,1,2,2,2,3,3,3,3,4,4,4,4,5,6,7,8,9,10,11,12,13,14,16,17,18,18,18,18,18,18 }, { 1,1,1,1,1,1,1,1,1,1,1,1,1,2,2,2,2,3,4,4,4,4,4,5,7,7,7,8,9,10,11,12,14,14,14,14,14,14,14 }, { 1,1,1,1,1,1,1,1,1,1,2,2,2,3,3,3,4,4,4,4,4,5,6,7,7,8,8,9,10,11,12,13,13,13,13,13,13,13,13 }, { 1,1,1,1,1,1,1,1,1,1,2,2,2,2,2,2,3,3,4,4,4,4,4,5,6,7,7,8,9,10,10,11,11,12,12,12,12,12,12 }, { 1,1,1,1,1,1,1,1,1,1,1,2,2,2,3,3,3,4,4,4,4,5,6,6,7,7,8,8,8,9,9,10,10,10,10,10,10,10,10 }, { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 }, { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 }, { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 }, { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 }, { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 }, { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 }, { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 }, { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 }, { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 }, { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 }, { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 }, },}, { 13, { 141,141,141,141,141,141,141,141,141,141,141,141,141,0,0,0,0,0,0,0,0 } , { 177,177,177,172,173,172,172,172,172,172,172,172,172,0,0,0,0,0,0,0,0 } , { { 1,1,1,1,1,1,2,2,2,3,4,5,5,8,10,11,13,15,18,22,24,28,34,40,43,48,56,65,70,76,85,93,100,110,122,132,141,152,162 }, { 1,1,1,1,1,1,1,2,2,2,3,3,3,4,5,6,8,9,10,12,15,18,20,22,25,30,35,40,44,48,54,60,65,73,80,85,92,94,95 }, { 1,1,1,1,1,1,1,2,2,3,3,3,4,4,4,5,5,6,8,10,14,16,18,20,24,30,32,36,40,44,48,52,54,58,59,60 ,62,62,62 }, { 1,1,1,1,1,1,1,1,1,2,2,2,3,3,4,4,5,5,6,8,9,10,12,13,15,17,20,22,24,28,32,35,38,42,42,42,42,42,42 }, { 1,1,1,1,1,1,1,2,2,2,2,3,3,3,4,4,5,5,6,7,8,10,11,12,14,15,17,18,21,24,26,29,32,34,36,36,36,36,36 }, { 1,1,1,1,1,1,1,2,2,2,2,3,3,3,3,4,4,5,5,6,7,8,9,10,12,13,15,16,18,20,22,24,26,28,28,28,28,28,28 }, { 1,1,1,1,1,1,1,1,1,2,2,2,2,2,2,3,3,4,5,5,6,6,7,8,9,10,11,13,14,15,17,19,21,22,22,22,22,22,22 }, { 1,1,1,1,1,1,1,2,2,2,3,3,3,3,4,4,5,5,6,6,7,8,8,9,10,11,12,14,15,17,18,19,20,20,20,20,20,20,20 }, { 1,1,1,1,1,2,2,2,2,2,2,2,3,3,3,3,4,4,5,6,6,7,7,8,9,10,11,12,13,15,15,16,16,16,16,16,16,16,16 }, { 1,1,1,1,1,1,1,1,2,2,2,3,3,3,4,4,4,5,5,6,7,8,9,9,10,11,12,12,12,13,13,14,14,14,14,14,14,14,14 }, { 1,1,1,1,1,1,1,1,2,2,2,2,2,2,3,3,3,4,4,5,5,6,7,7,8,9,10,10,10,11,11,12,12,12,12,12,12,12,12 }, { 1,1,1,1,1,1,1,1,2,2,2,2,2,2,3,3,3,3,4,4,5,5,6,6,7,7,8,8,8,9,9,10,10,10,10,10,10,10,10 }, { 1,1,1,1,1,1,1,1,2,2,2,2,2,2,3,3,3,4,4,4,5,5,6,6,7,7,8,8,8,8,8,8,8,8,8,8,8,8,8 }, { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 }, { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 }, { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 }, { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 }, { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 }, { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 }, { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 }, { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 }, },}, { 21, { 141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141 } , { 177,175,173,171,169,169,168,168,167,167,166,165,164,162,160,160,160,160,159,158,157 } , { { 1,1,1,1,2,2,3,4,5,6,7,8,9,10,11,12,13,14,16,19,22,24,27,30,33,37,42,44,50,55,60,65,70,75 ,80,88,93,95,100 }, { 1,1,1,1,2,2,3,4,5,6,7,8,9,10,11,12,13,14,15,18,20,22,25,27,31,35,38,42,46,50,55,61,66,71 ,76,83,89,89,89 }, { 1,1,1,1,2,2,3,3,4,5,6,7,8,8,9,10,11,12,13,15,18,19,22,24,26,30,33,38,40,45,50,55,60,66,70,70,70,70,70 }, { 1,1,1,1,1,1,2,2,3,4,5,6,7,7,8,9,10,10,11,13,16,17,19,21,23,25,28,34,36,39,45,50,55,55,55,55,55,55,55 }, { 1,1,1,1,1,1,2,2,3,4,4,5,6,6,7,8,8,9,10,12,14,15,17,18,20,21,25,28,30,34,39,39,39,39,39,39,39,39,39 }, { 1,1,1,1,1,1,2,2,3,4,4,4,5,5,6,7,8,8,9,10,12,13,15,16,18,19,22,25,26,28,30,30,30,30,30,30,30,30,30 }, { 1,1,1,1,1,1,2,2,2,3,3,3,4,4,5,6,7,7,8,9,11,12,13,14,17,17,20,22,24,26,26,26,26,26,26,26,26,26,26 }, { 1,1,1,1,1,1,2,2,2,3,3,3,4,4,5,5,6,7,7,8,10,11,12,13,15,16,18,20,22,23,23,23,23,23,23,23,23,23,23 }, { 1,1,1,1,1,1,1,1,1,2,2,2,3,3,4,4,5,6,7,7,9,10,11,13,14,15,16,18,19,19,19,19,19,19,19,19,19,19,19 }, { 1,1,1,1,1,1,1,1,1,2,2,2,2,3,4,4,5,6,7,7,8,10,11,13,14,15,15,16,17,17,17,17,17,17,17,17,17,17,17 }, { 1,1,1,1,1,1,1,1,1,2,2,2,2,3,4,4,5,6,7,7,8,9,10,11,13,14,13,14,14,14,14,14,14,14,14,14,14,14,14 }, { 1,1,1,1,1,1,1,1,1,2,2,2,3,3,4,4,5,5,6,6,7,8,9,10,12,13,12,13,13,13,13,13,13,13,13,13,13,13,13 }, { 1,1,1,1,1,1,1,1,1,2,2,2,3,3,4,4,5,5,6,6,7,8,8,9,11,12,12,12,12,12,12,12,12,12,12,12,12,12,12 }, { 1,1,1,1,1,1,1,1,1,1,2,2,2,3,3,4,5,6,6,7,7,8,8,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9 }, { 1,1,1,1,1,1,1,1,1,1,2,2,2,3,3,4,5,6,6,7,7,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8 }, { 1,1,1,1,1,1,1,1,1,1,2,2,2,3,3,4,5,6,6,7,7,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8 }, { 1,1,1,1,1,1,1,1,1,1,2,2,2,3,3,4,4,5,5,6,7,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8 }, { 1,1,1,1,1,1,1,1,1,1,2,2,2,3,3,4,4,5,5,6,7,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8 }, { 1,1,1,1,1,1,1,1,2,2,2,2,3,3,3,4,4,5,5,6,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7 }, { 1,1,1,1,1,1,1,1,2,2,2,2,3,3,3,4,4,5,5,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6 }, { 1,1,1,1,1,1,1,1,2,2,2,2,3,3,3,4,4,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5 }, },}, { 21, { 141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141 } , { 177,175,173,171,169,169,168,168,167,167,166,165,164,162,160,160,160,160,159,158,157 } , { { 1,1,1,2,5,5,8,11,14,16,19,22,36,40,44,48,52,56,64,76,88,96,145,162, 178,199,226,237,270,297,324,351,378,405,432,475,502,513,540 }, { 1,1,1,2,3,5,8,11,14,16,19,22,36,40,44,48,52,56,60,72,80,88,135,145, 167,189,205,226,248,270,297,329,356,383,410,448,480,480,480 }, { 1,1,1,2,3,5,6,8,11,14,16,19,32,32,36,40,44,48,52,60,72,76,118,129, 140,162,178,205,216,243,270,297,324,356,378,378,378,378,378 }, { 1,1,1,2,3,4,5,6,8,11,14,16,28,28,32,36,40,40,44,52,64,68,102, 113,124,135,151,183,194,210,243,270,297,297,297,297,297,297,297 }, { 1,1,1,2,3,4,5,6,8,11,11,14,24,24,28,32,32,36,40,48,56,60,91, 97,108,113,135,151,162,183,210,210,210,210,210,210,210,210,210 }, { 1,1,1,2,3,4,5,6,8,11,11,11,20,20,24,28,32,32,36,40,48,52,81, 86,97,102,118,135,140,151,162,162,162,162,162,162,162,162,162 }, { 1,1,1,2,3,4,5,6,7,8,8,8,16,16,20,24,28,28,32,36,44,48,70,75, 91,91,108,118,129,140,140,140,140,140,140,140,140,140,140 }, { 1,1,1,2,2,3,4,5,5,8,8,8,16,16,20,20,24,28,28,32,40,44,64,70, 81,86,97,108,118,124,124,124,124,124,124,124,124,124,124 }, { 1,1,1,2,2,3,3,4,4,5,5,6,12,12,16,16,20,24,28,28,36,40,59, 70,75,81,86,97,102,102,102,102,102,102,102,102,102,102,102 }, { 1,1,1,2,2,3,3,4,4,5,5,8,10,12,16,16,20,24,28,28,32,40, 59,70,75,81,81,86,91,91,91,91,91,91,91,91,91,91,91 }, { 1,1,1,2,2,3,3,4,4,5,6,8,10,12,16,16,20,24,28,28,32,36,54, 59,70,75,70,75,75,75,75,75,75,75,75,75,75,75,75 }, { 1,1,2,2,2,2,2,2,2,5,6,8,10,12,16,18,20,22,24,26,28,36,48, 54,60,65,70,70,70,70,70,70,70,70,70,70,70,70,70 }, { 1,1,1,2,2,3,3,4,4,5,6,8,10,12,15,16,18,20,22,24,28,32,43, 48,58,64,64,64,64,64,64,64,64,64,64,64,64,64,64 }, { 1,1,1,2,2,3,3,4,4,4,5,6,8,10,12,16,20,24,26,28,30,32,42, 48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48 }, { 1,1,1,2,2,3,3,4,4,4,5,6,8,10,12,15,18,20,24,28,30,32,32, 32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32 }, { 1,1,1,2,2,3,3,4,4,4,5,6,8,10,12,16,18,22,24,28,30,32,32, 32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32 }, { 1,1,1,2,2,3,3,4,4,4,5,6,8,10,12,16,18,20,22,24,28,32,32, 32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32 }, { 1,1,1,2,2,3,3,4,4,4,5,6,8,10,12,16,18,20,22,24,28,32,32, 32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32 }, { 1,1,1,2,2,3,3,4,5,5,6,8,10,12,14,16,18,20,22,24,28,28,28, 28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28 }, { 1,1,1,2,2,3,3,4,4,5,5,6,8,10,12,16,18,20,22,24,24,24,24, 24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24 }, { 1,1,1,2,2,3,3,3,4,5,5,6,8,10,12,15,16,18,20,20,20,20,20, 20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20 } },}, }; /* ----------------------------------------------------------- * Solis constants for data ajustment * ----------------------------------------------------------- */ static const struct { double m_infreq; double m_appp_offset; double m_involt193[2]; double m_involt194[2]; double m_incurr[2]; double m_battvolt[2]; double m_outvolt_s[2][2]; double m_outvolt_i[2][2]; double m_outcurr_s[2][2]; double m_outcurr_i[2][2]; double m_utilp_s[2][2]; double m_utilp_i[2][2]; double m_appp_s[2][2]; double m_appp_i[2][2]; } ctab[6] = { { 101620.0, 25.0, { 1.141, 13.0 }, { 1.141, 13.0 }, { 22.2, 800.0 }, { 1.0/7.19, 0.0 }, { { 1.45, 13.0 },{ 1.4, 17.0 } }, { { 1.45, 13.0 },{ 1.4, 17.0 } }, { { 1.0/20.5, 0.15 }, { 1.0/20.5, 0.15 } }, { { 1.0/20.5, 0.15 }, { 1.0/20.5, 0.15 } }, { { 1.0/12.8, 16.0 }, { 1.0/12.3, 15.0 } }, { { 1.0/12.8, 16.0 }, { 1.0/12.3, 15.0 } }, { { 1.0/13.46, 16.7 }, { 1.0/12.9, 19.0 } }, { { 1.0/13.46, 16.7 }, { 1.0/12.9, 19.0 } } }, { 101715.0, 28.0, { 1.141, 12.0 }, { 2.5, -250.0 }, { 22.2, 800.0 }, { 1.0/7.19, 0.6}, { { 1.44, 13.0 }, { 1.4, 18.0 } }, { { 2.9, 13.0 }, { 3.15, 2.0 } }, { { 1.0/21.75, 0.15 }, { 1.0/21.75, 0.15 } }, { { 1.0/49.0, 0.1 }, { 1.0/49.0, 0.1 } }, { { 1.0/12.87, 15.6 }, { 1.0/12.2, 13.0 } }, { { 1.0/14.5, 20.0 }, { 1.0/14.0, 25.0 } }, { { 1.0/13.5, 16.0 }, { 1.0/12.9, 17.0 } }, { { 1.0/15.4, 22.0 }, { 1.0/14.5, 22.0 } } }, { 101620.0, 35.0, { 1.141, 13.0 }, { 2.5, -250.0 }, { 22.2, 800.0 }, { 1.0/7.0, 0.0 }, { { 1.375, 16.0 }, { 1.41, 16.0 } }, { { 2.8, 20.0 }, { 2.9, 18.0 } }, { { 1.0/16.5, 0.1 }, { 1.0/16.8, 0.0 } }, { { 1.0/32.5, 0.0 }, { 1.0/32.5, 0.0 } }, { { 1.0/10.2, 11.0 }, { 1.0/9.4, 15.0 } }, { { 1.0/10.1, 26.0 }, { 1.0/9.4, 30.0 } }, { { 1.0/10.2, 11.0 }, { 1.0/9.4, 15.0 } }, { { 1.0/10.6, 26.0 }, { 1.0/9.8, 30.0 } } }, { 101700.0, 40.0, { 1.141, 13.0 }, { 2.5, -250.0 }, { 35.0, 800.0 }, { 1.0/7.19, 1.1 }, { { 1.45, 11.8 }, { 1.65, 0.0 } }, { { 2.93, 13.0 }, { 3.0, 12.0 } }, { { 1.0/12.2, 0.32 }, { 1.0/12.2, 0.32 } }, { { 1.0/23.2, 0.2 }, { 1.0/23.2, 0.20 } }, { { 1.0/7.0, 16.5 }, { 1.0/6.85, 13.0 } }, { { 1.0/7.15, 30.0 }, { 1.0/6.87, 23.0 } }, { { 1.0/7.45, 28.0 }, { 1.0/7.25, 18.2 } }, { { 1.0/7.55, 37.0 }, { 1.0/7.25, 29.0 } } }, { 101800.0, 56.0, { 1.127, 12.0 }, { 2.5, -250.0 }, { 35.0, 1000.0 }, { 1.0/3.52, 0.0 }, { { 1.41, 13.0 }, { 1.4, 17.0 } }, { { 2.73, 25.0 }, { 2.73, 30.0 } }, { { 1.0/8.15, 0.25 }, { 1.0/8.15, 0.25 } }, { { 1.0/16.0, 0.4 }, { 1.0/15.0, 0.4 } }, { { 1.0/4.87, 19.0 }, { 1.0/4.55, 17.0 } }, { { 1.0/4.78, 52.0 }, { 1.0/4.55, 55.0 } }, { { 1.0/5.15, 29.0 }, { 1.0/4.8, 26.0 } }, { { 1.0/4.78, 52.0 }, { 1.0/4.55, 55.0 } } }, /*STAY1200_USB double m_infreq; double m_appp_offset; double m_involt193[2]; double m_involt194[2]; double m_incurr[2]; double m_battvolt[2]; double m_outvolt_s[2][2]; double m_outvolt_i[2][2]; double m_outcurr_s[2][2]; double m_outcurr_i[2][2]; double m_utilp_s[2][2]; double m_utilp_i[2][2]; double m_appp_s[2][2]; double m_appp_i[2][2]; */ { 101800.0, /* m_infreq */ 56.0, /* m_appp_offset */ { 1.64, 9.34 }, /* m_involt193 - ok */ { 2.5, -250.0 }, /* m_involt194 */ { 35.0, 1000.0 }, /* m_incurr */ { 0.1551, 0.2525 }, /* m_battvolt */ { { 1.41, 13.0 }, { 1.4, 17.0 } }, /* m_outvolt_s */ { { 2.73, 25.0 }, { 2.73, 30.0 } }, /* m_outvolt_i */ { { 1.0/8.15, 0.25 }, { 1.0/8.15, 0.25 } }, /* m_outcurr_s */ { { 1.0/16.0, 0.4 }, { 1.0/15.0, 0.4 } }, /* m_outcurr_i */ { { 1.0/4.87, 19.0 }, { 1.0/4.55, 17.0 } }, /* m_utilp_s */ { { 1.0/4.78, 52.0 }, { 1.0/4.55, 55.0 } }, /* m_utilp_i */ { { 1.0/5.15, 29.0 }, { 1.0/4.8, 26.0 } }, /* m__app_s */ { { 1.0/4.78, 52.0 }, { 1.0/4.55, 55.0 } } /* m_app_i */ } }; /* Date, time and programming group */ static int const BASE_YEAR = 1998; /* Note: code below uses relative "unsigned char" years */ static int Day, Month, Year; static int isprogram = 0, progshut = 0, prgups = 0; static int dian=0, mesn=0, anon=0, weekn=0; static int dhour, dmin, lhour, lmin, ihour,imin, isec, hourshut, minshut; static uint8_t DaysOnWeek=0, DaysOffWeek=0, DaysStd = 0; static char seman[4]; /* buffers */ static unsigned char RecPack[PACKET_SIZE]; static unsigned char ConfigPack[12]; /* unsigned char MibData[161]; unsigned char DumpPack[242]; */ /* Identification */ static const char *Model; static int SolisModel, imodel; static int InputValue, Out220; /* Status group */ static unsigned char InputStatus,OutputStatus, BattStatus; /* Events group */ static unsigned char SourceEvents, OutputEvents, BattEvents; /* logical */ static bool_t detected = 0; static bool_t SourceFail, SourceLast, FailureFlag, SourceReturn, SuperHeat; static bool_t SuperHeatLast, OverCharge, OverChargeLast, LowBatt; static bool_t CriticBatt, CriticBattLast, Flag_inversor, InversorOn, InversorOnLast; /* Input group */ static double InVoltage, InCurrent, InFreq; static double InDownLim, InUpLim, NomInVolt; /* Output group */ static double OutVoltage, OutCurrent, OutFreq, OutDownLim, OutUpLim, NomOutVolt; /* Battery group */ static int Autonomy, BattExtension, maxauto; static double BattVoltage, Temperature, batcharge; /* Power group */ static double AppPower, UtilPower, upscharge; static int ChargePowerFactor, NominalPower, UpsPowerFactor; static void print_info(void); static int is_today( unsigned char, int ); static void autonomy_calc( int ); static void scan_received_pack(void); static void comm_receive(const unsigned char*, size_t); static void get_base_info(void); static void get_update_info(void); #endif /* INCLUDED_SOLIS_H */ nut-2.8.1/drivers/apc-hid.h0000644000175000017500000000221714500336654012415 00000000000000/* apc-hid.h - data to monitor APC USB/HID devices with NUT * * Copyright (C) * 2003 - 2005 Arnaud Quette * 2005 John Stamp * 2005 Peter Selinger * * Sponsored by MGE UPS SYSTEMS * * 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 2 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, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #ifndef APC_HID_H #define APC_HID_H #include "usbhid-ups.h" extern subdriver_t apc_subdriver; #endif /* APC_HID_H */ nut-2.8.1/drivers/solis.c0000644000175000017500000006440014502253356012235 00000000000000/* solis.c - driver for Microsol Solis UPS hardware Copyright (C) 2004 Silvino B. Magalhães 2019 Roberto Panerai Velloso 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 2 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, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 2004/10/10 - Version 0.10 - Initial release 2004/10/20 - Version 0.20 - add Battery information in driver 2004/10/26 - Version 0.30 - add commands and test shutdown 2004/10/30 - Version 0.40 - add model data structs 2005/06/30 - Version 0.41 - patch for solaris compability 2005/07/01 - Version 0.50 - add internal e external shutdown programming 2005/08/18 - Version 0.60 - save external shutdown programming to ups, and support new cables for solis 3 2015/09/19 - Version 0.65 - patch for correct reading for Microsol Back-Ups BZ1200-BR 2017/12/21 - Version 0.66 - remove memory leaks (unfreed strdup()s); remove ser_flush_in calls that were causing desync issues; other minor improvements in source code. (see the version control logs for more recent updates) Microsol contributed with UPS Solis 1.5 HS 1.5 KVA for my tests. http://www.microsol.com.br */ #include "main.h" /* Includes "config.h", must be first */ #include #include #include "nut_stdint.h" #include "serial.h" #include "nut_float.h" #include "solis.h" #include "timehead.h" #define DRIVER_NAME "Microsol Solis UPS driver" #define DRIVER_VERSION "0.69" /* driver description structure */ upsdrv_info_t upsdrv_info = { DRIVER_NAME, DRIVER_VERSION, "Silvino B. Magalhães " \ "Roberto Panerai Velloso ", DRV_STABLE, { NULL } }; #define false 0 #define true 1 #define RESP_END 0xFE #define ENDCHAR 13 /* replies end with CR */ /* solis commands */ #define CMD_UPSCONT 0xCC #define CMD_SHUT 0xDD #define CMD_SHUTRET 0xDE #define CMD_EVENT 0xCE #define CMD_DUMP 0xCD /* comment on english language */ /* #define PORTUGUESE */ /* The following Portuguese strings are in UTF-8. */ #ifdef PORTUGUESE #define M_UNKN "Modêlo solis desconhecido\n" #define NO_SOLIS "Solis não detectado! abortando ...\n" #define UPS_DATE "Data no UPS %4d/%02d/%02d\n" #define SYS_DATE "Data do Sistema %4d/%02d/%02d dia da semana %s\n" #define ERR_PACK "Pacote errado\n" #define NO_EVENT "Não há eventos\n" #define UPS_TIME "Hora interna UPS %0d:%02d:%02d\n" #define PRG_DAYS "Shutdown Programavel Dom Seg Ter Qua Qui Sex Sab\n" #define PRG_ONON "Programação shutdown ativa externa\n" #define PRG_ONOU "Programação shutdown ativa interna\n" #define TIME_OFF "UPS Hora desligar %02d:%02d\n" #define TIME_ON "UPS Hora ligar %02d:%02d\n" #define PRG_ONOF "Programação shutdown desativada\n" #define TODAY_DD "Desligamento hoje as %02d:%02d\n" #define SHUT_NOW "Shutdown iminente!\n" #else #define M_UNKN "Unknown solis model\n" #define NO_SOLIS "Solis not detected! aborting ...\n" #define UPS_DATE "UPS Date %4d/%02d/%02d\n" #define SYS_DATE "System Date %4d/%02d/%02d day of week %s\n" #define ERR_PACK "Wrong package\n" #define NO_EVENT "No events\n" #define UPS_TIME "UPS internal Time %0d:%02d:%02d\n" #define PRG_DAYS "Programming Shutdown Sun Mon Tue Wed Thu Fri Sat\n" #define PRG_ONON "External shutdown programming active\n" #define PRG_ONOU "Internal shutdown programming atcive\n" #define TIME_OFF "UPS Time power off %02d:%02d\n" #define TIME_ON "UPS Time power on %02d:%02d\n" #define PRG_ONOF "Shutdown programming not activated\n" #define TODAY_DD "Shutdown today at %02d:%02d\n" #define SHUT_NOW "Shutdown now!\n" #endif #define FMT_DAYS " %d %d %d %d %d %d %d\n" /* convert standard days string to firmware format */ static char* convert_days(char *cop) { static char alt[8]; int ish, fim; if (weekn >= 6 || weekn < 0) ish = 0; else ish = 1 + weekn; fim = 7 - ish; /* rotate left only 7 bits */ memcpy(alt, &cop[ish], (size_t)fim); if (ish > 0) memcpy(&alt[fim], cop, (size_t)ish); alt[7] = 0; /* string terminator */ return alt; } inline static int is_binary(char ch ) { return ( ch == '1' || ch == '0' ); } /* convert string to binary */ static uint8_t str2bin( char *binStr ) { uint8_t result = 0; int i; for (i = 0; i < 7; ++i) { char ch = binStr[i]; if (is_binary(ch)) result += ( (ch - '0') << (6 - i) ); else return 0; } return result; } /* revert firmware format to standard string binary days */ static uint8_t revert_days(unsigned char dweek) { char alt[8]; int i; for (i = 0; i < (6 - weekn); ++i) alt[i] = (dweek >> (5 - weekn - i)) & 0x01; for (i = 0; i < weekn+1; ++i) alt[i+(6-weekn)] = (dweek >> (6 - i)) & 0x01; for (i=0; i < 7; i++) alt[i] += '0'; alt[7] = 0; /* string terminator */ return str2bin(alt); } static int is_hour(char *hour, int qual) { int hora, min; if ((strlen(hour) != 5) || (sscanf(hour, "%d:%d", &hora, &min) != 2)) return -1; if (qual) { dhour = hora; dmin = min; } else { lhour = hora; lmin = min; } return 1; } static void send_shutdown( void ) { int i; for (i = 0; i < 10; i++) ser_send_char(upsfd, CMD_SHUT ); upslogx(LOG_NOTICE, "Ups shutdown command sent"); printf("Ups shutdown command sent\n"); } /* save config ups */ static void save_ups_config( void ) { int i, chks = 0; /* FIXME? Check for overflows with int => char truncations? * See also microsol-common.c for very similar code */ ConfigPack[0] = (unsigned char)0xCF; ConfigPack[1] = (unsigned char)ihour; ConfigPack[2] = (unsigned char)imin; ConfigPack[3] = (unsigned char)isec; ConfigPack[4] = (unsigned char)lhour; ConfigPack[5] = (unsigned char)lmin; ConfigPack[6] = (unsigned char)dhour; ConfigPack[7] = (unsigned char)dmin; ConfigPack[8] = (unsigned char)(weekn << 5); ConfigPack[8] = (unsigned char)ConfigPack[8] | (unsigned char)dian; ConfigPack[9] = (unsigned char)(mesn << 4); ConfigPack[9] = (unsigned char)ConfigPack[9] | (unsigned char)( anon - BASE_YEAR ); ConfigPack[10] = (unsigned char)DaysOffWeek; /* MSB zero */ ConfigPack[10] = ConfigPack[10] & (~(0x80)); for (i=0; i < 11; i++) chks += ConfigPack[i]; /* FIXME? Does truncation to char have same effect as %256 ? */ ConfigPack[11] = (unsigned char)(chks % 256); for (i=0; i < 12; i++) ser_send_char(upsfd, ConfigPack[i]); } /* print UPS internal variables */ static void print_info( void ) { printf(UPS_DATE, Year, Month, Day); printf(SYS_DATE, anon, mesn, dian, seman); printf(UPS_TIME, ihour, imin, isec); if (prgups > 0) { /*sunday, monday, tuesday, wednesday, thursday, friday, saturday*/ int week_days[7] = {0, 0, 0, 0, 0, 0, 0}; int i; /* this is the string to binary standard */ for (i = 0; i < 7; ++i) week_days[i] = (DaysStd >> (6 - i)) & 0x01; if (prgups == 3) printf(PRG_ONOU); else printf(PRG_ONON); printf(TIME_ON, lhour, lmin); printf(TIME_OFF, dhour, dmin); printf(PRG_DAYS); printf(FMT_DAYS, week_days[0], week_days[1], week_days[2], week_days[3], week_days[4], week_days[5], week_days[6]); } else printf(PRG_ONOF); } /* is today shutdown day ? */ inline static int is_today( unsigned char dweek, int nweek) { return (dweek >> (6 - nweek)) & 0x01; } /* all models */ static void autonomy_calc( int iauto ) { int indice, indd, lim, min, max, inf, sup, indc, bx, ipo = 0; bx = bext[iauto]; indice = RecPack[3]; indd = indice - 139; if (UtilPower > 20) ipo = (UtilPower - 51) / 100; indc = auton[iauto].maxi; if( ipo > indc ) return; min = auton[iauto].minc[ipo]; inf = min - 1; max = auton[iauto].maxc[ipo]; lim = max - 139; sup = max + 1; if (UtilPower <= 20) { Autonomy = 170; maxauto = 170; } else { maxauto = auton[iauto].mm[ipo][lim]; if( indice > inf && indice < sup ) Autonomy = auton[iauto].mm[ipo][indd]; else { if (indice > max) Autonomy = maxauto; if (indice < min) Autonomy = 0; } } if (BattExtension > 0 && iauto < 4) Autonomy = ( Autonomy * ( BattExtension + bx ) * 1.0 / bx ); } static void scan_received_pack(void) { int aux, im, ov; /* model independent data */ Year = (RecPack[ 19 ] & 0x0F) + BASE_YEAR; Month = (RecPack[ 19 ] & 0xF0) >> 4; Day = (RecPack[ 18 ] & 0x1F); DaysOnWeek = RecPack[17]; /* Days of week if in UPS shutdown programming mode */ if (prgups == 3) { DaysStd = revert_days( DaysOnWeek ); /* time for programming UPS off */ dhour = RecPack[15]; dmin = RecPack[16]; /* time for programming UPS on */ lhour = RecPack[13]; lmin = RecPack[14]; } /* UPS internal time */ ihour = RecPack[11]; imin = RecPack[10]; isec = RecPack[9]; if ((0x01 & RecPack[20]) == 0x01) Out220 = 1; CriticBatt = (0x04 & RecPack[20]) == 0x04; InversorOn = (0x08 & RecPack[20]) == 0x08; SuperHeat = (0x10 & RecPack[20]) == 0x10; SourceFail = (0x20 & RecPack[20]) == 0x20; OverCharge = (0x80 & RecPack[20]) == 0x80; if ((0x40 & RecPack[20]) == 0x40) InputValue = 1; else InputValue = 0; Temperature = 0x7F & RecPack[4]; if (0x80 & RecPack[4]) Temperature -= 128; /* model dependent data */ im = inds[imodel]; ov = Out220; if (SolisModel != 16) { if (RecPack[6] >= 194) InVoltage = RecPack[6] * ctab[imodel].m_involt194[0] + ctab[imodel].m_involt194[1]; else InVoltage = RecPack[6] * ctab[imodel].m_involt193[0] + ctab[imodel].m_involt193[1]; } else { /* Code InVoltage for STAY1200_USB */ if ((RecPack[20] & 0x1) == 0) /* IsOutVoltage 220 */ InVoltage = RecPack[2] * ctab[imodel].m_involt193[0] + ctab[imodel].m_involt193[1]; else InVoltage = RecPack[2] * ctab[imodel].m_involt193[0] + ctab[imodel].m_involt193[1] - 3.0; } BattVoltage = RecPack[ 3 ] * ctab[imodel].m_battvolt[0] + ctab[imodel].m_battvolt[1]; NominalPower = nompow[im]; if (SourceFail) { OutVoltage = RecPack[ 1 ] * ctab[imodel].m_outvolt_i[ov][0] + ctab[imodel].m_outvolt_i[ov][1]; OutCurrent = RecPack[ 5 ] * ctab[imodel].m_outcurr_i[ov][0] + ctab[imodel].m_outcurr_i[ov][1]; AppPower = ( RecPack[ 5 ] * RecPack[ 1 ] ) * ctab[imodel].m_appp_i[ov][0] + ctab[imodel].m_appp_i[ov][1]; UtilPower = ( RecPack[ 7 ] + RecPack[ 8 ] * 256 ) * ctab[imodel].m_utilp_i[ov][0] + ctab[imodel].m_utilp_i[ov][1]; InCurrent = 0; } else { OutVoltage = RecPack[ 1 ] * ctab[imodel].m_outvolt_s[ov][0] + ctab[imodel].m_outvolt_s[ov][1]; OutCurrent = RecPack[ 5 ] * ctab[imodel].m_outcurr_s[ov][0] + ctab[imodel].m_outcurr_s[ov][1]; AppPower = ( RecPack[ 5 ] * RecPack[ 1 ] ) * ctab[imodel].m_appp_s[ov][0] + ctab[imodel].m_appp_s[ov][1]; UtilPower = ( RecPack[ 7 ] + RecPack[ 8 ] * 256 ) * ctab[imodel].m_utilp_s[ov][0] + ctab[imodel].m_utilp_s[ov][1]; InCurrent = ( ctab[imodel].m_incurr[0] * 1.0 / BattVoltage ) - ( AppPower * 1.0 / ctab[imodel].m_incurr[1] ) + OutCurrent *( OutVoltage * 1.0 / InVoltage ); } if (SolisModel == 16) { int configRelay = (RecPack[6] & 0x38) >> 3; double TENSAO_SAIDA_F1_MR[8] = { 1.1549, 1.0925, 0.0, 0.0, 1.0929, 1.0885, 0.0, 0.8654262224145391 }; double TENSAO_SAIDA_F2_MR[8] = { -6.9157, 11.026, 10.43, 0.0, -0.6109, 12.18, 0.0, 13.677}; const double TENSAO_SAIDA_F2_MI[8] ={ 5.59, 9.47, 13.7, 0.0, 0.0, 0.0, 0.0, 0.0 }; const double TENSAO_SAIDA_F1_MI[8] = { 7.9, 9.1, 17.6, 0.0, 0.0, 0.0, 0.0, 0.0 }; const double corrente_saida_F1_MR = 0.12970000389100012; const double corrente_saida_F2_MR = 0.5387060281204546; /* double corrente_saida_F1_MI = 0.1372; double corrente_saida_F2_MI = 0.3456; */ if (SourceFail) { if (RecPack[20] == 0) { double a = RecPack[1] * 2; a /= 128.0; /* a = double sqrt(a); */ OutVoltage = RecPack[1] * a * TENSAO_SAIDA_F1_MI[configRelay] + TENSAO_SAIDA_F2_MI[configRelay]; } } else { double RealPower, potVA1, potVA2, potLin, potRe; OutCurrent = (float)(corrente_saida_F1_MR * RecPack[5] + corrente_saida_F2_MR); OutVoltage = RecPack[1] * TENSAO_SAIDA_F1_MR[configRelay] + TENSAO_SAIDA_F2_MR[configRelay]; AppPower = OutCurrent * OutVoltage; RealPower = (RecPack[7] + RecPack[8] * 256); potVA1 = 5.968 * AppPower - 284.36; potVA2 = 7.149 * AppPower - 567.18; potLin = 0.1664 * RealPower + 49.182; potRe = 0.1519 * RealPower + 32.644; if (fabs(potVA1 - RealPower) < fabs(potVA2 - RealPower)) RealPower = potLin; else RealPower = potRe; if (OutCurrent < 0.7) RealPower = AppPower; if (AppPower < RealPower) { double f = AppPower; AppPower = RealPower; RealPower = f; } } } aux = (RecPack[ 21 ] + RecPack[ 22 ] * 256); if (aux > 0) InFreq = ctab[imodel].m_infreq * 1.0 / aux; /* Specific for STAY1200_USB */ if (SolisModel == 16) { InFreq = ((float)(0.37 * (257 - (aux >> 8)))); } else InFreq = 0; /* input voltage offset */ if (InVoltage < InVolt_offset) { /* all is equal 30 */ InFreq = 0; InVoltage = 0; InCurrent = 0; } /* app power offset */ if (AppPower < ctab[imodel].m_appp_offset) { AppPower = 0; UtilPower = 0; ChargePowerFactor = 0; OutCurrent = 0; } if (im < 3) autonomy_calc(im); else { if (BattExtension == 80 && im == 3) autonomy_calc(im + 1); else autonomy_calc(im); } /* model independent data */ batcharge = ( Autonomy / maxauto ) * 100.0; upscharge = ( AppPower / NominalPower ) * 100.0; if (batcharge > 100.0) batcharge = 100.0; OutFreq = 60; if (!InversorOn) { OutVoltage = 0; OutFreq = 0; } if (!SourceFail && InversorOn) OutFreq = InFreq; if (AppPower < 0) /* charge pf */ ChargePowerFactor = 0; else { if( d_equal(AppPower, 0) ) ChargePowerFactor = 100; else ChargePowerFactor = (( UtilPower / AppPower) * 100); if(ChargePowerFactor > 100) ChargePowerFactor = 100; } if (SourceFail && SourceLast) /* first time failure */ FailureFlag = true; /* source return */ if (!SourceFail && !SourceLast) { SourceReturn = true; /* clean port: */ /* ser_flush_in(upsfd,"",0); */ } if((!SourceFail) == SourceLast) { SourceReturn = false; FailureFlag = false; } SourceLast = !SourceFail; /* Autonomy */ if (Autonomy < 5) LowBatt = true; else LowBatt = false; UpsPowerFactor = 700; /* input 110V or 220v */ if (InputValue == 0) { InDownLim = 75; InUpLim = 150; NomInVolt = 110; } else { InDownLim = 150; InUpLim = 300; NomInVolt = 220; } /* output volage 220V or 110V */ if (Out220) { OutDownLim = 190; OutUpLim = 250; NomOutVolt = 220; } else { OutDownLim = 100; OutUpLim = 140; NomOutVolt = 110; } if (SourceFail) /* source status */ InputStatus = 2; else InputStatus = 1; if (InversorOn) /* output status */ OutputStatus = 1; else OutputStatus = 2; if (OverCharge) OutputStatus = 3; if (CriticBatt) /* battery status */ BattStatus = 4; else BattStatus = 1; SourceEvents = 0; if (FailureFlag) SourceEvents = 1; if (SourceReturn) SourceEvents = 2; /* verify Inversor */ if (Flag_inversor) { InversorOnLast = InversorOn; Flag_inversor = false; } OutputEvents = 0; if (InversorOn && !InversorOnLast) OutputEvents = 26; if (InversorOnLast && !InversorOn) OutputEvents = 27; InversorOnLast = InversorOn; if (SuperHeat && !SuperHeatLast) OutputEvents = 12; if (SuperHeatLast && !SuperHeat) OutputEvents = 13; SuperHeatLast = SuperHeat; if (OverCharge && !OverChargeLast) OutputEvents = 10; if (OverChargeLast && !OverCharge) OutputEvents = 11; OverChargeLast = OverCharge; BattEvents = 0; CriticBattLast = CriticBatt; } static void comm_receive(const unsigned char *bufptr, size_t size) { if (size == packet_size) { int CheckSum = 0; size_t i; memcpy(RecPack, bufptr, packet_size); if (nut_debug_level >= 3) upsdebug_hex(3, "comm_receive: RecPack", RecPack, size); /* CheckSum verify */ for (i = 0 ; i < packet_size-2 ; ++i ) CheckSum += RecPack[i]; CheckSum = CheckSum % 256; upsdebugx(4, "%s: calculated checksum = 0x%02x, RecPack[23] = 0x%02x", __func__, CheckSum, RecPack[23]); /* clean port: */ /* ser_flush_in(upsfd,"",0); */ /* RecPack[0] == model number below: * SOLIS = 1; * RHINO = 2; * STAY = 3; * SOLIS_LI_700 = 169; * SOLIS_M11 = 171; * SOLIS_M15 = 175; * SOLIS_M14 = 174; * SOLIS_M13 = 173; * SOLISDC_M14 = 201; * SOLISDC_M13 = 206; * SOLISDC_M15 = 207; * CABECALHO_RHINO = 194; * PS800 = 185; * STAY1200_USB = 186; * PS350_CII = 184; * PS2200 = 187; * PS2200_22 = 188; * STAY700_USB = 189; * BZ1500 = 190; */ if ((((RecPack[0] & 0xF0) == 0xA0 ) || (RecPack[0] & 0xF0) == 0xB0) && (RecPack[24] == 254) && (RecPack[23] == CheckSum)) { if (!detected) { if (RecPack[0] == 186) SolisModel = 16; else SolisModel = (int) (RecPack[0] & 0x0F); if (SolisModel < 13) imodel = SolisModel - 10; /* 10 = 0, 11 = 1 */ else imodel = SolisModel - 11; /* 13 = 2, 14 = 3, 15 = 4 */ detected = true; } switch (SolisModel) { case 10: case 11: case 12: case 13: case 14: case 15: scan_received_pack(); break; case 16: /* STAY1200_USB model */ scan_received_pack(); break; default: printf(M_UNKN); scan_received_pack(); /* Scan anyway. */ break; } } } } static void get_base_info(void) { #ifdef PORTUGUESE const char DaysOfWeek[7][4]={"Dom", "Seg", "Ter", "Qua", "Qui", "Sex", "Sab"}; #else const char DaysOfWeek[7][4]={"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"}; #endif unsigned char packet[PACKET_SIZE], syncEOR = '\0', syncEOR_was_read = 0; int i1=0, i2=0; size_t i; ssize_t tam; time_t tmt; struct tm *now; struct tm tmbuf; time(&tmt); now = localtime_r(&tmt, &tmbuf); dian = now->tm_mday; mesn = now->tm_mon+1; anon = now->tm_year+1900; ihour = now->tm_hour; imin = now->tm_min; isec = now->tm_sec; weekn = now->tm_wday; strcpy(seman, DaysOfWeek[weekn]); if (testvar("battext")) BattExtension = atoi(getval("battext")); if (testvar("prgshut")) prgups = atoi(getval("prgshut")); if (prgups > 0 && prgups < 3) { if (testvar("daysweek")) DaysOnWeek = str2bin(convert_days(getval("daysweek"))); if (testvar("daysoff")) { char *doff = getval("daysoff"); DaysStd = str2bin(doff); DaysOffWeek = str2bin( convert_days(doff)); } if (testvar("houron")) i1 = is_hour(getval("houron"), 0); if (testvar("houroff")) i2 = is_hour(getval("houroff"), 1); if (i1 == 1 && i2 == 1 && (DaysOnWeek > 0)) { isprogram = 1; /* prgups == 1 ou 2 */ if (prgups == 2) save_ups_config(); /* save ups config */ } else { if (i2 == 1 && DaysOffWeek > 0) { isprogram = 1; DaysOnWeek = DaysOffWeek; } } } /* end prgups 1 - 2 */ /* dummy read attempt to sync - throw it out */ upsdebugx(3, "%s: sending CMD_UPSCONT and ENDCHAR to sync", __func__); ser_send(upsfd, "%c%c", CMD_UPSCONT, ENDCHAR); /* * - Read until end-of-response character (0xFE): * read up to 3 packets in size before giving up * synchronizing with the device. */ for (i = 0; i < packet_size*3; i++) { ser_get_char(upsfd, &syncEOR, 3, 0); syncEOR_was_read = 1; if(syncEOR == RESP_END) break; } if (!syncEOR_was_read || syncEOR != RESP_END) { /* synchronization failed */ fatalx(EXIT_FAILURE, NO_SOLIS); } else { upsdebugx(4, "%s: requesting %" PRIuSIZE " bytes from ser_get_buf_len()", __func__, packet_size); tam = ser_get_buf_len(upsfd, packet, packet_size, 3, 0); if (tam < 0) { upsdebugx(0, "%s: Error (%" PRIiSIZE ") reading from ser_get_buf_len()", __func__, tam); fatalx(EXIT_FAILURE, NO_SOLIS); } upsdebugx(2, "%s: received %" PRIiSIZE " bytes from ser_get_buf_len()", __func__, tam); if (tam > 0 && nut_debug_level >= 4) { upsdebug_hex(4, "received from ser_get_buf_len()", packet, (size_t)tam); } comm_receive(packet, (size_t)tam); } if (!detected) fatalx(EXIT_FAILURE, NO_SOLIS ); switch (SolisModel) { case 10: case 11: case 12: Model = "Solis 1.0"; break; case 13: Model = "Solis 1.5"; break; case 14: Model = "Solis 2.0"; break; case 15: Model = "Solis 3.0"; break; case 16: Model = "Microsol Back-Ups BZ1200-BR"; break; } /* if( isprogram ) */ if (prgups == 1) { hourshut = dhour; minshut = dmin; } else { if (prgups == 2 || prgups == 3) { /* broadcast before firmware shutdown */ if (dmin < 5) { if (dhour > 1) hourshut = dhour - 1; else hourshut = 23; minshut = 60 - ( 5 - dmin ); } else { hourshut = dhour; minshut = dmin - 5; } } } /* manufacturer */ dstate_setinfo("ups.mfr", "%s", "Microsol"); dstate_setinfo("ups.model", "%s", Model); dstate_setinfo("input.transfer.low", "%03.1f", InDownLim); dstate_setinfo("input.transfer.high", "%03.1f", InUpLim); dstate_addcmd("shutdown.return"); /* CMD_SHUTRET */ dstate_addcmd("shutdown.stayoff"); /* CMD_SHUT */ printf("Detected %s on %s\n", dstate_getinfo("ups.model"), device_path); print_info(); } static void get_update_info(void) { unsigned char temp[256]; int isday, hourn, minn; ssize_t tam; /* time update and programable shutdown block */ time_t tmt; struct tm *now; struct tm tmbuf; time(&tmt); now = localtime_r(&tmt, &tmbuf); hourn = now->tm_hour; minn = now->tm_min; weekn = now->tm_wday; if (isprogram || prgups == 3) { if (isprogram) isday = is_today(DaysStd, weekn); else isday = is_today( DaysStd, weekn); if (isday) printf(TODAY_DD, hourshut, minshut); if ( (hourn == hourshut) && (minn >= minshut) && isday) { printf( SHUT_NOW ); progshut = 1; } } /* programable shutdown end block */ /* get update package */ temp[0] = 0; /* flush temp buffer */ upsdebugx(3, "%s: requesting %" PRIuSIZE " bytes from ser_get_buf_len()", __func__, packet_size); tam = ser_get_buf_len(upsfd, temp, packet_size, 3, 0); if (tam < 0) { upsdebugx(0, "%s: Error (%" PRIiSIZE ") reading from ser_get_buf_len()", __func__, tam); fatalx(EXIT_FAILURE, NO_SOLIS); } upsdebugx(2, "%s: received %" PRIiSIZE " bytes from ser_get_buf_len()", __func__, tam); if(tam > 0 && nut_debug_level >= 4) upsdebug_hex(4, "received from ser_get_buf_len()", temp, (size_t)tam); comm_receive(temp, (size_t)tam); } static int instcmd(const char *cmdname, const char *extra) { if (!strcasecmp(cmdname, "shutdown.return")) { /* shutdown and restart */ ser_send_char(upsfd, CMD_SHUTRET); /* 0xDE */ /* ser_send_char(upsfd, ENDCHAR); */ return STAT_INSTCMD_HANDLED; } if (!strcasecmp(cmdname, "shutdown.stayoff")) { /* shutdown now (one way) */ ser_send_char(upsfd, CMD_SHUT); /* 0xDD */ /* ser_send_char(upsfd, ENDCHAR); */ return STAT_INSTCMD_HANDLED; } upslogx(LOG_NOTICE, "instcmd: unknown command [%s] [%s]", cmdname, extra); return STAT_INSTCMD_UNKNOWN; } void upsdrv_initinfo(void) { get_base_info(); upsh.instcmd = instcmd; } void upsdrv_updateinfo(void) { get_update_info(); /* new package for updates */ dstate_setinfo("output.voltage", "%03.1f", OutVoltage); dstate_setinfo("input.voltage", "%03.1f", InVoltage); dstate_setinfo("battery.voltage", "%02.1f", BattVoltage); dstate_setinfo("battery.charge", "%03.1f", batcharge); dstate_setinfo("output.current", "%03.1f", OutCurrent); status_init(); if (!SourceFail) status_set("OL"); /* on line */ else status_set("OB"); /* on battery */ if (Autonomy < 5) status_set("LB"); /* low battery */ if (progshut) { /* software programable shutdown immediately */ if( prgups == 2 ) send_shutdown(); /* Ups shutdown in 4-5 minutes -- redundant Ups shutdown */ status_set("LB"); /* no low battery but is a force shutdown */ } status_commit(); dstate_setinfo("ups.temperature", "%2.2f", Temperature); dstate_setinfo("input.frequency", "%2.1f", InFreq); dstate_setinfo("ups.load", "%03.1f", upscharge); dstate_dataok(); } /*! @brief Power down the attached load immediately. * Basic idea: find out line status and send appropriate command. * - on battery: send normal shutdown, UPS will return by itself on utility * - on line: send shutdown+return, UPS will cycle and return soon. */ void upsdrv_shutdown(void) { if (!SourceFail) { /* on line */ upslogx(LOG_NOTICE, "On line, sending shutdown+return command...\n"); ser_send_char(upsfd, CMD_SHUTRET ); } else { upslogx(LOG_NOTICE, "On battery, sending normal shutdown command...\n"); ser_send_char(upsfd, CMD_SHUT); } } void upsdrv_help(void) { printf("\nSolis options\n"); printf(" Battery Extension in AH\n"); printf(" battext = 80\n"); printf(" Programable UPS power on/off\n"); printf(" prgshut = 0 (default, no software programable shutdown)\n"); printf(" prgshut = 1 (software programable shutdown without UPS power off)\n"); printf(" prgshut = 2 (software programable shutdown with UPS power off)\n"); printf(" prgshut = 3 (activate UPS programable power on/off)\n"); printf(" Otherwise uses:\n"); printf(" daysweek = 1010101 ( power on days )\n"); printf(" daysoff = 1010101 ( power off days )\n"); printf(" where each digit is a day from sun...sat with 0 = off and 1 = on\n"); printf(" houron = hh:mm hh = hour 0-23 mm = minute 0-59 separated with :\n"); printf(" houroff = hh:mm hh = hour 0-23 mm = minute 0-59 separated with :\n"); printf(" where houron is power-on hour and houroff is shutdown and power-off hour\n"); printf(" Uses daysweek and houron to programming and save UPS power on/off\n"); printf(" These are valid only if prgshut = 2 or 3\n"); } void upsdrv_makevartable(void) { addvar(VAR_VALUE, "battext", "Battery Extension (0-80)min"); addvar(VAR_VALUE, "prgshut", "Programable power off (0-3)"); addvar(VAR_VALUE, "daysweek", "Days of week UPS power of/off"); addvar(VAR_VALUE, "daysoff", "Days of week Driver shutdown"); addvar(VAR_VALUE, "houron", "Power on hour (hh:mm)"); addvar(VAR_VALUE, "houroff", "Power off hour (hh:mm)"); } void upsdrv_initups(void) { upsfd = ser_open(device_path); ser_set_speed(upsfd, device_path, B9600); ser_set_dtr(upsfd, 1); ser_set_rts(upsfd, 0); } void upsdrv_cleanup(void) { ser_close(upsfd, device_path); } nut-2.8.1/drivers/nutdrv_qx_megatec-old.h0000644000175000017500000000201114273170601015366 00000000000000/* nutdrv_qx_megatec-old.h - Subdriver for Megatec/old protocol based UPSes * * Copyright (C) * 2013 Daniele Pezzini * * 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 2 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, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #ifndef NUTDRV_QX_MEGATEC_OLD_H #define NUTDRV_QX_MEGATEC_OLD_H #include "nutdrv_qx.h" extern subdriver_t megatec_old_subdriver; #endif /* NUTDRV_QX_MEGATECH_OLD_H */ nut-2.8.1/drivers/hidtypes.h0000644000175000017500000003034114500336654012740 00000000000000/* * types.h: HID Parser types definitions * * This file is part of the MGE UPS SYSTEMS HID Parser * * Copyright (C) * 1998-2003 MGE UPS SYSTEMS, Luc Descotils * 2015 Eaton, Arnaud Quette (Update MAX_REPORT) * * 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 2 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, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * -------------------------------------------------------------------------- */ #ifndef HIDTYPES_H #define HIDTYPES_H #ifdef __cplusplus /* *INDENT-OFF* */ extern "C" { /* *INDENT-ON* */ #endif /* __cplusplus */ #include #include "nut_stdint.h" /* * Constants * -------------------------------------------------------------------------- */ #define PATH_SIZE 10 /* Deep max for Path */ #define USAGE_TAB_SIZE 50 /* Size of usage stack */ #define MAX_REPORT 500 /* Including FEATURE, INPUT and OUTPUT */ #define REPORT_DSC_SIZE 6144 /* Size max of Report Descriptor */ #define MAX_REPORT_TS 3 /* Max time validity of a report */ /* * Items * -------------------------------------------------------------------------- */ #define SIZE_0 0x00 #define SIZE_1 0x01 #define SIZE_2 0x02 #define SIZE_4 0x03 #define SIZE_MASK 0x03 #define TYPE_MAIN 0x00 #define TYPE_GLOBAL 0x04 #define TYPE_LOCAL 0x08 #define TYPE_MASK 0x0C /* Main items */ #define ITEM_COLLECTION 0xA0 #define ITEM_END_COLLECTION 0xC0 #define ITEM_FEATURE 0xB0 #define ITEM_INPUT 0x80 #define ITEM_OUTPUT 0x90 /* Global items */ #define ITEM_UPAGE 0x04 #define ITEM_LOG_MIN 0x14 #define ITEM_LOG_MAX 0x24 #define ITEM_PHY_MIN 0x34 #define ITEM_PHY_MAX 0x44 #define ITEM_UNIT_EXP 0x54 #define ITEM_UNIT 0x64 #define ITEM_REP_SIZE 0x74 #define ITEM_REP_ID 0x84 #define ITEM_REP_COUNT 0x94 /* Local items */ #define ITEM_USAGE 0x08 #define ITEM_STRING 0x78 /* Long item */ #define ITEM_LONG 0xFC #define ITEM_MASK 0xFC /* Attribute Flags */ #define ATTR_DATA_CST 0x01 #define ATTR_NVOL_VOL 0x80 /* Usage Pages */ /* For more details, please see docs/hid-subdrivers.txt */ #define PAGE_POWER_DEVICE 0x84 #define PAGE_BATTERY_SYSTEM 0x85 /* Usage within Power Device page */ #define USAGE_POW_UNDEFINED 0x00840000 #define USAGE_POW_I_NAME 0x00840001 #define USAGE_POW_PRESENT_STATUS 0x00840002 #define USAGE_POW_CHANGED_STATUS 0x00840003 #define USAGE_POW_UPS 0x00840004 #define USAGE_POW_POWER_SUPPLY 0x00840005 #define USAGE_POW_PERIPHERAL_DEVICE 0x00840006 #define USAGE_POW_BATTERY_SYSTEM 0x00840010 #define USAGE_POW_BATTERY_SYSTEM_ID 0x00840011 #define USAGE_POW_BATTERY 0x00840012 #define USAGE_POW_BATTERY_ID 0x00840013 #define USAGE_POW_CHARGER 0x00840014 #define USAGE_POW_CHARGER_ID 0x00840015 #define USAGE_POW_POWER_CONVERTER 0x00840016 #define USAGE_POW_POWER_CONVERTER_ID 0x00840017 #define USAGE_POW_OUTLET_SYSTEM 0x00840018 #define USAGE_POW_OUTLET_SYSTEM_ID 0x00840019 #define USAGE_POW_INPUT 0x0084001A #define USAGE_POW_INPUT_ID 0x0084001B #define USAGE_POW_OUTPUT 0x0084001C #define USAGE_POW_OUTPUT_ID 0x0084001D #define USAGE_POW_FLOW 0x0084001E #define USAGE_POW_FLOW_ID 0x0084001F #define USAGE_POW_OUTLET 0x00840020 #define USAGE_POW_OUTLET_ID 0x00840021 #define USAGE_POW_GANG 0x00840022 #define USAGE_POW_GANG_ID 0x00840023 #define USAGE_POW_POWER_SUMMARY 0x00840024 #define USAGE_POW_POWER_SUMMARY_ID 0x00840025 #define USAGE_POW_VOLTAGE 0x00840030 #define USAGE_POW_CURRENT 0x00840031 #define USAGE_POW_FREQUENCY 0x00840032 #define USAGE_POW_APPARENT_POWER 0x00840033 #define USAGE_POW_ACTIVE_POWER 0x00840034 #define USAGE_POW_PERCENT_LOAD 0x00840035 #define USAGE_POW_TEMPERATURE 0x00840036 #define USAGE_POW_HUMIDITY 0x00840037 #define USAGE_POW_BAD_COUNT 0x00840038 #define USAGE_POW_CONFIG_VOLTAGE 0x00840040 #define USAGE_POW_CONFIG_CURRENT 0x00840041 #define USAGE_POW_CONFIG_FREQUENCY 0x00840042 #define USAGE_POW_CONFIG_APPARENT_POWER 0x00840043 #define USAGE_POW_CONFIG_ACTIVE_POWER 0x00840044 #define USAGE_POW_CONFIG_PERCENT_LOAD 0x00840045 #define USAGE_POW_CONFIG_TEMPERATURE 0x00840046 #define USAGE_POW_CONFIG_HUMIDITY 0x00840047 #define USAGE_POW_SWITCH_ON_CONTROL 0x00840050 #define USAGE_POW_SWITCH_OFF_CONTROL 0x00840051 #define USAGE_POW_TOGGLE_CONTROL 0x00840052 #define USAGE_POW_LOW_VOLTAGE_TRANSFER 0x00840053 #define USAGE_POW_HIGH_VOLTAGE_TRANSFER 0x00840054 #define USAGE_POW_DELAY_BEFORE_REBOOT 0x00840055 #define USAGE_POW_DELAY_BEFORE_STARTUP 0x00840056 #define USAGE_POW_DELAY_BEFORE_SHUTDOWN 0x00840057 #define USAGE_POW_TEST 0x00840058 #define USAGE_POW_MODULE_RESET 0x00840059 #define USAGE_POW_AUDIBLE_ALARM_CONTROL 0x0084005A #define USAGE_POW_PRESENT 0x00840060 #define USAGE_POW_GOOD 0x00840061 #define USAGE_POW_INTERNAL_FAILURE 0x00840062 #define USAGE_POW_VOLTAGE_OUT_OF_RANGE 0x00840063 #define USAGE_POW_FREQUENCY_OUT_OF_RANGE 0x00840064 #define USAGE_POW_OVERLOAD 0x00840065 #define USAGE_POW_OVER_CHARGED 0x00840066 #define USAGE_POW_OVER_TEMPERATURE 0x00840067 #define USAGE_POW_SHUTDOWN_REQUESTED 0x00840068 #define USAGE_POW_SHUTDOWN_IMMINENT 0x00840069 #define USAGE_POW_SWITCH_ON_OFF 0x0084006B #define USAGE_POW_SWITCHABLE 0x0084006C #define USAGE_POW_USED 0x0084006D #define USAGE_POW_BOOST 0x0084006E #define USAGE_POW_BUCK 0x0084006F #define USAGE_POW_INITIALIZED 0x00840070 #define USAGE_POW_TESTED 0x00840071 #define USAGE_POW_AWAITING_POWER 0x00840072 #define USAGE_POW_COMMUNICATION_LOST 0x00840073 #define USAGE_POW_I_MANUFACTURER 0x008400FD #define USAGE_POW_I_PRODUCT 0x008400FE #define USAGE_POW_I_SERIAL_NUMBER 0x008400FF /* Usage within Battery System page */ #define USAGE_BAT_UNDEFINED 0x00850000 #define USAGE_BAT_SMB_BATTERY_MODE 0x00850001 #define USAGE_BAT_SMB_BATTERY_STATUS 0x00850002 #define USAGE_BAT_SMB_ALARM_WARNING 0x00850003 #define USAGE_BAT_SMB_CHARGER_MODE 0x00850004 #define USAGE_BAT_SMB_CHARGER_STATUS 0x00850005 #define USAGE_BAT_SMB_CHARGER_SPEC_INFO 0x00850006 #define USAGE_BAT_SMB_SELECTOR_STATE 0x00850007 #define USAGE_BAT_SMB_SELECTOR_PRESETS 0x00850008 #define USAGE_BAT_SMB_SELECTOR_INFO 0x00850009 #define USAGE_BAT_OPTIONAL_MFG_FUNCTION_1 0x00850010 #define USAGE_BAT_OPTIONAL_MFG_FUNCTION_2 0x00850011 #define USAGE_BAT_OPTIONAL_MFG_FUNCTION_3 0x00850012 #define USAGE_BAT_OPTIONAL_MFG_FUNCTION_4 0x00850013 #define USAGE_BAT_OPTIONAL_MFG_FUNCTION_5 0x00850014 #define USAGE_BAT_CONNECTION_TO_SMBUS 0x00850015 #define USAGE_BAT_OUTPUT_CONNECTION 0x00850016 #define USAGE_BAT_CHARGER_CONNECTION 0x00850017 #define USAGE_BAT_BATTERY_INSERTION 0x00850018 #define USAGE_BAT_USE_NEXT 0x00850019 #define USAGE_BAT_OK_TO_USE 0x0085001A #define USAGE_BAT_BATTERY_SUPPORTED 0x0085001B #define USAGE_BAT_SELECTOR_REVISION 0x0085001C #define USAGE_BAT_CHARGING_INDICATOR 0x0085001D #define USAGE_BAT_MANUFACTURER_ACCESS 0x00850028 #define USAGE_BAT_REMAINING_CAPACITY_LIMIT 0x00850029 #define USAGE_BAT_REMAINING_TIME_LIMIT 0x0085002A #define USAGE_BAT_AT_RATE 0x0085002B #define USAGE_BAT_CAPACITY_MODE 0x0085002C #define USAGE_BAT_BROADCAST_TO_CHARGER 0x0085002D #define USAGE_BAT_PRIMARY_BATTERY 0x0085002E #define USAGE_BAT_CHARGE_CONTROLLER 0x0085002F #define USAGE_BAT_TERMINATE_CHARGE 0x00850040 #define USAGE_BAT_TERMINATE_DISCHARGE 0x00850041 #define USAGE_BAT_BELOW_REMAINING_CAPACITY_LIMIT 0x00850042 #define USAGE_BAT_REMAINING_TIME_LIMIT_EXPIRED 0x00850043 #define USAGE_BAT_CHARGING 0x00850044 #define USAGE_BAT_DISCHARGING 0x00850045 #define USAGE_BAT_FULLY_CHARGED 0x00850046 #define USAGE_BAT_FULLY_DISCHARGED 0x00850047 #define USAGE_BAT_CONDITIONING_FLAG 0x00850048 #define USAGE_BAT_AT_RATE_OK 0x00850049 #define USAGE_BAT_SMB_ERROR_CODE 0x0085004A #define USAGE_BAT_NEED_REPLACEMENT 0x0085004B #define USAGE_BAT_AT_RATE_TIME_TO_FULL 0x00850060 #define USAGE_BAT_AT_RATE_TIME_TO_EMPTY 0x00850061 #define USAGE_BAT_AVERAGE_CURRENT 0x00850062 #define USAGE_BAT_MAX_ERROR 0x00850063 #define USAGE_BAT_RELATIVE_STATE_OF_CHARGE 0x00850064 #define USAGE_BAT_ABSOLUTE_STATE_OF_CHARGE 0x00850065 #define USAGE_BAT_REMAINING_CAPACITY 0x00850066 #define USAGE_BAT_FULL_CHARGE_CAPACITY 0x00850067 #define USAGE_BAT_RUN_TIME_TO_EMPTY 0x00850068 #define USAGE_BAT_AVERAGE_TIME_TO_EMPTY 0x00850069 #define USAGE_BAT_AVERAGE_TIME_TO_FULL 0x0085006A #define USAGE_BAT_CYCLE_COUNT 0x0085006B #define USAGE_BAT_BATT_PACK_MODEL_LEVEL 0x00850080 #define USAGE_BAT_INTERNAL_CHARGE_CONTROLLER 0x00850081 #define USAGE_BAT_PRIMARY_BATTERY_SUPPORT 0x00850082 #define USAGE_BAT_DESIGN_CAPACITY 0x00850083 #define USAGE_BAT_SPECIFICATION_INFO 0x00850084 #define USAGE_BAT_MANUFACTURER_DATE 0x00850085 #define USAGE_BAT_SERIAL_NUMBER 0x00850086 #define USAGE_BAT_I_MANUFACTURER_NAME 0x00850087 #define USAGE_BAT_I_DEVICE_NAME 0x00850088 #define USAGE_BAT_I_DEVICE_CHEMISTRY 0x00850089 #define USAGE_BAT_MANUFACTURER_DATA 0x0085008A #define USAGE_BAT_RECHARGEABLE 0x0085008B #define USAGE_BAT_WARNING_CAPACITY_LIMIT 0x0085008C #define USAGE_BAT_CAPACITY_GRANULARITY_1 0x0085008D #define USAGE_BAT_CAPACITY_GRANULARITY_2 0x0085008E #define USAGE_BAT_I_OEMINFORMATION 0x0085008F #define USAGE_BAT_INHIBIT_CHARGE 0x008500C0 #define USAGE_BAT_ENABLE_POLLING 0x008500C1 #define USAGE_BAT_RESET_TO_ZERO 0x008500C2 #define USAGE_BAT_AC_PRESENT 0x008500D0 #define USAGE_BAT_BATTERY_PRESENT 0x008500D1 #define USAGE_BAT_POWER_FAIL 0x008500D2 #define USAGE_BAT_ALARM_INHIBITED 0x008500D3 #define USAGE_BAT_THERMISTOR_UNDER_RANGE 0x008500D4 #define USAGE_BAT_THERMISTOR_HOT 0x008500D5 #define USAGE_BAT_THERMISTOR_COLD 0x008500D6 #define USAGE_BAT_THERMISTOR_OVER_RANGE 0x008500D7 #define USAGE_BAT_VOLTAGE_OUT_OF_RANGE 0x008500D8 #define USAGE_BAT_CURRENT_OUT_OF_RANGE 0x008500D9 #define USAGE_BAT_CURRENT_NOT_REGULATED 0x008500DA #define USAGE_BAT_VOLTAGE_NOT_REGULATED 0x008500DB #define USAGE_BAT_MASTER_MODE 0x008500DC #define USAGE_BAT_CHARGER_SELECTOR_SUPPORT 0x008500F0 #define USAGE_BAT_CHARGER_SPEC 0x008500F1 #define USAGE_BAT_LEVEL_2 0x008500F2 #define USAGE_BAT_LEVEL_3 0x008500F3 /* * HIDNode_t struct * * Describe a HID Path point: Usage = bits 0..15, UPage = bits 16..31 * -------------------------------------------------------------------------- */ typedef uint32_t HIDNode_t; /* * HIDPath struct * * Describe a HID Path * -------------------------------------------------------------------------- */ typedef struct { uint8_t Size; /* HID Path size */ HIDNode_t Node[PATH_SIZE]; /* HID Path */ } HIDPath_t; /* * HIDData struct * * Describe a HID Data with its location in report * -------------------------------------------------------------------------- */ typedef struct { HIDPath_t Path; /* HID Path */ uint8_t ReportID; /* Report ID */ uint8_t Offset; /* Offset of data in report */ uint8_t Size; /* Size of data in bit */ uint8_t Type; /* Type : FEATURE / INPUT / OUTPUT */ uint8_t Attribute; /* Report field attribute */ long Unit; /* HID Unit */ int8_t UnitExp; /* Unit exponent */ long LogMin; /* Logical Min */ long LogMax; /* Logical Max */ long PhyMin; /* Physical Min */ long PhyMax; /* Physical Max */ int8_t have_PhyMin; /* Physical Min defined? */ int8_t have_PhyMax; /* Physical Max defined? */ } HIDData_t; /* * HIDDesc struct * * Holds a parsed report descriptor * -------------------------------------------------------------------------- */ typedef struct { size_t nitems; /* number of items in descriptor */ HIDData_t *item; /* list of items */ size_t replen[256]; /* list of report lengths, in byte */ } HIDDesc_t; #ifdef __cplusplus /* *INDENT-OFF* */ } /* extern "C" */ /* *INDENT-ON* */ #endif /* __cplusplus */ #endif /* HIDTYPES_H */ nut-2.8.1/drivers/blazer_ser.c0000644000175000017500000001171614501607135013233 00000000000000/* * blazer_ser.c: support for Megatec/Q1 serial protocol based UPSes * * OBSOLETION WARNING: Please to not base new development on this * codebase, instead create a new subdriver for nutdrv_qx which * generally covers all Megatec/Qx protocol family and aggregates * device support from such legacy drivers over time. * * A document describing the protocol implemented by this driver can be * found online at "https://www.networkupstools.org/protocols/megatec.html". * * Copyright (C) 2008 - Arjen de Korte * * 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 2 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, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "main.h" #include "serial.h" #include "blazer.h" #define DRIVER_NAME "Megatec/Q1 protocol serial driver" #define DRIVER_VERSION "1.60" /* driver description structure */ upsdrv_info_t upsdrv_info = { DRIVER_NAME, DRIVER_VERSION, "Arjen de Korte ", DRV_BETA, { NULL } }; #define SER_WAIT_SEC 1 /* 3 seconds for Best UPS */ /* * Generic command processing function. Send a command and read a reply. * Returns < 0 on error, 0 on timeout and the number of bytes read on * success. */ ssize_t blazer_command(const char *cmd, char *buf, size_t buflen) { #ifndef TESTING ssize_t ret; ser_flush_io(upsfd); ret = ser_send(upsfd, "%s", cmd); if (ret <= 0) { upsdebugx(3, "send: %s", ret ? strerror(errno) : "timeout"); return ret; } upsdebugx(3, "send: '%.*s'", (int)strcspn(cmd, "\r"), cmd); ret = ser_get_buf(upsfd, buf, buflen, SER_WAIT_SEC, 0); if (ret <= 0) { upsdebugx(3, "read: %s", ret ? strerror(errno) : "timeout"); return ret; } upsdebugx(3, "read: '%.*s'", (int)strcspn(buf, "\r"), buf); return ret; #else const struct { const char *cmd; const char *answer; } testing[] = { { "Q1\r", "(215.0 195.0 230.0 014 49.0 2.27 30.0 00101000\r" }, { "F\r", "#230.0 000 024.0 50.0\r" }, { "I\r", "#NOT_A_LIVE_UPS TESTING TESTING \r" }, { NULL } }; int i; memset(buf, 0, buflen); for (i = 0; cmd && testing[i].cmd; i++) { if (strcasecmp(cmd, testing[i].cmd)) { continue; } /* TODO: Range-check int vs ssize_t values */ return (ssize_t)snprintf(buf, buflen, "%s", testing[i].answer); } return (ssize_t)snprintf(buf, buflen, "%s", testing[i].cmd); #endif } void upsdrv_help(void) { printf("Read The Fine Manual ('man 8 blazer_ser')\n"); } void upsdrv_makevartable(void) { addvar(VAR_VALUE, "cablepower", "Set cable power for serial interface"); blazer_makevartable(); } void upsdrv_initups(void) { #ifndef TESTING #ifndef WIN32 /* TODO : Correctly set the port parameters for WIN32 */ const struct { const char *val; const int dtr; const int rts; } cablepower[] = { { "normal", 1, 0 }, /* default */ { "reverse", 0, 1 }, { "both", 1, 1 }, { "none", 0, 0 }, { NULL, 0, 0 } }; int i; const char *val; struct termios tio; /* * Open and lock the serial port and set the speed to 2400 baud. */ upsfd = ser_open(device_path); ser_set_speed(upsfd, device_path, B2400); if (tcgetattr(upsfd, &tio)) { fatal_with_errno(EXIT_FAILURE, "tcgetattr"); } /* * Use canonical mode input processing (to read reply line) */ tio.c_lflag |= ICANON; /* Canonical input (erase and kill processing) */ tio.c_cc[VEOF] = _POSIX_VDISABLE; tio.c_cc[VEOL] = '\r'; tio.c_cc[VERASE] = _POSIX_VDISABLE; tio.c_cc[VINTR] = _POSIX_VDISABLE; tio.c_cc[VKILL] = _POSIX_VDISABLE; tio.c_cc[VQUIT] = _POSIX_VDISABLE; tio.c_cc[VSUSP] = _POSIX_VDISABLE; tio.c_cc[VSTART] = _POSIX_VDISABLE; tio.c_cc[VSTOP] = _POSIX_VDISABLE; if (tcsetattr(upsfd, TCSANOW, &tio)) { fatal_with_errno(EXIT_FAILURE, "tcsetattr"); } val = getval("cablepower"); for (i = 0; val && cablepower[i].val; i++) { if (!strcasecmp(val, cablepower[i].val)) { break; } } if (!cablepower[i].val) { fatalx(EXIT_FAILURE, "Value '%s' not valid for 'cablepower'", val); } ser_set_dtr(upsfd, cablepower[i].dtr); ser_set_rts(upsfd, cablepower[i].rts); /* * Allow some time to settle for the cablepower */ usleep(100000); #else upsdebugx(0, "blazer_ser: upsdrv_init(): serial port setup for WIN32 currently has not been ported (TODO)"); #endif /* WIN32 */ #endif /* TESTING */ blazer_initups(); } void upsdrv_initinfo(void) { blazer_initinfo(); } void upsdrv_cleanup(void) { #ifndef TESTING ser_set_dtr(upsfd, 0); ser_close(upsfd, device_path); #endif } nut-2.8.1/drivers/nutdrv_qx_q1.h0000644000175000017500000000340614500336654013544 00000000000000/* nutdrv_qx_q1.h - Subdriver for Q1 protocol based UPSes * * Copyright (C) * 2013 Daniele Pezzini * * 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 2 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, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * NOTE: * This subdriver implements the same protocol as the one used by the 'megatec' subdriver minus the vendor (I) and ratings (F) queries. * In the claim function: * - it doesn't even try to get 'vendor' information (I) * - it checks only status (Q1), through 'input.voltage' variable * Therefore it should be able to work even if the UPS doesn't support vendor/ratings *and* the user doesn't use the 'novendor'/'norating' flags, as long as: * - the UPS replies a Q1-compliant answer (i.e. not necessary filled with all of the Q1-required data, but at least of the right length and with not available data filled with some replacement character) * - the UPS reports a valid input.voltage (used in the claim function) * - the UPS reports valid status bits (1st, 2nd, 3rd, 6th, 7th are the mandatory ones) * */ #ifndef NUTDRV_QX_Q1_H #define NUTDRV_QX_Q1_H #include "nutdrv_qx.h" extern subdriver_t q1_subdriver; #endif /* NUTDRV_QX_Q1_H */ nut-2.8.1/drivers/microsol-apc.c0000644000175000017500000001513114501607135013466 00000000000000/* microsol-apc.c - APC Back-UPS BR series UPS driver Copyright (C) 2004 Silvino B. Magalhães 2019 Roberto Panerai Velloso 2021 Ygor A. S. Regados 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 2 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, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 2021/03/19 - Version 0.70 - Initial release, based on solis driver */ #include "config.h" /* must be first */ #include #include #include "main.h" #include "serial.h" #include "nut_float.h" #include "timehead.h" #include "microsol-common.h" #include "microsol-apc.h" #define DRIVER_NAME "APC Back-UPS BR series UPS driver" #define DRIVER_VERSION "0.70" /* driver description structure */ upsdrv_info_t upsdrv_info = { DRIVER_NAME, DRIVER_VERSION, "Silvino B. Magalhães " "Roberto Panerai Velloso " "Ygor A. S. Regados ", DRV_STABLE, { NULL } }; #define false 0 #define true 1 #define RESP_END 0xFE #define ENDCHAR 13 /* replies end with CR */ /* solis commands */ #define CMD_UPSCONT 0xCC #define CMD_SHUT 0xDD #define CMD_SHUTRET 0xDE #define CMD_EVENT 0xCE #define CMD_DUMP 0xCD /** Check if UPS model is available here. */ bool_t ups_model_defined(void) { unsigned int model_index; for (model_index = 0; MODELS[model_index] != ups_model; model_index++); if (model_index == MODEL_COUNT) { return 0; } else { return 1; } } /** Set UPS model name. */ void set_ups_model(void) { switch (ups_model) { case 183: model_name = "BZ2200I-BR"; break; case 190: model_name = "BZ1500-BR"; break; case 191: model_name = "BZ2200BI-BR"; break; default: model_name = "Unknown UPS"; } } /** * Parse received packet with UPS instantaneous data. * This function parses model-specific values, such as voltage and battery times. */ void scan_received_pack_model_specific(void) { unsigned int relay_state; unsigned int model_index; float real_power_curve_1, real_power_curve_2, real_power_curve_3; float power_difference_1, power_difference_2, power_difference_3; bool_t recharging; /* Extract unprocessed data from packet */ input_voltage = received_packet[2]; output_voltage = received_packet[1]; output_current = received_packet[5]; battery_voltage = received_packet[3]; relay_state = (received_packet[6] & 0x28) >> 3; /* Find array indexes for detected UPS model */ for (model_index = 0; MODELS[model_index] != ups_model && model_index < MODEL_COUNT - 1; model_index++); if (MODELS[model_index] != ups_model) { upslogx(LOG_NOTICE, "UPS model not found, using fallback option."); } /* Start processing according to model */ nominal_power = NOMINAL_POWER[model_index]; input_voltage = INPUT_VOLTAGE_MULTIPLIER_A[model_index][output_220v] * input_voltage + INPUT_VOLTAGE_MULTIPLIER_B[model_index][output_220v]; battery_voltage = BATTERY_VOLTAGE_MULTIPLIER_A[model_index] * battery_voltage + BATTERY_VOLTAGE_MULTIPLIER_B[model_index]; output_current = OUTPUT_CURRENT_MULTIPLIER_A[model_index][line_unpowered] * output_current + OUTPUT_CURRENT_MULTIPLIER_B[model_index][line_unpowered]; if (ups_model == 190 && line_unpowered) { /* Special calculation for BZ1500 on battery */ output_voltage = battery_voltage * sqrt(output_voltage / 64.0) * OUTPUT_VOLTAGE_MULTIPLIER_A[model_index][line_unpowered][relay_state] - output_current * OUTPUT_VOLTAGE_MULTIPLIER_B[model_index][line_unpowered][relay_state]; output_voltage = 1.5091 * output_voltage + 1.5823; if (output_current > 4.0) output_voltage += output_current * 4.0; if (output_current > 3.0) output_voltage += output_current * 2.0; else if (output_voltage > 0.9) output_voltage += output_current / 3.0; else output_voltage -= 5.0; if (output_voltage < 100.0) output_voltage = 100; } else { output_voltage = OUTPUT_VOLTAGE_MULTIPLIER_A[model_index][line_unpowered][relay_state] * output_voltage + OUTPUT_VOLTAGE_MULTIPLIER_B[model_index][line_unpowered][relay_state]; } if (line_unpowered) { input_frequency = 0; output_frequency = 60; } else { input_frequency = 0.37 * (257 - ((received_packet[21] + received_packet[22] * 256) >> 8)); output_frequency = input_frequency; } apparent_power = output_current * output_voltage; real_power = received_packet[7] + 256 * received_packet[8]; real_power_curve_1 = REAL_POWER_CURVE_SELECTOR_A1[model_index][relay_state] * real_power + REAL_POWER_CURVE_SELECTOR_B1[model_index][relay_state]; real_power_curve_2 = REAL_POWER_CURVE_SELECTOR_A2[model_index][relay_state] * real_power + REAL_POWER_CURVE_SELECTOR_B2[model_index][relay_state]; real_power_curve_3 = REAL_POWER_CURVE_SELECTOR_A3[model_index][relay_state] * real_power + REAL_POWER_CURVE_SELECTOR_B3[model_index][relay_state]; power_difference_1 = fabs(real_power_curve_1 - apparent_power); power_difference_2 = fabs(real_power_curve_2 - apparent_power); power_difference_3 = fabs(real_power_curve_3 - apparent_power); if (power_difference_1 < power_difference_2 && power_difference_1 < power_difference_3) { real_power = REAL_POWER_MULTIPLIER_A1[model_index][relay_state] * real_power + REAL_POWER_MULTIPLIER_B1[model_index][relay_state]; } else if (power_difference_2 < power_difference_3) { real_power = REAL_POWER_MULTIPLIER_A2[model_index][relay_state] * real_power + REAL_POWER_MULTIPLIER_B2[model_index][relay_state]; } else { real_power = REAL_POWER_MULTIPLIER_A3[model_index][relay_state] * real_power + REAL_POWER_MULTIPLIER_B3[model_index][relay_state]; } /* If real power is greater than apparent power, invert values */ if (apparent_power < real_power) { apparent_power = apparent_power + real_power; real_power = apparent_power - real_power; apparent_power = apparent_power - real_power; } input_current = 1.1 * apparent_power / input_voltage; recharging = (0x02 & received_packet[20]) == 0x02; battery_charge = (100.0 * (battery_voltage - MIN_BATTERY_VOLTAGE[model_index])) / (MAX_BATTERY_VOLTAGE[model_index][recharging] - MIN_BATTERY_VOLTAGE[model_index]); } nut-2.8.1/drivers/mge-hid.h0000644000175000017500000000206114273170601012412 00000000000000/* mge-hid.h - data to monitor MGE UPS SYSTEMS HID (USB and serial) devices * * Copyright (C) 2003 - 2005 * Arnaud Quette * * Sponsored by MGE UPS SYSTEMS * * 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 2 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, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #ifndef MGE_HID_H #define MGE_HID_H #include "usbhid-ups.h" extern subdriver_t mge_subdriver; #endif /* MGE_HID_H */ nut-2.8.1/drivers/socomec_jbus.c0000644000175000017500000003336114502253356013561 00000000000000/* socomec_jbus.c - Driver for Socomec JBUS UPS * * Copyright (C) * 2021 Thanos Chatziathanassiou * * Based on documentation found freely on * https://www.socomec.com/files/live/sites/systemsite/files/GB-JBUS-MODBUS-for-Delphys-MP-and-Delphys-MX-operating-manual.pdf * but with dubious legal license. The document itself states: * ``CAUTION : “This is a product for restricted sales distribution to informed partners. * Installation restrictions or additional measures may be needed to prevent disturbances'' * YMMV * * 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 2 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, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #include "main.h" #include #define DRIVER_NAME "Socomec jbus driver" #define DRIVER_VERSION "0.07" #define CHECK_BIT(var,pos) ((var) & (1<<(pos))) #define MODBUS_SLAVE_ID 1 #define BATTERY_RUNTIME_CRITICAL 15 /* Variables */ static modbus_t *modbus_ctx = NULL; static int mrir(modbus_t * arg_ctx, int addr, int nb, uint16_t * dest); /* driver description structure */ upsdrv_info_t upsdrv_info = { DRIVER_NAME, DRIVER_VERSION, "Thanos Chatziathanassiou \n", DRV_BETA, {NULL} }; void upsdrv_initinfo(void) { uint16_t tab_reg[12]; int r; upsdebugx(2, "upsdrv_initinfo"); dstate_setinfo("device.mfr", "socomec jbus"); dstate_setinfo("device.model", "Socomec Generic"); upsdebugx(2, "initial read"); /* this is a neat trick, but not really helpful right now https://stackoverflow.com/questions/25811662/spliting-an-hex-into-2-hex-values/41733170#41733170 uint8_t *lowbyte; uint8_t *hibyte; */ r = mrir(modbus_ctx, 0x1000, 12, tab_reg); if (r == -1) { fatalx(EXIT_FAILURE, "failed to read UPS code from JBUS. r is %d error %s", r, modbus_strerror(errno)); } upsdebugx(2, "read UPS Code %d", tab_reg[0]); if (tab_reg[1]) { upsdebugx(2, "read UPS Power %d (kVA * 10)", tab_reg[1]); dstate_setinfo("ups.power", "%u", tab_reg[1]*100 ); } /* known Socomec Models */ switch (tab_reg[0]) { case 130: dstate_setinfo("ups.model", "%s", "DIGYS"); break; case 515: dstate_setinfo("ups.model", "%s", "DELPHYS MX"); break; case 516: dstate_setinfo("ups.model", "%s", "DELPHYS MX elite"); break; default: dstate_setinfo("ups.model", "Unknown Socomec JBUS. Send id %u and specify the model", tab_reg[0]); } if (tab_reg[3] && tab_reg[4] && tab_reg[5] && tab_reg[6] && tab_reg[7]) { dstate_setinfo("ups.serial", "%c%c%c%c%c%c%c%c%c%c", (tab_reg[3]&0xFF), (tab_reg[3]>>8), (tab_reg[4]&0xFF), (tab_reg[4]>>8), (tab_reg[5]&0xFF), (tab_reg[5]>>8), (tab_reg[6]&0xFF), (tab_reg[6]>>8), (tab_reg[7]&0xFF), (tab_reg[7]>>8) ); } /* upsh.instcmd = instcmd; */ /* upsh.setvar = setvar; */ } void upsdrv_updateinfo(void) { uint16_t tab_reg[64]; int r; upsdebugx(2, "upsdrv_updateinfo"); status_init(); /* ups configuration */ r = mrir(modbus_ctx, 0x10E0, 32, tab_reg); if (r == -1 || !tab_reg[0]) { upsdebugx(2, "Did not receive any data from the UPS at 0x10E0 ! Going stale r is %d error %s", r, modbus_strerror(errno)); dstate_datastale(); return; } dstate_setinfo("input.voltage", "%u", tab_reg[0]); dstate_setinfo("output.voltage", "%u", tab_reg[1]); dstate_setinfo("input.frequency", "%u", tab_reg[2]); dstate_setinfo("output.frequency", "%u", tab_reg[3]); upsdebugx(2, "battery capacity (Ah * 10) %u", tab_reg[8]); upsdebugx(2, "battery elements %u", tab_reg[9]); /* time and date */ r = mrir(modbus_ctx, 0x1360, 4, tab_reg); if (r == -1) { upsdebugx(2, "Did not receive any data from the UPS at 0x1360 ! Ignoring ? r is %d error %s", r, modbus_strerror(errno)); } dstate_setinfo("ups.time", "%02d:%02d:%02d", (tab_reg[1]&0xFF), (tab_reg[0]>>8), (tab_reg[0]&0xFF) ); dstate_setinfo("ups.date", "%04d/%02d/%02d", (tab_reg[3]+2000), (tab_reg[2]>>8), (tab_reg[1]>>8) ); /* ups status */ r = mrir(modbus_ctx, 0x1020, 6, tab_reg); if (r == -1) { upsdebugx(2, "Did not receive any data from the UPS at 0x1020 ! Ignoring ? r is %d error %s", r, modbus_strerror(errno)); /* dstate_datastale(); return; */ } if (CHECK_BIT(tab_reg[0], 0)) upsdebugx(2, "Rectifier Input supply present"); if (CHECK_BIT(tab_reg[0], 1)) upsdebugx(2, "Inverter ON "); if (CHECK_BIT(tab_reg[0], 2)) upsdebugx(2, "Rectifier ON"); if (CHECK_BIT(tab_reg[0], 3)) upsdebugx(2, "Load protected by inverter"); if (CHECK_BIT(tab_reg[0], 4)) upsdebugx(2, "Load on automatic bypass"); if (CHECK_BIT(tab_reg[0], 5)) upsdebugx(2, "Load on battery"); if (CHECK_BIT(tab_reg[0], 6)) upsdebugx(2, "Remote controls disable"); if (CHECK_BIT(tab_reg[0], 7)) upsdebugx(2, "Eco-mode ON"); if (CHECK_BIT(tab_reg[0], 14)) upsdebugx(2, "Battery Test failed"); if (CHECK_BIT(tab_reg[0], 15)) upsdebugx(2, "Battery near end of backup time"); if (CHECK_BIT(tab_reg[0], 16)) upsdebugx(2, "Battery disacharged"); if (CHECK_BIT(tab_reg[1], 0)) upsdebugx(2, "Battery OK"); if (CHECK_BIT(tab_reg[1], 10)) upsdebugx(2, "Bypass input supply present"); if (CHECK_BIT(tab_reg[1], 11)) upsdebugx(2, "Battery charging"); if (CHECK_BIT(tab_reg[1], 12)) upsdebugx(2, "Bypass input frequency out of tolerance"); if (CHECK_BIT(tab_reg[2], 0)) upsdebugx(2, "Unit operating"); if (CHECK_BIT(tab_reg[3], 0)) upsdebugx(2, "Maintenance mode active"); if (CHECK_BIT(tab_reg[4], 0)) upsdebugx(2, "Boost charge ON"); if (CHECK_BIT(tab_reg[4], 2)) upsdebugx(2, "Inverter switch closed"); if (CHECK_BIT(tab_reg[4], 3)) upsdebugx(2, "Bypass breaker closed"); if (CHECK_BIT(tab_reg[4], 4)) upsdebugx(2, "Maintenance bypass breaker closed"); if (CHECK_BIT(tab_reg[4], 5)) upsdebugx(2, "Remote maintenance bypass breaker closed"); if (CHECK_BIT(tab_reg[4], 6)) upsdebugx(2, "Output breaker closed (Q3)"); if (CHECK_BIT(tab_reg[4], 9)) upsdebugx(2, "Unit working"); if (CHECK_BIT(tab_reg[4], 12)) upsdebugx(2, "normal mode active"); /* alarms */ r = mrir(modbus_ctx, 0x1040, 4, tab_reg); alarm_init(); if (r == -1) { upsdebugx(2, "Did not receive any data from the UPS at 0x1040 ! Ignoring ? r is %d error %s", r, modbus_strerror(errno)); /* dstate_datastale(); return; */ } if (CHECK_BIT(tab_reg[0], 0)) { upsdebugx(2, "General Alarm"); alarm_set("General Alarm present."); } if (CHECK_BIT(tab_reg[0], 1)) { upsdebugx(2, "Battery failure"); alarm_set("Battery failure."); } if (CHECK_BIT(tab_reg[0], 2)) { upsdebugx(2, "UPS overload"); alarm_set("Overload fault."); } if (CHECK_BIT(tab_reg[0], 4)) { upsdebugx(2, "Control failure (com, internal supply...)"); alarm_set("Control failure (com, internal supply...)"); } if (CHECK_BIT(tab_reg[0], 5)) { upsdebugx(2, "Rectifier input supply out of tolerance "); alarm_set("Rectifier input supply out of tolerance."); } if (CHECK_BIT(tab_reg[0], 6)) { upsdebugx(2, "Bypass input supply out of tolerance "); alarm_set("Bypass input supply out of tolerance."); } if (CHECK_BIT(tab_reg[0], 7)) { upsdebugx(2, "Over temperature alarm "); alarm_set("Over temperature fault."); } if (CHECK_BIT(tab_reg[0], 8)) { upsdebugx(2, "Maintenance bypass closed"); alarm_set("Maintenance bypass closed."); } if (CHECK_BIT(tab_reg[0], 10)) { upsdebugx(2, "Battery charger fault"); alarm_set("Battery charger fault."); } if (CHECK_BIT(tab_reg[1], 1)) upsdebugx(2, "Improper condition of use"); if (CHECK_BIT(tab_reg[1], 2)) upsdebugx(2, "Inverter stopped for overload (or bypass transfer)"); if (CHECK_BIT(tab_reg[1], 3)) upsdebugx(2, "Microprocessor control system"); if (CHECK_BIT(tab_reg[1], 5)) upsdebugx(2, "Synchronisation fault (PLL fault)"); if (CHECK_BIT(tab_reg[1], 6)) upsdebugx(2, "Rectifier input supply fault"); if (CHECK_BIT(tab_reg[1], 7)) upsdebugx(2, "Rectifier preventive alarm"); if (CHECK_BIT(tab_reg[1], 9)) upsdebugx(2, "Inverter preventive alarm"); if (CHECK_BIT(tab_reg[1], 10)) upsdebugx(2, "Charger general alarm"); if (CHECK_BIT(tab_reg[1], 13)) upsdebugx(2, "Bypass preventive alarm"); if (CHECK_BIT(tab_reg[1], 15)) { upsdebugx(2, "Imminent STOP"); alarm_set("Imminent STOP."); } if (CHECK_BIT(tab_reg[2], 12)) { upsdebugx(2, "Servicing alarm"); alarm_set("Servicing alarm."); } if (CHECK_BIT(tab_reg[2], 15)) upsdebugx(2, "Battery room alarm"); if (CHECK_BIT(tab_reg[3], 0)) { upsdebugx(2, "Maintenance bypass alarm"); alarm_set("Maintenance bypass."); } if (CHECK_BIT(tab_reg[3], 1)) { upsdebugx(2, "Battery discharged"); alarm_set("Battery discharged."); } if (CHECK_BIT(tab_reg[3], 3)) upsdebugx(2, "Synoptic alarm"); if (CHECK_BIT(tab_reg[3], 4)) { upsdebugx(2, "Critical Rectifier fault"); alarm_set("Critical Rectifier fault."); } if (CHECK_BIT(tab_reg[3], 6)) { upsdebugx(2, "Critical Inverter fault"); alarm_set("Critical Inverter fault."); } if (CHECK_BIT(tab_reg[3], 10)) upsdebugx(2, "ESD activated"); if (CHECK_BIT(tab_reg[3], 11)) { upsdebugx(2, "Battery circuit open"); alarm_set("Battery circuit open."); } if (CHECK_BIT(tab_reg[3], 14)) { upsdebugx(2, "Bypass critical alarm"); alarm_set("Bypass critical alarm."); } /* measurements */ r = mrir(modbus_ctx, 0x1060, 48, tab_reg); if (r == -1) { upsdebugx(2, "Did not receive any data from the UPS at 0x1060 ! Ignoring ? r is %d error %s", r, modbus_strerror(errno)); /* dstate_datastale(); return; */ } if (tab_reg[1] == 0xFFFF && tab_reg[2] == 0xFFFF) { /* this a 1-phase model */ dstate_setinfo("input.phases", "1" ); dstate_setinfo("ups.load", "%u", tab_reg[0] ); dstate_setinfo("input.bypass.voltage", "%u", tab_reg[6] ); dstate_setinfo("output.voltage", "%u", tab_reg[9] ); if (tab_reg[15] != 0xFFFF) dstate_setinfo("output.current", "%u", tab_reg[15] ); } else { /* this a 3-phase model */ dstate_setinfo("input.phases", "3" ); dstate_setinfo("ups.load", "%u", tab_reg[3] ); dstate_setinfo("ups.L1.load", "%u", tab_reg[0] ); dstate_setinfo("ups.L2.load", "%u", tab_reg[1] ); dstate_setinfo("ups.L3.load", "%u", tab_reg[2] ); dstate_setinfo("input.bypass.L1-N.voltage", "%u", tab_reg[6] ); dstate_setinfo("input.bypass.L2-N.voltage", "%u", tab_reg[7] ); dstate_setinfo("input.bypass.L3-N.voltage", "%u", tab_reg[8] ); dstate_setinfo("output.L1-N.voltage", "%u", tab_reg[9] ); dstate_setinfo("output.L2-N.voltage", "%u", tab_reg[10] ); dstate_setinfo("output.L3-N.voltage", "%u", tab_reg[11] ); if (tab_reg[15] != 0xFFFF) dstate_setinfo("output.L1.current", "%u", tab_reg[15] ); if (tab_reg[16] != 0xFFFF) dstate_setinfo("output.L2.current", "%u", tab_reg[16] ); if (tab_reg[17] != 0xFFFF) dstate_setinfo("output.L3.current", "%u", tab_reg[17] ); } dstate_setinfo("battery.charge", "%u", tab_reg[4] ); dstate_setinfo("battery.capacity", "%u", (tab_reg[5]/10) ); dstate_setinfo("battery.voltage", "%.2f", (double) (tab_reg[20]) / 10); dstate_setinfo("battery.current", "%.2f", (double) (tab_reg[24]) / 10 ); dstate_setinfo("battery.runtime", "%u", tab_reg[23] ); dstate_setinfo("input.bypass.frequency", "%u", (tab_reg[18]/10) ); dstate_setinfo("output.frequency", "%u", (tab_reg[19]/10) ); if (tab_reg[22] != 0xFFFF) { dstate_setinfo("ambient.1.present", "yes"); dstate_setinfo("ambient.1.temperature", "%u", tab_reg[22] ); } if (tab_reg[23] == 0xFFFF) { /* battery.runtime == 0xFFFF means we're on mains */ status_set("OL"); } else if (tab_reg[23] > BATTERY_RUNTIME_CRITICAL) { /* we still have mora than BATTERY_RUNTIME_CRITICAL min left ? */ status_set("OB"); } else { status_set("LB"); } /*TODO: --essential ups.status TRIM/BOOST/OVER ups.alarm --dangerous ups.shutdown shutdown.return shutdown.stop shutdown.reboot shutdown.reboot.graceful bypass.start beeper.enable beeper.disable */ alarm_commit(); status_commit(); dstate_dataok(); return; } void upsdrv_shutdown(void) { /* replace with a proper shutdown function */ upslogx(LOG_ERR, "shutdown not supported"); set_exit_flag(-1); } void upsdrv_help(void) { } /* list flags and values that you want to receive via -x */ void upsdrv_makevartable(void) { } void upsdrv_initups(void) { int r; upsdebugx(2, "upsdrv_initups"); modbus_ctx = modbus_new_rtu(device_path, 9600, 'N', 8, 1); if (modbus_ctx == NULL) fatalx(EXIT_FAILURE, "Unable to create the libmodbus context"); r = modbus_set_slave(modbus_ctx, MODBUS_SLAVE_ID); /* slave ID */ if (r < 0) { modbus_free(modbus_ctx); fatalx(EXIT_FAILURE, "Invalid modbus slave ID %d",MODBUS_SLAVE_ID); } if (modbus_connect(modbus_ctx) == -1) { modbus_free(modbus_ctx); fatalx(EXIT_FAILURE, "modbus_connect: unable to connect: %s", modbus_strerror(errno)); } } void upsdrv_cleanup(void) { if (modbus_ctx != NULL) { modbus_close(modbus_ctx); modbus_free(modbus_ctx); } } /* Modbus Read Input Registers */ static int mrir(modbus_t * arg_ctx, int addr, int nb, uint16_t * dest) { int r, i; /* zero out the thing, because we might have reused it */ for (i=0; i * Author: Kirill Smelkov * * 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 2 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, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ /* * - NOTE the following document is referenced in this driver: * * TE-36862-B4 "COMLI COMMUNICATION PROTOCOL IMPLEMENTED IN PRS SYSTEMS", * by Eltek A/S * * * - AL175 debug levels: * * 1 user-level trace (status, instcmd, etc...) * 2 status decode errors * 3 COMLI proto handling errors * 4 raw IO trace * */ #include "main.h" #include "serial.h" #include "timehead.h" #include #include #include #include #include #include "nut_stdint.h" typedef uint8_t byte_t; #define DRIVER_NAME "Eltek AL175/COMLI driver" #define DRIVER_VERSION "0.14" /* driver description structure */ upsdrv_info_t upsdrv_info = { DRIVER_NAME, DRIVER_VERSION, "Kirill Smelkov \n" \ "Marine & Bridge Navigation Systems ", DRV_EXPERIMENTAL, { NULL } }; #define STX 0x02 #define ETX 0x03 #define ACK 0x06 /************ * RAW DATA * ************/ /** * raw_data buffer representation */ typedef struct { byte_t *buf; /*!< the whole buffer address */ size_t buf_size; /*!< the whole buffer size */ byte_t *begin; /*!< begin of content */ byte_t *end; /*!< one-past-end of content */ } raw_data_t; /** * pseudo-alloca raw_data buffer (alloca is not in POSIX) * @param varp ptr-to local raw_data_t variable to which to alloca * @param buf_array array allocated on stack which will be used as storage * (must be auto-variable) * @return alloca'ed memory as raw_data * * Example: * * raw_data_t ack; * byte_t ack_buf[8]; * * raw_alloc_onstack(&ack, ack_buf); */ #define raw_alloc_onstack(varp, buf_array) do { \ (varp)->buf = &(buf_array)[0]; \ (varp)->buf_size = sizeof(buf_array); \ \ (varp)->begin = (varp)->buf; \ (varp)->end = (varp)->buf; \ } while (0) /** * xmalloc raw buffer * @param size size in bytes * @return xmalloc'ed memory as raw_data */ static raw_data_t raw_xmalloc(size_t size) { raw_data_t data; data.buf = xmalloc(size); data.buf_size = size; data.begin = data.buf; data.end = data.buf; return data; } /** * free raw_data buffer * @param buf raw_data buffer to free */ static void raw_free(raw_data_t *buf) { free(buf->buf); buf->buf = NULL; buf->buf_size = 0; buf->begin = NULL; buf->end = NULL; } /***************************************************************************/ /*************** * COMLI types * ***************/ /** * COMLI message header info * @see 1. INTRODUCTION */ typedef struct { int id; /*!< Id[1:2] */ int stamp; /*!< Stamp[3] */ int type; /*!< Mess Type[4] */ } msg_head_t; /** * COMLI IO header info * @see 1. INTRODUCTION */ typedef struct { size_t addr; /*!< Addr[5:8] */ size_t len; /*!< NOB[9:10] */ } io_head_t; /** * maximum allowed io.len value */ #define IO_LEN_MAX 0xff /** * COMLI header info * @see 1. INTRODUCTION */ typedef struct { msg_head_t msg; /*!< message header [1:4] */ io_head_t io; /*!< io header [5:10] */ } comli_head_t; /****************** * MISC UTILITIES * ******************/ /** * convert hex string to int * @param head input string * @param len string length * @return parsed value (>=0) if success, -1 on error */ static long from_hex(const byte_t *head, unsigned len) { long val=0; while (len-- != 0) { int ch = *head; if (!isxdigit(ch)) return -1; /* wrong character */ val *= 0x10; if (isdigit(ch)) { val += (ch-'0'); } else { /* ch = toupper(ch) without locale-related problems */ if (ch < 'A') ch += 'A' - 'a'; val += 0x0A + (ch-'A'); } ++head; } return val; } /** * compute checksum of a buffer * @see 10. CHECKSUM BCC * @param buf buffer address * @param count no. of bytes in the buffer * @return computed checksum */ static byte_t compute_bcc(const byte_t *buf, size_t count) { byte_t bcc=0; size_t i; for (i=0; i> 7 ) | (byte_t)( (x & 0x40) >> 5 ) | (byte_t)( (x & 0x20) >> 3 ) | (byte_t)( (x & 0x10) >> 1 ) | (byte_t)( (x & 0x08) << 1 ) | (byte_t)( (x & 0x04) << 3 ) | (byte_t)( (x & 0x02) << 5 ) | (byte_t)( (x & 0x01) << 7 ); *buf = x; ++buf; --count; } } /********************************************************************/ /* * communication basics * * ME (Monitor Equipment) * PRS (Power Rectifier System) /think of it as of UPS in common speak/ * * there are 2 types of transactions: * * 'ACTIVATE COMMAND' * ME -> PRS (al_prep_activate) * ME <- PRS [ack] (al_check_ack) * * * 'READ REGISTER' * ME -> PRS (al_prep_read_req) * ME <- PRS [data] (al_parse_reply) * */ /******************** * COMLI primitives * ********************/ /************************ * COMLI: OUTPUT FRAMES * ************************/ /** * prepare COMLI sentence * @see 1. INTRODUCTION * @param dest [out] where to put the result * @param h COMLI header info * @param buf data part of the sentence * @param count amount of data bytes in the sentence * * @note: the data are copied into the sentence "as-is", there is no conversion is done. * if the caller wants to reverse bits it is necessary to call reverse_bits(...) prior * to comli_prepare. */ static void comli_prepare(raw_data_t *dest, const comli_head_t *h, const void *buf, size_t count) { /* * 0 1 2 3 4 5 6 7 8 9 10 11 - - - N-1 N * +-----+---------+-------+------+-------------------------+-----------+------------+-----+-----+ * | STX | IDh IDl | Stamp | type | addr1 addr2 addr3 addr4 | NOBh NOBl | ...data... | ETX | BCC | * +-----+---------+-------+------+-------------------------+-----------+------------+-----+-----+ * * ^ ^ * | | *begin end */ byte_t *out = dest->begin; /* it's caller responsibility to allocate enough space. else it is a bug in the program */ if ( (out+11+count+2) > (dest->buf + dest->buf_size) ) fatalx(EXIT_FAILURE, "too small dest in comli_prepare\n"); out[0] = STX; snprintf((char *)out+1, 10+1, "%02X%1i%1i%04zX%02zX", h->msg.id, h->msg.stamp, h->msg.type, h->io.addr, h->io.len); memcpy(out+11, buf, count); reverse_bits(out+11, count); out[11+count] = ETX; out[12+count] = compute_bcc(out+1, 10+count+1); dest->end = dest->begin + (11+count+2); } /** * prepare AL175 read data request * @see 2. MESSAGE TYPE 2 (COMMAND SENT FROM MONITORING EQUIPMENT) * @param dest [out] where to put the result * @param addr start address of requested area * @param count no. of requested bytes */ static void al_prep_read_req(raw_data_t *dest, size_t addr, size_t count) { comli_head_t h; h.msg.id = 0x14; h.msg.stamp = 1; h.msg.type = 2; h.io.addr = addr; h.io.len = count; comli_prepare(dest, &h, NULL, 0); } /** * prepare AL175 activate command * @see 4. MESSAGE TYPE 0 (ACTIVATE COMMAND) * @param dest [out] where to put the result * @param cmd command type [11] * @param subcmd command subtype [12] * @param pr1 first parameter [13:14] * @param pr2 second parameter [15:16] * @param pr3 third parameter [17:18] */ static void al_prep_activate(raw_data_t *dest, byte_t cmd, byte_t subcmd, uint16_t pr1, uint16_t pr2, uint16_t pr3) { comli_head_t h; char data[8+1]; h.msg.id = 0x14; h.msg.stamp = 1; h.msg.type = 0; h.io.addr = 0x4500; h.io.len = 8; /* NOTE: doc says we should use ASCII coding here, but the actual * values are > 0x80, so we use binary coding. And have to * make this "fit" into the char array required by snprintf */ data[0] = (char)cmd; data[1] = (char)subcmd; /* FIXME? One CI testcase builder claims here that * warning: '%2X' directive output may be truncated writing * between 2 and 4 bytes into a region of size between 3 and 5 * [-Wformat-truncation=] * but none others do, and I can't figure out how it thinks so :/ * * Per https://stackoverflow.com/questions/51534284/how-to-circumvent-format-truncation-warning-in-gcc * https://www.mail-archive.com/gcc-bugs@gcc.gnu.org/msg521037.html * and simlar googlable sources, this seems to be a bug-or-feature * linked to non-zero optimization level and/or not checking for the * return value (conveys runtime errors if any do happen). */ assert (pr1 <= UINT8_MAX); assert (pr2 <= UINT8_MAX); assert (pr3 <= UINT8_MAX); if (0 > snprintf(data+2, 6+1, "%2X%2X%2X", pr1, pr2, pr3)) { data[8] = '\0'; } comli_prepare(dest, &h, data, 8); } /*********************** * COMLI: INPUT FRAMES * ***********************/ /** * check COMLI frame for correct layout and bcc * @param f frame to check * * @return 0 (ok) -1 (error) */ static int comli_check_frame(/*const*/ raw_data_t f) { int bcc; byte_t *tail; if ( (f.end - f.begin) < 2 ) return -1; if (*f.begin!=STX) return -1; tail = f.end - 2; if (tail <= f.begin) return -1; if (tail[0]!=ETX) return -1; bcc = compute_bcc(f.begin+1, (size_t)(f.end - f.begin) - 2 /*STX & BCC*/); if (bcc!= tail[1]) return -1; return 0; } /** * parse reply header from PRS * @see 3. MESSAGE TYPE 0 (REPLY FROM PRS ON MESSAGE TYPE 2) * * @param io [out] parsed io_header * @param raw_reply_head [in] raw reply header from PRS * @return 0 (ok), -1 (error) * * @see al_parse_reply */ static int al_parse_reply_head(io_head_t *io, const raw_data_t raw_reply_head) { /* * 0 1 2 3 4 5 6 7 8 9 10 * +-----+---------+-------+------+-------------------------+-----------+-----------+ * | STX | IDh IDl | Stamp | type | addr1 addr2 addr3 addr4 | NOBh NOBl | ......... | * +-----+---------+-------+------+-------------------------+-----------+-----------+ * * ^ ^ * | | * begin end */ size_t io_addr, io_len; const byte_t *reply_head = raw_reply_head.begin - 1; if ( (raw_reply_head.end - raw_reply_head.begin) != 10) { upsdebugx(3, "%s: wrong size\t(%i != 10)", __func__, (int)(raw_reply_head.end - raw_reply_head.begin)); return -1; /* wrong size */ } if (reply_head[1]!='0' || reply_head[2]!='0') { upsdebugx(3, "%s: wrong id\t('%c%c' != '00')", __func__, reply_head[1], reply_head[2]); return -1; /* wrong id */ } if (reply_head[3]!='1') { upsdebugx(3, "%s: wrong stamp\t('%c' != '1')", __func__, reply_head[3]); return -1; /* wrong stamp */ } if (reply_head[4]!='0') { upsdebugx(3, "%s: wrong type\t('%c' != '0')", __func__, reply_head[4]); return -1; /* wrong type */ } /* Avoid signed/unsigned implicit conversion warnings * At least, when shuffling a signed long into unsigned long, * don't have to worry about overflows */ io_addr = (size_t)from_hex(&reply_head[5], 4); if (io_addr == -1UL) { upsdebugx(3, "%s: invalid addr\t('%c%c%c%c')", __func__, reply_head[5], reply_head[6], reply_head[7], reply_head[8]); return -1; /* wrong addr */ } io_len = (size_t)from_hex(&reply_head[9], 2); if (io_len == -1UL) { upsdebugx(3, "%s: invalid nob\t('%c%c')", __func__, reply_head[9], reply_head[10]); return -1; /* wrong NOB */ } if (io_len > IO_LEN_MAX) { upsdebugx(3, "nob too big\t(%" PRIuSIZE " > %i)", io_len, IO_LEN_MAX); return -1; /* too much data claimed */ } io->addr = io_addr; io->len = io_len; return 0; } /** * parse reply from PRS * @see 3. MESSAGE TYPE 0 (REPLY FROM PRS ON MESSAGE TYPE 2) * @param io_head [out] parsed io_header * @param io_buf [in] [out] raw_data where to place incoming data (see ...data... below) * @param raw_reply raw reply from PRS to check * @return 0 (ok), -1 (error) * * @see al_parse_reply_head */ static int al_parse_reply(io_head_t *io_head, raw_data_t *io_buf, /*const*/ raw_data_t raw_reply) { /* * 0 1 2 3 4 5 6 7 8 9 10 11 - - - N-1 N * +-----+---------+-------+------+-------------------------+-----------+------------+-----+-----+ * | STX | IDh IDl | Stamp | type | addr1 addr2 addr3 addr4 | NOBh NOBl | ...data... | ETX | BCC | * +-----+---------+-------+------+-------------------------+-----------+------------+-----+-----+ * * ^ ^ * | | * begin end */ int err; size_t i, io_buf_len; const byte_t *reply = NULL; /* 1: extract header and parse it */ /*const*/ raw_data_t raw_reply_head = raw_reply; if (raw_reply_head.begin + 10 <= raw_reply_head.end) raw_reply_head.end = raw_reply_head.begin + 10; err = al_parse_reply_head(io_head, raw_reply_head); if (err==-1) return -1; /* 2: process data */ reply = raw_reply.begin - 1; if ( (raw_reply.end - raw_reply.begin) != (ptrdiff_t)(10 + io_head->len)) { upsdebugx(3, "%s: corrupt sentence\t(%i != %" PRIiSIZE ")", __func__, (int)(raw_reply.end - raw_reply.begin), 10 + io_head->len); return -1; /* corrupt sentence */ } /* 3: extract the data */ if (io_buf->buf_size < io_head->len) { upsdebugx(3, "%s: too much data to fit in io_buf\t(%" PRIuSIZE " > %" PRIuSIZE ")", __func__, io_head->len, io_buf->buf_size); return -1; /* too much data to fit in io_buf */ } io_buf->begin = io_buf->buf; io_buf->end = io_buf->begin; for (i=0; ilen; ++i) *(io_buf->end++) = reply[11+i]; assert(io_buf->end - io_buf->begin >= 0); io_buf_len = (size_t)(io_buf->end - io_buf->begin); reverse_bits(io_buf->begin, io_buf_len ); upsdebug_hex(3, "\t\t--> payload", io_buf->begin, io_buf_len); return 0; /* all ok */ } /** * check acknowledge from PRS * @see 5. ACKNOWLEDGE FROM PRS * @param raw_ack raw acknowledge from PRS to check * @return 0 on success, -1 on error */ static int al_check_ack(/*const*/ raw_data_t raw_ack) { /* * 0 1 2 3 4 5 6 7 * +-----+---------+-------+------+-----+-----+-----+ * | STX | IDh IDl | Stamp | type | ACK | ETX | BCC | * +-----+---------+-------+------+-----+-----+-----+ * * ^ ^ * | | * begin end */ const byte_t *ack = raw_ack.begin - 1; if ( (raw_ack.end - raw_ack.begin) !=5) { upsdebugx(3, "%s: wrong size\t(%i != 5)", __func__, (int)(raw_ack.end - raw_ack.begin)); return -1; /* wrong size */ } if (ack[1]!='0' || ack[2]!='0') { upsdebugx(3, "%s: wrong id\t('%c%c' != '00')", __func__, ack[1], ack[2]); return -1; /* wrong id */ } /* the following in not mandated. it is just said it will be * "same as one received". but we always send '1' (0x31) as stamp * (see 4. MESSAGE TYPE 0 (ACTIVATE COMMAND). Hence, stamp checking * is hardcoded here. */ if (ack[3]!='1') { upsdebugx(3, "%s: wrong stamp\t('%c' != '1')", __func__, ack[3]); return -1; /* wrong stamp */ } if (ack[4]!='1') { upsdebugx(3, "%s: wrong type\t('%c' != '1')", __func__, ack[4]); return -1; /* wrong type */ } if (ack[5]!=ACK) { upsdebugx(3, "%s: wrong ack\t(0x%02X != 0x%02X)", __func__, ack[5], ACK); return -1; /* wrong ack */ } return 0; } /******************************************************************/ /********** * SERIAL * **********/ /* clear any flow control (copy from powercom.c) */ static void ser_disable_flow_control (void) { struct termios tio; tcflag_t x; tcgetattr (upsfd, &tio); /* Clumsy rewrite of a one-liner * tio.c_iflag &= ~ (IXON | IXOFF); * to avoid type conversion warnings */ x = (IXON | IXOFF); tio.c_iflag &= ~ x; tio.c_cc[VSTART] = _POSIX_VDISABLE; tio.c_cc[VSTOP] = _POSIX_VDISABLE; upsdebugx(4, "Flow control disable"); /* disable any flow control */ tcsetattr(upsfd, TCSANOW, &tio); } static void flush_rx_queue(void) { ser_flush_in(upsfd, "", /*verbose=*/nut_debug_level); } /** * transmit frame to PRS * * @param dmsg debug message prefix * @param frame the frame to tansmit * @return 0 (ok) -1 (error) */ static int tx(const char *dmsg, /*const*/ raw_data_t frame) { ssize_t err; size_t frame_len; assert(frame.end - frame.begin >= 0); frame_len = (size_t)(frame.end - frame.begin); upsdebug_ascii(3, dmsg, frame.begin, frame_len); err = ser_send_buf(upsfd, frame.begin, frame_len ); if (err==-1) { upslogx(LOG_ERR, "failed to send frame to PRS: %s", strerror(errno)); return -1; } if (err != (ssize_t)frame_len) { upslogx(LOG_ERR, "sent incomplete frame to PRS"); return -1; } return 0; } /*********** * CHATTER * ***********/ static time_t T_io_begin; /* start of current I/O transaction */ static int T_io_timeout; /* in seconds */ /* start new I/O transaction with maximum time limit */ static void io_new_transaction(int timeout) { T_io_begin = time(NULL); T_io_timeout = timeout; } /** * get next character from input stream * * @param ch ptr-to where store result * * @return -1 (error) 0 (timeout) >0 (got it) * */ static ssize_t get_char(char *ch) { time_t now = time(NULL); long rx_timeout; rx_timeout = T_io_timeout - (now - T_io_begin); /* negative rx_timeout -> time already out */ if (rx_timeout < 0) return 0; return ser_get_char(upsfd, ch, rx_timeout, 0); } /** * get next characters from input stream * * @param buf ptr-to output buffer * @param len buffer length * * @return -1 (error) 0 (timeout) >0 (no. of characters actually read) * */ static ssize_t get_buf(byte_t *buf, size_t len) { time_t now = time(NULL); long rx_timeout; rx_timeout = T_io_timeout - (now - T_io_begin); /* negative rx_timeout -> time already out */ if (rx_timeout < 0) return 0; return ser_get_buf_len(upsfd, buf, len, rx_timeout, 0); } /** * scan incoming bytes for specific character * * @return 0 (got it) -1 (error) */ static int scan_for(char c) { char in; ssize_t err; while (1) { err = get_char(&in); if (err==-1 || err==0 /*timeout*/) return -1; if (in==c) break; } return 0; } /** * receive 'activate command' ACK from PRS * * @return 0 (ok) -1 (error) */ static int recv_command_ack(void) { ssize_t err; raw_data_t ack; byte_t ack_buf[8]; /* 1: STX */ err = scan_for(STX); if (err==-1) return -1; raw_alloc_onstack(&ack, ack_buf); *(ack.end++) = STX; /* 2: ID1 ID2 STAMP MSG_TYPE ACK ETX BCC */ err = get_buf(ack.end, 7); if (err!=7) return -1; ack.end += 7; /* frame constructed - let's verify it */ assert (ack.end - ack.begin >= 0); upsdebug_ascii(3, "rx (ack):\t\t", ack.begin, (size_t)(ack.end - ack.begin)); /* generic layout */ err = comli_check_frame(ack); if (err==-1) return -1; /* shrink frame */ ack.begin += 1; ack.end -= 2; return al_check_ack(ack); } /** * receive 'read register' data from PRS * @param io [out] io header of received data * @param io_buf [in] [out] where to place incoming data * * @return 0 (ok) -1 (error) */ static int recv_register_data(io_head_t *io, raw_data_t *io_buf) { ssize_t err; int ret; size_t reply_head_len; raw_data_t reply_head; raw_data_t reply; byte_t reply_head_buf[11]; /* 1: STX */ err = scan_for(STX); if (err==-1) return -1; raw_alloc_onstack(&reply_head, reply_head_buf); *(reply_head.end++) = STX; /* 2: ID1 ID2 STAMP MSG_TYPE ADDR1 ADDR2 ADDR3 ADDR4 LEN1 LEN2 */ err = get_buf(reply_head.end, 10); if (err!=10) return -1; reply_head.end += 10; assert (reply_head.end - reply_head.begin >= 0); upsdebug_ascii(3, "rx (head):\t", reply_head.begin, (size_t)(reply_head.end - reply_head.begin)); /* 3: check header, extract IO info */ reply_head.begin += 1; /* temporarily strip STX */ err = al_parse_reply_head(io, reply_head); if (err==-1) return -1; reply_head.begin -= 1; /* restore STX */ upsdebugx(4, "\t\t--> addr: 0x%" PRIxSIZE " len: 0x%" PRIxSIZE, io->addr, io->len); /* 4: allocate space for full reply and copy header there */ reply = raw_xmalloc(11/*head*/ + io->len/*data*/ + 2/*ETX BCC*/); assert (reply_head.end - reply_head.begin >= 0); reply_head_len = (size_t)(reply_head.end - reply_head.begin); memcpy(reply.end, reply_head.begin, reply_head_len); reply.end += reply_head_len; /* 5: receive tail of the frame */ err = get_buf(reply.end, io->len + 2); if (err!=(int)(io->len+2)) { upsdebugx(4, "rx_tail failed, err=%" PRIiSIZE " (!= %" PRIiSIZE ")", err, io->len+2); ret = -1; goto out; } reply.end += io->len + 2; /* frame constructed, let's verify it */ assert (reply.end - reply.begin >= 0); upsdebug_ascii(3, "rx (head+data):\t", reply.begin, (size_t)(reply.end - reply.begin)); /* generic layout */ err = comli_check_frame(reply); if (err==-1) { upsdebugx(3, "%s: corrupt frame", __func__); ret = -1; goto out; } /* shrink frame */ reply.begin += 1; reply.end -= 2; /* XXX: a bit of processing duplication here */ ret = al_parse_reply(io, io_buf, reply); out: raw_free(&reply); return ret; } /*****************************************************************/ /********************* * AL175: DO COMMAND * *********************/ /** * do 'ACTIVATE COMMAND' * * @return 0 (ok) -1 (error) */ static int al175_do(byte_t cmd, byte_t subcmd, uint16_t pr1, uint16_t pr2, uint16_t pr3) { int err; raw_data_t CTRL_frame; byte_t CTRL_frame_buf[512]; raw_alloc_onstack(&CTRL_frame, CTRL_frame_buf); al_prep_activate(&CTRL_frame, cmd, subcmd, pr1, pr2, pr3); flush_rx_queue(); /* DROP */ err = tx("tx (ctrl):\t", CTRL_frame); /* TX */ if (err==-1) return -1; return recv_command_ack(); /* RX */ } /** * 'READ REGISTER' * */ static int al175_read(byte_t *dst, size_t addr, size_t count) { int err; raw_data_t REQ_frame; raw_data_t rx_data; io_head_t io; byte_t REQ_frame_buf[512]; raw_alloc_onstack(&REQ_frame, REQ_frame_buf); al_prep_read_req(&REQ_frame, addr, count); flush_rx_queue(); /* DROP */ err = tx("tx (req):\t", REQ_frame); /* TX */ if (err==-1) return -1; rx_data.buf = dst; rx_data.buf_size = count; rx_data.begin = dst; rx_data.end = dst; err = recv_register_data(&io, &rx_data); if (err==-1) return -1; if ((rx_data.end - rx_data.begin) < 0 || (size_t)(rx_data.end - rx_data.begin) != count) return -1; if ( (io.addr != addr) || (io.len != count) ) { upsdebugx(3, "%s: io_head mismatch\t(%" PRIxSIZE ",%" PRIxSIZE " != %" PRIxSIZE ",%" PRIxSIZE ")", __func__, io.addr, io.len, addr, count); return -1; } return 0; } /************* * NUT STUFF * *************/ /**************************** * ACTIVATE COMMANDS table * * see 8. ACTIVATE COMMANDS */ typedef uint16_t mm_t; /* minutes */ typedef uint16_t VV_t; /* voltage */ #define Z1 , 0 #define Z2 , 0, 0 #define Z3 , 0, 0, 0 #define ACT int /* Declare to keep compiler happy even if some routines below are not used currently */ ACT TOGGLE_PRS_ONOFF (void); ACT CANCEL_BOOST (void); ACT STOP_BATTERY_TEST (void); ACT START_BATTERY_TEST (VV_t EndVolt, mm_t Minutes); ACT SET_FLOAT_VOLTAGE (VV_t v); ACT SET_BOOST_VOLTAGE (VV_t v); ACT SET_HIGH_BATTERY_LIMIT (VV_t Vhigh); ACT SET_LOW_BATTERY_LIMIT (VV_t Vlow); ACT SET_DISCONNECT_LEVEL_AND_DELAY (VV_t level, mm_t delay); ACT RESET_ALARMS (void); ACT CHANGE_COMM_PROTOCOL (void); ACT SET_VOLTAGE_AT_ZERO_T (VV_t v); ACT SET_SLOPE_AT_ZERO_T (VV_t mv_per_degree); ACT SET_MAX_TCOMP_VOLTAGE (VV_t v); ACT SET_MIN_TCOMP_VOLTAGE (VV_t v); ACT SWITCH_TEMP_COMP (uint16_t on); ACT SWITCH_SYM_ALARM (void); /* Implement */ ACT TOGGLE_PRS_ONOFF (void) { return al175_do(0x81, 0x80 Z3); } ACT CANCEL_BOOST (void) { return al175_do(0x82, 0x80 Z3); } ACT STOP_BATTERY_TEST (void) { return al175_do(0x83, 0x80 Z3); } ACT START_BATTERY_TEST (VV_t EndVolt, mm_t Minutes) { return al175_do(0x83, 0x81, EndVolt, Minutes Z1); } ACT SET_FLOAT_VOLTAGE (VV_t v) { return al175_do(0x87, 0x80, v Z2); } ACT SET_BOOST_VOLTAGE (VV_t v) { return al175_do(0x87, 0x81, v Z2); } ACT SET_HIGH_BATTERY_LIMIT (VV_t Vhigh) { return al175_do(0x87, 0x82, Vhigh Z2); } ACT SET_LOW_BATTERY_LIMIT (VV_t Vlow) { return al175_do(0x87, 0x83, Vlow Z2); } ACT SET_DISCONNECT_LEVEL_AND_DELAY (VV_t level, mm_t delay) { return al175_do(0x87, 0x84, level, delay Z1); } ACT RESET_ALARMS (void) { return al175_do(0x88, 0x80 Z3); } ACT CHANGE_COMM_PROTOCOL (void) { return al175_do(0x89, 0x80 Z3); } ACT SET_VOLTAGE_AT_ZERO_T (VV_t v) { return al175_do(0x8a, 0x80, v Z2); } ACT SET_SLOPE_AT_ZERO_T (VV_t mv_per_degree) { return al175_do(0x8a, 0x81, mv_per_degree Z2); } ACT SET_MAX_TCOMP_VOLTAGE (VV_t v) { return al175_do(0x8a, 0x82, v Z2); } ACT SET_MIN_TCOMP_VOLTAGE (VV_t v) { return al175_do(0x8a, 0x83, v Z2); } ACT SWITCH_TEMP_COMP (uint16_t on) { return al175_do(0x8b, 0x80, on Z2); } ACT SWITCH_SYM_ALARM (void) { return al175_do(0x8c, 0x80 Z3); } /** * extract double value from a word */ static double d16(byte_t data[2]) { return (data[1] + 0x100*data[0]) / 100.0; } void upsdrv_updateinfo(void) { /* int flags; */ byte_t x4000[9]; /* registers from 0x4000 to 0x4040 inclusive */ byte_t x4048[2]; /* 0x4048 - 0x4050 */ byte_t x4100[8]; /* 0x4100 - 0x4138 */ byte_t x4180[8]; /* 0x4180 - 0x41b8 */ byte_t x4300[2]; /* 0x4300 - 0x4308 */ int err; double batt_current = 0.0; upsdebugx(4, " "); upsdebugx(4, "UPDATEINFO"); upsdebugx(4, "----------"); io_new_transaction(/*timeout=*/3); #define RECV(reg) do { \ err = al175_read(x ## reg, 0x ## reg, sizeof(x ## reg)); \ if (err==-1) { \ dstate_datastale(); \ return; \ } \ } while (0) RECV(4000); RECV(4048); RECV(4100); RECV(4180); RECV(4300); status_init(); /* XXX non conformant with NUT naming & not well understood what they mean */ #if 0 /* 0x4000 DIGITAL INPUT 1-8 */ dstate_setinfo("load.fuse", (x4000[0] & 0x80) ? "OK" : "BLOWN"); dstate_setinfo("battery.fuse", (x4000[0] & 0x40) ? "OK" : "BLOWN"); dstate_setinfo("symalarm.fuse", (x4000[0] & 0x20) ? "OK" : "BLOWN"); /* 0x4008 BATTERY INFORMATION */ dstate_setinfo("battery.contactor", (x4000[1] & 0x80) ? "XX" : "YY"); /* FIXME */ dstate_setinfo("load.contactor", (x4000[1] & 0x40) ? "XX" : "YY"); /* FIXME */ dstate_setinfo("lvd.contactor", (x4000[1] & 0x20) ? "XX" : "YY"); /* FIXME */ #endif if (x4000[0] & 0x40){ dstate_setinfo("battery.fuse", "FAIL"); status_set("RB"); }else{ dstate_setinfo("battery.fuse", "OK"); } if (x4000[0] & 0x20){ dstate_setinfo("battery.symmetry", "FAIL"); status_set("RB"); }else{ dstate_setinfo("battery.symmetry", "OK"); } if (x4000[1] & 0x01) /* battery test running */ status_set("TEST"); /* TODO: others from 0x4008 */ /* 0x4010 NOT USED */ /* 0x4018 NOT USED */ switch (x4000[4]) { /* 0x4020 MAINS VOLTAGE STATUS */ case 0: status_set("OL"); break; case 1: status_set("OB"); break; case 2: /* doc: "not applicable" */ default: upsdebugx(2, "%s: invalid mains voltage status\t(%i)", __func__, x4000[4]); } /* 0x4028 SYSTEM ON OFF STATUS */ switch (x4000[5]) { case 0: /* system on */ break; case 1: status_set("OFF"); break; default: upsdebugx(2, "%s: invalid system on/off status\t(%i)", __func__, x4000[5]); } switch (x4000[6]) { /* 0x4030 BATTERY TEST FAIL */ case 0: dstate_setinfo("ups.test.result", "OK"); break; case 1: status_set("RB"); dstate_setinfo("ups.test.result", "FAIL"); break; default: upsdebugx(2, "%s: invalid battery test fail\t(%i)", __func__, x4000[6]); } switch (x4000[7]) { /* 0x4038 BATTERY VOLTAGE STATUS */ case 0: /* normal */ break; case 1: status_set("LB"); break; case 2: status_set("HB"); break; default: upsdebugx(2, "%s: invalid battery voltage status\t(%i)", __func__, x4000[7]); } switch (x4000[8]) { /* 0x4040 POS./NEG. BATT. CURRENT */ case 0: batt_current = +1.0; break; /* positive */ case 1: batt_current = -1.0; break; /* negative */ default: upsdebugx(2, "%s: invalid pos/neg battery current\t(%i)", __func__, x4000[8]); } switch (x4048[0]) { /* 0x4048 BOOST STATUS */ case 0: /* no boost */; break; case 1: status_set("BOOST"); break; default: upsdebugx(2, "%s: invalid boost status\t(%i)", __func__, x4048[0]); } { const char *v=NULL; switch (x4048[1]) { /* 0x4050 SYSTEM VOLTAGE STAT. */ case 0: v = "48"; break; case 1: v = "24"; break; case 2: v = "12"; break; case 3: v = "26"; break; case 4: v = "60"; break; default: upsdebugx(2, "%s: invalid system voltage status\t(%i)", __func__, x4048[1]); } if (v) dstate_setinfo("output.voltage.nominal", "%s", v); } /* 0x4100 BATTERY VOLTAGE REF */ dstate_setinfo("battery.voltage.nominal", "%.2f", d16(x4100+0)); /* 0x4110 BOOST VOLTAGE REF */ dstate_setinfo("input.transfer.boost.low", "%.2f", d16(x4100+2)); /* XXX: boost.high ? */ /* 0x4120 HIGH BATT VOLT REF XXX */ /* 0x4130 LOW BATT VOLT REF XXX */ /* 0x4180 FLOAT VOLTAGE XXX */ /* 0x4190 BATT CURRENT */ batt_current *= d16(x4180+2); dstate_setinfo("battery.current", "%.2f", batt_current); /* 0x41b0 LOAD CURRENT (output.current in NUT) */ dstate_setinfo("output.current", "%.2f", d16(x4180+6)); /* 0x4300 BATTERY TEMPERATURE */ dstate_setinfo("battery.temperature", "%.2f", d16(x4300+0)); status_commit(); upsdebugx(1, "STATUS: %s", dstate_getinfo("ups.status")); dstate_dataok(); /* out: */ return; } void upsdrv_shutdown(void) { /* TODO use TOGGLE_PRS_ONOFF for shutdown */ /* tell the UPS to shut down, then return - DO NOT SLEEP HERE */ /* maybe try to detect the UPS here, but try a shutdown even if it doesn't respond at first if possible */ /* replace with a proper shutdown function */ upslogx(LOG_ERR, "shutdown not supported"); set_exit_flag(-1); /* you may have to check the line status since the commands for toggling power are frequently different for OL vs. OB */ /* OL: this must power cycle the load if possible */ /* OB: the load must remain off until the power returns */ } static int instcmd(const char *cmdname, const char *extra) { int err; upsdebugx(1, "INSTCMD: %s", cmdname); io_new_transaction(/*timeout=*/5); /* * test.battery.start * test.battery.stop */ if (!strcasecmp(cmdname, "test.battery.start")) { err = START_BATTERY_TEST(24, 1); return (!err ? STAT_INSTCMD_HANDLED : STAT_INSTCMD_FAILED); } if (!strcasecmp(cmdname, "test.battery.stop")) { err = STOP_BATTERY_TEST(); return (!err ? STAT_INSTCMD_HANDLED : STAT_INSTCMD_FAILED); } upslogx(LOG_NOTICE, "instcmd: unknown command [%s] [%s]", cmdname, extra); return STAT_INSTCMD_UNKNOWN; } /* no help */ void upsdrv_help(void) { } /* no -x flags */ void upsdrv_makevartable(void) { } void upsdrv_initups(void) { upsfd = ser_open(device_path); ser_set_speed(upsfd, device_path, B9600); ser_disable_flow_control(); } void upsdrv_cleanup(void) { ser_close(upsfd, device_path); } void upsdrv_initinfo(void) { /* TODO issue short io with UPS to detect it's presence */ /* try to detect the UPS here - call fatal_with_errno(EXIT_FAILURE, ) if it fails */ dstate_setinfo("ups.mfr", "Eltek"); dstate_setinfo("ups.model", "AL175"); /* ... */ /* instant commands */ dstate_addcmd ("test.battery.start"); dstate_addcmd ("test.battery.stop"); /* TODO rest instcmd(s) */ upsh.instcmd = instcmd; } nut-2.8.1/drivers/huawei-ups2000.c0000644000175000017500000017655614501607135013512 00000000000000/* * huawei-ups2000.c - Driver for Huawei UPS2000 (1kVA-3kVA) * * Note: If you're trying to debug the driver because it doesn't work, * please BE SURE to read the manual in "docs/man/huawei-ups2000.txt" * first! Otherwise you are guaranteed to waste your time! * * Long story short, Huawei UPS2000 (1kVA-3kVA) can be accessed via * RS-232, USB, or an optional RMS-MODBUS01B (RS-485) adapter. Only * RS-232 and USB are supported, RS-485 is not. Also, for most UPS * units, their USB ports are implemented via the MaxLinear RX21V1410 * USB-to-serial converter, and they DO NOT WORK without a special * "xr_serial" driver, only available on Linux 5.12+ (not BSD or Solaris). * Without this driver, the USB can still be recognized as a generic * USB ACM device, but it DOES NOT WORK. Alternatively, some newer UPS * units use the WCH CH341 chip, which should have better compatibility. * Detailed information will not be repeated here, please read * "docs/man/huawei-ups2000.txt". * * A document describing the protocol implemented by this driver can * be found online at: * * https://support.huawei.com/enterprise/en/doc/EDOC1000110696 * * Huawei UPS2000 driver implemented by * Copyright (C) 2020, 2021 Yifeng Li * The author is not affiliated with Huawei or other manufacturers. * * 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 2 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, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "config.h" /* must be the first header */ #include #include #include "main.h" #include "serial.h" #include "nut_stdint.h" #include "timehead.h" /* fallback gmtime_r() variants if needed (e.g. some WIN32) */ #define DRIVER_NAME "NUT Huawei UPS2000 (1kVA-3kVA) RS-232 Modbus driver" #define DRIVER_VERSION "0.05" #define CHECK_BIT(var,pos) ((var) & (1<<(pos))) #define MODBUS_SLAVE_ID 1 /* * Known UPS models. We only attempt to load the driver if * the initial communication indicates the UPS is a known * model of the UPS2000 series. */ static const char *supported_model[] = { "UPS2000", "UPS2000A", "UPS2000G", NULL }; /* * UPS2000 device identification. The information is obtained during * initial communication using Modbus command 0x2B (read device identi- * fication) to read the object 0x87 (device list). The object contains * a list of fields, each with a type, length, and value. The object is * parsed by ups2000_device_identification() and filled into the array * of struct ups2000_ident. * * Fields of interest are: * * 0x87, int32 (Device Count): Only one UPS unit is supported, * the driver aborts if more than one device is detected. * * 0x88, string (Device Description of the 1st unit): This is a * ASCII string that contains information about the 1st UPS unit. * This string, again, contains a list of fields. They are parsed * further into the array ups2000_desc. * */ #define UPS2000_IDENT_MAX_FIELDS 9 #define UPS2000_IDENT_MAX_LEN 128 #define UPS2000_IDENT_OFFSET static struct { uint8_t type; uint8_t len; uint8_t val[UPS2000_IDENT_MAX_LEN]; } ups2000_ident[UPS2000_IDENT_MAX_FIELDS]; /* * UPS2000 device description. The information is initially obtained * as field 0x88 in the UPS2000 device identification. This field is * a semicolon seperated ASCII string that contains multiple fields. * It is parsed again by ups2000_device_identification() and filled * into the ups2000_desc[] 2D array. The first dimension is used as * a key to select the wanted field (defined in the following enmu, * the second dimension is a NULL-terminated ASCII string. * * Note that ups2000_desc[0] is deliberately unused, the array begins * at one, allowing mapping from UPS2000_DESC_* to ups2000_desc[] * directly without using offsets. */ #define UPS2000_DESC_MAX_FIELDS 9 #define UPS2000_DESC_MAX_LEN 128 enum { UPS2000_DESC_MODEL = 1, UPS2000_DESC_FIRMWARE_REV, UPS2000_DESC_PROTOCOL_REV, UPS2000_DESC_ESN, UPS2000_DESC_DEVICE_ID, /* currently unused */ UPS2000_DESC_PARALLEL_ID /* currently unused */ }; static char ups2000_desc[UPS2000_DESC_MAX_FIELDS][UPS2000_DESC_MAX_LEN] = { { 0 } }; /* global variable for modbus communication */ static modbus_t *modbus_ctx = NULL; /* * How many seconds to wait before switching off/on/reboot the UPS? * * This can be set at startup time via a command-line argument, * or at runtime by writing to RW variables "ups.delay.shutdown" * and "ups.delay.start". See ups2000_delay_get/set. */ #define UPS2000_DELAY_INVALID 0xFFFF static uint16_t ups2000_offdelay = UPS2000_DELAY_INVALID; static uint16_t ups2000_ondelay = UPS2000_DELAY_INVALID; static uint16_t ups2000_rebootdelay = UPS2000_DELAY_INVALID; /* * Time when the current shutdown/reboot request is expected * to complete. This is used to calculate the ETA, See * ups2000_update_timers(). */ static time_t shutdown_at = 0; static time_t reboot_at = 0; static time_t start_at = 0; /* * Is it safe to enter bypass mode? It's checked by ups2000_update_alarm() * and used by ups2000_instcmd_bypass_start(). */ static bool bypass_available = 0; /* function prototypes */ static int ups2000_update_info(void); static int ups2000_update_status(void); static int ups2000_update_alarm(void); static int ups2000_update_timers(void); static void ups2000_device_identification(void); static size_t ups2000_read_serial(uint8_t *buf, size_t buf_len); static int ups2000_read_registers(modbus_t *ctx, int addr, int nb, uint16_t *dest); static int ups2000_write_register(modbus_t *ctx, int addr, uint16_t val); static int ups2000_write_registers(modbus_t *ctx, int addr, int nb, uint16_t *src); static uint16_t crc16(uint8_t *buffer, size_t buffer_length); static time_t time_seek(time_t t, int seconds); /* rw variables function prototypes */ static int ups2000_update_rw_var(void); static int setvar(const char *name, const char *val); static int ups2000_autostart_set(const uint16_t reg, const char *string); static int ups2000_autostart_get(const uint16_t reg); static int ups2000_beeper_set(const uint16_t reg, const char *string); static int ups2000_beeper_get(const uint16_t reg); static void ups2000_delay_get(void); static int ups2000_delay_set(const char *var, const char *string); /* instant command function prototypes */ static void ups2000_init_instcmd(void); static int instcmd(const char *cmd, const char *extra); static int ups2000_instcmd_load_on(const uint16_t reg); static int ups2000_instcmd_bypass_start(const uint16_t reg); static int ups2000_instcmd_beeper_toggle(const uint16_t reg); static int ups2000_instcmd_shutdown_stayoff(const uint16_t reg); static int ups2000_instcmd_shutdown_return(const uint16_t reg); static int ups2000_instcmd_shutdown_reboot(const uint16_t reg); static int ups2000_instcmd_shutdown_reboot_graceful(const uint16_t reg); /* driver description structure */ upsdrv_info_t upsdrv_info = { DRIVER_NAME, DRIVER_VERSION, "Yifeng Li \n", DRV_EXPERIMENTAL, { NULL } }; void upsdrv_initups(void) { int r; upsdebugx(2, "upsdrv_initups"); /* * This is an ugly workaround to a serious problem: libmodbus doesn't * support device identification. Although there's a function called * modbus_send_raw_request() for custom commands, but modbus_receive_ * confirmation() assumes a message length in the header, which is * incompatible with device identification - It simply stops reading * in the middle of the message and cannot receive our message. Worse, * there's no public API to receive a raw response. * * See: https://github.com/stephane/libmodbus/issues/231 * * Thus, the only thing we could do is opening it as a serial device * for device identification, and reopen it via libmodbus for other * commands as usual. We also have to copy the CRC-16 function from * the libmodbus source code since there's no public API to use that... */ upsfd = ser_open(device_path); ser_set_speed(upsfd, device_path, B9600); ser_set_rts(upsfd, 0); ser_set_dtr(upsfd, 0); modbus_ctx = modbus_new_rtu(device_path, 9600, 'N', 8, 1); if (modbus_ctx == NULL) fatalx(EXIT_FAILURE, "Unable to create the libmodbus context"); #if LIBMODBUS_VERSION_CHECK(3, 1, 2) /* * Although it rarely occurs, it can take as slow as 2 sec. for the * UPS to respond a read and finish transmitting the message. */ modbus_set_response_timeout(modbus_ctx, 2, 0); #else { struct timeval timeout; timeout.tv_sec = 2; timeout.tv_usec = 0; modbus_set_response_timeout(modbus_ctx, &timeout); } #endif r = modbus_set_slave(modbus_ctx, MODBUS_SLAVE_ID); if (r < 0) { modbus_free(modbus_ctx); fatalx(EXIT_FAILURE, "Invalid slave ID %d", MODBUS_SLAVE_ID); } if (modbus_connect(modbus_ctx) == -1) { modbus_free(modbus_ctx); fatalx(EXIT_FAILURE, "modbus_connect: unable to connect: %s", modbus_strerror(errno)); } } #define IDENT_REQUEST_LEN 7 #define IDENT_RESPONSE_MAX_LEN 128 #define IDENT_RESPONSE_HEADER_LEN 8 #define IDENT_RESPONSE_CRC_LEN 2 #define IDENT_FIELD_HEADER_LEN 2 static void ups2000_device_identification(void) { static const uint8_t ident_req[IDENT_REQUEST_LEN] = { MODBUS_SLAVE_ID, /* addr */ 0x2B, /* command: device identification */ 0x0E, /* MEI type */ 0x03, /* ReadDevID: extended identification */ 0x87, /* Object ID: device list */ 0x31, 0x75 /* CRC-16 */ }; /* * Response header: * 0x01, 0x2B, 0x0E, 0x03, 0x03, 0x00, 0x00, 0x02 * * Response fields: * header: 0x87, 0x04 // type (device counts), length * data: uint32_t * (e.g. 0x00, 0x00, 0x00, 0x01) * * header: 0x88, 0x?? // type (1st dev desc), length * data: ASCII string * (e.g. 1=UPS2000;2=V100R001C01SPC120;3=...) * * header: 0x89, 0x?? // type (2nd dev desc), length * data: ASCII string * * ... * header: 0xFF, 0x?? // type (120th dev desc), length * data: ASCII string * * CRC-16: * 0x??, 0x?? */ static const uint8_t expected_header[IDENT_RESPONSE_HEADER_LEN] = { MODBUS_SLAVE_ID, 0x2B, 0x0E, 0x03, 0x03, 0x00, 0x00, 0x02, }; bool serial_fail = 0; /* unable to read from serial */ uint16_t crc16_recv, crc16_calc; /* resp CRC */ bool crc16_fail = 0; /* resp CRC failure */ uint32_t ups_count = 0; /* number of UPS in the resp list */ uint8_t ident_response[IDENT_RESPONSE_MAX_LEN]; /* resp buf */ size_t ident_response_len; /* buf len */ uint8_t *ident_response_end = NULL; /* buf end marker (excluding CRC) */ uint8_t *ptr = NULL; /* buf iteratior */ /* a desc string copied from ups2000_ident[] */ char *ups2000_ident_desc = NULL; int i; ssize_t r; /* attempt to obtain a response header with valid CRC. */ for (i = 0; i < 3; i++) { /* step 1: record response length and initialize ptr */ upsdebugx(2, "ser_send_buf"); ser_flush_in(upsfd, "", nut_debug_level); r = ser_send_buf(upsfd, ident_req, IDENT_REQUEST_LEN); if (r != IDENT_REQUEST_LEN) { fatalx(EXIT_FAILURE, "unable to send request!\n"); } ident_response_len = ups2000_read_serial(ident_response, IDENT_RESPONSE_MAX_LEN); ptr = ident_response; ident_response_end = ptr + ident_response_len - IDENT_RESPONSE_CRC_LEN; /* step 2: check response length */ if (ident_response_len == 0) { upslogx(LOG_ERR, "unable to read from serial port %s, retry...", device_path); serial_fail = 1; continue; } else serial_fail = 0; upsdebug_hex(2, "ups2000_read_serial() received", ptr, ident_response_len); if (ptr + IDENT_RESPONSE_HEADER_LEN > ident_response_end) { fatalx(EXIT_FAILURE, "response header too short! " "expected %d, received %" PRIuSIZE ".", IDENT_RESPONSE_HEADER_LEN, ident_response_len); } /* step 3: check response CRC-16 */ crc16_recv = (uint16_t) ident_response_end[0] << 8 | ident_response_end[1]; crc16_calc = crc16(ident_response, ident_response_len - IDENT_RESPONSE_CRC_LEN); if (crc16_recv == crc16_calc) { crc16_fail = 0; break; } crc16_fail = 1; } /* step 4: check serial & CRC-16 verification status */ if (serial_fail) fatalx(EXIT_FAILURE, "unable to read from serial port %s!", device_path); if (crc16_fail) fatalx(EXIT_FAILURE, "response CRC verification failed!"); /* step 5: check response header */ if (memcmp(expected_header, ident_response, IDENT_RESPONSE_HEADER_LEN)) fatalx(EXIT_FAILURE, "unexpected response header!"); ptr += IDENT_RESPONSE_HEADER_LEN; /* step 6: extract ident fields */ memset(ups2000_ident, 0x00, sizeof(ups2000_ident)); for (i = 0; i < UPS2000_IDENT_MAX_FIELDS; i++) { uint8_t type, len; if (ptr + 2 > ident_response_end) break; type = *ptr++; len = *ptr++; if (len + 1 > UPS2000_IDENT_MAX_LEN) fatalx(EXIT_FAILURE, "response field too long!"); ups2000_ident[i].type = type; ups2000_ident[i].len = len; /* * Always zero-terminate the bytes, in case the data * is an ASCII string (i.e. device desc string), libc * string functions can be used. */ ups2000_ident[i].val[len] = '\0'; if (ptr + len > ident_response_end) fatalx(EXIT_FAILURE, "response field too short!"); memcpy(ups2000_ident[i].val, ptr, len); ptr += len; } /* step 7: validate device identification field 0x87 and 0x88 */ for (i = 0; i < UPS2000_IDENT_MAX_FIELDS; i++) { /* only one device is supported */ if (ups2000_ident[i].type == 0x87) { /* so we assume 0x87 must be 1 */ ups_count = (uint32_t)(ups2000_ident[i].val[0]) << 24 | (uint32_t)(ups2000_ident[i].val[1]) << 16 | (uint32_t)(ups2000_ident[i].val[2]) << 8 | (uint32_t)(ups2000_ident[i].val[3]); } if (ups2000_ident[i].type == 0x88) { /* * And only check 0x88, not 0x89, etc. Also copy the * string for later parsing via strtok(). */ ups2000_ident_desc = strdup((char *) ups2000_ident[i].val); break; } } if (ups_count != 1) fatalx(EXIT_FAILURE, "only 1 UPS is supported, %u found", ups_count); if (!ups2000_ident_desc) fatalx(EXIT_FAILURE, "device desc string not found"); /* * step 8: extract fields from the desc string. * (1=UPS2000;2=V100R001C01SPC120;3=...) */ for (i = 0; i < UPS2000_DESC_MAX_FIELDS; i++) { char *key; /* "1", "2", "3", ... */ char *val; /* "UPS2000", "V100R001C01SPC120", ... */ unsigned int idx = 0; if (i == 0) key = strtok(ups2000_ident_desc, "="); else key = strtok(NULL, "="); if (!key) break; val = strtok(NULL, ";"); if (!val) break; r = str_to_uint_strict(key, &idx, 10); if (!r || idx + 1 > UPS2000_DESC_MAX_FIELDS || idx < 1) fatalx(EXIT_FAILURE, "desc index %d is invalid!", idx); if (strlen(val) + 1 > UPS2000_DESC_MAX_LEN) fatalx(EXIT_FAILURE, "desc field %d too long!", idx); memcpy(ups2000_desc[idx], val, strlen(val) + 1); } free(ups2000_ident_desc); /* * step 9: Validate desc fields that we are going to use are valid. * * Note: UPS2000_DESC_DEVICE_ID and UPS2000_DESC_PARALLEL_ID are * currently unused and unchecked. */ for (i = UPS2000_DESC_MODEL; i <= UPS2000_DESC_ESN; i++) { if (strlen(ups2000_desc[i]) == 0) fatalx(EXIT_FAILURE, "desc field %d is missing!", i); } } void upsdrv_initinfo(void) { bool in_list = 0; int i = 0; upsdebugx(2, "upsdrv_initinfo"); ups2000_device_identification(); /* check whether the UPS is a known model */ for (i = 0; supported_model[i] != NULL; i++) { if (!strcmp(supported_model[i], ups2000_desc[UPS2000_DESC_MODEL])) { in_list = 1; } } if (!in_list) { fatalx(EXIT_FAILURE, "Unknown UPS model %s", ups2000_desc[UPS2000_DESC_MODEL]); } dstate_setinfo("device.mfr", "Huawei"); dstate_setinfo("device.type", "ups"); dstate_setinfo("device.model", "%s", ups2000_desc[UPS2000_DESC_MODEL]); dstate_setinfo("device.serial", "%s", ups2000_desc[UPS2000_DESC_ESN]); dstate_setinfo("ups.mfr", "Huawei"); dstate_setinfo("ups.model", "%s", ups2000_desc[UPS2000_DESC_MODEL]); dstate_setinfo("ups.firmware", "%s", ups2000_desc[UPS2000_DESC_FIRMWARE_REV]); dstate_setinfo("ups.firmware.aux", "%s", ups2000_desc[UPS2000_DESC_PROTOCOL_REV]); dstate_setinfo("ups.serial", "%s", ups2000_desc[UPS2000_DESC_ESN]); dstate_setinfo("ups.type", "online"); /* RW variables */ upsh.setvar = setvar; /* instant commands */ ups2000_init_instcmd(); upsh.instcmd = instcmd; } /* * All registers are uint16_t. But the data they represent can * be either an integer or a float. This information is used for * error checking (int and float have different invalid values). */ enum { REG_UINT16, REG_UINT32, /* occupies two registers */ REG_FLOAT, /* actually a misnomer, it should really be called fixed-point number, but we follow the datasheet */ }; #define REG_UINT16_INVALID 0xFFFFU #define REG_UINT32_INVALID 0xFFFFFFFFU #define REG_FLOAT_INVALID 0x7FFFU /* * Declare UPS attribute variables, format strings, registers, * and their scaling factors in a lookup table to avoid spaghetti * code. */ static struct { const char *name; const char *fmt; const uint16_t reg; const int datatype; /* only UINT32 occupies 2 regs */ const float scaling; /* scale it down to get the original */ } ups2000_var[] = { { "input.voltage", "%03.1f", 1000, REG_FLOAT, 10.0 }, { "input.frequency", "%02.1f", 1003, REG_FLOAT, 10.0 }, { "input.bypass.voltage", "%03.1f", 1004, REG_FLOAT, 10.0 }, { "input.bypass.frequency", "%03.1f", 1007, REG_FLOAT, 10.0 }, { "output.voltage", "%03.1f", 1008, REG_FLOAT, 10.0 }, { "output.current", "%03.1f", 1011, REG_FLOAT, 10.0 }, { "output.frequency", "%03.1f", 1014, REG_FLOAT, 10.0 }, { "output.realpower", "%02.1f", 1015, REG_FLOAT, 0.01 }, /* 10 / 1 kW */ { "output.power", "%03.1f", 1018, REG_FLOAT, 0.01 }, /* 10 / 1 kVA */ { "ups.load", "%02.1f", 1021, REG_FLOAT, 10.0 }, { "ups.temperature", "%02.1f", 1027, REG_FLOAT, 10.0 }, { "battery.voltage", "%02.1f", 2000, REG_FLOAT, 10.0 }, { "battery.charge", "%02.1f", 2003, REG_UINT16, 1.0 }, { "battery.runtime", "%.0f", 2004, REG_UINT32, 1.0 }, { "battery.packs", "%.0f", 2007, REG_UINT16, 1.0 }, { "battery.capacity", "%.0f", 2033, REG_UINT16, 1.0 }, { "ups.power.nominal", "%.0f", 9009, REG_FLOAT, 0.01 }, /* 10 / 1 kVA */ { NULL, NULL, 0, 0, 0 }, }; static int ups2000_update_info(void) { uint16_t reg[3][34]; int i; int r; upsdebugx(2, "ups2000_update_info"); /* * All status registers have an offset of 10000 * ups_number. * We only support 1 UPS, thus it's always 10000. Register * 1000 becomes 11000. */ r = ups2000_read_registers(modbus_ctx, 11000, 28, reg[0]); if (r != 28) return 1; r = ups2000_read_registers(modbus_ctx, 12000, 34, reg[1]); if (r != 34) return 1; r = ups2000_read_registers(modbus_ctx, 19009, 1, ®[2][9]); if (r != 1) return 1; for (i = 0; ups2000_var[i].name != NULL; i++) { uint16_t reg_id = ups2000_var[i].reg; uint8_t page = (uint8_t)(reg_id / 1000 - 1); uint8_t idx = (uint8_t)(reg_id % 1000); uint32_t val; bool invalid = 0; if (page == 8) /* hack for the lonely register 9009 */ page = 2; if (page > 2 || idx > 33) /* also suppress compiler warn */ fatalx(EXIT_FAILURE, "register calculation overflow!\n"); switch (ups2000_var[i].datatype) { case REG_FLOAT: val = reg[page][idx]; if (val == REG_FLOAT_INVALID) invalid = 1; break; case REG_UINT16: val = reg[page][idx]; if (val == REG_UINT16_INVALID) invalid = 1; break; case REG_UINT32: val = (uint32_t)(reg[page][idx]) << 16; val |= (uint32_t)(reg[page][idx + 1]); if (val == REG_UINT32_INVALID) invalid = 1; break; default: fatalx(EXIT_FAILURE, "invalid data type in register table!\n"); } if (invalid) { upslogx(LOG_ERR, "register %04d has invalid value %04x,", reg_id, val); return 1; } #ifdef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL #pragma GCC diagnostic push #endif #ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL #pragma GCC diagnostic ignored "-Wformat-nonliteral" #endif #ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_FORMAT_SECURITY #pragma GCC diagnostic ignored "-Wformat-security" #endif dstate_setinfo(ups2000_var[i].name, ups2000_var[i].fmt, (float) val / ups2000_var[i].scaling); #ifdef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL #pragma GCC diagnostic pop #endif } return 0; } /* * A lookup table of all the status registers and the list of * corresponding flags they represent. A register may set multiple * status flags, represented by an array of flags_t. * * There are two types of flags. If the flag is a "status flag" * for status_set(), for example, "OL" or "OB", the field * "status_name" is used. If the flag is a "data variable" for * dstate_setinfo(), the variable name and value is written in * "var_name" and "var_val" fields. * * For each flag, if it's indicated by a specific value in a * register, the "val" field is used. If a flag is indicated by * a bit, the "bit" field should be used. Fields "val" and "bit" * cannot be used at the same time, at least one must be "-1". * * Also, some important registers indicate basic system status * (e.g. whether the UPS is on line power or battery), this info * must always be available, and they are always expected to set * at least one flag. If the important register does not set any * flag, it means we've received an invalid or unknown value, * and we must report an error. The "must_set_flag" field is used * for this purpose. */ static struct { const uint16_t reg; bool must_set_flag; struct flags_t { const char *status_name; const int16_t val; const int bit; const char *var_name, *var_val; } flags[10]; } ups2000_status_reg[] = { { 1024, 1, { { "OFF", 0, -1, NULL, NULL }, { "BYPASS", 1, -1, NULL, NULL }, { "OL", 2, -1, NULL, NULL }, { "OB", 3, -1, NULL, NULL }, { "OL ECO", 5, -1, NULL, NULL }, { NULL, -1, -1, NULL, NULL }, }}, { 1043, 0, { { "CAL", -1, 2, NULL, NULL }, /* battery self-test */ { "LB", -1, 6, NULL, NULL }, { NULL, -1, -1, NULL, NULL }, }}, /* * Note: 3 = float charging, 4 = equalization charging, but * both of them are reported as "charging", not "floating". * The definition of "floating" in NUT is: "battery has * completed its charge cycle, and waiting to go to resting * mode", which is not true for UPS2000. */ { 2002, 1, { { "", 2, -1, "battery.charger.status", "resting" }, { "CHRG", 3, -1, "battery.charger.status", "charging" }, { "CHRG", 4, -1, "battery.charger.status", "charging" }, { "DISCHRG", 5, -1, "battery.charger.status", "discharging" }, { NULL, -1, -1, NULL, NULL }, }}, { 0, 0, { { NULL, -1, -1, NULL, NULL } } } }; static int ups2000_update_status(void) { int i, j; int r; upsdebugx(2, "ups2000_update_status"); for (i = 0; ups2000_status_reg[i].reg != 0; i++) { uint16_t reg, val; struct flags_t *flag; int flag_count = 0; reg = ups2000_status_reg[i].reg; r = ups2000_read_registers(modbus_ctx, reg + 10000, 1, &val); if (r != 1) return 1; if (val == REG_UINT16_INVALID) { upslogx(LOG_ERR, "register %04d has invalid value %04x,", reg, val); return 1; } flag = ups2000_status_reg[i].flags; for (j = 0; flag[j].status_name != NULL; j++) { /* * if the register is equal to the "val" we are looking * for, or if register has its n-th "bit" set... */ if ((flag[j].val != -1 && flag[j].val == val) || (flag[j].bit != -1 && CHECK_BIT(val, flag[j].bit))) { /* if it has a corresponding status flag */ if (strlen(flag[j].status_name) != 0) status_set(flag[j].status_name); /* or if it has a corresponding dstate variable (or both) */ if (flag[j].var_name && flag[j].var_val) dstate_setinfo(flag[j].var_name, "%s", flag[j].var_val); flag_count++; } } if (ups2000_status_reg[i].must_set_flag && flag_count == 0) { upslogx(LOG_ERR, "register %04d has invalid value %04x,", reg, val); return 1; } } return 0; } /* * A lookup table of all the alarm registers and the list of * corresponding alarms they represent. Each alarm condition is * listed by its register base address "reg" and its "bit" * position. * * Each alarm condition has an "alarm_id", "alarm_cause_id", * and "alarm_name". In addition, a few alarms conditions also * indicates conditions related to batteries that is needed to * be set via status_set(), those are listed in "status_name". * Unused "status_name" is set to NULL. * * After an alarm is reported/cleared by the UPS, the "active" * flag is changed to reflect its status. The error logging * code uses this variable to issue warnings only when needed * (i.e. only after a change, avoid issuing the same warning * repeatedly). */ #define ALARM_CLEAR_AUTO 1 #define ALARM_CLEAR_MANUAL 2 #define ALARM_CLEAR_DEPENDING 3 static struct { bool active; /* runtime: is this alarm currently active? */ const uint16_t reg; /* alarm register to check */ const int bit; /* alarm bit to check */ const int alarm_clear; /* auto or manual clear */ const int loglevel; /* warning or error */ const int alarm_id, alarm_cause_id; const char *status_name; /* corresponding NUT status word */ const char *alarm_name; /* alarm string */ const char *alarm_desc; /* brief explanation */ } ups2000_alarm[] = { { false, 40156, 3, ALARM_CLEAR_AUTO, LOG_ALERT, 30, 1, NULL, "UPS internal overtemperature", "The ambient temperature is over 50-degree C. " "Startup from standby mode is prohibited.", }, { false, 40161, 1, ALARM_CLEAR_AUTO, LOG_WARNING, 10, 1, NULL, "Abnormal bypass voltage", "Bypass input is unavailable or out-of-range. Wait for " "bypass input to recover, or change acceptable bypass " "range via front panel.", }, { false, 40161, 2, ALARM_CLEAR_AUTO, LOG_WARNING, 10, 2, NULL, "Abnormal bypass frequency", "Bypass input is unavailable or out-of-range. Wait for " "bypass input to recover, or change acceptable bypass " "range via front panel.", }, { false, 40163, 3, ALARM_CLEAR_DEPENDING, LOG_WARNING, 25, 1, NULL, "Battery overvoltage", "When the UPS is started, voltage of each battery exceeds 15 V. " "Or: current battery voltage exceeds 14.7 V.", }, { false, 40164, 1, ALARM_CLEAR_AUTO, LOG_WARNING, 29, 1, "RB", "Battery needs maintenance", "During the last battery self-check, the battery voltage " "was lower than the replacement threshold (11 V).", }, { false, 40164, 3, ALARM_CLEAR_AUTO, LOG_WARNING, 26, 1, NULL, "Battery undervoltage", NULL, }, { false, 40170, 4, ALARM_CLEAR_AUTO, LOG_ALERT, 22, 1, NULL, "Battery disconnected", "Battery is not connected, has loose connection, or faulty.", }, { false, 40173, 5, ALARM_CLEAR_AUTO, LOG_ALERT, 66, 1, "OVER", "Output overload (105%-110%)", "UPS will shut down or transfer to bypass mode in 5-10 minutes.", }, { false, 40173, 3, ALARM_CLEAR_AUTO, LOG_ALERT, 66, 2, "OVER", "Output overload (110%-130%)", "UPS will shut down or transfer to bypass mode in 30-60 seconds.", }, { false, 40174, 0, ALARM_CLEAR_DEPENDING, LOG_ALERT, 14, 1, NULL, "UPS startup timeout", "The inverter output voltage is not within +/- 2 V of the " "rated output. Or: battery is overdischarged.", }, { false, 40179, 14, ALARM_CLEAR_MANUAL, LOG_ALERT, 42, 15, NULL, "Rectifier fault (internal fault)", "Bus voltage is lower than 320 V.", }, { false, 40179, 15, ALARM_CLEAR_MANUAL, LOG_ALERT, 42, 17, NULL, "Rectifier fault (internal fault)", "Bus voltage is higher than 450 V.", }, { false, 40180, 1, ALARM_CLEAR_MANUAL, LOG_ALERT, 42, 18, NULL, "Rectifier fault (internal fault)", "Bus voltage is lower than 260 V.", }, { false, 40180, 5, ALARM_CLEAR_AUTO, LOG_ALERT, 42, 24, NULL, "EEPROM fault (internal fault)", "Faulty EEPROM. All settings are restored to " "factory default and cannot be saved.", }, { false, 40180, 6, ALARM_CLEAR_MANUAL, LOG_ALERT, 42, 27, NULL, "Inverter fault (internal fault)", "Inverter output overvoltage, undervoltage or " "undercurrent.", }, { false, 40180, 7, ALARM_CLEAR_DEPENDING, LOG_ALERT, 42, 28, NULL, "Inverter fault (internal fault)", "The inverter output voltage is lower than 100 V.", }, { false, 40180, 10, ALARM_CLEAR_MANUAL, LOG_ALERT, 42, 31, NULL, "Inverter fault (internal fault)", "The difference between the absolute value of the positive bus " "voltage and that of the negative bus voltage is 100 V.", }, { false, 40180, 11, ALARM_CLEAR_DEPENDING, LOG_ALERT, 42, 32, NULL, "UPS internal overtemperature", "The ambient temperature is over 50 degree C, " "switching to bypass mode.", }, { false, 40180, 13, ALARM_CLEAR_MANUAL, LOG_ALERT, 42, 36, NULL, "Charger fault (internal fault)", "The charger has no output. Faulty internal connections.", }, { false, 40182, 4, ALARM_CLEAR_MANUAL, LOG_ALERT, 42, 42, NULL, "Charger fault (internal fault)", "The charger has no output while the inverter is on, " "battery undervoltage. Faulty switching transistor.", }, { false, 40182, 13, ALARM_CLEAR_MANUAL, LOG_ALERT, 66, 3, "OVER", "Output overload shutdown", "UPS has shutdown or transferred to bypass mode.", }, { false, 40182, 14, ALARM_CLEAR_MANUAL, LOG_ALERT, 66, 4, "OVER", "Bypass output overload shutdown", "UPS has shutdown, bypass output was overload and exceeded " "time limit.", }, { false, 0, -1, -1, -1, -1, -1, NULL, NULL, NULL } }; /* don't spam the syslog */ static time_t alarm_logged_since = 0; #define UPS2000_LOG_INTERVAL 600 /* 10 minutes */ static int ups2000_update_alarm(void) { uint16_t val[27]; int i; int r; char alarm_buf[128]; size_t all_alarms_len = 0; int alarm_count = 0; bool alarm_logged = 0; bool alarm_rtfm = 0; time_t now = time(NULL); upsdebugx(2, "ups2000_update_alarm"); /* * All alarm registers have an offset of 1024 * ups_number. * We only support 1 UPS, it's always 1024. */ r = ups2000_read_registers(modbus_ctx, ups2000_alarm[0].reg + 1024, 27, val); if (r != 27) return 1; bypass_available = 1; /* register 40161 hack, see comments below */ for (i = 0; ups2000_alarm[i].alarm_id != -1; i++) { int idx = ups2000_alarm[i].reg - ups2000_alarm[0].reg; if (idx > 26 || idx < 0) fatalx(EXIT_FAILURE, "register calculation overflow!\n"); if (CHECK_BIT(val[idx], ups2000_alarm[i].bit)) { int gotlen; if (ups2000_alarm[i].reg == 40161) /* * HACK: special treatment for register 40161. If this * register indicates an alarm, we need to lock the * "bypass.on" command as a software foolproof mechanism. * It's written to the global "bypass_available" flag. */ bypass_available = 0; alarm_count++; gotlen = snprintf(alarm_buf, 128, "(ID %02d/%02d): %s!", ups2000_alarm[i].alarm_id, ups2000_alarm[i].alarm_cause_id, ups2000_alarm[i].alarm_name); if (gotlen < 0 || (uintmax_t)gotlen > SIZE_MAX) { fatalx(EXIT_FAILURE, "alarm_buf preparation over/under-flow!\n"); } all_alarms_len += (size_t)gotlen; alarm_set(alarm_buf); if (ups2000_alarm[i].status_name) status_set(ups2000_alarm[i].status_name); /* * Log the warning only if it's a new alarm, or if a long time * has paseed since we first warned it. */ if (!ups2000_alarm[i].active || difftime(now, alarm_logged_since) >= UPS2000_LOG_INTERVAL) { int loglevel; const char *alarm_word; /* * Most text editors have syntax highlighting, adding an * alarm word makes the log more readable */ loglevel = ups2000_alarm[i].loglevel; if (loglevel <= LOG_ERR) { alarm_word = "ERROR"; /* * If at least one error is serious, suggest reading * manual. */ alarm_rtfm = 1; } else { alarm_word = "WARNING"; } upslogx(loglevel, "%s: alarm %02d, Cause %02d: %s!", alarm_word, ups2000_alarm[i].alarm_id, ups2000_alarm[i].alarm_cause_id, ups2000_alarm[i].alarm_name); if (ups2000_alarm[i].alarm_desc) upslogx(loglevel, "%s", ups2000_alarm[i].alarm_desc); switch (ups2000_alarm[i].alarm_clear) { case ALARM_CLEAR_AUTO: upslogx(loglevel, "This alarm can be auto cleared."); break; case ALARM_CLEAR_MANUAL: upslogx(loglevel, "This alarm can only be manual cleared " "via front panel."); break; case ALARM_CLEAR_DEPENDING: upslogx(loglevel, "This alarm is auto or manual cleared " "depending on the specific problem."); } ups2000_alarm[i].active = 1; alarm_logged = 1; } } else { if (ups2000_alarm[i].active) { upslogx(LOG_WARNING, "Cleared alarm %02d, Cause %02d: %s", ups2000_alarm[i].alarm_id, ups2000_alarm[i].alarm_cause_id, ups2000_alarm[i].alarm_name); ups2000_alarm[i].active = 0; alarm_logged = 1; } } } if (alarm_count > 0) { /* append this to the alarm string as a friendly reminder */ int gotlen = snprintf(alarm_buf, 128, "Check log for details!"); if (gotlen < 0 || (uintmax_t)gotlen > SIZE_MAX) { fatalx(EXIT_FAILURE, "alarm_buf preparation over/under-flow!\n"); } all_alarms_len += (size_t)gotlen; alarm_set(alarm_buf); /* if the alarm string is too long, replace it with this */ if (all_alarms_len + 1 > ST_MAX_VALUE_LEN) { alarm_init(); /* discard all original alarms */ snprintf(alarm_buf, 128, "UPS has %d alarms in effect, " "check log for details!", alarm_count); alarm_set(alarm_buf); } /* * If we are doing a syslog, write the final message and refresh the * do-not-spam-the-log timer "alarm_logged_since". */ if (alarm_logged) { upslogx(LOG_WARNING, "UPS has %d alarms in effect.", alarm_count); if (alarm_rtfm) upslogx(LOG_WARNING, "Read Huawei User Manual for " "troubleshooting information."); alarm_logged_since = time(NULL); } } else { upsdebugx(2, "UPS has 0 alarms in effect."); if (alarm_logged) { upslogx(LOG_WARNING, "UPS has cleared all alarms."); alarm_logged_since = time(NULL); } } return 0; } void upsdrv_updateinfo(void) { int err = 0; upsdebugx(2, "upsdrv_updateinfo"); status_init(); alarm_init(); err += ups2000_update_timers(); err += ups2000_update_alarm(); err += ups2000_update_info(); err += ups2000_update_status(); err += ups2000_update_rw_var(); if (err > 0) { upsdebugx(2, "upsdrv_updateinfo failed, data stale."); dstate_datastale(); return; } alarm_commit(); status_commit(); dstate_dataok(); upsdebugx(2, "upsdrv_updateinfo done"); } /* * A lookup table of simple RW (configurable) variable "name", and their * "getter" and "setter". A "getter" function reads the variable from * the UPS, and a "setter" overwrites it. * * This struct only handles simple variables, delays are handled in another * table. */ static struct { const char *name; const uint16_t reg; int (*const getter)(const uint16_t); int (*const setter)(const uint16_t, const char *); } ups2000_rw_var[] = { { "ups.start.auto", 1044, ups2000_autostart_get, ups2000_autostart_set }, { "ups.beeper.status", 1046, ups2000_beeper_get, ups2000_beeper_set }, { NULL, 0, NULL, NULL }, }; /* * A specialized lookup table of startup, reboot and shutdown delays, * represented by RW variables. */ static struct ups2000_delay_t { const char *name; /* RW variable name */ uint16_t *const global_var; /* its corresponding global variable */ const char *varname_cmdline; /* cmdline argument passed to us */ const uint16_t min; /* minimum value allowed (seconds) */ const uint16_t max; /* maximum value allowed (seconds) */ const uint8_t step; /* can only be set in discrete steps */ const uint16_t dfault; /* default value */ } ups2000_rw_delay[] = { /* 5940 = 99 min. */ { "ups.delay.shutdown", &ups2000_offdelay, "offdelay", 6, 5940, 6, 60 }, { "ups.delay.reboot", &ups2000_rebootdelay, "rebootdelay", 6, 5940, 6, 60 }, { "ups.delay.start", &ups2000_ondelay, "ondelay", 60, 5940, 60, 60 }, { NULL, NULL, NULL, 0, 0, 0, 0 }, }; enum { SHUTDOWN, REBOOT, START }; static int ups2000_update_rw_var(void) { int i; int r; upsdebugx(2, "ups2000_update_rw_var"); for (i = 0; ups2000_rw_var[i].name != NULL; i++) { r = ups2000_rw_var[i].getter(ups2000_rw_var[i].reg); if (r != 0) return 1; } ups2000_delay_get(); return 0; } static int setvar(const char *name, const char *val) { int i; int r; for (i = 0; ups2000_rw_var[i].name != NULL; i++) { if (!strcasecmp(ups2000_rw_var[i].name, name)) { r = ups2000_rw_var[i].setter(ups2000_rw_var[i].reg, val); goto found; } } for (i = 0; ups2000_rw_delay[i].name != NULL; i++) { if (!strcasecmp(ups2000_rw_delay[i].name, name)) { r = ups2000_rw_var[i].setter(ups2000_rw_var[i].reg, val); goto found; } } return STAT_SET_UNKNOWN; found: if (r == STAT_SET_FAILED) upslogx(LOG_ERR, "setvar: setting variable [%s] to [%s] failed", name, val); else if (r == STAT_SET_INVALID) upslogx(LOG_WARNING, "setvar: [%s] is not valid for variable [%s]", val, name); return r; } static int ups2000_autostart_get(const uint16_t reg) { /* * "ups.start.auto" is not supported because it overcomplicates * the logic. The driver changes "ups.start.auto" internally to * allow shutdown and reboot commands to do their jobs. If we make * "ups.start.auto" an user configuration, it means we must (1) * watch for UPS front panel updates and apply the user setting to * the driver, and (2) save the restart setting temporally before * restarting, track the UPS restart process, and program the value * back later. * * Not supporting it greatly simplifies the logic - upsdrv_shutdown * always put the UPS in a restartable mode, following the standard * NUT behavior. Worse is better. (To prevent user confusion, we * don't even report this variable, otherwise the user may attempt * to change it using the front panel. */ NUT_UNUSED_VARIABLE(reg); return 0; } /* * Currently for internal use only, see comments above. */ static int ups2000_autostart_set(const uint16_t reg, const char *string) { uint16_t val; int r; if (!strcasecmp(string, "yes")) val = 1; else if (!strcasecmp(string, "no")) val = 0; else return STAT_SET_INVALID; r = ups2000_write_register(modbus_ctx, reg + 10000, val); if (r != 1) return STAT_SET_FAILED; return STAT_SET_HANDLED; } static int ups2000_beeper_get(const uint16_t reg) { uint16_t val; int r; r = ups2000_read_registers(modbus_ctx, reg + 10000, 1, &val); if (r != 1) return -1; if (val != 0 && val != 1) return -1; /* * The register is "beeper disable", but we need to report whether it's * enabled, thus we invert the boolean. */ if (val == 0) dstate_setinfo("ups.beeper.status", "enabled"); else dstate_setinfo("ups.beeper.status", "disabled"); dstate_setflags("ups.beeper.status", ST_FLAG_RW); dstate_addenum("ups.beeper.status", "enabled"); dstate_addenum("ups.beeper.status", "disabled"); return 0; } static int ups2000_beeper_set(const uint16_t reg, const char *string) { uint16_t val; int r; if (!strcasecmp(string, "disabled") || !strcasecmp(string, "muted")) { /* * Temporary "muted" is not supported. Only permanent "disabled" * is. This is why we only support "beeper.disable" as an instant * command, not "beeper.muted". But when setting it as a variable, * we try to be robust here and treat both as synonyms. */ val = 1; } else if (!strcasecmp(string, "enabled")) val = 0; else return STAT_SET_INVALID; r = ups2000_write_register(modbus_ctx, reg + 10000, val); if (r != 1) return STAT_SET_FAILED; return STAT_SET_HANDLED; } /* * Note: variables "ups.delay.{shutdown,start,reboot}" are software- * only variables. We only get the user settings, validate its value * and store them as global variables. The actual hardware register * are only programmed when a shutdown/reboot is issued. */ static void ups2000_delay_get(void) { char *cmdline; int i; int r; for (i = 0; ups2000_rw_delay[i].name != NULL; i++) { struct ups2000_delay_t *delay; delay = &ups2000_rw_delay[i]; if (*delay->global_var == UPS2000_DELAY_INVALID) { cmdline = getval(delay->varname_cmdline); if (cmdline) { r = ups2000_delay_set(delay->name, cmdline); if (r != STAT_SET_HANDLED) { upslogx(LOG_ERR, "servar: %s is invalid. " "Reverting to default %s %d seconds", delay->varname_cmdline, delay->varname_cmdline, delay->dfault); *delay->global_var = delay->dfault; } } else { *delay->global_var = delay->dfault; upslogx(LOG_INFO, "setvar: use default %s %d seconds", delay->varname_cmdline, delay->dfault); } } dstate_setinfo(delay->name, "%d", *delay->global_var); dstate_setflags(delay->name, ST_FLAG_RW); dstate_addrange(delay->name, delay->min, delay->max); } } static int ups2000_delay_set(const char *var, const char *string) { struct ups2000_delay_t *delay_schema = NULL; uint16_t delay, delay_rounded; int i; int r; r = str_to_ushort_strict(string, &delay, 10); if (!r) return STAT_SET_INVALID; for (i = 0; ups2000_rw_delay[i].name != NULL; i++) { if (!strcmp(ups2000_rw_delay[i].name, var)) { delay_schema = &ups2000_rw_delay[i]; break; } } if (!delay_schema) return STAT_SET_UNKNOWN; if (delay > delay_schema->max) return STAT_SET_INVALID; if (delay < delay_schema->min) { upslogx(LOG_NOTICE, "setvar: %s [%u] is too low, " "it has been set to %u seconds\n", delay_schema->varname_cmdline, delay, delay_schema->min); delay = delay_schema->min; } if (delay % delay_schema->step != 0) { delay_rounded = delay + delay_schema->step - delay % delay_schema->step; upslogx(LOG_NOTICE, "setvar: %s [%u] is not a multiple of %d, " "it has been rounded up to %u seconds\n", delay_schema->varname_cmdline, delay, delay_schema->step, delay_rounded); delay = delay_rounded; } *delay_schema->global_var = delay; return STAT_SET_HANDLED; } /* * A lookup table of all instant commands "cmd" and their * corresponding registers "reg". For each instant command, * it's handled by... * * 1. One register write, by writing "val1" to "reg1", the * simplest case. * * 2. Two register writes, by writing "val1" to "reg1", and * writing "val2" to "reg2". One after another. * * 3. Calling "*handler_func" and passing "reg1". This is * used to handle commands that needs additional processing. * If "reg1" is not necessary or unsuitable, "-1" is used. */ #define REG_NULL -1, -1 #define FUNC_NULL NULL static struct ups2000_cmd_t { const char *cmd; const int16_t reg1, val1, reg2, val2; int (*const handler_func)(const uint16_t); } ups2000_cmd[] = { { "test.battery.start.quick", 2028, 1, REG_NULL, FUNC_NULL }, { "test.battery.start.deep", 2021, 1, REG_NULL, FUNC_NULL }, { "test.battery.stop", 2023, 1, REG_NULL, FUNC_NULL }, { "beeper.enable", 1046, 0, REG_NULL, FUNC_NULL }, { "beeper.disable", 1046, 1, REG_NULL, FUNC_NULL }, { "load.off", 1045, 0, 1030, 1, FUNC_NULL }, { "bypass.stop", 1029, 1, 1045, 0, FUNC_NULL }, { "load.on", 1029, -1, REG_NULL, ups2000_instcmd_load_on }, { "bypass.start", REG_NULL, REG_NULL, ups2000_instcmd_bypass_start }, { "beeper.toggle", 1046, -1, REG_NULL, ups2000_instcmd_beeper_toggle }, { "shutdown.stayoff", 1049, -1, REG_NULL, ups2000_instcmd_shutdown_stayoff }, { "shutdown.return", REG_NULL, REG_NULL, ups2000_instcmd_shutdown_return }, { "shutdown.reboot", REG_NULL, REG_NULL, ups2000_instcmd_shutdown_reboot }, { "shutdown.reboot.graceful", REG_NULL, REG_NULL, ups2000_instcmd_shutdown_reboot_graceful }, { NULL, -1, -1, -1, -1, NULL }, }; static void ups2000_init_instcmd(void) { int i; for (i = 0; ups2000_cmd[i].cmd != NULL; i++) { dstate_addcmd(ups2000_cmd[i].cmd); } } static int instcmd(const char *cmd, const char *extra) { int i; int status; struct ups2000_cmd_t *cmd_action = NULL; NUT_UNUSED_VARIABLE(extra); for (i = 0; ups2000_cmd[i].cmd != NULL; i++) { if (!strcasecmp(cmd, ups2000_cmd[i].cmd)) { cmd_action = &ups2000_cmd[i]; } } if (!cmd_action) { upslogx(LOG_WARNING, "instcmd: command [%s] unknown", cmd); return STAT_INSTCMD_UNKNOWN; } if (cmd_action->handler_func) { /* handled by a function */ if (cmd_action->reg1 < 0) { upslogx(LOG_WARNING, "instcmd: command [%s] reg1 is negative", cmd); return STAT_INSTCMD_UNKNOWN; } else { status = cmd_action->handler_func((uint16_t)cmd_action->reg1); } } else if (cmd_action->reg1 >= 0 && cmd_action->val1 >= 0) { /* handled by a register write */ int r = ups2000_write_register(modbus_ctx, 10000 + cmd_action->reg1, (uint16_t)cmd_action->val1); if (r == 1) status = STAT_INSTCMD_HANDLED; else status = STAT_INSTCMD_FAILED; /* * if the previous write succeeds and there is an additional * register to write. */ if (r == 1 && cmd_action->reg2 >= 0 && cmd_action->val2 >= 0) { r = ups2000_write_register(modbus_ctx, 10000 + cmd_action->reg2, (uint16_t)cmd_action->val2); if (r == 1) status = STAT_INSTCMD_HANDLED; else status = STAT_INSTCMD_FAILED; } } else { fatalx(EXIT_FAILURE, "invalid ups2000_cmd table!"); } if (status == STAT_INSTCMD_FAILED) upslogx(LOG_ERR, "instcmd: command [%s] failed", cmd); else if (status == STAT_INSTCMD_HANDLED) upslogx(LOG_INFO, "instcmd: command [%s] handled", cmd); return status; } static int ups2000_instcmd_load_on(const uint16_t reg) { int r; const char *status; /* force refresh UPS status */ status_init(); r = ups2000_update_status(); if (r != 0) { /* * When the UPS status is updated, the code must set either OL, OB, OL ECO, * BYPASS, or OFF. These five options are mutually exclusive. If the register * value is invalid and set none of these flags, failure code 1 is returned. */ dstate_datastale(); return STAT_INSTCMD_FAILED; } status_commit(); status = dstate_getinfo("ups.status"); if (strstr(status, "OFF")) { /* no warning needed, continue at ups2000_write_register() below */ } else if (strstr(status, "OL") || strstr(status, "OB")) { /* * "Turning it on" has no effect if it's already on. Log a warning * while still accepting and executing the command. */ upslogx(LOG_WARNING, "load.on: UPS is already on."); upslogx(LOG_WARNING, "load.on: still executing command anyway."); } else if (strstr(status, "BYPASS")) { /* * If it's in bypass mode, reject this command. The UPS would otherwise * enter normal mode, but "load.on" is not supposed to affect the * normal/bypass status. Also log an error and suggest "bypass.stop". */ upslogx(LOG_ERR, "load.on error: UPS is already on, and is in bypass mode. " "To enter normal mode, use bypass.stop"); return STAT_INSTCMD_FAILED; } else { /* unreachable, see comments for r != 0 at the beginning */ upslogx(LOG_ERR, "load.on error: invalid ups.status (%s) detected. " "Please file a bug report!", status); return STAT_INSTCMD_FAILED; } r = ups2000_write_register(modbus_ctx, 10000 + reg, 1); if (r != 1) return STAT_INSTCMD_FAILED; return STAT_INSTCMD_HANDLED; } static int ups2000_instcmd_bypass_start(const uint16_t reg) { int r; NUT_UNUSED_VARIABLE(reg); /* force update alarms */ alarm_init(); r = ups2000_update_alarm(); if (r != 0) return STAT_INSTCMD_FAILED; alarm_commit(); /* bypass input has a power failure, refuse to bypass */ if (!bypass_available) { upslogx(LOG_ERR, "bypass input is abnormal, refuse to enter bypass mode."); return STAT_INSTCMD_FAILED; } /* enable "bypass on shutdown" */ r = ups2000_write_register(modbus_ctx, 10000 + 1045, 1); if (r != 1) return STAT_INSTCMD_FAILED; /* shutdown */ r = ups2000_write_register(modbus_ctx, 10000 + 1030, 1); if (r != 1) return STAT_INSTCMD_FAILED; return STAT_INSTCMD_HANDLED; } static int ups2000_instcmd_beeper_toggle(const uint16_t reg) { int r; const char *string; r = ups2000_beeper_get(reg); if (r != 0) return STAT_INSTCMD_FAILED; string = dstate_getinfo("ups.beeper.status"); if (!strcasecmp(string, "enabled")) r = ups2000_beeper_set(reg, "disabled"); else if (!strcasecmp(string, "disabled")) r = ups2000_beeper_set(reg, "enabled"); else return STAT_INSTCMD_FAILED; if (r != STAT_SET_HANDLED) return STAT_INSTCMD_FAILED; return STAT_INSTCMD_HANDLED; } /* * "ups.shutdown.stayoff": wait an optional offdelay and shutdown. * When the grid power returns, stay off. */ static int ups2000_instcmd_shutdown_stayoff(const uint16_t reg) { uint16_t val; int r; r = setvar("ups.start.auto", "no"); if (r != STAT_SET_HANDLED) return STAT_INSTCMD_FAILED; val = ups2000_offdelay * 10; /* scaling factor */ val /= 60; /* convert to minutes */ r = ups2000_write_register(modbus_ctx, 10000 + reg, val); if (r != 1) return STAT_INSTCMD_FAILED; return STAT_INSTCMD_HANDLED; } /* * Wait for "offdelay" second, turn off the load. Then, wait * for "ondelay" seconds. If the grid power still exists or * has returned after the timer, turn on the load. Otherwise, * shutdown the UPS. When combined with "ups.start.auto", it * guarantees the server can always be restarted even if there * is a power race. * * "shutdown.return", "shutdown.reboot" and "shutdown.reboot. * graceful" all rely on this function. */ static int ups2000_shutdown_guaranteed_return(uint16_t offdelay, uint16_t ondelay) { int r; uint16_t val[2]; r = setvar("ups.start.auto", "yes"); if (r != STAT_SET_HANDLED) return STAT_INSTCMD_FAILED; val[0] = (offdelay * 10) / 60; val[1] = ondelay / 60; r = ups2000_write_registers(modbus_ctx, 1047 + 10000, 2, val); if (r != 2) return STAT_INSTCMD_FAILED; return STAT_INSTCMD_HANDLED; } /* * "ups.shutdown.return": wait an optional "offdelay" and shutdown. * When the grid power returns, power on the load. */ static int ups2000_instcmd_shutdown_return(const uint16_t reg) { int r; NUT_UNUSED_VARIABLE(reg); r = ups2000_shutdown_guaranteed_return(ups2000_offdelay, ups2000_ondelay); if (r == STAT_INSTCMD_HANDLED) { shutdown_at = time_seek(time(NULL), ups2000_offdelay); } return r; } /* * "ups.shutdown.reboot": shutdown as soon as possible using the * smallest "rebootdelay" (inside the UPS, it's the same "ondelay" * timer), restart after an "ondelay". * * In our implementation, it's like "ups.shutdown.return", just * with a minimal "ondelay". */ static int ups2000_instcmd_shutdown_reboot(const uint16_t reg) { int r; NUT_UNUSED_VARIABLE(reg); r = ups2000_shutdown_guaranteed_return(ups2000_rw_delay[REBOOT].min, ups2000_ondelay); if (r == STAT_INSTCMD_HANDLED) { reboot_at = time_seek(time(NULL), ups2000_rw_delay[REBOOT].min); start_at = time_seek(reboot_at, ups2000_ondelay); } return r; } /* * "ups.shutdown.reboot.graceful": shutdown after a "rebootdelay" * (inside the UPS, it's the same "ondelay" timer), restart after * an "ondelay". * * In our implementation, it's like "ups.shutdown.return", just * with a "rebootdelay" instead of an "ondelay". */ static int ups2000_instcmd_shutdown_reboot_graceful(const uint16_t reg) { int r; NUT_UNUSED_VARIABLE(reg); r = ups2000_shutdown_guaranteed_return(ups2000_rebootdelay, ups2000_ondelay); if (r == STAT_INSTCMD_HANDLED) { reboot_at = time_seek(time(NULL), ups2000_rebootdelay); start_at = time_seek(reboot_at, ups2000_ondelay); } return r; } /* * List of countdown timers and pointers to their corresponding * global variables "at_time". They record estimated timestamps * when the actions are supposed to be performed. */ static struct { const char *name; time_t *const at_time; } ups2000_timers[] = { { "ups.timer.reboot", &reboot_at }, { "ups.timer.shutdown", &shutdown_at }, { "ups.timer.start", &start_at }, { NULL, NULL }, }; static int ups2000_update_timers(void) { time_t now; int eta; int i; now = time(NULL); for (i = 0; ups2000_timers[i].name != NULL; i++) { if (*ups2000_timers[i].at_time) { eta = difftime(*ups2000_timers[i].at_time, now); if (eta < 0) eta = 0; dstate_setinfo(ups2000_timers[i].name, "%d", eta); } else { dstate_setinfo(ups2000_timers[i].name, "%d", -1); } } return 0; } void upsdrv_shutdown(void) { int r; r = instcmd("shutdown.reboot", ""); if (r != STAT_INSTCMD_HANDLED) { upslogx(LOG_ERR, "upsdrv_shutdown failed!"); set_exit_flag(-1); } } void upsdrv_help(void) { } /* list flags and values that you want to receive via -x */ void upsdrv_makevartable(void) { char msg[64]; snprintf(msg, 64, "Set shutdown delay, in seconds, 6-second step" " (default=%d)", ups2000_rw_delay[SHUTDOWN].dfault); addvar(VAR_VALUE, "offdelay", msg); snprintf(msg, 64, "Set reboot delay, in seconds, 6-second step" " (default=%d).", ups2000_rw_delay[REBOOT].dfault); addvar(VAR_VALUE, "rebootdelay", msg); snprintf(msg, 64, "Set start delay, in seconds, 60-second step" " (default=%d).", ups2000_rw_delay[START].dfault); addvar(VAR_VALUE, "ondelay", msg); } void upsdrv_cleanup(void) { if (modbus_ctx != NULL) { modbus_close(modbus_ctx); modbus_free(modbus_ctx); } ser_close(upsfd, device_path); } /* * Seek time "t" forward or backward by n "seconds" without assuming * the underlying type and format of "time_t". This ensures maximum * portability. Although on POSIX and many other systems, "time_t" * is guaranteed to be in seconds. * * On error, abort the program. */ static time_t time_seek(time_t t, int seconds) { struct tm time_tm; time_t time_output; if (!t) fatalx(EXIT_FAILURE, "time_seek() failed!"); if (!gmtime_r(&t, &time_tm)) fatalx(EXIT_FAILURE, "time_seek() failed!"); time_tm.tm_sec += seconds; time_output = mktime(&time_tm); if (time_output == (time_t) -1) fatalx(EXIT_FAILURE, "time_seek() failed!"); return time_output; } /* * Read bytes from the UPS2000 serial port, until the buffer has * nothing left to read (after ser_get_buf() times out). The buffer * size is limited to buf_len (inclusive). * * On error, return 0. * * In the serial library, ser_get_buf() can be a short read, and * ser_get_buf_let() requires a precalculated length, necessiates * our own read function. */ static size_t ups2000_read_serial(uint8_t *buf, size_t buf_len) { ssize_t bytes = 0; size_t total = 0; /* wait 400 ms for the device to process our command */ usleep(400 * 1000); while (buf_len > 0) { bytes = ser_get_buf(upsfd, buf, buf_len, 1, 0); if (bytes < 0) return 0; /* read failure */ else if (bytes == 0) return total; /* nothing to read */ if ((size_t) bytes > buf_len) { /* * Assertion: This should never happen. bytes is always less or equal * to buf_len, and buf_len will never underflow under any circumstances. */ fatalx(EXIT_FAILURE, "ups2000_read_serial() reads too much!"); } total += (size_t)bytes; /* increment byte counter */ buf += bytes; /* advance buffer position */ buf_len -= (size_t)bytes; /* decrement limiter */ } return 0; /* buffer exhaustion */ } /* * Retry control. By default, we are in RETRY_ENABLE mode. For each * register read, we retry three times (1 sec. between each attempt), * before raising a fatal error and giving up. So far so good, but, * if the link went down, all operation would fail and the program * would become unresponsive due to excessive retrys. * * To prevent this problem, after the first fatal error, we stop all * retry attempts by entering RETRY_DISABLE_TEMPORARY mode, allowing * subsequent operation to fail without retry. Later, after the first * success is encountered, we move back to RETRY_ENABLE mode. */ enum { RETRY_ENABLE, RETRY_DISABLE_TEMPORARY }; static int retry_status = RETRY_ENABLE; /* * Read one or more registers using libmodbus. * * This is simply a wrapper for libmodbus's modbus_read_registers() with * retry and workaround logic. When an error has occured, we retry 3 times * before giving up, allowing us to recover from non-fatal failures without * triggering a data stale. */ static int ups2000_read_registers(modbus_t *ctx, int addr, int nb, uint16_t *dest) { int i; int r = -1; if (addr < 10000) upslogx(LOG_ERR, "Invalid register read from %04d detected. " "Please file a bug report!", addr); for (i = 0; i < 3; i++) { /* * If the previous read failed with a timeout, often there * are still unprocessed bytes in the serial buffer and they * would be mixed with the new data, creating invalid messages, * making all subsequent reads to fail as well. * * Flush read buffer first to avoid it. */ modbus_flush(ctx); r = modbus_read_registers(ctx, addr, nb, dest); /* generic retry for modbus read failures. */ if (retry_status == RETRY_ENABLE && r != nb) { upslogx(LOG_WARNING, "modbus_read_registers() failed (%d, errno %d): %s", r, errno, modbus_strerror(errno)); upslogx(LOG_WARNING, "Register %04d has a read failure. Retrying...", addr); sleep(1); continue; } else if (r == nb) retry_status = RETRY_ENABLE; /* * Workaround for buggy register 2002 (battery status). Sometimes * this register returns invalid values. This is a known problem * and it's not fatal, so we use LOG_INFO. */ if (retry_status == RETRY_ENABLE && addr == 12002 && (dest[0] < 2 || dest[0] > 5)) { upslogx(LOG_INFO, "Battery status has a non-fatal read failure, it's usually harmless. Retrying... "); sleep(1); continue; } else if (addr == 12002 && dest[0] >= 2 && dest[0] <= 5) retry_status = RETRY_ENABLE; return r; } /* Give up */ upslogx(LOG_ERR, "modbus_read_registers() failed (%d, errno %d): %s", r, errno, modbus_strerror(errno)); upslogx(LOG_ERR, "Register %04d has a fatal read failure.", addr); retry_status = RETRY_DISABLE_TEMPORARY; return r; } static int ups2000_write_registers(modbus_t *ctx, int addr, int nb, uint16_t *src) { int i; int r = -1; if (addr < 10000) upslogx(LOG_ERR, "Invalid register write to %04d detected. " "Please file a bug report!", addr); for (i = 0; i < 3; i++) { r = modbus_write_registers(ctx, addr, nb, src); /* generic retry for modbus write failures. */ if (retry_status == RETRY_ENABLE && r != nb) { upslogx(LOG_WARNING, "modbus_write_registers() failed (%d, errno %d): %s", r, errno, modbus_strerror(errno)); upslogx(LOG_WARNING, "Register %04d has a write failure. Retrying...", addr); sleep(1); continue; } else if (r == nb) retry_status = RETRY_ENABLE; return r; } /* Give up */ upslogx(LOG_ERR, "modbus_write_registers() failed (%d, errno %d): %s", r, errno, modbus_strerror(errno)); upslogx(LOG_ERR, "Register %04d has a fatal write failure.", addr); retry_status = RETRY_DISABLE_TEMPORARY; return r; } static int ups2000_write_register(modbus_t *ctx, int addr, uint16_t val) { return ups2000_write_registers(ctx, addr, 1, &val); } /* * The following CRC-16 code was copied from libmodbus. * * Copyright (C) 2001-2011 Stéphane Raimbault * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library 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 * Lesser General Public License for more details. */ /* Table of CRC values for high-order byte */ static const uint8_t table_crc_hi[] = { 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40 }; /* Table of CRC values for low-order byte */ static const uint8_t table_crc_lo[] = { 0x00, 0xC0, 0xC1, 0x01, 0xC3, 0x03, 0x02, 0xC2, 0xC6, 0x06, 0x07, 0xC7, 0x05, 0xC5, 0xC4, 0x04, 0xCC, 0x0C, 0x0D, 0xCD, 0x0F, 0xCF, 0xCE, 0x0E, 0x0A, 0xCA, 0xCB, 0x0B, 0xC9, 0x09, 0x08, 0xC8, 0xD8, 0x18, 0x19, 0xD9, 0x1B, 0xDB, 0xDA, 0x1A, 0x1E, 0xDE, 0xDF, 0x1F, 0xDD, 0x1D, 0x1C, 0xDC, 0x14, 0xD4, 0xD5, 0x15, 0xD7, 0x17, 0x16, 0xD6, 0xD2, 0x12, 0x13, 0xD3, 0x11, 0xD1, 0xD0, 0x10, 0xF0, 0x30, 0x31, 0xF1, 0x33, 0xF3, 0xF2, 0x32, 0x36, 0xF6, 0xF7, 0x37, 0xF5, 0x35, 0x34, 0xF4, 0x3C, 0xFC, 0xFD, 0x3D, 0xFF, 0x3F, 0x3E, 0xFE, 0xFA, 0x3A, 0x3B, 0xFB, 0x39, 0xF9, 0xF8, 0x38, 0x28, 0xE8, 0xE9, 0x29, 0xEB, 0x2B, 0x2A, 0xEA, 0xEE, 0x2E, 0x2F, 0xEF, 0x2D, 0xED, 0xEC, 0x2C, 0xE4, 0x24, 0x25, 0xE5, 0x27, 0xE7, 0xE6, 0x26, 0x22, 0xE2, 0xE3, 0x23, 0xE1, 0x21, 0x20, 0xE0, 0xA0, 0x60, 0x61, 0xA1, 0x63, 0xA3, 0xA2, 0x62, 0x66, 0xA6, 0xA7, 0x67, 0xA5, 0x65, 0x64, 0xA4, 0x6C, 0xAC, 0xAD, 0x6D, 0xAF, 0x6F, 0x6E, 0xAE, 0xAA, 0x6A, 0x6B, 0xAB, 0x69, 0xA9, 0xA8, 0x68, 0x78, 0xB8, 0xB9, 0x79, 0xBB, 0x7B, 0x7A, 0xBA, 0xBE, 0x7E, 0x7F, 0xBF, 0x7D, 0xBD, 0xBC, 0x7C, 0xB4, 0x74, 0x75, 0xB5, 0x77, 0xB7, 0xB6, 0x76, 0x72, 0xB2, 0xB3, 0x73, 0xB1, 0x71, 0x70, 0xB0, 0x50, 0x90, 0x91, 0x51, 0x93, 0x53, 0x52, 0x92, 0x96, 0x56, 0x57, 0x97, 0x55, 0x95, 0x94, 0x54, 0x9C, 0x5C, 0x5D, 0x9D, 0x5F, 0x9F, 0x9E, 0x5E, 0x5A, 0x9A, 0x9B, 0x5B, 0x99, 0x59, 0x58, 0x98, 0x88, 0x48, 0x49, 0x89, 0x4B, 0x8B, 0x8A, 0x4A, 0x4E, 0x8E, 0x8F, 0x4F, 0x8D, 0x4D, 0x4C, 0x8C, 0x44, 0x84, 0x85, 0x45, 0x87, 0x47, 0x46, 0x86, 0x82, 0x42, 0x43, 0x83, 0x41, 0x81, 0x80, 0x40 }; static uint16_t crc16(uint8_t * buffer, size_t buffer_length) { uint8_t crc_hi = 0xFF; /* high CRC byte initialized */ uint8_t crc_lo = 0xFF; /* low CRC byte initialized */ unsigned int i; /* will index into CRC lookup */ /* pass through message buffer */ while (buffer_length--) { i = crc_hi ^ *buffer++; /* calculate the CRC */ crc_hi = crc_lo ^ table_crc_hi[i]; crc_lo = table_crc_lo[i]; } return (uint16_t) crc_hi << 8 | crc_lo; } nut-2.8.1/drivers/belkin.h0000644000175000017500000000370114501607135012347 00000000000000/* belkin.h - serial commands for Belkin smart protocol units Copyright (C) 2000 Marcus Müller 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 2 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, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef WIN32 #include #endif #include "serial.h" #include "timehead.h" #define STATUS 'P' #define CONTROL 'S' #define MANUFACTURER "MNU" #define MODEL "MOD" #define VERSION_CMD "VER" #define RATING "RAT" #define STAT_INPUT "STI" #define STAT_OUTPUT "STO" #define STAT_BATTERY "STB" #define STAT_STATUS "STA" #define TEST_RESULT "TSR" #define POWER_ON "RON" #define POWER_OFF "ROF" #define POWER_SDTYPE "SDT" /* shutdown type? */ #define POWER_CYCLE "SDA" /* shutdown, then restore */ #define BUZZER "BUZ" #define BUZZER_ON "1" #define BUZZER_OFF0 "0" /* Switching the buzzer off can be either 0 or 2 */ #define BUZZER_OFF2 "2" /* Seems to be used for F6c1400 */ #define TEST "TST" #define TEST_10SEC "3" #define TEST_DEEP "4" #define TEST_CANCEL "0" /* The UPS Status "low battery" comes up 10s before the UPS actually stops. Therefore a shutdown is done at this battery % */ #define LOW_BAT 20 /* the maximum allowed number of missed replies */ #define MAXTRIES 3 /* dangerous instant commands must be reconfirmed within a 12 second window */ #define CONFIRM_DANGEROUS_COMMANDS 1 #define MINCMDTIME 3 #define MAXCMDTIME 15 nut-2.8.1/drivers/microdowell.c0000644000175000017500000010413114501607135013415 00000000000000/* * * microdowell.c: support for Microdowell Enterprise Nxx/Bxx serial protocol based UPSes * * Copyright (C) Elio Corbolante * * microdowell.c created on 27/09/2007 * * 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 2 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, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ /* anything commented is optional anything else is mandatory */ #include "main.h" #include "serial.h" #ifndef WIN32 #include #endif #include "timehead.h" #include "nut_stdint.h" #define ENTERPRISE_PROTOCOL #include "microdowell.h" #define MAX_START_DELAY 999999 #define MAX_SHUTDOWN_DELAY 32767 /* Maximum length of a string representing these values */ #define MAX_START_DELAY_LEN 6 #define MAX_SHUTDOWN_DELAY_LEN 5 #define DRIVER_NAME "MICRODOWELL UPS driver" #define DRIVER_VERSION "0.03" /* driver description structure */ upsdrv_info_t upsdrv_info = { DRIVER_NAME, DRIVER_VERSION, "Elio Corbolante ", DRV_STABLE, { NULL } }; static ENT_STRUCT ups ; /* common driver routines */ int instcmd(const char *cmdname, const char *extra); int setvar(const char *varname, const char *val); /* he knew... macros should evaluate their arguments only once */ #define CLAMP(x, min, max) (((x) < (min)) ? (min) : (((x) > (max)) ? (max) : (x))) static int CheckDataChecksum(unsigned char *Buff, size_t Len) { size_t i, Idx ; unsigned char Xor ; ups.FramePointer = Xor = 0 ; for (Idx=0 ; Idx < Len ; Idx++) if (Buff[Idx] == STX_CHAR) break ; ups.FramePointer = Idx ; /* Memorise start point. */ /* Check that the message is not to short... */ if ( (Idx > (Len-4)) || (Idx+Buff[Idx+1]+2 > Len) ) return(ERR_MSG_TOO_SHORT) ; /* Too short a message! */ /* Calculate checksum */ for (i=Idx+1 ; i < Idx+Buff[Idx+1]+2 ; i++) Xor ^= Buff[i] ; /* if Xor != then checksum error */ if (Xor != Buff[i]) return(ERR_MSG_CHECKSUM) ; /* error in checksum */ /* If checksum OK: return */ return(0) ; } static const char *ErrMessages[] = { /* 0 */ "errorcode NOT DEFINED", /* default error message */ /* 1 */ "I2C bus busy (e2prom)", /* 2 */ "Command received: checksum not valid", /* 3 */ "Command received: unrecognized command", /* 4 */ "WRITE: eeprom address not multiple of 8", /* 5 */ "READ: eeprom address (added with size) out of bound ", /* 6 */ "error writing e2prom address", /* 7 */ "error writing e2prom subaddress", /* 8 */ "error reading e2prom data", /* 9 */ "error writing e2prom address", /* 10 */ "error reading e2prom subaddress", /* 11 */ "error writing e2prom data", /* 12 */ "error writing e2prom address during data verification", /* 13 */ "error verification e2prom data", /* 14 */ "e2prom data are different from those in the write buffer", /* 15 */ "e2prom checksum error", /* 16 */ "NO CHARS FROM PORT", /* 17 */ "TOO FEW DATA RECEIVED: [STX] near end of message", /* 18 */ "CHECKSUM ERROR IN MESSAGE", /* 19 */ "OK", /* */ "" } ; static const char *PrintErr(int ErrCode) { int msgIndex = 0 ; /* The default 'msgIndex' is 0 (error code not defined) */ switch (ErrCode) { case ERR_NO_ERROR : msgIndex = 19 ; break ; case ERR_I2C_BUSY : msgIndex = 1 ; break ; case ERR_CMD_CHECKSUM : msgIndex = 2 ; break ; case ERR_CMD_UNRECOG : msgIndex = 3 ; break ; case ERR_EEP_NOBLOCK : msgIndex = 4 ; break ; case ERR_EEP_OOBOUND : msgIndex = 5 ; break ; case ERR_EEP_WADDR1 : msgIndex = 6 ; break ; case ERR_EEP_WSADDR1 : msgIndex = 7 ; break ; case ERR_EEP_RDATA : msgIndex = 8 ; break ; case ERR_EEP_WADDR2 : msgIndex = 9 ; break ; case ERR_EEP_WSADDR2 : msgIndex = 10 ; break ; case ERR_EEP_WDATA : msgIndex = 11 ; break ; case ERR_EEP_WADDRVER : msgIndex = 12 ; break ; case ERR_EEP_WDATAVER : msgIndex = 13 ; break ; case ERR_EEP_VERIFY : msgIndex = 14 ; break ; case ERR_EEP_CHECKSUM : msgIndex = 15 ; break ; case ERR_COM_NO_CHARS : msgIndex = 16 ; break ; case ERR_MSG_TOO_SHORT : msgIndex = 17 ; break ; case ERR_MSG_CHECKSUM : msgIndex = 18 ; break ; default : msgIndex = 0 ; break ; } return(ErrMessages[msgIndex]) ; } static int CheckErrCode(unsigned char * Buff) { auto int Ret ; switch (Buff[2]) { /* I have found an error */ case CMD_NACK : Ret = Buff[3] ; break ; case CMD_ACK : case CMD_GET_STATUS : case CMD_GET_MEASURES : case CMD_GET_CONFIG : case CMD_GET_BATT_STAT : case CMD_GET_MASK : case CMD_SET_TIMER : case CMD_BATT_TEST : case CMD_GET_BATT_TEST : case CMD_SD_ONESHOT : case CMD_GET_SD_ONESHOT: case CMD_SET_SCHEDULE : case CMD_GET_SCHEDULE : case CMD_GET_EEP_BLOCK : case CMD_SET_EEP_BLOCK : case CMD_GET_EEP_SEED : case CMD_INIT : Ret = 0 ; break ; /* command not recognized */ default: Ret = ERR_CMD_UNRECOG ; break ; } return(Ret) ; } static void SendCmdToSerial(unsigned char *Buff, size_t Len) { int i; unsigned char Tmp[20], Xor ; Tmp[0] = STX_CHAR ; Xor = Tmp[1] = (unsigned char) (Len & 0x1f) ; for (i=0 ; i < Tmp[1] ; i++) { Tmp[i+2] = Buff[i] ; Xor ^= Buff[i] ; } Tmp[Len+2] = Xor ; upsdebug_hex(4, "->UPS", Tmp, Len+3) ; /* flush serial port */ ser_flush_in(upsfd, "", 0) ; /* empty input buffer */ ser_send_buf(upsfd, Tmp, Len+3) ; /* send data to the UPS */ } static unsigned char * CmdSerial(unsigned char *OutBuffer, size_t Len, unsigned char *RetBuffer) { #define TMP_BUFF_LEN 1024 unsigned char InpBuff[TMP_BUFF_LEN+1] ; unsigned char TmpBuff[3] ; int i, ErrCode ; unsigned char *p ; size_t BuffLen ; /* The default error code (no received character) */ ErrCode = ERR_COM_NO_CHARS ; SendCmdToSerial(OutBuffer, Len) ; usleep(10000) ; /* small delay (1/100 s) */ /* get chars until timeout */ BuffLen = 0 ; while (ser_get_char(upsfd, TmpBuff, 0, 10000) == 1) { InpBuff[BuffLen++] = TmpBuff[0] ; if (BuffLen > TMP_BUFF_LEN) break ; } upsdebug_hex(4, "UPS->", InpBuff, BuffLen) ; if (BuffLen > 0) { ErrCode = CheckDataChecksum(InpBuff, BuffLen) ; /* upsdebugx(4, "ErrCode = %d / Len = %d", ErrCode, BuffLen); */ if (!ErrCode) { /* FramePointer to valid data! */ p = InpBuff + ups.FramePointer ; /* p now point to valid data. check if it is a error code. */ ErrCode = CheckErrCode(p) ; if (!ErrCode) { /* I copy the data read in the buffer */ for(i=0 ; i<(int) (p[1])+3 ; i++) RetBuffer[i] = p[i] ; ups.ErrCode = ups.ErrCount = ups.CommStatus = 0 ; return(RetBuffer) ; } } } /* if they have arrived here, wants to say that I have found an error.... */ ups.ErrCode = ErrCode ; ups.ErrCount++ ; if (ups.ErrCount > 3) { ups.CommStatus &= 0x80 ; ups.CommStatus |= (unsigned char) (ups.ErrCount & 0x7F) ; if (ups.ErrCount > 100) ups.ErrCount = 100 ; } return(NULL) ; /* There have been errors in the reading of the data */ } static int detect_hardware(void) { unsigned char OutBuff[20] ; unsigned char InpBuff[260] ; unsigned char *p ; int i, retries ; struct tm *Time ; struct tm tmbuf; time_t lTime ; ups.ge_2kVA = 0 ; for (retries=0 ; retries <= 4 ; retries++) { /* Identify UPS model */ OutBuff[0] = CMD_GET_EEP_BLOCK ; /* get EEPROM data */ OutBuff[1] = EEP_UPS_MODEL ; /* UPS model */ OutBuff[2] = 8 ; /* number of bytes */ if ((p = CmdSerial(OutBuff, LEN_GET_EEP_BLOCK, InpBuff)) != NULL) { /* got UPS model */ for (i=0 ; i<8 ; i++) ups.UpsModel[i] = (char)p[i+5] ; ups.UpsModel[8] = '\0' ; upsdebugx(2, "get 'UPS model': %s", PrintErr(ups.ErrCode)); break ; /* UPS identified: exit from ' for' LOOP */ } else { upsdebugx(1, "[%d] get 'UPS model': %s", retries, PrintErr(ups.ErrCode)); upslogx(LOG_ERR, "[%d] Unable to identify UPS model [%s]", retries, PrintErr(ups.ErrCode)); usleep(100000) ; /* small delay (1/10 s) for next retry */ } } /* check if I was unable to find the UPS */ if (retries == 4) /* UPS not found! */ return -1; /* UPS serial number */ OutBuff[0] = CMD_GET_EEP_BLOCK ; /* get EEPROM data */ OutBuff[1] = EEP_SERIAL_NUM ; /* UPS serial # */ OutBuff[2] = 8 ; /* number of bytes */ if ((p = CmdSerial(OutBuff, LEN_GET_EEP_BLOCK, InpBuff)) != NULL) { /* got UPS serial # */ for (i=0 ; i<8 ; i++) ups.SerialNumber[i] = (char)p[i+5] ; ups.SerialNumber[8] = '\0' ; upsdebugx(2, "get 'UPS Serial #': %s", PrintErr(ups.ErrCode)); } else { upsdebugx(1, "get 'UPS Serial #': %s", PrintErr(ups.ErrCode)); upslogx(LOG_ERR, "Unable to identify UPS serial # [%s]", PrintErr(ups.ErrCode)); return -1; } /* Get Production date & FW info */ OutBuff[0] = CMD_GET_EEP_BLOCK ; /* get EEPROM data */ OutBuff[1] = EEP_PROD_DATE ; /* Production date + HW version */ OutBuff[2] = 8 ; /* number of bytes */ if ((p = CmdSerial(OutBuff, LEN_GET_EEP_BLOCK, InpBuff)) != NULL) { /* got Production date & FW info */ p += 5 ; /* 'p' points to eeprom data */ ups.YearOfProd = 2000 + p[0] ; /* Production year of the UPS */ ups.MonthOfProd = p[1] ; /* Production month of the UPS */ ups.DayOfProd = p[2] ; /* Production day of the UPS */ ups.HW_MajorVersion = (p[3]>>4) & 0x0F ; /* Hardware: Major version */ ups.HW_MinorVersion = (p[3] & 0x0F) ; /* Hardware: Minor version */ ups.BR_MajorVersion = (p[4]>>4) & 0x0F ; /* BoardHardware: Major version */ ups.BR_MinorVersion = (p[4] & 0x0F) ; /* BoardHardware: Minor version */ ups.FW_MajorVersion = (p[5]>>4) & 0x0F ; /* Firmware: Major version */ ups.FW_MinorVersion = (p[5] & 0x0F) ; /* Firmware: Minor version */ ups.FW_SubVersion = p[6] ; /* Firmware: SUBVERSION (special releases */ ups.BatteryNumber = p[7] ; /* number of batteries in UPS */ upsdebugx(2, "get 'Production date': %s", PrintErr(ups.ErrCode)); } else { upsdebugx(1, "get 'Production date': %s", PrintErr(ups.ErrCode)); upslogx(LOG_ERR, "Unable to read Production date [%s]", PrintErr(ups.ErrCode)); return -1; } /* Get Battery substitution date */ OutBuff[0] = CMD_GET_EEP_BLOCK ; /* get EEPROM data */ OutBuff[1] = EEP_BATT_SUBST ; /* Battery substitution dates */ OutBuff[2] = 8 ; /* number of bytes */ if ((p = CmdSerial(OutBuff, LEN_GET_EEP_BLOCK, InpBuff)) != NULL) { /* got Battery substitution date */ p += 5 ; /* 'p' points to eeprom data */ upsdebugx(2, "get 'Battery Subst. Dates': %s", PrintErr(ups.ErrCode)); } else { upsdebugx(1, "get 'Battery Subst. Dates': %s", PrintErr(ups.ErrCode)); upslogx(LOG_ERR, "Unable to read Battery Subst. Dates [%s]", PrintErr(ups.ErrCode)); return -1; } /* Get working time (battery+normal)) */ OutBuff[0] = CMD_GET_EEP_BLOCK ; /* get EEPROM data */ OutBuff[1] = EEP_MIN_VBATT ; /* working time */ OutBuff[2] = 8 ; /* number of bytes */ if ((p = CmdSerial(OutBuff, LEN_GET_EEP_BLOCK, InpBuff)) != NULL) { /* got working time (battery+normal)) */ p += 5 ; /* 'p' points to eeprom data */ upsdebugx(2, "get 'UPS life info': %s", PrintErr(ups.ErrCode)); } else { upsdebugx(1, "get 'UPS life info': %s", PrintErr(ups.ErrCode)); upslogx(LOG_ERR, "Unable to read UPS life info [%s]", PrintErr(ups.ErrCode)); return -1; } /* Get the THRESHOLD table (0) */ OutBuff[0] = CMD_GET_EEP_BLOCK ; /* get EEPROM data */ OutBuff[1] = EEP_THRESHOLD_0 ; /* Thresholds table 0 */ OutBuff[2] = 8 ; /* number of bytes */ if ((p = CmdSerial(OutBuff, LEN_GET_EEP_BLOCK, InpBuff)) != NULL) { /* got the THRESHOLD table (0) */ p += 5 ; /* 'p' points to eeprom data */ upsdebugx(2, "get 'Thresholds table 0': %s", PrintErr(ups.ErrCode)); } else { upsdebugx(1, "get 'Thresholds table 0': %s", PrintErr(ups.ErrCode)); upslogx(LOG_ERR, "Unable to read Thresholds table 0 [%s]", PrintErr(ups.ErrCode)); return -1; } /* Get the THRESHOLD table (1) */ OutBuff[0] = CMD_GET_EEP_BLOCK ; /* get EEPROM data */ OutBuff[1] = EEP_THRESHOLD_1 ; /* Thresholds table 0 */ OutBuff[2] = 8 ; /* number of bytes */ if ((p = CmdSerial(OutBuff, LEN_GET_EEP_BLOCK, InpBuff)) != NULL) { /* got the THRESHOLD table (1) */ p += 5 ; /* 'p' points to eeprom data */ upsdebugx(2, "get 'Thresholds table 1': %s", PrintErr(ups.ErrCode)); } else { upsdebugx(1, "get 'Thresholds table 1': %s", PrintErr(ups.ErrCode)); upslogx(LOG_ERR, "Unable to read Thresholds table 1 [%s]", PrintErr(ups.ErrCode)); return -1; } /* Get the THRESHOLD table (2) */ OutBuff[0] = CMD_GET_EEP_BLOCK ; /* get EEPROM data */ OutBuff[1] = EEP_THRESHOLD_2 ; /* Thresholds table 0 */ OutBuff[2] = 8 ; /* number of bytes */ if ((p = CmdSerial(OutBuff, LEN_GET_EEP_BLOCK, InpBuff)) != NULL) { /* got the THRESHOLD table (2) */ p += 5 ; /* 'p' points to eeprom data */ upsdebugx(2, "get 'Thresholds table 2': %s", PrintErr(ups.ErrCode)); } else { upsdebugx(1, "get 'Thresholds table 2': %s", PrintErr(ups.ErrCode)); upslogx(LOG_ERR, "Unable to read Thresholds table 2 [%s]", PrintErr(ups.ErrCode)); return -1; } /* Get Option Bytes */ OutBuff[0] = CMD_GET_EEP_BLOCK ; /* get EEPROM data */ OutBuff[1] = EEP_OPT_BYTE_BLK ; /* Option Bytes */ OutBuff[2] = 8 ; /* number of bytes */ if ((p = CmdSerial(OutBuff, LEN_GET_EEP_BLOCK, InpBuff)) != NULL) { /* got Option Bytes */ p += 5 ; /* 'p' points to eeprom data */ dstate_setinfo("input.voltage.nominal", "%s", (p[EEP_OPT_BYTE_1] & 0x02) ? "110": "230") ; dstate_setinfo("input.frequency", "%s", (p[EEP_OPT_BYTE_1] & 0x01) ? "60.0": "50.0") ; upsdebugx(2, "get 'Option Bytes': %s", PrintErr(ups.ErrCode)); } else { upsdebugx(1, "get 'Option Bytes': %s", PrintErr(ups.ErrCode)); upslogx(LOG_ERR, "Unable to read Option Bytes [%s]", PrintErr(ups.ErrCode)); return -1; } /* Get UPS sensitivity (fault points) */ OutBuff[0] = CMD_GET_EEP_BLOCK ; /* get EEPROM data */ OutBuff[1] = EEP_FAULT_POINTS ; /* Number of fault points (sensitivity)) */ OutBuff[2] = 8 ; /* number of bytes */ if ((p = CmdSerial(OutBuff, LEN_GET_EEP_BLOCK, InpBuff)) != NULL) { /* got UPS sensitivity (fault points) */ p += 5 ; /* 'p' points to eeprom data */ switch (p[0]) { case 1 : dstate_setinfo("input.sensitivity", "H") ; break ; case 2 : dstate_setinfo("input.sensitivity", "M") ; break ; case 3 : dstate_setinfo("input.sensitivity", "L") ; break ; default : dstate_setinfo("input.sensitivity", "L") ; break ; } upsdebugx(2, "get 'Input Sensitivity': %s", PrintErr(ups.ErrCode)); } else { upsdebugx(1, "get 'Input Sensitivity': %s", PrintErr(ups.ErrCode)); upslogx(LOG_ERR, "Unable to read Input Sensitivity [%s]", PrintErr(ups.ErrCode)); return -1; } /* Set internal UPS clock */ time(&lTime) ; Time = localtime_r(&lTime, &tmbuf); OutBuff[0] = CMD_SET_TIMER ; /* set UPS internal timer */ OutBuff[1] = (Time->tm_wday+6) % 7 ; /* week day (0=monday) */ OutBuff[2] = (unsigned char)Time->tm_hour ; /* hours */ OutBuff[3] = (unsigned char)Time->tm_min ; /* minutes */ OutBuff[4] = (unsigned char)Time->tm_sec ; /* seconds */ if ((p = CmdSerial(OutBuff, LEN_SET_TIMER, InpBuff)) != NULL) { upsdebugx(2, "set 'UPS internal clock': %s", PrintErr(ups.ErrCode)); } else { upsdebugx(1, "set 'UPS internal clock': %s", PrintErr(ups.ErrCode)); upslogx(LOG_ERR, "Unable to set UPS internal clock [%s]", PrintErr(ups.ErrCode)); return -1; } return 0; /* everything was OK */ } /* ========================= */ void upsdrv_updateinfo(void) { unsigned char OutBuff[20] ; unsigned char InpBuff[260] ; unsigned char *p ; /* int i ; */ OutBuff[0] = CMD_GET_STATUS ; /* get UPS status */ if ((p = CmdSerial(OutBuff, LEN_GET_STATUS, InpBuff)) != NULL) { p += 3 ; /* 'p' points to received data */ status_init(); /* reset status flags */ /* store last UPS status */ ups.StatusUPS = (uint32_t)p[0] ; ups.StatusUPS |= ((uint32_t)p[1]<<8) ; ups.StatusUPS |= ((uint32_t)p[2]<<16) ; ups.StatusUPS |= ((uint32_t)p[3]<<24) ; ups.ShortStatus = (uint16_t)p[0]; ups.ShortStatus |= ((uint16_t)p[1]<<8) ; upsdebugx(1, "ups.StatusUPS: %08" PRIX32, ups.StatusUPS); upsdebugx(1, "ups.ShortStatus: %04" PRIX16, ups.ShortStatus); /* on battery? */ if (p[0] & 0x01) status_set("OB"); /* YES */ /* LOW battery? */ if (p[0] & 0x02) status_set("LB"); /* YES */ /* online? */ if (p[0] & 0x08) status_set("OL"); /* YES */ /* Overload? */ if (p[1] & 0xC0) status_set("OVER"); /* YES */ /* Offline/Init/Stanby/Waiting for mains? */ if (p[0] & 0xE0) status_set("OFF"); /* YES */ /* AVR on (boost)? */ if (p[4] & 0x04) status_set("BOOST"); /* YES */ /* AVR on (buck)? */ if (p[4] & 0x08) status_set("TRIM"); /* YES */ dstate_setinfo("ups.time", "%02d:%02d:%02d", p[6], p[7], p[8]) ; upsdebugx(3, "get 'Get Status': %s", PrintErr(ups.ErrCode)); } else { upsdebugx(1, "get 'Get Status': %s", PrintErr(ups.ErrCode)); /* upslogx(LOG_ERR, "get 'Get Status': %s", PrintErr(ups.ErrCode)); */ dstate_datastale(); return; } /* ========================= */ OutBuff[0] = CMD_GET_MEASURES ; /* get UPS values */ if ((p = CmdSerial(OutBuff, LEN_GET_MEASURES, InpBuff)) != NULL) { p += 3 ; /* 'p' points to received data */ dstate_setinfo("input.voltage", "%d", (int)((float)(p[2]*256 + p[3]) / 36.4)) ; if (ups.ge_2kVA) { dstate_setinfo("output.voltage", "%d", (int)((float)(p[6]*256 + p[7]) / 63.8)) ; dstate_setinfo("output.current", "%1.f", ((float)(p[8]*256 + p[9]) / 635.0)) ; dstate_setinfo("battery.voltage", "%.1f", ((float) (p[4]*256 + p[5])) / 329.0) ; } else { dstate_setinfo("output.voltage", "%d", (int)((float)(p[6]*256 + p[7]) / 36.4)) ; dstate_setinfo("output.current", "%1.f", ((float)(p[8]*256 + p[9]) / 1350.0)) ; dstate_setinfo("battery.voltage", "%.1f", ((float) (p[4]*256 + p[5])) / 585.0) ; } dstate_setinfo("ups.temperature", "%d", (int)(((float)(p[10]*256 + p[11])-202.97) / 1.424051)) ; upsdebugx(3, "get 'Get Measures': %s", PrintErr(ups.ErrCode)); } else { /* upsdebugx(1, "get 'Get Measures': %s", PrintErr(ups.ErrCode)); */ upslogx(LOG_ERR, "get 'Get Measures': %s", PrintErr(ups.ErrCode)); dstate_datastale(); return; } /* ========================= */ OutBuff[0] = CMD_GET_BAT_LD ; /* get UPS Battery and Load values */ if ((p = CmdSerial(OutBuff, LEN_GET_BAT_LD, InpBuff)) != NULL) { p += 3 ; /* 'p' points to received data */ dstate_setinfo("ups.power", "%d", (p[4]*256 + p[5])) ; /* dstate_setinfo("ups.realpower", "%d", (int)((float)(p[4]*256 + p[5]) * 0.6)) ; */ dstate_setinfo("battery.charge", "%d", (int)p[0]) ; dstate_setinfo("ups.load", "%d", (int)p[6]) ; upsdebugx(3, "get 'Get Batt+Load Status': %s", PrintErr(ups.ErrCode)); } else { /* upsdebugx(1, "get 'Get Batt+Load Status': %s", PrintErr(ups.ErrCode)); */ upslogx(LOG_ERR, "get 'Get Batt+Load Status': %s", PrintErr(ups.ErrCode)); dstate_datastale(); return; } status_commit(); dstate_dataok(); poll_interval = 2; } /* ========================= */ int instcmd(const char *cmdname, const char *extra) { unsigned char OutBuff[20] ; unsigned char InpBuff[260] ; unsigned char *p ; /* int i ; */ upsdebugx(1, "instcmd(%s, %s)", cmdname, extra); if (strcasecmp(cmdname, "load.on") == 0) { OutBuff[0] = CMD_SD_ONESHOT ; /* turn ON the outputs */ OutBuff[1] = 0xFF ; /* ALL outputs */ OutBuff[2] = 0x08 ; /* Enable outputs (immediately) */ OutBuff[3] = 0 ; OutBuff[4] = 0 ; OutBuff[5] = 0 ; OutBuff[6] = 0 ; OutBuff[7] = 0 ; if ((p = CmdSerial(OutBuff, LEN_SD_ONESHOT, InpBuff)) != NULL) { p += 3 ; /* 'p' points to received data */ upslogx(LOG_INFO, "Turning load on."); upsdebugx(1, "'SdOneshot(turn_ON)': %s", PrintErr(ups.ErrCode)); } else { upsdebugx(1, "'SdOneshot(turn_ON)': %s", PrintErr(ups.ErrCode)); upslogx(LOG_ERR, "'SdOneshot(turn_ON)': %s", PrintErr(ups.ErrCode)); } return STAT_INSTCMD_HANDLED; } if (strcasecmp(cmdname, "load.off") == 0) { OutBuff[0] = CMD_SD_ONESHOT ; /* turn ON the outputs */ OutBuff[1] = 0xFF ; /* ALL outputs */ OutBuff[2] = 0x04 ; /* Disable outputs (immediately) */ OutBuff[3] = 0 ; OutBuff[4] = 0 ; OutBuff[5] = 0 ; OutBuff[6] = 0 ; OutBuff[7] = 0 ; if ((p = CmdSerial(OutBuff, LEN_SD_ONESHOT, InpBuff)) != NULL) { p += 3 ; /* 'p' points to received data */ upslogx(LOG_INFO, "Turning load on."); upsdebugx(1, "'SdOneshot(turn_OFF)': %s", PrintErr(ups.ErrCode)); } else { upsdebugx(1, "'SdOneshot(turn_OFF)': %s", PrintErr(ups.ErrCode)); upslogx(LOG_ERR, "'SdOneshot(turn_OFF)': %s", PrintErr(ups.ErrCode)); } return STAT_INSTCMD_HANDLED; } if (strcasecmp(cmdname, "shutdown.return") == 0) { OutBuff[0] = CMD_SD_ONESHOT ; /* turn ON the outputs */ OutBuff[1] = 0xFF ; /* ALL outputs */ if (ups.StatusUPS & 0x01) OutBuff[2] = 0x02 ; /* Battery shutdown */ else OutBuff[2] = 0x01 ; /* Online shutdown */ if (ups.ShutdownDelay < 6) ups.ShutdownDelay = 6 ; OutBuff[3] = (ups.ShutdownDelay >> 8) & 0xFF ; /* SDDELAY (MSB) Shutdown value (seconds) */ OutBuff[4] = (ups.ShutdownDelay & 0xFF) ; /* SDDELAY (LSB) */ OutBuff[5] = (ups.WakeUpDelay >> 16) & 0xFF ; /* WUDELAY (MSB) Wakeup value (seconds) */ OutBuff[6] = (ups.WakeUpDelay >> 8) & 0xFF ; /* WUDELAY (...) */ OutBuff[7] = (ups.WakeUpDelay & 0xFF ) ; /* WUDELAY (LSB) */ if ((p = CmdSerial(OutBuff, LEN_SD_ONESHOT, InpBuff)) != NULL) { p += 3 ; /* 'p' points to received data */ upslogx(LOG_INFO, "Shutdown command(TYPE=%02x, SD=%u, WU=%u)", OutBuff[2], ups.ShutdownDelay, ups.WakeUpDelay) ; upsdebugx(3, "Shutdown command(TYPE=%02x, SD=%u, WU=%u): %s", OutBuff[2], ups.ShutdownDelay, ups.WakeUpDelay, PrintErr(ups.ErrCode)); } else { upsdebugx(1, "Shutdown command(TYPE=%02x, SD=%u, WU=%u): %s", OutBuff[2], ups.ShutdownDelay, ups.WakeUpDelay, PrintErr(ups.ErrCode)); upslogx(LOG_ERR, "Shutdown command(SD=%u, WU=%u): %s", ups.ShutdownDelay, ups.WakeUpDelay, PrintErr(ups.ErrCode)); } return STAT_INSTCMD_HANDLED; } if (strcasecmp(cmdname, "shutdown.stayoff") == 0) { OutBuff[0] = CMD_SD_ONESHOT ; /* turn ON the outputs */ OutBuff[1] = 0xFF ; /* ALL outputs */ if (ups.StatusUPS & 0x01) OutBuff[2] = 0x02 ; /* Battery shutdown */ else OutBuff[2] = 0x01 ; /* Online shutdown */ if (ups.ShutdownDelay < 6) ups.ShutdownDelay = 6 ; OutBuff[3] = (ups.ShutdownDelay >> 8) & 0xFF ; /* SDDELAY (MSB) Shutdown value (seconds) */ OutBuff[4] = (ups.ShutdownDelay & 0xFF) ; /* SDDELAY (LSB) */ OutBuff[5] = 0 ; /* WUDELAY (MSB) Wakeup value (seconds) */ OutBuff[6] = 0 ; /* WUDELAY (...) */ OutBuff[7] = 0 ; /* WUDELAY (LSB) */ if ((p = CmdSerial(OutBuff, LEN_SD_ONESHOT, InpBuff)) != NULL) { p += 3 ; /* 'p' points to received data */ upslogx(LOG_INFO, "shutdown.stayoff - (TYPE=%02x, SD=%u, WU=%u)", OutBuff[2], ups.ShutdownDelay, 0) ; upsdebugx(3, "shutdown.stayoff - (TYPE=%02x, SD=%u, WU=%u): %s", OutBuff[2], ups.ShutdownDelay, 0, PrintErr(ups.ErrCode)); } else { upsdebugx(1, "shutdown.stayoff - (TYPE=%02x, SD=%u, WU=%u): %s", OutBuff[2], ups.ShutdownDelay, 0, PrintErr(ups.ErrCode)); upslogx(LOG_ERR, "shutdown.stayoff - (TYPE=%02x, SD=%u, WU=%u)", OutBuff[2], ups.ShutdownDelay, 0) ; } return STAT_INSTCMD_HANDLED; } return STAT_INSTCMD_UNKNOWN; } #if (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_PUSH_POP_BESIDEFUNC) && (!defined HAVE_PRAGMA_GCC_DIAGNOSTIC_PUSH_POP_INSIDEFUNC) && ( (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_TYPE_LIMITS_BESIDEFUNC) || (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_TAUTOLOGICAL_CONSTANT_OUT_OF_RANGE_COMPARE_BESIDEFUNC) || defined (HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_TAUTOLOGICAL_COMPARE_BESIDEFUNC) ) # pragma GCC diagnostic push #endif #if (!defined HAVE_PRAGMA_GCC_DIAGNOSTIC_PUSH_POP_INSIDEFUNC) && (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_TYPE_LIMITS_BESIDEFUNC) # pragma GCC diagnostic ignored "-Wtype-limits" #endif #if (!defined HAVE_PRAGMA_GCC_DIAGNOSTIC_PUSH_POP_INSIDEFUNC) && (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_TAUTOLOGICAL_CONSTANT_OUT_OF_RANGE_COMPARE_BESIDEFUNC) # pragma GCC diagnostic ignored "-Wtautological-constant-out-of-range-compare" #endif #if (!defined HAVE_PRAGMA_GCC_DIAGNOSTIC_PUSH_POP_INSIDEFUNC) && (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_TAUTOLOGICAL_COMPARE_BESIDEFUNC) # pragma GCC diagnostic ignored "-Wtautological-compare" #endif int setvar(const char *varname, const char *val) { unsigned int delay; if (sscanf(val, "%u", &delay) != 1) { return STAT_SET_UNKNOWN; } if (strcasecmp(varname, "ups.delay.start") == 0) { #if (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_PUSH_POP) && ( (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_TYPE_LIMITS) || (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_TAUTOLOGICAL_CONSTANT_OUT_OF_RANGE_COMPARE) || defined (HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_TAUTOLOGICAL_COMPARE) ) # pragma GCC diagnostic push #endif #ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_TYPE_LIMITS # pragma GCC diagnostic ignored "-Wtype-limits" #endif #ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_TAUTOLOGICAL_CONSTANT_OUT_OF_RANGE_COMPARE # pragma GCC diagnostic ignored "-Wtautological-constant-out-of-range-compare" #endif #ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_TAUTOLOGICAL_COMPARE # pragma GCC diagnostic ignored "-Wtautological-compare" #endif /* Older CLANG (e.g. clang-3.4) seems to not support the GCC pragmas above */ #ifdef __clang__ #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wtautological-compare" #pragma clang diagnostic ignored "-Wtautological-constant-out-of-range-compare" #endif delay = CLAMP(delay, 0, MAX_START_DELAY); #ifdef __clang__ #pragma clang diagnostic pop #endif #if (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_PUSH_POP) && ( (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_TYPE_LIMITS) || (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_TAUTOLOGICAL_CONSTANT_OUT_OF_RANGE_COMPARE) || defined (HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_TAUTOLOGICAL_COMPARE) ) # pragma GCC diagnostic pop #endif upsdebugx(1, "set 'WUDELAY': %u/%u", delay, ups.WakeUpDelay); ups.WakeUpDelay = delay ; dstate_setinfo("ups.delay.start", "%u", ups.WakeUpDelay); dstate_dataok(); return STAT_SET_HANDLED; } if (strcasecmp(varname, "ups.delay.shutdown") == 0) { #if (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_PUSH_POP) && ( (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_TYPE_LIMITS) || (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_TAUTOLOGICAL_CONSTANT_OUT_OF_RANGE_COMPARE) || defined (HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_TAUTOLOGICAL_COMPARE) ) # pragma GCC diagnostic push #endif #ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_TYPE_LIMITS # pragma GCC diagnostic ignored "-Wtype-limits" #endif #ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_TAUTOLOGICAL_CONSTANT_OUT_OF_RANGE_COMPARE # pragma GCC diagnostic ignored "-Wtautological-constant-out-of-range-compare" #endif #ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_TAUTOLOGICAL_COMPARE # pragma GCC diagnostic ignored "-Wtautological-compare" #endif /* Older CLANG (e.g. clang-3.4) seems to not support the GCC pragmas above */ #ifdef __clang__ #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wtautological-compare" #pragma clang diagnostic ignored "-Wtautological-constant-out-of-range-compare" #endif delay = CLAMP(delay, 0, MAX_SHUTDOWN_DELAY); #ifdef __clang__ #pragma clang diagnostic pop #endif #if (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_PUSH_POP) && ( (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_TYPE_LIMITS) || (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_TAUTOLOGICAL_CONSTANT_OUT_OF_RANGE_COMPARE) || defined (HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_TAUTOLOGICAL_COMPARE) ) # pragma GCC diagnostic pop #endif upsdebugx(1, "set 'SDDELAY': %u/%u", delay, ups.ShutdownDelay); ups.ShutdownDelay = delay; dstate_setinfo("ups.delay.shutdown", "%u", ups.ShutdownDelay); dstate_dataok(); return STAT_SET_HANDLED; } return STAT_SET_UNKNOWN; } #if (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_PUSH_POP_BESIDEFUNC) && (!defined HAVE_PRAGMA_GCC_DIAGNOSTIC_PUSH_POP_INSIDEFUNC) && ( (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_TYPE_LIMITS_BESIDEFUNC) || (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_TAUTOLOGICAL_CONSTANT_OUT_OF_RANGE_COMPARE_BESIDEFUNC) || defined (HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_TAUTOLOGICAL_COMPARE_BESIDEFUNC) ) # pragma GCC diagnostic pop #endif void upsdrv_initinfo(void) { /* Get vars from ups.conf */ if (getval("ups.delay.shutdown")) { int ipv = atoi(getval("ups.delay.shutdown")); ups.ShutdownDelay = (unsigned int) CLAMP(ipv, 0, MAX_SHUTDOWN_DELAY); } else { ups.ShutdownDelay = 120; /* Shutdown delay in seconds */ } if (getval("ups.delay.start")) { int ipv = atoi(getval("ups.delay.start")); ups.WakeUpDelay = (unsigned int) CLAMP(ipv, 0, MAX_START_DELAY); } else { ups.WakeUpDelay = 10; /* WakeUp delay in seconds */ } if (detect_hardware() == -1) { fatalx(EXIT_FAILURE, "Unable to detect a Microdowell's Enterprise UPS on port %s\nCheck the cable, port name and try again", device_path); } /* I set the correspondig UPS variables They were read in 'detect_hardware()' some other variables were set in 'detect_hardware()' */ dstate_setinfo("ups.model", "Enterprise N%s", ups.UpsModel+3) ; dstate_setinfo("ups.power.nominal", "%d", atoi(ups.UpsModel+3) * 100) ; dstate_setinfo("ups.realpower.nominal", "%d", atoi(ups.UpsModel+3) * 60) ; ups.ge_2kVA = 0 ; /* differentiate between 2 type of UPSs */ if (atoi(ups.UpsModel+3) >= 20) ups.ge_2kVA = 1 ; dstate_setinfo("ups.type", "online-interactive") ; dstate_setinfo("ups.serial", "%s", ups.SerialNumber) ; dstate_setinfo("ups.firmware", "%d.%d (%d)", ups.FW_MajorVersion, ups.FW_MinorVersion, ups.FW_SubVersion) ; dstate_setinfo("ups.firmware.aux", "%d.%d %d.%d", ups.HW_MajorVersion, ups.HW_MinorVersion, ups.BR_MajorVersion, ups.BR_MinorVersion) ; dstate_setinfo("ups.mfr", "Microdowell") ; dstate_setinfo("ups.mfr.date", "%04d/%02d/%02d", ups.YearOfProd, ups.MonthOfProd, ups.DayOfProd) ; dstate_setinfo("battery.packs", "%d", ups.BatteryNumber) ; /* Register the available variables. */ dstate_setinfo("ups.delay.start", "%d", ups.WakeUpDelay); dstate_setflags("ups.delay.start", ST_FLAG_RW | ST_FLAG_STRING); dstate_setaux("ups.delay.start", MAX_START_DELAY_LEN); dstate_setinfo("ups.delay.shutdown", "%d", ups.ShutdownDelay); dstate_setflags("ups.delay.shutdown", ST_FLAG_RW | ST_FLAG_STRING); dstate_setaux("ups.delay.shutdown", MAX_SHUTDOWN_DELAY_LEN); dstate_addcmd("load.on"); dstate_addcmd("load.off"); dstate_addcmd("shutdown.return"); dstate_addcmd("shutdown.stayoff"); /* Register the available instant commands. */ /* dstate_addcmd("test.battery.start"); dstate_addcmd("test.battery.stop"); dstate_addcmd("shutdown.stop"); dstate_addcmd("beeper.toggle"); */ /* set handlers */ upsh.instcmd = instcmd ; upsh.setvar = setvar; } void upsdrv_shutdown(void) { unsigned char OutBuff[20] ; unsigned char InpBuff[260] ; unsigned char *p ; unsigned char BatteryFlag=0 ; OutBuff[0] = CMD_GET_STATUS ; /* get UPS status */ if ((p = CmdSerial(OutBuff, LEN_GET_STATUS, InpBuff)) != NULL) { p += 3 ; /* 'p' points to received data */ status_init(); /* reset status flags */ /* store last UPS status */ ups.StatusUPS = (uint32_t)p[0] ; ups.StatusUPS |= ((uint32_t)p[1]<<8) ; ups.StatusUPS |= ((uint32_t)p[2]<<16) ; ups.StatusUPS |= ((uint32_t)p[3]<<24) ; ups.ShortStatus = (uint16_t)p[0] ; ups.ShortStatus |= ((uint16_t)p[1]<<8) ; upsdebugx(1, "ups.StatusUPS: %08" PRIX32, ups.StatusUPS); upsdebugx(1, "ups.ShortStatus: %04" PRIX16, ups.ShortStatus); /* on battery? */ if (p[0] & 0x01) BatteryFlag = 1 ; /* YES */ upsdebugx(3, "get 'Get Status': %s", PrintErr(ups.ErrCode)); } else { upsdebugx(1, "get 'Get Status': %s", PrintErr(ups.ErrCode)); /* upslogx(LOG_ERR, "get 'Get Status': %s", PrintErr(ups.ErrCode)); */ } /* Send SHUTDOWN command */ OutBuff[0] = CMD_SD_ONESHOT ; /* Send SHUTDOWN command */ OutBuff[1] = 0xFF ; /* shutdown on ALL ports */ /* is the UPS on battery? */ if (BatteryFlag) OutBuff[2] = 0x02 ; /* Type of shutdown (BATTERY MODE) */ else OutBuff[2] = 0x01 ; /* Type of shutdown (ONLINE) */ if (ups.ShutdownDelay < 6) ups.ShutdownDelay = 6 ; OutBuff[3] = (ups.ShutdownDelay >> 8) & 0xFF ; /* SDDELAY (MSB) Shutdown value (seconds) */ OutBuff[4] = (ups.ShutdownDelay & 0xFF) ; /* SDDELAY (LSB) */ OutBuff[5] = (ups.WakeUpDelay >> 16) & 0xFF ; /* WUDELAY (MSB) Wakeup value (seconds) */ OutBuff[6] = (ups.WakeUpDelay >> 8) & 0xFF ; /* WUDELAY (...) */ OutBuff[7] = (ups.WakeUpDelay & 0xFF ) ; /* WUDELAY (LSB) */ if ((p = CmdSerial(OutBuff, LEN_SD_ONESHOT, InpBuff)) != NULL) { upsdebugx(2, "Shutdown command(TYPE=%02x, SD=%u, WU=%u): %s", OutBuff[2], ups.ShutdownDelay, ups.WakeUpDelay, PrintErr(ups.ErrCode)); } else { /* command not sent: print error code */ upsdebugx(1, "Shutdown command(TYPE=%02x, SD=%u, WU=%u): %s", OutBuff[2], ups.ShutdownDelay, ups.WakeUpDelay, PrintErr(ups.ErrCode)); upslogx(LOG_ERR, "Shutdown command(SD=%u, WU=%u): %s", ups.ShutdownDelay, ups.WakeUpDelay, PrintErr(ups.ErrCode)); } } void upsdrv_help(void) { } /* list flags and values that you want to receive via -x */ void upsdrv_makevartable(void) { /* allow '-x xyzzy' */ /* addvar(VAR_FLAG, "xyzzy", "Enable xyzzy mode"); */ /* allow '-x foo=' */ addvar(VAR_VALUE, "ups.delay.shutdown", "Override shutdown delay (120s)"); addvar(VAR_VALUE, "ups.delay.start", "Override restart delay (10s)"); } void upsdrv_initups(void) { upsfd = ser_open(device_path) ; ser_set_speed(upsfd, device_path, B19200) ; /* need to clear RTS and DTR: otherwise with default cable, communication will be problematic It is the same as removing pin7 from cable (pin 7 is needed for Plug&Play compatibility) */ ser_set_dtr(upsfd, 0); ser_set_rts(upsfd, 0); usleep(10000) ; /* small delay (1/100 s)) */ } void upsdrv_cleanup(void) { /* free(dynamic_mem); */ ser_close(upsfd, device_path) ; } nut-2.8.1/drivers/powerpanel.h0000644000175000017500000000303614500336654013264 00000000000000/* * powerpanel.h - Model specific data/definitions for CyberPower text/binary * protocol UPSes * * Copyright (C) * 2007 Doug Reynolds * 2007-2008 Arjen de Korte * * 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 2 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, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef POWERPANEL_H #define POWERPANEL_H #define ENDCHAR '\r' #define IGNCHAR "" #define MAXTRIES 3 #define UPSDELAY 50000 #define SER_WAIT_SEC 0 #define SER_WAIT_USEC 250000 typedef struct { const char *version; /* TODO: Rename: this is a subdriver type: "text" or "binary" */ const char *versionString; /* TODO: Rename: this is the actual subdriver version */ int (*instcmd)(const char *cmdname, const char *extra); int (*setvar)(const char *varname, const char *val); ssize_t (*initups)(void); void (*initinfo)(void); int (*updateinfo)(void); } subdriver_t; #endif /* POWERPANEL_H */ nut-2.8.1/drivers/nutdrv_qx_mustek.h0000644000175000017500000000175214273170601014530 00000000000000/* nutdrv_qx_mustek.h - Subdriver for Mustek protocol based UPSes * * Copyright (C) * 2013 Daniele Pezzini * * 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 2 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, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #ifndef NUTDRV_QX_MUSTEK_H #define NUTDRV_QX_MUSTEK_H #include "nutdrv_qx.h" extern subdriver_t mustek_subdriver; #endif /* NUTDRV_QX_MUSTEK_H */ nut-2.8.1/drivers/eaton-pdu-nlogic-mib.c0000644000175000017500000077741714501607135015036 00000000000000/* eaton-pdu-nlogic-mib.c - subdriver to monitor eaton-pdu-nlogic SNMP devices with NUT * * Copyright (C) * 2011 - 2016 Arnaud Quette * 2022 Eaton (author: Arnaud Quette ) * * Note: this subdriver was initially generated as a "stub" by the * gen-snmp-subdriver script. It must be customized! * * 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 2 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, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "eaton-pdu-nlogic-mib.h" #define EATON_PDU_NLOGIC_MIB_VERSION "0.1" #define EATON_PDU_NLOGIC_SYSOID ".1.3.6.1.4.1.534.7.1" static info_lkp_t eaton_nlogic_unit_switchability_info[] = { { 1, "yes", NULL, NULL }, { 2, "no", NULL, NULL }, { 0, NULL, NULL, NULL } }; static info_lkp_t eaton_nlogic_outlet_status_info[] = { { 1, "off", NULL, NULL }, { 2, "on", NULL, NULL }, { 3, "pendingOff", NULL, NULL }, /* transitional status */ { 4, "pendingOn", NULL, NULL }, /* transitional status */ { 0, NULL, NULL, NULL } }; /* Note: same as marlin_outlet_type_info + i5-20R */ static info_lkp_t eaton_nlogic_outlet_type_info[] = { { 0, "unknown", NULL, NULL }, { 1, "iecC13", NULL, NULL }, { 2, "iecC19", NULL, NULL }, { 3, "i5-20R", NULL, NULL }, { 10, "uk", NULL, NULL }, { 11, "french", NULL, NULL }, { 12, "schuko", NULL, NULL }, { 20, "nema515", NULL, NULL }, { 21, "nema51520", NULL, NULL }, { 22, "nema520", NULL, NULL }, { 23, "nemaL520", NULL, NULL }, { 24, "nemaL530", NULL, NULL }, { 25, "nema615", NULL, NULL }, { 26, "nema620", NULL, NULL }, { 27, "nemaL620", NULL, NULL }, { 28, "nemaL630", NULL, NULL }, { 29, "nemaL715", NULL, NULL }, { 30, "rf203p277", NULL, NULL }, { 0, NULL, NULL, NULL } }; /* EATON_PDU_NLOGIC Snmp2NUT lookup table */ static snmp_info_t eaton_pdu_nlogic_mib[] = { /* Data format: * { info_type, info_flags, info_len, OID, dfl, flags, oid2info }, * * info_type: NUT INFO_ or CMD_ element name * info_flags: flags to set in addinfo * info_len: length of strings if ST_FLAG_STRING, multiplier otherwise * OID: SNMP OID or NULL * dfl: default value * flags: snmp-ups internal flags (FIXME: ...) * oid2info: lookup table between OID and NUT values */ /* standard MIB items; if the vendor MIB contains better OIDs for * this (e.g. with daisy-chain support), consider adding those here */ { "device.description", ST_FLAG_STRING | ST_FLAG_RW, SU_INFOSIZE, ".1.3.6.1.2.1.1.1.0", NULL, SU_FLAG_OK, NULL }, { "device.contact", ST_FLAG_STRING | ST_FLAG_RW, SU_INFOSIZE, ".1.3.6.1.2.1.1.4.0", NULL, SU_FLAG_OK, NULL }, { "device.location", ST_FLAG_STRING | ST_FLAG_RW, SU_INFOSIZE, ".1.3.6.1.2.1.1.6.0", NULL, SU_FLAG_OK, NULL }, /* Device collection */ /* pduManufacturer.1 = STRING: "EATON" */ { "device.mfr", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.534.7.1.1.2.1.4.1", "EATON", SU_FLAG_STATIC, NULL }, /* pduModel.1 = STRING: "200-240V, 24A, 5.0kVA, 50/60Hz" */ { "device.model", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.534.7.1.1.2.1.3.1", "Eaton ePDU", SU_FLAG_STATIC, NULL }, /* pduSerialNumber.1 = STRING: "WMEL0046" */ { "device.serial", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.534.7.1.1.2.1.8.1", NULL, SU_FLAG_STATIC, NULL }, { "device.type", ST_FLAG_STRING, SU_INFOSIZE, NULL, "pdu", SU_FLAG_STATIC | SU_FLAG_ABSENT | SU_FLAG_OK, NULL }, /* pduPartNumber.1 = STRING: "EMSV0001" */ { "device.part", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.534.7.1.1.2.1.7.1", NULL, SU_FLAG_STATIC | SU_FLAG_OK, NULL }, /* For daisychain, there is only 1 physical interface! */ /* pduMACAddress.1 = Hex-STRING: 43 38 2D 34 35 2D 34 34 2D 33 30 2D 39 34 2D 31 */ { "device.macaddr", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.534.7.1.1.2.1.14.1", "", SU_FLAG_STATIC, NULL }, /* Number of daisychained units is processed according to present units * in the chain with new G3 firmware (02.00.0051, since autumn 2017): * Take string "unitsPresent" (ex: "0,3,4,5"), and count the amount * of "," separators+1 using an inline function */ /* FIXME: inline func */ /* pduNumberPDU.0 = INTEGER: 1 */ { "device.count", 0, 1, ".1.3.6.1.4.1.534.7.1.1.1.0", "0", SU_FLAG_STATIC, NULL /* &marlin_device_count_info[0] */ /* devices_count */ }, /* FIXME: this entry should be SU_FLAG_SEMI_STATIC */ /* pduFirmwareVersion.1 = STRING: "1.0.6" */ { "device.firmware", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.534.7.1.1.2.1.5.1", "", SU_FLAG_OK, NULL }, /* pduFirmwareVersionTimeStamp.1 = Hex-STRING: 32 30 32 31 2F 30 35 2F 32 39 20 30 39 3A 30 36 */ /* { "unmapped.pduFirmwareVersionTimeStamp", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.534.7.1.1.2.1.6.1", NULL, SU_FLAG_OK, NULL }, */ /* pduIdentIndex.1 = INTEGER: 1 */ /* { "unmapped.pduIdentIndex", 0, 1, ".1.3.6.1.4.1.534.7.1.1.2.1.1.1", NULL, SU_FLAG_OK, NULL }, */ /* pduName.1 = "" */ /* FIXME: RFC device.name? */ { "device.name", ST_FLAG_STRING | ST_FLAG_RW, 63, ".1.3.6.1.4.1.534.7.1.1.2.1.2.1", NULL, SU_FLAG_OK, NULL }, /* pduStatus.1 = INTEGER: 4 */ /* { "unmapped.pduStatus", 0, 1, ".1.3.6.1.4.1.534.7.1.1.2.1.9.1", NULL, SU_FLAG_OK, NULL }, */ /* Input collection */ /* pduInputPhaseCount.1 = INTEGER: 1 */ { "input.phases", 0, 1, ".1.3.6.1.4.1.534.7.1.1.2.1.11.1", NULL, SU_FLAG_OK, NULL }, /* pduInputType.1 = INTEGER: 1 */ /* { "unmapped.pduInputType", 0, 1, ".1.3.6.1.4.1.534.7.1.2.1.1.1.1", NULL, SU_FLAG_OK, NULL }, */ /* pduInputFrequency.1 = INTEGER: 499 */ { "input.frequency", 0, 0.1, ".1.3.6.1.4.1.534.7.1.2.1.1.2.1", NULL, 0, NULL }, /* pduInputTotalCurrent.1 = INTEGER: 0 */ { "input.current", 0, 0.01, ".1.3.6.1.4.1.534.7.1.2.1.1.11.1", NULL, SU_FLAG_OK, NULL }, /* pduInputPhaseVoltage.1.1 = INTEGER: 2418 */ { "input.voltage", 0, 0.1, ".1.3.6.1.4.1.534.7.1.2.2.1.3.1.1", NULL, SU_FLAG_OK, NULL }, /* Outlet groups collection */ /* pduGroupCount.1 = INTEGER: 1 */ { "outlet.group.count", 0, 1, ".1.3.6.1.4.1.534.7.1.1.2.1.12.1", NULL, SU_FLAG_STATIC, NULL }, /* pduGroupVoltage.1.1 = INTEGER: 2418 */ { "outlet.group.%i.voltage", 0, 0.1, ".1.3.6.1.4.1.534.7.1.3.1.1.5.1.%i", NULL, SU_OUTLET_GROUP, NULL }, /* pduGroupCurrent.1.1 = INTEGER: 0 */ { "outlet.group.%i.current", 0, 1, ".1.3.6.1.4.1.534.7.1.3.1.1.12.1.%i", NULL, SU_OUTLET_GROUP, NULL }, /* Outlet collection */ /* pduOutletCount.1 = INTEGER: 6 */ { "outlet.count", 0, 1, ".1.3.6.1.4.1.534.7.1.1.2.1.13.1", NULL, SU_FLAG_OK, NULL }, /* pduControllable.1 = INTEGER: 1 */ { "outlet.switchable", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.534.7.1.1.2.1.10.1", "no", SU_FLAG_STATIC, &eaton_nlogic_unit_switchability_info[0] }, /* pduOutletControlSwitchable.1.1 = INTEGER: 2 */ { "outlet.%i.switchable", ST_FLAG_RW |ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.534.7.1.5.2.1.8.1.%i", "no", SU_OUTLET, &eaton_nlogic_unit_switchability_info[0] }, /* pduOutletControlStatus.1.1 = INTEGER: 2 */ { "outlet.%i.status", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.534.7.1.5.2.1.1.1.%i", NULL, SU_OUTLET, &eaton_nlogic_outlet_status_info[0] }, /* pduOutletName.1.1 = STRING: "OUTLET 1" */ { "outlet.%i.name", ST_FLAG_RW |ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.534.7.1.5.1.1.2.1.%i", NULL, SU_OUTLET, NULL }, /* pduOutletType.1.1 = INTEGER: 2 */ { "outlet.%i.type", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.534.7.1.5.1.1.3.1.%i", "unknown", SU_FLAG_STATIC | SU_OUTLET, &eaton_nlogic_outlet_type_info[0] }, /* pduOutletCurrentRating.1.1 = INTEGER: 1600 */ { "outlet.%i.current.nominal", 0, 0.01, ".1.3.6.1.4.1.534.7.1.5.1.1.4.1.%i", NULL, SU_OUTLET | SU_FLAG_NEGINVALID, NULL }, /* pduOutletCurrent.1.1 = INTEGER: 0 */ { "outlet.%i.current", 0, 0.01, ".1.3.6.1.4.1.534.7.1.5.1.1.5.1.%i", NULL, SU_OUTLET | SU_FLAG_NEGINVALID, NULL }, /* pduOutletCurrentPercentLoad.1.1 = INTEGER: 0 */ { "outlet.%i.load", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.11.1.%i", NULL, SU_OUTLET | SU_FLAG_NEGINVALID, NULL }, /* pduOutletVA.1.1 = INTEGER: 0 */ { "outlet.%i.power", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.12.1.%i", NULL, SU_OUTLET | SU_FLAG_NEGINVALID, NULL }, /* pduOutletWatts.1.1 = INTEGER: 0 */ { "outlet.%i.realpower", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.13.1.%i", NULL, SU_OUTLET | SU_FLAG_NEGINVALID, NULL }, /* instant commands. */ /* pduOutletControlCommand.1.1 = INTEGER: 2 */ { "outlet.%i.load.off", 0, 1, ".1.3.6.1.4.1.534.7.1.5.2.1.10.1.%i", "1", SU_TYPE_CMD | SU_OUTLET, NULL }, { "outlet.%i.load.on", 0, 1, ".1.3.6.1.4.1.534.7.1.5.2.1.10.1.%i", "2", SU_TYPE_CMD | SU_OUTLET, NULL }, { "outlet.%i.load.cycle", 0, 1, ".1.3.6.1.4.1.534.7.1.5.2.1.10.1.%i", "5", SU_TYPE_CMD | SU_OUTLET, NULL }, /* Per-outlet shutdown / startup delay (configuration point, not the timers) * (by default each output socket startup is delayed by its number in seconds) */ /* pduOutletControlShutoffDelay.1.1 = INTEGER: 0 */ { "outlet.%i.delay.shutdown", ST_FLAG_RW, 1, ".1.3.6.1.4.1.534.7.1.5.2.1.9.1.%i", NULL, SU_FLAG_NEGINVALID | SU_OUTLET, NULL }, /* pduOutletControlSequenceDelay.1.1 = INTEGER: 0 */ { "outlet.%i.delay.start", ST_FLAG_RW, 1, ".1.3.6.1.4.1.534.7.1.5.2.1.6.1.%i", NULL, SU_FLAG_NEGINVALID | SU_OUTLET, NULL }, /* FIXME: need RFC! */ /* pduOutletControlRebootOffTime.1.1 = INTEGER: 5 */ { "outlet.%i.delay.reboot", ST_FLAG_RW, 1, ".1.3.6.1.4.1.534.7.1.5.2.1.7.1.%i", NULL, SU_FLAG_NEGINVALID | SU_OUTLET, NULL }, #if 0 /* FIXME: how to deal with these? Delays are in 1 OID and command in another. These versions should take the delay, set the related OID (need the outlet index, so miss context!) and then call the command */ /* Delayed version, parameter is mandatory (so dfl is NULL)! */ { "outlet.%i.load.off.delay", 0, 1, ".1.3.6.1.4.1.534.7.1.5.2.1.10.1.%i", NULL, SU_TYPE_CMD | SU_OUTLET, NULL }, + set "outlet.%i.delay.shutdown" + set itself to delayedOff (3) // &eaton_nlogic_outlet_delayed_off_info[0] { "outlet.%i.load.on.delay", 0, 1, ".1.3.6.1.4.1.534.7.1.5.2.1.10.1.%i", NULL, SU_TYPE_CMD | SU_OUTLET, NULL }, + set "outlet.%i.delay.start" + set itself to delayedOn (4), // &eaton_nlogic_outlet_delayed_on_info[0] { "outlet.%i.load.cycle.delay", 0, 1, ".1.3.6.1.4.1.534.7.1.5.2.1.10.1.%i", NULL, SU_TYPE_CMD | SU_OUTLET, NULL }, + set "outlet.%i.delay.start" + set itself to delayedReboot (6), // &eaton_nlogic_outlet_delayed_reboot_info[0] #endif #if WITH_UNMAPPED_DATA_POINTS /* pduIPv4Address.1 = IpAddress: 192.168.1.55 */ { "unmapped.pduIPv4Address", 0, 1, ".1.3.6.1.4.1.534.7.1.1.2.1.15.1", NULL, SU_FLAG_OK, NULL }, /* pduIPv6Address.1 = STRING: "FE80::CA45:44FF:FE30:9414" */ { "unmapped.pduIPv6Address", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.534.7.1.1.2.1.16.1", NULL, SU_FLAG_OK, NULL }, /* pduConfigSsh.1 = INTEGER: 1 */ { "unmapped.pduConfigSsh", 0, 1, ".1.3.6.1.4.1.534.7.1.1.3.1.2.1", NULL, SU_FLAG_OK, NULL }, /* pduConfigFtps.1 = INTEGER: 1 */ { "unmapped.pduConfigFtps", 0, 1, ".1.3.6.1.4.1.534.7.1.1.3.1.3.1", NULL, SU_FLAG_OK, NULL }, /* pduConfigHttp.1 = INTEGER: 0 */ { "unmapped.pduConfigHttp", 0, 1, ".1.3.6.1.4.1.534.7.1.1.3.1.4.1", NULL, SU_FLAG_OK, NULL }, /* pduConfigHttps.1 = INTEGER: 1 */ { "unmapped.pduConfigHttps", 0, 1, ".1.3.6.1.4.1.534.7.1.1.3.1.5.1", NULL, SU_FLAG_OK, NULL }, /* pduConfigIPv4IPv6Switch.1 = INTEGER: 3 */ { "unmapped.pduConfigIPv4IPv6Switch", 0, 1, ".1.3.6.1.4.1.534.7.1.1.3.1.6.1", NULL, SU_FLAG_OK, NULL }, /* pduConfigRedfishAPI.1 = INTEGER: 0 */ { "unmapped.pduConfigRedfishAPI", 0, 1, ".1.3.6.1.4.1.534.7.1.1.3.1.7.1", NULL, SU_FLAG_OK, NULL }, /* pduConfigOledDispalyOrientation.1 = INTEGER: 1 */ { "unmapped.pduConfigOledDispalyOrientation", 0, 1, ".1.3.6.1.4.1.534.7.1.1.3.1.8.1", NULL, SU_FLAG_OK, NULL }, /* pduConfigEnergyReset.1 = INTEGER: 1 */ { "unmapped.pduConfigEnergyReset", 0, 1, ".1.3.6.1.4.1.534.7.1.1.3.1.9.1", NULL, SU_FLAG_OK, NULL }, /* pduConfigNetworkManagementCardReset.1 = INTEGER: 0 */ { "unmapped.pduConfigNetworkManagementCardReset", 0, 1, ".1.3.6.1.4.1.534.7.1.1.3.1.10.1", NULL, SU_FLAG_OK, NULL }, /* pduConfigDaisyChainStatus.1 = INTEGER: 0 */ { "unmapped.pduConfigDaisyChainStatus", 0, 1, ".1.3.6.1.4.1.534.7.1.1.3.1.11.1", NULL, SU_FLAG_OK, NULL }, /* pduInputFrequencyStatus.1 = INTEGER: 1 */ { "unmapped.pduInputFrequencyStatus", 0, 1, ".1.3.6.1.4.1.534.7.1.2.1.1.3.1", NULL, SU_FLAG_OK, NULL }, /* pduInputPowerVA.1 = INTEGER: 0 */ { "unmapped.pduInputPowerVA", 0, 1, ".1.3.6.1.4.1.534.7.1.2.1.1.4.1", NULL, SU_FLAG_OK, NULL }, /* pduInputPowerWatts.1 = INTEGER: 0 */ { "unmapped.pduInputPowerWatts", 0, 1, ".1.3.6.1.4.1.534.7.1.2.1.1.5.1", NULL, SU_FLAG_OK, NULL }, /* pduInputTotalEnergy.1 = INTEGER: 0 */ { "unmapped.pduInputTotalEnergy", 0, 1, ".1.3.6.1.4.1.534.7.1.2.1.1.6.1", NULL, SU_FLAG_OK, NULL }, /* pduInputPowerWattHourTimer.1 = Hex-STRING: 32 30 32 31 2F 30 35 2F 32 39 20 30 39 3A 30 36 */ { "unmapped.pduInputPowerWattHourTimer", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.534.7.1.2.1.1.7.1", NULL, SU_FLAG_OK, NULL }, /* pduInputResettableEnergy.1 = INTEGER: 0 */ { "unmapped.pduInputResettableEnergy", 0, 1, ".1.3.6.1.4.1.534.7.1.2.1.1.8.1", NULL, SU_FLAG_OK, NULL }, /* pduInputPowerFactor.1 = INTEGER: 0 */ { "unmapped.pduInputPowerFactor", 0, 1, ".1.3.6.1.4.1.534.7.1.2.1.1.9.1", NULL, SU_FLAG_OK, NULL }, /* pduInputPowerVAR.1 = INTEGER: 0 */ { "unmapped.pduInputPowerVAR", 0, 1, ".1.3.6.1.4.1.534.7.1.2.1.1.10.1", NULL, SU_FLAG_OK, NULL }, /* pduInputPhaseIndex.1.1 = INTEGER: 1 */ { "unmapped.pduInputPhaseIndex", 0, 1, ".1.3.6.1.4.1.534.7.1.2.2.1.1.1.1", NULL, SU_FLAG_OK, NULL }, /* pduInputPhaseIndex.1.2 = INTEGER: 0 */ { "unmapped.pduInputPhaseIndex", 0, 1, ".1.3.6.1.4.1.534.7.1.2.2.1.1.1.2", NULL, SU_FLAG_OK, NULL }, /* pduInputPhaseIndex.1.3 = INTEGER: 0 */ { "unmapped.pduInputPhaseIndex", 0, 1, ".1.3.6.1.4.1.534.7.1.2.2.1.1.1.3", NULL, SU_FLAG_OK, NULL }, /* pduInputPhaseVoltageMeasType.1.1 = INTEGER: 1 */ { "unmapped.pduInputPhaseVoltageMeasType", 0, 1, ".1.3.6.1.4.1.534.7.1.2.2.1.2.1.1", NULL, SU_FLAG_OK, NULL }, /* pduInputPhaseVoltageMeasType.1.2 = INTEGER: 0 */ { "unmapped.pduInputPhaseVoltageMeasType", 0, 1, ".1.3.6.1.4.1.534.7.1.2.2.1.2.1.2", NULL, SU_FLAG_OK, NULL }, /* pduInputPhaseVoltageMeasType.1.3 = INTEGER: 0 */ { "unmapped.pduInputPhaseVoltageMeasType", 0, 1, ".1.3.6.1.4.1.534.7.1.2.2.1.2.1.3", NULL, SU_FLAG_OK, NULL }, /* pduInputPhaseVoltage.1.2 = INTEGER: 0 */ { "unmapped.pduInputPhaseVoltage", 0, 1, ".1.3.6.1.4.1.534.7.1.2.2.1.3.1.2", NULL, SU_FLAG_OK, NULL }, /* pduInputPhaseVoltage.1.3 = INTEGER: 0 */ { "unmapped.pduInputPhaseVoltage", 0, 1, ".1.3.6.1.4.1.534.7.1.2.2.1.3.1.3", NULL, SU_FLAG_OK, NULL }, /* pduInputPhaseVoltageThStatus.1.1 = INTEGER: 5 */ { "unmapped.pduInputPhaseVoltageThStatus", 0, 1, ".1.3.6.1.4.1.534.7.1.2.2.1.4.1.1", NULL, SU_FLAG_OK, NULL }, /* pduInputPhaseVoltageThStatus.1.2 = INTEGER: 0 */ { "unmapped.pduInputPhaseVoltageThStatus", 0, 1, ".1.3.6.1.4.1.534.7.1.2.2.1.4.1.2", NULL, SU_FLAG_OK, NULL }, /* pduInputPhaseVoltageThStatus.1.3 = INTEGER: 0 */ { "unmapped.pduInputPhaseVoltageThStatus", 0, 1, ".1.3.6.1.4.1.534.7.1.2.2.1.4.1.3", NULL, SU_FLAG_OK, NULL }, /* pduInputPhaseVoltageThLowerWarning.1.1 = INTEGER: 1900 */ { "unmapped.pduInputPhaseVoltageThLowerWarning", 0, 1, ".1.3.6.1.4.1.534.7.1.2.2.1.5.1.1", NULL, SU_FLAG_OK, NULL }, /* pduInputPhaseVoltageThLowerWarning.1.2 = INTEGER: 0 */ { "unmapped.pduInputPhaseVoltageThLowerWarning", 0, 1, ".1.3.6.1.4.1.534.7.1.2.2.1.5.1.2", NULL, SU_FLAG_OK, NULL }, /* pduInputPhaseVoltageThLowerWarning.1.3 = INTEGER: 0 */ { "unmapped.pduInputPhaseVoltageThLowerWarning", 0, 1, ".1.3.6.1.4.1.534.7.1.2.2.1.5.1.3", NULL, SU_FLAG_OK, NULL }, /* pduInputPhaseVoltageThLowerCritical.1.1 = INTEGER: 1800 */ { "unmapped.pduInputPhaseVoltageThLowerCritical", 0, 1, ".1.3.6.1.4.1.534.7.1.2.2.1.6.1.1", NULL, SU_FLAG_OK, NULL }, /* pduInputPhaseVoltageThLowerCritical.1.2 = INTEGER: 0 */ { "unmapped.pduInputPhaseVoltageThLowerCritical", 0, 1, ".1.3.6.1.4.1.534.7.1.2.2.1.6.1.2", NULL, SU_FLAG_OK, NULL }, /* pduInputPhaseVoltageThLowerCritical.1.3 = INTEGER: 0 */ { "unmapped.pduInputPhaseVoltageThLowerCritical", 0, 1, ".1.3.6.1.4.1.534.7.1.2.2.1.6.1.3", NULL, SU_FLAG_OK, NULL }, /* pduInputPhaseVoltageThUpperWarning.1.1 = INTEGER: 2150 */ { "unmapped.pduInputPhaseVoltageThUpperWarning", 0, 1, ".1.3.6.1.4.1.534.7.1.2.2.1.7.1.1", NULL, SU_FLAG_OK, NULL }, /* pduInputPhaseVoltageThUpperWarning.1.2 = INTEGER: 0 */ { "unmapped.pduInputPhaseVoltageThUpperWarning", 0, 1, ".1.3.6.1.4.1.534.7.1.2.2.1.7.1.2", NULL, SU_FLAG_OK, NULL }, /* pduInputPhaseVoltageThUpperWarning.1.3 = INTEGER: 0 */ { "unmapped.pduInputPhaseVoltageThUpperWarning", 0, 1, ".1.3.6.1.4.1.534.7.1.2.2.1.7.1.3", NULL, SU_FLAG_OK, NULL }, /* pduInputPhaseVoltageThUpperCritical.1.1 = INTEGER: 2250 */ { "unmapped.pduInputPhaseVoltageThUpperCritical", 0, 1, ".1.3.6.1.4.1.534.7.1.2.2.1.8.1.1", NULL, SU_FLAG_OK, NULL }, /* pduInputPhaseVoltageThUpperCritical.1.2 = INTEGER: 0 */ { "unmapped.pduInputPhaseVoltageThUpperCritical", 0, 1, ".1.3.6.1.4.1.534.7.1.2.2.1.8.1.2", NULL, SU_FLAG_OK, NULL }, /* pduInputPhaseVoltageThUpperCritical.1.3 = INTEGER: 0 */ { "unmapped.pduInputPhaseVoltageThUpperCritical", 0, 1, ".1.3.6.1.4.1.534.7.1.2.2.1.8.1.3", NULL, SU_FLAG_OK, NULL }, /* pduInputPhaseCurrentMeasType.1.1 = INTEGER: 1 */ { "unmapped.pduInputPhaseCurrentMeasType", 0, 1, ".1.3.6.1.4.1.534.7.1.2.2.1.9.1.1", NULL, SU_FLAG_OK, NULL }, /* pduInputPhaseCurrentMeasType.1.2 = INTEGER: 0 */ { "unmapped.pduInputPhaseCurrentMeasType", 0, 1, ".1.3.6.1.4.1.534.7.1.2.2.1.9.1.2", NULL, SU_FLAG_OK, NULL }, /* pduInputPhaseCurrentMeasType.1.3 = INTEGER: 0 */ { "unmapped.pduInputPhaseCurrentMeasType", 0, 1, ".1.3.6.1.4.1.534.7.1.2.2.1.9.1.3", NULL, SU_FLAG_OK, NULL }, /* pduInputPhaseCurrentRating.1.1 = INTEGER: 2400 */ { "unmapped.pduInputPhaseCurrentRating", 0, 1, ".1.3.6.1.4.1.534.7.1.2.2.1.10.1.1", NULL, SU_FLAG_OK, NULL }, /* pduInputPhaseCurrentRating.1.2 = INTEGER: 2400 */ { "unmapped.pduInputPhaseCurrentRating", 0, 1, ".1.3.6.1.4.1.534.7.1.2.2.1.10.1.2", NULL, SU_FLAG_OK, NULL }, /* pduInputPhaseCurrentRating.1.3 = INTEGER: 2400 */ { "unmapped.pduInputPhaseCurrentRating", 0, 1, ".1.3.6.1.4.1.534.7.1.2.2.1.10.1.3", NULL, SU_FLAG_OK, NULL }, /* pduInputPhaseCurrent.1.1 = INTEGER: 0 */ { "unmapped.pduInputPhaseCurrent", 0, 1, ".1.3.6.1.4.1.534.7.1.2.2.1.11.1.1", NULL, SU_FLAG_OK, NULL }, /* pduInputPhaseCurrent.1.2 = INTEGER: 0 */ { "unmapped.pduInputPhaseCurrent", 0, 1, ".1.3.6.1.4.1.534.7.1.2.2.1.11.1.2", NULL, SU_FLAG_OK, NULL }, /* pduInputPhaseCurrent.1.3 = INTEGER: 0 */ { "unmapped.pduInputPhaseCurrent", 0, 1, ".1.3.6.1.4.1.534.7.1.2.2.1.11.1.3", NULL, SU_FLAG_OK, NULL }, /* pduInputPhaseCurrentThStatus.1.1 = INTEGER: 1 */ { "unmapped.pduInputPhaseCurrentThStatus", 0, 1, ".1.3.6.1.4.1.534.7.1.2.2.1.12.1.1", NULL, SU_FLAG_OK, NULL }, /* pduInputPhaseCurrentThStatus.1.2 = INTEGER: 0 */ { "unmapped.pduInputPhaseCurrentThStatus", 0, 1, ".1.3.6.1.4.1.534.7.1.2.2.1.12.1.2", NULL, SU_FLAG_OK, NULL }, /* pduInputPhaseCurrentThStatus.1.3 = INTEGER: 0 */ { "unmapped.pduInputPhaseCurrentThStatus", 0, 1, ".1.3.6.1.4.1.534.7.1.2.2.1.12.1.3", NULL, SU_FLAG_OK, NULL }, /* pduInputPhaseCurrentThLowerWarning.1.1 = INTEGER: 0 */ { "unmapped.pduInputPhaseCurrentThLowerWarning", 0, 1, ".1.3.6.1.4.1.534.7.1.2.2.1.13.1.1", NULL, SU_FLAG_OK, NULL }, /* pduInputPhaseCurrentThLowerWarning.1.2 = INTEGER: 0 */ { "unmapped.pduInputPhaseCurrentThLowerWarning", 0, 1, ".1.3.6.1.4.1.534.7.1.2.2.1.13.1.2", NULL, SU_FLAG_OK, NULL }, /* pduInputPhaseCurrentThLowerWarning.1.3 = INTEGER: 0 */ { "unmapped.pduInputPhaseCurrentThLowerWarning", 0, 1, ".1.3.6.1.4.1.534.7.1.2.2.1.13.1.3", NULL, SU_FLAG_OK, NULL }, /* pduInputPhaseCurrentThLowerCritical.1.1 = INTEGER: 0 */ { "unmapped.pduInputPhaseCurrentThLowerCritical", 0, 1, ".1.3.6.1.4.1.534.7.1.2.2.1.14.1.1", NULL, SU_FLAG_OK, NULL }, /* pduInputPhaseCurrentThLowerCritical.1.2 = INTEGER: 0 */ { "unmapped.pduInputPhaseCurrentThLowerCritical", 0, 1, ".1.3.6.1.4.1.534.7.1.2.2.1.14.1.2", NULL, SU_FLAG_OK, NULL }, /* pduInputPhaseCurrentThLowerCritical.1.3 = INTEGER: 0 */ { "unmapped.pduInputPhaseCurrentThLowerCritical", 0, 1, ".1.3.6.1.4.1.534.7.1.2.2.1.14.1.3", NULL, SU_FLAG_OK, NULL }, /* pduInputPhaseCurrentThUpperWarning.1.1 = INTEGER: 2100 */ { "unmapped.pduInputPhaseCurrentThUpperWarning", 0, 1, ".1.3.6.1.4.1.534.7.1.2.2.1.15.1.1", NULL, SU_FLAG_OK, NULL }, /* pduInputPhaseCurrentThUpperWarning.1.2 = INTEGER: 0 */ { "unmapped.pduInputPhaseCurrentThUpperWarning", 0, 1, ".1.3.6.1.4.1.534.7.1.2.2.1.15.1.2", NULL, SU_FLAG_OK, NULL }, /* pduInputPhaseCurrentThUpperWarning.1.3 = INTEGER: 0 */ { "unmapped.pduInputPhaseCurrentThUpperWarning", 0, 1, ".1.3.6.1.4.1.534.7.1.2.2.1.15.1.3", NULL, SU_FLAG_OK, NULL }, /* pduInputPhaseCurrentThUpperCritical.1.1 = INTEGER: 2400 */ { "unmapped.pduInputPhaseCurrentThUpperCritical", 0, 1, ".1.3.6.1.4.1.534.7.1.2.2.1.16.1.1", NULL, SU_FLAG_OK, NULL }, /* pduInputPhaseCurrentThUpperCritical.1.2 = INTEGER: 0 */ { "unmapped.pduInputPhaseCurrentThUpperCritical", 0, 1, ".1.3.6.1.4.1.534.7.1.2.2.1.16.1.2", NULL, SU_FLAG_OK, NULL }, /* pduInputPhaseCurrentThUpperCritical.1.3 = INTEGER: 0 */ { "unmapped.pduInputPhaseCurrentThUpperCritical", 0, 1, ".1.3.6.1.4.1.534.7.1.2.2.1.16.1.3", NULL, SU_FLAG_OK, NULL }, /* pduInputPhaseCurrentPercentLoad.1.1 = INTEGER: 0 */ { "unmapped.pduInputPhaseCurrentPercentLoad", 0, 1, ".1.3.6.1.4.1.534.7.1.2.2.1.17.1.1", NULL, SU_FLAG_OK, NULL }, /* pduInputPhaseCurrentPercentLoad.1.2 = INTEGER: 0 */ { "unmapped.pduInputPhaseCurrentPercentLoad", 0, 1, ".1.3.6.1.4.1.534.7.1.2.2.1.17.1.2", NULL, SU_FLAG_OK, NULL }, /* pduInputPhaseCurrentPercentLoad.1.3 = INTEGER: 0 */ { "unmapped.pduInputPhaseCurrentPercentLoad", 0, 1, ".1.3.6.1.4.1.534.7.1.2.2.1.17.1.3", NULL, SU_FLAG_OK, NULL }, /* pduInputPhasePowerMeasType.1.1 = INTEGER: 1 */ { "unmapped.pduInputPhasePowerMeasType", 0, 1, ".1.3.6.1.4.1.534.7.1.2.2.1.18.1.1", NULL, SU_FLAG_OK, NULL }, /* pduInputPhasePowerMeasType.1.2 = INTEGER: 0 */ { "unmapped.pduInputPhasePowerMeasType", 0, 1, ".1.3.6.1.4.1.534.7.1.2.2.1.18.1.2", NULL, SU_FLAG_OK, NULL }, /* pduInputPhasePowerMeasType.1.3 = INTEGER: 0 */ { "unmapped.pduInputPhasePowerMeasType", 0, 1, ".1.3.6.1.4.1.534.7.1.2.2.1.18.1.3", NULL, SU_FLAG_OK, NULL }, /* pduInputPhasePowerVA.1.1 = INTEGER: 0 */ { "unmapped.pduInputPhasePowerVA", 0, 1, ".1.3.6.1.4.1.534.7.1.2.2.1.19.1.1", NULL, SU_FLAG_OK, NULL }, /* pduInputPhasePowerVA.1.2 = INTEGER: 0 */ { "unmapped.pduInputPhasePowerVA", 0, 1, ".1.3.6.1.4.1.534.7.1.2.2.1.19.1.2", NULL, SU_FLAG_OK, NULL }, /* pduInputPhasePowerVA.1.3 = INTEGER: 0 */ { "unmapped.pduInputPhasePowerVA", 0, 1, ".1.3.6.1.4.1.534.7.1.2.2.1.19.1.3", NULL, SU_FLAG_OK, NULL }, /* pduInputPhasePowerWatts.1.1 = INTEGER: 0 */ { "unmapped.pduInputPhasePowerWatts", 0, 1, ".1.3.6.1.4.1.534.7.1.2.2.1.20.1.1", NULL, SU_FLAG_OK, NULL }, /* pduInputPhasePowerWatts.1.2 = INTEGER: 0 */ { "unmapped.pduInputPhasePowerWatts", 0, 1, ".1.3.6.1.4.1.534.7.1.2.2.1.20.1.2", NULL, SU_FLAG_OK, NULL }, /* pduInputPhasePowerWatts.1.3 = INTEGER: 0 */ { "unmapped.pduInputPhasePowerWatts", 0, 1, ".1.3.6.1.4.1.534.7.1.2.2.1.20.1.3", NULL, SU_FLAG_OK, NULL }, /* pduInputPhasePowerWattHour.1.1 = INTEGER: 30 */ { "unmapped.pduInputPhasePowerWattHour", 0, 1, ".1.3.6.1.4.1.534.7.1.2.2.1.21.1.1", NULL, SU_FLAG_OK, NULL }, /* pduInputPhasePowerWattHour.1.2 = INTEGER: 0 */ { "unmapped.pduInputPhasePowerWattHour", 0, 1, ".1.3.6.1.4.1.534.7.1.2.2.1.21.1.2", NULL, SU_FLAG_OK, NULL }, /* pduInputPhasePowerWattHour.1.3 = INTEGER: 0 */ { "unmapped.pduInputPhasePowerWattHour", 0, 1, ".1.3.6.1.4.1.534.7.1.2.2.1.21.1.3", NULL, SU_FLAG_OK, NULL }, /* pduInputPhasePowerWattHourTimer.1.1 = Hex-STRING: 32 30 32 31 2F 30 35 2F 32 39 20 30 39 3A 30 36 */ { "unmapped.pduInputPhasePowerWattHourTimer", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.534.7.1.2.2.1.22.1.1", NULL, SU_FLAG_OK, NULL }, /* pduInputPhasePowerWattHourTimer.1.2 = Hex-STRING: 32 30 32 31 2F 30 35 2F 32 39 20 30 39 3A 30 36 */ { "unmapped.pduInputPhasePowerWattHourTimer", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.534.7.1.2.2.1.22.1.2", NULL, SU_FLAG_OK, NULL }, /* pduInputPhasePowerWattHourTimer.1.3 = Hex-STRING: 32 30 32 31 2F 30 35 2F 32 39 20 30 39 3A 30 36 */ { "unmapped.pduInputPhasePowerWattHourTimer", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.534.7.1.2.2.1.22.1.3", NULL, SU_FLAG_OK, NULL }, /* pduInputPhasePowerFactor.1.1 = INTEGER: 0 */ { "unmapped.pduInputPhasePowerFactor", 0, 1, ".1.3.6.1.4.1.534.7.1.2.2.1.23.1.1", NULL, SU_FLAG_OK, NULL }, /* pduInputPhasePowerFactor.1.2 = INTEGER: 0 */ { "unmapped.pduInputPhasePowerFactor", 0, 1, ".1.3.6.1.4.1.534.7.1.2.2.1.23.1.2", NULL, SU_FLAG_OK, NULL }, /* pduInputPhasePowerFactor.1.3 = INTEGER: 0 */ { "unmapped.pduInputPhasePowerFactor", 0, 1, ".1.3.6.1.4.1.534.7.1.2.2.1.23.1.3", NULL, SU_FLAG_OK, NULL }, /* pduInputPhasePowerVAR.1.1 = INTEGER: 0 */ { "unmapped.pduInputPhasePowerVAR", 0, 1, ".1.3.6.1.4.1.534.7.1.2.2.1.24.1.1", NULL, SU_FLAG_OK, NULL }, /* pduInputPhasePowerVAR.1.2 = INTEGER: 0 */ { "unmapped.pduInputPhasePowerVAR", 0, 1, ".1.3.6.1.4.1.534.7.1.2.2.1.24.1.2", NULL, SU_FLAG_OK, NULL }, /* pduInputPhasePowerVAR.1.3 = INTEGER: 0 */ { "unmapped.pduInputPhasePowerVAR", 0, 1, ".1.3.6.1.4.1.534.7.1.2.2.1.24.1.3", NULL, SU_FLAG_OK, NULL }, /* pduInputPhaseVoltageThResetThld.1.1 = INTEGER: 20 */ { "unmapped.pduInputPhaseVoltageThResetThld", 0, 1, ".1.3.6.1.4.1.534.7.1.2.2.1.25.1.1", NULL, SU_FLAG_OK, NULL }, /* pduInputPhaseVoltageThResetThld.1.2 = INTEGER: 0 */ { "unmapped.pduInputPhaseVoltageThResetThld", 0, 1, ".1.3.6.1.4.1.534.7.1.2.2.1.25.1.2", NULL, SU_FLAG_OK, NULL }, /* pduInputPhaseVoltageThResetThld.1.3 = INTEGER: 0 */ { "unmapped.pduInputPhaseVoltageThResetThld", 0, 1, ".1.3.6.1.4.1.534.7.1.2.2.1.25.1.3", NULL, SU_FLAG_OK, NULL }, /* pduInputPhaseVoltageThChangeDelay.1.1 = INTEGER: 0 */ { "unmapped.pduInputPhaseVoltageThChangeDelay", 0, 1, ".1.3.6.1.4.1.534.7.1.2.2.1.26.1.1", NULL, SU_FLAG_OK, NULL }, /* pduInputPhaseVoltageThChangeDelay.1.2 = INTEGER: 0 */ { "unmapped.pduInputPhaseVoltageThChangeDelay", 0, 1, ".1.3.6.1.4.1.534.7.1.2.2.1.26.1.2", NULL, SU_FLAG_OK, NULL }, /* pduInputPhaseVoltageThChangeDelay.1.3 = INTEGER: 0 */ { "unmapped.pduInputPhaseVoltageThChangeDelay", 0, 1, ".1.3.6.1.4.1.534.7.1.2.2.1.26.1.3", NULL, SU_FLAG_OK, NULL }, /* pduInputPhaseVoltageThCtrl.1.1 = INTEGER: 0 */ { "unmapped.pduInputPhaseVoltageThCtrl", 0, 1, ".1.3.6.1.4.1.534.7.1.2.2.1.27.1.1", NULL, SU_FLAG_OK, NULL }, /* pduInputPhaseVoltageThCtrl.1.2 = INTEGER: 0 */ { "unmapped.pduInputPhaseVoltageThCtrl", 0, 1, ".1.3.6.1.4.1.534.7.1.2.2.1.27.1.2", NULL, SU_FLAG_OK, NULL }, /* pduInputPhaseVoltageThCtrl.1.3 = INTEGER: 0 */ { "unmapped.pduInputPhaseVoltageThCtrl", 0, 1, ".1.3.6.1.4.1.534.7.1.2.2.1.27.1.3", NULL, SU_FLAG_OK, NULL }, /* pduInputPhaseCurrentThResetThld.1.1 = INTEGER: 100 */ { "unmapped.pduInputPhaseCurrentThResetThld", 0, 1, ".1.3.6.1.4.1.534.7.1.2.2.1.28.1.1", NULL, SU_FLAG_OK, NULL }, /* pduInputPhaseCurrentThResetThld.1.2 = INTEGER: 0 */ { "unmapped.pduInputPhaseCurrentThResetThld", 0, 1, ".1.3.6.1.4.1.534.7.1.2.2.1.28.1.2", NULL, SU_FLAG_OK, NULL }, /* pduInputPhaseCurrentThResetThld.1.3 = INTEGER: 0 */ { "unmapped.pduInputPhaseCurrentThResetThld", 0, 1, ".1.3.6.1.4.1.534.7.1.2.2.1.28.1.3", NULL, SU_FLAG_OK, NULL }, /* pduInputPhaseCurrentThChangeDelay.1.1 = INTEGER: 0 */ { "unmapped.pduInputPhaseCurrentThChangeDelay", 0, 1, ".1.3.6.1.4.1.534.7.1.2.2.1.29.1.1", NULL, SU_FLAG_OK, NULL }, /* pduInputPhaseCurrentThChangeDelay.1.2 = INTEGER: 0 */ { "unmapped.pduInputPhaseCurrentThChangeDelay", 0, 1, ".1.3.6.1.4.1.534.7.1.2.2.1.29.1.2", NULL, SU_FLAG_OK, NULL }, /* pduInputPhaseCurrentThChangeDelay.1.3 = INTEGER: 0 */ { "unmapped.pduInputPhaseCurrentThChangeDelay", 0, 1, ".1.3.6.1.4.1.534.7.1.2.2.1.29.1.3", NULL, SU_FLAG_OK, NULL }, /* pduInputPhaseCurrentThCtrl.1.1 = INTEGER: 12 */ { "unmapped.pduInputPhaseCurrentThCtrl", 0, 1, ".1.3.6.1.4.1.534.7.1.2.2.1.30.1.1", NULL, SU_FLAG_OK, NULL }, /* pduInputPhaseCurrentThCtrl.1.2 = INTEGER: 0 */ { "unmapped.pduInputPhaseCurrentThCtrl", 0, 1, ".1.3.6.1.4.1.534.7.1.2.2.1.30.1.2", NULL, SU_FLAG_OK, NULL }, /* pduInputPhaseCurrentThCtrl.1.3 = INTEGER: 0 */ { "unmapped.pduInputPhaseCurrentThCtrl", 0, 1, ".1.3.6.1.4.1.534.7.1.2.2.1.30.1.3", NULL, SU_FLAG_OK, NULL }, /* pduInputPowerThresholdThLowerWarning.1 = INTEGER: 0 */ { "unmapped.pduInputPowerThresholdThLowerWarning", 0, 1, ".1.3.6.1.4.1.534.7.1.2.2.1.31.1", NULL, SU_FLAG_OK, NULL }, /* pduInputPowerThresholdThLowerCritical.1 = INTEGER: 0 */ { "unmapped.pduInputPowerThresholdThLowerCritical", 0, 1, ".1.3.6.1.4.1.534.7.1.2.2.1.32.1", NULL, SU_FLAG_OK, NULL }, /* pduInputPowerThresholdThUpperWarning.1 = INTEGER: 0 */ { "unmapped.pduInputPowerThresholdThUpperWarning", 0, 1, ".1.3.6.1.4.1.534.7.1.2.2.1.33.1", NULL, SU_FLAG_OK, NULL }, /* pduInputPowerThresholdThUpperCritical.1 = INTEGER: 0 */ { "unmapped.pduInputPowerThresholdThUpperCritical", 0, 1, ".1.3.6.1.4.1.534.7.1.2.2.1.34.1", NULL, SU_FLAG_OK, NULL }, /* pduInputPowerThresholdThResetThld.1 = INTEGER: 0 */ { "unmapped.pduInputPowerThresholdThResetThld", 0, 1, ".1.3.6.1.4.1.534.7.1.2.2.1.35.1", NULL, SU_FLAG_OK, NULL }, /* pduInputPowerThresholdThChangeDelay.1 = INTEGER: 0 */ { "unmapped.pduInputPowerThresholdThChangeDelay", 0, 1, ".1.3.6.1.4.1.534.7.1.2.2.1.36.1", NULL, SU_FLAG_OK, NULL }, /* pduInputPowerThresholdThCtrl.1 = INTEGER: 15 */ { "unmapped.pduInputPowerThresholdThCtrl", 0, 1, ".1.3.6.1.4.1.534.7.1.2.2.1.37.1", NULL, SU_FLAG_OK, NULL }, /* pduInputEnergyThresholdThUpperWarning.1 = INTEGER: 2147483 */ { "unmapped.pduInputEnergyThresholdThUpperWarning", 0, 1, ".1.3.6.1.4.1.534.7.1.2.2.1.38.1", NULL, SU_FLAG_OK, NULL }, /* pduInputEnergyThresholdThUpperCritical.1 = INTEGER: 2147483 */ { "unmapped.pduInputEnergyThresholdThUpperCritical", 0, 1, ".1.3.6.1.4.1.534.7.1.2.2.1.39.1", NULL, SU_FLAG_OK, NULL }, /* pduInputEnergyThresholdThResetThld.1 = INTEGER: 0 */ { "unmapped.pduInputEnergyThresholdThResetThld", 0, 1, ".1.3.6.1.4.1.534.7.1.2.2.1.40.1", NULL, SU_FLAG_OK, NULL }, /* pduInputEnergyThresholdThChangeDelay.1 = INTEGER: 0 */ { "unmapped.pduInputEnergyThresholdThChangeDelay", 0, 1, ".1.3.6.1.4.1.534.7.1.2.2.1.41.1", NULL, SU_FLAG_OK, NULL }, /* pduInputEnergyThresholdThCtrl.1 = INTEGER: 3 */ { "unmapped.pduInputEnergyThresholdThCtrl", 0, 1, ".1.3.6.1.4.1.534.7.1.2.2.1.42.1", NULL, SU_FLAG_OK, NULL }, /* pduGroupIndex.1.1 = INTEGER: 1 */ { "unmapped.pduGroupIndex", 0, 1, ".1.3.6.1.4.1.534.7.1.3.1.1.1.1.1", NULL, SU_FLAG_OK, NULL }, /* pduGroupIndex.1.2 = INTEGER: 2 */ { "unmapped.pduGroupIndex", 0, 1, ".1.3.6.1.4.1.534.7.1.3.1.1.1.1.2", NULL, SU_FLAG_OK, NULL }, /* pduGroupIndex.1.3 = INTEGER: 3 */ { "unmapped.pduGroupIndex", 0, 1, ".1.3.6.1.4.1.534.7.1.3.1.1.1.1.3", NULL, SU_FLAG_OK, NULL }, /* pduGroupIndex.1.4 = INTEGER: 4 */ { "unmapped.pduGroupIndex", 0, 1, ".1.3.6.1.4.1.534.7.1.3.1.1.1.1.4", NULL, SU_FLAG_OK, NULL }, /* pduGroupIndex.1.5 = INTEGER: 5 */ { "unmapped.pduGroupIndex", 0, 1, ".1.3.6.1.4.1.534.7.1.3.1.1.1.1.5", NULL, SU_FLAG_OK, NULL }, /* pduGroupIndex.1.6 = INTEGER: 6 */ { "unmapped.pduGroupIndex", 0, 1, ".1.3.6.1.4.1.534.7.1.3.1.1.1.1.6", NULL, SU_FLAG_OK, NULL }, /* pduGroupIndex.1.7 = INTEGER: 7 */ { "unmapped.pduGroupIndex", 0, 1, ".1.3.6.1.4.1.534.7.1.3.1.1.1.1.7", NULL, SU_FLAG_OK, NULL }, /* pduGroupIndex.1.8 = INTEGER: 8 */ { "unmapped.pduGroupIndex", 0, 1, ".1.3.6.1.4.1.534.7.1.3.1.1.1.1.8", NULL, SU_FLAG_OK, NULL }, /* pduGroupIndex.1.9 = INTEGER: 9 */ { "unmapped.pduGroupIndex", 0, 1, ".1.3.6.1.4.1.534.7.1.3.1.1.1.1.9", NULL, SU_FLAG_OK, NULL }, /* pduGroupIndex.1.10 = INTEGER: 10 */ { "unmapped.pduGroupIndex", 0, 1, ".1.3.6.1.4.1.534.7.1.3.1.1.1.1.10", NULL, SU_FLAG_OK, NULL }, /* pduGroupIndex.1.11 = INTEGER: 11 */ { "unmapped.pduGroupIndex", 0, 1, ".1.3.6.1.4.1.534.7.1.3.1.1.1.1.11", NULL, SU_FLAG_OK, NULL }, /* pduGroupIndex.1.12 = INTEGER: 12 */ { "unmapped.pduGroupIndex", 0, 1, ".1.3.6.1.4.1.534.7.1.3.1.1.1.1.12", NULL, SU_FLAG_OK, NULL }, /* pduGroupName.1.1 = Hex-STRING: 42 31 00 */ { "unmapped.pduGroupName", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.534.7.1.3.1.1.2.1.1", NULL, SU_FLAG_OK, NULL }, /* pduGroupName.1.2 = Hex-STRING: 00 */ { "unmapped.pduGroupName", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.534.7.1.3.1.1.2.1.2", NULL, SU_FLAG_OK, NULL }, /* pduGroupName.1.3 = Hex-STRING: 00 */ { "unmapped.pduGroupName", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.534.7.1.3.1.1.2.1.3", NULL, SU_FLAG_OK, NULL }, /* pduGroupName.1.4 = Hex-STRING: 00 */ { "unmapped.pduGroupName", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.534.7.1.3.1.1.2.1.4", NULL, SU_FLAG_OK, NULL }, /* pduGroupName.1.5 = Hex-STRING: 00 */ { "unmapped.pduGroupName", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.534.7.1.3.1.1.2.1.5", NULL, SU_FLAG_OK, NULL }, /* pduGroupName.1.6 = Hex-STRING: 00 */ { "unmapped.pduGroupName", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.534.7.1.3.1.1.2.1.6", NULL, SU_FLAG_OK, NULL }, /* pduGroupName.1.7 = Hex-STRING: 00 */ { "unmapped.pduGroupName", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.534.7.1.3.1.1.2.1.7", NULL, SU_FLAG_OK, NULL }, /* pduGroupName.1.8 = Hex-STRING: 00 */ { "unmapped.pduGroupName", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.534.7.1.3.1.1.2.1.8", NULL, SU_FLAG_OK, NULL }, /* pduGroupName.1.9 = Hex-STRING: 00 */ { "unmapped.pduGroupName", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.534.7.1.3.1.1.2.1.9", NULL, SU_FLAG_OK, NULL }, /* pduGroupName.1.10 = Hex-STRING: 00 */ { "unmapped.pduGroupName", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.534.7.1.3.1.1.2.1.10", NULL, SU_FLAG_OK, NULL }, /* pduGroupName.1.11 = Hex-STRING: 00 */ { "unmapped.pduGroupName", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.534.7.1.3.1.1.2.1.11", NULL, SU_FLAG_OK, NULL }, /* pduGroupName.1.12 = Hex-STRING: 00 */ { "unmapped.pduGroupName", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.534.7.1.3.1.1.2.1.12", NULL, SU_FLAG_OK, NULL }, /* pduGroupType.1.1 = INTEGER: 5 */ { "unmapped.pduGroupType", 0, 1, ".1.3.6.1.4.1.534.7.1.3.1.1.3.1.1", NULL, SU_FLAG_OK, NULL }, /* pduGroupType.1.2 = INTEGER: 0 */ { "unmapped.pduGroupType", 0, 1, ".1.3.6.1.4.1.534.7.1.3.1.1.3.1.2", NULL, SU_FLAG_OK, NULL }, /* pduGroupType.1.3 = INTEGER: 0 */ { "unmapped.pduGroupType", 0, 1, ".1.3.6.1.4.1.534.7.1.3.1.1.3.1.3", NULL, SU_FLAG_OK, NULL }, /* pduGroupType.1.4 = INTEGER: 0 */ { "unmapped.pduGroupType", 0, 1, ".1.3.6.1.4.1.534.7.1.3.1.1.3.1.4", NULL, SU_FLAG_OK, NULL }, /* pduGroupType.1.5 = INTEGER: 0 */ { "unmapped.pduGroupType", 0, 1, ".1.3.6.1.4.1.534.7.1.3.1.1.3.1.5", NULL, SU_FLAG_OK, NULL }, /* pduGroupType.1.6 = INTEGER: 0 */ { "unmapped.pduGroupType", 0, 1, ".1.3.6.1.4.1.534.7.1.3.1.1.3.1.6", NULL, SU_FLAG_OK, NULL }, /* pduGroupType.1.7 = INTEGER: 0 */ { "unmapped.pduGroupType", 0, 1, ".1.3.6.1.4.1.534.7.1.3.1.1.3.1.7", NULL, SU_FLAG_OK, NULL }, /* pduGroupType.1.8 = INTEGER: 0 */ { "unmapped.pduGroupType", 0, 1, ".1.3.6.1.4.1.534.7.1.3.1.1.3.1.8", NULL, SU_FLAG_OK, NULL }, /* pduGroupType.1.9 = INTEGER: 0 */ { "unmapped.pduGroupType", 0, 1, ".1.3.6.1.4.1.534.7.1.3.1.1.3.1.9", NULL, SU_FLAG_OK, NULL }, /* pduGroupType.1.10 = INTEGER: 0 */ { "unmapped.pduGroupType", 0, 1, ".1.3.6.1.4.1.534.7.1.3.1.1.3.1.10", NULL, SU_FLAG_OK, NULL }, /* pduGroupType.1.11 = INTEGER: 0 */ { "unmapped.pduGroupType", 0, 1, ".1.3.6.1.4.1.534.7.1.3.1.1.3.1.11", NULL, SU_FLAG_OK, NULL }, /* pduGroupType.1.12 = INTEGER: 0 */ { "unmapped.pduGroupType", 0, 1, ".1.3.6.1.4.1.534.7.1.3.1.1.3.1.12", NULL, SU_FLAG_OK, NULL }, /* pduGroupVoltageMeasType.1.1 = INTEGER: 1 */ { "unmapped.pduGroupVoltageMeasType", 0, 1, ".1.3.6.1.4.1.534.7.1.3.1.1.4.1.1", NULL, SU_FLAG_OK, NULL }, /* pduGroupVoltageMeasType.1.2 = INTEGER: 0 */ { "unmapped.pduGroupVoltageMeasType", 0, 1, ".1.3.6.1.4.1.534.7.1.3.1.1.4.1.2", NULL, SU_FLAG_OK, NULL }, /* pduGroupVoltageMeasType.1.3 = INTEGER: 0 */ { "unmapped.pduGroupVoltageMeasType", 0, 1, ".1.3.6.1.4.1.534.7.1.3.1.1.4.1.3", NULL, SU_FLAG_OK, NULL }, /* pduGroupVoltageMeasType.1.4 = INTEGER: 0 */ { "unmapped.pduGroupVoltageMeasType", 0, 1, ".1.3.6.1.4.1.534.7.1.3.1.1.4.1.4", NULL, SU_FLAG_OK, NULL }, /* pduGroupVoltageMeasType.1.5 = INTEGER: 0 */ { "unmapped.pduGroupVoltageMeasType", 0, 1, ".1.3.6.1.4.1.534.7.1.3.1.1.4.1.5", NULL, SU_FLAG_OK, NULL }, /* pduGroupVoltageMeasType.1.6 = INTEGER: 0 */ { "unmapped.pduGroupVoltageMeasType", 0, 1, ".1.3.6.1.4.1.534.7.1.3.1.1.4.1.6", NULL, SU_FLAG_OK, NULL }, /* pduGroupVoltageMeasType.1.7 = INTEGER: 0 */ { "unmapped.pduGroupVoltageMeasType", 0, 1, ".1.3.6.1.4.1.534.7.1.3.1.1.4.1.7", NULL, SU_FLAG_OK, NULL }, /* pduGroupVoltageMeasType.1.8 = INTEGER: 0 */ { "unmapped.pduGroupVoltageMeasType", 0, 1, ".1.3.6.1.4.1.534.7.1.3.1.1.4.1.8", NULL, SU_FLAG_OK, NULL }, /* pduGroupVoltageMeasType.1.9 = INTEGER: 0 */ { "unmapped.pduGroupVoltageMeasType", 0, 1, ".1.3.6.1.4.1.534.7.1.3.1.1.4.1.9", NULL, SU_FLAG_OK, NULL }, /* pduGroupVoltageMeasType.1.10 = INTEGER: 0 */ { "unmapped.pduGroupVoltageMeasType", 0, 1, ".1.3.6.1.4.1.534.7.1.3.1.1.4.1.10", NULL, SU_FLAG_OK, NULL }, /* pduGroupVoltageMeasType.1.11 = INTEGER: 0 */ { "unmapped.pduGroupVoltageMeasType", 0, 1, ".1.3.6.1.4.1.534.7.1.3.1.1.4.1.11", NULL, SU_FLAG_OK, NULL }, /* pduGroupVoltageMeasType.1.12 = INTEGER: 0 */ { "unmapped.pduGroupVoltageMeasType", 0, 1, ".1.3.6.1.4.1.534.7.1.3.1.1.4.1.12", NULL, SU_FLAG_OK, NULL }, /* pduGroupVoltageThStatus.1.1 = INTEGER: 1 */ { "unmapped.pduGroupVoltageThStatus", 0, 1, ".1.3.6.1.4.1.534.7.1.3.1.1.6.1.1", NULL, SU_FLAG_OK, NULL }, /* pduGroupVoltageThStatus.1.2 = INTEGER: 0 */ { "unmapped.pduGroupVoltageThStatus", 0, 1, ".1.3.6.1.4.1.534.7.1.3.1.1.6.1.2", NULL, SU_FLAG_OK, NULL }, /* pduGroupVoltageThStatus.1.3 = INTEGER: 0 */ { "unmapped.pduGroupVoltageThStatus", 0, 1, ".1.3.6.1.4.1.534.7.1.3.1.1.6.1.3", NULL, SU_FLAG_OK, NULL }, /* pduGroupVoltageThStatus.1.4 = INTEGER: 0 */ { "unmapped.pduGroupVoltageThStatus", 0, 1, ".1.3.6.1.4.1.534.7.1.3.1.1.6.1.4", NULL, SU_FLAG_OK, NULL }, /* pduGroupVoltageThStatus.1.5 = INTEGER: 0 */ { "unmapped.pduGroupVoltageThStatus", 0, 1, ".1.3.6.1.4.1.534.7.1.3.1.1.6.1.5", NULL, SU_FLAG_OK, NULL }, /* pduGroupVoltageThStatus.1.6 = INTEGER: 0 */ { "unmapped.pduGroupVoltageThStatus", 0, 1, ".1.3.6.1.4.1.534.7.1.3.1.1.6.1.6", NULL, SU_FLAG_OK, NULL }, /* pduGroupVoltageThStatus.1.7 = INTEGER: 0 */ { "unmapped.pduGroupVoltageThStatus", 0, 1, ".1.3.6.1.4.1.534.7.1.3.1.1.6.1.7", NULL, SU_FLAG_OK, NULL }, /* pduGroupVoltageThStatus.1.8 = INTEGER: 0 */ { "unmapped.pduGroupVoltageThStatus", 0, 1, ".1.3.6.1.4.1.534.7.1.3.1.1.6.1.8", NULL, SU_FLAG_OK, NULL }, /* pduGroupVoltageThStatus.1.9 = INTEGER: 0 */ { "unmapped.pduGroupVoltageThStatus", 0, 1, ".1.3.6.1.4.1.534.7.1.3.1.1.6.1.9", NULL, SU_FLAG_OK, NULL }, /* pduGroupVoltageThStatus.1.10 = INTEGER: 0 */ { "unmapped.pduGroupVoltageThStatus", 0, 1, ".1.3.6.1.4.1.534.7.1.3.1.1.6.1.10", NULL, SU_FLAG_OK, NULL }, /* pduGroupVoltageThStatus.1.11 = INTEGER: 0 */ { "unmapped.pduGroupVoltageThStatus", 0, 1, ".1.3.6.1.4.1.534.7.1.3.1.1.6.1.11", NULL, SU_FLAG_OK, NULL }, /* pduGroupVoltageThStatus.1.12 = INTEGER: 0 */ { "unmapped.pduGroupVoltageThStatus", 0, 1, ".1.3.6.1.4.1.534.7.1.3.1.1.6.1.12", NULL, SU_FLAG_OK, NULL }, /* pduGroupVoltageThLowerWarning.1.1 = INTEGER: 0 */ { "unmapped.pduGroupVoltageThLowerWarning", 0, 1, ".1.3.6.1.4.1.534.7.1.3.1.1.7.1.1", NULL, SU_FLAG_OK, NULL }, /* pduGroupVoltageThLowerWarning.1.2 = INTEGER: 0 */ { "unmapped.pduGroupVoltageThLowerWarning", 0, 1, ".1.3.6.1.4.1.534.7.1.3.1.1.7.1.2", NULL, SU_FLAG_OK, NULL }, /* pduGroupVoltageThLowerWarning.1.3 = INTEGER: 0 */ { "unmapped.pduGroupVoltageThLowerWarning", 0, 1, ".1.3.6.1.4.1.534.7.1.3.1.1.7.1.3", NULL, SU_FLAG_OK, NULL }, /* pduGroupVoltageThLowerWarning.1.4 = INTEGER: 0 */ { "unmapped.pduGroupVoltageThLowerWarning", 0, 1, ".1.3.6.1.4.1.534.7.1.3.1.1.7.1.4", NULL, SU_FLAG_OK, NULL }, /* pduGroupVoltageThLowerWarning.1.5 = INTEGER: 0 */ { "unmapped.pduGroupVoltageThLowerWarning", 0, 1, ".1.3.6.1.4.1.534.7.1.3.1.1.7.1.5", NULL, SU_FLAG_OK, NULL }, /* pduGroupVoltageThLowerWarning.1.6 = INTEGER: 0 */ { "unmapped.pduGroupVoltageThLowerWarning", 0, 1, ".1.3.6.1.4.1.534.7.1.3.1.1.7.1.6", NULL, SU_FLAG_OK, NULL }, /* pduGroupVoltageThLowerWarning.1.7 = INTEGER: 0 */ { "unmapped.pduGroupVoltageThLowerWarning", 0, 1, ".1.3.6.1.4.1.534.7.1.3.1.1.7.1.7", NULL, SU_FLAG_OK, NULL }, /* pduGroupVoltageThLowerWarning.1.8 = INTEGER: 0 */ { "unmapped.pduGroupVoltageThLowerWarning", 0, 1, ".1.3.6.1.4.1.534.7.1.3.1.1.7.1.8", NULL, SU_FLAG_OK, NULL }, /* pduGroupVoltageThLowerWarning.1.9 = INTEGER: 0 */ { "unmapped.pduGroupVoltageThLowerWarning", 0, 1, ".1.3.6.1.4.1.534.7.1.3.1.1.7.1.9", NULL, SU_FLAG_OK, NULL }, /* pduGroupVoltageThLowerWarning.1.10 = INTEGER: 0 */ { "unmapped.pduGroupVoltageThLowerWarning", 0, 1, ".1.3.6.1.4.1.534.7.1.3.1.1.7.1.10", NULL, SU_FLAG_OK, NULL }, /* pduGroupVoltageThLowerWarning.1.11 = INTEGER: 0 */ { "unmapped.pduGroupVoltageThLowerWarning", 0, 1, ".1.3.6.1.4.1.534.7.1.3.1.1.7.1.11", NULL, SU_FLAG_OK, NULL }, /* pduGroupVoltageThLowerWarning.1.12 = INTEGER: 0 */ { "unmapped.pduGroupVoltageThLowerWarning", 0, 1, ".1.3.6.1.4.1.534.7.1.3.1.1.7.1.12", NULL, SU_FLAG_OK, NULL }, /* pduGroupVoltageThLowerCritical.1.1 = INTEGER: 0 */ { "unmapped.pduGroupVoltageThLowerCritical", 0, 1, ".1.3.6.1.4.1.534.7.1.3.1.1.8.1.1", NULL, SU_FLAG_OK, NULL }, /* pduGroupVoltageThLowerCritical.1.2 = INTEGER: 0 */ { "unmapped.pduGroupVoltageThLowerCritical", 0, 1, ".1.3.6.1.4.1.534.7.1.3.1.1.8.1.2", NULL, SU_FLAG_OK, NULL }, /* pduGroupVoltageThLowerCritical.1.3 = INTEGER: 0 */ { "unmapped.pduGroupVoltageThLowerCritical", 0, 1, ".1.3.6.1.4.1.534.7.1.3.1.1.8.1.3", NULL, SU_FLAG_OK, NULL }, /* pduGroupVoltageThLowerCritical.1.4 = INTEGER: 0 */ { "unmapped.pduGroupVoltageThLowerCritical", 0, 1, ".1.3.6.1.4.1.534.7.1.3.1.1.8.1.4", NULL, SU_FLAG_OK, NULL }, /* pduGroupVoltageThLowerCritical.1.5 = INTEGER: 0 */ { "unmapped.pduGroupVoltageThLowerCritical", 0, 1, ".1.3.6.1.4.1.534.7.1.3.1.1.8.1.5", NULL, SU_FLAG_OK, NULL }, /* pduGroupVoltageThLowerCritical.1.6 = INTEGER: 0 */ { "unmapped.pduGroupVoltageThLowerCritical", 0, 1, ".1.3.6.1.4.1.534.7.1.3.1.1.8.1.6", NULL, SU_FLAG_OK, NULL }, /* pduGroupVoltageThLowerCritical.1.7 = INTEGER: 0 */ { "unmapped.pduGroupVoltageThLowerCritical", 0, 1, ".1.3.6.1.4.1.534.7.1.3.1.1.8.1.7", NULL, SU_FLAG_OK, NULL }, /* pduGroupVoltageThLowerCritical.1.8 = INTEGER: 0 */ { "unmapped.pduGroupVoltageThLowerCritical", 0, 1, ".1.3.6.1.4.1.534.7.1.3.1.1.8.1.8", NULL, SU_FLAG_OK, NULL }, /* pduGroupVoltageThLowerCritical.1.9 = INTEGER: 0 */ { "unmapped.pduGroupVoltageThLowerCritical", 0, 1, ".1.3.6.1.4.1.534.7.1.3.1.1.8.1.9", NULL, SU_FLAG_OK, NULL }, /* pduGroupVoltageThLowerCritical.1.10 = INTEGER: 0 */ { "unmapped.pduGroupVoltageThLowerCritical", 0, 1, ".1.3.6.1.4.1.534.7.1.3.1.1.8.1.10", NULL, SU_FLAG_OK, NULL }, /* pduGroupVoltageThLowerCritical.1.11 = INTEGER: 0 */ { "unmapped.pduGroupVoltageThLowerCritical", 0, 1, ".1.3.6.1.4.1.534.7.1.3.1.1.8.1.11", NULL, SU_FLAG_OK, NULL }, /* pduGroupVoltageThLowerCritical.1.12 = INTEGER: 0 */ { "unmapped.pduGroupVoltageThLowerCritical", 0, 1, ".1.3.6.1.4.1.534.7.1.3.1.1.8.1.12", NULL, SU_FLAG_OK, NULL }, /* pduGroupVoltageThUpperWarning.1.1 = INTEGER: 0 */ { "unmapped.pduGroupVoltageThUpperWarning", 0, 1, ".1.3.6.1.4.1.534.7.1.3.1.1.9.1.1", NULL, SU_FLAG_OK, NULL }, /* pduGroupVoltageThUpperWarning.1.2 = INTEGER: 0 */ { "unmapped.pduGroupVoltageThUpperWarning", 0, 1, ".1.3.6.1.4.1.534.7.1.3.1.1.9.1.2", NULL, SU_FLAG_OK, NULL }, /* pduGroupVoltageThUpperWarning.1.3 = INTEGER: 0 */ { "unmapped.pduGroupVoltageThUpperWarning", 0, 1, ".1.3.6.1.4.1.534.7.1.3.1.1.9.1.3", NULL, SU_FLAG_OK, NULL }, /* pduGroupVoltageThUpperWarning.1.4 = INTEGER: 0 */ { "unmapped.pduGroupVoltageThUpperWarning", 0, 1, ".1.3.6.1.4.1.534.7.1.3.1.1.9.1.4", NULL, SU_FLAG_OK, NULL }, /* pduGroupVoltageThUpperWarning.1.5 = INTEGER: 0 */ { "unmapped.pduGroupVoltageThUpperWarning", 0, 1, ".1.3.6.1.4.1.534.7.1.3.1.1.9.1.5", NULL, SU_FLAG_OK, NULL }, /* pduGroupVoltageThUpperWarning.1.6 = INTEGER: 0 */ { "unmapped.pduGroupVoltageThUpperWarning", 0, 1, ".1.3.6.1.4.1.534.7.1.3.1.1.9.1.6", NULL, SU_FLAG_OK, NULL }, /* pduGroupVoltageThUpperWarning.1.7 = INTEGER: 0 */ { "unmapped.pduGroupVoltageThUpperWarning", 0, 1, ".1.3.6.1.4.1.534.7.1.3.1.1.9.1.7", NULL, SU_FLAG_OK, NULL }, /* pduGroupVoltageThUpperWarning.1.8 = INTEGER: 0 */ { "unmapped.pduGroupVoltageThUpperWarning", 0, 1, ".1.3.6.1.4.1.534.7.1.3.1.1.9.1.8", NULL, SU_FLAG_OK, NULL }, /* pduGroupVoltageThUpperWarning.1.9 = INTEGER: 0 */ { "unmapped.pduGroupVoltageThUpperWarning", 0, 1, ".1.3.6.1.4.1.534.7.1.3.1.1.9.1.9", NULL, SU_FLAG_OK, NULL }, /* pduGroupVoltageThUpperWarning.1.10 = INTEGER: 0 */ { "unmapped.pduGroupVoltageThUpperWarning", 0, 1, ".1.3.6.1.4.1.534.7.1.3.1.1.9.1.10", NULL, SU_FLAG_OK, NULL }, /* pduGroupVoltageThUpperWarning.1.11 = INTEGER: 0 */ { "unmapped.pduGroupVoltageThUpperWarning", 0, 1, ".1.3.6.1.4.1.534.7.1.3.1.1.9.1.11", NULL, SU_FLAG_OK, NULL }, /* pduGroupVoltageThUpperWarning.1.12 = INTEGER: 0 */ { "unmapped.pduGroupVoltageThUpperWarning", 0, 1, ".1.3.6.1.4.1.534.7.1.3.1.1.9.1.12", NULL, SU_FLAG_OK, NULL }, /* pduGroupVoltageThUpperCritical.1.1 = INTEGER: 0 */ { "unmapped.pduGroupVoltageThUpperCritical", 0, 1, ".1.3.6.1.4.1.534.7.1.3.1.1.10.1.1", NULL, SU_FLAG_OK, NULL }, /* pduGroupVoltageThUpperCritical.1.2 = INTEGER: 0 */ { "unmapped.pduGroupVoltageThUpperCritical", 0, 1, ".1.3.6.1.4.1.534.7.1.3.1.1.10.1.2", NULL, SU_FLAG_OK, NULL }, /* pduGroupVoltageThUpperCritical.1.3 = INTEGER: 0 */ { "unmapped.pduGroupVoltageThUpperCritical", 0, 1, ".1.3.6.1.4.1.534.7.1.3.1.1.10.1.3", NULL, SU_FLAG_OK, NULL }, /* pduGroupVoltageThUpperCritical.1.4 = INTEGER: 0 */ { "unmapped.pduGroupVoltageThUpperCritical", 0, 1, ".1.3.6.1.4.1.534.7.1.3.1.1.10.1.4", NULL, SU_FLAG_OK, NULL }, /* pduGroupVoltageThUpperCritical.1.5 = INTEGER: 0 */ { "unmapped.pduGroupVoltageThUpperCritical", 0, 1, ".1.3.6.1.4.1.534.7.1.3.1.1.10.1.5", NULL, SU_FLAG_OK, NULL }, /* pduGroupVoltageThUpperCritical.1.6 = INTEGER: 0 */ { "unmapped.pduGroupVoltageThUpperCritical", 0, 1, ".1.3.6.1.4.1.534.7.1.3.1.1.10.1.6", NULL, SU_FLAG_OK, NULL }, /* pduGroupVoltageThUpperCritical.1.7 = INTEGER: 0 */ { "unmapped.pduGroupVoltageThUpperCritical", 0, 1, ".1.3.6.1.4.1.534.7.1.3.1.1.10.1.7", NULL, SU_FLAG_OK, NULL }, /* pduGroupVoltageThUpperCritical.1.8 = INTEGER: 0 */ { "unmapped.pduGroupVoltageThUpperCritical", 0, 1, ".1.3.6.1.4.1.534.7.1.3.1.1.10.1.8", NULL, SU_FLAG_OK, NULL }, /* pduGroupVoltageThUpperCritical.1.9 = INTEGER: 0 */ { "unmapped.pduGroupVoltageThUpperCritical", 0, 1, ".1.3.6.1.4.1.534.7.1.3.1.1.10.1.9", NULL, SU_FLAG_OK, NULL }, /* pduGroupVoltageThUpperCritical.1.10 = INTEGER: 0 */ { "unmapped.pduGroupVoltageThUpperCritical", 0, 1, ".1.3.6.1.4.1.534.7.1.3.1.1.10.1.10", NULL, SU_FLAG_OK, NULL }, /* pduGroupVoltageThUpperCritical.1.11 = INTEGER: 0 */ { "unmapped.pduGroupVoltageThUpperCritical", 0, 1, ".1.3.6.1.4.1.534.7.1.3.1.1.10.1.11", NULL, SU_FLAG_OK, NULL }, /* pduGroupVoltageThUpperCritical.1.12 = INTEGER: 0 */ { "unmapped.pduGroupVoltageThUpperCritical", 0, 1, ".1.3.6.1.4.1.534.7.1.3.1.1.10.1.12", NULL, SU_FLAG_OK, NULL }, /* pdugroupCurrentRating.1.1 = INTEGER: 0 */ { "unmapped.pdugroupCurrentRating", 0, 1, ".1.3.6.1.4.1.534.7.1.3.1.1.11.1.1", NULL, SU_FLAG_OK, NULL }, /* pdugroupCurrentRating.1.2 = INTEGER: 0 */ { "unmapped.pdugroupCurrentRating", 0, 1, ".1.3.6.1.4.1.534.7.1.3.1.1.11.1.2", NULL, SU_FLAG_OK, NULL }, /* pdugroupCurrentRating.1.3 = INTEGER: 0 */ { "unmapped.pdugroupCurrentRating", 0, 1, ".1.3.6.1.4.1.534.7.1.3.1.1.11.1.3", NULL, SU_FLAG_OK, NULL }, /* pdugroupCurrentRating.1.4 = INTEGER: 0 */ { "unmapped.pdugroupCurrentRating", 0, 1, ".1.3.6.1.4.1.534.7.1.3.1.1.11.1.4", NULL, SU_FLAG_OK, NULL }, /* pdugroupCurrentRating.1.5 = INTEGER: 0 */ { "unmapped.pdugroupCurrentRating", 0, 1, ".1.3.6.1.4.1.534.7.1.3.1.1.11.1.5", NULL, SU_FLAG_OK, NULL }, /* pdugroupCurrentRating.1.6 = INTEGER: 0 */ { "unmapped.pdugroupCurrentRating", 0, 1, ".1.3.6.1.4.1.534.7.1.3.1.1.11.1.6", NULL, SU_FLAG_OK, NULL }, /* pdugroupCurrentRating.1.7 = INTEGER: 0 */ { "unmapped.pdugroupCurrentRating", 0, 1, ".1.3.6.1.4.1.534.7.1.3.1.1.11.1.7", NULL, SU_FLAG_OK, NULL }, /* pdugroupCurrentRating.1.8 = INTEGER: 0 */ { "unmapped.pdugroupCurrentRating", 0, 1, ".1.3.6.1.4.1.534.7.1.3.1.1.11.1.8", NULL, SU_FLAG_OK, NULL }, /* pdugroupCurrentRating.1.9 = INTEGER: 0 */ { "unmapped.pdugroupCurrentRating", 0, 1, ".1.3.6.1.4.1.534.7.1.3.1.1.11.1.9", NULL, SU_FLAG_OK, NULL }, /* pdugroupCurrentRating.1.10 = INTEGER: 0 */ { "unmapped.pdugroupCurrentRating", 0, 1, ".1.3.6.1.4.1.534.7.1.3.1.1.11.1.10", NULL, SU_FLAG_OK, NULL }, /* pdugroupCurrentRating.1.11 = INTEGER: 0 */ { "unmapped.pdugroupCurrentRating", 0, 1, ".1.3.6.1.4.1.534.7.1.3.1.1.11.1.11", NULL, SU_FLAG_OK, NULL }, /* pdugroupCurrentRating.1.12 = INTEGER: 0 */ { "unmapped.pdugroupCurrentRating", 0, 1, ".1.3.6.1.4.1.534.7.1.3.1.1.11.1.12", NULL, SU_FLAG_OK, NULL }, /* pduGroupCurrentThStatus.1.1 = INTEGER: 1 */ { "unmapped.pduGroupCurrentThStatus", 0, 1, ".1.3.6.1.4.1.534.7.1.3.1.1.13.1.1", NULL, SU_FLAG_OK, NULL }, /* pduGroupCurrentThStatus.1.2 = INTEGER: 0 */ { "unmapped.pduGroupCurrentThStatus", 0, 1, ".1.3.6.1.4.1.534.7.1.3.1.1.13.1.2", NULL, SU_FLAG_OK, NULL }, /* pduGroupCurrentThStatus.1.3 = INTEGER: 0 */ { "unmapped.pduGroupCurrentThStatus", 0, 1, ".1.3.6.1.4.1.534.7.1.3.1.1.13.1.3", NULL, SU_FLAG_OK, NULL }, /* pduGroupCurrentThStatus.1.4 = INTEGER: 0 */ { "unmapped.pduGroupCurrentThStatus", 0, 1, ".1.3.6.1.4.1.534.7.1.3.1.1.13.1.4", NULL, SU_FLAG_OK, NULL }, /* pduGroupCurrentThStatus.1.5 = INTEGER: 0 */ { "unmapped.pduGroupCurrentThStatus", 0, 1, ".1.3.6.1.4.1.534.7.1.3.1.1.13.1.5", NULL, SU_FLAG_OK, NULL }, /* pduGroupCurrentThStatus.1.6 = INTEGER: 0 */ { "unmapped.pduGroupCurrentThStatus", 0, 1, ".1.3.6.1.4.1.534.7.1.3.1.1.13.1.6", NULL, SU_FLAG_OK, NULL }, /* pduGroupCurrentThStatus.1.7 = INTEGER: 0 */ { "unmapped.pduGroupCurrentThStatus", 0, 1, ".1.3.6.1.4.1.534.7.1.3.1.1.13.1.7", NULL, SU_FLAG_OK, NULL }, /* pduGroupCurrentThStatus.1.8 = INTEGER: 0 */ { "unmapped.pduGroupCurrentThStatus", 0, 1, ".1.3.6.1.4.1.534.7.1.3.1.1.13.1.8", NULL, SU_FLAG_OK, NULL }, /* pduGroupCurrentThStatus.1.9 = INTEGER: 0 */ { "unmapped.pduGroupCurrentThStatus", 0, 1, ".1.3.6.1.4.1.534.7.1.3.1.1.13.1.9", NULL, SU_FLAG_OK, NULL }, /* pduGroupCurrentThStatus.1.10 = INTEGER: 0 */ { "unmapped.pduGroupCurrentThStatus", 0, 1, ".1.3.6.1.4.1.534.7.1.3.1.1.13.1.10", NULL, SU_FLAG_OK, NULL }, /* pduGroupCurrentThStatus.1.11 = INTEGER: 0 */ { "unmapped.pduGroupCurrentThStatus", 0, 1, ".1.3.6.1.4.1.534.7.1.3.1.1.13.1.11", NULL, SU_FLAG_OK, NULL }, /* pduGroupCurrentThStatus.1.12 = INTEGER: 0 */ { "unmapped.pduGroupCurrentThStatus", 0, 1, ".1.3.6.1.4.1.534.7.1.3.1.1.13.1.12", NULL, SU_FLAG_OK, NULL }, /* pduGroupCurrentThLowerWarning.1.1 = INTEGER: 0 */ { "unmapped.pduGroupCurrentThLowerWarning", 0, 1, ".1.3.6.1.4.1.534.7.1.3.1.1.14.1.1", NULL, SU_FLAG_OK, NULL }, /* pduGroupCurrentThLowerWarning.1.2 = INTEGER: 0 */ { "unmapped.pduGroupCurrentThLowerWarning", 0, 1, ".1.3.6.1.4.1.534.7.1.3.1.1.14.1.2", NULL, SU_FLAG_OK, NULL }, /* pduGroupCurrentThLowerWarning.1.3 = INTEGER: 0 */ { "unmapped.pduGroupCurrentThLowerWarning", 0, 1, ".1.3.6.1.4.1.534.7.1.3.1.1.14.1.3", NULL, SU_FLAG_OK, NULL }, /* pduGroupCurrentThLowerWarning.1.4 = INTEGER: 0 */ { "unmapped.pduGroupCurrentThLowerWarning", 0, 1, ".1.3.6.1.4.1.534.7.1.3.1.1.14.1.4", NULL, SU_FLAG_OK, NULL }, /* pduGroupCurrentThLowerWarning.1.5 = INTEGER: 0 */ { "unmapped.pduGroupCurrentThLowerWarning", 0, 1, ".1.3.6.1.4.1.534.7.1.3.1.1.14.1.5", NULL, SU_FLAG_OK, NULL }, /* pduGroupCurrentThLowerWarning.1.6 = INTEGER: 0 */ { "unmapped.pduGroupCurrentThLowerWarning", 0, 1, ".1.3.6.1.4.1.534.7.1.3.1.1.14.1.6", NULL, SU_FLAG_OK, NULL }, /* pduGroupCurrentThLowerWarning.1.7 = INTEGER: 0 */ { "unmapped.pduGroupCurrentThLowerWarning", 0, 1, ".1.3.6.1.4.1.534.7.1.3.1.1.14.1.7", NULL, SU_FLAG_OK, NULL }, /* pduGroupCurrentThLowerWarning.1.8 = INTEGER: 0 */ { "unmapped.pduGroupCurrentThLowerWarning", 0, 1, ".1.3.6.1.4.1.534.7.1.3.1.1.14.1.8", NULL, SU_FLAG_OK, NULL }, /* pduGroupCurrentThLowerWarning.1.9 = INTEGER: 0 */ { "unmapped.pduGroupCurrentThLowerWarning", 0, 1, ".1.3.6.1.4.1.534.7.1.3.1.1.14.1.9", NULL, SU_FLAG_OK, NULL }, /* pduGroupCurrentThLowerWarning.1.10 = INTEGER: 0 */ { "unmapped.pduGroupCurrentThLowerWarning", 0, 1, ".1.3.6.1.4.1.534.7.1.3.1.1.14.1.10", NULL, SU_FLAG_OK, NULL }, /* pduGroupCurrentThLowerWarning.1.11 = INTEGER: 0 */ { "unmapped.pduGroupCurrentThLowerWarning", 0, 1, ".1.3.6.1.4.1.534.7.1.3.1.1.14.1.11", NULL, SU_FLAG_OK, NULL }, /* pduGroupCurrentThLowerWarning.1.12 = INTEGER: 0 */ { "unmapped.pduGroupCurrentThLowerWarning", 0, 1, ".1.3.6.1.4.1.534.7.1.3.1.1.14.1.12", NULL, SU_FLAG_OK, NULL }, /* pduGroupCurrentThLowerCritical.1.1 = INTEGER: 0 */ { "unmapped.pduGroupCurrentThLowerCritical", 0, 1, ".1.3.6.1.4.1.534.7.1.3.1.1.15.1.1", NULL, SU_FLAG_OK, NULL }, /* pduGroupCurrentThLowerCritical.1.2 = INTEGER: 0 */ { "unmapped.pduGroupCurrentThLowerCritical", 0, 1, ".1.3.6.1.4.1.534.7.1.3.1.1.15.1.2", NULL, SU_FLAG_OK, NULL }, /* pduGroupCurrentThLowerCritical.1.3 = INTEGER: 0 */ { "unmapped.pduGroupCurrentThLowerCritical", 0, 1, ".1.3.6.1.4.1.534.7.1.3.1.1.15.1.3", NULL, SU_FLAG_OK, NULL }, /* pduGroupCurrentThLowerCritical.1.4 = INTEGER: 0 */ { "unmapped.pduGroupCurrentThLowerCritical", 0, 1, ".1.3.6.1.4.1.534.7.1.3.1.1.15.1.4", NULL, SU_FLAG_OK, NULL }, /* pduGroupCurrentThLowerCritical.1.5 = INTEGER: 0 */ { "unmapped.pduGroupCurrentThLowerCritical", 0, 1, ".1.3.6.1.4.1.534.7.1.3.1.1.15.1.5", NULL, SU_FLAG_OK, NULL }, /* pduGroupCurrentThLowerCritical.1.6 = INTEGER: 0 */ { "unmapped.pduGroupCurrentThLowerCritical", 0, 1, ".1.3.6.1.4.1.534.7.1.3.1.1.15.1.6", NULL, SU_FLAG_OK, NULL }, /* pduGroupCurrentThLowerCritical.1.7 = INTEGER: 0 */ { "unmapped.pduGroupCurrentThLowerCritical", 0, 1, ".1.3.6.1.4.1.534.7.1.3.1.1.15.1.7", NULL, SU_FLAG_OK, NULL }, /* pduGroupCurrentThLowerCritical.1.8 = INTEGER: 0 */ { "unmapped.pduGroupCurrentThLowerCritical", 0, 1, ".1.3.6.1.4.1.534.7.1.3.1.1.15.1.8", NULL, SU_FLAG_OK, NULL }, /* pduGroupCurrentThLowerCritical.1.9 = INTEGER: 0 */ { "unmapped.pduGroupCurrentThLowerCritical", 0, 1, ".1.3.6.1.4.1.534.7.1.3.1.1.15.1.9", NULL, SU_FLAG_OK, NULL }, /* pduGroupCurrentThLowerCritical.1.10 = INTEGER: 0 */ { "unmapped.pduGroupCurrentThLowerCritical", 0, 1, ".1.3.6.1.4.1.534.7.1.3.1.1.15.1.10", NULL, SU_FLAG_OK, NULL }, /* pduGroupCurrentThLowerCritical.1.11 = INTEGER: 0 */ { "unmapped.pduGroupCurrentThLowerCritical", 0, 1, ".1.3.6.1.4.1.534.7.1.3.1.1.15.1.11", NULL, SU_FLAG_OK, NULL }, /* pduGroupCurrentThLowerCritical.1.12 = INTEGER: 0 */ { "unmapped.pduGroupCurrentThLowerCritical", 0, 1, ".1.3.6.1.4.1.534.7.1.3.1.1.15.1.12", NULL, SU_FLAG_OK, NULL }, /* pduGroupCurrentThUpperWarning.1.1 = INTEGER: 0 */ { "unmapped.pduGroupCurrentThUpperWarning", 0, 1, ".1.3.6.1.4.1.534.7.1.3.1.1.16.1.1", NULL, SU_FLAG_OK, NULL }, /* pduGroupCurrentThUpperWarning.1.2 = INTEGER: 0 */ { "unmapped.pduGroupCurrentThUpperWarning", 0, 1, ".1.3.6.1.4.1.534.7.1.3.1.1.16.1.2", NULL, SU_FLAG_OK, NULL }, /* pduGroupCurrentThUpperWarning.1.3 = INTEGER: 0 */ { "unmapped.pduGroupCurrentThUpperWarning", 0, 1, ".1.3.6.1.4.1.534.7.1.3.1.1.16.1.3", NULL, SU_FLAG_OK, NULL }, /* pduGroupCurrentThUpperWarning.1.4 = INTEGER: 0 */ { "unmapped.pduGroupCurrentThUpperWarning", 0, 1, ".1.3.6.1.4.1.534.7.1.3.1.1.16.1.4", NULL, SU_FLAG_OK, NULL }, /* pduGroupCurrentThUpperWarning.1.5 = INTEGER: 0 */ { "unmapped.pduGroupCurrentThUpperWarning", 0, 1, ".1.3.6.1.4.1.534.7.1.3.1.1.16.1.5", NULL, SU_FLAG_OK, NULL }, /* pduGroupCurrentThUpperWarning.1.6 = INTEGER: 0 */ { "unmapped.pduGroupCurrentThUpperWarning", 0, 1, ".1.3.6.1.4.1.534.7.1.3.1.1.16.1.6", NULL, SU_FLAG_OK, NULL }, /* pduGroupCurrentThUpperWarning.1.7 = INTEGER: 0 */ { "unmapped.pduGroupCurrentThUpperWarning", 0, 1, ".1.3.6.1.4.1.534.7.1.3.1.1.16.1.7", NULL, SU_FLAG_OK, NULL }, /* pduGroupCurrentThUpperWarning.1.8 = INTEGER: 0 */ { "unmapped.pduGroupCurrentThUpperWarning", 0, 1, ".1.3.6.1.4.1.534.7.1.3.1.1.16.1.8", NULL, SU_FLAG_OK, NULL }, /* pduGroupCurrentThUpperWarning.1.9 = INTEGER: 0 */ { "unmapped.pduGroupCurrentThUpperWarning", 0, 1, ".1.3.6.1.4.1.534.7.1.3.1.1.16.1.9", NULL, SU_FLAG_OK, NULL }, /* pduGroupCurrentThUpperWarning.1.10 = INTEGER: 0 */ { "unmapped.pduGroupCurrentThUpperWarning", 0, 1, ".1.3.6.1.4.1.534.7.1.3.1.1.16.1.10", NULL, SU_FLAG_OK, NULL }, /* pduGroupCurrentThUpperWarning.1.11 = INTEGER: 0 */ { "unmapped.pduGroupCurrentThUpperWarning", 0, 1, ".1.3.6.1.4.1.534.7.1.3.1.1.16.1.11", NULL, SU_FLAG_OK, NULL }, /* pduGroupCurrentThUpperWarning.1.12 = INTEGER: 0 */ { "unmapped.pduGroupCurrentThUpperWarning", 0, 1, ".1.3.6.1.4.1.534.7.1.3.1.1.16.1.12", NULL, SU_FLAG_OK, NULL }, /* pduGroupCurrentThUpperCritical.1.1 = INTEGER: 0 */ { "unmapped.pduGroupCurrentThUpperCritical", 0, 1, ".1.3.6.1.4.1.534.7.1.3.1.1.17.1.1", NULL, SU_FLAG_OK, NULL }, /* pduGroupCurrentThUpperCritical.1.2 = INTEGER: 0 */ { "unmapped.pduGroupCurrentThUpperCritical", 0, 1, ".1.3.6.1.4.1.534.7.1.3.1.1.17.1.2", NULL, SU_FLAG_OK, NULL }, /* pduGroupCurrentThUpperCritical.1.3 = INTEGER: 0 */ { "unmapped.pduGroupCurrentThUpperCritical", 0, 1, ".1.3.6.1.4.1.534.7.1.3.1.1.17.1.3", NULL, SU_FLAG_OK, NULL }, /* pduGroupCurrentThUpperCritical.1.4 = INTEGER: 0 */ { "unmapped.pduGroupCurrentThUpperCritical", 0, 1, ".1.3.6.1.4.1.534.7.1.3.1.1.17.1.4", NULL, SU_FLAG_OK, NULL }, /* pduGroupCurrentThUpperCritical.1.5 = INTEGER: 0 */ { "unmapped.pduGroupCurrentThUpperCritical", 0, 1, ".1.3.6.1.4.1.534.7.1.3.1.1.17.1.5", NULL, SU_FLAG_OK, NULL }, /* pduGroupCurrentThUpperCritical.1.6 = INTEGER: 0 */ { "unmapped.pduGroupCurrentThUpperCritical", 0, 1, ".1.3.6.1.4.1.534.7.1.3.1.1.17.1.6", NULL, SU_FLAG_OK, NULL }, /* pduGroupCurrentThUpperCritical.1.7 = INTEGER: 0 */ { "unmapped.pduGroupCurrentThUpperCritical", 0, 1, ".1.3.6.1.4.1.534.7.1.3.1.1.17.1.7", NULL, SU_FLAG_OK, NULL }, /* pduGroupCurrentThUpperCritical.1.8 = INTEGER: 0 */ { "unmapped.pduGroupCurrentThUpperCritical", 0, 1, ".1.3.6.1.4.1.534.7.1.3.1.1.17.1.8", NULL, SU_FLAG_OK, NULL }, /* pduGroupCurrentThUpperCritical.1.9 = INTEGER: 0 */ { "unmapped.pduGroupCurrentThUpperCritical", 0, 1, ".1.3.6.1.4.1.534.7.1.3.1.1.17.1.9", NULL, SU_FLAG_OK, NULL }, /* pduGroupCurrentThUpperCritical.1.10 = INTEGER: 0 */ { "unmapped.pduGroupCurrentThUpperCritical", 0, 1, ".1.3.6.1.4.1.534.7.1.3.1.1.17.1.10", NULL, SU_FLAG_OK, NULL }, /* pduGroupCurrentThUpperCritical.1.11 = INTEGER: 0 */ { "unmapped.pduGroupCurrentThUpperCritical", 0, 1, ".1.3.6.1.4.1.534.7.1.3.1.1.17.1.11", NULL, SU_FLAG_OK, NULL }, /* pduGroupCurrentThUpperCritical.1.12 = INTEGER: 0 */ { "unmapped.pduGroupCurrentThUpperCritical", 0, 1, ".1.3.6.1.4.1.534.7.1.3.1.1.17.1.12", NULL, SU_FLAG_OK, NULL }, /* pduGroupCurrentPercentLoad.1.1 = INTEGER: 0 */ { "unmapped.pduGroupCurrentPercentLoad", 0, 1, ".1.3.6.1.4.1.534.7.1.3.1.1.18.1.1", NULL, SU_FLAG_OK, NULL }, /* pduGroupCurrentPercentLoad.1.2 = INTEGER: 0 */ { "unmapped.pduGroupCurrentPercentLoad", 0, 1, ".1.3.6.1.4.1.534.7.1.3.1.1.18.1.2", NULL, SU_FLAG_OK, NULL }, /* pduGroupCurrentPercentLoad.1.3 = INTEGER: 0 */ { "unmapped.pduGroupCurrentPercentLoad", 0, 1, ".1.3.6.1.4.1.534.7.1.3.1.1.18.1.3", NULL, SU_FLAG_OK, NULL }, /* pduGroupCurrentPercentLoad.1.4 = INTEGER: 0 */ { "unmapped.pduGroupCurrentPercentLoad", 0, 1, ".1.3.6.1.4.1.534.7.1.3.1.1.18.1.4", NULL, SU_FLAG_OK, NULL }, /* pduGroupCurrentPercentLoad.1.5 = INTEGER: 0 */ { "unmapped.pduGroupCurrentPercentLoad", 0, 1, ".1.3.6.1.4.1.534.7.1.3.1.1.18.1.5", NULL, SU_FLAG_OK, NULL }, /* pduGroupCurrentPercentLoad.1.6 = INTEGER: 0 */ { "unmapped.pduGroupCurrentPercentLoad", 0, 1, ".1.3.6.1.4.1.534.7.1.3.1.1.18.1.6", NULL, SU_FLAG_OK, NULL }, /* pduGroupCurrentPercentLoad.1.7 = INTEGER: 0 */ { "unmapped.pduGroupCurrentPercentLoad", 0, 1, ".1.3.6.1.4.1.534.7.1.3.1.1.18.1.7", NULL, SU_FLAG_OK, NULL }, /* pduGroupCurrentPercentLoad.1.8 = INTEGER: 0 */ { "unmapped.pduGroupCurrentPercentLoad", 0, 1, ".1.3.6.1.4.1.534.7.1.3.1.1.18.1.8", NULL, SU_FLAG_OK, NULL }, /* pduGroupCurrentPercentLoad.1.9 = INTEGER: 0 */ { "unmapped.pduGroupCurrentPercentLoad", 0, 1, ".1.3.6.1.4.1.534.7.1.3.1.1.18.1.9", NULL, SU_FLAG_OK, NULL }, /* pduGroupCurrentPercentLoad.1.10 = INTEGER: 0 */ { "unmapped.pduGroupCurrentPercentLoad", 0, 1, ".1.3.6.1.4.1.534.7.1.3.1.1.18.1.10", NULL, SU_FLAG_OK, NULL }, /* pduGroupCurrentPercentLoad.1.11 = INTEGER: 0 */ { "unmapped.pduGroupCurrentPercentLoad", 0, 1, ".1.3.6.1.4.1.534.7.1.3.1.1.18.1.11", NULL, SU_FLAG_OK, NULL }, /* pduGroupCurrentPercentLoad.1.12 = INTEGER: 0 */ { "unmapped.pduGroupCurrentPercentLoad", 0, 1, ".1.3.6.1.4.1.534.7.1.3.1.1.18.1.12", NULL, SU_FLAG_OK, NULL }, /* pduGroupPowerVA.1.1 = INTEGER: 0 */ { "unmapped.pduGroupPowerVA", 0, 1, ".1.3.6.1.4.1.534.7.1.3.1.1.19.1.1", NULL, SU_FLAG_OK, NULL }, /* pduGroupPowerVA.1.2 = INTEGER: 0 */ { "unmapped.pduGroupPowerVA", 0, 1, ".1.3.6.1.4.1.534.7.1.3.1.1.19.1.2", NULL, SU_FLAG_OK, NULL }, /* pduGroupPowerVA.1.3 = INTEGER: 0 */ { "unmapped.pduGroupPowerVA", 0, 1, ".1.3.6.1.4.1.534.7.1.3.1.1.19.1.3", NULL, SU_FLAG_OK, NULL }, /* pduGroupPowerVA.1.4 = INTEGER: 0 */ { "unmapped.pduGroupPowerVA", 0, 1, ".1.3.6.1.4.1.534.7.1.3.1.1.19.1.4", NULL, SU_FLAG_OK, NULL }, /* pduGroupPowerVA.1.5 = INTEGER: 0 */ { "unmapped.pduGroupPowerVA", 0, 1, ".1.3.6.1.4.1.534.7.1.3.1.1.19.1.5", NULL, SU_FLAG_OK, NULL }, /* pduGroupPowerVA.1.6 = INTEGER: 0 */ { "unmapped.pduGroupPowerVA", 0, 1, ".1.3.6.1.4.1.534.7.1.3.1.1.19.1.6", NULL, SU_FLAG_OK, NULL }, /* pduGroupPowerVA.1.7 = INTEGER: 0 */ { "unmapped.pduGroupPowerVA", 0, 1, ".1.3.6.1.4.1.534.7.1.3.1.1.19.1.7", NULL, SU_FLAG_OK, NULL }, /* pduGroupPowerVA.1.8 = INTEGER: 0 */ { "unmapped.pduGroupPowerVA", 0, 1, ".1.3.6.1.4.1.534.7.1.3.1.1.19.1.8", NULL, SU_FLAG_OK, NULL }, /* pduGroupPowerVA.1.9 = INTEGER: 0 */ { "unmapped.pduGroupPowerVA", 0, 1, ".1.3.6.1.4.1.534.7.1.3.1.1.19.1.9", NULL, SU_FLAG_OK, NULL }, /* pduGroupPowerVA.1.10 = INTEGER: 0 */ { "unmapped.pduGroupPowerVA", 0, 1, ".1.3.6.1.4.1.534.7.1.3.1.1.19.1.10", NULL, SU_FLAG_OK, NULL }, /* pduGroupPowerVA.1.11 = INTEGER: 0 */ { "unmapped.pduGroupPowerVA", 0, 1, ".1.3.6.1.4.1.534.7.1.3.1.1.19.1.11", NULL, SU_FLAG_OK, NULL }, /* pduGroupPowerVA.1.12 = INTEGER: 0 */ { "unmapped.pduGroupPowerVA", 0, 1, ".1.3.6.1.4.1.534.7.1.3.1.1.19.1.12", NULL, SU_FLAG_OK, NULL }, /* pduGroupPowerWatts.1.1 = INTEGER: 0 */ { "unmapped.pduGroupPowerWatts", 0, 1, ".1.3.6.1.4.1.534.7.1.3.1.1.20.1.1", NULL, SU_FLAG_OK, NULL }, /* pduGroupPowerWatts.1.2 = INTEGER: 0 */ { "unmapped.pduGroupPowerWatts", 0, 1, ".1.3.6.1.4.1.534.7.1.3.1.1.20.1.2", NULL, SU_FLAG_OK, NULL }, /* pduGroupPowerWatts.1.3 = INTEGER: 0 */ { "unmapped.pduGroupPowerWatts", 0, 1, ".1.3.6.1.4.1.534.7.1.3.1.1.20.1.3", NULL, SU_FLAG_OK, NULL }, /* pduGroupPowerWatts.1.4 = INTEGER: 0 */ { "unmapped.pduGroupPowerWatts", 0, 1, ".1.3.6.1.4.1.534.7.1.3.1.1.20.1.4", NULL, SU_FLAG_OK, NULL }, /* pduGroupPowerWatts.1.5 = INTEGER: 0 */ { "unmapped.pduGroupPowerWatts", 0, 1, ".1.3.6.1.4.1.534.7.1.3.1.1.20.1.5", NULL, SU_FLAG_OK, NULL }, /* pduGroupPowerWatts.1.6 = INTEGER: 0 */ { "unmapped.pduGroupPowerWatts", 0, 1, ".1.3.6.1.4.1.534.7.1.3.1.1.20.1.6", NULL, SU_FLAG_OK, NULL }, /* pduGroupPowerWatts.1.7 = INTEGER: 0 */ { "unmapped.pduGroupPowerWatts", 0, 1, ".1.3.6.1.4.1.534.7.1.3.1.1.20.1.7", NULL, SU_FLAG_OK, NULL }, /* pduGroupPowerWatts.1.8 = INTEGER: 0 */ { "unmapped.pduGroupPowerWatts", 0, 1, ".1.3.6.1.4.1.534.7.1.3.1.1.20.1.8", NULL, SU_FLAG_OK, NULL }, /* pduGroupPowerWatts.1.9 = INTEGER: 0 */ { "unmapped.pduGroupPowerWatts", 0, 1, ".1.3.6.1.4.1.534.7.1.3.1.1.20.1.9", NULL, SU_FLAG_OK, NULL }, /* pduGroupPowerWatts.1.10 = INTEGER: 0 */ { "unmapped.pduGroupPowerWatts", 0, 1, ".1.3.6.1.4.1.534.7.1.3.1.1.20.1.10", NULL, SU_FLAG_OK, NULL }, /* pduGroupPowerWatts.1.11 = INTEGER: 0 */ { "unmapped.pduGroupPowerWatts", 0, 1, ".1.3.6.1.4.1.534.7.1.3.1.1.20.1.11", NULL, SU_FLAG_OK, NULL }, /* pduGroupPowerWatts.1.12 = INTEGER: 0 */ { "unmapped.pduGroupPowerWatts", 0, 1, ".1.3.6.1.4.1.534.7.1.3.1.1.20.1.12", NULL, SU_FLAG_OK, NULL }, /* pduGroupPowerWattHour.1.1 = INTEGER: 0 */ { "unmapped.pduGroupPowerWattHour", 0, 1, ".1.3.6.1.4.1.534.7.1.3.1.1.21.1.1", NULL, SU_FLAG_OK, NULL }, /* pduGroupPowerWattHour.1.2 = INTEGER: 0 */ { "unmapped.pduGroupPowerWattHour", 0, 1, ".1.3.6.1.4.1.534.7.1.3.1.1.21.1.2", NULL, SU_FLAG_OK, NULL }, /* pduGroupPowerWattHour.1.3 = INTEGER: 0 */ { "unmapped.pduGroupPowerWattHour", 0, 1, ".1.3.6.1.4.1.534.7.1.3.1.1.21.1.3", NULL, SU_FLAG_OK, NULL }, /* pduGroupPowerWattHour.1.4 = INTEGER: 0 */ { "unmapped.pduGroupPowerWattHour", 0, 1, ".1.3.6.1.4.1.534.7.1.3.1.1.21.1.4", NULL, SU_FLAG_OK, NULL }, /* pduGroupPowerWattHour.1.5 = INTEGER: 0 */ { "unmapped.pduGroupPowerWattHour", 0, 1, ".1.3.6.1.4.1.534.7.1.3.1.1.21.1.5", NULL, SU_FLAG_OK, NULL }, /* pduGroupPowerWattHour.1.6 = INTEGER: 0 */ { "unmapped.pduGroupPowerWattHour", 0, 1, ".1.3.6.1.4.1.534.7.1.3.1.1.21.1.6", NULL, SU_FLAG_OK, NULL }, /* pduGroupPowerWattHour.1.7 = INTEGER: 0 */ { "unmapped.pduGroupPowerWattHour", 0, 1, ".1.3.6.1.4.1.534.7.1.3.1.1.21.1.7", NULL, SU_FLAG_OK, NULL }, /* pduGroupPowerWattHour.1.8 = INTEGER: 0 */ { "unmapped.pduGroupPowerWattHour", 0, 1, ".1.3.6.1.4.1.534.7.1.3.1.1.21.1.8", NULL, SU_FLAG_OK, NULL }, /* pduGroupPowerWattHour.1.9 = INTEGER: 0 */ { "unmapped.pduGroupPowerWattHour", 0, 1, ".1.3.6.1.4.1.534.7.1.3.1.1.21.1.9", NULL, SU_FLAG_OK, NULL }, /* pduGroupPowerWattHour.1.10 = INTEGER: 0 */ { "unmapped.pduGroupPowerWattHour", 0, 1, ".1.3.6.1.4.1.534.7.1.3.1.1.21.1.10", NULL, SU_FLAG_OK, NULL }, /* pduGroupPowerWattHour.1.11 = INTEGER: 0 */ { "unmapped.pduGroupPowerWattHour", 0, 1, ".1.3.6.1.4.1.534.7.1.3.1.1.21.1.11", NULL, SU_FLAG_OK, NULL }, /* pduGroupPowerWattHour.1.12 = INTEGER: 0 */ { "unmapped.pduGroupPowerWattHour", 0, 1, ".1.3.6.1.4.1.534.7.1.3.1.1.21.1.12", NULL, SU_FLAG_OK, NULL }, /* pduGroupPowerWattHourTimer.1.1 = Hex-STRING: 32 30 32 31 2F 30 35 2F 32 39 20 30 39 3A 30 36 */ { "unmapped.pduGroupPowerWattHourTimer", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.534.7.1.3.1.1.22.1.1", NULL, SU_FLAG_OK, NULL }, /* pduGroupPowerWattHourTimer.1.2 = Hex-STRING: 32 30 32 31 2F 30 35 2F 32 39 20 30 39 3A 30 36 */ { "unmapped.pduGroupPowerWattHourTimer", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.534.7.1.3.1.1.22.1.2", NULL, SU_FLAG_OK, NULL }, /* pduGroupPowerWattHourTimer.1.3 = Hex-STRING: 32 30 32 31 2F 30 35 2F 32 39 20 30 39 3A 30 36 */ { "unmapped.pduGroupPowerWattHourTimer", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.534.7.1.3.1.1.22.1.3", NULL, SU_FLAG_OK, NULL }, /* pduGroupPowerWattHourTimer.1.4 = Hex-STRING: 32 30 32 31 2F 30 35 2F 32 39 20 30 39 3A 30 36 */ { "unmapped.pduGroupPowerWattHourTimer", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.534.7.1.3.1.1.22.1.4", NULL, SU_FLAG_OK, NULL }, /* pduGroupPowerWattHourTimer.1.5 = Hex-STRING: 32 30 32 31 2F 30 35 2F 32 39 20 30 39 3A 30 36 */ { "unmapped.pduGroupPowerWattHourTimer", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.534.7.1.3.1.1.22.1.5", NULL, SU_FLAG_OK, NULL }, /* pduGroupPowerWattHourTimer.1.6 = Hex-STRING: 32 30 32 31 2F 30 35 2F 32 39 20 30 39 3A 30 36 */ { "unmapped.pduGroupPowerWattHourTimer", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.534.7.1.3.1.1.22.1.6", NULL, SU_FLAG_OK, NULL }, /* pduGroupPowerWattHourTimer.1.7 = Hex-STRING: 32 30 32 31 2F 30 35 2F 32 39 20 30 39 3A 30 36 */ { "unmapped.pduGroupPowerWattHourTimer", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.534.7.1.3.1.1.22.1.7", NULL, SU_FLAG_OK, NULL }, /* pduGroupPowerWattHourTimer.1.8 = Hex-STRING: 32 30 32 31 2F 30 35 2F 32 39 20 30 39 3A 30 36 */ { "unmapped.pduGroupPowerWattHourTimer", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.534.7.1.3.1.1.22.1.8", NULL, SU_FLAG_OK, NULL }, /* pduGroupPowerWattHourTimer.1.9 = Hex-STRING: 32 30 32 31 2F 30 35 2F 32 39 20 30 39 3A 30 36 */ { "unmapped.pduGroupPowerWattHourTimer", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.534.7.1.3.1.1.22.1.9", NULL, SU_FLAG_OK, NULL }, /* pduGroupPowerWattHourTimer.1.10 = Hex-STRING: 32 30 32 31 2F 30 35 2F 32 39 20 30 39 3A 30 36 */ { "unmapped.pduGroupPowerWattHourTimer", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.534.7.1.3.1.1.22.1.10", NULL, SU_FLAG_OK, NULL }, /* pduGroupPowerWattHourTimer.1.11 = Hex-STRING: 32 30 32 31 2F 30 35 2F 32 39 20 30 39 3A 30 36 */ { "unmapped.pduGroupPowerWattHourTimer", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.534.7.1.3.1.1.22.1.11", NULL, SU_FLAG_OK, NULL }, /* pduGroupPowerWattHourTimer.1.12 = Hex-STRING: 32 30 32 31 2F 30 35 2F 32 39 20 30 39 3A 30 36 */ { "unmapped.pduGroupPowerWattHourTimer", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.534.7.1.3.1.1.22.1.12", NULL, SU_FLAG_OK, NULL }, /* pduGroupPowerFactor.1.1 = INTEGER: 100 */ { "unmapped.pduGroupPowerFactor", 0, 1, ".1.3.6.1.4.1.534.7.1.3.1.1.23.1.1", NULL, SU_FLAG_OK, NULL }, /* pduGroupPowerFactor.1.2 = INTEGER: 0 */ { "unmapped.pduGroupPowerFactor", 0, 1, ".1.3.6.1.4.1.534.7.1.3.1.1.23.1.2", NULL, SU_FLAG_OK, NULL }, /* pduGroupPowerFactor.1.3 = INTEGER: 0 */ { "unmapped.pduGroupPowerFactor", 0, 1, ".1.3.6.1.4.1.534.7.1.3.1.1.23.1.3", NULL, SU_FLAG_OK, NULL }, /* pduGroupPowerFactor.1.4 = INTEGER: 0 */ { "unmapped.pduGroupPowerFactor", 0, 1, ".1.3.6.1.4.1.534.7.1.3.1.1.23.1.4", NULL, SU_FLAG_OK, NULL }, /* pduGroupPowerFactor.1.5 = INTEGER: 0 */ { "unmapped.pduGroupPowerFactor", 0, 1, ".1.3.6.1.4.1.534.7.1.3.1.1.23.1.5", NULL, SU_FLAG_OK, NULL }, /* pduGroupPowerFactor.1.6 = INTEGER: 0 */ { "unmapped.pduGroupPowerFactor", 0, 1, ".1.3.6.1.4.1.534.7.1.3.1.1.23.1.6", NULL, SU_FLAG_OK, NULL }, /* pduGroupPowerFactor.1.7 = INTEGER: 0 */ { "unmapped.pduGroupPowerFactor", 0, 1, ".1.3.6.1.4.1.534.7.1.3.1.1.23.1.7", NULL, SU_FLAG_OK, NULL }, /* pduGroupPowerFactor.1.8 = INTEGER: 0 */ { "unmapped.pduGroupPowerFactor", 0, 1, ".1.3.6.1.4.1.534.7.1.3.1.1.23.1.8", NULL, SU_FLAG_OK, NULL }, /* pduGroupPowerFactor.1.9 = INTEGER: 0 */ { "unmapped.pduGroupPowerFactor", 0, 1, ".1.3.6.1.4.1.534.7.1.3.1.1.23.1.9", NULL, SU_FLAG_OK, NULL }, /* pduGroupPowerFactor.1.10 = INTEGER: 0 */ { "unmapped.pduGroupPowerFactor", 0, 1, ".1.3.6.1.4.1.534.7.1.3.1.1.23.1.10", NULL, SU_FLAG_OK, NULL }, /* pduGroupPowerFactor.1.11 = INTEGER: 0 */ { "unmapped.pduGroupPowerFactor", 0, 1, ".1.3.6.1.4.1.534.7.1.3.1.1.23.1.11", NULL, SU_FLAG_OK, NULL }, /* pduGroupPowerFactor.1.12 = INTEGER: 0 */ { "unmapped.pduGroupPowerFactor", 0, 1, ".1.3.6.1.4.1.534.7.1.3.1.1.23.1.12", NULL, SU_FLAG_OK, NULL }, /* pduGroupPowerVAR.1.1 = INTEGER: 0 */ { "unmapped.pduGroupPowerVAR", 0, 1, ".1.3.6.1.4.1.534.7.1.3.1.1.24.1.1", NULL, SU_FLAG_OK, NULL }, /* pduGroupPowerVAR.1.2 = INTEGER: 0 */ { "unmapped.pduGroupPowerVAR", 0, 1, ".1.3.6.1.4.1.534.7.1.3.1.1.24.1.2", NULL, SU_FLAG_OK, NULL }, /* pduGroupPowerVAR.1.3 = INTEGER: 0 */ { "unmapped.pduGroupPowerVAR", 0, 1, ".1.3.6.1.4.1.534.7.1.3.1.1.24.1.3", NULL, SU_FLAG_OK, NULL }, /* pduGroupPowerVAR.1.4 = INTEGER: 0 */ { "unmapped.pduGroupPowerVAR", 0, 1, ".1.3.6.1.4.1.534.7.1.3.1.1.24.1.4", NULL, SU_FLAG_OK, NULL }, /* pduGroupPowerVAR.1.5 = INTEGER: 0 */ { "unmapped.pduGroupPowerVAR", 0, 1, ".1.3.6.1.4.1.534.7.1.3.1.1.24.1.5", NULL, SU_FLAG_OK, NULL }, /* pduGroupPowerVAR.1.6 = INTEGER: 0 */ { "unmapped.pduGroupPowerVAR", 0, 1, ".1.3.6.1.4.1.534.7.1.3.1.1.24.1.6", NULL, SU_FLAG_OK, NULL }, /* pduGroupPowerVAR.1.7 = INTEGER: 0 */ { "unmapped.pduGroupPowerVAR", 0, 1, ".1.3.6.1.4.1.534.7.1.3.1.1.24.1.7", NULL, SU_FLAG_OK, NULL }, /* pduGroupPowerVAR.1.8 = INTEGER: 0 */ { "unmapped.pduGroupPowerVAR", 0, 1, ".1.3.6.1.4.1.534.7.1.3.1.1.24.1.8", NULL, SU_FLAG_OK, NULL }, /* pduGroupPowerVAR.1.9 = INTEGER: 0 */ { "unmapped.pduGroupPowerVAR", 0, 1, ".1.3.6.1.4.1.534.7.1.3.1.1.24.1.9", NULL, SU_FLAG_OK, NULL }, /* pduGroupPowerVAR.1.10 = INTEGER: 0 */ { "unmapped.pduGroupPowerVAR", 0, 1, ".1.3.6.1.4.1.534.7.1.3.1.1.24.1.10", NULL, SU_FLAG_OK, NULL }, /* pduGroupPowerVAR.1.11 = INTEGER: 0 */ { "unmapped.pduGroupPowerVAR", 0, 1, ".1.3.6.1.4.1.534.7.1.3.1.1.24.1.11", NULL, SU_FLAG_OK, NULL }, /* pduGroupPowerVAR.1.12 = INTEGER: 0 */ { "unmapped.pduGroupPowerVAR", 0, 1, ".1.3.6.1.4.1.534.7.1.3.1.1.24.1.12", NULL, SU_FLAG_OK, NULL }, /* pduGroupOutletCount.1.1 = INTEGER: 6 */ { "unmapped.pduGroupOutletCount", 0, 1, ".1.3.6.1.4.1.534.7.1.3.1.1.25.1.1", NULL, SU_FLAG_OK, NULL }, /* pduGroupOutletCount.1.2 = INTEGER: 0 */ { "unmapped.pduGroupOutletCount", 0, 1, ".1.3.6.1.4.1.534.7.1.3.1.1.25.1.2", NULL, SU_FLAG_OK, NULL }, /* pduGroupOutletCount.1.3 = INTEGER: 0 */ { "unmapped.pduGroupOutletCount", 0, 1, ".1.3.6.1.4.1.534.7.1.3.1.1.25.1.3", NULL, SU_FLAG_OK, NULL }, /* pduGroupOutletCount.1.4 = INTEGER: 0 */ { "unmapped.pduGroupOutletCount", 0, 1, ".1.3.6.1.4.1.534.7.1.3.1.1.25.1.4", NULL, SU_FLAG_OK, NULL }, /* pduGroupOutletCount.1.5 = INTEGER: 0 */ { "unmapped.pduGroupOutletCount", 0, 1, ".1.3.6.1.4.1.534.7.1.3.1.1.25.1.5", NULL, SU_FLAG_OK, NULL }, /* pduGroupOutletCount.1.6 = INTEGER: 0 */ { "unmapped.pduGroupOutletCount", 0, 1, ".1.3.6.1.4.1.534.7.1.3.1.1.25.1.6", NULL, SU_FLAG_OK, NULL }, /* pduGroupOutletCount.1.7 = INTEGER: 0 */ { "unmapped.pduGroupOutletCount", 0, 1, ".1.3.6.1.4.1.534.7.1.3.1.1.25.1.7", NULL, SU_FLAG_OK, NULL }, /* pduGroupOutletCount.1.8 = INTEGER: 0 */ { "unmapped.pduGroupOutletCount", 0, 1, ".1.3.6.1.4.1.534.7.1.3.1.1.25.1.8", NULL, SU_FLAG_OK, NULL }, /* pduGroupOutletCount.1.9 = INTEGER: 0 */ { "unmapped.pduGroupOutletCount", 0, 1, ".1.3.6.1.4.1.534.7.1.3.1.1.25.1.9", NULL, SU_FLAG_OK, NULL }, /* pduGroupOutletCount.1.10 = INTEGER: 0 */ { "unmapped.pduGroupOutletCount", 0, 1, ".1.3.6.1.4.1.534.7.1.3.1.1.25.1.10", NULL, SU_FLAG_OK, NULL }, /* pduGroupOutletCount.1.11 = INTEGER: 0 */ { "unmapped.pduGroupOutletCount", 0, 1, ".1.3.6.1.4.1.534.7.1.3.1.1.25.1.11", NULL, SU_FLAG_OK, NULL }, /* pduGroupOutletCount.1.12 = INTEGER: 0 */ { "unmapped.pduGroupOutletCount", 0, 1, ".1.3.6.1.4.1.534.7.1.3.1.1.25.1.12", NULL, SU_FLAG_OK, NULL }, /* pduGroupBreakerStatus.1.1 = INTEGER: 0 */ { "unmapped.pduGroupBreakerStatus", 0, 1, ".1.3.6.1.4.1.534.7.1.3.1.1.26.1.1", NULL, SU_FLAG_OK, NULL }, /* pduGroupBreakerStatus.1.2 = INTEGER: 0 */ { "unmapped.pduGroupBreakerStatus", 0, 1, ".1.3.6.1.4.1.534.7.1.3.1.1.26.1.2", NULL, SU_FLAG_OK, NULL }, /* pduGroupBreakerStatus.1.3 = INTEGER: 0 */ { "unmapped.pduGroupBreakerStatus", 0, 1, ".1.3.6.1.4.1.534.7.1.3.1.1.26.1.3", NULL, SU_FLAG_OK, NULL }, /* pduGroupBreakerStatus.1.4 = INTEGER: 0 */ { "unmapped.pduGroupBreakerStatus", 0, 1, ".1.3.6.1.4.1.534.7.1.3.1.1.26.1.4", NULL, SU_FLAG_OK, NULL }, /* pduGroupBreakerStatus.1.5 = INTEGER: 0 */ { "unmapped.pduGroupBreakerStatus", 0, 1, ".1.3.6.1.4.1.534.7.1.3.1.1.26.1.5", NULL, SU_FLAG_OK, NULL }, /* pduGroupBreakerStatus.1.6 = INTEGER: 0 */ { "unmapped.pduGroupBreakerStatus", 0, 1, ".1.3.6.1.4.1.534.7.1.3.1.1.26.1.6", NULL, SU_FLAG_OK, NULL }, /* pduGroupBreakerStatus.1.7 = INTEGER: 0 */ { "unmapped.pduGroupBreakerStatus", 0, 1, ".1.3.6.1.4.1.534.7.1.3.1.1.26.1.7", NULL, SU_FLAG_OK, NULL }, /* pduGroupBreakerStatus.1.8 = INTEGER: 0 */ { "unmapped.pduGroupBreakerStatus", 0, 1, ".1.3.6.1.4.1.534.7.1.3.1.1.26.1.8", NULL, SU_FLAG_OK, NULL }, /* pduGroupBreakerStatus.1.9 = INTEGER: 0 */ { "unmapped.pduGroupBreakerStatus", 0, 1, ".1.3.6.1.4.1.534.7.1.3.1.1.26.1.9", NULL, SU_FLAG_OK, NULL }, /* pduGroupBreakerStatus.1.10 = INTEGER: 0 */ { "unmapped.pduGroupBreakerStatus", 0, 1, ".1.3.6.1.4.1.534.7.1.3.1.1.26.1.10", NULL, SU_FLAG_OK, NULL }, /* pduGroupBreakerStatus.1.11 = INTEGER: 0 */ { "unmapped.pduGroupBreakerStatus", 0, 1, ".1.3.6.1.4.1.534.7.1.3.1.1.26.1.11", NULL, SU_FLAG_OK, NULL }, /* pduGroupBreakerStatus.1.12 = INTEGER: 0 */ { "unmapped.pduGroupBreakerStatus", 0, 1, ".1.3.6.1.4.1.534.7.1.3.1.1.26.1.12", NULL, SU_FLAG_OK, NULL }, /* pduGroupVoltageThCtrl.1.1 = INTEGER: 0 */ { "unmapped.pduGroupVoltageThCtrl", 0, 1, ".1.3.6.1.4.1.534.7.1.3.1.1.27.1.1", NULL, SU_FLAG_OK, NULL }, /* pduGroupVoltageThCtrl.1.2 = INTEGER: 0 */ { "unmapped.pduGroupVoltageThCtrl", 0, 1, ".1.3.6.1.4.1.534.7.1.3.1.1.27.1.2", NULL, SU_FLAG_OK, NULL }, /* pduGroupVoltageThCtrl.1.3 = INTEGER: 0 */ { "unmapped.pduGroupVoltageThCtrl", 0, 1, ".1.3.6.1.4.1.534.7.1.3.1.1.27.1.3", NULL, SU_FLAG_OK, NULL }, /* pduGroupVoltageThCtrl.1.4 = INTEGER: 0 */ { "unmapped.pduGroupVoltageThCtrl", 0, 1, ".1.3.6.1.4.1.534.7.1.3.1.1.27.1.4", NULL, SU_FLAG_OK, NULL }, /* pduGroupVoltageThCtrl.1.5 = INTEGER: 0 */ { "unmapped.pduGroupVoltageThCtrl", 0, 1, ".1.3.6.1.4.1.534.7.1.3.1.1.27.1.5", NULL, SU_FLAG_OK, NULL }, /* pduGroupVoltageThCtrl.1.6 = INTEGER: 0 */ { "unmapped.pduGroupVoltageThCtrl", 0, 1, ".1.3.6.1.4.1.534.7.1.3.1.1.27.1.6", NULL, SU_FLAG_OK, NULL }, /* pduGroupVoltageThCtrl.1.7 = INTEGER: 0 */ { "unmapped.pduGroupVoltageThCtrl", 0, 1, ".1.3.6.1.4.1.534.7.1.3.1.1.27.1.7", NULL, SU_FLAG_OK, NULL }, /* pduGroupVoltageThCtrl.1.8 = INTEGER: 0 */ { "unmapped.pduGroupVoltageThCtrl", 0, 1, ".1.3.6.1.4.1.534.7.1.3.1.1.27.1.8", NULL, SU_FLAG_OK, NULL }, /* pduGroupVoltageThCtrl.1.9 = INTEGER: 0 */ { "unmapped.pduGroupVoltageThCtrl", 0, 1, ".1.3.6.1.4.1.534.7.1.3.1.1.27.1.9", NULL, SU_FLAG_OK, NULL }, /* pduGroupVoltageThCtrl.1.10 = INTEGER: 0 */ { "unmapped.pduGroupVoltageThCtrl", 0, 1, ".1.3.6.1.4.1.534.7.1.3.1.1.27.1.10", NULL, SU_FLAG_OK, NULL }, /* pduGroupVoltageThCtrl.1.11 = INTEGER: 0 */ { "unmapped.pduGroupVoltageThCtrl", 0, 1, ".1.3.6.1.4.1.534.7.1.3.1.1.27.1.11", NULL, SU_FLAG_OK, NULL }, /* pduGroupVoltageThCtrl.1.12 = INTEGER: 0 */ { "unmapped.pduGroupVoltageThCtrl", 0, 1, ".1.3.6.1.4.1.534.7.1.3.1.1.27.1.12", NULL, SU_FLAG_OK, NULL }, /* pduGroupCurrentThCtrl.1.1 = INTEGER: 0 */ { "unmapped.pduGroupCurrentThCtrl", 0, 1, ".1.3.6.1.4.1.534.7.1.3.1.1.28.1.1", NULL, SU_FLAG_OK, NULL }, /* pduGroupCurrentThCtrl.1.2 = INTEGER: 0 */ { "unmapped.pduGroupCurrentThCtrl", 0, 1, ".1.3.6.1.4.1.534.7.1.3.1.1.28.1.2", NULL, SU_FLAG_OK, NULL }, /* pduGroupCurrentThCtrl.1.3 = INTEGER: 0 */ { "unmapped.pduGroupCurrentThCtrl", 0, 1, ".1.3.6.1.4.1.534.7.1.3.1.1.28.1.3", NULL, SU_FLAG_OK, NULL }, /* pduGroupCurrentThCtrl.1.4 = INTEGER: 0 */ { "unmapped.pduGroupCurrentThCtrl", 0, 1, ".1.3.6.1.4.1.534.7.1.3.1.1.28.1.4", NULL, SU_FLAG_OK, NULL }, /* pduGroupCurrentThCtrl.1.5 = INTEGER: 0 */ { "unmapped.pduGroupCurrentThCtrl", 0, 1, ".1.3.6.1.4.1.534.7.1.3.1.1.28.1.5", NULL, SU_FLAG_OK, NULL }, /* pduGroupCurrentThCtrl.1.6 = INTEGER: 0 */ { "unmapped.pduGroupCurrentThCtrl", 0, 1, ".1.3.6.1.4.1.534.7.1.3.1.1.28.1.6", NULL, SU_FLAG_OK, NULL }, /* pduGroupCurrentThCtrl.1.7 = INTEGER: 0 */ { "unmapped.pduGroupCurrentThCtrl", 0, 1, ".1.3.6.1.4.1.534.7.1.3.1.1.28.1.7", NULL, SU_FLAG_OK, NULL }, /* pduGroupCurrentThCtrl.1.8 = INTEGER: 0 */ { "unmapped.pduGroupCurrentThCtrl", 0, 1, ".1.3.6.1.4.1.534.7.1.3.1.1.28.1.8", NULL, SU_FLAG_OK, NULL }, /* pduGroupCurrentThCtrl.1.9 = INTEGER: 0 */ { "unmapped.pduGroupCurrentThCtrl", 0, 1, ".1.3.6.1.4.1.534.7.1.3.1.1.28.1.9", NULL, SU_FLAG_OK, NULL }, /* pduGroupCurrentThCtrl.1.10 = INTEGER: 0 */ { "unmapped.pduGroupCurrentThCtrl", 0, 1, ".1.3.6.1.4.1.534.7.1.3.1.1.28.1.10", NULL, SU_FLAG_OK, NULL }, /* pduGroupCurrentThCtrl.1.11 = INTEGER: 0 */ { "unmapped.pduGroupCurrentThCtrl", 0, 1, ".1.3.6.1.4.1.534.7.1.3.1.1.28.1.11", NULL, SU_FLAG_OK, NULL }, /* pduGroupCurrentThCtrl.1.12 = INTEGER: 0 */ { "unmapped.pduGroupCurrentThCtrl", 0, 1, ".1.3.6.1.4.1.534.7.1.3.1.1.28.1.12", NULL, SU_FLAG_OK, NULL }, /* pduTemperatureScale.1 = INTEGER: 1 */ { "unmapped.pduTemperatureScale", 0, 1, ".1.3.6.1.4.1.534.7.1.4.1.1.1.1", NULL, SU_FLAG_OK, NULL }, /* pduTemperatureCount.1 = INTEGER: 0 */ { "unmapped.pduTemperatureCount", 0, 1, ".1.3.6.1.4.1.534.7.1.4.1.1.2.1", NULL, SU_FLAG_OK, NULL }, /* pduHumidityCount.1 = INTEGER: 0 */ { "unmapped.pduHumidityCount", 0, 1, ".1.3.6.1.4.1.534.7.1.4.1.1.3.1", NULL, SU_FLAG_OK, NULL }, /* pduDoorCount.1 = INTEGER: 0 */ { "unmapped.pduDoorCount", 0, 1, ".1.3.6.1.4.1.534.7.1.4.1.1.4.1", NULL, SU_FLAG_OK, NULL }, /* pduDryCount.1 = INTEGER: 0 */ { "unmapped.pduDryCount", 0, 1, ".1.3.6.1.4.1.534.7.1.4.1.1.5.1", NULL, SU_FLAG_OK, NULL }, /* pduSpotCount.1 = INTEGER: 0 */ { "unmapped.pduSpotCount", 0, 1, ".1.3.6.1.4.1.534.7.1.4.1.1.6.1", NULL, SU_FLAG_OK, NULL }, /* pduRopeCount.1 = INTEGER: 0 */ { "unmapped.pduRopeCount", 0, 1, ".1.3.6.1.4.1.534.7.1.4.1.1.7.1", NULL, SU_FLAG_OK, NULL }, /* pduHidCount.1 = INTEGER: 0 */ { "unmapped.pduHidCount", 0, 1, ".1.3.6.1.4.1.534.7.1.4.1.1.10.1", NULL, SU_FLAG_OK, NULL }, /* pduTemperatureIndex.1.1 = INTEGER: 0 */ { "unmapped.pduTemperatureIndex", 0, 1, ".1.3.6.1.4.1.534.7.1.4.2.1.1.1.1", NULL, SU_FLAG_OK, NULL }, /* pduTemperatureIndex.1.2 = INTEGER: 0 */ { "unmapped.pduTemperatureIndex", 0, 1, ".1.3.6.1.4.1.534.7.1.4.2.1.1.1.2", NULL, SU_FLAG_OK, NULL }, /* pduTemperatureIndex.1.3 = INTEGER: 0 */ { "unmapped.pduTemperatureIndex", 0, 1, ".1.3.6.1.4.1.534.7.1.4.2.1.1.1.3", NULL, SU_FLAG_OK, NULL }, /* pduTemperatureIndex.1.4 = INTEGER: 0 */ { "unmapped.pduTemperatureIndex", 0, 1, ".1.3.6.1.4.1.534.7.1.4.2.1.1.1.4", NULL, SU_FLAG_OK, NULL }, /* pduTemperatureIndex.1.5 = INTEGER: 0 */ { "unmapped.pduTemperatureIndex", 0, 1, ".1.3.6.1.4.1.534.7.1.4.2.1.1.1.5", NULL, SU_FLAG_OK, NULL }, /* pduTemperatureIndex.1.6 = INTEGER: 0 */ { "unmapped.pduTemperatureIndex", 0, 1, ".1.3.6.1.4.1.534.7.1.4.2.1.1.1.6", NULL, SU_FLAG_OK, NULL }, /* pduTemperatureName.1.1 = STRING: " " */ { "unmapped.pduTemperatureName", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.534.7.1.4.2.1.2.1.1", NULL, SU_FLAG_OK, NULL }, /* pduTemperatureName.1.2 = STRING: " " */ { "unmapped.pduTemperatureName", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.534.7.1.4.2.1.2.1.2", NULL, SU_FLAG_OK, NULL }, /* pduTemperatureName.1.3 = STRING: " " */ { "unmapped.pduTemperatureName", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.534.7.1.4.2.1.2.1.3", NULL, SU_FLAG_OK, NULL }, /* pduTemperatureName.1.4 = STRING: " " */ { "unmapped.pduTemperatureName", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.534.7.1.4.2.1.2.1.4", NULL, SU_FLAG_OK, NULL }, /* pduTemperatureName.1.5 = STRING: " " */ { "unmapped.pduTemperatureName", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.534.7.1.4.2.1.2.1.5", NULL, SU_FLAG_OK, NULL }, /* pduTemperatureName.1.6 = STRING: " " */ { "unmapped.pduTemperatureName", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.534.7.1.4.2.1.2.1.6", NULL, SU_FLAG_OK, NULL }, /* pduTemperatureProbeStatus.1.1 = INTEGER: 1 */ { "unmapped.pduTemperatureProbeStatus", 0, 1, ".1.3.6.1.4.1.534.7.1.4.2.1.3.1.1", NULL, SU_FLAG_OK, NULL }, /* pduTemperatureProbeStatus.1.2 = INTEGER: 1 */ { "unmapped.pduTemperatureProbeStatus", 0, 1, ".1.3.6.1.4.1.534.7.1.4.2.1.3.1.2", NULL, SU_FLAG_OK, NULL }, /* pduTemperatureProbeStatus.1.3 = INTEGER: 1 */ { "unmapped.pduTemperatureProbeStatus", 0, 1, ".1.3.6.1.4.1.534.7.1.4.2.1.3.1.3", NULL, SU_FLAG_OK, NULL }, /* pduTemperatureProbeStatus.1.4 = INTEGER: 1 */ { "unmapped.pduTemperatureProbeStatus", 0, 1, ".1.3.6.1.4.1.534.7.1.4.2.1.3.1.4", NULL, SU_FLAG_OK, NULL }, /* pduTemperatureProbeStatus.1.5 = INTEGER: 1 */ { "unmapped.pduTemperatureProbeStatus", 0, 1, ".1.3.6.1.4.1.534.7.1.4.2.1.3.1.5", NULL, SU_FLAG_OK, NULL }, /* pduTemperatureProbeStatus.1.6 = INTEGER: 1 */ { "unmapped.pduTemperatureProbeStatus", 0, 1, ".1.3.6.1.4.1.534.7.1.4.2.1.3.1.6", NULL, SU_FLAG_OK, NULL }, /* pduTemperatureValue.1.1 = INTEGER: 0 */ { "unmapped.pduTemperatureValue", 0, 1, ".1.3.6.1.4.1.534.7.1.4.2.1.4.1.1", NULL, SU_FLAG_OK, NULL }, /* pduTemperatureValue.1.2 = INTEGER: 0 */ { "unmapped.pduTemperatureValue", 0, 1, ".1.3.6.1.4.1.534.7.1.4.2.1.4.1.2", NULL, SU_FLAG_OK, NULL }, /* pduTemperatureValue.1.3 = INTEGER: 0 */ { "unmapped.pduTemperatureValue", 0, 1, ".1.3.6.1.4.1.534.7.1.4.2.1.4.1.3", NULL, SU_FLAG_OK, NULL }, /* pduTemperatureValue.1.4 = INTEGER: 0 */ { "unmapped.pduTemperatureValue", 0, 1, ".1.3.6.1.4.1.534.7.1.4.2.1.4.1.4", NULL, SU_FLAG_OK, NULL }, /* pduTemperatureValue.1.5 = INTEGER: 0 */ { "unmapped.pduTemperatureValue", 0, 1, ".1.3.6.1.4.1.534.7.1.4.2.1.4.1.5", NULL, SU_FLAG_OK, NULL }, /* pduTemperatureValue.1.6 = INTEGER: 0 */ { "unmapped.pduTemperatureValue", 0, 1, ".1.3.6.1.4.1.534.7.1.4.2.1.4.1.6", NULL, SU_FLAG_OK, NULL }, /* pduTemperatureThStatus.1.1 = INTEGER: 0 */ { "unmapped.pduTemperatureThStatus", 0, 1, ".1.3.6.1.4.1.534.7.1.4.2.1.5.1.1", NULL, SU_FLAG_OK, NULL }, /* pduTemperatureThStatus.1.2 = INTEGER: 0 */ { "unmapped.pduTemperatureThStatus", 0, 1, ".1.3.6.1.4.1.534.7.1.4.2.1.5.1.2", NULL, SU_FLAG_OK, NULL }, /* pduTemperatureThStatus.1.3 = INTEGER: 0 */ { "unmapped.pduTemperatureThStatus", 0, 1, ".1.3.6.1.4.1.534.7.1.4.2.1.5.1.3", NULL, SU_FLAG_OK, NULL }, /* pduTemperatureThStatus.1.4 = INTEGER: 0 */ { "unmapped.pduTemperatureThStatus", 0, 1, ".1.3.6.1.4.1.534.7.1.4.2.1.5.1.4", NULL, SU_FLAG_OK, NULL }, /* pduTemperatureThStatus.1.5 = INTEGER: 0 */ { "unmapped.pduTemperatureThStatus", 0, 1, ".1.3.6.1.4.1.534.7.1.4.2.1.5.1.5", NULL, SU_FLAG_OK, NULL }, /* pduTemperatureThStatus.1.6 = INTEGER: 0 */ { "unmapped.pduTemperatureThStatus", 0, 1, ".1.3.6.1.4.1.534.7.1.4.2.1.5.1.6", NULL, SU_FLAG_OK, NULL }, /* pduTemperatureThLowerWarning.1.1 = INTEGER: 0 */ { "unmapped.pduTemperatureThLowerWarning", 0, 1, ".1.3.6.1.4.1.534.7.1.4.2.1.6.1.1", NULL, SU_FLAG_OK, NULL }, /* pduTemperatureThLowerWarning.1.2 = INTEGER: 0 */ { "unmapped.pduTemperatureThLowerWarning", 0, 1, ".1.3.6.1.4.1.534.7.1.4.2.1.6.1.2", NULL, SU_FLAG_OK, NULL }, /* pduTemperatureThLowerWarning.1.3 = INTEGER: 0 */ { "unmapped.pduTemperatureThLowerWarning", 0, 1, ".1.3.6.1.4.1.534.7.1.4.2.1.6.1.3", NULL, SU_FLAG_OK, NULL }, /* pduTemperatureThLowerWarning.1.4 = INTEGER: 0 */ { "unmapped.pduTemperatureThLowerWarning", 0, 1, ".1.3.6.1.4.1.534.7.1.4.2.1.6.1.4", NULL, SU_FLAG_OK, NULL }, /* pduTemperatureThLowerWarning.1.5 = INTEGER: 0 */ { "unmapped.pduTemperatureThLowerWarning", 0, 1, ".1.3.6.1.4.1.534.7.1.4.2.1.6.1.5", NULL, SU_FLAG_OK, NULL }, /* pduTemperatureThLowerWarning.1.6 = INTEGER: 0 */ { "unmapped.pduTemperatureThLowerWarning", 0, 1, ".1.3.6.1.4.1.534.7.1.4.2.1.6.1.6", NULL, SU_FLAG_OK, NULL }, /* pduTemperatureThLowerCritical.1.1 = INTEGER: 0 */ { "unmapped.pduTemperatureThLowerCritical", 0, 1, ".1.3.6.1.4.1.534.7.1.4.2.1.7.1.1", NULL, SU_FLAG_OK, NULL }, /* pduTemperatureThLowerCritical.1.2 = INTEGER: 0 */ { "unmapped.pduTemperatureThLowerCritical", 0, 1, ".1.3.6.1.4.1.534.7.1.4.2.1.7.1.2", NULL, SU_FLAG_OK, NULL }, /* pduTemperatureThLowerCritical.1.3 = INTEGER: 0 */ { "unmapped.pduTemperatureThLowerCritical", 0, 1, ".1.3.6.1.4.1.534.7.1.4.2.1.7.1.3", NULL, SU_FLAG_OK, NULL }, /* pduTemperatureThLowerCritical.1.4 = INTEGER: 0 */ { "unmapped.pduTemperatureThLowerCritical", 0, 1, ".1.3.6.1.4.1.534.7.1.4.2.1.7.1.4", NULL, SU_FLAG_OK, NULL }, /* pduTemperatureThLowerCritical.1.5 = INTEGER: 0 */ { "unmapped.pduTemperatureThLowerCritical", 0, 1, ".1.3.6.1.4.1.534.7.1.4.2.1.7.1.5", NULL, SU_FLAG_OK, NULL }, /* pduTemperatureThLowerCritical.1.6 = INTEGER: 0 */ { "unmapped.pduTemperatureThLowerCritical", 0, 1, ".1.3.6.1.4.1.534.7.1.4.2.1.7.1.6", NULL, SU_FLAG_OK, NULL }, /* pduTemperatureThUpperWarning.1.1 = INTEGER: 0 */ { "unmapped.pduTemperatureThUpperWarning", 0, 1, ".1.3.6.1.4.1.534.7.1.4.2.1.8.1.1", NULL, SU_FLAG_OK, NULL }, /* pduTemperatureThUpperWarning.1.2 = INTEGER: 0 */ { "unmapped.pduTemperatureThUpperWarning", 0, 1, ".1.3.6.1.4.1.534.7.1.4.2.1.8.1.2", NULL, SU_FLAG_OK, NULL }, /* pduTemperatureThUpperWarning.1.3 = INTEGER: 0 */ { "unmapped.pduTemperatureThUpperWarning", 0, 1, ".1.3.6.1.4.1.534.7.1.4.2.1.8.1.3", NULL, SU_FLAG_OK, NULL }, /* pduTemperatureThUpperWarning.1.4 = INTEGER: 0 */ { "unmapped.pduTemperatureThUpperWarning", 0, 1, ".1.3.6.1.4.1.534.7.1.4.2.1.8.1.4", NULL, SU_FLAG_OK, NULL }, /* pduTemperatureThUpperWarning.1.5 = INTEGER: 0 */ { "unmapped.pduTemperatureThUpperWarning", 0, 1, ".1.3.6.1.4.1.534.7.1.4.2.1.8.1.5", NULL, SU_FLAG_OK, NULL }, /* pduTemperatureThUpperWarning.1.6 = INTEGER: 0 */ { "unmapped.pduTemperatureThUpperWarning", 0, 1, ".1.3.6.1.4.1.534.7.1.4.2.1.8.1.6", NULL, SU_FLAG_OK, NULL }, /* pduTemperatureThUpperCritical.1.1 = INTEGER: 0 */ { "unmapped.pduTemperatureThUpperCritical", 0, 1, ".1.3.6.1.4.1.534.7.1.4.2.1.9.1.1", NULL, SU_FLAG_OK, NULL }, /* pduTemperatureThUpperCritical.1.2 = INTEGER: 0 */ { "unmapped.pduTemperatureThUpperCritical", 0, 1, ".1.3.6.1.4.1.534.7.1.4.2.1.9.1.2", NULL, SU_FLAG_OK, NULL }, /* pduTemperatureThUpperCritical.1.3 = INTEGER: 0 */ { "unmapped.pduTemperatureThUpperCritical", 0, 1, ".1.3.6.1.4.1.534.7.1.4.2.1.9.1.3", NULL, SU_FLAG_OK, NULL }, /* pduTemperatureThUpperCritical.1.4 = INTEGER: 0 */ { "unmapped.pduTemperatureThUpperCritical", 0, 1, ".1.3.6.1.4.1.534.7.1.4.2.1.9.1.4", NULL, SU_FLAG_OK, NULL }, /* pduTemperatureThUpperCritical.1.5 = INTEGER: 0 */ { "unmapped.pduTemperatureThUpperCritical", 0, 1, ".1.3.6.1.4.1.534.7.1.4.2.1.9.1.5", NULL, SU_FLAG_OK, NULL }, /* pduTemperatureThUpperCritical.1.6 = INTEGER: 0 */ { "unmapped.pduTemperatureThUpperCritical", 0, 1, ".1.3.6.1.4.1.534.7.1.4.2.1.9.1.6", NULL, SU_FLAG_OK, NULL }, /* pduTemperatureThCtrl.1.1 = INTEGER: 0 */ { "unmapped.pduTemperatureThCtrl", 0, 1, ".1.3.6.1.4.1.534.7.1.4.2.1.10.1.1", NULL, SU_FLAG_OK, NULL }, /* pduTemperatureThCtrl.1.2 = INTEGER: 0 */ { "unmapped.pduTemperatureThCtrl", 0, 1, ".1.3.6.1.4.1.534.7.1.4.2.1.10.1.2", NULL, SU_FLAG_OK, NULL }, /* pduTemperatureThCtrl.1.3 = INTEGER: 0 */ { "unmapped.pduTemperatureThCtrl", 0, 1, ".1.3.6.1.4.1.534.7.1.4.2.1.10.1.3", NULL, SU_FLAG_OK, NULL }, /* pduTemperatureThCtrl.1.4 = INTEGER: 0 */ { "unmapped.pduTemperatureThCtrl", 0, 1, ".1.3.6.1.4.1.534.7.1.4.2.1.10.1.4", NULL, SU_FLAG_OK, NULL }, /* pduTemperatureThCtrl.1.5 = INTEGER: 0 */ { "unmapped.pduTemperatureThCtrl", 0, 1, ".1.3.6.1.4.1.534.7.1.4.2.1.10.1.5", NULL, SU_FLAG_OK, NULL }, /* pduTemperatureThCtrl.1.6 = INTEGER: 0 */ { "unmapped.pduTemperatureThCtrl", 0, 1, ".1.3.6.1.4.1.534.7.1.4.2.1.10.1.6", NULL, SU_FLAG_OK, NULL }, /* pduHumidityIndex.1.1 = INTEGER: 0 */ { "unmapped.pduHumidityIndex", 0, 1, ".1.3.6.1.4.1.534.7.1.4.3.1.1.1.1", NULL, SU_FLAG_OK, NULL }, /* pduHumidityIndex.1.2 = INTEGER: 0 */ { "unmapped.pduHumidityIndex", 0, 1, ".1.3.6.1.4.1.534.7.1.4.3.1.1.1.2", NULL, SU_FLAG_OK, NULL }, /* pduHumidityIndex.1.3 = INTEGER: 0 */ { "unmapped.pduHumidityIndex", 0, 1, ".1.3.6.1.4.1.534.7.1.4.3.1.1.1.3", NULL, SU_FLAG_OK, NULL }, /* pduHumidityIndex.1.4 = INTEGER: 0 */ { "unmapped.pduHumidityIndex", 0, 1, ".1.3.6.1.4.1.534.7.1.4.3.1.1.1.4", NULL, SU_FLAG_OK, NULL }, /* pduHumidityIndex.1.5 = INTEGER: 0 */ { "unmapped.pduHumidityIndex", 0, 1, ".1.3.6.1.4.1.534.7.1.4.3.1.1.1.5", NULL, SU_FLAG_OK, NULL }, /* pduHumidityIndex.1.6 = INTEGER: 0 */ { "unmapped.pduHumidityIndex", 0, 1, ".1.3.6.1.4.1.534.7.1.4.3.1.1.1.6", NULL, SU_FLAG_OK, NULL }, /* pduHumidityName.1.1 = STRING: " " */ { "unmapped.pduHumidityName", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.534.7.1.4.3.1.2.1.1", NULL, SU_FLAG_OK, NULL }, /* pduHumidityName.1.2 = STRING: " " */ { "unmapped.pduHumidityName", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.534.7.1.4.3.1.2.1.2", NULL, SU_FLAG_OK, NULL }, /* pduHumidityName.1.3 = STRING: " " */ { "unmapped.pduHumidityName", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.534.7.1.4.3.1.2.1.3", NULL, SU_FLAG_OK, NULL }, /* pduHumidityName.1.4 = STRING: " " */ { "unmapped.pduHumidityName", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.534.7.1.4.3.1.2.1.4", NULL, SU_FLAG_OK, NULL }, /* pduHumidityName.1.5 = STRING: " " */ { "unmapped.pduHumidityName", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.534.7.1.4.3.1.2.1.5", NULL, SU_FLAG_OK, NULL }, /* pduHumidityName.1.6 = STRING: " " */ { "unmapped.pduHumidityName", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.534.7.1.4.3.1.2.1.6", NULL, SU_FLAG_OK, NULL }, /* pduHumidityProbeStatus.1.1 = INTEGER: 1 */ { "unmapped.pduHumidityProbeStatus", 0, 1, ".1.3.6.1.4.1.534.7.1.4.3.1.3.1.1", NULL, SU_FLAG_OK, NULL }, /* pduHumidityProbeStatus.1.2 = INTEGER: 1 */ { "unmapped.pduHumidityProbeStatus", 0, 1, ".1.3.6.1.4.1.534.7.1.4.3.1.3.1.2", NULL, SU_FLAG_OK, NULL }, /* pduHumidityProbeStatus.1.3 = INTEGER: 1 */ { "unmapped.pduHumidityProbeStatus", 0, 1, ".1.3.6.1.4.1.534.7.1.4.3.1.3.1.3", NULL, SU_FLAG_OK, NULL }, /* pduHumidityProbeStatus.1.4 = INTEGER: 1 */ { "unmapped.pduHumidityProbeStatus", 0, 1, ".1.3.6.1.4.1.534.7.1.4.3.1.3.1.4", NULL, SU_FLAG_OK, NULL }, /* pduHumidityProbeStatus.1.5 = INTEGER: 1 */ { "unmapped.pduHumidityProbeStatus", 0, 1, ".1.3.6.1.4.1.534.7.1.4.3.1.3.1.5", NULL, SU_FLAG_OK, NULL }, /* pduHumidityProbeStatus.1.6 = INTEGER: 1 */ { "unmapped.pduHumidityProbeStatus", 0, 1, ".1.3.6.1.4.1.534.7.1.4.3.1.3.1.6", NULL, SU_FLAG_OK, NULL }, /* pduHumidityValue.1.1 = INTEGER: 0 */ { "unmapped.pduHumidityValue", 0, 1, ".1.3.6.1.4.1.534.7.1.4.3.1.4.1.1", NULL, SU_FLAG_OK, NULL }, /* pduHumidityValue.1.2 = INTEGER: 0 */ { "unmapped.pduHumidityValue", 0, 1, ".1.3.6.1.4.1.534.7.1.4.3.1.4.1.2", NULL, SU_FLAG_OK, NULL }, /* pduHumidityValue.1.3 = INTEGER: 0 */ { "unmapped.pduHumidityValue", 0, 1, ".1.3.6.1.4.1.534.7.1.4.3.1.4.1.3", NULL, SU_FLAG_OK, NULL }, /* pduHumidityValue.1.4 = INTEGER: 0 */ { "unmapped.pduHumidityValue", 0, 1, ".1.3.6.1.4.1.534.7.1.4.3.1.4.1.4", NULL, SU_FLAG_OK, NULL }, /* pduHumidityValue.1.5 = INTEGER: 0 */ { "unmapped.pduHumidityValue", 0, 1, ".1.3.6.1.4.1.534.7.1.4.3.1.4.1.5", NULL, SU_FLAG_OK, NULL }, /* pduHumidityValue.1.6 = INTEGER: 0 */ { "unmapped.pduHumidityValue", 0, 1, ".1.3.6.1.4.1.534.7.1.4.3.1.4.1.6", NULL, SU_FLAG_OK, NULL }, /* pduHumidityThStatus.1.1 = INTEGER: 0 */ { "unmapped.pduHumidityThStatus", 0, 1, ".1.3.6.1.4.1.534.7.1.4.3.1.5.1.1", NULL, SU_FLAG_OK, NULL }, /* pduHumidityThStatus.1.2 = INTEGER: 0 */ { "unmapped.pduHumidityThStatus", 0, 1, ".1.3.6.1.4.1.534.7.1.4.3.1.5.1.2", NULL, SU_FLAG_OK, NULL }, /* pduHumidityThStatus.1.3 = INTEGER: 0 */ { "unmapped.pduHumidityThStatus", 0, 1, ".1.3.6.1.4.1.534.7.1.4.3.1.5.1.3", NULL, SU_FLAG_OK, NULL }, /* pduHumidityThStatus.1.4 = INTEGER: 0 */ { "unmapped.pduHumidityThStatus", 0, 1, ".1.3.6.1.4.1.534.7.1.4.3.1.5.1.4", NULL, SU_FLAG_OK, NULL }, /* pduHumidityThStatus.1.5 = INTEGER: 0 */ { "unmapped.pduHumidityThStatus", 0, 1, ".1.3.6.1.4.1.534.7.1.4.3.1.5.1.5", NULL, SU_FLAG_OK, NULL }, /* pduHumidityThStatus.1.6 = INTEGER: 0 */ { "unmapped.pduHumidityThStatus", 0, 1, ".1.3.6.1.4.1.534.7.1.4.3.1.5.1.6", NULL, SU_FLAG_OK, NULL }, /* pduHumidityThLowerWarning.1.1 = INTEGER: 0 */ { "unmapped.pduHumidityThLowerWarning", 0, 1, ".1.3.6.1.4.1.534.7.1.4.3.1.6.1.1", NULL, SU_FLAG_OK, NULL }, /* pduHumidityThLowerWarning.1.2 = INTEGER: 0 */ { "unmapped.pduHumidityThLowerWarning", 0, 1, ".1.3.6.1.4.1.534.7.1.4.3.1.6.1.2", NULL, SU_FLAG_OK, NULL }, /* pduHumidityThLowerWarning.1.3 = INTEGER: 0 */ { "unmapped.pduHumidityThLowerWarning", 0, 1, ".1.3.6.1.4.1.534.7.1.4.3.1.6.1.3", NULL, SU_FLAG_OK, NULL }, /* pduHumidityThLowerWarning.1.4 = INTEGER: 0 */ { "unmapped.pduHumidityThLowerWarning", 0, 1, ".1.3.6.1.4.1.534.7.1.4.3.1.6.1.4", NULL, SU_FLAG_OK, NULL }, /* pduHumidityThLowerWarning.1.5 = INTEGER: 0 */ { "unmapped.pduHumidityThLowerWarning", 0, 1, ".1.3.6.1.4.1.534.7.1.4.3.1.6.1.5", NULL, SU_FLAG_OK, NULL }, /* pduHumidityThLowerWarning.1.6 = INTEGER: 0 */ { "unmapped.pduHumidityThLowerWarning", 0, 1, ".1.3.6.1.4.1.534.7.1.4.3.1.6.1.6", NULL, SU_FLAG_OK, NULL }, /* pduHumidityThLowerCritical.1.1 = INTEGER: 0 */ { "unmapped.pduHumidityThLowerCritical", 0, 1, ".1.3.6.1.4.1.534.7.1.4.3.1.7.1.1", NULL, SU_FLAG_OK, NULL }, /* pduHumidityThLowerCritical.1.2 = INTEGER: 0 */ { "unmapped.pduHumidityThLowerCritical", 0, 1, ".1.3.6.1.4.1.534.7.1.4.3.1.7.1.2", NULL, SU_FLAG_OK, NULL }, /* pduHumidityThLowerCritical.1.3 = INTEGER: 0 */ { "unmapped.pduHumidityThLowerCritical", 0, 1, ".1.3.6.1.4.1.534.7.1.4.3.1.7.1.3", NULL, SU_FLAG_OK, NULL }, /* pduHumidityThLowerCritical.1.4 = INTEGER: 0 */ { "unmapped.pduHumidityThLowerCritical", 0, 1, ".1.3.6.1.4.1.534.7.1.4.3.1.7.1.4", NULL, SU_FLAG_OK, NULL }, /* pduHumidityThLowerCritical.1.5 = INTEGER: 0 */ { "unmapped.pduHumidityThLowerCritical", 0, 1, ".1.3.6.1.4.1.534.7.1.4.3.1.7.1.5", NULL, SU_FLAG_OK, NULL }, /* pduHumidityThLowerCritical.1.6 = INTEGER: 0 */ { "unmapped.pduHumidityThLowerCritical", 0, 1, ".1.3.6.1.4.1.534.7.1.4.3.1.7.1.6", NULL, SU_FLAG_OK, NULL }, /* pduHumidityThUpperWarning.1.1 = INTEGER: 0 */ { "unmapped.pduHumidityThUpperWarning", 0, 1, ".1.3.6.1.4.1.534.7.1.4.3.1.8.1.1", NULL, SU_FLAG_OK, NULL }, /* pduHumidityThUpperWarning.1.2 = INTEGER: 0 */ { "unmapped.pduHumidityThUpperWarning", 0, 1, ".1.3.6.1.4.1.534.7.1.4.3.1.8.1.2", NULL, SU_FLAG_OK, NULL }, /* pduHumidityThUpperWarning.1.3 = INTEGER: 0 */ { "unmapped.pduHumidityThUpperWarning", 0, 1, ".1.3.6.1.4.1.534.7.1.4.3.1.8.1.3", NULL, SU_FLAG_OK, NULL }, /* pduHumidityThUpperWarning.1.4 = INTEGER: 0 */ { "unmapped.pduHumidityThUpperWarning", 0, 1, ".1.3.6.1.4.1.534.7.1.4.3.1.8.1.4", NULL, SU_FLAG_OK, NULL }, /* pduHumidityThUpperWarning.1.5 = INTEGER: 0 */ { "unmapped.pduHumidityThUpperWarning", 0, 1, ".1.3.6.1.4.1.534.7.1.4.3.1.8.1.5", NULL, SU_FLAG_OK, NULL }, /* pduHumidityThUpperWarning.1.6 = INTEGER: 0 */ { "unmapped.pduHumidityThUpperWarning", 0, 1, ".1.3.6.1.4.1.534.7.1.4.3.1.8.1.6", NULL, SU_FLAG_OK, NULL }, /* pduHumidityThUpperCritical.1.1 = INTEGER: 0 */ { "unmapped.pduHumidityThUpperCritical", 0, 1, ".1.3.6.1.4.1.534.7.1.4.3.1.9.1.1", NULL, SU_FLAG_OK, NULL }, /* pduHumidityThUpperCritical.1.2 = INTEGER: 0 */ { "unmapped.pduHumidityThUpperCritical", 0, 1, ".1.3.6.1.4.1.534.7.1.4.3.1.9.1.2", NULL, SU_FLAG_OK, NULL }, /* pduHumidityThUpperCritical.1.3 = INTEGER: 0 */ { "unmapped.pduHumidityThUpperCritical", 0, 1, ".1.3.6.1.4.1.534.7.1.4.3.1.9.1.3", NULL, SU_FLAG_OK, NULL }, /* pduHumidityThUpperCritical.1.4 = INTEGER: 0 */ { "unmapped.pduHumidityThUpperCritical", 0, 1, ".1.3.6.1.4.1.534.7.1.4.3.1.9.1.4", NULL, SU_FLAG_OK, NULL }, /* pduHumidityThUpperCritical.1.5 = INTEGER: 0 */ { "unmapped.pduHumidityThUpperCritical", 0, 1, ".1.3.6.1.4.1.534.7.1.4.3.1.9.1.5", NULL, SU_FLAG_OK, NULL }, /* pduHumidityThUpperCritical.1.6 = INTEGER: 0 */ { "unmapped.pduHumidityThUpperCritical", 0, 1, ".1.3.6.1.4.1.534.7.1.4.3.1.9.1.6", NULL, SU_FLAG_OK, NULL }, /* pduHumidityThCtrl.1.1 = INTEGER: 0 */ { "unmapped.pduHumidityThCtrl", 0, 1, ".1.3.6.1.4.1.534.7.1.4.3.1.10.1.1", NULL, SU_FLAG_OK, NULL }, /* pduHumidityThCtrl.1.2 = INTEGER: 0 */ { "unmapped.pduHumidityThCtrl", 0, 1, ".1.3.6.1.4.1.534.7.1.4.3.1.10.1.2", NULL, SU_FLAG_OK, NULL }, /* pduHumidityThCtrl.1.3 = INTEGER: 0 */ { "unmapped.pduHumidityThCtrl", 0, 1, ".1.3.6.1.4.1.534.7.1.4.3.1.10.1.3", NULL, SU_FLAG_OK, NULL }, /* pduHumidityThCtrl.1.4 = INTEGER: 0 */ { "unmapped.pduHumidityThCtrl", 0, 1, ".1.3.6.1.4.1.534.7.1.4.3.1.10.1.4", NULL, SU_FLAG_OK, NULL }, /* pduHumidityThCtrl.1.5 = INTEGER: 0 */ { "unmapped.pduHumidityThCtrl", 0, 1, ".1.3.6.1.4.1.534.7.1.4.3.1.10.1.5", NULL, SU_FLAG_OK, NULL }, /* pduHumidityThCtrl.1.6 = INTEGER: 0 */ { "unmapped.pduHumidityThCtrl", 0, 1, ".1.3.6.1.4.1.534.7.1.4.3.1.10.1.6", NULL, SU_FLAG_OK, NULL }, /* pduDoorIndex.1.1 = INTEGER: 0 */ { "unmapped.pduDoorIndex", 0, 1, ".1.3.6.1.4.1.534.7.1.4.4.1.1.1.1", NULL, SU_FLAG_OK, NULL }, /* pduDoorIndex.1.2 = INTEGER: 0 */ { "unmapped.pduDoorIndex", 0, 1, ".1.3.6.1.4.1.534.7.1.4.4.1.1.1.2", NULL, SU_FLAG_OK, NULL }, /* pduDoorName.1.1 = STRING: " " */ { "unmapped.pduDoorName", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.534.7.1.4.4.1.2.1.1", NULL, SU_FLAG_OK, NULL }, /* pduDoorName.1.2 = STRING: " " */ { "unmapped.pduDoorName", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.534.7.1.4.4.1.2.1.2", NULL, SU_FLAG_OK, NULL }, /* pduDoorProbeStatus.1.1 = INTEGER: 1 */ { "unmapped.pduDoorProbeStatus", 0, 1, ".1.3.6.1.4.1.534.7.1.4.4.1.3.1.1", NULL, SU_FLAG_OK, NULL }, /* pduDoorProbeStatus.1.2 = INTEGER: 1 */ { "unmapped.pduDoorProbeStatus", 0, 1, ".1.3.6.1.4.1.534.7.1.4.4.1.3.1.2", NULL, SU_FLAG_OK, NULL }, /* pduDoorState.1.1 = INTEGER: 0 */ { "unmapped.pduDoorState", 0, 1, ".1.3.6.1.4.1.534.7.1.4.4.1.4.1.1", NULL, SU_FLAG_OK, NULL }, /* pduDoorState.1.2 = INTEGER: 0 */ { "unmapped.pduDoorState", 0, 1, ".1.3.6.1.4.1.534.7.1.4.4.1.4.1.2", NULL, SU_FLAG_OK, NULL }, /* pduDryIndex.1.1 = INTEGER: 0 */ { "unmapped.pduDryIndex", 0, 1, ".1.3.6.1.4.1.534.7.1.4.5.1.1.1.1", NULL, SU_FLAG_OK, NULL }, /* pduDryIndex.1.2 = INTEGER: 0 */ { "unmapped.pduDryIndex", 0, 1, ".1.3.6.1.4.1.534.7.1.4.5.1.1.1.2", NULL, SU_FLAG_OK, NULL }, /* pduDryName.1.1 = STRING: " " */ { "unmapped.pduDryName", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.534.7.1.4.5.1.2.1.1", NULL, SU_FLAG_OK, NULL }, /* pduDryName.1.2 = STRING: " " */ { "unmapped.pduDryName", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.534.7.1.4.5.1.2.1.2", NULL, SU_FLAG_OK, NULL }, /* pduDryProbeStatus.1.1 = INTEGER: 1 */ { "unmapped.pduDryProbeStatus", 0, 1, ".1.3.6.1.4.1.534.7.1.4.5.1.3.1.1", NULL, SU_FLAG_OK, NULL }, /* pduDryProbeStatus.1.2 = INTEGER: 1 */ { "unmapped.pduDryProbeStatus", 0, 1, ".1.3.6.1.4.1.534.7.1.4.5.1.3.1.2", NULL, SU_FLAG_OK, NULL }, /* pduDryState.1.1 = INTEGER: 0 */ { "unmapped.pduDryState", 0, 1, ".1.3.6.1.4.1.534.7.1.4.5.1.4.1.1", NULL, SU_FLAG_OK, NULL }, /* pduDryState.1.2 = INTEGER: 0 */ { "unmapped.pduDryState", 0, 1, ".1.3.6.1.4.1.534.7.1.4.5.1.4.1.2", NULL, SU_FLAG_OK, NULL }, /* pduSpotIndex.1.1 = INTEGER: 0 */ { "unmapped.pduSpotIndex", 0, 1, ".1.3.6.1.4.1.534.7.1.4.6.1.1.1.1", NULL, SU_FLAG_OK, NULL }, /* pduSpotIndex.1.2 = INTEGER: 0 */ { "unmapped.pduSpotIndex", 0, 1, ".1.3.6.1.4.1.534.7.1.4.6.1.1.1.2", NULL, SU_FLAG_OK, NULL }, /* pduSpotName.1.1 = STRING: " " */ { "unmapped.pduSpotName", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.534.7.1.4.6.1.2.1.1", NULL, SU_FLAG_OK, NULL }, /* pduSpotName.1.2 = STRING: " " */ { "unmapped.pduSpotName", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.534.7.1.4.6.1.2.1.2", NULL, SU_FLAG_OK, NULL }, /* pduSpotProbeStatus.1.1 = INTEGER: 1 */ { "unmapped.pduSpotProbeStatus", 0, 1, ".1.3.6.1.4.1.534.7.1.4.6.1.3.1.1", NULL, SU_FLAG_OK, NULL }, /* pduSpotProbeStatus.1.2 = INTEGER: 1 */ { "unmapped.pduSpotProbeStatus", 0, 1, ".1.3.6.1.4.1.534.7.1.4.6.1.3.1.2", NULL, SU_FLAG_OK, NULL }, /* pduSpotState.1.1 = INTEGER: 0 */ { "unmapped.pduSpotState", 0, 1, ".1.3.6.1.4.1.534.7.1.4.6.1.4.1.1", NULL, SU_FLAG_OK, NULL }, /* pduSpotState.1.2 = INTEGER: 0 */ { "unmapped.pduSpotState", 0, 1, ".1.3.6.1.4.1.534.7.1.4.6.1.4.1.2", NULL, SU_FLAG_OK, NULL }, /* pduRopeIndex.1.1 = INTEGER: 0 */ { "unmapped.pduRopeIndex", 0, 1, ".1.3.6.1.4.1.534.7.1.4.7.1.1.1.1", NULL, SU_FLAG_OK, NULL }, /* pduRopeIndex.1.2 = INTEGER: 0 */ { "unmapped.pduRopeIndex", 0, 1, ".1.3.6.1.4.1.534.7.1.4.7.1.1.1.2", NULL, SU_FLAG_OK, NULL }, /* pduRopeName.1.1 = STRING: " " */ { "unmapped.pduRopeName", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.534.7.1.4.7.1.2.1.1", NULL, SU_FLAG_OK, NULL }, /* pduRopeName.1.2 = STRING: " " */ { "unmapped.pduRopeName", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.534.7.1.4.7.1.2.1.2", NULL, SU_FLAG_OK, NULL }, /* pduRopeProbeStatus.1.1 = INTEGER: 1 */ { "unmapped.pduRopeProbeStatus", 0, 1, ".1.3.6.1.4.1.534.7.1.4.7.1.3.1.1", NULL, SU_FLAG_OK, NULL }, /* pduRopeProbeStatus.1.2 = INTEGER: 1 */ { "unmapped.pduRopeProbeStatus", 0, 1, ".1.3.6.1.4.1.534.7.1.4.7.1.3.1.2", NULL, SU_FLAG_OK, NULL }, /* pduRopeState.1.1 = INTEGER: 0 */ { "unmapped.pduRopeState", 0, 1, ".1.3.6.1.4.1.534.7.1.4.7.1.4.1.1", NULL, SU_FLAG_OK, NULL }, /* pduRopeState.1.2 = INTEGER: 0 */ { "unmapped.pduRopeState", 0, 1, ".1.3.6.1.4.1.534.7.1.4.7.1.4.1.2", NULL, SU_FLAG_OK, NULL }, /* pduHIDIndex.1.1 = INTEGER: 0 */ { "unmapped.pduHIDIndex", 0, 1, ".1.3.6.1.4.1.534.7.1.4.10.1.1.1.1.1", NULL, SU_FLAG_OK, NULL }, /* pduHIDIndex.1.2 = INTEGER: 0 */ { "unmapped.pduHIDIndex", 0, 1, ".1.3.6.1.4.1.534.7.1.4.10.1.1.1.1.2", NULL, SU_FLAG_OK, NULL }, /* pduHidAisle.1.1 = INTEGER: 0 */ { "unmapped.pduHidAisle", 0, 1, ".1.3.6.1.4.1.534.7.1.4.10.1.1.2.1.1", NULL, SU_FLAG_OK, NULL }, /* pduHidAisle.1.2 = INTEGER: 0 */ { "unmapped.pduHidAisle", 0, 1, ".1.3.6.1.4.1.534.7.1.4.10.1.1.2.1.2", NULL, SU_FLAG_OK, NULL }, /* pduHidHandleOperation.1.1 = INTEGER: 2 */ { "unmapped.pduHidHandleOperation", 0, 1, ".1.3.6.1.4.1.534.7.1.4.10.1.1.3.1.1", NULL, SU_FLAG_OK, NULL }, /* pduHidHandleOperation.1.2 = INTEGER: 2 */ { "unmapped.pduHidHandleOperation", 0, 1, ".1.3.6.1.4.1.534.7.1.4.10.1.1.3.1.2", NULL, SU_FLAG_OK, NULL }, /* pduHIDVer.1.1 = Hex-STRING: 02 00 00 00 00 */ { "unmapped.pduHIDVer", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.534.7.1.4.10.1.1.4.1.1", NULL, SU_FLAG_OK, NULL }, /* pduHIDVer.1.2 = Hex-STRING: 02 00 00 00 00 */ { "unmapped.pduHIDVer", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.534.7.1.4.10.1.1.4.1.2", NULL, SU_FLAG_OK, NULL }, /* pduMechanicalLock.1.1 = INTEGER: 2 */ { "unmapped.pduMechanicalLock", 0, 1, ".1.3.6.1.4.1.534.7.1.4.10.1.1.5.1.1", NULL, SU_FLAG_OK, NULL }, /* pduMechanicalLock.1.2 = INTEGER: 2 */ { "unmapped.pduMechanicalLock", 0, 1, ".1.3.6.1.4.1.534.7.1.4.10.1.1.5.1.2", NULL, SU_FLAG_OK, NULL }, /* pduHidControlIndex.1.1 = INTEGER: 0 */ { "unmapped.pduHidControlIndex", 0, 1, ".1.3.6.1.4.1.534.7.1.4.10.2.1.1.1.1", NULL, SU_FLAG_OK, NULL }, /* pduHidControlIndex.1.2 = INTEGER: 0 */ { "unmapped.pduHidControlIndex", 0, 1, ".1.3.6.1.4.1.534.7.1.4.10.2.1.1.1.2", NULL, SU_FLAG_OK, NULL }, /* pduHidControlIndex.1.3 = INTEGER: 0 */ { "unmapped.pduHidControlIndex", 0, 1, ".1.3.6.1.4.1.534.7.1.4.10.2.1.1.1.3", NULL, SU_FLAG_OK, NULL }, /* pduHidControlIndex.1.4 = INTEGER: 0 */ { "unmapped.pduHidControlIndex", 0, 1, ".1.3.6.1.4.1.534.7.1.4.10.2.1.1.1.4", NULL, SU_FLAG_OK, NULL }, /* pduHidControlIndex.1.5 = INTEGER: 0 */ { "unmapped.pduHidControlIndex", 0, 1, ".1.3.6.1.4.1.534.7.1.4.10.2.1.1.1.5", NULL, SU_FLAG_OK, NULL }, /* pduHidControlIndex.1.6 = INTEGER: 0 */ { "unmapped.pduHidControlIndex", 0, 1, ".1.3.6.1.4.1.534.7.1.4.10.2.1.1.1.6", NULL, SU_FLAG_OK, NULL }, /* pduHidControlIndex.1.7 = INTEGER: 0 */ { "unmapped.pduHidControlIndex", 0, 1, ".1.3.6.1.4.1.534.7.1.4.10.2.1.1.1.7", NULL, SU_FLAG_OK, NULL }, /* pduHidControlIndex.1.8 = INTEGER: 0 */ { "unmapped.pduHidControlIndex", 0, 1, ".1.3.6.1.4.1.534.7.1.4.10.2.1.1.1.8", NULL, SU_FLAG_OK, NULL }, /* pduHidControlIndex.1.9 = INTEGER: 0 */ { "unmapped.pduHidControlIndex", 0, 1, ".1.3.6.1.4.1.534.7.1.4.10.2.1.1.1.9", NULL, SU_FLAG_OK, NULL }, /* pduHidControlIndex.1.10 = INTEGER: 0 */ { "unmapped.pduHidControlIndex", 0, 1, ".1.3.6.1.4.1.534.7.1.4.10.2.1.1.1.10", NULL, SU_FLAG_OK, NULL }, /* pduHidControlIndex.1.11 = INTEGER: 0 */ { "unmapped.pduHidControlIndex", 0, 1, ".1.3.6.1.4.1.534.7.1.4.10.2.1.1.1.11", NULL, SU_FLAG_OK, NULL }, /* pduHidControlIndex.1.12 = INTEGER: 0 */ { "unmapped.pduHidControlIndex", 0, 1, ".1.3.6.1.4.1.534.7.1.4.10.2.1.1.1.12", NULL, SU_FLAG_OK, NULL }, /* pduHidControlIndex.1.13 = INTEGER: 0 */ { "unmapped.pduHidControlIndex", 0, 1, ".1.3.6.1.4.1.534.7.1.4.10.2.1.1.1.13", NULL, SU_FLAG_OK, NULL }, /* pduHidControlIndex.1.14 = INTEGER: 0 */ { "unmapped.pduHidControlIndex", 0, 1, ".1.3.6.1.4.1.534.7.1.4.10.2.1.1.1.14", NULL, SU_FLAG_OK, NULL }, /* pduHidControlIndex.1.15 = INTEGER: 0 */ { "unmapped.pduHidControlIndex", 0, 1, ".1.3.6.1.4.1.534.7.1.4.10.2.1.1.1.15", NULL, SU_FLAG_OK, NULL }, /* pduHidControlIndex.1.16 = INTEGER: 0 */ { "unmapped.pduHidControlIndex", 0, 1, ".1.3.6.1.4.1.534.7.1.4.10.2.1.1.1.16", NULL, SU_FLAG_OK, NULL }, /* pduHidControlUserName.1.1 = "" */ { "unmapped.pduHidControlUserName", 0, 1, ".1.3.6.1.4.1.534.7.1.4.10.2.1.2.1.1", NULL, SU_FLAG_OK, NULL }, /* pduHidControlUserName.1.2 = "" */ { "unmapped.pduHidControlUserName", 0, 1, ".1.3.6.1.4.1.534.7.1.4.10.2.1.2.1.2", NULL, SU_FLAG_OK, NULL }, /* pduHidControlUserName.1.3 = "" */ { "unmapped.pduHidControlUserName", 0, 1, ".1.3.6.1.4.1.534.7.1.4.10.2.1.2.1.3", NULL, SU_FLAG_OK, NULL }, /* pduHidControlUserName.1.4 = "" */ { "unmapped.pduHidControlUserName", 0, 1, ".1.3.6.1.4.1.534.7.1.4.10.2.1.2.1.4", NULL, SU_FLAG_OK, NULL }, /* pduHidControlUserName.1.5 = "" */ { "unmapped.pduHidControlUserName", 0, 1, ".1.3.6.1.4.1.534.7.1.4.10.2.1.2.1.5", NULL, SU_FLAG_OK, NULL }, /* pduHidControlUserName.1.6 = "" */ { "unmapped.pduHidControlUserName", 0, 1, ".1.3.6.1.4.1.534.7.1.4.10.2.1.2.1.6", NULL, SU_FLAG_OK, NULL }, /* pduHidControlUserName.1.7 = "" */ { "unmapped.pduHidControlUserName", 0, 1, ".1.3.6.1.4.1.534.7.1.4.10.2.1.2.1.7", NULL, SU_FLAG_OK, NULL }, /* pduHidControlUserName.1.8 = "" */ { "unmapped.pduHidControlUserName", 0, 1, ".1.3.6.1.4.1.534.7.1.4.10.2.1.2.1.8", NULL, SU_FLAG_OK, NULL }, /* pduHidControlUserName.1.9 = "" */ { "unmapped.pduHidControlUserName", 0, 1, ".1.3.6.1.4.1.534.7.1.4.10.2.1.2.1.9", NULL, SU_FLAG_OK, NULL }, /* pduHidControlUserName.1.10 = "" */ { "unmapped.pduHidControlUserName", 0, 1, ".1.3.6.1.4.1.534.7.1.4.10.2.1.2.1.10", NULL, SU_FLAG_OK, NULL }, /* pduHidControlUserName.1.11 = "" */ { "unmapped.pduHidControlUserName", 0, 1, ".1.3.6.1.4.1.534.7.1.4.10.2.1.2.1.11", NULL, SU_FLAG_OK, NULL }, /* pduHidControlUserName.1.12 = "" */ { "unmapped.pduHidControlUserName", 0, 1, ".1.3.6.1.4.1.534.7.1.4.10.2.1.2.1.12", NULL, SU_FLAG_OK, NULL }, /* pduHidControlUserName.1.13 = "" */ { "unmapped.pduHidControlUserName", 0, 1, ".1.3.6.1.4.1.534.7.1.4.10.2.1.2.1.13", NULL, SU_FLAG_OK, NULL }, /* pduHidControlUserName.1.14 = "" */ { "unmapped.pduHidControlUserName", 0, 1, ".1.3.6.1.4.1.534.7.1.4.10.2.1.2.1.14", NULL, SU_FLAG_OK, NULL }, /* pduHidControlUserName.1.15 = "" */ { "unmapped.pduHidControlUserName", 0, 1, ".1.3.6.1.4.1.534.7.1.4.10.2.1.2.1.15", NULL, SU_FLAG_OK, NULL }, /* pduHidControlUserName.1.16 = "" */ { "unmapped.pduHidControlUserName", 0, 1, ".1.3.6.1.4.1.534.7.1.4.10.2.1.2.1.16", NULL, SU_FLAG_OK, NULL }, /* pduHidControlCardID.1.1 = INTEGER: 0 */ { "unmapped.pduHidControlCardID", 0, 1, ".1.3.6.1.4.1.534.7.1.4.10.2.1.3.1.1", NULL, SU_FLAG_OK, NULL }, /* pduHidControlCardID.1.2 = INTEGER: 0 */ { "unmapped.pduHidControlCardID", 0, 1, ".1.3.6.1.4.1.534.7.1.4.10.2.1.3.1.2", NULL, SU_FLAG_OK, NULL }, /* pduHidControlCardID.1.3 = INTEGER: 0 */ { "unmapped.pduHidControlCardID", 0, 1, ".1.3.6.1.4.1.534.7.1.4.10.2.1.3.1.3", NULL, SU_FLAG_OK, NULL }, /* pduHidControlCardID.1.4 = INTEGER: 0 */ { "unmapped.pduHidControlCardID", 0, 1, ".1.3.6.1.4.1.534.7.1.4.10.2.1.3.1.4", NULL, SU_FLAG_OK, NULL }, /* pduHidControlCardID.1.5 = INTEGER: 0 */ { "unmapped.pduHidControlCardID", 0, 1, ".1.3.6.1.4.1.534.7.1.4.10.2.1.3.1.5", NULL, SU_FLAG_OK, NULL }, /* pduHidControlCardID.1.6 = INTEGER: 0 */ { "unmapped.pduHidControlCardID", 0, 1, ".1.3.6.1.4.1.534.7.1.4.10.2.1.3.1.6", NULL, SU_FLAG_OK, NULL }, /* pduHidControlCardID.1.7 = INTEGER: 0 */ { "unmapped.pduHidControlCardID", 0, 1, ".1.3.6.1.4.1.534.7.1.4.10.2.1.3.1.7", NULL, SU_FLAG_OK, NULL }, /* pduHidControlCardID.1.8 = INTEGER: 0 */ { "unmapped.pduHidControlCardID", 0, 1, ".1.3.6.1.4.1.534.7.1.4.10.2.1.3.1.8", NULL, SU_FLAG_OK, NULL }, /* pduHidControlCardID.1.9 = INTEGER: 0 */ { "unmapped.pduHidControlCardID", 0, 1, ".1.3.6.1.4.1.534.7.1.4.10.2.1.3.1.9", NULL, SU_FLAG_OK, NULL }, /* pduHidControlCardID.1.10 = INTEGER: 0 */ { "unmapped.pduHidControlCardID", 0, 1, ".1.3.6.1.4.1.534.7.1.4.10.2.1.3.1.10", NULL, SU_FLAG_OK, NULL }, /* pduHidControlCardID.1.11 = INTEGER: 0 */ { "unmapped.pduHidControlCardID", 0, 1, ".1.3.6.1.4.1.534.7.1.4.10.2.1.3.1.11", NULL, SU_FLAG_OK, NULL }, /* pduHidControlCardID.1.12 = INTEGER: 0 */ { "unmapped.pduHidControlCardID", 0, 1, ".1.3.6.1.4.1.534.7.1.4.10.2.1.3.1.12", NULL, SU_FLAG_OK, NULL }, /* pduHidControlCardID.1.13 = INTEGER: 0 */ { "unmapped.pduHidControlCardID", 0, 1, ".1.3.6.1.4.1.534.7.1.4.10.2.1.3.1.13", NULL, SU_FLAG_OK, NULL }, /* pduHidControlCardID.1.14 = INTEGER: 0 */ { "unmapped.pduHidControlCardID", 0, 1, ".1.3.6.1.4.1.534.7.1.4.10.2.1.3.1.14", NULL, SU_FLAG_OK, NULL }, /* pduHidControlCardID.1.15 = INTEGER: 0 */ { "unmapped.pduHidControlCardID", 0, 1, ".1.3.6.1.4.1.534.7.1.4.10.2.1.3.1.15", NULL, SU_FLAG_OK, NULL }, /* pduHidControlCardID.1.16 = INTEGER: 0 */ { "unmapped.pduHidControlCardID", 0, 1, ".1.3.6.1.4.1.534.7.1.4.10.2.1.3.1.16", NULL, SU_FLAG_OK, NULL }, /* pduHidControlTimestamp.1.1 = STRING: "2000/00/00 00:00:00" */ { "unmapped.pduHidControlTimestamp", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.534.7.1.4.10.2.1.4.1.1", NULL, SU_FLAG_OK, NULL }, /* pduHidControlTimestamp.1.2 = STRING: "2000/00/00 00:00:00" */ { "unmapped.pduHidControlTimestamp", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.534.7.1.4.10.2.1.4.1.2", NULL, SU_FLAG_OK, NULL }, /* pduHidControlTimestamp.1.3 = STRING: "2000/00/00 00:00:00" */ { "unmapped.pduHidControlTimestamp", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.534.7.1.4.10.2.1.4.1.3", NULL, SU_FLAG_OK, NULL }, /* pduHidControlTimestamp.1.4 = STRING: "2000/00/00 00:00:00" */ { "unmapped.pduHidControlTimestamp", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.534.7.1.4.10.2.1.4.1.4", NULL, SU_FLAG_OK, NULL }, /* pduHidControlTimestamp.1.5 = STRING: "2000/00/00 00:00:00" */ { "unmapped.pduHidControlTimestamp", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.534.7.1.4.10.2.1.4.1.5", NULL, SU_FLAG_OK, NULL }, /* pduHidControlTimestamp.1.6 = STRING: "2000/00/00 00:00:00" */ { "unmapped.pduHidControlTimestamp", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.534.7.1.4.10.2.1.4.1.6", NULL, SU_FLAG_OK, NULL }, /* pduHidControlTimestamp.1.7 = STRING: "2000/00/00 00:00:00" */ { "unmapped.pduHidControlTimestamp", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.534.7.1.4.10.2.1.4.1.7", NULL, SU_FLAG_OK, NULL }, /* pduHidControlTimestamp.1.8 = STRING: "2000/00/00 00:00:00" */ { "unmapped.pduHidControlTimestamp", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.534.7.1.4.10.2.1.4.1.8", NULL, SU_FLAG_OK, NULL }, /* pduHidControlTimestamp.1.9 = STRING: "2000/00/00 00:00:00" */ { "unmapped.pduHidControlTimestamp", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.534.7.1.4.10.2.1.4.1.9", NULL, SU_FLAG_OK, NULL }, /* pduHidControlTimestamp.1.10 = STRING: "2000/00/00 00:00:00" */ { "unmapped.pduHidControlTimestamp", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.534.7.1.4.10.2.1.4.1.10", NULL, SU_FLAG_OK, NULL }, /* pduHidControlTimestamp.1.11 = STRING: "2000/00/00 00:00:00" */ { "unmapped.pduHidControlTimestamp", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.534.7.1.4.10.2.1.4.1.11", NULL, SU_FLAG_OK, NULL }, /* pduHidControlTimestamp.1.12 = STRING: "2000/00/00 00:00:00" */ { "unmapped.pduHidControlTimestamp", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.534.7.1.4.10.2.1.4.1.12", NULL, SU_FLAG_OK, NULL }, /* pduHidControlTimestamp.1.13 = STRING: "2000/00/00 00:00:00" */ { "unmapped.pduHidControlTimestamp", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.534.7.1.4.10.2.1.4.1.13", NULL, SU_FLAG_OK, NULL }, /* pduHidControlTimestamp.1.14 = STRING: "2000/00/00 00:00:00" */ { "unmapped.pduHidControlTimestamp", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.534.7.1.4.10.2.1.4.1.14", NULL, SU_FLAG_OK, NULL }, /* pduHidControlTimestamp.1.15 = STRING: "2000/00/00 00:00:00" */ { "unmapped.pduHidControlTimestamp", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.534.7.1.4.10.2.1.4.1.15", NULL, SU_FLAG_OK, NULL }, /* pduHidControlTimestamp.1.16 = STRING: "2000/00/00 00:00:00" */ { "unmapped.pduHidControlTimestamp", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.534.7.1.4.10.2.1.4.1.16", NULL, SU_FLAG_OK, NULL }, /* pduHidControlCardAisle.1.1 = INTEGER: 0 */ { "unmapped.pduHidControlCardAisle", 0, 1, ".1.3.6.1.4.1.534.7.1.4.10.2.1.5.1.1", NULL, SU_FLAG_OK, NULL }, /* pduHidControlCardAisle.1.2 = INTEGER: 0 */ { "unmapped.pduHidControlCardAisle", 0, 1, ".1.3.6.1.4.1.534.7.1.4.10.2.1.5.1.2", NULL, SU_FLAG_OK, NULL }, /* pduHidControlCardAisle.1.3 = INTEGER: 0 */ { "unmapped.pduHidControlCardAisle", 0, 1, ".1.3.6.1.4.1.534.7.1.4.10.2.1.5.1.3", NULL, SU_FLAG_OK, NULL }, /* pduHidControlCardAisle.1.4 = INTEGER: 0 */ { "unmapped.pduHidControlCardAisle", 0, 1, ".1.3.6.1.4.1.534.7.1.4.10.2.1.5.1.4", NULL, SU_FLAG_OK, NULL }, /* pduHidControlCardAisle.1.5 = INTEGER: 0 */ { "unmapped.pduHidControlCardAisle", 0, 1, ".1.3.6.1.4.1.534.7.1.4.10.2.1.5.1.5", NULL, SU_FLAG_OK, NULL }, /* pduHidControlCardAisle.1.6 = INTEGER: 0 */ { "unmapped.pduHidControlCardAisle", 0, 1, ".1.3.6.1.4.1.534.7.1.4.10.2.1.5.1.6", NULL, SU_FLAG_OK, NULL }, /* pduHidControlCardAisle.1.7 = INTEGER: 0 */ { "unmapped.pduHidControlCardAisle", 0, 1, ".1.3.6.1.4.1.534.7.1.4.10.2.1.5.1.7", NULL, SU_FLAG_OK, NULL }, /* pduHidControlCardAisle.1.8 = INTEGER: 0 */ { "unmapped.pduHidControlCardAisle", 0, 1, ".1.3.6.1.4.1.534.7.1.4.10.2.1.5.1.8", NULL, SU_FLAG_OK, NULL }, /* pduHidControlCardAisle.1.9 = INTEGER: 0 */ { "unmapped.pduHidControlCardAisle", 0, 1, ".1.3.6.1.4.1.534.7.1.4.10.2.1.5.1.9", NULL, SU_FLAG_OK, NULL }, /* pduHidControlCardAisle.1.10 = INTEGER: 0 */ { "unmapped.pduHidControlCardAisle", 0, 1, ".1.3.6.1.4.1.534.7.1.4.10.2.1.5.1.10", NULL, SU_FLAG_OK, NULL }, /* pduHidControlCardAisle.1.11 = INTEGER: 0 */ { "unmapped.pduHidControlCardAisle", 0, 1, ".1.3.6.1.4.1.534.7.1.4.10.2.1.5.1.11", NULL, SU_FLAG_OK, NULL }, /* pduHidControlCardAisle.1.12 = INTEGER: 0 */ { "unmapped.pduHidControlCardAisle", 0, 1, ".1.3.6.1.4.1.534.7.1.4.10.2.1.5.1.12", NULL, SU_FLAG_OK, NULL }, /* pduHidControlCardAisle.1.13 = INTEGER: 0 */ { "unmapped.pduHidControlCardAisle", 0, 1, ".1.3.6.1.4.1.534.7.1.4.10.2.1.5.1.13", NULL, SU_FLAG_OK, NULL }, /* pduHidControlCardAisle.1.14 = INTEGER: 0 */ { "unmapped.pduHidControlCardAisle", 0, 1, ".1.3.6.1.4.1.534.7.1.4.10.2.1.5.1.14", NULL, SU_FLAG_OK, NULL }, /* pduHidControlCardAisle.1.15 = INTEGER: 0 */ { "unmapped.pduHidControlCardAisle", 0, 1, ".1.3.6.1.4.1.534.7.1.4.10.2.1.5.1.15", NULL, SU_FLAG_OK, NULL }, /* pduHidControlCardAisle.1.16 = INTEGER: 0 */ { "unmapped.pduHidControlCardAisle", 0, 1, ".1.3.6.1.4.1.534.7.1.4.10.2.1.5.1.16", NULL, SU_FLAG_OK, NULL }, /* pduOutletIndex.1.1 = INTEGER: 1 */ { "unmapped.pduOutletIndex", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.1.1.1", NULL, SU_FLAG_OK, NULL }, /* pduOutletIndex.1.2 = INTEGER: 2 */ { "unmapped.pduOutletIndex", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.1.1.2", NULL, SU_FLAG_OK, NULL }, /* pduOutletIndex.1.3 = INTEGER: 3 */ { "unmapped.pduOutletIndex", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.1.1.3", NULL, SU_FLAG_OK, NULL }, /* pduOutletIndex.1.4 = INTEGER: 4 */ { "unmapped.pduOutletIndex", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.1.1.4", NULL, SU_FLAG_OK, NULL }, /* pduOutletIndex.1.5 = INTEGER: 5 */ { "unmapped.pduOutletIndex", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.1.1.5", NULL, SU_FLAG_OK, NULL }, /* pduOutletIndex.1.6 = INTEGER: 6 */ { "unmapped.pduOutletIndex", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.1.1.6", NULL, SU_FLAG_OK, NULL }, /* pduOutletIndex.1.7 = INTEGER: 0 */ { "unmapped.pduOutletIndex", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.1.1.7", NULL, SU_FLAG_OK, NULL }, /* pduOutletIndex.1.8 = INTEGER: 0 */ { "unmapped.pduOutletIndex", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.1.1.8", NULL, SU_FLAG_OK, NULL }, /* pduOutletIndex.1.9 = INTEGER: 0 */ { "unmapped.pduOutletIndex", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.1.1.9", NULL, SU_FLAG_OK, NULL }, /* pduOutletIndex.1.10 = INTEGER: 0 */ { "unmapped.pduOutletIndex", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.1.1.10", NULL, SU_FLAG_OK, NULL }, /* pduOutletIndex.1.11 = INTEGER: 0 */ { "unmapped.pduOutletIndex", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.1.1.11", NULL, SU_FLAG_OK, NULL }, /* pduOutletIndex.1.12 = INTEGER: 0 */ { "unmapped.pduOutletIndex", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.1.1.12", NULL, SU_FLAG_OK, NULL }, /* pduOutletIndex.1.13 = INTEGER: 0 */ { "unmapped.pduOutletIndex", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.1.1.13", NULL, SU_FLAG_OK, NULL }, /* pduOutletIndex.1.14 = INTEGER: 0 */ { "unmapped.pduOutletIndex", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.1.1.14", NULL, SU_FLAG_OK, NULL }, /* pduOutletIndex.1.15 = INTEGER: 0 */ { "unmapped.pduOutletIndex", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.1.1.15", NULL, SU_FLAG_OK, NULL }, /* pduOutletIndex.1.16 = INTEGER: 0 */ { "unmapped.pduOutletIndex", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.1.1.16", NULL, SU_FLAG_OK, NULL }, /* pduOutletIndex.1.17 = INTEGER: 0 */ { "unmapped.pduOutletIndex", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.1.1.17", NULL, SU_FLAG_OK, NULL }, /* pduOutletIndex.1.18 = INTEGER: 0 */ { "unmapped.pduOutletIndex", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.1.1.18", NULL, SU_FLAG_OK, NULL }, /* pduOutletIndex.1.19 = INTEGER: 0 */ { "unmapped.pduOutletIndex", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.1.1.19", NULL, SU_FLAG_OK, NULL }, /* pduOutletIndex.1.20 = INTEGER: 0 */ { "unmapped.pduOutletIndex", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.1.1.20", NULL, SU_FLAG_OK, NULL }, /* pduOutletIndex.1.21 = INTEGER: 0 */ { "unmapped.pduOutletIndex", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.1.1.21", NULL, SU_FLAG_OK, NULL }, /* pduOutletIndex.1.22 = INTEGER: 0 */ { "unmapped.pduOutletIndex", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.1.1.22", NULL, SU_FLAG_OK, NULL }, /* pduOutletIndex.1.23 = INTEGER: 0 */ { "unmapped.pduOutletIndex", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.1.1.23", NULL, SU_FLAG_OK, NULL }, /* pduOutletIndex.1.24 = INTEGER: 0 */ { "unmapped.pduOutletIndex", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.1.1.24", NULL, SU_FLAG_OK, NULL }, /* pduOutletIndex.1.25 = INTEGER: 0 */ { "unmapped.pduOutletIndex", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.1.1.25", NULL, SU_FLAG_OK, NULL }, /* pduOutletIndex.1.26 = INTEGER: 0 */ { "unmapped.pduOutletIndex", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.1.1.26", NULL, SU_FLAG_OK, NULL }, /* pduOutletIndex.1.27 = INTEGER: 0 */ { "unmapped.pduOutletIndex", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.1.1.27", NULL, SU_FLAG_OK, NULL }, /* pduOutletIndex.1.28 = INTEGER: 0 */ { "unmapped.pduOutletIndex", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.1.1.28", NULL, SU_FLAG_OK, NULL }, /* pduOutletIndex.1.29 = INTEGER: 0 */ { "unmapped.pduOutletIndex", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.1.1.29", NULL, SU_FLAG_OK, NULL }, /* pduOutletIndex.1.30 = INTEGER: 0 */ { "unmapped.pduOutletIndex", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.1.1.30", NULL, SU_FLAG_OK, NULL }, /* pduOutletIndex.1.31 = INTEGER: 0 */ { "unmapped.pduOutletIndex", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.1.1.31", NULL, SU_FLAG_OK, NULL }, /* pduOutletIndex.1.32 = INTEGER: 0 */ { "unmapped.pduOutletIndex", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.1.1.32", NULL, SU_FLAG_OK, NULL }, /* pduOutletIndex.1.33 = INTEGER: 0 */ { "unmapped.pduOutletIndex", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.1.1.33", NULL, SU_FLAG_OK, NULL }, /* pduOutletIndex.1.34 = INTEGER: 0 */ { "unmapped.pduOutletIndex", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.1.1.34", NULL, SU_FLAG_OK, NULL }, /* pduOutletIndex.1.35 = INTEGER: 0 */ { "unmapped.pduOutletIndex", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.1.1.35", NULL, SU_FLAG_OK, NULL }, /* pduOutletIndex.1.36 = INTEGER: 0 */ { "unmapped.pduOutletIndex", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.1.1.36", NULL, SU_FLAG_OK, NULL }, /* pduOutletIndex.1.37 = INTEGER: 0 */ { "unmapped.pduOutletIndex", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.1.1.37", NULL, SU_FLAG_OK, NULL }, /* pduOutletIndex.1.38 = INTEGER: 0 */ { "unmapped.pduOutletIndex", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.1.1.38", NULL, SU_FLAG_OK, NULL }, /* pduOutletIndex.1.39 = INTEGER: 0 */ { "unmapped.pduOutletIndex", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.1.1.39", NULL, SU_FLAG_OK, NULL }, /* pduOutletIndex.1.40 = INTEGER: 0 */ { "unmapped.pduOutletIndex", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.1.1.40", NULL, SU_FLAG_OK, NULL }, /* pduOutletIndex.1.41 = INTEGER: 0 */ { "unmapped.pduOutletIndex", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.1.1.41", NULL, SU_FLAG_OK, NULL }, /* pduOutletIndex.1.42 = INTEGER: 0 */ { "unmapped.pduOutletIndex", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.1.1.42", NULL, SU_FLAG_OK, NULL }, /* pduOutletIndex.1.43 = INTEGER: 0 */ { "unmapped.pduOutletIndex", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.1.1.43", NULL, SU_FLAG_OK, NULL }, /* pduOutletIndex.1.44 = INTEGER: 0 */ { "unmapped.pduOutletIndex", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.1.1.44", NULL, SU_FLAG_OK, NULL }, /* pduOutletIndex.1.45 = INTEGER: 0 */ { "unmapped.pduOutletIndex", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.1.1.45", NULL, SU_FLAG_OK, NULL }, /* pduOutletIndex.1.46 = INTEGER: 0 */ { "unmapped.pduOutletIndex", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.1.1.46", NULL, SU_FLAG_OK, NULL }, /* pduOutletIndex.1.47 = INTEGER: 0 */ { "unmapped.pduOutletIndex", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.1.1.47", NULL, SU_FLAG_OK, NULL }, /* pduOutletIndex.1.48 = INTEGER: 0 */ { "unmapped.pduOutletIndex", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.1.1.48", NULL, SU_FLAG_OK, NULL }, /* pduOutletActivePowerThStatus.1.1 = INTEGER: 1 */ { "unmapped.pduOutletActivePowerThStatus", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.6.1.1", NULL, SU_FLAG_OK, NULL }, /* pduOutletActivePowerThStatus.1.2 = INTEGER: 1 */ { "unmapped.pduOutletActivePowerThStatus", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.6.1.2", NULL, SU_FLAG_OK, NULL }, /* pduOutletActivePowerThStatus.1.3 = INTEGER: 1 */ { "unmapped.pduOutletActivePowerThStatus", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.6.1.3", NULL, SU_FLAG_OK, NULL }, /* pduOutletActivePowerThStatus.1.4 = INTEGER: 1 */ { "unmapped.pduOutletActivePowerThStatus", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.6.1.4", NULL, SU_FLAG_OK, NULL }, /* pduOutletActivePowerThStatus.1.5 = INTEGER: 1 */ { "unmapped.pduOutletActivePowerThStatus", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.6.1.5", NULL, SU_FLAG_OK, NULL }, /* pduOutletActivePowerThStatus.1.6 = INTEGER: 1 */ { "unmapped.pduOutletActivePowerThStatus", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.6.1.6", NULL, SU_FLAG_OK, NULL }, /* pduOutletActivePowerThStatus.1.7 = INTEGER: 0 */ { "unmapped.pduOutletActivePowerThStatus", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.6.1.7", NULL, SU_FLAG_OK, NULL }, /* pduOutletActivePowerThStatus.1.8 = INTEGER: 0 */ { "unmapped.pduOutletActivePowerThStatus", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.6.1.8", NULL, SU_FLAG_OK, NULL }, /* pduOutletActivePowerThStatus.1.9 = INTEGER: 0 */ { "unmapped.pduOutletActivePowerThStatus", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.6.1.9", NULL, SU_FLAG_OK, NULL }, /* pduOutletActivePowerThStatus.1.10 = INTEGER: 0 */ { "unmapped.pduOutletActivePowerThStatus", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.6.1.10", NULL, SU_FLAG_OK, NULL }, /* pduOutletActivePowerThStatus.1.11 = INTEGER: 0 */ { "unmapped.pduOutletActivePowerThStatus", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.6.1.11", NULL, SU_FLAG_OK, NULL }, /* pduOutletActivePowerThStatus.1.12 = INTEGER: 0 */ { "unmapped.pduOutletActivePowerThStatus", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.6.1.12", NULL, SU_FLAG_OK, NULL }, /* pduOutletActivePowerThStatus.1.13 = INTEGER: 0 */ { "unmapped.pduOutletActivePowerThStatus", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.6.1.13", NULL, SU_FLAG_OK, NULL }, /* pduOutletActivePowerThStatus.1.14 = INTEGER: 0 */ { "unmapped.pduOutletActivePowerThStatus", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.6.1.14", NULL, SU_FLAG_OK, NULL }, /* pduOutletActivePowerThStatus.1.15 = INTEGER: 0 */ { "unmapped.pduOutletActivePowerThStatus", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.6.1.15", NULL, SU_FLAG_OK, NULL }, /* pduOutletActivePowerThStatus.1.16 = INTEGER: 0 */ { "unmapped.pduOutletActivePowerThStatus", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.6.1.16", NULL, SU_FLAG_OK, NULL }, /* pduOutletActivePowerThStatus.1.17 = INTEGER: 0 */ { "unmapped.pduOutletActivePowerThStatus", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.6.1.17", NULL, SU_FLAG_OK, NULL }, /* pduOutletActivePowerThStatus.1.18 = INTEGER: 0 */ { "unmapped.pduOutletActivePowerThStatus", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.6.1.18", NULL, SU_FLAG_OK, NULL }, /* pduOutletActivePowerThStatus.1.19 = INTEGER: 0 */ { "unmapped.pduOutletActivePowerThStatus", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.6.1.19", NULL, SU_FLAG_OK, NULL }, /* pduOutletActivePowerThStatus.1.20 = INTEGER: 0 */ { "unmapped.pduOutletActivePowerThStatus", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.6.1.20", NULL, SU_FLAG_OK, NULL }, /* pduOutletActivePowerThStatus.1.21 = INTEGER: 0 */ { "unmapped.pduOutletActivePowerThStatus", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.6.1.21", NULL, SU_FLAG_OK, NULL }, /* pduOutletActivePowerThStatus.1.22 = INTEGER: 0 */ { "unmapped.pduOutletActivePowerThStatus", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.6.1.22", NULL, SU_FLAG_OK, NULL }, /* pduOutletActivePowerThStatus.1.23 = INTEGER: 0 */ { "unmapped.pduOutletActivePowerThStatus", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.6.1.23", NULL, SU_FLAG_OK, NULL }, /* pduOutletActivePowerThStatus.1.24 = INTEGER: 0 */ { "unmapped.pduOutletActivePowerThStatus", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.6.1.24", NULL, SU_FLAG_OK, NULL }, /* pduOutletActivePowerThStatus.1.25 = INTEGER: 0 */ { "unmapped.pduOutletActivePowerThStatus", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.6.1.25", NULL, SU_FLAG_OK, NULL }, /* pduOutletActivePowerThStatus.1.26 = INTEGER: 0 */ { "unmapped.pduOutletActivePowerThStatus", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.6.1.26", NULL, SU_FLAG_OK, NULL }, /* pduOutletActivePowerThStatus.1.27 = INTEGER: 0 */ { "unmapped.pduOutletActivePowerThStatus", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.6.1.27", NULL, SU_FLAG_OK, NULL }, /* pduOutletActivePowerThStatus.1.28 = INTEGER: 0 */ { "unmapped.pduOutletActivePowerThStatus", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.6.1.28", NULL, SU_FLAG_OK, NULL }, /* pduOutletActivePowerThStatus.1.29 = INTEGER: 0 */ { "unmapped.pduOutletActivePowerThStatus", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.6.1.29", NULL, SU_FLAG_OK, NULL }, /* pduOutletActivePowerThStatus.1.30 = INTEGER: 0 */ { "unmapped.pduOutletActivePowerThStatus", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.6.1.30", NULL, SU_FLAG_OK, NULL }, /* pduOutletActivePowerThStatus.1.31 = INTEGER: 0 */ { "unmapped.pduOutletActivePowerThStatus", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.6.1.31", NULL, SU_FLAG_OK, NULL }, /* pduOutletActivePowerThStatus.1.32 = INTEGER: 0 */ { "unmapped.pduOutletActivePowerThStatus", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.6.1.32", NULL, SU_FLAG_OK, NULL }, /* pduOutletActivePowerThStatus.1.33 = INTEGER: 0 */ { "unmapped.pduOutletActivePowerThStatus", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.6.1.33", NULL, SU_FLAG_OK, NULL }, /* pduOutletActivePowerThStatus.1.34 = INTEGER: 0 */ { "unmapped.pduOutletActivePowerThStatus", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.6.1.34", NULL, SU_FLAG_OK, NULL }, /* pduOutletActivePowerThStatus.1.35 = INTEGER: 0 */ { "unmapped.pduOutletActivePowerThStatus", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.6.1.35", NULL, SU_FLAG_OK, NULL }, /* pduOutletActivePowerThStatus.1.36 = INTEGER: 0 */ { "unmapped.pduOutletActivePowerThStatus", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.6.1.36", NULL, SU_FLAG_OK, NULL }, /* pduOutletActivePowerThStatus.1.37 = INTEGER: 0 */ { "unmapped.pduOutletActivePowerThStatus", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.6.1.37", NULL, SU_FLAG_OK, NULL }, /* pduOutletActivePowerThStatus.1.38 = INTEGER: 0 */ { "unmapped.pduOutletActivePowerThStatus", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.6.1.38", NULL, SU_FLAG_OK, NULL }, /* pduOutletActivePowerThStatus.1.39 = INTEGER: 0 */ { "unmapped.pduOutletActivePowerThStatus", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.6.1.39", NULL, SU_FLAG_OK, NULL }, /* pduOutletActivePowerThStatus.1.40 = INTEGER: 0 */ { "unmapped.pduOutletActivePowerThStatus", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.6.1.40", NULL, SU_FLAG_OK, NULL }, /* pduOutletActivePowerThStatus.1.41 = INTEGER: 0 */ { "unmapped.pduOutletActivePowerThStatus", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.6.1.41", NULL, SU_FLAG_OK, NULL }, /* pduOutletActivePowerThStatus.1.42 = INTEGER: 0 */ { "unmapped.pduOutletActivePowerThStatus", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.6.1.42", NULL, SU_FLAG_OK, NULL }, /* pduOutletActivePowerThStatus.1.43 = INTEGER: 0 */ { "unmapped.pduOutletActivePowerThStatus", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.6.1.43", NULL, SU_FLAG_OK, NULL }, /* pduOutletActivePowerThStatus.1.44 = INTEGER: 0 */ { "unmapped.pduOutletActivePowerThStatus", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.6.1.44", NULL, SU_FLAG_OK, NULL }, /* pduOutletActivePowerThStatus.1.45 = INTEGER: 0 */ { "unmapped.pduOutletActivePowerThStatus", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.6.1.45", NULL, SU_FLAG_OK, NULL }, /* pduOutletActivePowerThStatus.1.46 = INTEGER: 0 */ { "unmapped.pduOutletActivePowerThStatus", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.6.1.46", NULL, SU_FLAG_OK, NULL }, /* pduOutletActivePowerThStatus.1.47 = INTEGER: 0 */ { "unmapped.pduOutletActivePowerThStatus", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.6.1.47", NULL, SU_FLAG_OK, NULL }, /* pduOutletActivePowerThStatus.1.48 = INTEGER: 0 */ { "unmapped.pduOutletActivePowerThStatus", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.6.1.48", NULL, SU_FLAG_OK, NULL }, /* pduOutletActivePowerThLowerWarning.1.1 = INTEGER: 0 */ { "unmapped.pduOutletActivePowerThLowerWarning", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.7.1.1", NULL, SU_FLAG_OK, NULL }, /* pduOutletActivePowerThLowerWarning.1.2 = INTEGER: 0 */ { "unmapped.pduOutletActivePowerThLowerWarning", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.7.1.2", NULL, SU_FLAG_OK, NULL }, /* pduOutletActivePowerThLowerWarning.1.3 = INTEGER: 0 */ { "unmapped.pduOutletActivePowerThLowerWarning", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.7.1.3", NULL, SU_FLAG_OK, NULL }, /* pduOutletActivePowerThLowerWarning.1.4 = INTEGER: 0 */ { "unmapped.pduOutletActivePowerThLowerWarning", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.7.1.4", NULL, SU_FLAG_OK, NULL }, /* pduOutletActivePowerThLowerWarning.1.5 = INTEGER: 0 */ { "unmapped.pduOutletActivePowerThLowerWarning", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.7.1.5", NULL, SU_FLAG_OK, NULL }, /* pduOutletActivePowerThLowerWarning.1.6 = INTEGER: 0 */ { "unmapped.pduOutletActivePowerThLowerWarning", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.7.1.6", NULL, SU_FLAG_OK, NULL }, /* pduOutletActivePowerThLowerWarning.1.7 = INTEGER: 0 */ { "unmapped.pduOutletActivePowerThLowerWarning", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.7.1.7", NULL, SU_FLAG_OK, NULL }, /* pduOutletActivePowerThLowerWarning.1.8 = INTEGER: 0 */ { "unmapped.pduOutletActivePowerThLowerWarning", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.7.1.8", NULL, SU_FLAG_OK, NULL }, /* pduOutletActivePowerThLowerWarning.1.9 = INTEGER: 0 */ { "unmapped.pduOutletActivePowerThLowerWarning", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.7.1.9", NULL, SU_FLAG_OK, NULL }, /* pduOutletActivePowerThLowerWarning.1.10 = INTEGER: 0 */ { "unmapped.pduOutletActivePowerThLowerWarning", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.7.1.10", NULL, SU_FLAG_OK, NULL }, /* pduOutletActivePowerThLowerWarning.1.11 = INTEGER: 0 */ { "unmapped.pduOutletActivePowerThLowerWarning", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.7.1.11", NULL, SU_FLAG_OK, NULL }, /* pduOutletActivePowerThLowerWarning.1.12 = INTEGER: 0 */ { "unmapped.pduOutletActivePowerThLowerWarning", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.7.1.12", NULL, SU_FLAG_OK, NULL }, /* pduOutletActivePowerThLowerWarning.1.13 = INTEGER: 0 */ { "unmapped.pduOutletActivePowerThLowerWarning", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.7.1.13", NULL, SU_FLAG_OK, NULL }, /* pduOutletActivePowerThLowerWarning.1.14 = INTEGER: 0 */ { "unmapped.pduOutletActivePowerThLowerWarning", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.7.1.14", NULL, SU_FLAG_OK, NULL }, /* pduOutletActivePowerThLowerWarning.1.15 = INTEGER: 0 */ { "unmapped.pduOutletActivePowerThLowerWarning", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.7.1.15", NULL, SU_FLAG_OK, NULL }, /* pduOutletActivePowerThLowerWarning.1.16 = INTEGER: 0 */ { "unmapped.pduOutletActivePowerThLowerWarning", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.7.1.16", NULL, SU_FLAG_OK, NULL }, /* pduOutletActivePowerThLowerWarning.1.17 = INTEGER: 0 */ { "unmapped.pduOutletActivePowerThLowerWarning", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.7.1.17", NULL, SU_FLAG_OK, NULL }, /* pduOutletActivePowerThLowerWarning.1.18 = INTEGER: 0 */ { "unmapped.pduOutletActivePowerThLowerWarning", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.7.1.18", NULL, SU_FLAG_OK, NULL }, /* pduOutletActivePowerThLowerWarning.1.19 = INTEGER: 0 */ { "unmapped.pduOutletActivePowerThLowerWarning", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.7.1.19", NULL, SU_FLAG_OK, NULL }, /* pduOutletActivePowerThLowerWarning.1.20 = INTEGER: 0 */ { "unmapped.pduOutletActivePowerThLowerWarning", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.7.1.20", NULL, SU_FLAG_OK, NULL }, /* pduOutletActivePowerThLowerWarning.1.21 = INTEGER: 0 */ { "unmapped.pduOutletActivePowerThLowerWarning", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.7.1.21", NULL, SU_FLAG_OK, NULL }, /* pduOutletActivePowerThLowerWarning.1.22 = INTEGER: 0 */ { "unmapped.pduOutletActivePowerThLowerWarning", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.7.1.22", NULL, SU_FLAG_OK, NULL }, /* pduOutletActivePowerThLowerWarning.1.23 = INTEGER: 0 */ { "unmapped.pduOutletActivePowerThLowerWarning", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.7.1.23", NULL, SU_FLAG_OK, NULL }, /* pduOutletActivePowerThLowerWarning.1.24 = INTEGER: 0 */ { "unmapped.pduOutletActivePowerThLowerWarning", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.7.1.24", NULL, SU_FLAG_OK, NULL }, /* pduOutletActivePowerThLowerWarning.1.25 = INTEGER: 0 */ { "unmapped.pduOutletActivePowerThLowerWarning", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.7.1.25", NULL, SU_FLAG_OK, NULL }, /* pduOutletActivePowerThLowerWarning.1.26 = INTEGER: 0 */ { "unmapped.pduOutletActivePowerThLowerWarning", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.7.1.26", NULL, SU_FLAG_OK, NULL }, /* pduOutletActivePowerThLowerWarning.1.27 = INTEGER: 0 */ { "unmapped.pduOutletActivePowerThLowerWarning", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.7.1.27", NULL, SU_FLAG_OK, NULL }, /* pduOutletActivePowerThLowerWarning.1.28 = INTEGER: 0 */ { "unmapped.pduOutletActivePowerThLowerWarning", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.7.1.28", NULL, SU_FLAG_OK, NULL }, /* pduOutletActivePowerThLowerWarning.1.29 = INTEGER: 0 */ { "unmapped.pduOutletActivePowerThLowerWarning", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.7.1.29", NULL, SU_FLAG_OK, NULL }, /* pduOutletActivePowerThLowerWarning.1.30 = INTEGER: 0 */ { "unmapped.pduOutletActivePowerThLowerWarning", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.7.1.30", NULL, SU_FLAG_OK, NULL }, /* pduOutletActivePowerThLowerWarning.1.31 = INTEGER: 0 */ { "unmapped.pduOutletActivePowerThLowerWarning", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.7.1.31", NULL, SU_FLAG_OK, NULL }, /* pduOutletActivePowerThLowerWarning.1.32 = INTEGER: 0 */ { "unmapped.pduOutletActivePowerThLowerWarning", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.7.1.32", NULL, SU_FLAG_OK, NULL }, /* pduOutletActivePowerThLowerWarning.1.33 = INTEGER: 0 */ { "unmapped.pduOutletActivePowerThLowerWarning", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.7.1.33", NULL, SU_FLAG_OK, NULL }, /* pduOutletActivePowerThLowerWarning.1.34 = INTEGER: 0 */ { "unmapped.pduOutletActivePowerThLowerWarning", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.7.1.34", NULL, SU_FLAG_OK, NULL }, /* pduOutletActivePowerThLowerWarning.1.35 = INTEGER: 0 */ { "unmapped.pduOutletActivePowerThLowerWarning", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.7.1.35", NULL, SU_FLAG_OK, NULL }, /* pduOutletActivePowerThLowerWarning.1.36 = INTEGER: 0 */ { "unmapped.pduOutletActivePowerThLowerWarning", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.7.1.36", NULL, SU_FLAG_OK, NULL }, /* pduOutletActivePowerThLowerWarning.1.37 = INTEGER: 0 */ { "unmapped.pduOutletActivePowerThLowerWarning", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.7.1.37", NULL, SU_FLAG_OK, NULL }, /* pduOutletActivePowerThLowerWarning.1.38 = INTEGER: 0 */ { "unmapped.pduOutletActivePowerThLowerWarning", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.7.1.38", NULL, SU_FLAG_OK, NULL }, /* pduOutletActivePowerThLowerWarning.1.39 = INTEGER: 0 */ { "unmapped.pduOutletActivePowerThLowerWarning", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.7.1.39", NULL, SU_FLAG_OK, NULL }, /* pduOutletActivePowerThLowerWarning.1.40 = INTEGER: 0 */ { "unmapped.pduOutletActivePowerThLowerWarning", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.7.1.40", NULL, SU_FLAG_OK, NULL }, /* pduOutletActivePowerThLowerWarning.1.41 = INTEGER: 0 */ { "unmapped.pduOutletActivePowerThLowerWarning", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.7.1.41", NULL, SU_FLAG_OK, NULL }, /* pduOutletActivePowerThLowerWarning.1.42 = INTEGER: 0 */ { "unmapped.pduOutletActivePowerThLowerWarning", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.7.1.42", NULL, SU_FLAG_OK, NULL }, /* pduOutletActivePowerThLowerWarning.1.43 = INTEGER: 0 */ { "unmapped.pduOutletActivePowerThLowerWarning", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.7.1.43", NULL, SU_FLAG_OK, NULL }, /* pduOutletActivePowerThLowerWarning.1.44 = INTEGER: 0 */ { "unmapped.pduOutletActivePowerThLowerWarning", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.7.1.44", NULL, SU_FLAG_OK, NULL }, /* pduOutletActivePowerThLowerWarning.1.45 = INTEGER: 0 */ { "unmapped.pduOutletActivePowerThLowerWarning", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.7.1.45", NULL, SU_FLAG_OK, NULL }, /* pduOutletActivePowerThLowerWarning.1.46 = INTEGER: 0 */ { "unmapped.pduOutletActivePowerThLowerWarning", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.7.1.46", NULL, SU_FLAG_OK, NULL }, /* pduOutletActivePowerThLowerWarning.1.47 = INTEGER: 0 */ { "unmapped.pduOutletActivePowerThLowerWarning", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.7.1.47", NULL, SU_FLAG_OK, NULL }, /* pduOutletActivePowerThLowerWarning.1.48 = INTEGER: 0 */ { "unmapped.pduOutletActivePowerThLowerWarning", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.7.1.48", NULL, SU_FLAG_OK, NULL }, /* pduOutletActivePowerThLowerCritical.1.1 = INTEGER: 0 */ { "unmapped.pduOutletActivePowerThLowerCritical", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.8.1.1", NULL, SU_FLAG_OK, NULL }, /* pduOutletActivePowerThLowerCritical.1.2 = INTEGER: 0 */ { "unmapped.pduOutletActivePowerThLowerCritical", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.8.1.2", NULL, SU_FLAG_OK, NULL }, /* pduOutletActivePowerThLowerCritical.1.3 = INTEGER: 0 */ { "unmapped.pduOutletActivePowerThLowerCritical", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.8.1.3", NULL, SU_FLAG_OK, NULL }, /* pduOutletActivePowerThLowerCritical.1.4 = INTEGER: 0 */ { "unmapped.pduOutletActivePowerThLowerCritical", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.8.1.4", NULL, SU_FLAG_OK, NULL }, /* pduOutletActivePowerThLowerCritical.1.5 = INTEGER: 0 */ { "unmapped.pduOutletActivePowerThLowerCritical", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.8.1.5", NULL, SU_FLAG_OK, NULL }, /* pduOutletActivePowerThLowerCritical.1.6 = INTEGER: 0 */ { "unmapped.pduOutletActivePowerThLowerCritical", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.8.1.6", NULL, SU_FLAG_OK, NULL }, /* pduOutletActivePowerThLowerCritical.1.7 = INTEGER: 0 */ { "unmapped.pduOutletActivePowerThLowerCritical", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.8.1.7", NULL, SU_FLAG_OK, NULL }, /* pduOutletActivePowerThLowerCritical.1.8 = INTEGER: 0 */ { "unmapped.pduOutletActivePowerThLowerCritical", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.8.1.8", NULL, SU_FLAG_OK, NULL }, /* pduOutletActivePowerThLowerCritical.1.9 = INTEGER: 0 */ { "unmapped.pduOutletActivePowerThLowerCritical", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.8.1.9", NULL, SU_FLAG_OK, NULL }, /* pduOutletActivePowerThLowerCritical.1.10 = INTEGER: 0 */ { "unmapped.pduOutletActivePowerThLowerCritical", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.8.1.10", NULL, SU_FLAG_OK, NULL }, /* pduOutletActivePowerThLowerCritical.1.11 = INTEGER: 0 */ { "unmapped.pduOutletActivePowerThLowerCritical", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.8.1.11", NULL, SU_FLAG_OK, NULL }, /* pduOutletActivePowerThLowerCritical.1.12 = INTEGER: 0 */ { "unmapped.pduOutletActivePowerThLowerCritical", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.8.1.12", NULL, SU_FLAG_OK, NULL }, /* pduOutletActivePowerThLowerCritical.1.13 = INTEGER: 0 */ { "unmapped.pduOutletActivePowerThLowerCritical", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.8.1.13", NULL, SU_FLAG_OK, NULL }, /* pduOutletActivePowerThLowerCritical.1.14 = INTEGER: 0 */ { "unmapped.pduOutletActivePowerThLowerCritical", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.8.1.14", NULL, SU_FLAG_OK, NULL }, /* pduOutletActivePowerThLowerCritical.1.15 = INTEGER: 0 */ { "unmapped.pduOutletActivePowerThLowerCritical", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.8.1.15", NULL, SU_FLAG_OK, NULL }, /* pduOutletActivePowerThLowerCritical.1.16 = INTEGER: 0 */ { "unmapped.pduOutletActivePowerThLowerCritical", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.8.1.16", NULL, SU_FLAG_OK, NULL }, /* pduOutletActivePowerThLowerCritical.1.17 = INTEGER: 0 */ { "unmapped.pduOutletActivePowerThLowerCritical", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.8.1.17", NULL, SU_FLAG_OK, NULL }, /* pduOutletActivePowerThLowerCritical.1.18 = INTEGER: 0 */ { "unmapped.pduOutletActivePowerThLowerCritical", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.8.1.18", NULL, SU_FLAG_OK, NULL }, /* pduOutletActivePowerThLowerCritical.1.19 = INTEGER: 0 */ { "unmapped.pduOutletActivePowerThLowerCritical", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.8.1.19", NULL, SU_FLAG_OK, NULL }, /* pduOutletActivePowerThLowerCritical.1.20 = INTEGER: 0 */ { "unmapped.pduOutletActivePowerThLowerCritical", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.8.1.20", NULL, SU_FLAG_OK, NULL }, /* pduOutletActivePowerThLowerCritical.1.21 = INTEGER: 0 */ { "unmapped.pduOutletActivePowerThLowerCritical", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.8.1.21", NULL, SU_FLAG_OK, NULL }, /* pduOutletActivePowerThLowerCritical.1.22 = INTEGER: 0 */ { "unmapped.pduOutletActivePowerThLowerCritical", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.8.1.22", NULL, SU_FLAG_OK, NULL }, /* pduOutletActivePowerThLowerCritical.1.23 = INTEGER: 0 */ { "unmapped.pduOutletActivePowerThLowerCritical", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.8.1.23", NULL, SU_FLAG_OK, NULL }, /* pduOutletActivePowerThLowerCritical.1.24 = INTEGER: 0 */ { "unmapped.pduOutletActivePowerThLowerCritical", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.8.1.24", NULL, SU_FLAG_OK, NULL }, /* pduOutletActivePowerThLowerCritical.1.25 = INTEGER: 0 */ { "unmapped.pduOutletActivePowerThLowerCritical", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.8.1.25", NULL, SU_FLAG_OK, NULL }, /* pduOutletActivePowerThLowerCritical.1.26 = INTEGER: 0 */ { "unmapped.pduOutletActivePowerThLowerCritical", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.8.1.26", NULL, SU_FLAG_OK, NULL }, /* pduOutletActivePowerThLowerCritical.1.27 = INTEGER: 0 */ { "unmapped.pduOutletActivePowerThLowerCritical", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.8.1.27", NULL, SU_FLAG_OK, NULL }, /* pduOutletActivePowerThLowerCritical.1.28 = INTEGER: 0 */ { "unmapped.pduOutletActivePowerThLowerCritical", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.8.1.28", NULL, SU_FLAG_OK, NULL }, /* pduOutletActivePowerThLowerCritical.1.29 = INTEGER: 0 */ { "unmapped.pduOutletActivePowerThLowerCritical", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.8.1.29", NULL, SU_FLAG_OK, NULL }, /* pduOutletActivePowerThLowerCritical.1.30 = INTEGER: 0 */ { "unmapped.pduOutletActivePowerThLowerCritical", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.8.1.30", NULL, SU_FLAG_OK, NULL }, /* pduOutletActivePowerThLowerCritical.1.31 = INTEGER: 0 */ { "unmapped.pduOutletActivePowerThLowerCritical", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.8.1.31", NULL, SU_FLAG_OK, NULL }, /* pduOutletActivePowerThLowerCritical.1.32 = INTEGER: 0 */ { "unmapped.pduOutletActivePowerThLowerCritical", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.8.1.32", NULL, SU_FLAG_OK, NULL }, /* pduOutletActivePowerThLowerCritical.1.33 = INTEGER: 0 */ { "unmapped.pduOutletActivePowerThLowerCritical", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.8.1.33", NULL, SU_FLAG_OK, NULL }, /* pduOutletActivePowerThLowerCritical.1.34 = INTEGER: 0 */ { "unmapped.pduOutletActivePowerThLowerCritical", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.8.1.34", NULL, SU_FLAG_OK, NULL }, /* pduOutletActivePowerThLowerCritical.1.35 = INTEGER: 0 */ { "unmapped.pduOutletActivePowerThLowerCritical", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.8.1.35", NULL, SU_FLAG_OK, NULL }, /* pduOutletActivePowerThLowerCritical.1.36 = INTEGER: 0 */ { "unmapped.pduOutletActivePowerThLowerCritical", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.8.1.36", NULL, SU_FLAG_OK, NULL }, /* pduOutletActivePowerThLowerCritical.1.37 = INTEGER: 0 */ { "unmapped.pduOutletActivePowerThLowerCritical", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.8.1.37", NULL, SU_FLAG_OK, NULL }, /* pduOutletActivePowerThLowerCritical.1.38 = INTEGER: 0 */ { "unmapped.pduOutletActivePowerThLowerCritical", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.8.1.38", NULL, SU_FLAG_OK, NULL }, /* pduOutletActivePowerThLowerCritical.1.39 = INTEGER: 0 */ { "unmapped.pduOutletActivePowerThLowerCritical", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.8.1.39", NULL, SU_FLAG_OK, NULL }, /* pduOutletActivePowerThLowerCritical.1.40 = INTEGER: 0 */ { "unmapped.pduOutletActivePowerThLowerCritical", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.8.1.40", NULL, SU_FLAG_OK, NULL }, /* pduOutletActivePowerThLowerCritical.1.41 = INTEGER: 0 */ { "unmapped.pduOutletActivePowerThLowerCritical", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.8.1.41", NULL, SU_FLAG_OK, NULL }, /* pduOutletActivePowerThLowerCritical.1.42 = INTEGER: 0 */ { "unmapped.pduOutletActivePowerThLowerCritical", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.8.1.42", NULL, SU_FLAG_OK, NULL }, /* pduOutletActivePowerThLowerCritical.1.43 = INTEGER: 0 */ { "unmapped.pduOutletActivePowerThLowerCritical", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.8.1.43", NULL, SU_FLAG_OK, NULL }, /* pduOutletActivePowerThLowerCritical.1.44 = INTEGER: 0 */ { "unmapped.pduOutletActivePowerThLowerCritical", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.8.1.44", NULL, SU_FLAG_OK, NULL }, /* pduOutletActivePowerThLowerCritical.1.45 = INTEGER: 0 */ { "unmapped.pduOutletActivePowerThLowerCritical", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.8.1.45", NULL, SU_FLAG_OK, NULL }, /* pduOutletActivePowerThLowerCritical.1.46 = INTEGER: 0 */ { "unmapped.pduOutletActivePowerThLowerCritical", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.8.1.46", NULL, SU_FLAG_OK, NULL }, /* pduOutletActivePowerThLowerCritical.1.47 = INTEGER: 0 */ { "unmapped.pduOutletActivePowerThLowerCritical", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.8.1.47", NULL, SU_FLAG_OK, NULL }, /* pduOutletActivePowerThLowerCritical.1.48 = INTEGER: 0 */ { "unmapped.pduOutletActivePowerThLowerCritical", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.8.1.48", NULL, SU_FLAG_OK, NULL }, /* pduOutletActivePowerThUpperWarning.1.1 = INTEGER: 0 */ { "unmapped.pduOutletActivePowerThUpperWarning", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.9.1.1", NULL, SU_FLAG_OK, NULL }, /* pduOutletActivePowerThUpperWarning.1.2 = INTEGER: 0 */ { "unmapped.pduOutletActivePowerThUpperWarning", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.9.1.2", NULL, SU_FLAG_OK, NULL }, /* pduOutletActivePowerThUpperWarning.1.3 = INTEGER: 0 */ { "unmapped.pduOutletActivePowerThUpperWarning", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.9.1.3", NULL, SU_FLAG_OK, NULL }, /* pduOutletActivePowerThUpperWarning.1.4 = INTEGER: 0 */ { "unmapped.pduOutletActivePowerThUpperWarning", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.9.1.4", NULL, SU_FLAG_OK, NULL }, /* pduOutletActivePowerThUpperWarning.1.5 = INTEGER: 0 */ { "unmapped.pduOutletActivePowerThUpperWarning", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.9.1.5", NULL, SU_FLAG_OK, NULL }, /* pduOutletActivePowerThUpperWarning.1.6 = INTEGER: 0 */ { "unmapped.pduOutletActivePowerThUpperWarning", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.9.1.6", NULL, SU_FLAG_OK, NULL }, /* pduOutletActivePowerThUpperWarning.1.7 = INTEGER: 0 */ { "unmapped.pduOutletActivePowerThUpperWarning", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.9.1.7", NULL, SU_FLAG_OK, NULL }, /* pduOutletActivePowerThUpperWarning.1.8 = INTEGER: 0 */ { "unmapped.pduOutletActivePowerThUpperWarning", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.9.1.8", NULL, SU_FLAG_OK, NULL }, /* pduOutletActivePowerThUpperWarning.1.9 = INTEGER: 0 */ { "unmapped.pduOutletActivePowerThUpperWarning", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.9.1.9", NULL, SU_FLAG_OK, NULL }, /* pduOutletActivePowerThUpperWarning.1.10 = INTEGER: 0 */ { "unmapped.pduOutletActivePowerThUpperWarning", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.9.1.10", NULL, SU_FLAG_OK, NULL }, /* pduOutletActivePowerThUpperWarning.1.11 = INTEGER: 0 */ { "unmapped.pduOutletActivePowerThUpperWarning", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.9.1.11", NULL, SU_FLAG_OK, NULL }, /* pduOutletActivePowerThUpperWarning.1.12 = INTEGER: 0 */ { "unmapped.pduOutletActivePowerThUpperWarning", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.9.1.12", NULL, SU_FLAG_OK, NULL }, /* pduOutletActivePowerThUpperWarning.1.13 = INTEGER: 0 */ { "unmapped.pduOutletActivePowerThUpperWarning", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.9.1.13", NULL, SU_FLAG_OK, NULL }, /* pduOutletActivePowerThUpperWarning.1.14 = INTEGER: 0 */ { "unmapped.pduOutletActivePowerThUpperWarning", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.9.1.14", NULL, SU_FLAG_OK, NULL }, /* pduOutletActivePowerThUpperWarning.1.15 = INTEGER: 0 */ { "unmapped.pduOutletActivePowerThUpperWarning", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.9.1.15", NULL, SU_FLAG_OK, NULL }, /* pduOutletActivePowerThUpperWarning.1.16 = INTEGER: 0 */ { "unmapped.pduOutletActivePowerThUpperWarning", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.9.1.16", NULL, SU_FLAG_OK, NULL }, /* pduOutletActivePowerThUpperWarning.1.17 = INTEGER: 0 */ { "unmapped.pduOutletActivePowerThUpperWarning", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.9.1.17", NULL, SU_FLAG_OK, NULL }, /* pduOutletActivePowerThUpperWarning.1.18 = INTEGER: 0 */ { "unmapped.pduOutletActivePowerThUpperWarning", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.9.1.18", NULL, SU_FLAG_OK, NULL }, /* pduOutletActivePowerThUpperWarning.1.19 = INTEGER: 0 */ { "unmapped.pduOutletActivePowerThUpperWarning", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.9.1.19", NULL, SU_FLAG_OK, NULL }, /* pduOutletActivePowerThUpperWarning.1.20 = INTEGER: 0 */ { "unmapped.pduOutletActivePowerThUpperWarning", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.9.1.20", NULL, SU_FLAG_OK, NULL }, /* pduOutletActivePowerThUpperWarning.1.21 = INTEGER: 0 */ { "unmapped.pduOutletActivePowerThUpperWarning", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.9.1.21", NULL, SU_FLAG_OK, NULL }, /* pduOutletActivePowerThUpperWarning.1.22 = INTEGER: 0 */ { "unmapped.pduOutletActivePowerThUpperWarning", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.9.1.22", NULL, SU_FLAG_OK, NULL }, /* pduOutletActivePowerThUpperWarning.1.23 = INTEGER: 0 */ { "unmapped.pduOutletActivePowerThUpperWarning", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.9.1.23", NULL, SU_FLAG_OK, NULL }, /* pduOutletActivePowerThUpperWarning.1.24 = INTEGER: 0 */ { "unmapped.pduOutletActivePowerThUpperWarning", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.9.1.24", NULL, SU_FLAG_OK, NULL }, /* pduOutletActivePowerThUpperWarning.1.25 = INTEGER: 0 */ { "unmapped.pduOutletActivePowerThUpperWarning", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.9.1.25", NULL, SU_FLAG_OK, NULL }, /* pduOutletActivePowerThUpperWarning.1.26 = INTEGER: 0 */ { "unmapped.pduOutletActivePowerThUpperWarning", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.9.1.26", NULL, SU_FLAG_OK, NULL }, /* pduOutletActivePowerThUpperWarning.1.27 = INTEGER: 0 */ { "unmapped.pduOutletActivePowerThUpperWarning", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.9.1.27", NULL, SU_FLAG_OK, NULL }, /* pduOutletActivePowerThUpperWarning.1.28 = INTEGER: 0 */ { "unmapped.pduOutletActivePowerThUpperWarning", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.9.1.28", NULL, SU_FLAG_OK, NULL }, /* pduOutletActivePowerThUpperWarning.1.29 = INTEGER: 0 */ { "unmapped.pduOutletActivePowerThUpperWarning", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.9.1.29", NULL, SU_FLAG_OK, NULL }, /* pduOutletActivePowerThUpperWarning.1.30 = INTEGER: 0 */ { "unmapped.pduOutletActivePowerThUpperWarning", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.9.1.30", NULL, SU_FLAG_OK, NULL }, /* pduOutletActivePowerThUpperWarning.1.31 = INTEGER: 0 */ { "unmapped.pduOutletActivePowerThUpperWarning", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.9.1.31", NULL, SU_FLAG_OK, NULL }, /* pduOutletActivePowerThUpperWarning.1.32 = INTEGER: 0 */ { "unmapped.pduOutletActivePowerThUpperWarning", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.9.1.32", NULL, SU_FLAG_OK, NULL }, /* pduOutletActivePowerThUpperWarning.1.33 = INTEGER: 0 */ { "unmapped.pduOutletActivePowerThUpperWarning", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.9.1.33", NULL, SU_FLAG_OK, NULL }, /* pduOutletActivePowerThUpperWarning.1.34 = INTEGER: 0 */ { "unmapped.pduOutletActivePowerThUpperWarning", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.9.1.34", NULL, SU_FLAG_OK, NULL }, /* pduOutletActivePowerThUpperWarning.1.35 = INTEGER: 0 */ { "unmapped.pduOutletActivePowerThUpperWarning", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.9.1.35", NULL, SU_FLAG_OK, NULL }, /* pduOutletActivePowerThUpperWarning.1.36 = INTEGER: 0 */ { "unmapped.pduOutletActivePowerThUpperWarning", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.9.1.36", NULL, SU_FLAG_OK, NULL }, /* pduOutletActivePowerThUpperWarning.1.37 = INTEGER: 0 */ { "unmapped.pduOutletActivePowerThUpperWarning", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.9.1.37", NULL, SU_FLAG_OK, NULL }, /* pduOutletActivePowerThUpperWarning.1.38 = INTEGER: 0 */ { "unmapped.pduOutletActivePowerThUpperWarning", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.9.1.38", NULL, SU_FLAG_OK, NULL }, /* pduOutletActivePowerThUpperWarning.1.39 = INTEGER: 0 */ { "unmapped.pduOutletActivePowerThUpperWarning", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.9.1.39", NULL, SU_FLAG_OK, NULL }, /* pduOutletActivePowerThUpperWarning.1.40 = INTEGER: 0 */ { "unmapped.pduOutletActivePowerThUpperWarning", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.9.1.40", NULL, SU_FLAG_OK, NULL }, /* pduOutletActivePowerThUpperWarning.1.41 = INTEGER: 0 */ { "unmapped.pduOutletActivePowerThUpperWarning", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.9.1.41", NULL, SU_FLAG_OK, NULL }, /* pduOutletActivePowerThUpperWarning.1.42 = INTEGER: 0 */ { "unmapped.pduOutletActivePowerThUpperWarning", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.9.1.42", NULL, SU_FLAG_OK, NULL }, /* pduOutletActivePowerThUpperWarning.1.43 = INTEGER: 0 */ { "unmapped.pduOutletActivePowerThUpperWarning", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.9.1.43", NULL, SU_FLAG_OK, NULL }, /* pduOutletActivePowerThUpperWarning.1.44 = INTEGER: 0 */ { "unmapped.pduOutletActivePowerThUpperWarning", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.9.1.44", NULL, SU_FLAG_OK, NULL }, /* pduOutletActivePowerThUpperWarning.1.45 = INTEGER: 0 */ { "unmapped.pduOutletActivePowerThUpperWarning", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.9.1.45", NULL, SU_FLAG_OK, NULL }, /* pduOutletActivePowerThUpperWarning.1.46 = INTEGER: 0 */ { "unmapped.pduOutletActivePowerThUpperWarning", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.9.1.46", NULL, SU_FLAG_OK, NULL }, /* pduOutletActivePowerThUpperWarning.1.47 = INTEGER: 0 */ { "unmapped.pduOutletActivePowerThUpperWarning", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.9.1.47", NULL, SU_FLAG_OK, NULL }, /* pduOutletActivePowerThUpperWarning.1.48 = INTEGER: 0 */ { "unmapped.pduOutletActivePowerThUpperWarning", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.9.1.48", NULL, SU_FLAG_OK, NULL }, /* pduOutletActivePowerThUpperCritical.1.1 = INTEGER: 0 */ { "unmapped.pduOutletActivePowerThUpperCritical", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.10.1.1", NULL, SU_FLAG_OK, NULL }, /* pduOutletActivePowerThUpperCritical.1.2 = INTEGER: 0 */ { "unmapped.pduOutletActivePowerThUpperCritical", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.10.1.2", NULL, SU_FLAG_OK, NULL }, /* pduOutletActivePowerThUpperCritical.1.3 = INTEGER: 0 */ { "unmapped.pduOutletActivePowerThUpperCritical", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.10.1.3", NULL, SU_FLAG_OK, NULL }, /* pduOutletActivePowerThUpperCritical.1.4 = INTEGER: 0 */ { "unmapped.pduOutletActivePowerThUpperCritical", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.10.1.4", NULL, SU_FLAG_OK, NULL }, /* pduOutletActivePowerThUpperCritical.1.5 = INTEGER: 0 */ { "unmapped.pduOutletActivePowerThUpperCritical", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.10.1.5", NULL, SU_FLAG_OK, NULL }, /* pduOutletActivePowerThUpperCritical.1.6 = INTEGER: 0 */ { "unmapped.pduOutletActivePowerThUpperCritical", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.10.1.6", NULL, SU_FLAG_OK, NULL }, /* pduOutletActivePowerThUpperCritical.1.7 = INTEGER: 0 */ { "unmapped.pduOutletActivePowerThUpperCritical", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.10.1.7", NULL, SU_FLAG_OK, NULL }, /* pduOutletActivePowerThUpperCritical.1.8 = INTEGER: 0 */ { "unmapped.pduOutletActivePowerThUpperCritical", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.10.1.8", NULL, SU_FLAG_OK, NULL }, /* pduOutletActivePowerThUpperCritical.1.9 = INTEGER: 0 */ { "unmapped.pduOutletActivePowerThUpperCritical", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.10.1.9", NULL, SU_FLAG_OK, NULL }, /* pduOutletActivePowerThUpperCritical.1.10 = INTEGER: 0 */ { "unmapped.pduOutletActivePowerThUpperCritical", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.10.1.10", NULL, SU_FLAG_OK, NULL }, /* pduOutletActivePowerThUpperCritical.1.11 = INTEGER: 0 */ { "unmapped.pduOutletActivePowerThUpperCritical", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.10.1.11", NULL, SU_FLAG_OK, NULL }, /* pduOutletActivePowerThUpperCritical.1.12 = INTEGER: 0 */ { "unmapped.pduOutletActivePowerThUpperCritical", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.10.1.12", NULL, SU_FLAG_OK, NULL }, /* pduOutletActivePowerThUpperCritical.1.13 = INTEGER: 0 */ { "unmapped.pduOutletActivePowerThUpperCritical", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.10.1.13", NULL, SU_FLAG_OK, NULL }, /* pduOutletActivePowerThUpperCritical.1.14 = INTEGER: 0 */ { "unmapped.pduOutletActivePowerThUpperCritical", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.10.1.14", NULL, SU_FLAG_OK, NULL }, /* pduOutletActivePowerThUpperCritical.1.15 = INTEGER: 0 */ { "unmapped.pduOutletActivePowerThUpperCritical", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.10.1.15", NULL, SU_FLAG_OK, NULL }, /* pduOutletActivePowerThUpperCritical.1.16 = INTEGER: 0 */ { "unmapped.pduOutletActivePowerThUpperCritical", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.10.1.16", NULL, SU_FLAG_OK, NULL }, /* pduOutletActivePowerThUpperCritical.1.17 = INTEGER: 0 */ { "unmapped.pduOutletActivePowerThUpperCritical", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.10.1.17", NULL, SU_FLAG_OK, NULL }, /* pduOutletActivePowerThUpperCritical.1.18 = INTEGER: 0 */ { "unmapped.pduOutletActivePowerThUpperCritical", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.10.1.18", NULL, SU_FLAG_OK, NULL }, /* pduOutletActivePowerThUpperCritical.1.19 = INTEGER: 0 */ { "unmapped.pduOutletActivePowerThUpperCritical", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.10.1.19", NULL, SU_FLAG_OK, NULL }, /* pduOutletActivePowerThUpperCritical.1.20 = INTEGER: 0 */ { "unmapped.pduOutletActivePowerThUpperCritical", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.10.1.20", NULL, SU_FLAG_OK, NULL }, /* pduOutletActivePowerThUpperCritical.1.21 = INTEGER: 0 */ { "unmapped.pduOutletActivePowerThUpperCritical", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.10.1.21", NULL, SU_FLAG_OK, NULL }, /* pduOutletActivePowerThUpperCritical.1.22 = INTEGER: 0 */ { "unmapped.pduOutletActivePowerThUpperCritical", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.10.1.22", NULL, SU_FLAG_OK, NULL }, /* pduOutletActivePowerThUpperCritical.1.23 = INTEGER: 0 */ { "unmapped.pduOutletActivePowerThUpperCritical", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.10.1.23", NULL, SU_FLAG_OK, NULL }, /* pduOutletActivePowerThUpperCritical.1.24 = INTEGER: 0 */ { "unmapped.pduOutletActivePowerThUpperCritical", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.10.1.24", NULL, SU_FLAG_OK, NULL }, /* pduOutletActivePowerThUpperCritical.1.25 = INTEGER: 0 */ { "unmapped.pduOutletActivePowerThUpperCritical", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.10.1.25", NULL, SU_FLAG_OK, NULL }, /* pduOutletActivePowerThUpperCritical.1.26 = INTEGER: 0 */ { "unmapped.pduOutletActivePowerThUpperCritical", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.10.1.26", NULL, SU_FLAG_OK, NULL }, /* pduOutletActivePowerThUpperCritical.1.27 = INTEGER: 0 */ { "unmapped.pduOutletActivePowerThUpperCritical", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.10.1.27", NULL, SU_FLAG_OK, NULL }, /* pduOutletActivePowerThUpperCritical.1.28 = INTEGER: 0 */ { "unmapped.pduOutletActivePowerThUpperCritical", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.10.1.28", NULL, SU_FLAG_OK, NULL }, /* pduOutletActivePowerThUpperCritical.1.29 = INTEGER: 0 */ { "unmapped.pduOutletActivePowerThUpperCritical", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.10.1.29", NULL, SU_FLAG_OK, NULL }, /* pduOutletActivePowerThUpperCritical.1.30 = INTEGER: 0 */ { "unmapped.pduOutletActivePowerThUpperCritical", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.10.1.30", NULL, SU_FLAG_OK, NULL }, /* pduOutletActivePowerThUpperCritical.1.31 = INTEGER: 0 */ { "unmapped.pduOutletActivePowerThUpperCritical", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.10.1.31", NULL, SU_FLAG_OK, NULL }, /* pduOutletActivePowerThUpperCritical.1.32 = INTEGER: 0 */ { "unmapped.pduOutletActivePowerThUpperCritical", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.10.1.32", NULL, SU_FLAG_OK, NULL }, /* pduOutletActivePowerThUpperCritical.1.33 = INTEGER: 0 */ { "unmapped.pduOutletActivePowerThUpperCritical", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.10.1.33", NULL, SU_FLAG_OK, NULL }, /* pduOutletActivePowerThUpperCritical.1.34 = INTEGER: 0 */ { "unmapped.pduOutletActivePowerThUpperCritical", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.10.1.34", NULL, SU_FLAG_OK, NULL }, /* pduOutletActivePowerThUpperCritical.1.35 = INTEGER: 0 */ { "unmapped.pduOutletActivePowerThUpperCritical", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.10.1.35", NULL, SU_FLAG_OK, NULL }, /* pduOutletActivePowerThUpperCritical.1.36 = INTEGER: 0 */ { "unmapped.pduOutletActivePowerThUpperCritical", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.10.1.36", NULL, SU_FLAG_OK, NULL }, /* pduOutletActivePowerThUpperCritical.1.37 = INTEGER: 0 */ { "unmapped.pduOutletActivePowerThUpperCritical", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.10.1.37", NULL, SU_FLAG_OK, NULL }, /* pduOutletActivePowerThUpperCritical.1.38 = INTEGER: 0 */ { "unmapped.pduOutletActivePowerThUpperCritical", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.10.1.38", NULL, SU_FLAG_OK, NULL }, /* pduOutletActivePowerThUpperCritical.1.39 = INTEGER: 0 */ { "unmapped.pduOutletActivePowerThUpperCritical", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.10.1.39", NULL, SU_FLAG_OK, NULL }, /* pduOutletActivePowerThUpperCritical.1.40 = INTEGER: 0 */ { "unmapped.pduOutletActivePowerThUpperCritical", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.10.1.40", NULL, SU_FLAG_OK, NULL }, /* pduOutletActivePowerThUpperCritical.1.41 = INTEGER: 0 */ { "unmapped.pduOutletActivePowerThUpperCritical", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.10.1.41", NULL, SU_FLAG_OK, NULL }, /* pduOutletActivePowerThUpperCritical.1.42 = INTEGER: 0 */ { "unmapped.pduOutletActivePowerThUpperCritical", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.10.1.42", NULL, SU_FLAG_OK, NULL }, /* pduOutletActivePowerThUpperCritical.1.43 = INTEGER: 0 */ { "unmapped.pduOutletActivePowerThUpperCritical", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.10.1.43", NULL, SU_FLAG_OK, NULL }, /* pduOutletActivePowerThUpperCritical.1.44 = INTEGER: 0 */ { "unmapped.pduOutletActivePowerThUpperCritical", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.10.1.44", NULL, SU_FLAG_OK, NULL }, /* pduOutletActivePowerThUpperCritical.1.45 = INTEGER: 0 */ { "unmapped.pduOutletActivePowerThUpperCritical", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.10.1.45", NULL, SU_FLAG_OK, NULL }, /* pduOutletActivePowerThUpperCritical.1.46 = INTEGER: 0 */ { "unmapped.pduOutletActivePowerThUpperCritical", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.10.1.46", NULL, SU_FLAG_OK, NULL }, /* pduOutletActivePowerThUpperCritical.1.47 = INTEGER: 0 */ { "unmapped.pduOutletActivePowerThUpperCritical", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.10.1.47", NULL, SU_FLAG_OK, NULL }, /* pduOutletActivePowerThUpperCritical.1.48 = INTEGER: 0 */ { "unmapped.pduOutletActivePowerThUpperCritical", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.10.1.48", NULL, SU_FLAG_OK, NULL }, /* pduOutletWh.1.1 = INTEGER: 0 */ { "unmapped.pduOutletWh", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.14.1.1", NULL, SU_FLAG_OK, NULL }, /* pduOutletWh.1.2 = INTEGER: 0 */ { "unmapped.pduOutletWh", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.14.1.2", NULL, SU_FLAG_OK, NULL }, /* pduOutletWh.1.3 = INTEGER: 0 */ { "unmapped.pduOutletWh", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.14.1.3", NULL, SU_FLAG_OK, NULL }, /* pduOutletWh.1.4 = INTEGER: 0 */ { "unmapped.pduOutletWh", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.14.1.4", NULL, SU_FLAG_OK, NULL }, /* pduOutletWh.1.5 = INTEGER: 0 */ { "unmapped.pduOutletWh", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.14.1.5", NULL, SU_FLAG_OK, NULL }, /* pduOutletWh.1.6 = INTEGER: 0 */ { "unmapped.pduOutletWh", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.14.1.6", NULL, SU_FLAG_OK, NULL }, /* pduOutletWh.1.7 = INTEGER: 0 */ { "unmapped.pduOutletWh", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.14.1.7", NULL, SU_FLAG_OK, NULL }, /* pduOutletWh.1.8 = INTEGER: 0 */ { "unmapped.pduOutletWh", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.14.1.8", NULL, SU_FLAG_OK, NULL }, /* pduOutletWh.1.9 = INTEGER: 0 */ { "unmapped.pduOutletWh", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.14.1.9", NULL, SU_FLAG_OK, NULL }, /* pduOutletWh.1.10 = INTEGER: 0 */ { "unmapped.pduOutletWh", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.14.1.10", NULL, SU_FLAG_OK, NULL }, /* pduOutletWh.1.11 = INTEGER: 0 */ { "unmapped.pduOutletWh", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.14.1.11", NULL, SU_FLAG_OK, NULL }, /* pduOutletWh.1.12 = INTEGER: 0 */ { "unmapped.pduOutletWh", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.14.1.12", NULL, SU_FLAG_OK, NULL }, /* pduOutletWh.1.13 = INTEGER: 0 */ { "unmapped.pduOutletWh", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.14.1.13", NULL, SU_FLAG_OK, NULL }, /* pduOutletWh.1.14 = INTEGER: 0 */ { "unmapped.pduOutletWh", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.14.1.14", NULL, SU_FLAG_OK, NULL }, /* pduOutletWh.1.15 = INTEGER: 0 */ { "unmapped.pduOutletWh", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.14.1.15", NULL, SU_FLAG_OK, NULL }, /* pduOutletWh.1.16 = INTEGER: 0 */ { "unmapped.pduOutletWh", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.14.1.16", NULL, SU_FLAG_OK, NULL }, /* pduOutletWh.1.17 = INTEGER: 0 */ { "unmapped.pduOutletWh", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.14.1.17", NULL, SU_FLAG_OK, NULL }, /* pduOutletWh.1.18 = INTEGER: 0 */ { "unmapped.pduOutletWh", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.14.1.18", NULL, SU_FLAG_OK, NULL }, /* pduOutletWh.1.19 = INTEGER: 0 */ { "unmapped.pduOutletWh", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.14.1.19", NULL, SU_FLAG_OK, NULL }, /* pduOutletWh.1.20 = INTEGER: 0 */ { "unmapped.pduOutletWh", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.14.1.20", NULL, SU_FLAG_OK, NULL }, /* pduOutletWh.1.21 = INTEGER: 0 */ { "unmapped.pduOutletWh", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.14.1.21", NULL, SU_FLAG_OK, NULL }, /* pduOutletWh.1.22 = INTEGER: 0 */ { "unmapped.pduOutletWh", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.14.1.22", NULL, SU_FLAG_OK, NULL }, /* pduOutletWh.1.23 = INTEGER: 0 */ { "unmapped.pduOutletWh", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.14.1.23", NULL, SU_FLAG_OK, NULL }, /* pduOutletWh.1.24 = INTEGER: 0 */ { "unmapped.pduOutletWh", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.14.1.24", NULL, SU_FLAG_OK, NULL }, /* pduOutletWh.1.25 = INTEGER: 0 */ { "unmapped.pduOutletWh", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.14.1.25", NULL, SU_FLAG_OK, NULL }, /* pduOutletWh.1.26 = INTEGER: 0 */ { "unmapped.pduOutletWh", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.14.1.26", NULL, SU_FLAG_OK, NULL }, /* pduOutletWh.1.27 = INTEGER: 0 */ { "unmapped.pduOutletWh", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.14.1.27", NULL, SU_FLAG_OK, NULL }, /* pduOutletWh.1.28 = INTEGER: 0 */ { "unmapped.pduOutletWh", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.14.1.28", NULL, SU_FLAG_OK, NULL }, /* pduOutletWh.1.29 = INTEGER: 0 */ { "unmapped.pduOutletWh", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.14.1.29", NULL, SU_FLAG_OK, NULL }, /* pduOutletWh.1.30 = INTEGER: 0 */ { "unmapped.pduOutletWh", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.14.1.30", NULL, SU_FLAG_OK, NULL }, /* pduOutletWh.1.31 = INTEGER: 0 */ { "unmapped.pduOutletWh", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.14.1.31", NULL, SU_FLAG_OK, NULL }, /* pduOutletWh.1.32 = INTEGER: 0 */ { "unmapped.pduOutletWh", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.14.1.32", NULL, SU_FLAG_OK, NULL }, /* pduOutletWh.1.33 = INTEGER: 0 */ { "unmapped.pduOutletWh", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.14.1.33", NULL, SU_FLAG_OK, NULL }, /* pduOutletWh.1.34 = INTEGER: 0 */ { "unmapped.pduOutletWh", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.14.1.34", NULL, SU_FLAG_OK, NULL }, /* pduOutletWh.1.35 = INTEGER: 0 */ { "unmapped.pduOutletWh", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.14.1.35", NULL, SU_FLAG_OK, NULL }, /* pduOutletWh.1.36 = INTEGER: 0 */ { "unmapped.pduOutletWh", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.14.1.36", NULL, SU_FLAG_OK, NULL }, /* pduOutletWh.1.37 = INTEGER: 0 */ { "unmapped.pduOutletWh", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.14.1.37", NULL, SU_FLAG_OK, NULL }, /* pduOutletWh.1.38 = INTEGER: 0 */ { "unmapped.pduOutletWh", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.14.1.38", NULL, SU_FLAG_OK, NULL }, /* pduOutletWh.1.39 = INTEGER: 0 */ { "unmapped.pduOutletWh", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.14.1.39", NULL, SU_FLAG_OK, NULL }, /* pduOutletWh.1.40 = INTEGER: 0 */ { "unmapped.pduOutletWh", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.14.1.40", NULL, SU_FLAG_OK, NULL }, /* pduOutletWh.1.41 = INTEGER: 0 */ { "unmapped.pduOutletWh", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.14.1.41", NULL, SU_FLAG_OK, NULL }, /* pduOutletWh.1.42 = INTEGER: 0 */ { "unmapped.pduOutletWh", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.14.1.42", NULL, SU_FLAG_OK, NULL }, /* pduOutletWh.1.43 = INTEGER: 0 */ { "unmapped.pduOutletWh", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.14.1.43", NULL, SU_FLAG_OK, NULL }, /* pduOutletWh.1.44 = INTEGER: 0 */ { "unmapped.pduOutletWh", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.14.1.44", NULL, SU_FLAG_OK, NULL }, /* pduOutletWh.1.45 = INTEGER: 0 */ { "unmapped.pduOutletWh", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.14.1.45", NULL, SU_FLAG_OK, NULL }, /* pduOutletWh.1.46 = INTEGER: 0 */ { "unmapped.pduOutletWh", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.14.1.46", NULL, SU_FLAG_OK, NULL }, /* pduOutletWh.1.47 = INTEGER: 0 */ { "unmapped.pduOutletWh", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.14.1.47", NULL, SU_FLAG_OK, NULL }, /* pduOutletWh.1.48 = INTEGER: 0 */ { "unmapped.pduOutletWh", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.14.1.48", NULL, SU_FLAG_OK, NULL }, /* pduOutletWhTimer.1.1 = Hex-STRING: 32 30 32 31 2F 30 35 2F 32 39 20 30 39 3A 30 36 */ { "unmapped.pduOutletWhTimer", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.534.7.1.5.1.1.15.1.1", NULL, SU_FLAG_OK, NULL }, /* pduOutletWhTimer.1.2 = Hex-STRING: 32 30 32 31 2F 30 35 2F 32 39 20 30 39 3A 30 36 */ { "unmapped.pduOutletWhTimer", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.534.7.1.5.1.1.15.1.2", NULL, SU_FLAG_OK, NULL }, /* pduOutletWhTimer.1.3 = Hex-STRING: 32 30 32 31 2F 30 35 2F 32 39 20 30 39 3A 30 36 */ { "unmapped.pduOutletWhTimer", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.534.7.1.5.1.1.15.1.3", NULL, SU_FLAG_OK, NULL }, /* pduOutletWhTimer.1.4 = Hex-STRING: 32 30 32 31 2F 30 35 2F 32 39 20 30 39 3A 30 36 */ { "unmapped.pduOutletWhTimer", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.534.7.1.5.1.1.15.1.4", NULL, SU_FLAG_OK, NULL }, /* pduOutletWhTimer.1.5 = Hex-STRING: 32 30 32 31 2F 30 35 2F 32 39 20 30 39 3A 30 36 */ { "unmapped.pduOutletWhTimer", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.534.7.1.5.1.1.15.1.5", NULL, SU_FLAG_OK, NULL }, /* pduOutletWhTimer.1.6 = Hex-STRING: 32 30 32 31 2F 30 35 2F 32 39 20 30 39 3A 30 36 */ { "unmapped.pduOutletWhTimer", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.534.7.1.5.1.1.15.1.6", NULL, SU_FLAG_OK, NULL }, /* pduOutletWhTimer.1.7 = Hex-STRING: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 */ { "unmapped.pduOutletWhTimer", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.534.7.1.5.1.1.15.1.7", NULL, SU_FLAG_OK, NULL }, /* pduOutletWhTimer.1.8 = Hex-STRING: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 */ { "unmapped.pduOutletWhTimer", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.534.7.1.5.1.1.15.1.8", NULL, SU_FLAG_OK, NULL }, /* pduOutletWhTimer.1.9 = Hex-STRING: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 */ { "unmapped.pduOutletWhTimer", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.534.7.1.5.1.1.15.1.9", NULL, SU_FLAG_OK, NULL }, /* pduOutletWhTimer.1.10 = Hex-STRING: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 */ { "unmapped.pduOutletWhTimer", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.534.7.1.5.1.1.15.1.10", NULL, SU_FLAG_OK, NULL }, /* pduOutletWhTimer.1.11 = Hex-STRING: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 */ { "unmapped.pduOutletWhTimer", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.534.7.1.5.1.1.15.1.11", NULL, SU_FLAG_OK, NULL }, /* pduOutletWhTimer.1.12 = Hex-STRING: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 */ { "unmapped.pduOutletWhTimer", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.534.7.1.5.1.1.15.1.12", NULL, SU_FLAG_OK, NULL }, /* pduOutletWhTimer.1.13 = Hex-STRING: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 */ { "unmapped.pduOutletWhTimer", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.534.7.1.5.1.1.15.1.13", NULL, SU_FLAG_OK, NULL }, /* pduOutletWhTimer.1.14 = Hex-STRING: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 */ { "unmapped.pduOutletWhTimer", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.534.7.1.5.1.1.15.1.14", NULL, SU_FLAG_OK, NULL }, /* pduOutletWhTimer.1.15 = Hex-STRING: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 */ { "unmapped.pduOutletWhTimer", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.534.7.1.5.1.1.15.1.15", NULL, SU_FLAG_OK, NULL }, /* pduOutletWhTimer.1.16 = Hex-STRING: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 */ { "unmapped.pduOutletWhTimer", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.534.7.1.5.1.1.15.1.16", NULL, SU_FLAG_OK, NULL }, /* pduOutletWhTimer.1.17 = Hex-STRING: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 */ { "unmapped.pduOutletWhTimer", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.534.7.1.5.1.1.15.1.17", NULL, SU_FLAG_OK, NULL }, /* pduOutletWhTimer.1.18 = Hex-STRING: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 */ { "unmapped.pduOutletWhTimer", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.534.7.1.5.1.1.15.1.18", NULL, SU_FLAG_OK, NULL }, /* pduOutletWhTimer.1.19 = Hex-STRING: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 */ { "unmapped.pduOutletWhTimer", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.534.7.1.5.1.1.15.1.19", NULL, SU_FLAG_OK, NULL }, /* pduOutletWhTimer.1.20 = Hex-STRING: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 */ { "unmapped.pduOutletWhTimer", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.534.7.1.5.1.1.15.1.20", NULL, SU_FLAG_OK, NULL }, /* pduOutletWhTimer.1.21 = Hex-STRING: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 */ { "unmapped.pduOutletWhTimer", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.534.7.1.5.1.1.15.1.21", NULL, SU_FLAG_OK, NULL }, /* pduOutletWhTimer.1.22 = Hex-STRING: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 */ { "unmapped.pduOutletWhTimer", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.534.7.1.5.1.1.15.1.22", NULL, SU_FLAG_OK, NULL }, /* pduOutletWhTimer.1.23 = Hex-STRING: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 */ { "unmapped.pduOutletWhTimer", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.534.7.1.5.1.1.15.1.23", NULL, SU_FLAG_OK, NULL }, /* pduOutletWhTimer.1.24 = Hex-STRING: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 */ { "unmapped.pduOutletWhTimer", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.534.7.1.5.1.1.15.1.24", NULL, SU_FLAG_OK, NULL }, /* pduOutletWhTimer.1.25 = Hex-STRING: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 */ { "unmapped.pduOutletWhTimer", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.534.7.1.5.1.1.15.1.25", NULL, SU_FLAG_OK, NULL }, /* pduOutletWhTimer.1.26 = Hex-STRING: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 */ { "unmapped.pduOutletWhTimer", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.534.7.1.5.1.1.15.1.26", NULL, SU_FLAG_OK, NULL }, /* pduOutletWhTimer.1.27 = Hex-STRING: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 */ { "unmapped.pduOutletWhTimer", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.534.7.1.5.1.1.15.1.27", NULL, SU_FLAG_OK, NULL }, /* pduOutletWhTimer.1.28 = Hex-STRING: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 */ { "unmapped.pduOutletWhTimer", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.534.7.1.5.1.1.15.1.28", NULL, SU_FLAG_OK, NULL }, /* pduOutletWhTimer.1.29 = Hex-STRING: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 */ { "unmapped.pduOutletWhTimer", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.534.7.1.5.1.1.15.1.29", NULL, SU_FLAG_OK, NULL }, /* pduOutletWhTimer.1.30 = Hex-STRING: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 */ { "unmapped.pduOutletWhTimer", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.534.7.1.5.1.1.15.1.30", NULL, SU_FLAG_OK, NULL }, /* pduOutletWhTimer.1.31 = Hex-STRING: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 */ { "unmapped.pduOutletWhTimer", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.534.7.1.5.1.1.15.1.31", NULL, SU_FLAG_OK, NULL }, /* pduOutletWhTimer.1.32 = Hex-STRING: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 */ { "unmapped.pduOutletWhTimer", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.534.7.1.5.1.1.15.1.32", NULL, SU_FLAG_OK, NULL }, /* pduOutletWhTimer.1.33 = Hex-STRING: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 */ { "unmapped.pduOutletWhTimer", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.534.7.1.5.1.1.15.1.33", NULL, SU_FLAG_OK, NULL }, /* pduOutletWhTimer.1.34 = Hex-STRING: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 */ { "unmapped.pduOutletWhTimer", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.534.7.1.5.1.1.15.1.34", NULL, SU_FLAG_OK, NULL }, /* pduOutletWhTimer.1.35 = Hex-STRING: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 */ { "unmapped.pduOutletWhTimer", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.534.7.1.5.1.1.15.1.35", NULL, SU_FLAG_OK, NULL }, /* pduOutletWhTimer.1.36 = Hex-STRING: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 */ { "unmapped.pduOutletWhTimer", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.534.7.1.5.1.1.15.1.36", NULL, SU_FLAG_OK, NULL }, /* pduOutletWhTimer.1.37 = Hex-STRING: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 */ { "unmapped.pduOutletWhTimer", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.534.7.1.5.1.1.15.1.37", NULL, SU_FLAG_OK, NULL }, /* pduOutletWhTimer.1.38 = Hex-STRING: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 */ { "unmapped.pduOutletWhTimer", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.534.7.1.5.1.1.15.1.38", NULL, SU_FLAG_OK, NULL }, /* pduOutletWhTimer.1.39 = Hex-STRING: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 */ { "unmapped.pduOutletWhTimer", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.534.7.1.5.1.1.15.1.39", NULL, SU_FLAG_OK, NULL }, /* pduOutletWhTimer.1.40 = Hex-STRING: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 */ { "unmapped.pduOutletWhTimer", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.534.7.1.5.1.1.15.1.40", NULL, SU_FLAG_OK, NULL }, /* pduOutletWhTimer.1.41 = Hex-STRING: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 */ { "unmapped.pduOutletWhTimer", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.534.7.1.5.1.1.15.1.41", NULL, SU_FLAG_OK, NULL }, /* pduOutletWhTimer.1.42 = Hex-STRING: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 */ { "unmapped.pduOutletWhTimer", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.534.7.1.5.1.1.15.1.42", NULL, SU_FLAG_OK, NULL }, /* pduOutletWhTimer.1.43 = Hex-STRING: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 */ { "unmapped.pduOutletWhTimer", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.534.7.1.5.1.1.15.1.43", NULL, SU_FLAG_OK, NULL }, /* pduOutletWhTimer.1.44 = Hex-STRING: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 */ { "unmapped.pduOutletWhTimer", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.534.7.1.5.1.1.15.1.44", NULL, SU_FLAG_OK, NULL }, /* pduOutletWhTimer.1.45 = Hex-STRING: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 */ { "unmapped.pduOutletWhTimer", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.534.7.1.5.1.1.15.1.45", NULL, SU_FLAG_OK, NULL }, /* pduOutletWhTimer.1.46 = Hex-STRING: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 */ { "unmapped.pduOutletWhTimer", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.534.7.1.5.1.1.15.1.46", NULL, SU_FLAG_OK, NULL }, /* pduOutletWhTimer.1.47 = Hex-STRING: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 */ { "unmapped.pduOutletWhTimer", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.534.7.1.5.1.1.15.1.47", NULL, SU_FLAG_OK, NULL }, /* pduOutletWhTimer.1.48 = Hex-STRING: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 */ { "unmapped.pduOutletWhTimer", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.534.7.1.5.1.1.15.1.48", NULL, SU_FLAG_OK, NULL }, /* pduOutletPowerFactor.1.1 = INTEGER: 100 */ { "unmapped.pduOutletPowerFactor", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.16.1.1", NULL, SU_FLAG_OK, NULL }, /* pduOutletPowerFactor.1.2 = INTEGER: 100 */ { "unmapped.pduOutletPowerFactor", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.16.1.2", NULL, SU_FLAG_OK, NULL }, /* pduOutletPowerFactor.1.3 = INTEGER: 100 */ { "unmapped.pduOutletPowerFactor", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.16.1.3", NULL, SU_FLAG_OK, NULL }, /* pduOutletPowerFactor.1.4 = INTEGER: 100 */ { "unmapped.pduOutletPowerFactor", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.16.1.4", NULL, SU_FLAG_OK, NULL }, /* pduOutletPowerFactor.1.5 = INTEGER: 100 */ { "unmapped.pduOutletPowerFactor", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.16.1.5", NULL, SU_FLAG_OK, NULL }, /* pduOutletPowerFactor.1.6 = INTEGER: 100 */ { "unmapped.pduOutletPowerFactor", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.16.1.6", NULL, SU_FLAG_OK, NULL }, /* pduOutletPowerFactor.1.7 = INTEGER: 0 */ { "unmapped.pduOutletPowerFactor", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.16.1.7", NULL, SU_FLAG_OK, NULL }, /* pduOutletPowerFactor.1.8 = INTEGER: 0 */ { "unmapped.pduOutletPowerFactor", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.16.1.8", NULL, SU_FLAG_OK, NULL }, /* pduOutletPowerFactor.1.9 = INTEGER: 0 */ { "unmapped.pduOutletPowerFactor", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.16.1.9", NULL, SU_FLAG_OK, NULL }, /* pduOutletPowerFactor.1.10 = INTEGER: 0 */ { "unmapped.pduOutletPowerFactor", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.16.1.10", NULL, SU_FLAG_OK, NULL }, /* pduOutletPowerFactor.1.11 = INTEGER: 0 */ { "unmapped.pduOutletPowerFactor", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.16.1.11", NULL, SU_FLAG_OK, NULL }, /* pduOutletPowerFactor.1.12 = INTEGER: 0 */ { "unmapped.pduOutletPowerFactor", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.16.1.12", NULL, SU_FLAG_OK, NULL }, /* pduOutletPowerFactor.1.13 = INTEGER: 0 */ { "unmapped.pduOutletPowerFactor", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.16.1.13", NULL, SU_FLAG_OK, NULL }, /* pduOutletPowerFactor.1.14 = INTEGER: 0 */ { "unmapped.pduOutletPowerFactor", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.16.1.14", NULL, SU_FLAG_OK, NULL }, /* pduOutletPowerFactor.1.15 = INTEGER: 0 */ { "unmapped.pduOutletPowerFactor", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.16.1.15", NULL, SU_FLAG_OK, NULL }, /* pduOutletPowerFactor.1.16 = INTEGER: 0 */ { "unmapped.pduOutletPowerFactor", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.16.1.16", NULL, SU_FLAG_OK, NULL }, /* pduOutletPowerFactor.1.17 = INTEGER: 0 */ { "unmapped.pduOutletPowerFactor", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.16.1.17", NULL, SU_FLAG_OK, NULL }, /* pduOutletPowerFactor.1.18 = INTEGER: 0 */ { "unmapped.pduOutletPowerFactor", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.16.1.18", NULL, SU_FLAG_OK, NULL }, /* pduOutletPowerFactor.1.19 = INTEGER: 0 */ { "unmapped.pduOutletPowerFactor", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.16.1.19", NULL, SU_FLAG_OK, NULL }, /* pduOutletPowerFactor.1.20 = INTEGER: 0 */ { "unmapped.pduOutletPowerFactor", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.16.1.20", NULL, SU_FLAG_OK, NULL }, /* pduOutletPowerFactor.1.21 = INTEGER: 0 */ { "unmapped.pduOutletPowerFactor", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.16.1.21", NULL, SU_FLAG_OK, NULL }, /* pduOutletPowerFactor.1.22 = INTEGER: 0 */ { "unmapped.pduOutletPowerFactor", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.16.1.22", NULL, SU_FLAG_OK, NULL }, /* pduOutletPowerFactor.1.23 = INTEGER: 0 */ { "unmapped.pduOutletPowerFactor", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.16.1.23", NULL, SU_FLAG_OK, NULL }, /* pduOutletPowerFactor.1.24 = INTEGER: 0 */ { "unmapped.pduOutletPowerFactor", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.16.1.24", NULL, SU_FLAG_OK, NULL }, /* pduOutletPowerFactor.1.25 = INTEGER: 0 */ { "unmapped.pduOutletPowerFactor", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.16.1.25", NULL, SU_FLAG_OK, NULL }, /* pduOutletPowerFactor.1.26 = INTEGER: 0 */ { "unmapped.pduOutletPowerFactor", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.16.1.26", NULL, SU_FLAG_OK, NULL }, /* pduOutletPowerFactor.1.27 = INTEGER: 0 */ { "unmapped.pduOutletPowerFactor", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.16.1.27", NULL, SU_FLAG_OK, NULL }, /* pduOutletPowerFactor.1.28 = INTEGER: 0 */ { "unmapped.pduOutletPowerFactor", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.16.1.28", NULL, SU_FLAG_OK, NULL }, /* pduOutletPowerFactor.1.29 = INTEGER: 0 */ { "unmapped.pduOutletPowerFactor", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.16.1.29", NULL, SU_FLAG_OK, NULL }, /* pduOutletPowerFactor.1.30 = INTEGER: 0 */ { "unmapped.pduOutletPowerFactor", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.16.1.30", NULL, SU_FLAG_OK, NULL }, /* pduOutletPowerFactor.1.31 = INTEGER: 0 */ { "unmapped.pduOutletPowerFactor", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.16.1.31", NULL, SU_FLAG_OK, NULL }, /* pduOutletPowerFactor.1.32 = INTEGER: 0 */ { "unmapped.pduOutletPowerFactor", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.16.1.32", NULL, SU_FLAG_OK, NULL }, /* pduOutletPowerFactor.1.33 = INTEGER: 0 */ { "unmapped.pduOutletPowerFactor", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.16.1.33", NULL, SU_FLAG_OK, NULL }, /* pduOutletPowerFactor.1.34 = INTEGER: 0 */ { "unmapped.pduOutletPowerFactor", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.16.1.34", NULL, SU_FLAG_OK, NULL }, /* pduOutletPowerFactor.1.35 = INTEGER: 0 */ { "unmapped.pduOutletPowerFactor", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.16.1.35", NULL, SU_FLAG_OK, NULL }, /* pduOutletPowerFactor.1.36 = INTEGER: 0 */ { "unmapped.pduOutletPowerFactor", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.16.1.36", NULL, SU_FLAG_OK, NULL }, /* pduOutletPowerFactor.1.37 = INTEGER: 0 */ { "unmapped.pduOutletPowerFactor", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.16.1.37", NULL, SU_FLAG_OK, NULL }, /* pduOutletPowerFactor.1.38 = INTEGER: 0 */ { "unmapped.pduOutletPowerFactor", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.16.1.38", NULL, SU_FLAG_OK, NULL }, /* pduOutletPowerFactor.1.39 = INTEGER: 0 */ { "unmapped.pduOutletPowerFactor", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.16.1.39", NULL, SU_FLAG_OK, NULL }, /* pduOutletPowerFactor.1.40 = INTEGER: 0 */ { "unmapped.pduOutletPowerFactor", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.16.1.40", NULL, SU_FLAG_OK, NULL }, /* pduOutletPowerFactor.1.41 = INTEGER: 0 */ { "unmapped.pduOutletPowerFactor", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.16.1.41", NULL, SU_FLAG_OK, NULL }, /* pduOutletPowerFactor.1.42 = INTEGER: 0 */ { "unmapped.pduOutletPowerFactor", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.16.1.42", NULL, SU_FLAG_OK, NULL }, /* pduOutletPowerFactor.1.43 = INTEGER: 0 */ { "unmapped.pduOutletPowerFactor", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.16.1.43", NULL, SU_FLAG_OK, NULL }, /* pduOutletPowerFactor.1.44 = INTEGER: 0 */ { "unmapped.pduOutletPowerFactor", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.16.1.44", NULL, SU_FLAG_OK, NULL }, /* pduOutletPowerFactor.1.45 = INTEGER: 0 */ { "unmapped.pduOutletPowerFactor", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.16.1.45", NULL, SU_FLAG_OK, NULL }, /* pduOutletPowerFactor.1.46 = INTEGER: 0 */ { "unmapped.pduOutletPowerFactor", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.16.1.46", NULL, SU_FLAG_OK, NULL }, /* pduOutletPowerFactor.1.47 = INTEGER: 0 */ { "unmapped.pduOutletPowerFactor", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.16.1.47", NULL, SU_FLAG_OK, NULL }, /* pduOutletPowerFactor.1.48 = INTEGER: 0 */ { "unmapped.pduOutletPowerFactor", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.16.1.48", NULL, SU_FLAG_OK, NULL }, /* pduOutletVAR.1.1 = INTEGER: 0 */ { "unmapped.pduOutletVAR", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.17.1.1", NULL, SU_FLAG_OK, NULL }, /* pduOutletVAR.1.2 = INTEGER: 0 */ { "unmapped.pduOutletVAR", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.17.1.2", NULL, SU_FLAG_OK, NULL }, /* pduOutletVAR.1.3 = INTEGER: 0 */ { "unmapped.pduOutletVAR", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.17.1.3", NULL, SU_FLAG_OK, NULL }, /* pduOutletVAR.1.4 = INTEGER: 0 */ { "unmapped.pduOutletVAR", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.17.1.4", NULL, SU_FLAG_OK, NULL }, /* pduOutletVAR.1.5 = INTEGER: 0 */ { "unmapped.pduOutletVAR", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.17.1.5", NULL, SU_FLAG_OK, NULL }, /* pduOutletVAR.1.6 = INTEGER: 0 */ { "unmapped.pduOutletVAR", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.17.1.6", NULL, SU_FLAG_OK, NULL }, /* pduOutletVAR.1.7 = INTEGER: 0 */ { "unmapped.pduOutletVAR", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.17.1.7", NULL, SU_FLAG_OK, NULL }, /* pduOutletVAR.1.8 = INTEGER: 0 */ { "unmapped.pduOutletVAR", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.17.1.8", NULL, SU_FLAG_OK, NULL }, /* pduOutletVAR.1.9 = INTEGER: 0 */ { "unmapped.pduOutletVAR", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.17.1.9", NULL, SU_FLAG_OK, NULL }, /* pduOutletVAR.1.10 = INTEGER: 0 */ { "unmapped.pduOutletVAR", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.17.1.10", NULL, SU_FLAG_OK, NULL }, /* pduOutletVAR.1.11 = INTEGER: 0 */ { "unmapped.pduOutletVAR", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.17.1.11", NULL, SU_FLAG_OK, NULL }, /* pduOutletVAR.1.12 = INTEGER: 0 */ { "unmapped.pduOutletVAR", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.17.1.12", NULL, SU_FLAG_OK, NULL }, /* pduOutletVAR.1.13 = INTEGER: 0 */ { "unmapped.pduOutletVAR", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.17.1.13", NULL, SU_FLAG_OK, NULL }, /* pduOutletVAR.1.14 = INTEGER: 0 */ { "unmapped.pduOutletVAR", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.17.1.14", NULL, SU_FLAG_OK, NULL }, /* pduOutletVAR.1.15 = INTEGER: 0 */ { "unmapped.pduOutletVAR", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.17.1.15", NULL, SU_FLAG_OK, NULL }, /* pduOutletVAR.1.16 = INTEGER: 0 */ { "unmapped.pduOutletVAR", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.17.1.16", NULL, SU_FLAG_OK, NULL }, /* pduOutletVAR.1.17 = INTEGER: 0 */ { "unmapped.pduOutletVAR", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.17.1.17", NULL, SU_FLAG_OK, NULL }, /* pduOutletVAR.1.18 = INTEGER: 0 */ { "unmapped.pduOutletVAR", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.17.1.18", NULL, SU_FLAG_OK, NULL }, /* pduOutletVAR.1.19 = INTEGER: 0 */ { "unmapped.pduOutletVAR", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.17.1.19", NULL, SU_FLAG_OK, NULL }, /* pduOutletVAR.1.20 = INTEGER: 0 */ { "unmapped.pduOutletVAR", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.17.1.20", NULL, SU_FLAG_OK, NULL }, /* pduOutletVAR.1.21 = INTEGER: 0 */ { "unmapped.pduOutletVAR", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.17.1.21", NULL, SU_FLAG_OK, NULL }, /* pduOutletVAR.1.22 = INTEGER: 0 */ { "unmapped.pduOutletVAR", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.17.1.22", NULL, SU_FLAG_OK, NULL }, /* pduOutletVAR.1.23 = INTEGER: 0 */ { "unmapped.pduOutletVAR", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.17.1.23", NULL, SU_FLAG_OK, NULL }, /* pduOutletVAR.1.24 = INTEGER: 0 */ { "unmapped.pduOutletVAR", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.17.1.24", NULL, SU_FLAG_OK, NULL }, /* pduOutletVAR.1.25 = INTEGER: 0 */ { "unmapped.pduOutletVAR", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.17.1.25", NULL, SU_FLAG_OK, NULL }, /* pduOutletVAR.1.26 = INTEGER: 0 */ { "unmapped.pduOutletVAR", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.17.1.26", NULL, SU_FLAG_OK, NULL }, /* pduOutletVAR.1.27 = INTEGER: 0 */ { "unmapped.pduOutletVAR", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.17.1.27", NULL, SU_FLAG_OK, NULL }, /* pduOutletVAR.1.28 = INTEGER: 0 */ { "unmapped.pduOutletVAR", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.17.1.28", NULL, SU_FLAG_OK, NULL }, /* pduOutletVAR.1.29 = INTEGER: 0 */ { "unmapped.pduOutletVAR", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.17.1.29", NULL, SU_FLAG_OK, NULL }, /* pduOutletVAR.1.30 = INTEGER: 0 */ { "unmapped.pduOutletVAR", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.17.1.30", NULL, SU_FLAG_OK, NULL }, /* pduOutletVAR.1.31 = INTEGER: 0 */ { "unmapped.pduOutletVAR", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.17.1.31", NULL, SU_FLAG_OK, NULL }, /* pduOutletVAR.1.32 = INTEGER: 0 */ { "unmapped.pduOutletVAR", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.17.1.32", NULL, SU_FLAG_OK, NULL }, /* pduOutletVAR.1.33 = INTEGER: 0 */ { "unmapped.pduOutletVAR", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.17.1.33", NULL, SU_FLAG_OK, NULL }, /* pduOutletVAR.1.34 = INTEGER: 0 */ { "unmapped.pduOutletVAR", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.17.1.34", NULL, SU_FLAG_OK, NULL }, /* pduOutletVAR.1.35 = INTEGER: 0 */ { "unmapped.pduOutletVAR", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.17.1.35", NULL, SU_FLAG_OK, NULL }, /* pduOutletVAR.1.36 = INTEGER: 0 */ { "unmapped.pduOutletVAR", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.17.1.36", NULL, SU_FLAG_OK, NULL }, /* pduOutletVAR.1.37 = INTEGER: 0 */ { "unmapped.pduOutletVAR", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.17.1.37", NULL, SU_FLAG_OK, NULL }, /* pduOutletVAR.1.38 = INTEGER: 0 */ { "unmapped.pduOutletVAR", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.17.1.38", NULL, SU_FLAG_OK, NULL }, /* pduOutletVAR.1.39 = INTEGER: 0 */ { "unmapped.pduOutletVAR", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.17.1.39", NULL, SU_FLAG_OK, NULL }, /* pduOutletVAR.1.40 = INTEGER: 0 */ { "unmapped.pduOutletVAR", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.17.1.40", NULL, SU_FLAG_OK, NULL }, /* pduOutletVAR.1.41 = INTEGER: 0 */ { "unmapped.pduOutletVAR", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.17.1.41", NULL, SU_FLAG_OK, NULL }, /* pduOutletVAR.1.42 = INTEGER: 0 */ { "unmapped.pduOutletVAR", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.17.1.42", NULL, SU_FLAG_OK, NULL }, /* pduOutletVAR.1.43 = INTEGER: 0 */ { "unmapped.pduOutletVAR", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.17.1.43", NULL, SU_FLAG_OK, NULL }, /* pduOutletVAR.1.44 = INTEGER: 0 */ { "unmapped.pduOutletVAR", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.17.1.44", NULL, SU_FLAG_OK, NULL }, /* pduOutletVAR.1.45 = INTEGER: 0 */ { "unmapped.pduOutletVAR", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.17.1.45", NULL, SU_FLAG_OK, NULL }, /* pduOutletVAR.1.46 = INTEGER: 0 */ { "unmapped.pduOutletVAR", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.17.1.46", NULL, SU_FLAG_OK, NULL }, /* pduOutletVAR.1.47 = INTEGER: 0 */ { "unmapped.pduOutletVAR", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.17.1.47", NULL, SU_FLAG_OK, NULL }, /* pduOutletVAR.1.48 = INTEGER: 0 */ { "unmapped.pduOutletVAR", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.17.1.48", NULL, SU_FLAG_OK, NULL }, /* pduOutletBranch.1.1 = INTEGER: 0 */ { "unmapped.pduOutletBranch", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.18.1.1", NULL, SU_FLAG_OK, NULL }, /* pduOutletBranch.1.2 = INTEGER: 0 */ { "unmapped.pduOutletBranch", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.18.1.2", NULL, SU_FLAG_OK, NULL }, /* pduOutletBranch.1.3 = INTEGER: 0 */ { "unmapped.pduOutletBranch", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.18.1.3", NULL, SU_FLAG_OK, NULL }, /* pduOutletBranch.1.4 = INTEGER: 0 */ { "unmapped.pduOutletBranch", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.18.1.4", NULL, SU_FLAG_OK, NULL }, /* pduOutletBranch.1.5 = INTEGER: 0 */ { "unmapped.pduOutletBranch", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.18.1.5", NULL, SU_FLAG_OK, NULL }, /* pduOutletBranch.1.6 = INTEGER: 0 */ { "unmapped.pduOutletBranch", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.18.1.6", NULL, SU_FLAG_OK, NULL }, /* pduOutletBranch.1.7 = INTEGER: 0 */ { "unmapped.pduOutletBranch", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.18.1.7", NULL, SU_FLAG_OK, NULL }, /* pduOutletBranch.1.8 = INTEGER: 0 */ { "unmapped.pduOutletBranch", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.18.1.8", NULL, SU_FLAG_OK, NULL }, /* pduOutletBranch.1.9 = INTEGER: 0 */ { "unmapped.pduOutletBranch", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.18.1.9", NULL, SU_FLAG_OK, NULL }, /* pduOutletBranch.1.10 = INTEGER: 0 */ { "unmapped.pduOutletBranch", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.18.1.10", NULL, SU_FLAG_OK, NULL }, /* pduOutletBranch.1.11 = INTEGER: 0 */ { "unmapped.pduOutletBranch", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.18.1.11", NULL, SU_FLAG_OK, NULL }, /* pduOutletBranch.1.12 = INTEGER: 0 */ { "unmapped.pduOutletBranch", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.18.1.12", NULL, SU_FLAG_OK, NULL }, /* pduOutletBranch.1.13 = INTEGER: 0 */ { "unmapped.pduOutletBranch", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.18.1.13", NULL, SU_FLAG_OK, NULL }, /* pduOutletBranch.1.14 = INTEGER: 0 */ { "unmapped.pduOutletBranch", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.18.1.14", NULL, SU_FLAG_OK, NULL }, /* pduOutletBranch.1.15 = INTEGER: 0 */ { "unmapped.pduOutletBranch", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.18.1.15", NULL, SU_FLAG_OK, NULL }, /* pduOutletBranch.1.16 = INTEGER: 0 */ { "unmapped.pduOutletBranch", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.18.1.16", NULL, SU_FLAG_OK, NULL }, /* pduOutletBranch.1.17 = INTEGER: 0 */ { "unmapped.pduOutletBranch", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.18.1.17", NULL, SU_FLAG_OK, NULL }, /* pduOutletBranch.1.18 = INTEGER: 0 */ { "unmapped.pduOutletBranch", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.18.1.18", NULL, SU_FLAG_OK, NULL }, /* pduOutletBranch.1.19 = INTEGER: 0 */ { "unmapped.pduOutletBranch", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.18.1.19", NULL, SU_FLAG_OK, NULL }, /* pduOutletBranch.1.20 = INTEGER: 0 */ { "unmapped.pduOutletBranch", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.18.1.20", NULL, SU_FLAG_OK, NULL }, /* pduOutletBranch.1.21 = INTEGER: 0 */ { "unmapped.pduOutletBranch", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.18.1.21", NULL, SU_FLAG_OK, NULL }, /* pduOutletBranch.1.22 = INTEGER: 0 */ { "unmapped.pduOutletBranch", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.18.1.22", NULL, SU_FLAG_OK, NULL }, /* pduOutletBranch.1.23 = INTEGER: 0 */ { "unmapped.pduOutletBranch", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.18.1.23", NULL, SU_FLAG_OK, NULL }, /* pduOutletBranch.1.24 = INTEGER: 0 */ { "unmapped.pduOutletBranch", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.18.1.24", NULL, SU_FLAG_OK, NULL }, /* pduOutletBranch.1.25 = INTEGER: 0 */ { "unmapped.pduOutletBranch", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.18.1.25", NULL, SU_FLAG_OK, NULL }, /* pduOutletBranch.1.26 = INTEGER: 0 */ { "unmapped.pduOutletBranch", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.18.1.26", NULL, SU_FLAG_OK, NULL }, /* pduOutletBranch.1.27 = INTEGER: 0 */ { "unmapped.pduOutletBranch", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.18.1.27", NULL, SU_FLAG_OK, NULL }, /* pduOutletBranch.1.28 = INTEGER: 0 */ { "unmapped.pduOutletBranch", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.18.1.28", NULL, SU_FLAG_OK, NULL }, /* pduOutletBranch.1.29 = INTEGER: 0 */ { "unmapped.pduOutletBranch", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.18.1.29", NULL, SU_FLAG_OK, NULL }, /* pduOutletBranch.1.30 = INTEGER: 0 */ { "unmapped.pduOutletBranch", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.18.1.30", NULL, SU_FLAG_OK, NULL }, /* pduOutletBranch.1.31 = INTEGER: 0 */ { "unmapped.pduOutletBranch", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.18.1.31", NULL, SU_FLAG_OK, NULL }, /* pduOutletBranch.1.32 = INTEGER: 0 */ { "unmapped.pduOutletBranch", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.18.1.32", NULL, SU_FLAG_OK, NULL }, /* pduOutletBranch.1.33 = INTEGER: 0 */ { "unmapped.pduOutletBranch", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.18.1.33", NULL, SU_FLAG_OK, NULL }, /* pduOutletBranch.1.34 = INTEGER: 0 */ { "unmapped.pduOutletBranch", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.18.1.34", NULL, SU_FLAG_OK, NULL }, /* pduOutletBranch.1.35 = INTEGER: 0 */ { "unmapped.pduOutletBranch", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.18.1.35", NULL, SU_FLAG_OK, NULL }, /* pduOutletBranch.1.36 = INTEGER: 0 */ { "unmapped.pduOutletBranch", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.18.1.36", NULL, SU_FLAG_OK, NULL }, /* pduOutletBranch.1.37 = INTEGER: 0 */ { "unmapped.pduOutletBranch", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.18.1.37", NULL, SU_FLAG_OK, NULL }, /* pduOutletBranch.1.38 = INTEGER: 0 */ { "unmapped.pduOutletBranch", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.18.1.38", NULL, SU_FLAG_OK, NULL }, /* pduOutletBranch.1.39 = INTEGER: 0 */ { "unmapped.pduOutletBranch", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.18.1.39", NULL, SU_FLAG_OK, NULL }, /* pduOutletBranch.1.40 = INTEGER: 0 */ { "unmapped.pduOutletBranch", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.18.1.40", NULL, SU_FLAG_OK, NULL }, /* pduOutletBranch.1.41 = INTEGER: 0 */ { "unmapped.pduOutletBranch", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.18.1.41", NULL, SU_FLAG_OK, NULL }, /* pduOutletBranch.1.42 = INTEGER: 0 */ { "unmapped.pduOutletBranch", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.18.1.42", NULL, SU_FLAG_OK, NULL }, /* pduOutletBranch.1.43 = INTEGER: 0 */ { "unmapped.pduOutletBranch", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.18.1.43", NULL, SU_FLAG_OK, NULL }, /* pduOutletBranch.1.44 = INTEGER: 0 */ { "unmapped.pduOutletBranch", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.18.1.44", NULL, SU_FLAG_OK, NULL }, /* pduOutletBranch.1.45 = INTEGER: 0 */ { "unmapped.pduOutletBranch", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.18.1.45", NULL, SU_FLAG_OK, NULL }, /* pduOutletBranch.1.46 = INTEGER: 0 */ { "unmapped.pduOutletBranch", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.18.1.46", NULL, SU_FLAG_OK, NULL }, /* pduOutletBranch.1.47 = INTEGER: 0 */ { "unmapped.pduOutletBranch", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.18.1.47", NULL, SU_FLAG_OK, NULL }, /* pduOutletBranch.1.48 = INTEGER: 0 */ { "unmapped.pduOutletBranch", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.18.1.48", NULL, SU_FLAG_OK, NULL }, /* pduOutletActivePowerThResetThld.1.1 = INTEGER: 0 */ { "unmapped.pduOutletActivePowerThResetThld", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.19.1.1", NULL, SU_FLAG_OK, NULL }, /* pduOutletActivePowerThResetThld.1.2 = INTEGER: 0 */ { "unmapped.pduOutletActivePowerThResetThld", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.19.1.2", NULL, SU_FLAG_OK, NULL }, /* pduOutletActivePowerThResetThld.1.3 = INTEGER: 0 */ { "unmapped.pduOutletActivePowerThResetThld", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.19.1.3", NULL, SU_FLAG_OK, NULL }, /* pduOutletActivePowerThResetThld.1.4 = INTEGER: 0 */ { "unmapped.pduOutletActivePowerThResetThld", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.19.1.4", NULL, SU_FLAG_OK, NULL }, /* pduOutletActivePowerThResetThld.1.5 = INTEGER: 0 */ { "unmapped.pduOutletActivePowerThResetThld", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.19.1.5", NULL, SU_FLAG_OK, NULL }, /* pduOutletActivePowerThResetThld.1.6 = INTEGER: 0 */ { "unmapped.pduOutletActivePowerThResetThld", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.19.1.6", NULL, SU_FLAG_OK, NULL }, /* pduOutletActivePowerThResetThld.1.7 = INTEGER: 0 */ { "unmapped.pduOutletActivePowerThResetThld", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.19.1.7", NULL, SU_FLAG_OK, NULL }, /* pduOutletActivePowerThResetThld.1.8 = INTEGER: 0 */ { "unmapped.pduOutletActivePowerThResetThld", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.19.1.8", NULL, SU_FLAG_OK, NULL }, /* pduOutletActivePowerThResetThld.1.9 = INTEGER: 0 */ { "unmapped.pduOutletActivePowerThResetThld", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.19.1.9", NULL, SU_FLAG_OK, NULL }, /* pduOutletActivePowerThResetThld.1.10 = INTEGER: 0 */ { "unmapped.pduOutletActivePowerThResetThld", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.19.1.10", NULL, SU_FLAG_OK, NULL }, /* pduOutletActivePowerThResetThld.1.11 = INTEGER: 0 */ { "unmapped.pduOutletActivePowerThResetThld", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.19.1.11", NULL, SU_FLAG_OK, NULL }, /* pduOutletActivePowerThResetThld.1.12 = INTEGER: 0 */ { "unmapped.pduOutletActivePowerThResetThld", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.19.1.12", NULL, SU_FLAG_OK, NULL }, /* pduOutletActivePowerThResetThld.1.13 = INTEGER: 0 */ { "unmapped.pduOutletActivePowerThResetThld", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.19.1.13", NULL, SU_FLAG_OK, NULL }, /* pduOutletActivePowerThResetThld.1.14 = INTEGER: 0 */ { "unmapped.pduOutletActivePowerThResetThld", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.19.1.14", NULL, SU_FLAG_OK, NULL }, /* pduOutletActivePowerThResetThld.1.15 = INTEGER: 0 */ { "unmapped.pduOutletActivePowerThResetThld", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.19.1.15", NULL, SU_FLAG_OK, NULL }, /* pduOutletActivePowerThResetThld.1.16 = INTEGER: 0 */ { "unmapped.pduOutletActivePowerThResetThld", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.19.1.16", NULL, SU_FLAG_OK, NULL }, /* pduOutletActivePowerThResetThld.1.17 = INTEGER: 0 */ { "unmapped.pduOutletActivePowerThResetThld", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.19.1.17", NULL, SU_FLAG_OK, NULL }, /* pduOutletActivePowerThResetThld.1.18 = INTEGER: 0 */ { "unmapped.pduOutletActivePowerThResetThld", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.19.1.18", NULL, SU_FLAG_OK, NULL }, /* pduOutletActivePowerThResetThld.1.19 = INTEGER: 0 */ { "unmapped.pduOutletActivePowerThResetThld", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.19.1.19", NULL, SU_FLAG_OK, NULL }, /* pduOutletActivePowerThResetThld.1.20 = INTEGER: 0 */ { "unmapped.pduOutletActivePowerThResetThld", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.19.1.20", NULL, SU_FLAG_OK, NULL }, /* pduOutletActivePowerThResetThld.1.21 = INTEGER: 0 */ { "unmapped.pduOutletActivePowerThResetThld", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.19.1.21", NULL, SU_FLAG_OK, NULL }, /* pduOutletActivePowerThResetThld.1.22 = INTEGER: 0 */ { "unmapped.pduOutletActivePowerThResetThld", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.19.1.22", NULL, SU_FLAG_OK, NULL }, /* pduOutletActivePowerThResetThld.1.23 = INTEGER: 0 */ { "unmapped.pduOutletActivePowerThResetThld", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.19.1.23", NULL, SU_FLAG_OK, NULL }, /* pduOutletActivePowerThResetThld.1.24 = INTEGER: 0 */ { "unmapped.pduOutletActivePowerThResetThld", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.19.1.24", NULL, SU_FLAG_OK, NULL }, /* pduOutletActivePowerThResetThld.1.25 = INTEGER: 0 */ { "unmapped.pduOutletActivePowerThResetThld", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.19.1.25", NULL, SU_FLAG_OK, NULL }, /* pduOutletActivePowerThResetThld.1.26 = INTEGER: 0 */ { "unmapped.pduOutletActivePowerThResetThld", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.19.1.26", NULL, SU_FLAG_OK, NULL }, /* pduOutletActivePowerThResetThld.1.27 = INTEGER: 0 */ { "unmapped.pduOutletActivePowerThResetThld", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.19.1.27", NULL, SU_FLAG_OK, NULL }, /* pduOutletActivePowerThResetThld.1.28 = INTEGER: 0 */ { "unmapped.pduOutletActivePowerThResetThld", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.19.1.28", NULL, SU_FLAG_OK, NULL }, /* pduOutletActivePowerThResetThld.1.29 = INTEGER: 0 */ { "unmapped.pduOutletActivePowerThResetThld", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.19.1.29", NULL, SU_FLAG_OK, NULL }, /* pduOutletActivePowerThResetThld.1.30 = INTEGER: 0 */ { "unmapped.pduOutletActivePowerThResetThld", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.19.1.30", NULL, SU_FLAG_OK, NULL }, /* pduOutletActivePowerThResetThld.1.31 = INTEGER: 0 */ { "unmapped.pduOutletActivePowerThResetThld", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.19.1.31", NULL, SU_FLAG_OK, NULL }, /* pduOutletActivePowerThResetThld.1.32 = INTEGER: 0 */ { "unmapped.pduOutletActivePowerThResetThld", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.19.1.32", NULL, SU_FLAG_OK, NULL }, /* pduOutletActivePowerThResetThld.1.33 = INTEGER: 0 */ { "unmapped.pduOutletActivePowerThResetThld", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.19.1.33", NULL, SU_FLAG_OK, NULL }, /* pduOutletActivePowerThResetThld.1.34 = INTEGER: 0 */ { "unmapped.pduOutletActivePowerThResetThld", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.19.1.34", NULL, SU_FLAG_OK, NULL }, /* pduOutletActivePowerThResetThld.1.35 = INTEGER: 0 */ { "unmapped.pduOutletActivePowerThResetThld", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.19.1.35", NULL, SU_FLAG_OK, NULL }, /* pduOutletActivePowerThResetThld.1.36 = INTEGER: 0 */ { "unmapped.pduOutletActivePowerThResetThld", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.19.1.36", NULL, SU_FLAG_OK, NULL }, /* pduOutletActivePowerThResetThld.1.37 = INTEGER: 0 */ { "unmapped.pduOutletActivePowerThResetThld", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.19.1.37", NULL, SU_FLAG_OK, NULL }, /* pduOutletActivePowerThResetThld.1.38 = INTEGER: 0 */ { "unmapped.pduOutletActivePowerThResetThld", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.19.1.38", NULL, SU_FLAG_OK, NULL }, /* pduOutletActivePowerThResetThld.1.39 = INTEGER: 0 */ { "unmapped.pduOutletActivePowerThResetThld", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.19.1.39", NULL, SU_FLAG_OK, NULL }, /* pduOutletActivePowerThResetThld.1.40 = INTEGER: 0 */ { "unmapped.pduOutletActivePowerThResetThld", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.19.1.40", NULL, SU_FLAG_OK, NULL }, /* pduOutletActivePowerThResetThld.1.41 = INTEGER: 0 */ { "unmapped.pduOutletActivePowerThResetThld", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.19.1.41", NULL, SU_FLAG_OK, NULL }, /* pduOutletActivePowerThResetThld.1.42 = INTEGER: 0 */ { "unmapped.pduOutletActivePowerThResetThld", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.19.1.42", NULL, SU_FLAG_OK, NULL }, /* pduOutletActivePowerThResetThld.1.43 = INTEGER: 0 */ { "unmapped.pduOutletActivePowerThResetThld", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.19.1.43", NULL, SU_FLAG_OK, NULL }, /* pduOutletActivePowerThResetThld.1.44 = INTEGER: 0 */ { "unmapped.pduOutletActivePowerThResetThld", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.19.1.44", NULL, SU_FLAG_OK, NULL }, /* pduOutletActivePowerThResetThld.1.45 = INTEGER: 0 */ { "unmapped.pduOutletActivePowerThResetThld", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.19.1.45", NULL, SU_FLAG_OK, NULL }, /* pduOutletActivePowerThResetThld.1.46 = INTEGER: 0 */ { "unmapped.pduOutletActivePowerThResetThld", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.19.1.46", NULL, SU_FLAG_OK, NULL }, /* pduOutletActivePowerThResetThld.1.47 = INTEGER: 0 */ { "unmapped.pduOutletActivePowerThResetThld", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.19.1.47", NULL, SU_FLAG_OK, NULL }, /* pduOutletActivePowerThResetThld.1.48 = INTEGER: 0 */ { "unmapped.pduOutletActivePowerThResetThld", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.19.1.48", NULL, SU_FLAG_OK, NULL }, /* pduOutletActivePowerThChangeDelay.1.1 = INTEGER: 0 */ { "unmapped.pduOutletActivePowerThChangeDelay", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.20.1.1", NULL, SU_FLAG_OK, NULL }, /* pduOutletActivePowerThChangeDelay.1.2 = INTEGER: 0 */ { "unmapped.pduOutletActivePowerThChangeDelay", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.20.1.2", NULL, SU_FLAG_OK, NULL }, /* pduOutletActivePowerThChangeDelay.1.3 = INTEGER: 0 */ { "unmapped.pduOutletActivePowerThChangeDelay", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.20.1.3", NULL, SU_FLAG_OK, NULL }, /* pduOutletActivePowerThChangeDelay.1.4 = INTEGER: 0 */ { "unmapped.pduOutletActivePowerThChangeDelay", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.20.1.4", NULL, SU_FLAG_OK, NULL }, /* pduOutletActivePowerThChangeDelay.1.5 = INTEGER: 0 */ { "unmapped.pduOutletActivePowerThChangeDelay", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.20.1.5", NULL, SU_FLAG_OK, NULL }, /* pduOutletActivePowerThChangeDelay.1.6 = INTEGER: 0 */ { "unmapped.pduOutletActivePowerThChangeDelay", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.20.1.6", NULL, SU_FLAG_OK, NULL }, /* pduOutletActivePowerThChangeDelay.1.7 = INTEGER: 0 */ { "unmapped.pduOutletActivePowerThChangeDelay", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.20.1.7", NULL, SU_FLAG_OK, NULL }, /* pduOutletActivePowerThChangeDelay.1.8 = INTEGER: 0 */ { "unmapped.pduOutletActivePowerThChangeDelay", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.20.1.8", NULL, SU_FLAG_OK, NULL }, /* pduOutletActivePowerThChangeDelay.1.9 = INTEGER: 0 */ { "unmapped.pduOutletActivePowerThChangeDelay", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.20.1.9", NULL, SU_FLAG_OK, NULL }, /* pduOutletActivePowerThChangeDelay.1.10 = INTEGER: 0 */ { "unmapped.pduOutletActivePowerThChangeDelay", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.20.1.10", NULL, SU_FLAG_OK, NULL }, /* pduOutletActivePowerThChangeDelay.1.11 = INTEGER: 0 */ { "unmapped.pduOutletActivePowerThChangeDelay", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.20.1.11", NULL, SU_FLAG_OK, NULL }, /* pduOutletActivePowerThChangeDelay.1.12 = INTEGER: 0 */ { "unmapped.pduOutletActivePowerThChangeDelay", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.20.1.12", NULL, SU_FLAG_OK, NULL }, /* pduOutletActivePowerThChangeDelay.1.13 = INTEGER: 0 */ { "unmapped.pduOutletActivePowerThChangeDelay", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.20.1.13", NULL, SU_FLAG_OK, NULL }, /* pduOutletActivePowerThChangeDelay.1.14 = INTEGER: 0 */ { "unmapped.pduOutletActivePowerThChangeDelay", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.20.1.14", NULL, SU_FLAG_OK, NULL }, /* pduOutletActivePowerThChangeDelay.1.15 = INTEGER: 0 */ { "unmapped.pduOutletActivePowerThChangeDelay", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.20.1.15", NULL, SU_FLAG_OK, NULL }, /* pduOutletActivePowerThChangeDelay.1.16 = INTEGER: 0 */ { "unmapped.pduOutletActivePowerThChangeDelay", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.20.1.16", NULL, SU_FLAG_OK, NULL }, /* pduOutletActivePowerThChangeDelay.1.17 = INTEGER: 0 */ { "unmapped.pduOutletActivePowerThChangeDelay", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.20.1.17", NULL, SU_FLAG_OK, NULL }, /* pduOutletActivePowerThChangeDelay.1.18 = INTEGER: 0 */ { "unmapped.pduOutletActivePowerThChangeDelay", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.20.1.18", NULL, SU_FLAG_OK, NULL }, /* pduOutletActivePowerThChangeDelay.1.19 = INTEGER: 0 */ { "unmapped.pduOutletActivePowerThChangeDelay", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.20.1.19", NULL, SU_FLAG_OK, NULL }, /* pduOutletActivePowerThChangeDelay.1.20 = INTEGER: 0 */ { "unmapped.pduOutletActivePowerThChangeDelay", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.20.1.20", NULL, SU_FLAG_OK, NULL }, /* pduOutletActivePowerThChangeDelay.1.21 = INTEGER: 0 */ { "unmapped.pduOutletActivePowerThChangeDelay", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.20.1.21", NULL, SU_FLAG_OK, NULL }, /* pduOutletActivePowerThChangeDelay.1.22 = INTEGER: 0 */ { "unmapped.pduOutletActivePowerThChangeDelay", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.20.1.22", NULL, SU_FLAG_OK, NULL }, /* pduOutletActivePowerThChangeDelay.1.23 = INTEGER: 0 */ { "unmapped.pduOutletActivePowerThChangeDelay", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.20.1.23", NULL, SU_FLAG_OK, NULL }, /* pduOutletActivePowerThChangeDelay.1.24 = INTEGER: 0 */ { "unmapped.pduOutletActivePowerThChangeDelay", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.20.1.24", NULL, SU_FLAG_OK, NULL }, /* pduOutletActivePowerThChangeDelay.1.25 = INTEGER: 0 */ { "unmapped.pduOutletActivePowerThChangeDelay", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.20.1.25", NULL, SU_FLAG_OK, NULL }, /* pduOutletActivePowerThChangeDelay.1.26 = INTEGER: 0 */ { "unmapped.pduOutletActivePowerThChangeDelay", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.20.1.26", NULL, SU_FLAG_OK, NULL }, /* pduOutletActivePowerThChangeDelay.1.27 = INTEGER: 0 */ { "unmapped.pduOutletActivePowerThChangeDelay", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.20.1.27", NULL, SU_FLAG_OK, NULL }, /* pduOutletActivePowerThChangeDelay.1.28 = INTEGER: 0 */ { "unmapped.pduOutletActivePowerThChangeDelay", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.20.1.28", NULL, SU_FLAG_OK, NULL }, /* pduOutletActivePowerThChangeDelay.1.29 = INTEGER: 0 */ { "unmapped.pduOutletActivePowerThChangeDelay", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.20.1.29", NULL, SU_FLAG_OK, NULL }, /* pduOutletActivePowerThChangeDelay.1.30 = INTEGER: 0 */ { "unmapped.pduOutletActivePowerThChangeDelay", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.20.1.30", NULL, SU_FLAG_OK, NULL }, /* pduOutletActivePowerThChangeDelay.1.31 = INTEGER: 0 */ { "unmapped.pduOutletActivePowerThChangeDelay", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.20.1.31", NULL, SU_FLAG_OK, NULL }, /* pduOutletActivePowerThChangeDelay.1.32 = INTEGER: 0 */ { "unmapped.pduOutletActivePowerThChangeDelay", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.20.1.32", NULL, SU_FLAG_OK, NULL }, /* pduOutletActivePowerThChangeDelay.1.33 = INTEGER: 0 */ { "unmapped.pduOutletActivePowerThChangeDelay", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.20.1.33", NULL, SU_FLAG_OK, NULL }, /* pduOutletActivePowerThChangeDelay.1.34 = INTEGER: 0 */ { "unmapped.pduOutletActivePowerThChangeDelay", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.20.1.34", NULL, SU_FLAG_OK, NULL }, /* pduOutletActivePowerThChangeDelay.1.35 = INTEGER: 0 */ { "unmapped.pduOutletActivePowerThChangeDelay", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.20.1.35", NULL, SU_FLAG_OK, NULL }, /* pduOutletActivePowerThChangeDelay.1.36 = INTEGER: 0 */ { "unmapped.pduOutletActivePowerThChangeDelay", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.20.1.36", NULL, SU_FLAG_OK, NULL }, /* pduOutletActivePowerThChangeDelay.1.37 = INTEGER: 0 */ { "unmapped.pduOutletActivePowerThChangeDelay", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.20.1.37", NULL, SU_FLAG_OK, NULL }, /* pduOutletActivePowerThChangeDelay.1.38 = INTEGER: 0 */ { "unmapped.pduOutletActivePowerThChangeDelay", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.20.1.38", NULL, SU_FLAG_OK, NULL }, /* pduOutletActivePowerThChangeDelay.1.39 = INTEGER: 0 */ { "unmapped.pduOutletActivePowerThChangeDelay", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.20.1.39", NULL, SU_FLAG_OK, NULL }, /* pduOutletActivePowerThChangeDelay.1.40 = INTEGER: 0 */ { "unmapped.pduOutletActivePowerThChangeDelay", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.20.1.40", NULL, SU_FLAG_OK, NULL }, /* pduOutletActivePowerThChangeDelay.1.41 = INTEGER: 0 */ { "unmapped.pduOutletActivePowerThChangeDelay", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.20.1.41", NULL, SU_FLAG_OK, NULL }, /* pduOutletActivePowerThChangeDelay.1.42 = INTEGER: 0 */ { "unmapped.pduOutletActivePowerThChangeDelay", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.20.1.42", NULL, SU_FLAG_OK, NULL }, /* pduOutletActivePowerThChangeDelay.1.43 = INTEGER: 0 */ { "unmapped.pduOutletActivePowerThChangeDelay", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.20.1.43", NULL, SU_FLAG_OK, NULL }, /* pduOutletActivePowerThChangeDelay.1.44 = INTEGER: 0 */ { "unmapped.pduOutletActivePowerThChangeDelay", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.20.1.44", NULL, SU_FLAG_OK, NULL }, /* pduOutletActivePowerThChangeDelay.1.45 = INTEGER: 0 */ { "unmapped.pduOutletActivePowerThChangeDelay", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.20.1.45", NULL, SU_FLAG_OK, NULL }, /* pduOutletActivePowerThChangeDelay.1.46 = INTEGER: 0 */ { "unmapped.pduOutletActivePowerThChangeDelay", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.20.1.46", NULL, SU_FLAG_OK, NULL }, /* pduOutletActivePowerThChangeDelay.1.47 = INTEGER: 0 */ { "unmapped.pduOutletActivePowerThChangeDelay", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.20.1.47", NULL, SU_FLAG_OK, NULL }, /* pduOutletActivePowerThChangeDelay.1.48 = INTEGER: 0 */ { "unmapped.pduOutletActivePowerThChangeDelay", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.20.1.48", NULL, SU_FLAG_OK, NULL }, /* pduOutletActivePowerThCtrl.1.1 = INTEGER: 15 */ { "unmapped.pduOutletActivePowerThCtrl", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.21.1.1", NULL, SU_FLAG_OK, NULL }, /* pduOutletActivePowerThCtrl.1.2 = INTEGER: 15 */ { "unmapped.pduOutletActivePowerThCtrl", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.21.1.2", NULL, SU_FLAG_OK, NULL }, /* pduOutletActivePowerThCtrl.1.3 = INTEGER: 15 */ { "unmapped.pduOutletActivePowerThCtrl", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.21.1.3", NULL, SU_FLAG_OK, NULL }, /* pduOutletActivePowerThCtrl.1.4 = INTEGER: 15 */ { "unmapped.pduOutletActivePowerThCtrl", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.21.1.4", NULL, SU_FLAG_OK, NULL }, /* pduOutletActivePowerThCtrl.1.5 = INTEGER: 15 */ { "unmapped.pduOutletActivePowerThCtrl", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.21.1.5", NULL, SU_FLAG_OK, NULL }, /* pduOutletActivePowerThCtrl.1.6 = INTEGER: 15 */ { "unmapped.pduOutletActivePowerThCtrl", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.21.1.6", NULL, SU_FLAG_OK, NULL }, /* pduOutletActivePowerThCtrl.1.7 = INTEGER: 15 */ { "unmapped.pduOutletActivePowerThCtrl", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.21.1.7", NULL, SU_FLAG_OK, NULL }, /* pduOutletActivePowerThCtrl.1.8 = INTEGER: 15 */ { "unmapped.pduOutletActivePowerThCtrl", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.21.1.8", NULL, SU_FLAG_OK, NULL }, /* pduOutletActivePowerThCtrl.1.9 = INTEGER: 15 */ { "unmapped.pduOutletActivePowerThCtrl", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.21.1.9", NULL, SU_FLAG_OK, NULL }, /* pduOutletActivePowerThCtrl.1.10 = INTEGER: 15 */ { "unmapped.pduOutletActivePowerThCtrl", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.21.1.10", NULL, SU_FLAG_OK, NULL }, /* pduOutletActivePowerThCtrl.1.11 = INTEGER: 15 */ { "unmapped.pduOutletActivePowerThCtrl", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.21.1.11", NULL, SU_FLAG_OK, NULL }, /* pduOutletActivePowerThCtrl.1.12 = INTEGER: 15 */ { "unmapped.pduOutletActivePowerThCtrl", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.21.1.12", NULL, SU_FLAG_OK, NULL }, /* pduOutletActivePowerThCtrl.1.13 = INTEGER: 15 */ { "unmapped.pduOutletActivePowerThCtrl", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.21.1.13", NULL, SU_FLAG_OK, NULL }, /* pduOutletActivePowerThCtrl.1.14 = INTEGER: 15 */ { "unmapped.pduOutletActivePowerThCtrl", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.21.1.14", NULL, SU_FLAG_OK, NULL }, /* pduOutletActivePowerThCtrl.1.15 = INTEGER: 15 */ { "unmapped.pduOutletActivePowerThCtrl", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.21.1.15", NULL, SU_FLAG_OK, NULL }, /* pduOutletActivePowerThCtrl.1.16 = INTEGER: 15 */ { "unmapped.pduOutletActivePowerThCtrl", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.21.1.16", NULL, SU_FLAG_OK, NULL }, /* pduOutletActivePowerThCtrl.1.17 = INTEGER: 15 */ { "unmapped.pduOutletActivePowerThCtrl", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.21.1.17", NULL, SU_FLAG_OK, NULL }, /* pduOutletActivePowerThCtrl.1.18 = INTEGER: 15 */ { "unmapped.pduOutletActivePowerThCtrl", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.21.1.18", NULL, SU_FLAG_OK, NULL }, /* pduOutletActivePowerThCtrl.1.19 = INTEGER: 15 */ { "unmapped.pduOutletActivePowerThCtrl", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.21.1.19", NULL, SU_FLAG_OK, NULL }, /* pduOutletActivePowerThCtrl.1.20 = INTEGER: 15 */ { "unmapped.pduOutletActivePowerThCtrl", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.21.1.20", NULL, SU_FLAG_OK, NULL }, /* pduOutletActivePowerThCtrl.1.21 = INTEGER: 15 */ { "unmapped.pduOutletActivePowerThCtrl", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.21.1.21", NULL, SU_FLAG_OK, NULL }, /* pduOutletActivePowerThCtrl.1.22 = INTEGER: 15 */ { "unmapped.pduOutletActivePowerThCtrl", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.21.1.22", NULL, SU_FLAG_OK, NULL }, /* pduOutletActivePowerThCtrl.1.23 = INTEGER: 15 */ { "unmapped.pduOutletActivePowerThCtrl", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.21.1.23", NULL, SU_FLAG_OK, NULL }, /* pduOutletActivePowerThCtrl.1.24 = INTEGER: 15 */ { "unmapped.pduOutletActivePowerThCtrl", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.21.1.24", NULL, SU_FLAG_OK, NULL }, /* pduOutletActivePowerThCtrl.1.25 = INTEGER: 15 */ { "unmapped.pduOutletActivePowerThCtrl", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.21.1.25", NULL, SU_FLAG_OK, NULL }, /* pduOutletActivePowerThCtrl.1.26 = INTEGER: 15 */ { "unmapped.pduOutletActivePowerThCtrl", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.21.1.26", NULL, SU_FLAG_OK, NULL }, /* pduOutletActivePowerThCtrl.1.27 = INTEGER: 15 */ { "unmapped.pduOutletActivePowerThCtrl", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.21.1.27", NULL, SU_FLAG_OK, NULL }, /* pduOutletActivePowerThCtrl.1.28 = INTEGER: 15 */ { "unmapped.pduOutletActivePowerThCtrl", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.21.1.28", NULL, SU_FLAG_OK, NULL }, /* pduOutletActivePowerThCtrl.1.29 = INTEGER: 15 */ { "unmapped.pduOutletActivePowerThCtrl", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.21.1.29", NULL, SU_FLAG_OK, NULL }, /* pduOutletActivePowerThCtrl.1.30 = INTEGER: 15 */ { "unmapped.pduOutletActivePowerThCtrl", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.21.1.30", NULL, SU_FLAG_OK, NULL }, /* pduOutletActivePowerThCtrl.1.31 = INTEGER: 15 */ { "unmapped.pduOutletActivePowerThCtrl", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.21.1.31", NULL, SU_FLAG_OK, NULL }, /* pduOutletActivePowerThCtrl.1.32 = INTEGER: 15 */ { "unmapped.pduOutletActivePowerThCtrl", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.21.1.32", NULL, SU_FLAG_OK, NULL }, /* pduOutletActivePowerThCtrl.1.33 = INTEGER: 15 */ { "unmapped.pduOutletActivePowerThCtrl", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.21.1.33", NULL, SU_FLAG_OK, NULL }, /* pduOutletActivePowerThCtrl.1.34 = INTEGER: 15 */ { "unmapped.pduOutletActivePowerThCtrl", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.21.1.34", NULL, SU_FLAG_OK, NULL }, /* pduOutletActivePowerThCtrl.1.35 = INTEGER: 15 */ { "unmapped.pduOutletActivePowerThCtrl", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.21.1.35", NULL, SU_FLAG_OK, NULL }, /* pduOutletActivePowerThCtrl.1.36 = INTEGER: 15 */ { "unmapped.pduOutletActivePowerThCtrl", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.21.1.36", NULL, SU_FLAG_OK, NULL }, /* pduOutletActivePowerThCtrl.1.37 = INTEGER: 15 */ { "unmapped.pduOutletActivePowerThCtrl", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.21.1.37", NULL, SU_FLAG_OK, NULL }, /* pduOutletActivePowerThCtrl.1.38 = INTEGER: 15 */ { "unmapped.pduOutletActivePowerThCtrl", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.21.1.38", NULL, SU_FLAG_OK, NULL }, /* pduOutletActivePowerThCtrl.1.39 = INTEGER: 15 */ { "unmapped.pduOutletActivePowerThCtrl", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.21.1.39", NULL, SU_FLAG_OK, NULL }, /* pduOutletActivePowerThCtrl.1.40 = INTEGER: 15 */ { "unmapped.pduOutletActivePowerThCtrl", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.21.1.40", NULL, SU_FLAG_OK, NULL }, /* pduOutletActivePowerThCtrl.1.41 = INTEGER: 15 */ { "unmapped.pduOutletActivePowerThCtrl", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.21.1.41", NULL, SU_FLAG_OK, NULL }, /* pduOutletActivePowerThCtrl.1.42 = INTEGER: 15 */ { "unmapped.pduOutletActivePowerThCtrl", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.21.1.42", NULL, SU_FLAG_OK, NULL }, /* pduOutletActivePowerThCtrl.1.43 = INTEGER: 15 */ { "unmapped.pduOutletActivePowerThCtrl", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.21.1.43", NULL, SU_FLAG_OK, NULL }, /* pduOutletActivePowerThCtrl.1.44 = INTEGER: 15 */ { "unmapped.pduOutletActivePowerThCtrl", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.21.1.44", NULL, SU_FLAG_OK, NULL }, /* pduOutletActivePowerThCtrl.1.45 = INTEGER: 15 */ { "unmapped.pduOutletActivePowerThCtrl", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.21.1.45", NULL, SU_FLAG_OK, NULL }, /* pduOutletActivePowerThCtrl.1.46 = INTEGER: 15 */ { "unmapped.pduOutletActivePowerThCtrl", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.21.1.46", NULL, SU_FLAG_OK, NULL }, /* pduOutletActivePowerThCtrl.1.47 = INTEGER: 15 */ { "unmapped.pduOutletActivePowerThCtrl", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.21.1.47", NULL, SU_FLAG_OK, NULL }, /* pduOutletActivePowerThCtrl.1.48 = INTEGER: 15 */ { "unmapped.pduOutletActivePowerThCtrl", 0, 1, ".1.3.6.1.4.1.534.7.1.5.1.1.21.1.48", NULL, SU_FLAG_OK, NULL }, /* pduOutletControlOffCmd.1.1 = INTEGER: -1 */ { "unmapped.pduOutletControlOffCmd", 0, 1, ".1.3.6.1.4.1.534.7.1.5.2.1.2.1.1", NULL, SU_FLAG_OK, NULL }, /* pduOutletControlOffCmd.1.2 = INTEGER: -1 */ { "unmapped.pduOutletControlOffCmd", 0, 1, ".1.3.6.1.4.1.534.7.1.5.2.1.2.1.2", NULL, SU_FLAG_OK, NULL }, /* pduOutletControlOffCmd.1.3 = INTEGER: -1 */ { "unmapped.pduOutletControlOffCmd", 0, 1, ".1.3.6.1.4.1.534.7.1.5.2.1.2.1.3", NULL, SU_FLAG_OK, NULL }, /* pduOutletControlOffCmd.1.4 = INTEGER: -1 */ { "unmapped.pduOutletControlOffCmd", 0, 1, ".1.3.6.1.4.1.534.7.1.5.2.1.2.1.4", NULL, SU_FLAG_OK, NULL }, /* pduOutletControlOffCmd.1.5 = INTEGER: -1 */ { "unmapped.pduOutletControlOffCmd", 0, 1, ".1.3.6.1.4.1.534.7.1.5.2.1.2.1.5", NULL, SU_FLAG_OK, NULL }, /* pduOutletControlOffCmd.1.6 = INTEGER: -1 */ { "unmapped.pduOutletControlOffCmd", 0, 1, ".1.3.6.1.4.1.534.7.1.5.2.1.2.1.6", NULL, SU_FLAG_OK, NULL }, /* pduOutletControlOffCmd.1.7 = INTEGER: 0 */ { "unmapped.pduOutletControlOffCmd", 0, 1, ".1.3.6.1.4.1.534.7.1.5.2.1.2.1.7", NULL, SU_FLAG_OK, NULL }, /* pduOutletControlOffCmd.1.8 = INTEGER: 0 */ { "unmapped.pduOutletControlOffCmd", 0, 1, ".1.3.6.1.4.1.534.7.1.5.2.1.2.1.8", NULL, SU_FLAG_OK, NULL }, /* pduOutletControlOffCmd.1.9 = INTEGER: 0 */ { "unmapped.pduOutletControlOffCmd", 0, 1, ".1.3.6.1.4.1.534.7.1.5.2.1.2.1.9", NULL, SU_FLAG_OK, NULL }, /* pduOutletControlOffCmd.1.10 = INTEGER: 0 */ { "unmapped.pduOutletControlOffCmd", 0, 1, ".1.3.6.1.4.1.534.7.1.5.2.1.2.1.10", NULL, SU_FLAG_OK, NULL }, /* pduOutletControlOffCmd.1.11 = INTEGER: 0 */ { "unmapped.pduOutletControlOffCmd", 0, 1, ".1.3.6.1.4.1.534.7.1.5.2.1.2.1.11", NULL, SU_FLAG_OK, NULL }, /* pduOutletControlOffCmd.1.12 = INTEGER: 0 */ { "unmapped.pduOutletControlOffCmd", 0, 1, ".1.3.6.1.4.1.534.7.1.5.2.1.2.1.12", NULL, SU_FLAG_OK, NULL }, /* pduOutletControlOffCmd.1.13 = INTEGER: 0 */ { "unmapped.pduOutletControlOffCmd", 0, 1, ".1.3.6.1.4.1.534.7.1.5.2.1.2.1.13", NULL, SU_FLAG_OK, NULL }, /* pduOutletControlOffCmd.1.14 = INTEGER: 0 */ { "unmapped.pduOutletControlOffCmd", 0, 1, ".1.3.6.1.4.1.534.7.1.5.2.1.2.1.14", NULL, SU_FLAG_OK, NULL }, /* pduOutletControlOffCmd.1.15 = INTEGER: 0 */ { "unmapped.pduOutletControlOffCmd", 0, 1, ".1.3.6.1.4.1.534.7.1.5.2.1.2.1.15", NULL, SU_FLAG_OK, NULL }, /* pduOutletControlOffCmd.1.16 = INTEGER: 0 */ { "unmapped.pduOutletControlOffCmd", 0, 1, ".1.3.6.1.4.1.534.7.1.5.2.1.2.1.16", NULL, SU_FLAG_OK, NULL }, /* pduOutletControlOffCmd.1.17 = INTEGER: 0 */ { "unmapped.pduOutletControlOffCmd", 0, 1, ".1.3.6.1.4.1.534.7.1.5.2.1.2.1.17", NULL, SU_FLAG_OK, NULL }, /* pduOutletControlOffCmd.1.18 = INTEGER: 0 */ { "unmapped.pduOutletControlOffCmd", 0, 1, ".1.3.6.1.4.1.534.7.1.5.2.1.2.1.18", NULL, SU_FLAG_OK, NULL }, /* pduOutletControlOffCmd.1.19 = INTEGER: 0 */ { "unmapped.pduOutletControlOffCmd", 0, 1, ".1.3.6.1.4.1.534.7.1.5.2.1.2.1.19", NULL, SU_FLAG_OK, NULL }, /* pduOutletControlOffCmd.1.20 = INTEGER: 0 */ { "unmapped.pduOutletControlOffCmd", 0, 1, ".1.3.6.1.4.1.534.7.1.5.2.1.2.1.20", NULL, SU_FLAG_OK, NULL }, /* pduOutletControlOffCmd.1.21 = INTEGER: 0 */ { "unmapped.pduOutletControlOffCmd", 0, 1, ".1.3.6.1.4.1.534.7.1.5.2.1.2.1.21", NULL, SU_FLAG_OK, NULL }, /* pduOutletControlOffCmd.1.22 = INTEGER: 0 */ { "unmapped.pduOutletControlOffCmd", 0, 1, ".1.3.6.1.4.1.534.7.1.5.2.1.2.1.22", NULL, SU_FLAG_OK, NULL }, /* pduOutletControlOffCmd.1.23 = INTEGER: 0 */ { "unmapped.pduOutletControlOffCmd", 0, 1, ".1.3.6.1.4.1.534.7.1.5.2.1.2.1.23", NULL, SU_FLAG_OK, NULL }, /* pduOutletControlOffCmd.1.24 = INTEGER: 0 */ { "unmapped.pduOutletControlOffCmd", 0, 1, ".1.3.6.1.4.1.534.7.1.5.2.1.2.1.24", NULL, SU_FLAG_OK, NULL }, /* pduOutletControlOffCmd.1.25 = INTEGER: 0 */ { "unmapped.pduOutletControlOffCmd", 0, 1, ".1.3.6.1.4.1.534.7.1.5.2.1.2.1.25", NULL, SU_FLAG_OK, NULL }, /* pduOutletControlOffCmd.1.26 = INTEGER: 0 */ { "unmapped.pduOutletControlOffCmd", 0, 1, ".1.3.6.1.4.1.534.7.1.5.2.1.2.1.26", NULL, SU_FLAG_OK, NULL }, /* pduOutletControlOffCmd.1.27 = INTEGER: 0 */ { "unmapped.pduOutletControlOffCmd", 0, 1, ".1.3.6.1.4.1.534.7.1.5.2.1.2.1.27", NULL, SU_FLAG_OK, NULL }, /* pduOutletControlOffCmd.1.28 = INTEGER: 0 */ { "unmapped.pduOutletControlOffCmd", 0, 1, ".1.3.6.1.4.1.534.7.1.5.2.1.2.1.28", NULL, SU_FLAG_OK, NULL }, /* pduOutletControlOffCmd.1.29 = INTEGER: 0 */ { "unmapped.pduOutletControlOffCmd", 0, 1, ".1.3.6.1.4.1.534.7.1.5.2.1.2.1.29", NULL, SU_FLAG_OK, NULL }, /* pduOutletControlOffCmd.1.30 = INTEGER: 0 */ { "unmapped.pduOutletControlOffCmd", 0, 1, ".1.3.6.1.4.1.534.7.1.5.2.1.2.1.30", NULL, SU_FLAG_OK, NULL }, /* pduOutletControlOffCmd.1.31 = INTEGER: 0 */ { "unmapped.pduOutletControlOffCmd", 0, 1, ".1.3.6.1.4.1.534.7.1.5.2.1.2.1.31", NULL, SU_FLAG_OK, NULL }, /* pduOutletControlOffCmd.1.32 = INTEGER: 0 */ { "unmapped.pduOutletControlOffCmd", 0, 1, ".1.3.6.1.4.1.534.7.1.5.2.1.2.1.32", NULL, SU_FLAG_OK, NULL }, /* pduOutletControlOffCmd.1.33 = INTEGER: 0 */ { "unmapped.pduOutletControlOffCmd", 0, 1, ".1.3.6.1.4.1.534.7.1.5.2.1.2.1.33", NULL, SU_FLAG_OK, NULL }, /* pduOutletControlOffCmd.1.34 = INTEGER: 0 */ { "unmapped.pduOutletControlOffCmd", 0, 1, ".1.3.6.1.4.1.534.7.1.5.2.1.2.1.34", NULL, SU_FLAG_OK, NULL }, /* pduOutletControlOffCmd.1.35 = INTEGER: 0 */ { "unmapped.pduOutletControlOffCmd", 0, 1, ".1.3.6.1.4.1.534.7.1.5.2.1.2.1.35", NULL, SU_FLAG_OK, NULL }, /* pduOutletControlOffCmd.1.36 = INTEGER: 0 */ { "unmapped.pduOutletControlOffCmd", 0, 1, ".1.3.6.1.4.1.534.7.1.5.2.1.2.1.36", NULL, SU_FLAG_OK, NULL }, /* pduOutletControlOffCmd.1.37 = INTEGER: 0 */ { "unmapped.pduOutletControlOffCmd", 0, 1, ".1.3.6.1.4.1.534.7.1.5.2.1.2.1.37", NULL, SU_FLAG_OK, NULL }, /* pduOutletControlOffCmd.1.38 = INTEGER: 0 */ { "unmapped.pduOutletControlOffCmd", 0, 1, ".1.3.6.1.4.1.534.7.1.5.2.1.2.1.38", NULL, SU_FLAG_OK, NULL }, /* pduOutletControlOffCmd.1.39 = INTEGER: 0 */ { "unmapped.pduOutletControlOffCmd", 0, 1, ".1.3.6.1.4.1.534.7.1.5.2.1.2.1.39", NULL, SU_FLAG_OK, NULL }, /* pduOutletControlOffCmd.1.40 = INTEGER: 0 */ { "unmapped.pduOutletControlOffCmd", 0, 1, ".1.3.6.1.4.1.534.7.1.5.2.1.2.1.40", NULL, SU_FLAG_OK, NULL }, /* pduOutletControlOffCmd.1.41 = INTEGER: 0 */ { "unmapped.pduOutletControlOffCmd", 0, 1, ".1.3.6.1.4.1.534.7.1.5.2.1.2.1.41", NULL, SU_FLAG_OK, NULL }, /* pduOutletControlOffCmd.1.42 = INTEGER: 0 */ { "unmapped.pduOutletControlOffCmd", 0, 1, ".1.3.6.1.4.1.534.7.1.5.2.1.2.1.42", NULL, SU_FLAG_OK, NULL }, /* pduOutletControlOffCmd.1.43 = INTEGER: 0 */ { "unmapped.pduOutletControlOffCmd", 0, 1, ".1.3.6.1.4.1.534.7.1.5.2.1.2.1.43", NULL, SU_FLAG_OK, NULL }, /* pduOutletControlOffCmd.1.44 = INTEGER: 0 */ { "unmapped.pduOutletControlOffCmd", 0, 1, ".1.3.6.1.4.1.534.7.1.5.2.1.2.1.44", NULL, SU_FLAG_OK, NULL }, /* pduOutletControlOffCmd.1.45 = INTEGER: 0 */ { "unmapped.pduOutletControlOffCmd", 0, 1, ".1.3.6.1.4.1.534.7.1.5.2.1.2.1.45", NULL, SU_FLAG_OK, NULL }, /* pduOutletControlOffCmd.1.46 = INTEGER: 0 */ { "unmapped.pduOutletControlOffCmd", 0, 1, ".1.3.6.1.4.1.534.7.1.5.2.1.2.1.46", NULL, SU_FLAG_OK, NULL }, /* pduOutletControlOffCmd.1.47 = INTEGER: 0 */ { "unmapped.pduOutletControlOffCmd", 0, 1, ".1.3.6.1.4.1.534.7.1.5.2.1.2.1.47", NULL, SU_FLAG_OK, NULL }, /* pduOutletControlOffCmd.1.48 = INTEGER: 0 */ { "unmapped.pduOutletControlOffCmd", 0, 1, ".1.3.6.1.4.1.534.7.1.5.2.1.2.1.48", NULL, SU_FLAG_OK, NULL }, /* pduOutletControlOnCmd.1.1 = INTEGER: -1 */ { "unmapped.pduOutletControlOnCmd", 0, 1, ".1.3.6.1.4.1.534.7.1.5.2.1.3.1.1", NULL, SU_FLAG_OK, NULL }, /* pduOutletControlOnCmd.1.2 = INTEGER: -1 */ { "unmapped.pduOutletControlOnCmd", 0, 1, ".1.3.6.1.4.1.534.7.1.5.2.1.3.1.2", NULL, SU_FLAG_OK, NULL }, /* pduOutletControlOnCmd.1.3 = INTEGER: -1 */ { "unmapped.pduOutletControlOnCmd", 0, 1, ".1.3.6.1.4.1.534.7.1.5.2.1.3.1.3", NULL, SU_FLAG_OK, NULL }, /* pduOutletControlOnCmd.1.4 = INTEGER: -1 */ { "unmapped.pduOutletControlOnCmd", 0, 1, ".1.3.6.1.4.1.534.7.1.5.2.1.3.1.4", NULL, SU_FLAG_OK, NULL }, /* pduOutletControlOnCmd.1.5 = INTEGER: -1 */ { "unmapped.pduOutletControlOnCmd", 0, 1, ".1.3.6.1.4.1.534.7.1.5.2.1.3.1.5", NULL, SU_FLAG_OK, NULL }, /* pduOutletControlOnCmd.1.6 = INTEGER: -1 */ { "unmapped.pduOutletControlOnCmd", 0, 1, ".1.3.6.1.4.1.534.7.1.5.2.1.3.1.6", NULL, SU_FLAG_OK, NULL }, /* pduOutletControlOnCmd.1.7 = INTEGER: 0 */ { "unmapped.pduOutletControlOnCmd", 0, 1, ".1.3.6.1.4.1.534.7.1.5.2.1.3.1.7", NULL, SU_FLAG_OK, NULL }, /* pduOutletControlOnCmd.1.8 = INTEGER: 0 */ { "unmapped.pduOutletControlOnCmd", 0, 1, ".1.3.6.1.4.1.534.7.1.5.2.1.3.1.8", NULL, SU_FLAG_OK, NULL }, /* pduOutletControlOnCmd.1.9 = INTEGER: 0 */ { "unmapped.pduOutletControlOnCmd", 0, 1, ".1.3.6.1.4.1.534.7.1.5.2.1.3.1.9", NULL, SU_FLAG_OK, NULL }, /* pduOutletControlOnCmd.1.10 = INTEGER: 0 */ { "unmapped.pduOutletControlOnCmd", 0, 1, ".1.3.6.1.4.1.534.7.1.5.2.1.3.1.10", NULL, SU_FLAG_OK, NULL }, /* pduOutletControlOnCmd.1.11 = INTEGER: 0 */ { "unmapped.pduOutletControlOnCmd", 0, 1, ".1.3.6.1.4.1.534.7.1.5.2.1.3.1.11", NULL, SU_FLAG_OK, NULL }, /* pduOutletControlOnCmd.1.12 = INTEGER: 0 */ { "unmapped.pduOutletControlOnCmd", 0, 1, ".1.3.6.1.4.1.534.7.1.5.2.1.3.1.12", NULL, SU_FLAG_OK, NULL }, /* pduOutletControlOnCmd.1.13 = INTEGER: 0 */ { "unmapped.pduOutletControlOnCmd", 0, 1, ".1.3.6.1.4.1.534.7.1.5.2.1.3.1.13", NULL, SU_FLAG_OK, NULL }, /* pduOutletControlOnCmd.1.14 = INTEGER: 0 */ { "unmapped.pduOutletControlOnCmd", 0, 1, ".1.3.6.1.4.1.534.7.1.5.2.1.3.1.14", NULL, SU_FLAG_OK, NULL }, /* pduOutletControlOnCmd.1.15 = INTEGER: 0 */ { "unmapped.pduOutletControlOnCmd", 0, 1, ".1.3.6.1.4.1.534.7.1.5.2.1.3.1.15", NULL, SU_FLAG_OK, NULL }, /* pduOutletControlOnCmd.1.16 = INTEGER: 0 */ { "unmapped.pduOutletControlOnCmd", 0, 1, ".1.3.6.1.4.1.534.7.1.5.2.1.3.1.16", NULL, SU_FLAG_OK, NULL }, /* pduOutletControlOnCmd.1.17 = INTEGER: 0 */ { "unmapped.pduOutletControlOnCmd", 0, 1, ".1.3.6.1.4.1.534.7.1.5.2.1.3.1.17", NULL, SU_FLAG_OK, NULL }, /* pduOutletControlOnCmd.1.18 = INTEGER: 0 */ { "unmapped.pduOutletControlOnCmd", 0, 1, ".1.3.6.1.4.1.534.7.1.5.2.1.3.1.18", NULL, SU_FLAG_OK, NULL }, /* pduOutletControlOnCmd.1.19 = INTEGER: 0 */ { "unmapped.pduOutletControlOnCmd", 0, 1, ".1.3.6.1.4.1.534.7.1.5.2.1.3.1.19", NULL, SU_FLAG_OK, NULL }, /* pduOutletControlOnCmd.1.20 = INTEGER: 0 */ { "unmapped.pduOutletControlOnCmd", 0, 1, ".1.3.6.1.4.1.534.7.1.5.2.1.3.1.20", NULL, SU_FLAG_OK, NULL }, /* pduOutletControlOnCmd.1.21 = INTEGER: 0 */ { "unmapped.pduOutletControlOnCmd", 0, 1, ".1.3.6.1.4.1.534.7.1.5.2.1.3.1.21", NULL, SU_FLAG_OK, NULL }, /* pduOutletControlOnCmd.1.22 = INTEGER: 0 */ { "unmapped.pduOutletControlOnCmd", 0, 1, ".1.3.6.1.4.1.534.7.1.5.2.1.3.1.22", NULL, SU_FLAG_OK, NULL }, /* pduOutletControlOnCmd.1.23 = INTEGER: 0 */ { "unmapped.pduOutletControlOnCmd", 0, 1, ".1.3.6.1.4.1.534.7.1.5.2.1.3.1.23", NULL, SU_FLAG_OK, NULL }, /* pduOutletControlOnCmd.1.24 = INTEGER: 0 */ { "unmapped.pduOutletControlOnCmd", 0, 1, ".1.3.6.1.4.1.534.7.1.5.2.1.3.1.24", NULL, SU_FLAG_OK, NULL }, /* pduOutletControlOnCmd.1.25 = INTEGER: 0 */ { "unmapped.pduOutletControlOnCmd", 0, 1, ".1.3.6.1.4.1.534.7.1.5.2.1.3.1.25", NULL, SU_FLAG_OK, NULL }, /* pduOutletControlOnCmd.1.26 = INTEGER: 0 */ { "unmapped.pduOutletControlOnCmd", 0, 1, ".1.3.6.1.4.1.534.7.1.5.2.1.3.1.26", NULL, SU_FLAG_OK, NULL }, /* pduOutletControlOnCmd.1.27 = INTEGER: 0 */ { "unmapped.pduOutletControlOnCmd", 0, 1, ".1.3.6.1.4.1.534.7.1.5.2.1.3.1.27", NULL, SU_FLAG_OK, NULL }, /* pduOutletControlOnCmd.1.28 = INTEGER: 0 */ { "unmapped.pduOutletControlOnCmd", 0, 1, ".1.3.6.1.4.1.534.7.1.5.2.1.3.1.28", NULL, SU_FLAG_OK, NULL }, /* pduOutletControlOnCmd.1.29 = INTEGER: 0 */ { "unmapped.pduOutletControlOnCmd", 0, 1, ".1.3.6.1.4.1.534.7.1.5.2.1.3.1.29", NULL, SU_FLAG_OK, NULL }, /* pduOutletControlOnCmd.1.30 = INTEGER: 0 */ { "unmapped.pduOutletControlOnCmd", 0, 1, ".1.3.6.1.4.1.534.7.1.5.2.1.3.1.30", NULL, SU_FLAG_OK, NULL }, /* pduOutletControlOnCmd.1.31 = INTEGER: 0 */ { "unmapped.pduOutletControlOnCmd", 0, 1, ".1.3.6.1.4.1.534.7.1.5.2.1.3.1.31", NULL, SU_FLAG_OK, NULL }, /* pduOutletControlOnCmd.1.32 = INTEGER: 0 */ { "unmapped.pduOutletControlOnCmd", 0, 1, ".1.3.6.1.4.1.534.7.1.5.2.1.3.1.32", NULL, SU_FLAG_OK, NULL }, /* pduOutletControlOnCmd.1.33 = INTEGER: 0 */ { "unmapped.pduOutletControlOnCmd", 0, 1, ".1.3.6.1.4.1.534.7.1.5.2.1.3.1.33", NULL, SU_FLAG_OK, NULL }, /* pduOutletControlOnCmd.1.34 = INTEGER: 0 */ { "unmapped.pduOutletControlOnCmd", 0, 1, ".1.3.6.1.4.1.534.7.1.5.2.1.3.1.34", NULL, SU_FLAG_OK, NULL }, /* pduOutletControlOnCmd.1.35 = INTEGER: 0 */ { "unmapped.pduOutletControlOnCmd", 0, 1, ".1.3.6.1.4.1.534.7.1.5.2.1.3.1.35", NULL, SU_FLAG_OK, NULL }, /* pduOutletControlOnCmd.1.36 = INTEGER: 0 */ { "unmapped.pduOutletControlOnCmd", 0, 1, ".1.3.6.1.4.1.534.7.1.5.2.1.3.1.36", NULL, SU_FLAG_OK, NULL }, /* pduOutletControlOnCmd.1.37 = INTEGER: 0 */ { "unmapped.pduOutletControlOnCmd", 0, 1, ".1.3.6.1.4.1.534.7.1.5.2.1.3.1.37", NULL, SU_FLAG_OK, NULL }, /* pduOutletControlOnCmd.1.38 = INTEGER: 0 */ { "unmapped.pduOutletControlOnCmd", 0, 1, ".1.3.6.1.4.1.534.7.1.5.2.1.3.1.38", NULL, SU_FLAG_OK, NULL }, /* pduOutletControlOnCmd.1.39 = INTEGER: 0 */ { "unmapped.pduOutletControlOnCmd", 0, 1, ".1.3.6.1.4.1.534.7.1.5.2.1.3.1.39", NULL, SU_FLAG_OK, NULL }, /* pduOutletControlOnCmd.1.40 = INTEGER: 0 */ { "unmapped.pduOutletControlOnCmd", 0, 1, ".1.3.6.1.4.1.534.7.1.5.2.1.3.1.40", NULL, SU_FLAG_OK, NULL }, /* pduOutletControlOnCmd.1.41 = INTEGER: 0 */ { "unmapped.pduOutletControlOnCmd", 0, 1, ".1.3.6.1.4.1.534.7.1.5.2.1.3.1.41", NULL, SU_FLAG_OK, NULL }, /* pduOutletControlOnCmd.1.42 = INTEGER: 0 */ { "unmapped.pduOutletControlOnCmd", 0, 1, ".1.3.6.1.4.1.534.7.1.5.2.1.3.1.42", NULL, SU_FLAG_OK, NULL }, /* pduOutletControlOnCmd.1.43 = INTEGER: 0 */ { "unmapped.pduOutletControlOnCmd", 0, 1, ".1.3.6.1.4.1.534.7.1.5.2.1.3.1.43", NULL, SU_FLAG_OK, NULL }, /* pduOutletControlOnCmd.1.44 = INTEGER: 0 */ { "unmapped.pduOutletControlOnCmd", 0, 1, ".1.3.6.1.4.1.534.7.1.5.2.1.3.1.44", NULL, SU_FLAG_OK, NULL }, /* pduOutletControlOnCmd.1.45 = INTEGER: 0 */ { "unmapped.pduOutletControlOnCmd", 0, 1, ".1.3.6.1.4.1.534.7.1.5.2.1.3.1.45", NULL, SU_FLAG_OK, NULL }, /* pduOutletControlOnCmd.1.46 = INTEGER: 0 */ { "unmapped.pduOutletControlOnCmd", 0, 1, ".1.3.6.1.4.1.534.7.1.5.2.1.3.1.46", NULL, SU_FLAG_OK, NULL }, /* pduOutletControlOnCmd.1.47 = INTEGER: 0 */ { "unmapped.pduOutletControlOnCmd", 0, 1, ".1.3.6.1.4.1.534.7.1.5.2.1.3.1.47", NULL, SU_FLAG_OK, NULL }, /* pduOutletControlOnCmd.1.48 = INTEGER: 0 */ { "unmapped.pduOutletControlOnCmd", 0, 1, ".1.3.6.1.4.1.534.7.1.5.2.1.3.1.48", NULL, SU_FLAG_OK, NULL }, /* pduOutletControlRebootCmd.1.1 = INTEGER: -1 */ { "unmapped.pduOutletControlRebootCmd", 0, 1, ".1.3.6.1.4.1.534.7.1.5.2.1.4.1.1", NULL, SU_FLAG_OK, NULL }, /* pduOutletControlRebootCmd.1.2 = INTEGER: -1 */ { "unmapped.pduOutletControlRebootCmd", 0, 1, ".1.3.6.1.4.1.534.7.1.5.2.1.4.1.2", NULL, SU_FLAG_OK, NULL }, /* pduOutletControlRebootCmd.1.3 = INTEGER: -1 */ { "unmapped.pduOutletControlRebootCmd", 0, 1, ".1.3.6.1.4.1.534.7.1.5.2.1.4.1.3", NULL, SU_FLAG_OK, NULL }, /* pduOutletControlRebootCmd.1.4 = INTEGER: -1 */ { "unmapped.pduOutletControlRebootCmd", 0, 1, ".1.3.6.1.4.1.534.7.1.5.2.1.4.1.4", NULL, SU_FLAG_OK, NULL }, /* pduOutletControlRebootCmd.1.5 = INTEGER: -1 */ { "unmapped.pduOutletControlRebootCmd", 0, 1, ".1.3.6.1.4.1.534.7.1.5.2.1.4.1.5", NULL, SU_FLAG_OK, NULL }, /* pduOutletControlRebootCmd.1.6 = INTEGER: -1 */ { "unmapped.pduOutletControlRebootCmd", 0, 1, ".1.3.6.1.4.1.534.7.1.5.2.1.4.1.6", NULL, SU_FLAG_OK, NULL }, /* pduOutletControlRebootCmd.1.7 = INTEGER: 0 */ { "unmapped.pduOutletControlRebootCmd", 0, 1, ".1.3.6.1.4.1.534.7.1.5.2.1.4.1.7", NULL, SU_FLAG_OK, NULL }, /* pduOutletControlRebootCmd.1.8 = INTEGER: 0 */ { "unmapped.pduOutletControlRebootCmd", 0, 1, ".1.3.6.1.4.1.534.7.1.5.2.1.4.1.8", NULL, SU_FLAG_OK, NULL }, /* pduOutletControlRebootCmd.1.9 = INTEGER: 0 */ { "unmapped.pduOutletControlRebootCmd", 0, 1, ".1.3.6.1.4.1.534.7.1.5.2.1.4.1.9", NULL, SU_FLAG_OK, NULL }, /* pduOutletControlRebootCmd.1.10 = INTEGER: 0 */ { "unmapped.pduOutletControlRebootCmd", 0, 1, ".1.3.6.1.4.1.534.7.1.5.2.1.4.1.10", NULL, SU_FLAG_OK, NULL }, /* pduOutletControlRebootCmd.1.11 = INTEGER: 0 */ { "unmapped.pduOutletControlRebootCmd", 0, 1, ".1.3.6.1.4.1.534.7.1.5.2.1.4.1.11", NULL, SU_FLAG_OK, NULL }, /* pduOutletControlRebootCmd.1.12 = INTEGER: 0 */ { "unmapped.pduOutletControlRebootCmd", 0, 1, ".1.3.6.1.4.1.534.7.1.5.2.1.4.1.12", NULL, SU_FLAG_OK, NULL }, /* pduOutletControlRebootCmd.1.13 = INTEGER: 0 */ { "unmapped.pduOutletControlRebootCmd", 0, 1, ".1.3.6.1.4.1.534.7.1.5.2.1.4.1.13", NULL, SU_FLAG_OK, NULL }, /* pduOutletControlRebootCmd.1.14 = INTEGER: 0 */ { "unmapped.pduOutletControlRebootCmd", 0, 1, ".1.3.6.1.4.1.534.7.1.5.2.1.4.1.14", NULL, SU_FLAG_OK, NULL }, /* pduOutletControlRebootCmd.1.15 = INTEGER: 0 */ { "unmapped.pduOutletControlRebootCmd", 0, 1, ".1.3.6.1.4.1.534.7.1.5.2.1.4.1.15", NULL, SU_FLAG_OK, NULL }, /* pduOutletControlRebootCmd.1.16 = INTEGER: 0 */ { "unmapped.pduOutletControlRebootCmd", 0, 1, ".1.3.6.1.4.1.534.7.1.5.2.1.4.1.16", NULL, SU_FLAG_OK, NULL }, /* pduOutletControlRebootCmd.1.17 = INTEGER: 0 */ { "unmapped.pduOutletControlRebootCmd", 0, 1, ".1.3.6.1.4.1.534.7.1.5.2.1.4.1.17", NULL, SU_FLAG_OK, NULL }, /* pduOutletControlRebootCmd.1.18 = INTEGER: 0 */ { "unmapped.pduOutletControlRebootCmd", 0, 1, ".1.3.6.1.4.1.534.7.1.5.2.1.4.1.18", NULL, SU_FLAG_OK, NULL }, /* pduOutletControlRebootCmd.1.19 = INTEGER: 0 */ { "unmapped.pduOutletControlRebootCmd", 0, 1, ".1.3.6.1.4.1.534.7.1.5.2.1.4.1.19", NULL, SU_FLAG_OK, NULL }, /* pduOutletControlRebootCmd.1.20 = INTEGER: 0 */ { "unmapped.pduOutletControlRebootCmd", 0, 1, ".1.3.6.1.4.1.534.7.1.5.2.1.4.1.20", NULL, SU_FLAG_OK, NULL }, /* pduOutletControlRebootCmd.1.21 = INTEGER: 0 */ { "unmapped.pduOutletControlRebootCmd", 0, 1, ".1.3.6.1.4.1.534.7.1.5.2.1.4.1.21", NULL, SU_FLAG_OK, NULL }, /* pduOutletControlRebootCmd.1.22 = INTEGER: 0 */ { "unmapped.pduOutletControlRebootCmd", 0, 1, ".1.3.6.1.4.1.534.7.1.5.2.1.4.1.22", NULL, SU_FLAG_OK, NULL }, /* pduOutletControlRebootCmd.1.23 = INTEGER: 0 */ { "unmapped.pduOutletControlRebootCmd", 0, 1, ".1.3.6.1.4.1.534.7.1.5.2.1.4.1.23", NULL, SU_FLAG_OK, NULL }, /* pduOutletControlRebootCmd.1.24 = INTEGER: 0 */ { "unmapped.pduOutletControlRebootCmd", 0, 1, ".1.3.6.1.4.1.534.7.1.5.2.1.4.1.24", NULL, SU_FLAG_OK, NULL }, /* pduOutletControlRebootCmd.1.25 = INTEGER: 0 */ { "unmapped.pduOutletControlRebootCmd", 0, 1, ".1.3.6.1.4.1.534.7.1.5.2.1.4.1.25", NULL, SU_FLAG_OK, NULL }, /* pduOutletControlRebootCmd.1.26 = INTEGER: 0 */ { "unmapped.pduOutletControlRebootCmd", 0, 1, ".1.3.6.1.4.1.534.7.1.5.2.1.4.1.26", NULL, SU_FLAG_OK, NULL }, /* pduOutletControlRebootCmd.1.27 = INTEGER: 0 */ { "unmapped.pduOutletControlRebootCmd", 0, 1, ".1.3.6.1.4.1.534.7.1.5.2.1.4.1.27", NULL, SU_FLAG_OK, NULL }, /* pduOutletControlRebootCmd.1.28 = INTEGER: 0 */ { "unmapped.pduOutletControlRebootCmd", 0, 1, ".1.3.6.1.4.1.534.7.1.5.2.1.4.1.28", NULL, SU_FLAG_OK, NULL }, /* pduOutletControlRebootCmd.1.29 = INTEGER: 0 */ { "unmapped.pduOutletControlRebootCmd", 0, 1, ".1.3.6.1.4.1.534.7.1.5.2.1.4.1.29", NULL, SU_FLAG_OK, NULL }, /* pduOutletControlRebootCmd.1.30 = INTEGER: 0 */ { "unmapped.pduOutletControlRebootCmd", 0, 1, ".1.3.6.1.4.1.534.7.1.5.2.1.4.1.30", NULL, SU_FLAG_OK, NULL }, /* pduOutletControlRebootCmd.1.31 = INTEGER: 0 */ { "unmapped.pduOutletControlRebootCmd", 0, 1, ".1.3.6.1.4.1.534.7.1.5.2.1.4.1.31", NULL, SU_FLAG_OK, NULL }, /* pduOutletControlRebootCmd.1.32 = INTEGER: 0 */ { "unmapped.pduOutletControlRebootCmd", 0, 1, ".1.3.6.1.4.1.534.7.1.5.2.1.4.1.32", NULL, SU_FLAG_OK, NULL }, /* pduOutletControlRebootCmd.1.33 = INTEGER: 0 */ { "unmapped.pduOutletControlRebootCmd", 0, 1, ".1.3.6.1.4.1.534.7.1.5.2.1.4.1.33", NULL, SU_FLAG_OK, NULL }, /* pduOutletControlRebootCmd.1.34 = INTEGER: 0 */ { "unmapped.pduOutletControlRebootCmd", 0, 1, ".1.3.6.1.4.1.534.7.1.5.2.1.4.1.34", NULL, SU_FLAG_OK, NULL }, /* pduOutletControlRebootCmd.1.35 = INTEGER: 0 */ { "unmapped.pduOutletControlRebootCmd", 0, 1, ".1.3.6.1.4.1.534.7.1.5.2.1.4.1.35", NULL, SU_FLAG_OK, NULL }, /* pduOutletControlRebootCmd.1.36 = INTEGER: 0 */ { "unmapped.pduOutletControlRebootCmd", 0, 1, ".1.3.6.1.4.1.534.7.1.5.2.1.4.1.36", NULL, SU_FLAG_OK, NULL }, /* pduOutletControlRebootCmd.1.37 = INTEGER: 0 */ { "unmapped.pduOutletControlRebootCmd", 0, 1, ".1.3.6.1.4.1.534.7.1.5.2.1.4.1.37", NULL, SU_FLAG_OK, NULL }, /* pduOutletControlRebootCmd.1.38 = INTEGER: 0 */ { "unmapped.pduOutletControlRebootCmd", 0, 1, ".1.3.6.1.4.1.534.7.1.5.2.1.4.1.38", NULL, SU_FLAG_OK, NULL }, /* pduOutletControlRebootCmd.1.39 = INTEGER: 0 */ { "unmapped.pduOutletControlRebootCmd", 0, 1, ".1.3.6.1.4.1.534.7.1.5.2.1.4.1.39", NULL, SU_FLAG_OK, NULL }, /* pduOutletControlRebootCmd.1.40 = INTEGER: 0 */ { "unmapped.pduOutletControlRebootCmd", 0, 1, ".1.3.6.1.4.1.534.7.1.5.2.1.4.1.40", NULL, SU_FLAG_OK, NULL }, /* pduOutletControlRebootCmd.1.41 = INTEGER: 0 */ { "unmapped.pduOutletControlRebootCmd", 0, 1, ".1.3.6.1.4.1.534.7.1.5.2.1.4.1.41", NULL, SU_FLAG_OK, NULL }, /* pduOutletControlRebootCmd.1.42 = INTEGER: 0 */ { "unmapped.pduOutletControlRebootCmd", 0, 1, ".1.3.6.1.4.1.534.7.1.5.2.1.4.1.42", NULL, SU_FLAG_OK, NULL }, /* pduOutletControlRebootCmd.1.43 = INTEGER: 0 */ { "unmapped.pduOutletControlRebootCmd", 0, 1, ".1.3.6.1.4.1.534.7.1.5.2.1.4.1.43", NULL, SU_FLAG_OK, NULL }, /* pduOutletControlRebootCmd.1.44 = INTEGER: 0 */ { "unmapped.pduOutletControlRebootCmd", 0, 1, ".1.3.6.1.4.1.534.7.1.5.2.1.4.1.44", NULL, SU_FLAG_OK, NULL }, /* pduOutletControlRebootCmd.1.45 = INTEGER: 0 */ { "unmapped.pduOutletControlRebootCmd", 0, 1, ".1.3.6.1.4.1.534.7.1.5.2.1.4.1.45", NULL, SU_FLAG_OK, NULL }, /* pduOutletControlRebootCmd.1.46 = INTEGER: 0 */ { "unmapped.pduOutletControlRebootCmd", 0, 1, ".1.3.6.1.4.1.534.7.1.5.2.1.4.1.46", NULL, SU_FLAG_OK, NULL }, /* pduOutletControlRebootCmd.1.47 = INTEGER: 0 */ { "unmapped.pduOutletControlRebootCmd", 0, 1, ".1.3.6.1.4.1.534.7.1.5.2.1.4.1.47", NULL, SU_FLAG_OK, NULL }, /* pduOutletControlRebootCmd.1.48 = INTEGER: 0 */ { "unmapped.pduOutletControlRebootCmd", 0, 1, ".1.3.6.1.4.1.534.7.1.5.2.1.4.1.48", NULL, SU_FLAG_OK, NULL }, /* pduOutletControlPowerOnState.1.1 = INTEGER: 2 */ { "unmapped.pduOutletControlPowerOnState", 0, 1, ".1.3.6.1.4.1.534.7.1.5.2.1.5.1.1", NULL, SU_FLAG_OK, NULL }, /* pduOutletControlPowerOnState.1.2 = INTEGER: 2 */ { "unmapped.pduOutletControlPowerOnState", 0, 1, ".1.3.6.1.4.1.534.7.1.5.2.1.5.1.2", NULL, SU_FLAG_OK, NULL }, /* pduOutletControlPowerOnState.1.3 = INTEGER: 2 */ { "unmapped.pduOutletControlPowerOnState", 0, 1, ".1.3.6.1.4.1.534.7.1.5.2.1.5.1.3", NULL, SU_FLAG_OK, NULL }, /* pduOutletControlPowerOnState.1.4 = INTEGER: 2 */ { "unmapped.pduOutletControlPowerOnState", 0, 1, ".1.3.6.1.4.1.534.7.1.5.2.1.5.1.4", NULL, SU_FLAG_OK, NULL }, /* pduOutletControlPowerOnState.1.5 = INTEGER: 2 */ { "unmapped.pduOutletControlPowerOnState", 0, 1, ".1.3.6.1.4.1.534.7.1.5.2.1.5.1.5", NULL, SU_FLAG_OK, NULL }, /* pduOutletControlPowerOnState.1.6 = INTEGER: 2 */ { "unmapped.pduOutletControlPowerOnState", 0, 1, ".1.3.6.1.4.1.534.7.1.5.2.1.5.1.6", NULL, SU_FLAG_OK, NULL }, /* pduOutletControlPowerOnState.1.7 = INTEGER: 0 */ { "unmapped.pduOutletControlPowerOnState", 0, 1, ".1.3.6.1.4.1.534.7.1.5.2.1.5.1.7", NULL, SU_FLAG_OK, NULL }, /* pduOutletControlPowerOnState.1.8 = INTEGER: 0 */ { "unmapped.pduOutletControlPowerOnState", 0, 1, ".1.3.6.1.4.1.534.7.1.5.2.1.5.1.8", NULL, SU_FLAG_OK, NULL }, /* pduOutletControlPowerOnState.1.9 = INTEGER: 0 */ { "unmapped.pduOutletControlPowerOnState", 0, 1, ".1.3.6.1.4.1.534.7.1.5.2.1.5.1.9", NULL, SU_FLAG_OK, NULL }, /* pduOutletControlPowerOnState.1.10 = INTEGER: 0 */ { "unmapped.pduOutletControlPowerOnState", 0, 1, ".1.3.6.1.4.1.534.7.1.5.2.1.5.1.10", NULL, SU_FLAG_OK, NULL }, /* pduOutletControlPowerOnState.1.11 = INTEGER: 0 */ { "unmapped.pduOutletControlPowerOnState", 0, 1, ".1.3.6.1.4.1.534.7.1.5.2.1.5.1.11", NULL, SU_FLAG_OK, NULL }, /* pduOutletControlPowerOnState.1.12 = INTEGER: 0 */ { "unmapped.pduOutletControlPowerOnState", 0, 1, ".1.3.6.1.4.1.534.7.1.5.2.1.5.1.12", NULL, SU_FLAG_OK, NULL }, /* pduOutletControlPowerOnState.1.13 = INTEGER: 0 */ { "unmapped.pduOutletControlPowerOnState", 0, 1, ".1.3.6.1.4.1.534.7.1.5.2.1.5.1.13", NULL, SU_FLAG_OK, NULL }, /* pduOutletControlPowerOnState.1.14 = INTEGER: 0 */ { "unmapped.pduOutletControlPowerOnState", 0, 1, ".1.3.6.1.4.1.534.7.1.5.2.1.5.1.14", NULL, SU_FLAG_OK, NULL }, /* pduOutletControlPowerOnState.1.15 = INTEGER: 0 */ { "unmapped.pduOutletControlPowerOnState", 0, 1, ".1.3.6.1.4.1.534.7.1.5.2.1.5.1.15", NULL, SU_FLAG_OK, NULL }, /* pduOutletControlPowerOnState.1.16 = INTEGER: 0 */ { "unmapped.pduOutletControlPowerOnState", 0, 1, ".1.3.6.1.4.1.534.7.1.5.2.1.5.1.16", NULL, SU_FLAG_OK, NULL }, /* pduOutletControlPowerOnState.1.17 = INTEGER: 0 */ { "unmapped.pduOutletControlPowerOnState", 0, 1, ".1.3.6.1.4.1.534.7.1.5.2.1.5.1.17", NULL, SU_FLAG_OK, NULL }, /* pduOutletControlPowerOnState.1.18 = INTEGER: 0 */ { "unmapped.pduOutletControlPowerOnState", 0, 1, ".1.3.6.1.4.1.534.7.1.5.2.1.5.1.18", NULL, SU_FLAG_OK, NULL }, /* pduOutletControlPowerOnState.1.19 = INTEGER: 0 */ { "unmapped.pduOutletControlPowerOnState", 0, 1, ".1.3.6.1.4.1.534.7.1.5.2.1.5.1.19", NULL, SU_FLAG_OK, NULL }, /* pduOutletControlPowerOnState.1.20 = INTEGER: 0 */ { "unmapped.pduOutletControlPowerOnState", 0, 1, ".1.3.6.1.4.1.534.7.1.5.2.1.5.1.20", NULL, SU_FLAG_OK, NULL }, /* pduOutletControlPowerOnState.1.21 = INTEGER: 0 */ { "unmapped.pduOutletControlPowerOnState", 0, 1, ".1.3.6.1.4.1.534.7.1.5.2.1.5.1.21", NULL, SU_FLAG_OK, NULL }, /* pduOutletControlPowerOnState.1.22 = INTEGER: 0 */ { "unmapped.pduOutletControlPowerOnState", 0, 1, ".1.3.6.1.4.1.534.7.1.5.2.1.5.1.22", NULL, SU_FLAG_OK, NULL }, /* pduOutletControlPowerOnState.1.23 = INTEGER: 0 */ { "unmapped.pduOutletControlPowerOnState", 0, 1, ".1.3.6.1.4.1.534.7.1.5.2.1.5.1.23", NULL, SU_FLAG_OK, NULL }, /* pduOutletControlPowerOnState.1.24 = INTEGER: 0 */ { "unmapped.pduOutletControlPowerOnState", 0, 1, ".1.3.6.1.4.1.534.7.1.5.2.1.5.1.24", NULL, SU_FLAG_OK, NULL }, /* pduOutletControlPowerOnState.1.25 = INTEGER: 0 */ { "unmapped.pduOutletControlPowerOnState", 0, 1, ".1.3.6.1.4.1.534.7.1.5.2.1.5.1.25", NULL, SU_FLAG_OK, NULL }, /* pduOutletControlPowerOnState.1.26 = INTEGER: 0 */ { "unmapped.pduOutletControlPowerOnState", 0, 1, ".1.3.6.1.4.1.534.7.1.5.2.1.5.1.26", NULL, SU_FLAG_OK, NULL }, /* pduOutletControlPowerOnState.1.27 = INTEGER: 0 */ { "unmapped.pduOutletControlPowerOnState", 0, 1, ".1.3.6.1.4.1.534.7.1.5.2.1.5.1.27", NULL, SU_FLAG_OK, NULL }, /* pduOutletControlPowerOnState.1.28 = INTEGER: 0 */ { "unmapped.pduOutletControlPowerOnState", 0, 1, ".1.3.6.1.4.1.534.7.1.5.2.1.5.1.28", NULL, SU_FLAG_OK, NULL }, /* pduOutletControlPowerOnState.1.29 = INTEGER: 0 */ { "unmapped.pduOutletControlPowerOnState", 0, 1, ".1.3.6.1.4.1.534.7.1.5.2.1.5.1.29", NULL, SU_FLAG_OK, NULL }, /* pduOutletControlPowerOnState.1.30 = INTEGER: 0 */ { "unmapped.pduOutletControlPowerOnState", 0, 1, ".1.3.6.1.4.1.534.7.1.5.2.1.5.1.30", NULL, SU_FLAG_OK, NULL }, /* pduOutletControlPowerOnState.1.31 = INTEGER: 0 */ { "unmapped.pduOutletControlPowerOnState", 0, 1, ".1.3.6.1.4.1.534.7.1.5.2.1.5.1.31", NULL, SU_FLAG_OK, NULL }, /* pduOutletControlPowerOnState.1.32 = INTEGER: 0 */ { "unmapped.pduOutletControlPowerOnState", 0, 1, ".1.3.6.1.4.1.534.7.1.5.2.1.5.1.32", NULL, SU_FLAG_OK, NULL }, /* pduOutletControlPowerOnState.1.33 = INTEGER: 0 */ { "unmapped.pduOutletControlPowerOnState", 0, 1, ".1.3.6.1.4.1.534.7.1.5.2.1.5.1.33", NULL, SU_FLAG_OK, NULL }, /* pduOutletControlPowerOnState.1.34 = INTEGER: 0 */ { "unmapped.pduOutletControlPowerOnState", 0, 1, ".1.3.6.1.4.1.534.7.1.5.2.1.5.1.34", NULL, SU_FLAG_OK, NULL }, /* pduOutletControlPowerOnState.1.35 = INTEGER: 0 */ { "unmapped.pduOutletControlPowerOnState", 0, 1, ".1.3.6.1.4.1.534.7.1.5.2.1.5.1.35", NULL, SU_FLAG_OK, NULL }, /* pduOutletControlPowerOnState.1.36 = INTEGER: 0 */ { "unmapped.pduOutletControlPowerOnState", 0, 1, ".1.3.6.1.4.1.534.7.1.5.2.1.5.1.36", NULL, SU_FLAG_OK, NULL }, /* pduOutletControlPowerOnState.1.37 = INTEGER: 0 */ { "unmapped.pduOutletControlPowerOnState", 0, 1, ".1.3.6.1.4.1.534.7.1.5.2.1.5.1.37", NULL, SU_FLAG_OK, NULL }, /* pduOutletControlPowerOnState.1.38 = INTEGER: 0 */ { "unmapped.pduOutletControlPowerOnState", 0, 1, ".1.3.6.1.4.1.534.7.1.5.2.1.5.1.38", NULL, SU_FLAG_OK, NULL }, /* pduOutletControlPowerOnState.1.39 = INTEGER: 0 */ { "unmapped.pduOutletControlPowerOnState", 0, 1, ".1.3.6.1.4.1.534.7.1.5.2.1.5.1.39", NULL, SU_FLAG_OK, NULL }, /* pduOutletControlPowerOnState.1.40 = INTEGER: 0 */ { "unmapped.pduOutletControlPowerOnState", 0, 1, ".1.3.6.1.4.1.534.7.1.5.2.1.5.1.40", NULL, SU_FLAG_OK, NULL }, /* pduOutletControlPowerOnState.1.41 = INTEGER: 0 */ { "unmapped.pduOutletControlPowerOnState", 0, 1, ".1.3.6.1.4.1.534.7.1.5.2.1.5.1.41", NULL, SU_FLAG_OK, NULL }, /* pduOutletControlPowerOnState.1.42 = INTEGER: 0 */ { "unmapped.pduOutletControlPowerOnState", 0, 1, ".1.3.6.1.4.1.534.7.1.5.2.1.5.1.42", NULL, SU_FLAG_OK, NULL }, /* pduOutletControlPowerOnState.1.43 = INTEGER: 0 */ { "unmapped.pduOutletControlPowerOnState", 0, 1, ".1.3.6.1.4.1.534.7.1.5.2.1.5.1.43", NULL, SU_FLAG_OK, NULL }, /* pduOutletControlPowerOnState.1.44 = INTEGER: 0 */ { "unmapped.pduOutletControlPowerOnState", 0, 1, ".1.3.6.1.4.1.534.7.1.5.2.1.5.1.44", NULL, SU_FLAG_OK, NULL }, /* pduOutletControlPowerOnState.1.45 = INTEGER: 0 */ { "unmapped.pduOutletControlPowerOnState", 0, 1, ".1.3.6.1.4.1.534.7.1.5.2.1.5.1.45", NULL, SU_FLAG_OK, NULL }, /* pduOutletControlPowerOnState.1.46 = INTEGER: 0 */ { "unmapped.pduOutletControlPowerOnState", 0, 1, ".1.3.6.1.4.1.534.7.1.5.2.1.5.1.46", NULL, SU_FLAG_OK, NULL }, /* pduOutletControlPowerOnState.1.47 = INTEGER: 0 */ { "unmapped.pduOutletControlPowerOnState", 0, 1, ".1.3.6.1.4.1.534.7.1.5.2.1.5.1.47", NULL, SU_FLAG_OK, NULL }, /* pduOutletControlPowerOnState.1.48 = INTEGER: 0 */ { "unmapped.pduOutletControlPowerOnState", 0, 1, ".1.3.6.1.4.1.534.7.1.5.2.1.5.1.48", NULL, SU_FLAG_OK, NULL }, #endif /* if WITH_UNMAPPED_DATA_POINTS */ /* end of structure. */ { NULL, 0, 0, NULL, NULL, 0, NULL } }; mib2nut_info_t eaton_pdu_nlogic = { "eaton_pdu_nlogic", EATON_PDU_NLOGIC_MIB_VERSION, NULL, NULL, eaton_pdu_nlogic_mib, EATON_PDU_NLOGIC_SYSOID, NULL }; nut-2.8.1/drivers/nutdrv_qx_voltronic.c0000644000175000017500000040743414501607135015242 00000000000000/* nutdrv_qx_voltronic.c - Subdriver for Voltronic Power UPSes * * Copyright (C) * 2013 Daniele Pezzini * * 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 2 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, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #include "main.h" #include "nut_float.h" #include "nut_stdint.h" #include "nutdrv_qx.h" #include "nutdrv_qx_voltronic.h" #define VOLTRONIC_VERSION "Voltronic 0.08" /* Support functions */ static int voltronic_claim(void); static void voltronic_makevartable(void); static void voltronic_massive_unskip(const long protocol); /* Range/enum functions */ static int voltronic_batt_low(char *value, const size_t len); static int voltronic_bypass_volt_max(char *value, const size_t len); static int voltronic_bypass_volt_min(char *value, const size_t len); static int voltronic_bypass_freq_max(char *value, const size_t len); static int voltronic_bypass_freq_min(char *value, const size_t len); static int voltronic_eco_freq_min(char *value, const size_t len); static int voltronic_eco_freq_max(char *value, const size_t len); /* Preprocess functions */ static int voltronic_process_setvar(item_t *item, char *value, const size_t valuelen); static int voltronic_process_command(item_t *item, char *value, const size_t valuelen); static int voltronic_capability(item_t *item, char *value, const size_t valuelen); static int voltronic_capability_set(item_t *item, char *value, const size_t valuelen); static int voltronic_capability_set_nonut(item_t *item, char *value, const size_t valuelen); static int voltronic_capability_reset(item_t *item, char *value, const size_t valuelen); static int voltronic_eco_volt(item_t *item, char *value, const size_t valuelen); static int voltronic_eco_volt_range(item_t *item, char *value, const size_t valuelen); static int voltronic_eco_freq(item_t *item, char *value, const size_t valuelen); static int voltronic_bypass(item_t *item, char *value, const size_t valuelen); static int voltronic_batt_numb(item_t *item, char *value, const size_t valuelen); static int voltronic_batt_runtime(item_t *item, char *value, const size_t valuelen); static int voltronic_protocol(item_t *item, char *value, const size_t valuelen); static int voltronic_fault(item_t *item, char *value, const size_t valuelen); static int voltronic_warning(item_t *item, char *value, const size_t valuelen); static int voltronic_mode(item_t *item, char *value, const size_t valuelen); static int voltronic_status(item_t *item, char *value, const size_t valuelen); static int voltronic_output_powerfactor(item_t *item, char *value, const size_t valuelen); static int voltronic_serial_numb(item_t *item, char *value, const size_t valuelen); static int voltronic_outlet(item_t *item, char *value, const size_t valuelen); static int voltronic_outlet_delay(item_t *item, char *value, const size_t valuelen); static int voltronic_outlet_delay_set(item_t *item, char *value, const size_t valuelen); static int voltronic_p31b(item_t *item, char *value, const size_t valuelen); static int voltronic_p31b_set(item_t *item, char *value, const size_t valuelen); static int voltronic_p31g(item_t *item, char *value, const size_t valuelen); static int voltronic_p31g_set(item_t *item, char *value, const size_t valuelen); static int voltronic_phase(item_t *item, char *value, const size_t valuelen); static int voltronic_phase_set(item_t *item, char *value, const size_t valuelen); static int voltronic_parallel(item_t *item, char *value, const size_t valuelen); /* Capability vars */ static char *bypass_alarm, *battery_alarm, *bypass_when_off, *alarm_control, *converter_mode, *eco_mode, *battery_open_status_check, *bypass_forbidding, *site_fault_detection, *advanced_eco_mode, *constant_phase_angle, *limited_runtime_on_battery; /* ups.conf settings */ static long max_bypass_volt, min_bypass_volt, battery_number, output_phase_angle, work_range_type; static double max_bypass_freq, min_bypass_freq; /* == Ranges/enums == */ /* Range for ups.delay.start */ static info_rw_t voltronic_r_ondelay[] = { { "0", 0 }, { "599940", 0 }, { "", 0 } }; /* Range for ups.delay.shutdown */ static info_rw_t voltronic_r_offdelay[] = { { "12", 0 }, { "5940", 0 }, { "", 0 } }; /* Enumlist for output phase angle */ static info_rw_t voltronic_e_phase[] = { { "000", 0 }, { "120", 0 }, { "180", 0 }, { "240", 0 }, { "", 0 } }; /* Range for battery low voltage */ static info_rw_t voltronic_r_batt_low[] = { { "20", 0 }, { "24", voltronic_batt_low }, { "28", voltronic_batt_low }, { "", 0 } }; /* Preprocess range value for battery low voltage */ static int voltronic_batt_low(char *value, const size_t len) { long val = strtol(value, NULL, 10); const char *ovn = dstate_getinfo("output.voltage.nominal"), *ocn = dstate_getinfo("output.current.nominal"); NUT_UNUSED_VARIABLE(len); if (!ovn || !ocn) { upsdebugx(2, "%s: unable to get the value of output voltage nominal/output current nominal", __func__); return -1; } if ((strtol(ovn, NULL, 10) * strtol(ocn, NULL, 10)) < 1000) { if (val == 24) return 0; else return -1; } else { if (val == 28) return 0; else return -1; } } /* Range for outlet.n.delay.shutdown */ static info_rw_t voltronic_r_outlet_delay[] = { { "0", 0 }, { "59940", 0 }, { "", 0 } }; /* Enumlist for device grid working range type */ static info_rw_t voltronic_e_work_range[] = { { "Appliance", 0 }, /* 00 */ { "UPS", 0 }, /* 01 */ { "", 0 } }; /* Enumlist for battery type */ static info_rw_t voltronic_e_batt_type[] = { { "Li", 0 }, /* 00 */ { "Flooded", 0 }, /* 01 */ { "AGM", 0 }, /* 02 */ { "", 0 } }; /* Range for number of battery packs */ static info_rw_t voltronic_r_batt_packs[] = { { "1", 0 }, { "99", 0 }, { "", 0 } }; /* Range for number of batteries */ static info_rw_t voltronic_r_batt_numb[] = { { "1", 0 }, { "9", 0 }, { "", 0 } }; /* Range for Bypass Mode maximum voltage */ static info_rw_t voltronic_r_bypass_volt_max[] = { { "60", voltronic_bypass_volt_max }, /* P09 */ { "115", voltronic_bypass_volt_max }, /* P02/P03/P10/P13/P14/P99 ivn<200 */ { "120", voltronic_bypass_volt_max }, /* P01 ivn<200 */ { "132", voltronic_bypass_volt_max }, /* P99 ivn<200 */ { "138", voltronic_bypass_volt_max }, /* P02/P03/P10/P13/P14 ivn<200 */ { "140", voltronic_bypass_volt_max }, /* P01 ivn<200, P09 */ { "230", voltronic_bypass_volt_max }, /* P01 ivn>=200 */ { "231", voltronic_bypass_volt_max }, /* P02/P03/P10/P13/P14/P99 ivn>=200 */ { "261", voltronic_bypass_volt_max }, /* P99 ivn>=200 */ { "264", voltronic_bypass_volt_max }, /* P01 ivn>=200 */ { "276", voltronic_bypass_volt_max }, /* P02/P03/P10/P13/P14 ivn>=200 */ { "", 0 } }; /* Preprocess range value for Bypass Mode maximum voltage */ static int voltronic_bypass_volt_max(char *value, const size_t len) { long protocol = strtol(dstate_getinfo("ups.firmware.aux")+1, NULL, 10), val = strtol(value, NULL, 10), ivn; const char *involtnom = dstate_getinfo("input.voltage.nominal"); NUT_UNUSED_VARIABLE(len); if (!involtnom) { upsdebugx(2, "%s: unable to get input.voltage.nominal", __func__); return -1; } ivn = strtol(involtnom, NULL, 10); switch (val) { case 60: /* P09 */ if (protocol == 9) return 0; break; case 115: /* P02/P03/P10/P13/P14/P99 ivn<200 */ if (ivn >= 200) return -1; if (protocol == 2 || protocol == 3 || protocol == 10 || protocol == 13 || protocol == 14 || protocol == 99) return 0; break; case 120: /* P01 ivn<200 */ if (ivn >= 200) return -1; if (protocol == 1) return 0; break; case 132: /* P99 ivn<200 */ if (ivn >= 200) return -1; if (protocol == 99) return 0; break; case 138: /* P02/P03/P10/P13/P14 ivn<200 */ if (ivn >= 200) return -1; if (protocol == 2 || protocol == 3 || protocol == 10 || protocol == 13 || protocol == 14) return 0; break; case 140: /* P01 ivn<200, P09 */ if (protocol == 9) return 0; if (ivn >= 200) return -1; if (protocol == 1) return 0; break; case 230: /* P01 ivn>=200 */ if (ivn < 200) return -1; if (protocol == 1) return 0; break; case 231: /* P02/P03/P10/P13/P14/P99 ivn>=200 */ if (ivn < 200) return -1; if (protocol == 2 || protocol == 3 || protocol == 10 || protocol == 13 || protocol == 14 || protocol == 99) return 0; break; case 261: /* P99 ivn>=200 */ if (ivn < 200) return -1; if (protocol == 99) return 0; break; case 264: /* P01 ivn>=200 */ if (ivn < 200) return -1; if (protocol == 1) return 0; break; case 276: /* P02/P03/P10/P13/P14 ivn>=200 */ if (ivn < 200) return -1; if (protocol == 2 || protocol == 3 || protocol == 10 || protocol == 13 || protocol == 14) return 0; break; default: upsdebugx(2, "%s: unknown value (%s)", __func__, value); break; } return -1; } /* Range for Bypass Mode minimum voltage */ static info_rw_t voltronic_r_bypass_volt_min[] = { { "50", voltronic_bypass_volt_min }, /* P99 ivn<200 */ { "55", voltronic_bypass_volt_min }, /* P02/P03/P10/P13/P14 ivn<200 */ { "60", voltronic_bypass_volt_min }, /* P09 */ { "85", voltronic_bypass_volt_min }, /* P01/P99 ivn<200 */ { "104", voltronic_bypass_volt_min }, /* P02/P03/P10/P13/P14 ivn<200 */ { "110", voltronic_bypass_volt_min }, /* P02/P03/P10/P13/P14 ivn>=200 */ { "115", voltronic_bypass_volt_min }, /* P01 ivn<200 */ { "140", voltronic_bypass_volt_min }, /* P09 */ { "149", voltronic_bypass_volt_min }, /* P99 ivn>=200 */ { "170", voltronic_bypass_volt_min }, /* P01 ivn>=200 */ { "209", voltronic_bypass_volt_min }, /* P02/P03/P10/P13/P14/P99 ivn>=200 */ { "220", voltronic_bypass_volt_min }, /* P01 ivn>=200 */ { "", 0 } }; /* Preprocess range value for Bypass Mode minimum voltage */ static int voltronic_bypass_volt_min(char *value, const size_t len) { long protocol = strtol(dstate_getinfo("ups.firmware.aux")+1, NULL, 10), val = strtol(value, NULL, 10), ivn; const char *involtnom = dstate_getinfo("input.voltage.nominal"); NUT_UNUSED_VARIABLE(len); if (!involtnom) { upsdebugx(2, "%s: unable to get input.voltage.nominal", __func__); return -1; } ivn = strtol(involtnom, NULL, 10); switch (val) { case 50: /* P99 ivn<200 */ if (ivn >= 200) return -1; if (protocol == 99) return 0; break; case 55: /* P02/P03/P10/P13/P14 ivn<200 */ if (ivn >= 200) return -1; if (protocol == 2 || protocol == 3 || protocol == 10 || protocol == 13 || protocol == 14) return 0; break; case 60: /* P09 */ case 140: /* P09 */ if (protocol == 9) return 0; break; case 85: /* P01/P99 ivn<200 */ if (ivn >= 200) return -1; if (protocol == 1 || protocol == 99) return 0; break; case 104: /* P02/P03/P10/P13/P14 ivn<200 */ if (ivn >= 200) return -1; if (protocol == 2 || protocol == 3 || protocol == 10 || protocol == 13 || protocol == 14) return 0; break; case 110: /* P02/P03/P10/P13/P14 ivn>=200 */ if (ivn < 200) return -1; if (protocol == 2 || protocol == 3 || protocol == 10 || protocol == 13 || protocol == 14) return 0; break; case 115: /* P01 ivn<200 */ if (ivn >= 200) return -1; if (protocol == 1) return 0; break; case 149: /* P99 ivn>=200 */ if (ivn < 200) return -1; if (protocol == 99) return 0; break; case 170: /* P01 ivn>=200 */ if (ivn < 200) return -1; if (protocol == 1) return 0; break; case 209: /* P02/P03/P10/P13/P14/P99 ivn>=200 */ if (ivn < 200) return -1; if (protocol == 2 || protocol == 3 || protocol == 10 || protocol == 13 || protocol == 14 || protocol == 99) return 0; break; case 220: /* P01 ivn>=200 */ if (ivn < 200) return -1; if (protocol == 1) return 0; break; default: upsdebugx(2, "%s: unknown value (%s)", __func__, value); break; } return -1; } /* Range for Bypass Mode maximum frequency */ static info_rw_t voltronic_r_bypass_freq_max[] = { { "51.0", voltronic_bypass_freq_max }, /* P01/P09/P02/P03/P10/P13/P14/P99 ofn==50.0 */ { "54.0", voltronic_bypass_freq_max }, /* P02/P03/P10/P13/P14/P99 ofn==50.0 */ { "60.0", voltronic_bypass_freq_max }, /* P01/P09 ofn==50.0 */ { "61.0", voltronic_bypass_freq_max }, /* P01/P09/P02/P03/P10/P13/P14/P99 ofn==60.0 */ { "64.0", voltronic_bypass_freq_max }, /* P02/P03/P10/P13/P14/P99 ofn==60.0 */ { "70.0", voltronic_bypass_freq_max }, /* P01/P09 ofn==60.0 */ { "", 0 } }; /* Preprocess range value for Bypass Mode maximum frequency */ static int voltronic_bypass_freq_max(char *value, const size_t len) { long protocol = strtol(dstate_getinfo("ups.firmware.aux")+1, NULL, 10), val = strtol(value, NULL, 10); double ofn; const char *outfreqnom = dstate_getinfo("output.frequency.nominal"); NUT_UNUSED_VARIABLE(len); if (!outfreqnom) { upsdebugx(2, "%s: unable to get output.frequency.nominal", __func__); return -1; } ofn = strtod(outfreqnom, NULL); switch (val) { case 51: /* P01/P09/P02/P03/P10/P13/P14/P99 ofn==50.0 */ if (ofn != 50.0) return -1; if (protocol == 1 || protocol == 2 || protocol == 3 || protocol == 9 || protocol == 10 || protocol == 13 || protocol == 14 || protocol == 99) return 0; break; case 54: /* P02/P03/P10/P13/P14/P99 ofn==50.0 */ if (ofn != 50.0) return -1; if (protocol == 2 || protocol == 3 || protocol == 10 || protocol == 13 || protocol == 14 || protocol == 99) return 0; break; case 60: /* P01/P09 ofn==50.0 */ if (ofn != 50.0) return -1; if (protocol == 1 || protocol == 9) return 0; break; case 61: /* P01/P09/P02/P03/P10/P13/P14/P99 ofn==60.0 */ if (ofn != 60.0) return -1; if (protocol == 1 || protocol == 2 || protocol == 3 || protocol == 9 || protocol == 10 || protocol == 13 || protocol == 14 || protocol == 99) return 0; break; case 64: /* P02/P03/P10/P13/P14/P99 ofn==60.0 */ if (ofn != 60.0) return -1; if (protocol == 2 || protocol == 3 || protocol == 10 || protocol == 13 || protocol == 14 || protocol == 99) return 0; break; case 70: /* P01/P09 ofn==60.0 */ if (ofn != 60.0) return -1; if (protocol == 1 || protocol == 9) return 0; break; default: upsdebugx(2, "%s: unknown value (%s)", __func__, value); break; } return -1; } /* Range for Bypass Mode minimum frequency */ static info_rw_t voltronic_r_bypass_freq_min[] = { { "40.0", voltronic_bypass_freq_min }, /* P01/P09 ofn==50.0 */ { "46.0", voltronic_bypass_freq_min }, /* P02/P03/P10/P13/P14/P99 ofn==50.0 */ { "49.0", voltronic_bypass_freq_min }, /* P01/P09/P02/P03/P10/P13/P14/P99 ofn==50.0 */ { "50.0", voltronic_bypass_freq_min }, /* P01/P09 ofn==60.0 */ { "56.0", voltronic_bypass_freq_min }, /* P02/P03/P10/P13/P14/P99 ofn==60.0 */ { "59.0", voltronic_bypass_freq_min }, /* P01/P09/P02/P03/P10/P13/P14/P99 ofn==60.0 */ { "", 0 } }; /* Preprocess range value for Bypass Mode minimum frequency */ static int voltronic_bypass_freq_min(char *value, const size_t len) { long protocol = strtol(dstate_getinfo("ups.firmware.aux")+1, NULL, 10), val = strtol(value, NULL, 10); double ofn; const char *outfreqnom = dstate_getinfo("output.frequency.nominal"); NUT_UNUSED_VARIABLE(len); if (!outfreqnom) { upsdebugx(2, "%s: unable to get output.frequency.nominal", __func__); return -1; } ofn = strtod(outfreqnom, NULL); switch (val) { case 40: /* P01/P09 ofn==50.0 */ if (ofn != 50.0) return -1; if (protocol == 1 || protocol == 9) return 0; break; case 46: /* P02/P03/P10/P13/P14/P99 ofn==50.0 */ if (ofn != 50.0) return -1; if (protocol == 2 || protocol == 3 || protocol == 10 || protocol == 13 || protocol == 14 || protocol == 99) return 0; break; case 49: /* P01/P09/P02/P03/P10/P13/P14/P99 ofn==50.0 */ if (ofn != 50.0) return -1; if (protocol == 1 || protocol == 2 || protocol == 3 || protocol == 9 || protocol == 10 || protocol == 13 || protocol == 14 || protocol == 99) return 0; break; case 50: /* P01/P09 ofn==60.0 */ if (ofn != 60.0) return -1; if (protocol == 1 || protocol == 9) return 0; break; case 56: /* P02/P03/P10/P13/P14/P99 ofn==60.0 */ if (ofn != 60.0) return -1; if (protocol == 2 || protocol == 3 || protocol == 10 || protocol == 13 || protocol == 14 || protocol == 99) return 0; break; case 59: /* P01/P09/P02/P03/P10/P13/P14/P99 ofn==60.0 */ if (ofn != 60.0) return -1; if (protocol == 1 || protocol == 2 || protocol == 3 || protocol == 9 || protocol == 10 || protocol == 13 || protocol == 14 || protocol == 99) return 0; break; default: upsdebugx(2, "%s: unknown value (%s)", __func__, value); break; } return -1; } /* Range for Eco Mode maximum voltage: filled at runtime by voltronic_eco_volt */ static info_rw_t voltronic_r_eco_volt_max[] = { { "", 0 }, { "", 0 }, { "", 0 } }; /* Range for ECO Mode minimum voltage: filled at runtime by voltronic_eco_volt */ static info_rw_t voltronic_r_eco_volt_min[] = { { "", 0 }, { "", 0 }, { "", 0 } }; /* Range for ECO Mode minimum frequency */ static info_rw_t voltronic_r_eco_freq_min[] = { { "40.0", voltronic_eco_freq_min }, /* P01/P09 ofn==50.0 */ { "46.0", voltronic_eco_freq_min }, /* P02/P03/P10/P13/P14/P99 ofn==50.0 */ { "47.0", voltronic_eco_freq_min }, /* P01/P09 ofn==50.0 */ { "48.0", voltronic_eco_freq_min }, /* P02/P03/P10/P13/P14/P99 ofn==50.0 */ { "50.0", voltronic_eco_freq_min }, /* P01/P09 ofn==60.0 */ { "56.0", voltronic_eco_freq_min }, /* P02/P03/P10/P13/P14/P99 ofn==60.0 */ { "57.0", voltronic_eco_freq_min }, /* P01/P09 ofn==60.0 */ { "58.0", voltronic_eco_freq_min }, /* P02/P03/P10/P13/P14/P99 ofn==60.0 */ { "", 0 } }; /* Preprocess range value for ECO Mode minimum frequency */ static int voltronic_eco_freq_min(char *value, const size_t len) { long protocol = strtol(dstate_getinfo("ups.firmware.aux")+1, NULL, 10), val = strtol(value, NULL, 10); double ofn; const char *outfreqnom = dstate_getinfo("output.frequency.nominal"); NUT_UNUSED_VARIABLE(len); if (!outfreqnom) { upsdebugx(2, "%s: unable to get output.frequency.nominal", __func__); return -1; } ofn = strtod(outfreqnom, NULL); switch (val) { case 40: /* P01/P09 ofn==50.0 */ if (ofn != 50.0) return -1; if (protocol == 1 || protocol == 9) return 0; break; case 46: /* P02/P03/P10/P13/P14/P99 ofn==50.0 */ if (ofn != 50.0) return -1; if (protocol == 2 || protocol == 3 || protocol == 10 || protocol == 13 || protocol == 14 || protocol == 99) return 0; break; case 47: /* P01/P09 ofn==50.0 */ if (ofn != 50.0) return -1; if (protocol == 1 || protocol == 9) return 0; break; case 48: /* P02/P03/P10/P13/P14/P99 ofn==50.0 */ if (ofn != 50.0) return -1; if (protocol == 2 || protocol == 3 || protocol == 10 || protocol == 13 || protocol == 14 || protocol == 99) return 0; break; case 50: /* P01/P09 ofn==60.0 */ if (ofn != 60.0) return -1; if (protocol == 1 || protocol == 9) return 0; break; case 56: /* P02/P03/P10/P13/P14/P99 ofn==60.0 */ if (ofn != 60.0) return -1; if (protocol == 2 || protocol == 3 || protocol == 10 || protocol == 13 || protocol == 14 || protocol == 99) return 0; break; case 57: /* P01/P09 ofn==60.0 */ if (ofn != 60.0) return -1; if (protocol == 1 || protocol == 9) return 0; break; case 58: /* P02/P03/P10/P13/P14/P99 ofn==60.0 */ if (ofn != 60.0) return -1; if (protocol == 2 || protocol == 3 || protocol == 10 || protocol == 13 || protocol == 14 || protocol == 99) return 0; break; default: upsdebugx(2, "%s: unknown value (%s)", __func__, value); break; } return -1; } /* Range for ECO Mode maximum frequency */ static info_rw_t voltronic_r_eco_freq_max[] = { { "52.0", voltronic_eco_freq_max }, /* P02/P03/P10/P13/P14/P99 ofn==50.0 */ { "53.0", voltronic_eco_freq_max }, /* P01/P09 ofn==50.0 */ { "54.0", voltronic_eco_freq_max }, /* P02/P03/P10/P13/P14/P99 ofn==50.0 */ { "60.0", voltronic_eco_freq_max }, /* P01/P09 ofn==50.0 */ { "62.0", voltronic_eco_freq_max }, /* P02/P03/P10/P13/P14/P99 ofn==60.0 */ { "63.0", voltronic_eco_freq_max }, /* P01/P09 ofn==60.0 */ { "64.0", voltronic_eco_freq_max }, /* P02/P03/P10/P13/P14/P99 ofn==60.0 */ { "70.0", voltronic_eco_freq_max }, /* P01/P09 ofn==60.0 */ { "", 0 } }; /* Preprocess range value for ECO Mode maximum frequency */ static int voltronic_eco_freq_max(char *value, const size_t len) { long protocol = strtol(dstate_getinfo("ups.firmware.aux")+1, NULL, 10), val = strtol(value, NULL, 10); double ofn; const char *outfreqnom = dstate_getinfo("output.frequency.nominal"); NUT_UNUSED_VARIABLE(len); if (!outfreqnom) { upsdebugx(2, "%s: unable to get output.frequency.nominal", __func__); return -1; } ofn = strtod(outfreqnom, NULL); switch (val) { case 52: /* P02/P03/P10/P13/P14/P99 ofn==50.0 */ if (ofn != 50.0) return -1; if (protocol == 2 || protocol == 3 || protocol == 10 || protocol == 13 || protocol == 14 || protocol == 99) return 0; break; case 53: /* P01/P09 ofn==50.0 */ if (ofn != 50.0) return -1; if (protocol == 1 || protocol == 9) return 0; break; case 54: /* P02/P03/P10/P13/P14/P99 ofn==50.0 */ if (ofn != 50.0) return -1; if (protocol == 2 || protocol == 3 || protocol == 10 || protocol == 13 || protocol == 14 || protocol == 99) return 0; break; case 60: /* P01/P09 ofn==50.0 */ if (ofn != 50.0) return -1; if (protocol == 1 || protocol == 9) return 0; break; case 62: /* P02/P03/P10/P13/P14/P99 ofn==60.0 */ if (ofn != 60.0) return -1; if (protocol == 2 || protocol == 3 || protocol == 10 || protocol == 13 || protocol == 14 || protocol == 99) return 0; break; case 63: /* P01/P09 ofn==60.0 */ if (ofn != 60.0) return -1; if (protocol == 1 || protocol == 9) return 0; break; case 64: /* P02/P03/P10/P13/P14/P99 ofn==60.0 */ if (ofn != 60.0) return -1; if (protocol == 2 || protocol == 3 || protocol == 10 || protocol == 13 || protocol == 14 || protocol == 99) return 0; break; case 70: /* P01/P09 ofn==60.0 */ if (ofn != 60.0) return -1; if (protocol == 1 || protocol == 9) return 0; break; default: upsdebugx(2, "%s: unknown value (%s)", __func__, value); break; } return -1; } /* Enumlist for UPS capabilities that have a NUT var */ static info_rw_t voltronic_e_cap[] = { { "no", 0 }, { "yes", 0 }, { "", 0 } }; /* Enumlist for NONUT capabilities */ static info_rw_t voltronic_e_cap_nonut[] = { { "enabled", 0 }, { "disabled", 0 }, { "", 0 } }; /* == qx2nut lookup table == */ static item_t voltronic_qx2nut[] = { /* Query UPS for protocol * > [QPI\r] * < [(PI00\r] * 012345 * 0 */ { "ups.firmware.aux", 0, NULL, "QPI\r", "", 6, '(', "", 1, 4, "%s", QX_FLAG_STATIC, NULL, NULL, voltronic_protocol }, /* Query UPS for ratings * > [QRI\r] * < [(230.0 004 024.0 50.0\r] * 0123456789012345678901 * 0 1 2 */ { "output.voltage.nominal", 0, NULL, "QRI\r", "", 22, '(', "", 1, 5, "%.1f", QX_FLAG_STATIC, NULL, NULL, NULL }, { "output.current.nominal", 0, NULL, "QRI\r", "", 22, '(', "", 7, 9, "%.0f", QX_FLAG_STATIC, NULL, NULL, NULL }, { "battery.voltage.nominal", 0, NULL, "QRI\r", "", 22, '(', "", 11, 15, "%.1f", QX_FLAG_SEMI_STATIC, NULL, NULL, NULL }, /* as *per battery pack*: the value will change when the number of batteries is changed (battery_number through BATNn) */ { "output.frequency.nominal", 0, NULL, "QRI\r", "", 22, '(', "", 17, 20, "%.1f", QX_FLAG_STATIC, NULL, NULL, NULL }, /* Query UPS for ratings * > [QMD\r] * < [(#######OLHVT1K0 ###1000 80 1/1 230 230 02 12.0\r] <- Some UPS may reply with spaces instead of hashes * 012345678901234567890123456789012345678901234567 * 0 1 2 3 4 */ { "device.model", 0, NULL, "QMD\r", "", 48, '(', "", 1, 15, "%s", QX_FLAG_STATIC | QX_FLAG_TRIM, NULL, NULL, NULL }, { "ups.power.nominal", 0, NULL, "QMD\r", "", 48, '(', "", 17, 23, "%s", QX_FLAG_STATIC | QX_FLAG_TRIM, NULL, NULL, NULL }, { "output.powerfactor", 0, NULL, "QMD\r", "", 48, '(', "", 25, 26, "%.1f", QX_FLAG_STATIC, NULL, NULL, voltronic_output_powerfactor }, { "input.phases", 0, NULL, "QMD\r", "", 48, '(', "", 28, 28, "%.0f", QX_FLAG_STATIC, NULL, NULL, NULL }, { "output.phases", 0, NULL, "QMD\r", "", 48, '(', "", 30, 30, "%.0f", QX_FLAG_STATIC, NULL, NULL, NULL }, { "input.voltage.nominal", 0, NULL, "QMD\r", "", 48, '(', "", 32, 34, "%.1f", QX_FLAG_STATIC, NULL, NULL, NULL }, { "output.voltage.nominal", 0, NULL, "QMD\r", "", 48, '(', "", 36, 38, "%.1f", QX_FLAG_STATIC, NULL, NULL, NULL }, /* redundant with value from QRI */ /* { "battery_number", ST_FLAG_RW, voltronic_r_batt_numb, "QMD\r", "", 48, '(', "", 40, 41, "%d", QX_FLAG_SEMI_STATIC | QX_FLAG_RANGE | QX_FLAG_NONUT, NULL, NULL, voltronic_batt_numb }, *//* redundant with value from QBV */ /* { "battery.voltage.nominal", 0, NULL, "QMD\r", "", 48, '(', "", 43, 46, "%.1f", QX_FLAG_STATIC, NULL, NULL, NULL }, *//* as *per battery* vs *per pack* reported by QRI */ /* Query UPS for ratings * > [F\r] * < [#220.0 000 024.0 50.0\r] * 0123456789012345678901 * 0 1 2 */ { "input.voltage.nominal", 0, NULL, "F\r", "", 22, '#', "", 1, 5, "%.1f", QX_FLAG_STATIC, NULL, NULL, NULL }, { "input.current.nominal", 0, NULL, "F\r", "", 22, '#', "", 7, 9, "%.1f", QX_FLAG_STATIC, NULL, NULL, NULL }, { "battery.voltage.nominal", 0, NULL, "F\r", "", 22, '#', "", 11, 15, "%.1f", QX_FLAG_STATIC, NULL, NULL, NULL }, { "input.frequency.nominal", 0, NULL, "F\r", "", 22, '#', "", 17, 20, "%.1f", QX_FLAG_STATIC, NULL, NULL, NULL }, /* Query UPS for manufacturer * > [QMF\r] * < [(#######BOH\r] <- I don't know if it has a fixed length (-> so min length = ( + \r = 2). Hashes may be replaced by spaces * 012345678901 * 0 1 */ { "device.mfr", 0, NULL, "QMF\r", "", 2, '(', "", 1, 0, "%s", QX_FLAG_STATIC | QX_FLAG_TRIM, NULL, NULL, NULL }, /* Query UPS for firmware version * > [QVFW\r] * < [(VERFW:00322.02\r] * 0123456789012345 * 0 1 */ { "ups.firmware", 0, NULL, "QVFW\r", "", 16, '(', "", 7, 14, "%s", QX_FLAG_STATIC, NULL, NULL, NULL }, /* Query UPS for serial number * > [QID\r] * < [(12345679012345\r] <- As far as I know it hasn't a fixed length -> min length = ( + \r = 2 * 0123456789012345 * 0 1 */ { "device.serial", 0, NULL, "QID\r", "", 2, '(', "", 1, 0, "%s", QX_FLAG_STATIC, NULL, NULL, voltronic_serial_numb }, /* Query UPS for vendor infos * > [I\r] * < [#------------- ------ VT12046Q \r] * 012345678901234567890123456789012345678 * 0 1 2 3 */ { "device.mfr", 0, NULL, "I\r", "", 39, '#', "", 1, 15, "%s", QX_FLAG_STATIC | QX_FLAG_TRIM, NULL, NULL, NULL }, { "device.model", 0, NULL, "I\r", "", 39, '#', "", 17, 26, "%s", QX_FLAG_STATIC | QX_FLAG_TRIM, NULL, NULL, NULL }, { "ups.firmware", 0, NULL, "I\r", "", 39, '#', "", 28, 37, "%s", QX_FLAG_STATIC | QX_FLAG_TRIM, NULL, NULL, NULL }, /* Query UPS for status * > [QGS\r] * < [(234.9 50.0 229.8 50.0 000.0 000 369.1 ---.- 026.5 ---.- 018.8 100000000001\r] * 0123456789012345678901234567890123456789012345678901234567890123456789012345 * 0 1 2 3 4 5 6 7 */ { "input.voltage", 0, NULL, "QGS\r", "", 76, '(', "", 1, 5, "%.1f", 0, NULL, NULL, NULL }, { "input.frequency", 0, NULL, "QGS\r", "", 76, '(', "", 7, 10, "%.1f", 0, NULL, NULL, NULL }, { "output.voltage", 0, NULL, "QGS\r", "", 76, '(', "", 12, 16, "%.1f", 0, NULL, NULL, NULL }, { "output.frequency", 0, NULL, "QGS\r", "", 76, '(', "", 18, 21, "%.1f", 0, NULL, NULL, NULL }, { "output.current", 0, NULL, "QGS\r", "", 76, '(', "", 23, 27, "%.1f", 0, NULL, NULL, NULL }, { "ups.load", 0, NULL, "QGS\r", "", 76, '(', "", 29, 31, "%.0f", 0, NULL, NULL, NULL }, /* { "unknown.1", 0, NULL, "QGS\r", "", 76, '(', "", 33, 37, "%.1f", 0, NULL, NULL, NULL }, *//* Unknown */ /* { "unknown.2", 0, NULL, "QGS\r", "", 76, '(', "", 39, 43, "%.1f", 0, NULL, NULL, NULL }, *//* Unknown */ { "battery.voltage", 0, NULL, "QGS\r", "", 76, '(', "", 45, 49, "%.2f", 0, NULL, NULL, qx_multiply_battvolt }, /* { "unknown.3", 0, NULL, "QGS\r", "", 76, '(', "", 51, 55, "%.1f", 0, NULL, NULL, NULL }, *//* Unknown */ { "ups.temperature", 0, NULL, "QGS\r", "", 76, '(', "", 57, 61, "%.1f", 0, NULL, NULL, NULL }, { "ups.type", 0, NULL, "QGS\r", "", 76, '(', "", 63, 64, "%s", QX_FLAG_SEMI_STATIC, NULL, NULL, voltronic_status }, { "ups.status", 0, NULL, "QGS\r", "", 76, '(', "", 65, 65, "%s", QX_FLAG_QUICK_POLL, NULL, NULL, voltronic_status }, /* Utility Fail (Immediate) */ { "ups.status", 0, NULL, "QGS\r", "", 76, '(', "", 66, 66, "%s", QX_FLAG_QUICK_POLL, NULL, NULL, voltronic_status }, /* Battery Low */ { "ups.status", 0, NULL, "QGS\r", "", 76, '(', "", 67, 67, "%s", QX_FLAG_QUICK_POLL, NULL, NULL, voltronic_status }, /* Bypass/Boost or Buck Active */ { "ups.alarm", 0, NULL, "QGS\r", "", 76, '(', "", 67, 67, "%s", 0, NULL, NULL, voltronic_status }, /* Bypass/Boost or Buck Active */ { "ups.alarm", 0, NULL, "QGS\r", "", 76, '(', "", 68, 68, "%s", 0, NULL, NULL, voltronic_status }, /* UPS Fault */ /* { "unknown.4", 0, NULL, "QGS\r", "", 76, '(', "", 69, 69, "%s", 0, NULL, NULL, voltronic_status }, *//* Unknown */ { "ups.status", 0, NULL, "QGS\r", "", 76, '(', "", 70, 70, "%s", QX_FLAG_QUICK_POLL, NULL, NULL, voltronic_status }, /* Test in Progress */ { "ups.status", 0, NULL, "QGS\r", "", 76, '(', "", 71, 71, "%s", QX_FLAG_QUICK_POLL, NULL, NULL, voltronic_status }, /* Shutdown Active */ { "ups.beeper.status", 0, NULL, "QGS\r", "", 76, '(', "", 72, 72, "%s", 0, NULL, NULL, voltronic_status }, /* Beeper status - ups.beeper.status */ /* { "unknown.5", 0, NULL, "QGS\r", "", 76, '(', "", 73, 73, "%s", 0, NULL, NULL, voltronic_status }, *//* Unknown */ /* { "unknown.6", 0, NULL, "QGS\r", "", 76, '(', "", 74, 74, "%s", 0, NULL, NULL, voltronic_status }, *//* Unknown */ /* Query UPS for actual working mode * > [QMOD\r] * < [(S\r] * 012 * 0 */ { "ups.alarm", 0, NULL, "QMOD\r", "", 3, '(', "", 1, 1, "%s", 0, NULL, NULL, voltronic_mode }, { "ups.status", 0, NULL, "QMOD\r", "", 3, '(', "", 1, 1, "%s", 0, NULL, NULL, voltronic_mode }, /* Query UPS for faults and their type. Unskipped when a fault is found in 12bit flag of QGS, otherwise you'll get a fake reply. * > [QFS\r] * < [(OK\r] <- No fault * 0123 * 0 * < [(14 212.1 50.0 005.6 49.9 006 010.6 343.8 ---.- 026.2 021.8 01101100\r] <- Fault type + Short status * 012345678901234567890123456789012345678901234567890123456789012345678 * 0 1 2 3 4 5 6 */ { "ups.alarm", 0, NULL, "QFS\r", "", 4, '(', "", 1, 2, "%s", QX_FLAG_SKIP, NULL, NULL, voltronic_fault }, /* Query UPS for warnings and their type * > [QWS\r] * < [(0000000100000000000000000000000000000000000000000000000000000000\r] * 012345678901234567890123456789012345678901234567890123456789012345 * 0 1 2 3 4 5 6 */ { "ups.alarm", 0, NULL, "QWS\r", "", 66, '(', "", 1, 64, "%s", 0, NULL, NULL, voltronic_warning }, /* Query UPS for actual infos about battery * > [QBV\r] * < [(026.5 02 01 068 255\r] * 012345678901234567890 * 0 1 2 */ { "battery.voltage", 0, NULL, "QBV\r", "", 21, '(', "", 1, 5, "%.2f", 0, NULL, NULL, qx_multiply_battvolt }, { "battery_number", ST_FLAG_RW, voltronic_r_batt_numb, "QBV\r", "", 21, '(', "", 7, 9, "%d", QX_FLAG_SEMI_STATIC | QX_FLAG_RANGE | QX_FLAG_NONUT, NULL, NULL, voltronic_batt_numb }, /* Number of batteries that make a pack */ { "battery.packs", ST_FLAG_RW, voltronic_r_batt_packs, "QBV\r", "", 21, '(', "", 10, 11, "%.0f", QX_FLAG_SEMI_STATIC | QX_FLAG_RANGE, NULL, NULL, NULL }, /* Number of battery packs in parallel */ { "battery.charge", 0, NULL, "QBV\r", "", 21, '(', "", 13, 15, "%.0f", 0, NULL, NULL, NULL }, { "battery.runtime", 0, NULL, "QBV\r", "", 21, '(', "", 17, 19, "%.0f", 0, NULL, NULL, voltronic_batt_runtime }, /* Query UPS for last seen min/max load level * > [QLDL\r] * < [(021 023\r] <- minimum load level - maximum load level * 012345678 * 0 */ { "output.power.minimum.percent", 0, NULL, "QLDL\r", "", 9, '(', "", 1, 3, "%.0f", 0, NULL, NULL, NULL }, { "output.power.maximum.percent", 0, NULL, "QLDL\r", "", 9, '(', "", 5, 7, "%.0f", 0, NULL, NULL, NULL }, /* Query UPS for multi-phase voltages/frequencies * > [Q3**\r] * < [(123.4 123.4 123.4 123.4 123.4 123.4\r] <- Q3PV * < [(123.4 123.4 123.4 123.4 123.4 123.4\r] <- Q3OV * < [(123 123 123\r] <- Q3PC * < [(123 123 123\r] <- Q3OC * < [(123 123 123\r] <- Q3LD * < [(123.4 123.4 123.4\r] <- Q3YV - P09 protocol * < [(123.4 123.4 123.4 123.4 123.4 123.4\r] <- Q3YV - P10/P03 protocols * 0123456789012345678901234567890123456 * 0 1 2 3 * * P09 = 2-phase input/2-phase output * Q3PV (Input Voltage L1 | Input Voltage L2 | Input Voltage L3 | Input Voltage L1-L2 | Input Voltage L1-L3 | Input Voltage L2-L3 * Q3OV (Output Voltage L1 | Output Voltage L2 | Output Voltage L3 | Output Voltage L1-L2 | Output Voltage L1-L3 | Output Voltage L2-L3 * Q3PC (Input Current L1 | Input Current L2 | Input Current L3 * Q3OC (Output Current L1 | Output Current L2 | Output Current L3 * Q3LD (Output Load Level L1 | Output Load Level L2 | Output Load Level L3 * Q3YV (Output Bypass Voltage L1 | Output Bypass Voltage L2 | Output Bypass Voltage L3 * * P10 = 3-phase input/3-phase output / P03 = 3-phase input/ 1-phase output * Q3PV (Input Voltage L1 | Input Voltage L2 | Input Voltage L3 | Input Voltage L1-L2 | Input Voltage L2-L3 | Input Voltage L1-L3 * Q3OV (Output Voltage L1 | Output Voltage L2 | Output Voltage L3 | Output Voltage L1-L2 | Output Voltage L2-L3 | Output Voltage L1-L3 * Q3PC (Input Current L1 | Input Current L2 | Input Current L3 * Q3OC (Output Current L1 | Output Current L2 | Output Current L3 * Q3LD (Output Load Level L1 | Output Load Level L2 | Output Load Level L3 * Q3YV (Output Bypass Voltage L1 | Output Bypass Voltage L2 | Output Bypass Voltage L3 | Output Bypass Voltage L1-L2 | Output Bypass Voltage L2-L3 | Output Bypass Voltage L1-L3 * */ /* From Q3PV */ { "input.L1-N.voltage", 0, NULL, "Q3PV\r", "", 37, '(', "", 1, 5, "%.1f", QX_FLAG_SKIP, NULL, NULL, NULL }, { "input.L2-N.voltage", 0, NULL, "Q3PV\r", "", 37, '(', "", 7, 11, "%.1f", QX_FLAG_SKIP, NULL, NULL, NULL }, { "input.L3-N.voltage", 0, NULL, "Q3PV\r", "", 37, '(', "", 13, 17, "%.1f", QX_FLAG_SKIP, NULL, NULL, NULL }, { "input.L1-L2.voltage", 0, NULL, "Q3PV\r", "", 37, '(', "", 19, 23, "%.1f", QX_FLAG_SKIP, NULL, NULL, NULL }, { "input.L2-L3.voltage", 0, NULL, "Q3PV\r", "", 37, '(', "", 25, 29, "%.1f", QX_FLAG_SKIP, NULL, NULL, NULL }, { "input.L1-L3.voltage", 0, NULL, "Q3PV\r", "", 37, '(', "", 31, 35, "%.1f", QX_FLAG_SKIP, NULL, NULL, NULL }, /* { "input.L1-L3.voltage", 0, NULL, "Q3PV\r", "", 37, '(', "", 25, 29, "%.1f", QX_FLAG_SKIP, NULL, NULL, NULL }, *//* P09 *//* Commented out because P09 should be two-phase input/output UPSes */ /* { "input.L2-L3.voltage", 0, NULL, "Q3PV\r", "", 37, '(', "", 31, 35, "%.1f", QX_FLAG_SKIP, NULL, NULL, NULL }, *//* P09 *//* Commented out because P09 should be two-phase input/output UPSes */ /* From Q3PC */ { "input.L1.current", 0, NULL, "Q3PC\r", "", 13, '(', "", 1, 3, "%.0f", QX_FLAG_SKIP, NULL, NULL, NULL }, { "input.L2.current", 0, NULL, "Q3PC\r", "", 13, '(', "", 5, 7, "%.0f", QX_FLAG_SKIP, NULL, NULL, NULL }, { "input.L3.current", 0, NULL, "Q3PC\r", "", 13, '(', "", 9, 11, "%.0f", QX_FLAG_SKIP, NULL, NULL, NULL }, /* From Q3OV */ { "output.L1-N.voltage", 0, NULL, "Q3OV\r", "", 37, '(', "", 1, 5, "%.1f", QX_FLAG_SKIP, NULL, NULL, NULL }, { "output.L2-N.voltage", 0, NULL, "Q3OV\r", "", 37, '(', "", 7, 11, "%.1f", QX_FLAG_SKIP, NULL, NULL, NULL }, { "output.L3-N.voltage", 0, NULL, "Q3OV\r", "", 37, '(', "", 13, 17, "%.1f", QX_FLAG_SKIP, NULL, NULL, NULL }, { "output.L1-L2.voltage", 0, NULL, "Q3OV\r", "", 37, '(', "", 19, 23, "%.1f", QX_FLAG_SKIP, NULL, NULL, NULL }, { "output.L2-L3.voltage", 0, NULL, "Q3OV\r", "", 37, '(', "", 25, 29, "%.1f", QX_FLAG_SKIP, NULL, NULL, NULL }, { "output.L1-L3.voltage", 0, NULL, "Q3OV\r", "", 37, '(', "", 31, 35, "%.1f", QX_FLAG_SKIP, NULL, NULL, NULL }, /* { "output.L1-L3.voltage", 0, NULL, "Q3OV\r", "", 37, '(', "", 25, 29, "%.1f", QX_FLAG_SKIP, NULL, NULL, NULL }, *//* P09 *//* Commented out because P09 should be two-phase input/output UPSes */ /* { "output.L2-L3.voltage", 0, NULL, "Q3OV\r", "", 37, '(', "", 31, 35, "%.1f", QX_FLAG_SKIP, NULL, NULL, NULL }, *//* P09 *//* Commented out because P09 should be two-phase input/output UPSes */ /* From Q3OC */ { "output.L1.current", 0, NULL, "Q3OC\r", "", 13, '(', "", 1, 3, "%.0f", QX_FLAG_SKIP, NULL, NULL, NULL }, { "output.L2.current", 0, NULL, "Q3OC\r", "", 13, '(', "", 5, 7, "%.0f", QX_FLAG_SKIP, NULL, NULL, NULL }, { "output.L3.current", 0, NULL, "Q3OC\r", "", 13, '(', "", 9, 11, "%.0f", QX_FLAG_SKIP, NULL, NULL, NULL }, /* From Q3LD */ { "output.L1.power.percent", 0, NULL, "Q3LD\r", "", 13, '(', "", 1, 3, "%.0f", QX_FLAG_SKIP, NULL, NULL, NULL }, { "output.L2.power.percent", 0, NULL, "Q3LD\r", "", 13, '(', "", 5, 7, "%.0f", QX_FLAG_SKIP, NULL, NULL, NULL }, { "output.L3.power.percent", 0, NULL, "Q3LD\r", "", 13, '(', "", 9, 11, "%.0f", QX_FLAG_SKIP, NULL, NULL, NULL }, /* From Q3YV */ { "output.bypass.L1-N.voltage", 0, NULL, "Q3YV\r", "", 37, '(', "", 1, 5, "%.1f", QX_FLAG_SKIP, NULL, NULL, NULL }, { "output.bypass.L2-N.voltage", 0, NULL, "Q3YV\r", "", 37, '(', "", 7, 11, "%.1f", QX_FLAG_SKIP, NULL, NULL, NULL }, { "output.bypass.L3-N.voltage", 0, NULL, "Q3YV\r", "", 37, '(', "", 13, 17, "%.1f", QX_FLAG_SKIP, NULL, NULL, NULL }, { "output.bypass.L1-N.voltage", 0, NULL, "Q3YV\r", "", 19, '(', "", 1, 5, "%.1f", QX_FLAG_SKIP, NULL, NULL, NULL }, /* P09 */ { "output.bypass.L2-N.voltage", 0, NULL, "Q3YV\r", "", 19, '(', "", 7, 11, "%.1f", QX_FLAG_SKIP, NULL, NULL, NULL }, /* P09 */ /* { "output.bypass.L3-N.voltage", 0, NULL, "Q3YV\r", "", 19, '(', "", 13, 17, "%.1f", QX_FLAG_SKIP, NULL, NULL, NULL }, *//* P09 *//* Commented out because P09 should be two-phase input/output UPSes */ { "output.bypass.L1-L2.voltage", 0, NULL, "Q3YV\r", "", 37, '(', "", 19, 23, "%.1f", QX_FLAG_SKIP, NULL, NULL, NULL }, { "output.bypass.L2-L3.voltage", 0, NULL, "Q3YV\r", "", 37, '(', "", 25, 29, "%.1f", QX_FLAG_SKIP, NULL, NULL, NULL }, { "output.bypass.L1-L3.voltage", 0, NULL, "Q3YV\r", "", 37, '(', "", 31, 35, "%.1f", QX_FLAG_SKIP, NULL, NULL, NULL }, /* Query UPS for capability - total options available: 23; only those whom the UPS is capable of are reported as Enabled or Disabled * > [QFLAG\r] * < [(EpashcDbroegfl\r] * 0123456789012345 * 0 1 * min length = ( + E + D + \r = 4 */ { "ups.start.auto", ST_FLAG_RW, voltronic_e_cap, "QFLAG\r", "", 4, '(', "", 1, 0, "%s", QX_FLAG_SEMI_STATIC | QX_FLAG_ENUM, NULL, NULL, voltronic_capability }, { "battery.protection", ST_FLAG_RW, voltronic_e_cap, "QFLAG\r", "", 4, '(', "", 1, 0, "%s", QX_FLAG_SEMI_STATIC | QX_FLAG_ENUM, NULL, NULL, voltronic_capability }, { "battery.energysave", ST_FLAG_RW, voltronic_e_cap, "QFLAG\r", "", 4, '(', "", 1, 0, "%s", QX_FLAG_SEMI_STATIC | QX_FLAG_ENUM, NULL, NULL, voltronic_capability }, { "ups.start.battery", ST_FLAG_RW, voltronic_e_cap, "QFLAG\r", "", 4, '(', "", 1, 0, "%s", QX_FLAG_SEMI_STATIC | QX_FLAG_ENUM, NULL, NULL, voltronic_capability }, { "outlet.0.switchable", ST_FLAG_RW, voltronic_e_cap, "QFLAG\r", "", 4, '(', "", 1, 0, "%s", QX_FLAG_SEMI_STATIC | QX_FLAG_ENUM, NULL, NULL, voltronic_capability }, /* Not available in NUT */ { "bypass_alarm", 0, NULL, "QFLAG\r", "", 4, '(', "", 1, 0, "%s", QX_FLAG_SEMI_STATIC | QX_FLAG_NONUT, NULL, NULL, voltronic_capability }, { "battery_alarm", 0, NULL, "QFLAG\r", "", 4, '(', "", 1, 0, "%s", QX_FLAG_SEMI_STATIC | QX_FLAG_NONUT, NULL, NULL, voltronic_capability }, { "bypass_when_off", 0, NULL, "QFLAG\r", "", 4, '(', "", 1, 0, "%s", QX_FLAG_SEMI_STATIC | QX_FLAG_NONUT, NULL, NULL, voltronic_capability }, { "alarm_control", 0, NULL, "QFLAG\r", "", 4, '(', "", 1, 0, "%s", QX_FLAG_SEMI_STATIC | QX_FLAG_NONUT, NULL, NULL, voltronic_capability }, { "converter_mode", 0, NULL, "QFLAG\r", "", 4, '(', "", 1, 0, "%s", QX_FLAG_SEMI_STATIC | QX_FLAG_NONUT, NULL, NULL, voltronic_capability }, { "eco_mode", 0, NULL, "QFLAG\r", "", 4, '(', "", 1, 0, "%s", QX_FLAG_SEMI_STATIC | QX_FLAG_NONUT, NULL, NULL, voltronic_capability }, { "battery_open_status_check", 0, NULL, "QFLAG\r", "", 4, '(', "", 1, 0, "%s", QX_FLAG_SEMI_STATIC | QX_FLAG_NONUT, NULL, NULL, voltronic_capability }, { "bypass_forbidding", 0, NULL, "QFLAG\r", "", 4, '(', "", 1, 0, "%s", QX_FLAG_SEMI_STATIC | QX_FLAG_NONUT, NULL, NULL, voltronic_capability }, { "site_fault_detection", 0, NULL, "QFLAG\r", "", 4, '(', "", 1, 0, "%s", QX_FLAG_SEMI_STATIC | QX_FLAG_NONUT, NULL, NULL, voltronic_capability }, { "advanced_eco_mode", 0, NULL, "QFLAG\r", "", 4, '(', "", 1, 0, "%s", QX_FLAG_SEMI_STATIC | QX_FLAG_NONUT, NULL, NULL, voltronic_capability }, { "constant_phase_angle", 0, NULL, "QFLAG\r", "", 4, '(', "", 1, 0, "%s", QX_FLAG_SEMI_STATIC | QX_FLAG_NONUT, NULL, NULL, voltronic_capability }, { "limited_runtime_on_battery", 0, NULL, "QFLAG\r", "", 4, '(', "", 1, 0, "%s", QX_FLAG_SEMI_STATIC | QX_FLAG_NONUT, NULL, NULL, voltronic_capability }, /* Enable or Disable or Reset to safe default values capability options * > [PEX\r] > [PDX\r] > [PF\r] * < [(ACK\r] < [(ACK\r] < [(ACK\r] * 01234 01234 01234 * 0 0 0 */ { "ups.start.auto", 0, voltronic_e_cap, "P%sR\r", "", 5, '(', "", 1, 3, NULL, QX_FLAG_SETVAR | QX_FLAG_ENUM | QX_FLAG_SKIP, NULL, NULL, voltronic_capability_set }, { "battery.protection", 0, voltronic_e_cap, "P%sS\r", "", 5, '(', "", 1, 3, NULL, QX_FLAG_SETVAR | QX_FLAG_ENUM | QX_FLAG_SKIP, NULL, NULL, voltronic_capability_set }, { "battery.energysave", 0, voltronic_e_cap, "P%sG\r", "", 5, '(', "", 1, 3, NULL, QX_FLAG_SETVAR | QX_FLAG_ENUM | QX_FLAG_SKIP, NULL, NULL, voltronic_capability_set }, { "ups.start.battery", 0, voltronic_e_cap, "P%sC\r", "", 5, '(', "", 1, 3, NULL, QX_FLAG_SETVAR | QX_FLAG_ENUM | QX_FLAG_SKIP, NULL, NULL, voltronic_capability_set }, { "outlet.0.switchable", 0, voltronic_e_cap, "P%sJ\r", "", 5, '(', "", 1, 3, NULL, QX_FLAG_SETVAR | QX_FLAG_ENUM | QX_FLAG_SKIP, NULL, NULL, voltronic_capability_set }, /* Not available in NUT */ { "reset_to_default", 0, NULL, "PF\r", "", 5, '(', "", 1, 3, NULL, QX_FLAG_SETVAR | QX_FLAG_NONUT | QX_FLAG_SKIP, NULL, NULL, voltronic_capability_reset }, { "bypass_alarm", 0, voltronic_e_cap_nonut, "P%sP\r", "", 5, '(', "", 1, 3, NULL, QX_FLAG_SETVAR | QX_FLAG_ENUM | QX_FLAG_NONUT | QX_FLAG_SKIP, NULL, NULL, voltronic_capability_set_nonut }, { "battery_alarm", 0, voltronic_e_cap_nonut, "P%sB\r", "", 5, '(', "", 1, 3, NULL, QX_FLAG_SETVAR | QX_FLAG_ENUM | QX_FLAG_NONUT | QX_FLAG_SKIP, NULL, NULL, voltronic_capability_set_nonut }, { "bypass_when_off", 0, voltronic_e_cap_nonut, "P%sO\r", "", 5, '(', "", 1, 3, NULL, QX_FLAG_SETVAR | QX_FLAG_ENUM | QX_FLAG_NONUT | QX_FLAG_SKIP, NULL, NULL, voltronic_capability_set_nonut }, { "alarm_control", 0, voltronic_e_cap_nonut, "P%sA\r", "", 5, '(', "", 1, 3, NULL, QX_FLAG_SETVAR | QX_FLAG_ENUM | QX_FLAG_NONUT | QX_FLAG_SKIP, NULL, NULL, voltronic_capability_set_nonut }, { "converter_mode", 0, voltronic_e_cap_nonut, "P%sV\r", "", 5, '(', "", 1, 3, NULL, QX_FLAG_SETVAR | QX_FLAG_ENUM | QX_FLAG_NONUT | QX_FLAG_SKIP, NULL, NULL, voltronic_capability_set_nonut }, { "eco_mode", 0, voltronic_e_cap_nonut, "P%sE\r", "", 5, '(', "", 1, 3, NULL, QX_FLAG_SETVAR | QX_FLAG_ENUM | QX_FLAG_NONUT | QX_FLAG_SKIP, NULL, NULL, voltronic_capability_set_nonut }, { "battery_open_status_check", 0, voltronic_e_cap_nonut, "P%sD\r", "", 5, '(', "", 1, 3, NULL, QX_FLAG_SETVAR | QX_FLAG_ENUM | QX_FLAG_NONUT | QX_FLAG_SKIP, NULL, NULL, voltronic_capability_set_nonut }, { "bypass_forbidding", 0, voltronic_e_cap_nonut, "P%sF\r", "", 5, '(', "", 1, 3, NULL, QX_FLAG_SETVAR | QX_FLAG_ENUM | QX_FLAG_NONUT | QX_FLAG_SKIP, NULL, NULL, voltronic_capability_set_nonut }, { "site_fault_detection", 0, voltronic_e_cap_nonut, "P%sL\r", "", 5, '(', "", 1, 3, NULL, QX_FLAG_SETVAR | QX_FLAG_ENUM | QX_FLAG_NONUT | QX_FLAG_SKIP, NULL, NULL, voltronic_capability_set_nonut }, { "advanced_eco_mode", 0, voltronic_e_cap_nonut, "P%sN\r", "", 5, '(', "", 1, 3, NULL, QX_FLAG_SETVAR | QX_FLAG_ENUM | QX_FLAG_NONUT | QX_FLAG_SKIP, NULL, NULL, voltronic_capability_set_nonut }, { "constant_phase_angle", 0, voltronic_e_cap_nonut, "P%sQ\r", "", 5, '(', "", 1, 3, NULL, QX_FLAG_SETVAR | QX_FLAG_ENUM | QX_FLAG_NONUT | QX_FLAG_SKIP, NULL, NULL, voltronic_capability_set_nonut }, { "limited_runtime_on_battery", 0, voltronic_e_cap_nonut, "P%sW\r", "", 5, '(', "", 1, 3, NULL, QX_FLAG_SETVAR | QX_FLAG_ENUM | QX_FLAG_NONUT | QX_FLAG_SKIP, NULL, NULL, voltronic_capability_set_nonut }, /* Query UPS for programmable outlet (1-4) status * > [QSK1\r] * < [(1\r] <- if outlet is on -> (1 , if off -> (0 ; (NAK -> outlet is not programmable * 012 * 0 */ { "outlet.1.switchable", 0, NULL, "QSK1\r", "", 3, '(', "", 1, 1, "%s", QX_FLAG_SEMI_STATIC | QX_FLAG_SKIP, NULL, NULL, voltronic_outlet }, { "outlet.1.status", 0, NULL, "QSK1\r", "", 3, '(', "", 1, 1, "%s", QX_FLAG_SEMI_STATIC | QX_FLAG_SKIP, NULL, NULL, voltronic_outlet }, { "outlet.2.switchable", 0, NULL, "QSK2\r", "", 3, '(', "", 1, 1, "%s", QX_FLAG_SEMI_STATIC | QX_FLAG_SKIP, NULL, NULL, voltronic_outlet }, { "outlet.2.status", 0, NULL, "QSK2\r", "", 3, '(', "", 1, 1, "%s", QX_FLAG_SEMI_STATIC | QX_FLAG_SKIP, NULL, NULL, voltronic_outlet }, { "outlet.3.switchable", 0, NULL, "QSK3\r", "", 3, '(', "", 1, 1, "%s", QX_FLAG_SEMI_STATIC | QX_FLAG_SKIP, NULL, NULL, voltronic_outlet }, { "outlet.3.status", 0, NULL, "QSK3\r", "", 3, '(', "", 1, 1, "%s", QX_FLAG_SEMI_STATIC | QX_FLAG_SKIP, NULL, NULL, voltronic_outlet }, { "outlet.4.switchable", 0, NULL, "QSK4\r", "", 3, '(', "", 1, 1, "%s", QX_FLAG_SEMI_STATIC | QX_FLAG_SKIP, NULL, NULL, voltronic_outlet }, { "outlet.4.status", 0, NULL, "QSK4\r", "", 3, '(', "", 1, 1, "%s", QX_FLAG_SEMI_STATIC | QX_FLAG_SKIP, NULL, NULL, voltronic_outlet }, /* Query UPS for programmable outlet n (1-4) delay time before it shuts down the load when on battery mode * > [QSKT1\r] * < [(008\r] <- if delay time is set (by PSK[1-4]n) it'll report n (minutes) otherwise it'll report (NAK (also if outlet is not programmable) * 01234 * 0 */ { "outlet.1.delay.shutdown", ST_FLAG_RW, voltronic_r_outlet_delay, "QSKT1\r", "", 5, '(', "", 1, 3, "%.0f", QX_FLAG_SEMI_STATIC | QX_FLAG_RANGE | QX_FLAG_SKIP, NULL, NULL, voltronic_outlet_delay }, { "outlet.2.delay.shutdown", ST_FLAG_RW, voltronic_r_outlet_delay, "QSKT2\r", "", 5, '(', "", 1, 3, "%.0f", QX_FLAG_SEMI_STATIC | QX_FLAG_RANGE | QX_FLAG_SKIP, NULL, NULL, voltronic_outlet_delay }, { "outlet.3.delay.shutdown", ST_FLAG_RW, voltronic_r_outlet_delay, "QSKT3\r", "", 5, '(', "", 1, 3, "%.0f", QX_FLAG_SEMI_STATIC | QX_FLAG_RANGE | QX_FLAG_SKIP, NULL, NULL, voltronic_outlet_delay }, { "outlet.4.delay.shutdown", ST_FLAG_RW, voltronic_r_outlet_delay, "QSKT4\r", "", 5, '(', "", 1, 3, "%.0f", QX_FLAG_SEMI_STATIC | QX_FLAG_RANGE | QX_FLAG_SKIP, NULL, NULL, voltronic_outlet_delay }, /* Set delay time for programmable outlets * > [PSK1nnn\r] n = 0..9 * < [(ACK\r] * 01234 * 0 */ { "outlet.1.delay.shutdown", 0, voltronic_r_outlet_delay, "PSK1%03d\r", "", 5, '(', "", 1, 3, NULL, QX_FLAG_SETVAR | QX_FLAG_RANGE | QX_FLAG_SKIP, NULL, NULL, voltronic_outlet_delay_set }, { "outlet.2.delay.shutdown", 0, voltronic_r_outlet_delay, "PSK2%03d\r", "", 5, '(', "", 1, 3, NULL, QX_FLAG_SETVAR | QX_FLAG_RANGE | QX_FLAG_SKIP, NULL, NULL, voltronic_outlet_delay_set }, { "outlet.3.delay.shutdown", 0, voltronic_r_outlet_delay, "PSK3%03d\r", "", 5, '(', "", 1, 3, NULL, QX_FLAG_SETVAR | QX_FLAG_RANGE | QX_FLAG_SKIP, NULL, NULL, voltronic_outlet_delay_set }, { "outlet.4.delay.shutdown", 0, voltronic_r_outlet_delay, "PSK4%03d\r", "", 5, '(', "", 1, 3, NULL, QX_FLAG_SETVAR | QX_FLAG_RANGE | QX_FLAG_SKIP, NULL, NULL, voltronic_outlet_delay_set }, /* Query UPS for ECO Mode voltage limits * > [QHE\r] * < [(242 218\r] * 012345678 * 0 */ { "input.transfer.high", ST_FLAG_RW, voltronic_r_eco_volt_max, "QHE\r", "", 9, '(', "", 1, 3, "%.0f", QX_FLAG_SEMI_STATIC | QX_FLAG_RANGE | QX_FLAG_SKIP, NULL, NULL, voltronic_eco_volt }, { "input.transfer.low", ST_FLAG_RW, voltronic_r_eco_volt_min, "QHE\r", "", 9, '(', "", 5, 7, "%.0f", QX_FLAG_SEMI_STATIC | QX_FLAG_RANGE | QX_FLAG_SKIP, NULL, NULL, voltronic_eco_volt }, { "input.transfer.low.min", 0, NULL, "QHE\r", "", 9, '(', "", 5, 7, "%.0f", QX_FLAG_SEMI_STATIC | QX_FLAG_SKIP, NULL, NULL, voltronic_eco_volt_range }, { "input.transfer.low.max", 0, NULL, "QHE\r", "", 9, '(', "", 5, 7, "%.0f", QX_FLAG_SEMI_STATIC | QX_FLAG_SKIP, NULL, NULL, voltronic_eco_volt_range }, { "input.transfer.high.min", 0, NULL, "QHE\r", "", 9, '(', "", 1, 3, "%.0f", QX_FLAG_SEMI_STATIC | QX_FLAG_SKIP, NULL, NULL, voltronic_eco_volt_range }, { "input.transfer.high.max", 0, NULL, "QHE\r", "", 9, '(', "", 1, 3, "%.0f", QX_FLAG_SEMI_STATIC | QX_FLAG_SKIP, NULL, NULL, voltronic_eco_volt_range }, /* Set ECO Mode voltage limits * > [HEHnnn\r] > [HELnnn\r] n = 0..9 * < [(ACK\r] < [(ACK\r] * 01234 01234 * 0 0 */ { "input.transfer.high", 0, voltronic_r_eco_volt_max, "HEH%03.0f\r", "", 5, '(', "", 1, 3, NULL, QX_FLAG_SETVAR | QX_FLAG_RANGE | QX_FLAG_SKIP, NULL, NULL, voltronic_process_setvar }, { "input.transfer.low", 0, voltronic_r_eco_volt_min, "HEL%03.0f\r", "", 5, '(', "", 1, 3, NULL, QX_FLAG_SETVAR | QX_FLAG_RANGE | QX_FLAG_SKIP, NULL, NULL, voltronic_process_setvar }, /* Query UPS for ECO Mode frequency limits * > [QFRE\r] * < [(53.0 47.0\r] * 01234567890 * 0 1 */ { "input.frequency.high", ST_FLAG_RW, voltronic_r_eco_freq_max, "QFRE\r", "", 11, '(', "", 1, 4, "%.1f", QX_FLAG_SEMI_STATIC | QX_FLAG_RANGE | QX_FLAG_SKIP, NULL, NULL, voltronic_eco_freq }, { "input.frequency.low", ST_FLAG_RW, voltronic_r_eco_freq_min, "QFRE\r", "", 11, '(', "", 6, 9, "%.1f", QX_FLAG_SEMI_STATIC | QX_FLAG_RANGE | QX_FLAG_SKIP, NULL, NULL, voltronic_eco_freq }, /* Set ECO Mode frequency limits * > [FREHnn.n\r] > [FRELnn.n\r] n = 0..9 * < [(ACK\r] < [(ACK\r] * 01234 01234 * 0 0 */ { "input.frequency.high", 0, voltronic_r_eco_freq_max, "FREH%04.1f\r", "", 5, '(', "", 1, 3, NULL, QX_FLAG_SETVAR | QX_FLAG_RANGE | QX_FLAG_SKIP, NULL, NULL, voltronic_process_setvar }, { "input.frequency.low", 0, voltronic_r_eco_freq_min, "FREL%04.1f\r", "", 5, '(', "", 1, 3, NULL, QX_FLAG_SETVAR | QX_FLAG_RANGE | QX_FLAG_SKIP, NULL, NULL, voltronic_process_setvar }, /* Query UPS for Bypass Mode voltage limits * > [QBYV\r] * < [(264 170\r] * 012345678 * 0 */ { "max_bypass_volt", ST_FLAG_RW, voltronic_r_bypass_volt_max, "QBYV\r", "", 9, '(', "", 1, 3, "%.0f", QX_FLAG_SEMI_STATIC | QX_FLAG_RANGE | QX_FLAG_NONUT | QX_FLAG_SKIP, NULL, NULL, voltronic_bypass }, { "min_bypass_volt", ST_FLAG_RW, voltronic_r_bypass_volt_min, "QBYV\r", "", 9, '(', "", 5, 7, "%.0f", QX_FLAG_SEMI_STATIC | QX_FLAG_RANGE | QX_FLAG_NONUT | QX_FLAG_SKIP, NULL, NULL, voltronic_bypass }, /* Set Bypass Mode voltage limits * > [PHVnnn\r] > [PLVnnn\r] n = 0..9 * < [(ACK\r] < [(ACK\r] * 01234 01234 * 0 0 */ { "max_bypass_volt", 0, voltronic_r_bypass_volt_max, "PHV%03.0f\r", "", 5, '(', "", 1, 3, NULL, QX_FLAG_SETVAR | QX_FLAG_RANGE | QX_FLAG_NONUT | QX_FLAG_SKIP, NULL, NULL, voltronic_process_setvar }, { "min_bypass_volt", 0, voltronic_r_bypass_volt_min, "PLV%03.0f\r", "", 5, '(', "", 1, 3, NULL, QX_FLAG_SETVAR | QX_FLAG_RANGE | QX_FLAG_NONUT | QX_FLAG_SKIP, NULL, NULL, voltronic_process_setvar }, /* Query UPS for Bypass Mode frequency limits * > [QBYF\r] * < [(53.0 47.0\r] * 01234567890 * 0 1 */ { "max_bypass_freq", ST_FLAG_RW, voltronic_r_bypass_freq_max, "QBYF\r", "", 11, '(', "", 1, 4, "%.1f", QX_FLAG_SEMI_STATIC | QX_FLAG_RANGE | QX_FLAG_NONUT | QX_FLAG_SKIP, NULL, NULL, voltronic_bypass }, { "min_bypass_freq", ST_FLAG_RW, voltronic_r_bypass_freq_min, "QBYF\r", "", 11, '(', "", 6, 9, "%.1f", QX_FLAG_SEMI_STATIC | QX_FLAG_RANGE | QX_FLAG_NONUT | QX_FLAG_SKIP, NULL, NULL, voltronic_bypass }, /* Set Bypass Mode frequency limits * > [PGFnn.n\r] > [PSFnn.n\r] n = 0..9 * < [(ACK\r] < [(ACK\r] * 01234 01234 * 0 0 */ { "max_bypass_freq", 0, voltronic_r_bypass_freq_max, "PGF%04.1f\r", "", 5, '(', "", 1, 3, NULL, QX_FLAG_SETVAR | QX_FLAG_RANGE | QX_FLAG_NONUT | QX_FLAG_SKIP, NULL, NULL, voltronic_process_setvar }, { "min_bypass_freq", 0, voltronic_r_bypass_freq_min, "PSF%04.1f\r", "", 5, '(', "", 1, 3, NULL, QX_FLAG_SETVAR | QX_FLAG_RANGE | QX_FLAG_NONUT | QX_FLAG_SKIP, NULL, NULL, voltronic_process_setvar }, /* Set number of batteries that make a pack to n (integer, 1-9). NOTE: changing the number of batteries will change the UPS's estimation on battery charge/runtime * > [BATNn\r] * < [(ACK\r] * 01234 * 0 */ { "battery_number", 0, voltronic_r_batt_numb, "BATN%1.0f\r", "", 5, '(', "", 1, 3, NULL, QX_FLAG_SETVAR | QX_FLAG_RANGE | QX_FLAG_NONUT, NULL, NULL, voltronic_process_setvar }, /* Set number of battery packs in parallel to n (integer, 01-99). NOTE: changing the number of battery packs will change the UPS's estimation on battery charge/runtime * > [BATGNn\r] * < [(ACK\r] * 01234 * 0 */ { "battery.packs", 0, voltronic_r_batt_packs, "BATGN%02.0f\r", "", 5, '(', "", 1, 3, NULL, QX_FLAG_SETVAR | QX_FLAG_RANGE, NULL, NULL, voltronic_process_setvar }, /* Query UPS for battery type (Only P31) * > [QBT\r] * < [(01\r] <- 00="Li", 01="Flooded" or 02="AGM" * 0123 * 0 */ { "battery.type", ST_FLAG_RW, voltronic_e_batt_type, "QBT\r", "", 4, '(', "", 1, 2, "%s", QX_FLAG_SEMI_STATIC | QX_FLAG_ENUM | QX_FLAG_SKIP, NULL, NULL, voltronic_p31b }, /* Set battery type (Only P31) * > [PBTnn\r] nn = 00/01/02 * < [(ACK\r] * 01234 * 0 */ { "battery.type", 0, voltronic_e_batt_type, "PBT%02.0f\r", "", 5, '(', "", 1, 3, NULL, QX_FLAG_SETVAR | QX_FLAG_ENUM | QX_FLAG_SKIP, NULL, NULL, voltronic_p31b_set }, /* Query UPS for device grid working range (Only P31) * > [QGR\r] * < [(01\r] <- 00=Appliance, 01=UPS * 0123 * 0 */ { "work_range_type", ST_FLAG_RW, voltronic_e_work_range, "QGR\r", "", 4, '(', "", 1, 2, "%s", QX_FLAG_SEMI_STATIC | QX_FLAG_ENUM | QX_FLAG_NONUT | QX_FLAG_SKIP, NULL, NULL, voltronic_p31g }, /* Set device grid working range type (Only P31) * > [PBTnn\r] nn = 00/01 * < [(ACK\r] * 01234 * 0 */ { "work_range_type", 0, voltronic_e_work_range, "PGR%02.0f\r", "", 5, '(', "", 1, 3, NULL, QX_FLAG_SETVAR | QX_FLAG_ENUM | QX_FLAG_NONUT | QX_FLAG_SKIP, NULL, NULL, voltronic_p31g_set }, /* Query UPS for battery low voltage * > [RE0\r] * < [#20\r] * 012 * 0 */ { "battery.voltage.low", ST_FLAG_RW, voltronic_r_batt_low, "RE0\r", "", 3, '#', "", 1, 2, "%.1f", QX_FLAG_SEMI_STATIC | QX_FLAG_RANGE, NULL, NULL, NULL }, /* Set voltage for battery low to n (integer, 20..24/20..28). NOTE: changing the battery low voltage will change the UPS's estimation on battery charge/runtime * > [W0En\r] * < [(ACK\r] * 01234 * 0 */ { "battery.voltage.low", 0, voltronic_r_batt_low, "W0E%02.0f\r", "", 5, '(', "", 1, 3, NULL, QX_FLAG_SETVAR | QX_FLAG_RANGE, NULL, NULL, voltronic_process_setvar }, /* Query UPS for Phase Angle * > [QPD\r] * < [(000 120\r] <- Input Phase Angle - Output Phase Angle * 012345678 * 0 */ { "input_phase_angle", 0, NULL, "QPD\r", "", 9, '(', "", 1, 3, "%03d", QX_FLAG_SEMI_STATIC | QX_FLAG_NONUT, NULL, NULL, voltronic_phase }, { "output_phase_angle", ST_FLAG_RW, voltronic_e_phase, "QPD\r", "", 9, '(', "", 5, 7, "%03d", QX_FLAG_SEMI_STATIC | QX_FLAG_ENUM | QX_FLAG_NONUT, NULL, NULL, voltronic_phase }, /* Set output phase angle * > [PPDn\r] n = (000, 120, 180 or 240) * < [(ACK\r] * 01234 * 0 */ { "output_phase_angle", 0, voltronic_e_phase, "PPD%03.0f\r", "", 5, '(', "", 1, 3, NULL, QX_FLAG_SETVAR | QX_FLAG_ENUM | QX_FLAG_NONUT | QX_FLAG_SKIP, NULL, NULL, voltronic_phase_set }, /* Query UPS for master/slave for a system of UPSes in parallel * > [QPAR\r] * < [(001\r] <- 001 for master UPS, 002 and 003 for slave UPSes * 01234 * 0 */ { "voltronic_parallel", 0, NULL, "QPAR\r", "", 5, '(', "", 1, 3, "%s", QX_FLAG_STATIC | QX_FLAG_NONUT, NULL, NULL, voltronic_parallel }, /* Query UPS for ?? * > [QBDR\r] * < [(1234\r] <- unknown reply - My UPS (NAK at me * 012345 * 0 */ { "unknown.7", 0, NULL, "QBDR\r", "", 5, '(', "", 1, 0, "%s", QX_FLAG_STATIC | QX_FLAG_NONUT | QX_FLAG_SKIP, NULL, NULL, NULL }, /* Instant commands */ { "load.off", 0, NULL, "SOFF\r", "", 5, '(', "", 1, 3, NULL, QX_FLAG_CMD, NULL, NULL, NULL }, { "load.on", 0, NULL, "SON\r", "", 5, '(', "", 1, 3, NULL, QX_FLAG_CMD, NULL, NULL, NULL }, { "shutdown.return", 0, NULL, "S%s\r", "", 5, '(', "", 1, 3, NULL, QX_FLAG_CMD, NULL, NULL, voltronic_process_command }, { "shutdown.stayoff", 0, NULL, "S%sR0000\r", "", 5, '(', "", 1, 3, NULL, QX_FLAG_CMD, NULL, NULL, voltronic_process_command }, { "shutdown.stop", 0, NULL, "CS\r", "", 5, '(', "", 1, 3, NULL, QX_FLAG_CMD, NULL, NULL, NULL }, { "test.battery.start", 0, NULL, "T%s\r", "", 5, '(', "", 1, 3, NULL, QX_FLAG_CMD, NULL, NULL, voltronic_process_command }, { "test.battery.start.deep", 0, NULL, "TL\r", "", 5, '(', "", 1, 3, NULL, QX_FLAG_CMD, NULL, NULL, NULL }, { "test.battery.start.quick", 0, NULL, "T\r", "", 5, '(', "", 1, 3, NULL, QX_FLAG_CMD, NULL, NULL, NULL }, { "test.battery.stop", 0, NULL, "CT\r", "", 5, '(', "", 1, 3, NULL, QX_FLAG_CMD, NULL, NULL, NULL }, { "beeper.toggle", 0, NULL, "BZ%s\r", "", 5, '(', "", 1, 3, NULL, QX_FLAG_CMD, NULL, NULL, voltronic_process_command }, /* Enable/disable beeper: unskipped if the UPS can control alarm (capability) */ { "beeper.enable", 0, NULL, "PEA\r", "", 5, '(', "", 1, 3, NULL, QX_FLAG_CMD | QX_FLAG_SKIP, NULL, NULL, NULL }, { "beeper.disable", 0, NULL, "PDA\r", "", 5, '(', "", 1, 3, NULL, QX_FLAG_CMD | QX_FLAG_SKIP, NULL, NULL, NULL }, /* Outlet control: unskipped if the outlets are manageable */ { "outlet.1.load.off", 0, NULL, "SKOFF1\r", "", 5, '(', "", 1, 3, NULL, QX_FLAG_CMD | QX_FLAG_SKIP, NULL, NULL, NULL }, { "outlet.1.load.on", 0, NULL, "SKON1\r", "", 5, '(', "", 1, 3, NULL, QX_FLAG_CMD | QX_FLAG_SKIP, NULL, NULL, NULL }, { "outlet.2.load.off", 0, NULL, "SKOFF2\r", "", 5, '(', "", 1, 3, NULL, QX_FLAG_CMD | QX_FLAG_SKIP, NULL, NULL, NULL }, { "outlet.2.load.on", 0, NULL, "SKON2\r", "", 5, '(', "", 1, 3, NULL, QX_FLAG_CMD | QX_FLAG_SKIP, NULL, NULL, NULL }, { "outlet.3.load.off", 0, NULL, "SKOFF3\r", "", 5, '(', "", 1, 3, NULL, QX_FLAG_CMD | QX_FLAG_SKIP, NULL, NULL, NULL }, { "outlet.3.load.on", 0, NULL, "SKON3\r", "", 5, '(', "", 1, 3, NULL, QX_FLAG_CMD | QX_FLAG_SKIP, NULL, NULL, NULL }, { "outlet.4.load.off", 0, NULL, "SKOFF4\r", "", 5, '(', "", 1, 3, NULL, QX_FLAG_CMD | QX_FLAG_SKIP, NULL, NULL, NULL }, { "outlet.4.load.on", 0, NULL, "SKON4\r", "", 5, '(', "", 1, 3, NULL, QX_FLAG_CMD | QX_FLAG_SKIP, NULL, NULL, NULL }, /* Bypass: unskipped if the UPS is capable of ECO Mode */ { "bypass.start", 0, NULL, "PEE\r", "", 5, '(', "", 1, 3, NULL, QX_FLAG_CMD | QX_FLAG_SKIP, NULL, NULL, NULL }, { "bypass.stop", 0, NULL, "PDE\r", "", 5, '(', "", 1, 3, NULL, QX_FLAG_CMD | QX_FLAG_SKIP, NULL, NULL, NULL }, /* Server-side settable vars */ { "ups.delay.start", ST_FLAG_RW, voltronic_r_ondelay, NULL, "", 0, 0, "", 0, 0, DEFAULT_ONDELAY, QX_FLAG_ABSENT | QX_FLAG_SETVAR | QX_FLAG_RANGE, NULL, NULL, voltronic_process_setvar }, { "ups.delay.shutdown", ST_FLAG_RW, voltronic_r_offdelay, NULL, "", 0, 0, "", 0, 0, DEFAULT_OFFDELAY, QX_FLAG_ABSENT | QX_FLAG_SETVAR | QX_FLAG_RANGE, NULL, NULL, voltronic_process_setvar }, /* End of structure. */ { NULL, 0, NULL, NULL, "", 0, 0, "", 0, 0, NULL, 0, NULL, NULL, NULL } }; /* == Testing table == */ #ifdef TESTING static testing_t voltronic_testing[] = { { "QGS\r", "(234.9 50.0 229.8 50.0 000.0 00A 369.1 ---.- 026.5 ---.- 018.8 100000000001\r", -1 }, { "QPI\r", "(PI01\r", -1 }, { "QRI\r", "(230.0 004 024.0 50.0\r", -1 }, { "QMF\r", "(#####VOLTRONIC\r", -1 }, { "I\r", "#------------- ------ VT12046Q \r", -1 }, { "F\r", "#220.0 000 024.0 50.0\r", -1 }, { "QMD\r", "(#######OLHVT1K0 ###1000 80 2/2 230 230 02 12.0\r", -1 }, { "QFS\r", "(14 212.1 50.0 005.6 49.9 006 010.6 343.8 ---.- 026.2 021.8 01101100\r", -1 }, { "QMOD\r", "(S\r", -1 }, { "QVFW\r", "(VERFW:00322.02\r", -1 }, { "QID\r", "(685653211455\r", -1 }, { "QBV\r", "(026.5 02 01 068 255\r", -1 }, { "QFLAG\r", "(EpashcjDbroegfl\r", -1 }, { "QWS\r", "(0000000000000000000000000000000000000000000000000000000001000001\r", -1 }, { "QHE\r", "(242 218\r", -1 }, { "QBYV\r", "(264 170\r", -1 }, { "QBYF\r", "(53.0 47.0\r", -1 }, { "QSK1\r", "(1\r", -1 }, { "QSK2\r", "(0\r", -1 }, { "QSK3\r", "(1\r", -1 }, { "QSK4\r", "(NAK\r", -1 }, { "QSKT1\r", "(008\r", -1 }, { "QSKT2\r", "(012\r", -1 }, { "QSKT3\r", "(NAK\r", -1 }, { "QSKT4\r", "(007\r", -1 }, { "RE0\r", "#20\r", -1 }, { "W0E24\r", "(ACK\r", -1 }, { "PF\r", "(ACK\r", -1 }, { "PEA\r", "(ACK\r", -1 }, { "PDR\r", "(NAK\r", -1 }, { "HEH250\r", "(ACK\r", -1 }, { "HEL210\r", "(ACK\r", -1 }, { "PHV260\r", "(NAK\r", -1 }, { "PLV190\r", "(ACK\r", -1 }, { "PGF51.0\r", "(NAK\r", -1 }, { "PSF47.5\r", "(ACK\r", -1 }, { "BATN2\r", "(ACK\r", -1 }, { "BATGN04\r", "(ACK\r", -1 }, { "QBT\r", "(01\r", -1 }, { "PBT02\r", "(ACK\r", -1 }, { "QGR\r", "(00\r", -1 }, { "PGR01\r", "(ACK\r", -1 }, { "PSK1008\r", "(ACK\r", -1 }, { "PSK3987\r", "(ACK\r", -1 }, { "PSK2009\r", "(ACK\r", -1 }, { "PSK4012\r", "(ACK\r", -1 }, { "Q3PV\r", "(123.4 456.4 789.4 012.4 323.4 223.4\r", -1 }, { "Q3OV\r", "(253.4 163.4 023.4 143.4 103.4 523.4\r", -1 }, { "Q3OC\r", "(109 069 023\r", -1 }, { "Q3LD\r", "(005 033 089\r", -1 }, { "Q3YV\r", "(303.4 245.4 126.4 222.4 293.4 321.4\r", -1 }, { "Q3PC\r", "(002 023 051\r", -1 }, { "SOFF\r", "(NAK\r", -1 }, { "SON\r", "(ACK\r", -1 }, { "T\r", "(NAK\r", -1 }, { "TL\r", "(ACK\r", -1 }, { "CS\r", "(ACK\r", -1 }, { "CT\r", "(NAK\r", -1 }, { "BZOFF\r", "(ACK\r", -1 }, { "BZON\r", "(ACK\r", -1 }, { "S.3R0002\r", "(ACK\r", -1 }, { "S02R0024\r", "(NAK\r", -1 }, { "S.5\r", "(ACK\r", -1 }, { "T.3\r", "(ACK\r", -1 }, { "T02\r", "(NAK\r", -1 }, { "SKON1\r", "(ACK\r", -1 }, { "SKOFF1\r", "(NAK\r", -1 }, { "SKON2\r", "(ACK\r", -1 }, { "SKOFF2\r", "(ACK\r", -1 }, { "SKON3\r", "(NAK\r", -1 }, { "SKOFF3\r", "(ACK\r", -1 }, { "SKON4\r", "(NAK\r", -1 }, { "SKOFF4\r", "(NAK\r", -1 }, { "QPAR\r", "(003\r", -1 }, { "QPD\r", "(000 240\r", -1 }, { "PPD120\r", "(ACK\r", -1 }, { "QLDL\r", "(005 080\r", -1 }, { "QBDR\r", "(1234\r", -1 }, { "QFRE\r", "(50.0 00.0\r", -1 }, { "FREH54.0\r", "(ACK\r", -1 }, { "FREL47.0\r", "(ACK\r", -1 }, { "PEP\r", "(ACK\r", -1 }, { "PDP\r", "(ACK\r", -1 }, { "PEB\r", "(ACK\r", -1 }, { "PDB\r", "(ACK\r", -1 }, { "PER\r", "(NAK\r", -1 }, { "PDR\r", "(NAK\r", -1 }, { "PEO\r", "(ACK\r", -1 }, { "PDO\r", "(ACK\r", -1 }, { "PEA\r", "(ACK\r", -1 }, { "PDA\r", "(ACK\r", -1 }, { "PES\r", "(ACK\r", -1 }, { "PDS\r", "(ACK\r", -1 }, { "PEV\r", "(ACK\r", -1 }, { "PDV\r", "(ACK\r", -1 }, { "PEE\r", "(ACK\r", -1 }, { "PDE\r", "(ACK\r", -1 }, { "PEG\r", "(ACK\r", -1 }, { "PDG\r", "(NAK\r", -1 }, { "PED\r", "(ACK\r", -1 }, { "PDD\r", "(ACK\r", -1 }, { "PEC\r", "(ACK\r", -1 }, { "PDC\r", "(NAK\r", -1 }, { "PEF\r", "(NAK\r", -1 }, { "PDF\r", "(ACK\r", -1 }, { "PEJ\r", "(NAK\r", -1 }, { "PDJ\r", "(ACK\r", -1 }, { "PEL\r", "(ACK\r", -1 }, { "PDL\r", "(ACK\r", -1 }, { "PEN\r", "(ACK\r", -1 }, { "PDN\r", "(ACK\r", -1 }, { "PEQ\r", "(ACK\r", -1 }, { "PDQ\r", "(ACK\r", -1 }, { "PEW\r", "(NAK\r", -1 }, { "PDW\r", "(ACK\r", -1 }, { NULL } }; #endif /* TESTING */ /* == Support functions == */ /* This function allows the subdriver to "claim" a device: return 1 if the device is supported by this subdriver, else 0. */ static int voltronic_claim(void) { /* We need at least QGS and QPI to run this subdriver */ item_t *item = find_nut_info("input.voltage", 0, 0); /* Don't know what happened */ if (!item) return 0; /* No reply/Unable to get value */ if (qx_process(item, NULL)) return 0; /* Unable to process value */ if (ups_infoval_set(item) != 1) return 0; /* UPS Protocol */ item = find_nut_info("ups.firmware.aux", 0, 0); /* Don't know what happened */ if (!item) { dstate_delinfo("input.voltage"); return 0; } /* No reply/Unable to get value */ if (qx_process(item, NULL)) { dstate_delinfo("input.voltage"); return 0; } /* Unable to process value/Protocol out of range */ if (ups_infoval_set(item) != 1) { dstate_delinfo("input.voltage"); return 0; } return 1; } /* Subdriver-specific flags/vars */ static void voltronic_makevartable(void) { /* Capability vars */ addvar(VAR_FLAG, "reset_to_default", "Reset capability options and their limits to safe default values"); addvar(VAR_VALUE, "bypass_alarm", "Alarm (BEEP!) at Bypass Mode [enabled/disabled]"); addvar(VAR_VALUE, "battery_alarm", "Alarm (BEEP!) at Battery Mode [enabled/disabled]"); addvar(VAR_VALUE, "bypass_when_off", "Bypass when the UPS is Off [enabled/disabled]"); addvar(VAR_VALUE, "alarm_control", "Alarm (BEEP!) Control [enabled/disabled]"); addvar(VAR_VALUE, "converter_mode", "Converter Mode [enabled/disabled]"); addvar(VAR_VALUE, "eco_mode", "ECO Mode [enabled/disabled]"); addvar(VAR_VALUE, "battery_open_status_check", "Battery Open Status Check [enabled/disabled]"); addvar(VAR_VALUE, "bypass_forbidding", "Bypass not allowed (Bypass Forbidding) [enabled/disabled]"); addvar(VAR_VALUE, "site_fault_detection", "Site fault detection [enabled/disabled]"); addvar(VAR_VALUE, "advanced_eco_mode", "Advanced ECO Mode [enabled/disabled]"); addvar(VAR_VALUE, "constant_phase_angle", "Constant Phase Angle Function (Output and input phase angles are not equal) [enabled/disabled]"); addvar(VAR_VALUE, "limited_runtime_on_battery", "Limited runtime on battery mode [enabled/disabled]"); /* Bypass Mode frequency/voltage limits */ addvar(VAR_VALUE, "max_bypass_volt", "Maximum voltage for Bypass Mode"); addvar(VAR_VALUE, "min_bypass_volt", "Minimum voltage for Bypass Mode"); addvar(VAR_VALUE, "max_bypass_freq", "Maximum frequency for Bypass Mode"); addvar(VAR_VALUE, "min_bypass_freq", "Minimum frequency for Bypass Mode"); /* Device grid working range type for P31 UPSes */ addvar(VAR_VALUE, "work_range_type", "Device grid working range for P31 UPSes [Appliance/UPS]"); /* Output phase angle */ addvar(VAR_VALUE, "output_phase_angle", "Change output phase angle to the provided value [000, 120, 180, 240]°"); /* Number of batteries */ addvar(VAR_VALUE, "battery_number", "Set number of batteries that make a pack to n (integer, 1-9)"); /* For testing purposes */ addvar(VAR_FLAG, "testing", "If invoked the driver will exec also commands that still need testing"); } /* Unskip vars according to protocol used by the UPS */ static void voltronic_massive_unskip(const long protocol) { item_t *item; for (item = voltronic_qx2nut; item->info_type != NULL; item++) { if (!item->command) continue; if ( /* == Multiphase UPSes == */ /* P09 */ (protocol == 9 && ( /* (!strcasecmp(item->info_type, "input.L1-L3.voltage") && item->from == 25) || *//* Not unskipped because P09 should be 2-phase input/output */ /* (!strcasecmp(item->info_type, "input.L2-L3.voltage") && item->from == 31) || *//* Not unskipped because P09 should be 2-phase input/output */ /* (!strcasecmp(item->info_type, "output.L1-L3.voltage") && item->from == 25) || *//* Not unskipped because P09 should be 2-phase input/output */ /* (!strcasecmp(item->info_type, "output.L2-L3.voltage") && item->from == 31) || *//* Not unskipped because P09 should be 2-phase input/output */ (!strcasecmp(item->info_type, "output.bypass.L1-N.voltage") && item->answer_len == 19) || (!strcasecmp(item->info_type, "output.bypass.L2-N.voltage") && item->answer_len == 19)/* || (!strcasecmp(item->info_type, "output.bypass.L3-N.voltage") && item->answer_len == 19) *//* Not unskipped because P09 should be 2-phase input/output */ )) || /* P10 */ (protocol == 10 && ( !strcasecmp(item->info_type, "output.L3-N.voltage") || (!strcasecmp(item->info_type, "output.L2-L3.voltage") && item->from == 25) || (!strcasecmp(item->info_type, "output.L1-L3.voltage") && item->from == 31) || (!strcasecmp(item->info_type, "output.bypass.L1-N.voltage") && item->answer_len == 37) || (!strcasecmp(item->info_type, "output.bypass.L2-N.voltage") && item->answer_len == 37) || (!strcasecmp(item->info_type, "output.bypass.L3-N.voltage") && item->answer_len == 37) || !strcasecmp(item->info_type, "output.bypass.L1-L2.voltage") || !strcasecmp(item->info_type, "output.bypass.L2-L3.voltage") || !strcasecmp(item->info_type, "output.bypass.L1-L3.voltage") || !strcasecmp(item->info_type, "output.L3.current") || !strcasecmp(item->info_type, "output.L3.power.percent") )) || /* P09-P10 */ ((protocol == 9 || protocol == 10) && ( !strcasecmp(item->info_type, "output.L1-N.voltage") || !strcasecmp(item->info_type, "output.L2-N.voltage") ||/* !strcasecmp(item->info_type, "output.L3-N.voltage") || *//* Not unskipped because P09 should be 2-phase input/output */ !strcasecmp(item->info_type, "output.L1-L2.voltage") || !strcasecmp(item->info_type, "output.L1.current") || !strcasecmp(item->info_type, "output.L2.current") ||/* !strcasecmp(item->info_type, "output.L3.current") || *//* Not unskipped because P09 should be 2-phase input/output */ !strcasecmp(item->info_type, "output.L1.power.percent") || !strcasecmp(item->info_type, "output.L2.power.percent")/* || !strcasecmp(item->info_type, "output.L3.power.percent") *//* Not unskipped because P09 should be 2-phase input/output */ )) || /* P03-P09-P10 */ ((protocol == 3 || protocol == 9 || protocol == 10) && ( !strcasecmp(item->info_type, "input.L1-N.voltage") || !strcasecmp(item->info_type, "input.L2-N.voltage") ||/* !strcasecmp(item->info_type, "input.L3-N.voltage") ||*//* Not unskipped because P09 should be 2-phase input/output */ !strcasecmp(item->info_type, "input.L1-L2.voltage") || !strcasecmp(item->info_type, "input.L1.current") || !strcasecmp(item->info_type, "input.L2.current")/* || !strcasecmp(item->info_type, "input.L3.current")*//* Not unskipped because P09 should be 2-phase input/output */ )) || /* P03-P10 */ ((protocol == 3 || protocol == 10) && ( !strcasecmp(item->info_type, "input.L3-N.voltage") || (!strcasecmp(item->info_type, "input.L2-L3.voltage") && item->from == 25) || (!strcasecmp(item->info_type, "input.L1-L3.voltage") && item->from == 31) || !strcasecmp(item->info_type, "input.L3.current") )) || /* == P31 battery type/device grid working range == */ (protocol == 31 && ( !strcasecmp(item->info_type, "battery.type") || (!strcasecmp(item->info_type, "work_range_type") && !(item->qxflags & QX_FLAG_SETVAR)) || (!strcasecmp(item->info_type, "work_range_type") && (item->qxflags & QX_FLAG_SETVAR) && getval(item->info_type)) )) || /* == ByPass limits: all but P00/P08/P31 == */ (protocol != 0 && protocol != 8 && protocol != 31 && ( (!strcasecmp(item->info_type, "max_bypass_volt") && !(item->qxflags & QX_FLAG_SETVAR)) || (!strcasecmp(item->info_type, "min_bypass_volt") && !(item->qxflags & QX_FLAG_SETVAR)) || (!strcasecmp(item->info_type, "max_bypass_freq") && !(item->qxflags & QX_FLAG_SETVAR)) || (!strcasecmp(item->info_type, "min_bypass_freq") && !(item->qxflags & QX_FLAG_SETVAR)) )) || /* == Reset capabilities options to safe default values == */ (!strcasecmp(item->info_type, "reset_to_default") && testvar("reset_to_default")) || /* == QBDR (unknown) == */ (!strcasecmp(item->info_type, "unknown.7") && testvar("testing")) ) { item->qxflags &= ~QX_FLAG_SKIP; } } } /* == Preprocess functions == */ /* *SETVAR(/NONUT)* Preprocess setvars */ static int voltronic_process_setvar(item_t *item, char *value, const size_t valuelen) { double val; if (!strlen(value)) { upsdebugx(2, "%s: value not given for %s", __func__, item->info_type); return -1; } val = strtod(value, NULL); if (!strcasecmp(item->info_type, "ups.delay.start")) { /* Truncate to minute */ val -= ((int)val % 60); snprintf(value, valuelen, "%.0f", val); return 0; } else if (!strcasecmp(item->info_type, "ups.delay.shutdown")) { /* Truncate to nearest setable value */ if (val < 60) { val -= ((int)val % 6); } else { val -= ((int)val % 60); } snprintf(value, valuelen, "%.0f", val); return 0; } else if (!strcasecmp(item->info_type, "max_bypass_freq")) { if (d_equal(val, max_bypass_freq)) { upslogx(LOG_INFO, "%s is already set to %.1f", item->info_type, val); return -1; } } else if (!strcasecmp(item->info_type, "min_bypass_freq")) { if (d_equal(val, min_bypass_freq)) { upslogx(LOG_INFO, "%s is already set to %.1f", item->info_type, val); return -1; } } else if (!strcasecmp(item->info_type, "max_bypass_volt")) { if (d_equal(val, max_bypass_volt)) { upslogx(LOG_INFO, "%s is already set to %.0f", item->info_type, val); return -1; } } else if (!strcasecmp(item->info_type, "min_bypass_volt")) { if (d_equal(val, min_bypass_volt)) { upslogx(LOG_INFO, "%s is already set to %.0f", item->info_type, val); return -1; } } else if (!strcasecmp(item->info_type, "battery_number")) { if (d_equal(val, battery_number)) { upslogx(LOG_INFO, "%s is already set to %.0f", item->info_type, val); return -1; } } #ifdef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL #pragma GCC diagnostic push #endif #ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL #pragma GCC diagnostic ignored "-Wformat-nonliteral" #endif #ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_FORMAT_SECURITY #pragma GCC diagnostic ignored "-Wformat-security" #endif snprintf(value, valuelen, item->command, val); #ifdef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL #pragma GCC diagnostic pop #endif return 0; } /* *CMD* Preprocess instant commands */ static int voltronic_process_command(item_t *item, char *value, const size_t valuelen) { char buf[SMALLBUF] = ""; if (!strcasecmp(item->info_type, "shutdown.return")) { /* Sn: Shutdown after n minutes and then turn on when mains is back * SnRm: Shutdown after n minutes and then turn on after m minutes * Accepted values for n: .2 -> .9 , 01 -> 99 * Accepted values for m: 0001 -> 9999 */ long offdelay = strtol(dstate_getinfo("ups.delay.shutdown"), NULL, 10), ondelay = strtol(dstate_getinfo("ups.delay.start"), NULL, 10) / 60; if (ondelay == 0) { if (offdelay < 60) { snprintf(buf, sizeof(buf), ".%ld", offdelay / 6); } else { snprintf(buf, sizeof(buf), "%02ld", offdelay / 60); } } else if (offdelay < 60) { snprintf(buf, sizeof(buf), ".%ldR%04ld", offdelay / 6, ondelay); } else { snprintf(buf, sizeof(buf), "%02ldR%04ld", offdelay / 60, ondelay); } } else if (!strcasecmp(item->info_type, "shutdown.stayoff")) { /* SnR0000 * Shutdown after n minutes and stay off * Accepted values for n: .2 -> .9 , 01 -> 99 */ long offdelay = strtol(dstate_getinfo("ups.delay.shutdown"), NULL, 10); if (offdelay < 60) { snprintf(buf, sizeof(buf), ".%ld", offdelay / 6); } else { snprintf(buf, sizeof(buf), "%02ld", offdelay / 60); } } else if (!strcasecmp(item->info_type, "test.battery.start")) { /* Accepted values for test time: .2 -> .9 (.2=12sec ..), 01 -> 99 (minutes) * -> you have to invoke test.battery.start + number of seconds [12..5940] */ long delay; if (strlen(value) != strspn(value, "0123456789")) { upslogx(LOG_ERR, "%s: non numerical value [%s]", item->info_type, value); return -1; } delay = (strlen(value) > 0) ? strtol(value, NULL, 10) : 600; if ((delay < 12) || (delay > 5940)) { upslogx(LOG_ERR, "%s: battery test time '%ld' out of range [12..5940] seconds", item->info_type, delay); return -1; } /* test time < 1 minute */ if (delay < 60) { delay = delay / 6; snprintf(buf, sizeof(buf), ".%ld", delay); /* test time > 1 minute */ } else { delay = delay / 60; snprintf(buf, sizeof(buf), "%02ld", delay); } } else if (!strcasecmp(item->info_type, "beeper.toggle")) { const char *beeper_status = dstate_getinfo("ups.beeper.status"); /* If the UPS is beeping then we can call BZOFF; if we previously set BZOFF we can call BZON, provided that the beeper is not disabled */ /* The UPS can disable/enable alarm (from UPS capability) */ if (alarm_control) { if (!strcmp(beeper_status, "enabled")) { snprintf(buf, sizeof(buf), "OFF"); } else if (!strcmp(beeper_status, "muted")) { snprintf(buf, sizeof(buf), "ON"); /* Beeper disabled */ } else { upslogx(LOG_INFO, "The beeper is already disabled"); return -1; } /* The UPS can't disable/enable alarm (from UPS capability) */ } else { if (!strcmp(beeper_status, "enabled")) { snprintf(buf, sizeof(buf), "OFF"); } else if (!strcmp(beeper_status, "disabled")) { snprintf(buf, sizeof(buf), "ON"); } } } else { /* Don't know what happened */ return -1; } #ifdef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL #pragma GCC diagnostic push #endif #ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL #pragma GCC diagnostic ignored "-Wformat-nonliteral" #endif #ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_FORMAT_SECURITY #pragma GCC diagnostic ignored "-Wformat-security" #endif snprintf(value, valuelen, item->command, buf); #ifdef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL #pragma GCC diagnostic pop #endif return 0; } /* UPS capabilities */ static int voltronic_capability(item_t *item, char *value, const size_t valuelen) { char rawval[SMALLBUF], *enabled, *disabled, *val = NULL, *saveptr = NULL; item_t *unskip; snprintf(rawval, sizeof(rawval), "%s", item->value); enabled = strtok_r(rawval+1, "D", &saveptr); disabled = strtok_r(NULL, "\0", &saveptr); if (!enabled && !disabled) { upsdebugx(2, "%s: parsing failed", __func__); return -1; } enabled = enabled ? enabled : ""; disabled = disabled ? disabled : ""; /* NONUT items */ if (!strcasecmp(item->info_type, "bypass_alarm")) { if (strchr(enabled, 'p')) { val = bypass_alarm = "enabled"; } else if (strchr(disabled, 'p')) { val = bypass_alarm = "disabled"; } } else if (!strcasecmp(item->info_type, "battery_alarm")) { if (strchr(enabled, 'b')) { val = battery_alarm = "enabled"; } else if (strchr(disabled, 'b')) { val = battery_alarm = "disabled"; } } else if (!strcasecmp(item->info_type, "bypass_when_off")) { if (strchr(enabled, 'o')) { val = bypass_when_off = "enabled"; } else if (strchr(disabled, 'o')) { val = bypass_when_off = "disabled"; } } else if (!strcasecmp(item->info_type, "alarm_control")) { if (strchr(item->value, 'a')) { if (strchr(enabled, 'a')) { const char *beeper = dstate_getinfo("ups.beeper.status"); val = alarm_control = "enabled"; if (!beeper || strcmp(beeper, "muted")) { dstate_setinfo("ups.beeper.status", "enabled"); } } else if (strchr(disabled, 'a')) { val = alarm_control = "disabled"; dstate_setinfo("ups.beeper.status", "disabled"); } /* Unskip beeper.{enable,disable} instcmds */ unskip = find_nut_info("beeper.enable", QX_FLAG_CMD, 0); /* Don't know what happened */ if (!unskip) return -1; unskip->qxflags &= ~QX_FLAG_SKIP; unskip = find_nut_info("beeper.disable", QX_FLAG_CMD, 0); /* Don't know what happened */ if (!unskip) return -1; unskip->qxflags &= ~QX_FLAG_SKIP; } } else if (!strcasecmp(item->info_type, "converter_mode")) { if (strchr(enabled, 'v')) { val = converter_mode = "enabled"; } else if (strchr(disabled, 'v')) { val = converter_mode = "disabled"; } } else if (!strcasecmp(item->info_type, "eco_mode")) { if (strchr(item->value, 'e')) { if (strchr(enabled, 'e')) { val = eco_mode = "enabled"; } else if (strchr(disabled, 'e')) { val = eco_mode = "disabled"; } /* Unskip bypass.{start,stop} instcmds */ unskip = find_nut_info("bypass.start", QX_FLAG_CMD, 0); /* Don't know what happened */ if (!unskip) return -1; unskip->qxflags &= ~QX_FLAG_SKIP; unskip = find_nut_info("bypass.stop", QX_FLAG_CMD, 0); /* Don't know what happened */ if (!unskip) return -1; unskip->qxflags &= ~QX_FLAG_SKIP; /* Unskip input.transfer.{high,low} */ unskip = find_nut_info("input.transfer.high", QX_FLAG_SEMI_STATIC, 0); /* Don't know what happened */ if (!unskip) return -1; unskip->qxflags &= ~QX_FLAG_SKIP; unskip = find_nut_info("input.transfer.low", QX_FLAG_SEMI_STATIC, 0); /* Don't know what happened */ if (!unskip) return -1; unskip->qxflags &= ~QX_FLAG_SKIP; /* Unskip input.frequency.{high,low} */ unskip = find_nut_info("input.frequency.high", QX_FLAG_SEMI_STATIC, 0); /* Don't know what happened */ if (!unskip) return -1; unskip->qxflags &= ~QX_FLAG_SKIP; unskip = find_nut_info("input.frequency.low", QX_FLAG_SEMI_STATIC, 0); /* Don't know what happened */ if (!unskip) return -1; unskip->qxflags &= ~QX_FLAG_SKIP; } } else if (!strcasecmp(item->info_type, "battery_open_status_check")) { if (strchr(enabled, 'd')) { val = battery_open_status_check = "enabled"; } else if (strchr(disabled, 'd')) { val = battery_open_status_check = "disabled"; } } else if (!strcasecmp(item->info_type, "bypass_forbidding")) { if (strchr(enabled, 'f')) { val = bypass_forbidding = "enabled"; } else if (strchr(disabled, 'f')) { val = bypass_forbidding = "disabled"; } } else if (!strcasecmp(item->info_type, "site_fault_detection")) { if (strchr(enabled, 'l')) { val = site_fault_detection = "enabled"; } else if (strchr(disabled, 'l')) { val = site_fault_detection = "disabled"; } } else if (!strcasecmp(item->info_type, "advanced_eco_mode")) { if (strchr(enabled, 'n')) { val = advanced_eco_mode = "enabled"; } else if (strchr(disabled, 'n')) { val = advanced_eco_mode = "disabled"; } } else if (!strcasecmp(item->info_type, "constant_phase_angle")) { if (strchr(enabled, 'q')) { val = constant_phase_angle = "enabled"; } else if (strchr(disabled, 'q')) { val = constant_phase_angle = "disabled"; } } else if (!strcasecmp(item->info_type, "limited_runtime_on_battery")) { if (strchr(enabled, 'w')) { val = limited_runtime_on_battery = "enabled"; } else if (strchr(disabled, 'w')) { val = limited_runtime_on_battery = "disabled"; } /* } else if (!strcasecmp(item->info_type, "")) { if (strchr(enabled, 'h')) { unknown/unused } else if (strchr(disabled, 'h')) { } } else if (!strcasecmp(item->info_type, "")) { if (strchr(enabled, 't')) { unknown/unused } else if (strchr(disabled, 't')) { } } else if (!strcasecmp(item->info_type, "")) { if (strchr(enabled, 'k')) { unknown/unused } else if (strchr(disabled, 'k')) { } } else if (!strcasecmp(item->info_type, "")) { if (strchr(enabled, 'i')) { unknown/unused } else if (strchr(disabled, 'i')) { } } else if (!strcasecmp(item->info_type, "")) { if (strchr(enabled, 'm')) { unknown/unused } else if (strchr(disabled, 'm')) { } } else if (!strcasecmp(item->info_type, "")) { if (strchr(enabled, 'z')) { unknown/unused } else if (strchr(disabled, 'z')) { } */ /* Items with a NUT variable */ } else if (!strcasecmp(item->info_type, "ups.start.auto")) { if (strchr(enabled, 'r')) { val = "yes"; } else if (strchr(disabled, 'r')) { val = "no"; } } else if (!strcasecmp(item->info_type, "battery.protection")) { if (strchr(enabled, 's')) { val = "yes"; } else if (strchr(disabled, 's')) { val = "no"; } } else if (!strcasecmp(item->info_type, "battery.energysave")) { if (strchr(enabled, 'g')) { val = "yes"; } else if (strchr(disabled, 'g')) { val = "no"; } } else if (!strcasecmp(item->info_type, "ups.start.battery")) { if (strchr(enabled, 'c')) { val = "yes"; } else if (strchr(disabled, 'c')) { val = "no"; } } else if (!strcasecmp(item->info_type, "outlet.0.switchable")) { if (strchr(enabled, 'j')) { int i; char buf[SMALLBUF]; val = "yes"; /* Unskip outlet.n.{switchable,status} */ for (i = 1; i <= 4; i++) { snprintf(buf, sizeof(buf), "outlet.%d.switchable", i); unskip = find_nut_info(buf, 0, 0); /* Don't know what happened */ if (!unskip) return -1; unskip->qxflags &= ~QX_FLAG_SKIP; snprintf(buf, sizeof(buf), "outlet.%d.status", i); unskip = find_nut_info(buf, 0, 0); /* Don't know what happened */ if (!unskip) return -1; unskip->qxflags &= ~QX_FLAG_SKIP; } } else if (strchr(disabled, 'j')) { val = "no"; } } /* UPS doesn't have that capability */ if (!val) return -1; #ifdef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL #pragma GCC diagnostic push #endif #ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL #pragma GCC diagnostic ignored "-Wformat-nonliteral" #endif #ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_FORMAT_SECURITY #pragma GCC diagnostic ignored "-Wformat-security" #endif snprintf(value, valuelen, item->dfl, val); #ifdef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL #pragma GCC diagnostic pop #endif /* This item doesn't have a NUT var and we were not asked by the user to change its value */ if ((item->qxflags & QX_FLAG_NONUT) && !getval(item->info_type)) return 0; /* Unskip setvar */ unskip = find_nut_info(item->info_type, QX_FLAG_SETVAR, 0); /* Don't know what happened */ if (!unskip) return -1; unskip->qxflags &= ~QX_FLAG_SKIP; return 0; } /* *SETVAR* Set UPS capability options */ static int voltronic_capability_set(item_t *item, char *value, const size_t valuelen) { #ifdef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL #pragma GCC diagnostic push #endif #ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL #pragma GCC diagnostic ignored "-Wformat-nonliteral" #endif #ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_FORMAT_SECURITY #pragma GCC diagnostic ignored "-Wformat-security" #endif if (!strcasecmp(value, "yes")) { snprintf(value, valuelen, item->command, "E"); return 0; } if (!strcasecmp(value, "no")) { snprintf(value, valuelen, item->command, "D"); return 0; } #ifdef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL #pragma GCC diagnostic pop #endif /* At this point value should have been already checked against enum so this shouldn't happen.. however.. */ upslogx(LOG_ERR, "%s: given value [%s] is not acceptable. Enter either 'yes' or 'no'.", item->info_type, value); return -1; } /* *SETVAR/NONUT* Change UPS capability according to user configuration in ups.conf */ static int voltronic_capability_set_nonut(item_t *item, char *value, const size_t valuelen) { const char *match = NULL; int i; const struct { const char *type; /* Name of the option */ const char *match; /* Value reported by the UPS */ } capability[] = { { "bypass_alarm", bypass_alarm }, { "battery_alarm", battery_alarm }, { "bypass_when_off", bypass_when_off }, { "alarm_control", alarm_control }, { "converter_mode", converter_mode }, { "eco_mode", eco_mode }, { "battery_open_status_check", battery_open_status_check }, { "bypass_forbidding", bypass_forbidding }, { "site_fault_detection", site_fault_detection }, { "advanced_eco_mode", advanced_eco_mode }, { "constant_phase_angle", constant_phase_angle }, { "limited_runtime_on_battery", limited_runtime_on_battery }, { NULL, NULL } }; for (i = 0; capability[i].type; i++) { if (strcasecmp(item->info_type, capability[i].type)) continue; match = capability[i].match; break; } /* UPS doesn't have that capability */ if (!match) return -1; /* At this point value should have been already checked by nutdrv_qx's own setvar so this shouldn't happen.. however.. */ if (!strcasecmp(value, match)) { upslogx(LOG_INFO, "%s is already %s", item->info_type, match); return -1; } #ifdef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL #pragma GCC diagnostic push #endif #ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL #pragma GCC diagnostic ignored "-Wformat-nonliteral" #endif #ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_FORMAT_SECURITY #pragma GCC diagnostic ignored "-Wformat-security" #endif if (!strcasecmp(value, "disabled")) { snprintf(value, valuelen, item->command, "D"); } else if (!strcasecmp(value, "enabled")) { snprintf(value, valuelen, item->command, "E"); } else { /* At this point value should have been already checked against enum so this shouldn't happen.. however.. */ upslogx(LOG_ERR, "%s: [%s] is not within acceptable values [enabled/disabled]", item->info_type, value); return -1; } #ifdef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL #pragma GCC diagnostic pop #endif return 0; } /* *SETVAR/NONUT* Reset capability options and their limits to safe default values */ static int voltronic_capability_reset(item_t *item, char *value, const size_t valuelen) { /* Nothing to do */ if (!testvar("reset_to_default")) return -1; /* UPS capability options can be reset only when the UPS is in 'Standby Mode' (=OFF) (from QMOD) */ if (!((unsigned int)(qx_status()) & STATUS(OFF))) { upslogx(LOG_ERR, "%s: UPS capability options can be reset only when the " "UPS is in Standby Mode (i.e. ups.status = 'OFF').", item->info_type); return -1; } snprintf(value, valuelen, "%s", item->command); return 0; } /* Voltage limits for ECO Mode */ static int voltronic_eco_volt(item_t *item, char *value, const size_t valuelen) { const long protocol = strtol(dstate_getinfo("ups.firmware.aux")+1, NULL, 10); int ovn; const char *outvoltnom; char buf[SMALLBUF]; item_t *unskip; /* Range of accepted values for maximum voltage for ECO Mode */ struct { int lower; /* Lower limit */ int upper; /* Upper limit */ } max; /* Range of accepted values for minimum voltage for ECO Mode */ struct { int lower; /* Lower limit */ int upper; /* Upper limit */ } min; if (strspn(item->value, "0123456789 .") != strlen(item->value)) { upsdebugx(2, "%s: non numerical value [%s: %s]", __func__, item->info_type, item->value); return -1; } #ifdef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL #pragma GCC diagnostic push #endif #ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL #pragma GCC diagnostic ignored "-Wformat-nonliteral" #endif #ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_FORMAT_SECURITY #pragma GCC diagnostic ignored "-Wformat-security" #endif snprintf(value, valuelen, item->dfl, strtod(item->value, NULL)); #ifdef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL #pragma GCC diagnostic pop #endif outvoltnom = dstate_getinfo("output.voltage.nominal"); /* Since query for ratings (QRI) is not mandatory to run this driver, skip next steps if we can't get the value of output voltage nominal */ if (!outvoltnom) { upsdebugx(2, "%s: unable to get output voltage nominal", __func__); /* We return 0 since we have the value and all's ok: simply we can't set its range so we won't unskip SETVAR item and .{min,max} */ return 0; } { /* scoping */ long l = strtol(outvoltnom, NULL, 10); if (l > INT_MAX || l < 0) { /* See comments above */ upsdebugx(2, "%s: unable to get output voltage nominal: %ld", __func__, l); return 0; } ovn = (int)l; } /* For P01/P09 */ if (protocol == 1 || protocol == 9) { if (ovn >= 200) { min.lower = ovn - 24; min.upper = ovn - 7; max.lower = ovn + 7; max.upper = ovn + 24; } else { min.lower = ovn - 12; min.upper = ovn - 3; max.lower = ovn + 3; max.upper = ovn + 12; } /* For P02/P03/P10/P13/P14/P99 */ } else if (protocol == 2 || protocol == 3 || protocol == 10 || protocol == 13 || protocol == 14 || protocol == 99) { if (ovn >= 200) { min.lower = ovn - 24; min.upper = ovn - 11; max.lower = ovn + 11; max.upper = ovn + 24; } else { min.lower = ovn - 12; min.upper = ovn - 5; max.lower = ovn + 5; max.upper = ovn + 12; } /* ECO mode not supported */ } else { upsdebugx(2, "%s: the UPS doesn't seem to support ECO Mode", __func__); /* We return 0 since we have the value and all's ok: simply we can't set its range so we won't unskip SETVAR item and .{min,max} */ return 0; } if (!strcasecmp(item->info_type, "input.transfer.high")) { /* Fill voltronic_r_eco_volt_max */ snprintf(item->info_rw[0].value, sizeof(item->info_rw[0].value), "%d", max.lower); snprintf(item->info_rw[1].value, sizeof(item->info_rw[1].value), "%d", max.upper); } else if (!strcasecmp(item->info_type, "input.transfer.low")) { /* Fill voltronic_r_eco_volt_min */ snprintf(item->info_rw[0].value, sizeof(item->info_rw[0].value), "%d", min.lower); snprintf(item->info_rw[1].value, sizeof(item->info_rw[1].value), "%d", min.upper); } /* Unskip input.transfer.{high,low}.{min,max} */ snprintf(buf, sizeof(buf), "%s.min", item->info_type); unskip = find_nut_info(buf, QX_FLAG_SEMI_STATIC, 0); /* Don't know what happened */ if (!unskip) return -1; unskip->qxflags &= ~QX_FLAG_SKIP; snprintf(buf, sizeof(buf), "%s.max", item->info_type); unskip = find_nut_info(buf, QX_FLAG_SEMI_STATIC, 0); /* Don't know what happened */ if (!unskip) return -1; unskip->qxflags &= ~QX_FLAG_SKIP; /* Unskip input.transfer.{high,low} setvar */ unskip = find_nut_info(item->info_type, QX_FLAG_SETVAR, 0); /* Don't know what happened */ if (!unskip) return -1; unskip->qxflags &= ~QX_FLAG_SKIP; return 0; } /* Voltage limits for ECO Mode (max, min) */ static int voltronic_eco_volt_range(item_t *item, char *value, const size_t valuelen) { char *buf; int i; item_t *from; if (!strcasecmp(item->info_type, "input.transfer.low.min")) { buf = "input.transfer.low"; i = 0; } else if (!strcasecmp(item->info_type, "input.transfer.low.max")) { buf = "input.transfer.low"; i = 1; } else if (!strcasecmp(item->info_type, "input.transfer.high.min")) { buf = "input.transfer.high"; i = 0; } else if (!strcasecmp(item->info_type, "input.transfer.high.max")) { buf = "input.transfer.high"; i = 1; } else { /* Don't know what happened */ return -1; } from = find_nut_info(buf, QX_FLAG_SEMI_STATIC, 0); /* Don't know what happened */ if (!from) return -1; /* Value is set at runtime by voltronic_eco_volt, so if it's still unset something went wrong */ if (!strlen(from->info_rw[i].value)) return -1; snprintf(value, valuelen, "%s", from->info_rw[i].value); return 0; } /* Frequency limits for ECO Mode */ static int voltronic_eco_freq(item_t *item, char *value, const size_t valuelen) { item_t *unskip; if (strspn(item->value, "0123456789 .") != strlen(item->value)) { upsdebugx(2, "%s: non numerical value [%s: %s]", __func__, item->info_type, item->value); return -1; } #ifdef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL #pragma GCC diagnostic push #endif #ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL #pragma GCC diagnostic ignored "-Wformat-nonliteral" #endif #ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_FORMAT_SECURITY #pragma GCC diagnostic ignored "-Wformat-security" #endif snprintf(value, valuelen, item->dfl, strtod(item->value, NULL)); #ifdef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL #pragma GCC diagnostic pop #endif /* Unskip input.transfer.{high,low} setvar */ unskip = find_nut_info(item->info_type, QX_FLAG_SETVAR, 0); /* Don't know what happened */ if (!unskip) return -1; unskip->qxflags &= ~QX_FLAG_SKIP; return 0; } /* *NONUT* Voltage/frequency limits for Bypass Mode */ static int voltronic_bypass(item_t *item, char *value, const size_t valuelen) { item_t *unskip; double val; if (strspn(item->value, "0123456789 .") != strlen(item->value)) { upsdebugx(2, "%s: non numerical value [%s: %s]", __func__, item->info_type, item->value); return -1; } if (!strcasecmp(item->info_type, "max_bypass_volt")) { val = max_bypass_volt = strtol(item->value, NULL, 10); } else if (!strcasecmp(item->info_type, "min_bypass_volt")) { val = min_bypass_volt = strtol(item->value, NULL, 10); } else if (!strcasecmp(item->info_type, "max_bypass_freq")) { val = max_bypass_freq = strtod(item->value, NULL); } else if (!strcasecmp(item->info_type, "min_bypass_freq")) { val = min_bypass_freq = strtod(item->value, NULL); } else { /* Don't know what happened */ return -1; } #ifdef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL #pragma GCC diagnostic push #endif #ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL #pragma GCC diagnostic ignored "-Wformat-nonliteral" #endif #ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_FORMAT_SECURITY #pragma GCC diagnostic ignored "-Wformat-security" #endif snprintf(value, valuelen, item->dfl, val); #ifdef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL #pragma GCC diagnostic pop #endif /* No user-provided value to change.. */ if (!getval(item->info_type)) return 0; /* Unskip {min,max}_bypass_volt setvar */ unskip = find_nut_info(item->info_type, QX_FLAG_SETVAR, 0); /* Don't know what happened */ if (!unskip) return -1; unskip->qxflags &= ~QX_FLAG_SKIP; return 0; } /* *NONUT* Number of batteries */ static int voltronic_batt_numb(item_t *item, char *value, const size_t valuelen) { item_t *unskip; if (strspn(item->value, "0123456789 .") != strlen(item->value)) { upsdebugx(2, "%s: non numerical value [%s: %s]", __func__, item->info_type, item->value); return -1; } battery_number = strtol(item->value, NULL, 10); if (battery_number > INT_MAX) { upsdebugx(2, "%s: battery number out of range [%s: %s]", __func__, item->info_type, item->value); return -1; } #ifdef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL #pragma GCC diagnostic push #endif #ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL #pragma GCC diagnostic ignored "-Wformat-nonliteral" #endif #ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_FORMAT_SECURITY #pragma GCC diagnostic ignored "-Wformat-security" #endif snprintf(value, valuelen, item->dfl, (int)battery_number); #ifdef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL #pragma GCC diagnostic pop #endif /* No user-provided value to change.. */ if (!getval(item->info_type)) return 0; /* Unskip battery_number setvar */ unskip = find_nut_info("battery_number", QX_FLAG_SETVAR, 0); /* Don't know what happened */ if (!unskip) return -1; unskip->qxflags &= ~QX_FLAG_SKIP; return 0; } /* Battery runtime */ static int voltronic_batt_runtime(item_t *item, char *value, const size_t valuelen) { double runtime; if (strspn(item->value, "0123456789 .") != strlen(item->value)) { upsdebugx(2, "%s: non numerical value [%s: %s]", __func__, item->info_type, item->value); return -1; } /* Battery runtime is reported by the UPS in minutes, NUT expects seconds */ runtime = strtod(item->value, NULL) * 60; #ifdef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL #pragma GCC diagnostic push #endif #ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL #pragma GCC diagnostic ignored "-Wformat-nonliteral" #endif #ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_FORMAT_SECURITY #pragma GCC diagnostic ignored "-Wformat-security" #endif snprintf(value, valuelen, item->dfl, runtime); #ifdef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL #pragma GCC diagnostic pop #endif return 0; } /* Protocol used by the UPS */ static int voltronic_protocol(item_t *item, char *value, const size_t valuelen) { long protocol; if (strncasecmp(item->value, "PI", 2)) { upsdebugx(2, "%s: invalid start characters [%.2s]", __func__, item->value); return -1; } /* Here we exclude non numerical value and other non accepted protocols (hence the restricted comparison target) */ if (strspn(item->value+2, "0123489") != strlen(item->value+2)) { upslogx(LOG_ERR, "Protocol [%s] is not supported by this driver", item->value); return -1; } protocol = strtol(item->value+2, NULL, 10); switch (protocol) { case 0: case 1: case 2: case 3: case 8: case 9: case 10: case 13: case 14: case 31: case 99: break; default: upslogx(LOG_ERR, "Protocol [PI%02ld] is not supported by this driver", protocol); return -1; } snprintf(value, valuelen, "P%02ld", protocol); /* Unskip vars according to protocol */ voltronic_massive_unskip(protocol); return 0; } /* Fault reported by the UPS: * When the UPS is queried for status (QGS), if it reports a fault (6th bit of 12bit flag of the reply to QGS set to 1), the driver unskips the QFS item in qx2nut array: this function processes the reply to QFS query */ static int voltronic_fault(item_t *item, char *value, const size_t valuelen) { long protocol = strtol(dstate_getinfo("ups.firmware.aux")+1, NULL, 10); char alarm[LARGEBUF]; /* can sprintf() SMALLBUF plus markup into here */ upslogx(LOG_INFO, "Checking for faults.."); if (!strcasecmp(item->value, "OK")) { #ifdef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL #pragma GCC diagnostic push #endif #ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL #pragma GCC diagnostic ignored "-Wformat-nonliteral" #endif #ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_FORMAT_SECURITY #pragma GCC diagnostic ignored "-Wformat-security" #endif snprintf(value, valuelen, item->dfl, "No fault found"); #ifdef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL #pragma GCC diagnostic pop #endif upslogx(LOG_INFO, "%s", value); item->qxflags |= QX_FLAG_SKIP; return 0; } if ((strspn(item->value, "0123456789ABC") != 2) || ((item->value[0] != '1') && (strspn(item->value+1, "0123456789") != 1))) { snprintf(alarm, sizeof(alarm), "Unknown fault [%s]", item->value); /* P31 UPSes */ } else if (protocol == 31) { if (strpbrk(item->value+1, "ABC")) { snprintf(alarm, sizeof(alarm), "Unknown fault [%s]", item->value); } else { switch (strtol(item->value, NULL, 10)) { case 1: strcpy(alarm, "Fan failure."); break; case 2: strcpy(alarm, "Over temperature fault."); break; case 3: strcpy(alarm, "Battery voltage is too high."); break; case 4: strcpy(alarm, "Battery voltage too low."); break; case 5: strcpy(alarm, "Inverter relay short-circuited."); break; case 6: strcpy(alarm, "Inverter voltage over maximum value."); break; case 7: strcpy(alarm, "Overload fault."); update_status("OVER"); break; case 8: strcpy(alarm, "Bus voltage exceeds its upper limit."); break; case 9: strcpy(alarm, "Bus soft start fail."); break; case 10: strcpy(alarm, "Unknown fault [Fault code: 10]"); break; case 51: strcpy(alarm, "Over current fault."); break; case 52: strcpy(alarm, "Bus voltage below its under limit."); break; case 53: strcpy(alarm, "Inverter soft start fail."); break; case 54: strcpy(alarm, "Self test fail."); break; case 55: strcpy(alarm, "Output DC voltage exceeds its upper limit."); break; case 56: strcpy(alarm, "Battery open fault."); break; case 57: strcpy(alarm, "Current sensor fault."); break; case 58: strcpy(alarm, "Battery short."); break; case 59: strcpy(alarm, "Inverter voltage below its lower limit."); break; default: snprintf(alarm, sizeof(alarm), "Unknown fault [%s]", item->value); break; } } /* All other UPSes */ } else { switch (strtol(item->value, NULL, 10)) { case 1: switch (item->value[1]) { case 'A': strcpy(alarm, "L1 inverter negative power out of acceptable range."); break; case 'B': strcpy(alarm, "L2 inverter negative power out of acceptable range."); break; case 'C': strcpy(alarm, "L3 inverter negative power out of acceptable range."); break; default: strcpy(alarm, "Bus voltage not within default setting."); break; } break; case 2: strcpy(alarm, "Bus voltage over maximum value."); break; case 3: strcpy(alarm, "Bus voltage below minimum value."); break; case 4: strcpy(alarm, "Bus voltage differences out of acceptable range."); break; case 5: strcpy(alarm, "Bus voltage of slope rate drops too fast."); break; case 6: strcpy(alarm, "Over current in PFC input inductor."); break; case 11: strcpy(alarm, "Inverter voltage not within default setting."); break; case 12: strcpy(alarm, "Inverter voltage over maximum value."); break; case 13: strcpy(alarm, "Inverter voltage below minimum value."); break; case 14: strcpy(alarm, "Inverter short-circuited."); break; case 15: strcpy(alarm, "L2 phase inverter short-circuited."); break; case 16: strcpy(alarm, "L3 phase inverter short-circuited."); break; case 17: strcpy(alarm, "L1L2 inverter short-circuited."); break; case 18: strcpy(alarm, "L2L3 inverter short-circuited."); break; case 19: strcpy(alarm, "L3L1 inverter short-circuited."); break; case 21: strcpy(alarm, "Battery SCR short-circuited."); break; case 22: strcpy(alarm, "Line SCR short-circuited."); break; case 23: strcpy(alarm, "Inverter relay open fault."); break; case 24: strcpy(alarm, "Inverter relay short-circuited."); break; case 25: strcpy(alarm, "Input and output wires oppositely connected."); break; case 26: strcpy(alarm, "Battery oppositely connected."); break; case 27: strcpy(alarm, "Battery voltage is too high."); break; case 28: strcpy(alarm, "Battery voltage too low."); break; case 29: strcpy(alarm, "Failure for battery fuse being open-circuited."); break; case 31: strcpy(alarm, "CAN-bus communication fault."); break; case 32: strcpy(alarm, "Host signal circuit fault."); break; case 33: strcpy(alarm, "Synchronous signal circuit fault."); break; case 34: strcpy(alarm, "Synchronous pulse signal circuit fault."); break; case 35: strcpy(alarm, "Parallel cable disconnected."); break; case 36: strcpy(alarm, "Load unbalanced."); break; case 41: strcpy(alarm, "Over temperature fault."); break; case 42: strcpy(alarm, "Communication failure between CPUs in control board."); break; case 43: strcpy(alarm, "Overload fault."); update_status("OVER"); break; case 44: strcpy(alarm, "Fan failure."); break; case 45: strcpy(alarm, "Charger failure."); break; case 46: strcpy(alarm, "Model fault."); break; case 47: strcpy(alarm, "MCU communication fault."); break; default: snprintf(alarm, sizeof(alarm), "Unknown fault [%s]", item->value); break; } } #ifdef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL #pragma GCC diagnostic push #endif #ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL #pragma GCC diagnostic ignored "-Wformat-nonliteral" #endif #ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_FORMAT_SECURITY #pragma GCC diagnostic ignored "-Wformat-security" #endif snprintf(value, valuelen, item->dfl, alarm); #ifdef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL #pragma GCC diagnostic pop #endif upslogx(LOG_INFO, "Fault found: %s", alarm); item->qxflags |= QX_FLAG_SKIP; return 0; } /* Warnings reported by the UPS */ static int voltronic_warning(item_t *item, char *value, const size_t valuelen) { char warn[SMALLBUF] = "", unk[SMALLBUF] = "", bitwarns[SMALLBUF] = "", warns[4096] = ""; int i; if (strspn(item->value, "01") != strlen(item->value)) { upsdebugx(2, "%s: invalid reply from the UPS [%s]", __func__, item->value); return -1; } /* No warnings */ if (strspn(item->value, "0") == strlen(item->value)) { return 0; } snprintf(value, valuelen, "UPS warnings:"); for (i = 0; i < (int)strlen(item->value); i++) { int u = 0; if (item->value[i] == '1') { switch (i) { case 0: strcpy(warn, "Battery disconnected."); break; case 1: strcpy(warn, "Neutral not connected."); break; case 2: strcpy(warn, "Site fault."); break; case 3: strcpy(warn, "Phase sequence incorrect."); break; case 4: strcpy(warn, "Phase sequence incorrect in bypass."); break; case 5: strcpy(warn, "Input frequency unstable in bypass."); break; case 6: strcpy(warn, "Battery overcharged."); break; case 7: strcpy(warn, "Low battery."); update_status("LB"); break; case 8: strcpy(warn, "Overload alarm."); update_status("OVER"); break; case 9: strcpy(warn, "Fan alarm."); break; case 10: strcpy(warn, "EPO enabled."); break; case 11: strcpy(warn, "Unable to turn on UPS."); break; case 12: strcpy(warn, "Over temperature alarm."); break; case 13: strcpy(warn, "Charger alarm."); break; case 14: strcpy(warn, "Remote auto shutdown."); break; case 15: strcpy(warn, "L1 input fuse not working."); break; case 16: strcpy(warn, "L2 input fuse not working."); break; case 17: strcpy(warn, "L3 input fuse not working."); break; case 18: strcpy(warn, "Positive PFC abnormal in L1."); break; case 19: strcpy(warn, "Negative PFC abnormal in L1."); break; case 20: strcpy(warn, "Positive PFC abnormal in L2."); break; case 21: strcpy(warn, "Negative PFC abnormal in L2."); break; case 22: strcpy(warn, "Positive PFC abnormal in L3."); break; case 23: strcpy(warn, "Negative PFC abnormal in L3."); break; case 24: strcpy(warn, "Abnormal in CAN-bus communication."); break; case 25: strcpy(warn, "Abnormal in synchronous signal circuit."); break; case 26: strcpy(warn, "Abnormal in synchronous pulse signal circuit."); break; case 27: strcpy(warn, "Abnormal in host signal circuit."); break; case 28: strcpy(warn, "Male connector of parallel cable not connected well."); break; case 29: strcpy(warn, "Female connector of parallel cable not connected well."); break; case 30: strcpy(warn, "Parallel cable not connected well."); break; case 31: strcpy(warn, "Battery connection not consistent in parallel systems."); break; case 32: strcpy(warn, "AC connection not consistent in parallel systems."); break; case 33: strcpy(warn, "Bypass connection not consistent in parallel systems."); break; case 34: strcpy(warn, "UPS model types not consistent in parallel systems."); break; case 35: strcpy(warn, "Capacity of UPSes not consistent in parallel systems."); break; case 36: strcpy(warn, "Auto restart setting not consistent in parallel systems."); break; case 37: strcpy(warn, "Battery cell over charge."); break; case 38: strcpy(warn, "Battery protection setting not consistent in parallel systems."); break; case 39: strcpy(warn, "Battery detection setting not consistent in parallel systems."); break; case 40: strcpy(warn, "Bypass not allowed setting not consistent in parallel systems."); break; case 41: strcpy(warn, "Converter setting not consistent in parallel systems."); break; case 42: strcpy(warn, "High loss point for frequency in bypass mode not consistent in parallel systems."); break; case 43: strcpy(warn, "Low loss point for frequency in bypass mode not consistent in parallel systems."); break; case 44: strcpy(warn, "High loss point for voltage in bypass mode not consistent in parallel systems."); break; case 45: strcpy(warn, "Low loss point for voltage in bypass mode not consistent in parallel systems."); break; case 46: strcpy(warn, "High loss point for frequency in AC mode not consistent in parallel systems."); break; case 47: strcpy(warn, "Low loss point for frequency in AC mode not consistent in parallel systems."); break; case 48: strcpy(warn, "High loss point for voltage in AC mode not consistent in parallel systems."); break; case 49: strcpy(warn, "Low loss point for voltage in AC mode not consistent in parallel systems."); break; case 50: strcpy(warn, "Warning for locking in bypass mode after 3 consecutive overloads within 30 min."); break; case 51: strcpy(warn, "Warning for three-phase AC input current unbalance."); break; case 52: strcpy(warn, "Warning for a three-phase input current unbalance detected in battery mode."); break; case 53: strcpy(warn, "Warning for Inverter inter-current unbalance."); break; case 54: strcpy(warn, "Programmable outlets cut off pre-alarm."); break; case 55: strcpy(warn, "Warning for Battery replace."); update_status("RB"); break; case 56: strcpy(warn, "Abnormal warning on input phase angle."); break; case 57: strcpy(warn, "Warning!! Cover of maintain switch is open."); break; case 61: strcpy(warn, "EEPROM operation error."); break; default: snprintf(warn, sizeof(warn), "Unknown warning from UPS [bit: #%02d]", i + 1); u++; break; } upslogx(LOG_INFO, "Warning from UPS: %s", warn); if (u) { /* Unknown warnings */ snprintfcat(unk, sizeof(unk), ", #%02d", i + 1); } else { /* Known warnings */ if (strlen(warns) > 0) { /* For too long warnings (total) */ snprintfcat(bitwarns, sizeof(bitwarns), ", #%02d", i + 1); /* For warnings (total) not too long */ snprintfcat(warns, sizeof(warns), " %s", warn); } else { snprintf(bitwarns, sizeof(bitwarns), "Known (see log or manual) [bit: #%02d", i + 1); snprintf(warns, sizeof(warns), "%s", warn); } } } } /* There's some known warning, at least */ if (strlen(warns) > 0) { /* We have both known and unknown warnings */ if (strlen(unk) > 0) { /* Appending unknown ones to known ones; removing leading comma from unk - 'explicit' */ snprintfcat(warns, sizeof(warns), " Unknown warnings [bit:%s]", unk+1); /* Appending unknown ones to known ones; removing leading comma from unk - 'cryptic' */ snprintfcat(bitwarns, sizeof(bitwarns), "]; Unknown warnings [bit:%s]", unk+1); /* We have only known warnings */ } else { snprintfcat(bitwarns, sizeof(bitwarns), "]"); } /* We have only unknown warnings */ } else if (strlen(unk) > 0) { /* Removing leading comma from unk */ snprintf(warns, sizeof(warns), "Unknown warnings [bit:%s]", unk+1); strcpy(bitwarns, warns); } else { /* Don't know what happened */ upsdebugx(2, "%s: failed to process warnings", __func__); return -1; } /* If grand total of warnings doesn't exceed value of alarm (=ST_MAX_VALUE_LEN) minus some space (32) for other alarms.. */ if ((ST_MAX_VALUE_LEN - 32) > strlen(warns)) { /* ..then be explicit.. */ snprintfcat(value, valuelen, " %s", warns); /* ..otherwise.. */ } else { /* ..be cryptic */ snprintfcat(value, valuelen, " %s", bitwarns); } return 0; } /* Working mode reported by the UPS */ static int voltronic_mode(item_t *item, char *value, const size_t valuelen) { char *status = NULL, *alarm = NULL; switch (item->value[0]) { case 'P': alarm = "UPS is going ON"; break; case 'S': status = "OFF"; break; case 'Y': status = "BYPASS"; break; case 'L': status = "OL"; break; case 'B': status = "!OL"; break; case 'T': status = "CAL"; break; case 'F': alarm = "Fault reported by UPS."; break; case 'E': alarm = "UPS is in ECO Mode."; break; case 'C': alarm = "UPS is in Converter Mode."; break; case 'D': alarm = "UPS is shutting down!"; status = "FSD"; break; default: upsdebugx(2, "%s: invalid reply from the UPS [%s]", __func__, item->value); return -1; } #ifdef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL #pragma GCC diagnostic push #endif #ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL #pragma GCC diagnostic ignored "-Wformat-nonliteral" #endif #ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_FORMAT_SECURITY #pragma GCC diagnostic ignored "-Wformat-security" #endif if (alarm && !strcasecmp(item->info_type, "ups.alarm")) { snprintf(value, valuelen, item->dfl, alarm); } else if (status && !strcasecmp(item->info_type, "ups.status")) { snprintf(value, valuelen, item->dfl, status); } #ifdef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL #pragma GCC diagnostic pop #endif return 0; } /* Process status bits */ static int voltronic_status(item_t *item, char *value, const size_t valuelen) { char *val = ""; if (strspn(item->value, "01") != strlen(item->value)) { upsdebugx(3, "%s: unexpected value %s@%d->%s", __func__, item->value, item->from, item->value); return -1; } switch (item->from) { case 63: /* UPS Type - ups.type */ { long type = strtol(item->value, NULL, 10); if (!type) /* 00 -> Offline */ val = "offline"; else if (type == 1) /* 01 -> Line-interactive */ val = "line-interactive"; else if (type == 10) /* 10 -> Online */ val = "online"; else { upsdebugx(2, "%s: invalid type [%s: %s]", __func__, item->info_type, item->value); return -1; } } break; case 65: /* Utility Fail (Immediate) - ups.status */ if (item->value[0] == '1') val = "!OL"; else val = "OL"; break; case 66: /* Battery Low - ups.status */ if (item->value[0] == '1') val = "LB"; else val = "!LB"; break; case 67: /* Bypass/Boost or Buck Active - ups.{status,alarm} */ if (item->value[0] == '1') { double vi, vo; vi = strtod(dstate_getinfo("input.voltage"), NULL); vo = strtod(dstate_getinfo("output.voltage"), NULL); if (vo < 0.5 * vi) { upsdebugx(2, "%s: output voltage too low", __func__); return -1; } if (vo < 0.95 * vi) { val = "TRIM"; } else if (vo < 1.05 * vi) { long prot = strtol(dstate_getinfo("ups.firmware.aux")+1, NULL, 10); if (!prot || prot == 8) { /* ups.alarm */ if (!strcasecmp(item->info_type, "ups.alarm")) val = "UPS is in AVR Mode."; } else { /* ups.status */ if (!strcasecmp(item->info_type, "ups.status")) val = "BYPASS"; } } else if (vo < 1.5 * vi) { val = "BOOST"; } else { upsdebugx(2, "%s: output voltage too high", __func__); return -1; } } break; case 68: /* UPS Fault - ups.alarm */ if (item->value[0] == 1) { item_t *faultitem; for (faultitem = voltronic_qx2nut; faultitem->info_type != NULL; faultitem++) { if (!faultitem->command) continue; if (!strcasecmp(faultitem->command, "QFS\r")) { faultitem->qxflags &= ~QX_FLAG_SKIP; break; } } val = "UPS Fault!"; } break; /* case 69: *//* unknown */ /* break;*/ case 70: /* Test in Progress - ups.status */ if (item->value[0] == '1') val = "CAL"; else val = "!CAL"; break; case 71: /* Shutdown Active - ups.status */ if (item->value[0] == '1') val = "FSD"; else val = "!FSD"; break; case 72: /* Beeper status - ups.beeper.status */ /* The UPS has the ability to enable/disable the alarm (from UPS capability) */ if (alarm_control) { const char *beeper = dstate_getinfo("ups.beeper.status"); if (!beeper || strcasecmp(beeper, "disabled")) { if (item->value[0] == '0') /* Beeper On */ val = "enabled"; else val = "muted"; } /* The UPS lacks the ability to enable/disable the alarm (from UPS capability) */ } else { if (item->value[0] == '0') /* Beeper On */ val = "enabled"; else val = "disabled"; } break; /* case 73: *//* unknown */ /* break;*/ /* case 74: *//* unknown */ /* break;*/ default: /* Don't know what happened */ return -1; } snprintf(value, valuelen, "%s", val); return 0; } /* Output power factor */ static int voltronic_output_powerfactor(item_t *item, char *value, const size_t valuelen) { double opf; if (strspn(item->value, "0123456789 .") != strlen(item->value)) { upsdebugx(2, "%s: non numerical value [%s: %s]", __func__, item->info_type, item->value); return -1; } /* UPS report a value expressed in % so -> output.powerfactor*100 e.g. opf = 0,8 -> ups = 80 */ opf = strtod(item->value, NULL) * 0.01; #ifdef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL #pragma GCC diagnostic push #endif #ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL #pragma GCC diagnostic ignored "-Wformat-nonliteral" #endif #ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_FORMAT_SECURITY #pragma GCC diagnostic ignored "-Wformat-security" #endif snprintf(value, valuelen, item->dfl, opf); #ifdef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL #pragma GCC diagnostic pop #endif return 0; } /* UPS serial number */ static int voltronic_serial_numb(item_t *item, char *value, const size_t valuelen) { /* If the UPS report a 00..0 serial we'll log it but we won't store it in device.serial */ if (strspn(item->value, "0") == strlen(item->value)) { upslogx(LOG_INFO, "%s: UPS reported a non-significant serial [%s]", item->info_type, item->value); return -1; } #ifdef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL #pragma GCC diagnostic push #endif #ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL #pragma GCC diagnostic ignored "-Wformat-nonliteral" #endif #ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_FORMAT_SECURITY #pragma GCC diagnostic ignored "-Wformat-security" #endif snprintf(value, valuelen, item->dfl, item->value); #ifdef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL #pragma GCC diagnostic pop #endif return 0; } /* Outlet status */ static int voltronic_outlet(item_t *item, char *value, const size_t valuelen) { const char *status, *switchable; char number = item->info_type[7], buf[SMALLBUF]; item_t *outlet_item; switch (item->value[0]) { case '1': switchable = "yes"; status = "on"; break; case '0': switchable = "yes"; status = "off"; break; default: upsdebugx(2, "%s: invalid reply from the UPS [%s: %s]", __func__, item->info_type, item->value); return -1; } #ifdef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL #pragma GCC diagnostic push #endif #ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL #pragma GCC diagnostic ignored "-Wformat-nonliteral" #endif #ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_FORMAT_SECURITY #pragma GCC diagnostic ignored "-Wformat-security" #endif if (strstr(item->info_type, "switchable")) { snprintf(value, valuelen, item->dfl, switchable); } else if (strstr(item->info_type, "status")) { snprintf(value, valuelen, item->dfl, status); } else { /* Don't know what happened */ return -1; } #ifdef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL #pragma GCC diagnostic pop #endif /* Unskip outlet.n.delay.shutdown */ snprintf(buf, sizeof(buf), "outlet.%c.delay.shutdown", number); outlet_item = find_nut_info(buf, QX_FLAG_SEMI_STATIC, 0); /* Don't know what happened*/ if (!outlet_item) return -1; outlet_item->qxflags &= ~QX_FLAG_SKIP; /* Unskip outlet.n.load.on */ snprintf(buf, sizeof(buf), "outlet.%c.load.on", number); outlet_item = find_nut_info(buf, QX_FLAG_CMD, 0); /* Don't know what happened*/ if (!outlet_item) return -1; outlet_item->qxflags &= ~QX_FLAG_SKIP; /* Unskip outlet.n.load.off */ snprintf(buf, sizeof(buf), "outlet.%c.load.off", number); outlet_item = find_nut_info(buf, QX_FLAG_CMD, 0); /* Don't know what happened*/ if (!outlet_item) return -1; outlet_item->qxflags &= ~QX_FLAG_SKIP; return 0; } /* Outlet delay time */ static int voltronic_outlet_delay(item_t *item, char *value, const size_t valuelen) { char number = item->info_type[7], buf[SMALLBUF]; double val; item_t *setvar_item; if (strspn(item->value, "0123456789 .") != strlen(item->value)) { upsdebugx(2, "%s: non numerical value [%s: %s]", __func__, item->info_type, item->value); return -1; } /* UPS reports minutes, NUT expects seconds */ val = strtod(item->value, NULL) * 60; #ifdef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL #pragma GCC diagnostic push #endif #ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL #pragma GCC diagnostic ignored "-Wformat-nonliteral" #endif #ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_FORMAT_SECURITY #pragma GCC diagnostic ignored "-Wformat-security" #endif snprintf(value, valuelen, item->dfl, val); #ifdef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL #pragma GCC diagnostic pop #endif /* Unskip outlet.n.delay.shutdown setvar */ snprintf(buf, sizeof(buf), "outlet.%c.delay.shutdown", number); setvar_item = find_nut_info(buf, QX_FLAG_SETVAR, 0); /* Don't know what happened*/ if (!setvar_item) return -1; setvar_item->qxflags &= ~QX_FLAG_SKIP; return 0; } /* *SETVAR* Outlet delay time */ static int voltronic_outlet_delay_set(item_t *item, char *value, const size_t valuelen) { long delay = strtol(value, NULL, 10); if ((delay/60) > INT_MAX) { upsdebugx(2, "%s: invalid delay %ld sec set for UPS [%s]", __func__, delay, item->value); return -1; } /* From seconds to minute */ delay = delay / 60; #ifdef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL #pragma GCC diagnostic push #endif #ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL #pragma GCC diagnostic ignored "-Wformat-nonliteral" #endif #ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_FORMAT_SECURITY #pragma GCC diagnostic ignored "-Wformat-security" #endif snprintf(value, valuelen, item->command, (int)delay); #ifdef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL #pragma GCC diagnostic pop #endif return 0; } /* Type of battery */ static int voltronic_p31b(item_t *item, char *value, const size_t valuelen) { long val; if ((item->value[0] != '0') || (strspn(item->value+1, "012") != 1)) { upsdebugx(2, "%s: invalid battery type reported by the UPS [%s]", __func__, item->value); return -1; } val = strtol(item->value, NULL, 10); if (val < 0 || (uintmax_t)val > SIZE_MAX) { upsdebugx(2, "%s: invalid battery type reported by the UPS [%s]", __func__, item->value); return -1; } #ifdef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL #pragma GCC diagnostic push #endif #ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL #pragma GCC diagnostic ignored "-Wformat-nonliteral" #endif #ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_FORMAT_SECURITY #pragma GCC diagnostic ignored "-Wformat-security" #endif snprintf(value, valuelen, item->dfl, item->info_rw[(size_t)val].value); #ifdef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL #pragma GCC diagnostic pop #endif return 0; } /* *SETVAR* Type of battery */ static int voltronic_p31b_set(item_t *item, char *value, const size_t valuelen) { int i; if (!item->info_rw) return -1; for (i = 0; strlen(item->info_rw[i].value) > 0; i++) { if (!strcasecmp(item->info_rw[i].value, value)) break; } /* At this point value should already be checked against enum so this shouldn't happen.. however.. */ if (!strlen(item->info_rw[i].value)) { upslogx(LOG_ERR, "%s: value [%s] out of range", item->info_type, value); return -1; } snprintf(value, valuelen, "%d", i); return voltronic_process_setvar(item, value, valuelen); } /* *NONUT* Actual device grid working range type for P31 UPSes */ static int voltronic_p31g(item_t *item, char *value, const size_t valuelen) { long val; if ((item->value[0] != '0') || (strspn(item->value+1, "01") != 1)) { upsdebugx(2, "%s: invalid device grid working range reported by the UPS [%s]", __func__, item->value); return -1; } val = strtol(item->value, NULL, 10); if (val < 0 || (uintmax_t)val > SIZE_MAX) { upsdebugx(2, "%s: invalid device grid working range reported by the UPS [%s]", __func__, item->value); return -1; } #ifdef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL #pragma GCC diagnostic push #endif #ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL #pragma GCC diagnostic ignored "-Wformat-nonliteral" #endif #ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_FORMAT_SECURITY #pragma GCC diagnostic ignored "-Wformat-security" #endif snprintf(value, valuelen, item->dfl, item->info_rw[(size_t)val].value); #ifdef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL #pragma GCC diagnostic pop #endif work_range_type = val; return 0; } /* *SETVAR/NONUT* Device grid working range type for P31 UPSes */ static int voltronic_p31g_set(item_t *item, char *value, const size_t valuelen) { int i; if (!item->info_rw) return -1; for (i = 0; strlen(item->info_rw[i].value) > 0; i++) { if (!strcasecmp(item->info_rw[i].value, value)) break; } /* At this point value should have been already checked against enum so this shouldn't happen.. however.. */ if (!strlen(item->info_rw[i].value)) { upslogx(LOG_ERR, "%s: value [%s] out of range", item->info_type, value); return -1; } if (i == work_range_type) { upslogx(LOG_INFO, "%s is already set to %s", item->info_type, item->info_rw[i].value); return -1; } snprintf(value, valuelen, "%d", i); return voltronic_process_setvar(item, value, valuelen); } /* *NONUT* UPS actual input/output phase angles */ static int voltronic_phase(item_t *item, char *value, const size_t valuelen) { long angle; if (strspn(item->value, "0123456789 .") != strlen(item->value)) { upsdebugx(2, "%s: non numerical value [%s: %s]", __func__, item->info_type, item->value); return -1; } angle = strtol(item->value, NULL, 10); if (!strcasecmp(item->info_type, "output_phase_angle")) { output_phase_angle = angle; /* User-provided value to change.. */ if (getval(item->info_type)) { item_t *unskip; /* Unskip output_phase_angle setvar */ unskip = find_nut_info(item->info_type, QX_FLAG_SETVAR, 0); /* Don't know what happened */ if (!unskip) return -1; unskip->qxflags &= ~QX_FLAG_SKIP; } } if (angle < 0 || angle > INT_MAX) { upsdebugx(2, "%s: phase angle out of range [%s: %ld]", __func__, item->value, angle); return -1; } #ifdef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL #pragma GCC diagnostic push #endif #ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL #pragma GCC diagnostic ignored "-Wformat-nonliteral" #endif #ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_FORMAT_SECURITY #pragma GCC diagnostic ignored "-Wformat-security" #endif snprintf(value, valuelen, item->dfl, (int)angle); #ifdef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL #pragma GCC diagnostic pop #endif return 0; } /* *SETVAR/NONUT* Output phase angle */ static int voltronic_phase_set(item_t *item, char *value, const size_t valuelen) { int i; if (!item->info_rw) return -1; for (i = 0; strlen(item->info_rw[i].value) > 0; i++) { if (!strcasecmp(item->info_rw[i].value, value)) break; } /* At this point value should have been already checked against enum so this shouldn't happen.. however.. */ if (!strlen(item->info_rw[i].value)) { upslogx(LOG_ERR, "%s: value [%s] out of range", item->info_type, value); return -1; } if (strtol(item->info_rw[i].value, NULL, 10) == output_phase_angle) { upslogx(LOG_INFO, "%s is already set to %s", item->info_type, item->info_rw[i].value); return -1; } snprintf(value, valuelen, "%d", i); return voltronic_process_setvar(item, value, valuelen); } /* *NONUT* UPS is master/slave in a system of UPSes in parallel */ static int voltronic_parallel(item_t *item, char *value, const size_t valuelen) { char *type; if (strlen(item->value) != strspn(item->value, "0123456789")) { upsdebugx(2, "%s: non numerical value [%s: %s]", __func__, item->info_type, item->value); return -1; } /* 001 for master UPS, 002 and 003 for slave UPSes */ switch (strtol(item->value, NULL, 10)) { case 1: type = "master"; break; case 2: case 3: type = "slave"; break; default: upsdebugx(2, "%s: invalid reply from the UPS [%s]", __func__, item->value); return -1; } snprintf(value, valuelen, "This UPS is *%s* in a system of UPSes in parallel", type); return 0; } /* == Subdriver interface == */ subdriver_t voltronic_subdriver = { VOLTRONIC_VERSION, voltronic_claim, voltronic_qx2nut, NULL, NULL, voltronic_makevartable, "ACK", "(NAK\r", #ifdef TESTING voltronic_testing, #endif /* TESTING */ }; nut-2.8.1/drivers/apcsmart_tabs.c0000644000175000017500000001652714500336654013737 00000000000000/* apcsmart_tabs.c - common tables for APC smart protocol units * * Copyright (C) 1999 Russell Kroll * (C) 2000 Nigel Metheringham * (C) 2011+ Michal Soltys * * 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 2 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, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "apcsmart_tabs.h" /* APC_MULTI variables *must* be listed in order of preference */ apc_vartab_t apc_vartab[] = { /* name cmd flags regex nlen0 cnt */ { "ups.temperature", 'C', APC_POLL|APC_F_CELSIUS, NULL, 0, 0 }, { "ups.load", 'P', APC_POLL|APC_F_PERCENT, NULL, 0, 0 }, { "ups.test.interval", 'E', APC_F_HOURS, NULL, 0, 0 }, { "ups.test.result", 'X', APC_POLL, NULL, 0, 0 }, { "ups.delay.start", 'r', APC_F_SECONDS, NULL, 0, 0 }, { "ups.delay.shutdown", 'p', APC_F_SECONDS, NULL, 0, 0 }, { "ups.id", 'c', APC_STRING, NULL, 0, 0 }, { "ups.contacts", 'i', APC_POLL|APC_F_HEX, NULL, 0, 0 }, { "ups.display.language", '\014', 0, NULL, 0, 0 }, { "input.voltage", 'L', APC_POLL|APC_F_VOLT, NULL, 0, 0 }, { "input.frequency", 'F', APC_POLL|APC_F_DEC, NULL, 0, 0 }, { "input.sensitivity", 's', 0, NULL, 0, 0 }, { "input.quality", '9', APC_POLL|APC_F_HEX, NULL, 0, 0 }, { "input.transfer.low", 'l', APC_F_VOLT, NULL, 0, 0 }, { "input.transfer.high", 'u', APC_F_VOLT, NULL, 0, 0 }, { "input.transfer.reason", 'G', APC_POLL|APC_F_REASON, NULL, 0, 0 }, { "input.voltage.maximum", 'M', APC_POLL|APC_F_VOLT, NULL, 0, 0 }, { "input.voltage.minimum", 'N', APC_POLL|APC_F_VOLT, NULL, 0, 0 }, { "output.current", '/', APC_POLL|APC_F_AMP, NULL, 0, 0 }, { "output.voltage", 'O', APC_POLL|APC_F_VOLT, NULL, 0, 0 }, { "output.voltage.nominal", 'o', APC_F_VOLT, NULL, 0, 0 }, { "ambient.humidity", 'h', APC_POLL|APC_F_PERCENT, NULL, 0, 0 }, { "ambient.0.humidity", 'H', APC_POLL|APC_PACK|APC_F_PERCENT, NULL, 0, 0 }, { "ambient.0.humidity.high", '{', APC_POLL|APC_PACK|APC_F_PERCENT, NULL, 0, 0 }, { "ambient.0.humidity.low", '}', APC_POLL|APC_PACK|APC_F_PERCENT, NULL, 0, 0 }, { "ambient.temperature", 't', APC_POLL|APC_F_CELSIUS, NULL, 0, 0 }, { "ambient.0.temperature", 'T', APC_MULTI|APC_POLL|APC_PACK|APC_F_CELSIUS, "^[0-9]{2}\\.[0-9]{2}$", 0, 0 }, { "ambient.0.temperature.high", '[', APC_POLL|APC_PACK|APC_F_CELSIUS, NULL, 0, 0 }, { "ambient.0.temperature.low", ']', APC_POLL|APC_PACK|APC_F_CELSIUS, NULL, 0, 0 }, { "battery.date", 'x', APC_STRING, NULL, 0, 0 }, { "battery.charge", 'f', APC_POLL|APC_F_PERCENT, NULL, 0, 0 }, { "battery.charge.restart", 'e', APC_F_PERCENT, NULL, 0, 0 }, { "battery.voltage", 'B', APC_POLL|APC_F_VOLT, NULL, 0, 0 }, { "battery.voltage.nominal", 'g', 0, NULL, 0, 0 }, { "battery.runtime", 'j', APC_POLL|APC_F_MINUTES, NULL, 0, 0 }, { "battery.runtime.low", 'q', APC_F_MINUTES, NULL, 0, 0 }, { "battery.packs", '>', APC_F_DEC, NULL, 0, 0 }, { "battery.packs.bad", '<', APC_F_DEC, NULL, 0, 0 }, { "battery.alarm.threshold", 'k', 0, NULL, 0, 0 }, { "device.uptime", 'T', APC_MULTI|APC_POLL|APC_F_HOURS, "^[0-9]{3}\\.[0-9]{1}$", 0, 0 }, { "ups.serial", 'n', 0, NULL, 0, 0 }, { "ups.mfr.date", 'm', 0, NULL, 0, 0 }, { "ups.model", '\001', 0, NULL, 0, 0 }, { "ups.firmware.aux", 'v', 0, NULL, 0, 0 }, { "ups.firmware", 'b', APC_MULTI, "^[[:alnum:]]+\\.[[:alnum:]]+\\.[[:alnum:]]+$", 0, 0 }, { "ups.firmware", 'V', APC_MULTI, NULL, 0, 0 }, { NULL, 0, 0, NULL, 0, 0 } /* todo: I = alarm enable (hex field) - split into alarm.n.enable J = alarm status (hex field) - split into alarm.n.status 0x15 = output voltage selection (APC_F_VOLT) 0x5C = load power (APC_POLL|APC_F_PERCENT) */ }; /* * APC commands mapped to NUT's instant commands * the format of extra values is matched by extended posix regex * APC_CMD_CUSTOM means that the instant command is handled by separate * function, thus the actual APC cmd in the table is ignored */ apc_cmdtab_t apc_cmdtab[] = { { "shutdown.return", "^[Aa][Tt]:[0-9]{1,3}$", APC_CMD_GRACEDOWN, APC_NASTY }, { "shutdown.return", "^([Cc][Ss]|)$", APC_CMD_SOFTDOWN, APC_NASTY }, { "shutdown.stayoff", NULL, APC_CMD_SHUTDOWN, APC_NASTY|APC_REPEAT }, { "load.off", NULL, APC_CMD_OFF, APC_NASTY|APC_REPEAT }, { "load.on", NULL, APC_CMD_ON, APC_REPEAT }, { "calibrate.start", NULL, APC_CMD_CALTOGGLE, 0 }, { "calibrate.stop", NULL, APC_CMD_CALTOGGLE, 0 }, { "test.panel.start", NULL, APC_CMD_FPTEST, 0 }, { "test.failure.start", NULL, APC_CMD_SIMPWF, 0 }, { "test.battery.start", NULL, APC_CMD_BTESTTOGGLE, 0 }, { "test.battery.stop", NULL, APC_CMD_BTESTTOGGLE, 0 }, { "bypass.start", NULL, APC_CMD_BYPTOGGLE, 0 }, { "bypass.stop", NULL, APC_CMD_BYPTOGGLE, 0 }, { NULL, NULL, 0, 0 } }; /* compatibility with hardware that doesn't do APC_CMDSET ('a') */ apc_compattab_t apc_compattab[] = { /* APC Matrix */ { "0XI", "@789ABCDEFGKLMNOPQRSTUVWXYZcefgjklmnopqrsuwxz/<>\\^\014\026", 0 }, { "0XM", "@789ABCDEFGKLMNOPQRSTUVWXYZcefgjklmnopqrsuwxz/<>\\^\014\026", 0 }, { "0ZI", "@79ABCDEFGKLMNOPQRSUVWXYZcefgjklmnopqrsuxz/<>", 0 }, { "5UI", "@79ABCDEFGKLMNOPQRSUVWXYZcefgjklmnopqrsuxz/<>", 0 }, { "5ZM", "@79ABCDEFGKLMNOPQRSUVWXYZcefgjklmnopqrsuxz/<>", 0 }, /* APC600 */ { "6QD", "@79ABCDEFGKLMNOPQRSUVWXYZcefgjklmnopqrsuxz", 0 }, { "6QI", "@79ABCDEFGKLMNOPQRSUVWXYZcefgjklmnopqrsuxz", 0 }, { "6TD", "@79ABCDEFGKLMNOPQRSUVWXYZcefgjklmnopqrsuxz", 0 }, { "6TI", "@79ABCDEFGKLMNOPQRSUVWXYZcefgjklmnopqrsuxz", 0 }, /* SmartUPS 900 */ { "7QD", "@79ABCDEFGKLMNOPQRSUVWXYZcefgjklmnopqrsuxz", 0 }, { "7QI", "@79ABCDEFGKLMNOPQRSUVWXYZcefgjklmnopqrsuxz", 0 }, { "7TD", "@79ABCDEFGKLMNOPQRSUVWXYZcefgjklmnopqrsuxz", 0 }, { "7TI", "@79ABCDEFGKLMNOPQRSUVWXYZcefgjklmnopqrsuxz", 0 }, /* SmartUPS 600I */ { "6JI", "@789ABCFGKLMNOPQSTUVWXYZfg", 0 }, /* SmartUPS 900I */ { "7II", "@79ABCEFGKLMNOPQRSUVWXYZcfg", 0 }, /* SmartUPS 2000I */ { "9II", "@79ABCEFGKLMNOPQRSUVWXYZcfg", 0 }, { "9GI", "@79ABCEFGKLMNOPQRSUVWXYZcfg", 0 }, /* SmartUPS 1250I */ { "8II", "@79ABCEFGKLMNOPQRSUVWXYZcfg", 0 }, { "8GI", "@79ABCEFGKLMNOPQRSUVWXYZfg", 0 }, /* SmartUPS 1250 */ { "8QD", "@79ABCDEFGKLMNOPQRSUVWXYZcefgjklmnopqrsuxz", 0 }, { "8QI", "@79ABCDEFGKLMNOPQRSUVWXYZcefgjklmnopqrsuxz", 0 }, { "8TD", "@79ABCDEFGKLMNOPQRSUVWXYZcefgjklmnopqrsuxz", 0 }, { "8TI", "@79ABCDEFGKLMNOPQRSUVWXYZcefgjklmnopqrsuxz", 0 }, /* CS 350 */ { "5.4.D", "@\1ABPQRSUYbdfgjmnx9", 0 }, /* * certain set of UPSes returning voltage > 255V through 'b'; "set\1" * is matched explicitly (fake key); among the UPS models - some old * APC 600 ones */ { "set\1", "@789ABCFGKLMNOPQRSUVWXYZ", 0 }, { NULL, NULL, 0 } }; upsdrv_info_t apc_tab_info = { "APC command table", APC_TABLE_VERSION, "Russell Kroll \n" \ "Nigel Metheringham \n" \ "Michal Soltys ", DRV_STABLE, { NULL } }; nut-2.8.1/drivers/bcmxcp.c0000644000175000017500000030627614502253356012372 00000000000000/* bcmxcp.c - driver for powerware UPS Total rewrite of bcmxcp.c (nut ver-1.4.3) * Copyright (c) 2002, Martin Schroeder * * emes -at- geomer.de * * All rights reserved.* Copyright (C) 2004 Kjell Claesson 2004 Tore Ørpetveit 2011 - 2015 Arnaud Quette Thanks to Tore Ørpetveit that sent me the manuals for bcm/xcp. And to Fabio Di Niro and his metasys module. It influenced the layout of this driver. Modified for USB by Wolfgang Ocker ojw0000 2007Apr5 Oliver Wilcock - modified to control individual load segments (outlet.2.shutdown.return) on Powerware PW5125. Modified to support setvar for outlet.n.delay.start by Rich Wrenn (RFW) 9-3-11. Modified to support setvar for outlet.n.delay.shutdown by Arnaud Quette, 9-12-11 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 2 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, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA TODO List: Extend the parsing of the Standard ID Block, to read: Config Block Length: (High priority) Give information if config block is present, and how long it is, if it exist. If config block exist, read the config block and parse the 'Length of the Extended Limits Configuration Block' for extended configuration commands Statistic map Size: (Low priority) May be used to se if there is a Statistic Map. It holds data on the utility power quality for the past month and since last reset. Number of times on battery and how long. Up time and utility frequency deviation. (Only larger ups'es) Size of Alarm History Log: (Low priority) See if it have any alarm history block and enable command to dump it. Maximum Supported Command Length: ( Med. to High priority) Give info about the ups receive buffer size. Size of Alarm Block: ( Med. to High priority) Make a smarter handling of the Active alarm's if we know the length of the Active Alarm Block. Don't need the long loop to parse the alarm's. Maybe use another way to set up the alarm struct in the 'init_alarm_map'. Parse 'Communication Capabilities Block' ( Low priority) Get info of the connected ports ID, number of baud rates, command and respnse length. Parse 'Communication Port List Block': ( Low priority) This block gives info about the communication ports. Some ups'es have multiple comport's, and use one port for eatch load segment. In this block it is possible to get: Number of ports. (In this List) This Comport id (Which Comm Port is reporting this block.) Comport id (Id for eatch port listed. The first comport ID=1) Baudrate of the listed port. Serial config. Port usage: What this Comm Port is being used for: 0 = Unknown usage, No communication occurring. 1 = Undefined / Unknown communication occurring 2 = Waiting to communicate with a UPS 3 = Communication established with a UPS 4 = Waiting to communicate with software or adapter 5 = Communication established software (e.g., LanSafe) or adapter (e.g., ConnectUPS) 6 = Communicating with a Display Device 7 = Multi-drop Serial channel 8 = Communicating with an Outlet Controller Number of outlets. (Number of Outlets "assigned to" (controlled by) this Comm Port) Outlet number. (Each assigned Outlet is listed (1-64)) 'Set outlet parameter command (0x97)' to alter the delay settings or turn the outlet on or off with a delay (0 - 32767 seconds) Rewrite some parts of the driver, to minimise code duplication. (Like the instant commands) Implement support for Password Authorization (XCP spec, §4.3.2) Complete support for settable variables (upsh.setvar) */ #include "main.h" #include /* For ldexp() */ #include /*for FLT_MAX */ #include "nut_stdint.h" /* for uint8_t, uint16_t, uint32_t, ... */ #include "bcmxcp_io.h" #include "bcmxcp.h" #define DRIVER_NAME "BCMXCP UPS driver" #define DRIVER_VERSION "0.33" #define MAX_NUT_NAME_LENGTH 128 #define NUT_OUTLET_POSITION 7 /* driver description structure */ upsdrv_info_t upsdrv_info = { DRIVER_NAME, DRIVER_VERSION, "Martin Schroeder \n" \ "Kjell Claesson \n" \ "Tore Ørpetveit \n" \ "Arnaud Quette \n" \ "Wolfgang Ocker \n" \ "Oliver Wilcock\n" \ "Prachi Gandhi \n" \ "Alf Høgemark \n" \ "Gavrilov Igor", DRV_STABLE, { &comm_upsdrv_info, NULL } }; static uint16_t get_word(const unsigned char*); static uint32_t get_long(const unsigned char*); static float get_float(const unsigned char *data); static void init_command_map(void); static void init_meter_map(void); static void init_alarm_map(void); static bool_t init_command(int size); static void init_config(void); static void init_limit(void); static void init_ext_vars(void); static void init_topology(void); static void init_ups_meter_map(const unsigned char *map, unsigned char len); static void init_ups_alarm_map(const unsigned char *map, unsigned char len); static bool_t set_alarm_support_in_alarm_map(const unsigned char *map, const unsigned int mapIndex, const unsigned int bitmask, const unsigned int alarmMapIndex, const unsigned int alarmBlockIndex); static void decode_meter_map_entry(const unsigned char *entry, const unsigned char format, char* value); static unsigned char init_outlet(unsigned char len); static void init_system_test_capabilities(void); static int instcmd(const char *cmdname, const char *extra); static int setvar(const char *varname, const char *val); static int decode_instcmd_exec(const ssize_t res, const unsigned char exec_status, const char *cmdname, const char *success_msg); static int decode_setvar_exec(const ssize_t res, const unsigned char exec_status, const char *cmdname, const char *success_msg); static float calculate_ups_load(const unsigned char *data); static const char *nut_find_infoval(info_lkp_t *xcp2info, const double value, const bool_t debug_output_nonexisting); /* static const char *FreqTol[3] = {"+/-2%", "+/-5%", "+/-7"}; */ static const char *ABMStatus[4] = { "charging", "discharging", "floating", "resting" }; static const char *OutletStatus[9] = { "unknown", "on/closed", "off/open", "on with pending", "off with pending", "unknown", "unknown", "failed and closed", "failed and open" }; /* Standard Authorization Block */ static unsigned char AUTHOR[4] = {0xCF, 0x69, 0xE8, 0xD5}; static int nphases = 0; static uint16_t outlet_block_len = 0; static const char *cpu_name[5] = { "Cont:", "Inve:", "Rect:", "Netw:", "Disp:" }; static const char *horn_stat[3] = { "disabled", "enabled", "muted" }; /* Battery test results */ static info_lkp_t batt_test_info[] = { { 0, "No test initiated", NULL, NULL }, { 1, "In progress", NULL, NULL }, { 2, "Done and passed", NULL, NULL }, { 3, "Aborted", NULL, NULL }, { 4, "Done and error", NULL, NULL }, { 5, "Test scheduled", NULL, NULL }, /* Not sure about the meaning of the below ones! */ { 6, NULL, NULL, NULL }, /* The string was present but it has now been removed */ { 7, NULL, NULL, NULL }, /* The string was not installed at the last power up */ { 0, NULL, NULL, NULL } }; /* Topology map results */ static info_lkp_t topology_info[] = { { BCMXCP_TOPOLOGY_OFFLINE_SWITCHER_1P, "Off-line switcher, Single Phase", NULL, NULL }, { BCMXCP_TOPOLOGY_LINEINT_UPS_1P, "Line-Interactive UPS, Single Phase", NULL, NULL }, { BCMXCP_TOPOLOGY_LINEINT_UPS_2P, "Line-Interactive UPS, Two Phase", NULL, NULL }, { BCMXCP_TOPOLOGY_LINEINT_UPS_3P, "Line-Interactive UPS, Three Phase", NULL, NULL }, { BCMXCP_TOPOLOGY_DUAL_AC_ONLINE_UPS_1P, "Dual AC Input, On-Line UPS, Single Phase", NULL, NULL }, { BCMXCP_TOPOLOGY_DUAL_AC_ONLINE_UPS_2P, "Dual AC Input, On-Line UPS, Two Phase", NULL, NULL }, { BCMXCP_TOPOLOGY_DUAL_AC_ONLINE_UPS_3P, "Dual AC Input, On-Line UPS, Three Phase", NULL, NULL }, { BCMXCP_TOPOLOGY_ONLINE_UPS_1P, "On-Line UPS, Single Phase", NULL, NULL }, { BCMXCP_TOPOLOGY_ONLINE_UPS_2P, "On-Line UPS, Two Phase", NULL, NULL }, { BCMXCP_TOPOLOGY_ONLINE_UPS_3P, "On-Line UPS, Three Phase", NULL, NULL }, { BCMXCP_TOPOLOGY_PARA_REDUND_ONLINE_UPS_1P, "Parallel Redundant On-Line UPS, Single Phase", NULL, NULL }, { BCMXCP_TOPOLOGY_PARA_REDUND_ONLINE_UPS_2P, "Parallel Redundant On-Line UPS, Two Phase", NULL, NULL }, { BCMXCP_TOPOLOGY_PARA_REDUND_ONLINE_UPS_3P, "Parallel Redundant On-Line UPS, Three Phase", NULL, NULL }, { BCMXCP_TOPOLOGY_PARA_CAPACITY_ONLINE_UPS_1P, "Parallel for Capacity On-Line UPS, Single Phase", NULL, NULL }, { BCMXCP_TOPOLOGY_PARA_CAPACITY_ONLINE_UPS_2P, "Parallel for Capacity On-Line UPS, Two Phase", NULL, NULL }, { BCMXCP_TOPOLOGY_PARA_CAPACITY_ONLINE_UPS_3P, "Parallel for Capacity On-Line UPS, Three Phase", NULL, NULL }, { BCMXCP_TOPOLOGY_SYSTEM_BYPASS_MODULE_3P, "System Bypass Module, Three Phase", NULL, NULL }, { BCMXCP_TOPOLOGY_HOT_TIE_CABINET_3P, "Hot-Tie Cabinet, Three Phase", NULL, NULL }, { BCMXCP_TOPOLOGY_OUTLET_CONTROLLER_1P, "Outlet Controller, Single Phase", NULL, NULL }, { BCMXCP_TOPOLOGY_DUAL_AC_STATIC_SWITCH_3P, "Dual AC Input Static Switch Module, 3 Phase", NULL, NULL }, { 0, NULL, NULL, NULL } }; /* Command map results */ static info_lkp_t command_map_info[] = { { PW_INIT_BAT_TEST, "test.battery.start", NULL, NULL }, { PW_LOAD_OFF_RESTART, "shutdown.return", NULL, NULL }, { PW_UPS_OFF, "shutdown.stayoff", NULL, NULL }, { PW_UPS_ON, "load.on", NULL, NULL }, { PW_GO_TO_BYPASS, "bypass.start", NULL, NULL }, { 0, NULL, NULL, NULL } }; /* System test capabilities results */ static info_lkp_t system_test_info[] = { { PW_SYS_TEST_GENERAL, "test.system.start", NULL, NULL }, /* { PW_SYS_TEST_SCHEDULE_BATTERY_COMMISSION, "test.battery.start.delayed", NULL, NULL }, */ /* { PW_SYS_TEST_ALTERNATE_AC_INPUT, "test.alternate_acinput.start", NULL, NULL }, */ { PW_SYS_TEST_FLASH_LIGHTS, "test.panel.start", NULL, NULL }, { 0, NULL, NULL, NULL } }; /* allocate storage for shared variables (extern in bcmxcp.h) */ BCMXCP_COMMAND_MAP_ENTRY_t bcmxcp_command_map[BCMXCP_COMMAND_MAP_MAX]; BCMXCP_METER_MAP_ENTRY_t bcmxcp_meter_map[BCMXCP_METER_MAP_MAX]; BCMXCP_ALARM_MAP_ENTRY_t bcmxcp_alarm_map[BCMXCP_ALARM_MAP_MAX]; BCMXCP_STATUS_t bcmxcp_status; /* get_word function from nut driver metasys.c */ uint16_t get_word(const unsigned char *buffer) /* return a short integer reading a word in the supplied buffer */ { unsigned char a, b; uint16_t result; a = buffer[0]; b = buffer[1]; result = b*256 + a; return result; } /* get_long function from nut driver metasys.c for meter readings*/ uint32_t get_long(const unsigned char *buffer) /* return a long integer reading 4 bytes in the supplied buffer.*/ { unsigned char a, b, c, d; uint32_t result; a = buffer[0]; b = buffer[1]; c = buffer[2]; d = buffer[3]; result = (256*256*256*d) + (256*256*c) + (256*b) + a; return result; } /* get_float funktion for convering IEEE-754 to float */ float get_float(const unsigned char *data) { int s, e; unsigned long src; long f; src = ((unsigned long)data[3] << 24) | ((unsigned long)data[2] << 16) | ((unsigned long)data[1] << 8) | ((unsigned long)data[0]); s = (src & 0x80000000UL) >> 31; e = (src & 0x7F800000UL) >> 23; f = (src & 0x007FFFFFUL); if (e == 255 && f != 0) { /* NaN (Not a Number) */ return FLT_MAX; } if (e == 255 && f == 0 && s == 1) { /* Negative infinity */ return -FLT_MAX; } if (e == 255 && f == 0 && s == 0) { /* Positive infinity */ return FLT_MAX; } if (e > 0 && e < 255) { /* Normal number */ f += 0x00800000UL; if (s) f = -f; return ldexp(f, e - 150); } if (e == 0 && f != 0) { /* Denormal number */ if (s) f = -f; return ldexp(f, -149); } if (e == 0 && f == 0 && (s == 1 || s == 0)) { /* Zero */ return 0; } /* Never happens */ upslogx(LOG_ERR, "s = %d, e = %d, f = %lu\n", s, e, f); return 0; } /* lightweight function to calculate the 8-bit * two's complement checksum of buf, using XCP data length (including header) * the result must be 0 for the sequence data to be valid */ int checksum_test(const unsigned char *buf) { unsigned char checksum = 0; int i, length; /* buf[2] is the length of the XCP frame ; add 5 for the header */ length = (int)(buf[2]) + 5; for (i = 0; i < length; i++) { checksum += buf[i]; } /* Compute the 8-bit, Two's Complement checksum now and return it */ checksum = ((0x100 - checksum) & 0xFF); return (checksum == 0); } unsigned char calc_checksum(const unsigned char *buf) { unsigned char c; int i; c = 0; for (i = 0; i < 2 + buf[1]; i++) c -= buf[i]; return c; } void init_command_map(void) { int i = 0; /* Clean entire map */ memset(&bcmxcp_command_map, 0, sizeof(BCMXCP_COMMAND_MAP_ENTRY_t) * BCMXCP_COMMAND_MAP_MAX); /* Set all command descriptions */ bcmxcp_command_map[PW_ID_BLOCK_REQ].command_desc = "PW_ID_BLOCK_REQ"; bcmxcp_command_map[PW_EVENT_HISTORY_LOG_REQ].command_desc = "PW_EVENT_HISTORY_LOG_REQ"; bcmxcp_command_map[PW_STATUS_REQ].command_desc = "PW_STATUS_REQ"; bcmxcp_command_map[PW_METER_BLOCK_REQ].command_desc = "PW_METER_BLOCK_REQ"; bcmxcp_command_map[PW_CUR_ALARM_REQ].command_desc = "PW_CUR_ALARM_REQ"; bcmxcp_command_map[PW_CONFIG_BLOCK_REQ].command_desc = "PW_CONFIG_BLOCK_REQ"; bcmxcp_command_map[PW_UTILITY_STATISTICS_BLOCK_REQ].command_desc = "PW_UTILITY_STATISTICS_BLOCK_REQ"; bcmxcp_command_map[PW_WAVEFORM_BLOCK_REQ].command_desc = "PW_WAVEFORM_BLOCK_REQ"; bcmxcp_command_map[PW_BATTERY_REQ].command_desc = "PW_BATTERY_REQ"; bcmxcp_command_map[PW_LIMIT_BLOCK_REQ].command_desc = "PW_LIMIT_BLOCK_REQ"; bcmxcp_command_map[PW_TEST_RESULT_REQ].command_desc = "PW_TEST_RESULT_REQ"; bcmxcp_command_map[PW_COMMAND_LIST_REQ].command_desc = "PW_COMMAND_LIST_REQ"; bcmxcp_command_map[PW_OUT_MON_BLOCK_REQ].command_desc = "PW_OUT_MON_BLOCK_REQ"; bcmxcp_command_map[PW_COM_CAP_REQ].command_desc = "PW_COM_CAP_REQ"; bcmxcp_command_map[PW_UPS_TOP_DATA_REQ].command_desc = "PW_UPS_TOP_DATA_REQ"; bcmxcp_command_map[PW_COM_PORT_LIST_BLOCK_REQ].command_desc = "PW_COM_PORT_LIST_BLOCK_REQ"; bcmxcp_command_map[PW_REQUEST_SCRATCHPAD_DATA_REQ].command_desc = "PW_REQUEST_SCRATCHPAD_DATA_REQ"; bcmxcp_command_map[PW_GO_TO_BYPASS].command_desc = "PW_GO_TO_BYPASS"; bcmxcp_command_map[PW_UPS_ON].command_desc = "PW_UPS_ON"; bcmxcp_command_map[PW_LOAD_OFF_RESTART].command_desc = "PW_LOAD_OFF_RESTART"; bcmxcp_command_map[PW_UPS_OFF].command_desc = "PW_UPS_OFF"; bcmxcp_command_map[PW_DECREMENT_OUTPUT_VOLTAGE].command_desc = "PW_DECREMENT_OUTPUT_VOLTAGE"; bcmxcp_command_map[PW_INCREMENT_OUTPUT_VOLTAGE].command_desc = "PW_INCREMENT_OUTPUT_VOLTAGE"; bcmxcp_command_map[PW_SET_TIME_AND_DATE].command_desc = "PW_SET_TIME_AND_DATE"; bcmxcp_command_map[PW_UPS_ON_TIME].command_desc = "PW_UPS_ON_TIME"; bcmxcp_command_map[PW_UPS_ON_AT_TIME].command_desc = "PW_UPS_ON_AT_TIME"; bcmxcp_command_map[PW_UPS_OFF_TIME].command_desc = "PW_UPS_OFF_TIME"; bcmxcp_command_map[PW_UPS_OFF_AT_TIME].command_desc = "PW_UPS_OFF_AT_TIME"; bcmxcp_command_map[PW_SET_CONF_COMMAND].command_desc = "PW_SET_CONF_COMMAND"; bcmxcp_command_map[PW_SET_OUTLET_COMMAND].command_desc = "PW_SET_OUTLET_COMMAND"; bcmxcp_command_map[PW_SET_COM_COMMAND].command_desc = "PW_SET_COM_COMMAND"; bcmxcp_command_map[PW_SET_SCRATHPAD_SECTOR].command_desc = "PW_SET_SCRATHPAD_SECTOR"; bcmxcp_command_map[PW_SET_POWER_STRATEGY].command_desc = "PW_SET_POWER_STRATEGY"; bcmxcp_command_map[PW_SET_REQ_ONLY_MODE].command_desc = "PW_SET_REQ_ONLY_MODE"; bcmxcp_command_map[PW_SET_UNREQUESTED_MODE].command_desc = "PW_SET_UNREQUESTED_MODE"; bcmxcp_command_map[PW_INIT_BAT_TEST].command_desc = "PW_INIT_BAT_TEST"; bcmxcp_command_map[PW_INIT_SYS_TEST].command_desc = "PW_INIT_SYS_TEST"; bcmxcp_command_map[PW_SELECT_SUBMODULE].command_desc = "PW_SELECT_SUBMODULE"; bcmxcp_command_map[PW_AUTHORIZATION_CODE].command_desc = "PW_AUTHORIZATION_CODE"; for (i = 0; i < BCMXCP_COMMAND_MAP_MAX; i++) { bcmxcp_command_map[i].command_byte = 0; } } void init_meter_map(void) { /* Clean entire map */ memset(&bcmxcp_meter_map, 0, sizeof(BCMXCP_METER_MAP_ENTRY_t) * BCMXCP_METER_MAP_MAX); /* Set all corresponding mappings NUT <-> BCM/XCP */ bcmxcp_meter_map[BCMXCP_METER_MAP_OUTPUT_VOLTS_AB].nut_entity = "output.L1-L2.voltage"; bcmxcp_meter_map[BCMXCP_METER_MAP_OUTPUT_VOLTS_BC].nut_entity = "output.L2-L3.voltage"; bcmxcp_meter_map[BCMXCP_METER_MAP_OUTPUT_VOLTS_CA].nut_entity = "output.L3-L1.voltage"; bcmxcp_meter_map[BCMXCP_METER_MAP_INPUT_VOLTS_AB].nut_entity = "input.L1-L2.voltage"; bcmxcp_meter_map[BCMXCP_METER_MAP_INPUT_VOLTS_BC].nut_entity = "input.L2-L3.voltage"; bcmxcp_meter_map[BCMXCP_METER_MAP_INPUT_VOLTS_CA].nut_entity = "input.L3-L1.voltage"; bcmxcp_meter_map[BCMXCP_METER_MAP_INPUT_CURRENT_PHASE_B].nut_entity = "input.L2.current"; bcmxcp_meter_map[BCMXCP_METER_MAP_INPUT_CURRENT_PHASE_C].nut_entity = "input.L3.current"; bcmxcp_meter_map[BCMXCP_METER_MAP_INPUT_WATTS].nut_entity = "input.realpower"; bcmxcp_meter_map[BCMXCP_METER_MAP_OUTPUT_VA].nut_entity = "ups.power"; bcmxcp_meter_map[BCMXCP_METER_MAP_INPUT_VA].nut_entity = "input.power"; bcmxcp_meter_map[BCMXCP_METER_MAP_OUTPUT_POWER_FACTOR].nut_entity = "output.powerfactor"; bcmxcp_meter_map[BCMXCP_METER_MAP_INPUT_POWER_FACTOR].nut_entity = "input.powerfactor"; if (nphases == 1) { bcmxcp_meter_map[BCMXCP_METER_MAP_INPUT_CURRENT_PHASE_A].nut_entity = "input.current"; bcmxcp_meter_map[BCMXCP_METER_MAP_PERCENT_LOAD_PHASE_A].nut_entity = "ups.load"; /* TODO: Decide on corresponding three-phase variable mapping. */ bcmxcp_meter_map[BCMXCP_METER_MAP_BYPASS_VOLTS_PHASE_A].nut_entity = "input.bypass.voltage"; bcmxcp_meter_map[BCMXCP_METER_MAP_INPUT_VOLTS_PHASE_A].nut_entity = "input.voltage"; bcmxcp_meter_map[BCMXCP_METER_MAP_LOAD_CURRENT_PHASE_A].nut_entity = "output.current"; bcmxcp_meter_map[BCMXCP_METER_MAP_LOAD_CURRENT_PHASE_A_BAR_CHART].nut_entity = "output.current.nominal"; bcmxcp_meter_map[BCMXCP_METER_MAP_OUTPUT_VOLTS_A].nut_entity = "output.voltage"; bcmxcp_meter_map[BCMXCP_METER_MAP_OUTPUT_WATTS].nut_entity = "ups.realpower"; } else { bcmxcp_meter_map[BCMXCP_METER_MAP_INPUT_CURRENT_PHASE_A].nut_entity = "input.L1.current"; bcmxcp_meter_map[BCMXCP_METER_MAP_PERCENT_LOAD_PHASE_A].nut_entity = "output.L1.power.percent"; bcmxcp_meter_map[BCMXCP_METER_MAP_PERCENT_LOAD_PHASE_B].nut_entity = "output.L2.power.percent"; bcmxcp_meter_map[BCMXCP_METER_MAP_PERCENT_LOAD_PHASE_C].nut_entity = "output.L3.power.percent"; bcmxcp_meter_map[BCMXCP_METER_MAP_OUTPUT_VA_PHASE_A].nut_entity = "output.L1.power"; bcmxcp_meter_map[BCMXCP_METER_MAP_OUTPUT_VA_PHASE_B].nut_entity = "output.L2.power"; bcmxcp_meter_map[BCMXCP_METER_MAP_OUTPUT_VA_PHASE_C].nut_entity = "output.L3.power"; bcmxcp_meter_map[BCMXCP_METER_MAP_BYPASS_VOLTS_PHASE_A].nut_entity = "input.bypass.L1-N.voltage"; bcmxcp_meter_map[BCMXCP_METER_MAP_BYPASS_VOLTS_PHASE_B].nut_entity = "input.bypass.L2-N.voltage"; bcmxcp_meter_map[BCMXCP_METER_MAP_BYPASS_VOLTS_PHASE_C].nut_entity = "input.bypass.L3-N.voltage"; bcmxcp_meter_map[BCMXCP_METER_MAP_INPUT_VOLTS_PHASE_A].nut_entity = "input.L1-N.voltage"; bcmxcp_meter_map[BCMXCP_METER_MAP_LOAD_CURRENT_PHASE_A].nut_entity = "output.L1.current"; bcmxcp_meter_map[BCMXCP_METER_MAP_LOAD_CURRENT_PHASE_A_BAR_CHART].nut_entity = "output.L1.current.nominal"; bcmxcp_meter_map[BCMXCP_METER_MAP_OUTPUT_VOLTS_A].nut_entity = "output.L1-N.voltage"; } bcmxcp_meter_map[BCMXCP_METER_MAP_OUTPUT_FREQUENCY].nut_entity = "output.frequency"; bcmxcp_meter_map[BCMXCP_METER_MAP_INPUT_FREQUENCY].nut_entity = "input.frequency"; bcmxcp_meter_map[BCMXCP_METER_MAP_BYPASS_FREQUENCY].nut_entity = "input.bypass.frequency"; bcmxcp_meter_map[BCMXCP_METER_MAP_BATTERY_CURRENT].nut_entity = "battery.current"; bcmxcp_meter_map[BCMXCP_METER_MAP_BATTERY_VOLTAGE].nut_entity = "battery.voltage"; bcmxcp_meter_map[BCMXCP_METER_MAP_PERCENT_BATTERY_LEFT].nut_entity = "battery.charge"; bcmxcp_meter_map[BCMXCP_METER_MAP_BATTERY_TIME_REMAINING].nut_entity = "battery.runtime"; bcmxcp_meter_map[BCMXCP_METER_MAP_BATTERY_DCUV_BAR_CHART].nut_entity = "battery.voltage.low"; bcmxcp_meter_map[BCMXCP_METER_MAP_LOW_BATTERY_WARNING_V_BAR_CHART].nut_entity = "battery.charge.low"; bcmxcp_meter_map[BCMXCP_METER_MAP_BATTERY_DISCHARGING_CURRENT_BAR_CHART].nut_entity = "battery.current.total"; bcmxcp_meter_map[BCMXCP_METER_MAP_INPUT_VOLTS_PHASE_B].nut_entity = "input.L2-N.voltage"; bcmxcp_meter_map[BCMXCP_METER_MAP_INPUT_VOLTS_PHASE_C].nut_entity = "input.L3-N.voltage"; bcmxcp_meter_map[BCMXCP_METER_MAP_AMBIENT_TEMPERATURE].nut_entity = "ambient.temperature"; bcmxcp_meter_map[BCMXCP_METER_MAP_HEATSINK_TEMPERATURE].nut_entity = "ups.temperature"; bcmxcp_meter_map[BCMXCP_METER_MAP_POWER_SUPPLY_TEMPERATURE].nut_entity = "ambient.1.temperature"; bcmxcp_meter_map[BCMXCP_METER_MAP_LOAD_CURRENT_PHASE_B].nut_entity = "output.L2.current"; bcmxcp_meter_map[BCMXCP_METER_MAP_LOAD_CURRENT_PHASE_C].nut_entity = "output.L3.current"; bcmxcp_meter_map[BCMXCP_METER_MAP_LOAD_CURRENT_PHASE_B_BAR_CHART].nut_entity = "output.L2.current.nominal"; bcmxcp_meter_map[BCMXCP_METER_MAP_LOAD_CURRENT_PHASE_C_BAR_CHART].nut_entity = "output.L3.current.nominal"; bcmxcp_meter_map[BCMXCP_METER_MAP_OUTPUT_VA_BAR_CHART].nut_entity = "ups.power.nominal"; bcmxcp_meter_map[BCMXCP_METER_MAP_DATE].nut_entity = "ups.date"; bcmxcp_meter_map[BCMXCP_METER_MAP_TIME].nut_entity = "ups.time"; bcmxcp_meter_map[BCMXCP_METER_MAP_BATTERY_TEMPERATURE].nut_entity = "battery.temperature"; bcmxcp_meter_map[BCMXCP_METER_MAP_OUTPUT_VOLTS_B].nut_entity = "output.L2-N.voltage"; bcmxcp_meter_map[BCMXCP_METER_MAP_OUTPUT_VOLTS_C].nut_entity = "output.L3-N.voltage"; bcmxcp_meter_map[BCMXCP_METER_MAP_OUTPUT_WATTS_PHASE_A].nut_entity = "ups.L1-N.realpower"; bcmxcp_meter_map[BCMXCP_METER_MAP_OUTPUT_WATTS_PHASE_B].nut_entity = "ups.L2-N.realpower"; bcmxcp_meter_map[BCMXCP_METER_MAP_OUTPUT_WATTS_PHASE_C].nut_entity = "ups.L3-N.realpower"; bcmxcp_meter_map[BCMXCP_METER_MAP_OUTPUT_WATTS_PHASE_A_B_C_BAR_CHART].nut_entity = "ups.realpower.nominal"; bcmxcp_meter_map[BCMXCP_METER_MAP_LINE_EVENT_COUNTER].nut_entity = "input.quality"; } void init_alarm_map(void) { /* Clean entire map */ memset(&bcmxcp_alarm_map, 0, sizeof(BCMXCP_ALARM_MAP_ENTRY_t) * BCMXCP_ALARM_MAP_MAX); /* Set all alarm descriptions */ bcmxcp_alarm_map[BCMXCP_ALARM_INVERTER_AC_OVER_VOLTAGE].alarm_desc = "INVERTER_AC_OVER_VOLTAGE"; bcmxcp_alarm_map[BCMXCP_ALARM_INVERTER_AC_UNDER_VOLTAGE].alarm_desc = "INVERTER_AC_UNDER_VOLTAGE"; bcmxcp_alarm_map[BCMXCP_ALARM_INVERTER_OVER_OR_UNDER_FREQ].alarm_desc = "INVERTER_OVER_OR_UNDER_FREQ"; bcmxcp_alarm_map[BCMXCP_ALARM_BYPASS_AC_OVER_VOLTAGE].alarm_desc = "BYPASS_AC_OVER_VOLTAGE"; bcmxcp_alarm_map[BCMXCP_ALARM_BYPASS_AC_UNDER_VOLTAGE].alarm_desc = "BYPASS_AC_UNDER_VOLTAGE"; bcmxcp_alarm_map[BCMXCP_ALARM_BYPASS_OVER_OR_UNDER_FREQ].alarm_desc = "BYPASS_OVER_OR_UNDER_FREQ"; bcmxcp_alarm_map[BCMXCP_ALARM_INPUT_AC_OVER_VOLTAGE].alarm_desc = "INPUT_AC_OVER_VOLTAGE"; bcmxcp_alarm_map[BCMXCP_ALARM_INPUT_AC_UNDER_VOLTAGE].alarm_desc = "INPUT_AC_UNDER_VOLTAGE"; bcmxcp_alarm_map[BCMXCP_ALARM_INPUT_UNDER_OR_OVER_FREQ].alarm_desc = "INPUT_UNDER_OR_OVER_FREQ"; bcmxcp_alarm_map[BCMXCP_ALARM_OUTPUT_OVER_VOLTAGE].alarm_desc = "OUTPUT_OVER_VOLTAGE"; bcmxcp_alarm_map[BCMXCP_ALARM_OUTPUT_UNDER_VOLTAGE].alarm_desc = "OUTPUT_UNDER_VOLTAGE"; bcmxcp_alarm_map[BCMXCP_ALARM_OUTPUT_UNDER_OR_OVER_FREQ].alarm_desc = "OUTPUT_UNDER_OR_OVER_FREQ"; bcmxcp_alarm_map[BCMXCP_ALARM_REMOTE_EMERGENCY_PWR_OFF].alarm_desc = "REMOTE_EMERGENCY_PWR_OFF"; bcmxcp_alarm_map[BCMXCP_ALARM_REMOTE_GO_TO_BYPASS].alarm_desc = "REMOTE_GO_TO_BYPASS"; bcmxcp_alarm_map[BCMXCP_ALARM_BUILDING_ALARM_6].alarm_desc = "BUILDING_ALARM_6"; bcmxcp_alarm_map[BCMXCP_ALARM_BUILDING_ALARM_5].alarm_desc = "BUILDING_ALARM_5"; bcmxcp_alarm_map[BCMXCP_ALARM_BUILDING_ALARM_4].alarm_desc = "BUILDING_ALARM_4"; bcmxcp_alarm_map[BCMXCP_ALARM_BUILDING_ALARM_3].alarm_desc = "BUILDING_ALARM_3"; bcmxcp_alarm_map[BCMXCP_ALARM_BUILDING_ALARM_2].alarm_desc = "BUILDING_ALARM_2"; bcmxcp_alarm_map[BCMXCP_ALARM_BUILDING_ALARM_1].alarm_desc = "BUILDING_ALARM_1"; bcmxcp_alarm_map[BCMXCP_ALARM_STATIC_SWITCH_OVER_TEMP].alarm_desc = "STATIC_SWITCH_OVER_TEMP"; bcmxcp_alarm_map[BCMXCP_ALARM_CHARGER_OVER_TEMP].alarm_desc = "CHARGER_OVER_TEMP"; bcmxcp_alarm_map[BCMXCP_ALARM_CHARGER_LOGIC_PWR_FAIL].alarm_desc = "CHARGER_LOGIC_PWR_FAIL"; bcmxcp_alarm_map[BCMXCP_ALARM_CHARGER_OVER_VOLTAGE_OR_CURRENT].alarm_desc = "CHARGER_OVER_VOLTAGE_OR_CURRENT"; bcmxcp_alarm_map[BCMXCP_ALARM_INVERTER_OVER_TEMP].alarm_desc = "INVERTER_OVER_TEMP"; bcmxcp_alarm_map[BCMXCP_ALARM_OUTPUT_OVERLOAD].alarm_desc = "OUTPUT_OVERLOAD"; bcmxcp_alarm_map[BCMXCP_ALARM_RECTIFIER_INPUT_OVER_CURRENT].alarm_desc = "RECTIFIER_INPUT_OVER_CURRENT"; bcmxcp_alarm_map[BCMXCP_ALARM_INVERTER_OUTPUT_OVER_CURRENT].alarm_desc = "INVERTER_OUTPUT_OVER_CURRENT"; bcmxcp_alarm_map[BCMXCP_ALARM_DC_LINK_OVER_VOLTAGE].alarm_desc = "DC_LINK_OVER_VOLTAGE"; bcmxcp_alarm_map[BCMXCP_ALARM_DC_LINK_UNDER_VOLTAGE].alarm_desc = "DC_LINK_UNDER_VOLTAGE"; bcmxcp_alarm_map[BCMXCP_ALARM_RECTIFIER_FAILED].alarm_desc = "RECTIFIER_FAILED"; bcmxcp_alarm_map[BCMXCP_ALARM_INVERTER_FAULT].alarm_desc = "INVERTER_FAULT"; bcmxcp_alarm_map[BCMXCP_ALARM_BATTERY_CONNECTOR_FAIL].alarm_desc = "BATTERY_CONNECTOR_FAIL"; bcmxcp_alarm_map[BCMXCP_ALARM_BYPASS_BREAKER_FAIL].alarm_desc = "BYPASS_BREAKER_FAIL"; bcmxcp_alarm_map[BCMXCP_ALARM_CHARGER_FAIL].alarm_desc = "CHARGER_FAIL"; bcmxcp_alarm_map[BCMXCP_ALARM_RAMP_UP_FAILED].alarm_desc = "RAMP_UP_FAILED"; bcmxcp_alarm_map[BCMXCP_ALARM_STATIC_SWITCH_FAILED].alarm_desc = "STATIC_SWITCH_FAILED"; bcmxcp_alarm_map[BCMXCP_ALARM_ANALOG_AD_REF_FAIL].alarm_desc = "ANALOG_AD_REF_FAIL"; bcmxcp_alarm_map[BCMXCP_ALARM_BYPASS_UNCALIBRATED].alarm_desc = "BYPASS_UNCALIBRATED"; bcmxcp_alarm_map[BCMXCP_ALARM_RECTIFIER_UNCALIBRATED].alarm_desc = "RECTIFIER_UNCALIBRATED"; bcmxcp_alarm_map[BCMXCP_ALARM_OUTPUT_UNCALIBRATED].alarm_desc = "OUTPUT_UNCALIBRATED"; bcmxcp_alarm_map[BCMXCP_ALARM_INVERTER_UNCALIBRATED].alarm_desc = "INVERTER_UNCALIBRATED"; bcmxcp_alarm_map[BCMXCP_ALARM_DC_VOLT_UNCALIBRATED].alarm_desc = "DC_VOLT_UNCALIBRATED"; bcmxcp_alarm_map[BCMXCP_ALARM_OUTPUT_CURRENT_UNCALIBRATED].alarm_desc = "OUTPUT_CURRENT_UNCALIBRATED"; bcmxcp_alarm_map[BCMXCP_ALARM_RECTIFIER_CURRENT_UNCALIBRATED].alarm_desc = "RECTIFIER_CURRENT_UNCALIBRATED"; bcmxcp_alarm_map[BCMXCP_ALARM_BATTERY_CURRENT_UNCALIBRATED].alarm_desc = "BATTERY_CURRENT_UNCALIBRATED"; bcmxcp_alarm_map[BCMXCP_ALARM_INVERTER_ON_OFF_STAT_FAIL].alarm_desc = "INVERTER_ON_OFF_STAT_FAIL"; bcmxcp_alarm_map[BCMXCP_ALARM_BATTERY_CURRENT_LIMIT].alarm_desc = "BATTERY_CURRENT_LIMIT"; bcmxcp_alarm_map[BCMXCP_ALARM_INVERTER_STARTUP_FAIL].alarm_desc = "INVERTER_STARTUP_FAIL"; bcmxcp_alarm_map[BCMXCP_ALARM_ANALOG_BOARD_AD_STAT_FAIL].alarm_desc = "ANALOG_BOARD_AD_STAT_FAIL"; bcmxcp_alarm_map[BCMXCP_ALARM_OUTPUT_CURRENT_OVER_100].alarm_desc = "OUTPUT_CURRENT_OVER_100"; bcmxcp_alarm_map[BCMXCP_ALARM_BATTERY_GROUND_FAULT].alarm_desc = "BATTERY_GROUND_FAULT"; bcmxcp_alarm_map[BCMXCP_ALARM_WAITING_FOR_CHARGER_SYNC].alarm_desc = "WAITING_FOR_CHARGER_SYNC"; bcmxcp_alarm_map[BCMXCP_ALARM_NV_RAM_FAIL].alarm_desc = "NV_RAM_FAIL"; bcmxcp_alarm_map[BCMXCP_ALARM_ANALOG_BOARD_AD_TIMEOUT].alarm_desc = "ANALOG_BOARD_AD_TIMEOUT"; bcmxcp_alarm_map[BCMXCP_ALARM_SHUTDOWN_IMMINENT].alarm_desc = "SHUTDOWN_IMMINENT"; bcmxcp_alarm_map[BCMXCP_ALARM_BATTERY_LOW].alarm_desc = "BATTERY_LOW"; bcmxcp_alarm_map[BCMXCP_ALARM_UTILITY_FAIL].alarm_desc = "UTILITY_FAIL"; bcmxcp_alarm_map[BCMXCP_ALARM_OUTPUT_SHORT_CIRCUIT].alarm_desc = "OUTPUT_SHORT_CIRCUIT"; bcmxcp_alarm_map[BCMXCP_ALARM_UTILITY_NOT_PRESENT].alarm_desc = "UTILITY_NOT_PRESENT"; bcmxcp_alarm_map[BCMXCP_ALARM_FULL_TIME_CHARGING].alarm_desc = "FULL_TIME_CHARGING"; bcmxcp_alarm_map[BCMXCP_ALARM_FAST_BYPASS_COMMAND].alarm_desc = "FAST_BYPASS_COMMAND"; bcmxcp_alarm_map[BCMXCP_ALARM_AD_ERROR].alarm_desc = "AD_ERROR"; bcmxcp_alarm_map[BCMXCP_ALARM_INTERNAL_COM_FAIL].alarm_desc = "INTERNAL_COM_FAIL"; bcmxcp_alarm_map[BCMXCP_ALARM_RECTIFIER_SELFTEST_FAIL].alarm_desc = "RECTIFIER_SELFTEST_FAIL"; bcmxcp_alarm_map[BCMXCP_ALARM_RECTIFIER_EEPROM_FAIL].alarm_desc = "RECTIFIER_EEPROM_FAIL"; bcmxcp_alarm_map[BCMXCP_ALARM_RECTIFIER_EPROM_FAIL].alarm_desc = "RECTIFIER_EPROM_FAIL"; bcmxcp_alarm_map[BCMXCP_ALARM_INPUT_LINE_VOLTAGE_LOSS].alarm_desc = "INPUT_LINE_VOLTAGE_LOSS"; bcmxcp_alarm_map[BCMXCP_ALARM_BATTERY_DC_OVER_VOLTAGE].alarm_desc = "BATTERY_DC_OVER_VOLTAGE"; bcmxcp_alarm_map[BCMXCP_ALARM_POWER_SUPPLY_OVER_TEMP].alarm_desc = "POWER_SUPPLY_OVER_TEMP"; bcmxcp_alarm_map[BCMXCP_ALARM_POWER_SUPPLY_FAIL].alarm_desc = "POWER_SUPPLY_FAIL"; bcmxcp_alarm_map[BCMXCP_ALARM_POWER_SUPPLY_5V_FAIL].alarm_desc = "POWER_SUPPLY_5V_FAIL"; bcmxcp_alarm_map[BCMXCP_ALARM_POWER_SUPPLY_12V_FAIL].alarm_desc = "POWER_SUPPLY_12V_FAIL"; bcmxcp_alarm_map[BCMXCP_ALARM_HEATSINK_OVER_TEMP].alarm_desc = "HEATSINK_OVER_TEMP"; bcmxcp_alarm_map[BCMXCP_ALARM_HEATSINK_TEMP_SENSOR_FAIL].alarm_desc = "HEATSINK_TEMP_SENSOR_FAIL"; bcmxcp_alarm_map[BCMXCP_ALARM_RECTIFIER_CURRENT_OVER_125].alarm_desc = "RECTIFIER_CURRENT_OVER_125"; bcmxcp_alarm_map[BCMXCP_ALARM_RECTIFIER_FAULT_INTERRUPT_FAIL].alarm_desc = "RECTIFIER_FAULT_INTERRUPT_FAIL"; bcmxcp_alarm_map[BCMXCP_ALARM_RECTIFIER_POWER_CAPACITOR_FAIL].alarm_desc = "RECTIFIER_POWER_CAPACITOR_FAIL"; bcmxcp_alarm_map[BCMXCP_ALARM_INVERTER_PROGRAM_STACK_ERROR].alarm_desc = "INVERTER_PROGRAM_STACK_ERROR"; bcmxcp_alarm_map[BCMXCP_ALARM_INVERTER_BOARD_SELFTEST_FAIL].alarm_desc = "INVERTER_BOARD_SELFTEST_FAIL"; bcmxcp_alarm_map[BCMXCP_ALARM_INVERTER_AD_SELFTEST_FAIL].alarm_desc = "INVERTER_AD_SELFTEST_FAIL"; bcmxcp_alarm_map[BCMXCP_ALARM_INVERTER_RAM_SELFTEST_FAIL].alarm_desc = "INVERTER_RAM_SELFTEST_FAIL"; bcmxcp_alarm_map[BCMXCP_ALARM_NV_MEMORY_CHECKSUM_FAIL].alarm_desc = "NV_MEMORY_CHECKSUM_FAIL"; bcmxcp_alarm_map[BCMXCP_ALARM_PROGRAM_CHECKSUM_FAIL].alarm_desc = "PROGRAM_CHECKSUM_FAIL"; bcmxcp_alarm_map[BCMXCP_ALARM_INVERTER_CPU_SELFTEST_FAIL].alarm_desc = "INVERTER_CPU_SELFTEST_FAIL"; bcmxcp_alarm_map[BCMXCP_ALARM_NETWORK_NOT_RESPONDING].alarm_desc = "NETWORK_NOT_RESPONDING"; bcmxcp_alarm_map[BCMXCP_ALARM_FRONT_PANEL_SELFTEST_FAIL].alarm_desc = "FRONT_PANEL_SELFTEST_FAIL"; bcmxcp_alarm_map[BCMXCP_ALARM_NODE_EEPROM_VERIFICATION_ERROR].alarm_desc = "NODE_EEPROM_VERIFICATION_ERROR"; bcmxcp_alarm_map[BCMXCP_ALARM_OUTPUT_AC_OVER_VOLT_TEST_FAIL].alarm_desc = "OUTPUT_AC_OVER_VOLT_TEST_FAIL"; bcmxcp_alarm_map[BCMXCP_ALARM_OUTPUT_DC_OVER_VOLTAGE].alarm_desc = "OUTPUT_DC_OVER_VOLTAGE"; bcmxcp_alarm_map[BCMXCP_ALARM_INPUT_PHASE_ROTATION_ERROR].alarm_desc = "INPUT_PHASE_ROTATION_ERROR"; bcmxcp_alarm_map[BCMXCP_ALARM_INVERTER_RAMP_UP_TEST_FAILED].alarm_desc = "INVERTER_RAMP_UP_TEST_FAILED"; bcmxcp_alarm_map[BCMXCP_ALARM_INVERTER_OFF_COMMAND].alarm_desc = "INVERTER_OFF_COMMAND"; bcmxcp_alarm_map[BCMXCP_ALARM_INVERTER_ON_COMMAND].alarm_desc = "INVERTER_ON_COMMAND"; bcmxcp_alarm_map[BCMXCP_ALARM_TO_BYPASS_COMMAND].alarm_desc = "TO_BYPASS_COMMAND"; bcmxcp_alarm_map[BCMXCP_ALARM_FROM_BYPASS_COMMAND].alarm_desc = "FROM_BYPASS_COMMAND"; bcmxcp_alarm_map[BCMXCP_ALARM_AUTO_MODE_COMMAND].alarm_desc = "AUTO_MODE_COMMAND"; bcmxcp_alarm_map[BCMXCP_ALARM_EMERGENCY_SHUTDOWN_COMMAND].alarm_desc = "EMERGENCY_SHUTDOWN_COMMAND"; bcmxcp_alarm_map[BCMXCP_ALARM_SETUP_SWITCH_OPEN].alarm_desc = "SETUP_SWITCH_OPEN"; bcmxcp_alarm_map[BCMXCP_ALARM_INVERTER_OVER_VOLT_INT].alarm_desc = "INVERTER_OVER_VOLT_INT"; bcmxcp_alarm_map[BCMXCP_ALARM_INVERTER_UNDER_VOLT_INT].alarm_desc = "INVERTER_UNDER_VOLT_INT"; bcmxcp_alarm_map[BCMXCP_ALARM_ABSOLUTE_DCOV_ACOV].alarm_desc = "ABSOLUTE_DCOV_ACOV"; bcmxcp_alarm_map[BCMXCP_ALARM_PHASE_A_CURRENT_LIMIT].alarm_desc = "PHASE_A_CURRENT_LIMIT"; bcmxcp_alarm_map[BCMXCP_ALARM_PHASE_B_CURRENT_LIMIT].alarm_desc = "PHASE_B_CURRENT_LIMIT"; bcmxcp_alarm_map[BCMXCP_ALARM_PHASE_C_CURRENT_LIMIT].alarm_desc = "PHASE_C_CURRENT_LIMIT"; bcmxcp_alarm_map[BCMXCP_ALARM_BYPASS_NOT_AVAILABLE].alarm_desc = "BYPASS_NOT_AVAILABLE"; bcmxcp_alarm_map[BCMXCP_ALARM_RECTIFIER_BREAKER_OPEN].alarm_desc = "RECTIFIER_BREAKER_OPEN"; bcmxcp_alarm_map[BCMXCP_ALARM_BATTERY_CONTACTOR_OPEN].alarm_desc = "BATTERY_CONTACTOR_OPEN"; bcmxcp_alarm_map[BCMXCP_ALARM_INVERTER_CONTACTOR_OPEN].alarm_desc = "INVERTER_CONTACTOR_OPEN"; bcmxcp_alarm_map[BCMXCP_ALARM_BYPASS_BREAKER_OPEN].alarm_desc = "BYPASS_BREAKER_OPEN"; bcmxcp_alarm_map[BCMXCP_ALARM_INV_BOARD_ACOV_INT_TEST_FAIL].alarm_desc = "INV_BOARD_ACOV_INT_TEST_FAIL"; bcmxcp_alarm_map[BCMXCP_ALARM_INVERTER_OVER_TEMP_TRIP].alarm_desc = "INVERTER_OVER_TEMP_TRIP"; bcmxcp_alarm_map[BCMXCP_ALARM_INV_BOARD_ACUV_INT_TEST_FAIL].alarm_desc = "INV_BOARD_ACUV_INT_TEST_FAIL"; bcmxcp_alarm_map[BCMXCP_ALARM_INVERTER_VOLTAGE_FEEDBACK_ERROR].alarm_desc = "INVERTER_VOLTAGE_FEEDBACK_ERROR"; bcmxcp_alarm_map[BCMXCP_ALARM_DC_UNDER_VOLTAGE_TIMEOUT].alarm_desc = "DC_UNDER_VOLTAGE_TIMEOUT"; bcmxcp_alarm_map[BCMXCP_ALARM_AC_UNDER_VOLTAGE_TIMEOUT].alarm_desc = "AC_UNDER_VOLTAGE_TIMEOUT"; bcmxcp_alarm_map[BCMXCP_ALARM_DC_UNDER_VOLTAGE_WHILE_CHARGE].alarm_desc = "DC_UNDER_VOLTAGE_WHILE_CHARGE"; bcmxcp_alarm_map[BCMXCP_ALARM_INVERTER_VOLTAGE_BIAS_ERROR].alarm_desc = "INVERTER_VOLTAGE_BIAS_ERROR"; bcmxcp_alarm_map[BCMXCP_ALARM_RECTIFIER_PHASE_ROTATION].alarm_desc = "RECTIFIER_PHASE_ROTATION"; bcmxcp_alarm_map[BCMXCP_ALARM_BYPASS_PHASER_ROTATION].alarm_desc = "BYPASS_PHASER_ROTATION"; bcmxcp_alarm_map[BCMXCP_ALARM_SYSTEM_INTERFACE_BOARD_FAIL].alarm_desc = "SYSTEM_INTERFACE_BOARD_FAIL"; bcmxcp_alarm_map[BCMXCP_ALARM_PARALLEL_BOARD_FAIL].alarm_desc = "PARALLEL_BOARD_FAIL"; bcmxcp_alarm_map[BCMXCP_ALARM_LOST_LOAD_SHARING_PHASE_A].alarm_desc = "LOST_LOAD_SHARING_PHASE_A"; bcmxcp_alarm_map[BCMXCP_ALARM_LOST_LOAD_SHARING_PHASE_B].alarm_desc = "LOST_LOAD_SHARING_PHASE_B"; bcmxcp_alarm_map[BCMXCP_ALARM_LOST_LOAD_SHARING_PHASE_C].alarm_desc = "LOST_LOAD_SHARING_PHASE_C"; bcmxcp_alarm_map[BCMXCP_ALARM_DC_OVER_VOLTAGE_TIMEOUT].alarm_desc = "DC_OVER_VOLTAGE_TIMEOUT"; bcmxcp_alarm_map[BCMXCP_ALARM_BATTERY_TOTALLY_DISCHARGED].alarm_desc = "BATTERY_TOTALLY_DISCHARGED"; bcmxcp_alarm_map[BCMXCP_ALARM_INVERTER_PHASE_BIAS_ERROR].alarm_desc = "INVERTER_PHASE_BIAS_ERROR"; bcmxcp_alarm_map[BCMXCP_ALARM_INVERTER_VOLTAGE_BIAS_ERROR_2].alarm_desc = "INVERTER_VOLTAGE_BIAS_ERROR_2"; bcmxcp_alarm_map[BCMXCP_ALARM_DC_LINK_BLEED_COMPLETE].alarm_desc = "DC_LINK_BLEED_COMPLETE"; bcmxcp_alarm_map[BCMXCP_ALARM_LARGE_CHARGER_INPUT_CURRENT].alarm_desc = "LARGE_CHARGER_INPUT_CURRENT"; bcmxcp_alarm_map[BCMXCP_ALARM_INV_VOLT_TOO_LOW_FOR_RAMP_LEVEL].alarm_desc = "INV_VOLT_TOO_LOW_FOR_RAMP_LEVEL"; bcmxcp_alarm_map[BCMXCP_ALARM_LOSS_OF_REDUNDANCY].alarm_desc = "LOSS_OF_REDUNDANCY"; bcmxcp_alarm_map[BCMXCP_ALARM_LOSS_OF_SYNC_BUS].alarm_desc = "LOSS_OF_SYNC_BUS"; bcmxcp_alarm_map[BCMXCP_ALARM_RECTIFIER_BREAKER_SHUNT_TRIP].alarm_desc = "RECTIFIER_BREAKER_SHUNT_TRIP"; bcmxcp_alarm_map[BCMXCP_ALARM_LOSS_OF_CHARGER_SYNC].alarm_desc = "LOSS_OF_CHARGER_SYNC"; bcmxcp_alarm_map[BCMXCP_ALARM_INVERTER_LOW_LEVEL_TEST_TIMEOUT].alarm_desc = "INVERTER_LOW_LEVEL_TEST_TIMEOUT"; bcmxcp_alarm_map[BCMXCP_ALARM_OUTPUT_BREAKER_OPEN].alarm_desc = "OUTPUT_BREAKER_OPEN"; bcmxcp_alarm_map[BCMXCP_ALARM_CONTROL_POWER_ON].alarm_desc = "CONTROL_POWER_ON"; bcmxcp_alarm_map[BCMXCP_ALARM_INVERTER_ON].alarm_desc = "INVERTER_ON"; bcmxcp_alarm_map[BCMXCP_ALARM_CHARGER_ON].alarm_desc = "CHARGER_ON"; bcmxcp_alarm_map[BCMXCP_ALARM_BYPASS_ON].alarm_desc = "BYPASS_ON"; bcmxcp_alarm_map[BCMXCP_ALARM_BYPASS_POWER_LOSS].alarm_desc = "BYPASS_POWER_LOSS"; bcmxcp_alarm_map[BCMXCP_ALARM_ON_MANUAL_BYPASS].alarm_desc = "ON_MANUAL_BYPASS"; bcmxcp_alarm_map[BCMXCP_ALARM_BYPASS_MANUAL_TURN_OFF].alarm_desc = "BYPASS_MANUAL_TURN_OFF"; bcmxcp_alarm_map[BCMXCP_ALARM_INVERTER_BLEEDING_DC_LINK_VOLT].alarm_desc = "INVERTER_BLEEDING_DC_LINK_VOLT"; bcmxcp_alarm_map[BCMXCP_ALARM_CPU_ISR_ERROR].alarm_desc = "CPU_ISR_ERROR"; bcmxcp_alarm_map[BCMXCP_ALARM_SYSTEM_ISR_RESTART].alarm_desc = "SYSTEM_ISR_RESTART"; bcmxcp_alarm_map[BCMXCP_ALARM_PARALLEL_DC].alarm_desc = "PARALLEL_DC"; bcmxcp_alarm_map[BCMXCP_ALARM_BATTERY_NEEDS_SERVICE].alarm_desc = "BATTERY_NEEDS_SERVICE"; bcmxcp_alarm_map[BCMXCP_ALARM_BATTERY_CHARGING].alarm_desc = "BATTERY_CHARGING"; bcmxcp_alarm_map[BCMXCP_ALARM_BATTERY_NOT_CHARGED].alarm_desc = "BATTERY_NOT_CHARGED"; bcmxcp_alarm_map[BCMXCP_ALARM_DISABLED_BATTERY_TIME].alarm_desc = "DISABLED_BATTERY_TIME"; bcmxcp_alarm_map[BCMXCP_ALARM_SERIES_7000_ENABLE].alarm_desc = "SERIES_7000_ENABLE"; bcmxcp_alarm_map[BCMXCP_ALARM_OTHER_UPS_ON].alarm_desc = "OTHER_UPS_ON"; bcmxcp_alarm_map[BCMXCP_ALARM_PARALLEL_INVERTER].alarm_desc = "PARALLEL_INVERTER"; bcmxcp_alarm_map[BCMXCP_ALARM_UPS_IN_PARALLEL].alarm_desc = "UPS_IN_PARALLEL"; bcmxcp_alarm_map[BCMXCP_ALARM_OUTPUT_BREAKER_REALY_FAIL].alarm_desc = "OUTPUT_BREAKER_REALY_FAIL"; bcmxcp_alarm_map[BCMXCP_ALARM_CONTROL_POWER_OFF].alarm_desc = "CONTROL_POWER_OFF"; bcmxcp_alarm_map[BCMXCP_ALARM_LEVEL_2_OVERLOAD_PHASE_A].alarm_desc = "LEVEL_2_OVERLOAD_PHASE_A"; bcmxcp_alarm_map[BCMXCP_ALARM_LEVEL_2_OVERLOAD_PHASE_B].alarm_desc = "LEVEL_2_OVERLOAD_PHASE_B"; bcmxcp_alarm_map[BCMXCP_ALARM_LEVEL_2_OVERLOAD_PHASE_C].alarm_desc = "LEVEL_2_OVERLOAD_PHASE_C"; bcmxcp_alarm_map[BCMXCP_ALARM_LEVEL_3_OVERLOAD_PHASE_A].alarm_desc = "LEVEL_3_OVERLOAD_PHASE_A"; bcmxcp_alarm_map[BCMXCP_ALARM_LEVEL_3_OVERLOAD_PHASE_B].alarm_desc = "LEVEL_3_OVERLOAD_PHASE_B"; bcmxcp_alarm_map[BCMXCP_ALARM_LEVEL_3_OVERLOAD_PHASE_C].alarm_desc = "LEVEL_3_OVERLOAD_PHASE_C"; bcmxcp_alarm_map[BCMXCP_ALARM_LEVEL_4_OVERLOAD_PHASE_A].alarm_desc = "LEVEL_4_OVERLOAD_PHASE_A"; bcmxcp_alarm_map[BCMXCP_ALARM_LEVEL_4_OVERLOAD_PHASE_B].alarm_desc = "LEVEL_4_OVERLOAD_PHASE_B"; bcmxcp_alarm_map[BCMXCP_ALARM_LEVEL_4_OVERLOAD_PHASE_C].alarm_desc = "LEVEL_4_OVERLOAD_PHASE_C"; bcmxcp_alarm_map[BCMXCP_ALARM_UPS_ON_BATTERY].alarm_desc = "UPS_ON_BATTERY"; bcmxcp_alarm_map[BCMXCP_ALARM_UPS_ON_BYPASS].alarm_desc = "UPS_ON_BYPASS"; bcmxcp_alarm_map[BCMXCP_ALARM_LOAD_DUMPED].alarm_desc = "LOAD_DUMPED"; bcmxcp_alarm_map[BCMXCP_ALARM_LOAD_ON_INVERTER].alarm_desc = "LOAD_ON_INVERTER"; bcmxcp_alarm_map[BCMXCP_ALARM_UPS_ON_COMMAND].alarm_desc = "UPS_ON_COMMAND"; bcmxcp_alarm_map[BCMXCP_ALARM_UPS_OFF_COMMAND].alarm_desc = "UPS_OFF_COMMAND"; bcmxcp_alarm_map[BCMXCP_ALARM_LOW_BATTERY_SHUTDOWN].alarm_desc = "LOW_BATTERY_SHUTDOWN"; bcmxcp_alarm_map[BCMXCP_ALARM_AUTO_ON_ENABLED].alarm_desc = "AUTO_ON_ENABLED"; bcmxcp_alarm_map[BCMXCP_ALARM_SOFTWARE_INCOMPABILITY_DETECTED].alarm_desc = "SOFTWARE_INCOMPABILITY_DETECTED"; bcmxcp_alarm_map[BCMXCP_ALARM_INVERTER_TEMP_SENSOR_FAILED].alarm_desc = "INVERTER_TEMP_SENSOR_FAILED"; bcmxcp_alarm_map[BCMXCP_ALARM_DC_START_OCCURED].alarm_desc = "DC_START_OCCURED"; bcmxcp_alarm_map[BCMXCP_ALARM_IN_PARALLEL_OPERATION].alarm_desc = "IN_PARALLEL_OPERATION"; bcmxcp_alarm_map[BCMXCP_ALARM_SYNCING_TO_BYPASS].alarm_desc = "SYNCING_TO_BYPASS"; bcmxcp_alarm_map[BCMXCP_ALARM_RAMPING_UPS_UP].alarm_desc = "RAMPING_UPS_UP"; bcmxcp_alarm_map[BCMXCP_ALARM_INVERTER_ON_DELAY].alarm_desc = "INVERTER_ON_DELAY"; bcmxcp_alarm_map[BCMXCP_ALARM_CHARGER_ON_DELAY].alarm_desc = "CHARGER_ON_DELAY"; bcmxcp_alarm_map[BCMXCP_ALARM_WAITING_FOR_UTIL_INPUT].alarm_desc = "WAITING_FOR_UTIL_INPUT"; bcmxcp_alarm_map[BCMXCP_ALARM_CLOSE_BYPASS_BREAKER].alarm_desc = "CLOSE_BYPASS_BREAKER"; bcmxcp_alarm_map[BCMXCP_ALARM_TEMPORARY_BYPASS_OPERATION].alarm_desc = "TEMPORARY_BYPASS_OPERATION"; bcmxcp_alarm_map[BCMXCP_ALARM_SYNCING_TO_OUTPUT].alarm_desc = "SYNCING_TO_OUTPUT"; bcmxcp_alarm_map[BCMXCP_ALARM_BYPASS_FAILURE].alarm_desc = "BYPASS_FAILURE"; bcmxcp_alarm_map[BCMXCP_ALARM_AUTO_OFF_COMMAND_EXECUTED].alarm_desc = "AUTO_OFF_COMMAND_EXECUTED"; bcmxcp_alarm_map[BCMXCP_ALARM_AUTO_ON_COMMAND_EXECUTED].alarm_desc = "AUTO_ON_COMMAND_EXECUTED"; bcmxcp_alarm_map[BCMXCP_ALARM_BATTERY_TEST_FAILED].alarm_desc = "BATTERY_TEST_FAILED"; bcmxcp_alarm_map[BCMXCP_ALARM_FUSE_FAIL].alarm_desc = "FUSE_FAIL"; bcmxcp_alarm_map[BCMXCP_ALARM_FAN_FAIL].alarm_desc = "FAN_FAIL"; bcmxcp_alarm_map[BCMXCP_ALARM_SITE_WIRING_FAULT].alarm_desc = "SITE_WIRING_FAULT"; bcmxcp_alarm_map[BCMXCP_ALARM_BACKFEED_CONTACTOR_FAIL].alarm_desc = "BACKFEED_CONTACTOR_FAIL"; bcmxcp_alarm_map[BCMXCP_ALARM_ON_BUCK].alarm_desc = "ON_BUCK"; bcmxcp_alarm_map[BCMXCP_ALARM_ON_BOOST].alarm_desc = "ON_BOOST"; bcmxcp_alarm_map[BCMXCP_ALARM_ON_DOUBLE_BOOST].alarm_desc = "ON_DOUBLE_BOOST"; bcmxcp_alarm_map[BCMXCP_ALARM_BATTERIES_DISCONNECTED].alarm_desc = "BATTERIES_DISCONNECTED"; bcmxcp_alarm_map[BCMXCP_ALARM_UPS_CABINET_OVER_TEMP].alarm_desc = "UPS_CABINET_OVER_TEMP"; bcmxcp_alarm_map[BCMXCP_ALARM_TRANSFORMER_OVER_TEMP].alarm_desc = "TRANSFORMER_OVER_TEMP"; bcmxcp_alarm_map[BCMXCP_ALARM_AMBIENT_UNDER_TEMP].alarm_desc = "AMBIENT_UNDER_TEMP"; bcmxcp_alarm_map[BCMXCP_ALARM_AMBIENT_OVER_TEMP].alarm_desc = "AMBIENT_OVER_TEMP"; bcmxcp_alarm_map[BCMXCP_ALARM_CABINET_DOOR_OPEN].alarm_desc = "CABINET_DOOR_OPEN"; bcmxcp_alarm_map[BCMXCP_ALARM_CABINET_DOOR_OPEN_VOLT_PRESENT].alarm_desc = "CABINET_DOOR_OPEN_VOLT_PRESENT"; bcmxcp_alarm_map[BCMXCP_ALARM_AUTO_SHUTDOWN_PENDING].alarm_desc = "AUTO_SHUTDOWN_PENDING"; bcmxcp_alarm_map[BCMXCP_ALARM_TAP_SWITCHING_REALY_PENDING].alarm_desc = "TAP_SWITCHING_REALY_PENDING"; bcmxcp_alarm_map[BCMXCP_ALARM_UNABLE_TO_CHARGE_BATTERIES].alarm_desc = "UNABLE_TO_CHARGE_BATTERIES"; bcmxcp_alarm_map[BCMXCP_ALARM_STARTUP_FAILURE_CHECK_EPO].alarm_desc = "STARTUP_FAILURE_CHECK_EPO"; bcmxcp_alarm_map[BCMXCP_ALARM_AUTOMATIC_STARTUP_PENDING].alarm_desc = "AUTOMATIC_STARTUP_PENDING"; bcmxcp_alarm_map[BCMXCP_ALARM_MODEM_FAILED].alarm_desc = "MODEM_FAILED"; bcmxcp_alarm_map[BCMXCP_ALARM_INCOMING_MODEM_CALL_STARTED].alarm_desc = "INCOMING_MODEM_CALL_STARTED"; bcmxcp_alarm_map[BCMXCP_ALARM_OUTGOING_MODEM_CALL_STARTED].alarm_desc = "OUTGOING_MODEM_CALL_STARTED"; bcmxcp_alarm_map[BCMXCP_ALARM_MODEM_CONNECTION_ESTABLISHED].alarm_desc = "MODEM_CONNECTION_ESTABLISHED"; bcmxcp_alarm_map[BCMXCP_ALARM_MODEM_CALL_COMPLETED_SUCCESS].alarm_desc = "MODEM_CALL_COMPLETED_SUCCESS"; bcmxcp_alarm_map[BCMXCP_ALARM_MODEM_CALL_COMPLETED_FAIL].alarm_desc = "MODEM_CALL_COMPLETED_FAIL"; bcmxcp_alarm_map[BCMXCP_ALARM_INPUT_BREAKER_FAIL].alarm_desc = "INPUT_BREAKER_FAIL"; bcmxcp_alarm_map[BCMXCP_ALARM_SYSINIT_IN_PROGRESS].alarm_desc = "SYSINIT_IN_PROGRESS"; bcmxcp_alarm_map[BCMXCP_ALARM_AUTOCALIBRATION_FAIL].alarm_desc = "AUTOCALIBRATION_FAIL"; bcmxcp_alarm_map[BCMXCP_ALARM_SELECTIVE_TRIP_OF_MODULE].alarm_desc = "SELECTIVE_TRIP_OF_MODULE"; bcmxcp_alarm_map[BCMXCP_ALARM_INVERTER_OUTPUT_FAILURE].alarm_desc = "INVERTER_OUTPUT_FAILURE"; bcmxcp_alarm_map[BCMXCP_ALARM_ABNORMAL_OUTPUT_VOLT_AT_STARTUP].alarm_desc = "ABNORMAL_OUTPUT_VOLT_AT_STARTUP"; bcmxcp_alarm_map[BCMXCP_ALARM_RECTIFIER_OVER_TEMP].alarm_desc = "RECTIFIER_OVER_TEMP"; bcmxcp_alarm_map[BCMXCP_ALARM_CONFIG_ERROR].alarm_desc = "CONFIG_ERROR"; bcmxcp_alarm_map[BCMXCP_ALARM_REDUNDANCY_LOSS_DUE_TO_OVERLOAD].alarm_desc = "REDUNDANCY_LOSS_DUE_TO_OVERLOAD"; bcmxcp_alarm_map[BCMXCP_ALARM_ON_ALTERNATE_AC_SOURCE].alarm_desc = "ON_ALTERNATE_AC_SOURCE"; bcmxcp_alarm_map[BCMXCP_ALARM_IN_HIGH_EFFICIENCY_MODE].alarm_desc = "IN_HIGH_EFFICIENCY_MODE"; bcmxcp_alarm_map[BCMXCP_ALARM_SYSTEM_NOTICE_ACTIVE].alarm_desc = "SYSTEM_NOTICE_ACTIVE"; bcmxcp_alarm_map[BCMXCP_ALARM_SYSTEM_ALARM_ACTIVE].alarm_desc = "SYSTEM_ALARM_ACTIVE"; bcmxcp_alarm_map[BCMXCP_ALARM_ALTERNATE_POWER_SOURCE_NOT_AVAILABLE].alarm_desc = "ALTERNATE_POWER_SOURCE_NOT_AVAILABLE"; bcmxcp_alarm_map[BCMXCP_ALARM_CURRENT_BALANCE_FAILURE].alarm_desc = "CURRENT_BALANCE_FAILURE"; bcmxcp_alarm_map[BCMXCP_ALARM_CHECK_AIR_FILTER].alarm_desc = "CHECK_AIR_FILTER"; bcmxcp_alarm_map[BCMXCP_ALARM_SUBSYSTEM_NOTICE_ACTIVE].alarm_desc = "SUBSYSTEM_NOTICE_ACTIVE"; bcmxcp_alarm_map[BCMXCP_ALARM_SUBSYSTEM_ALARM_ACTIVE].alarm_desc = "SUBSYSTEM_ALARM_ACTIVE"; bcmxcp_alarm_map[BCMXCP_ALARM_CHARGER_ON_COMMAND].alarm_desc = "CHARGER_ON_COMMAND"; bcmxcp_alarm_map[BCMXCP_ALARM_CHARGER_OFF_COMMAND].alarm_desc = "CHARGER_OFF_COMMAND"; bcmxcp_alarm_map[BCMXCP_ALARM_UPS_NORMAL].alarm_desc = "UPS_NORMAL"; bcmxcp_alarm_map[BCMXCP_ALARM_INVERTER_PHASE_ROTATION].alarm_desc = "INVERTER_PHASE_ROTATION"; bcmxcp_alarm_map[BCMXCP_ALARM_UPS_OFF].alarm_desc = "UPS_OFF"; bcmxcp_alarm_map[BCMXCP_ALARM_EXTERNAL_COMMUNICATION_FAILURE].alarm_desc = "EXTERNAL_COMMUNICATION_FAILURE"; bcmxcp_alarm_map[BCMXCP_ALARM_BATTERY_TEST_INPROGRESS].alarm_desc = "BATTERY_TEST_INPROGRESS"; bcmxcp_alarm_map[BCMXCP_ALARM_SYSTEM_TEST_INPROGRESS].alarm_desc = "SYSTEM_TEST_INPROGRESS"; bcmxcp_alarm_map[BCMXCP_ALARM_BATTERY_TEST_ABORTED].alarm_desc = "BATTERY_TEST_ABORTED"; } /* Get information on UPS commands */ bool_t init_command(int size) { unsigned char answer[PW_ANSWER_MAX_SIZE]; unsigned char commandByte; const char* nutvalue; ssize_t res; int iIndex = 0, ncounter, NumComms = 0, i; upsdebugx(1, "entering init_command(%i)", size); res = command_read_sequence(PW_COMMAND_LIST_REQ, answer); if (res <= 0) { upsdebugx(2, "No command list block."); return FALSE; } else { upsdebugx(2, "Command list block supported."); res = answer[iIndex]; NumComms = (int)res; /* Number of commands implemented in this UPS */ upsdebugx(3, "Number of commands implemented in ups %" PRIiSIZE, res); iIndex++; res = answer[iIndex]; /* Entry length - bytes reported for each command */ iIndex++; upsdebugx(5, "bytes per command %" PRIiSIZE, res); /* In case of debug - make explanation of values */ upsdebugx(2, "Index\tCmd byte\tDescription"); /* Get command bytes if size of command block matches with size from standard ID block */ if (NumComms + 2 == size) { for (ncounter = 0; ncounter < NumComms; ncounter++) { commandByte = answer[iIndex]; if (commandByte < BCMXCP_COMMAND_MAP_MAX) { upsdebugx(2, "%03d\t%02x\t%s", ncounter, commandByte, bcmxcp_command_map[commandByte].command_desc); bcmxcp_command_map[commandByte].command_byte = commandByte; } else { upsdebugx(2, "%03d\t%02x\t%s", ncounter, commandByte, "Unknown command, the commandByte is not mapped"); } iIndex++; } /* Map supported commands to instcmd */ for (i = 0; i < BCMXCP_COMMAND_MAP_MAX; i++) { if (bcmxcp_command_map[i].command_desc != NULL) { if (bcmxcp_command_map[i].command_byte > 0) { if ((nutvalue = nut_find_infoval(command_map_info, bcmxcp_command_map[i].command_byte, FALSE)) != NULL) { dstate_addcmd(nutvalue); upsdebugx(2, "Added support for instcmd %s", nutvalue); } } } } return TRUE; } else { upsdebugx(1, "Invalid response received from Command List block"); return FALSE; } } } void init_ups_meter_map(const unsigned char *map, unsigned char len) { unsigned int iIndex, iOffset = 0; /* In case of debug - make explanation of values */ upsdebugx(2, "Index\tOffset\tFormat\tNUT"); /* Loop thru map */ for (iIndex = 0; iIndex < len && iIndex < BCMXCP_METER_MAP_MAX; iIndex++) { bcmxcp_meter_map[iIndex].format = map[iIndex]; if (map[iIndex] != 0) { /* Set meter map entry offset */ bcmxcp_meter_map[iIndex].meter_block_index = iOffset; /* Debug info */ upsdebugx(2, "%04d\t%04d\t%2x\t%s", iIndex, iOffset, bcmxcp_meter_map[iIndex].format, (bcmxcp_meter_map[iIndex].nut_entity == NULL ? "None" :bcmxcp_meter_map[iIndex].nut_entity)); iOffset += 4; } } upsdebugx(2, "\n"); } void decode_meter_map_entry(const unsigned char *entry, const unsigned char format, char* value) { uint32_t lValue = 0; char sFormat[32]; float fValue; unsigned char dd, mm, yy, cc, hh, ss; /* Paranoid input sanity checks */ if (value == NULL) return; *value = '\0'; if (entry == (unsigned char *)NULL || format == 0x00) return; /* Get data based on format */ if (format == 0xf0) { /* Long integer */ lValue = get_long(entry); snprintf(value, 127, "%d", (int)lValue); } else if ((format & 0xf0) == 0xf0) { /* Fixed point integer */ fValue = get_long(entry) / ldexp(1, format & 0x0f); snprintf(value, 127, "%.2f", fValue); } else if (format <= 0x97) { /* Floating point */ fValue = get_float(entry); /* Format is packed BCD */ snprintf(sFormat, 31, "%%%d.%df", ((format & 0xf0) >> 4), (format & 0x0f)); #ifdef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL #pragma GCC diagnostic push #endif #ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL #pragma GCC diagnostic ignored "-Wformat-nonliteral" #endif #ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_FORMAT_SECURITY #pragma GCC diagnostic ignored "-Wformat-security" #endif snprintf(value, 127, sFormat, fValue); #ifdef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL #pragma GCC diagnostic pop #endif } else if (format == 0xe2) { /* Seconds */ lValue = get_long(entry); snprintf(value, 127, "%d", (int)lValue); } else if (format == 0xe0) { /* Date */ /* Format is packed BCD for each byte, and cc uses most signifcant bit to signal date format */ dd = entry[0]; mm = entry[1]; yy = entry[2]; cc = entry[3]; /* Check format type */ if (cc & 0x80) { /* Month:Day format */ snprintf(value, 127, "%d%d/%d%d/%d%d%d%d", ((dd & 0xf0) >> 4), (dd & 0x0f), ((mm & 0xf0) >> 4), (mm & 0x0f), (((cc & 0x7f) & 0xf0) >> 4), ((cc & 0x7f) & 0x0f), ((yy & 0xf0) >> 4), (yy & 0x0f)); } else { /* Julian format */ /* TODO test this, unsure if the day part is correct, i.e. how we use the two bytes mm and dd to calculate the number of julian days */ snprintf(value, 127, "%d%d%d%d:%d%d%d", (((cc & 0x7f) & 0xf0) >> 4), ((cc & 0x7f) & 0x0f), ((yy & 0xf0) >> 4), (yy & 0x0f), (mm & 0x0f), ((dd & 0xf0) >> 4), (dd & 0x0f)); } } else if (format == 0xe1) { /* Time */ /* Format is packed BCD for each byte */ cc = entry[0]; ss = entry[1]; mm = entry[2]; hh = entry[3]; snprintf(value, 127, "%d%d:%d%d:%d%d.%d%d", ((hh & 0xf0) >> 4), (hh & 0x0f), ((mm & 0xf0) >> 4), (mm & 0x0f), ((ss & 0xf0) >> 4), (ss & 0x0f), ((cc & 0xf0) >> 4), (cc & 0x0f)); } else { /* Unknown format */ snprintf(value, 127, "???"); return; } return; } void init_ups_alarm_map(const unsigned char *map, unsigned char len) { unsigned int iIndex = 0; unsigned int alarm = 0; /* In case of debug - make explanation of values */ upsdebugx(2, "Index\tAlarm\tSupported"); /* Loop thru map */ for (iIndex = 0; iIndex < len && iIndex < BCMXCP_ALARM_MAP_MAX / 8; iIndex++) { /* Bit 0 */ if (set_alarm_support_in_alarm_map(map, iIndex, 0x01, iIndex * 8, alarm) == TRUE) alarm++; /* Bit 1 */ if (set_alarm_support_in_alarm_map(map, iIndex, 0x02, iIndex * 8 + 1, alarm) == TRUE) alarm++; /* Bit 2 */ if (set_alarm_support_in_alarm_map(map, iIndex, 0x04, iIndex * 8 + 2, alarm) == TRUE) alarm++; /* Bit 3 */ if (set_alarm_support_in_alarm_map(map, iIndex, 0x08, iIndex * 8 + 3, alarm) == TRUE) alarm++; /* Bit 4 */ if (set_alarm_support_in_alarm_map(map, iIndex, 0x10, iIndex * 8 + 4, alarm) == TRUE) alarm++; /* Bit 5 */ if (set_alarm_support_in_alarm_map(map, iIndex, 0x20, iIndex * 8 + 5, alarm) == TRUE) alarm++; /* Bit 6 */ if (set_alarm_support_in_alarm_map(map, iIndex, 0x40, iIndex * 8 + 6, alarm) == TRUE) alarm++; /* Bit 7 */ if (set_alarm_support_in_alarm_map(map, iIndex, 0x80, iIndex * 8 + 7, alarm) == TRUE) alarm++; } upsdebugx(2, "\n"); } bool_t set_alarm_support_in_alarm_map( const unsigned char *map, const unsigned int mapIndex, const unsigned int bitmask, const unsigned int alarmMapIndex, const unsigned int alarmBlockIndex ) { /* Check what the alarm block tells about the support for the alarm */ if (map[mapIndex] & bitmask) { /* Set alarm active */ assert (alarmBlockIndex < INT_MAX); bcmxcp_alarm_map[alarmMapIndex].alarm_block_index = (int)alarmBlockIndex; } else { /* Set alarm inactive */ bcmxcp_alarm_map[alarmMapIndex].alarm_block_index = -1; } /* Return if the alarm was supported or not */ if (bcmxcp_alarm_map[alarmMapIndex].alarm_block_index >= 0) { /* Debug info */ upsdebugx(2, "%04d\t%s\tYes", bcmxcp_alarm_map[alarmMapIndex].alarm_block_index, bcmxcp_alarm_map[alarmMapIndex].alarm_desc); return TRUE; } else { /* Debug info */ upsdebugx(3, "%04d\t%s\tNo", bcmxcp_alarm_map[alarmMapIndex].alarm_block_index, bcmxcp_alarm_map[alarmMapIndex].alarm_desc); return FALSE; } } unsigned char init_outlet(unsigned char len) { /* Note: (bug?) the argument "len" is not practically used in code below * Callers know it as "outlet_block_len" in their routines and it is greater than 8 */ unsigned char answer[PW_ANSWER_MAX_SIZE]; int iIndex = 0; ssize_t res; unsigned char num_outlet, size_outlet, num; unsigned char outlet_num, outlet_state; uint16_t auto_dly_off, auto_dly_on; char outlet_name[64]; res = command_read_sequence(PW_OUT_MON_BLOCK_REQ, answer); if (res <= 0) fatal_with_errno(EXIT_FAILURE, "Could not communicate with the ups"); else upsdebugx(1, "init_outlet(%i), res=%" PRIiSIZE, len, res); num_outlet = answer[iIndex++]; upsdebugx(2, "Number of outlets: %u", num_outlet); size_outlet = answer[iIndex++]; upsdebugx(2, "Number of bytes: %u", size_outlet); for (num = 1 ; num <= num_outlet ; num++) { outlet_num = answer[iIndex++]; upsdebugx(2, "Outlet number: %u", outlet_num); snprintf(outlet_name, sizeof(outlet_name)-1, "outlet.%u.id", num); dstate_setinfo(outlet_name, "%u", outlet_num); outlet_state = answer[iIndex++]; upsdebugx(2, "Outlet state: %u", outlet_state); snprintf(outlet_name, sizeof(outlet_name)-1, "outlet.%u.status", num); if (outlet_state>0 && outlet_state <9) dstate_setinfo(outlet_name, "%s", OutletStatus[outlet_state]); auto_dly_off = get_word(answer+iIndex); iIndex += 2; upsdebugx(2, "Auto delay off: %u", auto_dly_off); snprintf(outlet_name, sizeof(outlet_name)-1, "outlet.%u.delay.shutdown", num); dstate_setinfo(outlet_name, "%u", auto_dly_off); dstate_setflags(outlet_name, ST_FLAG_RW | ST_FLAG_STRING); dstate_setaux(outlet_name, 5); auto_dly_on = get_word(answer+iIndex); iIndex += 2; upsdebugx(2, "Auto delay on: %u", auto_dly_on); snprintf(outlet_name, sizeof(outlet_name)-1, "outlet.%u.delay.start", num); dstate_setinfo(outlet_name, "%u", auto_dly_on); dstate_setflags(outlet_name, ST_FLAG_RW | ST_FLAG_STRING); dstate_setaux(outlet_name, 5); } return num_outlet; } void init_ext_vars(void) { unsigned char answer[PW_ANSWER_MAX_SIZE], cbuf[5]; ssize_t length = 0; int index = 0; send_write_command(AUTHOR, 4); sleep(PW_SLEEP); /* Need to. Have to wait at least 0,25 sec max 16 sec */ cbuf[0] = PW_SET_CONF_COMMAND; cbuf[1] = PW_CONF_REQ; cbuf[2] = 0x0; cbuf[3] = 0x0; length = command_write_sequence(cbuf, 4, answer); if (length <= 0) fatal_with_errno(EXIT_FAILURE, "Could not communicate with the ups"); if (length < 4) /* UPS doesn't have configurable vars */ return; for (index=3; index < length; index++) { switch(answer[index]) { case PW_CONF_LOW_DEV_LIMIT: dstate_setinfo("input.transfer.boost.high", "%d", 0); dstate_setflags("input.transfer.boost.high", ST_FLAG_RW | ST_FLAG_STRING); dstate_setaux("input.transfer.boost.high", 3); break; case PW_CONF_HIGH_DEV_LIMIT: dstate_setinfo("input.transfer.trim.low", "%d", 0); dstate_setflags("input.transfer.trim.low", ST_FLAG_RW | ST_FLAG_STRING); dstate_setaux("input.transfer.trim.low", 3); break; case PW_CONF_LOW_BATT: dstate_setinfo("battery.runtime.low", "%d", 0); dstate_setflags("battery.runtime.low", ST_FLAG_RW | ST_FLAG_STRING); dstate_setaux("battery.runtime.low", 2); break; case PW_CONF_BEEPER: dstate_addcmd("beeper.disable"); dstate_addcmd("beeper.enable"); dstate_addcmd("beeper.mute"); break; case PW_CONF_RETURN_DELAY: dstate_setinfo("input.transfer.delay", "%d", 0); dstate_setflags("input.transfer.delay", ST_FLAG_RW | ST_FLAG_STRING); dstate_setaux("input.transfer.delay", 5); break; case PW_CONF_RETURN_CAP: dstate_setinfo("battery.charge.restart", "%d", 0); dstate_setflags("battery.charge.restart", ST_FLAG_RW | ST_FLAG_STRING); dstate_setaux("battery.charge.restart", 3); break; case PW_CONF_MAX_TEMP: dstate_setinfo("ambient.temperature.high", "%d", 0); dstate_setflags("ambient.temperature.high", ST_FLAG_RW | ST_FLAG_STRING); dstate_setaux("ambient.temperature.high", 3); break; case PW_CONF_NOMINAL_OUT_VOLTAGE: dstate_setinfo("output.voltage.nominal", "%d", 0); dstate_setflags("output.voltage.nominal", ST_FLAG_RW | ST_FLAG_STRING); dstate_setaux("output.voltage.nominal", 3); break; case PW_CONF_SLEEP_TH_LOAD: dstate_setinfo("battery.energysave.load", "%d", 0); dstate_setflags("battery.energysave.load", ST_FLAG_RW | ST_FLAG_STRING); dstate_setaux("battery.energysave.load", 3); break; case PW_CONF_SLEEP_DELAY: dstate_setinfo("battery.energysave.delay", "%d", 0); dstate_setflags("battery.energysave.delay", ST_FLAG_RW | ST_FLAG_STRING); dstate_setaux("battery.energysave.delay", 3); break; case PW_CONF_BATT_STRINGS: dstate_setinfo("battery.packs", "%d", 0); dstate_setflags("battery.packs", ST_FLAG_RW | ST_FLAG_STRING); dstate_setaux("battery.packs", 1); break; } } } void init_config(void) { unsigned char answer[PW_ANSWER_MAX_SIZE]; uint16_t voltage = 0, frequency = 0, tmp = 0; ssize_t res; char sValue[17]; char sPartNumber[17]; res = command_read_sequence(PW_CONFIG_BLOCK_REQ, answer); if (res <= 0) fatal_with_errno(EXIT_FAILURE, "Could not communicate with the ups"); /* Get validation mask for status bitmap */ bcmxcp_status.topology_mask = answer[BCMXCP_CONFIG_BLOCK_HW_MODULES_INSTALLED_BYTE3]; /* Nominal output voltage of ups */ voltage = get_word((answer + BCMXCP_CONFIG_BLOCK_NOMINAL_OUTPUT_VOLTAGE)); if (voltage != 0) dstate_setinfo("output.voltage.nominal", "%u", voltage); /* Nominal Output Frequency */ frequency = get_word((answer + BCMXCP_CONFIG_BLOCK_NOMINAL_OUTPUT_FREQ)); if (frequency != 0) dstate_setinfo("output.frequency.nominal", "%u", frequency); /*Number of EBM*/ tmp = (uint16_t) *(answer + BCMXCP_CONFIG_BLOCK_BATTERY_DATA_WORD3); if (tmp != 0) dstate_setinfo("battery.packs", "%u", tmp); #ifdef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_FORMAT_TRUNCATION #pragma GCC diagnostic push #endif #ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_FORMAT_TRUNCATION #pragma GCC diagnostic ignored "-Wformat-truncation" #endif /* NOTE: We intentionally limit the amount of characters picked from * "answer" into "sValue" and "sPartNumber" buffers (16 byte + NUL). */ /* UPS serial number */ snprintf(sValue, sizeof(sValue), "%s", answer + BCMXCP_CONFIG_BLOCK_SERIAL_NUMBER); if (sValue[0] != '\0') dstate_setinfo("ups.serial", "%s", sValue); /* UPS Part Number*/ snprintf(sPartNumber, sizeof(sPartNumber), "%s", answer + BCMXCP_CONFIG_BLOCK_PART_NUMBER); if (sPartNumber[0] != '\0') dstate_setinfo("device.part", "%s", sPartNumber); #ifdef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_FORMAT_TRUNCATION #pragma GCC diagnostic pop #endif } void init_limit(void) { unsigned char answer[PW_ANSWER_MAX_SIZE]; uint16_t value; ssize_t res; res = command_read_sequence(PW_LIMIT_BLOCK_REQ, answer); if (res <= 0) { fatal_with_errno(EXIT_FAILURE, "Could not communicate with the ups"); } /* Nominal input voltage */ value = get_word((answer + BCMXCP_EXT_LIMITS_BLOCK_NOMINAL_INPUT_VOLTAGE)); if (value != 0) { dstate_setinfo("input.voltage.nominal", "%u", value); } /* Nominal input frequency */ value = get_word((answer + BCMXCP_EXT_LIMITS_BLOCK_NOMINAL_INPUT_FREQ)); if (value != 0) { uint16_t fnom = value; dstate_setinfo("input.frequency.nominal", "%u", value); /* Input frequency deviation */ value = get_word((answer + BCMXCP_EXT_LIMITS_BLOCK_FREQ_DEV_LIMIT)); if (value != 0) { value /= 100; dstate_setinfo("input.frequency.low", "%u", fnom - value); dstate_setinfo("input.frequency.high", "%u", fnom + value); } } /* Bypass Voltage Low Deviation Limit / Transfer to Boost Voltage */ value = get_word((answer + BCMXCP_EXT_LIMITS_BLOCK_VOLTAGE_LOW_DEV_LIMIT)); if (value != 0) { dstate_setinfo("input.transfer.boost.high", "%u", value); } /* Bypass Voltage High Deviation Limit / Transfer to Buck Voltage */ value = get_word((answer + BCMXCP_EXT_LIMITS_BLOCK_VOLTAGE_HIGE_DEV_LIMIT)); if (value != 0) { dstate_setinfo("input.transfer.trim.low", "%u", value); } /* Low battery warning */ bcmxcp_status.lowbatt = answer[BCMXCP_EXT_LIMITS_BLOCK_LOW_BATT_WARNING] * 60; /* Check if we should warn the user that her shutdown delay is too long? */ if (bcmxcp_status.shutdowndelay > bcmxcp_status.lowbatt) upslogx(LOG_WARNING, "Shutdown delay longer than battery capacity when Low Battery " "warning is given. (max %d seconds)", bcmxcp_status.lowbatt); /* Horn Status: */ value = answer[BCMXCP_EXT_LIMITS_BLOCK_HORN_STATUS]; if (value <= 2) { dstate_setinfo("ups.beeper.status", "%s", horn_stat[value]); } /* Minimum Supported Input Voltage */ value = get_word((answer + BCMXCP_EXT_LIMITS_BLOCK_MIN_INPUT_VOLTAGE)); if (value != 0) { dstate_setinfo("input.transfer.low", "%u", value); } /* Maximum Supported Input Voltage */ value = get_word((answer + BCMXCP_EXT_LIMITS_BLOCK_MAX_INPUT_VOLTAGE)); if (value != 0) { dstate_setinfo("input.transfer.high", "%u", value); } /* Ambient Temperature Lower Alarm Limit */ value = answer[BCMXCP_EXT_LIMITS_BLOCK_AMBIENT_TEMP_LOW]; if (value != 0) { dstate_setinfo("ambient.temperature.low", "%u", value); } /* Ambient Temperature Upper Alarm Limit */ value = answer[BCMXCP_EXT_LIMITS_BLOCK_AMBIENT_TEMP_HIGE]; if (value != 0) { dstate_setinfo("ambient.temperature.high", "%u", value); } /*Sleep minimum load*/ value = answer[BCMXCP_EXT_LIMITS_BLOCK_SLEEP_TH_LOAD]; if (value != 0) { dstate_setinfo("battery.energysave.load", "%u", value); } /* Sleep delay*/ value = answer[BCMXCP_EXT_LIMITS_BLOCK_SLEEP_DELAY]; if (value != 0) { dstate_setinfo("battery.energysave.delay", "%u", value); } /* Low batt minutes warning*/ value = answer[BCMXCP_EXT_LIMITS_BLOCK_LOW_BATT_WARNING]; if (value != 0) { dstate_setinfo("battery.runtime.low", "%u", value); } /* Return to mains delay */ value = get_word(answer + BCMXCP_EXT_LIMITS_BLOCK_RETURN_STAB_DELAY); if (value != 0) { dstate_setinfo("input.transfer.delay", "%u", value); } /* Minimum return capacity*/ value = answer[BCMXCP_EXT_LIMITS_BLOCK_BATT_CAPACITY_RETURN]; if (value != 0) { dstate_setinfo("battery.charge.restart", "%u", value); } } void init_topology(void) { unsigned char answer[PW_ANSWER_MAX_SIZE]; const char* nutvalue; uint16_t value; ssize_t res; res = command_read_sequence(PW_UPS_TOP_DATA_REQ, answer); if (res <= 0) fatal_with_errno(EXIT_FAILURE, "Could not communicate with the ups"); value = get_word(answer); if ((nutvalue = nut_find_infoval(topology_info, value, TRUE)) != NULL) { dstate_setinfo("ups.description", "%s", nutvalue); } } void init_system_test_capabilities(void) { unsigned char answer[PW_ANSWER_MAX_SIZE], cbuf[5]; const char* nutvalue; ssize_t res; int value, i; /* Query what system test capabilities are supported */ send_write_command(AUTHOR, 4); sleep(PW_SLEEP); /* Need to. Have to wait at least 0,25 sec max 16 sec */ cbuf[0] = PW_INIT_SYS_TEST; cbuf[1] = PW_SYS_TEST_REPORT_CAPABILITIES; res = command_write_sequence(cbuf, 2, answer); if (res <= 0) { upslogx(LOG_ERR, "Short read from UPS"); return; } if ((unsigned char)answer[0] != BCMXCP_RETURN_ACCEPTED) { upsdebugx(2, "System test capabilities list not supported"); return; } /* Add instcmd for system test capabilities */ for (i = 3; i < res; i++) { value = answer[i]; if ((nutvalue = nut_find_infoval(system_test_info, value, TRUE)) != NULL) { upsdebugx(2, "Added support for instcmd %s", nutvalue); dstate_addcmd(nutvalue); } } } void upsdrv_initinfo(void) { unsigned char answer[PW_ANSWER_MAX_SIZE]; char *pTmp; char outlet_name[64]; char power_rating[10]; ssize_t res; unsigned int ncpu = 0; size_t buf; uint16_t iRating = 0, iIndex = 0, len; uint16_t conf_block_len = 0, alarm_block_len = 0, cmd_list_len = 0, topology_block_len = 0; bool_t got_cmd_list = FALSE; /* Init BCM/XCP command descriptions */ init_command_map(); /* Init BCM/XCP alarm descriptions */ init_alarm_map(); /* Get vars from ups.conf */ if (getval("shutdown_delay") != NULL) { int tmp = atoi(getval("shutdown_delay")); if (tmp >= 0) { bcmxcp_status.shutdowndelay = (unsigned int)tmp; } else { fatal_with_errno(EXIT_FAILURE, "Invalid setting for shutdown_delay: %s", getval("shutdown_delay")); } } else { bcmxcp_status.shutdowndelay = 120; } /* Get information on UPS from UPS ID block */ res = command_read_sequence(PW_ID_BLOCK_REQ, answer); if (res <= 0) fatal_with_errno(EXIT_FAILURE, "Could not communicate with the ups"); /* Get number of CPU's in ID block */ len = answer[iIndex++]; /* No overflow checks, len value is byte-sized here */ buf = len * 11; pTmp = xmalloc(buf+1); pTmp[0] = 0; /* If there is one or more CPU number, get it */ if (len > 0) { do { if ((answer[iIndex] != 0x00) || (answer[iIndex+1] != 0x00)) { /* Get the ups firmware. The major number is in the last byte, the minor is in the first */ snprintfcat(pTmp, buf+1, "%s%02x.%02x ", cpu_name[ncpu], answer[iIndex+1], answer[iIndex]); } iIndex += 2; len--; ncpu++; } while ((len > 0) && (ncpu <= 5)); dstate_setinfo("ups.firmware", "%s", pTmp); /* Increment index to point at end of CPU bytes. */ iIndex += len * 2; } free(pTmp); /* Get rating in kVA, if present */ if ((iRating = answer[iIndex++]) > 0) iRating *= 1000; else { /* The rating is given as 2 byte VA */ iRating = get_word(answer+iIndex) * 50; iIndex += 2; } dstate_setinfo("ups.power.nominal", "%u", iRating); /* Get information on Phases from UPS */ nphases = (answer[iIndex++]); dstate_setinfo("output.phases", "%d", nphases); /* Init BCM/XCP <-> NUT meter map */ init_meter_map(); /* Skip UPS' phase angle, as NUT do not care */ iIndex += 1; /* Set manufacturer name */ dstate_setinfo("ups.mfr", "Eaton"); /* Get length of UPS description */ len = answer[iIndex++]; /* Extract and reformat the model string */ pTmp = xmalloc(len+15); snprintf(pTmp, len + 1, "%s", answer + iIndex); pTmp[len+1] = 0; iIndex += len; /* power rating in the model name is in the form "i" * ie "1500i", "500i", ... * some models already includes it, so check to avoid duplication */ snprintf(power_rating, sizeof(power_rating), "%ii", iRating); if (strstr(pTmp, power_rating) == NULL) { snprintfcat(pTmp, len+10, " %s", power_rating); } dstate_setinfo("ups.model", "%s", str_rtrim(pTmp, ' ')); free(pTmp); /* Get meter map info from ups, and init our map */ len = answer[iIndex++]; upsdebugx(2, "Length of meter map: %u\n", len); /* Here and below, no range check needed - just initialized from unsigned char array */ init_ups_meter_map(answer+iIndex, (unsigned char)len); iIndex += len; /* Next is alarm map */ len = answer[iIndex++]; upsdebugx(2, "Length of alarm map: %u\n", len); init_ups_alarm_map(answer+iIndex, (unsigned char)len); iIndex += len; /* Then the Config_block_length */ conf_block_len = get_word(answer+iIndex); upsdebugx(2, "Length of Config_block: %u\n", conf_block_len); iIndex += 2; /* Next is statistics map */ len = answer[iIndex++]; upsdebugx(2, "Length of statistics map: %u\n", len); /* init_statistics_map(answer+iIndex, (unsigned char)len); */ iIndex += len; /* Size of the alarm history log */ len = get_word(answer+iIndex); upsdebugx(2, "Length of alarm history log: %u\n", len); iIndex += 2; /* Size of custom event log, always 0 according to spec */ iIndex += 2; /* Size of topology block */ topology_block_len = get_word(answer+iIndex); upsdebugx(2, "Length of topology block: %u\n", topology_block_len); iIndex += 2; /* Maximum supported command length */ len = answer[iIndex++]; upsdebugx(2, "Length of max supported command length: %u\n", len); /* Size of command list block */ if (iIndex < (unsigned int)res) cmd_list_len = get_word(answer+iIndex); upsdebugx(2, "Length of command list: %u\n", cmd_list_len); iIndex += 2; /* Size of outlet monitoring block */ if (iIndex < (unsigned int)res) outlet_block_len = get_word(answer+iIndex); upsdebugx(2, "Length of outlet_block: %u\n", outlet_block_len); iIndex += 2; /* Size of the alarm block */ if (iIndex < (unsigned int)res) alarm_block_len = get_word(answer+iIndex); upsdebugx(2, "Length of alarm_block: %u\n", alarm_block_len); /* End of UPS ID block request */ /* Due to a bug in PW5115 firmware, we need to use blocklength > 8. The protocol state that outlet block is only implemented if there is at least 2 outlet block. 5115 has only one outlet, but has outlet block! */ if (outlet_block_len > 8) { if (outlet_block_len > 255) fatal_with_errno(EXIT_FAILURE, "outlet_block_len overflow: %u", outlet_block_len); len = init_outlet((unsigned char)outlet_block_len /* arg ignored */); for (res = 1 ; (unsigned int)res <= (unsigned int)len ; res++) { snprintf(outlet_name, sizeof(outlet_name) - 1, "outlet.%" PRIiSIZE ".shutdown.return", res); dstate_addcmd(outlet_name); snprintf(outlet_name, sizeof(outlet_name) - 1, "outlet.%" PRIiSIZE ".load.on", res); dstate_addcmd(outlet_name); snprintf(outlet_name, sizeof(outlet_name) - 1, "outlet.%" PRIiSIZE ".load.off", res); dstate_addcmd(outlet_name); } } /* Get information on UPS configuration */ init_config(); /* Get information on UPS extended limits */ init_limit(); /* Get information on UPS commands */ if (cmd_list_len) got_cmd_list = init_command(cmd_list_len); /* Add default commands if we were not able to query UPS for support */ if (got_cmd_list == FALSE) { dstate_addcmd("shutdown.return"); dstate_addcmd("shutdown.stayoff"); dstate_addcmd("test.battery.start"); } /* Get information on UPS topology */ if (topology_block_len) init_topology(); /* Get information on system test capabilities */ if (bcmxcp_command_map[PW_INIT_SYS_TEST].command_byte > 0) { init_system_test_capabilities(); } /* Get information about configurable external variables*/ init_ext_vars(); upsh.instcmd = instcmd; upsh.setvar = setvar; } void upsdrv_updateinfo(void) { unsigned char answer[PW_ANSWER_MAX_SIZE]; unsigned char status, topology; char sValue[128]; int iIndex; ssize_t res; uint16_t value; bool_t has_ups_load = FALSE; int batt_status = 0; const char *nutvalue; float calculated_load; /* Get info from UPS */ res = command_read_sequence(PW_METER_BLOCK_REQ, answer); if (res <= 0) { upslogx(LOG_ERR, "Short read from UPS"); dstate_datastale(); return; } /* Loop thru meter map, get all data UPS is willing to offer */ for (iIndex = 0; iIndex < BCMXCP_METER_MAP_MAX; iIndex++) { if (bcmxcp_meter_map[iIndex].format != 0 && bcmxcp_meter_map[iIndex].nut_entity != NULL) { decode_meter_map_entry(answer + bcmxcp_meter_map[iIndex].meter_block_index, bcmxcp_meter_map[iIndex].format, sValue); /* Set result */ dstate_setinfo(bcmxcp_meter_map[iIndex].nut_entity, "%s", sValue); /* Check if we read ups.load */ if (has_ups_load == FALSE && !strcasecmp(bcmxcp_meter_map[iIndex].nut_entity, "ups.load")) { has_ups_load = TRUE; } } } /* Calculate ups.load if UPS does not report it directly */ if (has_ups_load == FALSE) { calculated_load = calculate_ups_load(answer); if (calculated_load >= 0.0f) { dstate_setinfo("ups.load", "%5.1f", calculated_load); } } /* Due to a bug in PW5115 firmware, we need to use blocklength > 8. The protocol state that outlet block is only implemented if there is at least 2 outlet block. 5115 has only one outlet, but has outlet block. */ if (outlet_block_len > 8) { if (outlet_block_len > 255) fatal_with_errno(EXIT_FAILURE, "outlet_block_len overflow: %u", outlet_block_len); init_outlet((unsigned char)outlet_block_len /* arg ignored */); } /* Get alarm info from UPS */ res = command_read_sequence(PW_CUR_ALARM_REQ, answer); if (res <= 0) { upslogx(LOG_ERR, "Short read from UPS"); dstate_datastale(); return; } else { bcmxcp_status.alarm_on_battery = 0; bcmxcp_status.alarm_low_battery = 0; /* Set alarms */ alarm_init(); /* Loop thru alarm map, get all alarms UPS is willing to offer */ for (iIndex = 0; iIndex < BCMXCP_ALARM_MAP_MAX; iIndex++) { if (bcmxcp_alarm_map[iIndex].alarm_block_index >= 0 && bcmxcp_alarm_map[iIndex].alarm_desc != NULL) { if (answer[bcmxcp_alarm_map[iIndex].alarm_block_index] > 0) { alarm_set(bcmxcp_alarm_map[iIndex].alarm_desc); if (iIndex == BCMXCP_ALARM_UPS_ON_BATTERY) { bcmxcp_status.alarm_on_battery = 1; } else if (iIndex == BCMXCP_ALARM_BATTERY_LOW) { bcmxcp_status.alarm_low_battery = 1; } else if (iIndex == BCMXCP_ALARM_BATTERY_TEST_FAILED) { bcmxcp_status.alarm_replace_battery = 1; } else if (iIndex == BCMXCP_ALARM_BATTERY_NEEDS_SERVICE) { bcmxcp_status.alarm_replace_battery = 1; } } } } /* Confirm alarms */ alarm_commit(); } /* Get status info from UPS */ res = command_read_sequence(PW_STATUS_REQ, answer); if (res <= 0) { upslogx(LOG_ERR, "Short read from UPS"); dstate_datastale(); return; } else { /* Get overall status */ memcpy(&status, answer, sizeof(status)); /* Get topology status bitmap, validate */ memcpy(&topology, answer+1, sizeof(topology)); topology &= bcmxcp_status.topology_mask; /* Set status */ status_init(); switch (status) { case BCMXCP_STATUS_ONLINE: /* On line, everything is fine */ status_set("OL"); break; case BCMXCP_STATUS_ONBATTERY: /* Off line */ if (bcmxcp_status.alarm_on_battery == 0) status_set("OB"); break; case BCMXCP_STATUS_OVERLOAD: /* Overload */ status_set("OL"); status_set("OVER"); break; case BCMXCP_STATUS_TRIM: /* Trim */ status_set("OL"); status_set("TRIM"); break; case BCMXCP_STATUS_BOOST1: case BCMXCP_STATUS_BOOST2: /* Boost */ status_set("OL"); status_set("BOOST"); break; case BCMXCP_STATUS_BYPASS: /* Bypass */ status_set("OL"); status_set("BYPASS"); break; case BCMXCP_STATUS_OFF: /* Mostly off */ status_set("OFF"); break; default: /* Unknown, assume it is OK... */ status_set("OL"); break; } /* We might have to modify status based on topology status */ if ((topology & 0x20) && bcmxcp_status.alarm_low_battery == 0) status_set("LB"); /* And finally, we might need to modify status based on alarms - the most correct way */ if (bcmxcp_status.alarm_on_battery) status_set("OB"); if (bcmxcp_status.alarm_low_battery) status_set("LB"); if (bcmxcp_status.alarm_replace_battery) status_set("RB"); status_commit(); } /* Get battery info from UPS, if exist */ res = command_read_sequence(PW_BATTERY_REQ, answer); if (res <= 0) { upsdebugx(1, "Failed to read Battery Status from UPS"); } else { /* Only parse the status (first byte) * Powerware 5115 RM output: * 02 00 78 1d 42 00 e0 17 42 1e 00 00 00 00 00 00 00 00 00 01 03 * Powerware 9130 output: * 03 0a d7 25 42 0a d7 25 42 00 9a 19 6d 43 cd cc 4c 3e 01 00 01 03 */ upsdebug_hex(2, "Battery Status", answer, (size_t)res); batt_status = answer[BCMXCP_BATTDATA_BLOCK_BATT_TEST_STATUS]; if ((nutvalue = nut_find_infoval(batt_test_info, batt_status, TRUE)) != NULL) { dstate_setinfo("ups.test.result", "%s", nutvalue); upsdebugx(2, "Battery Status = %s (%i)", nutvalue, batt_status); } else { upsdebugx(1, "Failed to extract Battery Status from answer"); } /*Extracting internal batteries ABM status*/ /*Placed first in ABM statuses list. For examples above - on position BCMXCP_BATTDATA_BLOCK_NUMBER_OF_STRINGS (18): PW5115RM - 0 - no external strings, no status bytes, so next byte (19) - number of ABM statuses, next (20) - first ABM Status for internal batteries. PW9130 - 1 - one external string, so one additional status byte (#19 - 00 - no test run), next(20) - number of ABM statuses, next (21) - ABM Status for internal batteries. */ value = *(answer + BCMXCP_BATTDATA_BLOCK_NUMBER_OF_STRINGS + *(answer + BCMXCP_BATTDATA_BLOCK_NUMBER_OF_STRINGS) * 1 + 2); upsdebugx(2, "ABM Status = %u ", value); if (value < 5) dstate_setinfo("battery.charger.status", "%s", ABMStatus[value-1]); } res = command_read_sequence(PW_LIMIT_BLOCK_REQ, answer); if (res <= 0) { upsdebugx(1, "Failed to read EXT LIMITs from UPS"); } else { /* Nominal input voltage */ value = get_word((answer + BCMXCP_EXT_LIMITS_BLOCK_NOMINAL_INPUT_VOLTAGE)); if (value != 0) { dstate_setinfo("input.voltage.nominal", "%u", value); } /* Bypass Voltage Low Deviation Limit / Transfer to Boost Voltage */ value = get_word((answer + BCMXCP_EXT_LIMITS_BLOCK_VOLTAGE_LOW_DEV_LIMIT)); if (value != 0) { dstate_setinfo("input.transfer.boost.high", "%u", value); } /* Bypass Voltage High Deviation Limit / Transfer to Buck Voltage */ value = get_word((answer + BCMXCP_EXT_LIMITS_BLOCK_VOLTAGE_HIGE_DEV_LIMIT)); if (value != 0) { dstate_setinfo("input.transfer.trim.low", "%u", value); } /* Minimum Supported Input Voltage */ value = get_word((answer + BCMXCP_EXT_LIMITS_BLOCK_MIN_INPUT_VOLTAGE)); if (value != 0) { dstate_setinfo("input.transfer.low", "%u", value); } /* Maximum Supported Input Voltage */ value = get_word((answer + BCMXCP_EXT_LIMITS_BLOCK_MAX_INPUT_VOLTAGE)); if (value != 0) { dstate_setinfo("input.transfer.high", "%u", value); } /* Horn Status: */ value = answer[BCMXCP_EXT_LIMITS_BLOCK_HORN_STATUS]; if (value <= 2) { dstate_setinfo("ups.beeper.status", "%s", horn_stat[value]); } /* AAmbient Temperature Upper Alarm Limit */ value = answer[BCMXCP_EXT_LIMITS_BLOCK_AMBIENT_TEMP_HIGE]; if (value != 0) { dstate_setinfo("ambient.temperature.high", "%u", value); } /*Sleep minimum load*/ value = answer[BCMXCP_EXT_LIMITS_BLOCK_SLEEP_TH_LOAD]; if (value != 0) { dstate_setinfo("battery.energysave.load", "%u", value); } /* Sleep delay*/ value = answer[BCMXCP_EXT_LIMITS_BLOCK_SLEEP_DELAY]; if (value != 0) { dstate_setinfo("battery.energysave.delay", "%u", value); } /* Low batt minutes warning*/ value = answer[BCMXCP_EXT_LIMITS_BLOCK_LOW_BATT_WARNING]; if (value != 0) { dstate_setinfo("battery.runtime.low", "%u", value); } /* Return to mains delay */ value = get_word(answer + BCMXCP_EXT_LIMITS_BLOCK_RETURN_STAB_DELAY); if (value != 0) { dstate_setinfo("input.transfer.delay", "%u", value); } /* Minimum return capacity*/ value = answer[BCMXCP_EXT_LIMITS_BLOCK_BATT_CAPACITY_RETURN]; if (value != 0) { dstate_setinfo("battery.charge.restart", "%u", value); } } res = command_read_sequence(PW_CONFIG_BLOCK_REQ, answer); if (res <= 0) { upsdebugx(1, "Failed to read CONF BLOCK from UPS"); } else { /*Nominal output voltage*/ value = get_word((answer + BCMXCP_CONFIG_BLOCK_NOMINAL_OUTPUT_VOLTAGE)); if (value != 0) dstate_setinfo("output.voltage.nominal", "%u", value); /*Number of EBM*/ value = (uint16_t) *(answer + BCMXCP_CONFIG_BLOCK_BATTERY_DATA_WORD3); if (value != 0) dstate_setinfo("battery.packs", "%u", value); } dstate_dataok(); } float calculate_ups_load(const unsigned char *answer) { char sValue[128]; float output = 0, max_output = -FLT_MAX, fValue = -FLT_MAX; if (bcmxcp_meter_map[BCMXCP_METER_MAP_OUTPUT_VA].format != 0 && /* Output VA */ bcmxcp_meter_map[BCMXCP_METER_MAP_OUTPUT_VA_BAR_CHART].format != 0) /* Max output VA */ { decode_meter_map_entry(answer + bcmxcp_meter_map[BCMXCP_METER_MAP_OUTPUT_VA].meter_block_index, bcmxcp_meter_map[BCMXCP_METER_MAP_OUTPUT_VA].format, sValue); output = atof(sValue); decode_meter_map_entry(answer + bcmxcp_meter_map[BCMXCP_METER_MAP_OUTPUT_VA_BAR_CHART].meter_block_index, bcmxcp_meter_map[BCMXCP_METER_MAP_OUTPUT_VA_BAR_CHART].format, sValue); max_output = atof(sValue); } else if (bcmxcp_meter_map[BCMXCP_METER_MAP_LOAD_CURRENT_PHASE_A].format != 0 && /* Output A */ bcmxcp_meter_map[BCMXCP_METER_MAP_LOAD_CURRENT_PHASE_A_BAR_CHART].format != 0) /* Max output A */ { decode_meter_map_entry(answer + bcmxcp_meter_map[BCMXCP_METER_MAP_LOAD_CURRENT_PHASE_A].meter_block_index, bcmxcp_meter_map[BCMXCP_METER_MAP_LOAD_CURRENT_PHASE_A].format, sValue); output = atof(sValue); decode_meter_map_entry(answer + bcmxcp_meter_map[BCMXCP_METER_MAP_LOAD_CURRENT_PHASE_A_BAR_CHART].meter_block_index, bcmxcp_meter_map[BCMXCP_METER_MAP_LOAD_CURRENT_PHASE_A_BAR_CHART].format, sValue); max_output = atof(sValue); } if (max_output > 0.0) fValue = 100 * (output / max_output); return fValue; } void upsdrv_shutdown(void) { upsdebugx(1, "upsdrv_shutdown..."); /* Try to shutdown with delay */ if (instcmd("shutdown.return", NULL) == STAT_INSTCMD_HANDLED) { /* Shutdown successful */ return; } /* If the above doesn't work, try shutdown.stayoff */ if (instcmd("shutdown.stayoff", NULL) == STAT_INSTCMD_HANDLED) { /* Shutdown successful */ return; } upslogx(LOG_ERR, "Shutdown failed!"); set_exit_flag(-1); } static int instcmd(const char *cmdname, const char *extra) { unsigned char answer[128], cbuf[6]; char success_msg[40]; char namebuf[MAX_NUT_NAME_LENGTH]; char varname[32]; const char *varvalue = NULL; ssize_t res; int sec, outlet_num; int sddelay = 0x03; /* outlet off in 3 seconds, by default */ upsdebugx(1, "entering instcmd(%s)(%s)", cmdname, extra); if (!strcasecmp(cmdname, "shutdown.return")) { send_write_command(AUTHOR, 4); sleep(PW_SLEEP); /* Need to. Have to wait at least 0,25 sec max 16 sec */ cbuf[0] = PW_LOAD_OFF_RESTART; cbuf[1] = (unsigned char)(bcmxcp_status.shutdowndelay & 0x00ff); /* "delay" sec delay for shutdown, */ cbuf[2] = (unsigned char)(bcmxcp_status.shutdowndelay >> 8); /* high byte sec. From ups.conf. */ res = command_write_sequence(cbuf, 3, answer); sec = (256 * (unsigned char)answer[3]) + (unsigned char)answer[2]; snprintf(success_msg, sizeof(success_msg)-1, "Going down in %d sec", sec); return decode_instcmd_exec(res, (unsigned char)answer[0], cmdname, success_msg); } if (!strcasecmp(cmdname, "shutdown.stayoff")) { send_write_command(AUTHOR, 4); sleep(PW_SLEEP); /* Need to. Have to wait at least 0,25 sec max 16 sec */ res = command_read_sequence(PW_UPS_OFF, answer); return decode_instcmd_exec(res, (unsigned char)answer[0], cmdname, "Going down NOW"); } if (!strcasecmp(cmdname, "load.on")) { send_write_command(AUTHOR, 4); sleep(PW_SLEEP); /* Need to. Have to wait at least 0,25 sec max 16 sec */ res = command_read_sequence(PW_UPS_ON, answer); return decode_instcmd_exec(res, (unsigned char)answer[0], cmdname, "Enabling"); } if (!strcasecmp(cmdname, "bypass.start")) { send_write_command(AUTHOR, 4); sleep(PW_SLEEP); /* Need to. Have to wait at least 0,25 sec max 16 sec */ res = command_read_sequence(PW_GO_TO_BYPASS, answer); return decode_instcmd_exec(res, (unsigned char)answer[0], cmdname, "Bypass enabled"); } /* Note: test result will be parsed from Battery status block, * part of the update loop, and published into ups.test.result */ if (!strcasecmp(cmdname, "test.battery.start")) { send_write_command(AUTHOR, 4); sleep(PW_SLEEP); /* Need to. Have to wait at least 0,25 sec max 16 sec */ cbuf[0] = PW_INIT_BAT_TEST; cbuf[1] = 0x0A; /* 10 sec start delay for test.*/ cbuf[2] = 0x1E; /* 30 sec test duration.*/ res = command_write_sequence(cbuf, 3, answer); return decode_instcmd_exec(res, (unsigned char)answer[0], cmdname, "Testing battery now"); /* Get test info from UPS ? Should we wait for 50 sec and get the answer from the test. Or return, as we may lose line power and need to do a shutdown.*/ } if (!strcasecmp(cmdname, "test.system.start")) { send_write_command(AUTHOR, 4); sleep(PW_SLEEP); /* Need to. Have to wait at least 0,25 sec max 16 sec */ cbuf[0] = PW_INIT_SYS_TEST; cbuf[1] = PW_SYS_TEST_GENERAL; res = command_write_sequence(cbuf, 2, answer); return decode_instcmd_exec(res, (unsigned char)answer[0], cmdname, "Testing system now"); } if (!strcasecmp(cmdname, "test.panel.start")) { send_write_command(AUTHOR, 4); sleep(PW_SLEEP); /* Need to. Have to wait at least 0,25 sec max 16 sec */ cbuf[0] = PW_INIT_SYS_TEST; cbuf[1] = PW_SYS_TEST_FLASH_LIGHTS; cbuf[2] = 0x0A; /* Flash and beep 10 times */ res = command_write_sequence(cbuf, 3, answer); return decode_instcmd_exec(res, (unsigned char)answer[0], cmdname, "Testing panel now"); } if (!strcasecmp(cmdname, "beeper.disable") || !strcasecmp(cmdname, "beeper.enable") || !strcasecmp(cmdname, "beeper.mute")) { send_write_command(AUTHOR, 4); sleep(PW_SLEEP); /* Need to. Have to wait at least 0,25 sec max 16 sec */ cbuf[0] = PW_SET_CONF_COMMAND; cbuf[1] = PW_CONF_BEEPER; switch (cmdname[7]) { case 'd': case 'D': { cbuf[2] = 0x0; /*disable beeper*/ break; } case 'e': case 'E': { cbuf[2] = 0x1; /*enable beeper*/ break; } case 'm': case 'M': { cbuf[2] = 0x2; break; /*mute beeper*/ } } cbuf[3] = 0x0; /*padding*/ res = command_write_sequence(cbuf, 4, answer); return decode_instcmd_exec(res, (unsigned char)answer[0], cmdname, "Beeper status changed"); } strncpy(namebuf, cmdname, sizeof(namebuf)); namebuf[NUT_OUTLET_POSITION] = 'n'; /* Assumes a maximum of 9 outlets */ if (!strcasecmp(namebuf, "outlet.n.shutdown.return")) { send_write_command(AUTHOR, 4); sleep(PW_SLEEP); /* Need to. Have to wait at least 0,25 sec max 16 sec */ /* Get the shutdown delay, if any */ snprintf(varname, sizeof(varname)-1, "outlet.%c.delay.shutdown", cmdname[NUT_OUTLET_POSITION]); if ((varvalue = dstate_getinfo(varname)) != NULL) { sddelay = atoi(varvalue); } /*if -1 then use global shutdown_delay from ups.conf*/ if (sddelay == -1) sddelay = (int)bcmxcp_status.shutdowndelay; outlet_num = cmdname[NUT_OUTLET_POSITION] - '0'; if (outlet_num < 1 || outlet_num > 9) return STAT_INSTCMD_FAILED; cbuf[0] = PW_LOAD_OFF_RESTART; cbuf[1] = sddelay & 0xff; cbuf[2] = (unsigned char)(sddelay >> 8); /* high byte of the 2 byte time argument */ cbuf[3] = (unsigned char)outlet_num; /* which outlet load segment? Assumes outlet number at position 8 of the command string. */ res = command_write_sequence(cbuf, 4, answer); sec = (256 * (unsigned char)answer[3]) + (unsigned char)answer[2]; snprintf(success_msg, sizeof(success_msg)-1, "Going down in %d sec", sec); return decode_instcmd_exec(res, (unsigned char)answer[0], cmdname, success_msg); } if (!strcasecmp(namebuf, "outlet.n.load.on") || !strcasecmp(namebuf, "outlet.n.load.off")) { send_write_command(AUTHOR, 4); sleep(PW_SLEEP); /* Need to. Have to wait at least 0,25 sec max 16 sec */ outlet_num = cmdname[NUT_OUTLET_POSITION] - '0'; if (outlet_num < 1 || outlet_num > 9) return STAT_INSTCMD_FAILED; cbuf[0] = (cmdname[NUT_OUTLET_POSITION+8] == 'n') ? PW_UPS_ON : PW_UPS_OFF; /* Cmd oN or not*/ cbuf[1] = (unsigned char)outlet_num; /* Outlet number */ res = command_write_sequence(cbuf, 2, answer); snprintf(success_msg, sizeof(success_msg)-1, "Outlet %d is %s", outlet_num, ((cmdname[NUT_OUTLET_POSITION+8] == 'n') ? "On" : "Off")); return decode_instcmd_exec(res, (unsigned char)answer[0], cmdname, success_msg); } upslogx(LOG_NOTICE, "instcmd: unknown command [%s]", cmdname); return STAT_INSTCMD_UNKNOWN; } static int decode_instcmd_exec(const ssize_t res, const unsigned char exec_status, const char *cmdname, const char *success_msg) { if (res <= 0) { upslogx(LOG_ERR, "[%s] Short read from UPS", cmdname); dstate_datastale(); return STAT_INSTCMD_FAILED; } /* Decode the status code from command execution */ switch (exec_status) { case BCMXCP_RETURN_ACCEPTED: { upslogx(LOG_NOTICE, "[%s] %s", cmdname, success_msg); upsdrv_comm_good(); return STAT_INSTCMD_HANDLED; } case BCMXCP_RETURN_ACCEPTED_PARAMETER_ADJUST: { upslogx(LOG_NOTICE, "[%s] Parameter adjusted", cmdname); upslogx(LOG_NOTICE, "[%s] %s", cmdname, success_msg); upsdrv_comm_good(); return STAT_INSTCMD_HANDLED; } case BCMXCP_RETURN_BUSY: { upslogx(LOG_NOTICE, "[%s] Busy or disbled by front panel", cmdname); return STAT_INSTCMD_FAILED; } case BCMXCP_RETURN_UNRECOGNISED: { upslogx(LOG_NOTICE, "[%s] Unrecognised command byte or corrupt checksum", cmdname); return STAT_INSTCMD_FAILED; } case BCMXCP_RETURN_INVALID_PARAMETER: { upslogx(LOG_NOTICE, "[%s] Invalid parameter", cmdname); return STAT_INSTCMD_INVALID; } case BCMXCP_RETURN_PARAMETER_OUT_OF_RANGE: { upslogx(LOG_NOTICE, "[%s] Parameter out of range", cmdname); return STAT_INSTCMD_INVALID; } default: { upslogx(LOG_NOTICE, "[%s] Not supported", cmdname); return STAT_INSTCMD_INVALID; } } } void upsdrv_help(void) { } /* list flags and values that you want to receive via -x */ void upsdrv_makevartable(void) { addvar(VAR_VALUE, "shutdown_delay", "Specify shutdown delay (seconds)"); addvar(VAR_VALUE, "baud_rate", "Specify communication speed (ex: 9600)"); } int setvar (const char *varname, const char *val) { unsigned char answer[128], cbuf[5]; char namebuf[MAX_NUT_NAME_LENGTH]; char success_msg[SMALLBUF]; ssize_t res; int sec, outlet_num, tmp; int onOff_setting = PW_AUTO_OFF_DELAY; upsdebugx(1, "entering setvar(%s, %s)", varname, val); if (!strcasecmp(varname, "input.transfer.boost.high")) { send_write_command(AUTHOR, 4); sleep(PW_SLEEP); /* Need to. Have to wait at least 0,25 sec max 16 sec */ tmp=atoi(val); if (tmp < 0 || tmp > 460) { return STAT_SET_INVALID; } cbuf[0]=PW_SET_CONF_COMMAND; cbuf[1]=PW_CONF_LOW_DEV_LIMIT; cbuf[2]=tmp&0xff; cbuf[3]=(unsigned char)(tmp>>8); res = command_write_sequence(cbuf, 4, answer); snprintf(success_msg, sizeof(success_msg)-1, " BOOST threshold volage set to %d V", tmp); return decode_setvar_exec(res, (unsigned char)answer[0], varname, success_msg); } if (!strcasecmp(varname, "input.transfer.trim.low")) { send_write_command(AUTHOR, 4); sleep(PW_SLEEP); /* Need to. Have to wait at least 0,25 sec max 16 sec */ tmp=atoi(val); if (tmp < 110 || tmp > 540) { return STAT_SET_INVALID; } cbuf[0]=PW_SET_CONF_COMMAND; cbuf[1]=PW_CONF_HIGH_DEV_LIMIT; cbuf[2]=tmp&0xff; cbuf[3]=(unsigned char)(tmp>>8); res = command_write_sequence(cbuf, 4, answer); snprintf(success_msg, sizeof(success_msg)-1, " TRIM threshold volage set to %d V", tmp); return decode_setvar_exec(res, (unsigned char)answer[0], varname, success_msg); } if (!strcasecmp(varname, "battery.runtime.low")) { send_write_command(AUTHOR, 4); sleep(PW_SLEEP); /* Need to. Have to wait at least 0,25 sec max 16 sec */ tmp=atoi(val); if (tmp < 0 || tmp > 30) { return STAT_SET_INVALID; } cbuf[0]=PW_SET_CONF_COMMAND; cbuf[1]=PW_CONF_LOW_BATT; cbuf[2]=tmp&0xff; cbuf[3]=0x0; res = command_write_sequence(cbuf, 4, answer); snprintf(success_msg, sizeof(success_msg)-1, " Low battery warning time set to %d min", tmp); return decode_setvar_exec(res, (unsigned char)answer[0], varname, success_msg); } if (!strcasecmp(varname, "input.transfer.delay")) { send_write_command(AUTHOR, 4); sleep(PW_SLEEP); /* Need to. Have to wait at least 0,25 sec max 16 sec */ tmp=atoi(val); if (tmp < 1 || tmp > 18000) { return STAT_SET_INVALID; } cbuf[0]=PW_SET_CONF_COMMAND; cbuf[1]=PW_CONF_RETURN_DELAY; cbuf[2]=tmp&0xff; cbuf[3]=(unsigned char)(tmp>>8); res = command_write_sequence(cbuf, 4, answer); snprintf(success_msg, sizeof(success_msg)-1, " Mains return delay set to %d sec", tmp); return decode_setvar_exec(res, (unsigned char)answer[0], varname, success_msg); } if (!strcasecmp(varname, "battery.charge.restart")) { send_write_command(AUTHOR, 4); sleep(PW_SLEEP); /* Need to. Have to wait at least 0,25 sec max 16 sec */ tmp=atoi(val); if (tmp < 0 || tmp > 100) { return STAT_SET_INVALID; } cbuf[0]=PW_SET_CONF_COMMAND; cbuf[1]=PW_CONF_RETURN_CAP; cbuf[2]=tmp&0xff; cbuf[3]=0x0; res = command_write_sequence(cbuf, 4, answer); snprintf(success_msg, sizeof(success_msg)-1, " Mains return minimum battery capacity set to %d %%", tmp); return decode_setvar_exec(res, (unsigned char)answer[0], varname, success_msg); } if (!strcasecmp(varname, "ambient.temperature.high")) { send_write_command(AUTHOR, 4); sleep(PW_SLEEP); /* Need to. Have to wait at least 0,25 sec max 16 sec */ tmp=atoi(val); if (tmp < 0 || tmp > 100) { return STAT_SET_INVALID; } cbuf[0]=PW_SET_CONF_COMMAND; cbuf[1]=PW_CONF_MAX_TEMP; cbuf[2]=tmp&0xff; cbuf[3]=0x0; res = command_write_sequence(cbuf, 4, answer); snprintf(success_msg, sizeof(success_msg)-1, " Maximum temperature set to %d C", tmp); return decode_setvar_exec(res, (unsigned char)answer[0], varname, success_msg); } if (!strcasecmp(varname, "output.voltage.nominal")) { send_write_command(AUTHOR, 4); sleep(PW_SLEEP); /* Need to. Have to wait at least 0,25 sec max 16 sec */ tmp=atoi(val); if (tmp < 0 || tmp > 460) { return STAT_SET_INVALID; } cbuf[0]=PW_SET_CONF_COMMAND; cbuf[1]=PW_CONF_NOMINAL_OUT_VOLTAGE; cbuf[2]=tmp&0xff; cbuf[3]=(unsigned char)(tmp>>8); res = command_write_sequence(cbuf, 4, answer); snprintf(success_msg, sizeof(success_msg)-1, " Nominal output voltage set to %d V", tmp); return decode_setvar_exec(res, (unsigned char)answer[0], varname, success_msg); } if (!strcasecmp(varname, "battery.energysave.load")) { send_write_command(AUTHOR, 4); sleep(PW_SLEEP); /* Need to. Have to wait at least 0,25 sec max 16 sec */ tmp=atoi(val); if (tmp < 0 || tmp > 100) { return STAT_SET_INVALID; } cbuf[0]=PW_SET_CONF_COMMAND; cbuf[1]=PW_CONF_SLEEP_TH_LOAD; cbuf[2]=tmp&0xff; cbuf[3]=0x0; res = command_write_sequence(cbuf, 4, answer); snprintf(success_msg, sizeof(success_msg)-1, " Minimum load before sleep countdown set to %d %%", tmp); return decode_setvar_exec(res, (unsigned char)answer[0], varname, success_msg); } if (!strcasecmp(varname, "battery.energysave.delay")) { send_write_command(AUTHOR, 4); sleep(PW_SLEEP); /* Need to. Have to wait at least 0,25 sec max 16 sec */ tmp=atoi(val); if (tmp < 0 || tmp > 255) { return STAT_SET_INVALID; } cbuf[0]=PW_SET_CONF_COMMAND; cbuf[1]=PW_CONF_SLEEP_DELAY; cbuf[2]=tmp&0xff; cbuf[3]=0x0; res = command_write_sequence(cbuf, 4, answer); snprintf(success_msg, sizeof(success_msg)-1, " Delay before sleep shutdown set to %d min", tmp); return decode_setvar_exec(res, (unsigned char)answer[0], varname, success_msg); } if (!strcasecmp(varname, "battery.packs")) { send_write_command(AUTHOR, 4); sleep(PW_SLEEP); /* Need to. Have to wait at least 0,25 sec max 16 sec */ tmp=atoi(val); if (tmp < 0 || tmp > 5) { return STAT_SET_INVALID; } cbuf[0]=PW_SET_CONF_COMMAND; cbuf[1]=PW_CONF_BATT_STRINGS; cbuf[2]=tmp&0xff; cbuf[3]=0x0; res = command_write_sequence(cbuf, 4, answer); snprintf(success_msg, sizeof(success_msg)-1, "EBM Count set to %d ", tmp); return decode_setvar_exec(res, (unsigned char)answer[0], varname, success_msg); } strncpy(namebuf, varname, sizeof(namebuf)); namebuf[NUT_OUTLET_POSITION] = 'n'; /* Assumes a maximum of 9 outlets */ if ( (!strcasecmp(namebuf, "outlet.n.delay.start")) || (!strcasecmp(namebuf, "outlet.n.delay.shutdown"))) { if (outlet_block_len <= 8) { return STAT_SET_INVALID; } if (!strcasecmp(namebuf, "outlet.n.delay.start")) { onOff_setting = PW_AUTO_ON_DELAY; } send_write_command(AUTHOR, 4); sleep(PW_SLEEP); /* Need to. Have to wait at least 0,25 sec max 16 sec */ outlet_num = varname[NUT_OUTLET_POSITION] - '0'; if (outlet_num < 1 || outlet_num > 9) { return STAT_SET_INVALID; } sec = atoi(val); /* Check value: * 0-32767 are valid values * -1 means no Automatic off or restart * for Auto Off Delay: * 0-30 are valid but ill-advised */ if (sec < -1 || sec > 0x7FFF) { return STAT_SET_INVALID; } cbuf[0] = PW_SET_OUTLET_COMMAND; /* Cmd */ cbuf[1] = (unsigned char)onOff_setting; /* Set Auto Off (1) or On (2) Delay */ cbuf[2] = (unsigned char)outlet_num; /* Outlet number */ cbuf[3] = sec&0xff; /* Delay in seconds LSB */ cbuf[4] = (unsigned char)(sec>>8); /* Delay in seconds MSB */ res = command_write_sequence(cbuf, 5, answer); snprintf(success_msg, sizeof(success_msg)-1, "Outlet %d %s delay set to %d sec", outlet_num, (onOff_setting == PW_AUTO_ON_DELAY) ? "start" : "shutdown", sec); return decode_setvar_exec(res, (unsigned char)answer[0], varname, success_msg); } return STAT_SET_INVALID; } static int decode_setvar_exec(const ssize_t res, const unsigned char exec_status, const char *cmdname, const char *success_msg) { if (res <= 0) { upslogx(LOG_ERR, "[%s] Short read from UPS", cmdname); dstate_datastale(); return STAT_SET_FAILED; } /* Decode the status code from command execution */ switch (exec_status) { case BCMXCP_RETURN_ACCEPTED: { upslogx(LOG_NOTICE, "[%s] %s", cmdname, success_msg); upsdrv_comm_good(); return STAT_SET_HANDLED; } case BCMXCP_RETURN_ACCEPTED_PARAMETER_ADJUST: { upslogx(LOG_NOTICE, "[%s] Parameter adjusted", cmdname); upslogx(LOG_NOTICE, "[%s] %s", cmdname, success_msg); upsdrv_comm_good(); return STAT_SET_HANDLED; } case BCMXCP_RETURN_BUSY: { upslogx(LOG_NOTICE, "[%s] Busy or disbled by front panel", cmdname); return STAT_SET_FAILED; } case BCMXCP_RETURN_UNRECOGNISED: { upslogx(LOG_NOTICE, "[%s] Unrecognised command byte or corrupt checksum", cmdname); return STAT_SET_FAILED; } case BCMXCP_RETURN_INVALID_PARAMETER: { upslogx(LOG_NOTICE, "[%s] Invalid parameter", cmdname); return STAT_SET_INVALID; } case BCMXCP_RETURN_PARAMETER_OUT_OF_RANGE: { upslogx(LOG_NOTICE, "[%s] Parameter out of range", cmdname); return STAT_SET_INVALID; } default: { upslogx(LOG_NOTICE, "[%s] Not supported", cmdname); return STAT_SET_INVALID; } } } /******************************* * Extracted from usbhid-ups.c * *******************************/ /* find the NUT value matching that XCP Item value */ static const char *nut_find_infoval(info_lkp_t *xcp2info, const double value, const bool_t debug_output_nonexisting) { info_lkp_t *info_lkp; /* if a conversion function is defined, use 'value' as argument for it */ if (xcp2info->fun != NULL) { return xcp2info->fun(value); } /* use 'value' as an index for a lookup in an array */ for (info_lkp = xcp2info; info_lkp->nut_value != NULL; info_lkp++) { if (info_lkp->xcp_value == (long)value) { upsdebugx(5, "nut_find_infoval: found %s (value: %ld)", info_lkp->nut_value, (long)value); return info_lkp->nut_value; } } if (debug_output_nonexisting == TRUE) { upsdebugx(3, "nut_find_infoval: no matching INFO_* value for this XCP value (%g)", value); } return NULL; } nut-2.8.1/drivers/liebert.c0000644000175000017500000001000714501607135012521 00000000000000/* liebert.c - support for Liebert UPS models via MultiLink cable. Copyright (C) 2002 Russell Kroll Based on old-style multilink.c driver: Copyright (C) 2001 Rick Lyons 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 2 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, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "config.h" #include "main.h" #include "serial.h" #include "attribute.h" #define DRIVER_NAME "Liebert MultiLink UPS driver" #define DRIVER_VERSION "1.04" /* driver description structure */ upsdrv_info_t upsdrv_info = { DRIVER_NAME, DRIVER_VERSION, "Russell Kroll \n" \ "Rick Lyons ", DRV_EXPERIMENTAL, { NULL } }; #define ML_ONBATTERY 0x55 void upsdrv_shutdown(void) { /* XXX: replace with a proper shutdown function (raise DTR) */ /* worse yet: stock cables don't support shutdown at all */ upslogx(LOG_ERR, "shutdown not supported"); set_exit_flag(-1); } void upsdrv_initinfo(void) { char *tmp; tmp = getval("mfr"); if (!tmp) dstate_setinfo("ups.mfr", "Liebert"); else dstate_setinfo("ups.mfr", "%s", tmp); tmp = getval("model"); if (!tmp) dstate_setinfo("ups.model", "MultiLink"); else dstate_setinfo("ups.model", "%s", tmp); } /* require this many OBs or LBs before actually setting it */ #define DEBOUNCE 3 /* normal idle loop - keep up with the current state of the UPS */ void upsdrv_updateinfo(void) { unsigned char c; unsigned int ob, lb; static unsigned int ob_state = 0, ob_last = 0, ob_ctr = 0; static unsigned int lb_state = 0, lb_last = 0, lb_ctr = 0; ob = lb = 0; /* the UPS connects RX to TX when on battery, so test for loopback */ ser_flush_in(upsfd, "", 0); c = ML_ONBATTERY; ser_send_char(upsfd, c); if (ser_get_char(upsfd, &c, 1, 0) == 1) { while (ser_get_char(upsfd, &c, 1, 0) == 1) continue; if (c == ML_ONBATTERY) ob = 1; } if (ser_get_dcd(upsfd)) lb = 1; /* state machine below to ensure status changes are debounced */ /* OB/OL state change: reset counter */ if (ob_last != ob) ob_ctr = 0; else ob_ctr++; upsdebugx(2, "OB: state %d last %d now %d ctr %d", ob_state, ob_last, ob, ob_ctr); if (ob_ctr >= DEBOUNCE) { if (ob != ob_state) { upsdebugx(2, "OB: toggling state"); if (ob_state == 0) ob_state = 1; else ob_state = 0; } } ob_last = ob; /* now do it again for LB */ /* state change: reset counter */ if (lb_last != lb) lb_ctr = 0; else lb_ctr++; upsdebugx(2, "LB: state %d last %d now %d ctr %d", lb_state, lb_last, lb, lb_ctr); if (lb_ctr >= DEBOUNCE) { if (lb != lb_state) { upsdebugx(2, "LB: toggling state"); if (lb_state == 0) lb_state = 1; else lb_state = 0; } } lb_last = lb; status_init(); if (ob_state == 1) status_set("OB"); /* on battery */ else status_set("OL"); /* on line */ if (lb_state == 1) status_set("LB"); /* low battery */ status_commit(); dstate_dataok(); } void upsdrv_makevartable(void) { addvar(VAR_VALUE, "mfr", "Override manufacturer name"); addvar(VAR_VALUE, "model", "Override model name"); } void upsdrv_help(void) { } void upsdrv_initups(void) { upsfd = ser_open(device_path); /* Speed should not matter (see comments in upsdrv_updateinfo), * but set it relatively low in case there are problems with higher * speeds. */ ser_set_speed(upsfd, device_path, B9600); /* raise RTS */ ser_set_rts(upsfd, 1); } void upsdrv_cleanup(void) { ser_close(upsfd, device_path); } nut-2.8.1/drivers/raritan-pdu-mib.h0000644000175000017500000000023514273170601014074 00000000000000#ifndef RARITAN_PDU_MIB_H #define RARITAN_PDU_MIB_H #include "main.h" #include "snmp-ups.h" extern mib2nut_info_t raritan; #endif /* RARITAN_PDU_MIB_H */ nut-2.8.1/drivers/mge-mib.h0000644000175000017500000000020114273170601012407 00000000000000#ifndef MGE_MIB_H #define MGE_MIB_H #include "main.h" #include "snmp-ups.h" extern mib2nut_info_t mge; #endif /* MGE_MIB_H */ nut-2.8.1/drivers/eaton-ups-pwnm2-mib.c0000644000175000017500000011212114501607135014614 00000000000000/* eaton-ups-pwnm2-mib.c - data to monitor Powerware and Eaton NM2 UPS with NUT * (using MIBs described in stdupsv1.mib and Xups.mib) * * Copyright (C) * 2005-2006 Olli Savia * 2005-2006 Niels Baggesen * 2015-2022 Eaton (author: Arnaud Quette ) * * 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 2 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, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #include "eaton-ups-pwnm2-mib.h" #if WITH_SNMP_LKP_FUN /* FIXME: shared helper code, need to be put in common */ #include "eaton-pdu-marlin-helpers.h" #endif #define PW_MIB_VERSION "0.105" /* Powerware UPS (Ingrasys X-SLOT and BD-SLOT) * Eaton Gigabit Network Card (Genepi) */ #define POWERWARE_SYSOID ".1.3.6.1.4.1.534.1" /* SNMP OIDs set */ #define PW_OID_MFR_NAME "1.3.6.1.4.1.534.1.1.1.0" /* XUPS-MIB::xupsIdentManufacturer.0 */ #define PW_OID_MODEL_NAME "1.3.6.1.4.1.534.1.1.2.0" /* XUPS-MIB::xupsIdentModel.0 */ #define PW_OID_FIRMREV "1.3.6.1.4.1.534.1.1.3.0" /* XUPS-MIB::xupsIdentSoftwareVersion.0 */ #define PW_OID_BATT_RUNTIME "1.3.6.1.4.1.534.1.2.1.0" /* XUPS-MIB::xupsBatTimeRemaining.0 */ #define PW_OID_BATT_VOLTAGE "1.3.6.1.4.1.534.1.2.2.0" /* XUPS-MIB::xupsBatVoltage.0 */ #define PW_OID_BATT_CURRENT "1.3.6.1.4.1.534.1.2.3.0" /* XUPS-MIB::xupsBatCurrent.0 */ #define PW_OID_BATT_CHARGE "1.3.6.1.4.1.534.1.2.4.0" /* XUPS-MIB::xupsBatCapacity.0 */ #define PW_OID_BATT_STATUS "1.3.6.1.4.1.534.1.2.5.0" /* XUPS-MIB::xupsBatteryAbmStatus.0 */ #define PW_OID_IN_FREQUENCY "1.3.6.1.4.1.534.1.3.1.0" /* XUPS-MIB::xupsInputFrequency.0 */ #define PW_OID_IN_LINE_BADS "1.3.6.1.4.1.534.1.3.2.0" /* XUPS-MIB::xupsInputLineBads.0 */ #define PW_OID_IN_LINES "1.3.6.1.4.1.534.1.3.3.0" /* XUPS-MIB::xupsInputNumPhases.0 */ #define PW_OID_IN_VOLTAGE "1.3.6.1.4.1.534.1.3.4.1.2" /* XUPS-MIB::xupsInputVoltage */ #define PW_OID_IN_CURRENT "1.3.6.1.4.1.534.1.3.4.1.3" /* XUPS-MIB::xupsInputCurrent */ #define PW_OID_IN_POWER "1.3.6.1.4.1.534.1.3.4.1.4" /* XUPS-MIB::xupsInputWatts */ #define PW_OID_OUT_LOAD "1.3.6.1.4.1.534.1.4.1.0" /* XUPS-MIB::xupsOutputLoad.0 */ #define PW_OID_OUT_FREQUENCY "1.3.6.1.4.1.534.1.4.2.0" /* XUPS-MIB::xupsOutputFrequency.0 */ #define PW_OID_OUT_LINES "1.3.6.1.4.1.534.1.4.3.0" /* XUPS-MIB::xupsOutputNumPhases.0 */ #define PW_OID_OUT_VOLTAGE "1.3.6.1.4.1.534.1.4.4.1.2" /* XUPS-MIB::xupsOutputVoltage */ #define PW_OID_OUT_CURRENT "1.3.6.1.4.1.534.1.4.4.1.3" /* XUPS-MIB::xupsOutputCurrent */ #define PW_OID_OUT_POWER "1.3.6.1.4.1.534.1.4.4.1.4" /* XUPS-MIB::xupsOutputWatts */ #define PW_OID_POWER_STATUS "1.3.6.1.4.1.534.1.4.5.0" /* XUPS-MIB::xupsOutputSource.0 */ #define PW_OID_BY_FREQUENCY "1.3.6.1.4.1.534.1.5.1.0" /* XUPS-MIB::xupsBypassFrequency.0 */ #define PW_OID_BY_LINES "1.3.6.1.4.1.534.1.5.2.0" /* XUPS-MIB::xupsBypassNumPhases.0 */ #define PW_OID_BY_VOLTAGE "1.3.6.1.4.1.534.1.5.3.1.2" /* XUPS-MIB::xupsBypassVoltage */ #define PW_OID_BATTEST_START "1.3.6.1.4.1.534.1.8.1" /* XUPS-MIB::xupsTestBattery set to startTest(1) to initiate test*/ #define PW_OID_CONT_OFFDELAY "1.3.6.1.4.1.534.1.9.1.0" /* XUPS-MIB::xupsControlOutputOffDelay */ #define PW_OID_CONT_ONDELAY "1.3.6.1.4.1.534.1.9.2.0" /* XUPS-MIB::xupsControlOutputOnDelay */ #define PW_OID_CONT_OFFT_DEL "1.3.6.1.4.1.534.1.9.3" /* XUPS-MIB::xupsControlOutputOffTrapDelay */ #define PW_OID_CONT_ONT_DEL "1.3.6.1.4.1.534.1.9.4" /* XUPS-MIB::xupsControlOutputOnTrapDelay */ #define PW_OID_CONT_LOAD_SHED_AND_RESTART "1.3.6.1.4.1.534.1.9.6" /* XUPS-MIB::xupsLoadShedSecsWithRestart */ #define PW_OID_CONF_OVOLTAGE "1.3.6.1.4.1.534.1.10.1.0" /* XUPS-MIB::xupsConfigOutputVoltage.0 */ #define PW_OID_CONF_IVOLTAGE "1.3.6.1.4.1.534.1.10.2.0" /* XUPS-MIB::xupsConfigInputVoltage.0 */ #define PW_OID_CONF_POWER "1.3.6.1.4.1.534.1.10.3.0" /* XUPS-MIB::xupsConfigOutputWatts.0 */ #define PW_OID_CONF_FREQ "1.3.6.1.4.1.534.1.10.4.0" /* XUPS-MIB::xupsConfigOutputFreq.0 */ #define PW_OID_ALARMS "1.3.6.1.4.1.534.1.7.1.0" /* XUPS-MIB::xupsAlarms */ #define PW_OID_ALARM_OB "1.3.6.1.4.1.534.1.7.3" /* XUPS-MIB::xupsOnBattery */ #define PW_OID_ALARM_LB "1.3.6.1.4.1.534.1.7.4" /* XUPS-MIB::xupsLowBattery */ #define IETF_OID_AGENTREV "1.3.6.1.2.1.33.1.1.4.0" /* UPS-MIB::upsIdentAgentSoftwareVersion.0 */ #define IETF_OID_IDENT "1.3.6.1.2.1.33.1.1.5.0" /* UPS-MIB::upsIdentName.0 */ #define IETF_OID_CONF_OUT_VA "1.3.6.1.2.1.33.1.9.5.0" /* UPS-MIB::upsConfigOutputVA.0 */ #define IETF_OID_CONF_RUNTIME_LOW "1.3.6.1.2.1.33.1.9.7.0" /* UPS-MIB::upsConfigLowBattTime.0 */ #define IETF_OID_LOAD_LEVEL "1.3.6.1.2.1.33.1.4.4.1.5" /* UPS-MIB::upsOutputPercentLoad */ #define IETF_OID_AUTO_RESTART "1.3.6.1.2.1.33.1.8.5.0" /* UPS-MIB::upsAutoRestart */ /* Delay before powering off in seconds */ #define DEFAULT_OFFDELAY 30 /* Delay before powering on in seconds */ #define DEFAULT_ONDELAY 20 /* Default shutdown.return delay in seconds */ #define DEFAULT_SHUTDOWNDELAY 0 static info_lkp_t pw_alarm_ob[] = { { 1, "OB", NULL, NULL }, { 2, "", NULL, NULL }, { 0, NULL, NULL, NULL } }; static info_lkp_t pw_alarm_lb[] = { { 1, "LB", NULL, NULL }, { 2, "", NULL, NULL }, { 0, NULL, NULL, NULL } }; static info_lkp_t pw_pwr_info[] = { { 1, "" /* other */, NULL, NULL }, { 2, "OFF" /* none */, NULL, NULL }, { 3, "OL" /* normal */, NULL, NULL }, { 4, "BYPASS" /* bypass */, NULL, NULL }, { 5, "OB" /* battery */, NULL, NULL }, { 6, "OL BOOST" /* booster */, NULL, NULL }, { 7, "OL TRIM" /* reducer */, NULL, NULL }, { 8, "OL" /* parallel capacity */, NULL, NULL }, { 9, "OL" /* parallel redundancy */, NULL, NULL }, { 10, "OL" /* high efficiency */, NULL, NULL }, { 11, "BYPASS" /* maintenanceBypass */, NULL, NULL }, { 11, "OL" /* essMode */, NULL, NULL }, { 0, NULL, NULL, NULL } }; /* FIXME: mapped to (experimental.)ups.type, but * should be output.source or ups.mode (need RFC) * to complement the above ups.status * along with having ups.type as described hereafter*/ /* FIXME: should be used by ups.mode or output.source (need RFC); * Note: this define is not set via project options; code was hidden with * original commit to "snmp-ups: support newer Genepi management cards"; * un-hidden to make it "experimental.*" namespace during backporting */ #ifndef USE_PW_MODE_INFO # define USE_PW_MODE_INFO 1 #endif #if USE_PW_MODE_INFO static info_lkp_t pw_mode_info[] = { { 1, "", NULL, NULL }, { 2, "", NULL, NULL }, { 3, "normal", NULL, NULL }, { 4, "", NULL, NULL }, { 5, "", NULL, NULL }, { 6, "", NULL, NULL }, { 7, "", NULL, NULL }, { 8, "parallel capacity", NULL, NULL }, { 9, "parallel redundancy", NULL, NULL }, { 10, "high efficiency", NULL, NULL }, /* Extended status values, * FIXME: check for source and completion */ { 240, "" /* battery (0xF0) */, NULL, NULL }, { 100, "" /* maintenanceBypass (0x64) */, NULL, NULL }, { 96, "" /* Bypass (0x60) */, NULL, NULL }, { 81, "high efficiency" /* high efficiency (0x51) */, NULL, NULL }, { 80, "normal" /* normal (0x50) */, NULL, NULL }, { 64, "" /* UPS supporting load, normal degraded mode (0x40) */, NULL, NULL }, { 16, "" /* none (0x10) */, NULL, NULL }, { 0, NULL, NULL, NULL } }; #endif /* USE_PW_MODE_INFO */ /* FIXME: may be standardized * extracted from bcmxcp.c->BCMXCP_TOPOLOGY_*, Make some common definitions */ static info_lkp_t pw_topology_info[] = { { 0x0000, "", NULL, NULL }, /* None; use the Table of Elements */ { 0x0010, "Off-line switcher, Single Phase", NULL, NULL }, { 0x0020, "Line-Interactive UPS, Single Phase", NULL, NULL }, { 0x0021, "Line-Interactive UPS, Two Phase", NULL, NULL }, { 0x0022, "Line-Interactive UPS, Three Phase", NULL, NULL }, { 0x0030, "Dual AC Input, On-Line UPS, Single Phase", NULL, NULL }, { 0x0031, "Dual AC Input, On-Line UPS, Two Phase", NULL, NULL }, { 0x0032, "Dual AC Input, On-Line UPS, Three Phase", NULL, NULL }, { 0x0040, "On-Line UPS, Single Phase", NULL, NULL }, { 0x0041, "On-Line UPS, Two Phase", NULL, NULL }, { 0x0042, "On-Line UPS, Three Phase", NULL, NULL }, { 0x0050, "Parallel Redundant On-Line UPS, Single Phase", NULL, NULL }, { 0x0051, "Parallel Redundant On-Line UPS, Two Phase", NULL, NULL }, { 0x0052, "Parallel Redundant On-Line UPS, Three Phase", NULL, NULL }, { 0x0060, "Parallel for Capacity On-Line UPS, Single Phase", NULL, NULL }, { 0x0061, "Parallel for Capacity On-Line UPS, Two Phase", NULL, NULL }, { 0x0062, "Parallel for Capacity On-Line UPS, Three Phase", NULL, NULL }, { 0x0102, "System Bypass Module, Three Phase", NULL, NULL }, { 0x0122, "Hot-Tie Cabinet, Three Phase", NULL, NULL }, { 0x0200, "Outlet Controller, Single Phase", NULL, NULL }, { 0x0222, "Dual AC Input Static Switch Module, 3 Phase", NULL, NULL }, { 0, NULL, NULL, NULL } }; /* Legacy implementation */ static info_lkp_t pw_battery_abm_status[] = { { 1, "CHRG", NULL, NULL }, { 2, "DISCHRG", NULL, NULL }, /* { 3, "Floating", NULL, NULL }, */ /* { 4, "Resting", NULL, NULL }, */ /* { 5, "Unknown", NULL, NULL }, */ { 0, NULL, NULL, NULL } }; static info_lkp_t pw_abm_status_info[] = { { 1, "charging", NULL, NULL }, { 2, "discharging", NULL, NULL }, { 3, "floating", NULL, NULL }, { 4, "resting", NULL, NULL }, { 5, "unknown", NULL, NULL }, /* Undefined - ABM is not activated */ { 6, "disabled", NULL, NULL }, /* ABM Charger Disabled */ { 0, NULL, NULL, NULL } }; static info_lkp_t pw_batt_test_info[] = { { 1, "Unknown", NULL, NULL }, { 2, "Done and passed", NULL, NULL }, { 3, "Done and error", NULL, NULL }, { 4, "In progress", NULL, NULL }, { 5, "Not supported", NULL, NULL }, { 6, "Inhibited", NULL, NULL }, { 7, "Scheduled", NULL, NULL }, { 0, NULL, NULL, NULL } }; static info_lkp_t pw_yes_no_info[] = { { 1, "yes", NULL, NULL }, { 2, "no", NULL, NULL }, { 0, NULL, NULL, NULL } }; static info_lkp_t pw_outlet_status_info[] = { { 1, "on", NULL, NULL }, { 2, "off", NULL, NULL }, { 3, "on", NULL, NULL }, /* pendingOff, transitional status */ { 4, "off", NULL, NULL }, /* pendingOn, transitional status */ /* { 5, "", NULL, NULL }, unknown */ /* { 6, "", NULL, NULL }, reserved */ { 7, "off", NULL, NULL }, /* Failed in Closed position */ { 8, "on", NULL, NULL }, /* Failed in Open position */ { 0, NULL, NULL, NULL } }; static info_lkp_t pw_ambient_drycontacts_info[] = { { -1, "unknown", NULL, NULL }, { 1, "opened", NULL, NULL }, { 2, "closed", NULL, NULL }, { 3, "opened", NULL, NULL }, /* openWithNotice */ { 4, "closed", NULL, NULL }, /* closedWithNotice */ { 0, NULL, NULL, NULL } }; #if WITH_SNMP_LKP_FUN /* Note: eaton_sensor_temperature_unit_fun() is defined in eaton-pdu-marlin-helpers.c * and su_temperature_read_fun() is in snmp-ups.c * Future work for DMF might provide same-named routines via LUA-C gateway. */ # if WITH_SNMP_LKP_FUN_DUMMY /* Temperature unit consideration */ const char *eaton_sensor_temperature_unit_fun(void *raw_snmp_value) { /* snmp_value here would be a (long*) */ NUT_UNUSED_VARIABLE(raw_snmp_value); return "unknown"; } /* FIXME: please DMF, though this should be in snmp-ups.c or equiv. */ const char *su_temperature_read_fun(void *raw_snmp_value) { /* snmp_value here would be a (long*) */ NUT_UNUSED_VARIABLE(raw_snmp_value); return "dummy"; }; # endif /* WITH_SNMP_LKP_FUN_DUMMY */ static info_lkp_t pw_sensor_temperature_unit_info[] = { { 0, "dummy", eaton_sensor_temperature_unit_fun, NULL }, { 0, NULL, NULL, NULL } }; static info_lkp_t pw_sensor_temperature_read_info[] = { { 0, "dummy", su_temperature_read_fun, NULL }, { 0, NULL, NULL, NULL } }; #else /* if not WITH_SNMP_LKP_FUN: */ /* FIXME: For now, DMF codebase falls back to old implementation with static * lookup/mapping tables for this, which can easily go into the DMF XML file. */ static info_lkp_t pw_sensor_temperature_unit_info[] = { { 0, "kelvin", NULL, NULL }, { 1, "celsius", NULL, NULL }, { 2, "fahrenheit", NULL, NULL }, { 0, NULL, NULL, NULL } }; #endif /* WITH_SNMP_LKP_FUN */ static info_lkp_t pw_ambient_drycontacts_polarity_info[] = { { 0, "normal-opened", NULL, NULL }, { 1, "normal-closed", NULL, NULL }, { 0, NULL, NULL, NULL } }; static info_lkp_t pw_ambient_drycontacts_state_info[] = { { 0, "inactive", NULL, NULL }, { 1, "active", NULL, NULL }, { 0, NULL, NULL, NULL } }; static info_lkp_t pw_emp002_ambient_presence_info[] = { { 0, "unknown", NULL, NULL }, { 2, "yes", NULL, NULL }, /* communicationOK */ { 3, "no", NULL, NULL }, /* communicationLost */ { 0, NULL, NULL, NULL } }; /* extracted from drivers/eaton-pdu-marlin-mib.c -> marlin_threshold_status_info */ static info_lkp_t pw_threshold_status_info[] = { { 0, "good", NULL, NULL }, /* No threshold triggered */ { 1, "warning-low", NULL, NULL }, /* Warning low threshold triggered */ { 2, "critical-low", NULL, NULL }, /* Critical low threshold triggered */ { 3, "warning-high", NULL, NULL }, /* Warning high threshold triggered */ { 4, "critical-high", NULL, NULL }, /* Critical high threshold triggered */ { 0, NULL, NULL, NULL } }; /* extracted from drivers/eaton-pdu-marlin-mib.c -> marlin_threshold_xxx_alarms_info */ static info_lkp_t pw_threshold_temperature_alarms_info[] = { { 0, "", NULL, NULL }, /* No threshold triggered */ { 1, "low temperature warning!", NULL, NULL }, /* Warning low threshold triggered */ { 2, "low temperature critical!", NULL, NULL }, /* Critical low threshold triggered */ { 3, "high temperature warning!", NULL, NULL }, /* Warning high threshold triggered */ { 4, "high temperature critical!", NULL, NULL }, /* Critical high threshold triggered */ { 0, NULL, NULL, NULL } }; static info_lkp_t pw_threshold_humidity_alarms_info[] = { { 0, "", NULL, NULL }, /* No threshold triggered */ { 1, "low humidity warning!", NULL, NULL }, /* Warning low threshold triggered */ { 2, "low humidity critical!", NULL, NULL }, /* Critical low threshold triggered */ { 3, "high humidity warning!", NULL, NULL }, /* Warning high threshold triggered */ { 4, "high humidity critical!", NULL, NULL }, /* Critical high threshold triggered */ { 0, NULL, NULL, NULL } }; /* Snmp2NUT lookup table */ static snmp_info_t pw_mib[] = { /* standard MIB items */ { "device.description", ST_FLAG_STRING | ST_FLAG_RW, SU_INFOSIZE, ".1.3.6.1.2.1.1.1.0", NULL, SU_FLAG_OK, NULL }, { "device.contact", ST_FLAG_STRING | ST_FLAG_RW, SU_INFOSIZE, ".1.3.6.1.2.1.1.4.0", NULL, SU_FLAG_OK, NULL }, { "device.location", ST_FLAG_STRING | ST_FLAG_RW, SU_INFOSIZE, ".1.3.6.1.2.1.1.6.0", NULL, SU_FLAG_OK, NULL }, /* FIXME: miss device page! */ /* UPS page */ /* info_type, info_flags, info_len, OID, dfl, flags, oid2info, setvar */ { "ups.mfr", ST_FLAG_STRING, SU_INFOSIZE, PW_OID_MFR_NAME, "", SU_FLAG_STATIC, NULL }, { "ups.model", ST_FLAG_STRING, SU_INFOSIZE, PW_OID_MODEL_NAME, "", SU_FLAG_STATIC, NULL }, /* FIXME: the 2 "firmware" entries below should be SU_FLAG_SEMI_STATIC */ { "ups.firmware", ST_FLAG_STRING, SU_INFOSIZE, PW_OID_FIRMREV, "", 0, NULL }, { "ups.firmware.aux", ST_FLAG_STRING, SU_INFOSIZE, IETF_OID_AGENTREV, "", 0, NULL }, { "ups.serial", ST_FLAG_STRING, SU_INFOSIZE, IETF_OID_IDENT, "", SU_FLAG_STATIC, NULL }, { "ups.load", 0, 1.0, PW_OID_OUT_LOAD, "", 0, NULL }, /* FIXME: should be removed in favor of output.power */ { "ups.power", 0, 1.0, PW_OID_OUT_POWER ".1", "", 0, NULL }, /* Duplicate of the above entry, but pointing at the first index */ /* xupsOutputWatts.1.0; Value (Integer): 300 */ { "ups.power", 0, 1.0, "1.3.6.1.4.1.534.1.4.4.1.4.1.0", "", 0, NULL }, { "ups.status", ST_FLAG_STRING, SU_INFOSIZE, PW_OID_POWER_STATUS, "OFF", SU_STATUS_PWR, &pw_pwr_info[0] }, { "ups.status", ST_FLAG_STRING, SU_INFOSIZE, PW_OID_ALARM_OB, "", SU_STATUS_BATT, &pw_alarm_ob[0] }, { "ups.status", ST_FLAG_STRING, SU_INFOSIZE, PW_OID_ALARM_LB, "", SU_STATUS_BATT, &pw_alarm_lb[0] }, { "ups.status", ST_FLAG_STRING, SU_INFOSIZE, PW_OID_BATT_STATUS, "", SU_STATUS_BATT, &pw_battery_abm_status[0] }, #if USE_PW_MODE_INFO /* FIXME: should be ups.mode or output.source (need RFC) */ /* Note: this define is not set via project options; code hidden with * commit to "snmp-ups: support newer Genepi management cards" */ { "experimental.ups.type", ST_FLAG_STRING, SU_INFOSIZE, PW_OID_POWER_STATUS, "", SU_FLAG_STATIC | SU_FLAG_OK, &pw_mode_info[0] }, #endif /* USE_PW_MODE_INFO */ /* xupsTopologyType.0; Value (Integer): 32 */ { "ups.type", ST_FLAG_STRING, SU_INFOSIZE, "1.3.6.1.4.1.534.1.13.1.0", "", SU_FLAG_STATIC | SU_FLAG_OK, &pw_topology_info[0] }, /* FIXME: should be removed in favor of their output. equivalent! */ { "ups.realpower.nominal", 0, 1.0, PW_OID_CONF_POWER, "", 0, NULL }, /* FIXME: should be removed in favor of output.power.nominal */ { "ups.power.nominal", 0, 1.0, IETF_OID_CONF_OUT_VA, "", 0, NULL }, /* XUPS-MIB::xupsEnvAmbientTemp.0 */ { "ups.temperature", 0, 1.0, "1.3.6.1.4.1.534.1.6.1.0", "", 0, NULL }, /* FIXME: These 2 data needs RFC! */ /* XUPS-MIB::xupsEnvAmbientLowerLimit.0 */ { "ups.temperature.low", ST_FLAG_RW, 1.0, "1.3.6.1.4.1.534.1.6.2.0", "", 0, NULL }, /* XUPS-MIB::xupsEnvAmbientUpperLimit.0 */ { "ups.temperature.high", ST_FLAG_RW, 1.0, "1.3.6.1.4.1.534.1.6.3.0", "", 0, NULL }, /* XUPS-MIB::xupsTestBatteryStatus */ { "ups.test.result", ST_FLAG_STRING, SU_INFOSIZE, "1.3.6.1.4.1.534.1.8.2.0", "", 0, &pw_batt_test_info[0] }, /* UPS-MIB::upsAutoRestart */ { "ups.start.auto", ST_FLAG_RW | ST_FLAG_STRING, SU_INFOSIZE, "1.3.6.1.2.1.33.1.8.5.0", "", SU_FLAG_OK, &pw_yes_no_info[0] }, /* XUPS-MIB::xupsBatteryAbmStatus.0 */ { "battery.charger.status", ST_FLAG_STRING, SU_INFOSIZE, "1.3.6.1.4.1.534.1.2.5.0", "", SU_STATUS_BATT, &pw_abm_status_info[0] }, /* Battery page */ { "battery.charge", 0, 1.0, PW_OID_BATT_CHARGE, "", 0, NULL }, { "battery.runtime", 0, 1.0, PW_OID_BATT_RUNTIME, "", 0, NULL }, { "battery.voltage", 0, 1.0, PW_OID_BATT_VOLTAGE, "", 0, NULL }, { "battery.current", 0, 0.1, PW_OID_BATT_CURRENT, "", 0, NULL }, { "battery.runtime.low", 0, 60.0, IETF_OID_CONF_RUNTIME_LOW, "", 0, NULL }, { "battery.date", ST_FLAG_RW | ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.534.1.2.6.0", NULL, SU_FLAG_OK, &su_convert_to_iso_date_info[FUNMAP_USDATE_TO_ISODATE] }, /* Output page */ { "output.phases", 0, 1.0, PW_OID_OUT_LINES, "", 0, NULL }, /* XUPS-MIB::xupsOutputFrequency.0 */ { "output.frequency", 0, 0.1, "1.3.6.1.4.1.534.1.4.2.0", "", 0, NULL }, /* XUPS-MIB::xupsConfigOutputFreq.0 */ { "output.frequency.nominal", 0, 0.1, "1.3.6.1.4.1.534.1.10.4.0", "", 0, NULL }, /* XUPS-MIB::xupsOutputVoltage.1 */ { "output.voltage", 0, 1.0, "1.3.6.1.4.1.534.1.4.4.1.2.1", "", SU_OUTPUT_1, NULL }, /* Duplicate of the above entry, but pointing at the first index */ /* xupsOutputVoltage.1.0; Value (Integer): 230 */ { "output.voltage", 0, 1.0, "1.3.6.1.4.1.534.1.4.4.1.2.1.0", "", SU_OUTPUT_1, NULL }, /* XUPS-MIB::xupsConfigOutputVoltage.0 */ { "output.voltage.nominal", 0, 1.0, "1.3.6.1.4.1.534.1.10.1.0", "", 0, NULL }, /* XUPS-MIB::xupsConfigLowOutputVoltageLimit.0 */ { "output.voltage.low", 0, 1.0, ".1.3.6.1.4.1.534.1.10.6.0", "", 0, NULL }, /* XUPS-MIB::xupsConfigHighOutputVoltageLimit.0 */ { "output.voltage.high", 0, 1.0, ".1.3.6.1.4.1.534.1.10.7.0", "", 0, NULL }, { "output.current", 0, 1.0, PW_OID_OUT_CURRENT ".1", "", SU_OUTPUT_1, NULL }, /* Duplicate of the above entry, but pointing at the first index */ /* xupsOutputCurrent.1.0; Value (Integer): 0 */ { "output.current", 0, 1.0, "1.3.6.1.4.1.534.1.4.4.1.3.1.0", "", SU_OUTPUT_1, NULL }, { "output.realpower", 0, 1.0, PW_OID_OUT_POWER ".1", "", SU_OUTPUT_1, NULL }, /* Duplicate of the above entry, but pointing at the first index */ /* Name/OID: xupsOutputWatts.1.0; Value (Integer): 1200 */ { "output.realpower", 0, 1.0, "1.3.6.1.4.1.534.1.4.4.1.4.1.0", "", 0, NULL }, /* Duplicate of "ups.realpower.nominal" * FIXME: map either ups or output, but not both (or have an auto-remap) */ { "output.realpower.nominal", 0, 1.0, PW_OID_CONF_POWER, "", 0, NULL }, { "output.L1-N.voltage", 0, 1.0, PW_OID_OUT_VOLTAGE ".1", "", SU_OUTPUT_3, NULL }, { "output.L2-N.voltage", 0, 1.0, PW_OID_OUT_VOLTAGE ".2", "", SU_OUTPUT_3, NULL }, { "output.L3-N.voltage", 0, 1.0, PW_OID_OUT_VOLTAGE ".3", "", SU_OUTPUT_3, NULL }, { "output.L1.current", 0, 1.0, PW_OID_OUT_CURRENT ".1", "", SU_OUTPUT_3, NULL }, { "output.L2.current", 0, 1.0, PW_OID_OUT_CURRENT ".2", "", SU_OUTPUT_3, NULL }, { "output.L3.current", 0, 1.0, PW_OID_OUT_CURRENT ".3", "", SU_OUTPUT_3, NULL }, { "output.L1.realpower", 0, 1.0, PW_OID_OUT_POWER ".1", "", SU_OUTPUT_3, NULL }, { "output.L2.realpower", 0, 1.0, PW_OID_OUT_POWER ".2", "", SU_OUTPUT_3, NULL }, { "output.L3.realpower", 0, 1.0, PW_OID_OUT_POWER ".3", "", SU_OUTPUT_3, NULL }, /* FIXME: should better be output.Lx.load */ { "output.L1.power.percent", 0, 1.0, IETF_OID_LOAD_LEVEL ".1", "", SU_OUTPUT_3, NULL }, { "output.L2.power.percent", 0, 1.0, IETF_OID_LOAD_LEVEL ".2", "", SU_OUTPUT_3, NULL }, { "output.L3.power.percent", 0, 1.0, IETF_OID_LOAD_LEVEL ".3", "", SU_OUTPUT_3, NULL }, { "output.voltage.nominal", 0, 1.0, PW_OID_CONF_OVOLTAGE, "", 0, NULL }, /* Input page */ { "input.phases", 0, 1.0, PW_OID_IN_LINES, "", 0, NULL }, { "input.frequency", 0, 0.1, PW_OID_IN_FREQUENCY, "", 0, NULL }, { "input.voltage", 0, 1.0, PW_OID_IN_VOLTAGE ".0", "", SU_INPUT_1, NULL }, /* Duplicate of the above entry, but pointing at the first index */ /* xupsInputVoltage.1[.0]; Value (Integer): 245 */ { "input.voltage", 0, 1.0, "1.3.6.1.4.1.534.1.3.4.1.2.1", "", SU_INPUT_1, NULL }, /* XUPS-MIB::xupsConfigInputVoltage.0 */ { "input.voltage.nominal", 0, 1.0, "1.3.6.1.4.1.534.1.10.2.0", "", 0, NULL }, { "input.current", 0, 0.1, PW_OID_IN_CURRENT ".0", "", SU_INPUT_1, NULL }, { "input.L1-N.voltage", 0, 1.0, PW_OID_IN_VOLTAGE ".1", "", SU_INPUT_3, NULL }, { "input.L2-N.voltage", 0, 1.0, PW_OID_IN_VOLTAGE ".2", "", SU_INPUT_3, NULL }, { "input.L3-N.voltage", 0, 1.0, PW_OID_IN_VOLTAGE ".3", "", SU_INPUT_3, NULL }, { "input.L1.current", 0, 1.0, PW_OID_IN_CURRENT ".1", "", SU_INPUT_3, NULL }, { "input.L2.current", 0, 1.0, PW_OID_IN_CURRENT ".2", "", SU_INPUT_3, NULL }, { "input.L3.current", 0, 1.0, PW_OID_IN_CURRENT ".3", "", SU_INPUT_3, NULL }, { "input.L1.realpower", 0, 1.0, PW_OID_IN_POWER ".1", "", SU_INPUT_3, NULL }, { "input.L2.realpower", 0, 1.0, PW_OID_IN_POWER ".2", "", SU_INPUT_3, NULL }, { "input.L3.realpower", 0, 1.0, PW_OID_IN_POWER ".3", "", SU_INPUT_3, NULL }, { "input.quality", 0, 1.0, PW_OID_IN_LINE_BADS, "", 0, NULL }, /* FIXME: this segfaults! do we assume the same number of bypass phases as input phases? { "input.bypass.phases", 0, 1.0, PW_OID_BY_LINES, "", 0, NULL }, */ { "input.bypass.frequency", 0, 0.1, PW_OID_BY_FREQUENCY, "", 0, NULL }, { "input.bypass.voltage", 0, 1.0, PW_OID_BY_VOLTAGE ".0", "", SU_INPUT_1, NULL }, /* Duplicate of the above entry, but pointing at the first index */ /* xupsBypassVoltage.1.0; Value (Integer): 244 */ { "input.bypass.voltage", 0, 1.0, "1.3.6.1.4.1.534.1.5.3.1.2.1.0", "", SU_INPUT_1, NULL }, { "input.bypass.L1-N.voltage", 0, 1.0, PW_OID_BY_VOLTAGE ".1", "", SU_INPUT_3, NULL }, { "input.bypass.L2-N.voltage", 0, 1.0, PW_OID_BY_VOLTAGE ".2", "", SU_INPUT_3, NULL }, { "input.bypass.L3-N.voltage", 0, 1.0, PW_OID_BY_VOLTAGE ".3", "", SU_INPUT_3, NULL }, /* Outlet page */ /* Master outlet id always equal to 0 */ { "outlet.id", 0, 1, NULL, "0", SU_FLAG_STATIC , NULL }, /* XUPS-MIB:: xupsSwitchable.0 */ { "outlet.switchable", 0, 1, ".1.3.6.1.4.1.534.1.9.7.0", NULL, SU_FLAG_STATIC , &pw_yes_no_info[0] }, /* XUPS-MIB::xupsNumReceptacles; Value (Integer): 2 */ { "outlet.count", 0, 1, ".1.3.6.1.4.1.534.1.12.1.0", NULL, SU_FLAG_STATIC, NULL }, /* XUPS-MIB::xupsRecepIndex.X; Value (Integer): X */ { "outlet.%i.id", 0, 1, ".1.3.6.1.4.1.534.1.12.2.1.1.%i", NULL, SU_FLAG_STATIC | SU_OUTLET, NULL }, /* This MIB does not provide outlets switchability info. So map to a nearby OID, for data activation, and map all values to "yes" */ { "outlet.%i.switchable", 0, 1, ".1.3.6.1.4.1.534.1.12.2.1.1.%i", NULL, SU_FLAG_STATIC | SU_OUTLET, NULL }, /* XUPS-MIB::xupsRecepStatus.X; Value (Integer): 1 */ { "outlet.%i.status", 0, 1, ".1.3.6.1.4.1.534.1.12.2.1.2.%i", NULL, SU_OUTLET, &pw_outlet_status_info[0] }, /* Ambient collection */ /* EMP001 (legacy) mapping */ /* XUPS-MIB::xupsEnvRemoteTemp.0 */ { "ambient.temperature", 0, 1.0, "1.3.6.1.4.1.534.1.6.5.0", "", 0, NULL }, /* XUPS-MIB::xupsEnvRemoteTempLowerLimit.0 */ { "ambient.temperature.low", ST_FLAG_RW, 1.0, "1.3.6.1.4.1.534.1.6.9.0", "", 0, NULL }, /* XUPS-MIB::xupsEnvRemoteTempUpperLimit.0 */ { "ambient.temperature.high", ST_FLAG_RW, 1.0, "1.3.6.1.4.1.534.1.6.10.0", "", 0, NULL }, /* XUPS-MIB::xupsEnvRemoteHumidity.0 */ { "ambient.humidity", 0, 1.0, "1.3.6.1.4.1.534.1.6.6.0", "", 0, NULL }, /* XUPS-MIB::xupsEnvRemoteHumidityLowerLimit.0 */ { "ambient.humidity.low", ST_FLAG_RW, 1.0, "1.3.6.1.4.1.534.1.6.11.0", "", 0, NULL }, /* XUPS-MIB::xupsEnvRemoteHumidityUpperLimit.0 */ { "ambient.humidity.high", ST_FLAG_RW, 1.0, "1.3.6.1.4.1.534.1.6.12.0", "", 0, NULL }, /* XUPS-MIB::xupsContactDescr.n */ { "ambient.contacts.1.name", ST_FLAG_STRING, 1.0, ".1.3.6.1.4.1.534.1.6.8.1.4.1", "", 0, NULL }, { "ambient.contacts.2.name", ST_FLAG_STRING, 1.0, ".1.3.6.1.4.1.534.1.6.8.1.4.2", "", 0, NULL }, /* XUPS-MIB::xupsContactState.n */ { "ambient.contacts.1.status", ST_FLAG_STRING, 1.0, ".1.3.6.1.4.1.534.1.6.8.1.3.1", "", 0, &pw_ambient_drycontacts_info[0] }, { "ambient.contacts.2.status", ST_FLAG_STRING, 1.0, ".1.3.6.1.4.1.534.1.6.8.1.3.2", "", 0, &pw_ambient_drycontacts_info[0] }, /* EMP002 (EATON EMP MIB) mapping, including daisychain support */ /* Warning: indexes start at '1' not '0'! */ /* sensorCount.0 */ { "ambient.count", ST_FLAG_RW, 1.0, ".1.3.6.1.4.1.534.6.8.1.1.1.0", "", 0, NULL }, /* CommunicationStatus.n */ { "ambient.%i.present", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.534.6.8.1.1.4.1.1.%i", NULL, SU_AMBIENT_TEMPLATE, &pw_emp002_ambient_presence_info[0] }, /* sensorName.n: OctetString EMPDT1H1C2 @1 */ { "ambient.%i.name", ST_FLAG_STRING, 1.0, ".1.3.6.1.4.1.534.6.8.1.1.3.1.1.%i", "", SU_AMBIENT_TEMPLATE, NULL }, /* sensorManufacturer.n */ { "ambient.%i.mfr", ST_FLAG_STRING, 1.0, ".1.3.6.1.4.1.534.6.8.1.1.2.1.6.%i", "", SU_AMBIENT_TEMPLATE, NULL }, /* sensorModel.n */ { "ambient.%i.model", ST_FLAG_STRING, 1.0, ".1.3.6.1.4.1.534.6.8.1.1.2.1.7.%i", "", SU_AMBIENT_TEMPLATE, NULL }, /* sensorSerialNumber.n */ { "ambient.%i.serial", ST_FLAG_STRING, 1.0, ".1.3.6.1.4.1.534.6.8.1.1.2.1.9.%i", "", SU_AMBIENT_TEMPLATE, NULL }, /* sensorUuid.n */ { "ambient.%i.id", ST_FLAG_STRING, 1.0, ".1.3.6.1.4.1.534.6.8.1.1.2.1.2.%i", "", SU_AMBIENT_TEMPLATE, NULL }, /* sensorAddress.n */ { "ambient.%i.address", 0, 1, ".1.3.6.1.4.1.534.6.8.1.1.2.1.4.%i", "", SU_AMBIENT_TEMPLATE, NULL }, /* sensorFirmwareVersion.n */ { "ambient.%i.firmware", ST_FLAG_STRING, 1.0, ".1.3.6.1.4.1.534.6.8.1.1.2.1.10.%i", "", SU_AMBIENT_TEMPLATE, NULL }, /* temperatureUnit.1 * MUST be before the temperature data reading! */ { "ambient.%i.temperature.unit", 0, 1.0, ".1.3.6.1.4.1.534.6.8.1.2.5.0", "", SU_AMBIENT_TEMPLATE, &pw_sensor_temperature_unit_info[0] }, /* temperatureValue.n.1 */ { "ambient.%i.temperature", 0, 0.1, ".1.3.6.1.4.1.534.6.8.1.2.3.1.3.%i.1", "", SU_AMBIENT_TEMPLATE, #if WITH_SNMP_LKP_FUN &pw_sensor_temperature_read_info[0] #else NULL #endif }, { "ambient.%i.temperature.status", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.534.6.8.1.2.3.1.1.%i.1", NULL, SU_AMBIENT_TEMPLATE, &pw_threshold_status_info[0] }, { "ups.alarm", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.534.6.8.1.2.3.1.1.%i.1", NULL, SU_AMBIENT_TEMPLATE, &pw_threshold_temperature_alarms_info[0] }, /* FIXME: ambient.n.temperature.{minimum,maximum} */ /* temperatureThresholdLowCritical.n.1 */ { "ambient.%i.temperature.low.critical", ST_FLAG_RW, 0.1, ".1.3.6.1.4.1.534.6.8.1.2.2.1.6.%i.1", "", SU_AMBIENT_TEMPLATE, NULL }, /* temperatureThresholdLowWarning.n.1 */ { "ambient.%i.temperature.low.warning", ST_FLAG_RW, 0.1, ".1.3.6.1.4.1.534.6.8.1.2.2.1.5.%i.1", "", SU_AMBIENT_TEMPLATE, NULL }, /* temperatureThresholdHighWarning.n.1 */ { "ambient.%i.temperature.high.warning", ST_FLAG_RW, 0.1, ".1.3.6.1.4.1.534.6.8.1.2.2.1.7.%i.1", "", SU_AMBIENT_TEMPLATE, NULL }, /* temperatureThresholdHighCritical.n.1 */ { "ambient.%i.temperature.high.critical", ST_FLAG_RW, 0.1, ".1.3.6.1.4.1.534.6.8.1.2.2.1.8.%i.1", "", SU_AMBIENT_TEMPLATE, NULL }, /* humidityValue.n.1 */ { "ambient.%i.humidity", 0, 0.1, ".1.3.6.1.4.1.534.6.8.1.3.3.1.3.%i.1", "", SU_AMBIENT_TEMPLATE, NULL }, { "ambient.%i.humidity.status", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.534.6.8.1.3.3.1.1.%i.1", NULL, SU_AMBIENT_TEMPLATE, &pw_threshold_status_info[0] }, { "ups.alarm", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.534.6.8.1.3.3.1.1.%i.1", NULL, SU_AMBIENT_TEMPLATE, &pw_threshold_humidity_alarms_info[0] }, /* FIXME: consider ambient.n.humidity.{minimum,maximum} */ /* humidityThresholdLowCritical.n.1 */ { "ambient.%i.humidity.low.critical", ST_FLAG_RW, 0.1, ".1.3.6.1.4.1.534.6.8.1.3.2.1.6.%i.1", "", SU_AMBIENT_TEMPLATE, NULL }, /* humidityThresholdLowWarning.n.1 */ { "ambient.%i.humidity.low.warning", ST_FLAG_RW, 0.1, ".1.3.6.1.4.1.534.6.8.1.3.2.1.5.%i.1", "", SU_AMBIENT_TEMPLATE, NULL }, /* humidityThresholdHighWarning.n.1 */ { "ambient.%i.humidity.high.warning", ST_FLAG_RW, 0.1, ".1.3.6.1.4.1.534.6.8.1.3.2.1.7.%i.1", "", SU_AMBIENT_TEMPLATE, NULL }, /* humidityThresholdHighCritical.n.1 */ { "ambient.%i.humidity.high.critical", ST_FLAG_RW, 0.1, ".1.3.6.1.4.1.534.6.8.1.3.2.1.8.%i.1", "", SU_AMBIENT_TEMPLATE, NULL }, /* digitalInputName.n.{1,2} */ { "ambient.%i.contacts.1.name", ST_FLAG_STRING, 1.0, ".1.3.6.1.4.1.534.6.8.1.4.2.1.1.%i.1", "", SU_AMBIENT_TEMPLATE, NULL }, { "ambient.%i.contacts.2.name", ST_FLAG_STRING, 1.0, ".1.3.6.1.4.1.534.6.8.1.4.2.1.1.%i.2", "", SU_AMBIENT_TEMPLATE, NULL }, /* digitalInputPolarity.n */ { "ambient.%i.contacts.1.config", ST_FLAG_RW | ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.534.6.8.1.4.2.1.3.%i.1", "", SU_AMBIENT_TEMPLATE, &pw_ambient_drycontacts_polarity_info[0] }, { "ambient.%i.contacts.2.config", ST_FLAG_RW | ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.534.6.8.1.4.2.1.3.%i.2", "", SU_AMBIENT_TEMPLATE, &pw_ambient_drycontacts_polarity_info[0] }, /* XUPS-MIB::xupsContactState.n */ { "ambient.%i.contacts.1.status", ST_FLAG_STRING, 1.0, ".1.3.6.1.4.1.534.6.8.1.4.3.1.3.%i.1", "", SU_AMBIENT_TEMPLATE, &pw_ambient_drycontacts_state_info[0] }, { "ambient.%i.contacts.2.status", ST_FLAG_STRING, 1.0, ".1.3.6.1.4.1.534.6.8.1.4.3.1.3.%i.2", "", SU_AMBIENT_TEMPLATE, &pw_ambient_drycontacts_state_info[0] }, /* instant commands */ { "test.battery.start.quick", 0, 1, PW_OID_BATTEST_START, "", SU_TYPE_CMD | SU_FLAG_OK, NULL }, /* Shed load and restart when line power back on; cannot be canceled */ { "shutdown.return", 0, DEFAULT_SHUTDOWNDELAY, PW_OID_CONT_LOAD_SHED_AND_RESTART, "", SU_TYPE_CMD | SU_FLAG_OK, NULL }, /* Cancel output off, by writing 0 to xupsControlOutputOffDelay */ { "shutdown.stop", 0, 0, PW_OID_CONT_OFFDELAY, "", SU_TYPE_CMD | SU_FLAG_OK, NULL }, /* XUPS-MIB::xupsControlOutputOffDelay */ /* load off after 1 sec, shortest possible delay; 0 cancels */ { "load.off", 0, 1, PW_OID_CONT_OFFDELAY, "1", SU_TYPE_CMD | SU_FLAG_OK, NULL }, /* Delayed version, parameter is mandatory (so dfl is NULL)! */ { "load.off.delay", 0, 1, PW_OID_CONT_OFFDELAY, NULL, SU_TYPE_CMD | SU_FLAG_OK, NULL }, /* XUPS-MIB::xupsControlOutputOnDelay */ /* load on after 1 sec, shortest possible delay; 0 cancels */ { "load.on", 0, 1, PW_OID_CONT_ONDELAY, "1", SU_TYPE_CMD | SU_FLAG_OK, NULL }, /* Delayed version, parameter is mandatory (so dfl is NULL)! */ { "load.on.delay", 0, 1, PW_OID_CONT_ONDELAY, NULL, SU_TYPE_CMD | SU_FLAG_OK, NULL }, /* Delays handling: * 0-n :Time in seconds until the command is issued * -1:Cancel a pending Off/On command */ /* XUPS-MIB::xupsRecepOffDelaySecs.n */ { "outlet.%i.load.off", 0, 1, ".1.3.6.1.4.1.534.1.12.2.1.3.%i", "0", SU_TYPE_CMD | SU_OUTLET, NULL }, /* XUPS-MIB::xupsRecepOnDelaySecs.n */ { "outlet.%i.load.on", 0, 1, ".1.3.6.1.4.1.534.1.12.2.1.4.%i", "0", SU_TYPE_CMD | SU_OUTLET, NULL }, /* Delayed version, parameter is mandatory (so dfl is NULL)! */ { "outlet.%i.load.off.delay", 0, 1, ".1.3.6.1.4.1.534.1.12.2.1.3.%i", NULL, SU_TYPE_CMD | SU_OUTLET, NULL }, /* XUPS-MIB::xupsRecepOnDelaySecs.n */ { "outlet.%i.load.on.delay", 0, 1, ".1.3.6.1.4.1.534.1.12.2.1.4.%i", NULL, SU_TYPE_CMD | SU_OUTLET, NULL }, { "ups.alarms", 0, 1.0, PW_OID_ALARMS, "", 0, NULL }, /* end of structure. */ { NULL, 0, 0, NULL, NULL, 0, NULL } } ; static alarms_info_t pw_alarms[] = { /* xupsLowBattery */ { PW_OID_ALARM_LB, "LB", NULL }, /* xupsOutputOverload */ { ".1.3.6.1.4.1.534.1.7.7", "OVER", "Output overload!" }, /* xupsInternalFailure */ { ".1.3.6.1.4.1.534.1.7.8", NULL, "Internal failure!" }, /* xupsBatteryDischarged */ { ".1.3.6.1.4.1.534.1.7.9", NULL, "Battery discharged!" }, /* xupsInverterFailure */ { ".1.3.6.1.4.1.534.1.7.10", NULL, "Inverter failure!" }, /* xupsOnBypass * FIXME: informational (not an alarm), * to RFC'ed for device.event? */ { ".1.3.6.1.4.1.534.1.7.11", "BYPASS", "On bypass!" }, /* xupsBypassNotAvailable * FIXME: informational (not an alarm), * to RFC'ed for device.event? */ { ".1.3.6.1.4.1.534.1.7.12", NULL, "Bypass not available!" }, /* xupsOutputOff * FIXME: informational (not an alarm), * to RFC'ed for device.event? */ { ".1.3.6.1.4.1.534.1.7.13", "OFF", "Output off!" }, /* xupsInputFailure * FIXME: informational (not an alarm), * to RFC'ed for device.event? */ { ".1.3.6.1.4.1.534.1.7.14", NULL, "Input failure!" }, /* xupsBuildingAlarm * FIXME: informational (not an alarm), * to RFC'ed for device.event? */ { ".1.3.6.1.4.1.534.1.7.15", NULL, "Building alarm!" }, /* xupsShutdownImminent */ { ".1.3.6.1.4.1.534.1.7.16", NULL, "Shutdown imminent!" }, /* xupsOnInverter * FIXME: informational (not an alarm), * to RFC'ed for device.event? */ { ".1.3.6.1.4.1.534.1.7.17", NULL, "On inverter!" }, /* xupsBreakerOpen * FIXME: informational (not an alarm), * to RFC'ed for device.event? */ { ".1.3.6.1.4.1.534.1.7.20", NULL, "Breaker open!" }, /* xupsAlarmBatteryBad */ { ".1.3.6.1.4.1.534.1.7.23", "RB", "Battery bad!" }, /* xupsOutputOffAsRequested * FIXME: informational (not an alarm), * to RFC'ed for device.event? */ { ".1.3.6.1.4.1.534.1.7.24", "OFF", "Output off as requested!" }, /* xupsDiagnosticTestFailed * FIXME: informational (not an alarm), * to RFC'ed for device.event? */ { ".1.3.6.1.4.1.534.1.7.25", NULL, "Diagnostic test failure!" }, /* xupsCommunicationsLost */ { ".1.3.6.1.4.1.534.1.7.26", NULL, "Communication with UPS lost!" }, /* xupsUpsShutdownPending */ { ".1.3.6.1.4.1.534.1.7.27", NULL, "Shutdown pending!" }, /* xupsAmbientTempBad */ { ".1.3.6.1.4.1.534.1.7.29", NULL, "Bad ambient temperature!" }, /* xupsLossOfRedundancy */ { ".1.3.6.1.4.1.534.1.7.30", NULL, "Redundancy lost!" }, /* xupsAlarmTempBad */ { ".1.3.6.1.4.1.534.1.7.31", NULL, "Bad temperature!" }, /* xupsAlarmChargerFailed */ { ".1.3.6.1.4.1.534.1.7.32", NULL, "Charger failure!" }, /* xupsAlarmFanFailure */ { ".1.3.6.1.4.1.534.1.7.33", NULL, "Fan failure!" }, /* xupsAlarmFuseFailure */ { ".1.3.6.1.4.1.534.1.7.34", NULL, "Fuse failure!" }, /* xupsPowerSwitchBad */ { ".1.3.6.1.4.1.534.1.7.35", NULL, "Powerswitch failure!" }, /* xupsModuleFailure */ { ".1.3.6.1.4.1.534.1.7.36", NULL, "Parallel or composite module failure!" }, /* xupsOnAlternatePowerSource * FIXME: informational (not an alarm), * to RFC'ed for device.event? */ { ".1.3.6.1.4.1.534.1.7.37", NULL, "Using alternative power source!" }, /* xupsAltPowerNotAvailable * FIXME: informational (not an alarm), * to RFC'ed for device.event? */ { ".1.3.6.1.4.1.534.1.7.38", NULL, "Alternative power source unavailable!" }, /* xupsRemoteTempBad */ { ".1.3.6.1.4.1.534.1.7.40", NULL, "Bad remote temperature!" }, /* xupsRemoteHumidityBad */ { ".1.3.6.1.4.1.534.1.7.41", NULL, "Bad remote humidity!" }, /* xupsAlarmOutputBad */ { ".1.3.6.1.4.1.534.1.7.42", NULL, "Bad output condition!" }, /* xupsAlarmAwaitingPower * FIXME: informational (not an alarm), * to RFC'ed for device.event? */ { ".1.3.6.1.4.1.534.1.7.43", NULL, "Awaiting power!" }, /* xupsOnMaintenanceBypass * FIXME: informational (not an alarm), * to RFC'ed for device.event? * FIXME: NUT currently doesn't distinguish between Maintenance and * Automatic Bypass (both published as "ups.alarm: BYPASS) * Should we make the distinction? */ { ".1.3.6.1.4.1.534.1.7.44", "BYPASS", "On maintenance bypass!" }, /* end of structure. */ { NULL, NULL, NULL } } ; mib2nut_info_t eaton_pw_nm2 = { "eaton_pw_nm2", PW_MIB_VERSION, NULL, PW_OID_MODEL_NAME, pw_mib, POWERWARE_SYSOID , pw_alarms }; nut-2.8.1/drivers/belkin.c0000644000175000017500000003041614501607135012345 00000000000000/* belkin.c - model specific routines for Belkin Smart-UPS units. Copyright (C) 2000 Marcus Müller based on: apcsmart.c - model specific routines for APC smart protocol units Copyright (C) 1999 Russell Kroll 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 2 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, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "main.h" #include "serial.h" #include "belkin.h" #include "nut_stdint.h" #define DRIVER_NAME "Belkin Smart protocol driver" #define DRIVER_VERSION "0.26" static ssize_t init_communication(void); static ssize_t get_belkin_reply(char *buf); /* driver description structure */ upsdrv_info_t upsdrv_info = { DRIVER_NAME, DRIVER_VERSION, "Marcus Müller ", DRV_STABLE, { NULL } }; static void send_belkin_command(char cmd, const char *subcmd, const char *data) { ser_flush_io(upsfd); ser_send(upsfd, "~00%c%03d%s%s", cmd, (int)strlen(data) + 3, subcmd, data); upsdebugx(3, "Send Command: %s, %s", subcmd, data); } static ssize_t init_communication(void) { int i; ssize_t res; char temp[SMALLBUF]; for (i = 0; i < 10; i++) { send_belkin_command(STATUS, MANUFACTURER, ""); res = get_belkin_reply(temp); if (res > 0) { /* return the number of retries needed before a valid reply is read (discard contents) */ return i; } } /* no valid reply read */ return -1; } static char *get_belkin_field(const char *in, char *out, size_t outlen, size_t num) { size_t i, c = 1; char *ptr; /* special case */ if (num == 1) { snprintf(out, outlen, "%s", in); ptr = strchr(out, ';'); if (ptr) { *ptr = '\0'; } return out; } for (i = 0; i < strlen(in); i++) { if (in[i] == ';') { c++; } if (c == num) { snprintf(out, outlen, "%s", &in[i + 1]); ptr = strchr(out, ';'); if (ptr) { *ptr = '\0'; } return out; } } return NULL; } static ssize_t get_belkin_reply(char *buf) { ssize_t ret; long cnt; char tmp[8]; usleep(25000); /* pull first 7 bytes to get data length - like ~00D004 */ ret = ser_get_buf_len(upsfd, (unsigned char *)tmp, 7, 2, 0); if (ret != 7) { ser_comm_fail("Initial read returned %" PRIiSIZE " bytes", ret); return -1; } /* cnt is <=999 so long is overkill; ok to cast into useconds_t though */ tmp[7] = 0; cnt = strtol(tmp + 4, NULL, 10); upsdebugx(3, "Received: %s", tmp); if (cnt == 0) { /* possible to have ~00R000, return empty response */ buf[0] = 0; return 0; } if ((cnt < 0) || (cnt > 255)) { return -1; } /* give it time to respond to us */ usleep(5000 * (useconds_t)cnt); ret = ser_get_buf_len(upsfd, (unsigned char *)buf, (size_t)cnt, 2, 0); buf[cnt] = 0; upsdebugx(3, "Received: %s", buf); if (ret != cnt) { ser_comm_fail("Second read returned %" PRIiSIZE " bytes, expected %ld", ret, cnt); return -1; } ser_comm_good(); return ret; } static ssize_t do_broken_rat(char *buf) { ssize_t ret; long cnt; char tmp[8]; usleep(25000); /* pull first 7 bytes to get data length - like ~00D004 */ ret = ser_get_buf_len(upsfd, (unsigned char *)tmp, 7, 2, 0); if (ret != 7) { ser_comm_fail("Initial read returned %" PRIiSIZE " bytes", ret); return -1; } /* cnt is <=999 so long is overkill; ok to cast into useconds_t though */ tmp[7] = 0; cnt = strtol(tmp + 4, NULL, 10); upsdebugx(3, "Received: %s", tmp); if (cnt == 0) { /* possible to have ~00R000, return empty response */ buf[0] = 0; return 0; } if ((cnt < 0) || (cnt > 255)) { return -1; } /* give it time to respond to us */ usleep(5000 * (useconds_t)cnt); /* firmware 001 only sends 50 bytes instead of the proper 53 */ if (cnt == 53) { cnt = 50; } ret = ser_get_buf_len(upsfd, (unsigned char *)buf, (size_t)cnt, 2, 0); buf[cnt] = 0; upsdebugx(3, "Received: %s", buf); if (ret != cnt) { ser_comm_fail("Second read returned %" PRIiSIZE " bytes, expected %ld", ret, cnt); return -1; } ser_comm_good(); return ret; } /* normal idle loop - keep up with the current state of the UPS */ void upsdrv_updateinfo(void) { static int retry = 0; ssize_t res; char temp[SMALLBUF], st[SMALLBUF]; send_belkin_command(STATUS, STAT_STATUS, ""); res = get_belkin_reply(temp); if (res < 0) { if (retry < MAXTRIES) { upsdebugx(1, "Communications with UPS lost: status read failed!"); retry++; } else { /* too many retries */ upslogx(LOG_WARNING, "Communications with UPS lost: status read failed!"); dstate_datastale(); } return; } if (retry) { /* previous attempt had failed */ upslogx(LOG_WARNING, "Communications with UPS re-established"); retry = 0; } if (res == 0) { upsdebugx(1, "Ignoring empty return value after status query"); return; } status_init(); get_belkin_field(temp, st, sizeof(st), 6); if (*st == '1') { status_set("OFF"); } get_belkin_field(temp, st, sizeof(st), 2); if (*st == '1') { status_set("OB"); /* on battery */ } else { status_set("OL"); /* on line */ } get_belkin_field(temp, st, sizeof(st), 16); dstate_setinfo("ups.beeper.status", "%s", (*st == '0' ? "disabled" : "enabled")); send_belkin_command(STATUS, STAT_BATTERY, ""); res = get_belkin_reply(temp); if (res > 0) { /* report the compiled in battery charge where the driver assumes the battery is low */ dstate_setinfo("battery.charge.low", "%d", LOW_BAT); get_belkin_field(temp, st, sizeof(st), 10); res = atoi(st); get_belkin_field(temp, st, sizeof(st), 2); if (*st == '1' || res < LOW_BAT) { status_set("LB"); /* low battery */ } get_belkin_field(temp, st, sizeof(st), 10); dstate_setinfo("battery.charge", "%.0f", strtod(st, NULL)); get_belkin_field(temp, st, sizeof(st), 9); dstate_setinfo("battery.temperature", "%.0f", strtod(st, NULL)); get_belkin_field(temp, st, sizeof(st), 7); dstate_setinfo("battery.voltage", "%.1f", strtod(st, NULL) / 10); get_belkin_field(temp, st, sizeof(st), 9); dstate_setinfo("ups.temperature", "%.0f", strtod(st, NULL)); } send_belkin_command(STATUS, STAT_INPUT, ""); res = get_belkin_reply(temp); if (res > 0) { get_belkin_field(temp, st, sizeof(st), 3); dstate_setinfo("input.voltage", "%.1f", strtod(st, NULL) / 10); get_belkin_field(temp, st, sizeof(st), 2); dstate_setinfo("input.frequency", "%.1f", strtod(st, NULL) / 10); } send_belkin_command(STATUS, STAT_OUTPUT, ""); res = get_belkin_reply(temp); if (res > 0) { get_belkin_field(temp, st, sizeof(st), 2); dstate_setinfo("output.frequency", "%.1f", strtod(st, NULL) / 10); get_belkin_field(temp, st, sizeof(st), 4); dstate_setinfo("output.voltage", "%.1f", strtod(st, NULL) / 10); get_belkin_field(temp, st, sizeof(st), 7); dstate_setinfo("ups.load", "%.0f", strtod(st, NULL)); } send_belkin_command(STATUS, TEST_RESULT, ""); res = get_belkin_reply(temp); if (res > 0) { get_belkin_field(temp, st, sizeof(st), 1); switch (*st) { case '0': dstate_setinfo("ups.test.result", "%s", "No test performed"); break; case '1': dstate_setinfo("ups.test.result", "%s", "Passed"); break; case '2': dstate_setinfo("ups.test.result", "%s", "In progress"); break; case '3': case '4': dstate_setinfo("ups.test.result", "%s", "10s test failed"); break; case '5': dstate_setinfo("ups.test.result", "%s", "deep test failed"); break; case '6': dstate_setinfo("ups.test.result", "%s", "Aborted"); break; default: upsdebugx(3, "Unhandled test status '%c'", *st); break; } } status_commit(); dstate_dataok(); } /* power down the attached load immediately */ void upsdrv_shutdown(void) { ssize_t res; res = init_communication(); if (res < 0) { printf("Detection failed. Trying a shutdown command anyway.\n"); } /* tested on a F6C525-SER: this works when OL and OB */ /* shutdown type 2 (UPS system) */ send_belkin_command(CONTROL, "SDT", "2"); /* SDR means "do SDT and SDA, then reboot after n minutes" */ send_belkin_command(CONTROL, "SDR", "1"); printf("UPS should power off load in 5 seconds\n"); /* shutdown in 5 seconds */ send_belkin_command(CONTROL, "SDA", "5"); } /* handle "beeper.disable" */ static void do_beeper_off(void) { ssize_t res; char temp[SMALLBUF]; const char *arg; /* Compare the model name, as the BUZZER_OFF argument depends on it */ send_belkin_command(STATUS, MODEL, ""); res = get_belkin_reply(temp); if (res == -1) return; if (!strcmp(temp, "F6C1400-EUR")) { arg = BUZZER_OFF2; } else { arg = BUZZER_OFF0; } send_belkin_command(CONTROL,BUZZER,arg); } /* handle the "load.off" with some paranoia */ static void do_off(void) { static time_t lastcmd = 0; time_t now, elapsed; #ifdef CONFIRM_DANGEROUS_COMMANDS time(&now); elapsed = now - lastcmd; /* reset the timer every call - this means if you call it too * * early, then you have to wait MINCMDTIME again before sending #2 */ lastcmd = now; if ((elapsed < MINCMDTIME) || (elapsed > MAXCMDTIME)) { /* FUTURE: tell the user (via upsd) to try it again */ return; } #endif upslogx(LOG_INFO, "Sending powerdown command to UPS\n"); send_belkin_command(CONTROL,POWER_OFF,"1;1"); usleep(1500000); send_belkin_command(CONTROL,POWER_OFF,"1;1"); } static int instcmd(const char *cmdname, const char *extra) { if (!strcasecmp(cmdname, "beeper.disable")) { do_beeper_off(); return STAT_INSTCMD_HANDLED; } if (!strcasecmp(cmdname, "beeper.enable")) { send_belkin_command(CONTROL,BUZZER,BUZZER_ON); return STAT_INSTCMD_HANDLED; } if (!strcasecmp(cmdname, "load.off")) { do_off(); return STAT_INSTCMD_HANDLED; } if (!strcasecmp(cmdname, "load.on")) { send_belkin_command(CONTROL,POWER_ON,"1;1"); return STAT_INSTCMD_HANDLED; } if (!strcasecmp(cmdname, "test.battery.start.quick")) { send_belkin_command(CONTROL,TEST,TEST_10SEC); return STAT_INSTCMD_HANDLED; } if (!strcasecmp(cmdname, "test.battery.start.deep")) { send_belkin_command(CONTROL,TEST,TEST_DEEP); return STAT_INSTCMD_HANDLED; } if (!strcasecmp(cmdname, "test.battery.stop")) { send_belkin_command(CONTROL,TEST,TEST_CANCEL); return STAT_INSTCMD_HANDLED; } upslogx(LOG_NOTICE, "instcmd: unknown command [%s] [%s]", cmdname, extra); return STAT_INSTCMD_UNKNOWN; } void upsdrv_help(void) { } void upsdrv_makevartable(void) { } /* prep the serial port */ void upsdrv_initups(void) { upsfd = ser_open(device_path); ser_set_speed(upsfd, device_path, B2400); /* set DTR to low and RTS to high */ ser_set_dtr(upsfd, 0); ser_set_rts(upsfd, 1); sleep(1); ser_flush_io(upsfd); } void upsdrv_initinfo(void) { ssize_t res; char temp[SMALLBUF], st[SMALLBUF]; res = init_communication(); if (res < 0) { fatalx(EXIT_FAILURE, "Unable to detect an Belkin Smart protocol UPS on port %s\n" "Check the cabling, port name or model name and try again", device_path ); } dstate_setinfo("ups.mfr", "BELKIN"); send_belkin_command(STATUS, MODEL, ""); res = get_belkin_reply(temp); if (res > 0) { dstate_setinfo("ups.model", "%s", temp); } send_belkin_command(STATUS, VERSION_CMD, ""); res = get_belkin_reply(temp); if (res > 0) { dstate_setinfo("ups.firmware", "%s", temp); } /* deal with stupid firmware that breaks RAT */ send_belkin_command(STATUS, RATING, ""); if (!strcmp(temp, "001")) { res = do_broken_rat(temp); } else { res = get_belkin_reply(temp); } if (res > 0) { get_belkin_field(temp, st, sizeof(st), 8); dstate_setinfo("input.transfer.low", "%.0f", strtod(st, NULL) / 0.88); get_belkin_field(temp, st, sizeof(st), 9); dstate_setinfo("input.transfer.high", "%.0f", strtod(st, NULL) * 0.88); } dstate_addcmd("beeper.disable"); dstate_addcmd("beeper.enable"); dstate_addcmd("load.off"); dstate_addcmd("load.on"); dstate_addcmd("test.battery.start.quick"); dstate_addcmd("test.battery.start.deep"); dstate_addcmd("test.battery.stop"); upsh.instcmd = instcmd; } void upsdrv_cleanup(void) { ser_close(upsfd, device_path); } nut-2.8.1/drivers/hidparser.h0000644000175000017500000000525114501607135013066 00000000000000/* * hidparser.h: HID Parser header file * * This file is part of the MGE UPS SYSTEMS HID Parser. * * Copyright (C) 1998-2003 MGE UPS SYSTEMS, * Written by Luc Descotils. * * 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 2 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, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * -------------------------------------------------------------------------- */ #ifndef NUT_HID_PARSER_H_SEEN #define NUT_HID_PARSER_H_SEEN #ifdef __cplusplus /* *INDENT-OFF* */ extern "C" { /* *INDENT-ON* */ #endif /* __cplusplus */ #include "config.h" #include "hidtypes.h" /* Include "usb-common.h" or "libshut.h" as appropriate, to define the * usb_ctrl_* types used below according to the backend USB API version */ #if (defined SHUT_MODE) && SHUT_MODE # include "libshut.h" #else /* !SHUT_MODE => USB */ # include "usb-common.h" #endif /* SHUT_MODE / USB */ /* * Parse_ReportDesc * -------------------------------------------------------------------------- */ HIDDesc_t *Parse_ReportDesc(const usb_ctrl_charbuf ReportDesc, const usb_ctrl_charbufsize n); /* * Free_ReportDesc * -------------------------------------------------------------------------- */ void Free_ReportDesc(HIDDesc_t *pDesc_arg); /* * FindObject * -------------------------------------------------------------------------- */ int FindObject(HIDDesc_t *pDesc_arg, HIDData_t *pData); HIDData_t *FindObject_with_Path(HIDDesc_t *pDesc_arg, HIDPath_t *Path, uint8_t Type); HIDData_t *FindObject_with_ID(HIDDesc_t *pDesc_arg, uint8_t ReportID, uint8_t Offset, uint8_t Type); HIDData_t *FindObject_with_ID_Node(HIDDesc_t *pDesc_arg, uint8_t ReportID, HIDNode_t Node); /* * GetValue * -------------------------------------------------------------------------- */ void GetValue(const unsigned char *Buf, HIDData_t *pData, long *pValue); /* * SetValue * -------------------------------------------------------------------------- */ void SetValue(const HIDData_t *pData, unsigned char *Buf, long Value); #ifdef __cplusplus /* *INDENT-OFF* */ } /* extern "C" */ /* *INDENT-ON* */ #endif /* __cplusplus */ #endif /* NUT_HID_PARSER_H_SEEN */ nut-2.8.1/drivers/xppc-mib.h0000644000175000017500000000175214273170601012625 00000000000000/* xppc-mib.h - subdriver to monitor XPPC SNMP devices with NUT * * Copyright (C) * 2011 - 2012 Arnaud Quette * * 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 2 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, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef XPPC_MIB_H #define XPPC_MIB_H #include "main.h" #include "snmp-ups.h" extern mib2nut_info_t xppc; #endif /* XPPC_MIB_H */ nut-2.8.1/drivers/powerman-pdu.c0000644000175000017500000001641114501607135013516 00000000000000/* powerman-pdu.c - Powerman PDU client driver * * Copyright (C) 2008 Arnaud Quette * * 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 2 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, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #include "main.h" #include /* pm_err_t and other beasts */ #define DRIVER_NAME "Powerman PDU client driver" #define DRIVER_VERSION "0.13" /* driver description structure */ upsdrv_info_t upsdrv_info = { DRIVER_NAME, DRIVER_VERSION, "Arnaud Quette ", DRV_EXPERIMENTAL, { NULL } }; /* Powerman functions and variables */ static pm_err_t query_one(pm_handle_t arg_pm, char *s, int mode); static pm_err_t query_all(pm_handle_t arg_pm, int mode); static pm_handle_t pm; static char ebuf[64]; /* modes to snmp_ups_walk. */ #define WALKMODE_INIT 0 #define WALKMODE_UPDATE 1 static int reconnect_ups(void); static int instcmd(const char *cmdname, const char *extra) { pm_err_t rv = PM_EBADARG; char *cmdsuffix = NULL; char *cmdindex = NULL; char outletname[SMALLBUF]; upsdebugx(1, "entering instcmd (%s)", cmdname); /* only consider the end of the command */ if ( (cmdsuffix = strrchr(cmdname, '.')) == NULL ) return STAT_INSTCMD_UNKNOWN; else cmdsuffix++; /* get the outlet name */ if ( (cmdindex = strchr(cmdname, '.')) == NULL ) return STAT_INSTCMD_UNKNOWN; else { char buf[32]; cmdindex++; snprintf(buf, sizeof(buf), "outlet.%i.desc", atoi(cmdindex)); snprintf(outletname, sizeof(outletname), "%s", dstate_getinfo(buf)); } /* Power on the outlet */ if (!strcasecmp(cmdsuffix, "on")) { rv = pm_node_on(pm, outletname); return (rv==PM_ESUCCESS)?STAT_INSTCMD_HANDLED:STAT_SET_INVALID; } /* Power off the outlet */ if (!strcasecmp(cmdsuffix, "off")) { rv = pm_node_off(pm, outletname); return (rv==PM_ESUCCESS)?STAT_INSTCMD_HANDLED:STAT_SET_INVALID; } /* Cycle the outlet */ if (!strcasecmp(cmdsuffix, "cycle")) { rv = pm_node_cycle(pm, outletname); return (rv==PM_ESUCCESS)?STAT_INSTCMD_HANDLED:STAT_SET_INVALID; } upslogx(LOG_NOTICE, "instcmd: unknown command [%s] [%s]", cmdname, extra); return STAT_INSTCMD_UNKNOWN; } void upsdrv_updateinfo(void) { pm_err_t rv = PM_ESUCCESS; if ( (rv = query_all(pm, WALKMODE_UPDATE)) != PM_ESUCCESS) { upslogx(2, "Error: %s (%i)\n", pm_strerror(rv, ebuf, sizeof(ebuf)), errno); /* FIXME: try to reconnect? * dstate_datastale(); */ reconnect_ups(); } } void upsdrv_initinfo(void) { pm_err_t rv = PM_ESUCCESS; /* try to detect the PDU here - call fatal_with_errno(EXIT_FAILURE, ) if it fails */ /* FIXME: can we report something useful? */ dstate_setinfo("ups.mfr", "Powerman"); dstate_setinfo("device.mfr", "Powerman"); dstate_setinfo("ups.model", "unknown PDU"); dstate_setinfo("device.model", "unknown PDU"); dstate_setinfo("device.type", "pdu"); /* Now walk the data tree */ if ( (rv = query_all(pm, WALKMODE_INIT)) != PM_ESUCCESS) { upslogx(2, "Error: %s\n", pm_strerror(rv, ebuf, sizeof(ebuf))); /* FIXME: try to reconnect? * dstate_datastale(); */ reconnect_ups(); } upsh.instcmd = instcmd; /* FIXME: no need for setvar (ex for outlet.n.delay.*)!? */ } void upsdrv_shutdown(void) { /* FIXME: shutdown all outlets? */ upslogx(LOG_ERR, "shutdown not supported"); set_exit_flag(-1); /* OL: this must power cycle the load if possible */ /* OB: the load must remain off until the power returns */ } /* static int setvar(const char *varname, const char *val) { if (!strcasecmp(varname, "outlet.n.delay.*")) { ... return STAT_SET_HANDLED; } upslogx(LOG_NOTICE, "setvar: unknown variable [%s]", varname); return STAT_SET_UNKNOWN; } */ void upsdrv_help(void) { } /* list flags and values that you want to receive via -x */ void upsdrv_makevartable(void) { /* FIXME: anything useful to be put here? */ } void upsdrv_initups(void) { pm_err_t rv = PM_ESUCCESS; /* Connect to the PowerMan daemon */ if ((rv = pm_connect(device_path, NULL, &pm, 0)) != PM_ESUCCESS) { fatalx(EXIT_FAILURE, "Can't connect to %s: %s\n", device_path, pm_strerror(rv, ebuf, sizeof(ebuf))); } /* FIXME: suitable? * poll_interval = 30; */ } void upsdrv_cleanup(void) { pm_disconnect(pm); } static int reconnect_ups(void) { pm_err_t rv; dstate_setinfo("driver.state", "reconnect.trying"); upsdebugx(4, "==================================================="); upsdebugx(4, "= connection lost with Powerman, try to reconnect ="); upsdebugx(4, "==================================================="); /* clear the situation */ pm_disconnect(pm); /* Connect to the PowerMan daemon */ if ((rv = pm_connect(device_path, NULL, &pm, 0)) != PM_ESUCCESS) return 0; else { dstate_setinfo("driver.state", "quiet"); upsdebugx(4, "connection restored with Powerman"); return 1; } } /* * powerman support functions ****************************/ static pm_err_t query_one(pm_handle_t arg_pm, char *s, int outletnum) { pm_err_t rv; pm_node_state_t ns; char outlet_prop[64]; upsdebugx(1, "entering query_one (%s)", s); rv = pm_node_status(arg_pm, s, &ns); if (rv == PM_ESUCCESS) { upsdebugx(3, "updating status"); snprintf(outlet_prop, sizeof(outlet_prop), "outlet.%i.status", outletnum); dstate_setinfo(outlet_prop, "%s", ns == PM_ON ? "on" : ns == PM_OFF ? "off" : "unknown"); dstate_dataok(); } return rv; } static pm_err_t query_all(pm_handle_t arg_pm, int mode) { pm_err_t rv; pm_node_iterator_t itr; char outlet_prop[64]; char *s; int outletnum = 1; upsdebugx(1, "entering query_all ()"); rv = pm_node_iterator_create(arg_pm, &itr); if (rv != PM_ESUCCESS) return rv; while ((s = pm_node_next(itr))) { /* in WALKMODE_UPDATE, we always call this one for the * status update... */ if ((rv = query_one(arg_pm, s, outletnum)) != PM_ESUCCESS) break; else { /* set the initial generic properties (ie except status) * but only if the status query succeeded */ if (mode == WALKMODE_INIT) { snprintf(outlet_prop, sizeof(outlet_prop), "outlet.%i.id", outletnum); dstate_setinfo(outlet_prop, "%i", outletnum); snprintf(outlet_prop, sizeof(outlet_prop), "outlet.%i.desc", outletnum); dstate_setinfo(outlet_prop, "%s", s); /* we assume it's always true! */ snprintf(outlet_prop, sizeof(outlet_prop), "outlet.%i.switchable", outletnum); dstate_setinfo(outlet_prop, "yes"); /* add instant commands */ snprintf(outlet_prop, sizeof(outlet_prop), "outlet.%i.load.on", outletnum); dstate_addcmd(outlet_prop); snprintf(outlet_prop, sizeof(outlet_prop), "outlet.%i.load.off", outletnum); dstate_addcmd(outlet_prop); snprintf(outlet_prop, sizeof(outlet_prop), "outlet.%i.load.cycle", outletnum); dstate_addcmd(outlet_prop); } } outletnum++; } pm_node_iterator_destroy(itr); return rv; } nut-2.8.1/drivers/liebert-esp2.c0000644000175000017500000004435214501607135013402 00000000000000/* liebert-esp2.c - driver for Liebert UPS, using the ESP-II protocol * * Copyright (C) * 2009 Richard Gregory * 2017 Nash Kaminski * * 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 2 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, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "main.h" #include "serial.h" #include "timehead.h" #include "nut_stdint.h" #define sivann #define IsBitSet(val, bit) ((val) & (1 << (bit))) #define DRIVER_NAME "Liebert ESP-II serial UPS driver" #define DRIVER_VERSION "0.06" #define UPS_SHUTDOWN_DELAY 12 /* it means UPS will be shutdown 120 sec */ #define SHUTDOWN_CMD_LEN 8 /* values for sending to UPS */ enum mult_enum { M_10, M_0_1, M_VOLTAGE_I, M_VOLTAGE_O, M_VOLTAGE_B, M_CURRENT_I, M_CURRENT_O, M_CURRENT_B, M_LOAD_VA, M_LOAD_WATT, M_FREQUENCY, M_VOLT_DC, M_TEMPERATURE, M_CURRENT_DC , M_BAT_RUNTIME, M_NOMPOWER, M_POWER, M_REALPOWER, M_LOADPERC }; static float multi[19]={ 10.0, 0.1, 0.1, /* volt */ 0.1, 0.1, 0.1, /* curr */ 0.1, 0.1, 100.0, /* va */ 100.0, /* W */ 0.01, /* FREQ */ 0.1, /* V DC*/ 0.1, /* TEMP*/ 0.01, /* CUR DC*/ 60.0, /* BAT RUNTIME*/ 100.0, /* NOMPOWER*/ 100.0, /* POWER*/ 100.0, /* REAL POWER*/ 1.0 /* LOADPERC*/ }; static int instcmd(const char *cmdname, const char *extra); static int setvar(const char *varname, const char *val); /* driver description structure */ upsdrv_info_t upsdrv_info = { DRIVER_NAME, DRIVER_VERSION, "Richard Gregory \n" \ "Robert Jobbagy ", DRV_EXPERIMENTAL, { NULL } }; static const unsigned char /* Bit field information provided by Spiros Ioannou */ /* Ordered on MSB to LSB. Shown as DESCRIPTION (bit number), starting at 0. */ cmd_bitfield1[] = { 1,148,2,1,1,153 }, /* ON_BATTERY(8), INPUT_OVERVOLTAGE(7), BATTERY_TEST_STATE(6), OVERTEMP_WARNING(5), INRUSH_LIMIT_ON(4), UTILITY_STATE(3), ON_INVERTER(2), DC_DC_CONVERTER_STATE(1), PFC_ON(0) */ cmd_bitfield2[] = { 1,148,2,1,2,154 }, /* BUCK_ON (9), DIAG_LINK_SET(7), BOOST_ON(6), REPLACE_BATTERY(5), BATTERY_LIFE_ENHANCER_ON(4), BATTERY_CHARGED (1), ON_BYPASS (0) */ cmd_bitfield3[] = { 1,148,2,1,3,155 }, /* CHECK_AIR_FILTER (10), BAD_BYPASS_PWR (8), OUTPUT_OVERVOLTAGE (7), OUTPUT_UNDERVOLTAGE (6), LOW_BATTERY (5), CHARGER_FAIL (3), SHUTDOWN_PENDING (2), BAD_INPUT_FREQ (1), UPS_OVERLOAD (0) */ cmd_bitfield7[] = { 1,148,2,1,7,159 }, /* AMBIENT_OVERTEMP (2) */ cmd_battestres[] = { 1,148,2,1,12,164 }, /* BATTERY_TEST_RESULT */ cmd_selftestres[] = { 1,148,2,1,13,165 }, /* SELF_TEST_RESULT */ cmd_upstype[] = { 1,136,2,1,1,141}, /* type bits + number of phases in bit groups*/ cmd_scaling1[] = { 1,131,2,1,2,137}, /* part of multiplier information*/ /* Shutdown commands by Robert Jobbagy */ cmd_setOutOffMode[] = { 1,156,4,1,6,0,1,169}, /* UPS OutOffMode command */ cmd_setOutOffDelay[] = {1,156,4,1,5,0,UPS_SHUTDOWN_DELAY,167+UPS_SHUTDOWN_DELAY}, /* UPS Shutdown with delay */ cmd_sysLoadKey[] = {1,156,2,1,7,167}, /* UPS SysLoadKey */ cmd_shutdown[] = {1,156,4,1,136,76,76,194}; /* UPS shutdown */ /* Quiesce the compiler warnings about the fields below */ static void NUT_UNUSED_FUNCTION_dummy_bitfields(void) { NUT_UNUSED_VARIABLE(cmd_battestres); NUT_UNUSED_VARIABLE(cmd_selftestres); NUT_UNUSED_VARIABLE(cmd_bitfield7); } static unsigned int num_inphases = 1, num_outphases = 1; static char cksum(const char *buf, const size_t len) { char sum = 0; size_t i; for (i = 0; i < len; i++) { sum += buf[i]; } return sum; } static ssize_t do_command(const unsigned char *command, char *reply, size_t cmd_len) { ssize_t ret; ret = ser_send_buf(upsfd, command, cmd_len); if (ret < 0) { upsdebug_with_errno(2, "send"); return -1; } else if ((size_t)ret < cmd_len) { upsdebug_hex(2, "send: truncated", command, (size_t)ret); return -1; } upsdebug_hex(2, "send", command, (size_t)ret); ret = ser_get_buf_len(upsfd, reply, 8, 1, 0); /* it needs that this driver works with USB to Serial cable */ if (ret < 0) { upsdebug_with_errno(2, "read"); return -1; } else if (ret < 6) { upsdebug_hex(2, "read: truncated", reply, (size_t)ret); return -1; } else if (reply[7] != cksum(reply, 7)) { upsdebug_hex(2, "read: checksum error", reply, (size_t)ret); return -1; } upsdebug_hex(2, "read", reply, (size_t)ret); return ret; } void upsdrv_initinfo(void) { struct { const char *var; unsigned char len; } vartab[] = { { "ups.model", 15 }, { "ups.firmware", 8 }, { "ups.serial", 10 }, { "ups.mfr.date", 4 }, { NULL, 0 } }; char buf[LARGEBUF]; int i, bitn, vari, offset=4, readok=0; ssize_t ret=0; char command[6], reply[8]; unsigned int value; dstate_setinfo("ups.mfr", "%s", "Liebert"); for (vari = 0; vartab[vari].var; vari++) { upsdebugx(1, "reading: %s", vartab[vari].var); for (i = 0; i < vartab[vari].len; i++) { snprintf(command, sizeof(command), "\x01\x88\x02\x01%c", i+offset); command[5] = cksum(command, 5); ret = do_command((unsigned char *)command, reply, 6); if (ret < 8) { upsdebug_hex(2, "send: truncated", command, (size_t)ret); break; } buf[i<<1] = reply[6]; buf[(i<<1)+1] = reply[5]; } buf[i<<1] = 0; upsdebugx(1, "return: %" PRIiSIZE " (8=success)", ret); if (ret == 8) { /* last command successful */ dstate_setinfo(vartab[vari].var,"%s",buf); readok++; } offset+=vartab[vari].len; } /* for */ if (!readok) { fatalx(EXIT_FAILURE, "ESP-II capable UPS not detected"); } /* determine number of input & output phases and ups type */ memcpy(command,cmd_upstype,6); ret = do_command((unsigned char *)command, reply, 6); if (ret < 8) { upsdebug_hex(2, "send: phase detection: truncated", command, (size_t)ret); } else { /* input: from bit 0 to bit 1 (2 bits) */ for (value=0,bitn=0;bitn<2;bitn++) { if (IsBitSet(reply[6],(unsigned short int)bitn)) /* bit range measurement on LSByte*/ value+=(1<<(unsigned short int)(bitn - 0)); } num_inphases=value; dstate_setinfo("input.phases", "%d", value); /* output: from bit 4 to bit 5 (2 bits)*/ for (value=0,bitn=4;bitn<6;bitn++) { if (IsBitSet(reply[6],(unsigned short int)bitn)) /* bit range measurement on LSByte*/ value+=(1<<(unsigned short int)(bitn - 4)); } num_outphases=value; dstate_setinfo("output.phases", "%d", value); if (reply[5] & (1<<4)) { /* ISOFFLINE */ dstate_setinfo("ups.type", "offline") ; } else if (reply[5] & (1<<5)) { /* ISINTERACTIVE */ dstate_setinfo("ups.type", "line-interactive") ; } else { dstate_setinfo("ups.type", "online") ; } } /* determine scaling */ /* full scaling output not defined yet, but we can differentiate sets of * multipliers based on a sample scaling reading */ memcpy(command,cmd_scaling1,6); ret = do_command((unsigned char *)command, reply, 6); if (ret < 8) { upsdebug_hex(2, "send: scaling detection: truncated", command, (size_t)ret); } else { /* add here multipliers that differentiate between models */ switch (reply[6]) { case 1: /* GXT-2 */ multi[M_FREQUENCY]=0.1; /* Confirmed correct on a Liebert GXT2-6000RT208 */ multi[M_VOLT_DC]=0.1; multi[M_POWER]=1.0; multi[M_NOMPOWER]=1.0; break; case 2: /* NXe */ multi[M_FREQUENCY]=0.01; multi[M_VOLT_DC]=0.1; multi[M_POWER]=100.0; multi[M_NOMPOWER]=100.0; break; default: /* the default values from definition of multi will be used */ break; } } upsh.instcmd = instcmd; upsh.setvar = setvar; } void upsdrv_updateinfo(void) { typedef struct { const unsigned char cmd[6]; const char *var; const char *fmt; const int multindex; } cmd_s; static cmd_s vartab[] = { /* common vars */ { { 1,149,2,1,1,154 }, "battery.runtime", "%.0f", M_BAT_RUNTIME }, { { 1,149,2,1,2,155 }, "battery.voltage", "%.1f", M_VOLT_DC }, { { 1,149,2,1,3,156 }, "battery.current", "%.2f", M_CURRENT_DC }, { { 1,161,2,1,13,178 }, "battery.voltage.nominal", "%.1f", M_VOLT_DC }, { { 1,149,2,1,12,165 }, "battery.temperature", "%.1f", M_TEMPERATURE }, { { 1,149,2,1,14,167 }, "ups.temperature", "%.1f", M_TEMPERATURE }, { { 1,161,2,1,8,173 }, "ups.power.nominal", "%.0f", M_NOMPOWER }, { { 1,161,2,1,4,169 }, "ups.delay.start", "%.0f", M_10 }, { { 1,161,2,1,14,179 },"battery.runtime.low", "%.0f", M_BAT_RUNTIME }, { { 1,149,2,1,8,161 }, "input.frequency", "%.1f", M_FREQUENCY }, { { 1,149,2,1,10,163 }, "input.bypass.frequency", "%.1f", M_FREQUENCY }, { { 1,161,2,1,9,174 }, "input.frequency.nominal", "%.1f", M_FREQUENCY }, { { 1,149,2,1,9,162 }, "output.frequency", "%.1f", M_FREQUENCY }, { { 1,161,2,1,10,175 }, "output.frequency.nominal", "%.1f", M_FREQUENCY }, { { 0 }, NULL, NULL, 0 } }; static cmd_s vartab1o[] = { /* 1-phase out */ { { 1,149,2,1,7,160 }, "ups.load", "%.0f", M_LOADPERC }, { { 1,149,2,1,6,159 }, "ups.power", "%.0f", M_POWER }, { { 1,149,2,1,5,158 }, "ups.realpower", "%.0f", M_POWER }, { { 1,144,2,1,3,151 }, "output.voltage", "%.1f", M_VOLTAGE_O }, { { 1,144,2,1,4,152 }, "output.current", "%.1f", M_CURRENT_O }, { { 0 }, NULL, NULL, 0 } }; static cmd_s vartab1i[] = { /* 1-phase in*/ { { 1,144,2,1,1,149 }, "input.voltage", "%.1f", M_VOLTAGE_I }, { { 1,144,2,1,5,153 }, "input.bypass.voltage", "%.1f", M_VOLTAGE_B }, { { 1,144,2,1,6,154 }, "input.bypass.current", "%.1f", M_CURRENT_B }, { { 0 }, NULL, NULL, 0 } }; static cmd_s vartab2o[] = { /*split-phase out, only V line-line is reported*/ { { 1,144,2,1,24,172 }, "output.L1.power.percent", "%.0f", M_LOADPERC }, { { 1,145,2,1,24,173 }, "output.L2.power.percent", "%.0f", M_LOADPERC }, { { 1,144,2,1,22,170 }, "output.L1.power", "%.0f", M_POWER }, { { 1,145,2,1,22,171 }, "output.L2.power", "%.0f", M_POWER }, { { 1,144,2,1,21,169 }, "output.L1.realpower", "%.0f", M_POWER }, { { 1,145,2,1,21,170 }, "output.L2.realpower", "%.0f", M_POWER }, { { 1,144,2,1,3,151 }, "output.voltage", "%.1f", M_VOLTAGE_O }, { { 0 }, NULL, NULL, 0 } }; static cmd_s vartab3o[] = { /*3-phase out */ { { 1,144,2,1,24,172 }, "output.L1.power.percent", "%.0f", M_LOADPERC }, { { 1,145,2,1,24,173 }, "output.L2.power.percent", "%.0f", M_LOADPERC }, { { 1,146,2,1,24,174 }, "output.L3.power.percent", "%.0f", M_LOADPERC }, { { 1,144,2,1,22,170 }, "output.L1.power", "%.0f", M_POWER }, { { 1,145,2,1,22,171 }, "output.L2.power", "%.0f", M_POWER }, { { 1,146,2,1,22,172 }, "output.L3.power", "%.0f", M_POWER }, { { 1,144,2,1,21,169 }, "output.L1.realpower", "%.0f", M_POWER }, { { 1,145,2,1,21,170 }, "output.L2.realpower", "%.0f", M_POWER }, { { 1,146,2,1,21,171 }, "output.L3.realpower", "%.0f", M_POWER }, { { 1,144,2,1,3,151 }, "output.L1-N.voltage", "%.1f", M_VOLTAGE_O }, { { 1,145,2,1,3,152 }, "output.L2-N.voltage", "%.1f", M_VOLTAGE_O }, { { 1,146,2,1,3,153 }, "output.L3-N.voltage", "%.1f", M_VOLTAGE_O }, { { 1,144,2,1,14,162 }, "output.L1.crestfactor", "%.1f", M_0_1 }, { { 1,145,2,1,14,163 }, "output.L2.crestfactor", "%.1f", M_0_1 }, { { 1,146,2,1,14,164 }, "output.L3.crestfactor", "%.1f", M_0_1 }, { { 0 }, NULL, NULL, 0 } }; static cmd_s vartab2i[] = { /*split-phase in, only reports V L-L */ { { 1,144,2,1,1,149 }, "input.voltage", "%.1f", M_VOLTAGE_I }, { { 1,144,2,1,5,153 }, "input.bypass.voltage", "%.1f", M_VOLTAGE_B }, { { 1,144,2,1,6,154 }, "input.bypass.current", "%.1f", M_CURRENT_B }, { { 1,144,2,1,2,150 }, "input.current", "%.1f", M_CURRENT_I }, { { 0 }, NULL, NULL, 0 } }; static cmd_s vartab3i[] = { /*3-phase in */ { { 1,144,2,1,1,149 }, "input.L1-N.voltage", "%.1f", M_VOLTAGE_I }, { { 1,145,2,1,1,150 }, "input.L2-N.voltage", "%.1f", M_VOLTAGE_I }, { { 1,146,2,1,1,151 }, "input.L3-N.voltage", "%.1f", M_VOLTAGE_I }, { { 1,144,2,1,5,153 }, "input.L1-N.bypass.voltage", "%.1f", M_VOLTAGE_B }, { { 1,145,2,1,5,154 }, "input.L2-N.bypass.voltage", "%.1f", M_VOLTAGE_B }, { { 1,146,2,1,5,155 }, "input.L3-N.bypass.voltage", "%.1f", M_VOLTAGE_B }, { { 1,144,2,1,6,154 }, "input.L1-N.bypass.current", "%.1f", M_CURRENT_B }, { { 1,145,2,1,6,155 }, "input.L2-N.bypass.current", "%.1f", M_CURRENT_B }, { { 1,146,2,1,6,156 }, "input.L3-N.bypass.current", "%.1f", M_CURRENT_B }, { { 1,144,2,1,2,150 }, "input.L1.current", "%.1f", M_CURRENT_I }, { { 1,145,2,1,2,151 }, "input.L2.current", "%.1f", M_CURRENT_I }, { { 1,146,2,1,2,152 }, "input.L3.current", "%.1f", M_CURRENT_I }, { { 0 }, NULL, NULL, 0 } }; static cmd_s * cmdin_p; static cmd_s * cmdout_p; const char *val; char reply[8]; ssize_t ret; int i; for (i = 0; vartab[i].var; i++) { int16_t intval; ret = do_command(vartab[i].cmd, reply, 6); if (ret < 8) { continue; } intval = (unsigned char)reply[5]; intval <<= 8; intval += (unsigned char)reply[6]; #ifdef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL #pragma GCC diagnostic push #endif #ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL #pragma GCC diagnostic ignored "-Wformat-nonliteral" #endif #ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_FORMAT_SECURITY #pragma GCC diagnostic ignored "-Wformat-security" #endif dstate_setinfo(vartab[i].var, vartab[i].fmt, multi[vartab[i].multindex] * intval); #ifdef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL #pragma GCC diagnostic pop #endif } if (num_inphases==3){ cmdin_p=vartab3i; } else if(num_inphases==2){ cmdin_p=vartab2i; } else { cmdin_p=vartab1i; } if (num_outphases==3){ cmdout_p=vartab3o; } else if(num_outphases==2){ cmdout_p=vartab2o; } else { cmdout_p=vartab1o; } for (i = 0; cmdin_p[i].var; i++) { int16_t intval; ret = do_command(cmdin_p[i].cmd, reply, 6); if (ret < 8) { continue; } intval = (unsigned char)reply[5]; intval <<= 8; intval += (unsigned char)reply[6]; #ifdef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL #pragma GCC diagnostic push #endif #ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL #pragma GCC diagnostic ignored "-Wformat-nonliteral" #endif #ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_FORMAT_SECURITY #pragma GCC diagnostic ignored "-Wformat-security" #endif dstate_setinfo(cmdin_p[i].var, cmdin_p[i].fmt, multi[cmdin_p[i].multindex] * intval); #ifdef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL #pragma GCC diagnostic pop #endif } for (i = 0; cmdout_p[i].var; i++) { int16_t intval; ret = do_command(cmdout_p[i].cmd, reply, 6); if (ret < 8) { continue; } intval = (unsigned char)reply[5]; intval <<= 8; intval += (unsigned char)reply[6]; #ifdef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL #pragma GCC diagnostic push #endif #ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL #pragma GCC diagnostic ignored "-Wformat-nonliteral" #endif #ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_FORMAT_SECURITY #pragma GCC diagnostic ignored "-Wformat-security" #endif dstate_setinfo(cmdout_p[i].var, cmdout_p[i].fmt, multi[cmdout_p[i].multindex] * intval); #ifdef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL #pragma GCC diagnostic pop #endif } status_init(); ret = do_command(cmd_bitfield1, reply, 6); if (ret < 8) { upslogx(LOG_ERR, "Failed reading bitfield #1"); dstate_datastale(); return; } if (reply[5] & (1<<0)) { /* ON_BATTERY */ status_set("OB"); } else { status_set("OL"); } val = dstate_getinfo("battery.current"); if (val) { if (atof(val) > 0.05) { status_set("CHRG"); } if (atof(val) < -0.05) { status_set("DISCHRG"); } } ret = do_command(cmd_bitfield2, reply, 6); if (ret < 8) { upslogx(LOG_ERR, "Failed reading bitfield #2"); dstate_datastale(); return; } if (reply[6] & (1<<0)) { /* ON_BYPASS */ status_set("BYPASS"); } if (reply[6] & (1<<5)) { /* REPLACE_BATTERY */ status_set("RB"); } if (reply[6] & (1<<6)) { /* BOOST_ON */ status_set("BOOST"); } if (reply[5] & (1<<1)) { /* BUCK_ON */ status_set("TRIM"); } ret = do_command(cmd_bitfield3, reply, 6); if (ret < 8) { upslogx(LOG_ERR, "Failed reading bitfield #3"); dstate_datastale(); return; } if (reply[6] & (1<<0) ) { /* UPS_OVERLOAD */ status_set("OVER"); } if (reply[6] & (1<<5) ) { /* LOW_BATTERY */ status_set("LB"); } status_commit(); dstate_dataok(); } void upsdrv_shutdown(void) { char reply[8]; if(!(do_command(cmd_setOutOffMode, reply, 8) != -1) && (do_command(cmd_setOutOffDelay, reply, 8) != -1) && (do_command(cmd_sysLoadKey, reply, 6) != -1) && (do_command(cmd_shutdown, reply, 8) != -1)) upslogx(LOG_ERR, "Failed to shutdown UPS"); } static int instcmd(const char *cmdname, const char *extra) { /* if (!strcasecmp(cmdname, "test.battery.stop")) { ser_send_buf(upsfd, ...); return STAT_INSTCMD_HANDLED; } */ upslogx(LOG_NOTICE, "instcmd: unknown command [%s] [%s]", cmdname, extra); return STAT_INSTCMD_UNKNOWN; } static int setvar(const char *varname, const char *val) { /* if (!strcasecmp(varname, "ups.test.interval")) { ser_send_buf(upsfd, ...); return STAT_SET_HANDLED; } */ upslogx(LOG_NOTICE, "setvar: unknown variable [%s] [%s]", varname, val); return STAT_SET_UNKNOWN; } void upsdrv_help(void) { } /* list flags and values that you want to receive via -x */ void upsdrv_makevartable(void) { addvar (VAR_VALUE, "baudrate", "serial line speed"); } void upsdrv_initups(void) { const char *val = getval("baudrate"); speed_t baudrate = B2400; /* No-op, just made to quiesce the compiler warnings */ NUT_UNUSED_FUNCTION_dummy_bitfields(); if (val) { switch (atoi(val)) { case 1200: baudrate = B1200; break; case 2400: baudrate = B2400; break; case 4800: baudrate = B4800; break; case 9600: baudrate = B9600; break; case 19200: baudrate = B19200; break; default: fatalx(EXIT_FAILURE, "Baudrate [%s] unsupported", val); } } upsfd = ser_open(device_path); ser_set_speed(upsfd, device_path, baudrate); } void upsdrv_cleanup(void) { ser_close(upsfd, device_path); } nut-2.8.1/drivers/apc-hid.c0000644000175000017500000006734414501607135012420 00000000000000/* apc-hid.c - data to monitor APC USB/HID devices with NUT * * Copyright (C) * 2003 - 2009 Arnaud Quette * 2005 John Stamp * 2005 Peter Selinger * 2009 - 2010 Arjen de Korte * * Sponsored by MGE UPS SYSTEMS * and Eaton * * 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 2 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, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #include "main.h" /* for getval() */ #include "hidparser.h" /* for FindObject_with_ID_Node() */ #include "usbhid-ups.h" #include "apc-hid.h" #include "usb-common.h" #define APC_HID_VERSION "APC HID 0.100" /* APC */ #define APC_VENDORID 0x051d /* Tweaks */ static char * tweak_max_report[] = { /* Back-UPS ES 700 does NOT overflow. */ /* Back-UPS ES 725 does NOT overflow. */ /* Back-UPS ES 525 overflows on ReportID 0x0c (UPS.PowerSummary.RemainingCapacity). */ "Back-UPS ES 525", /* Back-UPS CS 650 overflows on ReportID 0x46 */ "Back-UPS CS", NULL}; /* Don't use interrupt pipe on 5G models (used by proprietary protocol) */ static void *disable_interrupt_pipe(USBDevice_t *device) { NUT_UNUSED_VARIABLE(device); if (use_interrupt_pipe == TRUE) { /* FIXME? Suggest data from "device" to help the setup below? */ upslogx(LOG_INFO, "interrupt pipe disabled (add 'pollonly' flag to 'ups.conf' to get rid of this message)"); use_interrupt_pipe= FALSE; } return NULL; } /* Some models need special tweaks */ static void *general_apc_check(USBDevice_t *device) { int i = 0; if (!device->Product) { upslogx(LOG_WARNING, "device->Product is NULL so it is not possible to determine whether to activate max_report_size workaround"); return NULL; } /* Some models of Back-UPS overflow on some ReportID. * This results in some data not being exposed and IO errors on * WIN32, causing endless reconnection or driver's failure */ while( tweak_max_report[i] != NULL ) { if(!strncmp(device->Product, tweak_max_report[i], strlen(tweak_max_report[i]))) { max_report_size = 1; return NULL; } i++; } return NULL; } /* USB IDs device table */ static usb_device_id_t apc_usb_device_table[] = { /* APC AP9584 Serial->USB kit */ { USB_DEVICE(APC_VENDORID, 0x0000), NULL }, /* various models */ { USB_DEVICE(APC_VENDORID, 0x0002), general_apc_check }, /* various 5G models */ { USB_DEVICE(APC_VENDORID, 0x0003), disable_interrupt_pipe }, /* APC Smart UPS 1000 with latest firmware 04.3 * seems to have bumped the productid from 3 to 4 * See https://github.com/networkupstools/nut/issues/1429 */ { USB_DEVICE(APC_VENDORID, 0x0004), disable_interrupt_pipe }, /* Terminating entry */ { 0, 0, NULL } }; /* returns statically allocated string - must not use it again before done with result! */ static const char *apc_date_conversion_fun(double value) { static char buf[20]; int year, month, day; if ((long)value == 0) { return "not set"; } /* APC apparently uses a hexadecimal-as-decimal format, e.g., 0x102202 = October 22, 2002 */ year = ((long)value & 0xf) + 10 * (((long)value>>4) & 0xf); month = (((long)value>>16) & 0xf) + 10 * (((long)value>>20) & 0xf); day = (((long)value>>8) & 0xf) + 10 * (((long)value>>12) & 0xf); /* Y2K conversion - hope that this format will be retired before 2070 :) */ if (year >= 70) { year += 1900; } else { year += 2000; } snprintf(buf, sizeof(buf), "%04d/%02d/%02d", year, month, day); return buf; } static double apc_date_conversion_reverse(const char *date_string) { int year, month, day; long date; sscanf(date_string, "%04d/%02d/%02d", &year, &month, &day); if(year >= 2070 || month > 12 || day > 31) return 0; year %= 100; date = ((year / 10 & 0x0F) << 4) + (year % 10); date += ((month / 10 & 0x0F) << 20) + ((month % 10) << 16); date += ((day / 10 & 0x0F) << 12) + ((day % 10) << 8); return (double) date; } static info_lkp_t apc_date_conversion[] = { { 0, NULL, apc_date_conversion_fun, apc_date_conversion_reverse } }; /* This was determined empirically from observing a BackUPS LS 500 */ static info_lkp_t apcstatusflag_info[] = { { 8, "!off", NULL, NULL }, /* Normal operation */ { 16, "!off", NULL, NULL }, /* This occurs briefly during power-on, and corresponds to status 'DISCHRG'. */ { 0, "off", NULL, NULL }, { 0, NULL, NULL, NULL } }; /* Reason of the last battery transfer (from apcupsd) */ static info_lkp_t apc_linefailcause_vrange_info[] = { { 1, "vrange", NULL, NULL }, /* Low line voltage */ { 2, "vrange", NULL, NULL }, /* High line voltage */ { 4, "vrange", NULL, NULL }, /* notch, spike, or blackout */ { 8, "vrange", NULL, NULL }, /* Notch or blackout */ { 9, "vrange", NULL, NULL }, /* Spike or blackout */ { 0, "!vrange", NULL, NULL }, /* No transfers have ocurred */ { 0, NULL, NULL, NULL } }; static info_lkp_t apc_linefailcause_frange_info[] = { { 7, "frange", NULL, NULL }, /* Input frequency out of range */ { 0, "!frange", NULL, NULL }, /* No transfers have ocurred */ { 0, NULL, NULL, NULL } }; #if 0 /* these input.transfer.reason can't be mapped at the moment... */ { 3, "ripple", NULL, NULL }, /* Ripple */ { 5, "self test", NULL, NULL }, /* Self Test or Discharge Calibration commanded * Test usage, front button, or 2 week self test */ { 6, "forced", NULL, NULL }, /* DelayBeforeShutdown or APCDelayBeforeShutdown */ { 10, "forced", NULL, NULL }, /* Graceful shutdown by accessories */ { 11, "self test", NULL, NULL }, /* Test usage invoked */ { 12, "self test", NULL, NULL }, /* Front button initiated self test */ { 13, "self test", NULL, NULL }, /* 2 week self test */ { 0, NULL, NULL, NULL } #endif static info_lkp_t apc_sensitivity_info[] = { { 0, "low", NULL, NULL }, { 1, "medium", NULL, NULL }, { 2, "high", NULL, NULL }, { 0, NULL, NULL, NULL } }; /* --------------------------------------------------------------- */ /* Vendor-specific usage table */ /* --------------------------------------------------------------- */ /* APC usage table */ static usage_lkp_t apc_usage_lkp[] = { { "APCGeneralCollection", 0xff860005 }, { "APCEnvironment", 0xff860006 }, { "APCProbe1", 0xff860007 }, { "APCProbe2", 0xff860008 }, { "APCBattReplaceDate", 0xff860016 }, /* usage seen in dumps but unknown: * - ff860018 * Path: UPS.Battery.ff860018, Type: Feature, ReportID: 0x48, Offset: 0, Size: 32, Value: 0 */ { "APCBattCapBeforeStartup", 0xff860019 }, /* FIXME: exploit */ /* usage seen in dumps but unknown: * - ff86001a * Path: UPS.Battery.ff86001a, Type: Input, ReportID: 0x1b, Offset: 0, Size: 8, Value: 3 * Path: UPS.Battery.ff86001a, Type: Feature, ReportID: 0x1b, Offset: 0, Size: 8, Value: 3 * - ff86001b * Path: UPS.Battery.ff86001b, Type: Input, ReportID: 0x1c, Offset: 0, Size: 8, Value: 0 * Path: UPS.Battery.ff86001b, Type: Feature, ReportID: 0x1c, Offset: 0, Size: 8, Value: 0 * - ff860023 * Path: UPS.ff860001.ff860023, Type: Feature, ReportID: 0x60, Offset: 0, Size: 16, Value: 0 * - ff860024 * Path: UPS.Battery.ff860024, Type: Feature, ReportID: 0x47, Offset: 0, Size: 8, Value: 245 * Path: UPS.PowerConverter.ff860024, Type: Feature, ReportID: 0x51, Offset: 0, Size: 8, Value: 145 * - ff860025 * Path: UPS.ff860001.ff860025, Type: Feature, ReportID: 0x62, Offset: 0, Size: 32, Value: 0 * - ff860026 * Path: UPS.ff860001.ff860026, Type: Feature, ReportID: 0x61, Offset: 0, Size: 8, Value: 10 * - ff860027 * Path: UPS.ff860027, Type: Feature, ReportID: 0x3e, Offset: 0, Size: 32, Value: 0 * - ff860028 * Path: UPS.ff860028, Type: Feature, ReportID: 0x3f, Offset: 0, Size: 32, Value: 0 * - ff860030 * Path: UPS.Output.ff860030, Type: Feature, ReportID: 0x42, Offset: 0, Size: 16, Value: 5.8 */ { "APC_UPS_FirmwareRevision", 0xff860042 }, { "APCLineFailCause", 0xff860052 }, { "APCStatusFlag", 0xff860060 }, { "APCSensitivity", 0xff860061 }, { "APCPanelTest", 0xff860072 }, /* FIXME: exploit */ { "APCShutdownAfterDelay", 0xff860076 }, /* FIXME: exploit */ { "APC_USB_FirmwareRevision", 0xff860079 }, /* FIXME: exploit */ { "APCDelayBeforeReboot", 0xff86007c }, /* WARNING: apcupsd maps this as APCForceShutdown... which one is right? */ { "APCDelayBeforeShutdown", 0xff86007d }, { "APCDelayBeforeStartup", 0xff86007e }, /* FIXME: exploit */ /* usage seen in dumps but unknown: * - ff860080 * Path: UPS.PresentStatus.ff860080, Type: Input, ReportID: 0x33, Offset: 12, Size: 1, Value: 0 * Path: UPS.PresentStatus.ff860080, Type: Feature, ReportID: 0x33, Offset: 12, Size: 1, Value: 0 * Path: UPS.PowerSummary.PresentStatus.ff860080, Type: Input, ReportID: 0x07, Offset: 12, Size: 1, Value: 0 * Path: UPS.PowerSummary.PresentStatus.ff860080, Type: Feature, ReportID: 0x07, Offset: 12, Size: 1, Value: 0 * - ff860090, ff860091 * Path: UPS.ff860090.ff860091, Type: Feature, ReportID: 0x8c, Offset: 0, Size: 8, Value: 1.000000 * - ff860092 * Path: UPS.ff860090.ff860092, Type: Feature, ReportID: 0x8d, Offset: 0, Size: 8, Value: 25.000000 * - ff860093 * Path: UPS.ff860090.ff860093, Type: Feature, ReportID: 0x8e, Offset: 0, Size: 8, Value: 83.000000 * - ff860094 * Path: UPS.ff860090.ff860094, Type: Feature, ReportID: 0x8f, Offset: 0, Size: 8, Value: 0.000000 * - ff860095 * Path: UPS.ff860090.ff860095, Type: Feature, ReportID: 0x90, Offset: 0, Size: 8, Value: 1.000000 * - ff860096 * Path: UPS.ff860090.ff860096, Type: Feature, ReportID: 0x91, Offset: 0, Size: 16, Value: 4.000000 * - ff860097 * Path: UPS.ff860090.ff860097, Type: Feature, ReportID: 0x92, Offset: 0, Size: 16, Value: 4.000000 */ /* Note (Arnaud): BUP stands for BackUPS Pro * This is a HID uncompliant special (manufacturer) collection * FIXME: these need to be used... */ { "BUPHibernate", 0x00850058 }, /* FIXME: exploit */ { "BUPBattCapBeforeStartup", 0x00860012 }, /* FIXME: exploit */ { "BUPDelayBeforeStartup", 0x00860076 }, /* FIXME: exploit */ { "BUPSelfTest", 0x00860010 }, /* FIXME: exploit */ { NULL, 0 } }; /* * USB USAGE NOTES for APC (from Russell Kroll in the old hidups) * * FIXME: read 0xff86.... instead of 0x(00)86....? * * 0x860013 == 44200155090 - capability again * == locale 4, 4 choices, 2 bytes, 00, 15, 50, 90 * == minimum charge to return online * * 0x860060 == "441HMLL" - looks like a 'capability' string * == locale 4, 4 choices, 1 byte each * == line sensitivity (high, medium, low, low) * NOTE! the above does not seem to correspond to my info * * 0x860062 == D43133136127130 * == locale D, 4 choices, 3 bytes, 133, 136, 127, 130 * == high transfer voltage * * 0x860064 == D43103100097106 * == locale D, 4 choices, 3 bytes, 103, 100, 097, 106 * == low transfer voltage * * 0x860066 == 441HMLL (see 860060) * * 0x860074 == 4410TLN * == locale 4, 4 choices, 1 byte, 0, T, L, N * == alarm setting (5s, 30s, low battery, none) * * 0x860077 == 443060180300600 * == locale 4, 4 choices, 3 bytes, 060,180,300,600 * == wake-up delay (after power returns) */ static usage_tables_t apc_utab[] = { apc_usage_lkp, hid_usage_lkp, NULL, }; /* --------------------------------------------------------------- */ /* HID2NUT lookup table */ /* --------------------------------------------------------------- */ /* HID2NUT lookup table */ static hid_info_t apc_hid2nut[] = { /* Battery page */ { "battery.charge", 0, 0, "UPS.PowerSummary.RemainingCapacity", NULL, "%.0f", 0, NULL }, { "battery.charge.low", ST_FLAG_RW | ST_FLAG_STRING, 10, "UPS.PowerSummary.RemainingCapacityLimit", NULL, "%.0f", HU_FLAG_SEMI_STATIC, NULL }, { "battery.charge.warning", 0, 0, "UPS.PowerSummary.WarningCapacityLimit", NULL, "%.0f", 0, NULL }, { "battery.runtime", 0, 0, "UPS.Battery.RunTimeToEmpty", NULL, "%.0f", 0, NULL }, { "battery.runtime", 0, 0, "UPS.PowerSummary.RunTimeToEmpty", NULL, "%.0f", 0, NULL }, { "battery.runtime.low", ST_FLAG_RW | ST_FLAG_STRING, 10, "UPS.Battery.RemainingTimeLimit", NULL, "%.0f", HU_FLAG_SEMI_STATIC, NULL }, { "battery.runtime.low", ST_FLAG_RW | ST_FLAG_STRING, 10, "UPS.PowerSummary.RemainingTimeLimit", NULL, "%.0f", HU_FLAG_SEMI_STATIC, NULL }, { "battery.voltage", 0, 0, "UPS.Battery.Voltage", NULL, "%.1f", 0, NULL }, { "battery.voltage", 0, 0, "UPS.PowerSummary.Voltage", NULL, "%.1f", 0, NULL }, { "battery.voltage.nominal", 0, 0, "UPS.Battery.ConfigVoltage", NULL, "%.1f", 0, NULL }, { "battery.voltage.nominal", 0, 0, "UPS.PowerSummary.ConfigVoltage", NULL, "%.1f", 0, NULL }, /* Back-UPS 500 */ { "battery.temperature", 0, 0, "UPS.Battery.Temperature", NULL, "%s", 0, kelvin_celsius_conversion }, { "battery.type", 0, 0, "UPS.PowerSummary.iDeviceChemistry", NULL, "%s", 0, stringid_conversion }, { "battery.mfr.date", ST_FLAG_RW | ST_FLAG_STRING, 10, "UPS.Battery.ManufacturerDate", NULL, "%s", HU_FLAG_SEMI_STATIC, date_conversion }, { "battery.mfr.date", 0, 0, "UPS.PowerSummary.APCBattReplaceDate", NULL, "%s", 0, apc_date_conversion }, /* Back-UPS 500, Back-UPS ES/CyberFort 500 */ { "battery.date", 0, 0, "UPS.Battery.APCBattReplaceDate", NULL, "%s", 0, apc_date_conversion }, /* Observed values: 0x0 on Back-UPS ES 650, 0x92501 on Back-UPS BF500 whose manufacture date was 2005/01/20 - this makes little sense but at least it's a valid date. */ /* UPS page */ { "ups.load", 0, 0, "UPS.Output.PercentLoad", NULL, "%.1f", 0, NULL }, { "ups.load", 0, 0, "UPS.PowerConverter.PercentLoad", NULL, "%.0f", 0, NULL }, /* USB HID PDC defaults */ { "ups.delay.start", ST_FLAG_RW | ST_FLAG_STRING, 10, "UPS.PowerSummary.DelayBeforeStartup", NULL, DEFAULT_ONDELAY, HU_FLAG_ABSENT, NULL}, { "ups.delay.shutdown", ST_FLAG_RW | ST_FLAG_STRING, 10, "UPS.PowerSummary.DelayBeforeShutdown", NULL, DEFAULT_OFFDELAY, HU_FLAG_ABSENT, NULL}, { "ups.timer.start", 0, 0, "UPS.PowerSummary.DelayBeforeStartup", NULL, "%.0f", HU_FLAG_QUICK_POLL, NULL}, { "ups.timer.shutdown", 0, 0, "UPS.PowerSummary.DelayBeforeShutdown", NULL, "%.0f", HU_FLAG_QUICK_POLL, NULL}, { "ups.timer.reboot", 0, 0, "UPS.PowerSummary.DelayBeforeReboot", NULL, "%.0f", HU_FLAG_QUICK_POLL, NULL}, /* used by APC SmartUPS RM */ { "ups.delay.start", ST_FLAG_RW | ST_FLAG_STRING, 10, "UPS.Output.DelayBeforeStartup", NULL, DEFAULT_ONDELAY, HU_FLAG_ABSENT, NULL}, { "ups.delay.shutdown", ST_FLAG_RW | ST_FLAG_STRING, 10, "UPS.Output.DelayBeforeShutdown", NULL, DEFAULT_OFFDELAY, HU_FLAG_ABSENT, NULL}, { "ups.timer.start", 0, 0, "UPS.Output.DelayBeforeStartup", NULL, "%.0f", HU_FLAG_QUICK_POLL, NULL}, { "ups.timer.shutdown", 0, 0, "UPS.Output.DelayBeforeShutdown", NULL, "%.0f", HU_FLAG_QUICK_POLL, NULL}, { "ups.timer.reboot", 0, 0, "UPS.Output.DelayBeforeReboot", NULL, "%.0f", HU_FLAG_QUICK_POLL, NULL}, /* used by APC BackUPS ES */ { "ups.delay.start", ST_FLAG_RW | ST_FLAG_STRING, 10, "UPS.APCGeneralCollection.APCDelayBeforeStartup", NULL, DEFAULT_ONDELAY, HU_FLAG_ABSENT, NULL}, { "ups.delay.shutdown", ST_FLAG_RW | ST_FLAG_STRING, 10, "UPS.APCGeneralCollection.APCDelayBeforeShutdown", NULL, DEFAULT_OFFDELAY, HU_FLAG_ABSENT, NULL}, { "ups.timer.start", 0, 0, "UPS.APCGeneralCollection.APCDelayBeforeStartup", NULL, "%.0f", HU_FLAG_QUICK_POLL, NULL}, { "ups.timer.shutdown", 0, 0, "UPS.APCGeneralCollection.APCDelayBeforeShutdown", NULL, "%.0f", HU_FLAG_QUICK_POLL, NULL}, { "ups.timer.reboot", 0, 0, "UPS.APCGeneralCollection.APCDelayBeforeReboot", NULL, "%.0f", HU_FLAG_QUICK_POLL, NULL}, { "ups.test.result", 0, 0, "UPS.Battery.Test", NULL, "%s", 0, test_read_info }, { "ups.beeper.status", 0, 0, "UPS.PowerSummary.AudibleAlarmControl", NULL, "%s", 0, beeper_info }, { "ups.mfr.date", 0, 0, "UPS.ManufacturerDate", NULL, "%s", 0, date_conversion }, { "ups.mfr.date", 0, 0, "UPS.PowerSummary.ManufacturerDate", NULL, "%s", 0, date_conversion }, /* Back-UPS 500 */ { "ups.realpower.nominal", 0, 0, "UPS.PowerConverter.ConfigActivePower", NULL, "%.0f", 0, NULL }, { "ups.realpower.nominal", 0, 0, "UPS.Output.ConfigActivePower", NULL, "%.0f", 0, NULL }, /* the below one need to be discussed as we might need to complete * the ups.test sub collection * { "ups.test.panel", 0, 0, "UPS.APCPanelTest", NULL, "%.0f", 0, NULL }, */ /* Special case: ups.status & ups.alarm */ { "BOOL", 0, 0, "UPS.PowerSummary.PresentStatus.ACPresent", NULL, NULL, HU_FLAG_QUICK_POLL, online_info }, { "BOOL", 0, 0, "UPS.PowerSummary.PresentStatus.Discharging", NULL, NULL, HU_FLAG_QUICK_POLL, discharging_info }, { "BOOL", 0, 0, "UPS.PowerSummary.PresentStatus.Charging", NULL, NULL, HU_FLAG_QUICK_POLL, charging_info }, { "BOOL", 0, 0, "UPS.PowerSummary.PresentStatus.ShutdownImminent", NULL, NULL, 0, shutdownimm_info }, { "BOOL", 0, 0, "UPS.PowerSummary.PresentStatus.BelowRemainingCapacityLimit", NULL, NULL, HU_FLAG_QUICK_POLL, lowbatt_info }, { "BOOL", 0, 0, "UPS.PowerSummary.PresentStatus.Overload", NULL, NULL, 0, overload_info }, { "BOOL", 0, 0, "UPS.PowerSummary.PresentStatus.NeedReplacement", NULL, NULL, 0, replacebatt_info }, { "BOOL", 0, 0, "UPS.PowerSummary.PresentStatus.RemainingTimeLimitExpired", NULL, NULL, 0, timelimitexpired_info }, { "BOOL", 0, 0, "UPS.PowerSummary.PresentStatus.BatteryPresent", NULL, NULL, 0, nobattery_info }, { "BOOL", 0, 0, "UPS.PowerSummary.Charging", NULL, NULL, HU_FLAG_QUICK_POLL, charging_info }, /* Back-UPS 500 */ { "BOOL", 0, 0, "UPS.PowerSummary.Discharging", NULL, NULL, HU_FLAG_QUICK_POLL, discharging_info }, /* Back-UPS 500 */ { "BOOL", 0, 0, "UPS.PowerSummary.ACPresent", NULL, NULL, HU_FLAG_QUICK_POLL, online_info }, /* Back-UPS 500 */ { "BOOL", 0, 0, "UPS.PowerSummary.BelowRemainingCapacityLimit", NULL, NULL, HU_FLAG_QUICK_POLL, lowbatt_info }, /* Back-UPS 500 */ { "BOOL", 0, 0, "UPS.PowerSummary.ShutdownImminent", NULL, NULL, 0, shutdownimm_info }, { "BOOL", 0, 0, "UPS.PowerSummary.APCStatusFlag", NULL, NULL, HU_FLAG_QUICK_POLL, apcstatusflag_info }, /* APC Back-UPS LS 500 */ /* we map 2 times "input.transfer.reason" to be able to clear * both vrange (voltage) and frange (frequency) */ { "BOOL", 0, 0, "UPS.Input.APCLineFailCause", NULL, NULL, 0, apc_linefailcause_vrange_info }, { "BOOL", 0, 0, "UPS.Input.APCLineFailCause", NULL, NULL, 0, apc_linefailcause_frange_info }, /* Input page */ { "input.voltage", 0, 0, "UPS.Input.Voltage", NULL, "%.1f", 0, NULL }, { "input.voltage.nominal", 0, 0, "UPS.Input.ConfigVoltage", NULL, "%.0f", 0, NULL }, { "input.transfer.low", ST_FLAG_RW | ST_FLAG_STRING, 10, "UPS.Output.LowVoltageTransfer", NULL, "%.0f", HU_FLAG_SEMI_STATIC, NULL }, { "input.transfer.high", ST_FLAG_RW | ST_FLAG_STRING, 10, "UPS.Output.HighVoltageTransfer", NULL, "%.0f", HU_FLAG_SEMI_STATIC, NULL }, /* used by APC BackUPS RS */ { "input.transfer.low", ST_FLAG_RW | ST_FLAG_STRING, 10, "UPS.Input.LowVoltageTransfer", NULL, "%.0f", HU_FLAG_SEMI_STATIC, NULL }, { "input.transfer.high", ST_FLAG_RW | ST_FLAG_STRING, 10, "UPS.Input.HighVoltageTransfer", NULL, "%.0f", HU_FLAG_SEMI_STATIC, NULL }, { "input.sensitivity", ST_FLAG_RW | ST_FLAG_STRING, 10, "UPS.Input.APCSensitivity", NULL, "%s", HU_FLAG_SEMI_STATIC, apc_sensitivity_info }, /* Output page */ { "output.voltage", 0, 0, "UPS.Output.Voltage", NULL, "%.1f", 0, NULL }, { "output.voltage.nominal", 0, 0, "UPS.Output.ConfigVoltage", NULL, "%.1f", 0, NULL }, { "output.current", 0, 0, "UPS.Output.Current", NULL, "%.2f", 0, NULL }, { "output.frequency", 0, 0, "UPS.Output.Frequency", NULL, "%.1f", 0, NULL }, /* Environmental page */ { "ambient.temperature", 0, 0, "UPS.APCEnvironment.APCProbe1.Temperature", NULL, "%s", 0, kelvin_celsius_conversion }, { "ambient.humidity", 0, 0, "UPS.APCEnvironment.APCProbe1.Humidity", NULL, "%.1f", 0, NULL }, /* { "ambient.temperature", 0, 0, "UPS.APCEnvironment.APCProbe2.Temperature", NULL, "%.1f", 0, kelvin_celsius_conversion }, { "ambient.humidity", 0, 0, "UPS.APCEnvironment.APCProbe2.Humidity", NULL, "%.1f", 0, NULL }, */ /* instant commands. */ /* test.* split into subset while waiting for extradata support * ie: test.battery.start quick */ { "test.battery.start.quick", 0, 0, "UPS.BatterySystem.Battery.Test", NULL, "1", HU_TYPE_CMD, NULL }, { "test.battery.start.quick", 0, 0, "UPS.Battery.Test", NULL, "1", HU_TYPE_CMD, NULL }, /* Back-UPS RS (experimental) */ { "test.battery.start.deep", 0, 0, "UPS.BatterySystem.Battery.Test", NULL, "2", HU_TYPE_CMD, NULL }, { "test.battery.start.deep", 0, 0, "UPS.Battery.Test", NULL, "2", HU_TYPE_CMD, NULL }, /* Back-UPS RS (experimental) */ { "test.battery.stop", 0, 0, "UPS.BatterySystem.Battery.Test", NULL, "3", HU_TYPE_CMD, NULL }, { "test.battery.stop", 0, 0, "UPS.Battery.Test", NULL, "3", HU_TYPE_CMD, NULL }, /* Back-UPS RS (experimental) */ { "test.panel.start", 0, 0, "UPS.APCPanelTest", NULL, "1", HU_TYPE_CMD, NULL }, { "test.panel.stop", 0, 0, "UPS.APCPanelTest", NULL, "0", HU_TYPE_CMD, NULL }, { "test.panel.start", 0, 0, "UPS.PowerSummary.APCPanelTest", NULL, "1", HU_TYPE_CMD, NULL }, /* Back-UPS 500 */ { "test.panel.stop", 0, 0, "UPS.PowerSummary.APCPanelTest", NULL, "0", HU_TYPE_CMD, NULL }, /* Back-UPS 500 */ /* USB HID PDC defaults */ { "load.off.delay", 0, 0, "UPS.PowerSummary.DelayBeforeShutdown", NULL, DEFAULT_OFFDELAY, HU_TYPE_CMD, NULL }, { "load.on.delay", 0, 0, "UPS.PowerSummary.DelayBeforeStartup", NULL, DEFAULT_ONDELAY, HU_TYPE_CMD, NULL }, { "shutdown.stop", 0, 0, "UPS.PowerSummary.DelayBeforeShutdown", NULL, "-1", HU_TYPE_CMD, NULL }, { "shutdown.reboot", 0, 0, "UPS.PowerSummary.DelayBeforeReboot", NULL, "10", HU_TYPE_CMD, NULL }, /* used by APC SmartUPS RM */ { "load.off.delay", 0, 0, "UPS.Output.DelayBeforeShutdown", NULL, DEFAULT_OFFDELAY, HU_TYPE_CMD, NULL }, { "load.on.delay", 0, 0, "UPS.Output.DelayBeforeStartup", NULL, DEFAULT_ONDELAY, HU_TYPE_CMD, NULL }, { "shutdown.stop", 0, 0, "UPS.Output.DelayBeforeShutdown", NULL, "-1", HU_TYPE_CMD, NULL }, { "shutdown.reboot", 0, 0, "UPS.Output.DelayBeforeReboot", NULL, "10", HU_TYPE_CMD, NULL }, /* used by APC BackUPS ES */ { "load.off.delay", 0, 0, "UPS.APCGeneralCollection.APCDelayBeforeShutdown", NULL, DEFAULT_OFFDELAY, HU_TYPE_CMD, NULL }, { "load.on.delay", 0, 0, "UPS.APCGeneralCollection.APCDelayBeforeStartup", NULL, DEFAULT_ONDELAY, HU_TYPE_CMD, NULL }, { "shutdown.stop", 0, 0, "UPS.APCGeneralCollection.APCDelayBeforeShutdown", NULL, "-1", HU_TYPE_CMD, NULL }, { "shutdown.reboot", 0, 0, "UPS.APCGeneralCollection.APCDelayBeforeReboot", NULL, "10", HU_TYPE_CMD, NULL }, /* used by APC BackUPS CS */ { "shutdown.return", 0, 0, "UPS.Output.APCDelayBeforeReboot", NULL, "1", HU_TYPE_CMD, NULL }, { "beeper.on", 0, 0, "UPS.PowerSummary.AudibleAlarmControl", NULL, "2", HU_TYPE_CMD, NULL }, { "beeper.off", 0, 0, "UPS.PowerSummary.AudibleAlarmControl", NULL, "3", HU_TYPE_CMD, NULL }, { "beeper.enable", 0, 0, "UPS.PowerSummary.AudibleAlarmControl", NULL, "2", HU_TYPE_CMD, NULL }, { "beeper.disable", 0, 0, "UPS.PowerSummary.AudibleAlarmControl", NULL, "1", HU_TYPE_CMD, NULL }, { "beeper.mute", 0, 0, "UPS.PowerSummary.AudibleAlarmControl", NULL, "3", HU_TYPE_CMD, NULL }, /* end of structure. */ { NULL, 0, 0, NULL, NULL, NULL, 0, NULL } }; static const char *apc_format_model(HIDDevice_t *hd) { static char model[64]; char *ptr1, *ptr2; /* FIXME?: what is the path "UPS.APC_UPS_FirmwareRevision"? */ snprintf(model, sizeof(model), "%s", hd->Product ? hd->Product : "unknown"); ptr1 = strstr(model, "FW:"); if (ptr1) { *(ptr1 - 1) = '\0'; ptr1 += strlen("FW:"); ptr2 = strstr(ptr1, "USB FW:"); if (ptr2) { *(ptr2 - 1) = '\0'; ptr2 += strlen("USB FW:"); dstate_setinfo("ups.firmware.aux", "%s", ptr2); } dstate_setinfo("ups.firmware", "%s", ptr1); } return model; } static const char *apc_format_mfr(HIDDevice_t *hd) { return hd->Vendor ? hd->Vendor : "APC"; } static const char *apc_format_serial(HIDDevice_t *hd) { return hd->Serial; } /* this function allows the subdriver to "claim" a device: return 1 if * the device is supported by this subdriver, else 0. */ static int apc_claim(HIDDevice_t *hd) { int status = is_usb_device_supported(apc_usb_device_table, hd); switch (status) { case POSSIBLY_SUPPORTED: /* by default, reject, unless the productid option is given */ if (getval("productid")) { return 1; } possibly_supported("APC", hd); return 0; case SUPPORTED: return 1; case NOT_SUPPORTED: default: return 0; } } /* apc_fix_report_desc * * The Back-UPS XS 1400U reports incorrect logical min/max values for the * UPS.Input.ConfigVoltage and UPS.Input.Voltage when operating in a * 220-240V region. Detect this and fix it. * This same fix may be applicable to other APC UPS units as well, though * the report IDs may be different. */ static int apc_fix_report_desc(HIDDevice_t *pDev, HIDDesc_t *pDesc_arg) { HIDData_t *pData; int res = 0; int vendorID = pDev->VendorID; int productID = pDev->ProductID; if (vendorID != APC_VENDORID || productID != 0x0002) { return 0; } if (disable_fix_report_desc) { upsdebugx(3, "NOT Attempting Report Descriptor fix for UPS: " "Vendor: %04x, Product: %04x " "(got disable_fix_report_desc in config)", vendorID, productID); return 0; } upsdebugx(3, "Attempting Report Descriptor fix for UPS: Vendor: %04x, Product: %04x", vendorID, productID); /* Look at the High Voltage Transfer logical max value: * If the HVT logmax is greater than the configured or input voltage limit * then the configured/input voltage limits are probably incorrect. * Arbitrarily set the input voltage logical min/max to 0 .. 2*HVT logmax and the * configured (nominal) input voltage logical max to 255 (it's a single byte value) * Path: UPS.Input.ConfigVoltage, Type: Feature, ReportID: 0x30, Offset: 0, Size: 8 * Path: UPS.Input.Voltage, Type: Feature, ReportID: 0x31, Offset: 0, Size: 16 * Path: UPS.Input.HighVoltageTransfer, Type: Feature, ReportID: 0x33, Offset: 0, Size: 16 */ if ((pData=FindObject_with_ID_Node(pDesc_arg, 0x33, USAGE_POW_HIGH_VOLTAGE_TRANSFER))) { long hvt_logmin = pData->LogMin; long hvt_logmax = pData->LogMax; upsdebugx(4, "Report Descriptor: highVoltageTransfer LogMin: %ld LogMax: %ld", hvt_logmin, hvt_logmax); if ((pData=FindObject_with_ID_Node(pDesc_arg, 0x31, USAGE_POW_VOLTAGE))) { long voltage_logmin = pData->LogMin; long voltage_logmax = pData->LogMax; upsdebugx(4, "Report Descriptor: voltage LogMin: %ld LogMax: %ld", voltage_logmin, voltage_logmax); if (hvt_logmax > voltage_logmax) { pData->LogMin = 0; /* a reasonable lower limit for voltage */ pData->LogMax = hvt_logmax * 2; /* it may be smoking at this point */ upsdebugx(3, "Fixing Report Descriptor. Set voltage LogMin = %ld, LogMax = %ld", pData->LogMin , pData->LogMax); res = 1; } } if ((pData=FindObject_with_ID_Node(pDesc_arg, 0x30, USAGE_POW_CONFIG_VOLTAGE))) { long cvoltage_logmin = pData->LogMin; long cvoltage_logmax = pData->LogMax; upsdebugx(4, "Report Descriptor: configVoltage LogMin: %ld LogMax: %ld", cvoltage_logmin, cvoltage_logmax); if (hvt_logmax > cvoltage_logmax) { pData->LogMax = 255; upsdebugx(3, "Fixing Report Descriptor. Set configVoltage LogMin = %ld, LogMax = %ld", pData->LogMin , pData->LogMax); res = 1; } } } return res; } subdriver_t apc_subdriver = { APC_HID_VERSION, apc_claim, apc_utab, apc_hid2nut, apc_format_model, apc_format_mfr, apc_format_serial, apc_fix_report_desc, }; nut-2.8.1/drivers/apc-ats-mib.c0000644000175000017500000007470514501607135013207 00000000000000/* apcats-mib.c - subdriver to monitor apcats SNMP devices with NUT * * Copyright (C) * 2011 - 2012 Arnaud Quette * 2016 Arnaud Quette * * Note: this subdriver was initially generated as a "stub" by the * gen-snmp-subdriver script. It must be customized! * * 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 2 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, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "apc-ats-mib.h" #define APC_ATS_MIB_VERSION "0.6" #define APC_ATS_SYSOID ".1.3.6.1.4.1.318.1.3.11" #define APC_ATS_OID_MODEL_NAME ".1.3.6.1.4.1.318.1.1.8.1.5.0" static info_lkp_t apc_ats_sensitivity_info[] = { { 1, "high", NULL, NULL }, { 2, "low", NULL, NULL }, { 0, NULL, NULL, NULL } }; static info_lkp_t apc_ats_output_status_info[] = { { 1, "OFF", NULL, NULL }, /* fail */ { 2, "OL", NULL, NULL }, /* ok */ { 0, NULL, NULL, NULL } }; static info_lkp_t apc_ats_outletgroups_name_info[] = { { 1, "total", NULL, NULL }, { 2, "bank1", NULL, NULL }, { 3, "bank2", NULL, NULL }, { 0, NULL, NULL, NULL } }; static info_lkp_t apc_ats_outletgroups_status_info[] = { { 1, "OL", NULL, NULL }, /* normal */ { 2, "", NULL, NULL }, /* lowload */ { 3, "", NULL, NULL }, /* nearoverload */ { 4, "OVER", NULL, NULL }, /* overload */ { 0, NULL, NULL, NULL } }; /* APC ATS Snmp2NUT lookup table */ static snmp_info_t apc_ats_mib[] = { /* standard MIB items */ { "device.description", ST_FLAG_STRING | ST_FLAG_RW, SU_INFOSIZE, ".1.3.6.1.2.1.1.1.0", NULL, SU_FLAG_OK, NULL }, { "device.contact", ST_FLAG_STRING | ST_FLAG_RW, SU_INFOSIZE, ".1.3.6.1.2.1.1.4.0", NULL, SU_FLAG_OK, NULL }, { "device.location", ST_FLAG_STRING | ST_FLAG_RW, SU_INFOSIZE, ".1.3.6.1.2.1.1.6.0", NULL, SU_FLAG_OK, NULL }, /* Device collection */ { "device.type", ST_FLAG_STRING, SU_INFOSIZE, NULL, "ats", SU_FLAG_STATIC | SU_FLAG_ABSENT | SU_FLAG_OK, NULL }, /* ats2IdentManufacturer.0 = STRING: EATON */ { "device.mfr", ST_FLAG_STRING, SU_INFOSIZE, NULL, "APC", SU_FLAG_STATIC | SU_FLAG_ABSENT | SU_FLAG_OK, NULL }, /* atsIdentModelNumber.0 = STRING: "AP7724" */ { "device.model", ST_FLAG_STRING, SU_INFOSIZE, APC_ATS_OID_MODEL_NAME, NULL, SU_FLAG_OK, NULL }, /* FIXME: RFC for device.firmware! */ /* atsIdentHardwareRev.0 = STRING: "R01" */ { "ups.firmware", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.318.1.1.8.1.1.0", NULL, SU_FLAG_OK, NULL }, /* FIXME: RFC for device.firmware.aux! */ /* atsIdentFirmwareRev.0 = STRING: "3.0.5" */ { "ups.firmware.aux", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.318.1.1.8.1.2.0", NULL, SU_FLAG_OK, NULL }, /* atsIdentFirmwareDate.0 = STRING: "09/13/11" */ /*{ "unmapped.atsIdentFirmwareDate", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.318.1.1.8.1.3.0", NULL, SU_FLAG_OK, NULL },*/ /* atsIdentSerialNumber.0 = STRING: "5A1516T15268" */ { "device.serial", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.318.1.1.8.1.6.0", NULL, SU_FLAG_OK, NULL }, /* FIXME: RFC for device.mfr.date! */ /* atsIdentDateOfManufacture.0 = STRING: "04/18/2015" */ { "ups.mfr.date", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.318.1.1.8.1.4.0", NULL, SU_FLAG_OK, NULL }, /* atsConfigProductName.0 = STRING: "m-ups-04" */ { "ups.id", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.318.1.1.8.4.1.0", NULL, SU_FLAG_OK, NULL }, /* Input collection */ /* atsIdentNominalLineVoltage.0 = INTEGER: 230 */ { "input.voltage.nominal", 0, 1, ".1.3.6.1.4.1.318.1.1.8.1.7.0", NULL, SU_FLAG_OK, NULL }, /* atsIdentNominalLineFrequency.0 = INTEGER: 50 */ { "input.frequency.nominal", 0, 1, ".1.3.6.1.4.1.318.1.1.8.1.8.0", NULL, SU_FLAG_OK, NULL }, /* atsStatusSelectedSource.0 = INTEGER: sourceB(2) */ { "input.source", 0, 1, ".1.3.6.1.4.1.318.1.1.8.5.1.2.0", NULL, SU_FLAG_OK, NULL }, /* atsConfigPreferredSource.0 = INTEGER: sourceB(2) */ { "input.source.preferred", ST_FLAG_RW, 1, ".1.3.6.1.4.1.318.1.1.8.4.2.0", NULL, SU_FLAG_OK, NULL }, /* atsInputVoltage.1.1.1 = INTEGER: 216 */ { "input.1.voltage", 0, 1, ".1.3.6.1.4.1.318.1.1.8.5.3.3.1.3.1.1.1", NULL, SU_FLAG_OK, NULL }, /* atsInputVoltage.2.1.1 = INTEGER: 215 */ { "input.2.voltage", 0, 1, ".1.3.6.1.4.1.318.1.1.8.5.3.3.1.3.2.1.1", NULL, SU_FLAG_OK, NULL }, /* atsInputFrequency.1 = INTEGER: 50 */ { "input.1.frequency", 0, 1, ".1.3.6.1.4.1.318.1.1.8.5.3.2.1.4.1", NULL, SU_FLAG_OK, NULL }, /* atsInputFrequency.2 = INTEGER: 50 */ { "input.2.frequency", 0, 1, ".1.3.6.1.4.1.318.1.1.8.5.3.2.1.4.2", NULL, SU_FLAG_OK, NULL }, /* atsConfigVoltageSensitivity.0 = INTEGER: high(1) */ { "input.sensitivity", ST_FLAG_RW, 1, ".1.3.6.1.4.1.318.1.1.8.4.4.0", NULL, SU_FLAG_OK, &apc_ats_sensitivity_info[0] }, /* FIXME: RFC for input.count! */ /* atsNumInputs.0 = INTEGER: 2 */ { "input.count", 0, 1, ".1.3.6.1.4.1.318.1.1.8.5.3.1.0", NULL, SU_FLAG_OK, NULL }, /* Output collection */ /* atsOutputFrequency.1 = INTEGER: 50 */ { "output.frequency", 0, 1, ".1.3.6.1.4.1.318.1.1.8.5.4.2.1.4.1", NULL, SU_FLAG_OK, NULL }, /* atsOutputBankOutputVoltage.1 = INTEGER: 215 */ { "output.voltage", 0, 1, ".1.3.6.1.4.1.318.1.1.8.5.4.5.1.6.1", NULL, SU_FLAG_OK, NULL }, /* UPS collection */ /* FIXME: RFC for device.status! */ /* atsStatusVoltageOutStatus.0 = INTEGER: ok(2) */ { "ups.status", 0, 1, ".1.3.6.1.4.1.318.1.1.8.5.1.15.0", NULL, SU_FLAG_OK, &apc_ats_output_status_info[0] }, /* Outlet groups collection */ /* Note: prefer the OutputBank data to the ConfigBank ones */ /* atsConfigBankTableSize.0 = INTEGER: 3 */ /*{ "outlet.group.count", 0, 1, ".1.3.6.1.4.1.318.1.1.8.4.13.0", NULL, SU_FLAG_OK, NULL },*/ /* atsOutputBankTableSize.0 = INTEGER: 3 */ { "outlet.group.count", 0, 1, ".1.3.6.1.4.1.318.1.1.8.5.4.4.0", NULL, SU_FLAG_OK, NULL }, /* atsConfigBankTableIndex.%i = INTEGER: %i */ /*{ "outlet.group.%i.id", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.318.1.1.8.4.14.1.1.%i", NULL, SU_FLAG_OK, NULL },*/ /* atsOutputBankTableIndex.%i = INTEGER: %i */ { "outlet.group.%i.id", 0, 1, ".1.3.6.1.4.1.318.1.1.8.5.4.5.1.1.%i", NULL, SU_FLAG_OK | SU_OUTLET_GROUP, NULL }, /* atsConfigBank.%i = INTEGER: total(1) */ /*{ "outlet.group.%i.name", 0, 1, ".1.3.6.1.4.1.318.1.1.8.4.14.1.2.%i", NULL, SU_FLAG_STATIC | SU_OUTLET_GROUP, &apc_ats_group_name_info[0] },*/ /* atsOutputBank.1 = INTEGER: total(1) */ { "outlet.group.%i.name", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.318.1.1.8.5.4.5.1.3.%i", NULL, SU_FLAG_STATIC | SU_OUTLET_GROUP, &apc_ats_outletgroups_name_info[0] }, /* atsOutputBankCurrent.%i = Gauge32: 88 */ { "outlet.group.%i.current", 0, 0.1, ".1.3.6.1.4.1.318.1.1.8.5.4.5.1.4.%i", NULL, SU_OUTLET_GROUP, NULL }, /* atsOutputBankState.%i = INTEGER: normal(1) */ { "outlet.group.%i.status", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.318.1.1.8.5.4.5.1.5.%i", NULL, SU_OUTLET_GROUP, &apc_ats_outletgroups_status_info[0] }, /* atsOutputBankOutputVoltage.%i = INTEGER: 215 */ { "outlet.group.%i.voltage", 0, 1, ".1.3.6.1.4.1.318.1.1.8.5.4.5.1.6.%i", NULL, SU_OUTLET_GROUP, NULL }, /* atsOutputBankPower.1 = INTEGER: 1883 */ { "outlet.group.%i.realpower", 0, 1, ".1.3.6.1.4.1.318.1.1.8.5.4.5.1.15.%i", NULL, SU_FLAG_NEGINVALID | SU_OUTLET_GROUP, NULL }, #if WITH_UNMAPPED_DATA_POINTS /* FIXME: Remaining data to be processed */ /* atsIdentDeviceRating.0 = INTEGER: 32 */ { "unmapped.atsIdentDeviceRating", 0, 1, ".1.3.6.1.4.1.318.1.1.8.1.9.0", NULL, SU_FLAG_OK, NULL }, /* atsCalibrationNumInputs.0 = INTEGER: 2 */ { "unmapped.atsCalibrationNumInputs", 0, 1, ".1.3.6.1.4.1.318.1.1.8.2.1.1.0", NULL, SU_FLAG_OK, NULL }, /* atsCalibrationNumInputPhases.0 = INTEGER: 1 */ { "unmapped.atsCalibrationNumInputPhases", 0, 1, ".1.3.6.1.4.1.318.1.1.8.2.1.2.0", NULL, SU_FLAG_OK, NULL }, /* atsCalibrationInputTableIndex.1.1.1 = INTEGER: 1 */ { "unmapped.atsCalibrationInputTableIndex", 0, 1, ".1.3.6.1.4.1.318.1.1.8.2.1.3.1.1.1.1.1", NULL, SU_FLAG_OK, NULL }, /* atsCalibrationInputTableIndex.2.1.1 = INTEGER: 2 */ { "unmapped.atsCalibrationInputTableIndex", 0, 1, ".1.3.6.1.4.1.318.1.1.8.2.1.3.1.1.2.1.1", NULL, SU_FLAG_OK, NULL }, /* atsCalibrationInputPhaseTableIndex.1.1.1 = INTEGER: 1 */ { "unmapped.atsCalibrationInputPhaseTableIndex", 0, 1, ".1.3.6.1.4.1.318.1.1.8.2.1.3.1.2.1.1.1", NULL, SU_FLAG_OK, NULL }, /* atsCalibrationInputPhaseTableIndex.2.1.1 = INTEGER: 1 */ { "unmapped.atsCalibrationInputPhaseTableIndex", 0, 1, ".1.3.6.1.4.1.318.1.1.8.2.1.3.1.2.2.1.1", NULL, SU_FLAG_OK, NULL }, /* atsLineVoltageCalibrationFactor.1.1.1 = INTEGER: 487 */ { "unmapped.atsLineVoltageCalibrationFactor", 0, 1, ".1.3.6.1.4.1.318.1.1.8.2.1.3.1.3.1.1.1", NULL, SU_FLAG_OK, NULL }, /* atsLineVoltageCalibrationFactor.2.1.1 = INTEGER: 488 */ { "unmapped.atsLineVoltageCalibrationFactor", 0, 1, ".1.3.6.1.4.1.318.1.1.8.2.1.3.1.3.2.1.1", NULL, SU_FLAG_OK, NULL }, /* atsCalibrationPowerSupplyVoltages.0 = INTEGER: 5 */ { "unmapped.atsCalibrationPowerSupplyVoltages", 0, 1, ".1.3.6.1.4.1.318.1.1.8.2.2.1.0", NULL, SU_FLAG_OK, NULL }, /* atsCalibrationPowerSupplyVoltageTableIndex.1 = INTEGER: 1 */ { "unmapped.atsCalibrationPowerSupplyVoltageTableIndex", 0, 1, ".1.3.6.1.4.1.318.1.1.8.2.2.2.1.1.1", NULL, SU_FLAG_OK, NULL }, /* atsCalibrationPowerSupplyVoltageTableIndex.2 = INTEGER: 2 */ { "unmapped.atsCalibrationPowerSupplyVoltageTableIndex", 0, 1, ".1.3.6.1.4.1.318.1.1.8.2.2.2.1.1.2", NULL, SU_FLAG_OK, NULL }, /* atsCalibrationPowerSupplyVoltageTableIndex.3 = INTEGER: 3 */ { "unmapped.atsCalibrationPowerSupplyVoltageTableIndex", 0, 1, ".1.3.6.1.4.1.318.1.1.8.2.2.2.1.1.3", NULL, SU_FLAG_OK, NULL }, /* atsCalibrationPowerSupplyVoltageTableIndex.4 = INTEGER: 4 */ { "unmapped.atsCalibrationPowerSupplyVoltageTableIndex", 0, 1, ".1.3.6.1.4.1.318.1.1.8.2.2.2.1.1.4", NULL, SU_FLAG_OK, NULL }, /* atsCalibrationPowerSupplyVoltageTableIndex.5 = INTEGER: 5 */ { "unmapped.atsCalibrationPowerSupplyVoltageTableIndex", 0, 1, ".1.3.6.1.4.1.318.1.1.8.2.2.2.1.1.5", NULL, SU_FLAG_OK, NULL }, /* atsCalibrationPowerSupplyVoltage.1 = INTEGER: powerSupply24V(1) */ { "unmapped.atsCalibrationPowerSupplyVoltage", 0, 1, ".1.3.6.1.4.1.318.1.1.8.2.2.2.1.2.1", NULL, SU_FLAG_OK, NULL }, /* atsCalibrationPowerSupplyVoltage.2 = INTEGER: powerSupply12V(2) */ { "unmapped.atsCalibrationPowerSupplyVoltage", 0, 1, ".1.3.6.1.4.1.318.1.1.8.2.2.2.1.2.2", NULL, SU_FLAG_OK, NULL }, /* atsCalibrationPowerSupplyVoltage.3 = INTEGER: powerSupply(3) */ { "unmapped.atsCalibrationPowerSupplyVoltage", 0, 1, ".1.3.6.1.4.1.318.1.1.8.2.2.2.1.2.3", NULL, SU_FLAG_OK, NULL }, /* atsCalibrationPowerSupplyVoltage.4 = INTEGER: powerSupply24VSourceB(4) */ { "unmapped.atsCalibrationPowerSupplyVoltage", 0, 1, ".1.3.6.1.4.1.318.1.1.8.2.2.2.1.2.4", NULL, SU_FLAG_OK, NULL }, /* atsCalibrationPowerSupplyVoltage.5 = INTEGER: powerSupplyMinus12V(5) */ { "unmapped.atsCalibrationPowerSupplyVoltage", 0, 1, ".1.3.6.1.4.1.318.1.1.8.2.2.2.1.2.5", NULL, SU_FLAG_OK, NULL }, /* atsPowerSupplyVoltageCalibrationFactor.1 = INTEGER: 521 */ { "unmapped.atsPowerSupplyVoltageCalibrationFactor", 0, 1, ".1.3.6.1.4.1.318.1.1.8.2.2.2.1.3.1", NULL, SU_FLAG_OK, NULL }, /* atsPowerSupplyVoltageCalibrationFactor.2 = INTEGER: 1076 */ { "unmapped.atsPowerSupplyVoltageCalibrationFactor", 0, 1, ".1.3.6.1.4.1.318.1.1.8.2.2.2.1.3.2", NULL, SU_FLAG_OK, NULL }, /* atsPowerSupplyVoltageCalibrationFactor.3 = INTEGER: 2560 */ { "unmapped.atsPowerSupplyVoltageCalibrationFactor", 0, 1, ".1.3.6.1.4.1.318.1.1.8.2.2.2.1.3.3", NULL, SU_FLAG_OK, NULL }, /* atsPowerSupplyVoltageCalibrationFactor.4 = INTEGER: 521 */ { "unmapped.atsPowerSupplyVoltageCalibrationFactor", 0, 1, ".1.3.6.1.4.1.318.1.1.8.2.2.2.1.3.4", NULL, SU_FLAG_OK, NULL }, /* atsPowerSupplyVoltageCalibrationFactor.5 = INTEGER: 975 */ { "unmapped.atsPowerSupplyVoltageCalibrationFactor", 0, 1, ".1.3.6.1.4.1.318.1.1.8.2.2.2.1.3.5", NULL, SU_FLAG_OK, NULL }, /* atsCalibrationNumOutputs.0 = INTEGER: 1 */ { "unmapped.atsCalibrationNumOutputs", 0, 1, ".1.3.6.1.4.1.318.1.1.8.2.3.1.0", NULL, SU_FLAG_OK, NULL }, /* atsCalibrationNumOutputPhases.0 = INTEGER: 1 */ { "unmapped.atsCalibrationNumOutputPhases", 0, 1, ".1.3.6.1.4.1.318.1.1.8.2.3.2.0", NULL, SU_FLAG_OK, NULL }, /* atsCalibrationOutputTableIndex.1.phase1.1 = INTEGER: 1 */ { "unmapped.atsCalibrationOutputTableIndex", 0, 1, ".1.3.6.1.4.1.318.1.1.8.2.3.3.1.1.1.1.1", NULL, SU_FLAG_OK, NULL }, /* atsCalibrationOutputPhasesTableIndex.1.phase1.1 = INTEGER: phase1(1) */ { "unmapped.atsCalibrationOutputPhasesTableIndex", 0, 1, ".1.3.6.1.4.1.318.1.1.8.2.3.3.1.2.1.1.1", NULL, SU_FLAG_OK, NULL }, /* atsOutputCurrentCalibrationFactor.1.phase1.1 = INTEGER: 487 */ { "unmapped.atsOutputCurrentCalibrationFactor", 0, 1, ".1.3.6.1.4.1.318.1.1.8.2.3.3.1.3.1.1.1", NULL, SU_FLAG_OK, NULL }, /* atsControlResetATS.0 = INTEGER: none(1) */ { "unmapped.atsControlResetATS", 0, 1, ".1.3.6.1.4.1.318.1.1.8.3.1.0", NULL, SU_FLAG_OK, NULL }, /* atsControlClearAllAlarms.0 = INTEGER: -1 */ { "unmapped.atsControlClearAllAlarms", 0, 1, ".1.3.6.1.4.1.318.1.1.8.3.2.0", NULL, SU_FLAG_OK, NULL }, /* atsConfigFrontPanelLockout.0 = INTEGER: enableFrontPanel(2) */ { "unmapped.atsConfigFrontPanelLockout", 0, 1, ".1.3.6.1.4.1.318.1.1.8.4.3.0", NULL, SU_FLAG_OK, NULL }, /* atsConfigTransferVoltageRange.0 = INTEGER: medium(2) */ { "unmapped.atsConfigTransferVoltageRange", 0, 1, ".1.3.6.1.4.1.318.1.1.8.4.5.0", NULL, SU_FLAG_OK, NULL }, /* atsConfigCurrentLimit.0 = INTEGER: 32 */ { "unmapped.atsConfigCurrentLimit", 0, 1, ".1.3.6.1.4.1.318.1.1.8.4.6.0", NULL, SU_FLAG_OK, NULL }, /* atsConfigResetValues.0 = INTEGER: -1 */ { "unmapped.atsConfigResetValues", 0, 1, ".1.3.6.1.4.1.318.1.1.8.4.7.0", NULL, SU_FLAG_OK, NULL }, /* atsConfigLineVRMS.0 = INTEGER: 230 */ { "unmapped.atsConfigLineVRMS", 0, 1, ".1.3.6.1.4.1.318.1.1.8.4.8.0", NULL, SU_FLAG_OK, NULL }, /* atsConfigLineVRMSNarrowLimit.0 = INTEGER: 16 */ { "unmapped.atsConfigLineVRMSNarrowLimit", 0, 1, ".1.3.6.1.4.1.318.1.1.8.4.9.0", NULL, SU_FLAG_OK, NULL }, /* atsConfigLineVRMSMediumLimit.0 = INTEGER: 23 */ { "unmapped.atsConfigLineVRMSMediumLimit", 0, 1, ".1.3.6.1.4.1.318.1.1.8.4.10.0", NULL, SU_FLAG_OK, NULL }, /* atsConfigLineVRMSWideLimit.0 = INTEGER: 30 */ { "unmapped.atsConfigLineVRMSWideLimit", 0, 1, ".1.3.6.1.4.1.318.1.1.8.4.11.0", NULL, SU_FLAG_OK, NULL }, /* atsConfigFrequencyDeviation.0 = INTEGER: two(2) */ { "unmapped.atsConfigFrequencyDeviation", 0, 1, ".1.3.6.1.4.1.318.1.1.8.4.12.0", NULL, SU_FLAG_OK, NULL }, /* Outlet groups collection */ /* atsConfigBankLowLoadThreshold.1 = INTEGER: 0 */ { "unmapped.atsConfigBankLowLoadThreshold", 0, 1, ".1.3.6.1.4.1.318.1.1.8.4.14.1.3.1", NULL, SU_FLAG_OK, NULL }, /* atsConfigBankLowLoadThreshold.2 = INTEGER: 0 */ { "unmapped.atsConfigBankLowLoadThreshold", 0, 1, ".1.3.6.1.4.1.318.1.1.8.4.14.1.3.2", NULL, SU_FLAG_OK, NULL }, /* atsConfigBankLowLoadThreshold.3 = INTEGER: 0 */ { "unmapped.atsConfigBankLowLoadThreshold", 0, 1, ".1.3.6.1.4.1.318.1.1.8.4.14.1.3.3", NULL, SU_FLAG_OK, NULL }, /* atsConfigBankNearOverLoadThreshold.1 = INTEGER: 28 */ { "unmapped.atsConfigBankNearOverLoadThreshold", 0, 1, ".1.3.6.1.4.1.318.1.1.8.4.14.1.4.1", NULL, SU_FLAG_OK, NULL }, /* atsConfigBankNearOverLoadThreshold.2 = INTEGER: 12 */ { "unmapped.atsConfigBankNearOverLoadThreshold", 0, 1, ".1.3.6.1.4.1.318.1.1.8.4.14.1.4.2", NULL, SU_FLAG_OK, NULL }, /* atsConfigBankNearOverLoadThreshold.3 = INTEGER: 12 */ { "unmapped.atsConfigBankNearOverLoadThreshold", 0, 1, ".1.3.6.1.4.1.318.1.1.8.4.14.1.4.3", NULL, SU_FLAG_OK, NULL }, /* atsConfigBankOverLoadThreshold.1 = INTEGER: 32 */ { "unmapped.atsConfigBankOverLoadThreshold", 0, 1, ".1.3.6.1.4.1.318.1.1.8.4.14.1.5.1", NULL, SU_FLAG_OK, NULL }, /* atsConfigBankOverLoadThreshold.2 = INTEGER: 16 */ { "unmapped.atsConfigBankOverLoadThreshold", 0, 1, ".1.3.6.1.4.1.318.1.1.8.4.14.1.5.2", NULL, SU_FLAG_OK, NULL }, /* atsConfigBankOverLoadThreshold.3 = INTEGER: 16 */ { "unmapped.atsConfigBankOverLoadThreshold", 0, 1, ".1.3.6.1.4.1.318.1.1.8.4.14.1.5.3", NULL, SU_FLAG_OK, NULL }, /* atsConfigPhaseTableSize.0 = INTEGER: 0 */ { "unmapped.atsConfigPhaseTableSize", 0, 1, ".1.3.6.1.4.1.318.1.1.8.4.15.0", NULL, SU_FLAG_OK, NULL }, /* atsStatusCommStatus.0 = INTEGER: atsCommEstablished(2) */ { "unmapped.atsStatusCommStatus", 0, 1, ".1.3.6.1.4.1.318.1.1.8.5.1.1.0", NULL, SU_FLAG_OK, NULL }, /* atsStatusRedundancyState.0 = INTEGER: atsFullyRedundant(2) */ { "unmapped.atsStatusRedundancyState", 0, 1, ".1.3.6.1.4.1.318.1.1.8.5.1.3.0", NULL, SU_FLAG_OK, NULL }, /* atsStatusOverCurrentState.0 = INTEGER: atsCurrentOK(2) */ { "unmapped.atsStatusOverCurrentState", 0, 1, ".1.3.6.1.4.1.318.1.1.8.5.1.4.0", NULL, SU_FLAG_OK, NULL }, /* atsStatus5VPowerSupply.0 = INTEGER: atsPowerSupplyOK(2) */ { "unmapped.atsStatus5VPowerSupply", 0, 1, ".1.3.6.1.4.1.318.1.1.8.5.1.5.0", NULL, SU_FLAG_OK, NULL }, /* atsStatus24VPowerSupply.0 = INTEGER: atsPowerSupplyOK(2) */ { "unmapped.atsStatus24VPowerSupply", 0, 1, ".1.3.6.1.4.1.318.1.1.8.5.1.6.0", NULL, SU_FLAG_OK, NULL }, /* atsStatus24VSourceBPowerSupply.0 = INTEGER: atsPowerSupplyOK(2) */ { "unmapped.atsStatus24VSourceBPowerSupply", 0, 1, ".1.3.6.1.4.1.318.1.1.8.5.1.7.0", NULL, SU_FLAG_OK, NULL }, /* atsStatusPlus12VPowerSupply.0 = INTEGER: atsPowerSupplyOK(2) */ { "unmapped.atsStatusPlus12VPowerSupply", 0, 1, ".1.3.6.1.4.1.318.1.1.8.5.1.8.0", NULL, SU_FLAG_OK, NULL }, /* atsStatusMinus12VPowerSupply.0 = INTEGER: atsPowerSupplyOK(2) */ { "unmapped.atsStatusMinus12VPowerSupply", 0, 1, ".1.3.6.1.4.1.318.1.1.8.5.1.9.0", NULL, SU_FLAG_OK, NULL }, /* atsStatusSwitchStatus.0 = INTEGER: ok(2) */ { "unmapped.atsStatusSwitchStatus", 0, 1, ".1.3.6.1.4.1.318.1.1.8.5.1.10.0", NULL, SU_FLAG_OK, NULL }, /* atsStatusFrontPanel.0 = INTEGER: unlocked(2) */ { "unmapped.atsStatusFrontPanel", 0, 1, ".1.3.6.1.4.1.318.1.1.8.5.1.11.0", NULL, SU_FLAG_OK, NULL }, /* atsStatusSourceAStatus.0 = INTEGER: ok(2) */ { "unmapped.atsStatusSourceAStatus", 0, 1, ".1.3.6.1.4.1.318.1.1.8.5.1.12.0", NULL, SU_FLAG_OK, NULL }, /* atsStatusSourceBStatus.0 = INTEGER: ok(2) */ { "unmapped.atsStatusSourceBStatus", 0, 1, ".1.3.6.1.4.1.318.1.1.8.5.1.13.0", NULL, SU_FLAG_OK, NULL }, /* atsStatusPhaseSyncStatus.0 = INTEGER: inSync(1) */ { "unmapped.atsStatusPhaseSyncStatus", 0, 1, ".1.3.6.1.4.1.318.1.1.8.5.1.14.0", NULL, SU_FLAG_OK, NULL }, /* atsStatusHardwareStatus.0 = INTEGER: ok(2) */ { "unmapped.atsStatusHardwareStatus", 0, 1, ".1.3.6.1.4.1.318.1.1.8.5.1.16.0", NULL, SU_FLAG_OK, NULL }, /* atsStatusResetMaxMinValues.0 = INTEGER: -1 */ { "unmapped.atsStatusResetMaxMinValues", 0, 1, ".1.3.6.1.4.1.318.1.1.8.5.2.1.0", NULL, SU_FLAG_OK, NULL }, /* atsInputTableIndex.1 = INTEGER: 1 */ { "unmapped.atsInputTableIndex", 0, 1, ".1.3.6.1.4.1.318.1.1.8.5.3.2.1.1.1", NULL, SU_FLAG_OK, NULL }, /* atsInputTableIndex.2 = INTEGER: 2 */ { "unmapped.atsInputTableIndex", 0, 1, ".1.3.6.1.4.1.318.1.1.8.5.3.2.1.1.2", NULL, SU_FLAG_OK, NULL }, /* atsNumInputPhases.1 = INTEGER: 1 */ { "unmapped.atsNumInputPhases", 0, 1, ".1.3.6.1.4.1.318.1.1.8.5.3.2.1.2.1", NULL, SU_FLAG_OK, NULL }, /* atsNumInputPhases.2 = INTEGER: 1 */ { "unmapped.atsNumInputPhases", 0, 1, ".1.3.6.1.4.1.318.1.1.8.5.3.2.1.2.2", NULL, SU_FLAG_OK, NULL }, /* atsInputVoltageOrientation.1 = INTEGER: singlePhase(2) */ { "unmapped.atsInputVoltageOrientation", 0, 1, ".1.3.6.1.4.1.318.1.1.8.5.3.2.1.3.1", NULL, SU_FLAG_OK, NULL }, /* atsInputVoltageOrientation.2 = INTEGER: singlePhase(2) */ { "unmapped.atsInputVoltageOrientation", 0, 1, ".1.3.6.1.4.1.318.1.1.8.5.3.2.1.3.2", NULL, SU_FLAG_OK, NULL }, /* atsInputType.1 = INTEGER: main(2) */ { "unmapped.atsInputType", 0, 1, ".1.3.6.1.4.1.318.1.1.8.5.3.2.1.5.1", NULL, SU_FLAG_OK, NULL }, /* atsInputType.2 = INTEGER: main(2) */ { "unmapped.atsInputType", 0, 1, ".1.3.6.1.4.1.318.1.1.8.5.3.2.1.5.2", NULL, SU_FLAG_OK, NULL }, /* atsInputName.1 = STRING: "Source A" */ { "unmapped.atsInputName", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.318.1.1.8.5.3.2.1.6.1", NULL, SU_FLAG_OK, NULL }, /* atsInputName.2 = STRING: "Source B" */ { "unmapped.atsInputName", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.318.1.1.8.5.3.2.1.6.2", NULL, SU_FLAG_OK, NULL }, /* atsInputPhaseTableIndex.1.1.1 = INTEGER: 1 */ { "unmapped.atsInputPhaseTableIndex", 0, 1, ".1.3.6.1.4.1.318.1.1.8.5.3.3.1.1.1.1.1", NULL, SU_FLAG_OK, NULL }, /* atsInputPhaseTableIndex.2.1.1 = INTEGER: 2 */ { "unmapped.atsInputPhaseTableIndex", 0, 1, ".1.3.6.1.4.1.318.1.1.8.5.3.3.1.1.2.1.1", NULL, SU_FLAG_OK, NULL }, /* atsInputPhaseIndex.1.1.1 = INTEGER: 1 */ { "unmapped.atsInputPhaseIndex", 0, 1, ".1.3.6.1.4.1.318.1.1.8.5.3.3.1.2.1.1.1", NULL, SU_FLAG_OK, NULL }, /* atsInputPhaseIndex.2.1.1 = INTEGER: 1 */ { "unmapped.atsInputPhaseIndex", 0, 1, ".1.3.6.1.4.1.318.1.1.8.5.3.3.1.2.2.1.1", NULL, SU_FLAG_OK, NULL }, /* atsInputMaxVoltage.1.1.1 = INTEGER: -1 */ { "unmapped.atsInputMaxVoltage", 0, 1, ".1.3.6.1.4.1.318.1.1.8.5.3.3.1.4.1.1.1", NULL, SU_FLAG_OK, NULL }, /* atsInputMaxVoltage.2.1.1 = INTEGER: -1 */ { "unmapped.atsInputMaxVoltage", 0, 1, ".1.3.6.1.4.1.318.1.1.8.5.3.3.1.4.2.1.1", NULL, SU_FLAG_OK, NULL }, /* atsInputMinVoltage.1.1.1 = INTEGER: -1 */ { "unmapped.atsInputMinVoltage", 0, 1, ".1.3.6.1.4.1.318.1.1.8.5.3.3.1.5.1.1.1", NULL, SU_FLAG_OK, NULL }, /* atsInputMinVoltage.2.1.1 = INTEGER: -1 */ { "unmapped.atsInputMinVoltage", 0, 1, ".1.3.6.1.4.1.318.1.1.8.5.3.3.1.5.2.1.1", NULL, SU_FLAG_OK, NULL }, /* atsInputCurrent.1.1.1 = INTEGER: -1 */ { "unmapped.atsInputCurrent", 0, 1, ".1.3.6.1.4.1.318.1.1.8.5.3.3.1.6.1.1.1", NULL, SU_FLAG_OK, NULL }, /* atsInputCurrent.2.1.1 = INTEGER: -1 */ { "unmapped.atsInputCurrent", 0, 1, ".1.3.6.1.4.1.318.1.1.8.5.3.3.1.6.2.1.1", NULL, SU_FLAG_OK, NULL }, /* atsInputMaxCurrent.1.1.1 = INTEGER: -1 */ { "unmapped.atsInputMaxCurrent", 0, 1, ".1.3.6.1.4.1.318.1.1.8.5.3.3.1.7.1.1.1", NULL, SU_FLAG_OK, NULL }, /* atsInputMaxCurrent.2.1.1 = INTEGER: -1 */ { "unmapped.atsInputMaxCurrent", 0, 1, ".1.3.6.1.4.1.318.1.1.8.5.3.3.1.7.2.1.1", NULL, SU_FLAG_OK, NULL }, /* atsInputMinCurrent.1.1.1 = INTEGER: -1 */ { "unmapped.atsInputMinCurrent", 0, 1, ".1.3.6.1.4.1.318.1.1.8.5.3.3.1.8.1.1.1", NULL, SU_FLAG_OK, NULL }, /* atsInputMinCurrent.2.1.1 = INTEGER: -1 */ { "unmapped.atsInputMinCurrent", 0, 1, ".1.3.6.1.4.1.318.1.1.8.5.3.3.1.8.2.1.1", NULL, SU_FLAG_OK, NULL }, /* atsInputPower.1.1.1 = INTEGER: -1 */ { "unmapped.atsInputPower", 0, 1, ".1.3.6.1.4.1.318.1.1.8.5.3.3.1.9.1.1.1", NULL, SU_FLAG_OK, NULL }, /* atsInputPower.2.1.1 = INTEGER: -1 */ { "unmapped.atsInputPower", 0, 1, ".1.3.6.1.4.1.318.1.1.8.5.3.3.1.9.2.1.1", NULL, SU_FLAG_OK, NULL }, /* atsInputMaxPower.1.1.1 = INTEGER: -1 */ { "unmapped.atsInputMaxPower", 0, 1, ".1.3.6.1.4.1.318.1.1.8.5.3.3.1.10.1.1.1", NULL, SU_FLAG_OK, NULL }, /* atsInputMaxPower.2.1.1 = INTEGER: -1 */ { "unmapped.atsInputMaxPower", 0, 1, ".1.3.6.1.4.1.318.1.1.8.5.3.3.1.10.2.1.1", NULL, SU_FLAG_OK, NULL }, /* atsInputMinPower.1.1.1 = INTEGER: -1 */ { "unmapped.atsInputMinPower", 0, 1, ".1.3.6.1.4.1.318.1.1.8.5.3.3.1.11.1.1.1", NULL, SU_FLAG_OK, NULL }, /* atsInputMinPower.2.1.1 = INTEGER: -1 */ { "unmapped.atsInputMinPower", 0, 1, ".1.3.6.1.4.1.318.1.1.8.5.3.3.1.11.2.1.1", NULL, SU_FLAG_OK, NULL }, /* atsNumOutputs.0 = INTEGER: 1 */ { "unmapped.atsNumOutputs", 0, 1, ".1.3.6.1.4.1.318.1.1.8.5.4.1.0", NULL, SU_FLAG_OK, NULL }, /* atsOutputTableIndex.1 = INTEGER: 1 */ { "unmapped.atsOutputTableIndex", 0, 1, ".1.3.6.1.4.1.318.1.1.8.5.4.2.1.1.1", NULL, SU_FLAG_OK, NULL }, /* atsNumOutputPhases.1 = INTEGER: 1 */ { "unmapped.atsNumOutputPhases", 0, 1, ".1.3.6.1.4.1.318.1.1.8.5.4.2.1.2.1", NULL, SU_FLAG_OK, NULL }, /* atsOutputVoltageOrientation.1 = INTEGER: singlePhase(2) */ { "unmapped.atsOutputVoltageOrientation", 0, 1, ".1.3.6.1.4.1.318.1.1.8.5.4.2.1.3.1", NULL, SU_FLAG_OK, NULL }, /* atsOutputPhase.1 = INTEGER: phase1(1) */ { "unmapped.atsOutputPhase", 0, 1, ".1.3.6.1.4.1.318.1.1.8.5.4.5.1.2.1", NULL, SU_FLAG_OK, NULL }, /* atsOutputPhase.2 = INTEGER: phase1(1) */ { "unmapped.atsOutputPhase", 0, 1, ".1.3.6.1.4.1.318.1.1.8.5.4.5.1.2.2", NULL, SU_FLAG_OK, NULL }, /* atsOutputPhase.3 = INTEGER: phase1(1) */ { "unmapped.atsOutputPhase", 0, 1, ".1.3.6.1.4.1.318.1.1.8.5.4.5.1.2.3", NULL, SU_FLAG_OK, NULL }, /* atsOutputBankMaxCurrent.1 = INTEGER: -1 */ { "unmapped.atsOutputBankMaxCurrent", 0, 1, ".1.3.6.1.4.1.318.1.1.8.5.4.5.1.7.1", NULL, SU_FLAG_OK, NULL }, /* atsOutputBankMaxCurrent.2 = INTEGER: -1 */ { "unmapped.atsOutputBankMaxCurrent", 0, 1, ".1.3.6.1.4.1.318.1.1.8.5.4.5.1.7.2", NULL, SU_FLAG_OK, NULL }, /* atsOutputBankMaxCurrent.3 = INTEGER: -1 */ { "unmapped.atsOutputBankMaxCurrent", 0, 1, ".1.3.6.1.4.1.318.1.1.8.5.4.5.1.7.3", NULL, SU_FLAG_OK, NULL }, /* atsOutputBankMinCurrent.1 = INTEGER: -1 */ { "unmapped.atsOutputBankMinCurrent", 0, 1, ".1.3.6.1.4.1.318.1.1.8.5.4.5.1.8.1", NULL, SU_FLAG_OK, NULL }, /* atsOutputBankMinCurrent.2 = INTEGER: -1 */ { "unmapped.atsOutputBankMinCurrent", 0, 1, ".1.3.6.1.4.1.318.1.1.8.5.4.5.1.8.2", NULL, SU_FLAG_OK, NULL }, /* atsOutputBankMinCurrent.3 = INTEGER: -1 */ { "unmapped.atsOutputBankMinCurrent", 0, 1, ".1.3.6.1.4.1.318.1.1.8.5.4.5.1.8.3", NULL, SU_FLAG_OK, NULL }, /* atsOutputBankLoad.1 = INTEGER: 1883 */ { "unmapped.atsOutputBankLoad", 0, 1, ".1.3.6.1.4.1.318.1.1.8.5.4.5.1.9.1", NULL, SU_FLAG_OK, NULL }, /* atsOutputBankLoad.2 = INTEGER: 984 */ { "unmapped.atsOutputBankLoad", 0, 1, ".1.3.6.1.4.1.318.1.1.8.5.4.5.1.9.2", NULL, SU_FLAG_OK, NULL }, /* atsOutputBankLoad.3 = INTEGER: 898 */ { "unmapped.atsOutputBankLoad", 0, 1, ".1.3.6.1.4.1.318.1.1.8.5.4.5.1.9.3", NULL, SU_FLAG_OK, NULL }, /* atsOutputBankMaxLoad.1 = INTEGER: -1 */ { "unmapped.atsOutputBankMaxLoad", 0, 1, ".1.3.6.1.4.1.318.1.1.8.5.4.5.1.10.1", NULL, SU_FLAG_OK, NULL }, /* atsOutputBankMaxLoad.2 = INTEGER: -1 */ { "unmapped.atsOutputBankMaxLoad", 0, 1, ".1.3.6.1.4.1.318.1.1.8.5.4.5.1.10.2", NULL, SU_FLAG_OK, NULL }, /* atsOutputBankMaxLoad.3 = INTEGER: -1 */ { "unmapped.atsOutputBankMaxLoad", 0, 1, ".1.3.6.1.4.1.318.1.1.8.5.4.5.1.10.3", NULL, SU_FLAG_OK, NULL }, /* atsOutputBankMinLoad.1 = INTEGER: -1 */ { "unmapped.atsOutputBankMinLoad", 0, 1, ".1.3.6.1.4.1.318.1.1.8.5.4.5.1.11.1", NULL, SU_FLAG_OK, NULL }, /* atsOutputBankMinLoad.2 = INTEGER: -1 */ { "unmapped.atsOutputBankMinLoad", 0, 1, ".1.3.6.1.4.1.318.1.1.8.5.4.5.1.11.2", NULL, SU_FLAG_OK, NULL }, /* atsOutputBankMinLoad.3 = INTEGER: -1 */ { "unmapped.atsOutputBankMinLoad", 0, 1, ".1.3.6.1.4.1.318.1.1.8.5.4.5.1.11.3", NULL, SU_FLAG_OK, NULL }, /* atsOutputBankPercentLoad.1 = INTEGER: 25 */ { "unmapped.atsOutputBankPercentLoad", 0, 1, ".1.3.6.1.4.1.318.1.1.8.5.4.5.1.12.1", NULL, SU_FLAG_OK, NULL }, /* atsOutputBankPercentLoad.2 = INTEGER: 13 */ { "unmapped.atsOutputBankPercentLoad", 0, 1, ".1.3.6.1.4.1.318.1.1.8.5.4.5.1.12.2", NULL, SU_FLAG_OK, NULL }, /* atsOutputBankPercentLoad.3 = INTEGER: 12 */ { "unmapped.atsOutputBankPercentLoad", 0, 1, ".1.3.6.1.4.1.318.1.1.8.5.4.5.1.12.3", NULL, SU_FLAG_OK, NULL }, /* atsOutputBankMaxPercentLoad.1 = INTEGER: -1 */ { "unmapped.atsOutputBankMaxPercentLoad", 0, 1, ".1.3.6.1.4.1.318.1.1.8.5.4.5.1.13.1", NULL, SU_FLAG_OK, NULL }, /* atsOutputBankMaxPercentLoad.2 = INTEGER: -1 */ { "unmapped.atsOutputBankMaxPercentLoad", 0, 1, ".1.3.6.1.4.1.318.1.1.8.5.4.5.1.13.2", NULL, SU_FLAG_OK, NULL }, /* atsOutputBankMaxPercentLoad.3 = INTEGER: -1 */ { "unmapped.atsOutputBankMaxPercentLoad", 0, 1, ".1.3.6.1.4.1.318.1.1.8.5.4.5.1.13.3", NULL, SU_FLAG_OK, NULL }, /* atsOutputBankMinPercentLoad.1 = INTEGER: -1 */ { "unmapped.atsOutputBankMinPercentLoad", 0, 1, ".1.3.6.1.4.1.318.1.1.8.5.4.5.1.14.1", NULL, SU_FLAG_OK, NULL }, /* atsOutputBankMinPercentLoad.2 = INTEGER: -1 */ { "unmapped.atsOutputBankMinPercentLoad", 0, 1, ".1.3.6.1.4.1.318.1.1.8.5.4.5.1.14.2", NULL, SU_FLAG_OK, NULL }, /* atsOutputBankMinPercentLoad.3 = INTEGER: -1 */ { "unmapped.atsOutputBankMinPercentLoad", 0, 1, ".1.3.6.1.4.1.318.1.1.8.5.4.5.1.14.3", NULL, SU_FLAG_OK, NULL }, /* atsOutputBankMaxPower.1 = INTEGER: -1 */ { "unmapped.atsOutputBankMaxPower", 0, 1, ".1.3.6.1.4.1.318.1.1.8.5.4.5.1.16.1", NULL, SU_FLAG_OK, NULL }, /* atsOutputBankMaxPower.2 = INTEGER: -1 */ { "unmapped.atsOutputBankMaxPower", 0, 1, ".1.3.6.1.4.1.318.1.1.8.5.4.5.1.16.2", NULL, SU_FLAG_OK, NULL }, /* atsOutputBankMaxPower.3 = INTEGER: -1 */ { "unmapped.atsOutputBankMaxPower", 0, 1, ".1.3.6.1.4.1.318.1.1.8.5.4.5.1.16.3", NULL, SU_FLAG_OK, NULL }, /* atsOutputBankMinPower.1 = INTEGER: -1 */ { "unmapped.atsOutputBankMinPower", 0, 1, ".1.3.6.1.4.1.318.1.1.8.5.4.5.1.17.1", NULL, SU_FLAG_OK, NULL }, /* atsOutputBankMinPower.2 = INTEGER: -1 */ { "unmapped.atsOutputBankMinPower", 0, 1, ".1.3.6.1.4.1.318.1.1.8.5.4.5.1.17.2", NULL, SU_FLAG_OK, NULL }, /* atsOutputBankMinPower.3 = INTEGER: -1 */ { "unmapped.atsOutputBankMinPower", 0, 1, ".1.3.6.1.4.1.318.1.1.8.5.4.5.1.17.3", NULL, SU_FLAG_OK, NULL }, /* atsOutputBankPercentPower.1 = INTEGER: 25 */ { "unmapped.atsOutputBankPercentPower", 0, 1, ".1.3.6.1.4.1.318.1.1.8.5.4.5.1.18.1", NULL, SU_FLAG_OK, NULL }, /* atsOutputBankPercentPower.2 = INTEGER: 13 */ { "unmapped.atsOutputBankPercentPower", 0, 1, ".1.3.6.1.4.1.318.1.1.8.5.4.5.1.18.2", NULL, SU_FLAG_OK, NULL }, /* atsOutputBankPercentPower.3 = INTEGER: 12 */ { "unmapped.atsOutputBankPercentPower", 0, 1, ".1.3.6.1.4.1.318.1.1.8.5.4.5.1.18.3", NULL, SU_FLAG_OK, NULL }, /* atsOutputBankMaxPercentPower.1 = INTEGER: -1 */ { "unmapped.atsOutputBankMaxPercentPower", 0, 1, ".1.3.6.1.4.1.318.1.1.8.5.4.5.1.19.1", NULL, SU_FLAG_OK, NULL }, /* atsOutputBankMaxPercentPower.2 = INTEGER: -1 */ { "unmapped.atsOutputBankMaxPercentPower", 0, 1, ".1.3.6.1.4.1.318.1.1.8.5.4.5.1.19.2", NULL, SU_FLAG_OK, NULL }, /* atsOutputBankMaxPercentPower.3 = INTEGER: -1 */ { "unmapped.atsOutputBankMaxPercentPower", 0, 1, ".1.3.6.1.4.1.318.1.1.8.5.4.5.1.19.3", NULL, SU_FLAG_OK, NULL }, /* atsOutputBankMinPercentPower.1 = INTEGER: -1 */ { "unmapped.atsOutputBankMinPercentPower", 0, 1, ".1.3.6.1.4.1.318.1.1.8.5.4.5.1.20.1", NULL, SU_FLAG_OK, NULL }, /* atsOutputBankMinPercentPower.2 = INTEGER: -1 */ { "unmapped.atsOutputBankMinPercentPower", 0, 1, ".1.3.6.1.4.1.318.1.1.8.5.4.5.1.20.2", NULL, SU_FLAG_OK, NULL }, /* atsOutputBankMinPercentPower.3 = INTEGER: -1 */ { "unmapped.atsOutputBankMinPercentPower", 0, 1, ".1.3.6.1.4.1.318.1.1.8.5.4.5.1.20.3", NULL, SU_FLAG_OK, NULL }, #endif /* if WITH_UNMAPPED_DATA_POINTS */ /* end of structure. */ { NULL, 0, 0, NULL, NULL, 0, NULL } }; mib2nut_info_t apc_ats = { "apc_ats", APC_ATS_MIB_VERSION, NULL, APC_ATS_OID_MODEL_NAME, apc_ats_mib, APC_ATS_SYSOID, NULL }; nut-2.8.1/drivers/snmp-ups.h0000644000175000017500000004156714501607135012701 00000000000000/* snmp-ups.h - NUT Meta SNMP driver (support different MIBS) * * Based on NET-SNMP API (Simple Network Management Protocol V1-2) * * Copyright (C) * 2002-2010 Arnaud Quette * 2015-2021 Eaton (author: Arnaud Quette ) * 2016-2021 Eaton (author: Jim Klimov ) * 2002-2006 Dmitry Frolov * J.W. Hoogervorst * Niels Baggesen * * Sponsored by Eaton * and originally by MGE UPS SYSTEMS * * 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 2 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, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /* TODO list: - complete shutdown - add enum values to OIDs. - optimize network flow by: 1) caching OID values (as in usbhid-ups) with timestamping and lifetime 2) constructing one big packet (calling snmp_add_null_var for each OID request we made), instead of sending many small packets - add support for registration and traps (manager mode) => Issue: 1 trap listener for N snmp-ups drivers! - complete mib2nut data (add all OID translation to NUT) - externalize mib2nut data in .m2n files and load at driver startup using parseconf()... - adjust information logging. - move numeric OIDs into th mib2nut tables and remove defines - move mib2nut into c files (à la usbhid-ups)? - add a claim function and move to usbhid-ups style for specific processing - rework the flagging system */ #ifndef SNMP_UPS_H #define SNMP_UPS_H #include "nut_stdint.h" /* uint32_t */ /* FIXME: still needed? * workaround for buggy Net-SNMP config */ #ifdef PACKAGE_BUGREPORT #undef PACKAGE_BUGREPORT #endif #ifdef PACKAGE_NAME #undef PACKAGE_NAME #endif #ifdef PACKAGE_VERSION #undef PACKAGE_VERSION #endif #ifdef PACKAGE_STRING #undef PACKAGE_STRING #endif #ifdef PACKAGE_TARNAME #undef PACKAGE_TARNAME #endif #ifdef HAVE_DMALLOC_H #undef HAVE_DMALLOC_H #endif #ifdef WIN32 # ifdef random # undef random # endif # ifdef _WIN32_WINNT # undef _WIN32_WINNT # endif #endif #include #include #ifndef ONE_SEC /* This macro name disappeared from net-snmp sources and headers * after v5.9 tag, and was replaced by explicit expression below: */ # define ONE_SEC (1000L * 1000L) #endif /* Force numeric OIDs by disabling MIB loading */ #ifdef DISABLE_MIB_LOADING # undef DISABLE_MIB_LOADING #endif #define DISABLE_MIB_LOADING 1 /* Parameters default values */ #define DEFAULT_POLLFREQ 30 /* in seconds */ #define DEFAULT_NETSNMP_RETRIES 5 #define DEFAULT_NETSNMP_TIMEOUT 1 /* in seconds */ #define DEFAULT_SEMISTATICFREQ 10 /* in snmpwalk update cycles */ /* use explicit booleans */ #ifndef FALSE typedef enum ebool { FALSE, TRUE } bool_t; #else typedef int bool_t; #endif /* Common SNMP data and lookup definitions */ /* special functions to interpret items: take UPS answer, return string to set in INFO, max len NOTE: FFE means For Future Extensions */ /* typedef void (*interpreter)(char *, char *, int); */ #ifndef WITH_SNMP_LKP_FUN /* Recent addition of fun/nuf hooks in info_lkp_t is not well handled by * all corners of the codebase, e.g. not by DMF. So at least until that * is fixed, (TODO) we enable those bits of code only optionally during * a build for particular usage. Conversely, experimenters can define * this macro to a specific value while building the codebase and see * what happens under different conditions ;) */ # if (defined WITH_DMFMIB) && (WITH_DMFMIB != 0) # define WITH_SNMP_LKP_FUN 0 # else # define WITH_SNMP_LKP_FUN 1 # endif #endif #ifndef WITH_SNMP_LKP_FUN_DUMMY # define WITH_SNMP_LKP_FUN_DUMMY 0 #endif /* for lookup between OID values and INFO_ value */ typedef struct { int oid_value; /* SNMP OID value */ const char *info_value; /* NUT INFO_* value */ #if WITH_SNMP_LKP_FUN /* FIXME: Currently we do not have a way to provide custom C code * via DMF - keep old approach until we get the ability, e.g. by * requiring a LUA implementation to be passed alongside C lookups. */ /* * Currently there are a few cases using a "fun_vp2s" type of lookup * function, while the "nuf_s2l" type was added for completeness but * is not really handled and does not have real consumers in the * existing NUT codebase (static mib2nut tables in *-mib.c files). * Related to su_find_infoval() (long* => string), su_find_valinfo() * (string => long) and su_find_strval() (char* => string) routines * defined below. */ const char *(*fun_vp2s)(void *snmp_value); /* optional SNMP to NUT mapping function, converting a pointer to SNMP data (e.g. numeric or string) into a NUT string */ long (*nuf_s2l)(const char *nut_value); /* optional NUT to SNMP mapping function, converting a NUT string into SNMP numeric data */ #endif /* WITH_SNMP_LKP_FUN */ } info_lkp_t; /* Structure containing info about one item that can be requested from UPS and set in INFO. If no interpreter functions is defined, use sprintf with given format string. If unit is not NONE, values are converted according to the multiplier table */ typedef uint32_t snmp_info_flags_t; /* To extend when 32 bits become too congested */ #define PRI_SU_FLAGS PRIu32 typedef struct { char *info_type; /* INFO_ or CMD_ element */ int info_flags; /* flags to set in addinfo: see ST_FLAG_* * defined in include/extstate.h */ double info_len; /* length of strings if ST_FLAG_STRING, * multiplier otherwise. */ char *OID; /* SNMP OID or NULL */ char *dfl; /* default value */ snmp_info_flags_t flags; /* snmp-ups internal flags: see SU_* bit-shifts * defined below (SU_FLAG*, SU_TYPE*, SU_STATUS* * and others for outlets, phases, daisy-chains, * etc.) * NOTE that some *-mib.c mappings can specify * a zero in this field... better fix that in * favor of explicit values with a meaning! * Current code treats such zero values as * "OK if avail, otherwise discarded". * NOTE: With C99+ a "long" is guaranteed to be * at least 4 bytes; consider "unsigned long long" * when/if we get more than 32 flag values. */ info_lkp_t *oid2info; /* lookup table between OID and NUT values */ } snmp_info_t; /* "flags" bits 0..9 */ #define SU_FLAG_OK (1UL << 0) /* show element to upsd - * internal to snmp driver */ #define SU_FLAG_STATIC (1UL << 1) /* retrieve info only once. */ #define SU_FLAG_ABSENT (1UL << 2) /* data is absent in the device, * use default value. */ #define SU_FLAG_STALE (1UL << 3) /* data stale, don't try too often - * internal to snmp driver */ #define SU_FLAG_NEGINVALID (1UL << 4) /* Invalid if negative value */ #define SU_FLAG_UNIQUE (1UL << 5) /* There can be only be one * provider of this info, * disable the other providers */ /* Note: older releases defined the following flag, but removed it by 2.7.5: * #define SU_FLAG_SETINT (1UL << 6)*/ /* save value */ #define SU_FLAG_ZEROINVALID (1UL << 6) /* Invalid if "0" value */ #define SU_FLAG_NAINVALID (1UL << 7) /* Invalid if "N/A" value */ #define SU_CMD_OFFSET (1UL << 8) /* Add +1 to the OID index */ #define SU_FLAG_SEMI_STATIC (1UL << 9) /* Refresh this entry once in several walks * (for R/W values user can set on device, * like descriptions or contacts) */ /* Notes on outlet templates usage: * - outlet.count MUST exist and MUST be declared before any outlet template * Otherwise, the driver will try to determine it by itself... * - the first outlet template MUST NOT be a server side variable (ie MUST have * a valid OID) in order to detect the base SNMP index (0 or 1) */ /* "flags" bit 10 */ #define SU_OUTLET_GROUP (1UL << 10) /* outlet group template definition */ #define SU_OUTLET (1UL << 11) /* outlet template definition */ /* Phase specific data */ /* "flags" bits 12..17 */ #define SU_PHASES (0x0000003F << 12) #define SU_INPHASES (0x00000003 << 12) #define SU_INPUT_1 (1UL << 12) /* only if 1 input phase */ #define SU_INPUT_3 (1UL << 13) /* only if 3 input phases */ #define SU_OUTPHASES (0x00000003 << 14) #define SU_OUTPUT_1 (1UL << 14) /* only if 1 output phase */ #define SU_OUTPUT_3 (1UL << 15) /* only if 3 output phases */ #define SU_BYPPHASES (0x00000003 << 16) #define SU_BYPASS_1 (1UL << 16) /* only if 1 bypass phase */ #define SU_BYPASS_3 (1UL << 17) /* only if 3 bypass phases */ /* FIXME: use input.phases and output.phases to replace this */ /* hints for su_ups_set, applicable only to rw vars */ /* "flags" bits 18..20 */ #define SU_TYPE_INT (1UL << 18) /* cast to int when setting value */ #define SU_TYPE_TIME (1UL << 19) /* cast to int */ #define SU_TYPE_CMD (1UL << 20) /* instant command */ /* The following helper macro is used like: * if (SU_TYPE(su_info_p) == SU_TYPE_CMD) { ... } */ #define SU_TYPE(t) ((t)->flags & (7UL << 18)) /* Daisychain template definition */ /* the following 2 flags specify the position of the daisychain device index * in the formatting string. This is useful when considering daisychain with * templates, such as outlets / outlets groups, which already have a format * string specifier */ /* "flags" bits 21..23 (and 24 reserved for DMF) */ #define SU_TYPE_DAISY_1 (1UL << 21) /* Daisychain index is the 1st %i specifier in a template with more than one */ #define SU_TYPE_DAISY_2 (1UL << 22) /* Daisychain index is the 2nd %i specifier in a template with more than one */ #define SU_TYPE_DAISY(t) ((t)->flags & (11UL << 21)) /* Mask the SU_TYPE_DAISY_{1,2,MASTER_ONLY} but not SU_DAISY */ #define SU_DAISY (1UL << 23) /* Daisychain template definition - set at run-time for devices with detected "device.count" over 1 */ /* NOTE: Previously SU_DAISY had same bit-flag value as SU_TYPE_DAISY_2 */ #define SU_TYPE_DAISY_MASTER_ONLY (1UL << 24) /* Only valid for daisychain master (device.1) */ /* Free slot: (1UL << 25) */ #define SU_AMBIENT_TEMPLATE (1UL << 26) /* ambient template definition */ /* Reserved slot -- to import from DMF branch codebase: //#define SU_FLAG_FUNCTION (1UL << 27) */ /* status string components * FIXME: these should be removed, since there is no added value. * Ie, this can be guessed from info->type! */ /* "flags" bits 28..31 */ #define SU_STATUS_PWR (1UL << 28) /* indicates power status element */ #define SU_STATUS_BATT (1UL << 29) /* indicates battery status element */ #define SU_STATUS_CAL (1UL << 30) /* indicates calibration status element */ #define SU_STATUS_RB (1UL << 31) /* indicates replace battery status element */ #define SU_STATUS_NUM_ELEM 4 /* Obsolete? No references found in codebase */ #define SU_STATUS_INDEX(t) (((unsigned long)(t) >> 28) & 15UL) /* Despite similar names, definitons below are not among the bit-flags ;) */ #define SU_VAR_COMMUNITY "community" #define SU_VAR_VERSION "snmp_version" #define SU_VAR_RETRIES "snmp_retries" #define SU_VAR_TIMEOUT "snmp_timeout" #define SU_VAR_SEMISTATICFREQ "semistaticfreq" #define SU_VAR_MIBS "mibs" #define SU_VAR_POLLFREQ "pollfreq" /* SNMP v3 related parameters */ #define SU_VAR_SECLEVEL "secLevel" #define SU_VAR_SECNAME "secName" #define SU_VAR_AUTHPASSWD "authPassword" #define SU_VAR_PRIVPASSWD "privPassword" #define SU_VAR_AUTHPROT "authProtocol" #define SU_VAR_PRIVPROT "privProtocol" #define SU_VAR_ONDELAY "ondelay" #define SU_VAR_OFFDELAY "offdelay" #define SU_INFOSIZE 128 #define SU_BUFSIZE 32 #define SU_LARGEBUF 256 #define SU_STALE_RETRY 10 /* retry to retrieve stale element */ /* after this number of iterations. */ /* FIXME: this is for *all* elements */ /* modes to snmp_ups_walk. */ #define SU_WALKMODE_INIT 0 #define SU_WALKMODE_UPDATE 1 /* modes for su_setOID */ #define SU_MODE_INSTCMD 1 #define SU_MODE_SETVAR 2 /* log spew limiters */ #define SU_ERR_LIMIT 10 /* start limiting after this many errors in a row */ #define SU_ERR_RATE 100 /* only print every nth error once limiting starts */ typedef struct { const char * OID; const char *status_value; /* when not NULL, set ups.status to this */ const char *alarm_value; /* when not NULL, set ups.alarm to this */ } alarms_info_t; typedef struct { const char *mib_name; const char *mib_version; const char *oid_pwr_status; const char *oid_auto_check; /* FIXME: rename to SysOID */ snmp_info_t *snmp_info; /* pointer to the good Snmp2Nut lookup data */ const char *sysOID; /* OID to match against sysOID, aka MIB * main entry point */ alarms_info_t *alarms_info; } mib2nut_info_t; /* Common SNMP functions */ void nut_snmp_init(const char *type, const char *hostname); void nut_snmp_cleanup(void); struct snmp_pdu *nut_snmp_get(const char *OID); bool_t nut_snmp_get_str(const char *OID, char *buf, size_t buf_len, info_lkp_t *oid2info); bool_t nut_snmp_get_oid(const char *OID, char *buf, size_t buf_len); bool_t nut_snmp_get_int(const char *OID, long *pval); bool_t nut_snmp_set(const char *OID, char type, const char *value); bool_t nut_snmp_set_str(const char *OID, const char *value); bool_t nut_snmp_set_int(const char *OID, long value); bool_t nut_snmp_set_time(const char *OID, long value); void nut_snmp_perror(struct snmp_session *sess, int status, struct snmp_pdu *response, const char *fmt, ...) __attribute__ ((__format__ (__printf__, 4, 5))); void su_startup(void); void su_cleanup(void); void su_init_instcmds(void); void su_setuphandlers(void); /* need to deal with external function ptr */ void su_setinfo(snmp_info_t *su_info_p, const char *value); void su_status_set(snmp_info_t *, long value); void su_alarm_set(snmp_info_t *, long value); snmp_info_t *su_find_info(const char *type); bool_t snmp_ups_walk(int mode); bool_t su_ups_get(snmp_info_t *su_info_p); bool_t load_mib2nut(const char *mib); /* Practical logic around lookup functions, see fun_vp2s and nuf_s2l * fields in struct info_lkp_t */ const char *su_find_infoval(info_lkp_t *oid2info, void *value); long su_find_valinfo(info_lkp_t *oid2info, const char* value); const char *su_find_strval(info_lkp_t *oid2info, void *value); /***************************************************** * Common conversion structs and functions provided by snmp-ups-helpers.c * so they can be used and so "shared" by different subdrivers *****************************************************/ const char *su_usdate_to_isodate_info_fun(void *raw_date); extern info_lkp_t su_convert_to_iso_date_info[]; /* Name the mapping location in that array for consumers to reference */ #define FUNMAP_USDATE_TO_ISODATE 0 /* Process temperature value according to 'temperature_unit' */ const char *su_temperature_read_fun(void *raw_snmp_value); /* Temperature handling, to convert back to Celsius (NUT standard) */ extern int temperature_unit; #define TEMPERATURE_UNKNOWN 0 #define TEMPERATURE_CELSIUS 1 #define TEMPERATURE_KELVIN 2 #define TEMPERATURE_FAHRENHEIT 3 /***************************************************** * End of Subdrivers shared helpers functions *****************************************************/ int su_setvar(const char *varname, const char *val); int su_instcmd(const char *cmdname, const char *extradata); void su_shutdown_ups(void); void set_delays(void); void read_mibconf(char *mib); extern struct snmp_session g_snmp_sess, *g_snmp_sess_p; extern const char *OID_pwr_status; extern int g_pwr_battery; extern int pollfreq; /* polling frequency */ extern int input_phases, output_phases, bypass_phases; extern int semistaticfreq; /* semistatic entry update frequency */ /* pointer to the Snmp2Nut lookup table */ extern mib2nut_info_t *mib2nut_info; /* FIXME: to be trashed */ extern snmp_info_t *snmp_info; extern alarms_info_t *alarms_info; /* Common daisychain structure and functions */ bool_t daisychain_init(void); int su_addcmd(snmp_info_t *su_info_p); /* Structure containing info about each daisychain device, including phases * for input, output and bypass */ typedef struct { long input_phases; long output_phases; long bypass_phases; } daisychain_info_t; #endif /* SNMP_UPS_H */ nut-2.8.1/drivers/genericups.h0000644000175000017500000002340014500336654013251 00000000000000/* genericups.h - contact closure UPS line status definitions Copyright (C) 1999, 2000 Russell Kroll 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 2 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, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef NUT_GENERICUPS_H_SEEN #define NUT_GENERICUPS_H_SEEN 1 static struct { const char *mfr; /* value for INFO_MFR */ const char *model; /* value for INFO_MODEL */ const char *desc; /* used in -h listing */ int line_norm; int line_ol, val_ol; int line_bl, val_bl; int line_rb, val_rb; int line_bypass, val_bypass; int line_sd; } upstab[] = { /* Type 0 */ { "UPSONIC", "LAN Saver 600", "UPSONIC LAN Saver 600", TIOCM_DTR | TIOCM_RTS, /* cable power: DTR + RTS */ TIOCM_CTS, 0, /* online: CTS off */ TIOCM_CD, TIOCM_CD, /* low battery: CD on */ 0, 0, /* replace battery: none */ 0, 0, /* battery bypass: none */ TIOCM_RTS /* shutdown: RTS */ }, /* Type 1 */ { "APC", "Back-UPS", "APC Back-UPS (940-0095A/C cable)", TIOCM_DTR, /* cable power: DTR */ TIOCM_RNG, 0, /* online: RNG off */ TIOCM_CD, TIOCM_CD, /* low battery: CD on */ 0, 0, /* replace battery: none */ 0, 0, /* battery bypass: none */ TIOCM_RTS /* shutdown: RTS */ }, /* Type 2 */ { "APC", "Back-UPS", "APC Back-UPS (940-0020B/C cable)", TIOCM_RTS, /* cable power: RTS */ TIOCM_CTS, 0, /* online: CTS off */ TIOCM_CD, TIOCM_CD, /* low battery: CD on */ 0, 0, /* replace battery: none */ 0, 0, /* battery bypass: none */ TIOCM_DTR|TIOCM_RTS /* shutdown: DTR + RTS */ }, /* Type 3 */ { "PowerTech", "Comp1000", "PowerTech Comp1000 with DTR as cable power", TIOCM_DTR, /* cable power: DTR */ TIOCM_CTS, 0, /* online: CTS off */ TIOCM_CD, TIOCM_CD, /* low battery: CD on */ 0, 0, /* replace battery: none */ 0, 0, /* battery bypass: none */ TIOCM_DTR | TIOCM_RTS /* shutdown: DTR + RTS */ }, /* Type 4 */ { "Generic", "Generic RUPS model", "Generic RUPS model", TIOCM_RTS, /* cable power: RTS */ TIOCM_CTS, TIOCM_CTS, /* online: CTS on */ TIOCM_CD, 0, /* low battery: CD off */ 0, 0, /* replace battery: none */ 0, 0, /* battery bypass: none */ 0 /* shutdown: none */ }, /* Type 5 */ { "TrippLite", "Internet Office Series", "Tripp Lite UPS with Lan2.2 interface (black 73-0844 cable)", TIOCM_DTR, /* cable power: DTR */ TIOCM_CTS, TIOCM_CTS, /* online: CTS on */ TIOCM_CD, 0, /* low battery: CD off */ 0, 0, /* replace battery: none */ 0, 0, /* battery bypass: none */ TIOCM_DTR | TIOCM_RTS /* shutdown: DTR + RTS */ }, /* Type 6 */ { "Best", "Patriot", "Best Patriot (INT51 cable)", TIOCM_DTR, /* cable power: DTR */ TIOCM_CTS, TIOCM_CTS, /* online: CTS on */ TIOCM_CD, 0, /* low battery: CD off */ 0, 0, /* replace battery: none */ 0, 0, /* battery bypass: none */ TIOCM_RTS /* shutdown: set RTS */ }, /* Type 7 */ { "CyberPower", "Power99", "CyberPower Power99", TIOCM_RTS, /* cable power: RTS */ TIOCM_CTS, TIOCM_CTS, /* online: CTS on */ TIOCM_CD, 0, /* low battery: CD off */ 0, 0, /* replace battery: none */ 0, 0, /* battery bypass: none */ TIOCM_DTR /* shutdown: set DTR */ }, /* Type 8 */ { "Nitram", "Elite UPS", "Nitram Elite 500", TIOCM_DTR, /* cable power: DTR */ TIOCM_CTS, TIOCM_CTS, /* online: CTS on */ TIOCM_CD, 0, /* low battery: CD off */ 0, 0, /* replace battery: none */ 0, 0, /* battery bypass: none */ -1 /* shutdown: unknown */ }, /* Type 9 */ { "APC", "Back-UPS", "APC Back-UPS (940-0023A cable)", 0, /* cable power: none */ TIOCM_CD, 0, /* online: CD off */ TIOCM_CTS, TIOCM_CTS, /* low battery: CTS on */ 0, 0, /* replace battery: none */ 0, 0, /* battery bypass: none */ TIOCM_RTS /* shutdown: RTS */ }, /* Type 10 (duplicate from 7) */ { "Victron", "Lite", "Victron Lite (crack cable)", TIOCM_RTS, /* cable power: RTS */ TIOCM_CTS, TIOCM_CTS, /* online: CTS on */ TIOCM_CD, 0, /* low battery: CD off */ 0, 0, /* replace battery: none */ 0, 0, /* battery bypass: none */ TIOCM_DTR /* shutdown: DTR */ }, /* Type 11 */ { "Powerware", "3115", "Powerware 3115", TIOCM_DTR, /* cable power: DTR */ TIOCM_CTS, 0, /* online: CTS off */ TIOCM_CD, 0, /* low battery: CD off */ 0, 0, /* replace battery: none */ 0, 0, /* battery bypass: none */ TIOCM_ST /* shutdown: ST */ }, /* Type 12 */ { "APC", "Back-UPS Office", "APC Back-UPS Office (940-0119A cable)", TIOCM_RTS, /* cable power: RTS */ TIOCM_CTS, 0, /* online: CTS off */ TIOCM_CD, TIOCM_CD, /* low battery: CD on */ 0, 0, /* replace battery: none */ 0, 0, /* battery bypass: none */ TIOCM_DTR /* shutdown: raise DTR */ }, /* Type 13 */ { "RPT", "Repoteck", "Repoteck RPT-800A, RPT-162A", TIOCM_DTR | TIOCM_RTS, /* cable power: DTR + RTS */ TIOCM_CD, TIOCM_CD, /* On-line : DCD on */ TIOCM_CTS, 0, /* Battery low: CTS off */ 0, 0, /* replace battery: none */ 0, 0, /* battery bypass: none */ TIOCM_ST /* shutdown: TX BREA */ }, /* Type 14 */ { "Online", "P250, P500, P750, P1250", "Online P-series", TIOCM_DTR, /* cable power: DTR */ TIOCM_CD, TIOCM_CD, /* online: CD on */ TIOCM_CTS, 0, /* low battery: CTS off */ 0, 0, /* replace battery: none */ 0, 0, /* battery bypass: none */ TIOCM_RTS /* shutdown: raise RTS */ }, /* Type 15 */ { "Powerware", "5119", "Powerware 5119", TIOCM_DTR, /* cable power: DTR */ TIOCM_CTS, TIOCM_CTS, /* online: CTS on */ TIOCM_CD, 0, /* low battery: CD off */ 0, 0, /* replace battery: none */ 0, 0, /* battery bypass: none */ TIOCM_ST /* shutdown: ST (break) */ }, /* Type 16 */ { "Nitram", "Elite UPS", "Nitram Elite 2002", TIOCM_DTR | TIOCM_RTS, /* cable power: DTR + RTS */ TIOCM_CTS, TIOCM_CTS, /* online: CTS on */ TIOCM_CD, 0, /* low battery: CD off */ 0, 0, /* replace battery: none */ 0, 0, /* battery bypass: none */ -1 /* shutdown: unknown */ }, /* Type 17 (duplicate from 8) */ { "PowerKinetics", "9001", "PowerKinetics 9001", TIOCM_DTR, /* cable power: DTR */ TIOCM_CTS, TIOCM_CTS, /* online: CTS on */ TIOCM_CD, 0, /* low battery: CD off */ 0, 0, /* replace battery: none */ 0, 0, /* battery bypass: none */ -1 /* shutdown: unknown */ }, /* Type 18 */ { "TrippLite", "Omni 450LAN", "TrippLite UPS with Martin's cabling", TIOCM_DTR, /* cable power: DTR */ TIOCM_CTS, TIOCM_CTS, /* online: CTS on */ TIOCM_CD, TIOCM_CD, /* low battery: CAR on */ 0, 0, /* replace battery: none */ 0, 0, /* battery bypass: none */ -1 /* shutdown: none */ }, /* Type 19 (duplicate from 6) */ { "Fideltronik", "Ares Series", "Fideltronik Ares Series", TIOCM_DTR, /* cable power: DTR */ TIOCM_CTS, TIOCM_CTS, /* online: CTS on */ TIOCM_CD, 0, /* low battery: DCD off */ 0, 0, /* replace battery: none */ 0, 0, /* battery bypass: none */ TIOCM_RTS /* shutdown: set RTS */ }, /* Type 20 */ /* docs/cables/powerware.txt */ { "Powerware", "5119 RM", "Powerware 5119 RM", TIOCM_DTR, /* cable power: DTR */ TIOCM_CTS, 0, /* online: CTS off */ TIOCM_CD, TIOCM_CD, /* low battery: CD on */ 0, 0, /* replace battery: none */ 0, 0, /* battery bypass: none */ TIOCM_ST /* shutdown: ST (break) */ }, /* Type 21 */ /* http://lists.exploits.org/upsdev/Oct2004/00004.html */ { "Generic", "Generic RUPS 2000", "Generic RUPS 2000 (Megatec M2501 cable)", TIOCM_RTS, /* cable power: RTS */ TIOCM_CTS, TIOCM_CTS, /* online: CTS on */ TIOCM_CD, 0, /* low battery: CD off */ 0, 0, /* replace battery: none */ 0, 0, /* battery bypass: none */ TIOCM_RTS | TIOCM_DTR /* shutdown: RTS+DTR */ }, /* Type 22 (duplicate from 7)*/ { "Gamatronic Electronic Industries", "Generic Alarm UPS", "Gamatronic UPSs with alarm interface", TIOCM_RTS, /* cable power: RTS */ TIOCM_CTS, TIOCM_CTS, /* online: CTS on */ TIOCM_CD, 0, /* low battery: CD off */ 0, 0, /* replace battery: none */ 0, 0, /* battery bypass: none */ TIOCM_DTR /* shutdown: DTR */ }, /* Type 23 */ { "Generic", "Generic FTTx Battery Backup", "FTTx (Fiber to the x) battery backup with 4-wire telemetry interface", TIOCM_RTS, /* cable power: RTS */ TIOCM_CTS, TIOCM_CTS, /* online: CTS on */ TIOCM_CD, 0, /* low battery: CD off */ TIOCM_RI, 0, /* replace battery: RI off */ TIOCM_DSR, 0, /* battery bypass: DSR off */ 0 /* shutdown: none */ }, /* add any new entries directly above this line */ { NULL, NULL, NULL, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } }; #endif /* NUT_GENERICUPS_H_SEEN */ nut-2.8.1/drivers/microdowell.h0000644000175000017500000004461314500336654013436 00000000000000#ifndef MICRODOWELL_H #define MICRODOWELL_H #ifdef ENTERPRISE_PROTOCOL #include #include "nut_stdint.h" #define STX_CHAR '[' #define ERR_COM_NO_CHARS -999 /* nessun carattere dalla porta seriale */ #define ERR_MSG_TOO_SHORT -998 /* messaggio troppo breve: non arriva sino al Checksum */ #define ERR_MSG_CHECKSUM -997 /* checksum non valido */ #define ERR_COM_TIMEOUT -996 /* timeout in lettura */ #define ERR_CLR_RX_BUFF -900 /* bisogna cancellare il buffer (non è un errore!) */ #define COMMAND_NOT_VALID -50 /* comando non valido */ #define PARAMETER_NOT_VALID -51 /* parametro non valido */ #define ERR_UPS_NOT_FOUND -10 /* non trovo un UPS */ #define ERR_COM_PORT_OPEN -11 /* impossibile aprire la porta di comunicazione */ #define ERR_COM_SET_PORT -12 /* impossibile configurare la porta di comunicazione */ #define ERR_COM_UNDEF_PORT -20 /* porta non valida o non esistente */ #define ERR_USB_DRIVER -13 /* impossibile aprire il driver USB */ #define ERR_USB_COMM_KO -14 /* interfaccia USB OK: gruppo spento o guasto */ #define ERR_UPS_UNKNOWN -30 /* impossibile identificare l'UPS */ #define ERR_PRG_THREAD -40 /* impossibile creare uno thread */ #define ERR_PRG_INVALID_DATA -60 /* dati non validi */ #define ERR_NO_ERROR 0x00 /* no errors */ #define ERR_I2C_BUSY 0x01 /* I2C bus busy (e2prom) */ #define ERR_CMD_CHECKSUM 0x10 /* Checksum not valid */ #define ERR_CMD_UNRECOG 0x11 /* unrecognized command */ #define ERR_EEP_NOBLOCK 0x08 /* WRITE: eeprom address not multiple of 8 */ #define ERR_EEP_OOBOUND 0x09 /* READ: eeprom address out of bound (with size) */ #define ERR_EEP_WADDR1 0x28 /* error writing e2prom address */ #define ERR_EEP_WSADDR1 0x29 /* error writing e2prom subaddress */ #define ERR_EEP_RDATA 0x2A /* error reading e2prom data */ #define ERR_EEP_WADDR2 0x50 /* error writing e2prom address */ #define ERR_EEP_WSADDR2 0x51 /* error reading e2prom subaddress */ #define ERR_EEP_WDATA 0x52 /* error writing e2prom data */ #define ERR_EEP_WADDRVER 0x53 /* error writing e2prom address during data verification */ #define ERR_EEP_WDATAVER 0x54 /* error verification e2prom data */ #define ERR_EEP_VERIFY 0x55 /* e2prom data are different from those in the write buffer */ #define ERR_EEP_CHECKSUM 0x90 /* e2prom checksum error */ #define CMD_ACK 0x06 /* ACK */ #define CMD_NACK 0x15 /* NACK */ #define CMD_GET_STATUS 0x00 /* comando di acquisizione STATUS */ #define CMD_GET_MEASURES 0x01 /* comando di acquisizione MISURE */ #define CMD_GET_CONFIG 0x02 /* comando di acquisizione CONFIGURAZIONE */ #define CMD_GET_BATT_STAT 0x03 /* comando di acquisizione Battery+Load Status */ #define CMD_GET_BAT_LD 0x03 /* comando di acquisizione Battery+Load Status */ #define CMD_GET_MASK 0x07 /* comando di acquisizione MASCHERA PUNTI */ #define CMD_SET_TIMER 0x20 /* comando di CONFIGURAZIONE TIMER */ #define CMD_BATT_TEST 0x21 /* comando di CONFIGURAZIONE TEST BATTERIA */ #define CMD_GET_BATT_TEST 0x22 /* comando di LETTURA TEST BATTERIA */ #define CMD_SD_ONESHOT 0x40 /* comando di SCRITTURA SHUTDOWN ONESHOT */ #define CMD_GET_SD_ONESHOT 0x41 /* comando di LETTURA SHUTDOWN ONESHOT */ #define CMD_SET_SCHEDULE 0x42 /* comando di SCRITTURA SCHEDULE */ #define CMD_GET_SCHEDULE 0x43 /* comando di LETTURA SCHEDULE */ #define CMD_GET_EEP_BLOCK 0x50 /* comando di LETTURA BLOCCO EEPROM */ #define CMD_SET_EEP_BLOCK 0x51 /* comando di SCRITTURA BLOCCO EEPROM */ #define CMD_GET_EEP_SEED 0x52 /* comando di acquisizione SEME PROGR. EEPROM */ #define CMD_INIT 0xF0 /* comando di REINIZIALIZZAZIONE UPS */ #define LEN_ACK 1 /* ACK */ #define LEN_NACK 2 /* NACK */ #define LEN_GET_STATUS 1 /* comando di acquisizione STATUS */ #define LEN_GET_MEASURES 1 /* comando di acquisizione MISURE */ #define LEN_GET_CONFIG 1 /* comando di acquisizione CONFIGURAZIONE */ #define LEN_GET_BATT_STAT 1 /* comando di acquisizione Battery+Load Status */ #define LEN_GET_BAT_LD 1 /* comando di acquisizione Battery+Load Status */ #define LEN_GET_MASK 1 /* comando di acquisizione MASCHERA PUNTI */ #define LEN_SET_TIMER 5 /* comando di CONFIGURAZIONE TIMER */ #define LEN_BATT_TEST 4 /* comando di CONFIGURAZIONE TEST BATTERIA */ #define LEN_GET_BATT_TEST 1 /* comando di LETTURA TEST BATTERIA */ #define LEN_SD_ONESHOT 8 /* comando di SCRITTURA SHUTDOWN ONESHOT */ #define LEN_GET_SD_ONESHOT 1 /* comando di LETTURA SHUTDOWN ONESHOT */ #define LEN_SET_SCHEDULE 8 /* comando di SCRITTURA SCHEDULE */ #define LEN_GET_SCHEDULE 2 /* comando di LETTURA SCHEDULE */ #define LEN_GET_EEP_BLOCK 3 /* comando di SCRITTURA BLOCCO EEPROM */ #define LEN_SET_EEP_BLOCK 12 /* comando di SCRITTURA BLOCCO EEPROM */ #define LEN_GET_EEP_SEED 1 /* comando di acquisizione SEME PROGR. EEPROM */ #define LEN_INIT 1 /* comando di REINIZIALIZZAZIONE UPS */ /* non completamente definiti! */ #define RET_GET_STATUS 10 /* comando di acquisizione STATUS */ #define RET_GET_MEASURES 15 /* comando di acquisizione MISURE */ #define RET_GET_CONFIG 11 /* comando di acquisizione CONFIGURAZIONE */ #define RET_GET_BATT_STAT 10 /* comando di acquisizione Battery+Load Status */ #define RET_GET_BAT_LD 10 /* comando di acquisizione Battery+Load Status */ #define RET_GET_MASK 1 /* comando di acquisizione MASCHERA PUNTI */ #define RET_SET_TIMER 5 /* comando di CONFIGURAZIONE TIMER */ #define RET_BATT_TEST 4 /* comando di CONFIGURAZIONE TEST BATTERIA */ #define RET_GET_BATT_TEST 1 /* comando di LETTURA TEST BATTERIA */ #define RET_SD_ONESHOT 8 /* comando di SCRITTURA SHUTDOWN ONESHOT */ #define RET_GET_SD_ONESHOT 1 /* comando di LETTURA SHUTDOWN ONESHOT */ #define RET_SET_SCHEDULE 8 /* comando di SCRITTURA SCHEDULE */ #define RET_GET_SCHEDULE 8 /* comando di LETTURA SCHEDULE */ #define RET_GET_EEP_BLOCK 11 /* comando di SCRITTURA BLOCCO EEPROM */ #define RET_SET_EEP_BLOCK 12 /* comando di SCRITTURA BLOCCO EEPROM */ #define RET_GET_EEP_SEED 1 /* comando di acquisizione SEME PROGR. EEPROM */ #define RET_INIT 1 /* comando di REINIZIALIZZAZIONE UPS */ /* ======================================================= */ /* Indirizzi delle variabili memorizzate nella EEPROM: // */ /* ======================================================= */ #define EEP_OPT_BYTE_BLK 0x00 /* Option Bytes block */ #define EEP_MAGIC 0x00 /* magic number: deve essere a 0xAA */ #define EEP_CHECKSUM 0x01 /* XOR longitudinale da 0x?? a 0x?? */ #define EEP_OUT_CONFIG 0x02 /* vedi documentazione */ #define EEP_OPT_BYTE_0 0x02 /* vedi documentazione */ #define EEP_OPT_BYTE_1 0x03 /* vedi documentazione */ #define EEP_STATUS 0x04 /* Status UPS */ #define EEP_THRESHOLD_0 0x08 /* Blocco 0 con gli threshold */ #define EEP_MEAN_MIN 0x08 /* UPS minimum AC voltage intervention point */ #define EEP_MEAN_MAX 0x0A /* UPS maximum AC voltage intervention point */ #define EEP_AVR_MIN 0x0C /* AVR minimum AC voltage intervention point */ #define EEP_AVR_MAX 0x0E /* AVR maximum AC voltage intervention point */ #define EEP_THRESHOLD_1 0x10 /* Blocco 1 con gli threshold */ #define EEP_BLOW_VALUE 0x10 /* Battery LOW threshold voltage */ #define EEP_BEND_VALUE 0x12 /* Battery END threshold voltage */ #define EEP_VMETER_0 0x14 /* Led 0 Voltage indicator threshold */ #define EEP_VMETER_1 0x16 /* Led 1 Voltage indicator threshold */ #define EEP_THRESHOLD_2 0x18 /* Blocco 2 con gli threshold */ #define EEP_VMETER_2 0x18 /* Led 2 Voltage indicator threshold */ #define EEP_VMETER_3 0x1A /* Led 3 Voltage indicator threshold */ #define EEP_VMETER_4 0x1C /* Led 4 Voltage indicator threshold */ #define EEP_FAULT_POINTS 0x20 /* number of fault points (in an half sine wave) after which USP enter battery mode */ #define EEP_CHARGER_MIN 0x21 /* Threshold voltage for battery charger */ #define EEP_TEMP_MAX 0x28 /* Maximum temperature: over this value an alarm will be generated */ #define EEP_TEMP_FAULT 0x2A /* Fault temperature: over this value, UPS will shut down immediately */ #define EEP_FANSPEED_0 0x2C /* Temperature for fan activation (low speed) */ #define EEP_FANSPEED_1 0x2E /* Temperature for fan activation (medium speed) */ #define EEP_FANSPEED_2 0x30 /* Temperature for fan activation (high speed) */ #define EEP_IOUT 0x38 /* */ #define EEP_IOUT_OVRLD 0x38 /* Maximum current: over this value an alarm will be generated */ #define EEP_IOUT_FAULT 0x3A /* Fault current: over this value, UPS will shut down immediately */ #define EEP_PWRMTR_0 0x3C /* Led 0 Power indicator threshold */ #define EEP_PWRMTR_1 0x3E /* Led 1 Power indicator threshold */ #define EEP_PWRMTR_2 0x40 /* Led 2 Power indicator threshold */ #define EEP_PWRMTR_3 0x42 /* Led 3 Power indicator threshold */ #define EEP_PWRMTR_4 0x44 /* Led 4 Power indicator threshold */ #define EEP_PWRMTR_5 0x46 /* Between "Full power" and "Overload" Power indicator level */ #define EEP_INPUT_MASK_0 0x48 /* Half sine input mask (0-7 of 10 points) */ #define EEP_INPUT_MASK_8 0x50 /* Half sine input mask (8-9 of 10 points) */ #define EEP_MIN_VBATT 0x60 /* Minimum battery voltaged reached from the last power-on */ #define EEP_RUNTIME_H 0x62 /* Working time in minutes (max ~=32 years) (MSB first) */ #define EEP_BAT_TIME_M 0x65 /* Time in Battery mode: seconds*2 (max ~=390 days). (MSB first) */ #define EEP_UPS_MODEL 0x80 /* Model of the UPS in ASCII. For the Enterprise line, the structure is: */ /* ENTxxyyy */ /* where: xx = Power rating in watts/100 (zero padded at left) */ /* yyy = model variants (if not defined, space padded to the right) */ #define EEP_NETWRK_ID 0x88 /* Network ID in ASCII (not used) - space padded */ #define EEP_NETWRK_NAME 0x90 /* Network Name in ASCII (not used) - space padded */ #define EEP_SERIAL_NUM 0x98 /* Serial Number in ASCII - zero padded (at left) */ #define EEP_PROD_DATE 0xA0 /* */ #define EEP_PROD_YEAR 0xA0 /* Year of production (add 2000) */ #define EEP_PROD_WEEK 0xA1 /* Week of production [0-51] */ #define EEP_PROD_HW_VER 0xA2 /* Hardware version: 2 nibbles ? Major and Minor number. */ #define EEP_PROD_BRD_VER 0xA3 /* Board version: 2 nibbles ? Major and Minor number. */ #define EEP_PROD_FW_VER 0xA4 /* Firmware version: 2 nibbles ? Major and Minor number. */ #define EEP_PROD_FW_SVER 0xA5 /* Firmware SUBversion: 2 nibbles ? Major and Minor number. */ #define EEP_PROD_BTTRS 0xA6 /* number of batteries installed in the UPS */ #define EEP_BATT_SUBST 0xA8 /* battery replacement block */ #define EEP_BATT_YEAR_0 0xA8 /* Year of 1st battery replacement (add 2000) */ #define EEP_BATT_WEEK_0 0xA9 /* Week of 1st battery replacement */ #define EEP_BATT_YEAR_1 0xAA /* Year of 2nd battery replacement (add 2000) */ #define EEP_BATT_WEEK_1 0xAB /* Week of 2nd battery replacement */ #define EEP_BATT_YEAR_2 0xAC /* Year of 3rd battery replacement (add 2000) */ #define EEP_BATT_WEEK_2 0xAD /* Week of 3rd battery replacement */ #define EEP_BATT_YEAR_3 0xAE /* Year of 4th battery replacement (add 2000) */ #define EEP_BATT_WEEK_3 0xAF /* Week of 4th battery replacement */ #define EEP_SCHEDULE 0xC8 /* Start of SCHEDULING table */ #define EEP_SCHEDULE_0 0xC8 /* 1st Scheduling slot */ #define EEP_SCHEDULE_1 0xD0 /* 2nd Scheduling slot */ #define EEP_SCHEDULE_2 0xD8 /* 3rd Scheduling slot */ #define EEP_SCHEDULE_3 0xE0 /* 4th Scheduling slot */ #define EEP_SCHEDULE_4 0xE8 /* 5th Scheduling slot */ #define EEP_SCHEDULE_5 0xF0 /* 6th Scheduling slot */ #define BIT_NO_COMM_UPS 0x0001 /* Event 2 - communications with the UPS lost */ #define BIT_COMM_OK 0x0002 /* Event 3 - communications with the UPS reestablished */ #define BIT_BATTERY_MODE 0x0004 /* Event 5 - the UPS is in Battery mode */ #define BIT_BATTERY_LOW 0x0008 /* Event 6 - the UPS has a LOW battery level */ #define BIT_MAINS_OK 0x0010 /* Event 7 - return of the mains */ #define BIT_OVERLOAD 0x0020 /* Event 8 - the UPS is overloaded */ #define BIT_HIGH_TEMPERATURE 0x0040 /* Event 9 - the UPS is in overtemperature */ #define BIT_GENERIC_FAULT 0x0080 /* Event 11 - there is a generic fault */ #define BIT_SYSTEM_SHUTDOWN 0x0100 /* Event 14 - the UPS will shut down IMMEDIATELY */ #define BIT_STANDBY 0x0200 /* Event 32 - the UPS went in STANDBY MODE */ #define BIT_BATTERY_END 0x0400 /* Event 33 - the UPS went in battery END */ #define BIT_EVENT_0 0x1000 /* evento ?? */ #define BIT_EVENT_1 0x2000 /* evento ?? */ #define BIT_FIRST_TIME 0x4000 /* se è la prima volta che chiamo la funzione */ #define BIT_POLL_RESTART 0x8000 /* se riesco ad identificare l'UPS dopo lo scollegamento, reinvio i dati */ typedef struct { int Port ; /* porta a cui è collegato l' UPS: */ /* 0 = USB */ /* n = COMn */ char Opened ; /* BOOL flag che identifica se la porta è aperta */ int ErrCode ; /* ultimo codice di errore in fase di lettura */ int ErrCount ; /* conteggio degli errori */ unsigned char PollFlag ; /* identifica se posso accedere all'UPS */ /* 0x01: se TRUE, polling abilitato */ /* 0x02: se TRUE, la routine di polling dati è attiva: devo attendere */ /* 0x04: se TRUE, bisogna rileggere la configurazione del gruppo */ /* ------------------------------------------------------------------------ */ unsigned long Counter ; /* contatore: viene incrementato ad ogni nuovo POLL */ unsigned char CommStatus ; /* stato delle comunicazioni */ /* unsigned char FramePointer ; */ size_t FramePointer ; /* puntatore al carattere di START dei dati ricevuti */ /* ------------------------------------------------------------------------ */ char UpsModel[9] ; /* modello UPS (8 caratteri) */ unsigned char ge_2kVA ; /* if more or equal to 2KVA */ char SerialNumber[9] ; /* numero di serie dell'UPS */ unsigned short int YearOfProd ; /* anno di produzione dell'UPS */ unsigned char MonthOfProd ; /* Mese di produzione dell'UPS */ unsigned char DayOfProd ; /* Giorno di produzione dell'UPS */ unsigned char HW_MajorVersion ; /* Hardware: Major version */ unsigned char HW_MinorVersion ; /* Hardware: Minor version */ unsigned char BR_MajorVersion ; /* BoardHardware: Major version */ unsigned char BR_MinorVersion ; /* BoardHardware: Minor version */ unsigned char FW_MajorVersion ; /* Firmware: Major version */ unsigned char FW_MinorVersion ; /* Firmware: Minor version */ unsigned char FW_SubVersion ; /* Firmware: SUBVERSION (special releases */ /* for particular customers) */ unsigned char BatteryNumber ; /* number of batteries in UPS */ /* ------------------------------------------------------------------------ */ uint32_t StatusUPS ; /* flag di stato dell'UPS 4 byte): 1=TRUE */ /* bit 0 => BATTERY_MODE */ /* bit 1 => BATTERY_LOW */ /* bit 2 => BATTERY_END */ /* bit 3 => ONLINE (funzionamento in rete) */ /* bit 4 => MAINS_ON (rete di ingresso presente) */ /* bit 5 => STANDBY (UPS in modo Standby) */ /* bit 6 => WAIT_MAINS (UPS in fase di INIT + attesa rete) */ /* bit 7 => INIT (UPS in fase di inizializzazione) */ /* ------ */ /* bit 8 => MASK_OK (semionda OK) */ /* bit 9 => MEAN_OK (media tensione di ingresso OK) */ /* bit 10 => SYNC_OK (sincronizzazione semionda OK) */ /* bit 11 => FAULT (generico) */ /* bit 12 => TEMP_MAX (superato livello critico di temperatura) */ /* bit 13 => TEMP_FAULT (Fault da temperatura: UPS si spegne) */ /* bit 14 => LOAD_MAX (soglia overload superata) */ /* bit 15 => LOAD_FAULT (Fault da carico: UPS si spegne) */ /* ------ */ /* bit 16 => INV_FAULT (Fault dell'inverter) */ /* bit 17 => IINV_MAX (eccessiva corrente sull'inverter) */ /* bit 18 => IINV_FAULT (Fault sulla corrente inverter: l'UPS si spegne) */ /* bit 19 => 50_60Hz (1=60Hz) */ /* bit 20 => EEP_FAULT (problemi con la EEPROM) */ /* bit 21 => VOUT_FAULT (tensione uscita troppo bassa) */ /* bit 22 => - non definito - */ /* bit 23 => - non definito - */ /* ------ */ /* bit 24 to 31 => - NON DEFINITI - */ uint16_t ShortStatus ; /* the LSB 2 bytes of the status */ unsigned char OutConfig ; /* stato uscite UPS */ float Vinput ; /* tensione di INPUT in 1/10 di Volt */ float Voutput ; /* tensione di OUTPUT in 1/10 di Volt */ float Temp ; /* temperatura in 1/10 di grado */ float InpFreq ; /* Frequenza di INPUT in 1/10 di Hz */ float OutFreq ; /* Frequenza di OUTPUT in 1/10 di Hz */ float OutCurrent ; /* Corrente di Output in 1/10 di A */ unsigned char LoadPerc ; /* Percentuale di carico */ unsigned short int LoadVA ; /* Carico in VA */ float ChgCurrent ; /* corrente carica batterie */ float Vbatt ; /* tensione delle batterie in 1/10 di Volt */ unsigned char PercBatt ; /* percentuale di carica della batteria */ unsigned short int RtimeEmpty; /* minuti alla scarica della batteria */ unsigned char PercEmpty ; /* percentuale alla scarica: 0%=scarica, 100%=carica */ unsigned char OutStatus ; /* stato delle uscite */ unsigned char Year ; /* */ unsigned char Month ; /* */ unsigned char Day ; /* */ unsigned char WeekDay ; /* Giorno della settimana */ unsigned char Hour ; /* Ora */ unsigned char Min ; /* minuti */ unsigned char Sec ; /* secondi */ unsigned char BattLowPerc ; /* percentuale carica batteria quando va in BLOW */ unsigned long Rtime ; /* numero di minuti di accensione dell'UPS */ unsigned long RtimeBatt ; /* numero di secondi*2 in modalità batteria dall'accensione */ /* ------------------------------------------------------------------------ */ unsigned int ShutdownDelay ; /* Shutdown delay in seconds */ unsigned int WakeUpDelay ; /* WakeUp delay in seconds */ } ENT_STRUCT ; #endif /* ENTERPRISE_PROTOCOL */ #endif nut-2.8.1/drivers/sms_ser.c0000644000175000017500000005365014514200703012553 00000000000000/* * sms_ser.c: code for mono protocol for SMS Brazil UPSes * * Copyright (C) 2023 - Alex W. Baule * * 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 2 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, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * Reference of the derivative work: riello driver */ #include "config.h" /* must be the first header */ #include #include "common.h" /* for upsdebugx() etc */ #include "sms_ser.h" #include "main.h" #include "serial.h" #define ENDCHAR '\r' #define DRIVER_NAME "SMS Brazil UPS driver" #define DRIVER_VERSION "1.00" #define QUERY_SIZE 7 #define BUFFER_SIZE 18 #define RESULT_SIZE 18 #define HUMAN_VALUES 7 static uint16_t bootdelay = DEFAULT_BOOTDELAY; static uint8_t bufOut[BUFFER_SIZE]; static uint8_t bufIn[BUFFER_SIZE]; static SmsData DeviceData; /* driver description structure */ upsdrv_info_t upsdrv_info = { DRIVER_NAME, DRIVER_VERSION, "Alex W. Baulé ", DRV_BETA, {NULL}}; void sms_parse_features(uint8_t *rawvalues, SmsData *results) { char tbattery[6]; char frequency[4]; memset(results->voltageRange, 0, sizeof(results->voltageRange)); memset(results->currentRange, 0, sizeof(results->currentRange)); memset(tbattery, 0, sizeof(tbattery)); memset(frequency, 0, sizeof(frequency)); for (int i = 1; i < BUFFER_SIZE - 2; i++) { if (i <= 7) { snprintfcat(results->voltageRange, 14, "%c", rawvalues[i]); } else if (i <= 10) { snprintfcat(results->currentRange, 6, "%c", rawvalues[i]); } else if (i <= 13) { snprintfcat(tbattery, sizeof(tbattery), "%c", rawvalues[i]); } else { snprintfcat(frequency, sizeof(frequency), "%c", rawvalues[i]); } } results->voltageBattery = atoi(tbattery); results->frequency = atoi(frequency); } void sms_parse_information(uint8_t *rawvalues, SmsData *results) { /* Count from 1 to ignore first char and remove 2 from BUFFER_SIZE * to compensate the start and ignore '\r' from end. */ memset(results->model, 0, sizeof(results->model)); memset(results->version, 0, sizeof(results->version)); for (int i = 1; i < BUFFER_SIZE - 2; i++) { if (i <= 12) { snprintfcat(results->model, 24, "%c", rawvalues[i]); } else { snprintfcat(results->version, 6, "%c", rawvalues[i]); } } } void sms_parse_results(uint8_t *rawvalues, SmsData *results) { char buf[BUFFER_SIZE]; uint8_t byte, mask; long v; double h; memset(buf, 0, BUFFER_SIZE); sprintf(buf, "0x%02x%02x", (unsigned char)rawvalues[1], (unsigned char)rawvalues[2]); v = strtol(buf, NULL, 16); /* 16 == hex */ h = v / 10; results->lastinputVac = h; memset(buf, 0, BUFFER_SIZE); sprintf(buf, "0x%02x%02x", (unsigned char)rawvalues[3], (unsigned char)rawvalues[4]); v = strtol(buf, NULL, 16); /* 16 == hex */ h = v / 10; results->inputVac = h; memset(buf, 0, BUFFER_SIZE); sprintf(buf, "0x%02x%02x", (unsigned char)rawvalues[5], (unsigned char)rawvalues[6]); v = strtol(buf, NULL, 16); /* 16 == hex */ h = v / 10; results->outputVac = h; memset(buf, 0, BUFFER_SIZE); sprintf(buf, "0x%02x%02x", (unsigned char)rawvalues[7], (unsigned char)rawvalues[8]); v = strtol(buf, NULL, 16); /* 16 == hex */ h = v / 10; results->outputpower = h; memset(buf, 0, BUFFER_SIZE); sprintf(buf, "0x%02x%02x", (unsigned char)rawvalues[9], (unsigned char)rawvalues[10]); v = strtol(buf, NULL, 16); /* 16 == hex */ h = v / 10; results->outputHz = h; memset(buf, 0, BUFFER_SIZE); sprintf(buf, "0x%02x%02x", (unsigned char)rawvalues[11], (unsigned char)rawvalues[12]); v = strtol(buf, NULL, 16); /* 16 == hex */ h = v / 10; results->batterylevel = h; memset(buf, 0, BUFFER_SIZE); sprintf(buf, "0x%02x%02x", (unsigned char)rawvalues[13], (unsigned char)rawvalues[14]); v = strtol(buf, NULL, 16); /* 16 == hex */ h = v / 10; results->temperatureC = h; byte = rawvalues[15]; mask = 1; results->beepon = ((byte & (mask << 0)) != 0) ? true : false; results->shutdown = ((byte & (mask << 1)) != 0) ? true : false; results->test = ((byte & (mask << 2)) != 0) ? true : false; results->upsok = ((byte & (mask << 3)) != 0) ? true : false; results->boost = ((byte & (mask << 4)) != 0) ? true : false; results->bypass = ((byte & (mask << 5)) != 0) ? true : false; results->lowbattery = ((byte & (mask << 6)) != 0) ? true : false; results->onbattery = ((byte & (mask << 7)) != 0) ? true : false; } static int get_ups_nominal(void) { uint8_t length; ssize_t ret; upsdebugx(LOG_DEBUG, "get_ups_nominal"); length = sms_prepare_get_status(&bufOut[0]); if (ser_send_buf(upsfd, bufOut, length) == 0) { upsdebugx(LOG_ERR, "Communication error while writing to port"); return -1; } memset(bufIn, 0, BUFFER_SIZE); ret = ser_get_buf_len(upsfd, &bufIn[0], BUFFER_SIZE, 3, 1000); if (ret < RESULT_SIZE) { upslogx(LOG_ERR, "Short read from UPS"); dstate_datastale(); return -1; } upsdebugx(3, "Get nominal Ok: received byte %" PRIiSIZE, ret); if (bufIn[0] == '=' || bufIn[0] == '<' || bufIn[0] == '>') { sms_parse_results(&bufIn[0], &DeviceData); return 0; } upsdebugx(3, "Invalid query response from 'Q' command"); return -1; } static int get_ups_information(void) { uint8_t length; ssize_t ret; upsdebugx(LOG_DEBUG, "get_ups_information"); length = sms_prepare_get_information(&bufOut[0]); if (ser_send_buf(upsfd, bufOut, length) == 0) { upsdebugx(LOG_ERR, "Communication error while writing to port"); return -1; } memset(bufIn, 0, BUFFER_SIZE); ret = ser_get_buf_len(upsfd, &bufIn[0], BUFFER_SIZE, 3, 1000); if (ret < RESULT_SIZE) { upslogx(LOG_ERR, "Short read from UPS"); dstate_datastale(); return -1; } upsdebugx(3, "Get information Ok: received byte %" PRIiSIZE, ret); if (bufIn[0] == ';' || bufIn[0] == ':') { sms_parse_information(&bufIn[0], &DeviceData); return 0; } upsdebugx(3, "Invalid query response from 'I' command"); return -1; } static int get_ups_features(void) { uint8_t length; ssize_t ret; upsdebugx(LOG_DEBUG, "get_ups_features"); length = sms_prepare_get_features(&bufOut[0]); if (ser_send_buf(upsfd, bufOut, length) == 0) { upsdebugx(LOG_ERR, "Communication error while writing to port"); return -1; } memset(bufIn, 0, BUFFER_SIZE); ret = ser_get_buf_len(upsfd, &bufIn[0], BUFFER_SIZE, 3, 1000); if (ret < RESULT_SIZE) { upslogx(LOG_ERR, "Short read from UPS"); dstate_datastale(); return -1; } upsdebugx(LOG_DEBUG, "Get features Ok: received byte %" PRIiSIZE, ret); if (bufIn[0] == ';' || bufIn[0] == ':') { sms_parse_features(&bufIn[0], &DeviceData); return 0; } upsdebugx(LOG_ERR, "Invalid query response from 'F' command"); return -1; } static int sms_instcmd(const char *cmdname, const char *extra) { size_t length; if (!strcasecmp(cmdname, "test.battery.start")) { long delay = extra ? strtol(extra, NULL, 10) : 10; length = sms_prepare_test_battery_nsec(&bufOut[0], delay); if (ser_send_buf(upsfd, bufOut, length) == 0) { upsdebugx(3, "failed to send test.battery.start"); return STAT_INSTCMD_FAILED; } upsdebugx(3, "command test.battery.start OK!"); return STAT_INSTCMD_HANDLED; } if (!strcasecmp(cmdname, "test.battery.start.quick")) { length = sms_prepare_test_battery_low(&bufOut[0]); if (ser_send_buf(upsfd, bufOut, length) == 0) { upsdebugx(3, "failed to send test.battery.start.quick"); return STAT_INSTCMD_FAILED; } upsdebugx(3, "command test.battery.start.quick OK!"); return STAT_INSTCMD_HANDLED; } if (!strcasecmp(cmdname, "test.battery.stop")) { length = sms_prepare_cancel_test(&bufOut[0]); if (ser_send_buf(upsfd, bufOut, length) == 0) { upsdebugx(3, "failed to send test.battery.stop"); return STAT_INSTCMD_FAILED; } upsdebugx(3, "command test.battery.stop OK!"); return STAT_INSTCMD_HANDLED; } if (!strcasecmp(cmdname, "beeper.toggle")) { length = sms_prepare_set_beep(&bufOut[0]); if (ser_send_buf(upsfd, bufOut, length) == 0) { upsdebugx(3, "failed to send beeper.toggle"); return STAT_INSTCMD_FAILED; } upsdebugx(3, "command beeper.toggle OK!"); return STAT_INSTCMD_HANDLED; } if (!strcasecmp(cmdname, "shutdown.return")) { length = sms_prepare_shutdown_restore(&bufOut[0]); if (ser_send_buf(upsfd, bufOut, length) == 0) { upsdebugx(3, "failed to send shutdown.return"); return STAT_INSTCMD_FAILED; } upsdebugx(3, "command shutdown.return OK!"); return STAT_INSTCMD_HANDLED; } if (!strcasecmp(cmdname, "shutdown.reboot")) { uint16_t delay = bootdelay; if (extra) { long ldelay = strtol(extra, NULL, bootdelay); if (ldelay >= 0 && (intmax_t)ldelay < (intmax_t)UINT16_MAX) { delay = (uint16_t)ldelay; } else { upsdebugx(3, "tried to set up extra shutdown.reboot delay ut it was out of range, keeping default"); } } length = sms_prepare_shutdown_nsec(&bufOut[0], delay); if (ser_send_buf(upsfd, bufOut, length) == 0) { upsdebugx(3, "failed to send shutdown.reboot"); return STAT_INSTCMD_FAILED; } upsdebugx(3, "command shutdown.reboot OK!"); return STAT_INSTCMD_HANDLED; } if (!strcasecmp(cmdname, "shutdown.stop")) { length = sms_prepare_cancel_shutdown(&bufOut[0]); if (ser_send_buf(upsfd, bufOut, length) == 0) { upsdebugx(3, "failed to send shutdown.stop"); return STAT_INSTCMD_FAILED; } upsdebugx(3, "command shutdown.stop OK!"); return STAT_INSTCMD_HANDLED; } upslogx(LOG_NOTICE, "sms_instcmd: unknown command [%s]", cmdname); return STAT_INSTCMD_UNKNOWN; } static int sms_setvar(const char *varname, const char *val) { if (!strcasecmp(varname, "ups.delay.reboot")) { int ipv = atoi(val); if (ipv >= 0) bootdelay = (unsigned int)ipv; dstate_setinfo("ups.delay.reboot", "%u", bootdelay); return STAT_SET_HANDLED; } return STAT_SET_UNKNOWN; } void upsdrv_initinfo(void) { char *battery_status; upsdebugx(LOG_DEBUG, "upsdrv_initinfo"); if (get_ups_features() != 0) { upslogx(LOG_ERR, "Short read from UPS"); dstate_datastale(); return; } if (get_ups_information() != 0) { upslogx(LOG_ERR, "Short read from UPS"); dstate_datastale(); return; } if (get_ups_nominal() == 0) { dstate_setinfo("device.model", "%s", DeviceData.model); dstate_setinfo("ups.firmware", "%s", DeviceData.version); dstate_setinfo("input.voltage.nominal", "%s", DeviceData.voltageRange); dstate_setinfo("input.current.nominal", "%s", DeviceData.currentRange); dstate_setinfo("output.frequency.nominal", "%d", DeviceData.frequency); dstate_setinfo("ups.beeper.status", "%s", (DeviceData.beepon == 1) ? "enabled" : "disabled"); dstate_setinfo("input.voltage.extended", "%.2f", DeviceData.lastinputVac); dstate_setinfo("input.voltage", "%.2f", DeviceData.inputVac); dstate_setinfo("output.voltage", "%.2f", DeviceData.outputVac); dstate_setinfo("ups.load", "%.2f", DeviceData.outputpower); dstate_setinfo("output.frequency", "%.2f", DeviceData.outputHz); dstate_setinfo("battery.charge", "%.2f", DeviceData.batterylevel); dstate_setinfo("battery.voltage.nominal", "%d", DeviceData.voltageBattery); dstate_setinfo("battery.packs", "%d", DeviceData.voltageBattery / 12); dstate_setinfo("battery.voltage", "%.2f", (DeviceData.voltageBattery * DeviceData.batterylevel) / 100); dstate_setinfo("ups.temperature", "%.2f", DeviceData.temperatureC); if (DeviceData.onbattery && (uint8_t)DeviceData.batterylevel < 100) { upsdebugx(LOG_DEBUG, "on battery and battery < last battery"); battery_status = "discharging"; } else if (!DeviceData.onbattery && (uint8_t)DeviceData.batterylevel < 100) { upsdebugx(LOG_DEBUG, "on power and battery > last battery"); battery_status = "charging"; } else if (!DeviceData.onbattery && (uint8_t)DeviceData.batterylevel == 100) { upsdebugx(LOG_DEBUG, "on power and battery == 100"); battery_status = "resting"; } else { upsdebugx(LOG_DEBUG, "none, floating"); battery_status = "floating"; } dstate_setinfo("battery.charger.status", "%s", battery_status); } else { upslogx(LOG_ERR, "Short read from UPS"); dstate_datastale(); return; } dstate_addcmd("test.battery.start"); dstate_addcmd("test.battery.start.quick"); dstate_addcmd("test.battery.stop"); dstate_addcmd("beeper.toggle"); dstate_addcmd("shutdown.return"); dstate_addcmd("shutdown.stop"); dstate_addcmd("shutdown.reboot"); upsh.instcmd = sms_instcmd; upsh.setvar = sms_setvar; } void upsdrv_updateinfo(void) { char *battery_status; upsdebugx(LOG_DEBUG, "upsdrv_updateinfo"); if (get_ups_nominal() != 0) { upslogx(LOG_ERR, "Short read from UPS"); dstate_datastale(); return; } dstate_setinfo("device.model", "%s", DeviceData.model); dstate_setinfo("ups.firmware", "%s", DeviceData.version); dstate_setinfo("battery.voltage.nominal", "%s", DeviceData.voltageRange); dstate_setinfo("output.frequency.nominal", "%d", DeviceData.frequency); dstate_setinfo("ups.beeper.status", "%s", (DeviceData.beepon == 1) ? "enabled" : "disabled"); dstate_setinfo("input.voltage.extended", "%.2f", DeviceData.lastinputVac); dstate_setinfo("input.voltage", "%.2f", DeviceData.inputVac); dstate_setinfo("output.voltage", "%.2f", DeviceData.outputVac); dstate_setinfo("ups.load", "%.2f", DeviceData.outputpower); dstate_setinfo("output.frequency", "%.2f", DeviceData.outputHz); dstate_setinfo("battery.charge", "%.2f", DeviceData.batterylevel); dstate_setinfo("battery.voltage.nominal", "%d", DeviceData.voltageBattery); dstate_setinfo("battery.packs", "%d", DeviceData.voltageBattery / 12); dstate_setinfo("battery.voltage", "%.2f", (DeviceData.voltageBattery * DeviceData.batterylevel) / 100); dstate_setinfo("ups.temperature", "%.2f", DeviceData.temperatureC); upsdebugx(LOG_DEBUG, "battery level: %.2f", DeviceData.batterylevel); upsdebugx(LOG_DEBUG, "bypass: %d", DeviceData.bypass); upsdebugx(LOG_DEBUG, "onBattery: %d", DeviceData.onbattery); if (DeviceData.onbattery && (uint8_t)DeviceData.batterylevel < 100) { upsdebugx(LOG_DEBUG, "on battery and battery < last battery"); battery_status = "discharging"; } else if (!DeviceData.onbattery && (uint8_t)DeviceData.batterylevel < 100) { upsdebugx(LOG_DEBUG, "on power and battery > last battery"); battery_status = "charging"; } else if (!DeviceData.onbattery && (uint8_t)DeviceData.batterylevel == 100) { upsdebugx(LOG_DEBUG, "on power and battery == 100"); battery_status = "resting"; } else { upsdebugx(LOG_DEBUG, "none, floating"); battery_status = "floating"; } dstate_setinfo("battery.charger.status", "%s", battery_status); status_init(); if (DeviceData.bypass) { upsdebugx(LOG_DEBUG, "setting status to BYPASS"); status_set("BYPASS"); } else if (DeviceData.onbattery) { upsdebugx(LOG_DEBUG, "setting status to OB"); status_set("OB"); } else if (DeviceData.lowbattery) { upsdebugx(LOG_DEBUG, "setting status to LB"); status_set("LB"); } else if (!DeviceData.upsok) { upsdebugx(LOG_DEBUG, "setting status to RB"); status_set("RB"); } else if (DeviceData.boost) { upsdebugx(LOG_DEBUG, "setting status to BOOST"); status_set("BOOST"); } else if (!DeviceData.onbattery) { /* sometimes the flag "onacpower" is not set */ upsdebugx(LOG_DEBUG, "setting status to OL"); status_set("OL"); } else { /* None of these parameters is ON, but we got some response, * so the device is (administratively) OFF ? */ upsdebugx(LOG_DEBUG, "setting status to OFF"); status_set("OFF"); } status_commit(); dstate_dataok(); poll_interval = 5; } void upsdrv_shutdown(void) { /* tell the UPS to shut down, then return - DO NOT SLEEP HERE */ int retry; /* maybe try to detect the UPS here, but try a shutdown even if * it doesn't respond at first if possible */ /* replace with a proper shutdown function */ /* you may have to check the line status since the commands * for toggling power are frequently different for OL vs. OB */ /* OL: this must power cycle the load if possible */ /* OB: the load must remain off until the power returns */ upsdebugx(2, "upsdrv Shutdown execute"); for (retry = 1; retry <= MAXTRIES; retry++) { if (sms_instcmd("shutdown.stop", NULL) != STAT_INSTCMD_HANDLED) { continue; } if (sms_instcmd("shutdown.return", NULL) != STAT_INSTCMD_HANDLED) { continue; } upslogx(LOG_ERR, "Shutting down"); set_exit_flag(-2); /* EXIT_SUCCESS */ return; } upslogx(LOG_ERR, "Shutdown failed!"); set_exit_flag(-1); } void upsdrv_help(void) { } /* list flags and values that you want to receive via -x */ void upsdrv_makevartable(void) { char msg[256]; upsdebugx(LOG_DEBUG, "upsdrv_makevartable"); snprintf(msg, sizeof msg, "Set reboot delay, in seconds (default=%d).", DEFAULT_BOOTDELAY); addvar(VAR_VALUE, "rebootdelay", msg); } void upsdrv_initups(void) { char *val; upsdebugx(LOG_DEBUG, "upsdrv_initups"); upsfd = ser_open(device_path); ser_set_speed(upsfd, device_path, B2400); if ((val = getval("rebootdelay"))) { int ipv = atoi(val); if (ipv >= 0) bootdelay = (unsigned int)ipv; } } void upsdrv_cleanup(void) { upsdebugx(LOG_DEBUG, "upsdrv_cleanup"); /* free(dynamic_mem); */ ser_close(upsfd, device_path); } uint8_t sms_prepare_get_status(uint8_t *buffer) { buffer[0] = 'Q'; buffer[1] = 255; buffer[2] = 255; buffer[3] = 255; buffer[4] = 255; buffer[5] = (buffer[0] + buffer[1] + buffer[2] + buffer[3] + buffer[4]) * 255; buffer[6] = ENDCHAR; return 7; } uint8_t sms_prepare_get_information(uint8_t *buffer) { buffer[0] = 'I'; buffer[1] = 255; buffer[2] = 255; buffer[3] = 255; buffer[4] = 255; buffer[5] = (buffer[0] + buffer[1] + buffer[2] + buffer[3] + buffer[4]) * 255; buffer[6] = ENDCHAR; return 7; } uint8_t sms_prepare_get_features(uint8_t *buffer) { buffer[0] = 'F'; buffer[1] = 255; buffer[2] = 255; buffer[3] = 255; buffer[4] = 255; buffer[5] = (buffer[0] + buffer[1] + buffer[2] + buffer[3] + buffer[4]) * 255; buffer[6] = ENDCHAR; return 7; } uint8_t sms_prepare_set_beep(uint8_t *buffer) { buffer[0] = 'M'; buffer[1] = 255; buffer[2] = 255; buffer[3] = 255; buffer[4] = 255; buffer[5] = (buffer[0] + buffer[1] + buffer[2] + buffer[3] + buffer[4]) * 255; buffer[6] = ENDCHAR; return 7; } uint8_t sms_prepare_test_battery_low(uint8_t *buffer) { buffer[0] = 'L'; buffer[1] = 255; buffer[2] = 255; buffer[3] = 255; buffer[4] = 255; buffer[5] = (buffer[0] + buffer[1] + buffer[2] + buffer[3] + buffer[4]) * 255; buffer[6] = ENDCHAR; return 7; } uint8_t sms_prepare_test_battery_nsec(uint8_t *buffer, uint16_t delay) { buffer[0] = 'T'; buffer[1] = (uint8_t)(delay % 256); buffer[2] = 255; buffer[3] = 255; buffer[4] = 255; buffer[5] = (buffer[0] + buffer[1] + buffer[2] + buffer[3] + buffer[4]) * 255; buffer[6] = ENDCHAR; return 7; } uint8_t sms_prepare_shutdown_nsec(uint8_t *buffer, uint16_t delay) { buffer[0] = 'S'; buffer[1] = (uint8_t)(delay % 256); buffer[2] = 255; buffer[3] = 255; buffer[4] = 255; buffer[5] = (buffer[0] + buffer[1] + buffer[2] + buffer[3] + buffer[4]) * 255; buffer[6] = ENDCHAR; return 7; } uint8_t sms_prepare_shutdown_restore(uint8_t *buffer) { buffer[0] = 'R'; buffer[1] = 255; buffer[2] = 255; buffer[3] = 255; buffer[4] = 255; buffer[5] = (buffer[0] + buffer[1] + buffer[2] + buffer[3] + buffer[4]) * 255; buffer[6] = ENDCHAR; return 7; } uint8_t sms_prepare_cancel_test(uint8_t *buffer) { buffer[0] = 'D'; buffer[1] = 255; buffer[2] = 255; buffer[3] = 255; buffer[4] = 255; buffer[5] = (buffer[0] + buffer[1] + buffer[2] + buffer[3] + buffer[4]) * 255; buffer[6] = ENDCHAR; return 7; } uint8_t sms_prepare_cancel_shutdown(uint8_t *buffer) { buffer[0] = 'C'; buffer[1] = 255; buffer[2] = 255; buffer[3] = 255; buffer[4] = 255; buffer[5] = (buffer[0] + buffer[1] + buffer[2] + buffer[3] + buffer[4]) * 255; buffer[6] = ENDCHAR; return 7; } nut-2.8.1/drivers/tripplite.h0000644000175000017500000000504714500336654013130 00000000000000/* tripplite.h - model specific routines for Tripp Lite SmartUPS models (tested with: "SMART 700" [on back -- "SmartPro UPS" on front], "SMART700SER") tripplite.c was derived from Russell Kroll's bestups.c by Rik Faith. Copyright (C) 1999 Russell Kroll Copyright (C) 2001 Rickard E. (Rik) Faith Copyright (C) 2004,2008 Nicholas J. Kain 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 2 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, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef NUT_TRIPPLITE_H_SEEN #define NUT_TRIPPLITE_H_SEEN 1 #define ENDCHAR '\n' /* replies end with CR LF -- use LF to end */ #define IGNCHAR '\r' /* ignore CR */ #define MAXTRIES 3 /* max number of times we try to detect ups */ #define SER_WAIT_SEC 1 /* allow 1.0 sec for ser_get calls */ #define SER_WAIT_USEC 0 #define DEFAULT_OFFDELAY 64 /* seconds (max 0xFF) */ #define DEFAULT_STARTDELAY 60 /* seconds (max 0xFFFFFF) */ #define DEFAULT_BOOTDELAY 64 /* seconds (max 0xFF) */ /* Sometimes the UPS seems to return bad data, so we range check it. */ #define INVOLT_MAX 270 #define INVOLT_MIN 0 #define FREQ_MAX 80.0 #define FREQ_MIN 30.0 #define TEMP_MAX 100 #define TEMP_MIN 0 #define LOAD_MAX 100 #define LOAD_MIN 0 /* We calculate battery charge (q) as a function of voltage (V). * It seems that this function probably varies by firmware revision or * UPS model - the Windows monitoring software gives different q for a * given V than the old open source Tripp Lite monitoring software. * * The discharge curve should be the same for any given battery chemistry, * so it should only be necessary to specify the minimum and maximum * voltages likely to be seen in operation. */ /* Interval notation for Q% = 10% <= [minV, maxV] <= 100% */ #define MAX_VOLT 13.4 /* Max battery voltage (100%) */ #define MIN_VOLT 11.0 /* Min battery voltage (10%) */ #endif /* NUT_TRIPPLITE_H_SEEN */ nut-2.8.1/drivers/dummy-ups.h0000644000175000017500000002251314500336654013051 00000000000000/* dummy-ups.h - NUT testing driver and repeater Copyright (C) 2005 - 2012 Arnaud Quette 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 2 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, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef NUT_DUMMY_UPS_H_SEEN #define NUT_DUMMY_UPS_H_SEEN 1 /* This file lists all valid data with their type and info. * * These are then enabled through a definition file, specified * as the "port" parameter (only the file name, not the path). * * The format of this file is the same as an upsc dump: * * : * * FIXME: use cmdvartab for conformance checking * ... * Once the driver is loaded: * - change the value by using upsrw * - ?you can add new variables and change variable values by * editing the definition file? */ /* from usbhid-ups.h */ /* --------------------------------------------------------------- */ /* Struct & data for ups.status processing */ /* --------------------------------------------------------------- */ #if 0 /* XXX status lookup table not currently used???? */ /* * Status lookup table type definition */ typedef struct { const char *status_str; /* ups.status string */ int status_value; /* ups.status flag bit */ } status_lkp_t; #define STATUS_CAL (1 << 0) /* calibration */ #define STATUS_TRIM (1 << 1) /* SmartTrim */ #define STATUS_BOOST (1 << 2) /* SmartBoost */ #define STATUS_OL (1 << 3) /* on line */ #define STATUS_OB (1 << 4) /* on battery */ #define STATUS_OVER (1 << 5) /* overload */ #define STATUS_LB (1 << 6) /* low battery */ #define STATUS_RB (1 << 7) /* replace battery */ #define STATUS_BYPASS (1 << 8) /* on bypass */ #define STATUS_OFF (1 << 9) /* ups is off */ #define STATUS_CHRG (1 << 10) /* charging */ #define STATUS_DISCHRG (1 << 11) /* discharging */ /* * Status lookup table */ status_lkp_t status_info[] = { { "CAL", STATUS_CAL }, { "TRIM", STATUS_TRIM }, { "BOOST", STATUS_BOOST }, { "OL", STATUS_OL }, { "OB", STATUS_OB }, { "OVER", STATUS_OVER }, { "LB", STATUS_LB }, { "RB", STATUS_RB }, { "BYPASS", STATUS_BYPASS }, { "OFF", STATUS_OFF }, { "CHRG", STATUS_CHRG }, { "DISCHRG", STATUS_DISCHRG }, { "NULL", 0 }, }; #endif /* 0 -- not currently used??? */ typedef struct { char hid_value; /* HID value */ char *nut_value; /* NUT value */ } info_enum_t; /* --------------------------------------------------------------- */ /* Structure containing information about how to get/set data */ /* from/to the UPS and convert these to/from NUT standard */ /* --------------------------------------------------------------- */ typedef struct { const char *info_type; /* NUT variable name */ int info_flags; /* NUT flags (to set in addinfo) */ float info_len; /* if ST_FLAG_STRING: length of the string */ /* if HU_TYPE_CMD: command value ; multiplier (or max len) otherwise */ const char *default_value; /* if HU_FLAG_ABSENT: default value ; format otherwise */ int drv_flags; /* */ char **var_values; /* all possible values for this variable (allows to check data...) */ /* FIXME: "void *" so we can have bound or enum */ /* interpreter interpret; */ /* FFE: interpreter fct, NULL if not needed */ } dummy_info_t; /* data flags */ #define DU_FLAG_NONE 0 #define DU_FLAG_INIT 1 /* intialy show element to upsd */ /* --------------------------------------------------------------- */ /* Data table (all possible info from NUT, then enable upon cong */ /* --------------------------------------------------------------- */ /* FIXME: need to enforce value check with enum or bounds */ /* This array is only used from dummy-ups.c (there's a namesake * for apcupsd-ups.c defined elsewhere) */ static dummy_info_t nut_data[] = { /* Essential variables, loaded before parsing the definition file */ { "ups.mfr", ST_FLAG_STRING | ST_FLAG_RW, 32, "Dummy Manufacturer", DU_FLAG_INIT, NULL }, { "ups.model", ST_FLAG_STRING | ST_FLAG_RW, 32, "Dummy UPS", DU_FLAG_INIT, NULL }, { "ups.status", ST_FLAG_STRING | ST_FLAG_RW, 32, "OL", DU_FLAG_INIT, NULL }, /* Other known variables */ { "ups.serial", ST_FLAG_STRING | ST_FLAG_RW, 32, NULL, DU_FLAG_NONE, NULL }, { "ups.load", ST_FLAG_RW, 32, NULL, DU_FLAG_NONE, NULL }, { "ups.alarm", ST_FLAG_STRING | ST_FLAG_RW, 32, NULL, DU_FLAG_NONE, NULL }, { "ups.time", ST_FLAG_STRING | ST_FLAG_RW, 16, NULL, DU_FLAG_NONE, NULL }, { "ups.date", ST_FLAG_STRING | ST_FLAG_RW, 16, NULL, DU_FLAG_NONE, NULL }, { "ups.mfr.date", ST_FLAG_STRING | ST_FLAG_RW, 16, NULL, DU_FLAG_NONE, NULL }, { "ups.serial", ST_FLAG_STRING | ST_FLAG_RW, 16, NULL, DU_FLAG_NONE, NULL }, { "ups.firmware", ST_FLAG_STRING | ST_FLAG_RW, 16, NULL, DU_FLAG_NONE, NULL }, { "ups.firmware.aux", ST_FLAG_STRING | ST_FLAG_RW, 16, NULL, DU_FLAG_NONE, NULL }, { "ups.temperature", ST_FLAG_RW, 1, NULL, DU_FLAG_NONE, NULL }, { "ups.id", ST_FLAG_STRING | ST_FLAG_RW, 16, NULL, DU_FLAG_NONE, NULL }, { "ups.delay.start", ST_FLAG_RW, 1, NULL, DU_FLAG_NONE, NULL }, { "ups.delay.reboot", ST_FLAG_RW, 1, NULL, DU_FLAG_NONE, NULL }, { "ups.delay.shutdown", ST_FLAG_RW, 1, NULL, DU_FLAG_NONE, NULL }, { "ups.test.interval", ST_FLAG_RW, 1, NULL, DU_FLAG_NONE, NULL }, { "ups.test.result", ST_FLAG_STRING | ST_FLAG_RW, 16, NULL, DU_FLAG_NONE, NULL }, /* ups.display.language ups.contacts ups.power ups.power.nominal */ { "input.voltage", ST_FLAG_RW, 1, NULL, DU_FLAG_NONE, NULL }, { "input.voltage.maximum", ST_FLAG_RW, 1, NULL, DU_FLAG_NONE, NULL }, { "input.voltage.minimum", ST_FLAG_RW, 1, NULL, DU_FLAG_NONE, NULL }, { "input.voltage.nominal", ST_FLAG_RW, 1, NULL, DU_FLAG_NONE, NULL }, { "input.transfer.reason", ST_FLAG_STRING | ST_FLAG_RW, 1, NULL, DU_FLAG_NONE, NULL }, { "input.transfer.low", ST_FLAG_RW, 1, NULL, DU_FLAG_NONE, NULL }, { "input.transfer.high", ST_FLAG_RW, 1, NULL, DU_FLAG_NONE, NULL }, { "input.sensitivity", ST_FLAG_STRING | ST_FLAG_RW, 1, NULL, DU_FLAG_NONE, NULL }, { "input.quality", ST_FLAG_STRING | ST_FLAG_RW, 6, NULL, DU_FLAG_NONE, NULL }, { "input.frequency", ST_FLAG_RW, 1, NULL, DU_FLAG_NONE, NULL }, { "input.transfer.boost.low", ST_FLAG_RW, 1, NULL, DU_FLAG_NONE, NULL }, { "input.transfer.boost.high", ST_FLAG_RW, 1, NULL, DU_FLAG_NONE, NULL }, { "input.transfer.trim.low", ST_FLAG_RW, 1, NULL, DU_FLAG_NONE, NULL }, { "input.transfer.trim.high", ST_FLAG_RW, 1, NULL, DU_FLAG_NONE, NULL }, { "output.voltage", ST_FLAG_RW, 1, NULL, DU_FLAG_NONE, NULL }, { "output.frequency", ST_FLAG_RW, 1, NULL, DU_FLAG_NONE, NULL }, { "output.current", ST_FLAG_RW, 1, NULL, DU_FLAG_NONE, NULL }, /* output.voltage.nominal */ { "battery.charge", ST_FLAG_RW, 1, NULL, DU_FLAG_NONE, NULL }, { "battery.charge.low", ST_FLAG_RW, 1, NULL, DU_FLAG_NONE, NULL }, { "battery.voltage", ST_FLAG_RW, 1, NULL, DU_FLAG_NONE, NULL }, { "battery.current", ST_FLAG_RW, 1, NULL, DU_FLAG_NONE, NULL }, { "battery.runtime", ST_FLAG_RW, 1, NULL, DU_FLAG_NONE, NULL }, { "battery.runtime.low", ST_FLAG_RW, 1, NULL, DU_FLAG_NONE, NULL }, { "battery.charge.restart", ST_FLAG_RW, 1, NULL, DU_FLAG_NONE, NULL }, { "battery.temperature", ST_FLAG_RW, 1, NULL, DU_FLAG_NONE, NULL }, { "battery.voltage.nominal", ST_FLAG_RW, 1, NULL, DU_FLAG_NONE, NULL }, /* battery.alarm.threshold battery.date battery.packs battery.packs.bad */ { "ambient.temperature", ST_FLAG_RW, 1, NULL, DU_FLAG_NONE, NULL }, { "ambient.temperature.alarm", ST_FLAG_RW, 1, NULL, DU_FLAG_NONE, NULL }, { "ambient.temperature.high", ST_FLAG_RW, 1, NULL, DU_FLAG_NONE, NULL }, { "ambient.temperature.low", ST_FLAG_RW, 1, NULL, DU_FLAG_NONE, NULL }, { "ambient.humidity", ST_FLAG_RW, 1, NULL, DU_FLAG_NONE, NULL }, { "ambient.humidity.alarm", ST_FLAG_RW, 1, NULL, DU_FLAG_NONE, NULL }, { "ambient.humidity.high", ST_FLAG_RW, 1, NULL, DU_FLAG_NONE, NULL }, { "ambient.humidity.low", ST_FLAG_RW, 1, NULL, DU_FLAG_NONE, NULL }, /* FIXME: how to manage these? (i.e. index ) outlet.n.id outlet.n.desc outlet.n.switch outlet.n.status outlet.n.switchable outlet.n.autoswitch.charge.low outlet.n.delay.shutdown outlet.n.delay.start ... driver.name driver.version driver.version.internal | Internal driver version | 1.23.45 | driver.parameter.xxx driver.flag.xxx No need for these! server.info server.version Cmds load.off load.on shutdown.return shutdown.stayoff shutdown.stop shutdown.reboot shutdown.reboot.graceful test.panel.start test.panel.stop test.failure.start test.failure.stop test.battery.start test.battery.stop calibrate.start calibrate.stop bypass.start bypass.stop reset.input.minmax reset.watchdog beeper.enable beeper.disable */ /* end of structure. */ { NULL, 0, 0, NULL, DU_FLAG_NONE, NULL } }; #endif /* NUT_DUMMY_UPS_H_SEEN */ nut-2.8.1/drivers/netxml-ups.c0000644000175000017500000012453114502253356013222 00000000000000/* netxml-ups.c Driver routines for network XML UPS units Copyright (C) 2008-2009 Arjen de Korte 2013 Vaclav Krpec 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 2 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, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "main.h" #include "netxml-ups.h" #include "mge-xml.h" #include "dstate.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include "nut_stdint.h" #define DRIVER_NAME "network XML UPS" #define DRIVER_VERSION "0.45" /** *_OBJECT query multi-part body boundary */ #define FORM_POST_BOUNDARY "NUT-NETXML-UPS-OBJECTS" #ifdef WIN32 /* FIXME ?? skip alarm handling */ #define HAVE_NE_SET_CONNECT_TIMEOUT 1 #define HAVE_NE_SOCK_CONNECT_TIMEOUT 1 #endif /* driver description structure */ upsdrv_info_t upsdrv_info = { DRIVER_NAME, DRIVER_VERSION, "Arjen de Korte " \ "Vaclav Krpec ", DRV_EXPERIMENTAL, { NULL } }; /** *_OBJECT query status */ typedef enum { OBJECT_OK = 0, /**< OK */ OBJECT_PARSE_ERROR, /**< Parse error */ OBJECT_ERROR, /**< Generic error */ } object_query_status_t; /* end of typedef enum */ /** *_OBJECT entry type */ typedef enum { SET_OBJECT_REQUEST, /**< SET_OBJECT request */ SET_OBJECT_RESPONSE, /**< SET_OBJECT response */ } object_query_type_t; /* end of typedef enum */ /** *_OBJECT POST request mode */ typedef enum { RAW_POST, /**< RAW POST mode */ FORM_POST, /**< FORM POST mode */ } object_post_mode_t; /* end of typedef enum */ typedef struct set_object_req set_object_req_t; /**< SET_OBJECT request carrier */ typedef struct set_object_resp set_object_resp_t; /**< SET_OBJECT response carrier */ typedef struct object_entry object_entry_t; /**< *_OBJECT entry carrier */ typedef struct object_query object_query_t; /**< *_OBJECT query handle */ /** SET_OBJECT request carrier */ struct set_object_req { char *name; /**< OBJECT name */ char *value; /**< OBJECT value */ }; /* end of struct set_object_req */ /** SET_OBJECT response carrier */ struct set_object_resp { char *name; /**< OBJECT name */ char *unit; /**< OBJECT unit */ char *access; /**< OBJECT access */ char *value; /**< OBJECT value */ }; /* end of struct set_object_resp */ /** *_OBJECT query entry */ struct object_entry { /** Payload */ union { set_object_req_t req; /**< Request entry */ set_object_resp_t resp; /**< Response entry */ } payld; /* Metadata */ object_entry_t *next; /**< Next entry */ object_entry_t *prev; /**< Previous entry */ }; /* end of struct object_entry */ /** *_OBJECT query handle */ struct object_query { object_query_status_t status; /**< Query status */ object_query_type_t type; /**< List entries type */ object_post_mode_t mode; /**< POST request mode */ size_t cnt; /**< Count of entries */ object_entry_t *head; /**< List head */ object_entry_t *tail; /**< List tail */ }; /* end of struct object_query */ /** * \brief *_OBJECT query constructor * * \param type Query type * \param mode Query mode * * \return *_OBJECT query handle or \c NULL in case of memory error */ static object_query_t *object_query_create( object_query_type_t type, object_post_mode_t mode); /** * \brief Number of *_OBJECT query entries * * \param handle Query handle * * \return NUmber of entries */ static size_t object_query_size(object_query_t *handle); /** * \brief *_OBJECT query destructor * * \param handle Query handle */ static void object_query_destroy(object_query_t *handle); /** * \brief SET_OBJECT: add request query entry * * \param handle Request query handle * \param name OBJECT name * \param value OBJECT value * * \return Query entry or \c NULL in case of memory error */ static object_entry_t *set_object_add( object_query_t *handle, const char *name, const char *value); /** * \brief SET_OBJECT: RAW POST mode implementation * * \param req SET_OBJECT request * * \return Response to the request */ static object_query_t *set_object_raw(object_query_t *req); /** * \brief SET_OBJECT: FORM POST mode implementation * * \param req SET_OBJECT request * * \return \c NULL (FORM POST mode resp. is ignored by specification) */ static object_query_t *set_object_form(object_query_t *req); /** * \brief SET_OBJECT: implementation * * \param req SET_OBJECT request * * \return Response to the request */ static object_query_t *set_object(object_query_t *req); /** * \brief SET_OBJECT: RAW POST mode request serialisation * * \param handle Request query handle * * \return POST request body */ static ne_buffer *set_object_serialise_raw(object_query_t *handle); /** * \brief SET_OBJECT: FORM POST mode request serialisation * * \param handle Request query handle * * \return POST request body */ static ne_buffer *set_object_serialise_form(object_query_t *handle); /* FIXME: * "built with neon library %s" LIBNEON_VERSION * subdrivers (limited to MGE only ATM) */ /* Global vars */ uint32_t ups_status = 0; static int timeout = 5; int shutdown_duration = 120; static int shutdown_timer = 0; static time_t lastheard = 0; static subdriver_t *subdriver = &mge_xml_subdriver; static ne_session *session = NULL; static ne_socket *sock = NULL; static ne_uri uri; static char *product_page = NULL; /* Support functions */ static void netxml_alarm_set(void); static void netxml_status_set(void); static int netxml_authenticate(void *userdata, const char *realm, int attempt, char *username, char *password); static int netxml_dispatch_request(ne_request *request, ne_xml_parser *parser); static int netxml_get_page(const char *page); static int instcmd(const char *cmdname, const char *extra); static int setvar(const char *varname, const char *val); static int netxml_alarm_subscribe(const char *page); #if HAVE_NE_SET_CONNECT_TIMEOUT && HAVE_NE_SOCK_CONNECT_TIMEOUT /* we don't need to use alarm() */ #else static void netxml_alarm_handler(int sig) { /* don't do anything here, just return */ } #endif void upsdrv_initinfo(void) { char *page, *last = NULL; char buf[SMALLBUF]; snprintf(buf, sizeof(buf), "%s", subdriver->initinfo); for (page = strtok_r(buf, " ", &last); page != NULL; page = strtok_r(NULL, " ", &last)) { if (netxml_get_page(page) != NE_OK) { continue; } /* store product page, for later use */ product_page = xstrdup(page); dstate_setinfo("driver.version.data", "%s", subdriver->version); if (testvar("subscribe") && (netxml_alarm_subscribe(subdriver->subscribe) == NE_OK)) { /* TODO: port extrafd to Windows */ #ifndef WIN32 extrafd = ne_sock_fd(sock); #endif time(&lastheard); } /* Register r/w variables */ vname_register_rw(); /* Set UPS driver handler callbacks */ upsh.setvar = &setvar; upsh.instcmd = &instcmd; return; } fatalx(EXIT_FAILURE, "%s: communication failure [%s]", __func__, ne_get_error(session)); } void upsdrv_updateinfo(void) { ssize_t ret; int errors = 0; /* We really should be dealing with alarms through a separate callback, so that we can keep the * processing of alarms and polling for data separated. Currently, this isn't supported by the * driver main body, so we'll have to revert to polling each time we're called, unless the * socket indicates we're no longer connected. */ if (testvar("subscribe")) { char buf[LARGEBUF]; ret = ne_sock_read(sock, buf, sizeof(buf)); if (ret > 0) { /* alarm message received */ ne_xml_parser *parser = ne_xml_create(); upsdebugx(2, "%s: ne_sock_read(%" PRIiSIZE " bytes) => %s", __func__, ret, buf); ne_xml_push_handler(parser, subdriver->startelm_cb, subdriver->cdata_cb, subdriver->endelm_cb, NULL); ne_xml_parse(parser, buf, strlen(buf)); ne_xml_destroy(parser); time(&lastheard); } else if ((ret == NE_SOCK_TIMEOUT) && (difftime(time(NULL), lastheard) < 180)) { /* timed out */ upsdebugx(2, "%s: ne_sock_read(timeout)", __func__); } else { /* connection closed or unknown error */ upslogx(LOG_ERR, "NSM connection with '%s' lost", uri.host); upsdebugx(2, "%s: ne_sock_read(%" PRIiSIZE ") => %s", __func__, ret, ne_sock_error(sock)); ne_sock_close(sock); if (netxml_alarm_subscribe(subdriver->subscribe) == NE_OK) { /* TODO: port extrafd to Windows */ #ifndef WIN32 extrafd = ne_sock_fd(sock); #endif time(&lastheard); return; } dstate_datastale(); /* TODO: port extrafd to Windows */ #ifndef WIN32 extrafd = ERROR_FD; #endif return; } } /* get additional data */ ret = netxml_get_page(subdriver->getobject); if (ret != NE_OK) { errors++; } ret = netxml_get_page(subdriver->summary); if (ret != NE_OK) { errors++; } /* also refresh the product information, at least for firmware information */ ret = netxml_get_page(product_page); if (ret != NE_OK) { errors++; } if (errors > 1) { dstate_datastale(); return; } status_init(); alarm_init(); netxml_alarm_set(); alarm_commit(); netxml_status_set(); status_commit(); dstate_dataok(); } void upsdrv_shutdown(void) { /* tell the UPS to shut down, then return - DO NOT SLEEP HERE */ /* maybe try to detect the UPS here, but try a shutdown even if it doesn't respond at first if possible */ /* replace with a proper shutdown function */ /* fatalx(EXIT_FAILURE, "shutdown not supported"); */ /* you may have to check the line status since the commands for toggling power are frequently different for OL vs. OB */ /* OL: this must power cycle the load if possible */ /* OB: the load must remain off until the power returns */ int status = STAT_SET_FAILED; /* pessimistic assumption */ object_query_t *resp = NULL; object_query_t *req = NULL; /* Pragmatic do { ... } while (0) loop allowing break to cleanup */ do { /* Create SET_OBJECT request */ req = object_query_create(SET_OBJECT_REQUEST, FORM_POST); if (NULL == req) break; if (NULL == set_object_add(req, "battery.runtime.low", "999999999")) break; /* Send SET_OBJECT request */ resp = set_object(req); #if (0) /* FORM_POST method response is ignored, we can only hope it worked... */ if (NULL == resp) break; /* Check if setting was done */ if (1 > object_query_size(resp)) { status = STAT_SET_UNKNOWN; break; } #endif /* end of code removal */ status = STAT_SET_HANDLED; /* success */ } while (0); /* end of pragmatic loop, break target */ /* Cleanup */ if (NULL != req) object_query_destroy(req); if (NULL != resp) object_query_destroy(resp); if (STAT_SET_HANDLED != status) { upslogx(LOG_ERR, "Shutdown failed: %d", status); set_exit_flag(-1); } } static int instcmd(const char *cmdname, const char *extra) { /* if (!strcasecmp(cmdname, "test.battery.stop")) { ser_send_buf(upsfd, ...); return STAT_INSTCMD_HANDLED; } */ upslogx(LOG_NOTICE, "%s: unknown command [%s] [%s]", __func__, cmdname, extra); return STAT_INSTCMD_UNKNOWN; } static int setvar(const char *varname, const char *val) { int status = STAT_SET_FAILED; /* pessimistic assumption */ object_query_t *resp = NULL; object_query_t *req = NULL; /* Pragmatic do { ... } while (0) loop allowing break to cleanup */ do { /* Create SET_OBJECT request */ req = object_query_create(SET_OBJECT_REQUEST, FORM_POST); if (NULL == req) break; if (NULL == set_object_add(req, varname, val)) break; /* Send SET_OBJECT request */ resp = set_object(req); if (NULL == resp) break; /* Check if setting was done */ if (1 > object_query_size(resp)) { status = STAT_SET_UNKNOWN; break; } status = STAT_SET_HANDLED; /* success */ } while (0); /* end of pragmatic loop, break target */ /* Cleanup */ if (NULL != req) object_query_destroy(req); if (NULL != resp) object_query_destroy(resp); return status; } void upsdrv_help(void) { } /* list flags and values that you want to receive via -x */ void upsdrv_makevartable(void) { char buf[SMALLBUF]; snprintf(buf, sizeof(buf), "network timeout (default: %d seconds)", timeout); addvar(VAR_VALUE, "timeout", buf); addvar(VAR_FLAG, "subscribe", "authenticated subscription on NMC"); addvar(VAR_VALUE | VAR_SENSITIVE, "login", "login value for authenticated mode"); addvar(VAR_VALUE | VAR_SENSITIVE, "password", "password value for authenticated mode"); snprintf(buf, sizeof(buf), "shutdown duration in second (default: %d seconds)", shutdown_duration); addvar(VAR_VALUE, "shutdown_duration", buf); if( shutdown_timer > 0 ) { snprintf(buf, sizeof(buf), "shutdown timer in second (default: %d seconds)", shutdown_timer); } else { snprintf(buf, sizeof(buf), "shutdown timer in second (default: none)"); } addvar(VAR_VALUE, "shutdown_timer", buf); /* Legacy MGE-XML conversion from 2000's, not needed in modern firmwares */ addvar(VAR_FLAG, "do_convert_deci", "enable legacy convert_deci() for certain measurements 10x too large"); } void upsdrv_initups(void) { int ret; char *val; FILE *fp; #if HAVE_NE_SET_CONNECT_TIMEOUT && HAVE_NE_SOCK_CONNECT_TIMEOUT /* we don't need to use alarm() */ #else struct sigaction sa; sigemptyset(&sa.sa_mask); sa.sa_flags = 0; sa.sa_handler = netxml_alarm_handler; sigaction(SIGALRM, &sa, NULL); #endif /* allow override of default network timeout value */ val = getval("timeout"); if (val) { timeout = atoi(val); if (timeout < 1) { fatalx(EXIT_FAILURE, "timeout must be greater than 0"); } } val = getval("shutdown_duration"); if (val) { shutdown_duration = atoi(val); if (shutdown_duration < 0) { fatalx(EXIT_FAILURE, "shutdown duration must be greater than or equal to 0"); } } val = getval("shutdown_timer"); if (val) { shutdown_timer = atoi(val); if (shutdown_timer < 0) { fatalx(EXIT_FAILURE, "shutdown timer must be greater than or equal to 0"); } } if (nut_debug_level > 5) { ne_debug_init(stderr, NE_DBG_HTTP | NE_DBG_HTTPBODY); } if (ne_sock_init()) { fatalx(EXIT_FAILURE, "%s: failed to initialize socket libraries", progname); } if (ne_uri_parse(device_path, &uri) || uri.host == NULL) { fatalx(EXIT_FAILURE, "%s: invalid hostname '%s'", progname, device_path); } /* if (uri.scheme == NULL) { uri.scheme = strdup("http"); } if (uri.host == NULL) { uri.host = strdup(device_path); } */ if (uri.port == 0) { uri.port = ne_uri_defaultport(uri.scheme); } upsdebugx(1, "using %s://%s port %d", uri.scheme, uri.host, uri.port); session = ne_session_create(uri.scheme, uri.host, uri.port); /* timeout if we can't (re)connect to the UPS */ #ifdef HAVE_NE_SET_CONNECT_TIMEOUT ne_set_connect_timeout(session, timeout); #endif /* just wait for a couple of seconds */ ne_set_read_timeout(session, timeout); ne_set_useragent(session, subdriver->version); if (strcasecmp(uri.scheme, "https") == 0) { ne_ssl_trust_default_ca(session); } ne_set_server_auth(session, netxml_authenticate, NULL); /* if debug level is set, direct output to stderr */ if (!nut_debug_level) { #ifndef WIN32 fp = fopen("/dev/null", "w"); #else fp = fopen("nul", "w"); #endif } else { fp = stderr; } if (!fp) { fatal_with_errno(EXIT_FAILURE, "Connectivity test failed"); } /* see if we have a connection */ ret = ne_get(session, subdriver->initups, fileno(fp)); if (!nut_debug_level) { fclose(fp); } else { fprintf(fp, "\n"); } if (ret != NE_OK) { fatalx(EXIT_FAILURE, "Connectivity test: %s", ne_get_error(session)); } upslogx(LOG_INFO, "Connectivity test: %s", ne_get_error(session)); } void upsdrv_cleanup(void) { free(subdriver->configure); free(subdriver->subscribe); free(subdriver->summary); free(subdriver->getobject); free(subdriver->setobject); free(product_page); if (sock) { ne_sock_close(sock); } if (session) { ne_session_destroy(session); } ne_uri_free(&uri); } /********************************************************************** * Support functions *********************************************************************/ static int netxml_get_page(const char *page) { int ret = NE_ERROR; ne_request *request; ne_xml_parser *parser; upsdebugx(2, "%s: %s", __func__, (page != NULL)?page:"(null)"); if (page != NULL) { request = ne_request_create(session, "GET", page); parser = ne_xml_create(); ne_xml_push_handler(parser, subdriver->startelm_cb, subdriver->cdata_cb, subdriver->endelm_cb, NULL); ret = netxml_dispatch_request(request, parser); if (ret) { upsdebugx(2, "%s: %s", __func__, ne_get_error(session)); } ne_xml_destroy(parser); ne_request_destroy(request); } return ret; } static int netxml_alarm_subscribe(const char *page) { ssize_t ret; int secret = -1; unsigned int port = 0; char buf[LARGEBUF], *s; ne_request *request; ne_sock_addr *addr; const ne_inet_addr *ai; char resp_buf[LARGEBUF]; /* Clear response buffer */ memset(resp_buf, 0, sizeof(resp_buf)); upsdebugx(2, "%s: %s", __func__, page); sock = ne_sock_create(); if (gethostname(buf, sizeof(buf)) == 0) { dstate_setinfo("driver.hostname", "%s", buf); } else { dstate_setinfo("driver.hostname", ""); } #ifdef HAVE_NE_SOCK_CONNECT_TIMEOUT ne_sock_connect_timeout(sock, timeout); #endif ne_sock_read_timeout(sock, 1); netxml_get_page(subdriver->configure); snprintf(buf, sizeof(buf), "\n"); snprintfcat(buf, sizeof(buf), "\n"); snprintfcat(buf, sizeof(buf), "%s v%s\n", progname, DRIVER_VERSION); snprintfcat(buf, sizeof(buf), "connected socket\n"); snprintfcat(buf, sizeof(buf), "%s\n", dstate_getinfo("driver.hostname")); snprintfcat(buf, sizeof(buf), "\n"); snprintfcat(buf, sizeof(buf), "%d\n", shutdown_duration); if( shutdown_timer > 0 ) { snprintfcat(buf, sizeof(buf), "%d\r\n", shutdown_timer); } else { snprintfcat(buf, sizeof(buf), "NONE\n"); } snprintfcat(buf, sizeof(buf), "LOCAL\n"); snprintfcat(buf, sizeof(buf), "1\n"); snprintfcat(buf, sizeof(buf), "\n"); snprintfcat(buf, sizeof(buf), "\n"); snprintfcat(buf, sizeof(buf), "\n"); /* now send subscription message setting all the proper flags */ request = ne_request_create(session, "POST", page); ne_set_request_body_buffer(request, buf, strlen(buf)); /* as the NMC reply is not xml standard compliant let's parse it this way */ do { #ifndef HAVE_NE_SOCK_CONNECT_TIMEOUT alarm(timeout+1); #endif ret = ne_begin_request(request); #ifndef HAVE_NE_SOCK_CONNECT_TIMEOUT alarm(0); #endif if (ret != NE_OK) { break; } ret = ne_read_response_block(request, resp_buf, sizeof(resp_buf)); if (ret == NE_OK) { ret = ne_end_request(request); } } while (ret == NE_RETRY); ne_request_destroy(request); /* due to different formats used by the various NMCs, we need to\ break up the reply in lines and parse each one separately */ for (s = strtok(resp_buf, "\r\n"); s != NULL; s = strtok(NULL, "\r\n")) { long long int tmp_port = -1, tmp_secret = -1; upsdebugx(2, "%s: parsing %s", __func__, s); if (!strncasecmp(s, "", 6) && (sscanf(s+6, "%lli", &tmp_port) != 1)) { return NE_RETRY; } /* FIXME? Does a port==0 make sense here? Or should the test below be for port<1? * Legacy code until a fix here used sscanf() above to get a '%u' value... */ if (tmp_port < 0 || tmp_port > UINT_MAX) { upsdebugx(2, "%s: parsing initial subcription failed, bad port value", __func__); return NE_RETRY; } if (!strncasecmp(s, "", 8) && (sscanf(s+8, "%lli", &tmp_secret) != 1)) { return NE_RETRY; } if (tmp_secret < 0 || tmp_secret > UINT_MAX) { upsdebugx(2, "%s: parsing initial subcription failed, bad secret value", __func__); return NE_RETRY; } /* Range of valid values constrained above */ port = (unsigned int)tmp_port; secret = (int)tmp_secret; } if ((port < 1) || (secret == -1)) { upsdebugx(2, "%s: parsing initial subcription failed", __func__); return NE_RETRY; } /* Resolve the given hostname. 'flags' must be zero. Hex * string IPv6 addresses (e.g. `::1') may be enclosed in brackets * (e.g. `[::1]'). */ addr = ne_addr_resolve(uri.host, 0); /* Returns zero if name resolution was successful, non-zero on * error. */ if (ne_addr_result(addr) != 0) { upsdebugx(2, "%s: name resolution failure on %s: %s", __func__, uri.host, ne_addr_error(addr, buf, sizeof(buf))); ne_addr_destroy(addr); return NE_RETRY; } for (ai = ne_addr_first(addr); ai != NULL; ai = ne_addr_next(addr)) { upsdebugx(2, "%s: connecting to host %s port %d", __func__, ne_iaddr_print(ai, buf, sizeof(buf)), port); #ifndef HAVE_NE_SOCK_CONNECT_TIMEOUT alarm(timeout+1); #endif ret = ne_sock_connect(sock, ai, port); #ifndef HAVE_NE_SOCK_CONNECT_TIMEOUT alarm(0); #endif if (ret == NE_OK) { upsdebugx(2, "%s: connection to %s open on fd %d", __func__, uri.host, ne_sock_fd(sock)); break; } } ne_addr_destroy(addr); if (ai == NULL) { upsdebugx(2, "%s: failed to create listening socket", __func__); return NE_RETRY; } snprintf(buf, sizeof(buf), "", secret); ret = ne_sock_fullwrite(sock, buf, strlen(buf) + 1); if (ret != NE_OK) { upsdebugx(2, "%s: send failed: %s", __func__, ne_sock_error(sock)); return NE_RETRY; } ret = ne_sock_read(sock, buf, sizeof(buf)); if (ret < 1) { upsdebugx(2, "%s: read failed: %s", __func__, ne_sock_error(sock)); return NE_RETRY; } if (strcasecmp(buf, "")) { upsdebugx(2, "%s: subscription rejected", __func__); return NE_RETRY; } upslogx(LOG_INFO, "NSM connection to '%s' established", uri.host); return NE_OK; } static int netxml_dispatch_request(ne_request *request, ne_xml_parser *parser) { int ret; /* * Starting with neon-0.27.0 the ne_xml_dispatch_request() function will check * for a valid XML content-type (following RFC 3023 rules) in the header. * Unfortunately, (at least) the Transverse NMC doesn't follow this RFC, so * we can't use this anymore and we'll have to roll our own here. */ do { #ifndef HAVE_NE_SET_CONNECT_TIMEOUT alarm(timeout+1); #endif ret = ne_begin_request(request); #ifndef HAVE_NE_SET_CONNECT_TIMEOUT alarm(0); #endif if (ret != NE_OK) { break; } ret = ne_xml_parse_response(request, parser); if (ret == NE_OK) { ret = ne_end_request(request); } } while (ret == NE_RETRY); return ret; } /* Supply the 'login' and 'password' when authentication is required */ static int netxml_authenticate(void *userdata, const char *realm, int attempt, char *username, char *password) { char *val; NUT_UNUSED_VARIABLE(userdata); upsdebugx(2, "%s: realm = [%s], attempt = %d", __func__, realm, attempt); val = getval("login"); snprintf(username, NE_ABUFSIZ, "%s", val ? val : ""); val = getval("password"); snprintf(password, NE_ABUFSIZ, "%s", val ? val : ""); return attempt; } /* Convert the local status information to NUT format and set NUT alarms. */ static void netxml_alarm_set(void) { if (STATUS_BIT(REPLACEBATT)) { alarm_set("Replace battery!"); } if (STATUS_BIT(SHUTDOWNIMM)) { alarm_set("Shutdown imminent!"); } if (STATUS_BIT(FANFAIL)) { alarm_set("Fan failure!"); } if (STATUS_BIT(NOBATTERY)) { alarm_set("No battery installed!"); } if (STATUS_BIT(BATTVOLTLO)) { alarm_set("Battery voltage too low!"); } if (STATUS_BIT(BATTVOLTHI)) { alarm_set("Battery voltage too high!"); } if (STATUS_BIT(CHARGERFAIL)) { alarm_set("Battery charger fail!"); } if (STATUS_BIT(OVERHEAT)) { alarm_set("Temperature too high!"); } if (STATUS_BIT(COMMFAULT)) { alarm_set("Communication fault!"); } if (STATUS_BIT(INTERNALFAULT)) { alarm_set("Internal UPS fault!"); } if (STATUS_BIT(FUSEFAULT)) { alarm_set("Fuse fault!"); } if (STATUS_BIT(BYPASSAUTO)) { alarm_set("Automatic bypass mode!"); } if (STATUS_BIT(BYPASSMAN)) { alarm_set("Manual bypass mode!"); } } /* Convert the local status information to NUT format and set NUT status. */ static void netxml_status_set(void) { if (STATUS_BIT(VRANGE)) { dstate_setinfo("input.transfer.reason", "input voltage out of range"); } else if (STATUS_BIT(FRANGE)) { dstate_setinfo("input.transfer.reason", "input frequency out of range"); } else { dstate_delinfo("input.transfer.reason"); } if (STATUS_BIT(ONLINE)) { status_set("OL"); /* on line */ } else { status_set("OB"); /* on battery */ } if (STATUS_BIT(DISCHRG)) { status_set("DISCHRG"); /* discharging */ } if (STATUS_BIT(CHRG)) { status_set("CHRG"); /* charging */ } if (STATUS_BIT(LOWBATT)) { status_set("LB"); /* low battery */ } if (STATUS_BIT(OVERLOAD)) { status_set("OVER"); /* overload */ } if (STATUS_BIT(REPLACEBATT)) { status_set("RB"); /* replace batt */ } if (STATUS_BIT(TRIM)) { status_set("TRIM"); /* SmartTrim */ } if (STATUS_BIT(BOOST)) { status_set("BOOST"); /* SmartBoost */ } if (STATUS_BIT(BYPASSAUTO) || STATUS_BIT(BYPASSMAN)) { status_set("BYPASS"); /* on bypass */ } if (STATUS_BIT(OFF)) { status_set("OFF"); /* ups is off */ } if (STATUS_BIT(SHUTDOWNIMM)) { status_set("FSD"); /* shutdown imminent */ } if (STATUS_BIT(CALIB)) { status_set("CAL"); /* calibrating */ } } /* * *_OBJECT interface implementation */ static object_query_t *object_query_create( object_query_type_t type, object_post_mode_t mode) { object_query_t *handle = (object_query_t *)calloc(1, sizeof(object_query_t)); if (NULL == handle) return NULL; handle->type = type; handle->mode = mode; return handle; } static size_t object_query_size(object_query_t *handle) { assert(NULL != handle); return handle->cnt; } /** * \brief SET_OBJECT request list entry destructor * * \param req SET_OBJECT request list entry */ static void set_object_req_destroy(set_object_req_t *req) { assert(NULL != req); if (NULL != req->name) free(req->name); if (NULL != req->value) free(req->value); } /** * \brief SET_OBJECT response list entry destructor * * \param resp SET_OBJECT response list entry */ static void set_object_resp_destroy(set_object_resp_t *resp) { assert(NULL != resp); if (NULL != resp->name) free(resp->name); if (NULL != resp->unit) free(resp->unit); if (NULL != resp->access) free(resp->access); if (NULL != resp->value) free(resp->value); } /** * \brief *_OBJECT query entry destructor * * \param handle SET_OBJECT query handle * \param entry SET_OBJECT query entry */ static void object_entry_destroy(object_query_t *handle, object_entry_t *entry) { assert(NULL != handle); assert(NULL != entry); /* Sanity checks */ assert(0 < handle->cnt); /* Relink list */ if (entry == handle->head) { handle->head = entry->next; } else { assert(NULL != entry->prev); entry->prev->next = entry->next; } if (entry == handle->tail) { handle->tail = entry->prev; } else { assert(NULL != entry->next); entry->next->prev = entry->prev; } --handle->cnt; /* Destroy payload */ switch (handle->type) { case SET_OBJECT_REQUEST: set_object_req_destroy(&entry->payld.req); break; case SET_OBJECT_RESPONSE: set_object_resp_destroy(&entry->payld.resp); break; } /* Destroy entry */ free(entry); } static void object_query_destroy(object_query_t *handle) { assert(NULL != handle); /* Destroy entries */ while (handle->cnt) object_entry_destroy(handle, handle->head); /* Destroy handle */ free(handle); } /** * \brief Add *_OBJECT list entry (at list end) * * \param handle Entry list handle * \param entry Entry */ static void object_add_entry(object_query_t *handle, object_entry_t *entry) { assert(NULL != handle); assert(NULL != entry); /* Sanity checks */ assert(SET_OBJECT_REQUEST == handle->type); /* Add entry at end of bi-directional list */ if (handle->cnt) { assert(NULL != handle->tail); assert(NULL == handle->tail->next); handle->tail->next = entry; entry->prev = handle->tail; } /* Add the very first entry */ else { handle->head = entry; entry->prev = NULL; } handle->tail = entry; entry->next = NULL; ++handle->cnt; } static object_entry_t *set_object_add( object_query_t *handle, const char *name, const char *value) { char *name_cpy; char *value_cpy; object_entry_t *entry; assert(NULL != name); assert(NULL != value); entry = (object_entry_t *)calloc(1, sizeof(object_entry_t)); if (NULL == entry) return NULL; /* Copy payload data */ name_cpy = strdup(name); value_cpy = strdup(value); /* Cleanup in case of memory error */ if (NULL == name_cpy || NULL == value_cpy) { if (NULL != name_cpy) free(name_cpy); if (NULL != value_cpy) free(value_cpy); free(entry); return NULL; } /* Set payload */ entry->payld.req.name = name_cpy; entry->payld.req.value = value_cpy; /* Enlist */ object_add_entry(handle, entry); return entry; } /** * \brief Common SET_OBJECT entries serialiser * * \param buff Buffer * \param entry SET_OBJECT request entry * * \return OBJECT_OK on success * \return OBJECT_ERROR otherwise */ static object_query_status_t set_object_serialise_entries(ne_buffer *buff, object_entry_t *entry) { object_query_status_t status = OBJECT_OK; assert(NULL != buff); ne_buffer_zappend(buff, "\r\n"); ne_buffer_zappend(buff, "\r\n"); for (; NULL != entry; entry = entry->next) { const char *vname = vname_nut2mge_xml(entry->payld.req.name); /* Serialise one object */ if (NULL != vname) { ne_buffer_zappend(buff, " "); ne_buffer_zappend(buff, entry->payld.req.value); ne_buffer_zappend(buff, "\r\n"); } /* Var. name resolution error */ else status = OBJECT_ERROR; } ne_buffer_zappend(buff, "\r\n"); return status; } static ne_buffer *set_object_serialise_raw(object_query_t *handle) { ne_buffer *buff; assert(NULL != handle); /* Sanity checks */ assert(SET_OBJECT_REQUEST == handle->type); /* Create buffer */ buff = ne_buffer_create(); /* neon API ref. states that the function always succeeds */ assert(NULL != buff); /* Serialise all entries */ set_object_serialise_entries(buff, handle->head); return buff; } static ne_buffer *set_object_serialise_form(object_query_t *handle) { const char *vname = NULL; ne_buffer *buff; assert(NULL != handle); /* Sanity checks */ assert(SET_OBJECT_REQUEST == handle->type); /* Create buffer */ buff = ne_buffer_create(); /* neon API ref. states that the function always succeeds */ assert(NULL != buff); /* Simple request */ if (1 == object_query_size(handle)) { assert(NULL != handle->head); /* TODO: Simple req. doesn't seem to work vname = vname_nut2mge_xml(handle->head->payld.req.name); */ } if (NULL != vname) { assert(NULL != handle->head); ne_buffer_zappend(buff, "objectName="); ne_buffer_zappend(buff, vname); ne_buffer_zappend(buff, "&objectValue="); ne_buffer_zappend(buff, handle->head->payld.req.value); } /* Multi set request (or empty request) */ else { /* Add request prologue */ ne_buffer_zappend(buff, "--" FORM_POST_BOUNDARY "\r\n"); ne_buffer_zappend(buff, "Content-Disposition: form-data; name=\"file\"; " "filename=\"Configuration.xml\"\r\n"); ne_buffer_zappend(buff, "Content-Type: application/octet-stream\r\n"); ne_buffer_zappend(buff, "\r\n"); /* Serialise all entries */ set_object_serialise_entries(buff, handle->head); /* Add request epilogue */ ne_buffer_zappend(buff, "--" FORM_POST_BOUNDARY "--\r\n"); } return buff; } /** * \brief neon callback for SET_OBJECT RAW POST mode response element start * * \param userdata Obfuscated SET_OBJECT_RESPONSE query handle * \param parent Element parent * \param nspace Element namespace (empty) * \param name Element name * \param attrs Element attributes * * \return \c NE_XML_STATEROOT + distance of the element from root */ static int set_object_raw_resp_start_element( void *userdata, int parent, const char *nspace, const char *name, const char **attrs) { object_query_t *handle = (object_query_t *)userdata; assert(NULL != handle); /* Sanity checks */ assert(SET_OBJECT_RESPONSE == handle->type); /* Check that namespace is empty */ if (NULL != nspace && '\0' != *nspace) { handle->status = OBJECT_PARSE_ERROR; return NE_XML_STATEROOT; } /* OBJECT (as a SET_OBJECT child) */ if (NE_XML_STATEROOT + 1 == parent && 0 == strcasecmp(name, "OBJECT")) { size_t i; object_entry_t *entry = (object_entry_t *)calloc(1, sizeof(object_entry_t)); /* Memory error */ if (NULL == entry) { handle->status = OBJECT_ERROR; return NE_XML_STATEROOT; } /* Set attributes */ for (i = 0; NULL != attrs[i] && NULL != attrs[i + 1]; i += 2) { char **attr = NULL; const char *aval = NULL; /* Skip unset attribute name and/or value (useless) */ if (NULL == attrs[i] || NULL == attrs[i + 1]) continue; /* Obviously, the following holds, now */ assert(NULL != attrs[i]); assert(NULL != attrs[i + 1]); /* name */ if (0 == strcasecmp(attrs[i], "name")) { attr = &entry->payld.resp.name; aval = vname_mge_xml2nut(attrs[i + 1]); } /* unit */ else if (0 == strcasecmp(attrs[i], "unit")) { attr = &entry->payld.resp.unit; aval = attrs[i + 1]; } /* access */ else if (0 == strcasecmp(attrs[i], "access")) { attr = &entry->payld.resp.access; aval = attrs[i + 1]; } /* Set known attribute */ if (NULL != attr) { /* Copy value */ if (NULL != aval) { *attr = strdup(aval); if (NULL == *attr) handle->status = OBJECT_ERROR; } /* Value resolution error */ else handle->status = OBJECT_ERROR; } } object_add_entry(handle, entry); return NE_XML_STATEROOT + 2; /* signal to cdata callback */ } /* SET_OBJECT (as the root child) */ if (NE_XML_STATEROOT == parent && 0 == strcasecmp(name, "SET_OBJECT")) return NE_XML_STATEROOT + 1; /* Unknown element (as a SET_OBJECT child) */ if (NE_XML_STATEROOT + 1 == parent) return NE_XML_STATEROOT + 1; /* Ignore any other root children */ return NE_XML_STATEROOT; } /** * \brief neon callback for SET_OBJECT RAW POST mode response data start * * The callback is used to set OBJECT element value. * This is done for state \c NE_XML_STATEROOT + 2 * (see \ref set_object_raw_resp_start_element). * * \param userdata Obfuscated SET_OBJECT_RESPONSE query handle * \param state Element distance from root * \param cdata Character data * \param len Character data length * * \return state */ static int set_object_raw_resp_cdata( void *userdata, int state, const char *cdata, size_t len) { object_query_t *handle = (object_query_t *)userdata; assert(NULL != handle); /* Sanity checks */ assert(SET_OBJECT_RESPONSE == handle->type); /* Ignore any element except OBJECT */ if (NE_XML_STATEROOT + 2 != state) return state; if (OBJECT_OK == handle->status) { char *value; /* Set last object value */ assert(NULL != handle->tail); assert(NULL != handle->tail->payld.resp.name); value = vvalue_mge_xml2nut(handle->tail->payld.resp.name, cdata, len); handle->tail->payld.resp.value = value; if (NULL == handle->tail->payld.resp.value) handle->status = OBJECT_ERROR; } return state; } /** * \brief neon callback for SET_OBJECT RAW POST mode response element start * * \param userdata Obfuscated SET_OBJECT_RESPONSE query handle * \param state Element distance from root * \param nspace Element namespace (empty) * \param name Element name * * \return \c NE_XML_STATEROOT + distance of the element from root */ static int set_object_raw_resp_end_element( void *userdata, int state, const char *nspace, const char *name) { NUT_UNUSED_VARIABLE(userdata); NUT_UNUSED_VARIABLE(nspace); /* OBJECT (as a SET_OBJECT child) */ if (NE_XML_STATEROOT + 2 == state) { assert(0 == strcasecmp(name, "OBJECT")); return NE_XML_STATEROOT + 1; } /* * Otherwise, state is either NE_XML_STATEROOT or NE_XML_STATEROOT + 1 * In any case, we return NE_XML_STATEROOT */ return NE_XML_STATEROOT; } static object_query_t *set_object_deserialise_raw(ne_buffer *buff) { int ne_status; object_query_t *handle; ne_xml_parser *parser; assert(NULL != buff); /* Create SET_OBJECT query response */ handle = object_query_create(SET_OBJECT_RESPONSE, RAW_POST); if (NULL == handle) return NULL; /* Create XML parser */ parser = ne_xml_create(); /* neon API ref. states that the function always succeeds */ assert(NULL != parser); /* Set element & data handlers */ ne_xml_push_handler( parser, set_object_raw_resp_start_element, set_object_raw_resp_cdata, set_object_raw_resp_end_element, handle); /* Parse the response */ ne_status = ne_xml_parse(parser, buff->data, buff->used); if (NE_OK != ne_status) handle->status = OBJECT_PARSE_ERROR; /* Destroy parser */ ne_xml_destroy(parser); return handle; } /** * \brief Send HTTP request over a session * * The function creates HTTP request, sends it and reads-out the response. * * \param[in] argsession HTTP session * \param[in] method Request method * \param[in] arguri Request URI * \param[in] ct Request content type (optional, \c NULL accepted) * \param[in] req_body Request body (optional, \c NULL is accepted) * \param[out] resp_body Response body (optional, \c NULL is accepted) * * \return HTTP status code if response was sent, 0 on send error */ static int send_http_request( ne_session *argsession, const char *method, const char *arguri, const char *ct, ne_buffer *req_body, ne_buffer *resp_body) { int resp_code = 0; ne_request *req = NULL; /* Create request */ req = ne_request_create(argsession, method, arguri); /* Neon claims that request creation is always successful */ assert(NULL != req); do { /* Pragmatic do ... while (0) loop allowing breaks on error */ const ne_status *req_st; int status; /* Set Content-Type */ if (NULL != ct) ne_add_request_header(req, "Content-Type", ct); /* Set request body */ if (NULL != req_body) /* BEWARE: The terminating '\0' byte is "used", too */ ne_set_request_body_buffer(req, req_body->data, req_body->used - 1); /* Send request */ status = ne_begin_request(req); if (NE_OK != status) { break; } /* Read response */ assert(NE_OK == status); for (;;) { char buff[512]; ssize_t read; read = ne_read_response_block(req, buff, sizeof(buff)); /* Read failure */ if (0 > read) { status = NE_ERROR; break; } if (0 == read) break; if (NULL != resp_body) ne_buffer_append(resp_body, buff, (size_t)read); } if (NE_OK != status) { break; } /* Request served */ ne_end_request(req); /* Get response code */ req_st = ne_get_status(req); assert(NULL != req_st); resp_code = req_st->code; } while (0); /* end of do ... while (0) pragmatic loop */ if (NULL != req) ne_request_destroy(req); return resp_code; } static object_query_t *set_object_raw(object_query_t *req) { int resp_code; object_query_t *resp = NULL; ne_buffer *req_body = NULL; ne_buffer *resp_body = NULL; assert(NULL != req); /* Sanity check */ assert(SET_OBJECT_REQUEST == req->type); assert(RAW_POST == req->mode); /* Serialise request POST data */ req_body = set_object_serialise_raw(req); /* Send request */ resp_body = ne_buffer_create(); assert(NULL != resp_body); resp_code = send_http_request(session, "POST", "/set_obj.htm", NULL, req_body, resp_body); /* * Repeat in case of 401 - Unauthorised * * Note that this is a WA of NMC sending Connection: close * header in the 401 response, in which case neon closes * connection (quite rightfully). */ if (401 == resp_code) resp_code = send_http_request(session, "POST", "/set_obj.htm", NULL, req_body, resp_body); /* Deserialise response */ if (200 == resp_code) resp = set_object_deserialise_raw(resp_body); /* Cleanup */ if (NULL != req_body) ne_buffer_destroy(req_body); if (NULL != resp_body) ne_buffer_destroy(resp_body); return resp; } static object_query_t *set_object_form(object_query_t *req) { int resp_code; ne_buffer *req_body = NULL; const char *ct = "multipart/form-data; boundary=" FORM_POST_BOUNDARY; /* TODO: Single request doesn't seem to work if (1 == object_query_size(req)) ct = "application/x-form-urlencoded"; */ assert(NULL != req); /* Sanity check */ assert(SET_OBJECT_REQUEST == req->type); assert(FORM_POST == req->mode); /* Serialise request POST data */ req_body = set_object_serialise_form(req); /* Send request (response is ignored by the proto. spec v3) */ resp_code = send_http_request(session, "POST", "/Forms/set_obj_2", ct, req_body, NULL); /* * Repeat in case of 401 - Unauthorised * * Note that this is a WA of NMC sending Connection: close * header in the 401 response, in which case neon closes * connection (quite rightfully). */ if (401 == resp_code) { resp_code = send_http_request(session, "POST", "/Forms/set_obj_2", ct, req_body, NULL); } /* Cleanup */ if (NULL != req_body) ne_buffer_destroy(req_body); return NULL; } static object_query_t *set_object(object_query_t *req) { object_query_t *resp = NULL; assert(NULL != req); /* Sanity checks */ assert(SET_OBJECT_REQUEST == req->type); /* Select implementation by POST request mode */ switch (req->mode) { case RAW_POST: resp = set_object_raw(req); break; case FORM_POST: resp = set_object_form(req); break; } return resp; } nut-2.8.1/drivers/hpe-pdu-mib.c0000644000175000017500000012320214502253356013207 00000000000000/* hpe-pdu-mib.c - subdriver to monitor HPE ePDU SNMP devices with NUT * * Copyright (C) * 2011 - 2016 Arnaud Quette * 2019 Arnaud Quette * * 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 2 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, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #include "hpe-pdu-mib.h" #include "dstate.h" #define HPE_EPDU_MIB_VERSION "0.33" #define HPE_EPDU_MIB_SYSOID ".1.3.6.1.4.1.232.165.7" #define HPE_EPDU_OID_MODEL_NAME ".1.3.6.1.4.1.232.165.7.1.2.1.3.0" static info_lkp_t hpe_pdu_outlet_status_info[] = { { 1, "off", NULL, NULL }, { 2, "on", NULL, NULL }, { 3, "pendingOff", NULL, NULL }, /* transitional status */ { 4, "pendingOn", NULL, NULL }, /* transitional status */ { 0, NULL, NULL, NULL } }; static info_lkp_t hpe_pdu_outletgroups_status_info[] = { { 1, "N/A", NULL, NULL }, /* notApplicable, if group.type == outlet-section */ { 2, "on", NULL, NULL }, /* breakerOn */ { 3, "off", NULL, NULL }, /* breakerOff */ { 0, NULL, NULL, NULL } }; static info_lkp_t hpe_pdu_outlet_switchability_info[] = { { 1, "yes", NULL, NULL }, { 2, "no", NULL, NULL }, { 0, NULL, NULL, NULL } }; /* The physical type of outlet */ static info_lkp_t hpe_pdu_outlet_type_info[] = { { 0, "unknown", NULL, NULL }, { 1, "iecC13", NULL, NULL }, { 2, "iecC19", NULL, NULL }, { 10, "uk", NULL, NULL }, { 11, "french", NULL, NULL }, { 12, "schuko", NULL, NULL }, { 20, "nema515", NULL, NULL }, { 21, "nema51520", NULL, NULL }, { 22, "nema520", NULL, NULL }, { 23, "nemaL520", NULL, NULL }, { 24, "nemaL530", NULL, NULL }, { 25, "nema615", NULL, NULL }, { 26, "nema620", NULL, NULL }, { 27, "nemaL620", NULL, NULL }, { 28, "nemaL630", NULL, NULL }, { 29, "nemaL715", NULL, NULL }, { 30, "rf203p277", NULL, NULL }, { 0, NULL, NULL, NULL } }; static info_lkp_t hpe_pdu_ambient_presence_info[] = { { -1, "unknown", NULL, NULL }, { 1, "no", NULL, NULL }, /* disconnected */ { 2, "yes", NULL, NULL }, /* connected */ { 0, NULL, NULL, NULL } }; static info_lkp_t hpe_pdu_threshold_status_info[] = { { 1, "good", NULL, NULL }, /* No threshold triggered */ { 2, "warning-low", NULL, NULL }, /* Warning low threshold triggered */ { 3, "critical-low", NULL, NULL }, /* Critical low threshold triggered */ { 4, "warning-high", NULL, NULL }, /* Warning high threshold triggered */ { 5, "critical-high", NULL, NULL }, /* Critical high threshold triggered */ { 0, NULL, NULL, NULL } }; static info_lkp_t hpe_pdu_threshold_frequency_status_info[] = { { 1, "good", NULL, NULL }, /* No threshold triggered */ { 2, "out-of-range", NULL, NULL }, /* Frequency out of range triggered */ { 0, NULL, NULL, NULL } }; static info_lkp_t hpe_pdu_ambient_drycontacts_info[] = { { -1, "unknown", NULL, NULL }, { 0, "unknown", NULL, NULL }, { 1, "open", NULL, NULL }, { 2, "closed", NULL, NULL }, { 3, "bad", NULL, NULL }, /* FIXME: what to do with that? */ { 0, NULL, NULL, NULL } }; static info_lkp_t hpe_pdu_threshold_voltage_alarms_info[] = { { 1, "", NULL, NULL }, /* No threshold triggered */ { 2, "low voltage warning!", NULL, NULL }, /* Warning low threshold triggered */ { 3, "low voltage critical!", NULL, NULL }, /* Critical low threshold triggered */ { 4, "high voltage warning!", NULL, NULL }, /* Warning high threshold triggered */ { 5, "high voltage critical!", NULL, NULL }, /* Critical high threshold triggered */ { 0, NULL, NULL, NULL } }; static info_lkp_t hpe_pdu_threshold_current_alarms_info[] = { { 1, "", NULL, NULL }, /* No threshold triggered */ { 2, "low current warning!", NULL, NULL }, /* Warning low threshold triggered */ { 3, "low current critical!", NULL, NULL }, /* Critical low threshold triggered */ { 4, "high current warning!", NULL, NULL }, /* Warning high threshold triggered */ { 5, "high current critical!", NULL, NULL }, /* Critical high threshold triggered */ { 0, NULL, NULL, NULL } }; static info_lkp_t hpe_pdu_threshold_frequency_alarm_info[] = { { 1, "", NULL, NULL }, /* No threshold triggered */ { 2, "frequency out of range!", NULL, NULL }, /* Frequency out of range triggered */ { 0, NULL, NULL, NULL } }; static info_lkp_t hpe_pdu_threshold_temperature_alarms_info[] = { { 1, "", NULL, NULL }, /* No threshold triggered */ { 2, "low temperature warning!", NULL, NULL }, /* Warning low threshold triggered */ { 3, "low temperature critical!", NULL, NULL }, /* Critical low threshold triggered */ { 4, "high temperature warning!", NULL, NULL }, /* Warning high threshold triggered */ { 5, "high temperature critical!", NULL, NULL }, /* Critical high threshold triggered */ { 0, NULL, NULL, NULL } }; static info_lkp_t hpe_pdu_threshold_humidity_alarms_info[] = { { 1, "", NULL, NULL }, /* No threshold triggered */ { 2, "low humidity warning!", NULL, NULL }, /* Warning low threshold triggered */ { 3, "low humidity critical!", NULL, NULL }, /* Critical low threshold triggered */ { 4, "high humidity warning!", NULL, NULL }, /* Warning high threshold triggered */ { 5, "high humidity critical!", NULL, NULL }, /* Critical high threshold triggered */ { 0, NULL, NULL, NULL } }; static info_lkp_t hpe_pdu_outlet_group_type_info[] = { { 0, "unknown", NULL, NULL }, { 1, "unknown", NULL, NULL }, { 2, "breaker1pole", NULL, NULL }, { 3, "breaker2pole", NULL, NULL }, { 4, "breaker3pole", NULL, NULL }, { 5, "outlet-section", NULL, NULL }, { 0, NULL, NULL, NULL } }; static info_lkp_t hpe_pdu_input_type_info[] = { { 1, "1", NULL, NULL }, /* singlePhase */ { 2, "2", NULL, NULL }, /* splitPhase */ { 3, "3", NULL, NULL }, /* threePhaseDelta */ { 4, "3", NULL, NULL }, /* threePhaseWye */ { 0, NULL, NULL, NULL } }; static info_lkp_t hpe_pdu_outlet_group_phase_info[] = { { 1, "L1", NULL, NULL }, /* singlePhase */ { 2, "L1", NULL, NULL }, /* phase1toN */ { 3, "L2", NULL, NULL }, /* phase2toN */ { 4, "L3", NULL, NULL }, /* phase3toN */ { 5, "L1", NULL, NULL }, /* phase1to2 */ { 6, "L2", NULL, NULL }, /* phase2to3 */ { 7, "L3", NULL, NULL }, /* phase3to1 */ { 0, NULL, NULL, NULL } }; /* Snmp2NUT lookup table for HPE PDU MIB */ static snmp_info_t hpe_pdu_mib[] = { /* standard MIB items */ { "device.description", ST_FLAG_STRING | ST_FLAG_RW, SU_INFOSIZE, ".1.3.6.1.2.1.1.1.0", NULL, SU_FLAG_OK, NULL }, { "device.contact", ST_FLAG_STRING | ST_FLAG_RW, SU_INFOSIZE, ".1.3.6.1.2.1.1.4.0", NULL, SU_FLAG_OK, NULL }, { "device.location", ST_FLAG_STRING | ST_FLAG_RW, SU_INFOSIZE, ".1.3.6.1.2.1.1.6.0", NULL, SU_FLAG_OK, NULL }, /* Device collection */ { "device.mfr", ST_FLAG_STRING, SU_INFOSIZE, NULL, "HPE", SU_FLAG_STATIC | SU_FLAG_ABSENT | SU_FLAG_OK, NULL }, /* pdu2Model.0 = STRING: "HP 8.6kVA 208V 30A 3Ph NA/JP maPDU" */ { "device.model", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.232.165.7.1.2.1.3.%i", "HPE ePDU", SU_FLAG_STATIC | SU_FLAG_OK, NULL }, /* pdu2SerialNumber.0 = STRING: "CN94230105" */ { "device.serial", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.232.165.7.1.2.1.7.%i", "", SU_FLAG_STATIC | SU_FLAG_OK, NULL }, { "device.type", ST_FLAG_STRING, SU_INFOSIZE, NULL, "pdu", SU_FLAG_STATIC | SU_FLAG_ABSENT | SU_FLAG_OK, NULL }, /* pdu2PartNumber.0 = STRING: "H8B52A" */ { "device.part", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.232.165.7.1.2.1.6.%i", "", SU_FLAG_STATIC | SU_FLAG_OK, NULL }, /* For daisychain, there is only 1 physical interface! */ { "device.macaddr", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.2.1.2.2.1.6.2", "", SU_FLAG_STATIC | SU_FLAG_OK, NULL }, /* Daisychained devices support * Notes: this definition is used to: * - estimate the number of devices, based on the below OID iteration capabilities * - determine the base index of the SNMP OID (ie 0 or 1) */ /* pdu2NumberPDU.0 = INTEGER: 1 */ { "device.count", 0, 1, ".1.3.6.1.4.1.232.165.7.1.1.0", "1", SU_FLAG_STATIC, NULL }, /* UPS collection */ { "ups.mfr", ST_FLAG_STRING, SU_INFOSIZE, NULL, "HPE", SU_FLAG_STATIC | SU_FLAG_ABSENT | SU_FLAG_OK, NULL }, { "ups.model", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.232.165.7.1.2.1.3.%i", "HPE ePDU", SU_FLAG_STATIC | SU_FLAG_OK, NULL }, /* FIXME: use unitName.0 (ePDU)? * { "ups.id", ST_FLAG_STRING, SU_INFOSIZE, AR_OID_DEVICE_NAME, "unknown", SU_FLAG_STATIC | SU_FLAG_OK, NULL, NULL }, */ { "ups.serial", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.232.165.7.1.2.1.7.%i", "", SU_FLAG_STATIC | SU_FLAG_OK, NULL }, /* FIXME: this entry should be SU_FLAG_SEMI_STATIC */ /* pdu2FirmwareVersion.0 = STRING: "02.00.0043" */ { "ups.firmware", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.232.165.7.1.2.1.5.%i", "", SU_FLAG_OK, NULL }, { "ups.type", ST_FLAG_STRING, SU_INFOSIZE, NULL, "pdu", SU_FLAG_STATIC | SU_FLAG_ABSENT | SU_FLAG_OK, NULL }, /* FIXME: needs a date reformatting callback * 2011-8-29,16:27:25.0,+1:0 * Hex-STRING: 07 DB 08 1D 10 0C 36 00 2B 01 00 00 * { "ups.date", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.534.6.6.7.1.2.1.8.0", "", SU_FLAG_STATIC | SU_FLAG_OK, NULL }, * { "ups.time", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.534.6.6.7.1.2.1.8.0", "", SU_FLAG_STATIC | SU_FLAG_OK, NULL }, */ /* Input collection */ /* Note: for daisychain mode, we must handle phase(s) per device, not as a whole */ /* pdu2InputType.0 = INTEGER: threePhaseWye(4) */ { "input.phases", 0, 1, ".1.3.6.1.4.1.232.165.7.2.1.1.1.%i", NULL, SU_FLAG_STATIC, &hpe_pdu_input_type_info[0] }, /* Frequency is measured globally */ /* pdu2InputFrequency.0 = INTEGER: 500 */ { "input.frequency", 0, 0.1, ".1.3.6.1.4.1.232.165.7.2.1.1.2.%i", NULL, 0, NULL }, /* pdu2InputFrequencyStatus.0 = INTEGER: good(1) */ { "input.frequency.status", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.232.165.7.2.1.1.3.%i", NULL, SU_FLAG_OK, &hpe_pdu_threshold_frequency_status_info[0] }, { "ups.alarm", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.232.165.7.2.1.1.3.%i", NULL, SU_FLAG_OK, &hpe_pdu_threshold_frequency_alarm_info[0] }, /* inputCurrentPercentLoad (measured globally) * Current percent load, based on the rated current capacity */ /* FIXME: input.load is mapped on input.L1.load for both single and 3phase !!! */ { "input.load", 0, 1.0, ".1.3.6.1.4.1.534.6.6.7.3.3.1.11.%i.1.1", NULL, SU_FLAG_NEGINVALID | SU_FLAG_OK, NULL }, /* pdu2InputPhaseCurrentPercentLoad.0.1 = INTEGER: 0 */ { "input.L1.load", 0, 1.0, ".1.3.6.1.4.1.232.165.7.2.2.1.18.%i.1", NULL, SU_FLAG_NEGINVALID | SU_FLAG_OK, NULL }, /* pdu2InputPhaseCurrentPercentLoad.0.2 = INTEGER: 0 */ { "input.L1.load", 0, 1.0, ".1.3.6.1.4.1.232.165.7.2.2.1.18.%i.2", NULL, SU_FLAG_NEGINVALID | SU_FLAG_OK, NULL }, /* pdu2InputPhaseCurrentPercentLoad.0.3 = INTEGER: 0 */ { "input.L1.load", 0, 1.0, ".1.3.6.1.4.1.232.165.7.2.2.1.18.%i.3", NULL, SU_FLAG_NEGINVALID | SU_FLAG_OK, NULL }, /* FIXME: * - Voltage is only measured per phase, as mV! * so input.voltage == input.L1.voltage for both single and 3phase * - As per NUT namespace (https://www.networkupstools.org/docs/developer-guide.chunked/apas01.html#_valid_contexts) * Voltage has to be expressed either phase-phase or phase-neutral * This is depending on OID inputVoltageMeasType * INTEGER {singlePhase (1),phase1toN (2),phase2toN (3),phase3toN (4),phase1to2 (5),phase2to3 (6),phase3to1 (7) * => RFC input.Lx.voltage.context */ /* pdu2InputPhaseVoltage.0.1 = INTEGER: 216790 */ { "input.voltage", 0, 0.001, ".1.3.6.1.4.1.232.165.7.2.2.1.3.%i.1", NULL, 0, NULL }, /* pdu2InputPhaseVoltageThStatus.0.1 = INTEGER: good(1) */ { "input.voltage.status", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.232.165.7.2.2.1.4.%i.1", NULL, SU_FLAG_OK, &hpe_pdu_threshold_status_info[0] }, { "ups.alarm", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.232.165.7.2.2.1.4.%i.1", NULL, SU_FLAG_OK, &hpe_pdu_threshold_voltage_alarms_info[0] }, /* pdu2InputPhaseVoltageThLowerWarning.0.1 = INTEGER: 190000 */ { "input.voltage.low.warning", ST_FLAG_RW, 0.001, ".1.3.6.1.4.1.232.165.7.2.2.1.5.%i.1", NULL, SU_FLAG_NEGINVALID, NULL }, /* pdu2InputPhaseVoltageThLowerCritical.0.1 = INTEGER: 180000 */ { "input.voltage.low.critical", ST_FLAG_RW, 0.001, ".1.3.6.1.4.1.232.165.7.2.2.1.6.%i.1", NULL, SU_FLAG_NEGINVALID, NULL }, /* pdu2InputPhaseVoltageThUpperWarning.0.1 = INTEGER: 255000 */ { "input.voltage.high.warning", ST_FLAG_RW, 0.001, ".1.3.6.1.4.1.232.165.7.2.2.1.7.%i.1", NULL, SU_FLAG_NEGINVALID, NULL }, /* pdu2InputPhaseVoltageThUpperCritical.0.1 = INTEGER: 265000 */ { "input.voltage.high.critical", ST_FLAG_RW, 0.001, ".1.3.6.1.4.1.232.165.7.2.2.1.8.%i.1", NULL, SU_FLAG_NEGINVALID, NULL }, /* pdu2InputPhaseVoltage.0.1 = INTEGER: 216790 */ { "input.L1.voltage", 0, 0.001, ".1.3.6.1.4.1.232.165.7.2.2.1.3.%i.1", NULL, 0, NULL }, /* pdu2InputPhaseVoltageThStatus.0.1 = INTEGER: good(1) */ { "input.L1.voltage.status", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.232.165.7.2.2.1.4.%i.1", NULL, SU_FLAG_OK, &hpe_pdu_threshold_status_info[0] }, { "L1.alarm", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.232.165.7.2.2.1.4.%i.1", NULL, SU_FLAG_OK, &hpe_pdu_threshold_voltage_alarms_info[0] }, /* pdu2InputPhaseVoltageThLowerWarning.0.1 = INTEGER: 190000 */ { "input.L1.voltage.low.warning", ST_FLAG_RW, 0.001, ".1.3.6.1.4.1.232.165.7.2.2.1.5.%i.1", NULL, SU_FLAG_NEGINVALID, NULL }, /* pdu2InputPhaseVoltageThLowerCritical.0.1 = INTEGER: 180000 */ { "input.L1.voltage.low.critical", ST_FLAG_RW, 0.001, ".1.3.6.1.4.1.232.165.7.2.2.1.6.%i.1", NULL, SU_FLAG_NEGINVALID, NULL }, /* pdu2InputPhaseVoltageThUpperWarning.0.1 = INTEGER: 255000 */ { "input.L1.voltage.high.warning", ST_FLAG_RW, 0.001, ".1.3.6.1.4.1.232.165.7.2.2.1.7.%i.1", NULL, SU_FLAG_NEGINVALID, NULL }, /* pdu2InputPhaseVoltageThUpperCritical.0.1 = INTEGER: 265000 */ { "input.L1.voltage.high.critical", ST_FLAG_RW, 0.001, ".1.3.6.1.4.1.232.165.7.2.2.1.8.%i.1", NULL, SU_FLAG_NEGINVALID, NULL }, /* pdu2InputPhaseVoltage.0.2 = INTEGER: 216790 */ { "input.L2.voltage", 0, 0.001, ".1.3.6.1.4.1.232.165.7.2.2.1.3.%i.2", NULL, 0, NULL }, /* pdu2InputPhaseVoltageThStatus.0.2 = INTEGER: good(1) */ { "input.L2.voltage.status", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.232.165.7.2.2.1.4.%i.2", NULL, SU_FLAG_OK, &hpe_pdu_threshold_status_info[0] }, { "L2.alarm", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.232.165.7.2.2.1.4.%i.2", NULL, SU_FLAG_OK, &hpe_pdu_threshold_voltage_alarms_info[0] }, /* pdu2InputPhaseVoltageThLowerWarning.0.2 = INTEGER: 190000 */ { "input.L2.voltage.low.warning", ST_FLAG_RW, 0.001, ".1.3.6.1.4.1.232.165.7.2.2.1.5.%i.2", NULL, SU_FLAG_NEGINVALID, NULL }, /* pdu2InputPhaseVoltageThLowerCritical.0.2 = INTEGER: 180000 */ { "input.L2.voltage.low.critical", ST_FLAG_RW, 0.001, ".1.3.6.1.4.1.232.165.7.2.2.1.6.%i.2", NULL, SU_FLAG_NEGINVALID, NULL }, /* pdu2InputPhaseVoltageThUpperWarning.0.2 = INTEGER: 255000 */ { "input.L2.voltage.high.warning", ST_FLAG_RW, 0.001, ".1.3.6.1.4.1.232.165.7.2.2.1.7.%i.2", NULL, SU_FLAG_NEGINVALID, NULL }, /* pdu2InputPhaseVoltageThUpperCritical.0.2 = INTEGER: 265000 */ { "input.L2.voltage.high.critical", ST_FLAG_RW, 0.001, ".1.3.6.1.4.1.232.165.7.2.2.1.8.%i.2", NULL, SU_FLAG_NEGINVALID, NULL }, /* pdu2InputPhaseVoltage.0.3 = INTEGER: 216790 */ { "input.L3.voltage", 0, 0.001, ".1.3.6.1.4.1.232.165.7.2.2.1.3.%i.3", NULL, 0, NULL }, /* pdu2InputPhaseVoltageThStatus.0.3 = INTEGER: good(1) */ { "input.L3.voltage.status", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.232.165.7.2.2.1.4.%i.3", NULL, SU_FLAG_OK, &hpe_pdu_threshold_status_info[0] }, { "L3.alarm", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.232.165.7.2.2.1.4.%i.3", NULL, SU_FLAG_OK, &hpe_pdu_threshold_voltage_alarms_info[0] }, /* pdu2InputPhaseVoltageThLowerWarning.0.3 = INTEGER: 190000 */ { "input.L3.voltage.low.warning", ST_FLAG_RW, 0.001, ".1.3.6.1.4.1.232.165.7.2.2.1.5.%i.3", NULL, SU_FLAG_NEGINVALID, NULL }, /* pdu2InputPhaseVoltageThLowerCritical.0.3 = INTEGER: 180000 */ { "input.L3.voltage.low.critical", ST_FLAG_RW, 0.001, ".1.3.6.1.4.1.232.165.7.2.2.1.6.%i.3", NULL, SU_FLAG_NEGINVALID, NULL }, /* pdu2InputPhaseVoltageThUpperWarning.0.3 = INTEGER: 255000 */ { "input.L3.voltage.high.warning", ST_FLAG_RW, 0.001, ".1.3.6.1.4.1.232.165.7.2.2.1.7.%i.3", NULL, SU_FLAG_NEGINVALID, NULL }, /* pdu2InputPhaseVoltageThUpperCritical.0.3 = INTEGER: 265000 */ { "input.L3.voltage.high.critical", ST_FLAG_RW, 0.001, ".1.3.6.1.4.1.232.165.7.2.2.1.8.%i.3", NULL, SU_FLAG_NEGINVALID, NULL }, /* FIXME: * - input.current is mapped on input.L1.current for both single and 3phase !!! */ /* pdu2InputPhaseCurrent.0.1 = INTEGER: 185 */ { "input.current", 0, 0.001, ".1.3.6.1.4.1.232.165.7.2.2.1.11.%i.1", NULL, 0, NULL }, /* pdu2InputPhaseCurrentRating.0.1 = INTEGER: 24000 */ { "input.current.nominal", 0, 0.001, ".1.3.6.1.4.1.232.165.7.2.2.1.10.%i.1", NULL, SU_FLAG_NEGINVALID, NULL }, /* pdu2InputPhaseCurrentThStatus.0.1 = INTEGER: good(1) */ { "input.current.status", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.232.165.7.2.2.1.12.%i.1", NULL, SU_FLAG_OK, &hpe_pdu_threshold_status_info[0] }, { "ups.alarm", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.232.165.7.2.2.1.12.%i.1", NULL, SU_FLAG_OK, &hpe_pdu_threshold_current_alarms_info[0] }, /* pdu2InputPhaseCurrentThLowerWarning.0.1 = INTEGER: 0 */ { "input.current.low.warning", ST_FLAG_RW, 0.001, ".1.3.6.1.4.1.232.165.7.2.2.1.13.%i.1", NULL, SU_FLAG_NEGINVALID, NULL }, /* pdu2InputPhaseCurrentThLowerCritical.0.1 = INTEGER: -1 */ { "input.current.low.critical", ST_FLAG_RW, 0.001, ".1.3.6.1.4.1.232.165.7.2.2.1.14.%i.1", NULL, SU_FLAG_NEGINVALID, NULL }, /* pdu2InputPhaseCurrentThUpperWarning.0.1 = INTEGER: 19200 */ { "input.current.high.warning", ST_FLAG_RW, 0.001, ".1.3.6.1.4.1.232.165.7.2.2.1.15.%i.1", NULL, SU_FLAG_NEGINVALID, NULL }, /* pdu2InputPhaseCurrentThUpperCritical.0.1 = INTEGER: 24000 */ { "input.current.high.critical", ST_FLAG_RW, 0.001, ".1.3.6.1.4.1.232.165.7.2.2.1.16.%i.1", NULL, SU_FLAG_NEGINVALID, NULL }, /* pdu2InputPhaseCurrent.0.1 = INTEGER: 185 */ { "input.L1.current", 0, 0.001, ".1.3.6.1.4.1.232.165.7.2.2.1.11.%i.1", NULL, 0, NULL }, /* pdu2InputPhaseCurrentRating.0.1 = INTEGER: 24000 */ { "input.L1.current.nominal", 0, 0.001, ".1.3.6.1.4.1.232.165.7.2.2.1.10.%i.1", NULL, SU_FLAG_NEGINVALID, NULL }, /* pdu2InputPhaseCurrentThStatus.0.1 = INTEGER: good(1) */ { "input.L1.current.status", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.232.165.7.2.2.1.12.%i.1", NULL, SU_FLAG_OK, &hpe_pdu_threshold_status_info[0] }, { "L1.alarm", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.232.165.7.2.2.1.12.%i.1", NULL, SU_FLAG_OK, &hpe_pdu_threshold_current_alarms_info[0] }, /* pdu2InputPhaseCurrentThLowerWarning.0.1 = INTEGER: 0 */ { "input.L1.current.low.warning", ST_FLAG_RW, 0.001, ".1.3.6.1.4.1.232.165.7.2.2.1.13.%i.1", NULL, SU_FLAG_NEGINVALID, NULL }, /* pdu2InputPhaseCurrentThLowerCritical.0.1 = INTEGER: -1 */ { "input.L1.current.low.critical", ST_FLAG_RW, 0.001, ".1.3.6.1.4.1.232.165.7.2.2.1.14.%i.1", NULL, SU_FLAG_NEGINVALID, NULL }, /* pdu2InputPhaseCurrentThUpperWarning.0.1 = INTEGER: 19200 */ { "input.L1.current.high.warning", ST_FLAG_RW, 0.001, ".1.3.6.1.4.1.232.165.7.2.2.1.15.%i.1", NULL, SU_FLAG_NEGINVALID, NULL }, /* pdu2InputPhaseCurrentThUpperCritical.0.1 = INTEGER: 24000 */ { "input.L1.current.high.critical", ST_FLAG_RW, 0.001, ".1.3.6.1.4.1.232.165.7.2.2.1.16.%i.1", NULL, SU_FLAG_NEGINVALID, NULL }, /* pdu2InputPhaseCurrent.0.2 = INTEGER: 185 */ { "input.L2.current", 0, 0.001, ".1.3.6.1.4.1.232.165.7.2.2.1.11.%i.2", NULL, 0, NULL }, /* pdu2InputPhaseCurrentRating.0.2 = INTEGER: 24000 */ { "input.L2.current.nominal", 0, 0.001, ".1.3.6.1.4.1.232.165.7.2.2.1.10.%i.2", NULL, SU_FLAG_NEGINVALID, NULL }, /* pdu2InputPhaseCurrentThStatus.0.2 = INTEGER: good(1) */ { "input.L2.current.status", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.232.165.7.2.2.1.12.%i.2", NULL, SU_FLAG_OK, &hpe_pdu_threshold_status_info[0] }, { "L2.alarm", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.232.165.7.2.2.1.12.%i.2", NULL, SU_FLAG_OK, &hpe_pdu_threshold_current_alarms_info[0] }, /* pdu2InputPhaseCurrentThLowerWarning.0.2 = INTEGER: 0 */ { "input.L2.current.low.warning", ST_FLAG_RW, 0.001, ".1.3.6.1.4.1.232.165.7.2.2.1.13.%i.2", NULL, SU_FLAG_NEGINVALID, NULL }, /* pdu2InputPhaseCurrentThLowerCritical.0.2 = INTEGER: -1 */ { "input.L2.current.low.critical", ST_FLAG_RW, 0.001, ".1.3.6.1.4.1.232.165.7.2.2.1.14.%i.2", NULL, SU_FLAG_NEGINVALID, NULL }, /* pdu2InputPhaseCurrentThUpperWarning.0.2 = INTEGER: 19200 */ { "input.L2.current.high.warning", ST_FLAG_RW, 0.001, ".1.3.6.1.4.1.232.165.7.2.2.1.15.%i.2", NULL, SU_FLAG_NEGINVALID, NULL }, /* pdu2InputPhaseCurrentThUpperCritical.0.2 = INTEGER: 24000 */ { "input.L2.current.high.critical", ST_FLAG_RW, 0.001, ".1.3.6.1.4.1.232.165.7.2.2.1.16.%i.2", NULL, SU_FLAG_NEGINVALID, NULL }, /* pdu2InputPhaseCurrent.0.3 = INTEGER: 185 */ { "input.L3.current", 0, 0.001, ".1.3.6.1.4.1.232.165.7.2.2.1.11.%i.3", NULL, 0, NULL }, /* pdu2InputPhaseCurrentRating.0.3 = INTEGER: 24000 */ { "input.L3.current.nominal", 0, 0.001, ".1.3.6.1.4.1.232.165.7.2.2.1.10.%i.3", NULL, SU_FLAG_NEGINVALID, NULL }, /* pdu2InputPhaseCurrentThStatus.0.3 = INTEGER: good(1) */ { "input.L3.current.status", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.232.165.7.2.2.1.12.%i.3", NULL, SU_FLAG_OK, &hpe_pdu_threshold_status_info[0] }, { "L2.alarm", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.232.165.7.2.2.1.12.%i.2", NULL, SU_FLAG_OK, &hpe_pdu_threshold_current_alarms_info[0] }, /* pdu2InputPhaseCurrentThLowerWarning.0.3 = INTEGER: 0 */ { "input.L3.current.low.warning", ST_FLAG_RW, 0.001, ".1.3.6.1.4.1.232.165.7.2.2.1.13.%i.3", NULL, SU_FLAG_NEGINVALID, NULL }, /* pdu2InputPhaseCurrentThLowerCritical.0.3 = INTEGER: -1 */ { "input.L3.current.low.critical", ST_FLAG_RW, 0.001, ".1.3.6.1.4.1.232.165.7.2.2.1.14.%i.3", NULL, SU_FLAG_NEGINVALID, NULL }, /* pdu2InputPhaseCurrentThUpperWarning.0.3 = INTEGER: 19200 */ { "input.L3.current.high.warning", ST_FLAG_RW, 0.001, ".1.3.6.1.4.1.232.165.7.2.2.1.15.%i.3", NULL, SU_FLAG_NEGINVALID, NULL }, /* pdu2InputPhaseCurrentThUpperCritical.0.3 = INTEGER: 24000 */ { "input.L3.current.high.critical", ST_FLAG_RW, 0.001, ".1.3.6.1.4.1.232.165.7.2.2.1.16.%i.3", NULL, SU_FLAG_NEGINVALID, NULL }, /* pdu2InputPowerWatts.0 = INTEGER: 19 */ { "input.realpower", 0, 1.0, ".1.3.6.1.4.1.232.165.7.2.1.1.5.%i", NULL, SU_FLAG_NEGINVALID | SU_FLAG_UNIQUE | SU_FLAG_OK, NULL }, /* pdu2InputPhasePowerWatts.0.1 = INTEGER: 19 */ { "input.L1.realpower", 0, 1.0, ".1.3.6.1.4.1.232.165.7.2.2.1.21.%i.1", NULL, SU_FLAG_NEGINVALID | SU_FLAG_OK, NULL }, /* pdu2InputPhasePowerWatts.0.2 = INTEGER: 0 */ { "input.L2.realpower", 0, 1.0, ".1.3.6.1.4.1.232.165.7.2.2.1.21.%i.2", NULL, SU_FLAG_NEGINVALID | SU_FLAG_OK, NULL }, /* pdu2InputPhasePowerWatts.0.3 = INTEGER: 0 */ { "input.L3.realpower", 0, 1.0, ".1.3.6.1.4.1.232.165.7.2.2.1.21.%i.3", NULL, SU_FLAG_NEGINVALID | SU_FLAG_OK, NULL }, /* Sum of all phases apparent power, valid for Shark 1ph/3ph only */ /* pdu2InputPowerVA.0 = INTEGER: 39 */ { "input.power", 0, 1.0, ".1.3.6.1.4.1.232.165.7.2.1.1.4.%i", NULL, SU_FLAG_NEGINVALID | SU_FLAG_UNIQUE | SU_FLAG_OK, NULL }, /* pdu2InputPhasePowerVA.0.1 = INTEGER: 40 */ { "input.L1.power", 0, 1.0, ".1.3.6.1.4.1.232.165.7.2.2.1.20.%i.1", NULL, SU_FLAG_NEGINVALID | SU_FLAG_OK, NULL }, /* pdu2InputPhasePowerVA.0.2 = INTEGER: 0 */ { "input.L2.power", 0, 1.0, ".1.3.6.1.4.1.232.165.7.2.2.1.20.%i.2", NULL, SU_FLAG_NEGINVALID | SU_FLAG_OK, NULL }, /* pdu2InputPhasePowerVA.0.3 = INTEGER: 0 */ { "input.L3.power", 0, 1.0, ".1.3.6.1.4.1.232.165.7.2.2.1.20.%i.3", NULL, SU_FLAG_NEGINVALID | SU_FLAG_OK, NULL }, /* TODO: handle statistics */ #if WITH_UNMAPPED_DATA_POINTS /* pdu2InputPowerWattHour.0 = INTEGER: 91819 */ { "unmapped.pdu2InputPowerWattHour", 0, 1, ".1.3.6.1.4.1.232.165.7.2.1.1.6.0", NULL, SU_FLAG_OK, NULL }, /* pdu2InputPowerWattHourTimer.0 = STRING: "16/10/2017,17:58:53" */ { "unmapped.pdu2InputPowerWattHourTimer", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.232.165.7.2.1.1.7.0", NULL, SU_FLAG_OK, NULL }, #endif /* #if WIH_UNMAPPED_DATA_POINTS */ /* pdu2InputPowerFactor.0 = INTEGER: 483 */ { "input.powerfactor", 0, 0.001, ".1.3.6.1.4.1.232.165.7.2.1.1.8.%i", NULL, SU_FLAG_NEGINVALID | SU_FLAG_OK, NULL }, /* Ambient collection */ /* pdu2TemperatureProbeStatus.0.1 = INTEGER: disconnected(1) */ { "ambient.present", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.232.165.7.4.2.1.3.%i.1", NULL, SU_FLAG_OK, &hpe_pdu_ambient_presence_info[0] }, /* pdu2TemperatureThStatus.0.1 = INTEGER: good(1) */ { "ambient.temperature.status", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.232.165.7.4.2.1.5.%i.1", NULL, SU_FLAG_OK, &hpe_pdu_threshold_status_info[0] }, { "ups.alarm", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.232.165.7.4.2.1.5.%i.1", NULL, SU_FLAG_OK, &hpe_pdu_threshold_temperature_alarms_info[0] }, /* pdu2TemperatureValue.0.1 = INTEGER: 0 */ { "ambient.temperature", 0, 0.1, ".1.3.6.1.4.1.232.165.7.4.2.1.4.%i.1", NULL, SU_FLAG_OK, NULL }, /* Low and high threshold use the respective critical levels */ /* pdu2TemperatureThLowerCritical.0.1 = INTEGER: 50 */ { "ambient.temperature.low", ST_FLAG_RW, 0.1, ".1.3.6.1.4.1.232.165.7.4.2.1.7.%i.1", NULL, SU_FLAG_NEGINVALID | SU_FLAG_OK, NULL }, { "ambient.temperature.low.critical", ST_FLAG_RW, 0.1, ".1.3.6.1.4.1.232.165.7.4.2.1.7.%i.1", NULL, SU_FLAG_NEGINVALID | SU_FLAG_OK, NULL }, /* pdu2TemperatureThLowerWarning.0.1 = INTEGER: 100 */ { "ambient.temperature.low.warning", ST_FLAG_RW, 0.1, ".1.3.6.1.4.1.232.165.7.4.2.1.6.%i.1", NULL, SU_FLAG_NEGINVALID | SU_FLAG_OK, NULL }, /* pdu2TemperatureThUpperCritical.0.1 = INTEGER: 650 */ { "ambient.temperature.high", ST_FLAG_RW, 0.1, ".1.3.6.1.4.1.232.165.7.4.2.1.9.%i.1", NULL, SU_FLAG_NEGINVALID | SU_FLAG_OK, NULL }, { "ambient.temperature.high.critical", ST_FLAG_RW, 0.1, ".1.3.6.1.4.1.232.165.7.4.2.1.9.%i.1", NULL, SU_FLAG_NEGINVALID | SU_FLAG_OK, NULL }, /* pdu2TemperatureThUpperWarning.0.1 = INTEGER: 200 */ { "ambient.temperature.high.warning", ST_FLAG_RW, 0.1, ".1.3.6.1.4.1.232.165.7.4.2.1.8.%i.1", NULL, SU_FLAG_NEGINVALID | SU_FLAG_OK, NULL }, /* pdu2HumidityThStatus.0.1 = INTEGER: good(1) */ { "ambient.humidity.status", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.232.165.7.4.3.1.5.%i.1", NULL, SU_FLAG_OK, &hpe_pdu_threshold_status_info[0] }, { "ups.alarm", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.232.165.7.4.3.1.5.%i.1", NULL, SU_FLAG_OK, &hpe_pdu_threshold_humidity_alarms_info[0] }, /* pdu2HumidityValue.0.1 = INTEGER: 0 */ { "ambient.humidity", 0, 0.1, ".1.3.6.1.4.1.232.165.7.4.3.1.4.%i.1", NULL, SU_FLAG_OK, NULL }, /* Low and high threshold use the respective critical levels */ /* pdu2HumidityThLowerCritical.0.1 = INTEGER: 100 */ { "ambient.humidity.low", ST_FLAG_RW, 0.1, ".1.3.6.1.4.1.232.165.7.4.3.1.7.%i.1", NULL, SU_FLAG_NEGINVALID | SU_FLAG_OK, NULL }, { "ambient.humidity.low.critical", ST_FLAG_RW, 0.1, ".1.3.6.1.4.1.232.165.7.4.3.1.7.%i.1", NULL, SU_FLAG_NEGINVALID | SU_FLAG_OK, NULL }, /* pdu2HumidityThLowerWarning.0.1 = INTEGER: 200 */ { "ambient.humidity.low.warning", ST_FLAG_RW, 0.1, ".1.3.6.1.4.1.232.165.7.4.3.1.6.%i.1", NULL, SU_FLAG_NEGINVALID | SU_FLAG_OK, NULL }, /* pdu2HumidityThUpperWarning.0.1 = INTEGER: 250 */ { "ambient.humidity.high.warning", ST_FLAG_RW, 0.1, ".1.3.6.1.4.1.232.165.7.4.3.1.8.%i.1", NULL, SU_FLAG_NEGINVALID | SU_FLAG_OK, NULL }, /* pdu2HumidityThUpperCritical.0.1 = INTEGER: 900 */ { "ambient.humidity.high", ST_FLAG_RW, 0.1, ".1.3.6.1.4.1.232.165.7.4.3.1.9.%i.1", NULL, SU_FLAG_NEGINVALID | SU_FLAG_OK, NULL }, { "ambient.humidity.high.critical", ST_FLAG_RW, 0.1, ".1.3.6.1.4.1.232.165.7.4.3.1.9.%i.1", NULL, SU_FLAG_NEGINVALID | SU_FLAG_OK, NULL }, /* Dry contacts on TH module */ /* pdu2ContactState.0.1 = INTEGER: contactBad(3) */ { "ambient.contacts.1.status", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.232.165.7.4.4.1.4.%i.1", NULL, SU_FLAG_OK, &hpe_pdu_ambient_drycontacts_info[0] }, /* pdu2ContactState.0.2 = INTEGER: contactBad(3) */ { "ambient.contacts.2.status", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.232.165.7.4.4.1.4.%i.2", NULL, SU_FLAG_OK, &hpe_pdu_ambient_drycontacts_info[0] }, /* Outlet collection */ { "outlet.id", 0, 1, NULL, "0", SU_FLAG_STATIC | SU_FLAG_ABSENT | SU_FLAG_OK, NULL }, { "outlet.desc", ST_FLAG_RW | ST_FLAG_STRING, 20, NULL, "All outlets", SU_FLAG_STATIC | SU_FLAG_ABSENT | SU_FLAG_OK, NULL }, /* pdu2OutletCount.0 = INTEGER: 24 */ { "outlet.count", 0, 1, ".1.3.6.1.4.1.232.165.7.1.2.1.12.%i", "0", SU_FLAG_STATIC | SU_FLAG_OK, NULL }, /* outlet template definition * Indexes start from 1, ie outlet.1 => .1 */ /* Note: the first definition is used to determine the base index (ie 0 or 1) */ /* pdu2OutletName.0.%i = STRING: "Outlet L1-%i" */ { "outlet.%i.desc", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.232.165.7.5.1.1.2.%i.%i", NULL, SU_FLAG_STATIC | SU_FLAG_OK | SU_OUTLET | SU_TYPE_DAISY_1, NULL }, /* pdu2OutletControlStatus.0.%i = INTEGER: on(2) */ { "outlet.%i.status", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.232.165.7.5.2.1.1.%i.%i", NULL, SU_FLAG_OK | SU_OUTLET | SU_TYPE_DAISY_1, &hpe_pdu_outlet_status_info[0] }, /* Numeric identifier of the outlet, tied to the whole unit */ { "outlet.%i.id", 0, 1, NULL, "%i", SU_FLAG_STATIC | SU_FLAG_ABSENT | SU_FLAG_OK | SU_OUTLET | SU_TYPE_DAISY_1, NULL }, #if 0 /* FIXME: the last part of the OID gives the group number (i.e. %i.1 means "group 1") * Need to address that, without multiple declaration (%i.%i, SU_OUTLET | SU_OUTLET_GROUP)? */ { "outlet.%i.groupid", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.534.6.6.7.6.2.1.3.%i.%i.1", NULL, SU_FLAG_STATIC | SU_FLAG_UNIQUE | SU_OUTLET | SU_TYPE_DAISY_1, NULL }, { "outlet.%i.groupid", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.534.6.6.7.6.2.1.3.%i.%i.2", NULL, SU_FLAG_STATIC | SU_FLAG_UNIQUE | SU_OUTLET | SU_TYPE_DAISY_1, NULL }, { "outlet.%i.groupid", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.534.6.6.7.6.2.1.3.%i.%i.3", NULL, SU_FLAG_STATIC | SU_FLAG_UNIQUE | SU_OUTLET | SU_TYPE_DAISY_1, NULL }, { "outlet.%i.groupid", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.534.6.6.7.6.2.1.3.%i.%i.4", NULL, SU_FLAG_STATIC | SU_FLAG_UNIQUE | SU_OUTLET | SU_TYPE_DAISY_1, NULL }, { "outlet.%i.groupid", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.534.6.6.7.6.2.1.3.%i.%i.5", NULL, SU_FLAG_STATIC | SU_FLAG_UNIQUE | SU_OUTLET | SU_TYPE_DAISY_1, NULL }, { "outlet.%i.groupid", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.534.6.6.7.6.2.1.3.%i.%i.6", NULL, SU_FLAG_STATIC | SU_FLAG_UNIQUE | SU_OUTLET | SU_TYPE_DAISY_1, NULL }, #endif /* pdu2OutletCurrent.0.%i = INTEGER: 0 */ { "outlet.%i.current", 0, 0.001, ".1.3.6.1.4.1.232.165.7.5.1.1.5.%i.%i", NULL, SU_OUTLET | SU_TYPE_DAISY_1, NULL }, /* pdu2OutletCurrentThStatus.0.%i = INTEGER: good(1) */ { "outlet.%i.current.status", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.232.165.7.5.1.1.6.%i.%i", NULL, SU_OUTLET | SU_TYPE_DAISY_1, &hpe_pdu_threshold_status_info[0] }, { "outlet.%i.alarm", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.232.165.7.5.1.1.6.%i.%i", NULL, SU_OUTLET | SU_TYPE_DAISY_1, &hpe_pdu_threshold_current_alarms_info[0] }, /* pdu2OutletCurrentThLowerWarning.0.%i = INTEGER: 0 */ { "outlet.%i.current.low.warning", ST_FLAG_RW, 0.001, ".1.3.6.1.4.1.232.165.7.5.1.1.7.%i.%i", NULL, SU_FLAG_NEGINVALID | SU_OUTLET | SU_TYPE_DAISY_1, NULL }, /* pdu2OutletCurrentThLowerCritical.0.%i = INTEGER: -1 */ { "outlet.%i.current.low.critical", ST_FLAG_RW, 0.001, ".1.3.6.1.4.1.232.165.7.5.1.1.8.%i.%i", NULL, SU_FLAG_NEGINVALID | SU_OUTLET | SU_TYPE_DAISY_1, NULL }, /* pdu2OutletCurrentThUpperWarning.0.1 = INTEGER: 8000 */ { "outlet.%i.current.high.warning", ST_FLAG_RW, 0.001, ".1.3.6.1.4.1.232.165.7.5.1.1.9.%i.%i", NULL, SU_FLAG_NEGINVALID | SU_OUTLET | SU_TYPE_DAISY_1, NULL }, /* pdu2OutletCurrentThUpperCritical.0.1 = INTEGER: 10000 */ { "outlet.%i.current.high.critical", ST_FLAG_RW, 0.001, ".1.3.6.1.4.1.232.165.7.5.1.1.10.%i.%i", NULL, SU_FLAG_NEGINVALID | SU_OUTLET | SU_TYPE_DAISY_1, NULL }, /* pdu2OutletWatts.0.1 = INTEGER: 0 */ { "outlet.%i.realpower", 0, 1.0, ".1.3.6.1.4.1.232.165.7.5.1.1.14.%i.%i", NULL, SU_FLAG_NEGINVALID | SU_OUTLET | SU_TYPE_DAISY_1, NULL }, /* pdu2OutletVA.0.%i = INTEGER: 0 */ { "outlet.%i.power", 0, 1.0, ".1.3.6.1.4.1.232.165.7.5.1.1.13.%i.%i", NULL, SU_OUTLET | SU_TYPE_DAISY_1, NULL }, /* pdu2OutletControlSwitchable.0.%i = INTEGER: switchable(1) */ { "outlet.%i.switchable", ST_FLAG_RW, SU_INFOSIZE, ".1.3.6.1.4.1.232.165.7.5.2.1.8.%i.%i", "no", SU_FLAG_STATIC | SU_OUTLET | SU_FLAG_OK | SU_TYPE_DAISY_1, &hpe_pdu_outlet_switchability_info[0] }, /* pdu2OutletType.0.%i = INTEGER: iecC13(1) */ { "outlet.%i.type", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.232.165.7.5.1.1.3.%i.%i", "unknown", SU_FLAG_STATIC | SU_OUTLET | SU_TYPE_DAISY_1, &hpe_pdu_outlet_type_info[0] }, /* pdu2OutletPowerFactor.0.%i = INTEGER: 1000 */ { "outlet.%i.powerfactor", 0, 0.001, ".1.3.6.1.4.1.232.165.7.5.1.1.17.%i.%i", NULL, SU_OUTLET | SU_TYPE_DAISY_1, NULL }, /* TODO: handle statistics */ #if WITH_UNMAPPED_DATA_POINTS /* pdu2OutletWh.0.1 = INTEGER: 1167 * Note: setting this to zero resets the counter and timestamp => instcmd ???counter???.reset */ { "unmapped.pdu2OutletWh", 0, 1, ".1.3.6.1.4.1.232.165.7.5.1.1.15.%i.%i", NULL, SU_FLAG_OK, NULL }, /* pdu2OutletWhTimer.0.1 = STRING: "25/03/2016,09:03:26" */ { "unmapped.pdu2OutletWhTimer", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.232.165.7.5.1.1.16.%i.%i", NULL, SU_FLAG_OK, NULL }, #endif /* #if WITH_UNMAPPED_DATA_POINTS */ /* Outlet groups collection */ /* pdu2GroupCount.0 = INTEGER: 3 */ { "outlet.group.count", 0, 1, ".1.3.6.1.4.1.232.165.7.1.2.1.11.%i", "0", SU_FLAG_STATIC | SU_TYPE_DAISY_1, NULL }, /* outlet groups template definition * Indexes start from 1, ie outlet.group.1 => .1 */ /* Note: the first definition is used to determine the base index (ie 0 or 1) */ /* pdu2GroupIndex.0.%i = INTEGER: %i */ { "outlet.group.%i.id", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.232.165.7.3.1.1.1.%i.%i", NULL, SU_FLAG_STATIC | SU_OUTLET_GROUP | SU_TYPE_DAISY_1, NULL }, /* pdu2GroupName.0.%i = STRING: "Section L1" */ { "outlet.group.%i.name", ST_FLAG_RW | ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.232.165.7.3.1.1.2.%i.%i", NULL, SU_FLAG_STATIC | SU_OUTLET_GROUP | SU_TYPE_DAISY_1, NULL }, /* pdu2GroupType.0.%i = INTEGER: breaker2pole(3) */ { "outlet.group.%i.type", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.232.165.7.3.1.1.3.%i.%i", NULL, SU_FLAG_STATIC | SU_OUTLET_GROUP | SU_TYPE_DAISY_1, &hpe_pdu_outlet_group_type_info[0] }, /* pdu2GroupVoltageMeasType.0.1 = INTEGER: phase1to2(5) */ { "outlet.group.%i.phase", 0, SU_INFOSIZE, ".1.3.6.1.4.1.232.165.7.3.1.1.4.%i.%i", NULL, SU_FLAG_STATIC | SU_OUTLET_GROUP | SU_TYPE_DAISY_1, &hpe_pdu_outlet_group_phase_info[0] }, /* pdu2groupBreakerStatus.0.%i = INTEGER: breakerOn(2) */ { "outlet.group.%i.status", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.232.165.7.3.1.1.27.%i.%i", NULL, SU_FLAG_OK | SU_FLAG_NAINVALID | SU_OUTLET_GROUP | SU_TYPE_DAISY_1, &hpe_pdu_outletgroups_status_info[0] }, /* pdu2GroupOutletCount.0.%i = INTEGER: 8 */ { "outlet.group.%i.count", 0, 1, ".1.3.6.1.4.1.232.165.7.3.1.1.26.%i.%i", NULL, SU_OUTLET_GROUP | SU_TYPE_DAISY_1, NULL }, /* pdu2GroupVoltage.0.%i = INTEGER: 216760 */ { "outlet.group.%i.voltage", 0, 0.001, ".1.3.6.1.4.1.232.165.7.3.1.1.5.%i.%i", NULL, SU_OUTLET_GROUP | SU_TYPE_DAISY_1, NULL }, /* pdu2GroupVoltageThStatus.0.%i = INTEGER: good(1) */ { "outlet.group.%i.voltage.status", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.232.165.7.3.1.1.6.%i.%i", NULL, SU_OUTLET_GROUP | SU_TYPE_DAISY_1, &hpe_pdu_threshold_status_info[0] }, { "outlet.group.%i.alarm", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.232.165.7.3.1.1.6.%i.%i", NULL, SU_OUTLET_GROUP | SU_TYPE_DAISY_1, &hpe_pdu_threshold_voltage_alarms_info[0] }, /* pdu2GroupVoltageThLowerWarning.0.%i = INTEGER: 190000 */ { "outlet.group.%i.voltage.low.warning", ST_FLAG_RW, 0.001, ".1.3.6.1.4.1.232.165.7.3.1.1.7.%i.%i", NULL, SU_FLAG_NEGINVALID | SU_OUTLET_GROUP | SU_TYPE_DAISY_1, NULL }, /* pdu2GroupVoltageThLowerCritical.0.%i = INTEGER: 180000 */ { "outlet.group.%i.voltage.low.critical", ST_FLAG_RW, 0.001, ".1.3.6.1.4.1.232.165.7.3.1.1.8.%i.%i", NULL, SU_FLAG_NEGINVALID | SU_OUTLET_GROUP | SU_TYPE_DAISY_1, NULL }, /* pdu2GroupVoltageThUpperWarning.0.%i = INTEGER: 255000 */ { "outlet.group.%i.voltage.high.warning", ST_FLAG_RW, 0.001, ".1.3.6.1.4.1.232.165.7.3.1.1.9.%i.%i", NULL, SU_FLAG_NEGINVALID | SU_OUTLET_GROUP | SU_TYPE_DAISY_1, NULL }, /* pdu2GroupVoltageThUpperCritical.0.%i = INTEGER: 265000 */ { "outlet.group.%i.voltage.high.critical", ST_FLAG_RW, 0.001, ".1.3.6.1.4.1.232.165.7.3.1.1.10.%i.%i", NULL, SU_FLAG_NEGINVALID | SU_OUTLET_GROUP | SU_TYPE_DAISY_1, NULL }, /* pdu2GroupCurrent.0.%i = INTEGER: 0 */ { "outlet.group.%i.current", 0, 0.001, ".1.3.6.1.4.1.232.165.7.3.1.1.12.%i.%i", NULL, SU_OUTLET_GROUP | SU_TYPE_DAISY_1, NULL }, /* pdu2groupCurrentRating.0.%i = INTEGER: 16000 */ { "outlet.group.%i.current.nominal", 0, 0.001, ".1.3.6.1.4.1.232.165.7.3.1.1.11.%i.%i", NULL, SU_OUTLET_GROUP | SU_TYPE_DAISY_1, NULL }, /* pdu2GroupCurrentThStatus.0.%i = INTEGER: good(1) */ { "outlet.group.%i.current.status", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.232.165.7.3.1.1.13.%i.%i", NULL, SU_OUTLET_GROUP | SU_TYPE_DAISY_1, &hpe_pdu_threshold_status_info[0] }, { "outlet.group.%i.alarm", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.232.165.7.3.1.1.13.%i.%i", NULL, SU_OUTLET_GROUP | SU_TYPE_DAISY_1, &hpe_pdu_threshold_current_alarms_info[0] }, /* pdu2GroupCurrentThLowerWarning.0.%i = INTEGER: 0 */ { "outlet.group.%i.current.low.warning", ST_FLAG_RW, 0.001, ".1.3.6.1.4.1.232.165.7.3.1.1.14.%i.%i", NULL, SU_FLAG_NEGINVALID | SU_OUTLET_GROUP | SU_TYPE_DAISY_1, NULL }, /* pdu2GroupCurrentThLowerCritical.0.%i = INTEGER: -1 */ { "outlet.group.%i.current.low.critical", ST_FLAG_RW, 0.001, ".1.3.6.1.4.1.232.165.7.3.1.1.15.%i.%i", NULL, SU_FLAG_NEGINVALID | SU_OUTLET_GROUP | SU_TYPE_DAISY_1, NULL }, /* pdu2GroupCurrentThUpperWarning.0.%i = INTEGER: 12800 */ { "outlet.group.%i.current.high.warning", ST_FLAG_RW, 0.001, ".1.3.6.1.4.1.232.165.7.3.1.1.16.%i.%i", NULL, SU_FLAG_NEGINVALID | SU_OUTLET_GROUP | SU_TYPE_DAISY_1, NULL }, /* pdu2GroupCurrentThUpperCritical.0.%i = INTEGER: 16000 */ { "outlet.group.%i.current.high.critical", ST_FLAG_RW, 0.001, ".1.3.6.1.4.1.232.165.7.3.1.1.17.%i.%i", NULL, SU_FLAG_NEGINVALID | SU_OUTLET_GROUP | SU_TYPE_DAISY_1, NULL }, /* pdu2GroupCurrentPercentLoad.0.%i = INTEGER: 0 */ { "outlet.group.%i.load", 0, 1.0, ".1.3.6.1.4.1.232.165.7.3.1.1.19.%i.%i", NULL, SU_FLAG_NEGINVALID | SU_OUTLET_GROUP | SU_TYPE_DAISY_1, NULL }, /* pdu2GroupPowerWatts.0.%i = INTEGER: 0 */ { "outlet.group.%i.realpower", 0, 1.0, ".1.3.6.1.4.1.232.165.7.3.1.1.21.%i.%i", NULL, SU_FLAG_NEGINVALID | SU_OUTLET_GROUP | SU_TYPE_DAISY_1, NULL }, /* pdu2GroupPowerVA.0.%i = INTEGER: 0 */ { "outlet.group.%i.power", 0, 1.0, ".1.3.6.1.4.1.232.165.7.3.1.1.20.%i.%i", NULL, SU_FLAG_NEGINVALID | SU_OUTLET_GROUP | SU_TYPE_DAISY_1, NULL }, /* pdu2GroupPowerFactor.0.%i = INTEGER: 1000 */ { "outlet.group.%i.powerfactor", 0, 0.001, ".1.3.6.1.4.1.232.165.7.3.1.1.24.%i.%i", NULL, SU_OUTLET | SU_TYPE_DAISY_1, NULL }, /* TODO: handle statistics */ #if WITH_UNMAPPED_DATA_POINTS /* pdu2GroupPowerWattHour.0.%i = INTEGER: 1373 * Note: setting this to zero resets the counter and timestamp => instcmd .reset */ { "unmapped.pdu2GroupPowerWattHour", 0, 1, ".1.3.6.1.4.1.232.165.7.3.1.1.22.%i.%i", NULL, SU_FLAG_OK, NULL }, /* pdu2GroupPowerWattHourTimer.0.%i = STRING: "25/03/2016,09:01:16" */ { "unmapped.pdu2GroupPowerWattHourTimer", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.232.165.7.3.1.1.23.%i.%i", NULL, SU_FLAG_OK, NULL }, #endif /* #if WITH_UNMAPPED_DATA_POINTS */ /* instant commands. */ /* TODO: handle delays (outlet.%i.{on,off}.delay) */ /* pdu2OutletControlOffCmd.0.%i = INTEGER: -1 */ { "outlet.%i.load.off", 0, 1, ".1.3.6.1.4.1.232.165.7.5.2.1.2.%i.%i", "0", SU_TYPE_CMD | SU_OUTLET | SU_TYPE_DAISY_1, NULL }, /* pdu2OutletControlOnCmd.0.%i = INTEGER: -1 */ { "outlet.%i.load.on", 0, 1, ".1.3.6.1.4.1.232.165.7.5.2.1.3.%i.%i", "0", SU_TYPE_CMD | SU_OUTLET | SU_TYPE_DAISY_1, NULL }, /* pdu2OutletControlRebootCmd.0.%i = INTEGER: -1 */ { "outlet.%i.load.cycle", 0, 1, ".1.3.6.1.4.1.232.165.7.5.2.1.4.%i.%i", "0", SU_TYPE_CMD | SU_OUTLET | SU_TYPE_DAISY_1, NULL }, /* Delayed version, parameter is mandatory (so dfl is NULL)! */ /* pdu2OutletControlOffCmd.0.%i = INTEGER: -1 */ { "outlet.%i.load.off.delay", 0, 1, ".1.3.6.1.4.1.232.165.7.5.2.1.2.%i.%i", NULL, SU_TYPE_CMD | SU_OUTLET | SU_TYPE_DAISY_1, NULL }, /* pdu2OutletControlOnCmd.0.%i = INTEGER: -1 */ { "outlet.%i.load.on.delay", 0, 1, ".1.3.6.1.4.1.232.165.7.5.2.1.3.%i.%i", NULL, SU_TYPE_CMD | SU_OUTLET | SU_TYPE_DAISY_1, NULL }, /* pdu2OutletControlRebootCmd.0.%i = INTEGER: -1 */ { "outlet.%i.load.cycle.delay", 0, 1, ".1.3.6.1.4.1.232.165.7.5.2.1.4.%i.%i", NULL, SU_TYPE_CMD | SU_OUTLET | SU_TYPE_DAISY_1, NULL }, /* end of structure. */ { NULL, 0, 0, NULL, NULL, 0, NULL } }; mib2nut_info_t hpe_pdu = { "hpe_epdu", HPE_EPDU_MIB_VERSION, NULL, HPE_EPDU_OID_MODEL_NAME, hpe_pdu_mib, HPE_EPDU_MIB_SYSOID, NULL }; nut-2.8.1/drivers/bestups.c0000644000175000017500000002507414501607135012572 00000000000000/* bestups.c - model specific routines for Best-UPS Fortress models OBSOLETION WARNING: Please to not base new development on this codebase, instead create a new subdriver for nutdrv_qx which generally covers all Megatec/Qx protocol family and aggregates device support from such legacy drivers over time. Copyright (C) 1999 Russell Kroll ID config option by Jason White 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 2 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, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "main.h" #include "serial.h" #include "nut_stdint.h" #define DRIVER_NAME "Best UPS driver" #define DRIVER_VERSION "1.08" /* driver description structure */ upsdrv_info_t upsdrv_info = { DRIVER_NAME, DRIVER_VERSION, "Russell Kroll \n" \ "Jason White ", DRV_STABLE, { NULL } }; #define ENDCHAR 13 /* replies end with CR */ #define MAXTRIES 5 #define UPSDELAY 50000 /* 50 ms delay required for reliable operation */ #define SER_WAIT_SEC 3 /* allow 3.0 sec for ser_get calls */ #define SER_WAIT_USEC 0 static float lowvolt = 0, highvolt = 0; static int battvoltmult = 1; static int inverted_bypass_bit = 0; static void model_set(const char *abbr, const char *rating) { if (!strcmp(abbr, "FOR")) { dstate_setinfo("ups.mfr", "%s", "Best Power"); dstate_setinfo("ups.model", "Fortress %s", rating); return; } if (!strcmp(abbr, "FTC")) { dstate_setinfo("ups.mfr", "%s", "Best Power"); dstate_setinfo("ups.model", "Fortress Telecom %s", rating); return; } if (!strcmp(abbr, "PRO")) { dstate_setinfo("ups.mfr", "%s", "Best Power"); dstate_setinfo("ups.model", "Patriot Pro %s", rating); inverted_bypass_bit = 1; return; } if (!strcmp(abbr, "PR2")) { dstate_setinfo("ups.mfr", "%s", "Best Power"); dstate_setinfo("ups.model", "Patriot Pro II %s", rating); inverted_bypass_bit = 1; return; } if (!strcmp(abbr, "325")) { dstate_setinfo("ups.mfr", "%s", "Sola Australia"); dstate_setinfo("ups.model", "Sola 325 %s", rating); return; } if (!strcmp(abbr, "520")) { dstate_setinfo("ups.mfr", "%s", "Sola Australia"); dstate_setinfo("ups.model", "Sola 520 %s", rating); return; } if (!strcmp(abbr, "610")) { dstate_setinfo("ups.mfr", "%s", "Best Power"); dstate_setinfo("ups.model", "610 %s", rating); return; } if (!strcmp(abbr, "620")) { dstate_setinfo("ups.mfr", "%s", "Sola Australia"); dstate_setinfo("ups.model", "Sola 620 %s", rating); return; } if (!strcmp(abbr, "AX1")) { dstate_setinfo("ups.mfr", "%s", "Best Power"); dstate_setinfo("ups.model", "Axxium Rackmount %s", rating); return; } dstate_setinfo("ups.mfr", "%s", "Unknown"); dstate_setinfo("ups.model", "Unknown %s (%s)", abbr, rating); printf("Unknown model detected - please report this ID: '%s'\n", abbr); } static int instcmd(const char *cmdname, const char *extra) { if (!strcasecmp(cmdname, "test.battery.stop")) { ser_send_pace(upsfd, UPSDELAY, "CT\r"); return STAT_INSTCMD_HANDLED; } if (!strcasecmp(cmdname, "test.battery.start")) { ser_send_pace(upsfd, UPSDELAY, "T\r"); return STAT_INSTCMD_HANDLED; } upslogx(LOG_NOTICE, "instcmd: unknown command [%s] [%s]", cmdname, extra); return STAT_INSTCMD_UNKNOWN; } static int get_ident(char *buf, size_t bufsize) { int i; ssize_t ret; char *ID; ID = getval("ID"); /* user-supplied override from ups.conf */ if (ID) { upsdebugx(2, "NOTE: using user-supplied ID response"); snprintf(buf, bufsize, "%s", ID); return 1; } for (i = 0; i < MAXTRIES; i++) { ser_send_pace(upsfd, UPSDELAY, "\rID\r"); ret = ser_get_line(upsfd, buf, bufsize, ENDCHAR, "", SER_WAIT_SEC, SER_WAIT_USEC); if (ret > 0) upsdebugx(2, "get_ident: got [%s]", buf); /* buf must start with ( and be in the range [25-27] */ if ((ret > 0) && (buf[0] != '(') && (strlen(buf) >= 25) && (strlen(buf) <= 27)) return 1; sleep(1); } upslogx(LOG_INFO, "Giving up on hardware detection after %d tries", MAXTRIES); return 0; } static void ups_ident(void) { int i; char buf[256], *ptr; char *model = NULL, *rating = NULL; if (!get_ident(buf, sizeof(buf))) { fatalx(EXIT_FAILURE, "Unable to detect a Best/SOLA or Phoenix protocol UPS"); } /* FOR,750,120,120,20.0,27.6 */ ptr = strtok(buf, ","); for (i = 0; ptr; i++) { switch (i) { case 0: model = ptr; break; case 1: rating = ptr; break; case 2: dstate_setinfo("input.voltage.nominal", "%d", atoi(ptr)); break; case 3: dstate_setinfo("output.voltage.nominal", "%d", atoi(ptr)); break; case 4: lowvolt = atof(ptr); break; case 5: highvolt = atof(ptr); break; } ptr = strtok(NULL, ","); } if ((!model) || (!rating)) { fatalx(EXIT_FAILURE, "Didn't get a valid ident string"); } model_set(model, rating); /* Battery voltage multiplier */ ptr = getval("battvoltmult"); if (ptr) { battvoltmult = atoi(ptr); } /* Lookup the nominal battery voltage (should be between lowvolt and highvolt */ for (i = 0; i < 8; i++) { const int nominal[] = { 2, 6, 12, 24, 36, 48, 72, 96 }; if ((lowvolt < nominal[i]) && (highvolt > nominal[i])) { dstate_setinfo("battery.voltage.nominal", "%d", battvoltmult * nominal[i]); break; } } ptr = getval("nombattvolt"); if (ptr) { highvolt = atof(ptr); } } static void ups_sync(void) { char buf[256]; int i; ssize_t ret; for (i = 0; i < MAXTRIES; i++) { ser_send_pace(upsfd, UPSDELAY, "\rQ1\r"); ret = ser_get_line(upsfd, buf, sizeof(buf), ENDCHAR, "", SER_WAIT_SEC, SER_WAIT_USEC); /* return once we get something that looks usable */ if ((ret > 0) && (buf[0] == '(')) return; usleep(250000); } fatalx(EXIT_FAILURE, "Unable to detect a Best/SOLA or Phoenix protocol UPS"); } void upsdrv_initinfo(void) { ups_sync(); ups_ident(); printf("Detected %s %s on %s\n", dstate_getinfo("ups.mfr"), dstate_getinfo("ups.model"), device_path); /* paranoia - cancel any shutdown that might already be running */ ser_send_pace(upsfd, UPSDELAY, "C\r"); upsh.instcmd = instcmd; dstate_addcmd("test.battery.start"); dstate_addcmd("test.battery.stop"); } static int ups_on_line(void) { int i; ssize_t ret; char temp[256], pstat[32]; for (i = 0; i < MAXTRIES; i++) { ser_send_pace(upsfd, UPSDELAY, "\rQ1\r"); ret = ser_get_line(upsfd, temp, sizeof(temp), ENDCHAR, "", SER_WAIT_SEC, SER_WAIT_USEC); /* Q1 must return 46 bytes starting with a ( */ if ((ret > 0) && (temp[0] == '(') && (strlen(temp) == 46)) { sscanf(temp, "%*s %*s %*s %*s %*s %*s %*s %s", pstat); if (pstat[0] == '0') return 1; /* on line */ return 0; /* on battery */ } sleep(1); } upslogx(LOG_ERR, "Status read failed: assuming on battery"); return 0; /* on battery */ } void upsdrv_shutdown(void) { printf("The UPS will shut down in approximately one minute.\n"); if (ups_on_line()) printf("The UPS will restart in about one minute.\n"); else printf("The UPS will restart when power returns.\n"); ser_send_pace(upsfd, UPSDELAY, "S01R0001\r"); } void upsdrv_updateinfo(void) { char involt[16], outvolt[16], loadpct[16], acfreq[16], battvolt[16], upstemp[16], pstat[16], buf[256]; float bvoltp; ssize_t ret; ret = ser_send_pace(upsfd, UPSDELAY, "\rQ1\r"); if (ret < 1) { ser_comm_fail("ser_send_pace failed"); dstate_datastale(); return; } /* these things need a long time to respond completely */ usleep(200000); ret = ser_get_line(upsfd, buf, sizeof(buf), ENDCHAR, "", SER_WAIT_SEC, SER_WAIT_USEC); if (ret < 1) { ser_comm_fail("Poll failed: %s", ret ? strerror(errno) : "timeout"); dstate_datastale(); return; } if (ret < 46) { ser_comm_fail("Poll failed: short read (got %" PRIiSIZE " bytes)", ret); dstate_datastale(); return; } if (ret > 46) { ser_comm_fail("Poll failed: response too long (got %" PRIiSIZE " bytes)", ret); dstate_datastale(); return; } if (buf[0] != '(') { ser_comm_fail("Poll failed: invalid start character (got %02x)", buf[0]); dstate_datastale(); return; } ser_comm_good(); sscanf(buf, "%*c%s %*s %s %s %s %s %s %s", involt, outvolt, loadpct, acfreq, battvolt, upstemp, pstat); /* Guesstimation of battery charge left (inaccurate) */ bvoltp = 100 * (atof(battvolt) - lowvolt) / (highvolt - lowvolt); if (bvoltp > 100) { bvoltp = 100; } dstate_setinfo("battery.voltage", "%.1f", battvoltmult * atof(battvolt)); dstate_setinfo("input.voltage", "%s", involt); dstate_setinfo("output.voltage", "%s", outvolt); dstate_setinfo("ups.load", "%s", loadpct); dstate_setinfo("input.frequency", "%s", acfreq); if(upstemp[0] != 'X') { dstate_setinfo("ups.temperature", "%s", upstemp); } dstate_setinfo("battery.charge", "%02.1f", bvoltp); status_init(); if (pstat[0] == '0') { status_set("OL"); /* on line */ /* only allow these when OL since they're bogus when OB */ if (pstat[2] == (inverted_bypass_bit ? '0' : '1')) { /* boost or trim in effect */ if (atof(involt) < atof(outvolt)) status_set("BOOST"); if (atof(involt) > atof(outvolt)) status_set("TRIM"); } } else { status_set("OB"); /* on battery */ } if (pstat[1] == '1') status_set("LB"); /* low battery */ status_commit(); dstate_dataok(); } void upsdrv_help(void) { } void upsdrv_makevartable(void) { addvar(VAR_VALUE, "nombattvolt", "Override nominal battery voltage"); addvar(VAR_VALUE, "battvoltmult", "Battery voltage multiplier"); addvar(VAR_VALUE, "ID", "Force UPS ID response string"); } void upsdrv_initups(void) { upsdebugx(0, "Please note that this driver is deprecated and will not receive\n" "new development. If it works for managing your devices - fine,\n" "but if you are running it to try setting up a new device, please\n" "consider the newer nutdrv_qx instead, which should handle all 'Qx'\n" "protocol variants for NUT. (Please also report if your device works\n" "with this driver, but nutdrv_qx would not actually support it with\n" "any subdriver!)\n"); upsfd = ser_open(device_path); ser_set_speed(upsfd, device_path, B2400); } void upsdrv_cleanup(void) { ser_close(upsfd, device_path); } nut-2.8.1/drivers/eaton-ats16-nm2-mib.c0000644000175000017500000004012114501607135014374 00000000000000/* eaton-ats16-nm2-mib.c - subdriver to monitor Eaton ATS16 SNMP devices with NUT * using newer Network-M2 cards * * Copyright (C) * 2011-2012 Arnaud Quette * 2016-2020 Eaton (author: Arnaud Quette ) * * Note: this subdriver was initially generated as a "stub" by the * gen-snmp-subdriver script. It must be customized! * * 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 2 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, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "eaton-ats16-nm2-mib.h" #define EATON_ATS16_NM2_MIB_VERSION "0.22" #define EATON_ATS16_NM2_SYSOID ".1.3.6.1.4.1.534.10.2" /* newer Network-M2 */ #define EATON_ATS16_NM2_MODEL ".1.3.6.1.4.1.534.10.2.1.2.0" static info_lkp_t eaton_ats16_nm2_source_info[] = { { 1, "init", NULL, NULL }, { 2, "diagnosis", NULL, NULL }, { 3, "off", NULL, NULL }, { 4, "1", NULL, NULL }, { 5, "2", NULL, NULL }, { 6, "safe", NULL, NULL }, { 7, "fault", NULL, NULL }, { 0, NULL, NULL, NULL } }; static info_lkp_t eaton_ats16_nm2_sensitivity_info[] = { { 1, "normal", NULL, NULL }, { 2, "high", NULL, NULL }, { 3, "low", NULL, NULL }, { 0, NULL, NULL, NULL } }; static info_lkp_t eaton_ats16_nm2_input_frequency_status_info[] = { { 1, "good", NULL, NULL }, /* No threshold triggered */ { 2, "out-of-range", NULL, NULL }, /* Frequency out of range triggered */ { 0, NULL, NULL, NULL } }; static info_lkp_t eaton_ats16_nm2_input_voltage_status_info[] = { { 1, "good", NULL, NULL }, /* No threshold triggered */ { 2, "derated-range", NULL, NULL }, /* Voltage derated */ { 3, "out-of-range", NULL, NULL }, /* Voltage out of range triggered */ { 4, "unknown", NULL, NULL }, /* "missing" */ { 0, NULL, NULL, NULL } }; static info_lkp_t eaton_ats16_nm2_test_result_info[] = { { 1, "done and passed", NULL, NULL }, { 2, "done and warning", NULL, NULL }, { 3, "done and error", NULL, NULL }, { 4, "aborted", NULL, NULL }, { 5, "in progress", NULL, NULL }, { 6, "no test initiated", NULL, NULL }, { 0, NULL, NULL, NULL } }; static info_lkp_t eaton_ats16_nm2_output_status_info[] = { { 1, "OFF", NULL, NULL }, /* Output not powered */ { 2, "OL", NULL, NULL }, /* Output powered */ { 0, NULL, NULL, NULL } }; static info_lkp_t eaton_ats16_ambient_drycontacts_info[] = { { -1, "unknown", NULL, NULL }, { 1, "opened", NULL, NULL }, { 2, "closed", NULL, NULL }, { 3, "opened", NULL, NULL }, /* openWithNotice */ { 4, "closed", NULL, NULL }, /* closedWithNotice */ { 0, NULL, NULL, NULL } }; /* EATON_ATS Snmp2NUT lookup table */ static snmp_info_t eaton_ats16_nm2_mib[] = { /* standard MIB items */ { "device.description", ST_FLAG_STRING | ST_FLAG_RW, SU_INFOSIZE, ".1.3.6.1.2.1.1.1.0", NULL, SU_FLAG_OK, NULL }, { "device.contact", ST_FLAG_STRING | ST_FLAG_RW, SU_INFOSIZE, ".1.3.6.1.2.1.1.4.0", NULL, SU_FLAG_OK, NULL }, { "device.location", ST_FLAG_STRING | ST_FLAG_RW, SU_INFOSIZE, ".1.3.6.1.2.1.1.6.0", NULL, SU_FLAG_OK, NULL }, /* Device collection */ { "device.type", ST_FLAG_STRING, SU_INFOSIZE, NULL, "ats", SU_FLAG_STATIC | SU_FLAG_ABSENT | SU_FLAG_OK, NULL }, /* ats2IdentManufacturer.0 = STRING: EATON */ { "device.mfr", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.534.10.2.1.1.0", "Eaton", SU_FLAG_STATIC | SU_FLAG_OK, NULL }, /* ats2IdentModel.0 = STRING: Eaton ATS */ { "device.model", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.534.10.2.1.2.0", "ATS", SU_FLAG_STATIC | SU_FLAG_OK, NULL }, /* FIXME: RFC for device.firmware! */ /* FIXME: the 2 "firmware" entries below should be SU_FLAG_SEMI_STATIC */ /* ats2IdentFWVersion.0 = STRING: 00.00.0009 */ { "ups.firmware", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.534.10.2.1.3.0", NULL, SU_FLAG_OK, NULL }, /* FIXME: RFC for device.firmware.aux! */ /* ats2IdentRelease.0 = STRING: 1.7.5 */ { "ups.firmware.aux", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.534.10.2.1.7.0", NULL, SU_FLAG_OK, NULL }, /* ats2IdentSerialNumber.0 = STRING: GA04F23009 */ { "device.serial", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.534.10.2.1.5.0", NULL, SU_FLAG_STATIC | SU_FLAG_OK, NULL }, /* ats2IdentPartNumber.0 = STRING: EATS16N */ { "device.part", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.534.10.2.1.6.0", NULL, SU_FLAG_STATIC | SU_FLAG_OK, NULL }, /* ats2IdentAgentVersion.0 = STRING: 301F23C28 */ /* { "unmapped.ats2IdentAgentVersion", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.534.10.2.1.7.0", NULL, SU_FLAG_OK, NULL, NULL }, */ /* ats2InputDephasing.0 = INTEGER: 2 degrees */ /* { "unmapped.ats2InputDephasing", 0, 1, ".1.3.6.1.4.1.534.10.2.2.1.1.0", NULL, SU_FLAG_OK, NULL, NULL }, */ /* Input collection */ /* ats2InputIndex.source1 = INTEGER: source1(1) */ { "input.1.id", 0, 1, ".1.3.6.1.4.1.534.10.2.2.2.1.1.1", NULL, SU_FLAG_STATIC | SU_FLAG_OK, NULL }, /* ats2InputIndex.source2 = INTEGER: source2(2) */ { "input.2.id", 0, 1, ".1.3.6.1.4.1.534.10.2.2.2.1.1.2", NULL, SU_FLAG_STATIC | SU_FLAG_OK, NULL }, /* ats2InputVoltage.source1 = INTEGER: 2292 0.1 V */ { "input.1.voltage", 0, 0.1, ".1.3.6.1.4.1.534.10.2.2.2.1.2.1", NULL, SU_FLAG_OK, NULL }, /* ats2InputVoltage.source2 = INTEGER: 2432 0.1 V */ { "input.2.voltage", 0, 0.1, ".1.3.6.1.4.1.534.10.2.2.2.1.2.2", NULL, SU_FLAG_OK, NULL }, /* ats2InputStatusVoltage.source1 = INTEGER: normalRange(1) */ { "input.1.voltage.status", ST_FLAG_STRING, 1, ".1.3.6.1.4.1.534.10.2.3.2.1.5.1", NULL, SU_FLAG_OK, eaton_ats16_nm2_input_voltage_status_info }, /* ats2InputStatusVoltage.source2 = INTEGER: normalRange(1) */ { "input.2.voltage.status", ST_FLAG_STRING, 1, ".1.3.6.1.4.1.534.10.2.3.2.1.5.2", NULL, SU_FLAG_OK, eaton_ats16_nm2_input_voltage_status_info }, /* ats2InputFrequency.source1 = INTEGER: 500 0.1 Hz */ { "input.1.frequency", 0, 0.1, ".1.3.6.1.4.1.534.10.2.2.2.1.3.1", NULL, SU_FLAG_OK, NULL }, /* ats2InputFrequency.source2 = INTEGER: 500 0.1 Hz */ { "input.2.frequency", 0, 0.1, ".1.3.6.1.4.1.534.10.2.2.2.1.3.2", NULL, SU_FLAG_OK, NULL }, /* ats2InputStatusFrequency.source1 = INTEGER: good(1) */ { "input.1.frequency.status", ST_FLAG_STRING, 1, ".1.3.6.1.4.1.534.10.2.3.2.1.2.1", NULL, SU_FLAG_OK, eaton_ats16_nm2_input_frequency_status_info }, /* ats2InputStatusFrequency.source2 = INTEGER: good(1) */ { "input.2.frequency.status", ST_FLAG_STRING, 1, ".1.3.6.1.4.1.534.10.2.3.2.1.2.2", NULL, SU_FLAG_OK, eaton_ats16_nm2_input_frequency_status_info }, /* ats2ConfigSensitivity.0 = INTEGER: normal(1) */ { "input.sensitivity", ST_FLAG_RW, SU_INFOSIZE, ".1.3.6.1.4.1.534.10.2.4.6.0", NULL, SU_FLAG_OK, &eaton_ats16_nm2_sensitivity_info[0] }, /* ats2OperationMode.0 = INTEGER: source1(4) */ { "input.source", ST_FLAG_STRING, 1, ".1.3.6.1.4.1.534.10.2.2.4.0", NULL, SU_FLAG_OK, eaton_ats16_nm2_source_info }, /* ats2ConfigPreferred.0 = INTEGER: source1(1) */ { "input.source.preferred", ST_FLAG_RW, 1, ".1.3.6.1.4.1.534.10.2.4.5.0", NULL, SU_FLAG_OK, NULL }, /* ats2InputDephasing = INTEGER: 181 */ { "input.phase.shift", 0, 1, ".1.3.6.1.4.1.534.10.2.2.1.1.0", NULL, SU_FLAG_OK, NULL }, /* Output collection */ /* ats2OutputVoltage.0 = INTEGER: 2304 0.1 V */ { "output.voltage", 0, 0.1, ".1.3.6.1.4.1.534.10.2.2.3.1.0", NULL, SU_FLAG_OK, NULL }, /* ats2ConfigOutputVoltage.0 = INTEGER: 230 1 V */ { "output.voltage.nominal", ST_FLAG_RW, 1, ".1.3.6.1.4.1.534.10.2.4.4.0", NULL, SU_FLAG_OK, NULL }, /* ats2OutputCurrent.0 = INTEGER: 5 0.1 A */ { "output.current", 0, 0.1, ".1.3.6.1.4.1.534.10.2.2.3.2.0", NULL, SU_FLAG_OK, NULL }, /* UPS collection */ /* FIXME: RFC for device.test.result! */ /* ats2ConfigTransferTest.0 = INTEGER: noTestInitiated(6) */ { "ups.test.result", 0, 1, ".1.3.6.1.4.1.534.10.2.4.8.0", NULL, SU_FLAG_OK, eaton_ats16_nm2_test_result_info }, /* FIXME: RFC for device.status! */ /* ats2StatusOutput.0 = INTEGER: outputPowered(2) */ { "ups.status", 0, 1, ".1.3.6.1.4.1.534.10.2.3.3.2.0", NULL, SU_FLAG_OK, eaton_ats16_nm2_output_status_info }, /* Ambient collection */ /* ats2EnvRemoteTemp.0 = INTEGER: 0 degrees Centigrade */ { "ambient.temperature", 0, 1, ".1.3.6.1.4.1.534.10.2.5.1.0", NULL, SU_FLAG_OK, NULL }, /* ats2EnvRemoteTempLowerLimit.0 = INTEGER: 5 degrees Centigrade */ { "ambient.temperature.low", ST_FLAG_RW, 1, ".1.3.6.1.4.1.534.10.2.5.5.0", NULL, SU_FLAG_OK, NULL }, /* ats2EnvRemoteTempUpperLimit.0 = INTEGER: 40 degrees Centigrade */ { "ambient.temperature.high", ST_FLAG_RW, 1, ".1.3.6.1.4.1.534.10.2.5.6.0", NULL, SU_FLAG_OK, NULL }, /* ats2EnvRemoteHumidity.0 = INTEGER: 0 percent */ { "ambient.humidity", 0, 1, ".1.3.6.1.4.1.534.10.2.5.2.0", NULL, SU_FLAG_OK, NULL }, /* ats2EnvRemoteHumidityLowerLimit.0 = INTEGER: 5 percent */ { "ambient.humidity.low", ST_FLAG_RW, 1, ".1.3.6.1.4.1.534.10.2.5.7.0", NULL, SU_FLAG_OK, NULL }, /* ats2EnvRemoteHumidityUpperLimit.0 = INTEGER: 90 percent */ { "ambient.humidity.high", ST_FLAG_RW, 1, ".1.3.6.1.4.1.534.10.2.5.8.0", NULL, SU_FLAG_OK, NULL }, /* Dry contacts on EMP001 TH module */ /* ats2ContactState.1 = INTEGER: open(1) */ { "ambient.contacts.1.status", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.534.10.2.5.4.1.3.1", NULL, SU_FLAG_OK, &eaton_ats16_ambient_drycontacts_info[0] }, /* ats2ContactState.2 = INTEGER: open(1) */ { "ambient.contacts.2.status", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.534.10.2.5.4.1.3.2", NULL, SU_FLAG_OK, &eaton_ats16_ambient_drycontacts_info[0] }, #if WITH_UNMAPPED_DATA_POINTS /* FIXME: Remaining data to be processed */ /* ats2InputStatusDephasing.0 = INTEGER: normal(1) */ { "unmapped.ats2InputStatusDephasing", 0, 1, ".1.3.6.1.4.1.534.10.2.3.1.1.0", NULL, SU_FLAG_OK, NULL }, /* ats2InputStatusIndex.source1 = INTEGER: source1(1) */ { "unmapped.ats2InputStatusIndex", 0, 1, ".1.3.6.1.4.1.534.10.2.3.2.1.1.1", NULL, SU_FLAG_OK, NULL }, /* ats2InputStatusIndex.source2 = INTEGER: source2(2) */ { "unmapped.ats2InputStatusIndex", 0, 1, ".1.3.6.1.4.1.534.10.2.3.2.1.1.2", NULL, SU_FLAG_OK, NULL }, /* ats2InputStatusGood.source1 = INTEGER: voltageAndFreqNormalRange(2) */ { "unmapped.ats2InputStatusGood", 0, 1, ".1.3.6.1.4.1.534.10.2.3.2.1.3.1", NULL, SU_FLAG_OK, NULL }, /* ats2InputStatusGood.source2 = INTEGER: voltageAndFreqNormalRange(2) */ { "unmapped.ats2InputStatusGood", 0, 1, ".1.3.6.1.4.1.534.10.2.3.2.1.3.2", NULL, SU_FLAG_OK, NULL }, /* ats2InputStatusInternalFailure.source1 = INTEGER: good(1) */ { "unmapped.ats2InputStatusInternalFailure", 0, 1, ".1.3.6.1.4.1.534.10.2.3.2.1.4.1", NULL, SU_FLAG_OK, NULL }, /* ats2InputStatusInternalFailure.source2 = INTEGER: good(1) */ { "unmapped.ats2InputStatusInternalFailure", 0, 1, ".1.3.6.1.4.1.534.10.2.3.2.1.4.2", NULL, SU_FLAG_OK, NULL }, /* ats2InputStatusUsed.source1 = INTEGER: poweringLoad(2) */ { "unmapped.ats2InputStatusUsed", 0, 1, ".1.3.6.1.4.1.534.10.2.3.2.1.6.1", NULL, SU_FLAG_OK, NULL }, /* ats2InputStatusUsed.source2 = INTEGER: notPoweringLoad(1) */ { "unmapped.ats2InputStatusUsed", 0, 1, ".1.3.6.1.4.1.534.10.2.3.2.1.6.2", NULL, SU_FLAG_OK, NULL }, /* ats2StatusInternalFailure.0 = INTEGER: good(1) */ { "unmapped.ats2StatusInternalFailure", 0, 1, ".1.3.6.1.4.1.534.10.2.3.3.1.0", NULL, SU_FLAG_OK, NULL }, /* ats2StatusOverload.0 = INTEGER: noOverload(1) */ { "unmapped.ats2StatusOverload", 0, 1, ".1.3.6.1.4.1.534.10.2.3.3.3.0", NULL, SU_FLAG_OK, NULL }, /* ats2StatusOverTemperature.0 = INTEGER: noOverTemperature(1) */ { "unmapped.ats2StatusOverTemperature", 0, 1, ".1.3.6.1.4.1.534.10.2.3.3.4.0", NULL, SU_FLAG_OK, NULL }, /* ats2StatusShortCircuit.0 = INTEGER: noShortCircuit(1) */ { "unmapped.ats2StatusShortCircuit", 0, 1, ".1.3.6.1.4.1.534.10.2.3.3.5.0", NULL, SU_FLAG_OK, NULL }, /* ats2StatusCommunicationLost.0 = INTEGER: good(1) */ { "unmapped.ats2StatusCommunicationLost", 0, 1, ".1.3.6.1.4.1.534.10.2.3.3.6.0", NULL, SU_FLAG_OK, NULL }, /* ats2StatusConfigurationFailure.0 = INTEGER: good(1) */ { "unmapped.ats2StatusConfigurationFailure", 0, 1, ".1.3.6.1.4.1.534.10.2.3.3.7.0", NULL, SU_FLAG_OK, NULL }, /* ats2ConfigTimeRTC.0 = Wrong Type (should be Counter32): Gauge32: 19191036 */ { "unmapped.ats2ConfigTimeRTC", 0, 1, ".1.3.6.1.4.1.534.10.2.4.1.1.0", NULL, SU_FLAG_OK, NULL }, /* ats2ConfigTimeTextDate.0 = STRING: 08/11/1970 */ { "unmapped.ats2ConfigTimeTextDate", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.534.10.2.4.1.2.0", NULL, SU_FLAG_OK, NULL }, /* ats2ConfigTimeTextTime.0 = STRING: 02/50/36 */ { "unmapped.ats2ConfigTimeTextTime", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.534.10.2.4.1.3.0", NULL, SU_FLAG_OK, NULL }, /* ats2ConfigInputVoltageRating.0 = INTEGER: 1 1 V */ { "unmapped.ats2ConfigInputVoltageRating", 0, 1, ".1.3.6.1.4.1.534.10.2.4.2.0", NULL, SU_FLAG_OK, NULL }, /* ats2ConfigInputFrequencyRating.0 = INTEGER: 50 Hz */ { "unmapped.ats2ConfigInputFrequencyRating", 0, 1, ".1.3.6.1.4.1.534.10.2.4.3.0", NULL, SU_FLAG_OK, NULL }, /* ats2ConfigTransferMode.0 = INTEGER: standard(1) */ { "unmapped.ats2ConfigTransferMode", 0, 1, ".1.3.6.1.4.1.534.10.2.4.7.0", NULL, SU_FLAG_OK, NULL }, /* ats2ConfigBrownoutLow.0 = INTEGER: 202 1 V */ { "unmapped.ats2ConfigBrownoutLow", 0, 1, ".1.3.6.1.4.1.534.10.2.4.9.0", NULL, SU_FLAG_OK, NULL }, /* ats2ConfigBrownoutLowDerated.0 = INTEGER: 189 1 V */ { "unmapped.ats2ConfigBrownoutLowDerated", 0, 1, ".1.3.6.1.4.1.534.10.2.4.10.0", NULL, SU_FLAG_OK, NULL }, /* ats2ConfigBrownoutHigh.0 = INTEGER: 258 1 V */ { "unmapped.ats2ConfigBrownoutHigh", 0, 1, ".1.3.6.1.4.1.534.10.2.4.11.0", NULL, SU_FLAG_OK, NULL }, /* ats2ConfigHysteresisVoltage.0 = INTEGER: 5 1 V */ { "unmapped.ats2ConfigHysteresisVoltage", 0, 1, ".1.3.6.1.4.1.534.10.2.4.12.0", NULL, SU_FLAG_OK, NULL }, /* Ambient collection */ /* ats2EnvNumContacts.0 = INTEGER: 2 */ { "unmapped.ats2EnvNumContacts", 0, 1, ".1.3.6.1.4.1.534.10.2.5.3.0", NULL, SU_FLAG_OK, NULL }, /* ats2ContactIndex.1 = INTEGER: 1 */ { "unmapped.ats2ContactIndex", 0, 1, ".1.3.6.1.4.1.534.10.2.5.4.1.1.1", NULL, SU_FLAG_OK, NULL }, /* ats2ContactIndex.2 = INTEGER: 2 */ { "unmapped.ats2ContactIndex", 0, 1, ".1.3.6.1.4.1.534.10.2.5.4.1.1.2", NULL, SU_FLAG_OK, NULL }, /* ats2ContactType.1 = INTEGER: notUsed(4) */ { "unmapped.ats2ContactType", 0, 1, ".1.3.6.1.4.1.534.10.2.5.4.1.2.1", NULL, SU_FLAG_OK, NULL }, /* ats2ContactType.2 = INTEGER: notUsed(4) */ { "unmapped.ats2ContactType", 0, 1, ".1.3.6.1.4.1.534.10.2.5.4.1.2.2", NULL, SU_FLAG_OK, NULL }, /* ats2ContactState.1 = INTEGER: open(1) */ { "unmapped.ats2ContactState", 0, 1, ".1.3.6.1.4.1.534.10.2.5.4.1.3.1", NULL, SU_FLAG_OK, NULL }, /* ats2ContactState.2 = INTEGER: open(1) */ { "unmapped.ats2ContactState", 0, 1, ".1.3.6.1.4.1.534.10.2.5.4.1.3.2", NULL, SU_FLAG_OK, NULL }, /* ats2ContactDescr.1 = STRING: Input #1 */ { "unmapped.ats2ContactDescr", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.534.10.2.5.4.1.4.1", NULL, SU_FLAG_OK, NULL }, /* ats2ContactDescr.2 = STRING: Input #2 */ { "unmapped.ats2ContactDescr", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.534.10.2.5.4.1.4.2", NULL, SU_FLAG_OK, NULL }, #endif /* if WITH_UNMAPPED_DATA_POINTS */ /* end of structure. */ { NULL, 0, 0, NULL, NULL, 0, NULL } }; /* Note: keep the legacy definition intact, to avoid breaking compatibility */ /* FIXME: The lines below are duplicated to fix an issue with the code generator (nut-snmpinfo.py -> line is discarding) */ /* Note: * due to a bug in tools/nut-snmpinfo.py, prepending a 2nd mib2nut_info_t * declaration with a comment line results in data extraction not being * done for all entries in the file. Hence the above comment line being * after its belonging declaration! */ /*mib2nut_info_t eaton_ats16_nm2 = { "eaton_ats16_nm2", EATON_ATS16_NM2_MIB_VERSION, NULL, EATON_ATS16_NM2_MODEL, eaton_ats16_nm2_mib, EATON_ATS16_NM2_SYSOID, NULL };*/ mib2nut_info_t eaton_ats16_nm2 = { "eaton_ats16_nm2", EATON_ATS16_NM2_MIB_VERSION, NULL, EATON_ATS16_NM2_MODEL, eaton_ats16_nm2_mib, EATON_ATS16_NM2_SYSOID, NULL }; nut-2.8.1/drivers/eaton-pdu-revelation-mib.h0000644000175000017500000000235314377374134015727 00000000000000/* eaton-pdu-revelation-mib.h - subdriver to monitor Eaton ePDU SNMP devices with NUT * * Copyright (C) * 2010 Arjen de Korte * 2011 - 2012 Arnaud Quette * 2017 Arnaud Quette * 2017 Jim Klimov * * 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 2 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, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef EATON_EPDU_REVELATION_MIB_H #define EATON_EPDU_REVELATION_MIB_H #include "main.h" #include "snmp-ups.h" extern mib2nut_info_t aphel_revelation; #endif /* EATON_EPDU_REVELATION_MIB_H */ nut-2.8.1/drivers/genericups.c0000644000175000017500000002640214501607135013245 00000000000000/* genericups.c - support for generic contact-closure UPS models Copyright (C) 1999 Russell Kroll 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 2 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, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "config.h" /* must be first */ #ifndef WIN32 #include #else #include "wincompat.h" #endif #include "main.h" #include "serial.h" #include "genericups.h" #include "nut_stdint.h" #define DRIVER_NAME "Generic contact-closure UPS driver" #define DRIVER_VERSION "1.39" /* driver description structure */ upsdrv_info_t upsdrv_info = { DRIVER_NAME, DRIVER_VERSION, "Russell Kroll ", DRV_STABLE, { NULL } }; static int upstype = -1; static void parse_output_signals(const char *value, int *line) { int old_line = *line; /* parse signals the serial port can output */ *line = 0; upsdebugx(4, "%s: enter", __func__); /* Note: for future drivers, please use strtok() or similar tokenizing * methods, such that it is easier to spot configuration mistakes. With * this code, a misspelled control line may go unnoticed. I'd fix it * The Right Way (tm), but these UPSes are ancient. */ if (strstr(value, "DTR") && !strstr(value, "-DTR")) { upsdebugx(3, "%s: override DTR", __func__); *line |= TIOCM_DTR; } if (strstr(value, "RTS") && !strstr(value, "-RTS")) { upsdebugx(3, "%s: override RTS", __func__); *line |= TIOCM_RTS; } if (strstr(value, "ST")) { upsdebugx(3, "%s: override ST", __func__); *line |= TIOCM_ST; } if (strstr(value, "CTS")) { fatalx(EXIT_FAILURE, "Can't override output with CTS (not an output)"); } if (strstr(value, "DCD")) { fatalx(EXIT_FAILURE, "Can't override output with DCD (not an output)"); } if (strstr(value, "RNG")) { fatalx(EXIT_FAILURE, "Can't override output with RNG (not an output)"); } if (strstr(value, "DSR")) { fatalx(EXIT_FAILURE, "Can't override output with DSR (not an output)"); } if (strstr(value, "NULL") || strstr(value, "none")) { upsdebugx(3, "%s: disable", __func__); *line = 0; } if(*line == old_line) { upslogx(LOG_NOTICE, "%s: output overrides specified, but no effective difference - check for typos?", __func__); } upsdebugx(4, "%s: exit", __func__); } static void parse_input_signals(const char *value, int *line, int *val) { /* parse signals the serial port can input */ int old_line = *line, old_val = *val; *line = 0; *val = 0; upsdebugx(4, "%s: enter", __func__); if (strstr(value, "CTS")) { *line |= TIOCM_CTS; if (!strstr(value, "-CTS")) { upsdebugx(3, "%s: override CTS (active low)", __func__); *val |= TIOCM_CTS; } else { upsdebugx(3, "%s: override CTS", __func__); } } if (strstr(value, "DCD")) { *line |= TIOCM_CD; if (!strstr(value, "-DCD")) { upsdebugx(3, "%s: override DCD (active low)", __func__); *val |= TIOCM_CD; } else { upsdebugx(3, "%s: override DCD", __func__); } } if (strstr(value, "RNG")) { *line |= TIOCM_RNG; if (!strstr(value, "-RNG")) { upsdebugx(3, "%s: override RNG (active low)", __func__); *val |= TIOCM_RNG; } else { upsdebugx(3, "%s: override RNG", __func__); } } if (strstr(value, "DSR")) { *line |= TIOCM_DSR; if (!strstr(value, "-DSR")) { upsdebugx(3, "%s: override DSR (active low)", __func__); *val |= TIOCM_DSR; } else { upsdebugx(3, "%s: override DSR", __func__); } } if (strstr(value, "DTR")) { fatalx(EXIT_FAILURE, "Can't override input with DTR (not an input)"); } if (strstr(value, "RTS")) { fatalx(EXIT_FAILURE, "Can't override input with RTS (not an input)"); } if (strstr(value, "ST")) { fatalx(EXIT_FAILURE, "Can't override input with ST (not an input)"); } if (strstr(value, "NULL") || strstr(value, "none")) { *line = 0; *val = 0; upsdebugx(3, "%s: disable", __func__); } if((*line == old_line) && (*val == old_val)) { upslogx(LOG_NOTICE, "%s: input overrides specified, but no effective difference - check for typos?", __func__); } upsdebugx(4, "%s: exit", __func__); } void upsdrv_initinfo(void) { char *v; /* setup the basics */ dstate_setinfo("ups.mfr", "%s", ((v = getval("mfr")) != NULL) ? v : upstab[upstype].mfr); dstate_setinfo("ups.model", "%s", ((v = getval("model")) != NULL) ? v : upstab[upstype].model); if ((v = getval("serial")) != NULL) { dstate_setinfo("ups.serial", "%s", v); } /* User wants to override the input signal definitions. See also upsdrv_initups(). */ if ((v = getval("OL")) != NULL) { parse_input_signals(v, &upstab[upstype].line_ol, &upstab[upstype].val_ol); upsdebugx(2, "parse_input_signals: OL overridden with %s\n", v); } if ((v = getval("LB")) != NULL) { parse_input_signals(v, &upstab[upstype].line_bl, &upstab[upstype].val_bl); upsdebugx(2, "parse_input_signals: LB overridden with %s\n", v); } if ((v = getval("RB")) != NULL) { parse_input_signals(v, &upstab[upstype].line_rb, &upstab[upstype].val_rb); upsdebugx(2, "parse_input_signals: RB overridden with %s\n", v); } if ((v = getval("BYPASS")) != NULL) { parse_input_signals(v, &upstab[upstype].line_bypass, &upstab[upstype].val_bypass); upsdebugx(2, "parse_input_signals: BYPASS overridden with %s\n", v); } } /* normal idle loop - keep up with the current state of the UPS */ void upsdrv_updateinfo(void) { int flags, ol, bl, rb, bypass, ret; #ifndef WIN32 ret = ioctl(upsfd, TIOCMGET, &flags); #else ret = w32_getcomm( upsfd, &flags ); #endif if (ret != 0) { upslog_with_errno(LOG_INFO, "ioctl failed"); ser_comm_fail("Status read failed"); dstate_datastale(); return; } /* Always online when OL is disabled */ ol = ((flags & upstab[upstype].line_ol) == upstab[upstype].val_ol); /* Always have the flags cleared when other status flags are disabled */ bl = upstab[upstype].line_bl != 0 && ((flags & upstab[upstype].line_bl) == upstab[upstype].val_bl); rb = upstab[upstype].line_rb != 0 && ((flags & upstab[upstype].line_rb) == upstab[upstype].val_rb); bypass = upstab[upstype].line_bypass != 0 && ((flags & upstab[upstype].line_bypass) == upstab[upstype].val_bypass); status_init(); if (bl) { status_set("LB"); /* low battery */ } if (ol) { status_set("OL"); /* on line */ } else { status_set("OB"); /* on battery */ } if (rb) { status_set("RB"); /* replace battery */ } if (bypass) { status_set("BYPASS"); /* battery bypass */ } status_commit(); upsdebugx(5, "ups.status: %s %s %s %s\n", ol ? "OL" : "OB", bl ? "BL" : "", rb ? "RB" : "", bypass ? "BYPASS" : ""); ser_comm_good(); dstate_dataok(); } /* show all possible UPS types */ static void listtypes(void) { int i; printf("Valid UPS types:\n\n"); for (i = 0; upstab[i].mfr != NULL; i++) { printf("%i: %s\n", i, upstab[i].desc); } } /* set the flags for this UPS type */ static void set_ups_type(void) { int i; if (!getval("upstype")) { fatalx(EXIT_FAILURE, "No upstype set - see help text / man page!"); } upstype = atoi(getval("upstype")); for (i = 0; upstab[i].mfr != NULL; i++) { if (upstype == i) { upslogx(LOG_INFO, "UPS type: %s\n", upstab[i].desc); return; } } listtypes(); fatalx(EXIT_FAILURE, "\nFatal error: unknown UPS type number"); } /* power down the attached load immediately */ void upsdrv_shutdown(void) { int flags, ret; if (upstype == -1) { upslogx(LOG_ERR, "No upstype set - see help text / man page!"); set_exit_flag(-1); return; } flags = upstab[upstype].line_sd; if (flags == -1) { upslogx(LOG_ERR, "No shutdown command defined for this model!"); set_exit_flag(-1); return; } if (flags == TIOCM_ST) { #ifndef WIN32 #ifndef HAVE_TCSENDBREAK upslogx(LOG_ERR, "Need to send a BREAK, but don't have tcsendbreak!"); set_exit_flag(-1); return; #endif #endif ret = tcsendbreak(upsfd, 4901); if (ret != 0) { upslog_with_errno(LOG_ERR, "tcsendbreak"); set_exit_flag(-1); } return; } #ifndef WIN32 ret = ioctl(upsfd, TIOCMSET, &flags); #else ret = w32_setcomm(upsfd,&flags); #endif if (ret != 0) { upslog_with_errno(LOG_ERR, "ioctl TIOCMSET"); set_exit_flag(-1); return; } if (getval("sdtime")) { long sdtime; sdtime = strtol(getval("sdtime"), (char **) NULL, 10); upslogx(LOG_INFO, "Holding shutdown signal for %ld seconds...\n", sdtime); if (sdtime > 0) { #ifdef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_UNREACHABLE_CODE #pragma GCC diagnostic push #endif #ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_UNREACHABLE_CODE #pragma GCC diagnostic ignored "-Wunreachable-code" #endif #ifdef __clang__ #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wunreachable-code" #endif /* Different platforms, different sizes, none fits all... */ if (sizeof(long) > sizeof(unsigned int) && sdtime < (long)UINT_MAX) { #ifdef __clang__ #pragma clang diagnostic pop #endif #ifdef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_UNREACHABLE_CODE #pragma GCC diagnostic pop #endif sleep((unsigned int)sdtime); } else { sleep(UINT_MAX); } } } } void upsdrv_help(void) { listtypes(); } void upsdrv_makevartable(void) { addvar(VAR_VALUE, "upstype", "Set UPS type (required)"); addvar(VAR_VALUE, "mfr", "Override manufacturer name"); addvar(VAR_VALUE, "model", "Override model name"); addvar(VAR_VALUE, "serial", "Specify the serial number"); addvar(VAR_VALUE, "CP", "Override cable power setting"); addvar(VAR_VALUE, "OL", "Override on line signal"); addvar(VAR_VALUE, "LB", "Override low battery signal"); addvar(VAR_VALUE, "RB", "Override replace battery signal"); addvar(VAR_VALUE, "BYPASS", "Override battery bypass signal"); addvar(VAR_VALUE, "SD", "Override shutdown setting"); addvar(VAR_VALUE, "sdtime", "Hold time for shutdown value (seconds)"); } void upsdrv_initups(void) { struct termios tio; char *v; set_ups_type(); upsfd = ser_open(device_path); if (tcgetattr(upsfd, &tio)) { fatal_with_errno(EXIT_FAILURE, "tcgetattr"); } /* don't hang up on last close */ tio.c_cflag &= ~((tcflag_t)HUPCL); if (tcsetattr(upsfd, TCSANOW, &tio)) { fatal_with_errno(EXIT_FAILURE, "tcsetattr"); } /* See if the user wants to override the output signal definitions this must be done here, since we might go to upsdrv_shutdown() immediately. Input signal definition override is handled in upsdrv_initinfo() */ if ((v = getval("CP")) != NULL) { parse_output_signals(v, &upstab[upstype].line_norm); upsdebugx(2, "parse_output_signals: CP overridden with %s\n", v); } if ((v = getval("SD")) != NULL) { parse_output_signals(v, &upstab[upstype].line_sd); upsdebugx(2, "parse_output_signals: SD overridden with %s\n", v); } #ifndef WIN32 if (ioctl(upsfd, TIOCMSET, &upstab[upstype].line_norm)) { #else if (w32_setcomm(upsfd,&upstab[upstype].line_norm)) { #endif fatal_with_errno(EXIT_FAILURE, "ioctl TIOCMSET"); } } void upsdrv_cleanup(void) { ser_close(upsfd, device_path); } nut-2.8.1/drivers/mge-xml.c0000644000175000017500000021763114502253356012460 00000000000000/* mge-xml.c Model specific routines for Eaton / MGE XML protocol UPSes Copyright (C) 2008-2009 Arjen de Korte 2009-2021 Eaton (author: Arnaud Quette ) 2017 Eaton (author: Jim Klimov ) 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 2 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, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "config.h" /* must be the first header */ #include #include #include #include #include "common.h" #include "dstate.h" #include "netxml-ups.h" #include "mge-xml.h" #include "main.h" /* for testvar() */ #ifdef WIN32 #include "wincompat.h" #endif #define MGE_XML_VERSION "MGEXML/0.36" #define MGE_XML_INITUPS "/" #define MGE_XML_INITINFO "/mgeups/product.xml /product.xml /ws/product.xml" #define ST_FLAG_RW 0x0001 #define ST_FLAG_STATIC 0x0002 static int mge_ambient_value = 0; /* The number of phases is not present in XML data as a separate node, * but we can infer it from presence of non-zero data on several * per-line nodes. */ static int inited_phaseinfo_in = 0, inited_phaseinfo_bypass = 0, inited_phaseinfo_out = 0, num_inphases = -1, num_bypassphases = -1, num_outphases = -1; static char mge_scratch_buf[256]; static char var[128]; static char val[128]; static int mge_shutdown_pending = 0; /* This flag flips to 0 when/if we post the detailed deprecation message */ static int mge_report_deprecation__convert_deci = 1; typedef enum { ROOTPARENT = NE_XML_STATEROOT, _UNEXPECTED, _PARSEERROR, PRODUCT_INFO = 100, /* "/mgeups/product.xml" */ PI_SUMMARY = 110, PI_HTML_PROPERTIES_PAGE, PI_XML_SUMMARY_PAGE, PI_CENTRAL_CFG, PI_CSV_LOGS, /* /PI_SUMMARY */ PI_ALARMS = 120, PI_SUBSCRIPTION, PI_POLLING, /* /ALARMS */ PI_MANAGEMENT = 130, PI_MANAGEMENT_PAGE, PI_XML_MANAGEMENT_PAGE, /* /MANAGEMENT */ PI_UPS_DATA = 140, PI_GET_OBJECT, PI_SET_OBJECT, /* /UPS_DATA */ /* /PRODUCT_INFO */ SUMMARY = 200, /* "/upsprop.xml" */ SU_OBJECT, /* /SUMMARY */ GET_OBJECT = 300, /* "/getvalue.cgi" */ GO_OBJECT, /* /GET_OBJECT */ SET_OBJECT = 400, /* "/setvalue.cgi" */ SO_OBJECT, /* /SET_OBJECT */ ALARM = 500, XML_CLIENT = 600, XC_GENERAL = 610, XC_STARTUP, XC_SHUTDOWN, XC_BROADCAST } mge_xml_state_t; typedef struct { const char *nutname; /* NUT variable name */ uint32_t nutflags; /* NUT flags (to set in addinfo) */ size_t nutlen; /* length of the NUT string */ const char *xmlname; /* XML variable name */ uint32_t xmlflags; /* XML flags (to be used to determine what kind of variable this is */ size_t xmllen; /* length of the XML string */ const char *(*convert)(const char *value); /* conversion function from XML<->NUT value (returns NULL if no further processing is required) */ } xml_info_t; static const char *online_info(const char *arg_val) { if (arg_val[0] == '1') { STATUS_SET(ONLINE); } else { STATUS_CLR(ONLINE); } return NULL; } static const char *discharging_info(const char *arg_val) { if (arg_val[0] == '1') { STATUS_SET(DISCHRG); /* Workaround NMC bug: both charging and discharging set to 1 */ if(STATUS_BIT(CHRG)) { STATUS_CLR(CHRG); } } else { STATUS_CLR(DISCHRG); } return NULL; } static const char *charging_info(const char *arg_val) { if (arg_val[0] == '1') { STATUS_SET(CHRG); } else { STATUS_CLR(CHRG); } return NULL; } static const char *lowbatt_info(const char *arg_val) { if (arg_val[0] == '1') { STATUS_SET(LOWBATT); } else { STATUS_CLR(LOWBATT); } return NULL; } static const char *overload_info(const char *arg_val) { if (arg_val[0] == '1') { STATUS_SET(OVERLOAD); } else { STATUS_CLR(OVERLOAD); } return NULL; } static const char *replacebatt_info(const char *arg_val) { if (arg_val[0] == '1') { STATUS_SET(REPLACEBATT); } else { STATUS_CLR(REPLACEBATT); } return NULL; } static const char *trim_info(const char *arg_val) { if (arg_val[0] == '1') { STATUS_SET(TRIM); } else { STATUS_CLR(TRIM); } return NULL; } static const char *boost_info(const char *arg_val) { if (arg_val[0] == '1') { STATUS_SET(BOOST); } else { STATUS_CLR(BOOST); } return NULL; } static const char *bypass_aut_info(const char *arg_val) { if (arg_val[0] == '1') { STATUS_SET(BYPASSAUTO); } else { STATUS_CLR(BYPASSAUTO); } return NULL; } static const char *bypass_man_info(const char *arg_val) { if (arg_val[0] == '1') { STATUS_SET(BYPASSMAN); } else { STATUS_CLR(BYPASSMAN); } return NULL; } static const char *off_info(const char *arg_val) { if (arg_val[0] == '0') { STATUS_SET(OFF); } else { STATUS_CLR(OFF); } return NULL; } /* note: this value is reverted (0=set, 1=not set). We report "battery not installed" rather than "battery installed", so that devices that don't implement this variable have a battery by default */ static const char *nobattery_info(const char *arg_val) { if (arg_val[0] == '0') { STATUS_SET(NOBATTERY); } else { STATUS_CLR(NOBATTERY); } return NULL; } static const char *fanfail_info(const char *arg_val) { if (arg_val[0] == '1') { STATUS_SET(FANFAIL); } else { STATUS_CLR(FANFAIL); } return NULL; } #if 0 static const char *shutdownimm_info(const char *arg_val) { if (arg_val[0] == '1') { STATUS_SET(SHUTDOWNIMM); } else { STATUS_CLR(SHUTDOWNIMM); } return NULL; } #endif static const char *overheat_info(const char *arg_val) { if (arg_val[0] == '1') { STATUS_SET(OVERHEAT); } else { STATUS_CLR(OVERHEAT); } return NULL; } static const char *commfault_info(const char *arg_val) { if (arg_val[0] == '1') { STATUS_SET(COMMFAULT); } else { STATUS_CLR(COMMFAULT); } return NULL; } static const char *internalfailure_info(const char *arg_val) { if (arg_val[0] == '1') { STATUS_SET(INTERNALFAULT); } else { STATUS_CLR(INTERNALFAULT); } return NULL; } static const char *battvoltlo_info(const char *arg_val) { if (arg_val[0] == '1') { STATUS_SET(BATTVOLTLO); } else { STATUS_CLR(BATTVOLTLO); } return NULL; } static const char *battvolthi_info(const char *arg_val) { if (arg_val[0] == '1') { STATUS_SET(BATTVOLTHI); } else { STATUS_CLR(BATTVOLTHI); } return NULL; } static const char *chargerfail_info(const char *arg_val) { if ((arg_val[0] == '1') || !strncasecmp(arg_val, "Yes", 3)) { STATUS_SET(CHARGERFAIL); } else { STATUS_CLR(CHARGERFAIL); } return NULL; } static const char *vrange_info(const char *arg_val) { if ((arg_val[0] == '1') || !strncasecmp(arg_val, "Yes", 3)) { STATUS_SET(VRANGE); } else { STATUS_CLR(VRANGE); } return NULL; } static const char *frange_info(const char *arg_val) { if ((arg_val[0] == '1') || !strncasecmp(arg_val, "Yes", 3)) { STATUS_SET(FRANGE); } else { STATUS_CLR(FRANGE); } return NULL; } static const char *fuse_fault_info(const char *arg_val) { if (arg_val[0] == '1') { STATUS_SET(FUSEFAULT); } else { STATUS_CLR(FUSEFAULT); } return NULL; } static const char *yes_no_info(const char *arg_val) { switch(arg_val[0]) { case '1': return "yes"; case '0': return "no"; default: upsdebugx(2, "%s: unexpected value [%s]", __func__, arg_val); return ""; } } static const char *on_off_info(const char *arg_val) { switch(arg_val[0]) { case '1': return "on"; case '0': return "off"; default: upsdebugx(2, "%s: unexpected value [%s]", __func__, arg_val); return ""; } } static const char *convert_deci(const char *arg_val) { /* Note: this routine was needed for original MGE devices, before the company * was bought out and split in 2007 between Eaton (1ph devices) and Schneider * (3ph devices). Those firmwares back when the driver was written apparently * served 10x the measured values. Not sure if any such units are in service * now (with same FW, and with no upgrade path). Reign of XML/PDC is waning. * For currently known NetXML servers, the value served is good without more * conversions. If older devices pop up in the field, we can add an estimation * by e.g. reported voltage and amps (to be an order of magnitude for power). * Alternately we can look at model names and/or firmware versions or release * dates, if we get those and if we know enough to map them to either logic. */ if (testvar("do_convert_deci")) { /* Old code for old devices: */ if (mge_report_deprecation__convert_deci) { upslogx(LOG_NOTICE, "%s() is now deprecated, so values from XML are normally not decimated. This driver instance has however configured do_convert_deci in your ups.conf, so this behavior for old MGE NetXML-capable devices is preserved.", __func__); mge_report_deprecation__convert_deci = 0; } snprintf(mge_scratch_buf, sizeof(mge_scratch_buf), "%.1f", 0.1 * (float)(atoi(arg_val))); return mge_scratch_buf; } if (mge_report_deprecation__convert_deci) { upslogx(LOG_NOTICE, "%s() is now deprecated, so values from XML are not decimated. If you happen to have an old MGE NetXML-capable device that now shows measurements 10x too big, and a firmware update does not solve this, please inform NUT devs via the issue tracker at %s with details about your hardware and firmware versions. Also try to enable do_convert_deci in your ups.conf", __func__, PACKAGE_BUGREPORT ); mge_report_deprecation__convert_deci = 0; } upsdebugx(5, "%s() is now deprecated, so value '%s' is not decimated. If this change broke your setup, please see details logged above.", __func__, arg_val); return arg_val; } /* Ignore a zero value if the UPS is not switched off */ static const char *ignore_if_zero(const char *arg_val) { if (atoi(arg_val) == 0) { return NULL; } return convert_deci(arg_val); } /* Set the 'ups.date' from the combined value * (ex. 2008/03/01 15:23:26) and return the time */ static const char *split_date_time(const char *arg_val) { char *last = NULL; snprintf(mge_scratch_buf, sizeof(mge_scratch_buf), "%s", arg_val); dstate_setinfo("ups.date", "%s", strtok_r(mge_scratch_buf, " -", &last)); return strtok_r(NULL, " ", &last); } static const char *url_convert(const char *arg_val) { char buf[256], *last = NULL; snprintf(buf, sizeof(buf), "%s", arg_val); snprintf(mge_scratch_buf, sizeof(mge_scratch_buf), "/%s", strtok_r(buf, " \r\n\t", &last)); return mge_scratch_buf; } static const char *mge_battery_capacity(const char *arg_val) { snprintf(mge_scratch_buf, sizeof(mge_scratch_buf), "%.2f", (float)(atoi(arg_val)) / 3600.0); return mge_scratch_buf; } static const char *mge_powerfactor_conversion(const char *arg_val) { snprintf(mge_scratch_buf, sizeof(mge_scratch_buf), "%.2f", (float)(atoi(arg_val)) / 100.0); return mge_scratch_buf; } static const char *mge_beeper_info(const char *arg_val) { switch (atoi(arg_val)) { case 1: return "disabled"; case 2: return "enabled"; case 3: return "muted"; } return NULL; } static const char *mge_upstype_conversion(const char *arg_val) { switch (atoi(arg_val)) { case 1: return "offline / line interactive"; case 2: return "online"; case 3: return "online - unitary/parallel"; case 4: return "online - parallel with hot standy"; case 5: return "online - hot standby redundancy"; } return NULL; } static const char *mge_sensitivity_info(const char *arg_val) { switch (atoi(arg_val)) { case 0: return "normal"; case 1: return "high"; case 2: return "low"; } return NULL; } static const char *mge_test_result_info(const char *arg_val) { STATUS_CLR(CALIB); switch (atoi(arg_val)) { case 1: return "done and passed"; case 2: return "done and warning"; case 3: return "done and error"; case 4: return "aborted"; case 5: STATUS_SET(CALIB); return "in progress"; case 6: return "no test initiated"; case 7: return "test scheduled"; } return NULL; } static const char *mge_ambient_info(const char *arg_val) { switch (mge_ambient_value) { case 1: return arg_val; default: return NULL; } } static const char *mge_drycontact_info(const char *arg_val) { /* these values should theoretically be obtained through * Environment.Input[1].State[x].Description * Examples: * open * closed */ switch (atoi(arg_val)) { case 0: return "opened"; case 1: return "closed"; default: return NULL; } } static const char *mge_timer_shutdown(const char *delay_before_shutoff) { if (atoi(delay_before_shutoff) > -1 ) { STATUS_SET(SHUTDOWNIMM); mge_shutdown_pending = 1; if( atoi(delay_before_shutoff) > shutdown_duration ) { STATUS_CLR(SHUTDOWNIMM); mge_shutdown_pending = 0; } } else { STATUS_CLR(SHUTDOWNIMM); mge_shutdown_pending = 0; } return val; } static const char *mge_shutdown_imminent(const char *arg_val) { const int shutdown_delay = atoi(arg_val); /* shutdown is already managed by mge_timer_shutdown, give up */ if(mge_shutdown_pending) { return NULL; } /* We may have "NONE" or "-1" or ?? as value * We also double check both the string and numeric values to be zero!*/ if ((arg_val) && (arg_val[0] == '0') && (shutdown_delay == 0)) { STATUS_SET(SHUTDOWNIMM); } else { STATUS_CLR(SHUTDOWNIMM); } return NULL; } static xml_info_t mge_xml2nut[] = { /* NMC configuration (mapped 1:1 for now) */ { "device.contact", ST_FLAG_RW, 0, "System.Contact", 0, 0, NULL }, { "device.location", ST_FLAG_RW, 0, "System.Location", 0, 0, NULL }, /* Not used for now; might however be used in future for history & stats collection { "System.History.Log.Interval", ST_FLAG_RW, 0, "System.History.Log.Interval", 0, 0, NULL }, */ #if (0) /* not interresting for NUT */ { "System.Environment.Log.Interval", ST_FLAG_RW, 0, "System.Environment.Log.Interval", 0, 0, NULL }, { "System.Outlet[1].iName", ST_FLAG_RW, 0, "System.Outlet[1].iName", 0, 0, NULL }, /* Mapped as ups.delay.shutdown { "System.ShutdownDuration", ST_FLAG_RW, 0, "System.ShutdownDuration", 0, 0, NULL }, */ { "System.ShutdownTimerSelected", ST_FLAG_RW, 0, "System.ShutdownTimerSelected", 0, 0, NULL }, { "System.ShutdownTimer", ST_FLAG_RW, 0, "System.ShutdownTimer", 0, 0, NULL }, /* Mapped as battery.runtime.low { "System.RunTimeToEmptyLimit", ST_FLAG_RW, 0, "System.RunTimeToEmptyLimit", 0, 0, NULL }, */ { "System.RemainingCapacityLimit", ST_FLAG_RW, 0, "System.RemainingCapacityLimit", 0, 0, NULL }, { "System.RestartLevel", ST_FLAG_RW, 0, "System.RestartLevel", 0, 0, NULL }, { "System.Outlet[2].iName", ST_FLAG_RW, 0, "System.Outlet[2].iName", 0, 0, NULL }, /* Mapped as outlet.1.delay.shutdown { "System.Outlet[2].ShutdownDuration", ST_FLAG_RW, 0, "System.Outlet[2].ShutdownDuration", 0, 0, NULL }, */ { "System.Outlet[2].ShutdownTimer", ST_FLAG_RW, 0, "System.Outlet[2].ShutdownTimer", 0, 0, NULL }, { "System.Outlet[2].StartupTimer", ST_FLAG_RW, 0, "System.Outlet[2].StartupTimer", 0, 0, NULL }, { "System.Outlet[2].RemainingCapacityLimit", ST_FLAG_RW, 0, "System.Outlet[2].RemainingCapacityLimit", 0, 0, NULL }, /* For future extension, and support of shutdown on load segment * { "System.Outlet[2].RunTimeToShutdown", ST_FLAG_RW, 0, "System.Outlet[2].RunTimeToShutdown", 0, 0, NULL }, */ { "System.Outlet[3].iName", ST_FLAG_RW, 0, "System.Outlet[3].iName", 0, 0, NULL }, /* Mapped as outlet.2.delay.shutdown { "System.Outlet[3].ShutdownDuration", ST_FLAG_RW, 0, "System.Outlet[3].ShutdownDuration", 0, 0, NULL }, */ { "System.Outlet[3].ShutdownTimer", ST_FLAG_RW, 0, "System.Outlet[3].ShutdownTimer", 0, 0, NULL }, { "System.Outlet[3].StartupTimer", ST_FLAG_RW, 0, "System.Outlet[3].StartupTimer", 0, 0, NULL }, { "System.Outlet[3].RemainingCapacityLimit", ST_FLAG_RW, 0, "System.Outlet[3].RemainingCapacityLimit", 0, 0, NULL }, /* For future extension, and support of shutdown on load segment * { "System.Outlet[3].RunTimeToShutdown", ST_FLAG_RW, 0, "System.Outlet[3].RunTimeToShutdown", 0, 0, NULL }, */ { "System.Outlet[1].OffDelay", ST_FLAG_RW, 0, "System.Outlet[1].OffDelay", 0, 0, NULL }, { "System.Outlet[1].Toggle", ST_FLAG_RW, 0, "System.Outlet[1].Toggle", 0, 0, NULL }, { "System.Outlet[1].OnDelay", ST_FLAG_RW, 0, "System.Outlet[1].OnDelay", 0, 0, NULL }, { "System.Outlet[2].OffDelay", ST_FLAG_RW, 0, "System.Outlet[2].OffDelay", 0, 0, NULL }, { "System.Outlet[2].Toggle", ST_FLAG_RW, 0, "System.Outlet[2].Toggle", 0, 0, NULL }, { "System.Outlet[2].OnDelay", ST_FLAG_RW, 0, "System.Outlet[2].OnDelay", 0, 0, NULL }, { "System.Outlet[3].OffDelay", ST_FLAG_RW, 0, "System.Outlet[3].OffDelay", 0, 0, NULL }, { "System.Outlet[3].Toggle", ST_FLAG_RW, 0, "System.Outlet[3].Toggle", 0, 0, NULL }, { "System.Outlet[3].OnDelay", ST_FLAG_RW, 0, "System.Outlet[3].OnDelay", 0, 0, NULL }, { "System.Login", ST_FLAG_RW, 0, "System.Login", 0, 0, NULL }, { "System.Password", ST_FLAG_RW, 0, "System.Password", 0, 0, NULL }, { "System.Security", ST_FLAG_RW, 0, "System.Security", 0, 0, NULL }, { "System.FirmwareUpgrade", ST_FLAG_RW, 0, "System.FirmwareUpgrade", 0, 0, NULL }, { "System.Network.SNMP.ReadCommunity", ST_FLAG_RW, 0, "System.Network.SNMP.ReadCommunity", 0, 0, NULL }, { "System.Network.SNMP.ReadCommunityName", 0, 0, "System.Network.SNMP.ReadCommunityName", 0, 0, NULL }, { "System.Network.SNMP.ReadCommunitySecurityLevel", 0, 0, "System.Network.SNMP.ReadCommunitySecurityLevel", 0, 0, NULL }, { "System.Network.SNMP.ReadCommunitySecurityRight", 0, 0, "System.Network.SNMP.ReadCommunitySecurityRight", 0, 0, NULL }, { "System.Network.SNMP.WriteCommunity", ST_FLAG_RW, 0, "System.Network.SNMP.WriteCommunity", 0, 0, NULL }, { "System.Network.SNMP.WriteCommunityName", 0, 0, "System.Network.SNMP.WriteCommunityName", 0, 0, NULL }, { "System.Network.SNMP.WriteCommunitySecurityLevel", 0, 0, "System.Network.SNMP.WriteCommunitySecurityLevel", 0, 0, NULL }, { "System.Network.SNMP.WriteCommunitySecurityRight", ST_FLAG_RW, 0, "System.Network.SNMP.WriteCommunitySecurityRight", 0, 0, NULL }, { "System.Network.SNMP.Admin", ST_FLAG_RW, 0, "System.Network.SNMP.Admin", 0, 0, NULL }, { "System.Network.SNMP.AdminPassword", ST_FLAG_RW, 0, "System.Network.SNMP.AdminPassword", 0, 0, NULL }, { "System.Network.SNMP.AdminSecurityLevel", ST_FLAG_RW, 0, "System.Network.SNMP.AdminSecurityLevel", 0, 0, NULL }, { "System.Network.SNMP.AdminSecurityRight", 0, 0, "System.Network.SNMP.AdminSecurityRight", 0, 0, NULL }, { "System.Network.SNMP.User", ST_FLAG_RW, 0, "System.Network.SNMP.User", 0, 0, NULL }, { "System.Network.SNMP.UserPassword", ST_FLAG_RW, 0, "System.Network.SNMP.UserPassword", 0, 0, NULL }, { "System.Network.SNMP.UserSecurityLevel", ST_FLAG_RW, 0, "System.Network.SNMP.UserSecurityLevel", 0, 0, NULL }, { "System.Network.SNMP.UserSecurityRight", 0, 0, "System.Network.SNMP.UserSecurityRight", 0, 0, NULL }, { "System.Network.SNMP.NotificationUserName", ST_FLAG_RW, 0, "System.Network.SNMP.NotificationUserName", 0, 0, NULL }, { "System.Network.SNMP.snmpVersion", ST_FLAG_RW, 0, "System.Network.SNMP.snmpVersion", 0, 0, NULL }, { "System.Network.SNMP.engineBoots", 0, 0, "System.Network.SNMP.engineBoots", 0, 0, NULL }, { "System.Network.Telnet.Access", ST_FLAG_RW, 0, "System.Network.Telnet.Access", 0, 0, NULL }, { "System.Network.Telnet.Security", ST_FLAG_RW, 0, "System.Network.Telnet.Security", 0, 0, NULL }, { "System.Network.Telnet.Console", ST_FLAG_RW, 0, "System.Network.Telnet.Console", 0, 0, NULL }, { "System.Email.Sender", ST_FLAG_RW, 0, "System.Email.Sender", 0, 0, NULL }, { "System.Email.Subject", ST_FLAG_RW, 0, "System.Email.Subject", 0, 0, NULL }, { "System.Email.UPSName", ST_FLAG_RW, 0, "System.Email.UPSName", 0, 0, NULL }, { "System.Email.Message", ST_FLAG_RW, 0, "System.Email.Message", 0, 0, NULL }, { "System.Email.Localization", ST_FLAG_RW, 0, "System.Email.Localization", 0, 0, NULL }, { "System.Email.EventName", ST_FLAG_RW, 0, "System.Email.EventName", 0, 0, NULL }, { "System.Email[0].Recipient", ST_FLAG_RW, 0, "System.Email[0].Recipient", 0, 0, NULL }, { "System.Email[0].Selected", ST_FLAG_RW, 0, "System.Email[0].Selected", 0, 0, NULL }, { "System.Email[0].Enotify", ST_FLAG_RW, 0, "System.Email[0].Enotify", 0, 0, NULL }, { "System.Email[0].Measures.Log", ST_FLAG_RW, 0, "System.Email[0].Measures.Log", 0, 0, NULL }, { "System.Email[0].Events.Log", ST_FLAG_RW, 0, "System.Email[0].Events.Log", 0, 0, NULL }, { "System.Email[0].SystemEvents.Log", ST_FLAG_RW, 0, "System.Email[0].SystemEvents.Log", 0, 0, NULL }, { "System.Email[0].Environment.Log", ST_FLAG_RW, 0, "System.Email[0].Environment.Log", 0, 0, NULL }, { "System.Email[0].Report.Periodicity", ST_FLAG_RW, 0, "System.Email[0].Report.Periodicity", 0, 0, NULL }, { "System.Email[0].Report.Hour", ST_FLAG_RW, 0, "System.Email[0].Report.Hour", 0, 0, NULL }, { "System.Email[0].Report.Next", ST_FLAG_RW, 0, "System.Email[0].Report.Next", 0, 0, NULL }, { "System.Email[0].EventList.Discharging", ST_FLAG_RW, 0, "System.Email[0].EventList.Discharging", 0, 0, NULL }, { "System.Email[0].EventList.ACPresent", ST_FLAG_RW, 0, "System.Email[0].EventList.ACPresent", 0, 0, NULL }, { "System.Email[0].EventList.RunTimeToShutdown", ST_FLAG_RW, 0, "System.Email[0].EventList.RunTimeToShutdown", 0, 0, NULL }, { "System.Email[0].EventList.BelowRemainingCapacityLimit", ST_FLAG_RW, 0, "System.Email[0].EventList.BelowRemainingCapacityLimit", 0, 0, NULL }, { "System.Email[0].EventList.NeedReplacement.1", ST_FLAG_RW, 0, "System.Email[0].EventList.NeedReplacement.1", 0, 0, NULL }, { "System.Email[0].EventList.NeedReplacement.0", ST_FLAG_RW, 0, "System.Email[0].EventList.NeedReplacement.0", 0, 0, NULL }, { "System.Email[0].EventList.Overload.1", ST_FLAG_RW, 0, "System.Email[0].EventList.Overload.1", 0, 0, NULL }, { "System.Email[0].EventList.Overload.0", ST_FLAG_RW, 0, "System.Email[0].EventList.Overload.0", 0, 0, NULL }, { "System.Email[0].EventList.InternalFailure.1", ST_FLAG_RW, 0, "System.Email[0].EventList.InternalFailure.1", 0, 0, NULL }, { "System.Email[0].EventList.InternalFailure.0", ST_FLAG_RW, 0, "System.Email[0].EventList.InternalFailure.0", 0, 0, NULL }, { "System.Email[0].EventList.CommunicationLost.1", ST_FLAG_RW, 0, "System.Email[0].EventList.CommunicationLost.1", 0, 0, NULL }, { "System.Email[0].EventList.CommunicationLost.0", ST_FLAG_RW, 0, "System.Email[0].EventList.CommunicationLost.0", 0, 0, NULL }, { "System.Email[0].EventList.Charger.InternalFailure", ST_FLAG_RW, 0, "System.Email[0].EventList.Charger.InternalFailure", 0, 0, NULL }, { "System.Email[0].EventList.Input[2].Used.1", ST_FLAG_RW, 0, "System.Email[0].EventList.Input[2].Used.1", 0, 0, NULL }, { "System.Email[0].EventList.Input[2].Used.0", ST_FLAG_RW, 0, "System.Email[0].EventList.Input[2].Used.0", 0, 0, NULL }, { "System.Email[0].EventList.PowerModule.RedundancyLost.1", ST_FLAG_RW, 0, "System.Email[0].EventList.PowerModule.RedundancyLost.1", 0, 0, NULL }, { "System.Email[0].EventList.PowerModule.RedundancyLost.0", ST_FLAG_RW, 0, "System.Email[0].EventList.PowerModule.RedundancyLost.0", 0, 0, NULL }, { "System.Email[0].EventList.PowerModule.ProtectionLost.1", ST_FLAG_RW, 0, "System.Email[0].EventList.PowerModule.ProtectionLost.1", 0, 0, NULL }, { "System.Email[0].EventList.PowerModule.ProtectionLost.0", ST_FLAG_RW, 0, "System.Email[0].EventList.PowerModule.ProtectionLost.0", 0, 0, NULL }, { "System.Email[0].EventList.FirmwareUpgrade", ST_FLAG_RW, 0, "System.Email[0].EventList.FirmwareUpgrade", 0, 0, NULL }, { "System.Email[0].EventList.Environment.CommunicationLost", ST_FLAG_RW, 0, "System.Email[0].EventList.Environment.CommunicationLost", 0, 0, NULL }, { "System.Email[0].EventList.Environment.Notify", ST_FLAG_RW, 0, "System.Email[0].EventList.Environment.Notify", 0, 0, NULL }, { "System.Email[1].Recipient", ST_FLAG_RW, 0, "System.Email[1].Recipient", 0, 0, NULL }, { "System.Email[1].Selected", ST_FLAG_RW, 0, "System.Email[1].Selected", 0, 0, NULL }, { "System.Email[1].Enotify", ST_FLAG_RW, 0, "System.Email[1].Enotify", 0, 0, NULL }, { "System.Email[1].Measures.Log", ST_FLAG_RW, 0, "System.Email[1].Measures.Log", 0, 0, NULL }, { "System.Email[1].Events.Log", ST_FLAG_RW, 0, "System.Email[1].Events.Log", 0, 0, NULL }, { "System.Email[1].SystemEvents.Log", ST_FLAG_RW, 0, "System.Email[1].SystemEvents.Log", 0, 0, NULL }, { "System.Email[1].Environment.Log", ST_FLAG_RW, 0, "System.Email[1].Environment.Log", 0, 0, NULL }, { "System.Email[1].Report.Periodicity", ST_FLAG_RW, 0, "System.Email[1].Report.Periodicity", 0, 0, NULL }, { "System.Email[1].Report.Hour", ST_FLAG_RW, 0, "System.Email[1].Report.Hour", 0, 0, NULL }, { "System.Email[1].Report.Next", ST_FLAG_RW, 0, "System.Email[1].Report.Next", 0, 0, NULL }, { "System.Email[1].EventList.Discharging", ST_FLAG_RW, 0, "System.Email[1].EventList.Discharging", 0, 0, NULL }, { "System.Email[1].EventList.ACPresent", ST_FLAG_RW, 0, "System.Email[1].EventList.ACPresent", 0, 0, NULL }, { "System.Email[1].EventList.RunTimeToShutdown", ST_FLAG_RW, 0, "System.Email[1].EventList.RunTimeToShutdown", 0, 0, NULL }, { "System.Email[1].EventList.BelowRemainingCapacityLimit", ST_FLAG_RW, 0, "System.Email[1].EventList.BelowRemainingCapacityLimit", 0, 0, NULL }, { "System.Email[1].EventList.NeedReplacement.1", ST_FLAG_RW, 0, "System.Email[1].EventList.NeedReplacement.1", 0, 0, NULL }, { "System.Email[1].EventList.NeedReplacement.0", ST_FLAG_RW, 0, "System.Email[1].EventList.NeedReplacement.0", 0, 0, NULL }, { "System.Email[1].EventList.Overload.1", ST_FLAG_RW, 0, "System.Email[1].EventList.Overload.1", 0, 0, NULL }, { "System.Email[1].EventList.Overload.0", ST_FLAG_RW, 0, "System.Email[1].EventList.Overload.0", 0, 0, NULL }, { "System.Email[1].EventList.InternalFailure.1", ST_FLAG_RW, 0, "System.Email[1].EventList.InternalFailure.1", 0, 0, NULL }, { "System.Email[1].EventList.InternalFailure.0", ST_FLAG_RW, 0, "System.Email[1].EventList.InternalFailure.0", 0, 0, NULL }, { "System.Email[1].EventList.CommunicationLost.1", ST_FLAG_RW, 0, "System.Email[1].EventList.CommunicationLost.1", 0, 0, NULL }, { "System.Email[1].EventList.CommunicationLost.0", ST_FLAG_RW, 0, "System.Email[1].EventList.CommunicationLost.0", 0, 0, NULL }, { "System.Email[1].EventList.Charger.InternalFailure", ST_FLAG_RW, 0, "System.Email[1].EventList.Charger.InternalFailure", 0, 0, NULL }, { "System.Email[1].EventList.Input[2].Used.1", ST_FLAG_RW, 0, "System.Email[1].EventList.Input[2].Used.1", 0, 0, NULL }, { "System.Email[1].EventList.Input[2].Used.0", ST_FLAG_RW, 0, "System.Email[1].EventList.Input[2].Used.0", 0, 0, NULL }, { "System.Email[1].EventList.PowerModule.RedundancyLost.1", ST_FLAG_RW, 0, "System.Email[1].EventList.PowerModule.RedundancyLost.1", 0, 0, NULL }, { "System.Email[1].EventList.PowerModule.RedundancyLost.0", ST_FLAG_RW, 0, "System.Email[1].EventList.PowerModule.RedundancyLost.0", 0, 0, NULL }, { "System.Email[1].EventList.PowerModule.ProtectionLost.1", ST_FLAG_RW, 0, "System.Email[1].EventList.PowerModule.ProtectionLost.1", 0, 0, NULL }, { "System.Email[1].EventList.PowerModule.ProtectionLost.0", ST_FLAG_RW, 0, "System.Email[1].EventList.PowerModule.ProtectionLost.0", 0, 0, NULL }, { "System.Email[1].EventList.FirmwareUpgrade", ST_FLAG_RW, 0, "System.Email[1].EventList.FirmwareUpgrade", 0, 0, NULL }, { "System.Email[1].EventList.Environment.CommunicationLost", ST_FLAG_RW, 0, "System.Email[1].EventList.Environment.CommunicationLost", 0, 0, NULL }, { "System.Email[1].EventList.Environment.Notify", ST_FLAG_RW, 0, "System.Email[1].EventList.Environment.Notify", 0, 0, NULL }, { "System.Email[2].Recipient", ST_FLAG_RW, 0, "System.Email[2].Recipient", 0, 0, NULL }, { "System.Email[2].Selected", ST_FLAG_RW, 0, "System.Email[2].Selected", 0, 0, NULL }, { "System.Email[2].Enotify", ST_FLAG_RW, 0, "System.Email[2].Enotify", 0, 0, NULL }, { "System.Email[2].Measures.Log", ST_FLAG_RW, 0, "System.Email[2].Measures.Log", 0, 0, NULL }, { "System.Email[2].Events.Log", ST_FLAG_RW, 0, "System.Email[2].Events.Log", 0, 0, NULL }, { "System.Email[2].SystemEvents.Log", ST_FLAG_RW, 0, "System.Email[2].SystemEvents.Log", 0, 0, NULL }, { "System.Email[2].Environment.Log", ST_FLAG_RW, 0, "System.Email[2].Environment.Log", 0, 0, NULL }, { "System.Email[2].Report.Periodicity", ST_FLAG_RW, 0, "System.Email[2].Report.Periodicity", 0, 0, NULL }, { "System.Email[2].Report.Hour", ST_FLAG_RW, 0, "System.Email[2].Report.Hour", 0, 0, NULL }, { "System.Email[2].Report.Next", ST_FLAG_RW, 0, "System.Email[2].Report.Next", 0, 0, NULL }, { "System.Email[2].EventList.Discharging", ST_FLAG_RW, 0, "System.Email[2].EventList.Discharging", 0, 0, NULL }, { "System.Email[2].EventList.ACPresent", ST_FLAG_RW, 0, "System.Email[2].EventList.ACPresent", 0, 0, NULL }, { "System.Email[2].EventList.RunTimeToShutdown", ST_FLAG_RW, 0, "System.Email[2].EventList.RunTimeToShutdown", 0, 0, NULL }, { "System.Email[2].EventList.BelowRemainingCapacityLimit", ST_FLAG_RW, 0, "System.Email[2].EventList.BelowRemainingCapacityLimit", 0, 0, NULL }, { "System.Email[2].EventList.NeedReplacement.1", ST_FLAG_RW, 0, "System.Email[2].EventList.NeedReplacement.1", 0, 0, NULL }, { "System.Email[2].EventList.NeedReplacement.0", ST_FLAG_RW, 0, "System.Email[2].EventList.NeedReplacement.0", 0, 0, NULL }, { "System.Email[2].EventList.Overload.1", ST_FLAG_RW, 0, "System.Email[2].EventList.Overload.1", 0, 0, NULL }, { "System.Email[2].EventList.Overload.0", ST_FLAG_RW, 0, "System.Email[2].EventList.Overload.0", 0, 0, NULL }, { "System.Email[2].EventList.InternalFailure.1", ST_FLAG_RW, 0, "System.Email[2].EventList.InternalFailure.1", 0, 0, NULL }, { "System.Email[2].EventList.InternalFailure.0", ST_FLAG_RW, 0, "System.Email[2].EventList.InternalFailure.0", 0, 0, NULL }, { "System.Email[2].EventList.CommunicationLost.1", ST_FLAG_RW, 0, "System.Email[2].EventList.CommunicationLost.1", 0, 0, NULL }, { "System.Email[2].EventList.CommunicationLost.0", ST_FLAG_RW, 0, "System.Email[2].EventList.CommunicationLost.0", 0, 0, NULL }, { "System.Email[2].EventList.Charger.InternalFailure", ST_FLAG_RW, 0, "System.Email[2].EventList.Charger.InternalFailure", 0, 0, NULL }, { "System.Email[2].EventList.Input[2].Used.1", ST_FLAG_RW, 0, "System.Email[2].EventList.Input[2].Used.1", 0, 0, NULL }, { "System.Email[2].EventList.Input[2].Used.0", ST_FLAG_RW, 0, "System.Email[2].EventList.Input[2].Used.0", 0, 0, NULL }, { "System.Email[2].EventList.PowerModule.RedundancyLost.1", ST_FLAG_RW, 0, "System.Email[2].EventList.PowerModule.RedundancyLost.1", 0, 0, NULL }, { "System.Email[2].EventList.PowerModule.RedundancyLost.0", ST_FLAG_RW, 0, "System.Email[2].EventList.PowerModule.RedundancyLost.0", 0, 0, NULL }, { "System.Email[2].EventList.PowerModule.ProtectionLost.1", ST_FLAG_RW, 0, "System.Email[2].EventList.PowerModule.ProtectionLost.1", 0, 0, NULL }, { "System.Email[2].EventList.PowerModule.ProtectionLost.0", ST_FLAG_RW, 0, "System.Email[2].EventList.PowerModule.ProtectionLost.0", 0, 0, NULL }, { "System.Email[2].EventList.FirmwareUpgrade", ST_FLAG_RW, 0, "System.Email[2].EventList.FirmwareUpgrade", 0, 0, NULL }, { "System.Email[2].EventList.Environment.CommunicationLost", ST_FLAG_RW, 0, "System.Email[2].EventList.Environment.CommunicationLost", 0, 0, NULL }, { "System.Email[2].EventList.Environment.Notify", ST_FLAG_RW, 0, "System.Email[2].EventList.Environment.Notify", 0, 0, NULL }, { "System.Email[3].Recipient", ST_FLAG_RW, 0, "System.Email[3].Recipient", 0, 0, NULL }, { "System.Email[3].Selected", ST_FLAG_RW, 0, "System.Email[3].Selected", 0, 0, NULL }, { "System.Email[3].Enotify", ST_FLAG_RW, 0, "System.Email[3].Enotify", 0, 0, NULL }, { "System.Email[3].Measures.Log", ST_FLAG_RW, 0, "System.Email[3].Measures.Log", 0, 0, NULL }, { "System.Email[3].Events.Log", ST_FLAG_RW, 0, "System.Email[3].Events.Log", 0, 0, NULL }, { "System.Email[3].SystemEvents.Log", ST_FLAG_RW, 0, "System.Email[3].SystemEvents.Log", 0, 0, NULL }, { "System.Email[3].Environment.Log", ST_FLAG_RW, 0, "System.Email[3].Environment.Log", 0, 0, NULL }, { "System.Email[3].Report.Periodicity", ST_FLAG_RW, 0, "System.Email[3].Report.Periodicity", 0, 0, NULL }, { "System.Email[3].Report.Hour", ST_FLAG_RW, 0, "System.Email[3].Report.Hour", 0, 0, NULL }, { "System.Email[3].Report.Next", ST_FLAG_RW, 0, "System.Email[3].Report.Next", 0, 0, NULL }, { "System.Email[3].EventList.Discharging", ST_FLAG_RW, 0, "System.Email[3].EventList.Discharging", 0, 0, NULL }, { "System.Email[3].EventList.ACPresent", ST_FLAG_RW, 0, "System.Email[3].EventList.ACPresent", 0, 0, NULL }, { "System.Email[3].EventList.RunTimeToShutdown", ST_FLAG_RW, 0, "System.Email[3].EventList.RunTimeToShutdown", 0, 0, NULL }, { "System.Email[3].EventList.BelowRemainingCapacityLimit", ST_FLAG_RW, 0, "System.Email[3].EventList.BelowRemainingCapacityLimit", 0, 0, NULL }, { "System.Email[3].EventList.NeedReplacement.1", ST_FLAG_RW, 0, "System.Email[3].EventList.NeedReplacement.1", 0, 0, NULL }, { "System.Email[3].EventList.NeedReplacement.0", ST_FLAG_RW, 0, "System.Email[3].EventList.NeedReplacement.0", 0, 0, NULL }, { "System.Email[3].EventList.Overload.1", ST_FLAG_RW, 0, "System.Email[3].EventList.Overload.1", 0, 0, NULL }, { "System.Email[3].EventList.Overload.0", ST_FLAG_RW, 0, "System.Email[3].EventList.Overload.0", 0, 0, NULL }, { "System.Email[3].EventList.InternalFailure.1", ST_FLAG_RW, 0, "System.Email[3].EventList.InternalFailure.1", 0, 0, NULL }, { "System.Email[3].EventList.InternalFailure.0", ST_FLAG_RW, 0, "System.Email[3].EventList.InternalFailure.0", 0, 0, NULL }, { "System.Email[3].EventList.CommunicationLost.1", ST_FLAG_RW, 0, "System.Email[3].EventList.CommunicationLost.1", 0, 0, NULL }, { "System.Email[3].EventList.CommunicationLost.0", ST_FLAG_RW, 0, "System.Email[3].EventList.CommunicationLost.0", 0, 0, NULL }, { "System.Email[3].EventList.Charger.InternalFailure", ST_FLAG_RW, 0, "System.Email[3].EventList.Charger.InternalFailure", 0, 0, NULL }, { "System.Email[3].EventList.Input[2].Used.1", ST_FLAG_RW, 0, "System.Email[3].EventList.Input[2].Used.1", 0, 0, NULL }, { "System.Email[3].EventList.Input[2].Used.0", ST_FLAG_RW, 0, "System.Email[3].EventList.Input[2].Used.0", 0, 0, NULL }, { "System.Email[3].EventList.PowerModule.RedundancyLost.1", ST_FLAG_RW, 0, "System.Email[3].EventList.PowerModule.RedundancyLost.1", 0, 0, NULL }, { "System.Email[3].EventList.PowerModule.RedundancyLost.0", ST_FLAG_RW, 0, "System.Email[3].EventList.PowerModule.RedundancyLost.0", 0, 0, NULL }, { "System.Email[3].EventList.PowerModule.ProtectionLost.1", ST_FLAG_RW, 0, "System.Email[3].EventList.PowerModule.ProtectionLost.1", 0, 0, NULL }, { "System.Email[3].EventList.PowerModule.ProtectionLost.0", ST_FLAG_RW, 0, "System.Email[3].EventList.PowerModule.ProtectionLost.0", 0, 0, NULL }, { "System.Email[3].EventList.FirmwareUpgrade", ST_FLAG_RW, 0, "System.Email[3].EventList.FirmwareUpgrade", 0, 0, NULL }, { "System.Email[3].EventList.Environment.CommunicationLost", ST_FLAG_RW, 0, "System.Email[3].EventList.Environment.CommunicationLost", 0, 0, NULL }, { "System.Email[3].EventList.Environment.Notify", ST_FLAG_RW, 0, "System.Email[3].EventList.Environment.Notify", 0, 0, NULL }, { "System.Schedule[0].Off", ST_FLAG_RW, 0, "System.Schedule[0].Off", 0, 0, NULL }, { "System.Schedule[0].On", ST_FLAG_RW, 0, "System.Schedule[0].On", 0, 0, NULL }, { "System.Schedule[1].Off", ST_FLAG_RW, 0, "System.Schedule[1].Off", 0, 0, NULL }, { "System.Schedule[1].On", ST_FLAG_RW, 0, "System.Schedule[1].On", 0, 0, NULL }, { "System.Schedule[2].Off", ST_FLAG_RW, 0, "System.Schedule[2].Off", 0, 0, NULL }, { "System.Schedule[2].On", ST_FLAG_RW, 0, "System.Schedule[2].On", 0, 0, NULL }, { "System.Schedule[3].Off", ST_FLAG_RW, 0, "System.Schedule[3].Off", 0, 0, NULL }, { "System.Schedule[3].On", ST_FLAG_RW, 0, "System.Schedule[3].On", 0, 0, NULL }, { "System.Schedule[4].Off", ST_FLAG_RW, 0, "System.Schedule[4].Off", 0, 0, NULL }, { "System.Schedule[4].On", ST_FLAG_RW, 0, "System.Schedule[4].On", 0, 0, NULL }, { "System.Schedule[5].Off", ST_FLAG_RW, 0, "System.Schedule[5].Off", 0, 0, NULL }, { "System.Schedule[5].On", ST_FLAG_RW, 0, "System.Schedule[5].On", 0, 0, NULL }, { "System.Schedule[6].Off", ST_FLAG_RW, 0, "System.Schedule[6].Off", 0, 0, NULL }, { "System.Schedule[6].On", ST_FLAG_RW, 0, "System.Schedule[6].On", 0, 0, NULL }, { "System.NetworkManagementSystem[0].Name", ST_FLAG_RW, 0, "System.NetworkManagementSystem[0].Name", 0, 0, NULL }, { "System.NetworkManagementSystem[0].HostName", ST_FLAG_RW, 0, "System.NetworkManagementSystem[0].HostName", 0, 0, NULL }, { "System.NetworkManagementSystem[0].TrapCommunity", ST_FLAG_RW, 0, "System.NetworkManagementSystem[0].TrapCommunity", 0, 0, NULL }, { "System.NetworkManagementSystem[0].TrapSnmpVersion", ST_FLAG_RW, 0, "System.NetworkManagementSystem[0].TrapSnmpVersion", 0, 0, NULL }, { "System.NetworkManagementSystem[0].TrapSelectedMibs", ST_FLAG_RW, 0, "System.NetworkManagementSystem[0].TrapSelectedMibs", 0, 0, NULL }, { "System.NetworkManagementSystem[1].Name", ST_FLAG_RW, 0, "System.NetworkManagementSystem[1].Name", 0, 0, NULL }, { "System.NetworkManagementSystem[1].HostName", ST_FLAG_RW, 0, "System.NetworkManagementSystem[1].HostName", 0, 0, NULL }, { "System.NetworkManagementSystem[1].TrapCommunity", ST_FLAG_RW, 0, "System.NetworkManagementSystem[1].TrapCommunity", 0, 0, NULL }, { "System.NetworkManagementSystem[1].TrapSnmpVersion", ST_FLAG_RW, 0, "System.NetworkManagementSystem[1].TrapSnmpVersion", 0, 0, NULL }, { "System.NetworkManagementSystem[1].TrapSelectedMibs", ST_FLAG_RW, 0, "System.NetworkManagementSystem[1].TrapSelectedMibs", 0, 0, NULL }, { "System.NetworkManagementSystem[2].Name", ST_FLAG_RW, 0, "System.NetworkManagementSystem[2].Name", 0, 0, NULL }, { "System.NetworkManagementSystem[2].HostName", ST_FLAG_RW, 0, "System.NetworkManagementSystem[2].HostName", 0, 0, NULL }, { "System.NetworkManagementSystem[2].TrapCommunity", ST_FLAG_RW, 0, "System.NetworkManagementSystem[2].TrapCommunity", 0, 0, NULL }, { "System.NetworkManagementSystem[2].TrapSnmpVersion", ST_FLAG_RW, 0, "System.NetworkManagementSystem[2].TrapSnmpVersion", 0, 0, NULL }, { "System.NetworkManagementSystem[2].TrapSelectedMibs", ST_FLAG_RW, 0, "System.NetworkManagementSystem[2].TrapSelectedMibs", 0, 0, NULL }, { "System.ClientCfg.ShutdownTimer.Select", ST_FLAG_RW, 0, "System.ClientCfg.ShutdownTimer.Select", 0, 0, NULL }, { "System.ClientCfg.ShutdownTimer", ST_FLAG_RW, 0, "System.ClientCfg.ShutdownTimer", 0, 0, NULL }, { "System.ClientCfg.ShutdownDuration", ST_FLAG_RW, 0, "System.ClientCfg.ShutdownDuration", 0, 0, NULL }, { "System.ClientCfg.BroadcastAdmins", ST_FLAG_RW, 0, "System.ClientCfg.BroadcastAdmins", 0, 0, NULL }, { "System.ClientCfg.BroadcastUsers", ST_FLAG_RW, 0, "System.ClientCfg.BroadcastUsers", 0, 0, NULL }, { "Environment.iName", ST_FLAG_RW, 0, "Environment.iName", 0, 0, NULL }, { "Environment.Temperature.Unit", ST_FLAG_RW, 0, "Environment.Temperature.Unit", 0, 0, NULL }, { "Environment.Temperature.Hysteresis", ST_FLAG_RW, 0, "Environment.Temperature.Hysteresis", 0, 0, NULL }, { "Environment.Temperature.Offset", ST_FLAG_RW, 0, "Environment.Temperature.Offset", 0, 0, NULL }, { "Environment.Temperature.HighNotify", ST_FLAG_RW, 0, "Environment.Temperature.HighNotify", 0, 0, NULL }, { "Environment.Temperature.LowNotify", ST_FLAG_RW, 0, "Environment.Temperature.LowNotify", 0, 0, NULL }, { "Environment.Temperature.HighShutdown", ST_FLAG_RW, 0, "Environment.Temperature.HighShutdown", 0, 0, NULL }, { "Environment.Temperature.LowShutdown", ST_FLAG_RW, 0, "Environment.Temperature.LowShutdown", 0, 0, NULL }, { "Environment.Humidity.Hysteresis", ST_FLAG_RW, 0, "Environment.Humidity.Hysteresis", 0, 0, NULL }, { "Environment.Humidity.Offset", ST_FLAG_RW, 0, "Environment.Humidity.Offset", 0, 0, NULL }, { "Environment.Humidity.HighNotify", ST_FLAG_RW, 0, "Environment.Humidity.HighNotify", 0, 0, NULL }, { "Environment.Humidity.LowNotify", ST_FLAG_RW, 0, "Environment.Humidity.LowNotify", 0, 0, NULL }, { "Environment.Humidity.HighShutdown", ST_FLAG_RW, 0, "Environment.Humidity.HighShutdown", 0, 0, NULL }, { "Environment.Humidity.LowShutdown", ST_FLAG_RW, 0, "Environment.Humidity.LowShutdown", 0, 0, NULL }, { "Environment.Input[1].iName", ST_FLAG_RW, 0, "Environment.Input[1].iName", 0, 0, NULL }, { "Environment.Input[1].State[0].Description", ST_FLAG_RW, 0, "Environment.Input[1].State[0].Description", 0, 0, NULL }, { "Environment.Input[1].State[0].Notify", ST_FLAG_RW, 0, "Environment.Input[1].State[0].Notify", 0, 0, NULL }, { "Environment.Input[1].State[0].Shutdown", ST_FLAG_RW, 0, "Environment.Input[1].State[0].Shutdown", 0, 0, NULL }, { "Environment.Input[1].State[1].Description", ST_FLAG_RW, 0, "Environment.Input[1].State[1].Description", 0, 0, NULL }, { "Environment.Input[1].State[1].Notify", ST_FLAG_RW, 0, "Environment.Input[1].State[1].Notify", 0, 0, NULL }, { "Environment.Input[1].State[1].Shutdown", ST_FLAG_RW, 0, "Environment.Input[1].State[1].Shutdown", 0, 0, NULL }, { "Environment.Input[2].iName", ST_FLAG_RW, 0, "Environment.Input[2].iName", 0, 0, NULL }, { "Environment.Input[2].State[0].Description", ST_FLAG_RW, 0, "Environment.Input[2].State[0].Description", 0, 0, NULL }, { "Environment.Input[2].State[0].Notify", ST_FLAG_RW, 0, "Environment.Input[2].State[0].Notify", 0, 0, NULL }, { "Environment.Input[2].State[0].Shutdown", ST_FLAG_RW, 0, "Environment.Input[2].State[0].Shutdown", 0, 0, NULL }, { "Environment.Input[2].State[1].Description", ST_FLAG_RW, 0, "Environment.Input[2].State[1].Description", 0, 0, NULL }, { "Environment.Input[2].State[1].Notify", ST_FLAG_RW, 0, "Environment.Input[2].State[1].Notify", 0, 0, NULL }, { "Environment.Input[2].State[1].Shutdown", ST_FLAG_RW, 0, "Environment.Input[2].State[1].Shutdown", 0, 0, NULL }, { "System.TimeSync", ST_FLAG_RW, 0, "System.TimeSync", 0, 0, NULL }, { "System.TimeNtp", ST_FLAG_RW, 0, "System.TimeNtp", 0, 0, NULL }, { "System.TimeZone", ST_FLAG_RW, 0, "System.TimeZone", 0, 0, NULL }, { "System.TimeDaylight", ST_FLAG_RW, 0, "System.TimeDaylight", 0, 0, NULL }, #endif /* not interresting for NUT */ /* Special case: boolean values that are mapped to ups.status and ups.alarm */ { NULL, 0, 0, "UPS.PowerSummary.PresentStatus.ACPresent", 0, 0, online_info }, { NULL, 0, 0, "UPS.PowerSummary.PresentStatus.Charging", 0, 0, charging_info }, /* NMC bug: keep discharging test AFTER charging test */ { NULL, 0, 0, "UPS.PowerSummary.PresentStatus.Discharging", 0, 0, discharging_info }, { NULL, 0, 0, "UPS.PowerSummary.PresentStatus.BelowRemainingCapacityLimit", 0, 0, lowbatt_info }, { NULL, 0, 0, "UPS.PowerSummary.PresentStatus.Overload", 0, 0, overload_info }, { NULL, 0, 0, "UPS.PowerSummary.PresentStatus.NeedReplacement", 0, 0, replacebatt_info }, { NULL, 0, 0, "UPS.PowerConverter.Input[1].PresentStatus.Buck", 0, 0, trim_info }, { NULL, 0, 0, "UPS.PowerConverter.Input[1].PresentStatus.Boost", 0, 0, boost_info }, { NULL, 0, 0, "UPS.PowerConverter.Input[1].PresentStatus.VoltageOutOfRange", 0, 0, vrange_info }, { NULL, 0, 0, "UPS.PowerConverter.Input[1].PresentStatus.FrequencyOutOfRange", 0, 0, frange_info }, { NULL, 0, 0, "UPS.PowerConverter.Input[1].PresentStatus.FuseFault", 0, 0, fuse_fault_info }, { NULL, 0, 0, "UPS.PowerConverter.Input[1].PresentStatus.InternalFailure", 0, 0, internalfailure_info }, { NULL, 0, 0, "UPS.PowerSummary.PresentStatus.Good", 0, 0, off_info }, /* { NULL, 0, 0, "UPS.PowerConverter.Input[1].PresentStatus.Used", 0, 0, online_info }, */ { NULL, 0, 0, "UPS.PowerConverter.Input[2].PresentStatus.Used", 0, 0, bypass_aut_info }, /* Automatic bypass */ /* { NULL, 0, 0, "UPS.PowerConverter.Input[3].PresentStatus.Used", 0, 0, onbatt_info }, */ { NULL, 0, 0, "UPS.PowerConverter.Input[4].PresentStatus.Used", 0, 0, bypass_man_info }, /* Manual bypass */ { NULL, 0, 0, "UPS.PowerSummary.PresentStatus.FanFailure", 0, 0, fanfail_info }, { NULL, 0, 0, "UPS.BatterySystem.Battery.PresentStatus.Present", 0, 0, nobattery_info }, { NULL, 0, 0, "UPS.BatterySystem.Charger.PresentStatus.InternalFailure", 0, 0, chargerfail_info }, { NULL, 0, 0, "UPS.BatterySystem.Charger.PresentStatus.VoltageTooHigh", 0, 0, battvolthi_info }, { NULL, 0, 0, "UPS.BatterySystem.Charger.PresentStatus.VoltageTooLow", 0, 0, battvoltlo_info }, { NULL, 0, 0, "UPS.PowerSummary.PresentStatus.InternalFailure", 0, 0, internalfailure_info }, { NULL, 0, 0, "UPS.PowerSummary.PresentStatus.CommunicationLost", 0, 0, commfault_info }, { NULL, 0, 0, "UPS.PowerSummary.PresentStatus.OverTemperature", 0, 0, overheat_info }, /* { NULL, 0, 0, "UPS.PowerSummary.PresentStatus.ShutdownImminent", 0, 0, shutdownimm_info }, */ /* Battery page */ { "battery.charge", 0, 0, "UPS.PowerSummary.RemainingCapacity", 0, 0, NULL }, { "battery.charge.low", 0, 0, "UPS.PowerSummary.RemainingCapacityLimitSetting", 0, 0, NULL }, { "battery.charge.low", 0, 0, "UPS.PowerSummary.RemainingCapacityLimit", 0, 0, NULL }, /* Read only */ { "battery.charge.restart", 0, 0, "UPS.PowerSummary.RestartLevel", 0, 0, NULL }, { "battery.capacity", 0, 0, "UPS.BatterySystem.Battery.DesignCapacity", 0, 0, mge_battery_capacity }, /* conversion needed from As to Ah */ { "battery.runtime", 0, 0, "UPS.PowerSummary.RunTimeToEmpty", 0, 0, NULL }, { "battery.runtime.low", ST_FLAG_RW, 0, "System.RunTimeToEmptyLimit", 0, 0, NULL }, { "battery.temperature", 0, 0, "UPS.BatterySystem.Battery.Temperature", 0, 0, NULL }, { "battery.packs.external", 0, 0, "UPS.BatterySystem.Battery.Count", 0, 0, NULL }, { "battery.type", ST_FLAG_STATIC, 0, "UPS.PowerSummary.iDeviceChemistry", 0, 0, NULL }, { "battery.type", ST_FLAG_STATIC, 0, "UPS.PowerSummary.iDeviceChemistery", 0, 0, NULL }, /* [sic] */ { "battery.voltage.nominal", ST_FLAG_STATIC, 0, "UPS.BatterySystem.ConfigVoltage", 0, 0, NULL }, { "battery.protection", 0, 0, "UPS.BatterySystem.Battery.DeepDischargeProtection", 0, 0, yes_no_info }, { "battery.energysave", 0, 0, "UPS.PowerConverter.Input[3].EnergySaving", 0, 0, yes_no_info }, /* UPS page */ { "ups.mfr", ST_FLAG_STATIC, 0, "UPS.PowerSummary.iManufacturer", 0, 0, NULL }, { "ups.model", ST_FLAG_STATIC, 0, "System.Description", 0, 0, NULL }, { "ups.model", ST_FLAG_STATIC, 0, "UPS.PowerSummary.iProduct", 0, 0, NULL }, { "ups.model.aux", ST_FLAG_STATIC, 0, "UPS.PowerSummary.iModel", 0, 0, NULL }, { "ups.time", 0, 0, "System.LastAcquisition", 0, 0, split_date_time }, /* -> XML variable System.Location [Computer Room] doesn't map to any NUT variable */ /* -> XML variable System.Contact [Computer Room Manager] doesn't map to any NUT variable */ /* -> XML variable UPS.PowerSummary.iProduct [Evolution] doesn't map to any NUT variable */ /* -> XML variable UPS.PowerSummary.iModel [650] doesn't map to any NUT variable */ { "ups.serial", ST_FLAG_STATIC, 0, "UPS.PowerSummary.iSerialNumber", 0, 0, NULL }, { "ups.firmware", ST_FLAG_STATIC, 0, "UPS.PowerSummary.iVersion", 0, 0, NULL }, { "ups.load", 0, 0, "UPS.PowerSummary.PercentLoad", 0, 0, NULL }, { "ups.load.high", 0, 0, "UPS.Flow[4].ConfigPercentLoad", 0, 0, NULL }, { "ups.delay.shutdown", ST_FLAG_RW, 0, "System.ShutdownDuration", 0, 0, NULL }, { "ups.timer.start", ST_FLAG_RW, 0, "UPS.PowerSummary.DelayBeforeStartup", 0, 0, NULL}, { "ups.timer.shutdown", ST_FLAG_RW, 0, "UPS.PowerSummary.DelayBeforeShutdown", 0, 0, mge_timer_shutdown }, /* Catch shutdown imminent criteria, keep it after UPS.PowerSummary.DelayBeforeShutdown managment */ { NULL, 0, 0, "System.RunTimeToShutdown", 0, 0, mge_shutdown_imminent }, { "ups.timer.reboot", 0, 0, "UPS.PowerSummary.DelayBeforeReboot", 0, 0, NULL }, { "ups.test.result", 0, 0, "UPS.BatterySystem.Battery.Test", 0, 0, mge_test_result_info }, { "ups.test.interval", 0, 0, "UPS.BatterySystem.Battery.TestPeriod", 0, 0, NULL }, { "ups.beeper.status", 0 ,0, "UPS.BatterySystem.Battery.AudibleAlarmControl", 0, 0, mge_beeper_info }, { "ups.beeper.status", 0 ,0, "UPS.PowerSummary.AudibleAlarmControl", 0, 0, mge_beeper_info }, { "ups.temperature", 0, 0, "UPS.PowerSummary.Temperature", 0, 0, NULL }, { "ups.power.nominal", ST_FLAG_STATIC, 0, "UPS.Flow[4].ConfigApparentPower", 0, 0, NULL }, { "ups.power", 0, 0, "UPS.PowerConverter.Output.ApparentPower", 0, 0, NULL }, { "ups.L1.power", 0, 0, "UPS.PowerConverter.Output.Phase[1].ApparentPower", 0, 0, NULL }, { "ups.L2.power", 0, 0, "UPS.PowerConverter.Output.Phase[2].ApparentPower", 0, 0, NULL }, { "ups.L3.power", 0, 0, "UPS.PowerConverter.Output.Phase[3].ApparentPower", 0, 0, NULL }, { "ups.realpower", 0, 0, "UPS.PowerConverter.Output.ActivePower", 0, 0, NULL }, { "ups.L1.realpower", 0, 0, "UPS.PowerConverter.Output.Phase[1].ActivePower", 0, 0, NULL }, { "ups.L2.realpower", 0, 0, "UPS.PowerConverter.Output.Phase[2].ActivePower", 0, 0, NULL }, { "ups.L3.realpower", 0, 0, "UPS.PowerConverter.Output.Phase[3].ActivePower", 0, 0, NULL }, { "ups.realpower.nominal", ST_FLAG_STATIC, 0, "UPS.Flow[4].ConfigActivePower", 0, 0, NULL }, { "ups.start.auto", 0, 0, "UPS.PowerConverter.Input[1].AutomaticRestart", 0, 0, yes_no_info }, { "ups.start.battery", 0, 0, "UPS.PowerConverter.Input[3].StartOnBattery", 0, 0, yes_no_info }, { "ups.start.reboot", 0, 0, "UPS.PowerConverter.Output.ForcedReboot", 0, 0, yes_no_info }, { "ups.type", ST_FLAG_STATIC, 0, "UPS.PowerConverter.ConverterType", 0, 0, mge_upstype_conversion }, /* Input page */ { "input.voltage", 0, 0, "UPS.PowerConverter.Input[1].Voltage", 0, 0, NULL }, { "input.L1-N.voltage", 0, 0, "UPS.PowerConverter.Input[1].Phase[1].Voltage", 0, 0, NULL }, { "input.L2-N.voltage", 0, 0, "UPS.PowerConverter.Input[1].Phase[2].Voltage", 0, 0, NULL }, { "input.L3-N.voltage", 0, 0, "UPS.PowerConverter.Input[1].Phase[3].Voltage", 0, 0, NULL }, { "input.L1-L2.voltage", 0, 0, "UPS.PowerConverter.Input[1].Phase[12].Voltage", 0, 0, NULL }, { "input.L2-L3.voltage", 0, 0, "UPS.PowerConverter.Input[1].Phase[23].Voltage", 0, 0, NULL }, { "input.L3-L1.voltage", 0, 0, "UPS.PowerConverter.Input[1].Phase[31].Voltage", 0, 0, NULL }, { "input.L1-L2.voltage", 0, 0, "UPS.PowerConverter.Input[1].Phase[11].Voltage", 0, 0, convert_deci }, { "input.L2-L3.voltage", 0, 0, "UPS.PowerConverter.Input[1].Phase[22].Voltage", 0, 0, convert_deci }, { "input.L3-L1.voltage", 0, 0, "UPS.PowerConverter.Input[1].Phase[33].Voltage", 0, 0, convert_deci }, { "input.voltage.nominal", 0, 0, "UPS.Flow[1].ConfigVoltage", 0, 0, NULL }, { "input.current", 0, 0, "UPS.PowerConverter.Input[1].Current", 0, 0, NULL }, { "input.L1.current", 0, 0, "UPS.PowerConverter.Input[1].Phase[1].Current", 0, 0, convert_deci }, { "input.L2.current", 0, 0, "UPS.PowerConverter.Input[1].Phase[2].Current", 0, 0, convert_deci }, { "input.L3.current", 0, 0, "UPS.PowerConverter.Input[1].Phase[3].Current", 0, 0, convert_deci }, { "input.current.nominal", 0, 0, "UPS.Flow[1].ConfigCurrent", 0, 0, NULL }, { "input.frequency", 0, 0, "UPS.PowerConverter.Input[1].Frequency", 0, 0, NULL }, { "input.frequency.nominal", 0, 0, "UPS.Flow[1].ConfigFrequency", 0, 0, NULL }, { "input.voltage.extended", 0, 0, "UPS.PowerConverter.Output.ExtendedVoltageMode", 0, 0, yes_no_info }, { "input.frequency.extended", 0, 0, "UPS.PowerConverter.Output.ExtendedFrequencyMode", 0, 0, yes_no_info }, /* same as "input.transfer.boost.low" */ { "input.transfer.low", 0, 0, "UPS.PowerConverter.Output.LowVoltageTransfer", 0, 0, NULL }, { "input.transfer.boost.low", 0, 0, "UPS.PowerConverter.Output.LowVoltageBoostTransfer", 0, 0, NULL }, { "input.transfer.boost.high", 0, 0, "UPS.PowerConverter.Output.HighVoltageBoostTransfer", 0, 0, NULL }, { "input.transfer.trim.low", 0, 0, "UPS.PowerConverter.Output.LowVoltageBuckTransfer", 0, 0, NULL }, /* same as "input.transfer.trim.high" */ { "input.transfer.high", 0, 0, "UPS.PowerConverter.Output.HighVoltageTransfer", 0, 0, NULL }, { "input.transfer.trim.high", 0, 0, "UPS.PowerConverter.Output.HighVoltageBuckTransfer", 0, 0, NULL }, { "input.sensitivity", 0, 0, "UPS.PowerConverter.Output.SensitivityMode", 0, 0, mge_sensitivity_info }, /* Bypass page */ { "input.bypass.voltage", 0, 0, "UPS.PowerConverter.Input[2].Voltage", 0, 0, NULL }, { "input.bypass.L1-N.voltage", 0, 0, "UPS.PowerConverter.Input[2].Phase[1].Voltage", 0, 0, NULL }, { "input.bypass.L2-N.voltage", 0, 0, "UPS.PowerConverter.Input[2].Phase[2].Voltage", 0, 0, NULL }, { "input.bypass.L3-N.voltage", 0, 0, "UPS.PowerConverter.Input[2].Phase[3].Voltage", 0, 0, NULL }, { "input.bypass.L1-L2.voltage", 0, 0, "UPS.PowerConverter.Input[2].Phase[12].Voltage", 0, 0, NULL }, { "input.bypass.L2-L3.voltage", 0, 0, "UPS.PowerConverter.Input[2].Phase[23].Voltage", 0, 0, NULL }, { "input.bypass.L3-L1.voltage", 0, 0, "UPS.PowerConverter.Input[2].Phase[31].Voltage", 0, 0, NULL }, { "input.bypass.L1-L2.voltage", 0, 0, "UPS.PowerConverter.Input[2].Phase[11].Voltage", 0, 0, NULL }, { "input.bypass.L2-L3.voltage", 0, 0, "UPS.PowerConverter.Input[2].Phase[22].Voltage", 0, 0, NULL }, { "input.bypass.L3-L1.voltage", 0, 0, "UPS.PowerConverter.Input[2].Phase[33].Voltage", 0, 0, NULL }, { "input.bypass.voltage.nominal", 0, 0, "UPS.Flow[2].ConfigVoltage", 0, 0, NULL }, { "input.bypass.current", 0, 0, "UPS.PowerConverter.Input[2].Current", 0, 0, NULL }, { "input.bypass.L1.current", 0, 0, "UPS.PowerConverter.Input[2].Phase[1].Current", 0, 0, NULL }, { "input.bypass.L2.current", 0, 0, "UPS.PowerConverter.Input[2].Phase[2].Current", 0, 0, NULL }, { "input.bypass.L3.current", 0, 0, "UPS.PowerConverter.Input[2].Phase[3].Current", 0, 0, NULL }, { "input.bypass.current.nominal", 0, 0, "UPS.Flow[2].ConfigCurrent", 0, 0, NULL }, { "input.bypass.frequency", 0, 0, "UPS.PowerConverter.Input[2].Frequency", 0, 0, NULL }, { "input.bypass.frequency.nominal", 0, 0, "UPS.Flow[2].ConfigFrequency", 0, 0, NULL }, /* Output page */ { "output.voltage", 0, 0, "UPS.PowerConverter.Output.Voltage", 0, 0, NULL }, { "output.L1-N.voltage", 0, 0, "UPS.PowerConverter.Output.Phase[1].Voltage", 0, 0, NULL }, { "output.L2-N.voltage", 0, 0, "UPS.PowerConverter.Output.Phase[2].Voltage", 0, 0, NULL }, { "output.L3-N.voltage", 0, 0, "UPS.PowerConverter.Output.Phase[3].Voltage", 0, 0, NULL }, { "output.L1-L2.voltage", 0, 0, "UPS.PowerConverter.Output.Phase[12].Voltage", 0, 0, NULL }, { "output.L2-L3.voltage", 0, 0, "UPS.PowerConverter.Output.Phase[23].Voltage", 0, 0, NULL }, { "output.L3-L1.voltage", 0, 0, "UPS.PowerConverter.Output.Phase[31].Voltage", 0, 0, NULL }, { "output.L1-L2.voltage", 0, 0, "UPS.PowerConverter.Output.Phase[11].Voltage", 0, 0, ignore_if_zero }, { "output.L2-L3.voltage", 0, 0, "UPS.PowerConverter.Output.Phase[22].Voltage", 0, 0, ignore_if_zero }, { "output.L3-L1.voltage", 0, 0, "UPS.PowerConverter.Output.Phase[33].Voltage", 0, 0, ignore_if_zero }, { "output.voltage.nominal", 0, 0, "UPS.Flow[4].ConfigVoltage", 0, 0, NULL }, { "output.current", 0, 0, "UPS.PowerConverter.Output.Current", 0, 0, NULL }, { "output.L1.current", 0, 0, "UPS.PowerConverter.Output.Phase[1].Current", 0, 0, convert_deci }, { "output.L2.current", 0, 0, "UPS.PowerConverter.Output.Phase[2].Current", 0, 0, convert_deci }, { "output.L3.current", 0, 0, "UPS.PowerConverter.Output.Phase[3].Current", 0, 0, convert_deci }, { "output.current.nominal", 0, 0, "UPS.Flow[4].ConfigCurrent", 0, 0, NULL }, { "output.frequency", 0, 0, "UPS.PowerConverter.Output.Frequency", 0, 0, NULL }, { "output.frequency.nominal", 0, 0, "UPS.Flow[4].ConfigFrequency", 0, 0, NULL }, { "output.powerfactor", 0, 0, "UPS.PowerConverter.Output.PowerFactor", 0, 0, mge_powerfactor_conversion }, /* Ambient page */ { "ambient.humidity", 0, 0, "Environment.Humidity", 0, 0, NULL }, { "ambient.humidity.high", ST_FLAG_RW, 0, "Environment.Humidity.HighThreshold", 0, 0, NULL }, { "ambient.humidity.low", ST_FLAG_RW, 0, "Environment.Humidity.LowThreshold", 0, 0, NULL }, { "ambient.humidity.maximum", 0, 0, "Environment.PresentStatus.HighHumidity", 0, 0, mge_ambient_info }, { "ambient.humidity.minimum", 0, 0, "Environment.PresentStatus.LowHumidity", 0, 0, mge_ambient_info }, { "ambient.temperature", 0, 0, "Environment.Temperature", 0, 0, NULL }, { "ambient.temperature.high", ST_FLAG_RW, 0, "Environment.Temperature.HighThreshold", 0, 0, NULL }, { "ambient.temperature.low", ST_FLAG_RW, 0, "Environment.Temperature.LowThreshold", 0, 0, NULL }, { "ambient.temperature.maximum", 0, 0, "Environment.PresentStatus.HighTemperature", 0, 0, mge_ambient_info }, { "ambient.temperature.minimum", 0, 0, "Environment.PresentStatus.LowTemperature", 0, 0, mge_ambient_info }, { "ambient.contacts.1.status", 0, 0, "Environment.Input[1].PresentStatus.State", 0, 0, mge_drycontact_info }, { "ambient.contacts.2.status", 0, 0, "Environment.Input[2].PresentStatus.State", 0, 0, mge_drycontact_info }, /* Outlet page (using MGE UPS SYSTEMS - PowerShare technology) */ { "outlet.id", 0, 0, "UPS.OutletSystem.Outlet[1].OutletID", 0, 0, NULL }, { "outlet.desc", 0, 0, "UPS.OutletSystem.Outlet[1].iName", 0, 0, NULL }, { "outlet.switchable", 0, 0, "UPS.OutletSystem.Outlet[1].PresentStatus.Switchable", 0, 0, yes_no_info }, { "outlet.1.id", 0, 0, "UPS.OutletSystem.Outlet[2].OutletID", 0, 0, NULL }, { "outlet.1.desc", 0, 0, "UPS.OutletSystem.Outlet[2].iName", 0, 0, NULL }, { "outlet.1.switchable", 0, 0, "UPS.OutletSystem.Outlet[2].PresentStatus.Switchable", 0, 0, yes_no_info }, { "outlet.1.status", 0, 0, "UPS.OutletSystem.Outlet[2].PresentStatus.SwitchOnOff", 0, 0, on_off_info }, /* For low end models, with 1 non backup'ed outlet */ { "outlet.1.status", 0, 0, "UPS.PowerSummary.PresentStatus.ACPresent", 0, 0, NULL }, /* on_off_info */ { "outlet.1.battery.charge.low", 0, 0, "UPS.OutletSystem.Outlet[2].RemainingCapacityLimit", 0, 0, NULL }, { "outlet.1.timer.start", 0, 0, "UPS.OutletSystem.Outlet[2].DelayBeforeStartup", 0, 0, NULL }, { "outlet.1.timer.shutdown", 0, 0, "UPS.OutletSystem.Outlet[2].DelayBeforeShutdown", 0, 0, NULL }, { "outlet.1.delay.start", 0, 0, "UPS.OutletSystem.Outlet[2].StartupTimer", 0, 0, NULL }, /* { "outlet.1.delay.shutdown", 0, 0, "UPS.OutletSystem.Outlet[2].ShutdownTimer", 0, 0, NULL }, */ { "outlet.1.delay.shutdown", ST_FLAG_RW, 0, "System.Outlet[2].ShutdownDuration", 0, 0, NULL }, { "outlet.2.id", 0, 0, "UPS.OutletSystem.Outlet[3].OutletID", 0, 0, NULL }, { "outlet.2.desc", 0, 0, "UPS.OutletSystem.Outlet[3].iName", 0, 0, NULL }, { "outlet.2.switchable", 0, 0, "UPS.OutletSystem.Outlet[3].PresentStatus.Switchable", 0, 0, yes_no_info }, { "outlet.2.status", 0, 0, "UPS.OutletSystem.Outlet[3].PresentStatus.SwitchOnOff", 0, 0, on_off_info }, { "outlet.2.battery.charge.low", 0, 0, "UPS.OutletSystem.Outlet[3].RemainingCapacityLimit", 0, 0, NULL }, { "outlet.2.timer.start", 0, 0, "UPS.OutletSystem.Outlet[3].DelayBeforeStartup", 0, 0, NULL }, { "outlet.2.timer.shutdown", 0, 0, "UPS.OutletSystem.Outlet[3].DelayBeforeShutdown", 0, 0, NULL }, { "outlet.2.delay.start", 0, 0, "UPS.OutletSystem.Outlet[3].StartupTimer", 0, 0, NULL }, /* { "outlet.2.delay.shutdown", 0, 0, "UPS.OutletSystem.Outlet[3].ShutdownTimer", 0, 0, NULL }, */ { "outlet.2.delay.shutdown", ST_FLAG_RW, 0, "System.Outlet[3].ShutdownDuration", 0, 0, NULL }, /* For newer ePDU Monitored */ { "outlet.1.desc", 0, 0, "PDU.OutletSystem.Outlet[1].iName", 0, 0, NULL }, { "outlet.1.current", 0, 0, "PDU.OutletSystem.Outlet[1].Current", 0, 0, convert_deci }, /* FIXME: also map these? * "PDU.OutletSystem.Outlet[1].CurrentLimit" => settable, triggers CurrentTooHigh * "PDU.OutletSystem.Outlet[1].PresentStatus.CurrentTooHigh" (0/1) */ { "outlet.2.desc", 0, 0, "PDU.OutletSystem.Outlet[2].iName", 0, 0, NULL }, { "outlet.2.current", 0, 0, "PDU.OutletSystem.Outlet[2].Current", 0, 0, convert_deci }, { "outlet.3.desc", 0, 0, "PDU.OutletSystem.Outlet[3].iName", 0, 0, NULL }, { "outlet.3.current", 0, 0, "PDU.OutletSystem.Outlet[3].Current", 0, 0, convert_deci }, { "outlet.4.desc", 0, 0, "PDU.OutletSystem.Outlet[2].iName", 0, 0, NULL }, { "outlet.4.current", 0, 0, "PDU.OutletSystem.Outlet[2].Current", 0, 0, convert_deci }, { "outlet.5.desc", 0, 0, "PDU.OutletSystem.Outlet[3].iName", 0, 0, NULL }, { "outlet.5.current", 0, 0, "PDU.OutletSystem.Outlet[3].Current", 0, 0, convert_deci }, { "outlet.6.desc", 0, 0, "PDU.OutletSystem.Outlet[2].iName", 0, 0, NULL }, { "outlet.6.current", 0, 0, "PDU.OutletSystem.Outlet[2].Current", 0, 0, convert_deci }, { "outlet.7.desc", 0, 0, "PDU.OutletSystem.Outlet[3].iName", 0, 0, NULL }, { "outlet.7.current", 0, 0, "PDU.OutletSystem.Outlet[3].Current", 0, 0, convert_deci }, { "outlet.8.desc", 0, 0, "PDU.OutletSystem.Outlet[2].iName", 0, 0, NULL }, { "outlet.8.current", 0, 0, "PDU.OutletSystem.Outlet[2].Current", 0, 0, convert_deci }, { NULL, 0, 0, NULL, 0, 0, NULL } }; /* A start-element callback for element with given namespace/name. */ static int mge_xml_startelm_cb(void *userdata, int parent, const char *nspace, const char *name, const char **atts) { int state = _UNEXPECTED; NUT_UNUSED_VARIABLE(userdata); NUT_UNUSED_VARIABLE(nspace); switch(parent) { case ROOTPARENT: if (!strcasecmp(name, "PRODUCT_INFO")) { /* name="Network Management Card" type="Mosaic M" version="BA" */ /* name="Network Management Card" type="Transverse" version="GB (SN 49EH29101)" */ /* name="Monitored ePDU" type="Monitored ePDU" version="Version Upgrade" */ /* name="PDU Network Management Card" type="SCOB" version="02.00.0036" signature="34008876" protocol="XML.V4" */ int i; for (i = 0; atts[i] && atts[i+1]; i += 2) { if (!strcasecmp(atts[i], "name")) { snprintf(val, sizeof(val), "%s", atts[i+1]); } if (!strcasecmp(atts[i], "type")) { snprintfcat(val, sizeof(val), "/%s", atts[i+1]); if (!strcasecmp(atts[i+1], "Transverse")) { mge_ambient_value = 1; } else if (strstr(atts[i+1], "ePDU")) { dstate_setinfo("device.type", "pdu"); } } if (!strcasecmp(atts[i], "version")) { char *s; snprintfcat(val, sizeof(val), "/%s", atts[i+1]); s = strstr(val, " (SN "); if (s) { dstate_setinfo("ups.serial", "%s", str_rtrim(s + 5, ')')); s[0] = '\0'; } dstate_setinfo("ups.firmware.aux", "%s", val); } /* netxml-ups currently only supports XML version 3 (for UPS), * and not version 4 (for UPS and PDU)! */ if (!strcasecmp(atts[i], "protocol")) { if (!strcasecmp(atts[i+1], "XML.V4")) { fatalx(EXIT_FAILURE, "XML v4 protocol is not supported!"); } } } state = PRODUCT_INFO; break; } if (!strcasecmp(name, "SUMMARY")) { state = SUMMARY; break; } if (!strcasecmp(name, "GET_OBJECT")) { state = GET_OBJECT; break; } if (!strcasecmp(name, "SET_OBJECT")) { state = SET_OBJECT; break; } if (!strcasecmp(name, "ALARM")) { int i; var[0] = val[0] = '\0'; for (i = 0; atts[i] && atts[i+1]; i += 2) { if (!strcasecmp(atts[i], "object")) { snprintf(var, sizeof(var), "%s", atts[i+1]); } if (!strcasecmp(atts[i], "value")) { snprintf(val, sizeof(var), "%s", atts[i+1]); } if (!strcasecmp(atts[i], "date")) { dstate_setinfo("ups.time", "%s", split_date_time(atts[i+1])); } } state = ALARM; break; } if (!strcasecmp(name, "XML-CLIENT")) { state = XML_CLIENT; break; } break; case PRODUCT_INFO: if (!strcasecmp(name, "SUMMARY")) { state = PI_SUMMARY; break; } if (!strcasecmp(name, "ALARMS")) { state = PI_ALARMS; break; } if (!strcasecmp(name, "MANAGEMENT")) { state = PI_MANAGEMENT; break; } if ( (!strcasecmp(name, "UPS_DATA")) || (!strcasecmp(name, "DEV_DATA")) ) { state = PI_UPS_DATA; break; } break; case PI_SUMMARY: if (!strcasecmp(name, "HTML_PROPERTIES_PAGE")) { /* url="mgeups/default.htm" */ state = PI_HTML_PROPERTIES_PAGE; break; } if (!strcasecmp(name, "XML_SUMMARY_PAGE")) { /* url="upsprop.xml" or url="ws/summary.xml" */ int i; for (i = 0; atts[i] && atts[i+1]; i += 2) { if (!strcasecmp(atts[i], "url")) { free(mge_xml_subdriver.summary); mge_xml_subdriver.summary = strdup(url_convert(atts[i+1])); } } state = PI_XML_SUMMARY_PAGE; break; } if (!strcasecmp(name, "CENTRAL_CFG")) { /* url="config.xml" */ int i; for (i = 0; atts[i] && atts[i+1]; i += 2) { if (!strcasecmp(atts[i], "url")) { free(mge_xml_subdriver.configure); mge_xml_subdriver.configure = strdup(url_convert(atts[i+1])); } } state = PI_CENTRAL_CFG; break; } if (!strcasecmp(name, "CSV_LOGS")) { /* url="logevent.csv" dateRange="no" eventFiltering="no" */ state = PI_CSV_LOGS; break; } break; case PI_ALARMS: if (!strcasecmp(name, "SUBSCRIPTION")) { /* url="subscribe.cgi" security="basic" */ int i; for (i = 0; atts[i] && atts[i+1]; i += 2) { if (!strcasecmp(atts[i], "url")) { free(mge_xml_subdriver.subscribe); mge_xml_subdriver.subscribe = strdup(url_convert(atts[i+1])); } } state = PI_SUBSCRIPTION; break; } if (!strcasecmp(name, "POLLING")) { /* url="mgeups/lastalarms.cgi" security="none" */ state = PI_POLLING; break; } break; case PI_MANAGEMENT: if (!strcasecmp(name, "MANAGEMENT_PAGE")) { /* name="Manager list" id="ManagerList" url="FS/FLASH0/TrapReceiverList.cfg" security="none" */ /* name="Shutdown criteria settings" id="Shutdown" url="FS/FLASH0/ShutdownParameters.cfg" security="none" */ /* name="Network settings" id="Network" url="FS/FLASH0/NetworkSettings.cfg" security="none" */ /* name="Centralized configuration settings" id="ClientCfg" url="FS/FLASH0/CentralizedConfig.cfg" security="none" */ state = PI_MANAGEMENT_PAGE; break; } if (!strcasecmp(name, "XML_MANAGEMENT_PAGE")) { /* name="Set Card Time" id="SetTime" url="management/set_time.xml" security="none" */ state = PI_XML_MANAGEMENT_PAGE; break; } break; case PI_UPS_DATA: if (!strcasecmp(name, "GET_OBJECT")) { /* url="getvalue.cgi" security="none" */ int i; for (i = 0; atts[i] && atts[i+1]; i += 2) { if (!strcasecmp(atts[i], "url")) { free(mge_xml_subdriver.getobject); mge_xml_subdriver.getobject = strdup(url_convert(atts[i+1])); } } state = PI_GET_OBJECT; break; } if (!strcasecmp(name, "SET_OBJECT")) { /* url="setvalue.cgi" security="ssl" */ int i; for (i = 0; atts[i] && atts[i+1]; i += 2) { if (!strcasecmp(atts[i], "url")) { free(mge_xml_subdriver.setobject); mge_xml_subdriver.setobject = strdup(url_convert(atts[i+1])); } } state = PI_SET_OBJECT; break; } break; case SUMMARY: if (!strcasecmp(name, "OBJECT")) { /* name="UPS.PowerSummary.iProduct" */ int i; for (i = 0; atts[i] && atts[i+1]; i += 2) { if (!strcasecmp(atts[i], "name")) { snprintf(var, sizeof(var), "%s", atts[i+1]); val[0] = '\0'; /*don't inherit something from another object */ } } state = SU_OBJECT; break; } break; case GET_OBJECT: if (!strcasecmp(name, "OBJECT")) { /* name="System.RunTimeToEmptyLimit" unit="s" access="RW" */ int i; for (i = 0; atts[i] && atts[i+1]; i += 2) { if (!strcasecmp(atts[i], "name")) { snprintf(var, sizeof(var), "%s", atts[i+1]); val[0] = '\0'; /*don't inherit something from another object */ } if (!strcasecmp(atts[i], "access")) { /* do something with RO/RW access? */ } } state = GO_OBJECT; break; } break; case XML_CLIENT: if (!strcasecmp(name, "GENERAL")) { state = XC_GENERAL; break; } /* FIXME? Is the fall-through to handling "GENERAL" intended? * was so in legacy code before the goto below... */ goto fallthrough_case_general; case XC_GENERAL: fallthrough_case_general: if (!strcasecmp(name, "STARTUP")) { /* config="CENTRALIZED" */ state = XC_STARTUP; break; } if (!strcasecmp(name, "SHUTDOWN")) { /* shutdownTimer="NONE" shutdownDuration="150" */ int i; for (i = 0; atts[i] && atts[i+1]; i += 2) { if (!strcasecmp(atts[i], "shutdownTimer")) { dstate_setinfo("driver.timer.shutdown", "%s", atts[i+1]); } if (!strcasecmp(atts[i], "shutdownDuration")) { dstate_setinfo("driver.delay.shutdown", "%s", atts[i+1]); } } state = XC_SHUTDOWN; break; } if (!strcasecmp(name, "BROADCAST")) { /* admins="ON" users="ON" */ state = XC_BROADCAST; break; } } upsdebugx(3, "%s: name <%s> (parent = %d, state = %d)", __func__, name, parent, state); return state; } /* Character data callback; may return non-zero to abort the parse. */ static int mge_xml_cdata_cb(void *userdata, int state, const char *cdata, size_t len) { NUT_UNUSED_VARIABLE(userdata); /* skip empty lines */ if ((len == 1) && (cdata[0] == '\n')) { upsdebugx(3, "%s: cdata ignored (state = %d)", __func__, state); return 0; } upsdebugx(3, "%s: cdata [%.*s] (state = %d)", __func__, (int)len, cdata, state); switch(state) { case ALARM: upsdebugx(2, "ALARM%.*s", (int)len, cdata); break; case SU_OBJECT: case GO_OBJECT: snprintfcat(val, sizeof(val), "%.*s", (int)len, cdata); break; } return 0; } /* End element callback; may return non-zero to abort the parse. */ static int mge_xml_endelm_cb(void *userdata, int state, const char *nspace, const char *name) { xml_info_t *info; const char *value; NUT_UNUSED_VARIABLE(userdata); NUT_UNUSED_VARIABLE(nspace); /* ignore objects for which no value was set */ if (strlen(val) == 0) { upsdebugx(3, "%s: name ignored, no value set (state = %d)", __func__, name, state); return 0; } upsdebugx(3, "%s: name (state = %d)", __func__, name, state); switch(state) { case ALARM: case SU_OBJECT: case GO_OBJECT: for (info = mge_xml2nut; info->xmlname != NULL; info++) { if (strcasecmp(var, info->xmlname)) { continue; } upsdebugx(3, "-> XML variable %s [%s] maps to NUT variable %s", var, val, info->nutname); if ((info->nutflags & ST_FLAG_STATIC) && dstate_getinfo(info->nutname)) { return 0; } if (info->convert) { value = info->convert(val); upsdebugx(4, "-> XML variable %s [%s] which maps to NUT variable %s was converted to value %s for the NUT driver state", var, val, info->nutname, value); } else { value = val; } if (value != NULL) { dstate_setinfo(info->nutname, "%s", value); } return 0; } upsdebugx(3, "-> XML variable %s [%s] doesn't map to any NUT variable", var, val); break; case PI_GET_OBJECT: case GET_OBJECT: /* We've just got a snapshot of all runtime data, saved well into * dstate's already, so can estimate missing values if needed. */ /* For phase setup, we assume it does not change during run-time. * Essentially this means that once we've detected it is N-phase, * it stays this way for the rest of the driver run/life-time. */ /* To change this behavior just flip the maychange flag to "1" */ dstate_detect_phasecount("input.", 1, &inited_phaseinfo_in, &num_inphases, 0); dstate_detect_phasecount("input.bypass.", 1, &inited_phaseinfo_bypass, &num_bypassphases, 0); dstate_detect_phasecount("output.", 1, &inited_phaseinfo_out, &num_outphases, 0); break; } return 0; } subdriver_t mge_xml_subdriver = { MGE_XML_VERSION, MGE_XML_INITUPS, MGE_XML_INITINFO, NULL, NULL, NULL, NULL, NULL, mge_xml_startelm_cb, mge_xml_cdata_cb, mge_xml_endelm_cb, }; const char *vname_nut2mge_xml(const char *name) { size_t i = 0; assert(NULL != name); for (; i < sizeof(mge_xml2nut) / sizeof(xml_info_t); ++i) { xml_info_t *info = mge_xml2nut + i; if (NULL != info->nutname) if (0 == strcasecmp(name, info->nutname)) return info->xmlname; } return NULL; } const char *vname_mge_xml2nut(const char *name) { size_t i = 0; assert(NULL != name); for (; i < sizeof(mge_xml2nut) / sizeof(xml_info_t); ++i) { xml_info_t *info = mge_xml2nut + i; if (NULL != info->xmlname) if (0 == strcasecmp(name, info->xmlname)) return info->nutname; } return NULL; } char *vvalue_mge_xml2nut(const char *name, const char *value, size_t len) { size_t i = 0; assert(NULL != name); for (; i < sizeof(mge_xml2nut) / sizeof(xml_info_t); ++i) { xml_info_t *info = mge_xml2nut + i; if (NULL != info->nutname) if (0 == strcasecmp(name, info->nutname)) { /* Copy value */ char *vcpy = (char *)malloc((len + 1) * sizeof(char)); if (NULL == vcpy) return vcpy; memcpy(vcpy, value, len * sizeof(char)); vcpy[len] = '\0'; /* Convert */ if (NULL != info->convert) { char *vconv = (char *)info->convert(vcpy); free(vcpy); return vconv; } else return vcpy; } } return NULL; } void vname_register_rw(void) { size_t i = 0; for (; i < sizeof(mge_xml2nut) / sizeof(xml_info_t); ++i) { xml_info_t *info = mge_xml2nut + i; if (NULL != info->nutname && info->nutflags & ST_FLAG_RW) { dstate_setinfo(info->nutname, "%s", ""); dstate_setflags(info->nutname, ST_FLAG_RW); } } } nut-2.8.1/drivers/generic_gpio_common.c0000644000175000017500000003616314501607135015110 00000000000000/* generic_gpio_common.c - common NUT driver code for GPIO attached UPS devices * * Copyright (C) * 2023 Modris Berzonis * * 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 2 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, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #include "config.h" #include "main.h" #include "attribute.h" #include "generic_gpio_common.h" struct gpioups_t *gpioupsfd = (struct gpioups_t *)NULL; #ifndef DRIVERS_MAIN_WITHOUT_MAIN static #endif /* DRIVERS_MAIN_WITHOUT_MAIN */ struct gpioups_t *generic_gpio_open(const char *chipName); #ifndef DRIVERS_MAIN_WITHOUT_MAIN static #endif /* DRIVERS_MAIN_WITHOUT_MAIN */ void generic_gpio_close(struct gpioups_t *gpioupsfd); #ifndef DRIVERS_MAIN_WITHOUT_MAIN static #endif /* DRIVERS_MAIN_WITHOUT_MAIN */ void get_ups_rules(struct gpioups_t *upsfd, unsigned char *rulesString); #ifndef DRIVERS_MAIN_WITHOUT_MAIN static #endif /* DRIVERS_MAIN_WITHOUT_MAIN */ void add_rule_item(struct gpioups_t *upsfd, int newValue); #ifndef DRIVERS_MAIN_WITHOUT_MAIN static #endif /* DRIVERS_MAIN_WITHOUT_MAIN */ int get_rule_lex(unsigned char *rulesBuff, int *startPos, int *endPos); #ifndef DRIVERS_MAIN_WITHOUT_MAIN static #endif /* DRIVERS_MAIN_WITHOUT_MAIN */ int calc_rule_states(int upsLinesStates[], int cRules[], int subCount, int sIndex); #ifndef DRIVERS_MAIN_WITHOUT_MAIN static #endif /* DRIVERS_MAIN_WITHOUT_MAIN */ void update_ups_states(struct gpioups_t *gpioupsfd); /* * allocate common data structures and process/check rules */ #ifndef DRIVERS_MAIN_WITHOUT_MAIN static #endif /* DRIVERS_MAIN_WITHOUT_MAIN */ struct gpioups_t *generic_gpio_open(const char *chipName) { struct gpioups_t *upsfdlocal=xcalloc(sizeof(*upsfdlocal),1); upsfdlocal->runOptions=0; /* don't use ROPT_REQRES and ROPT_EVMODE yet */ upsfdlocal->chipName=chipName; if(!testvar("rules")) /* rules is required configuration parameter */ fatalx(EXIT_FAILURE, "UPS status calculation rules not specified"); get_ups_rules(upsfdlocal, (unsigned char *)getval("rules")); upsfdlocal->upsLinesStates = xcalloc(sizeof(int), upsfdlocal->upsLinesCount); return upsfdlocal; } /* * release common data structures */ #ifndef DRIVERS_MAIN_WITHOUT_MAIN static #endif /* DRIVERS_MAIN_WITHOUT_MAIN */ void generic_gpio_close(struct gpioups_t *gpioupsfdlocal) { if (gpioupsfdlocal) { if (gpioupsfdlocal->upsLines) { free(gpioupsfdlocal->upsLines); } if (gpioupsfdlocal->upsLinesStates) { free(gpioupsfdlocal->upsLinesStates); } if (gpioupsfdlocal->rules) { int i; for (i=0; i < gpioupsfdlocal->rulesCount; i++) { free(gpioupsfdlocal->rules[i]); } } free(gpioupsfdlocal); gpioupsfdlocal = NULL; } } /* * add compiled subrules item to the array */ #ifndef DRIVERS_MAIN_WITHOUT_MAIN static #endif /* DRIVERS_MAIN_WITHOUT_MAIN */ void add_rule_item(struct gpioups_t *upsfdlocal, int newValue) { int subCount = (upsfdlocal->rules[upsfdlocal->rulesCount-1]) ? upsfdlocal->rules[upsfdlocal->rulesCount-1]->subCount+1 : 1; int itemSize = subCount*sizeof(upsfdlocal->rules[0]->cRules[0])+sizeof(rulesint); upsfdlocal->rules[upsfdlocal->rulesCount-1] = xrealloc(upsfdlocal->rules[upsfdlocal->rulesCount-1], itemSize); upsfdlocal->rules[upsfdlocal->rulesCount-1]->subCount = subCount; upsfdlocal->rules[upsfdlocal->rulesCount-1]->cRules[subCount-1] = newValue; } /* * get next lexem out of rules configuration string recognizing separators = and ; , * logical commands ^ , & , | , state names - several ascii characters matching NUT states, * and several numbers to denote GPIO chip lines to read statuses */ #ifndef DRIVERS_MAIN_WITHOUT_MAIN static #endif /* DRIVERS_MAIN_WITHOUT_MAIN */ int get_rule_lex(unsigned char *rulesBuff, int *startPos, int *endPos) { static unsigned char lexType[256]={ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 00 0x00 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 16 0x10 */ 0, 0, 0, 0, 0, 0,'&', 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 32 0x20 */ '0','0','0','0','0','0','0','0','0','0', 0,';', 0,'=', 0, 0, /* 48 0x30 */ 0,'a','a','a','a','a','a','a','a','a','a','a','a','a','a','a', /* 64 0x40 */ 'a','a','a','a','a','a','a','a','a','a','a', 0, 0, 0,'^', 0, /* 80 0x50 */ 0,'a','a','a','a','a','a','a','a','a','a','a','a','a','a','a', /* 96 0x60 */ 'a','a','a','a','a','a','a','a','a','a','a', 0,'|', 0, 0, 0, /* 112 0x70 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 128 0x80 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 144 0x90 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 160 0xa0 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 176 0xb0 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 192 0xc0 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 208 0xd0 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 224 0xe0 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 /* 240 0xf0 */ }; unsigned char lexTypeChr = lexType[rulesBuff[*startPos]]; *endPos = (*startPos)+1; if(lexTypeChr == 'a' || lexTypeChr == '0') { for(; lexType[rulesBuff[*endPos]] == lexTypeChr; (*endPos)++); } return (int)lexTypeChr; } /* * split subrules and translate them to array of commands/line numbers */ #ifndef DRIVERS_MAIN_WITHOUT_MAIN static #endif /* DRIVERS_MAIN_WITHOUT_MAIN */ void get_ups_rules(struct gpioups_t *upsfdlocal, unsigned char *rulesString) { /* statename=[^]line[&||[line]] */ char lexBuff[33]; int startPos = 0, endPos; int lexType; int lexStatus = 0; int i, j, k; int tranformationDelta; upsdebugx(4, "rules = [%s]", rulesString); /* state machine to process rules definition */ while((lexType=get_rule_lex(rulesString, &startPos, &endPos)) > 0 && lexStatus >= 0) { memset(lexBuff, 0, sizeof(lexBuff)); strncpy(lexBuff, (char *)(rulesString+startPos), endPos-startPos); upsdebugx(4, "rules start %d, end %d, lexType %d, lex [%s]", startPos, endPos, lexType, lexBuff ); switch(lexStatus) { case 0: if(lexType != 'a') { lexStatus=-1; } else { lexStatus = 1; upsfdlocal->rulesCount++; upsfdlocal->rules = xrealloc(upsfdlocal->rules, (size_t)(sizeof(upsfdlocal->rules[0])*upsfdlocal->rulesCount)); upsfdlocal->rules[upsfdlocal->rulesCount-1] = xcalloc(sizeof(rulesint), 1); strncpy(upsfdlocal->rules[upsfdlocal->rulesCount-1]->stateName, (char *)(rulesString+startPos), endPos-startPos); upsfdlocal->rules[upsfdlocal->rulesCount-1]->stateName[endPos-startPos] = 0; } break; case 1: if(lexType != '=') { lexStatus = -1; } else { lexStatus = 2; } break; case 2: if(lexType == '^') { lexStatus = 3; add_rule_item(upsfdlocal, RULES_CMD_NOT); } else if(lexType == '0') { lexStatus = 4; add_rule_item(upsfdlocal, atoi((char *)(rulesString+startPos))); } else { lexStatus = -1; } break; case 3: if(lexType != '0') { lexStatus = -1; } else { lexStatus = 4; add_rule_item(upsfdlocal, atoi((char *)(rulesString+startPos))); } break; case 4: if(lexType == '&') { lexStatus = 2; add_rule_item(upsfdlocal, RULES_CMD_AND); } else if(lexType == '|') { lexStatus = 2; add_rule_item(upsfdlocal, RULES_CMD_OR); } else if(lexType == ';') { lexStatus = 0; } else { lexStatus = -1; } break; default: lexStatus = -1; break; } if(lexStatus == -1) fatalx(LOG_ERR, "Line processing rule error at position %d", startPos); startPos = endPos; } if(lexType == 0 && lexStatus != 0) fatalx(LOG_ERR, "Line processing rule error at position %d", startPos); /* debug printout for extracted rules */ upsdebugx(4, "rules count [%d]", upsfdlocal->rulesCount); for(i = 0; i < upsfdlocal->rulesCount; i++) { upsdebugx(4, "rule state name [%s], subcount %d", upsfdlocal->rules[i]->stateName, upsfdlocal->rules[i]->subCount ); for(j = 0; jrules[i]->subCount; j++) { upsdebugx(4, "[%s] substate %d [%d]", upsfdlocal->rules[i]->stateName, j, upsfdlocal->rules[i]->cRules[j] ); } } /* get gpio lines used in rules, find max line number used to check with chip lines count*/ upsfdlocal->upsLinesCount = 0; upsfdlocal->upsMaxLine = 0; for(i = 0; i < upsfdlocal->rulesCount; i++) { for(j = 0; j < upsfdlocal->rules[i]->subCount; j++) { int pinOnList = 0; for(k = 0; k < upsfdlocal->upsLinesCount && !pinOnList; k++) { if(upsfdlocal->upsLines[k] == upsfdlocal->rules[i]->cRules[j]) { pinOnList = 1; } } if(!pinOnList) { if(upsfdlocal->rules[i]->cRules[j] >= 0) { upsfdlocal->upsLinesCount++; upsfdlocal->upsLines = xrealloc(upsfdlocal->upsLines, sizeof(upsfdlocal->upsLines[0])*upsfdlocal->upsLinesCount); upsfdlocal->upsLines[upsfdlocal->upsLinesCount-1] = upsfdlocal->rules[i]->cRules[j]; if(upsfdlocal->upsLines[upsfdlocal->upsLinesCount-1] > upsfdlocal->upsMaxLine) { upsfdlocal->upsMaxLine = upsfdlocal->upsLines[upsfdlocal->upsLinesCount-1]; } } } } } upsdebugx(4, "UPS line count = %d", upsfdlocal->upsLinesCount); for(i = 0; i < upsfdlocal->upsLinesCount; i++) { upsdebugx(4, "UPS line%d number %d", i, upsfdlocal->upsLines[i]); } /* transform lines to indexes for easier state calculation */ tranformationDelta = upsfdlocal->upsMaxLine - RULES_CMD_LAST + 1; for(i = 0; i < upsfdlocal->rulesCount; i++) { for(j = 0; j < upsfdlocal->rules[i]->subCount; j++) { if(upsfdlocal->rules[i]->cRules[j] >= 0) { upsfdlocal->rules[i]->cRules[j] -= tranformationDelta; } } } for(k = 0; k < upsfdlocal->upsLinesCount; k++) { for(i = 0; i < upsfdlocal->rulesCount; i++) { for(j = 0; j < upsfdlocal->rules[i]->subCount; j++) { if((upsfdlocal->rules[i]->cRules[j] + tranformationDelta) == upsfdlocal->upsLines[k]) { upsfdlocal->rules[i]->cRules[j] = k; } } } } /* debug printout of transformed lines numbers */ upsdebugx(4, "rules count [%d] translated", upsfdlocal->rulesCount); for(i = 0; i < upsfdlocal->rulesCount; i++) { upsdebugx(4, "rule state name [%s], subcount %d translated", upsfdlocal->rules[i]->stateName, upsfdlocal->rules[i]->subCount ); for(j = 0; j < upsfdlocal->rules[i]->subCount; j++) { upsdebugx(4, "[%s] substate %d [%d]", upsfdlocal->rules[i]->stateName, j, upsfdlocal->rules[i]->cRules[j] ); } } } /* * calculate state rule value based on GPIO line values */ #ifndef DRIVERS_MAIN_WITHOUT_MAIN static #endif /* DRIVERS_MAIN_WITHOUT_MAIN */ int calc_rule_states(int upsLinesStates[], int cRules[], int subCount, int sIndex) { int ruleVal = 0; int iopStart = sIndex; int rs; if(iopStart < subCount) { /* calculate left side */ if(cRules[iopStart] >= 0) { ruleVal = upsLinesStates[cRules[iopStart]]; } else { iopStart++; ruleVal = !upsLinesStates[cRules[iopStart]]; } iopStart++; } for(; iopStart < subCount; iopStart++) { /* right side calculation */ if(cRules[iopStart] == RULES_CMD_OR) { ruleVal = ruleVal || calc_rule_states(upsLinesStates, cRules, subCount, iopStart+1); break; } else { iopStart++; if(cRules[iopStart] == RULES_CMD_NOT) { iopStart++; rs = !upsLinesStates[cRules[iopStart]]; } else { rs = upsLinesStates[cRules[iopStart]]; } ruleVal = ruleVal && rs; } } return ruleVal; } /* * set ups state according to rules, do adjustments for CHRG/DISCHRG * and battery charge states */ #ifndef DRIVERS_MAIN_WITHOUT_MAIN static #endif /* DRIVERS_MAIN_WITHOUT_MAIN */ void update_ups_states(struct gpioups_t *gpioupsfdlocal) { int batLow = 0; int bypass = 0; int chargerStatusSet = 0; int ruleNo; status_init(); for(ruleNo = 0; ruleNo < gpioupsfdlocal->rulesCount; ruleNo++) { gpioupsfdlocal->rules[ruleNo]->currVal = calc_rule_states( gpioupsfdlocal->upsLinesStates, gpioupsfdlocal->rules[ruleNo]->cRules, gpioupsfdlocal->rules[ruleNo]->subCount, 0 ); if(gpioupsfdlocal->rules[ruleNo]->currVal) { status_set(gpioupsfdlocal->rules[ruleNo]->stateName); if(!strcmp(gpioupsfdlocal->rules[ruleNo]->stateName, "CHRG")) { dstate_setinfo("battery.charger.status", "%s", "charging"); chargerStatusSet++; } if(!strcmp(gpioupsfdlocal->rules[ruleNo]->stateName, "DISCHRG")) { dstate_setinfo("battery.charger.status", "%s", "discharging"); chargerStatusSet++; } if(!strcmp(gpioupsfdlocal->rules[ruleNo]->stateName, "LB")) { batLow = 1; } if(!strcmp(gpioupsfdlocal->rules[ruleNo]->stateName, "BYPASS")) { bypass = 1; } } if(gpioupsfdlocal->aInfoAvailable && gpioupsfdlocal->rules[ruleNo]->archVal != gpioupsfdlocal->rules[ruleNo]->currVal) { upslogx(LOG_WARNING, "UPS state [%s] changed to %d", gpioupsfdlocal->rules[ruleNo]->stateName, gpioupsfdlocal->rules[ruleNo]->currVal ); } gpioupsfdlocal->rules[ruleNo]->archVal = gpioupsfdlocal->rules[ruleNo]->currVal; } if(chargerStatusSet <= 0) { dstate_delinfo("battery.charger.status"); } if(dstate_getinfo("battery.charge.low")!=NULL) { if(batLow) { dstate_setinfo("battery.charge", "%s", dstate_getinfo("battery.charge.low")); } else { dstate_setinfo("battery.charge", "%s", "100"); } } if(bypass) { dstate_delinfo("battery.charge"); } gpioupsfdlocal->aInfoAvailable = 1; status_commit(); } void upsdrv_initinfo(void) { if(testvar("mfr")) { dstate_setinfo("device.mfr", "%s", getval("mfr")); } if(testvar("model")) { dstate_setinfo("device.model", "%s", getval("model")); } } void upsdrv_updateinfo(void) { /* read GPIO lines states */ gpio_get_lines_states(gpioupsfd); /* calculate/set UPS states based on line values */ update_ups_states(gpioupsfd); /* no protocol failures possible - mark data as OK */ dstate_dataok(); } void upsdrv_shutdown(void) { /* replace with a proper shutdown function */ upslogx(LOG_ERR, "shutdown not supported"); set_exit_flag(-1); } void upsdrv_help(void) { } /* list flags and values that you want to receive via -x */ void upsdrv_makevartable(void) { addvar(VAR_VALUE, "mfr", "Override UPS manufacturer name"); addvar(VAR_VALUE, "model", "Override UPS model name"); addvar(VAR_VALUE, "rules", "Line rules to produce status strings"); } void upsdrv_initups(void) { /* prepare rules and allocate related structures */ gpioupsfd=generic_gpio_open(device_path); /* open GPIO chip and check pin consistence */ if(gpioupsfd) { gpio_open(gpioupsfd); } } void upsdrv_cleanup(void) { /* release gpio library resources */ gpio_close(gpioupsfd); /* release related generic resources */ generic_gpio_close(gpioupsfd); } nut-2.8.1/drivers/hpe-pdu3-cis-mib.c0000644000175000017500000037551214501607135014060 00000000000000/* hpe-pdu3-cis-mib.c - subdriver to monitor HPE_PDU_CIS SNMP devices with NUT * * Copyright (C) * 2011 - 2016 Arnaud Quette * 2022 Eaton (author: Arnaud Quette ) * * 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 2 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, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "hpe-pdu3-cis-mib.h" #define HPE_PDU3_CIS_MIB_VERSION "0.1" #define HPE_PDU3_CIS_SYSOID ".1.3.6.1.4.1.232.165.11" #define HPE_PDU3_OID_MODEL_NAME ".1.3.6.1.4.1.232.165.11.1.2.1.3.1" static info_lkp_t hpe_cis_unit_switchability_info[] = { { 1, "yes", NULL, NULL }, { 2, "no", NULL, NULL }, { 0, NULL, NULL, NULL } }; static info_lkp_t hpe_cis_outlet_group_type_info[] = { { 2, "breaker1pole", NULL, NULL }, { 3, "breaker2pole", NULL, NULL }, { 4, "breaker3pole", NULL, NULL }, { 5, "outlet-section", NULL, NULL }, { 0, NULL, NULL, NULL } }; /* Note: same as marlin_outlet_type_info + i5-20R */ /* and to eaton_nlogic_outlet_type_info - few entries */ static info_lkp_t hpe_cis_outlet_type_info[] = { { 1, "iecC13", NULL, NULL }, { 2, "iecC19", NULL, NULL }, { 10, "uk", NULL, NULL }, { 11, "french", NULL, NULL }, { 12, "schuko", NULL, NULL }, { 20, "nema515", NULL, NULL }, { 21, "nema51520", NULL, NULL }, { 22, "nema520", NULL, NULL }, { 23, "nemaL520", NULL, NULL }, { 24, "nemaL530", NULL, NULL }, { 25, "nema615", NULL, NULL }, { 26, "nema620", NULL, NULL }, { 27, "nemaL620", NULL, NULL }, { 28, "nemaL630", NULL, NULL }, { 29, "nemaL715", NULL, NULL }, { 30, "rf203p277", NULL, NULL }, { 0, NULL, NULL, NULL } }; /* Same as eaton_nlogic_outlet_status_info */ static info_lkp_t hpe_cis_outlet_status_info[] = { { 1, "off", NULL, NULL }, { 2, "on", NULL, NULL }, { 3, "pendingOff", NULL, NULL }, /* transitional status */ { 4, "pendingOn", NULL, NULL }, /* transitional status */ { 0, NULL, NULL, NULL } }; static info_lkp_t hpe_cis_outlet_switchability_info[] = { { 1, "yes", NULL, NULL }, /* switchable */ { 2, "no", NULL, NULL }, /* notSwitchable */ { 0, NULL, NULL, NULL } }; /* HPE_PDU_CIS Snmp2NUT lookup table */ static snmp_info_t hpe_pdu3_cis_mib[] = { /* standard MIB items; if the vendor MIB contains better OIDs for * this (e.g. with daisy-chain support), consider adding those here */ /* Device collection */ { "device.description", ST_FLAG_STRING | ST_FLAG_RW, SU_INFOSIZE, ".1.3.6.1.2.1.1.1.0", NULL, SU_FLAG_OK, NULL }, { "device.contact", ST_FLAG_STRING | ST_FLAG_RW, SU_INFOSIZE, ".1.3.6.1.2.1.1.4.0", NULL, SU_FLAG_OK, NULL }, { "device.location", ST_FLAG_STRING | ST_FLAG_RW, SU_INFOSIZE, ".1.3.6.1.2.1.1.6.0", NULL, SU_FLAG_OK, NULL }, /* pdu3NumberPDU.0 = INTEGER: 1 (for daisychain support) */ /* { "device.count", 0, 1, ".1.3.6.1.4.1.232.165.11.1.1.0", NULL, SU_FLAG_OK, NULL }, */ /* pdu3Manufacturer.1 = STRING: "HPE" */ { "device.mfr", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.232.165.11.1.2.1.4.1", NULL, SU_FLAG_STATIC | SU_FLAG_OK, NULL }, /* pdu3Model.1 = STRING: "230V, 32A, 7.4kVA, 50/60Hz" */ { "device.model", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.232.165.11.1.2.1.3.1", NULL, SU_FLAG_OK, NULL }, /* pdu3FirmwareVersion.1 = STRING: "2.0.0.J" */ { "device.firmware", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.232.165.11.1.2.1.5.1", NULL, SU_FLAG_OK, NULL }, /* pdu3PartNumber.1 = STRING: "P9S18A" */ { "device.part", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.232.165.11.1.2.1.7.1", NULL, SU_FLAG_OK, NULL }, /* pdu3SerialNumber.1 = STRING: "CN09416708" */ { "device.serial", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.232.165.11.1.2.1.8.1", NULL, SU_FLAG_OK, NULL }, /* pdu3MACAddress.1 = Hex-STRING: EC EB B8 3D 78 6D */ { "device.macaddr", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.232.165.11.1.2.1.14.1", NULL, SU_FLAG_OK, NULL }, { "device.type", ST_FLAG_STRING, SU_INFOSIZE, NULL, "pdu", SU_FLAG_STATIC | SU_FLAG_ABSENT | SU_FLAG_OK, NULL }, /* Input collection */ /* pdu3InputPhaseCount.1 = INTEGER: 1 */ { "input.phases", 0, 1, ".1.3.6.1.4.1.232.165.11.1.2.1.11.1", NULL, SU_FLAG_OK, NULL }, /* pdu3InputPowerVA.1 = INTEGER: 922 */ { "input.power", 0, 0.001, ".1.3.6.1.4.1.232.165.11.2.1.1.4.1", NULL, SU_FLAG_NEGINVALID | SU_FLAG_UNIQUE | SU_FLAG_OK, NULL }, /* pdu3InputPowerWatts.1 = INTEGER: 900 */ { "input.realpower", 0, 0.001, ".1.3.6.1.4.1.232.165.11.2.1.1.5.1", NULL, SU_FLAG_NEGINVALID | SU_FLAG_UNIQUE | SU_FLAG_OK, NULL }, /* pdu3InputPhaseCurrentRating.1.%i = INTEGER: 3200 */ /* (can be instanciated by phase) */ { "input.current.nominal", 0, 0.01, ".1.3.6.1.4.1.232.165.11.2.2.1.10.1.1", NULL, 0, NULL }, /* pdu3InputPhaseCurrent.1.%i = INTEGER: 398 */ /* (can be instanciated by phase) */ { "input.current", 0, 0.01, ".1.3.6.1.4.1.232.165.11.2.2.1.11.1.1", NULL, 0, NULL }, /* pdu3InputPhaseVoltage.1.%i = INTEGER: 2286 */ /* (can be instanciated by phase) */ { "input.voltage", 0, 0.1, ".1.3.6.1.4.1.232.165.11.2.2.1.3.1.1", NULL, 0, NULL }, /* pdu3InputFrequency.%i = INTEGER: 500 */ /* (can be instanciated by phase) */ { "input.frequency", 0, 0.1, ".1.3.6.1.4.1.232.165.11.2.1.1.2.1", NULL, 0, NULL }, /* Outlet groups collection */ /* pdu3GroupCount.1 = INTEGER: 2 */ { "outlet.group.count", 0, 1, ".1.3.6.1.4.1.232.165.11.1.2.1.12.1", NULL, SU_FLAG_OK, NULL }, /* pdu3GroupName.1.%i = STRING: "B01" */ { "outlet.group.%i.name", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.232.165.11.3.1.1.2.1.%i", NULL, SU_FLAG_STATIC | SU_OUTLET_GROUP /*| SU_TYPE_DAISY_1*/, NULL }, /* pdu3GroupType.1.%i = INTEGER: 2 */ { "outlet.group.%i.type", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.232.165.11.3.1.1.3.1.%i", NULL, SU_FLAG_STATIC | SU_OUTLET_GROUP /*| SU_TYPE_DAISY_1*/, &hpe_cis_outlet_group_type_info[0] }, /* pdu3GroupCurrentPercentLoad.1.%i = INTEGER: 11 */ { "outlet.group.%i.load", 0, 1.0, ".1.3.6.1.4.1.232.165.11.3.1.1.18.1.%i", NULL, SU_FLAG_NEGINVALID | SU_OUTLET_GROUP /*| SU_TYPE_DAISY_1*/, NULL }, /* pdu3GroupCurrent.1.1 = INTEGER: 187 */ { "outlet.group.%i.current", 0, 0.01, ".1.3.6.1.4.1.232.165.11.3.1.1.12.1.%i", NULL, SU_OUTLET_GROUP /*| SU_TYPE_DAISY_1*/, NULL }, /* pdu3GroupVoltage.1.%i = INTEGER: 2286 */ { "outlet.group.%i.voltage", 0, 0.1, ".1.3.6.1.4.1.232.165.11.3.1.1.5.1.%i", NULL, SU_OUTLET_GROUP, NULL }, /* pdu3GroupOutletCount.1.1 = INTEGER: 12 */ { "outlet.group.%i.count", 0, 1, ".1.3.6.1.4.1.232.165.11.3.1.1.25.1.1", NULL, SU_OUTLET_GROUP /* | SU_TYPE_DAISY_1 */, NULL }, /* Outlet collection */ /* pdu3OutletCount.1 = INTEGER: 24 */ { "outlet.count", 0, 1, ".1.3.6.1.4.1.232.165.11.1.2.1.13.1", NULL, SU_FLAG_OK, NULL }, /* pdu3Controllable.1 = INTEGER: 1 */ { "outlet.switchable", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.232.165.11.1.2.1.10.1", "no", SU_FLAG_STATIC, &hpe_cis_unit_switchability_info[0] }, /* pdu3OutletControlStatus.1.1 = INTEGER: 2 */ { "outlet.%i.status", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.232.165.11.5.2.1.1.1.%i", NULL, SU_OUTLET, &hpe_cis_outlet_status_info[0] }, /* pdu3OutletName.1.%i = STRING: "CABNIET A FAN DOOR" */ { "outlet.%i.name", ST_FLAG_RW |ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.232.165.11.5.1.1.2.1.%i", NULL, SU_OUTLET, NULL }, /* pdu3OutletType.1.%i = INTEGER: 2 */ { "outlet.%i.type", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.232.165.11.5.1.1.3.1.%i", "unknown", SU_FLAG_STATIC | SU_OUTLET, &hpe_cis_outlet_type_info[0] }, /* pdu3OutletCurrentRating.1.%i = INTEGER: 2000 */ { "outlet.%i.current.nominal", 0, 0.01, ".1.3.6.1.4.1.232.165.11.5.1.1.4.1.%i", NULL, SU_OUTLET | SU_FLAG_NEGINVALID, NULL }, /* pdu3OutletCurrent.1.%i = INTEGER: 36 */ { "outlet.%i.current", 0, 0.01, ".1.3.6.1.4.1.232.165.11.5.1.1.5.1.%i", NULL, SU_OUTLET | SU_FLAG_NEGINVALID, NULL }, /* pdu3OutletCurrentPercentLoad.1.%i = INTEGER: 18 */ { "outlet.%i.load", 0, 1, ".1.3.6.1.4.1.232.165.11.5.1.1.11.1.%i", NULL, SU_OUTLET | SU_FLAG_NEGINVALID, NULL }, /* pdu3OutletVA.1.%i = INTEGER: 84 */ { "outlet.%i.power", 0, 1, ".1.3.6.1.4.1.232.165.11.5.1.1.12.1.%i", NULL, SU_OUTLET | SU_FLAG_NEGINVALID, NULL }, /* pdu3OutletWatts.1.%i = INTEGER: 84 */ { "outlet.%i.realpower", 0, 1, ".1.3.6.1.4.1.232.165.11.5.1.1.13.1.%i", NULL, SU_OUTLET | SU_FLAG_NEGINVALID, NULL }, /* pdu3OutletControlSwitchable.1.%i = INTEGER: 1 */ { "outlet.%i.switchable", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.232.165.11.5.2.1.8.1.%i", "no", SU_OUTLET | SU_FLAG_UNIQUE | SU_TYPE_DAISY_1, &hpe_cis_outlet_switchability_info[0] }, /* instant commands. */ /* Delays handling: * 0-n :Time in seconds until the group command is issued * -1:Cancel a pending group-level Off/On/Reboot command */ /* pdu3OutletControlOffCmd.1.%i = INTEGER: -1 */ { "outlet.%i.load.off", 0, 1, ".1.3.6.1.4.1.232.165.11.5.2.1.2.1.%i", "0", SU_TYPE_CMD | SU_OUTLET /*| SU_TYPE_DAISY_1*/, NULL }, /* pdu3OutletControlOnCmd.1.%i = INTEGER: -1 */ { "outlet.%i.load.on", 0, 1, ".1.3.6.1.4.1.232.165.11.5.2.1.3.1.%i", "0", SU_TYPE_CMD | SU_OUTLET /*| SU_TYPE_DAISY_1*/, NULL }, /* pdu3OutletControlRebootCmd.1.%i = INTEGER: -1 */ { "outlet.%i.load.cycle", 0, 1, ".1.3.6.1.4.1.232.165.11.5.2.1.4.1.%i", "0", SU_TYPE_CMD | SU_OUTLET /*| SU_TYPE_DAISY_1*/, NULL }, #if 0 /* Per-outlet shutdown / startup delay (configuration point, not the timers) * outletControlShutoffDelay.0.3 = INTEGER: 120 * outletControlSequenceDelay.0.8 = INTEGER: 8 * (by default each output socket startup is delayed by its number in seconds) */ { "outlet.%i.delay.shutdown", ST_FLAG_RW, 1, ".1.3.6.1.4.1.534.6.6.7.6.6.1.10.%i.%i", NULL, SU_FLAG_NEGINVALID | SU_OUTLET /*| SU_TYPE_DAISY_1*/, NULL }, { "outlet.%i.delay.start", ST_FLAG_RW, 1, ".1.3.6.1.4.1.534.6.6.7.6.6.1.7.%i.%i", NULL, SU_FLAG_NEGINVALID | SU_OUTLET /*| SU_TYPE_DAISY_1*/, NULL }, #endif /* Delayed version, parameter is mandatory (so dfl is NULL)! */ { "outlet.%i.load.off.delay", 0, 1, ".1.3.6.1.4.1.232.165.11.5.2.1.2.1.%i", NULL, SU_TYPE_CMD | SU_OUTLET /*| SU_TYPE_DAISY_1*/, NULL }, { "outlet.%i.load.on.delay", 0, 1, ".1.3.6.1.4.1.232.165.11.5.2.1.3.1.%i", NULL, SU_TYPE_CMD | SU_OUTLET /*| SU_TYPE_DAISY_1*/, NULL }, { "outlet.%i.load.cycle.delay", 0, 1, ".1.3.6.1.4.1.232.165.11.5.2.1.4.1.%i", NULL, SU_TYPE_CMD | SU_OUTLET /*| SU_TYPE_DAISY_1*/, NULL }, #if 0 /* Per-outlet shutdown / startup timers * outletControlOffCmd.0.1 = INTEGER: -1 * outletControlOnCmd.0.1 = INTEGER: -1 */ { "outlet.%i.timer.shutdown", 0, 1, ".1.3.6.1.4.1.534.6.6.7.6.6.1.3.%i.%i", NULL, SU_OUTLET /*| SU_TYPE_DAISY_1*/, NULL }, { "outlet.%i.timer.start", 0, 1, ".1.3.6.1.4.1.534.6.6.7.6.6.1.4.%i.%i", NULL, SU_OUTLET /*| SU_TYPE_DAISY_1*/, NULL }, #endif #if WITH_UNMAPPED_DATA_POINTS /* pdu3IdentIndex.1 = INTEGER: 1 */ { "unmapped.pdu3IdentIndex", 0, 1, ".1.3.6.1.4.1.232.165.11.1.2.1.1.1", NULL, SU_FLAG_OK, NULL }, /* pdu3Name.1 = "" */ { "unmapped.pdu3Name", 0, 1, ".1.3.6.1.4.1.232.165.11.1.2.1.2.1", NULL, SU_FLAG_OK, NULL }, /* pdu3FirmwareVersionTimeStamp.1 = Hex-STRING: 32 30 31 36 2F 31 31 2F 30 31 20 32 30 3A 30 38 3A 33 39 00 */ { "unmapped.pdu3FirmwareVersionTimeStamp", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.232.165.11.1.2.1.6.1", NULL, SU_FLAG_OK, NULL }, /* pdu3Status.1 = INTEGER: 2 */ { "unmapped.pdu3Status", 0, 1, ".1.3.6.1.4.1.232.165.11.1.2.1.9.1", NULL, SU_FLAG_OK, NULL }, /* pdu3IPv4Address.1 = IpAddress: [PDU_IP] */ { "unmapped.pdu3IPv4Address", 0, 1, ".1.3.6.1.4.1.232.165.11.1.2.1.15.1", NULL, SU_FLAG_OK, NULL }, /* pdu3IPv6Address.1 = STRING: "FE80::EEEB:B8FF:FE3D:786D" */ { "unmapped.pdu3IPv6Address", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.232.165.11.1.2.1.16.1", NULL, SU_FLAG_OK, NULL }, /* pdu3ConfigSsh.1 = INTEGER: 1 */ { "unmapped.pdu3ConfigSsh", 0, 1, ".1.3.6.1.4.1.232.165.11.1.3.1.2.1", NULL, SU_FLAG_OK, NULL }, /* pdu3ConfigFtps.1 = INTEGER: 1 */ { "unmapped.pdu3ConfigFtps", 0, 1, ".1.3.6.1.4.1.232.165.11.1.3.1.3.1", NULL, SU_FLAG_OK, NULL }, /* pdu3ConfigHttp.1 = INTEGER: 1 */ { "unmapped.pdu3ConfigHttp", 0, 1, ".1.3.6.1.4.1.232.165.11.1.3.1.4.1", NULL, SU_FLAG_OK, NULL }, /* pdu3ConfigHttps.1 = INTEGER: 1 */ { "unmapped.pdu3ConfigHttps", 0, 1, ".1.3.6.1.4.1.232.165.11.1.3.1.5.1", NULL, SU_FLAG_OK, NULL }, /* pdu3ConfigIPv4IPv6Switch.1 = INTEGER: 1 */ { "unmapped.pdu3ConfigIPv4IPv6Switch", 0, 1, ".1.3.6.1.4.1.232.165.11.1.3.1.6.1", NULL, SU_FLAG_OK, NULL }, /* pdu3ConfigRedfishAPI.1 = INTEGER: 0 */ { "unmapped.pdu3ConfigRedfishAPI", 0, 1, ".1.3.6.1.4.1.232.165.11.1.3.1.7.1", NULL, SU_FLAG_OK, NULL }, /* pdu3ConfigOledDispalyOrientation.1 = INTEGER: 1 */ { "unmapped.pdu3ConfigOledDispalyOrientation", 0, 1, ".1.3.6.1.4.1.232.165.11.1.3.1.8.1", NULL, SU_FLAG_OK, NULL }, /* pdu3ConfigEnergyReset.1 = INTEGER: 1 */ { "unmapped.pdu3ConfigEnergyReset", 0, 1, ".1.3.6.1.4.1.232.165.11.1.3.1.9.1", NULL, SU_FLAG_OK, NULL }, /* pdu3ConfigNetworkManagementCardReset.1 = INTEGER: 0 */ { "unmapped.pdu3ConfigNetworkManagementCardReset", 0, 1, ".1.3.6.1.4.1.232.165.11.1.3.1.10.1", NULL, SU_FLAG_OK, NULL }, /* pdu3ConfigDaisyChainStatus.1 = INTEGER: 0 */ { "unmapped.pdu3ConfigDaisyChainStatus", 0, 1, ".1.3.6.1.4.1.232.165.11.1.3.1.11.1", NULL, SU_FLAG_OK, NULL }, /* pdu3InputType.1 = INTEGER: 1 */ { "unmapped.pdu3InputType", 0, 1, ".1.3.6.1.4.1.232.165.11.2.1.1.1.1", NULL, SU_FLAG_OK, NULL }, /* pdu3InputFrequencyStatus.1 = INTEGER: 1 */ { "unmapped.pdu3InputFrequencyStatus", 0, 1, ".1.3.6.1.4.1.232.165.11.2.1.1.3.1", NULL, SU_FLAG_OK, NULL }, /* pdu3InputTotalEnergy.1 = INTEGER: 0 */ { "unmapped.pdu3InputTotalEnergy", 0, 1, ".1.3.6.1.4.1.232.165.11.2.1.1.6.1", NULL, SU_FLAG_OK, NULL }, /* pdu3InputPowerWattHourTimer.1 = Hex-STRING: 32 30 31 36 2F 31 30 2F 31 31 20 30 32 3A 34 36 3A 35 30 00 */ { "unmapped.pdu3InputPowerWattHourTimer", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.232.165.11.2.1.1.7.1", NULL, SU_FLAG_OK, NULL }, /* pdu3InputResettableEnergy.1 = INTEGER: 0 */ { "unmapped.pdu3InputResettableEnergy", 0, 1, ".1.3.6.1.4.1.232.165.11.2.1.1.8.1", NULL, SU_FLAG_OK, NULL }, /* pdu3InputPowerFactor.1 = INTEGER: 97 */ { "unmapped.pdu3InputPowerFactor", 0, 1, ".1.3.6.1.4.1.232.165.11.2.1.1.9.1", NULL, SU_FLAG_OK, NULL }, /* pdu3InputPowerVAR.1 = INTEGER: 197 */ { "unmapped.pdu3InputPowerVAR", 0, 1, ".1.3.6.1.4.1.232.165.11.2.1.1.10.1", NULL, SU_FLAG_OK, NULL }, /* pdu3InputPhaseIndex.1.1 = INTEGER: 1 */ { "unmapped.pdu3InputPhaseIndex", 0, 1, ".1.3.6.1.4.1.232.165.11.2.2.1.1.1.1", NULL, SU_FLAG_OK, NULL }, /* pdu3InputPhaseIndex.1.2 = INTEGER: 0 */ { "unmapped.pdu3InputPhaseIndex", 0, 1, ".1.3.6.1.4.1.232.165.11.2.2.1.1.1.2", NULL, SU_FLAG_OK, NULL }, /* pdu3InputPhaseIndex.1.3 = INTEGER: 0 */ { "unmapped.pdu3InputPhaseIndex", 0, 1, ".1.3.6.1.4.1.232.165.11.2.2.1.1.1.3", NULL, SU_FLAG_OK, NULL }, /* pdu3InputPhaseVoltageMeasType.1.1 = INTEGER: 1 */ { "unmapped.pdu3InputPhaseVoltageMeasType", 0, 1, ".1.3.6.1.4.1.232.165.11.2.2.1.2.1.1", NULL, SU_FLAG_OK, NULL }, /* pdu3InputPhaseVoltageMeasType.1.2 = INTEGER: 0 */ { "unmapped.pdu3InputPhaseVoltageMeasType", 0, 1, ".1.3.6.1.4.1.232.165.11.2.2.1.2.1.2", NULL, SU_FLAG_OK, NULL }, /* pdu3InputPhaseVoltageMeasType.1.3 = INTEGER: 0 */ { "unmapped.pdu3InputPhaseVoltageMeasType", 0, 1, ".1.3.6.1.4.1.232.165.11.2.2.1.2.1.3", NULL, SU_FLAG_OK, NULL }, /* pdu3InputPhaseVoltageThStatus.1.1 = INTEGER: 1 */ { "unmapped.pdu3InputPhaseVoltageThStatus", 0, 1, ".1.3.6.1.4.1.232.165.11.2.2.1.4.1.1", NULL, SU_FLAG_OK, NULL }, /* pdu3InputPhaseVoltageThStatus.1.2 = INTEGER: 0 */ { "unmapped.pdu3InputPhaseVoltageThStatus", 0, 1, ".1.3.6.1.4.1.232.165.11.2.2.1.4.1.2", NULL, SU_FLAG_OK, NULL }, /* pdu3InputPhaseVoltageThStatus.1.3 = INTEGER: 0 */ { "unmapped.pdu3InputPhaseVoltageThStatus", 0, 1, ".1.3.6.1.4.1.232.165.11.2.2.1.4.1.3", NULL, SU_FLAG_OK, NULL }, /* pdu3InputPhaseVoltageThLowerWarning.1.1 = INTEGER: 1900 */ { "unmapped.pdu3InputPhaseVoltageThLowerWarning", 0, 1, ".1.3.6.1.4.1.232.165.11.2.2.1.5.1.1", NULL, SU_FLAG_OK, NULL }, /* pdu3InputPhaseVoltageThLowerWarning.1.2 = INTEGER: 0 */ { "unmapped.pdu3InputPhaseVoltageThLowerWarning", 0, 1, ".1.3.6.1.4.1.232.165.11.2.2.1.5.1.2", NULL, SU_FLAG_OK, NULL }, /* pdu3InputPhaseVoltageThLowerWarning.1.3 = INTEGER: 0 */ { "unmapped.pdu3InputPhaseVoltageThLowerWarning", 0, 1, ".1.3.6.1.4.1.232.165.11.2.2.1.5.1.3", NULL, SU_FLAG_OK, NULL }, /* pdu3InputPhaseVoltageThLowerCritical.1.1 = INTEGER: 1800 */ { "unmapped.pdu3InputPhaseVoltageThLowerCritical", 0, 1, ".1.3.6.1.4.1.232.165.11.2.2.1.6.1.1", NULL, SU_FLAG_OK, NULL }, /* pdu3InputPhaseVoltageThLowerCritical.1.2 = INTEGER: 0 */ { "unmapped.pdu3InputPhaseVoltageThLowerCritical", 0, 1, ".1.3.6.1.4.1.232.165.11.2.2.1.6.1.2", NULL, SU_FLAG_OK, NULL }, /* pdu3InputPhaseVoltageThLowerCritical.1.3 = INTEGER: 0 */ { "unmapped.pdu3InputPhaseVoltageThLowerCritical", 0, 1, ".1.3.6.1.4.1.232.165.11.2.2.1.6.1.3", NULL, SU_FLAG_OK, NULL }, /* pdu3InputPhaseVoltageThUpperWarning.1.1 = INTEGER: 2500 */ { "unmapped.pdu3InputPhaseVoltageThUpperWarning", 0, 1, ".1.3.6.1.4.1.232.165.11.2.2.1.7.1.1", NULL, SU_FLAG_OK, NULL }, /* pdu3InputPhaseVoltageThUpperWarning.1.2 = INTEGER: 0 */ { "unmapped.pdu3InputPhaseVoltageThUpperWarning", 0, 1, ".1.3.6.1.4.1.232.165.11.2.2.1.7.1.2", NULL, SU_FLAG_OK, NULL }, /* pdu3InputPhaseVoltageThUpperWarning.1.3 = INTEGER: 0 */ { "unmapped.pdu3InputPhaseVoltageThUpperWarning", 0, 1, ".1.3.6.1.4.1.232.165.11.2.2.1.7.1.3", NULL, SU_FLAG_OK, NULL }, /* pdu3InputPhaseVoltageThUpperCritical.1.1 = INTEGER: 2600 */ { "unmapped.pdu3InputPhaseVoltageThUpperCritical", 0, 1, ".1.3.6.1.4.1.232.165.11.2.2.1.8.1.1", NULL, SU_FLAG_OK, NULL }, /* pdu3InputPhaseVoltageThUpperCritical.1.2 = INTEGER: 0 */ { "unmapped.pdu3InputPhaseVoltageThUpperCritical", 0, 1, ".1.3.6.1.4.1.232.165.11.2.2.1.8.1.2", NULL, SU_FLAG_OK, NULL }, /* pdu3InputPhaseVoltageThUpperCritical.1.3 = INTEGER: 0 */ { "unmapped.pdu3InputPhaseVoltageThUpperCritical", 0, 1, ".1.3.6.1.4.1.232.165.11.2.2.1.8.1.3", NULL, SU_FLAG_OK, NULL }, /* pdu3InputPhaseCurrentMeasType.1.1 = INTEGER: 1 */ { "unmapped.pdu3InputPhaseCurrentMeasType", 0, 1, ".1.3.6.1.4.1.232.165.11.2.2.1.9.1.1", NULL, SU_FLAG_OK, NULL }, /* pdu3InputPhaseCurrentMeasType.1.2 = INTEGER: 0 */ { "unmapped.pdu3InputPhaseCurrentMeasType", 0, 1, ".1.3.6.1.4.1.232.165.11.2.2.1.9.1.2", NULL, SU_FLAG_OK, NULL }, /* pdu3InputPhaseCurrentMeasType.1.3 = INTEGER: 0 */ { "unmapped.pdu3InputPhaseCurrentMeasType", 0, 1, ".1.3.6.1.4.1.232.165.11.2.2.1.9.1.3", NULL, SU_FLAG_OK, NULL }, /* pdu3InputPhaseCurrentThStatus.1.1 = INTEGER: 1 */ { "unmapped.pdu3InputPhaseCurrentThStatus", 0, 1, ".1.3.6.1.4.1.232.165.11.2.2.1.12.1.1", NULL, SU_FLAG_OK, NULL }, /* pdu3InputPhaseCurrentThStatus.1.2 = INTEGER: 0 */ { "unmapped.pdu3InputPhaseCurrentThStatus", 0, 1, ".1.3.6.1.4.1.232.165.11.2.2.1.12.1.2", NULL, SU_FLAG_OK, NULL }, /* pdu3InputPhaseCurrentThStatus.1.3 = INTEGER: 0 */ { "unmapped.pdu3InputPhaseCurrentThStatus", 0, 1, ".1.3.6.1.4.1.232.165.11.2.2.1.12.1.3", NULL, SU_FLAG_OK, NULL }, /* pdu3InputPhaseCurrentThLowerWarning.1.1 = INTEGER: 0 */ { "unmapped.pdu3InputPhaseCurrentThLowerWarning", 0, 1, ".1.3.6.1.4.1.232.165.11.2.2.1.13.1.1", NULL, SU_FLAG_OK, NULL }, /* pdu3InputPhaseCurrentThLowerWarning.1.2 = INTEGER: 0 */ { "unmapped.pdu3InputPhaseCurrentThLowerWarning", 0, 1, ".1.3.6.1.4.1.232.165.11.2.2.1.13.1.2", NULL, SU_FLAG_OK, NULL }, /* pdu3InputPhaseCurrentThLowerWarning.1.3 = INTEGER: 0 */ { "unmapped.pdu3InputPhaseCurrentThLowerWarning", 0, 1, ".1.3.6.1.4.1.232.165.11.2.2.1.13.1.3", NULL, SU_FLAG_OK, NULL }, /* pdu3InputPhaseCurrentThLowerCritical.1.1 = INTEGER: 0 */ { "unmapped.pdu3InputPhaseCurrentThLowerCritical", 0, 1, ".1.3.6.1.4.1.232.165.11.2.2.1.14.1.1", NULL, SU_FLAG_OK, NULL }, /* pdu3InputPhaseCurrentThLowerCritical.1.2 = INTEGER: 0 */ { "unmapped.pdu3InputPhaseCurrentThLowerCritical", 0, 1, ".1.3.6.1.4.1.232.165.11.2.2.1.14.1.2", NULL, SU_FLAG_OK, NULL }, /* pdu3InputPhaseCurrentThLowerCritical.1.3 = INTEGER: 0 */ { "unmapped.pdu3InputPhaseCurrentThLowerCritical", 0, 1, ".1.3.6.1.4.1.232.165.11.2.2.1.14.1.3", NULL, SU_FLAG_OK, NULL }, /* pdu3InputPhaseCurrentThUpperWarning.1.1 = INTEGER: 2200 */ { "unmapped.pdu3InputPhaseCurrentThUpperWarning", 0, 1, ".1.3.6.1.4.1.232.165.11.2.2.1.15.1.1", NULL, SU_FLAG_OK, NULL }, /* pdu3InputPhaseCurrentThUpperWarning.1.2 = INTEGER: 0 */ { "unmapped.pdu3InputPhaseCurrentThUpperWarning", 0, 1, ".1.3.6.1.4.1.232.165.11.2.2.1.15.1.2", NULL, SU_FLAG_OK, NULL }, /* pdu3InputPhaseCurrentThUpperWarning.1.3 = INTEGER: 0 */ { "unmapped.pdu3InputPhaseCurrentThUpperWarning", 0, 1, ".1.3.6.1.4.1.232.165.11.2.2.1.15.1.3", NULL, SU_FLAG_OK, NULL }, /* pdu3InputPhaseCurrentThUpperCritical.1.1 = INTEGER: 2800 */ { "unmapped.pdu3InputPhaseCurrentThUpperCritical", 0, 1, ".1.3.6.1.4.1.232.165.11.2.2.1.16.1.1", NULL, SU_FLAG_OK, NULL }, /* pdu3InputPhaseCurrentThUpperCritical.1.2 = INTEGER: 0 */ { "unmapped.pdu3InputPhaseCurrentThUpperCritical", 0, 1, ".1.3.6.1.4.1.232.165.11.2.2.1.16.1.2", NULL, SU_FLAG_OK, NULL }, /* pdu3InputPhaseCurrentThUpperCritical.1.3 = INTEGER: 0 */ { "unmapped.pdu3InputPhaseCurrentThUpperCritical", 0, 1, ".1.3.6.1.4.1.232.165.11.2.2.1.16.1.3", NULL, SU_FLAG_OK, NULL }, /* pdu3InputPhaseCurrentPercentLoad.1.1 = INTEGER: 124 */ { "unmapped.pdu3InputPhaseCurrentPercentLoad", 0, 1, ".1.3.6.1.4.1.232.165.11.2.2.1.17.1.1", NULL, SU_FLAG_OK, NULL }, /* pdu3InputPhaseCurrentPercentLoad.1.2 = INTEGER: 0 */ { "unmapped.pdu3InputPhaseCurrentPercentLoad", 0, 1, ".1.3.6.1.4.1.232.165.11.2.2.1.17.1.2", NULL, SU_FLAG_OK, NULL }, /* pdu3InputPhaseCurrentPercentLoad.1.3 = INTEGER: 0 */ { "unmapped.pdu3InputPhaseCurrentPercentLoad", 0, 1, ".1.3.6.1.4.1.232.165.11.2.2.1.17.1.3", NULL, SU_FLAG_OK, NULL }, /* pdu3InputPhasePowerMeasType.1.1 = INTEGER: 1 */ { "unmapped.pdu3InputPhasePowerMeasType", 0, 1, ".1.3.6.1.4.1.232.165.11.2.2.1.18.1.1", NULL, SU_FLAG_OK, NULL }, /* pdu3InputPhasePowerMeasType.1.2 = INTEGER: 0 */ { "unmapped.pdu3InputPhasePowerMeasType", 0, 1, ".1.3.6.1.4.1.232.165.11.2.2.1.18.1.2", NULL, SU_FLAG_OK, NULL }, /* pdu3InputPhasePowerMeasType.1.3 = INTEGER: 0 */ { "unmapped.pdu3InputPhasePowerMeasType", 0, 1, ".1.3.6.1.4.1.232.165.11.2.2.1.18.1.3", NULL, SU_FLAG_OK, NULL }, /* pdu3InputPhasePowerVA.1.1 = INTEGER: 921 */ { "unmapped.pdu3InputPhasePowerVA", 0, 1, ".1.3.6.1.4.1.232.165.11.2.2.1.19.1.1", NULL, SU_FLAG_OK, NULL }, /* pdu3InputPhasePowerVA.1.2 = INTEGER: 921 */ { "unmapped.pdu3InputPhasePowerVA", 0, 1, ".1.3.6.1.4.1.232.165.11.2.2.1.19.1.2", NULL, SU_FLAG_OK, NULL }, /* pdu3InputPhasePowerVA.1.3 = INTEGER: 921 */ { "unmapped.pdu3InputPhasePowerVA", 0, 1, ".1.3.6.1.4.1.232.165.11.2.2.1.19.1.3", NULL, SU_FLAG_OK, NULL }, /* pdu3InputPhasePowerWatts.1.1 = INTEGER: 899 */ { "unmapped.pdu3InputPhasePowerWatts", 0, 1, ".1.3.6.1.4.1.232.165.11.2.2.1.20.1.1", NULL, SU_FLAG_OK, NULL }, /* pdu3InputPhasePowerWatts.1.2 = INTEGER: 0 */ { "unmapped.pdu3InputPhasePowerWatts", 0, 1, ".1.3.6.1.4.1.232.165.11.2.2.1.20.1.2", NULL, SU_FLAG_OK, NULL }, /* pdu3InputPhasePowerWatts.1.3 = INTEGER: 0 */ { "unmapped.pdu3InputPhasePowerWatts", 0, 1, ".1.3.6.1.4.1.232.165.11.2.2.1.20.1.3", NULL, SU_FLAG_OK, NULL }, /* pdu3InputPhasePowerWattHour.1.1 = INTEGER: 0 */ { "unmapped.pdu3InputPhasePowerWattHour", 0, 1, ".1.3.6.1.4.1.232.165.11.2.2.1.21.1.1", NULL, SU_FLAG_OK, NULL }, /* pdu3InputPhasePowerWattHour.1.2 = INTEGER: 0 */ { "unmapped.pdu3InputPhasePowerWattHour", 0, 1, ".1.3.6.1.4.1.232.165.11.2.2.1.21.1.2", NULL, SU_FLAG_OK, NULL }, /* pdu3InputPhasePowerWattHour.1.3 = INTEGER: 0 */ { "unmapped.pdu3InputPhasePowerWattHour", 0, 1, ".1.3.6.1.4.1.232.165.11.2.2.1.21.1.3", NULL, SU_FLAG_OK, NULL }, /* pdu3InputPhasePowerWattHourTimer.1.1 = Hex-STRING: 32 30 31 36 2F 31 30 2F 31 31 20 30 32 3A 34 36 3A 35 30 00 */ { "unmapped.pdu3InputPhasePowerWattHourTimer", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.232.165.11.2.2.1.22.1.1", NULL, SU_FLAG_OK, NULL }, /* pdu3InputPhasePowerWattHourTimer.1.2 = Hex-STRING: 32 30 31 36 2F 31 30 2F 31 31 20 30 32 3A 34 36 3A 35 30 00 */ { "unmapped.pdu3InputPhasePowerWattHourTimer", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.232.165.11.2.2.1.22.1.2", NULL, SU_FLAG_OK, NULL }, /* pdu3InputPhasePowerWattHourTimer.1.3 = Hex-STRING: 32 30 31 36 2F 31 30 2F 31 31 20 30 32 3A 34 36 3A 35 30 00 */ { "unmapped.pdu3InputPhasePowerWattHourTimer", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.232.165.11.2.2.1.22.1.3", NULL, SU_FLAG_OK, NULL }, /* pdu3InputPhasePowerFactor.1.1 = INTEGER: 97 */ { "unmapped.pdu3InputPhasePowerFactor", 0, 1, ".1.3.6.1.4.1.232.165.11.2.2.1.23.1.1", NULL, SU_FLAG_OK, NULL }, /* pdu3InputPhasePowerFactor.1.2 = INTEGER: 0 */ { "unmapped.pdu3InputPhasePowerFactor", 0, 1, ".1.3.6.1.4.1.232.165.11.2.2.1.23.1.2", NULL, SU_FLAG_OK, NULL }, /* pdu3InputPhasePowerFactor.1.3 = INTEGER: 0 */ { "unmapped.pdu3InputPhasePowerFactor", 0, 1, ".1.3.6.1.4.1.232.165.11.2.2.1.23.1.3", NULL, SU_FLAG_OK, NULL }, /* pdu3InputPhasePowerVAR.1.1 = INTEGER: 195 */ { "unmapped.pdu3InputPhasePowerVAR", 0, 1, ".1.3.6.1.4.1.232.165.11.2.2.1.24.1.1", NULL, SU_FLAG_OK, NULL }, /* pdu3InputPhasePowerVAR.1.2 = INTEGER: 0 */ { "unmapped.pdu3InputPhasePowerVAR", 0, 1, ".1.3.6.1.4.1.232.165.11.2.2.1.24.1.2", NULL, SU_FLAG_OK, NULL }, /* pdu3InputPhasePowerVAR.1.3 = INTEGER: 0 */ { "unmapped.pdu3InputPhasePowerVAR", 0, 1, ".1.3.6.1.4.1.232.165.11.2.2.1.24.1.3", NULL, SU_FLAG_OK, NULL }, /* pdu3GroupIndex.1.1 = INTEGER: 1 */ { "unmapped.pdu3GroupIndex", 0, 1, ".1.3.6.1.4.1.232.165.11.3.1.1.1.1.1", NULL, SU_FLAG_OK, NULL }, /* pdu3GroupIndex.1.2 = INTEGER: 2 */ { "unmapped.pdu3GroupIndex", 0, 1, ".1.3.6.1.4.1.232.165.11.3.1.1.1.1.2", NULL, SU_FLAG_OK, NULL }, /* pdu3GroupIndex.1.3 = INTEGER: 3 */ { "unmapped.pdu3GroupIndex", 0, 1, ".1.3.6.1.4.1.232.165.11.3.1.1.1.1.3", NULL, SU_FLAG_OK, NULL }, /* pdu3GroupIndex.1.4 = INTEGER: 4 */ { "unmapped.pdu3GroupIndex", 0, 1, ".1.3.6.1.4.1.232.165.11.3.1.1.1.1.4", NULL, SU_FLAG_OK, NULL }, /* pdu3GroupIndex.1.5 = INTEGER: 5 */ { "unmapped.pdu3GroupIndex", 0, 1, ".1.3.6.1.4.1.232.165.11.3.1.1.1.1.5", NULL, SU_FLAG_OK, NULL }, /* pdu3GroupIndex.1.6 = INTEGER: 6 */ { "unmapped.pdu3GroupIndex", 0, 1, ".1.3.6.1.4.1.232.165.11.3.1.1.1.1.6", NULL, SU_FLAG_OK, NULL }, /* pdu3GroupIndex.1.7 = INTEGER: 7 */ { "unmapped.pdu3GroupIndex", 0, 1, ".1.3.6.1.4.1.232.165.11.3.1.1.1.1.7", NULL, SU_FLAG_OK, NULL }, /* pdu3GroupIndex.1.8 = INTEGER: 8 */ { "unmapped.pdu3GroupIndex", 0, 1, ".1.3.6.1.4.1.232.165.11.3.1.1.1.1.8", NULL, SU_FLAG_OK, NULL }, /* pdu3GroupIndex.1.9 = INTEGER: 9 */ { "unmapped.pdu3GroupIndex", 0, 1, ".1.3.6.1.4.1.232.165.11.3.1.1.1.1.9", NULL, SU_FLAG_OK, NULL }, /* pdu3GroupIndex.1.10 = INTEGER: 10 */ { "unmapped.pdu3GroupIndex", 0, 1, ".1.3.6.1.4.1.232.165.11.3.1.1.1.1.10", NULL, SU_FLAG_OK, NULL }, /* pdu3GroupIndex.1.11 = INTEGER: 11 */ { "unmapped.pdu3GroupIndex", 0, 1, ".1.3.6.1.4.1.232.165.11.3.1.1.1.1.11", NULL, SU_FLAG_OK, NULL }, /* pdu3GroupIndex.1.12 = INTEGER: 12 */ { "unmapped.pdu3GroupIndex", 0, 1, ".1.3.6.1.4.1.232.165.11.3.1.1.1.1.12", NULL, SU_FLAG_OK, NULL }, /* pdu3GroupVoltageMeasType.1.1 = INTEGER: 1 */ { "unmapped.pdu3GroupVoltageMeasType", 0, 1, ".1.3.6.1.4.1.232.165.11.3.1.1.4.1.1", NULL, SU_FLAG_OK, NULL }, /* pdu3GroupVoltageMeasType.1.2 = INTEGER: 1 */ { "unmapped.pdu3GroupVoltageMeasType", 0, 1, ".1.3.6.1.4.1.232.165.11.3.1.1.4.1.2", NULL, SU_FLAG_OK, NULL }, /* pdu3GroupVoltageMeasType.1.3 = INTEGER: 0 */ { "unmapped.pdu3GroupVoltageMeasType", 0, 1, ".1.3.6.1.4.1.232.165.11.3.1.1.4.1.3", NULL, SU_FLAG_OK, NULL }, /* pdu3GroupVoltageMeasType.1.4 = INTEGER: 0 */ { "unmapped.pdu3GroupVoltageMeasType", 0, 1, ".1.3.6.1.4.1.232.165.11.3.1.1.4.1.4", NULL, SU_FLAG_OK, NULL }, /* pdu3GroupVoltageMeasType.1.5 = INTEGER: 0 */ { "unmapped.pdu3GroupVoltageMeasType", 0, 1, ".1.3.6.1.4.1.232.165.11.3.1.1.4.1.5", NULL, SU_FLAG_OK, NULL }, /* pdu3GroupVoltageMeasType.1.6 = INTEGER: 0 */ { "unmapped.pdu3GroupVoltageMeasType", 0, 1, ".1.3.6.1.4.1.232.165.11.3.1.1.4.1.6", NULL, SU_FLAG_OK, NULL }, /* pdu3GroupVoltageMeasType.1.7 = INTEGER: 0 */ { "unmapped.pdu3GroupVoltageMeasType", 0, 1, ".1.3.6.1.4.1.232.165.11.3.1.1.4.1.7", NULL, SU_FLAG_OK, NULL }, /* pdu3GroupVoltageMeasType.1.8 = INTEGER: 0 */ { "unmapped.pdu3GroupVoltageMeasType", 0, 1, ".1.3.6.1.4.1.232.165.11.3.1.1.4.1.8", NULL, SU_FLAG_OK, NULL }, /* pdu3GroupVoltageMeasType.1.9 = INTEGER: 0 */ { "unmapped.pdu3GroupVoltageMeasType", 0, 1, ".1.3.6.1.4.1.232.165.11.3.1.1.4.1.9", NULL, SU_FLAG_OK, NULL }, /* pdu3GroupVoltageMeasType.1.10 = INTEGER: 0 */ { "unmapped.pdu3GroupVoltageMeasType", 0, 1, ".1.3.6.1.4.1.232.165.11.3.1.1.4.1.10", NULL, SU_FLAG_OK, NULL }, /* pdu3GroupVoltageMeasType.1.11 = INTEGER: 0 */ { "unmapped.pdu3GroupVoltageMeasType", 0, 1, ".1.3.6.1.4.1.232.165.11.3.1.1.4.1.11", NULL, SU_FLAG_OK, NULL }, /* pdu3GroupVoltageMeasType.1.12 = INTEGER: 0 */ { "unmapped.pdu3GroupVoltageMeasType", 0, 1, ".1.3.6.1.4.1.232.165.11.3.1.1.4.1.12", NULL, SU_FLAG_OK, NULL }, /* pdu3GroupVoltageThStatus.1.1 = INTEGER: 1 */ { "unmapped.pdu3GroupVoltageThStatus", 0, 1, ".1.3.6.1.4.1.232.165.11.3.1.1.6.1.1", NULL, SU_FLAG_OK, NULL }, /* pdu3GroupVoltageThStatus.1.2 = INTEGER: 1 */ { "unmapped.pdu3GroupVoltageThStatus", 0, 1, ".1.3.6.1.4.1.232.165.11.3.1.1.6.1.2", NULL, SU_FLAG_OK, NULL }, /* pdu3GroupVoltageThStatus.1.3 = INTEGER: 0 */ { "unmapped.pdu3GroupVoltageThStatus", 0, 1, ".1.3.6.1.4.1.232.165.11.3.1.1.6.1.3", NULL, SU_FLAG_OK, NULL }, /* pdu3GroupVoltageThStatus.1.4 = INTEGER: 0 */ { "unmapped.pdu3GroupVoltageThStatus", 0, 1, ".1.3.6.1.4.1.232.165.11.3.1.1.6.1.4", NULL, SU_FLAG_OK, NULL }, /* pdu3GroupVoltageThStatus.1.5 = INTEGER: 0 */ { "unmapped.pdu3GroupVoltageThStatus", 0, 1, ".1.3.6.1.4.1.232.165.11.3.1.1.6.1.5", NULL, SU_FLAG_OK, NULL }, /* pdu3GroupVoltageThStatus.1.6 = INTEGER: 0 */ { "unmapped.pdu3GroupVoltageThStatus", 0, 1, ".1.3.6.1.4.1.232.165.11.3.1.1.6.1.6", NULL, SU_FLAG_OK, NULL }, /* pdu3GroupVoltageThStatus.1.7 = INTEGER: 0 */ { "unmapped.pdu3GroupVoltageThStatus", 0, 1, ".1.3.6.1.4.1.232.165.11.3.1.1.6.1.7", NULL, SU_FLAG_OK, NULL }, /* pdu3GroupVoltageThStatus.1.8 = INTEGER: 0 */ { "unmapped.pdu3GroupVoltageThStatus", 0, 1, ".1.3.6.1.4.1.232.165.11.3.1.1.6.1.8", NULL, SU_FLAG_OK, NULL }, /* pdu3GroupVoltageThStatus.1.9 = INTEGER: 0 */ { "unmapped.pdu3GroupVoltageThStatus", 0, 1, ".1.3.6.1.4.1.232.165.11.3.1.1.6.1.9", NULL, SU_FLAG_OK, NULL }, /* pdu3GroupVoltageThStatus.1.10 = INTEGER: 0 */ { "unmapped.pdu3GroupVoltageThStatus", 0, 1, ".1.3.6.1.4.1.232.165.11.3.1.1.6.1.10", NULL, SU_FLAG_OK, NULL }, /* pdu3GroupVoltageThStatus.1.11 = INTEGER: 0 */ { "unmapped.pdu3GroupVoltageThStatus", 0, 1, ".1.3.6.1.4.1.232.165.11.3.1.1.6.1.11", NULL, SU_FLAG_OK, NULL }, /* pdu3GroupVoltageThStatus.1.12 = INTEGER: 0 */ { "unmapped.pdu3GroupVoltageThStatus", 0, 1, ".1.3.6.1.4.1.232.165.11.3.1.1.6.1.12", NULL, SU_FLAG_OK, NULL }, /* pdu3GroupVoltageThLowerWarning.1.1 = INTEGER: 0 */ { "unmapped.pdu3GroupVoltageThLowerWarning", 0, 1, ".1.3.6.1.4.1.232.165.11.3.1.1.7.1.1", NULL, SU_FLAG_OK, NULL }, /* pdu3GroupVoltageThLowerWarning.1.2 = INTEGER: 0 */ { "unmapped.pdu3GroupVoltageThLowerWarning", 0, 1, ".1.3.6.1.4.1.232.165.11.3.1.1.7.1.2", NULL, SU_FLAG_OK, NULL }, /* pdu3GroupVoltageThLowerWarning.1.3 = INTEGER: 0 */ { "unmapped.pdu3GroupVoltageThLowerWarning", 0, 1, ".1.3.6.1.4.1.232.165.11.3.1.1.7.1.3", NULL, SU_FLAG_OK, NULL }, /* pdu3GroupVoltageThLowerWarning.1.4 = INTEGER: 0 */ { "unmapped.pdu3GroupVoltageThLowerWarning", 0, 1, ".1.3.6.1.4.1.232.165.11.3.1.1.7.1.4", NULL, SU_FLAG_OK, NULL }, /* pdu3GroupVoltageThLowerWarning.1.5 = INTEGER: 0 */ { "unmapped.pdu3GroupVoltageThLowerWarning", 0, 1, ".1.3.6.1.4.1.232.165.11.3.1.1.7.1.5", NULL, SU_FLAG_OK, NULL }, /* pdu3GroupVoltageThLowerWarning.1.6 = INTEGER: 0 */ { "unmapped.pdu3GroupVoltageThLowerWarning", 0, 1, ".1.3.6.1.4.1.232.165.11.3.1.1.7.1.6", NULL, SU_FLAG_OK, NULL }, /* pdu3GroupVoltageThLowerWarning.1.7 = INTEGER: 0 */ { "unmapped.pdu3GroupVoltageThLowerWarning", 0, 1, ".1.3.6.1.4.1.232.165.11.3.1.1.7.1.7", NULL, SU_FLAG_OK, NULL }, /* pdu3GroupVoltageThLowerWarning.1.8 = INTEGER: 0 */ { "unmapped.pdu3GroupVoltageThLowerWarning", 0, 1, ".1.3.6.1.4.1.232.165.11.3.1.1.7.1.8", NULL, SU_FLAG_OK, NULL }, /* pdu3GroupVoltageThLowerWarning.1.9 = INTEGER: 0 */ { "unmapped.pdu3GroupVoltageThLowerWarning", 0, 1, ".1.3.6.1.4.1.232.165.11.3.1.1.7.1.9", NULL, SU_FLAG_OK, NULL }, /* pdu3GroupVoltageThLowerWarning.1.10 = INTEGER: 0 */ { "unmapped.pdu3GroupVoltageThLowerWarning", 0, 1, ".1.3.6.1.4.1.232.165.11.3.1.1.7.1.10", NULL, SU_FLAG_OK, NULL }, /* pdu3GroupVoltageThLowerWarning.1.11 = INTEGER: 0 */ { "unmapped.pdu3GroupVoltageThLowerWarning", 0, 1, ".1.3.6.1.4.1.232.165.11.3.1.1.7.1.11", NULL, SU_FLAG_OK, NULL }, /* pdu3GroupVoltageThLowerWarning.1.12 = INTEGER: 0 */ { "unmapped.pdu3GroupVoltageThLowerWarning", 0, 1, ".1.3.6.1.4.1.232.165.11.3.1.1.7.1.12", NULL, SU_FLAG_OK, NULL }, /* pdu3GroupVoltageThLowerCritical.1.1 = INTEGER: 0 */ { "unmapped.pdu3GroupVoltageThLowerCritical", 0, 1, ".1.3.6.1.4.1.232.165.11.3.1.1.8.1.1", NULL, SU_FLAG_OK, NULL }, /* pdu3GroupVoltageThLowerCritical.1.2 = INTEGER: 0 */ { "unmapped.pdu3GroupVoltageThLowerCritical", 0, 1, ".1.3.6.1.4.1.232.165.11.3.1.1.8.1.2", NULL, SU_FLAG_OK, NULL }, /* pdu3GroupVoltageThLowerCritical.1.3 = INTEGER: 0 */ { "unmapped.pdu3GroupVoltageThLowerCritical", 0, 1, ".1.3.6.1.4.1.232.165.11.3.1.1.8.1.3", NULL, SU_FLAG_OK, NULL }, /* pdu3GroupVoltageThLowerCritical.1.4 = INTEGER: 0 */ { "unmapped.pdu3GroupVoltageThLowerCritical", 0, 1, ".1.3.6.1.4.1.232.165.11.3.1.1.8.1.4", NULL, SU_FLAG_OK, NULL }, /* pdu3GroupVoltageThLowerCritical.1.5 = INTEGER: 0 */ { "unmapped.pdu3GroupVoltageThLowerCritical", 0, 1, ".1.3.6.1.4.1.232.165.11.3.1.1.8.1.5", NULL, SU_FLAG_OK, NULL }, /* pdu3GroupVoltageThLowerCritical.1.6 = INTEGER: 0 */ { "unmapped.pdu3GroupVoltageThLowerCritical", 0, 1, ".1.3.6.1.4.1.232.165.11.3.1.1.8.1.6", NULL, SU_FLAG_OK, NULL }, /* pdu3GroupVoltageThLowerCritical.1.7 = INTEGER: 0 */ { "unmapped.pdu3GroupVoltageThLowerCritical", 0, 1, ".1.3.6.1.4.1.232.165.11.3.1.1.8.1.7", NULL, SU_FLAG_OK, NULL }, /* pdu3GroupVoltageThLowerCritical.1.8 = INTEGER: 0 */ { "unmapped.pdu3GroupVoltageThLowerCritical", 0, 1, ".1.3.6.1.4.1.232.165.11.3.1.1.8.1.8", NULL, SU_FLAG_OK, NULL }, /* pdu3GroupVoltageThLowerCritical.1.9 = INTEGER: 0 */ { "unmapped.pdu3GroupVoltageThLowerCritical", 0, 1, ".1.3.6.1.4.1.232.165.11.3.1.1.8.1.9", NULL, SU_FLAG_OK, NULL }, /* pdu3GroupVoltageThLowerCritical.1.10 = INTEGER: 0 */ { "unmapped.pdu3GroupVoltageThLowerCritical", 0, 1, ".1.3.6.1.4.1.232.165.11.3.1.1.8.1.10", NULL, SU_FLAG_OK, NULL }, /* pdu3GroupVoltageThLowerCritical.1.11 = INTEGER: 0 */ { "unmapped.pdu3GroupVoltageThLowerCritical", 0, 1, ".1.3.6.1.4.1.232.165.11.3.1.1.8.1.11", NULL, SU_FLAG_OK, NULL }, /* pdu3GroupVoltageThLowerCritical.1.12 = INTEGER: 0 */ { "unmapped.pdu3GroupVoltageThLowerCritical", 0, 1, ".1.3.6.1.4.1.232.165.11.3.1.1.8.1.12", NULL, SU_FLAG_OK, NULL }, /* pdu3GroupVoltageThUpperWarning.1.%i = INTEGER: 0 */ { "unmapped.pdu3GroupVoltageThUpperWarning", 0, 1, ".1.3.6.1.4.1.232.165.11.3.1.1.9.1.%i", NULL, SU_FLAG_OK, NULL }, /* pdu3GroupVoltageThUpperCritical.1.1 = INTEGER: 0 */ { "unmapped.pdu3GroupVoltageThUpperCritical", 0, 1, ".1.3.6.1.4.1.232.165.11.3.1.1.10.1.1", NULL, SU_FLAG_OK, NULL }, /* pdu3GroupVoltageThUpperCritical.1.2 = INTEGER: 0 */ { "unmapped.pdu3GroupVoltageThUpperCritical", 0, 1, ".1.3.6.1.4.1.232.165.11.3.1.1.10.1.2", NULL, SU_FLAG_OK, NULL }, /* pdu3GroupVoltageThUpperCritical.1.3 = INTEGER: 0 */ { "unmapped.pdu3GroupVoltageThUpperCritical", 0, 1, ".1.3.6.1.4.1.232.165.11.3.1.1.10.1.3", NULL, SU_FLAG_OK, NULL }, /* pdu3GroupVoltageThUpperCritical.1.4 = INTEGER: 0 */ { "unmapped.pdu3GroupVoltageThUpperCritical", 0, 1, ".1.3.6.1.4.1.232.165.11.3.1.1.10.1.4", NULL, SU_FLAG_OK, NULL }, /* pdu3GroupVoltageThUpperCritical.1.5 = INTEGER: 0 */ { "unmapped.pdu3GroupVoltageThUpperCritical", 0, 1, ".1.3.6.1.4.1.232.165.11.3.1.1.10.1.5", NULL, SU_FLAG_OK, NULL }, /* pdu3GroupVoltageThUpperCritical.1.6 = INTEGER: 0 */ { "unmapped.pdu3GroupVoltageThUpperCritical", 0, 1, ".1.3.6.1.4.1.232.165.11.3.1.1.10.1.6", NULL, SU_FLAG_OK, NULL }, /* pdu3GroupVoltageThUpperCritical.1.7 = INTEGER: 0 */ { "unmapped.pdu3GroupVoltageThUpperCritical", 0, 1, ".1.3.6.1.4.1.232.165.11.3.1.1.10.1.7", NULL, SU_FLAG_OK, NULL }, /* pdu3GroupVoltageThUpperCritical.1.8 = INTEGER: 0 */ { "unmapped.pdu3GroupVoltageThUpperCritical", 0, 1, ".1.3.6.1.4.1.232.165.11.3.1.1.10.1.8", NULL, SU_FLAG_OK, NULL }, /* pdu3GroupVoltageThUpperCritical.1.9 = INTEGER: 0 */ { "unmapped.pdu3GroupVoltageThUpperCritical", 0, 1, ".1.3.6.1.4.1.232.165.11.3.1.1.10.1.9", NULL, SU_FLAG_OK, NULL }, /* pdu3GroupVoltageThUpperCritical.1.10 = INTEGER: 0 */ { "unmapped.pdu3GroupVoltageThUpperCritical", 0, 1, ".1.3.6.1.4.1.232.165.11.3.1.1.10.1.10", NULL, SU_FLAG_OK, NULL }, /* pdu3GroupVoltageThUpperCritical.1.11 = INTEGER: 0 */ { "unmapped.pdu3GroupVoltageThUpperCritical", 0, 1, ".1.3.6.1.4.1.232.165.11.3.1.1.10.1.11", NULL, SU_FLAG_OK, NULL }, /* pdu3GroupVoltageThUpperCritical.1.12 = INTEGER: 0 */ { "unmapped.pdu3GroupVoltageThUpperCritical", 0, 1, ".1.3.6.1.4.1.232.165.11.3.1.1.10.1.12", NULL, SU_FLAG_OK, NULL }, /* pdu3groupCurrentRating.1.1 = INTEGER: 1600 */ { "unmapped.pdu3groupCurrentRating", 0, 1, ".1.3.6.1.4.1.232.165.11.3.1.1.11.1.1", NULL, SU_FLAG_OK, NULL }, /* pdu3groupCurrentRating.1.2 = INTEGER: 1600 */ { "unmapped.pdu3groupCurrentRating", 0, 1, ".1.3.6.1.4.1.232.165.11.3.1.1.11.1.2", NULL, SU_FLAG_OK, NULL }, /* pdu3groupCurrentRating.1.3 = INTEGER: 0 */ { "unmapped.pdu3groupCurrentRating", 0, 1, ".1.3.6.1.4.1.232.165.11.3.1.1.11.1.3", NULL, SU_FLAG_OK, NULL }, /* pdu3groupCurrentRating.1.4 = INTEGER: 0 */ { "unmapped.pdu3groupCurrentRating", 0, 1, ".1.3.6.1.4.1.232.165.11.3.1.1.11.1.4", NULL, SU_FLAG_OK, NULL }, /* pdu3groupCurrentRating.1.5 = INTEGER: 0 */ { "unmapped.pdu3groupCurrentRating", 0, 1, ".1.3.6.1.4.1.232.165.11.3.1.1.11.1.5", NULL, SU_FLAG_OK, NULL }, /* pdu3groupCurrentRating.1.6 = INTEGER: 0 */ { "unmapped.pdu3groupCurrentRating", 0, 1, ".1.3.6.1.4.1.232.165.11.3.1.1.11.1.6", NULL, SU_FLAG_OK, NULL }, /* pdu3groupCurrentRating.1.7 = INTEGER: 0 */ { "unmapped.pdu3groupCurrentRating", 0, 1, ".1.3.6.1.4.1.232.165.11.3.1.1.11.1.7", NULL, SU_FLAG_OK, NULL }, /* pdu3groupCurrentRating.1.8 = INTEGER: 0 */ { "unmapped.pdu3groupCurrentRating", 0, 1, ".1.3.6.1.4.1.232.165.11.3.1.1.11.1.8", NULL, SU_FLAG_OK, NULL }, /* pdu3groupCurrentRating.1.9 = INTEGER: 0 */ { "unmapped.pdu3groupCurrentRating", 0, 1, ".1.3.6.1.4.1.232.165.11.3.1.1.11.1.9", NULL, SU_FLAG_OK, NULL }, /* pdu3groupCurrentRating.1.10 = INTEGER: 0 */ { "unmapped.pdu3groupCurrentRating", 0, 1, ".1.3.6.1.4.1.232.165.11.3.1.1.11.1.10", NULL, SU_FLAG_OK, NULL }, /* pdu3groupCurrentRating.1.11 = INTEGER: 0 */ { "unmapped.pdu3groupCurrentRating", 0, 1, ".1.3.6.1.4.1.232.165.11.3.1.1.11.1.11", NULL, SU_FLAG_OK, NULL }, /* pdu3groupCurrentRating.1.12 = INTEGER: 0 */ { "unmapped.pdu3groupCurrentRating", 0, 1, ".1.3.6.1.4.1.232.165.11.3.1.1.11.1.12", NULL, SU_FLAG_OK, NULL }, /* pdu3GroupCurrentThStatus.1.%i = INTEGER: 1 */ { "unmapped.pdu3GroupCurrentThStatus", 0, 1, ".1.3.6.1.4.1.232.165.11.3.1.1.13.1.%i", NULL, SU_FLAG_OK, NULL }, /* pdu3GroupCurrentThLowerWarning.1.%i = INTEGER: 0 */ { "unmapped.pdu3GroupCurrentThLowerWarning", 0, 1, ".1.3.6.1.4.1.232.165.11.3.1.1.14.1.%i", NULL, SU_FLAG_OK, NULL }, /* pdu3GroupCurrentThLowerCritical.1.1 = INTEGER: 0 */ { "unmapped.pdu3GroupCurrentThLowerCritical", 0, 1, ".1.3.6.1.4.1.232.165.11.3.1.1.15.1.1", NULL, SU_FLAG_OK, NULL }, /* pdu3GroupCurrentThLowerCritical.1.2 = INTEGER: 0 */ { "unmapped.pdu3GroupCurrentThLowerCritical", 0, 1, ".1.3.6.1.4.1.232.165.11.3.1.1.15.1.2", NULL, SU_FLAG_OK, NULL }, /* pdu3GroupCurrentThLowerCritical.1.3 = INTEGER: 0 */ { "unmapped.pdu3GroupCurrentThLowerCritical", 0, 1, ".1.3.6.1.4.1.232.165.11.3.1.1.15.1.3", NULL, SU_FLAG_OK, NULL }, /* pdu3GroupCurrentThLowerCritical.1.4 = INTEGER: 0 */ { "unmapped.pdu3GroupCurrentThLowerCritical", 0, 1, ".1.3.6.1.4.1.232.165.11.3.1.1.15.1.4", NULL, SU_FLAG_OK, NULL }, /* pdu3GroupCurrentThLowerCritical.1.5 = INTEGER: 0 */ { "unmapped.pdu3GroupCurrentThLowerCritical", 0, 1, ".1.3.6.1.4.1.232.165.11.3.1.1.15.1.5", NULL, SU_FLAG_OK, NULL }, /* pdu3GroupCurrentThLowerCritical.1.6 = INTEGER: 0 */ { "unmapped.pdu3GroupCurrentThLowerCritical", 0, 1, ".1.3.6.1.4.1.232.165.11.3.1.1.15.1.6", NULL, SU_FLAG_OK, NULL }, /* pdu3GroupCurrentThLowerCritical.1.7 = INTEGER: 0 */ { "unmapped.pdu3GroupCurrentThLowerCritical", 0, 1, ".1.3.6.1.4.1.232.165.11.3.1.1.15.1.7", NULL, SU_FLAG_OK, NULL }, /* pdu3GroupCurrentThLowerCritical.1.8 = INTEGER: 0 */ { "unmapped.pdu3GroupCurrentThLowerCritical", 0, 1, ".1.3.6.1.4.1.232.165.11.3.1.1.15.1.8", NULL, SU_FLAG_OK, NULL }, /* pdu3GroupCurrentThLowerCritical.1.9 = INTEGER: 0 */ { "unmapped.pdu3GroupCurrentThLowerCritical", 0, 1, ".1.3.6.1.4.1.232.165.11.3.1.1.15.1.9", NULL, SU_FLAG_OK, NULL }, /* pdu3GroupCurrentThLowerCritical.1.10 = INTEGER: 0 */ { "unmapped.pdu3GroupCurrentThLowerCritical", 0, 1, ".1.3.6.1.4.1.232.165.11.3.1.1.15.1.10", NULL, SU_FLAG_OK, NULL }, /* pdu3GroupCurrentThLowerCritical.1.11 = INTEGER: 0 */ { "unmapped.pdu3GroupCurrentThLowerCritical", 0, 1, ".1.3.6.1.4.1.232.165.11.3.1.1.15.1.11", NULL, SU_FLAG_OK, NULL }, /* pdu3GroupCurrentThLowerCritical.1.12 = INTEGER: 0 */ { "unmapped.pdu3GroupCurrentThLowerCritical", 0, 1, ".1.3.6.1.4.1.232.165.11.3.1.1.15.1.12", NULL, SU_FLAG_OK, NULL }, /* pdu3GroupCurrentThUpperWarning.1.1 = INTEGER: 1100 */ { "unmapped.pdu3GroupCurrentThUpperWarning", 0, 1, ".1.3.6.1.4.1.232.165.11.3.1.1.16.1.1", NULL, SU_FLAG_OK, NULL }, /* pdu3GroupCurrentThUpperWarning.1.2 = INTEGER: 1100 */ { "unmapped.pdu3GroupCurrentThUpperWarning", 0, 1, ".1.3.6.1.4.1.232.165.11.3.1.1.16.1.2", NULL, SU_FLAG_OK, NULL }, /* pdu3GroupCurrentThUpperWarning.1.3 = INTEGER: 0 */ { "unmapped.pdu3GroupCurrentThUpperWarning", 0, 1, ".1.3.6.1.4.1.232.165.11.3.1.1.16.1.3", NULL, SU_FLAG_OK, NULL }, /* pdu3GroupCurrentThUpperWarning.1.4 = INTEGER: 0 */ { "unmapped.pdu3GroupCurrentThUpperWarning", 0, 1, ".1.3.6.1.4.1.232.165.11.3.1.1.16.1.4", NULL, SU_FLAG_OK, NULL }, /* pdu3GroupCurrentThUpperWarning.1.5 = INTEGER: 0 */ { "unmapped.pdu3GroupCurrentThUpperWarning", 0, 1, ".1.3.6.1.4.1.232.165.11.3.1.1.16.1.5", NULL, SU_FLAG_OK, NULL }, /* pdu3GroupCurrentThUpperWarning.1.6 = INTEGER: 0 */ { "unmapped.pdu3GroupCurrentThUpperWarning", 0, 1, ".1.3.6.1.4.1.232.165.11.3.1.1.16.1.6", NULL, SU_FLAG_OK, NULL }, /* pdu3GroupCurrentThUpperWarning.1.7 = INTEGER: 0 */ { "unmapped.pdu3GroupCurrentThUpperWarning", 0, 1, ".1.3.6.1.4.1.232.165.11.3.1.1.16.1.7", NULL, SU_FLAG_OK, NULL }, /* pdu3GroupCurrentThUpperWarning.1.8 = INTEGER: 0 */ { "unmapped.pdu3GroupCurrentThUpperWarning", 0, 1, ".1.3.6.1.4.1.232.165.11.3.1.1.16.1.8", NULL, SU_FLAG_OK, NULL }, /* pdu3GroupCurrentThUpperWarning.1.9 = INTEGER: 0 */ { "unmapped.pdu3GroupCurrentThUpperWarning", 0, 1, ".1.3.6.1.4.1.232.165.11.3.1.1.16.1.9", NULL, SU_FLAG_OK, NULL }, /* pdu3GroupCurrentThUpperWarning.1.10 = INTEGER: 0 */ { "unmapped.pdu3GroupCurrentThUpperWarning", 0, 1, ".1.3.6.1.4.1.232.165.11.3.1.1.16.1.10", NULL, SU_FLAG_OK, NULL }, /* pdu3GroupCurrentThUpperWarning.1.11 = INTEGER: 0 */ { "unmapped.pdu3GroupCurrentThUpperWarning", 0, 1, ".1.3.6.1.4.1.232.165.11.3.1.1.16.1.11", NULL, SU_FLAG_OK, NULL }, /* pdu3GroupCurrentThUpperWarning.1.12 = INTEGER: 0 */ { "unmapped.pdu3GroupCurrentThUpperWarning", 0, 1, ".1.3.6.1.4.1.232.165.11.3.1.1.16.1.12", NULL, SU_FLAG_OK, NULL }, /* pdu3GroupCurrentThUpperCritical.1.1 = INTEGER: 1400 */ { "unmapped.pdu3GroupCurrentThUpperCritical", 0, 1, ".1.3.6.1.4.1.232.165.11.3.1.1.17.1.1", NULL, SU_FLAG_OK, NULL }, /* pdu3GroupCurrentThUpperCritical.1.2 = INTEGER: 1400 */ { "unmapped.pdu3GroupCurrentThUpperCritical", 0, 1, ".1.3.6.1.4.1.232.165.11.3.1.1.17.1.2", NULL, SU_FLAG_OK, NULL }, /* pdu3GroupCurrentThUpperCritical.1.3 = INTEGER: 0 */ { "unmapped.pdu3GroupCurrentThUpperCritical", 0, 1, ".1.3.6.1.4.1.232.165.11.3.1.1.17.1.3", NULL, SU_FLAG_OK, NULL }, /* pdu3GroupCurrentThUpperCritical.1.4 = INTEGER: 0 */ { "unmapped.pdu3GroupCurrentThUpperCritical", 0, 1, ".1.3.6.1.4.1.232.165.11.3.1.1.17.1.4", NULL, SU_FLAG_OK, NULL }, /* pdu3GroupCurrentThUpperCritical.1.5 = INTEGER: 0 */ { "unmapped.pdu3GroupCurrentThUpperCritical", 0, 1, ".1.3.6.1.4.1.232.165.11.3.1.1.17.1.5", NULL, SU_FLAG_OK, NULL }, /* pdu3GroupCurrentThUpperCritical.1.6 = INTEGER: 0 */ { "unmapped.pdu3GroupCurrentThUpperCritical", 0, 1, ".1.3.6.1.4.1.232.165.11.3.1.1.17.1.6", NULL, SU_FLAG_OK, NULL }, /* pdu3GroupCurrentThUpperCritical.1.7 = INTEGER: 0 */ { "unmapped.pdu3GroupCurrentThUpperCritical", 0, 1, ".1.3.6.1.4.1.232.165.11.3.1.1.17.1.7", NULL, SU_FLAG_OK, NULL }, /* pdu3GroupCurrentThUpperCritical.1.8 = INTEGER: 0 */ { "unmapped.pdu3GroupCurrentThUpperCritical", 0, 1, ".1.3.6.1.4.1.232.165.11.3.1.1.17.1.8", NULL, SU_FLAG_OK, NULL }, /* pdu3GroupCurrentThUpperCritical.1.9 = INTEGER: 0 */ { "unmapped.pdu3GroupCurrentThUpperCritical", 0, 1, ".1.3.6.1.4.1.232.165.11.3.1.1.17.1.9", NULL, SU_FLAG_OK, NULL }, /* pdu3GroupCurrentThUpperCritical.1.10 = INTEGER: 0 */ { "unmapped.pdu3GroupCurrentThUpperCritical", 0, 1, ".1.3.6.1.4.1.232.165.11.3.1.1.17.1.10", NULL, SU_FLAG_OK, NULL }, /* pdu3GroupCurrentThUpperCritical.1.11 = INTEGER: 0 */ { "unmapped.pdu3GroupCurrentThUpperCritical", 0, 1, ".1.3.6.1.4.1.232.165.11.3.1.1.17.1.11", NULL, SU_FLAG_OK, NULL }, /* pdu3GroupCurrentThUpperCritical.1.12 = INTEGER: 0 */ { "unmapped.pdu3GroupCurrentThUpperCritical", 0, 1, ".1.3.6.1.4.1.232.165.11.3.1.1.17.1.12", NULL, SU_FLAG_OK, NULL }, /* pdu3GroupPowerVA.1.1 = INTEGER: 430 */ { "unmapped.pdu3GroupPowerVA", 0, 1, ".1.3.6.1.4.1.232.165.11.3.1.1.19.1.1", NULL, SU_FLAG_OK, NULL }, /* pdu3GroupPowerVA.1.2 = INTEGER: 530 */ { "unmapped.pdu3GroupPowerVA", 0, 1, ".1.3.6.1.4.1.232.165.11.3.1.1.19.1.2", NULL, SU_FLAG_OK, NULL }, /* pdu3GroupPowerVA.1.3 = INTEGER: 0 */ { "unmapped.pdu3GroupPowerVA", 0, 1, ".1.3.6.1.4.1.232.165.11.3.1.1.19.1.3", NULL, SU_FLAG_OK, NULL }, /* pdu3GroupPowerVA.1.4 = INTEGER: 0 */ { "unmapped.pdu3GroupPowerVA", 0, 1, ".1.3.6.1.4.1.232.165.11.3.1.1.19.1.4", NULL, SU_FLAG_OK, NULL }, /* pdu3GroupPowerVA.1.5 = INTEGER: 0 */ { "unmapped.pdu3GroupPowerVA", 0, 1, ".1.3.6.1.4.1.232.165.11.3.1.1.19.1.5", NULL, SU_FLAG_OK, NULL }, /* pdu3GroupPowerVA.1.6 = INTEGER: 0 */ { "unmapped.pdu3GroupPowerVA", 0, 1, ".1.3.6.1.4.1.232.165.11.3.1.1.19.1.6", NULL, SU_FLAG_OK, NULL }, /* pdu3GroupPowerVA.1.7 = INTEGER: 0 */ { "unmapped.pdu3GroupPowerVA", 0, 1, ".1.3.6.1.4.1.232.165.11.3.1.1.19.1.7", NULL, SU_FLAG_OK, NULL }, /* pdu3GroupPowerVA.1.8 = INTEGER: 0 */ { "unmapped.pdu3GroupPowerVA", 0, 1, ".1.3.6.1.4.1.232.165.11.3.1.1.19.1.8", NULL, SU_FLAG_OK, NULL }, /* pdu3GroupPowerVA.1.9 = INTEGER: 0 */ { "unmapped.pdu3GroupPowerVA", 0, 1, ".1.3.6.1.4.1.232.165.11.3.1.1.19.1.9", NULL, SU_FLAG_OK, NULL }, /* pdu3GroupPowerVA.1.10 = INTEGER: 0 */ { "unmapped.pdu3GroupPowerVA", 0, 1, ".1.3.6.1.4.1.232.165.11.3.1.1.19.1.10", NULL, SU_FLAG_OK, NULL }, /* pdu3GroupPowerVA.1.11 = INTEGER: 0 */ { "unmapped.pdu3GroupPowerVA", 0, 1, ".1.3.6.1.4.1.232.165.11.3.1.1.19.1.11", NULL, SU_FLAG_OK, NULL }, /* pdu3GroupPowerVA.1.12 = INTEGER: 0 */ { "unmapped.pdu3GroupPowerVA", 0, 1, ".1.3.6.1.4.1.232.165.11.3.1.1.19.1.12", NULL, SU_FLAG_OK, NULL }, /* pdu3GroupPowerWatts.1.1 = INTEGER: 422 */ { "unmapped.pdu3GroupPowerWatts", 0, 1, ".1.3.6.1.4.1.232.165.11.3.1.1.20.1.1", NULL, SU_FLAG_OK, NULL }, /* pdu3GroupPowerWatts.1.2 = INTEGER: 512 */ { "unmapped.pdu3GroupPowerWatts", 0, 1, ".1.3.6.1.4.1.232.165.11.3.1.1.20.1.2", NULL, SU_FLAG_OK, NULL }, /* pdu3GroupPowerWatts.1.3 = INTEGER: 0 */ { "unmapped.pdu3GroupPowerWatts", 0, 1, ".1.3.6.1.4.1.232.165.11.3.1.1.20.1.3", NULL, SU_FLAG_OK, NULL }, /* pdu3GroupPowerWatts.1.4 = INTEGER: 0 */ { "unmapped.pdu3GroupPowerWatts", 0, 1, ".1.3.6.1.4.1.232.165.11.3.1.1.20.1.4", NULL, SU_FLAG_OK, NULL }, /* pdu3GroupPowerWatts.1.5 = INTEGER: 0 */ { "unmapped.pdu3GroupPowerWatts", 0, 1, ".1.3.6.1.4.1.232.165.11.3.1.1.20.1.5", NULL, SU_FLAG_OK, NULL }, /* pdu3GroupPowerWatts.1.6 = INTEGER: 0 */ { "unmapped.pdu3GroupPowerWatts", 0, 1, ".1.3.6.1.4.1.232.165.11.3.1.1.20.1.6", NULL, SU_FLAG_OK, NULL }, /* pdu3GroupPowerWatts.1.7 = INTEGER: 0 */ { "unmapped.pdu3GroupPowerWatts", 0, 1, ".1.3.6.1.4.1.232.165.11.3.1.1.20.1.7", NULL, SU_FLAG_OK, NULL }, /* pdu3GroupPowerWatts.1.8 = INTEGER: 0 */ { "unmapped.pdu3GroupPowerWatts", 0, 1, ".1.3.6.1.4.1.232.165.11.3.1.1.20.1.8", NULL, SU_FLAG_OK, NULL }, /* pdu3GroupPowerWatts.1.9 = INTEGER: 0 */ { "unmapped.pdu3GroupPowerWatts", 0, 1, ".1.3.6.1.4.1.232.165.11.3.1.1.20.1.9", NULL, SU_FLAG_OK, NULL }, /* pdu3GroupPowerWatts.1.10 = INTEGER: 0 */ { "unmapped.pdu3GroupPowerWatts", 0, 1, ".1.3.6.1.4.1.232.165.11.3.1.1.20.1.10", NULL, SU_FLAG_OK, NULL }, /* pdu3GroupPowerWatts.1.11 = INTEGER: 0 */ { "unmapped.pdu3GroupPowerWatts", 0, 1, ".1.3.6.1.4.1.232.165.11.3.1.1.20.1.11", NULL, SU_FLAG_OK, NULL }, /* pdu3GroupPowerWatts.1.12 = INTEGER: 0 */ { "unmapped.pdu3GroupPowerWatts", 0, 1, ".1.3.6.1.4.1.232.165.11.3.1.1.20.1.12", NULL, SU_FLAG_OK, NULL }, /* pdu3GroupPowerWattHour.1.1 = INTEGER: 0 */ { "unmapped.pdu3GroupPowerWattHour", 0, 1, ".1.3.6.1.4.1.232.165.11.3.1.1.21.1.1", NULL, SU_FLAG_OK, NULL }, /* pdu3GroupPowerWattHour.1.2 = INTEGER: 0 */ { "unmapped.pdu3GroupPowerWattHour", 0, 1, ".1.3.6.1.4.1.232.165.11.3.1.1.21.1.2", NULL, SU_FLAG_OK, NULL }, /* pdu3GroupPowerWattHour.1.3 = INTEGER: 0 */ { "unmapped.pdu3GroupPowerWattHour", 0, 1, ".1.3.6.1.4.1.232.165.11.3.1.1.21.1.3", NULL, SU_FLAG_OK, NULL }, /* pdu3GroupPowerWattHour.1.4 = INTEGER: 0 */ { "unmapped.pdu3GroupPowerWattHour", 0, 1, ".1.3.6.1.4.1.232.165.11.3.1.1.21.1.4", NULL, SU_FLAG_OK, NULL }, /* pdu3GroupPowerWattHour.1.5 = INTEGER: 0 */ { "unmapped.pdu3GroupPowerWattHour", 0, 1, ".1.3.6.1.4.1.232.165.11.3.1.1.21.1.5", NULL, SU_FLAG_OK, NULL }, /* pdu3GroupPowerWattHour.1.6 = INTEGER: 0 */ { "unmapped.pdu3GroupPowerWattHour", 0, 1, ".1.3.6.1.4.1.232.165.11.3.1.1.21.1.6", NULL, SU_FLAG_OK, NULL }, /* pdu3GroupPowerWattHour.1.7 = INTEGER: 0 */ { "unmapped.pdu3GroupPowerWattHour", 0, 1, ".1.3.6.1.4.1.232.165.11.3.1.1.21.1.7", NULL, SU_FLAG_OK, NULL }, /* pdu3GroupPowerWattHour.1.8 = INTEGER: 0 */ { "unmapped.pdu3GroupPowerWattHour", 0, 1, ".1.3.6.1.4.1.232.165.11.3.1.1.21.1.8", NULL, SU_FLAG_OK, NULL }, /* pdu3GroupPowerWattHour.1.9 = INTEGER: 0 */ { "unmapped.pdu3GroupPowerWattHour", 0, 1, ".1.3.6.1.4.1.232.165.11.3.1.1.21.1.9", NULL, SU_FLAG_OK, NULL }, /* pdu3GroupPowerWattHour.1.10 = INTEGER: 0 */ { "unmapped.pdu3GroupPowerWattHour", 0, 1, ".1.3.6.1.4.1.232.165.11.3.1.1.21.1.10", NULL, SU_FLAG_OK, NULL }, /* pdu3GroupPowerWattHour.1.11 = INTEGER: 0 */ { "unmapped.pdu3GroupPowerWattHour", 0, 1, ".1.3.6.1.4.1.232.165.11.3.1.1.21.1.11", NULL, SU_FLAG_OK, NULL }, /* pdu3GroupPowerWattHour.1.12 = INTEGER: 0 */ { "unmapped.pdu3GroupPowerWattHour", 0, 1, ".1.3.6.1.4.1.232.165.11.3.1.1.21.1.12", NULL, SU_FLAG_OK, NULL }, /* pdu3GroupPowerWattHourTimer.1.1 = Hex-STRING: 32 30 31 36 2F 31 30 2F 31 31 20 30 32 3A 34 36 3A 35 30 00 */ { "unmapped.pdu3GroupPowerWattHourTimer", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.232.165.11.3.1.1.22.1.1", NULL, SU_FLAG_OK, NULL }, /* pdu3GroupPowerWattHourTimer.1.2 = Hex-STRING: 32 30 31 36 2F 31 30 2F 31 31 20 30 32 3A 34 36 3A 35 30 00 */ { "unmapped.pdu3GroupPowerWattHourTimer", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.232.165.11.3.1.1.22.1.2", NULL, SU_FLAG_OK, NULL }, /* pdu3GroupPowerWattHourTimer.1.3 = Hex-STRING: 32 30 31 36 2F 31 30 2F 31 31 20 30 32 3A 34 36 3A 35 30 00 */ { "unmapped.pdu3GroupPowerWattHourTimer", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.232.165.11.3.1.1.22.1.3", NULL, SU_FLAG_OK, NULL }, /* pdu3GroupPowerWattHourTimer.1.4 = Hex-STRING: 32 30 31 36 2F 31 30 2F 31 31 20 30 32 3A 34 36 3A 35 30 00 */ { "unmapped.pdu3GroupPowerWattHourTimer", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.232.165.11.3.1.1.22.1.4", NULL, SU_FLAG_OK, NULL }, /* pdu3GroupPowerWattHourTimer.1.5 = Hex-STRING: 32 30 31 36 2F 31 30 2F 31 31 20 30 32 3A 34 36 3A 35 30 00 */ { "unmapped.pdu3GroupPowerWattHourTimer", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.232.165.11.3.1.1.22.1.5", NULL, SU_FLAG_OK, NULL }, /* pdu3GroupPowerWattHourTimer.1.6 = Hex-STRING: 32 30 31 36 2F 31 30 2F 31 31 20 30 32 3A 34 36 3A 35 30 00 */ { "unmapped.pdu3GroupPowerWattHourTimer", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.232.165.11.3.1.1.22.1.6", NULL, SU_FLAG_OK, NULL }, /* pdu3GroupPowerWattHourTimer.1.7 = Hex-STRING: 32 30 31 36 2F 31 30 2F 31 31 20 30 32 3A 34 36 3A 35 30 00 */ { "unmapped.pdu3GroupPowerWattHourTimer", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.232.165.11.3.1.1.22.1.7", NULL, SU_FLAG_OK, NULL }, /* pdu3GroupPowerWattHourTimer.1.8 = Hex-STRING: 32 30 31 36 2F 31 30 2F 31 31 20 30 32 3A 34 36 3A 35 30 00 */ { "unmapped.pdu3GroupPowerWattHourTimer", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.232.165.11.3.1.1.22.1.8", NULL, SU_FLAG_OK, NULL }, /* pdu3GroupPowerWattHourTimer.1.9 = Hex-STRING: 32 30 31 36 2F 31 30 2F 31 31 20 30 32 3A 34 36 3A 35 30 00 */ { "unmapped.pdu3GroupPowerWattHourTimer", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.232.165.11.3.1.1.22.1.9", NULL, SU_FLAG_OK, NULL }, /* pdu3GroupPowerWattHourTimer.1.10 = Hex-STRING: 32 30 31 36 2F 31 30 2F 31 31 20 30 32 3A 34 36 3A 35 30 00 */ { "unmapped.pdu3GroupPowerWattHourTimer", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.232.165.11.3.1.1.22.1.10", NULL, SU_FLAG_OK, NULL }, /* pdu3GroupPowerWattHourTimer.1.11 = Hex-STRING: 32 30 31 36 2F 31 30 2F 31 31 20 30 32 3A 34 36 3A 35 30 00 */ { "unmapped.pdu3GroupPowerWattHourTimer", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.232.165.11.3.1.1.22.1.11", NULL, SU_FLAG_OK, NULL }, /* pdu3GroupPowerWattHourTimer.1.12 = Hex-STRING: 32 30 31 36 2F 31 30 2F 31 31 20 30 32 3A 34 36 3A 35 30 00 */ { "unmapped.pdu3GroupPowerWattHourTimer", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.232.165.11.3.1.1.22.1.12", NULL, SU_FLAG_OK, NULL }, /* pdu3GroupPowerFactor.1.1 = INTEGER: 98 */ { "unmapped.pdu3GroupPowerFactor", 0, 1, ".1.3.6.1.4.1.232.165.11.3.1.1.23.1.1", NULL, SU_FLAG_OK, NULL }, /* pdu3GroupPowerFactor.1.2 = INTEGER: 97 */ { "unmapped.pdu3GroupPowerFactor", 0, 1, ".1.3.6.1.4.1.232.165.11.3.1.1.23.1.2", NULL, SU_FLAG_OK, NULL }, /* pdu3GroupPowerFactor.1.3 = INTEGER: 0 */ { "unmapped.pdu3GroupPowerFactor", 0, 1, ".1.3.6.1.4.1.232.165.11.3.1.1.23.1.3", NULL, SU_FLAG_OK, NULL }, /* pdu3GroupPowerFactor.1.4 = INTEGER: 0 */ { "unmapped.pdu3GroupPowerFactor", 0, 1, ".1.3.6.1.4.1.232.165.11.3.1.1.23.1.4", NULL, SU_FLAG_OK, NULL }, /* pdu3GroupPowerFactor.1.5 = INTEGER: 0 */ { "unmapped.pdu3GroupPowerFactor", 0, 1, ".1.3.6.1.4.1.232.165.11.3.1.1.23.1.5", NULL, SU_FLAG_OK, NULL }, /* pdu3GroupPowerFactor.1.6 = INTEGER: 0 */ { "unmapped.pdu3GroupPowerFactor", 0, 1, ".1.3.6.1.4.1.232.165.11.3.1.1.23.1.6", NULL, SU_FLAG_OK, NULL }, /* pdu3GroupPowerFactor.1.7 = INTEGER: 0 */ { "unmapped.pdu3GroupPowerFactor", 0, 1, ".1.3.6.1.4.1.232.165.11.3.1.1.23.1.7", NULL, SU_FLAG_OK, NULL }, /* pdu3GroupPowerFactor.1.8 = INTEGER: 0 */ { "unmapped.pdu3GroupPowerFactor", 0, 1, ".1.3.6.1.4.1.232.165.11.3.1.1.23.1.8", NULL, SU_FLAG_OK, NULL }, /* pdu3GroupPowerFactor.1.9 = INTEGER: 0 */ { "unmapped.pdu3GroupPowerFactor", 0, 1, ".1.3.6.1.4.1.232.165.11.3.1.1.23.1.9", NULL, SU_FLAG_OK, NULL }, /* pdu3GroupPowerFactor.1.10 = INTEGER: 0 */ { "unmapped.pdu3GroupPowerFactor", 0, 1, ".1.3.6.1.4.1.232.165.11.3.1.1.23.1.10", NULL, SU_FLAG_OK, NULL }, /* pdu3GroupPowerFactor.1.11 = INTEGER: 0 */ { "unmapped.pdu3GroupPowerFactor", 0, 1, ".1.3.6.1.4.1.232.165.11.3.1.1.23.1.11", NULL, SU_FLAG_OK, NULL }, /* pdu3GroupPowerFactor.1.12 = INTEGER: 0 */ { "unmapped.pdu3GroupPowerFactor", 0, 1, ".1.3.6.1.4.1.232.165.11.3.1.1.23.1.12", NULL, SU_FLAG_OK, NULL }, /* pdu3GroupPowerVAR.1.1 = INTEGER: 43 */ { "unmapped.pdu3GroupPowerVAR", 0, 1, ".1.3.6.1.4.1.232.165.11.3.1.1.24.1.1", NULL, SU_FLAG_OK, NULL }, /* pdu3GroupPowerVAR.1.2 = INTEGER: 36 */ { "unmapped.pdu3GroupPowerVAR", 0, 1, ".1.3.6.1.4.1.232.165.11.3.1.1.24.1.2", NULL, SU_FLAG_OK, NULL }, /* pdu3GroupPowerVAR.1.3 = INTEGER: 0 */ { "unmapped.pdu3GroupPowerVAR", 0, 1, ".1.3.6.1.4.1.232.165.11.3.1.1.24.1.3", NULL, SU_FLAG_OK, NULL }, /* pdu3GroupPowerVAR.1.4 = INTEGER: 0 */ { "unmapped.pdu3GroupPowerVAR", 0, 1, ".1.3.6.1.4.1.232.165.11.3.1.1.24.1.4", NULL, SU_FLAG_OK, NULL }, /* pdu3GroupPowerVAR.1.5 = INTEGER: 0 */ { "unmapped.pdu3GroupPowerVAR", 0, 1, ".1.3.6.1.4.1.232.165.11.3.1.1.24.1.5", NULL, SU_FLAG_OK, NULL }, /* pdu3GroupPowerVAR.1.6 = INTEGER: 0 */ { "unmapped.pdu3GroupPowerVAR", 0, 1, ".1.3.6.1.4.1.232.165.11.3.1.1.24.1.6", NULL, SU_FLAG_OK, NULL }, /* pdu3GroupPowerVAR.1.7 = INTEGER: 0 */ { "unmapped.pdu3GroupPowerVAR", 0, 1, ".1.3.6.1.4.1.232.165.11.3.1.1.24.1.7", NULL, SU_FLAG_OK, NULL }, /* pdu3GroupPowerVAR.1.8 = INTEGER: 0 */ { "unmapped.pdu3GroupPowerVAR", 0, 1, ".1.3.6.1.4.1.232.165.11.3.1.1.24.1.8", NULL, SU_FLAG_OK, NULL }, /* pdu3GroupPowerVAR.1.9 = INTEGER: 0 */ { "unmapped.pdu3GroupPowerVAR", 0, 1, ".1.3.6.1.4.1.232.165.11.3.1.1.24.1.9", NULL, SU_FLAG_OK, NULL }, /* pdu3GroupPowerVAR.1.10 = INTEGER: 0 */ { "unmapped.pdu3GroupPowerVAR", 0, 1, ".1.3.6.1.4.1.232.165.11.3.1.1.24.1.10", NULL, SU_FLAG_OK, NULL }, /* pdu3GroupPowerVAR.1.11 = INTEGER: 0 */ { "unmapped.pdu3GroupPowerVAR", 0, 1, ".1.3.6.1.4.1.232.165.11.3.1.1.24.1.11", NULL, SU_FLAG_OK, NULL }, /* pdu3GroupPowerVAR.1.12 = INTEGER: 0 */ { "unmapped.pdu3GroupPowerVAR", 0, 1, ".1.3.6.1.4.1.232.165.11.3.1.1.24.1.12", NULL, SU_FLAG_OK, NULL }, /* pdu3GroupBreakerStatus.1.1 = INTEGER: 2 */ { "unmapped.pdu3GroupBreakerStatus", 0, 1, ".1.3.6.1.4.1.232.165.11.3.1.1.26.1.1", NULL, SU_FLAG_OK, NULL }, /* pdu3GroupBreakerStatus.1.2 = INTEGER: 2 */ { "unmapped.pdu3GroupBreakerStatus", 0, 1, ".1.3.6.1.4.1.232.165.11.3.1.1.26.1.2", NULL, SU_FLAG_OK, NULL }, /* pdu3GroupBreakerStatus.1.3 = INTEGER: 0 */ { "unmapped.pdu3GroupBreakerStatus", 0, 1, ".1.3.6.1.4.1.232.165.11.3.1.1.26.1.3", NULL, SU_FLAG_OK, NULL }, /* pdu3GroupBreakerStatus.1.4 = INTEGER: 0 */ { "unmapped.pdu3GroupBreakerStatus", 0, 1, ".1.3.6.1.4.1.232.165.11.3.1.1.26.1.4", NULL, SU_FLAG_OK, NULL }, /* pdu3GroupBreakerStatus.1.5 = INTEGER: 0 */ { "unmapped.pdu3GroupBreakerStatus", 0, 1, ".1.3.6.1.4.1.232.165.11.3.1.1.26.1.5", NULL, SU_FLAG_OK, NULL }, /* pdu3GroupBreakerStatus.1.6 = INTEGER: 0 */ { "unmapped.pdu3GroupBreakerStatus", 0, 1, ".1.3.6.1.4.1.232.165.11.3.1.1.26.1.6", NULL, SU_FLAG_OK, NULL }, /* pdu3GroupBreakerStatus.1.7 = INTEGER: 0 */ { "unmapped.pdu3GroupBreakerStatus", 0, 1, ".1.3.6.1.4.1.232.165.11.3.1.1.26.1.7", NULL, SU_FLAG_OK, NULL }, /* pdu3GroupBreakerStatus.1.8 = INTEGER: 0 */ { "unmapped.pdu3GroupBreakerStatus", 0, 1, ".1.3.6.1.4.1.232.165.11.3.1.1.26.1.8", NULL, SU_FLAG_OK, NULL }, /* pdu3GroupBreakerStatus.1.9 = INTEGER: 0 */ { "unmapped.pdu3GroupBreakerStatus", 0, 1, ".1.3.6.1.4.1.232.165.11.3.1.1.26.1.9", NULL, SU_FLAG_OK, NULL }, /* pdu3GroupBreakerStatus.1.10 = INTEGER: 0 */ { "unmapped.pdu3GroupBreakerStatus", 0, 1, ".1.3.6.1.4.1.232.165.11.3.1.1.26.1.10", NULL, SU_FLAG_OK, NULL }, /* pdu3GroupBreakerStatus.1.11 = INTEGER: 0 */ { "unmapped.pdu3GroupBreakerStatus", 0, 1, ".1.3.6.1.4.1.232.165.11.3.1.1.26.1.11", NULL, SU_FLAG_OK, NULL }, /* pdu3GroupBreakerStatus.1.12 = INTEGER: 0 */ { "unmapped.pdu3GroupBreakerStatus", 0, 1, ".1.3.6.1.4.1.232.165.11.3.1.1.26.1.12", NULL, SU_FLAG_OK, NULL }, /* pdu3TemperatureScale.1 = INTEGER: 1 */ { "unmapped.pdu3TemperatureScale", 0, 1, ".1.3.6.1.4.1.232.165.11.4.1.1.1.1", NULL, SU_FLAG_OK, NULL }, /* pdu3TemperatureCount.1 = INTEGER: 1 */ { "unmapped.pdu3TemperatureCount", 0, 1, ".1.3.6.1.4.1.232.165.11.4.1.1.2.1", NULL, SU_FLAG_OK, NULL }, /* pdu3HumidityCount.1 = INTEGER: 1 */ { "unmapped.pdu3HumidityCount", 0, 1, ".1.3.6.1.4.1.232.165.11.4.1.1.3.1", NULL, SU_FLAG_OK, NULL }, /* pdu3ContactCount.1 = INTEGER: 0 */ { "unmapped.pdu3ContactCount", 0, 1, ".1.3.6.1.4.1.232.165.11.4.1.1.4.1", NULL, SU_FLAG_OK, NULL }, /* pdu3TemperatureIndex.1.1 = INTEGER: 1 */ { "unmapped.pdu3TemperatureIndex", 0, 1, ".1.3.6.1.4.1.232.165.11.4.2.1.1.1.1", NULL, SU_FLAG_OK, NULL }, /* pdu3TemperatureIndex.1.2 = INTEGER: 0 */ { "unmapped.pdu3TemperatureIndex", 0, 1, ".1.3.6.1.4.1.232.165.11.4.2.1.1.1.2", NULL, SU_FLAG_OK, NULL }, /* = INTEGER: 0 */ { "unmapped. = INTEGER: 0", 0, 1, ".1.3.6.1.4.1.232.165.11.4.2.1.1.1.3", NULL, SU_FLAG_OK, NULL }, /* = INTEGER: 0 */ { "unmapped. = INTEGER: 0", 0, 1, ".1.3.6.1.4.1.232.165.11.4.2.1.1.1.4", NULL, SU_FLAG_OK, NULL }, /* = INTEGER: 0 */ { "unmapped. = INTEGER: 0", 0, 1, ".1.3.6.1.4.1.232.165.11.4.2.1.1.1.5", NULL, SU_FLAG_OK, NULL }, /* = INTEGER: 0 */ { "unmapped. = INTEGER: 0", 0, 1, ".1.3.6.1.4.1.232.165.11.4.2.1.1.1.6", NULL, SU_FLAG_OK, NULL }, /* pdu3TemperatureName.1.1 = STRING: "T" */ { "unmapped.pdu3TemperatureName", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.232.165.11.4.2.1.2.1.1", NULL, SU_FLAG_OK, NULL }, /* pdu3TemperatureName.1.2 = STRING: " " */ { "unmapped.pdu3TemperatureName", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.232.165.11.4.2.1.2.1.2", NULL, SU_FLAG_OK, NULL }, /* = STRING: " " */ { "unmapped. = STRING: " "", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.232.165.11.4.2.1.2.1.3", NULL, SU_FLAG_OK, NULL }, /* = STRING: " " */ { "unmapped. = STRING: " "", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.232.165.11.4.2.1.2.1.4", NULL, SU_FLAG_OK, NULL }, /* = STRING: " " */ { "unmapped. = STRING: " "", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.232.165.11.4.2.1.2.1.5", NULL, SU_FLAG_OK, NULL }, /* = STRING: " " */ { "unmapped. = STRING: " "", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.232.165.11.4.2.1.2.1.6", NULL, SU_FLAG_OK, NULL }, /* pdu3TemperatureProbeStatus.1.1 = INTEGER: 2 */ { "unmapped.pdu3TemperatureProbeStatus", 0, 1, ".1.3.6.1.4.1.232.165.11.4.2.1.3.1.1", NULL, SU_FLAG_OK, NULL }, /* pdu3TemperatureProbeStatus.1.2 = INTEGER: 1 */ { "unmapped.pdu3TemperatureProbeStatus", 0, 1, ".1.3.6.1.4.1.232.165.11.4.2.1.3.1.2", NULL, SU_FLAG_OK, NULL }, /* = INTEGER: 1 */ { "unmapped. = INTEGER: 1", 0, 1, ".1.3.6.1.4.1.232.165.11.4.2.1.3.1.3", NULL, SU_FLAG_OK, NULL }, /* = INTEGER: 1 */ { "unmapped. = INTEGER: 1", 0, 1, ".1.3.6.1.4.1.232.165.11.4.2.1.3.1.4", NULL, SU_FLAG_OK, NULL }, /* = INTEGER: 1 */ { "unmapped. = INTEGER: 1", 0, 1, ".1.3.6.1.4.1.232.165.11.4.2.1.3.1.5", NULL, SU_FLAG_OK, NULL }, /* = INTEGER: 1 */ { "unmapped. = INTEGER: 1", 0, 1, ".1.3.6.1.4.1.232.165.11.4.2.1.3.1.6", NULL, SU_FLAG_OK, NULL }, /* pdu3TemperatureValue.1.1 = INTEGER: 27 */ { "unmapped.pdu3TemperatureValue", 0, 1, ".1.3.6.1.4.1.232.165.11.4.2.1.4.1.1", NULL, SU_FLAG_OK, NULL }, /* pdu3TemperatureValue.1.2 = INTEGER: 0 */ { "unmapped.pdu3TemperatureValue", 0, 1, ".1.3.6.1.4.1.232.165.11.4.2.1.4.1.2", NULL, SU_FLAG_OK, NULL }, /* = INTEGER: 0 */ { "unmapped. = INTEGER: 0", 0, 1, ".1.3.6.1.4.1.232.165.11.4.2.1.4.1.3", NULL, SU_FLAG_OK, NULL }, /* = INTEGER: 0 */ { "unmapped. = INTEGER: 0", 0, 1, ".1.3.6.1.4.1.232.165.11.4.2.1.4.1.4", NULL, SU_FLAG_OK, NULL }, /* = INTEGER: 0 */ { "unmapped. = INTEGER: 0", 0, 1, ".1.3.6.1.4.1.232.165.11.4.2.1.4.1.5", NULL, SU_FLAG_OK, NULL }, /* = INTEGER: 0 */ { "unmapped. = INTEGER: 0", 0, 1, ".1.3.6.1.4.1.232.165.11.4.2.1.4.1.6", NULL, SU_FLAG_OK, NULL }, /* pdu3TemperatureThStatus.1.1 = INTEGER: 1 */ { "unmapped.pdu3TemperatureThStatus", 0, 1, ".1.3.6.1.4.1.232.165.11.4.2.1.5.1.1", NULL, SU_FLAG_OK, NULL }, /* pdu3TemperatureThStatus.1.2 = INTEGER: 0 */ { "unmapped.pdu3TemperatureThStatus", 0, 1, ".1.3.6.1.4.1.232.165.11.4.2.1.5.1.2", NULL, SU_FLAG_OK, NULL }, /* = INTEGER: 0 */ { "unmapped. = INTEGER: 0", 0, 1, ".1.3.6.1.4.1.232.165.11.4.2.1.5.1.3", NULL, SU_FLAG_OK, NULL }, /* = INTEGER: 0 */ { "unmapped. = INTEGER: 0", 0, 1, ".1.3.6.1.4.1.232.165.11.4.2.1.5.1.4", NULL, SU_FLAG_OK, NULL }, /* = INTEGER: 0 */ { "unmapped. = INTEGER: 0", 0, 1, ".1.3.6.1.4.1.232.165.11.4.2.1.5.1.5", NULL, SU_FLAG_OK, NULL }, /* = INTEGER: 0 */ { "unmapped. = INTEGER: 0", 0, 1, ".1.3.6.1.4.1.232.165.11.4.2.1.5.1.6", NULL, SU_FLAG_OK, NULL }, /* pdu3TemperatureThLowerWarning.1.1 = INTEGER: 15 */ { "unmapped.pdu3TemperatureThLowerWarning", 0, 1, ".1.3.6.1.4.1.232.165.11.4.2.1.6.1.1", NULL, SU_FLAG_OK, NULL }, /* pdu3TemperatureThLowerWarning.1.2 = INTEGER: 0 */ { "unmapped.pdu3TemperatureThLowerWarning", 0, 1, ".1.3.6.1.4.1.232.165.11.4.2.1.6.1.2", NULL, SU_FLAG_OK, NULL }, /* = INTEGER: 0 */ { "unmapped. = INTEGER: 0", 0, 1, ".1.3.6.1.4.1.232.165.11.4.2.1.6.1.3", NULL, SU_FLAG_OK, NULL }, /* = INTEGER: 0 */ { "unmapped. = INTEGER: 0", 0, 1, ".1.3.6.1.4.1.232.165.11.4.2.1.6.1.4", NULL, SU_FLAG_OK, NULL }, /* = INTEGER: 0 */ { "unmapped. = INTEGER: 0", 0, 1, ".1.3.6.1.4.1.232.165.11.4.2.1.6.1.5", NULL, SU_FLAG_OK, NULL }, /* = INTEGER: 0 */ { "unmapped. = INTEGER: 0", 0, 1, ".1.3.6.1.4.1.232.165.11.4.2.1.6.1.6", NULL, SU_FLAG_OK, NULL }, /* pdu3TemperatureThLowerCritical.1.1 = INTEGER: 10 */ { "unmapped.pdu3TemperatureThLowerCritical", 0, 1, ".1.3.6.1.4.1.232.165.11.4.2.1.7.1.1", NULL, SU_FLAG_OK, NULL }, /* pdu3TemperatureThLowerCritical.1.2 = INTEGER: 0 */ { "unmapped.pdu3TemperatureThLowerCritical", 0, 1, ".1.3.6.1.4.1.232.165.11.4.2.1.7.1.2", NULL, SU_FLAG_OK, NULL }, /* = INTEGER: 0 */ { "unmapped. = INTEGER: 0", 0, 1, ".1.3.6.1.4.1.232.165.11.4.2.1.7.1.3", NULL, SU_FLAG_OK, NULL }, /* = INTEGER: 0 */ { "unmapped. = INTEGER: 0", 0, 1, ".1.3.6.1.4.1.232.165.11.4.2.1.7.1.4", NULL, SU_FLAG_OK, NULL }, /* = INTEGER: 0 */ { "unmapped. = INTEGER: 0", 0, 1, ".1.3.6.1.4.1.232.165.11.4.2.1.7.1.5", NULL, SU_FLAG_OK, NULL }, /* = INTEGER: 0 */ { "unmapped. = INTEGER: 0", 0, 1, ".1.3.6.1.4.1.232.165.11.4.2.1.7.1.6", NULL, SU_FLAG_OK, NULL }, /* pdu3TemperatureThUpperWarning.1.1 = INTEGER: 30 */ { "unmapped.pdu3TemperatureThUpperWarning", 0, 1, ".1.3.6.1.4.1.232.165.11.4.2.1.8.1.1", NULL, SU_FLAG_OK, NULL }, /* pdu3TemperatureThUpperWarning.1.2 = INTEGER: 0 */ { "unmapped.pdu3TemperatureThUpperWarning", 0, 1, ".1.3.6.1.4.1.232.165.11.4.2.1.8.1.2", NULL, SU_FLAG_OK, NULL }, /* = INTEGER: 0 */ { "unmapped. = INTEGER: 0", 0, 1, ".1.3.6.1.4.1.232.165.11.4.2.1.8.1.3", NULL, SU_FLAG_OK, NULL }, /* = INTEGER: 0 */ { "unmapped. = INTEGER: 0", 0, 1, ".1.3.6.1.4.1.232.165.11.4.2.1.8.1.4", NULL, SU_FLAG_OK, NULL }, /* = INTEGER: 0 */ { "unmapped. = INTEGER: 0", 0, 1, ".1.3.6.1.4.1.232.165.11.4.2.1.8.1.5", NULL, SU_FLAG_OK, NULL }, /* = INTEGER: 0 */ { "unmapped. = INTEGER: 0", 0, 1, ".1.3.6.1.4.1.232.165.11.4.2.1.8.1.6", NULL, SU_FLAG_OK, NULL }, /* pdu3TemperatureThUpperCritical.1.1 = INTEGER: 35 */ { "unmapped.pdu3TemperatureThUpperCritical", 0, 1, ".1.3.6.1.4.1.232.165.11.4.2.1.9.1.1", NULL, SU_FLAG_OK, NULL }, /* pdu3TemperatureThUpperCritical.1.2 = INTEGER: 0 */ { "unmapped.pdu3TemperatureThUpperCritical", 0, 1, ".1.3.6.1.4.1.232.165.11.4.2.1.9.1.2", NULL, SU_FLAG_OK, NULL }, /* = INTEGER: 0 */ { "unmapped. = INTEGER: 0", 0, 1, ".1.3.6.1.4.1.232.165.11.4.2.1.9.1.3", NULL, SU_FLAG_OK, NULL }, /* = INTEGER: 0 */ { "unmapped. = INTEGER: 0", 0, 1, ".1.3.6.1.4.1.232.165.11.4.2.1.9.1.4", NULL, SU_FLAG_OK, NULL }, /* = INTEGER: 0 */ { "unmapped. = INTEGER: 0", 0, 1, ".1.3.6.1.4.1.232.165.11.4.2.1.9.1.5", NULL, SU_FLAG_OK, NULL }, /* = INTEGER: 0 */ { "unmapped. = INTEGER: 0", 0, 1, ".1.3.6.1.4.1.232.165.11.4.2.1.9.1.6", NULL, SU_FLAG_OK, NULL }, /* pdu3HumidityIndex.1.1 = INTEGER: 2 */ { "unmapped.pdu3HumidityIndex", 0, 1, ".1.3.6.1.4.1.232.165.11.4.3.1.1.1.1", NULL, SU_FLAG_OK, NULL }, /* pdu3HumidityIndex.1.2 = INTEGER: 0 */ { "unmapped.pdu3HumidityIndex", 0, 1, ".1.3.6.1.4.1.232.165.11.4.3.1.1.1.2", NULL, SU_FLAG_OK, NULL }, /* = INTEGER: 0 */ { "unmapped. = INTEGER: 0", 0, 1, ".1.3.6.1.4.1.232.165.11.4.3.1.1.1.3", NULL, SU_FLAG_OK, NULL }, /* = INTEGER: 0 */ { "unmapped. = INTEGER: 0", 0, 1, ".1.3.6.1.4.1.232.165.11.4.3.1.1.1.4", NULL, SU_FLAG_OK, NULL }, /* = INTEGER: 0 */ { "unmapped. = INTEGER: 0", 0, 1, ".1.3.6.1.4.1.232.165.11.4.3.1.1.1.5", NULL, SU_FLAG_OK, NULL }, /* = INTEGER: 0 */ { "unmapped. = INTEGER: 0", 0, 1, ".1.3.6.1.4.1.232.165.11.4.3.1.1.1.6", NULL, SU_FLAG_OK, NULL }, /* pdu3HumidityName.1.1 = STRING: "RH" */ { "unmapped.pdu3HumidityName", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.232.165.11.4.3.1.2.1.1", NULL, SU_FLAG_OK, NULL }, /* pdu3HumidityName.1.2 = STRING: " " */ { "unmapped.pdu3HumidityName", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.232.165.11.4.3.1.2.1.2", NULL, SU_FLAG_OK, NULL }, //FIXME: missing sub MIB for ambient sensor? /* = STRING: " " */ { "unmapped. = STRING: " "", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.232.165.11.4.3.1.2.1.3", NULL, SU_FLAG_OK, NULL }, /* = STRING: " " */ { "unmapped. = STRING: " "", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.232.165.11.4.3.1.2.1.4", NULL, SU_FLAG_OK, NULL }, /* = STRING: " " */ { "unmapped. = STRING: " "", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.232.165.11.4.3.1.2.1.5", NULL, SU_FLAG_OK, NULL }, /* = STRING: " " */ { "unmapped. = STRING: " "", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.232.165.11.4.3.1.2.1.6", NULL, SU_FLAG_OK, NULL }, /* pdu3HumidityProbeStatus.1.1 = INTEGER: 2 */ { "unmapped.pdu3HumidityProbeStatus", 0, 1, ".1.3.6.1.4.1.232.165.11.4.3.1.3.1.1", NULL, SU_FLAG_OK, NULL }, /* pdu3HumidityProbeStatus.1.2 = INTEGER: 1 */ { "unmapped.pdu3HumidityProbeStatus", 0, 1, ".1.3.6.1.4.1.232.165.11.4.3.1.3.1.2", NULL, SU_FLAG_OK, NULL }, /* = INTEGER: 1 */ { "unmapped. = INTEGER: 1", 0, 1, ".1.3.6.1.4.1.232.165.11.4.3.1.3.1.3", NULL, SU_FLAG_OK, NULL }, /* = INTEGER: 1 */ { "unmapped. = INTEGER: 1", 0, 1, ".1.3.6.1.4.1.232.165.11.4.3.1.3.1.4", NULL, SU_FLAG_OK, NULL }, /* = INTEGER: 1 */ { "unmapped. = INTEGER: 1", 0, 1, ".1.3.6.1.4.1.232.165.11.4.3.1.3.1.5", NULL, SU_FLAG_OK, NULL }, /* = INTEGER: 1 */ { "unmapped. = INTEGER: 1", 0, 1, ".1.3.6.1.4.1.232.165.11.4.3.1.3.1.6", NULL, SU_FLAG_OK, NULL }, /* pdu3HumidityValue.1.1 = INTEGER: 27 */ { "unmapped.pdu3HumidityValue", 0, 1, ".1.3.6.1.4.1.232.165.11.4.3.1.4.1.1", NULL, SU_FLAG_OK, NULL }, /* pdu3HumidityValue.1.2 = INTEGER: 0 */ { "unmapped.pdu3HumidityValue", 0, 1, ".1.3.6.1.4.1.232.165.11.4.3.1.4.1.2", NULL, SU_FLAG_OK, NULL }, /* = INTEGER: 0 */ { "unmapped. = INTEGER: 0", 0, 1, ".1.3.6.1.4.1.232.165.11.4.3.1.4.1.3", NULL, SU_FLAG_OK, NULL }, /* = INTEGER: 0 */ { "unmapped. = INTEGER: 0", 0, 1, ".1.3.6.1.4.1.232.165.11.4.3.1.4.1.4", NULL, SU_FLAG_OK, NULL }, /* = INTEGER: 0 */ { "unmapped. = INTEGER: 0", 0, 1, ".1.3.6.1.4.1.232.165.11.4.3.1.4.1.5", NULL, SU_FLAG_OK, NULL }, /* = INTEGER: 0 */ { "unmapped. = INTEGER: 0", 0, 1, ".1.3.6.1.4.1.232.165.11.4.3.1.4.1.6", NULL, SU_FLAG_OK, NULL }, /* pdu3HumidityThStatus.1.1 = INTEGER: 2 */ { "unmapped.pdu3HumidityThStatus", 0, 1, ".1.3.6.1.4.1.232.165.11.4.3.1.5.1.1", NULL, SU_FLAG_OK, NULL }, /* pdu3HumidityThStatus.1.2 = INTEGER: 0 */ { "unmapped.pdu3HumidityThStatus", 0, 1, ".1.3.6.1.4.1.232.165.11.4.3.1.5.1.2", NULL, SU_FLAG_OK, NULL }, /* = INTEGER: 0 */ { "unmapped. = INTEGER: 0", 0, 1, ".1.3.6.1.4.1.232.165.11.4.3.1.5.1.3", NULL, SU_FLAG_OK, NULL }, /* = INTEGER: 0 */ { "unmapped. = INTEGER: 0", 0, 1, ".1.3.6.1.4.1.232.165.11.4.3.1.5.1.4", NULL, SU_FLAG_OK, NULL }, /* = INTEGER: 0 */ { "unmapped. = INTEGER: 0", 0, 1, ".1.3.6.1.4.1.232.165.11.4.3.1.5.1.5", NULL, SU_FLAG_OK, NULL }, /* = INTEGER: 0 */ { "unmapped. = INTEGER: 0", 0, 1, ".1.3.6.1.4.1.232.165.11.4.3.1.5.1.6", NULL, SU_FLAG_OK, NULL }, /* pdu3HumidityThLowerWarning.1.1 = INTEGER: 30 */ { "unmapped.pdu3HumidityThLowerWarning", 0, 1, ".1.3.6.1.4.1.232.165.11.4.3.1.6.1.1", NULL, SU_FLAG_OK, NULL }, /* pdu3HumidityThLowerWarning.1.2 = INTEGER: 0 */ { "unmapped.pdu3HumidityThLowerWarning", 0, 1, ".1.3.6.1.4.1.232.165.11.4.3.1.6.1.2", NULL, SU_FLAG_OK, NULL }, /* = INTEGER: 0 */ { "unmapped. = INTEGER: 0", 0, 1, ".1.3.6.1.4.1.232.165.11.4.3.1.6.1.3", NULL, SU_FLAG_OK, NULL }, /* = INTEGER: 0 */ { "unmapped. = INTEGER: 0", 0, 1, ".1.3.6.1.4.1.232.165.11.4.3.1.6.1.4", NULL, SU_FLAG_OK, NULL }, /* = INTEGER: 0 */ { "unmapped. = INTEGER: 0", 0, 1, ".1.3.6.1.4.1.232.165.11.4.3.1.6.1.5", NULL, SU_FLAG_OK, NULL }, /* = INTEGER: 0 */ { "unmapped. = INTEGER: 0", 0, 1, ".1.3.6.1.4.1.232.165.11.4.3.1.6.1.6", NULL, SU_FLAG_OK, NULL }, /* pdu3HumidityThLowerCritical.1.1 = INTEGER: 10 */ { "unmapped.pdu3HumidityThLowerCritical", 0, 1, ".1.3.6.1.4.1.232.165.11.4.3.1.7.1.1", NULL, SU_FLAG_OK, NULL }, /* pdu3HumidityThLowerCritical.1.2 = INTEGER: 0 */ { "unmapped.pdu3HumidityThLowerCritical", 0, 1, ".1.3.6.1.4.1.232.165.11.4.3.1.7.1.2", NULL, SU_FLAG_OK, NULL }, /* = INTEGER: 0 */ { "unmapped. = INTEGER: 0", 0, 1, ".1.3.6.1.4.1.232.165.11.4.3.1.7.1.3", NULL, SU_FLAG_OK, NULL }, /* = INTEGER: 0 */ { "unmapped. = INTEGER: 0", 0, 1, ".1.3.6.1.4.1.232.165.11.4.3.1.7.1.4", NULL, SU_FLAG_OK, NULL }, /* = INTEGER: 0 */ { "unmapped. = INTEGER: 0", 0, 1, ".1.3.6.1.4.1.232.165.11.4.3.1.7.1.5", NULL, SU_FLAG_OK, NULL }, /* = INTEGER: 0 */ { "unmapped. = INTEGER: 0", 0, 1, ".1.3.6.1.4.1.232.165.11.4.3.1.7.1.6", NULL, SU_FLAG_OK, NULL }, /* pdu3HumidityThUpperWarning.1.1 = INTEGER: 60 */ { "unmapped.pdu3HumidityThUpperWarning", 0, 1, ".1.3.6.1.4.1.232.165.11.4.3.1.8.1.1", NULL, SU_FLAG_OK, NULL }, /* pdu3HumidityThUpperWarning.1.2 = INTEGER: 0 */ { "unmapped.pdu3HumidityThUpperWarning", 0, 1, ".1.3.6.1.4.1.232.165.11.4.3.1.8.1.2", NULL, SU_FLAG_OK, NULL }, /* = INTEGER: 0 */ { "unmapped. = INTEGER: 0", 0, 1, ".1.3.6.1.4.1.232.165.11.4.3.1.8.1.3", NULL, SU_FLAG_OK, NULL }, /* = INTEGER: 0 */ { "unmapped. = INTEGER: 0", 0, 1, ".1.3.6.1.4.1.232.165.11.4.3.1.8.1.4", NULL, SU_FLAG_OK, NULL }, /* = INTEGER: 0 */ { "unmapped. = INTEGER: 0", 0, 1, ".1.3.6.1.4.1.232.165.11.4.3.1.8.1.5", NULL, SU_FLAG_OK, NULL }, /* = INTEGER: 0 */ { "unmapped. = INTEGER: 0", 0, 1, ".1.3.6.1.4.1.232.165.11.4.3.1.8.1.6", NULL, SU_FLAG_OK, NULL }, /* pdu3HumidityThUpperCritical.1.1 = INTEGER: 80 */ { "unmapped.pdu3HumidityThUpperCritical", 0, 1, ".1.3.6.1.4.1.232.165.11.4.3.1.9.1.1", NULL, SU_FLAG_OK, NULL }, /* pdu3HumidityThUpperCritical.1.2 = INTEGER: 0 */ { "unmapped.pdu3HumidityThUpperCritical", 0, 1, ".1.3.6.1.4.1.232.165.11.4.3.1.9.1.2", NULL, SU_FLAG_OK, NULL }, /* = INTEGER: 0 */ { "unmapped. = INTEGER: 0", 0, 1, ".1.3.6.1.4.1.232.165.11.4.3.1.9.1.3", NULL, SU_FLAG_OK, NULL }, /* = INTEGER: 0 */ { "unmapped. = INTEGER: 0", 0, 1, ".1.3.6.1.4.1.232.165.11.4.3.1.9.1.4", NULL, SU_FLAG_OK, NULL }, /* = INTEGER: 0 */ { "unmapped. = INTEGER: 0", 0, 1, ".1.3.6.1.4.1.232.165.11.4.3.1.9.1.5", NULL, SU_FLAG_OK, NULL }, /* = INTEGER: 0 */ { "unmapped. = INTEGER: 0", 0, 1, ".1.3.6.1.4.1.232.165.11.4.3.1.9.1.6", NULL, SU_FLAG_OK, NULL }, /* pdu3ContactIndex.1.1 = INTEGER: 0 */ { "unmapped.pdu3ContactIndex", 0, 1, ".1.3.6.1.4.1.232.165.11.4.4.1.1.1.1", NULL, SU_FLAG_OK, NULL }, /* pdu3ContactIndex.1.2 = INTEGER: 0 */ { "unmapped.pdu3ContactIndex", 0, 1, ".1.3.6.1.4.1.232.165.11.4.4.1.1.1.2", NULL, SU_FLAG_OK, NULL }, /* pdu3ContactName.1.1 = STRING: " " */ { "unmapped.pdu3ContactName", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.232.165.11.4.4.1.2.1.1", NULL, SU_FLAG_OK, NULL }, /* pdu3ContactName.1.2 = STRING: " " */ { "unmapped.pdu3ContactName", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.232.165.11.4.4.1.2.1.2", NULL, SU_FLAG_OK, NULL }, /* pdu3ContactProbeStatus.1.1 = INTEGER: 1 */ { "unmapped.pdu3ContactProbeStatus", 0, 1, ".1.3.6.1.4.1.232.165.11.4.4.1.3.1.1", NULL, SU_FLAG_OK, NULL }, /* pdu3ContactProbeStatus.1.2 = INTEGER: 1 */ { "unmapped.pdu3ContactProbeStatus", 0, 1, ".1.3.6.1.4.1.232.165.11.4.4.1.3.1.2", NULL, SU_FLAG_OK, NULL }, /* pdu3ContactState.1.1 = INTEGER: 0 */ { "unmapped.pdu3ContactState", 0, 1, ".1.3.6.1.4.1.232.165.11.4.4.1.4.1.1", NULL, SU_FLAG_OK, NULL }, /* pdu3ContactState.1.2 = INTEGER: 0 */ { "unmapped.pdu3ContactState", 0, 1, ".1.3.6.1.4.1.232.165.11.4.4.1.4.1.2", NULL, SU_FLAG_OK, NULL }, /* pdu3OutletIndex.1.1 = INTEGER: 1 */ { "unmapped.pdu3OutletIndex", 0, 1, ".1.3.6.1.4.1.232.165.11.5.1.1.1.1.1", NULL, SU_FLAG_OK, NULL }, /* pdu3OutletIndex.1.2 = INTEGER: 2 */ { "unmapped.pdu3OutletIndex", 0, 1, ".1.3.6.1.4.1.232.165.11.5.1.1.1.1.2", NULL, SU_FLAG_OK, NULL }, /* pdu3OutletIndex.1.3 = INTEGER: 3 */ { "unmapped.pdu3OutletIndex", 0, 1, ".1.3.6.1.4.1.232.165.11.5.1.1.1.1.3", NULL, SU_FLAG_OK, NULL }, /* pdu3OutletIndex.1.4 = INTEGER: 4 */ { "unmapped.pdu3OutletIndex", 0, 1, ".1.3.6.1.4.1.232.165.11.5.1.1.1.1.4", NULL, SU_FLAG_OK, NULL }, /* pdu3OutletIndex.1.5 = INTEGER: 5 */ { "unmapped.pdu3OutletIndex", 0, 1, ".1.3.6.1.4.1.232.165.11.5.1.1.1.1.5", NULL, SU_FLAG_OK, NULL }, /* pdu3OutletIndex.1.6 = INTEGER: 6 */ { "unmapped.pdu3OutletIndex", 0, 1, ".1.3.6.1.4.1.232.165.11.5.1.1.1.1.6", NULL, SU_FLAG_OK, NULL }, /* pdu3OutletIndex.1.7 = INTEGER: 7 */ { "unmapped.pdu3OutletIndex", 0, 1, ".1.3.6.1.4.1.232.165.11.5.1.1.1.1.7", NULL, SU_FLAG_OK, NULL }, /* pdu3OutletIndex.1.8 = INTEGER: 8 */ { "unmapped.pdu3OutletIndex", 0, 1, ".1.3.6.1.4.1.232.165.11.5.1.1.1.1.8", NULL, SU_FLAG_OK, NULL }, /* pdu3OutletIndex.1.9 = INTEGER: 9 */ { "unmapped.pdu3OutletIndex", 0, 1, ".1.3.6.1.4.1.232.165.11.5.1.1.1.1.9", NULL, SU_FLAG_OK, NULL }, /* pdu3OutletIndex.1.10 = INTEGER: 10 */ { "unmapped.pdu3OutletIndex", 0, 1, ".1.3.6.1.4.1.232.165.11.5.1.1.1.1.10", NULL, SU_FLAG_OK, NULL }, /* pdu3OutletIndex.1.11 = INTEGER: 11 */ { "unmapped.pdu3OutletIndex", 0, 1, ".1.3.6.1.4.1.232.165.11.5.1.1.1.1.11", NULL, SU_FLAG_OK, NULL }, /* pdu3OutletIndex.1.12 = INTEGER: 12 */ { "unmapped.pdu3OutletIndex", 0, 1, ".1.3.6.1.4.1.232.165.11.5.1.1.1.1.12", NULL, SU_FLAG_OK, NULL }, /* pdu3OutletIndex.1.13 = INTEGER: 13 */ { "unmapped.pdu3OutletIndex", 0, 1, ".1.3.6.1.4.1.232.165.11.5.1.1.1.1.13", NULL, SU_FLAG_OK, NULL }, /* pdu3OutletIndex.1.14 = INTEGER: 14 */ { "unmapped.pdu3OutletIndex", 0, 1, ".1.3.6.1.4.1.232.165.11.5.1.1.1.1.14", NULL, SU_FLAG_OK, NULL }, /* pdu3OutletIndex.1.15 = INTEGER: 15 */ { "unmapped.pdu3OutletIndex", 0, 1, ".1.3.6.1.4.1.232.165.11.5.1.1.1.1.15", NULL, SU_FLAG_OK, NULL }, /* pdu3OutletIndex.1.16 = INTEGER: 16 */ { "unmapped.pdu3OutletIndex", 0, 1, ".1.3.6.1.4.1.232.165.11.5.1.1.1.1.16", NULL, SU_FLAG_OK, NULL }, /* pdu3OutletIndex.1.17 = INTEGER: 17 */ { "unmapped.pdu3OutletIndex", 0, 1, ".1.3.6.1.4.1.232.165.11.5.1.1.1.1.17", NULL, SU_FLAG_OK, NULL }, /* pdu3OutletIndex.1.18 = INTEGER: 18 */ { "unmapped.pdu3OutletIndex", 0, 1, ".1.3.6.1.4.1.232.165.11.5.1.1.1.1.18", NULL, SU_FLAG_OK, NULL }, /* pdu3OutletIndex.1.19 = INTEGER: 19 */ { "unmapped.pdu3OutletIndex", 0, 1, ".1.3.6.1.4.1.232.165.11.5.1.1.1.1.19", NULL, SU_FLAG_OK, NULL }, /* pdu3OutletIndex.1.20 = INTEGER: 20 */ { "unmapped.pdu3OutletIndex", 0, 1, ".1.3.6.1.4.1.232.165.11.5.1.1.1.1.20", NULL, SU_FLAG_OK, NULL }, /* pdu3OutletIndex.1.21 = INTEGER: 21 */ { "unmapped.pdu3OutletIndex", 0, 1, ".1.3.6.1.4.1.232.165.11.5.1.1.1.1.21", NULL, SU_FLAG_OK, NULL }, /* pdu3OutletIndex.1.22 = INTEGER: 22 */ { "unmapped.pdu3OutletIndex", 0, 1, ".1.3.6.1.4.1.232.165.11.5.1.1.1.1.22", NULL, SU_FLAG_OK, NULL }, /* pdu3OutletIndex.1.23 = INTEGER: 23 */ { "unmapped.pdu3OutletIndex", 0, 1, ".1.3.6.1.4.1.232.165.11.5.1.1.1.1.23", NULL, SU_FLAG_OK, NULL }, /* pdu3OutletIndex.1.24 = INTEGER: 24 */ { "unmapped.pdu3OutletIndex", 0, 1, ".1.3.6.1.4.1.232.165.11.5.1.1.1.1.24", NULL, SU_FLAG_OK, NULL }, /* pdu3OutletIndex.1.25 = INTEGER: 0 */ { "unmapped.pdu3OutletIndex", 0, 1, ".1.3.6.1.4.1.232.165.11.5.1.1.1.1.25", NULL, SU_FLAG_OK, NULL }, /* pdu3OutletIndex.1.26 = INTEGER: 0 */ { "unmapped.pdu3OutletIndex", 0, 1, ".1.3.6.1.4.1.232.165.11.5.1.1.1.1.26", NULL, SU_FLAG_OK, NULL }, /* pdu3OutletIndex.1.27 = INTEGER: 0 */ { "unmapped.pdu3OutletIndex", 0, 1, ".1.3.6.1.4.1.232.165.11.5.1.1.1.1.27", NULL, SU_FLAG_OK, NULL }, /* pdu3OutletIndex.1.28 = INTEGER: 0 */ { "unmapped.pdu3OutletIndex", 0, 1, ".1.3.6.1.4.1.232.165.11.5.1.1.1.1.28", NULL, SU_FLAG_OK, NULL }, /* pdu3OutletIndex.1.29 = INTEGER: 0 */ { "unmapped.pdu3OutletIndex", 0, 1, ".1.3.6.1.4.1.232.165.11.5.1.1.1.1.29", NULL, SU_FLAG_OK, NULL }, /* pdu3OutletIndex.1.30 = INTEGER: 0 */ { "unmapped.pdu3OutletIndex", 0, 1, ".1.3.6.1.4.1.232.165.11.5.1.1.1.1.30", NULL, SU_FLAG_OK, NULL }, /* pdu3OutletIndex.1.31 = INTEGER: 0 */ { "unmapped.pdu3OutletIndex", 0, 1, ".1.3.6.1.4.1.232.165.11.5.1.1.1.1.31", NULL, SU_FLAG_OK, NULL }, /* pdu3OutletIndex.1.32 = INTEGER: 0 */ { "unmapped.pdu3OutletIndex", 0, 1, ".1.3.6.1.4.1.232.165.11.5.1.1.1.1.32", NULL, SU_FLAG_OK, NULL }, /* pdu3OutletIndex.1.33 = INTEGER: 0 */ { "unmapped.pdu3OutletIndex", 0, 1, ".1.3.6.1.4.1.232.165.11.5.1.1.1.1.33", NULL, SU_FLAG_OK, NULL }, /* pdu3OutletIndex.1.34 = INTEGER: 0 */ { "unmapped.pdu3OutletIndex", 0, 1, ".1.3.6.1.4.1.232.165.11.5.1.1.1.1.34", NULL, SU_FLAG_OK, NULL }, /* pdu3OutletIndex.1.35 = INTEGER: 0 */ { "unmapped.pdu3OutletIndex", 0, 1, ".1.3.6.1.4.1.232.165.11.5.1.1.1.1.35", NULL, SU_FLAG_OK, NULL }, /* pdu3OutletIndex.1.36 = INTEGER: 0 */ { "unmapped.pdu3OutletIndex", 0, 1, ".1.3.6.1.4.1.232.165.11.5.1.1.1.1.36", NULL, SU_FLAG_OK, NULL }, /* pdu3OutletIndex.1.37 = INTEGER: 0 */ { "unmapped.pdu3OutletIndex", 0, 1, ".1.3.6.1.4.1.232.165.11.5.1.1.1.1.37", NULL, SU_FLAG_OK, NULL }, /* pdu3OutletIndex.1.38 = INTEGER: 0 */ { "unmapped.pdu3OutletIndex", 0, 1, ".1.3.6.1.4.1.232.165.11.5.1.1.1.1.38", NULL, SU_FLAG_OK, NULL }, /* pdu3OutletIndex.1.39 = INTEGER: 0 */ { "unmapped.pdu3OutletIndex", 0, 1, ".1.3.6.1.4.1.232.165.11.5.1.1.1.1.39", NULL, SU_FLAG_OK, NULL }, /* pdu3OutletIndex.1.40 = INTEGER: 0 */ { "unmapped.pdu3OutletIndex", 0, 1, ".1.3.6.1.4.1.232.165.11.5.1.1.1.1.40", NULL, SU_FLAG_OK, NULL }, /* pdu3OutletIndex.1.41 = INTEGER: 0 */ { "unmapped.pdu3OutletIndex", 0, 1, ".1.3.6.1.4.1.232.165.11.5.1.1.1.1.41", NULL, SU_FLAG_OK, NULL }, /* pdu3OutletIndex.1.42 = INTEGER: 0 */ { "unmapped.pdu3OutletIndex", 0, 1, ".1.3.6.1.4.1.232.165.11.5.1.1.1.1.42", NULL, SU_FLAG_OK, NULL }, /* pdu3OutletIndex.1.43 = INTEGER: 0 */ { "unmapped.pdu3OutletIndex", 0, 1, ".1.3.6.1.4.1.232.165.11.5.1.1.1.1.43", NULL, SU_FLAG_OK, NULL }, /* pdu3OutletIndex.1.44 = INTEGER: 0 */ { "unmapped.pdu3OutletIndex", 0, 1, ".1.3.6.1.4.1.232.165.11.5.1.1.1.1.44", NULL, SU_FLAG_OK, NULL }, /* pdu3OutletIndex.1.45 = INTEGER: 0 */ { "unmapped.pdu3OutletIndex", 0, 1, ".1.3.6.1.4.1.232.165.11.5.1.1.1.1.45", NULL, SU_FLAG_OK, NULL }, /* pdu3OutletIndex.1.46 = INTEGER: 0 */ { "unmapped.pdu3OutletIndex", 0, 1, ".1.3.6.1.4.1.232.165.11.5.1.1.1.1.46", NULL, SU_FLAG_OK, NULL }, /* pdu3OutletIndex.1.47 = INTEGER: 0 */ { "unmapped.pdu3OutletIndex", 0, 1, ".1.3.6.1.4.1.232.165.11.5.1.1.1.1.47", NULL, SU_FLAG_OK, NULL }, /* pdu3OutletIndex.1.48 = INTEGER: 0 */ { "unmapped.pdu3OutletIndex", 0, 1, ".1.3.6.1.4.1.232.165.11.5.1.1.1.1.48", NULL, SU_FLAG_OK, NULL }, /* pdu3OutletActivePowerThStatus.1.1 = INTEGER: 1 */ { "unmapped.pdu3OutletActivePowerThStatus", 0, 1, ".1.3.6.1.4.1.232.165.11.5.1.1.6.1.1", NULL, SU_FLAG_OK, NULL }, /* pdu3OutletActivePowerThStatus.1.2 = INTEGER: 1 */ { "unmapped.pdu3OutletActivePowerThStatus", 0, 1, ".1.3.6.1.4.1.232.165.11.5.1.1.6.1.2", NULL, SU_FLAG_OK, NULL }, /* pdu3OutletActivePowerThStatus.1.3 = INTEGER: 1 */ { "unmapped.pdu3OutletActivePowerThStatus", 0, 1, ".1.3.6.1.4.1.232.165.11.5.1.1.6.1.3", NULL, SU_FLAG_OK, NULL }, /* pdu3OutletActivePowerThStatus.1.4 = INTEGER: 1 */ { "unmapped.pdu3OutletActivePowerThStatus", 0, 1, ".1.3.6.1.4.1.232.165.11.5.1.1.6.1.4", NULL, SU_FLAG_OK, NULL }, /* pdu3OutletActivePowerThStatus.1.5 = INTEGER: 1 */ { "unmapped.pdu3OutletActivePowerThStatus", 0, 1, ".1.3.6.1.4.1.232.165.11.5.1.1.6.1.5", NULL, SU_FLAG_OK, NULL }, /* pdu3OutletActivePowerThStatus.1.6 = INTEGER: 1 */ { "unmapped.pdu3OutletActivePowerThStatus", 0, 1, ".1.3.6.1.4.1.232.165.11.5.1.1.6.1.6", NULL, SU_FLAG_OK, NULL }, /* pdu3OutletActivePowerThStatus.1.7 = INTEGER: 1 */ { "unmapped.pdu3OutletActivePowerThStatus", 0, 1, ".1.3.6.1.4.1.232.165.11.5.1.1.6.1.7", NULL, SU_FLAG_OK, NULL }, /* pdu3OutletActivePowerThStatus.1.8 = INTEGER: 1 */ { "unmapped.pdu3OutletActivePowerThStatus", 0, 1, ".1.3.6.1.4.1.232.165.11.5.1.1.6.1.8", NULL, SU_FLAG_OK, NULL }, /* pdu3OutletActivePowerThStatus.1.9 = INTEGER: 1 */ { "unmapped.pdu3OutletActivePowerThStatus", 0, 1, ".1.3.6.1.4.1.232.165.11.5.1.1.6.1.9", NULL, SU_FLAG_OK, NULL }, /* pdu3OutletActivePowerThStatus.1.10 = INTEGER: 1 */ { "unmapped.pdu3OutletActivePowerThStatus", 0, 1, ".1.3.6.1.4.1.232.165.11.5.1.1.6.1.10", NULL, SU_FLAG_OK, NULL }, /* pdu3OutletActivePowerThStatus.1.11 = INTEGER: 1 */ { "unmapped.pdu3OutletActivePowerThStatus", 0, 1, ".1.3.6.1.4.1.232.165.11.5.1.1.6.1.11", NULL, SU_FLAG_OK, NULL }, /* pdu3OutletActivePowerThStatus.1.12 = INTEGER: 1 */ { "unmapped.pdu3OutletActivePowerThStatus", 0, 1, ".1.3.6.1.4.1.232.165.11.5.1.1.6.1.12", NULL, SU_FLAG_OK, NULL }, /* pdu3OutletActivePowerThStatus.1.13 = INTEGER: 1 */ { "unmapped.pdu3OutletActivePowerThStatus", 0, 1, ".1.3.6.1.4.1.232.165.11.5.1.1.6.1.13", NULL, SU_FLAG_OK, NULL }, /* pdu3OutletActivePowerThStatus.1.14 = INTEGER: 1 */ { "unmapped.pdu3OutletActivePowerThStatus", 0, 1, ".1.3.6.1.4.1.232.165.11.5.1.1.6.1.14", NULL, SU_FLAG_OK, NULL }, /* pdu3OutletActivePowerThStatus.1.15 = INTEGER: 1 */ { "unmapped.pdu3OutletActivePowerThStatus", 0, 1, ".1.3.6.1.4.1.232.165.11.5.1.1.6.1.15", NULL, SU_FLAG_OK, NULL }, /* pdu3OutletActivePowerThStatus.1.16 = INTEGER: 1 */ { "unmapped.pdu3OutletActivePowerThStatus", 0, 1, ".1.3.6.1.4.1.232.165.11.5.1.1.6.1.16", NULL, SU_FLAG_OK, NULL }, /* pdu3OutletActivePowerThStatus.1.17 = INTEGER: 1 */ { "unmapped.pdu3OutletActivePowerThStatus", 0, 1, ".1.3.6.1.4.1.232.165.11.5.1.1.6.1.17", NULL, SU_FLAG_OK, NULL }, /* pdu3OutletActivePowerThStatus.1.18 = INTEGER: 1 */ { "unmapped.pdu3OutletActivePowerThStatus", 0, 1, ".1.3.6.1.4.1.232.165.11.5.1.1.6.1.18", NULL, SU_FLAG_OK, NULL }, /* pdu3OutletActivePowerThStatus.1.19 = INTEGER: 1 */ { "unmapped.pdu3OutletActivePowerThStatus", 0, 1, ".1.3.6.1.4.1.232.165.11.5.1.1.6.1.19", NULL, SU_FLAG_OK, NULL }, /* pdu3OutletActivePowerThStatus.1.20 = INTEGER: 1 */ { "unmapped.pdu3OutletActivePowerThStatus", 0, 1, ".1.3.6.1.4.1.232.165.11.5.1.1.6.1.20", NULL, SU_FLAG_OK, NULL }, /* pdu3OutletActivePowerThStatus.1.21 = INTEGER: 1 */ { "unmapped.pdu3OutletActivePowerThStatus", 0, 1, ".1.3.6.1.4.1.232.165.11.5.1.1.6.1.21", NULL, SU_FLAG_OK, NULL }, /* pdu3OutletActivePowerThStatus.1.22 = INTEGER: 1 */ { "unmapped.pdu3OutletActivePowerThStatus", 0, 1, ".1.3.6.1.4.1.232.165.11.5.1.1.6.1.22", NULL, SU_FLAG_OK, NULL }, /* pdu3OutletActivePowerThStatus.1.23 = INTEGER: 1 */ { "unmapped.pdu3OutletActivePowerThStatus", 0, 1, ".1.3.6.1.4.1.232.165.11.5.1.1.6.1.23", NULL, SU_FLAG_OK, NULL }, /* pdu3OutletActivePowerThStatus.1.24 = INTEGER: 1 */ { "unmapped.pdu3OutletActivePowerThStatus", 0, 1, ".1.3.6.1.4.1.232.165.11.5.1.1.6.1.24", NULL, SU_FLAG_OK, NULL }, /* pdu3OutletActivePowerThStatus.1.25 = INTEGER: 0 */ { "unmapped.pdu3OutletActivePowerThStatus", 0, 1, ".1.3.6.1.4.1.232.165.11.5.1.1.6.1.25", NULL, SU_FLAG_OK, NULL }, /* pdu3OutletActivePowerThStatus.1.26 = INTEGER: 0 */ { "unmapped.pdu3OutletActivePowerThStatus", 0, 1, ".1.3.6.1.4.1.232.165.11.5.1.1.6.1.26", NULL, SU_FLAG_OK, NULL }, /* pdu3OutletActivePowerThStatus.1.27 = INTEGER: 0 */ { "unmapped.pdu3OutletActivePowerThStatus", 0, 1, ".1.3.6.1.4.1.232.165.11.5.1.1.6.1.27", NULL, SU_FLAG_OK, NULL }, /* pdu3OutletActivePowerThStatus.1.28 = INTEGER: 0 */ { "unmapped.pdu3OutletActivePowerThStatus", 0, 1, ".1.3.6.1.4.1.232.165.11.5.1.1.6.1.28", NULL, SU_FLAG_OK, NULL }, /* pdu3OutletActivePowerThStatus.1.29 = INTEGER: 0 */ { "unmapped.pdu3OutletActivePowerThStatus", 0, 1, ".1.3.6.1.4.1.232.165.11.5.1.1.6.1.29", NULL, SU_FLAG_OK, NULL }, /* pdu3OutletActivePowerThStatus.1.30 = INTEGER: 0 */ { "unmapped.pdu3OutletActivePowerThStatus", 0, 1, ".1.3.6.1.4.1.232.165.11.5.1.1.6.1.30", NULL, SU_FLAG_OK, NULL }, /* pdu3OutletActivePowerThStatus.1.31 = INTEGER: 0 */ { "unmapped.pdu3OutletActivePowerThStatus", 0, 1, ".1.3.6.1.4.1.232.165.11.5.1.1.6.1.31", NULL, SU_FLAG_OK, NULL }, /* pdu3OutletActivePowerThStatus.1.32 = INTEGER: 0 */ { "unmapped.pdu3OutletActivePowerThStatus", 0, 1, ".1.3.6.1.4.1.232.165.11.5.1.1.6.1.32", NULL, SU_FLAG_OK, NULL }, /* pdu3OutletActivePowerThStatus.1.33 = INTEGER: 0 */ { "unmapped.pdu3OutletActivePowerThStatus", 0, 1, ".1.3.6.1.4.1.232.165.11.5.1.1.6.1.33", NULL, SU_FLAG_OK, NULL }, /* pdu3OutletActivePowerThStatus.1.34 = INTEGER: 0 */ { "unmapped.pdu3OutletActivePowerThStatus", 0, 1, ".1.3.6.1.4.1.232.165.11.5.1.1.6.1.34", NULL, SU_FLAG_OK, NULL }, /* pdu3OutletActivePowerThStatus.1.35 = INTEGER: 0 */ { "unmapped.pdu3OutletActivePowerThStatus", 0, 1, ".1.3.6.1.4.1.232.165.11.5.1.1.6.1.35", NULL, SU_FLAG_OK, NULL }, /* pdu3OutletActivePowerThStatus.1.36 = INTEGER: 0 */ { "unmapped.pdu3OutletActivePowerThStatus", 0, 1, ".1.3.6.1.4.1.232.165.11.5.1.1.6.1.36", NULL, SU_FLAG_OK, NULL }, /* pdu3OutletActivePowerThStatus.1.37 = INTEGER: 0 */ { "unmapped.pdu3OutletActivePowerThStatus", 0, 1, ".1.3.6.1.4.1.232.165.11.5.1.1.6.1.37", NULL, SU_FLAG_OK, NULL }, /* pdu3OutletActivePowerThStatus.1.38 = INTEGER: 0 */ { "unmapped.pdu3OutletActivePowerThStatus", 0, 1, ".1.3.6.1.4.1.232.165.11.5.1.1.6.1.38", NULL, SU_FLAG_OK, NULL }, /* pdu3OutletActivePowerThStatus.1.39 = INTEGER: 0 */ { "unmapped.pdu3OutletActivePowerThStatus", 0, 1, ".1.3.6.1.4.1.232.165.11.5.1.1.6.1.39", NULL, SU_FLAG_OK, NULL }, /* pdu3OutletActivePowerThStatus.1.40 = INTEGER: 0 */ { "unmapped.pdu3OutletActivePowerThStatus", 0, 1, ".1.3.6.1.4.1.232.165.11.5.1.1.6.1.40", NULL, SU_FLAG_OK, NULL }, /* pdu3OutletActivePowerThStatus.1.41 = INTEGER: 0 */ { "unmapped.pdu3OutletActivePowerThStatus", 0, 1, ".1.3.6.1.4.1.232.165.11.5.1.1.6.1.41", NULL, SU_FLAG_OK, NULL }, /* pdu3OutletActivePowerThStatus.1.42 = INTEGER: 0 */ { "unmapped.pdu3OutletActivePowerThStatus", 0, 1, ".1.3.6.1.4.1.232.165.11.5.1.1.6.1.42", NULL, SU_FLAG_OK, NULL }, /* pdu3OutletActivePowerThStatus.1.43 = INTEGER: 0 */ { "unmapped.pdu3OutletActivePowerThStatus", 0, 1, ".1.3.6.1.4.1.232.165.11.5.1.1.6.1.43", NULL, SU_FLAG_OK, NULL }, /* pdu3OutletActivePowerThStatus.1.44 = INTEGER: 0 */ { "unmapped.pdu3OutletActivePowerThStatus", 0, 1, ".1.3.6.1.4.1.232.165.11.5.1.1.6.1.44", NULL, SU_FLAG_OK, NULL }, /* pdu3OutletActivePowerThStatus.1.45 = INTEGER: 0 */ { "unmapped.pdu3OutletActivePowerThStatus", 0, 1, ".1.3.6.1.4.1.232.165.11.5.1.1.6.1.45", NULL, SU_FLAG_OK, NULL }, /* pdu3OutletActivePowerThStatus.1.46 = INTEGER: 0 */ { "unmapped.pdu3OutletActivePowerThStatus", 0, 1, ".1.3.6.1.4.1.232.165.11.5.1.1.6.1.46", NULL, SU_FLAG_OK, NULL }, /* pdu3OutletActivePowerThStatus.1.47 = INTEGER: 0 */ { "unmapped.pdu3OutletActivePowerThStatus", 0, 1, ".1.3.6.1.4.1.232.165.11.5.1.1.6.1.47", NULL, SU_FLAG_OK, NULL }, /* pdu3OutletActivePowerThStatus.1.48 = INTEGER: 0 */ { "unmapped.pdu3OutletActivePowerThStatus", 0, 1, ".1.3.6.1.4.1.232.165.11.5.1.1.6.1.48", NULL, SU_FLAG_OK, NULL }, /* pdu3OutletActivePowerThLowerWarning.1.1 = INTEGER: 0 */ { "unmapped.pdu3OutletActivePowerThLowerWarning", 0, 1, ".1.3.6.1.4.1.232.165.11.5.1.1.7.1.1", NULL, SU_FLAG_OK, NULL }, /* pdu3OutletActivePowerThLowerWarning.1.2 = INTEGER: 0 */ { "unmapped.pdu3OutletActivePowerThLowerWarning", 0, 1, ".1.3.6.1.4.1.232.165.11.5.1.1.7.1.2", NULL, SU_FLAG_OK, NULL }, /* pdu3OutletActivePowerThLowerWarning.1.3 = INTEGER: 0 */ { "unmapped.pdu3OutletActivePowerThLowerWarning", 0, 1, ".1.3.6.1.4.1.232.165.11.5.1.1.7.1.3", NULL, SU_FLAG_OK, NULL }, /* pdu3OutletActivePowerThLowerWarning.1.4 = INTEGER: 0 */ { "unmapped.pdu3OutletActivePowerThLowerWarning", 0, 1, ".1.3.6.1.4.1.232.165.11.5.1.1.7.1.4", NULL, SU_FLAG_OK, NULL }, /* pdu3OutletActivePowerThLowerWarning.1.5 = INTEGER: 0 */ { "unmapped.pdu3OutletActivePowerThLowerWarning", 0, 1, ".1.3.6.1.4.1.232.165.11.5.1.1.7.1.5", NULL, SU_FLAG_OK, NULL }, /* pdu3OutletActivePowerThLowerWarning.1.6 = INTEGER: 0 */ { "unmapped.pdu3OutletActivePowerThLowerWarning", 0, 1, ".1.3.6.1.4.1.232.165.11.5.1.1.7.1.6", NULL, SU_FLAG_OK, NULL }, /* pdu3OutletActivePowerThLowerWarning.1.7 = INTEGER: 0 */ { "unmapped.pdu3OutletActivePowerThLowerWarning", 0, 1, ".1.3.6.1.4.1.232.165.11.5.1.1.7.1.7", NULL, SU_FLAG_OK, NULL }, /* pdu3OutletActivePowerThLowerWarning.1.8 = INTEGER: 0 */ { "unmapped.pdu3OutletActivePowerThLowerWarning", 0, 1, ".1.3.6.1.4.1.232.165.11.5.1.1.7.1.8", NULL, SU_FLAG_OK, NULL }, /* pdu3OutletActivePowerThLowerWarning.1.9 = INTEGER: 0 */ { "unmapped.pdu3OutletActivePowerThLowerWarning", 0, 1, ".1.3.6.1.4.1.232.165.11.5.1.1.7.1.9", NULL, SU_FLAG_OK, NULL }, /* pdu3OutletActivePowerThLowerWarning.1.10 = INTEGER: 0 */ { "unmapped.pdu3OutletActivePowerThLowerWarning", 0, 1, ".1.3.6.1.4.1.232.165.11.5.1.1.7.1.10", NULL, SU_FLAG_OK, NULL }, /* pdu3OutletActivePowerThLowerWarning.1.11 = INTEGER: 0 */ { "unmapped.pdu3OutletActivePowerThLowerWarning", 0, 1, ".1.3.6.1.4.1.232.165.11.5.1.1.7.1.11", NULL, SU_FLAG_OK, NULL }, /* pdu3OutletActivePowerThLowerWarning.1.12 = INTEGER: 0 */ { "unmapped.pdu3OutletActivePowerThLowerWarning", 0, 1, ".1.3.6.1.4.1.232.165.11.5.1.1.7.1.12", NULL, SU_FLAG_OK, NULL }, /* pdu3OutletActivePowerThLowerWarning.1.13 = INTEGER: 0 */ { "unmapped.pdu3OutletActivePowerThLowerWarning", 0, 1, ".1.3.6.1.4.1.232.165.11.5.1.1.7.1.13", NULL, SU_FLAG_OK, NULL }, /* pdu3OutletActivePowerThLowerWarning.1.14 = INTEGER: 0 */ { "unmapped.pdu3OutletActivePowerThLowerWarning", 0, 1, ".1.3.6.1.4.1.232.165.11.5.1.1.7.1.14", NULL, SU_FLAG_OK, NULL }, /* pdu3OutletActivePowerThLowerWarning.1.15 = INTEGER: 0 */ { "unmapped.pdu3OutletActivePowerThLowerWarning", 0, 1, ".1.3.6.1.4.1.232.165.11.5.1.1.7.1.15", NULL, SU_FLAG_OK, NULL }, /* pdu3OutletActivePowerThLowerWarning.1.16 = INTEGER: 0 */ { "unmapped.pdu3OutletActivePowerThLowerWarning", 0, 1, ".1.3.6.1.4.1.232.165.11.5.1.1.7.1.16", NULL, SU_FLAG_OK, NULL }, /* pdu3OutletActivePowerThLowerWarning.1.17 = INTEGER: 0 */ { "unmapped.pdu3OutletActivePowerThLowerWarning", 0, 1, ".1.3.6.1.4.1.232.165.11.5.1.1.7.1.17", NULL, SU_FLAG_OK, NULL }, /* pdu3OutletActivePowerThLowerWarning.1.18 = INTEGER: 0 */ { "unmapped.pdu3OutletActivePowerThLowerWarning", 0, 1, ".1.3.6.1.4.1.232.165.11.5.1.1.7.1.18", NULL, SU_FLAG_OK, NULL }, /* pdu3OutletActivePowerThLowerWarning.1.19 = INTEGER: 0 */ { "unmapped.pdu3OutletActivePowerThLowerWarning", 0, 1, ".1.3.6.1.4.1.232.165.11.5.1.1.7.1.19", NULL, SU_FLAG_OK, NULL }, /* pdu3OutletActivePowerThLowerWarning.1.20 = INTEGER: 0 */ { "unmapped.pdu3OutletActivePowerThLowerWarning", 0, 1, ".1.3.6.1.4.1.232.165.11.5.1.1.7.1.20", NULL, SU_FLAG_OK, NULL }, /* pdu3OutletActivePowerThLowerWarning.1.21 = INTEGER: 0 */ { "unmapped.pdu3OutletActivePowerThLowerWarning", 0, 1, ".1.3.6.1.4.1.232.165.11.5.1.1.7.1.21", NULL, SU_FLAG_OK, NULL }, /* pdu3OutletActivePowerThLowerWarning.1.22 = INTEGER: 0 */ { "unmapped.pdu3OutletActivePowerThLowerWarning", 0, 1, ".1.3.6.1.4.1.232.165.11.5.1.1.7.1.22", NULL, SU_FLAG_OK, NULL }, /* pdu3OutletActivePowerThLowerWarning.1.23 = INTEGER: 0 */ { "unmapped.pdu3OutletActivePowerThLowerWarning", 0, 1, ".1.3.6.1.4.1.232.165.11.5.1.1.7.1.23", NULL, SU_FLAG_OK, NULL }, /* pdu3OutletActivePowerThLowerWarning.1.24 = INTEGER: 0 */ { "unmapped.pdu3OutletActivePowerThLowerWarning", 0, 1, ".1.3.6.1.4.1.232.165.11.5.1.1.7.1.24", NULL, SU_FLAG_OK, NULL }, /* pdu3OutletActivePowerThLowerWarning.1.25 = INTEGER: 0 */ { "unmapped.pdu3OutletActivePowerThLowerWarning", 0, 1, ".1.3.6.1.4.1.232.165.11.5.1.1.7.1.25", NULL, SU_FLAG_OK, NULL }, /* pdu3OutletActivePowerThLowerWarning.1.26 = INTEGER: 0 */ { "unmapped.pdu3OutletActivePowerThLowerWarning", 0, 1, ".1.3.6.1.4.1.232.165.11.5.1.1.7.1.26", NULL, SU_FLAG_OK, NULL }, /* pdu3OutletActivePowerThLowerWarning.1.27 = INTEGER: 0 */ { "unmapped.pdu3OutletActivePowerThLowerWarning", 0, 1, ".1.3.6.1.4.1.232.165.11.5.1.1.7.1.27", NULL, SU_FLAG_OK, NULL }, /* pdu3OutletActivePowerThLowerWarning.1.28 = INTEGER: 0 */ { "unmapped.pdu3OutletActivePowerThLowerWarning", 0, 1, ".1.3.6.1.4.1.232.165.11.5.1.1.7.1.28", NULL, SU_FLAG_OK, NULL }, /* pdu3OutletActivePowerThLowerWarning.1.29 = INTEGER: 0 */ { "unmapped.pdu3OutletActivePowerThLowerWarning", 0, 1, ".1.3.6.1.4.1.232.165.11.5.1.1.7.1.29", NULL, SU_FLAG_OK, NULL }, /* pdu3OutletActivePowerThLowerWarning.1.30 = INTEGER: 0 */ { "unmapped.pdu3OutletActivePowerThLowerWarning", 0, 1, ".1.3.6.1.4.1.232.165.11.5.1.1.7.1.30", NULL, SU_FLAG_OK, NULL }, /* pdu3OutletActivePowerThLowerWarning.1.31 = INTEGER: 0 */ { "unmapped.pdu3OutletActivePowerThLowerWarning", 0, 1, ".1.3.6.1.4.1.232.165.11.5.1.1.7.1.31", NULL, SU_FLAG_OK, NULL }, /* pdu3OutletActivePowerThLowerWarning.1.32 = INTEGER: 0 */ { "unmapped.pdu3OutletActivePowerThLowerWarning", 0, 1, ".1.3.6.1.4.1.232.165.11.5.1.1.7.1.32", NULL, SU_FLAG_OK, NULL }, /* pdu3OutletActivePowerThLowerWarning.1.33 = INTEGER: 0 */ { "unmapped.pdu3OutletActivePowerThLowerWarning", 0, 1, ".1.3.6.1.4.1.232.165.11.5.1.1.7.1.33", NULL, SU_FLAG_OK, NULL }, /* pdu3OutletActivePowerThLowerWarning.1.34 = INTEGER: 0 */ { "unmapped.pdu3OutletActivePowerThLowerWarning", 0, 1, ".1.3.6.1.4.1.232.165.11.5.1.1.7.1.34", NULL, SU_FLAG_OK, NULL }, /* pdu3OutletActivePowerThLowerWarning.1.35 = INTEGER: 0 */ { "unmapped.pdu3OutletActivePowerThLowerWarning", 0, 1, ".1.3.6.1.4.1.232.165.11.5.1.1.7.1.35", NULL, SU_FLAG_OK, NULL }, /* pdu3OutletActivePowerThLowerWarning.1.36 = INTEGER: 0 */ { "unmapped.pdu3OutletActivePowerThLowerWarning", 0, 1, ".1.3.6.1.4.1.232.165.11.5.1.1.7.1.36", NULL, SU_FLAG_OK, NULL }, /* pdu3OutletActivePowerThLowerWarning.1.37 = INTEGER: 0 */ { "unmapped.pdu3OutletActivePowerThLowerWarning", 0, 1, ".1.3.6.1.4.1.232.165.11.5.1.1.7.1.37", NULL, SU_FLAG_OK, NULL }, /* pdu3OutletActivePowerThLowerWarning.1.38 = INTEGER: 0 */ { "unmapped.pdu3OutletActivePowerThLowerWarning", 0, 1, ".1.3.6.1.4.1.232.165.11.5.1.1.7.1.38", NULL, SU_FLAG_OK, NULL }, /* pdu3OutletActivePowerThLowerWarning.1.39 = INTEGER: 0 */ { "unmapped.pdu3OutletActivePowerThLowerWarning", 0, 1, ".1.3.6.1.4.1.232.165.11.5.1.1.7.1.39", NULL, SU_FLAG_OK, NULL }, /* pdu3OutletActivePowerThLowerWarning.1.40 = INTEGER: 0 */ { "unmapped.pdu3OutletActivePowerThLowerWarning", 0, 1, ".1.3.6.1.4.1.232.165.11.5.1.1.7.1.40", NULL, SU_FLAG_OK, NULL }, /* pdu3OutletActivePowerThLowerWarning.1.41 = INTEGER: 0 */ { "unmapped.pdu3OutletActivePowerThLowerWarning", 0, 1, ".1.3.6.1.4.1.232.165.11.5.1.1.7.1.41", NULL, SU_FLAG_OK, NULL }, /* pdu3OutletActivePowerThLowerWarning.1.42 = INTEGER: 0 */ { "unmapped.pdu3OutletActivePowerThLowerWarning", 0, 1, ".1.3.6.1.4.1.232.165.11.5.1.1.7.1.42", NULL, SU_FLAG_OK, NULL }, /* pdu3OutletActivePowerThLowerWarning.1.43 = INTEGER: 0 */ { "unmapped.pdu3OutletActivePowerThLowerWarning", 0, 1, ".1.3.6.1.4.1.232.165.11.5.1.1.7.1.43", NULL, SU_FLAG_OK, NULL }, /* pdu3OutletActivePowerThLowerWarning.1.44 = INTEGER: 0 */ { "unmapped.pdu3OutletActivePowerThLowerWarning", 0, 1, ".1.3.6.1.4.1.232.165.11.5.1.1.7.1.44", NULL, SU_FLAG_OK, NULL }, /* pdu3OutletActivePowerThLowerWarning.1.45 = INTEGER: 0 */ { "unmapped.pdu3OutletActivePowerThLowerWarning", 0, 1, ".1.3.6.1.4.1.232.165.11.5.1.1.7.1.45", NULL, SU_FLAG_OK, NULL }, /* pdu3OutletActivePowerThLowerWarning.1.46 = INTEGER: 0 */ { "unmapped.pdu3OutletActivePowerThLowerWarning", 0, 1, ".1.3.6.1.4.1.232.165.11.5.1.1.7.1.46", NULL, SU_FLAG_OK, NULL }, /* pdu3OutletActivePowerThLowerWarning.1.47 = INTEGER: 0 */ { "unmapped.pdu3OutletActivePowerThLowerWarning", 0, 1, ".1.3.6.1.4.1.232.165.11.5.1.1.7.1.47", NULL, SU_FLAG_OK, NULL }, /* pdu3OutletActivePowerThLowerWarning.1.48 = INTEGER: 0 */ { "unmapped.pdu3OutletActivePowerThLowerWarning", 0, 1, ".1.3.6.1.4.1.232.165.11.5.1.1.7.1.48", NULL, SU_FLAG_OK, NULL }, /* pdu3OutletActivePowerThLowerCritical.1.1 = INTEGER: 0 */ { "unmapped.pdu3OutletActivePowerThLowerCritical", 0, 1, ".1.3.6.1.4.1.232.165.11.5.1.1.8.1.1", NULL, SU_FLAG_OK, NULL }, /* pdu3OutletActivePowerThLowerCritical.1.2 = INTEGER: 0 */ { "unmapped.pdu3OutletActivePowerThLowerCritical", 0, 1, ".1.3.6.1.4.1.232.165.11.5.1.1.8.1.2", NULL, SU_FLAG_OK, NULL }, /* pdu3OutletActivePowerThLowerCritical.1.3 = INTEGER: 0 */ { "unmapped.pdu3OutletActivePowerThLowerCritical", 0, 1, ".1.3.6.1.4.1.232.165.11.5.1.1.8.1.3", NULL, SU_FLAG_OK, NULL }, /* pdu3OutletActivePowerThLowerCritical.1.4 = INTEGER: 0 */ { "unmapped.pdu3OutletActivePowerThLowerCritical", 0, 1, ".1.3.6.1.4.1.232.165.11.5.1.1.8.1.4", NULL, SU_FLAG_OK, NULL }, /* pdu3OutletActivePowerThLowerCritical.1.5 = INTEGER: 0 */ { "unmapped.pdu3OutletActivePowerThLowerCritical", 0, 1, ".1.3.6.1.4.1.232.165.11.5.1.1.8.1.5", NULL, SU_FLAG_OK, NULL }, /* pdu3OutletActivePowerThLowerCritical.1.6 = INTEGER: 0 */ { "unmapped.pdu3OutletActivePowerThLowerCritical", 0, 1, ".1.3.6.1.4.1.232.165.11.5.1.1.8.1.6", NULL, SU_FLAG_OK, NULL }, /* pdu3OutletActivePowerThLowerCritical.1.7 = INTEGER: 0 */ { "unmapped.pdu3OutletActivePowerThLowerCritical", 0, 1, ".1.3.6.1.4.1.232.165.11.5.1.1.8.1.7", NULL, SU_FLAG_OK, NULL }, /* pdu3OutletActivePowerThLowerCritical.1.8 = INTEGER: 0 */ { "unmapped.pdu3OutletActivePowerThLowerCritical", 0, 1, ".1.3.6.1.4.1.232.165.11.5.1.1.8.1.8", NULL, SU_FLAG_OK, NULL }, /* pdu3OutletActivePowerThLowerCritical.1.9 = INTEGER: 0 */ { "unmapped.pdu3OutletActivePowerThLowerCritical", 0, 1, ".1.3.6.1.4.1.232.165.11.5.1.1.8.1.9", NULL, SU_FLAG_OK, NULL }, /* pdu3OutletActivePowerThLowerCritical.1.10 = INTEGER: 0 */ { "unmapped.pdu3OutletActivePowerThLowerCritical", 0, 1, ".1.3.6.1.4.1.232.165.11.5.1.1.8.1.10", NULL, SU_FLAG_OK, NULL }, /* pdu3OutletActivePowerThLowerCritical.1.11 = INTEGER: 0 */ { "unmapped.pdu3OutletActivePowerThLowerCritical", 0, 1, ".1.3.6.1.4.1.232.165.11.5.1.1.8.1.11", NULL, SU_FLAG_OK, NULL }, /* pdu3OutletActivePowerThLowerCritical.1.12 = INTEGER: 0 */ { "unmapped.pdu3OutletActivePowerThLowerCritical", 0, 1, ".1.3.6.1.4.1.232.165.11.5.1.1.8.1.12", NULL, SU_FLAG_OK, NULL }, /* pdu3OutletActivePowerThLowerCritical.1.13 = INTEGER: 0 */ { "unmapped.pdu3OutletActivePowerThLowerCritical", 0, 1, ".1.3.6.1.4.1.232.165.11.5.1.1.8.1.13", NULL, SU_FLAG_OK, NULL }, /* pdu3OutletActivePowerThLowerCritical.1.14 = INTEGER: 0 */ { "unmapped.pdu3OutletActivePowerThLowerCritical", 0, 1, ".1.3.6.1.4.1.232.165.11.5.1.1.8.1.14", NULL, SU_FLAG_OK, NULL }, /* pdu3OutletActivePowerThLowerCritical.1.15 = INTEGER: 0 */ { "unmapped.pdu3OutletActivePowerThLowerCritical", 0, 1, ".1.3.6.1.4.1.232.165.11.5.1.1.8.1.15", NULL, SU_FLAG_OK, NULL }, /* pdu3OutletActivePowerThLowerCritical.1.16 = INTEGER: 0 */ { "unmapped.pdu3OutletActivePowerThLowerCritical", 0, 1, ".1.3.6.1.4.1.232.165.11.5.1.1.8.1.16", NULL, SU_FLAG_OK, NULL }, /* pdu3OutletActivePowerThLowerCritical.1.17 = INTEGER: 0 */ { "unmapped.pdu3OutletActivePowerThLowerCritical", 0, 1, ".1.3.6.1.4.1.232.165.11.5.1.1.8.1.17", NULL, SU_FLAG_OK, NULL }, /* pdu3OutletActivePowerThLowerCritical.1.18 = INTEGER: 0 */ { "unmapped.pdu3OutletActivePowerThLowerCritical", 0, 1, ".1.3.6.1.4.1.232.165.11.5.1.1.8.1.18", NULL, SU_FLAG_OK, NULL }, /* pdu3OutletActivePowerThLowerCritical.1.19 = INTEGER: 0 */ { "unmapped.pdu3OutletActivePowerThLowerCritical", 0, 1, ".1.3.6.1.4.1.232.165.11.5.1.1.8.1.19", NULL, SU_FLAG_OK, NULL }, /* pdu3OutletActivePowerThLowerCritical.1.20 = INTEGER: 0 */ { "unmapped.pdu3OutletActivePowerThLowerCritical", 0, 1, ".1.3.6.1.4.1.232.165.11.5.1.1.8.1.20", NULL, SU_FLAG_OK, NULL }, /* pdu3OutletActivePowerThLowerCritical.1.21 = INTEGER: 0 */ { "unmapped.pdu3OutletActivePowerThLowerCritical", 0, 1, ".1.3.6.1.4.1.232.165.11.5.1.1.8.1.21", NULL, SU_FLAG_OK, NULL }, /* pdu3OutletActivePowerThLowerCritical.1.22 = INTEGER: 0 */ { "unmapped.pdu3OutletActivePowerThLowerCritical", 0, 1, ".1.3.6.1.4.1.232.165.11.5.1.1.8.1.22", NULL, SU_FLAG_OK, NULL }, /* pdu3OutletActivePowerThLowerCritical.1.23 = INTEGER: 0 */ { "unmapped.pdu3OutletActivePowerThLowerCritical", 0, 1, ".1.3.6.1.4.1.232.165.11.5.1.1.8.1.23", NULL, SU_FLAG_OK, NULL }, /* pdu3OutletActivePowerThLowerCritical.1.24 = INTEGER: 0 */ { "unmapped.pdu3OutletActivePowerThLowerCritical", 0, 1, ".1.3.6.1.4.1.232.165.11.5.1.1.8.1.24", NULL, SU_FLAG_OK, NULL }, /* pdu3OutletActivePowerThLowerCritical.1.25 = INTEGER: 0 */ { "unmapped.pdu3OutletActivePowerThLowerCritical", 0, 1, ".1.3.6.1.4.1.232.165.11.5.1.1.8.1.25", NULL, SU_FLAG_OK, NULL }, /* pdu3OutletActivePowerThLowerCritical.1.26 = INTEGER: 0 */ { "unmapped.pdu3OutletActivePowerThLowerCritical", 0, 1, ".1.3.6.1.4.1.232.165.11.5.1.1.8.1.26", NULL, SU_FLAG_OK, NULL }, /* pdu3OutletActivePowerThLowerCritical.1.27 = INTEGER: 0 */ { "unmapped.pdu3OutletActivePowerThLowerCritical", 0, 1, ".1.3.6.1.4.1.232.165.11.5.1.1.8.1.27", NULL, SU_FLAG_OK, NULL }, /* pdu3OutletActivePowerThLowerCritical.1.28 = INTEGER: 0 */ { "unmapped.pdu3OutletActivePowerThLowerCritical", 0, 1, ".1.3.6.1.4.1.232.165.11.5.1.1.8.1.28", NULL, SU_FLAG_OK, NULL }, /* pdu3OutletActivePowerThLowerCritical.1.29 = INTEGER: 0 */ { "unmapped.pdu3OutletActivePowerThLowerCritical", 0, 1, ".1.3.6.1.4.1.232.165.11.5.1.1.8.1.29", NULL, SU_FLAG_OK, NULL }, /* pdu3OutletActivePowerThLowerCritical.1.30 = INTEGER: 0 */ { "unmapped.pdu3OutletActivePowerThLowerCritical", 0, 1, ".1.3.6.1.4.1.232.165.11.5.1.1.8.1.30", NULL, SU_FLAG_OK, NULL }, /* pdu3OutletActivePowerThLowerCritical.1.31 = INTEGER: 0 */ { "unmapped.pdu3OutletActivePowerThLowerCritical", 0, 1, ".1.3.6.1.4.1.232.165.11.5.1.1.8.1.31", NULL, SU_FLAG_OK, NULL }, /* pdu3OutletActivePowerThLowerCritical.1.32 = INTEGER: 0 */ { "unmapped.pdu3OutletActivePowerThLowerCritical", 0, 1, ".1.3.6.1.4.1.232.165.11.5.1.1.8.1.32", NULL, SU_FLAG_OK, NULL }, /* pdu3OutletActivePowerThLowerCritical.1.33 = INTEGER: 0 */ { "unmapped.pdu3OutletActivePowerThLowerCritical", 0, 1, ".1.3.6.1.4.1.232.165.11.5.1.1.8.1.33", NULL, SU_FLAG_OK, NULL }, /* pdu3OutletActivePowerThLowerCritical.1.34 = INTEGER: 0 */ { "unmapped.pdu3OutletActivePowerThLowerCritical", 0, 1, ".1.3.6.1.4.1.232.165.11.5.1.1.8.1.34", NULL, SU_FLAG_OK, NULL }, /* pdu3OutletActivePowerThLowerCritical.1.35 = INTEGER: 0 */ { "unmapped.pdu3OutletActivePowerThLowerCritical", 0, 1, ".1.3.6.1.4.1.232.165.11.5.1.1.8.1.35", NULL, SU_FLAG_OK, NULL }, /* pdu3OutletActivePowerThLowerCritical.1.36 = INTEGER: 0 */ { "unmapped.pdu3OutletActivePowerThLowerCritical", 0, 1, ".1.3.6.1.4.1.232.165.11.5.1.1.8.1.36", NULL, SU_FLAG_OK, NULL }, /* pdu3OutletActivePowerThLowerCritical.1.37 = INTEGER: 0 */ { "unmapped.pdu3OutletActivePowerThLowerCritical", 0, 1, ".1.3.6.1.4.1.232.165.11.5.1.1.8.1.37", NULL, SU_FLAG_OK, NULL }, /* pdu3OutletActivePowerThLowerCritical.1.38 = INTEGER: 0 */ { "unmapped.pdu3OutletActivePowerThLowerCritical", 0, 1, ".1.3.6.1.4.1.232.165.11.5.1.1.8.1.38", NULL, SU_FLAG_OK, NULL }, /* pdu3OutletActivePowerThLowerCritical.1.39 = INTEGER: 0 */ { "unmapped.pdu3OutletActivePowerThLowerCritical", 0, 1, ".1.3.6.1.4.1.232.165.11.5.1.1.8.1.39", NULL, SU_FLAG_OK, NULL }, /* pdu3OutletActivePowerThLowerCritical.1.40 = INTEGER: 0 */ { "unmapped.pdu3OutletActivePowerThLowerCritical", 0, 1, ".1.3.6.1.4.1.232.165.11.5.1.1.8.1.40", NULL, SU_FLAG_OK, NULL }, /* pdu3OutletActivePowerThLowerCritical.1.41 = INTEGER: 0 */ { "unmapped.pdu3OutletActivePowerThLowerCritical", 0, 1, ".1.3.6.1.4.1.232.165.11.5.1.1.8.1.41", NULL, SU_FLAG_OK, NULL }, /* pdu3OutletActivePowerThLowerCritical.1.42 = INTEGER: 0 */ { "unmapped.pdu3OutletActivePowerThLowerCritical", 0, 1, ".1.3.6.1.4.1.232.165.11.5.1.1.8.1.42", NULL, SU_FLAG_OK, NULL }, /* pdu3OutletActivePowerThLowerCritical.1.43 = INTEGER: 0 */ { "unmapped.pdu3OutletActivePowerThLowerCritical", 0, 1, ".1.3.6.1.4.1.232.165.11.5.1.1.8.1.43", NULL, SU_FLAG_OK, NULL }, /* pdu3OutletActivePowerThLowerCritical.1.44 = INTEGER: 0 */ { "unmapped.pdu3OutletActivePowerThLowerCritical", 0, 1, ".1.3.6.1.4.1.232.165.11.5.1.1.8.1.44", NULL, SU_FLAG_OK, NULL }, /* pdu3OutletActivePowerThLowerCritical.1.45 = INTEGER: 0 */ { "unmapped.pdu3OutletActivePowerThLowerCritical", 0, 1, ".1.3.6.1.4.1.232.165.11.5.1.1.8.1.45", NULL, SU_FLAG_OK, NULL }, /* pdu3OutletActivePowerThLowerCritical.1.46 = INTEGER: 0 */ { "unmapped.pdu3OutletActivePowerThLowerCritical", 0, 1, ".1.3.6.1.4.1.232.165.11.5.1.1.8.1.46", NULL, SU_FLAG_OK, NULL }, /* pdu3OutletActivePowerThLowerCritical.1.47 = INTEGER: 0 */ { "unmapped.pdu3OutletActivePowerThLowerCritical", 0, 1, ".1.3.6.1.4.1.232.165.11.5.1.1.8.1.47", NULL, SU_FLAG_OK, NULL }, /* pdu3OutletActivePowerThLowerCritical.1.48 = INTEGER: 0 */ { "unmapped.pdu3OutletActivePowerThLowerCritical", 0, 1, ".1.3.6.1.4.1.232.165.11.5.1.1.8.1.48", NULL, SU_FLAG_OK, NULL }, /* pdu3OutletActivePowerThUpperWarning.1.1 = INTEGER: 0 */ { "unmapped.pdu3OutletActivePowerThUpperWarning", 0, 1, ".1.3.6.1.4.1.232.165.11.5.1.1.9.1.1", NULL, SU_FLAG_OK, NULL }, /* pdu3OutletActivePowerThUpperWarning.1.2 = INTEGER: 0 */ { "unmapped.pdu3OutletActivePowerThUpperWarning", 0, 1, ".1.3.6.1.4.1.232.165.11.5.1.1.9.1.2", NULL, SU_FLAG_OK, NULL }, /* pdu3OutletActivePowerThUpperWarning.1.3 = INTEGER: 0 */ { "unmapped.pdu3OutletActivePowerThUpperWarning", 0, 1, ".1.3.6.1.4.1.232.165.11.5.1.1.9.1.3", NULL, SU_FLAG_OK, NULL }, /* pdu3OutletActivePowerThUpperWarning.1.4 = INTEGER: 0 */ { "unmapped.pdu3OutletActivePowerThUpperWarning", 0, 1, ".1.3.6.1.4.1.232.165.11.5.1.1.9.1.4", NULL, SU_FLAG_OK, NULL }, /* pdu3OutletActivePowerThUpperWarning.1.5 = INTEGER: 0 */ { "unmapped.pdu3OutletActivePowerThUpperWarning", 0, 1, ".1.3.6.1.4.1.232.165.11.5.1.1.9.1.5", NULL, SU_FLAG_OK, NULL }, /* pdu3OutletActivePowerThUpperWarning.1.6 = INTEGER: 0 */ { "unmapped.pdu3OutletActivePowerThUpperWarning", 0, 1, ".1.3.6.1.4.1.232.165.11.5.1.1.9.1.6", NULL, SU_FLAG_OK, NULL }, /* pdu3OutletActivePowerThUpperWarning.1.7 = INTEGER: 0 */ { "unmapped.pdu3OutletActivePowerThUpperWarning", 0, 1, ".1.3.6.1.4.1.232.165.11.5.1.1.9.1.7", NULL, SU_FLAG_OK, NULL }, /* pdu3OutletActivePowerThUpperWarning.1.8 = INTEGER: 0 */ { "unmapped.pdu3OutletActivePowerThUpperWarning", 0, 1, ".1.3.6.1.4.1.232.165.11.5.1.1.9.1.8", NULL, SU_FLAG_OK, NULL }, /* pdu3OutletActivePowerThUpperWarning.1.9 = INTEGER: 0 */ { "unmapped.pdu3OutletActivePowerThUpperWarning", 0, 1, ".1.3.6.1.4.1.232.165.11.5.1.1.9.1.9", NULL, SU_FLAG_OK, NULL }, /* pdu3OutletActivePowerThUpperWarning.1.10 = INTEGER: 0 */ { "unmapped.pdu3OutletActivePowerThUpperWarning", 0, 1, ".1.3.6.1.4.1.232.165.11.5.1.1.9.1.10", NULL, SU_FLAG_OK, NULL }, /* pdu3OutletActivePowerThUpperWarning.1.11 = INTEGER: 0 */ { "unmapped.pdu3OutletActivePowerThUpperWarning", 0, 1, ".1.3.6.1.4.1.232.165.11.5.1.1.9.1.11", NULL, SU_FLAG_OK, NULL }, /* pdu3OutletActivePowerThUpperWarning.1.12 = INTEGER: 0 */ { "unmapped.pdu3OutletActivePowerThUpperWarning", 0, 1, ".1.3.6.1.4.1.232.165.11.5.1.1.9.1.12", NULL, SU_FLAG_OK, NULL }, /* pdu3OutletActivePowerThUpperWarning.1.13 = INTEGER: 0 */ { "unmapped.pdu3OutletActivePowerThUpperWarning", 0, 1, ".1.3.6.1.4.1.232.165.11.5.1.1.9.1.13", NULL, SU_FLAG_OK, NULL }, /* pdu3OutletActivePowerThUpperWarning.1.14 = INTEGER: 0 */ { "unmapped.pdu3OutletActivePowerThUpperWarning", 0, 1, ".1.3.6.1.4.1.232.165.11.5.1.1.9.1.14", NULL, SU_FLAG_OK, NULL }, /* pdu3OutletActivePowerThUpperWarning.1.15 = INTEGER: 0 */ { "unmapped.pdu3OutletActivePowerThUpperWarning", 0, 1, ".1.3.6.1.4.1.232.165.11.5.1.1.9.1.15", NULL, SU_FLAG_OK, NULL }, /* pdu3OutletActivePowerThUpperWarning.1.16 = INTEGER: 0 */ { "unmapped.pdu3OutletActivePowerThUpperWarning", 0, 1, ".1.3.6.1.4.1.232.165.11.5.1.1.9.1.16", NULL, SU_FLAG_OK, NULL }, /* pdu3OutletActivePowerThUpperWarning.1.17 = INTEGER: 0 */ { "unmapped.pdu3OutletActivePowerThUpperWarning", 0, 1, ".1.3.6.1.4.1.232.165.11.5.1.1.9.1.17", NULL, SU_FLAG_OK, NULL }, /* pdu3OutletActivePowerThUpperWarning.1.18 = INTEGER: 0 */ { "unmapped.pdu3OutletActivePowerThUpperWarning", 0, 1, ".1.3.6.1.4.1.232.165.11.5.1.1.9.1.18", NULL, SU_FLAG_OK, NULL }, /* pdu3OutletActivePowerThUpperWarning.1.19 = INTEGER: 0 */ { "unmapped.pdu3OutletActivePowerThUpperWarning", 0, 1, ".1.3.6.1.4.1.232.165.11.5.1.1.9.1.19", NULL, SU_FLAG_OK, NULL }, /* pdu3OutletActivePowerThUpperWarning.1.20 = INTEGER: 0 */ { "unmapped.pdu3OutletActivePowerThUpperWarning", 0, 1, ".1.3.6.1.4.1.232.165.11.5.1.1.9.1.20", NULL, SU_FLAG_OK, NULL }, /* pdu3OutletActivePowerThUpperWarning.1.21 = INTEGER: 0 */ { "unmapped.pdu3OutletActivePowerThUpperWarning", 0, 1, ".1.3.6.1.4.1.232.165.11.5.1.1.9.1.21", NULL, SU_FLAG_OK, NULL }, /* pdu3OutletActivePowerThUpperWarning.1.22 = INTEGER: 0 */ { "unmapped.pdu3OutletActivePowerThUpperWarning", 0, 1, ".1.3.6.1.4.1.232.165.11.5.1.1.9.1.22", NULL, SU_FLAG_OK, NULL }, /* pdu3OutletActivePowerThUpperWarning.1.23 = INTEGER: 0 */ { "unmapped.pdu3OutletActivePowerThUpperWarning", 0, 1, ".1.3.6.1.4.1.232.165.11.5.1.1.9.1.23", NULL, SU_FLAG_OK, NULL }, /* pdu3OutletActivePowerThUpperWarning.1.24 = INTEGER: 0 */ { "unmapped.pdu3OutletActivePowerThUpperWarning", 0, 1, ".1.3.6.1.4.1.232.165.11.5.1.1.9.1.24", NULL, SU_FLAG_OK, NULL }, /* pdu3OutletActivePowerThUpperWarning.1.25 = INTEGER: 0 */ { "unmapped.pdu3OutletActivePowerThUpperWarning", 0, 1, ".1.3.6.1.4.1.232.165.11.5.1.1.9.1.25", NULL, SU_FLAG_OK, NULL }, /* pdu3OutletActivePowerThUpperWarning.1.26 = INTEGER: 0 */ { "unmapped.pdu3OutletActivePowerThUpperWarning", 0, 1, ".1.3.6.1.4.1.232.165.11.5.1.1.9.1.26", NULL, SU_FLAG_OK, NULL }, /* pdu3OutletActivePowerThUpperWarning.1.27 = INTEGER: 0 */ { "unmapped.pdu3OutletActivePowerThUpperWarning", 0, 1, ".1.3.6.1.4.1.232.165.11.5.1.1.9.1.27", NULL, SU_FLAG_OK, NULL }, /* pdu3OutletActivePowerThUpperWarning.1.28 = INTEGER: 0 */ { "unmapped.pdu3OutletActivePowerThUpperWarning", 0, 1, ".1.3.6.1.4.1.232.165.11.5.1.1.9.1.28", NULL, SU_FLAG_OK, NULL }, /* pdu3OutletActivePowerThUpperWarning.1.29 = INTEGER: 0 */ { "unmapped.pdu3OutletActivePowerThUpperWarning", 0, 1, ".1.3.6.1.4.1.232.165.11.5.1.1.9.1.29", NULL, SU_FLAG_OK, NULL }, /* pdu3OutletActivePowerThUpperWarning.1.30 = INTEGER: 0 */ { "unmapped.pdu3OutletActivePowerThUpperWarning", 0, 1, ".1.3.6.1.4.1.232.165.11.5.1.1.9.1.30", NULL, SU_FLAG_OK, NULL }, /* pdu3OutletActivePowerThUpperWarning.1.31 = INTEGER: 0 */ { "unmapped.pdu3OutletActivePowerThUpperWarning", 0, 1, ".1.3.6.1.4.1.232.165.11.5.1.1.9.1.31", NULL, SU_FLAG_OK, NULL }, /* pdu3OutletActivePowerThUpperWarning.1.32 = INTEGER: 0 */ { "unmapped.pdu3OutletActivePowerThUpperWarning", 0, 1, ".1.3.6.1.4.1.232.165.11.5.1.1.9.1.32", NULL, SU_FLAG_OK, NULL }, /* pdu3OutletActivePowerThUpperWarning.1.33 = INTEGER: 0 */ { "unmapped.pdu3OutletActivePowerThUpperWarning", 0, 1, ".1.3.6.1.4.1.232.165.11.5.1.1.9.1.33", NULL, SU_FLAG_OK, NULL }, /* pdu3OutletActivePowerThUpperWarning.1.34 = INTEGER: 0 */ { "unmapped.pdu3OutletActivePowerThUpperWarning", 0, 1, ".1.3.6.1.4.1.232.165.11.5.1.1.9.1.34", NULL, SU_FLAG_OK, NULL }, /* pdu3OutletActivePowerThUpperWarning.1.35 = INTEGER: 0 */ { "unmapped.pdu3OutletActivePowerThUpperWarning", 0, 1, ".1.3.6.1.4.1.232.165.11.5.1.1.9.1.35", NULL, SU_FLAG_OK, NULL }, /* pdu3OutletActivePowerThUpperWarning.1.36 = INTEGER: 0 */ { "unmapped.pdu3OutletActivePowerThUpperWarning", 0, 1, ".1.3.6.1.4.1.232.165.11.5.1.1.9.1.36", NULL, SU_FLAG_OK, NULL }, /* pdu3OutletActivePowerThUpperWarning.1.37 = INTEGER: 0 */ { "unmapped.pdu3OutletActivePowerThUpperWarning", 0, 1, ".1.3.6.1.4.1.232.165.11.5.1.1.9.1.37", NULL, SU_FLAG_OK, NULL }, /* pdu3OutletActivePowerThUpperWarning.1.38 = INTEGER: 0 */ { "unmapped.pdu3OutletActivePowerThUpperWarning", 0, 1, ".1.3.6.1.4.1.232.165.11.5.1.1.9.1.38", NULL, SU_FLAG_OK, NULL }, /* pdu3OutletActivePowerThUpperWarning.1.39 = INTEGER: 0 */ { "unmapped.pdu3OutletActivePowerThUpperWarning", 0, 1, ".1.3.6.1.4.1.232.165.11.5.1.1.9.1.39", NULL, SU_FLAG_OK, NULL }, /* pdu3OutletActivePowerThUpperWarning.1.40 = INTEGER: 0 */ { "unmapped.pdu3OutletActivePowerThUpperWarning", 0, 1, ".1.3.6.1.4.1.232.165.11.5.1.1.9.1.40", NULL, SU_FLAG_OK, NULL }, /* pdu3OutletActivePowerThUpperWarning.1.41 = INTEGER: 0 */ { "unmapped.pdu3OutletActivePowerThUpperWarning", 0, 1, ".1.3.6.1.4.1.232.165.11.5.1.1.9.1.41", NULL, SU_FLAG_OK, NULL }, /* pdu3OutletActivePowerThUpperWarning.1.42 = INTEGER: 0 */ { "unmapped.pdu3OutletActivePowerThUpperWarning", 0, 1, ".1.3.6.1.4.1.232.165.11.5.1.1.9.1.42", NULL, SU_FLAG_OK, NULL }, /* pdu3OutletActivePowerThUpperWarning.1.43 = INTEGER: 0 */ { "unmapped.pdu3OutletActivePowerThUpperWarning", 0, 1, ".1.3.6.1.4.1.232.165.11.5.1.1.9.1.43", NULL, SU_FLAG_OK, NULL }, /* pdu3OutletActivePowerThUpperWarning.1.44 = INTEGER: 0 */ { "unmapped.pdu3OutletActivePowerThUpperWarning", 0, 1, ".1.3.6.1.4.1.232.165.11.5.1.1.9.1.44", NULL, SU_FLAG_OK, NULL }, /* pdu3OutletActivePowerThUpperWarning.1.45 = INTEGER: 0 */ { "unmapped.pdu3OutletActivePowerThUpperWarning", 0, 1, ".1.3.6.1.4.1.232.165.11.5.1.1.9.1.45", NULL, SU_FLAG_OK, NULL }, /* pdu3OutletActivePowerThUpperWarning.1.46 = INTEGER: 0 */ { "unmapped.pdu3OutletActivePowerThUpperWarning", 0, 1, ".1.3.6.1.4.1.232.165.11.5.1.1.9.1.46", NULL, SU_FLAG_OK, NULL }, /* pdu3OutletActivePowerThUpperWarning.1.47 = INTEGER: 0 */ { "unmapped.pdu3OutletActivePowerThUpperWarning", 0, 1, ".1.3.6.1.4.1.232.165.11.5.1.1.9.1.47", NULL, SU_FLAG_OK, NULL }, /* pdu3OutletActivePowerThUpperWarning.1.48 = INTEGER: 0 */ { "unmapped.pdu3OutletActivePowerThUpperWarning", 0, 1, ".1.3.6.1.4.1.232.165.11.5.1.1.9.1.48", NULL, SU_FLAG_OK, NULL }, /* pdu3OutletActivePowerThUpperCritical.1.1 = INTEGER: 0 */ { "unmapped.pdu3OutletActivePowerThUpperCritical", 0, 1, ".1.3.6.1.4.1.232.165.11.5.1.1.10.1.1", NULL, SU_FLAG_OK, NULL }, /* pdu3OutletActivePowerThUpperCritical.1.2 = INTEGER: 0 */ { "unmapped.pdu3OutletActivePowerThUpperCritical", 0, 1, ".1.3.6.1.4.1.232.165.11.5.1.1.10.1.2", NULL, SU_FLAG_OK, NULL }, /* pdu3OutletActivePowerThUpperCritical.1.3 = INTEGER: 0 */ { "unmapped.pdu3OutletActivePowerThUpperCritical", 0, 1, ".1.3.6.1.4.1.232.165.11.5.1.1.10.1.3", NULL, SU_FLAG_OK, NULL }, /* pdu3OutletActivePowerThUpperCritical.1.4 = INTEGER: 0 */ { "unmapped.pdu3OutletActivePowerThUpperCritical", 0, 1, ".1.3.6.1.4.1.232.165.11.5.1.1.10.1.4", NULL, SU_FLAG_OK, NULL }, /* pdu3OutletActivePowerThUpperCritical.1.5 = INTEGER: 0 */ { "unmapped.pdu3OutletActivePowerThUpperCritical", 0, 1, ".1.3.6.1.4.1.232.165.11.5.1.1.10.1.5", NULL, SU_FLAG_OK, NULL }, /* pdu3OutletActivePowerThUpperCritical.1.6 = INTEGER: 0 */ { "unmapped.pdu3OutletActivePowerThUpperCritical", 0, 1, ".1.3.6.1.4.1.232.165.11.5.1.1.10.1.6", NULL, SU_FLAG_OK, NULL }, /* pdu3OutletActivePowerThUpperCritical.1.7 = INTEGER: 0 */ { "unmapped.pdu3OutletActivePowerThUpperCritical", 0, 1, ".1.3.6.1.4.1.232.165.11.5.1.1.10.1.7", NULL, SU_FLAG_OK, NULL }, /* pdu3OutletActivePowerThUpperCritical.1.8 = INTEGER: 0 */ { "unmapped.pdu3OutletActivePowerThUpperCritical", 0, 1, ".1.3.6.1.4.1.232.165.11.5.1.1.10.1.8", NULL, SU_FLAG_OK, NULL }, /* pdu3OutletActivePowerThUpperCritical.1.9 = INTEGER: 0 */ { "unmapped.pdu3OutletActivePowerThUpperCritical", 0, 1, ".1.3.6.1.4.1.232.165.11.5.1.1.10.1.9", NULL, SU_FLAG_OK, NULL }, /* pdu3OutletActivePowerThUpperCritical.1.10 = INTEGER: 0 */ { "unmapped.pdu3OutletActivePowerThUpperCritical", 0, 1, ".1.3.6.1.4.1.232.165.11.5.1.1.10.1.10", NULL, SU_FLAG_OK, NULL }, /* pdu3OutletActivePowerThUpperCritical.1.11 = INTEGER: 0 */ { "unmapped.pdu3OutletActivePowerThUpperCritical", 0, 1, ".1.3.6.1.4.1.232.165.11.5.1.1.10.1.11", NULL, SU_FLAG_OK, NULL }, /* pdu3OutletActivePowerThUpperCritical.1.12 = INTEGER: 0 */ { "unmapped.pdu3OutletActivePowerThUpperCritical", 0, 1, ".1.3.6.1.4.1.232.165.11.5.1.1.10.1.12", NULL, SU_FLAG_OK, NULL }, /* pdu3OutletActivePowerThUpperCritical.1.13 = INTEGER: 0 */ { "unmapped.pdu3OutletActivePowerThUpperCritical", 0, 1, ".1.3.6.1.4.1.232.165.11.5.1.1.10.1.13", NULL, SU_FLAG_OK, NULL }, /* pdu3OutletActivePowerThUpperCritical.1.14 = INTEGER: 0 */ { "unmapped.pdu3OutletActivePowerThUpperCritical", 0, 1, ".1.3.6.1.4.1.232.165.11.5.1.1.10.1.14", NULL, SU_FLAG_OK, NULL }, /* pdu3OutletActivePowerThUpperCritical.1.15 = INTEGER: 0 */ { "unmapped.pdu3OutletActivePowerThUpperCritical", 0, 1, ".1.3.6.1.4.1.232.165.11.5.1.1.10.1.15", NULL, SU_FLAG_OK, NULL }, /* pdu3OutletActivePowerThUpperCritical.1.16 = INTEGER: 0 */ { "unmapped.pdu3OutletActivePowerThUpperCritical", 0, 1, ".1.3.6.1.4.1.232.165.11.5.1.1.10.1.16", NULL, SU_FLAG_OK, NULL }, /* pdu3OutletActivePowerThUpperCritical.1.17 = INTEGER: 0 */ { "unmapped.pdu3OutletActivePowerThUpperCritical", 0, 1, ".1.3.6.1.4.1.232.165.11.5.1.1.10.1.17", NULL, SU_FLAG_OK, NULL }, /* pdu3OutletActivePowerThUpperCritical.1.18 = INTEGER: 0 */ { "unmapped.pdu3OutletActivePowerThUpperCritical", 0, 1, ".1.3.6.1.4.1.232.165.11.5.1.1.10.1.18", NULL, SU_FLAG_OK, NULL }, /* pdu3OutletActivePowerThUpperCritical.1.19 = INTEGER: 0 */ { "unmapped.pdu3OutletActivePowerThUpperCritical", 0, 1, ".1.3.6.1.4.1.232.165.11.5.1.1.10.1.19", NULL, SU_FLAG_OK, NULL }, /* pdu3OutletActivePowerThUpperCritical.1.20 = INTEGER: 0 */ { "unmapped.pdu3OutletActivePowerThUpperCritical", 0, 1, ".1.3.6.1.4.1.232.165.11.5.1.1.10.1.20", NULL, SU_FLAG_OK, NULL }, /* pdu3OutletActivePowerThUpperCritical.1.21 = INTEGER: 0 */ { "unmapped.pdu3OutletActivePowerThUpperCritical", 0, 1, ".1.3.6.1.4.1.232.165.11.5.1.1.10.1.21", NULL, SU_FLAG_OK, NULL }, /* pdu3OutletActivePowerThUpperCritical.1.22 = INTEGER: 0 */ { "unmapped.pdu3OutletActivePowerThUpperCritical", 0, 1, ".1.3.6.1.4.1.232.165.11.5.1.1.10.1.22", NULL, SU_FLAG_OK, NULL }, /* pdu3OutletActivePowerThUpperCritical.1.23 = INTEGER: 0 */ { "unmapped.pdu3OutletActivePowerThUpperCritical", 0, 1, ".1.3.6.1.4.1.232.165.11.5.1.1.10.1.23", NULL, SU_FLAG_OK, NULL }, /* pdu3OutletActivePowerThUpperCritical.1.24 = INTEGER: 0 */ { "unmapped.pdu3OutletActivePowerThUpperCritical", 0, 1, ".1.3.6.1.4.1.232.165.11.5.1.1.10.1.24", NULL, SU_FLAG_OK, NULL }, /* pdu3OutletActivePowerThUpperCritical.1.25 = INTEGER: 0 */ { "unmapped.pdu3OutletActivePowerThUpperCritical", 0, 1, ".1.3.6.1.4.1.232.165.11.5.1.1.10.1.25", NULL, SU_FLAG_OK, NULL }, /* pdu3OutletActivePowerThUpperCritical.1.26 = INTEGER: 0 */ { "unmapped.pdu3OutletActivePowerThUpperCritical", 0, 1, ".1.3.6.1.4.1.232.165.11.5.1.1.10.1.26", NULL, SU_FLAG_OK, NULL }, /* pdu3OutletActivePowerThUpperCritical.1.27 = INTEGER: 0 */ { "unmapped.pdu3OutletActivePowerThUpperCritical", 0, 1, ".1.3.6.1.4.1.232.165.11.5.1.1.10.1.27", NULL, SU_FLAG_OK, NULL }, /* pdu3OutletActivePowerThUpperCritical.1.28 = INTEGER: 0 */ { "unmapped.pdu3OutletActivePowerThUpperCritical", 0, 1, ".1.3.6.1.4.1.232.165.11.5.1.1.10.1.28", NULL, SU_FLAG_OK, NULL }, /* pdu3OutletActivePowerThUpperCritical.1.29 = INTEGER: 0 */ { "unmapped.pdu3OutletActivePowerThUpperCritical", 0, 1, ".1.3.6.1.4.1.232.165.11.5.1.1.10.1.29", NULL, SU_FLAG_OK, NULL }, /* pdu3OutletActivePowerThUpperCritical.1.30 = INTEGER: 0 */ { "unmapped.pdu3OutletActivePowerThUpperCritical", 0, 1, ".1.3.6.1.4.1.232.165.11.5.1.1.10.1.30", NULL, SU_FLAG_OK, NULL }, /* pdu3OutletActivePowerThUpperCritical.1.31 = INTEGER: 0 */ { "unmapped.pdu3OutletActivePowerThUpperCritical", 0, 1, ".1.3.6.1.4.1.232.165.11.5.1.1.10.1.31", NULL, SU_FLAG_OK, NULL }, /* pdu3OutletActivePowerThUpperCritical.1.32 = INTEGER: 0 */ { "unmapped.pdu3OutletActivePowerThUpperCritical", 0, 1, ".1.3.6.1.4.1.232.165.11.5.1.1.10.1.32", NULL, SU_FLAG_OK, NULL }, /* pdu3OutletActivePowerThUpperCritical.1.33 = INTEGER: 0 */ { "unmapped.pdu3OutletActivePowerThUpperCritical", 0, 1, ".1.3.6.1.4.1.232.165.11.5.1.1.10.1.33", NULL, SU_FLAG_OK, NULL }, /* pdu3OutletActivePowerThUpperCritical.1.34 = INTEGER: 0 */ { "unmapped.pdu3OutletActivePowerThUpperCritical", 0, 1, ".1.3.6.1.4.1.232.165.11.5.1.1.10.1.34", NULL, SU_FLAG_OK, NULL }, /* pdu3OutletActivePowerThUpperCritical.1.35 = INTEGER: 0 */ { "unmapped.pdu3OutletActivePowerThUpperCritical", 0, 1, ".1.3.6.1.4.1.232.165.11.5.1.1.10.1.35", NULL, SU_FLAG_OK, NULL }, /* pdu3OutletActivePowerThUpperCritical.1.36 = INTEGER: 0 */ { "unmapped.pdu3OutletActivePowerThUpperCritical", 0, 1, ".1.3.6.1.4.1.232.165.11.5.1.1.10.1.36", NULL, SU_FLAG_OK, NULL }, /* pdu3OutletActivePowerThUpperCritical.1.37 = INTEGER: 0 */ { "unmapped.pdu3OutletActivePowerThUpperCritical", 0, 1, ".1.3.6.1.4.1.232.165.11.5.1.1.10.1.37", NULL, SU_FLAG_OK, NULL }, /* pdu3OutletActivePowerThUpperCritical.1.38 = INTEGER: 0 */ { "unmapped.pdu3OutletActivePowerThUpperCritical", 0, 1, ".1.3.6.1.4.1.232.165.11.5.1.1.10.1.38", NULL, SU_FLAG_OK, NULL }, /* pdu3OutletActivePowerThUpperCritical.1.39 = INTEGER: 0 */ { "unmapped.pdu3OutletActivePowerThUpperCritical", 0, 1, ".1.3.6.1.4.1.232.165.11.5.1.1.10.1.39", NULL, SU_FLAG_OK, NULL }, /* pdu3OutletActivePowerThUpperCritical.1.40 = INTEGER: 0 */ { "unmapped.pdu3OutletActivePowerThUpperCritical", 0, 1, ".1.3.6.1.4.1.232.165.11.5.1.1.10.1.40", NULL, SU_FLAG_OK, NULL }, /* pdu3OutletActivePowerThUpperCritical.1.41 = INTEGER: 0 */ { "unmapped.pdu3OutletActivePowerThUpperCritical", 0, 1, ".1.3.6.1.4.1.232.165.11.5.1.1.10.1.41", NULL, SU_FLAG_OK, NULL }, /* pdu3OutletActivePowerThUpperCritical.1.42 = INTEGER: 0 */ { "unmapped.pdu3OutletActivePowerThUpperCritical", 0, 1, ".1.3.6.1.4.1.232.165.11.5.1.1.10.1.42", NULL, SU_FLAG_OK, NULL }, /* pdu3OutletActivePowerThUpperCritical.1.43 = INTEGER: 0 */ { "unmapped.pdu3OutletActivePowerThUpperCritical", 0, 1, ".1.3.6.1.4.1.232.165.11.5.1.1.10.1.43", NULL, SU_FLAG_OK, NULL }, /* pdu3OutletActivePowerThUpperCritical.1.44 = INTEGER: 0 */ { "unmapped.pdu3OutletActivePowerThUpperCritical", 0, 1, ".1.3.6.1.4.1.232.165.11.5.1.1.10.1.44", NULL, SU_FLAG_OK, NULL }, /* pdu3OutletActivePowerThUpperCritical.1.45 = INTEGER: 0 */ { "unmapped.pdu3OutletActivePowerThUpperCritical", 0, 1, ".1.3.6.1.4.1.232.165.11.5.1.1.10.1.45", NULL, SU_FLAG_OK, NULL }, /* pdu3OutletActivePowerThUpperCritical.1.46 = INTEGER: 0 */ { "unmapped.pdu3OutletActivePowerThUpperCritical", 0, 1, ".1.3.6.1.4.1.232.165.11.5.1.1.10.1.46", NULL, SU_FLAG_OK, NULL }, /* pdu3OutletActivePowerThUpperCritical.1.47 = INTEGER: 0 */ { "unmapped.pdu3OutletActivePowerThUpperCritical", 0, 1, ".1.3.6.1.4.1.232.165.11.5.1.1.10.1.47", NULL, SU_FLAG_OK, NULL }, /* pdu3OutletActivePowerThUpperCritical.1.48 = INTEGER: 0 */ { "unmapped.pdu3OutletActivePowerThUpperCritical", 0, 1, ".1.3.6.1.4.1.232.165.11.5.1.1.10.1.48", NULL, SU_FLAG_OK, NULL }, /* pdu3OutletWh.1.%i = INTEGER: 0 */ { "unmapped.pdu3OutletWh", 0, 1, ".1.3.6.1.4.1.232.165.11.5.1.1.14.1.%i", NULL, SU_FLAG_OK, NULL }, /* pdu3OutletWhTimer.1.%i = Hex-STRING: 32 30 31 36 2F 31 30 2F 31 31 20 30 32 3A 34 36 3A 35 30 00 */ { "unmapped.pdu3OutletWhTimer", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.232.165.11.5.1.1.15.1.%i", NULL, SU_FLAG_OK, NULL }, /* pdu3OutletPowerFactor.1.%i = INTEGER: 88 */ { "unmapped.pdu3OutletPowerFactor", 0, 1, ".1.3.6.1.4.1.232.165.11.5.1.1.16.1.%i", NULL, SU_FLAG_OK, NULL }, /* pdu3OutletVAR.1.%i = INTEGER: 2 */ { "unmapped.pdu3OutletVAR", 0, 1, ".1.3.6.1.4.1.232.165.11.5.1.1.17.1.%i", NULL, SU_FLAG_OK, NULL }, /* pdu3OutletControlPowerOnState.1.%i = INTEGER: 2 */ { "unmapped.pdu3OutletControlPowerOnState", 0, 1, ".1.3.6.1.4.1.232.165.11.5.2.1.5.1.%i", NULL, SU_FLAG_OK, NULL }, /* pdu3OutletControlSequenceDelay.1.%i = INTEGER: 0 */ { "unmapped.pdu3OutletControlSequenceDelay", 0, 1, ".1.3.6.1.4.1.232.165.11.5.2.1.6.1.%i", NULL, SU_FLAG_OK, NULL }, /* pdu3OutletControlRebootOffTime.1.%i = INTEGER: 5 */ { "unmapped.pdu3OutletControlRebootOffTime", 0, 1, ".1.3.6.1.4.1.232.165.11.5.2.1.7.1.%i", NULL, SU_FLAG_OK, NULL }, /* pdu3OutletControlShutoffDelay.1.%i = INTEGER: 0 */ { "unmapped.pdu3OutletControlShutoffDelay", 0, 1, ".1.3.6.1.4.1.232.165.11.5.2.1.9.1.%i", NULL, SU_FLAG_OK, NULL }, #endif /* WITH_UNMAPPED_DATA_POINTS */ /* end of structure. */ { NULL, 0, 0, NULL, NULL, 0, NULL } }; mib2nut_info_t hpe_pdu3_cis = { "hpe_pdu3_cis", HPE_PDU3_CIS_MIB_VERSION, NULL, HPE_PDU3_OID_MODEL_NAME, hpe_pdu3_cis_mib, HPE_PDU3_CIS_SYSOID, NULL }; nut-2.8.1/drivers/bestfcom.c0000644000175000017500000005300214501607135012677 00000000000000/* bestfcom.c - model specific routines for Best Power F-Command ups models This module is yet another rewritten mangle of the bestuferrups driver. This driver was written in an attempt to consolidate the various Best Fortress/FERRUPS modules that support the 'f'-command set and provide support for more of these models. Models tested with this new version: FortressII LI720 FERRUPS FE2.1K FERRUPS FE4.3K FERRUPS FE18K FERRUPS FD4.3K From bestuferrups.c : This module is a 40% rewritten mangle of the bestfort module by Grant, which is a 75% rewritten mangle of the bestups module by Russell. It has no test battery command since my ME3100 does this by itself. (same as Grant's driver in this respect) Copyright (C) 2002 Andreas Wrede Copyright (C) 2000 John Stone Copyright (C) 2000 Grant Taylor Copyright (C) 1999 Russell Kroll 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 2 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, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "main.h" #include "serial.h" #define DRIVER_NAME "Best Ferrups/Fortress driver" #define DRIVER_VERSION "0.14" /* driver description structure */ upsdrv_info_t upsdrv_info = { DRIVER_NAME, DRIVER_VERSION, "Andreas Wrede \n" \ "John Stone \n" \ "Grant Taylor \n" \ "Russell Kroll ", DRV_EXPERIMENTAL, { NULL } }; #define ENDCHAR '\r' #define IGNCHARS "\012" #define UPSDELAY 1 /* BEST Factory UPS Model Codes */ #define FORTRESS 00 #define PATRIOT 01 #define FORTRESSII 02 #define FERRUPS 03 #define UNITY1 04 /* Internal driver UPS Model Codes */ #define UNKNOWN 000 #define FDxxxx 100 #define FExxxx 200 #define LIxxxx 300 #define MExxxx 400 #define MDxxxx 500 #include #include #include /* Blob of UPS configuration data from the formatconfig string */ static struct { int valid; /* set to 1 when this is filled in */ float idealbvolts; /* various interesting battery voltages */ float fullvolts; float lowvolts; float emptyvolts; int va; /* capacity of UPS in Volt-Amps */ int watts; /* capacity of UPS in watts */ int model; /* enumerated model type */ int type; /* enumerated ups type*/ char name[16]; /* ups type name*/ } fc; static int inverter_status; /* Forward decls */ /* Set up all the funky shared memory stuff used to communicate with upsd */ void upsdrv_initinfo (void) { /* now set up room for all future variables that are supported */ /* dstate_setinfo("driver.name", "%s", "bestfcom"); */ dstate_setinfo("ups.mfr", "%s", "Best Power"); switch(fc.model) { case MExxxx: dstate_setinfo("ups.model", "%s ME%d", fc.name, fc.va); break; case MDxxxx: dstate_setinfo("ups.model", "%s MD%d", fc.name, fc.va); break; case FDxxxx: dstate_setinfo("ups.model", "%s FD%d", fc.name, fc.va); break; case FExxxx: dstate_setinfo("ups.model", "%s FE%d", fc.name, fc.va); break; case LIxxxx: dstate_setinfo("ups.model", "%s LI%d", fc.name, fc.va); break; default: fatalx(EXIT_FAILURE, "Unknown model - oops!"); /* Will never get here, upsdrv_initups() will catch */ } dstate_setinfo("ups.power.nominal", "%d", fc.va); dstate_setinfo("ups.realpower.nominal", "%d", fc.watts); /* Do we really need to waste time on this? */ /* if (fc.model != FDxxxx) { if (execute("d 00\r", tmp, sizeof(tmp)) > 0) sscanf(tmp, "00 Time %8s", time); if (execute("d 10\r", tmp, sizeof(tmp)) > 0) sscanf(tmp, "10 Date %8s", date); dstate_setinfo("ups.time", "%s", time); dstate_setinfo("ups.date", "%s", date); } */ dstate_setinfo("battery.voltage.nominal", "%05.2f", (double)fc.idealbvolts); upsdebugx(1, "Best Power %s detected", dstate_getinfo("ups.model")); upsdebugx(1, "Battery voltages: %5.2f nominal, %5.2f full, %5.2f low, %5.2f empty", fc.idealbvolts, fc.fullvolts, fc.lowvolts, fc.emptyvolts); } /* atoi() without the freebie octal conversion */ static int bcd2i (const char *bcdstring, const int bcdlen) { int i, digit, total = 0, factor = 1; for (i = 1; i < bcdlen; i++) factor *= 10; for (i = 0; i < bcdlen; i++) { digit = bcdstring[i] - '0'; if (digit > 9) { digit = 0; } total += digit * factor; factor /= 10; } return total; } #define POLL_ALERT "{" static void alert_handler(char ch) { char buf[SMALLBUF]; NUT_UNUSED_VARIABLE(ch); /* Received an Inverter status alarm : * "\r\n{Inverter: On}\r\n=>" * Try to flush the message */ ser_get_line(upsfd, buf, sizeof(buf), '\012', "", 0, 20000); } /* Debugging display from kermit: ---------------------------------------------------- time^M^M^JFeb 20, 22:13:32^M^J^M^J=>id^M^JUnit ID "ME3.1K12345"^M^J^M^J=> ---------------------------------------------------- */ static ssize_t execute(const char *cmd, char *result, size_t resultsize) { ssize_t ret; char buf[SMALLBUF]; unsigned char ch; /* Check for the Inverter status alarm if pending : * "\r\n{Inverter: On}\r\n=>" */ ser_get_line_alert(upsfd, buf, sizeof(buf), '\012', "", POLL_ALERT, alert_handler, 0, 20000); ser_send(upsfd, "%s", cmd); /* Give the UPS some time to chew on what we just sent */ usleep(50000); /* delete command echo up to \012 but no further */ for (ch = '\0'; ch != '\012'; ser_get_char(upsfd, &ch, 0, 10000)); /* get command response */ ret = ser_get_line(upsfd, result, resultsize, '\015', "\012", 3, 0); return ret; } /* format command response -> 80 chars chrg line status ||alrm || Date Invtr |12| error | ||Time| || |Vi||Vo| |Io|| VA | |Vb||Hz||rt| || |vr|CS 011314581801000000010000011601160000002300026600000265600000190000000000E00106E6\r 01161706430100010001000002040121000000980011890000057959980001002200000064080727\r 011800364801000100010000021301200000003100037100001343599803060024000000680807A0\r 0121022719010001000100000208011900190000000000000005676001082200350000000006101A\r 00000000000100000000000002370236000000220005190000026850000009002600000000030161\r 0 0 1 1 2 2 3 3 4 4 5 5 6 6 7 7 8 0 5 0 5 0 5 0 5 0 5 0 5 0 5 0 5 0 Above f-responses listed in this order: FortressII LI720 FERRUPS FE4.3K FERRUPS FE18K FERRUPS FD4.3K Fortress ?????? (from Holger's old Best Fortress notes) */ void upsdrv_updateinfo(void) { char fstring[512]; if (! fc.valid) { upsdebugx(1, "upsupdate run before ups_ident() read ups config"); #ifdef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_UNREACHABLE_CODE #pragma GCC diagnostic push #endif #ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_UNREACHABLE_CODE #pragma GCC diagnostic ignored "-Wunreachable-code" #endif #ifdef __clang__ #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wunreachable-code" #endif /* NOTE: This assert() always fails because of "0": * error: will never be executed [-Werror,-Wunreachable-code] * ((0) ? (void) (0) : __assert_fail ("0", "bestfcom.c", 254, __PRETTY_FUNCTION__)); * ^ */ assert(0); #ifdef __clang__ #pragma clang diagnostic pop #endif #ifdef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_UNREACHABLE_CODE #pragma GCC diagnostic pop #endif } if (execute("f\r", fstring, sizeof(fstring)) >= 80) { int inverter=0, charger=0, vin=0, vout=0, btimeleft=0, linestat=0, alstat=0, vaout=0; double ampsout=0.0, vbatt=0.0, battpercent=0.0, loadpercent=0.0, upstemp=0.0, acfreq=0.0; char tmp[32]; upsdebugx(3, "f response: %d %s", (int)strlen(fstring), fstring); /* Inverter status. 0=off 1=on */ inverter = bcd2i(&fstring[16], 2); /* Charger status. 0=off 1=on */ charger = bcd2i(&fstring[18], 2); /* Input Voltage. integer number */ vin = bcd2i(&fstring[24], 4); /* Output Voltage. integer number */ vout = bcd2i(&fstring[28], 4); /* Battery voltage. int times 10 */ vbatt = ((double)(bcd2i(&fstring[50], 4)) / 10.0); /* Alarm status reg 1. Bitmask */ alstat = bcd2i(&fstring[20], 2); /* Alarm status reg 2. Bitmask */ alstat = alstat | (bcd2i(&fstring[22], 2) << 8); /* AC line frequency */ acfreq = ((double)(bcd2i(&fstring[54], 4)) / 100.0); /* Runtime remaining (UPS reports minutes) */ btimeleft = bcd2i(&fstring[58], 4) * 60; if (fc.model != FDxxxx) { /* Iout. int times 10 */ ampsout = ((double)(bcd2i(&fstring[36], 4)) / 10.0); /* Volt-amps out. int */ vaout = bcd2i(&fstring[40], 6); /* Line status. Bitmask */ linestat = bcd2i(&fstring[72], 2); } if (fc.model != LIxxxx) { upstemp = (double)(bcd2i(&fstring[62], 4)); } /* Percent Load */ switch(fc.model) { case LIxxxx: case FDxxxx: case FExxxx: case MExxxx: if (execute("d 16\r", tmp, sizeof(tmp)) > 0) { int l; sscanf(tmp, "16 FullLoad%% %d", &l); loadpercent = (double) l; } break; case MDxxxx: if (execute("d 22\r", tmp, sizeof(tmp)) > 0) { int l; sscanf(tmp, "22 FullLoad%% %d", &l); loadpercent = (double) l; } break; default: /* Will never happen, caught in upsdrv_initups() */ fatalx(EXIT_FAILURE, "Unknown model in upsdrv_updateinfo()"); } /* Compute battery percent left based on battery voltages. */ battpercent = ((vbatt - fc.emptyvolts) / (fc.idealbvolts - fc.emptyvolts) * 100.0); if (battpercent < 0.0) battpercent = 0.0; else if (battpercent > 100.0) battpercent = 100.0; /* Compute status string */ { int lowbatt, lowvolts, overload, replacebatt, boosting, trimming; lowbatt = alstat & (1<<1); overload = alstat & (1<<6); replacebatt = alstat & (1<<10); boosting = inverter && (linestat & (1<<2)) && (vin < 115); trimming = inverter && (linestat & (1<<2)) && (vin > 115); /* status bits can be unreliable, so try to help it out */ lowvolts = (vbatt <= fc.lowvolts); status_init(); if (inverter) { if (inverter_status < 1) { upsdebugx(1, "Inverter On, charger: %d battery time left: %d", charger, btimeleft); } inverter_status = 1; status_set("OB"); } else { if (inverter_status) { upsdebugx(1, "Inverter Off, charger: %d battery time left: %d", charger, btimeleft); } inverter_status = 0; status_set("OL"); } if (lowbatt | lowvolts) status_set("LB"); if (trimming) status_set("TRIM"); if (boosting) status_set("BOOST"); if (replacebatt) status_set("RB"); if (overload) status_set("OVER"); status_commit(); } upsdebugx(2, "Poll: inverter %d charger %d vin %d vout %d vaout %d btimeleft %d", inverter, charger, vin, vout, vaout, btimeleft); upsdebugx(2, " vbatt %5.1f batpcnt %5.1f loadpcnt %5.1f upstemp %5.1f ampsout %5.1f acfreq %5.2f", vbatt, battpercent, loadpercent, upstemp, ampsout, acfreq); /* Stuff information into info structures */ dstate_setinfo("input.voltage", "%05.1f", (double)vin); dstate_setinfo("input.frequency", "%05.2f", acfreq); dstate_setinfo("output.voltage", "%05.1f", (double)vout); dstate_setinfo("output.current", "%04.1f", ampsout); dstate_setinfo("battery.charge", "%02.1f", battpercent); dstate_setinfo("battery.voltage", "%02.1f", vbatt); dstate_setinfo("battery.runtime", "%d", btimeleft); dstate_setinfo("ups.load", "%02.1f", loadpercent); if (vaout) dstate_setinfo("ups.power", "%d", vaout); if (upstemp) dstate_setinfo("ups.temperature", "%05.1f", (double)upstemp); dstate_dataok(); } else { upsdebugx(1, "failed f response. strlen: %d", (int)strlen(fstring)); dstate_datastale(); } /* if (execute("f\r", fstring, sizeof(fstring)) >= 80) */ return; } static void ups_sync(void) { char buf[256]; /* A bit better sanity might be good here. As is, we expect the human to observe the time being totally not a time. */ if (execute("time\r", buf, sizeof(buf)) > 0) { upsdebugx(1, "UPS Time: %s", buf); } else { fatalx(EXIT_FAILURE, "Error connecting to UPS."); } /* old Ferrups prompt for new time so send a blank line */ execute("\r", buf, sizeof(buf)); ser_get_line(upsfd, buf, sizeof(buf), '>', "\012", 3, 0); } /* power down the attached load immediately */ void upsdrv_shutdown(void) { /* NB: hard-wired password */ ser_send(upsfd, "pw377\r"); ser_send(upsfd, "o 10 a\r"); /* power off in 10 seconds and restart when line power returns, FE7K required a min of 5 seconds for off to function */ } /* list flags and values that you want to receive via -x */ void upsdrv_makevartable(void) { } void upsdrv_help(void) { } static void sync_serial(void) { char buffer[10]; ser_flush_in(upsfd, "", 1); ser_send(upsfd, "\r"); sleep(UPSDELAY); ser_get_line(upsfd, buffer, sizeof(buffer), '\r', "\012", 3, 0); ser_get_line(upsfd, buffer, sizeof(buffer), ENDCHAR, IGNCHARS, 3, 0); while (ser_get_line(upsfd, buffer, sizeof(buffer), '>', "\012", 3, 0) <= 0) { printf("."); ser_send(upsfd, "\r"); sleep(UPSDELAY); } } /* Begin code stolen from bestups.c */ static void setup_serial(void) { struct termios tio; if (tcgetattr(upsfd, &tio) == -1) fatal_with_errno(EXIT_FAILURE, "tcgetattr"); tio.c_iflag = IXON | IXOFF; tio.c_oflag = 0; tio.c_cflag = (CS8 | CREAD | HUPCL | CLOCAL); tio.c_lflag = 0; tio.c_cc[VMIN] = 1; tio.c_cc[VTIME] = 0; #ifdef HAVE_CFSETISPEED cfsetispeed(&tio, B1200); /* baud change here */ cfsetospeed(&tio, B1200); #else #error This system lacks cfsetispeed() and has no other means to set the speed #endif if (tcsetattr(upsfd, TCSANOW, &tio) == -1) fatal_with_errno(EXIT_FAILURE, "tcsetattr"); /* end code stolen from bestups.c */ sync_serial(); } /* These models don't support the formatconfig (fc) command so use the identify command. "id\r" returns : FERRUPS Uninterruptible Power System By Best Power Technology, Inc. Route 1 Highway 80 / P.O. Box 280 Necedah, WI 54646 USA Sales: (800) 356-5794 Service: (800) 356-5737 FAX: (608) 565-2221 Copyright (C) 1993, 1994, 1995 Best Power Technology, Inc. Model: FE4.3KVA Unit ID: FE4.3K02376 Serial #: FE4.3K02376 Version: 8.07 Released: 08/01/1995 */ static void upsdrv_init_nofc(void) { char tmp[256], rstring[1024]; /* This is a Best UPS * Set initial values for old Fortress??? */ /* Attempt the id command */ ser_send(upsfd, "id\r"); /* prevent upsrecv from timing out */ sleep(UPSDELAY); ser_get_line(upsfd, rstring, sizeof(rstring), '>', "", 3, 0); rstring[sizeof(rstring) - 1] = '\0'; upsdebugx(2, "id response: %s", rstring); /* Better way to identify this unit is using "d 15\r", which results in "15 M# MD1KVA", "id\r" yields "Unit ID "C1K03588"" */ if (strstr(rstring, "Unit ID \"C1K")){ fc.model = MDxxxx; snprintf(fc.name, sizeof(fc.name), "%s", "Micro Ferrups"); /* Determine load rating by Unit Id? */ if (strstr(rstring, "Unit ID \"C1K")) { fc.va = 1100; fc.watts = 770; /* Approximate, based on 0.7 power factor */ } } else if (strstr(rstring, "Unit ID \"ME")){ fc.model = MExxxx; snprintf(fc.name, sizeof(fc.name), "%s", "Micro Ferrups"); /* Determine load rating by Unit Id? */ if (strstr(rstring, "Unit ID \"ME3.1K")) { fc.va = 3100; fc.watts = 2200; } } else if (strstr(rstring, "Unit ID \"FD")){ fc.model = FDxxxx; snprintf(fc.name, sizeof(fc.name), "%s", "Ferrups"); /* Determine load rating by Unit Id? */ if (strstr(rstring, "Unit ID \"FD4.3K")) { fc.va = 4300; fc.watts = 3000; } } else if (strstr(rstring, "Model: FE") || strstr(rstring, "Model: FE")) { fc.model = FExxxx; fc.type = FERRUPS; snprintf(fc.name, sizeof(fc.name), "%s", "Ferrups"); } else if (strlen(rstring) < 300 ) { /* How does the old Fortress respond to this? */ upsdebugx(2, "Old Best Fortress???"); /* fc.model = FORTRESS; */ } if (fc.model == UNKNOWN) { fatalx(EXIT_FAILURE, "Unknown model %s in upsdrv_init_nofc()", rstring); } switch(fc.model) { case MExxxx: case MDxxxx: case FDxxxx: /* determine shutdown battery voltage */ if (execute("d 27\r", tmp, sizeof(tmp)) > 0) { sscanf(tmp, "27 LowBatt %f", &fc.emptyvolts); } /* determine near low battery voltage */ if (execute("d 30\r", tmp, sizeof(tmp)) > 0) { sscanf(tmp, "30 NLBatt %f", &fc.lowvolts); } /* determine fully charged battery voltage */ if (execute("d 28\r", tmp, sizeof(tmp)) > 0) { sscanf(tmp, "28 Hi Batt %f", &fc.fullvolts); } fc.fullvolts = 13.70; /* determine "ideal" voltage by a guess */ fc.idealbvolts = ((fc.fullvolts - fc.emptyvolts) * 0.7) + fc.emptyvolts; break; case FExxxx: if (execute("d 45\r", tmp, sizeof(tmp)) > 0) { sscanf(tmp, "45 RatedVA %d", &fc.va); /* 4300 */ } if (execute("d 46\r", tmp, sizeof(tmp)) > 0) { sscanf(tmp, "46 RatedW %d", &fc.watts); /* 3000 */ } if (execute("d 65\r", tmp, sizeof(tmp)) > 0) { sscanf(tmp, "65 LoBatV %f", &fc.emptyvolts); /* 41.00 */ } if (execute("d 66\r", tmp, sizeof(tmp)) > 0) { sscanf(tmp, "66 NLBatV %f", &fc.lowvolts); /* 44.00 */ } if (execute("d 67\r", tmp, sizeof(tmp)) > 0) { sscanf(tmp, "67 HiBatV %f", &fc.fullvolts); /* 59.60 */ } fc.idealbvolts = ((fc.fullvolts - fc.emptyvolts) * 0.7) + fc.emptyvolts; if (fc.va < 1.0) { fatalx(EXIT_FAILURE, "Error determining Ferrups UPS rating."); } break; default: fatalx(EXIT_FAILURE, "Unknown model %s in upsdrv_init_nofc()", rstring); } fc.valid = 1; } /* These models support the formatconfig (fc) command formatconfig (fc) response is a one-line packed string starting with $ Model Wt rat Vout VHi FrLo BatVN BatNLo LRuntime Model | | | | | | | | | | | | | | | | | | E rev VA rat Vin VLo FrN FrHi BatHi BatLo Opt O || | | | | | | | | | | | | | | | T $010207010600720004701201200911446000570063000240028802150190003??????\LI????VA\\| $010207010600720004701201200911446000570063000240028802150190003??????\LI720VU\LI720VU18112\| 0 0 1 1 2 2 3 3 4 4 5 5 6 6 7 7 8 0 5 0 5 0 5 0 5 0 5 0 5 0 5 0 5 0 Model: [0,1] => 00 = unk, 01 = Patriot/SPS, 02 = FortressII, 03 = Ferrups, 04 = Unity/1 [2,3] => 00 = LI520, 01 = LI720, 02 = LI1020, 03 = LI1420, 07 = ??? */ static void upsdrv_init_fc(const char *fcstring) { char tmp[256]; upsdebugx(3, "fc response: %d %s", (int)strlen(fcstring), fcstring); /* Obtain Model */ if (memcmp(fcstring, "$", 1)) { fatalx(EXIT_FAILURE, "Bad response from formatconfig command in upsdrv_init_fc()"); } if (memcmp(fcstring+3, "00", 2) == 0) { fatalx(EXIT_FAILURE, "UPS type unknown in upsdrv_init_fc()"); } if (memcmp(fcstring+3, "01", 2) == 0) { fatalx(EXIT_FAILURE, "Best Patriot UPS not supported"); } else if (memcmp(fcstring+3, "02", 2) == 0) { snprintf(fc.name, sizeof(fc.name), "%s", "FortressII"); fc.type = FORTRESSII; } else if (memcmp(fcstring+3, "03", 2) == 0) { snprintf(fc.name, sizeof(fc.name), "%s", "Ferrups"); fc.type = FERRUPS; } else if (memcmp(fcstring+3, "04", 2) == 0) { snprintf(fc.name, sizeof(fc.name), "%s", "Unity/1"); fc.type = UNITY1; } /* (fc.type == FORTRESSII || fc.type == FERRUPS || fc.type == UNITY1) */ if (memcmp(fcstring+5, "00", 2) == 0) { /* fc.model = LI520; */ fc.model = LIxxxx; } else if (memcmp(fcstring+5, "01", 2) == 0) { /* fc.model = LI720; */ fc.model = LIxxxx; } else if (memcmp(fcstring+5, "02", 2) == 0) { /* fc.model = LI1020; */ fc.model = LIxxxx; } else if (memcmp(fcstring+5, "03", 2) == 0) { /* fc.model = LI1420; */ fc.model = LIxxxx; } else if (memcmp(fcstring+71, "LI", 2) == 0) { fc.model = LIxxxx; } switch(fc.model) { case LIxxxx: fc.va = bcd2i(&fcstring[11], 5); fc.watts = bcd2i(&fcstring[16], 5); /* determine shutdown battery voltage */ fc.emptyvolts= ((double)(bcd2i(&fcstring[57], 4)) / 10.0); /* determine fully charged battery voltage */ fc.lowvolts= ((double)(bcd2i(&fcstring[53], 4)) / 10.0); /* determine fully charged battery voltage */ fc.fullvolts= ((double)(bcd2i(&fcstring[49], 4)) / 10.0); /* determine "ideal" voltage by a guess */ fc.idealbvolts = ((fc.fullvolts - fc.emptyvolts) * 0.7) + fc.emptyvolts; break; default: fatalx(EXIT_FAILURE, "Unknown model %s in upsdrv_init_fc()", tmp); } fc.valid = 1; } void upsdrv_initups(void) { char rstring[256]; upsfd = ser_open(device_path); ser_set_speed(upsfd, device_path, B1200); setup_serial(); ups_sync(); inverter_status = 0; fc.model = UNKNOWN; if (execute("f\r", rstring, sizeof(rstring)) < 1 ) { fatalx(EXIT_FAILURE, "Failed format request in upsdrc_initups()"); } execute("fc\r", rstring, sizeof(rstring)); if (strlen(rstring) < 80 ) { ser_get_line(upsfd, rstring, sizeof(rstring), '>', "\012", 3, 0); upsdrv_init_nofc(); } else { upsdrv_init_fc(rstring); } return; } void upsdrv_cleanup(void) { ser_close(upsfd, device_path); } nut-2.8.1/drivers/upscode2.c0000644000175000017500000012133714501607135012630 00000000000000/* upscode2.c - model specific routines for UPSes using the UPScode II command set. This includes PowerWare, Fiskars, Compaq (PowerWare OEM?), some IBM (PowerWare OEM?) Copyright (C) 2002 H?vard Lygre Copyright (C) 2004-2006 Niels Baggesen Copyright (C) 2006 Niklas Edmundsson 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 2 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, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ /* * Currently testing against * Fiskars PowerRite Max * Fiskars PowerServer 10 * Fiskars PowerServer 30 * Powerware Profile (9150) * Powerware 9305 * * Also tested against * Compaq T1500h (Per J?nsson ) * Powerware 9120 (Gorm J. Siiger ) * Fiskars PowerServer 10 (Per Larsson ) */ #include "main.h" #include "serial.h" #include "timehead.h" #include "nut_stdint.h" #include "nut_float.h" #define DRIVER_NAME "UPScode II UPS driver" #define DRIVER_VERSION "0.91" /* driver description structure */ upsdrv_info_t upsdrv_info = { DRIVER_NAME, DRIVER_VERSION, "H K Lygre, \n" \ "Niels Baggesen \n" \ "Niklas Edmundsson ", DRV_EXPERIMENTAL, { NULL } }; #define ENDCHAR '\n' /* default values */ #define OUT_PACE_USEC 200 #define INP_TIMO_SEC 2 #define FULL_UPDATE_TIMER 60 #define UPSC_BUFLEN 256 /* Size of response buffers from UPS */ /* Status messages from UPS */ #define UPSC_STAT_ONLINE (1UL << 0) #define UPSC_STAT_ONBATT (1UL << 1) #define UPSC_STAT_LOBATT (1UL << 2) #define UPSC_STAT_REPLACEBATT (1UL << 3) #define UPSC_STAT_BOOST (1UL << 4) #define UPSC_STAT_TRIM (1UL << 5) #define UPSC_STAT_OVERLOAD (1UL << 6) #define UPSC_STAT_CALIBRATION (1UL << 7) #define UPSC_STAT_OFF (1UL << 8) #define UPSC_STAT_BYPASS (1UL << 9) #define UPSC_STAT_NOTINIT (1UL << 31) typedef enum { t_ignore, /* Ignore this response */ t_value, /* Sets a NUT variable */ t_final, /* Marks the end of UPS data for this command */ t_string, /* Set a NUT string variable */ t_finstr, /* Set a NUT string variable, and marks end of data */ t_setval, /* Sets a variable in the driver and possibly in NUT */ t_setrecip, /* Sets a driver variable to 1/value and possibly NUT */ t_setpct, t_setrecpct, t_status, /* Sets a status bit */ t_alarm, /* Sets an alarm message */ t_list /* The value must be matched in the list */ } type_t; typedef struct simple_s { const char *code; type_t type; const char *desc; uint32_t status; float *aux; struct simple_s *stats; } simple_t; typedef struct { const char *cmd; const char *upsc; const char *upsp; int enabled; } cmd_t; static int can_upda = 0, can_upbs = 0, can_upid = 0, can_uppm = 0, can_updt = 0, can_uptm = 0, can_upsd = 0, can_uppc = 0; static char has_uppm_p[100]; static int input_timeout_sec = INP_TIMO_SEC, full_update_timer = FULL_UPDATE_TIMER, use_crlf = 0, use_pre_lf = 0, buffer_empty = 0; static useconds_t output_pace_usec = OUT_PACE_USEC; static uint32_t status = UPSC_STAT_NOTINIT; static time_t last_full = 0; static float batt_volt_low = 0, batt_volt_nom = 0, batt_volt_high = 0, batt_volt = 0, batt_cap_nom = -1, batt_charge = -1, batt_current = -1, batt_disch_curr_max = 0, batt_runtime = -1, batt_runtime_max = -1, kilo_to_unity = 1000.0, outpwr_factor = 1000.0, nom_out_current = -1, max_out_current = -1; /* To get average battery current */ #define NUM_BATTHIST 60 static float batthist[NUM_BATTHIST]; static int numbatthist=0, lastbatthist=0; static int inited_phaseinfo = 0, num_inphases = 1, num_outphases = 1; /* Status codes for the STAT and STMF status responses */ static simple_t att[] = { { "00", t_ignore, NULL, 0, NULL, NULL }, { "AC", t_alarm, "Aux contact failure", 0, NULL, NULL }, { "BA", t_alarm, "Batteries disconnected", 0, NULL, NULL }, { "BC", t_alarm, "Backfeed contact failure", 0, NULL, NULL }, { "BD", t_alarm, "Abnormal battery discharge", 0, NULL, NULL }, { "BF", t_alarm, "Battery fuse failure", 0, NULL, NULL }, { "BL", t_status, "Battery low limit", UPSC_STAT_LOBATT, NULL, NULL }, { "BO", t_alarm, "Battery over voltage", 0, NULL, NULL }, { "BP", t_alarm, "Bypass fuse failure", 0, NULL, NULL }, { "BR", t_alarm, "Abnormal battery recharge", 0, NULL, NULL }, { "BT", t_alarm, "Battery over temperature", 0, NULL, NULL }, { "BX", t_alarm, "Bypass unavailable", 0, NULL, NULL }, { "BY", t_alarm, "Battery failure", 0, NULL, NULL }, { "CE", t_alarm, "Configuration error", 0, NULL, NULL }, { "CM", t_alarm, "Battery converter failure", 0, NULL, NULL }, { "CT", t_alarm, "Cabinet over temperature", 0, NULL, NULL }, { "DO", t_alarm, "DC over voltage", 0, NULL, NULL }, { "DU", t_alarm, "DC under voltage", 0, NULL, NULL }, { "EP", t_alarm, "Emergency power off", 0, NULL, NULL }, { "FF", t_alarm, "Fan failure", 0, NULL, NULL }, { "FH", t_alarm, "Line frequency high", 0, NULL, NULL }, { "FL", t_alarm, "Line frequency low", 0, NULL, NULL }, { "FT", t_alarm, "Filter over temperature", 0, NULL, NULL }, { "GF", t_alarm, "Ground failure", 0, NULL, NULL }, { "HT", t_alarm, "Charger over temperature", 0, NULL, NULL }, { "IB", t_alarm, "Internal data bus failure", 0, NULL, NULL }, { "IF", t_alarm, "Inverter fuse failure", 0, NULL, NULL }, { "IM", t_alarm, "Inverter failure", 0, NULL, NULL }, { "IO", t_alarm, "Inverter over voltage", 0, NULL, NULL }, { "IP", t_alarm, "Internal power supply failure", 0, NULL, NULL }, { "IT", t_alarm, "Inverter over temperature", 0, NULL, NULL }, { "IU", t_alarm, "Inverter under voltage", 0, NULL, NULL }, { "IV", t_alarm, "Inverter off", 0, NULL, NULL }, { "LR", t_alarm, "Loss of redundancy", 0, NULL, NULL }, { "NF", t_alarm, "Neutral fault", 0, NULL, NULL }, { "OD", t_status, "UPS not supplying load", UPSC_STAT_OFF, NULL, NULL }, { "OF", t_alarm, "Oscillator failure", 0, NULL, NULL }, { "OL", t_status, "Overload", UPSC_STAT_OVERLOAD, NULL, NULL }, { "OR", t_alarm, "Redundancy overload", 0, NULL, NULL }, { "OV", t_alarm, "Abnormal output voltage", 0, NULL, NULL }, { "OW", t_alarm, "Output failure", 0, NULL, NULL }, { "PB", t_alarm, "Parallel bus failure", 0, NULL, NULL }, { "PE", t_alarm, "Phase rotation error", 0, NULL, NULL }, { "RE", t_alarm, "Rectifier off", 0, NULL, NULL }, { "RF", t_alarm, "Rectifier fuse failure", 0, NULL, NULL }, { "RM", t_alarm, "Rectifier failure", 0, NULL, NULL }, { "RT", t_alarm, "Rectifier over temperature", 0, NULL, NULL }, { "SM", t_alarm, "Static switch failure", 0, NULL, NULL }, { "ST", t_alarm, "Static switch over temperature", 0, NULL, NULL }, { "TT", t_alarm, "Trafo over temperature", 0, NULL, NULL }, { "UD", t_alarm, "UPS disabled", 0, NULL, NULL }, { "UO", t_alarm, "Utility over voltage", 0, NULL, NULL }, { "US", t_alarm, "Unsynchronized", 0, NULL, NULL }, { "UU", t_alarm, "Utility under voltage", 0, NULL, NULL }, { "VE", t_alarm, "internal voltage error", 0, NULL, NULL }, { NULL, t_ignore, NULL, 0, NULL, NULL } }; /* Status code for the STLR response */ static simple_t stlr[] = { { "NO", t_ignore, NULL, 0, NULL, NULL }, { "SD", t_status, NULL, UPSC_STAT_TRIM, NULL, NULL }, { "SU", t_status, NULL, UPSC_STAT_BOOST, NULL, NULL }, { "DU", t_status, NULL, UPSC_STAT_BOOST, NULL, NULL }, { NULL, t_ignore, NULL, 0, NULL, NULL } }; /* Status code for the STEA and STEM responses */ static simple_t env[] = { { "HH", t_ignore, "Humidity high", 0, NULL, NULL }, { "HL", t_ignore, "Humidity low", 0, NULL, NULL }, { "TH", t_ignore, "Temperature high", 0, NULL, NULL }, { "TL", t_ignore, "Temperature low", 0, NULL, NULL }, { "01", t_ignore, "Environment alarm 1", 0, NULL, NULL }, { "02", t_ignore, "Environment alarm 2", 0, NULL, NULL }, { "03", t_ignore, "Environment alarm 3", 0, NULL, NULL }, { "04", t_ignore, "Environment alarm 4", 0, NULL, NULL }, { "05", t_ignore, "Environment alarm 5", 0, NULL, NULL }, { "06", t_ignore, "Environment alarm 6", 0, NULL, NULL }, { "07", t_ignore, "Environment alarm 7", 0, NULL, NULL }, { "08", t_ignore, "Environment alarm 8", 0, NULL, NULL }, { "09", t_ignore, "Environment alarm 9", 0, NULL, NULL }, { NULL, t_ignore, NULL, 0, NULL, NULL } }; /* Responses for UPSS and UPDS */ static simple_t simple[] = { { "STAT", t_list, NULL, 0, NULL, att }, { "STBO", t_status, NULL, UPSC_STAT_ONBATT, NULL, NULL }, { "STBL", t_status, NULL, UPSC_STAT_LOBATT, NULL, NULL }, { "STBM", t_ignore, NULL, 0, NULL, NULL }, { "STBP", t_status, NULL, UPSC_STAT_BYPASS, NULL, NULL }, { "STEA", t_list, NULL, 0, NULL, env }, { "STEM", t_list, NULL, 0, NULL, env }, { "STLR", t_list, NULL, 0, NULL, stlr }, { "STMF", t_list, NULL, 0, NULL, att }, { "STOK", t_ignore, NULL, 0, NULL, NULL }, { "STUF", t_status, NULL, UPSC_STAT_ONBATT, NULL, NULL }, { "BTIME", t_setval, NULL, 0, &batt_runtime, NULL }, { "METE1", t_value, "ambient.temperature", 0, NULL, NULL }, { "MERH1", t_value, "ambient.humidity", 0, NULL, NULL }, { "MIFFF", t_value, "input.frequency", 0, NULL, NULL }, { "MIIL1", t_value, "input.current", 0, NULL, NULL }, { "MIIL2", t_value, "input.L2.current", 0, NULL, NULL }, { "MIIL3", t_value, "input.L3.current", 0, NULL, NULL }, { "MIPL1", t_value, "input.realpower", 0, NULL, NULL }, { "MIPL2", t_value, "input.L2.realpower", 0, NULL, NULL }, { "MIPL3", t_value, "input.L3.realpower", 0, NULL, NULL }, { "MISL1", t_value, "input.power", 0, NULL, NULL }, { "MISL2", t_value, "input.L2.power", 0, NULL, NULL }, { "MISL3", t_value, "input.L3.power", 0, NULL, NULL }, { "MIUL1", t_value, "input.voltage", 0, NULL, NULL }, { "MIUL2", t_value, "input.L2-N.voltage", 0, NULL, NULL }, { "MIUL3", t_value, "input.L3-N.voltage", 0, NULL, NULL }, { "MIU12", t_value, "input.L1-L2.voltage", 0, NULL, NULL }, { "MIU23", t_value, "input.L2-L3.voltage", 0, NULL, NULL }, { "MIU31", t_value, "input.L3-L1.voltage", 0, NULL, NULL }, { "MBCH1", t_setval, NULL, 0, &batt_charge, NULL }, /* battery.charge */ { "MBIII", t_setval, "battery.current", 0, &batt_current, NULL }, { "MBINE", t_ignore, /* "battery.current.negative" */ NULL, 0, NULL, NULL }, { "MBIPO", t_ignore, /* "battery.current.positive" */ NULL, 0, NULL, NULL }, { "MBUNE", t_ignore, /* "battery.voltage.negative" */ NULL, 0, NULL, NULL }, { "MBUPO", t_ignore, /* "battery.voltage.positive" */ NULL, 0, NULL, NULL }, { "MBUUU", t_setval, "battery.voltage", 0, &batt_volt, NULL }, { "MLUNE", t_ignore, /* "dc.voltage.negative" */ NULL, 0, NULL, NULL }, { "MLUPO", t_ignore, /* "dc.voltage.positive" */ NULL, 0, NULL, NULL }, { "MLUUU", t_ignore, /* "dc.voltage" */ NULL, 0, NULL, NULL }, { "MOFFF", t_final, "output.frequency", 0, NULL, NULL }, { "MOIL1", t_value, "output.current", 0, NULL, NULL }, { "MOIL2", t_value, "output.L2.current", 0, NULL, NULL }, { "MOIL3", t_value, "output.L3.current", 0, NULL, NULL }, { "MOIP1", t_value, "output.current.peak", 0, NULL, NULL }, { "MOIP2", t_value, "output.L2.current.peak", 0, NULL, NULL }, { "MOIP3", t_value, "output.L3.current.peak", 0, NULL, NULL }, { "MOPL1", t_value, "output.realpower", 0, &kilo_to_unity, NULL }, { "MOPL2", t_value, "output.L2.realpower", 0, &kilo_to_unity, NULL }, { "MOPL3", t_value, "output.L3.realpower", 0, &kilo_to_unity, NULL }, { "MOSL1", t_value, "output.power", 0, NULL, NULL }, { "MOSL2", t_value, "output.L2.power", 0, NULL, NULL }, { "MOSL3", t_value, "output.L3.power", 0, NULL, NULL }, { "MOUL1", t_value, "output.voltage", 0, NULL, NULL }, { "MOUL2", t_value, "output.L2-N.voltage", 0, NULL, NULL }, { "MOUL3", t_value, "output.L3-N.voltage", 0, NULL, NULL }, { "MOU12", t_value, "output.L1-L2.voltage", 0, NULL, NULL }, { "MOU23", t_value, "output.L2-L3.voltage", 0, NULL, NULL }, { "MOU31", t_value, "output.L3-L1.voltage", 0, NULL, NULL }, { "MPUL1", t_value, "input.bypass.L1-N.voltage", 0, NULL, NULL }, { "MPUL2", t_value, "input.bypass.L2-N.voltage", 0, NULL, NULL }, { "MPUL3", t_value, "input.bypass.L3-N.voltage", 0, NULL, NULL }, { "MUTE1", t_value, "ups.temperature", 0, NULL, NULL }, { NULL, t_ignore, NULL, 0, NULL, NULL } }; /* Responses for UPDV */ static simple_t nominal[] = { { "NIUHH", t_value, "input.voltage.maximum", 0, NULL, NULL }, { "NIULL", t_value, "input.voltage.minimum", 0, NULL, NULL }, { "NIUNN", t_value, "input.voltage.nominal", 0, NULL, NULL }, { "NIIHH", t_value, "input.current.maximum", 0, NULL, NULL }, { "NIILL", t_value, "input.current.minimum", 0, NULL, NULL }, { "NIINN", t_value, "input.current.nominal", 0, NULL, NULL }, { "NIPHH", t_value, "input.realpower.maximum", 0, NULL, NULL }, { "NIPNN", t_value, "input.realpower.nominal", 0, NULL, NULL }, { "NISHH", t_value, "input.power.maximum", 0, NULL, NULL }, { "NISNN", t_value, "input.power.nominal", 0, NULL, NULL }, { "NBAHN", t_setval, "battery.capacity.nominal", 0, &batt_cap_nom, NULL }, { "NBIHH", t_ignore, "battery charge current maximum", 0, NULL, NULL }, { "NBILL", t_setval, NULL, 0, &batt_disch_curr_max, NULL }, { "NBINN", t_value, "battery.current.nominal", 0, NULL, NULL }, { "NBTHH", t_setval, NULL, 0, &batt_runtime_max, NULL }, { "NBUHH", t_setval, "battery.voltage.maximum", 0, &batt_volt_high, NULL }, { "NBULL", t_setval, "battery.voltage.minimum", 0, &batt_volt_low, NULL }, { "NBUNN", t_setval, "battery.voltage.nominal", 0, &batt_volt_nom, NULL }, { "NOFHH", t_value, "output.frequency.maximum", 0, NULL, NULL }, { "NOFLL", t_final, "output.frequency.minimum", 0, NULL, NULL }, { "NOIHH", t_setval, "output.current.maximum", 0, &max_out_current, NULL }, { "NOINN", t_setval, "output.current.nominal", 0, &nom_out_current, NULL }, { "NOPNN", t_value, "output.realpower.nominal", 0, &outpwr_factor, NULL }, { "NOSNN", t_value, "ups.power.nominal", 0, &outpwr_factor, NULL }, { "NOUHH", t_value, "output.voltage.maximum", 0, NULL, NULL }, { "NOULL", t_value, "output.voltage.minimum", 0, NULL, NULL }, { "NOUNN", t_value, "output.voltage.nominal", 0, NULL, NULL }, { "NUTEH", t_value, "ups.temperature.maximum", 0, NULL, NULL }, { NULL, t_ignore, NULL, 0, NULL, NULL } }; /* Status responses for UPBS command */ static simple_t battery[] = { { "MBTE1", t_value, "battery.1.temperature", 0, NULL, NULL }, { "MBIN1", t_ignore, NULL /* aging index */, 0, NULL, NULL }, { "BDAT1", t_string, "battery.1.date", 0, NULL, NULL }, { "MBTE2", t_value, "battery.2.temperature.2", 0, NULL, NULL }, { "MBIN2", t_ignore, NULL, 0, NULL, NULL }, { "BDAT2", t_string, "battery.2.date", 0, NULL, NULL }, { "MBTE3", t_value, "battery.3.temperature", 0, NULL, NULL }, { "MBIN3", t_ignore, NULL, 0, NULL, NULL }, { "BDAT3", t_string, "battery.3.date", 0, NULL, NULL }, { "MBTE4", t_value, "battery.4.temperature", 0, NULL, NULL }, { "MBIN4", t_ignore, NULL, 0, NULL, NULL }, { "BDAT4", t_string, "battery.4.date", 0, NULL, NULL }, { "MBTE5", t_value, "battery.5.temperature", 0, NULL, NULL }, { "MBIN5", t_ignore, NULL, 0, NULL, NULL }, { "BDAT5", t_string, "battery.5.date", 0, NULL, NULL }, { "MBTE6", t_value, "battery.6.temperature", 0, NULL, NULL }, { "MBIN6", t_ignore, NULL, 0, NULL, NULL }, { "BDAT6", t_string, "battery.6.date", 0, NULL, NULL }, { "MBTE7", t_value, "battery.7.temperature", 0, NULL, NULL }, { "MBIN7", t_ignore, NULL, 0, NULL, NULL }, { "BDAT7", t_string, "battery.7.date", 0, NULL, NULL }, { "MBTE8", t_value, "battery.8.temperature", 0, NULL, NULL }, { "MBIN8", t_ignore, NULL, 0, NULL, NULL }, { "BDAT8", t_finstr, "battery.8.date", 0, NULL, NULL }, { NULL, t_ignore, NULL, 0, NULL, NULL } }; static cmd_t commands[] = { { "load.off", NULL, NULL, 0 }, { "load.on", NULL, NULL, 0 }, { "shutdown.return", "UPPF", "IJHLDMGCIU", 0 }, { "shutdown.stayoff", "UPPD", "LGGNLMDPGV", 0 }, { "shutdown.stop", "UPPU", NULL, 0 }, { "shutdown.reboot", "UPPC", "IJHLDMGCIU", 0 }, { "shutdown.reboot.graceful", NULL, NULL, 0 }, { "test.panel.start", "UPIS", NULL, 0 }, { "test.panel.stop", NULL, NULL, 0 }, { "test.failure.start", NULL, NULL, 0 }, { "test.failure.stop", NULL, NULL, 0 }, { "test.battery.start", "UPBT", "1", 0 }, { "test.battery.stop", NULL, NULL, 0 }, { "calibrate.start", NULL, NULL, 0 }, { "calibrate.stop", NULL, NULL, 0 }, { "bypass.start", NULL, NULL, 0 }, { "bypass.stop", NULL, NULL, 0 }, { "reset.input.minmax", NULL, NULL, 0 }, { "reset.watchdog", NULL, NULL, 0 }, { "beeper.enable", NULL, NULL, 0 }, { "beeper.disable", NULL, NULL, 0 }, { "beeper.on", NULL, NULL, 0 }, { "beeper.off", NULL, NULL, 0 }, { NULL, NULL, NULL, 0 } }; static cmd_t variables[] = { { "ups.delay.reboot", "UPCD", "ACCD", 0 }, { "ups.delay.shutdown", "UPSD", "ACSD", 0 }, { NULL, NULL, NULL, 0 } }; static int instcmd (const char *auxcmd, const char *data); static int setvar (const char *var, const char *data); static void upsc_setstatus(unsigned int upsc_status); static void upsc_flush_input(void); static void upsc_getbaseinfo(void); static int upsc_commandlist(void); static int upsc_getparams(const char *cmd, const simple_t *table); static int upsc_getvalue(const char *cmd, const char *param, const char *resp, const char *var, char *ret); static ssize_t upscsend(const char *cmd); static ssize_t upscrecv(char *buf); static int upsc_simple(const simple_t *sp, const char *var, const char *val); static void check_uppm(void); static float batt_charge_pct(void); void upsdrv_help(void) { } void upsdrv_initups(void) { struct termios tio; speed_t baud = B1200; char *str; if ((str = getval("baudrate")) != NULL) { int temp = atoi(str); switch (temp) { case 300: baud = B300; break; case 600: baud = B600; break; case 1200: baud = B1200; break; case 2400: baud = B2400; break; case 4800: baud = B4800; break; case 9600: baud = B9600; break; case 19200: baud = B19200; break; case 38400: baud = B38400; break; default: fatalx(EXIT_FAILURE, "Unrecognized baudrate: %s", str); } upsdebugx(1, "baud_rate = %d", temp); } upsfd = ser_open(device_path); ser_set_speed(upsfd, device_path, baud); if (tcgetattr(upsfd, &tio) != 0) fatal_with_errno(EXIT_FAILURE, "tcgetattr(%s)", device_path); tio.c_lflag = ICANON; tio.c_iflag |= IGNCR; /* Ignore CR */ tio.c_cc[VMIN] = 0; tio.c_cc[VTIME] = 0; tcsetattr(upsfd, TCSANOW, &tio); if ((str = getval("input_timeout")) != NULL) { int temp = atoi(str); if (temp <= 0) fatalx(EXIT_FAILURE, "Bad input_timeout parameter: %s", str); input_timeout_sec = temp; } upsdebugx(1, "input_timeout = %d Sec", input_timeout_sec); if ((str = getval("output_pace")) != NULL) { /* Range should be at least up to 1000000; a C99+ long guarantees that */ long temp = atol(str); if (temp <= 0) fatalx(EXIT_FAILURE, "Bad output_pace parameter: %s", str); output_pace_usec = (useconds_t)temp; } upsdebugx(1, "output_pace = %" PRIuMAX " uSec", (uintmax_t)output_pace_usec); if ((str = getval("full_update_timer")) != NULL) { int temp = atoi(str); if (temp <= 0) fatalx(EXIT_FAILURE, "Bad full_update_timer parameter: %s", str); full_update_timer = temp; } upsdebugx(1, "full_update_timer = %d Sec", full_update_timer); use_crlf = testvar("use_crlf"); upsdebugx(1, "use_crlf = %d", use_crlf); use_pre_lf = testvar("use_pre_lf"); upsdebugx(1, "use_pre_lf = %d", use_pre_lf); } void upsdrv_initinfo(void) { if (!upsc_commandlist()) { upslogx(LOG_ERR, "No contact with UPS, delaying init."); status = UPSC_STAT_NOTINIT; return; } else { status = 0; } upsc_getbaseinfo(); if (can_upda) { upsc_flush_input(); upscsend("UPDA"); } if (can_upid) { upsc_getvalue("UPID", NULL, "ACID", "ups.id", NULL); } if (can_uppm) { check_uppm(); } /* make sure we have some sensible defaults */ setvar("ups.delay.shutdown", "10"); setvar("ups.delay.reboot", "60"); upsh.instcmd = instcmd; upsh.setvar = setvar; } /* Change a variable name in a table */ static void change_name(simple_t *sp, const char *oldname, const char *newname) { while(sp->code) { if (sp->desc && !strcmp(sp->desc, oldname)) { sp->desc = strdup(newname); if (dstate_getinfo(oldname)) { dstate_setinfo(newname, "%s", dstate_getinfo(oldname)); } dstate_delinfo(oldname); upsdebugx(1, "Changing name: %s => %s", oldname, newname); break; } sp++; } } static float calc_upsload(void) { float load=-1, nom_out_power=-1, nom_out_realpower=-1, maxcurr, tmp; const char *s; /* Some UPSen (Fiskars 9000 for example) only reports current, and * only the max current */ if (nom_out_current > 0) { maxcurr = nom_out_current; } else { maxcurr = max_out_current; } if (maxcurr > 0) { if ((s=dstate_getinfo("output.L1.current")) || (s=dstate_getinfo("output.current"))) { if (sscanf(s, "%f", &tmp) == 1) { load = tmp/maxcurr; } } if ((s=dstate_getinfo("output.L2.current"))) { if (sscanf(s, "%f", &tmp) == 1) { tmp=tmp/maxcurr; if (tmp>load) { load = tmp; } } } if ((s=dstate_getinfo("output.L3.current"))) { if (sscanf(s, "%f", &tmp) == 1) { tmp=tmp/maxcurr; if (tmp>load) { load = tmp; } } } } /* This is aggregated (all phases) */ if ((s=dstate_getinfo("ups.power.nominal"))) { if (sscanf(s, "%f", &nom_out_power) != 1) { nom_out_power = -1; } } if (nom_out_power > 0) { if ((s=dstate_getinfo("output.L1.power"))) { if (sscanf(s, "%f", &tmp) == 1) { tmp /= (nom_out_power/num_outphases); if (tmp>load) { load = tmp; } dstate_setinfo("output.L1.power.percent", "%.1f", tmp*100); } } if ((s=dstate_getinfo("output.L2.power"))) { if (sscanf(s, "%f", &tmp) == 1) { tmp /= (nom_out_power/num_outphases); if (tmp>load) { load = tmp; } dstate_setinfo("output.L2.power.percent", "%.1f", tmp*100); } } if ((s=dstate_getinfo("output.L3.power"))) { if (sscanf(s, "%f", &tmp) == 1) { tmp /= (nom_out_power/num_outphases); if (tmp>load) { load = tmp; } dstate_setinfo("output.L3.power.percent", "%.1f", tmp*100); } } } /* This is aggregated (all phases) */ if ((s=dstate_getinfo("output.realpower.nominal"))) { if (sscanf(s, "%f", &nom_out_realpower) != 1) { nom_out_realpower = -1; } } if (nom_out_realpower >= 0) { if ((s=dstate_getinfo("output.L1.realpower"))) { if (sscanf(s, "%f", &tmp) == 1) { tmp /= (nom_out_realpower/num_outphases); if (tmp>load) { load = tmp; } dstate_setinfo("output.L1.realpower.percent", "%.1f", tmp*100); } } if ((s=dstate_getinfo("output.L2.realpower"))) { if (sscanf(s, "%f", &tmp) == 1) { tmp /= (nom_out_realpower/num_outphases); if (tmp>load) { load = tmp; } dstate_setinfo("output.L2.realpower.percent", "%.1f", tmp*100); } } if ((s=dstate_getinfo("output.L3.realpower"))) { if (sscanf(s, "%f", &tmp) == 1) { tmp /= (nom_out_realpower/num_outphases); if (tmp>load) { load = tmp; } dstate_setinfo("output.L3.realpower.percent", "%.1f", tmp*100); } } } return load; } void upsdrv_updateinfo(void) { time_t now; int ok; float load; if (status & UPSC_STAT_NOTINIT) { upsdrv_initinfo(); } if (status & UPSC_STAT_NOTINIT) { return; } status = 0; ok = upsc_getparams("UPDS", simple); time(&now); if (ok && now - last_full > full_update_timer) { last_full = now; ok = upsc_getparams("UPDV", nominal); if (ok && can_upbs) ok = upsc_getparams("UPBS", battery); } if (!ok) { dstate_datastale(); last_full = 0; return; } if (!inited_phaseinfo) { if (dstate_getinfo("input.L3-L1.voltage") || dstate_getinfo("input.L3-N.voltage")) { num_inphases = 3; change_name(simple, "input.current", "input.L1.current"); change_name(simple, "input.realpower", "input.L1.realpower"); change_name(simple, "input.power", "input.L1.power"); change_name(simple, "input.voltage", "input.L1-N.voltage"); } if (dstate_getinfo("output.L3-L1.voltage") || dstate_getinfo("output.L3-N.voltage")) { const char *s; num_outphases = 3; if ((s=dstate_getinfo("ups.model")) && (!strncmp(s, "UPS9075", 7) || !strncmp(s, "UPS9100", 7) || !strncmp(s, "UPS9150", 7) || !strncmp(s, "UPS9200", 7) || !strncmp(s, "UPS9250", 7) || !strncmp(s, "UPS9300", 7) || !strncmp(s, "UPS9400", 7) || !strncmp(s, "UPS9500", 7) || !strncmp(s, "UPS9600", 7)) ) { /* Insert kludges for Fiskars UPS9000 here */ upslogx(LOG_INFO, "Fiskars UPS9000 detected, protocol kludges activated"); batt_volt_nom = 384; dstate_setinfo("battery.voltage.nominal", "%.0f", batt_volt_nom); } else { outpwr_factor *= 3; } change_name(simple, "output.current", "output.L1.current"); change_name(simple, "output.current.peak", "output.L1.current.peak"); change_name(simple, "output.realpower", "output.L1.realpower"); change_name(simple, "output.power", "output.L1.power"); change_name(simple, "output.voltage", "output.L1-N.voltage"); } dstate_setinfo("input.phases", "%d", num_inphases); dstate_setinfo("output.phases", "%d", num_outphases); inited_phaseinfo=1; } load = calc_upsload(); if (load >= 0) { upsdebugx(2, "ups.load: %.1f", load*100); dstate_setinfo("ups.load", "%.1f", load*100); } else { upsdebugx(2, "ups.load: No value"); } /* TODO/FIXME: Set UPS date/time on startup and daily if needed */ if (can_updt) { char dtbuf[UPSC_BUFLEN]; if (upsc_getvalue("UPDT", "0", "ACDT", NULL, dtbuf)) { dstate_setinfo("ups.date", "%s", dtbuf); } } if (can_uptm) { char tmbuf[UPSC_BUFLEN]; if (upsc_getvalue("UPTM", "0", "ACTM", NULL, tmbuf)) { dstate_setinfo("ups.time", "%s", tmbuf); } } if (batt_charge < 0) { if (batt_current < 0) { /* Reset battery current history if discharging */ numbatthist = lastbatthist = 0; } batt_charge = batt_charge_pct(); } if (batt_charge >= 0) { dstate_setinfo("battery.charge", "%.1f", batt_charge); } else { dstate_delinfo("battery.charge"); } /* 9999 == unknown value */ if (batt_runtime >= 0 && batt_runtime < 9999) { dstate_setinfo("battery.runtime", "%.0f", batt_runtime*60); } else if (load > 0 && ! f_equal(batt_disch_curr_max, 0)) { float est_battcurr = load * fabs(batt_disch_curr_max); /* Peukert equation */ float runtime = (batt_cap_nom*3600)/pow(est_battcurr, 1.35); upsdebugx(2, "Calculated runtime: %.0f seconds", runtime); if (batt_runtime_max > 0 && runtime > batt_runtime_max*60) { runtime = batt_runtime_max*60; } dstate_setinfo("battery.runtime", "%.0f", runtime); } else if (batt_runtime_max > 0) { /* Show max possible runtime as reported by UPS */ dstate_setinfo("battery.runtime", "%.0f", batt_runtime_max*60); } else { dstate_delinfo("battery.runtime"); } /* Some UPSen only provides this when on battery, so reset between * each iteration to make sure we use the right value */ batt_charge = -1; batt_runtime = -1; if (!(status & UPSC_STAT_ONBATT)) status |= UPSC_STAT_ONLINE; upsc_setstatus(status); dstate_dataok(); ser_comm_good(); } void upsdrv_shutdown(void) { upslogx(LOG_EMERG, "Shutting down..."); /* send shutdown command twice, just to be sure */ instcmd("shutdown.reboot", NULL); sleep(1); instcmd("shutdown.reboot", NULL); sleep(1); } static int instcmd (const char *auxcmd, const char *data) { cmd_t *cp; if (!strcasecmp(auxcmd, "beeper.off")) { /* compatibility mode for old command */ upslogx(LOG_WARNING, "The 'beeper.off' command has been renamed to 'beeper.disable'"); return instcmd("beeper.disable", NULL); } if (!strcasecmp(auxcmd, "beeper.on")) { /* compatibility mode for old command */ upslogx(LOG_WARNING, "The 'beeper.on' command has been renamed to 'beeper.enable'"); return instcmd("beeper.enable", NULL); } upsdebugx(1, "Instcmd: %s %s", auxcmd, data ? data : "\"\""); for (cp = commands; cp->cmd; cp++) { if (strcasecmp(cp->cmd, auxcmd)) { continue; } upscsend(cp->upsc); if (cp->upsp) { upscsend(cp->upsp); } else if (data) { upscsend(data); } return STAT_INSTCMD_HANDLED; } upslogx(LOG_INFO, "instcmd: unknown command %s", auxcmd); return STAT_INSTCMD_UNKNOWN; } static int setvar (const char *var, const char *data) { cmd_t *cp; upsdebugx(1, "Setvar: %s %s", var, data); for (cp = variables; cp->cmd; cp++) { if (strcasecmp(cp->cmd, var)) { continue; } upsc_getvalue(cp->upsc, data, cp->upsp, cp->cmd, NULL); return STAT_SET_HANDLED; } upslogx(LOG_INFO, "Setvar: unsettable variable %s", var); return STAT_SET_UNKNOWN; } /* list flags and values that you want to receive via -x */ void upsdrv_makevartable(void) { addvar(VAR_VALUE, "manufacturer", "manufacturer [unknown]"); addvar(VAR_VALUE, "baudrate", "Serial interface baudrate [1200]"); addvar(VAR_VALUE, "input_timeout", "Command response timeout [2]"); addvar(VAR_VALUE, "output_pace", "Output character delay in usecs [200]"); addvar(VAR_VALUE, "full_update", "Delay between full value downloads [60]"); addvar(VAR_FLAG, "use_crlf", "Use CR-LF to terminate commands to UPS"); addvar(VAR_FLAG, "use_pre_lf", "Use LF to introduce commands to UPS"); } void upsdrv_cleanup(void) { ser_close(upsfd, device_path); } /* * Generate status string from bitfield */ static void upsc_setstatus(unsigned int upsc_status) { /* Save into global state variable for the driver instance */ status = upsc_status; /* * I'll look for all available statuses, even though they might not be * supported in the UPScode II protocol. */ status_init(); if (status & UPSC_STAT_ONLINE) status_set("OL"); if (status & UPSC_STAT_ONBATT) status_set("OB"); if (status & UPSC_STAT_LOBATT) status_set("LB"); if (status & UPSC_STAT_REPLACEBATT) status_set("RB"); if (status & UPSC_STAT_BOOST) status_set("BOOST"); if (status & UPSC_STAT_TRIM) status_set("TRIM"); if (status & UPSC_STAT_OVERLOAD) status_set("OVER"); if (status & UPSC_STAT_CALIBRATION) status_set("CAL"); if (status & UPSC_STAT_OFF) status_set("OFF"); if (status & UPSC_STAT_BYPASS) status_set("BYPASS"); status_commit(); } /* Add \r to end of command and send to UPS */ /* returns < 0 on errors, 0 on timeout and > 0 on success. */ static ssize_t upscsend(const char *cmd) { ssize_t res; res = ser_send_pace(upsfd, output_pace_usec, "%s%s%s", use_pre_lf ? "\n" : "", cmd, use_crlf ? "\r\n" : "\r"); if (res < 0) { upsdebug_with_errno(3, "upscsend"); } else if (res == 0) { upsdebugx(3, "upscsend: Timeout"); } else { upsdebugx(3, "upscsend: '%s'", cmd); } return res; } /* Return a string read from UPS */ /* returns < 0 on errors, 0 on timeout and > 0 on success. */ static ssize_t upscrecv(char *buf) { ssize_t res; /* NOTE: the serial port is set to use Canonical Mode Input Processing, which means ser_get_buf() either returns one line terminated with ENDCHAR, an error or times out. */ while (1) { res = ser_get_buf(upsfd, buf, UPSC_BUFLEN, input_timeout_sec, 0); if (res != 1) { break; } /* Only one character, must be ENDCHAR */ upsdebugx(3, "upscrecv: Empty line"); } if (res < 0) { upsdebug_with_errno(3, "upscrecv"); } else if (res == 0) { upsdebugx(3, "upscrecv: Timeout"); } else { /* Note: s should end up same as buf */ char *s = str_rtrim(buf, ENDCHAR); upsdebugx(3, "upscrecv: %" PRIiSIZE " bytes:\t'%s'", res-1, s); } return res; } static void upsc_flush_input(void) { /* char buf[UPSC_BUFLEN]; do { upscrecv(buf); if (strlen(buf) > 0) upsdebugx(1, "Skipping input: %s", buf); } while (strlen(buf) > 0); */ ser_flush_in(upsfd, "", nut_debug_level); } /* check which commands this ups supports. * Returns TRUE if command list was recieved, FALSE otherwise */ static int upsc_commandlist(void) { char buf[UPSC_BUFLEN]; cmd_t *cp; upsc_flush_input(); upscsend("UPCL"); while (1) { upscrecv(buf); if (strlen(buf) == 0) { upslogx(LOG_ERR, "Missing UPCL after UPCL"); return 0; } upsdebugx(2, "Supports command: %s", buf); if (strcmp(buf, "UPBS") == 0) can_upbs = 1; else if (strcmp(buf, "UPPM") == 0) can_uppm = 1; else if (strcmp(buf, "UPID") == 0) can_upid = 1; else if (strcmp(buf, "UPDA") == 0) can_upda = 1; else if (strcmp(buf, "UPDT") == 0) can_updt = 1; else if (strcmp(buf, "UPTM") == 0) can_uptm = 1; else if (strcmp(buf, "UPSD") == 0) can_upsd = 1; else if (strcmp(buf, "UPPC") == 0) can_uppc = 1; for (cp = commands; cp->cmd; cp++) { if (cp->upsc && strcmp(cp->upsc, buf) == 0) { upsdebugx(1, "instcmd: %s %s", cp->cmd, cp->upsc); dstate_addcmd(cp->cmd); cp->enabled = 1; break; } } for (cp = variables; cp->cmd; cp++) { if (cp->upsc && strcmp(cp->upsc, buf) == 0) { upsdebugx(1, "setvar: %s %s", cp->cmd, cp->upsc); cp->enabled = 1; break; } } if (strcmp(buf, "UPCL") == 0) break; } for (cp = variables; cp->cmd; cp++) { if (cp->enabled) { upsc_getvalue(cp->upsc, "0000", cp->upsp, cp->cmd, NULL); dstate_setflags(cp->cmd, ST_FLAG_RW | ST_FLAG_STRING); dstate_setaux(cp->cmd, 7); } } return 1; } /* get limits and parameters */ static int upsc_getparams(const char *cmd, const simple_t *table) { char var[UPSC_BUFLEN]; char val[UPSC_BUFLEN]; int first = 1; upsc_flush_input(); upscsend(cmd); buffer_empty = 0; while (!buffer_empty) { upscrecv(var); if (strlen(var) == 0) { if (first) upscrecv(var); if (strlen(var) == 0) { ser_comm_fail("Empty string from UPS for %s!", cmd); break; } } first = 0; upscrecv(val); if (strlen(val) == 0) { ser_comm_fail("Empty value from UPS for %s %s!", cmd, var); break; } upsdebugx(2, "Parameter %s %s", var, val); if (!upsc_simple(table, var, val)) upslogx(LOG_ERR, "Unknown response to %s: %s %s", cmd, var, val); } return buffer_empty; } static void check_uppm(void) { int i, last = 0; char var[UPSC_BUFLEN]; char val[UPSC_BUFLEN]; upsc_flush_input(); upscsend("UPPM"); upscsend("0"); upscrecv(var); if (strcmp(var, "ACPM")) upslogx(LOG_ERR, "Bad response to UPPM: %s", var); while (1) { int intval, stat; upscrecv(var); if (strlen(var) == 0) break; upsdebugx(2, "UPPM available: %s", var); stat = sscanf(var, "P%2d", &intval); if (stat != 1) { upslogx(LOG_ERR, "Bad response to UPPM: %s", var); return; } has_uppm_p[intval] = 1; if (intval > last) last = intval; } for (i = 0; i <= last; i++) { if (!has_uppm_p[i]) continue; upscsend("UPPM"); snprintf(var, sizeof(var), "P%.2d", i); upscsend(var); upscrecv(val); if (strcmp(val, "ACPM")) { upslogx(LOG_ERR, "Bad response to UPPM %s: %s", var, val); continue; } upscrecv(var); upsdebugx(1, "UPPM value: %s", var); } } static int upsc_getvalue(const char *cmd, const char *param, const char *resp, const char *nutvar, char *ret) { char var[UPSC_BUFLEN]; char val[UPSC_BUFLEN]; upsdebugx(2, "Request value: %s %s", cmd, param ? param : "\"\""); upscsend(cmd); if (param) upscsend(param); upscrecv(var); upscrecv(val); upsdebugx(2, "Got value: %s %s", var, val); if (strcmp(var, resp)) { upslogx(LOG_ERR, "Bad response to %s %s: %s %s", cmd, param ? param : "\"\"", var, val); return 0; } else { if (nutvar) dstate_setinfo(nutvar, "%s", val); if (ret) strcpy(ret, val); } return 1; } static void upsc_getbaseinfo(void) { char *buf; dstate_setinfo("ups.mfr", "%s", ((buf = getval("manufacturer")) != NULL) ? buf : "unknown"); if (!upsc_getvalue("UPTP", NULL, "NNAME", "ups.model", NULL)) upsc_getvalue("UPTP", NULL, "NNAME", "ups.model", NULL); upsc_getvalue("UPSN", "0", "ACSN", "ups.serial", NULL); } static int upsc_simple(const simple_t *sp, const char *var, const char *val) { int stat; float fval; while (sp->code) { if (strcmp(sp->code, var) == 0) { switch (sp->type) { case t_setval: stat = sscanf(val, "%f", &fval); if (stat != 1) upslogx(LOG_ERR, "Bad float: %s %s", var, val); if (sp->desc) dstate_setinfo(sp->desc, "%.2f", fval); *sp->aux = fval; break; case t_setrecip: stat = sscanf(val, "%f", &fval); if (stat != 1) upslogx(LOG_ERR, "Bad float: %s %s", var, val); if (sp->desc) dstate_setinfo(sp->desc, "%s", val); *sp->aux = 1/fval; break; case t_setpct: stat = sscanf(val, "%f", &fval); if (stat != 1) upslogx(LOG_ERR, "Bad float: %s %s", var, val); *sp->aux = fval*100; if (sp->desc) dstate_setinfo(sp->desc, "%s", val); break; case t_setrecpct: stat = sscanf(val, "%f", &fval); if (stat != 1) upslogx(LOG_ERR, "Bad float: %s %s", var, val); *sp->aux = 1/fval*100; if (sp->desc) dstate_setinfo(sp->desc, "%s", val); break; case t_final: buffer_empty = 1; /* FIXME? Should this really fall through, or should break? */ goto fallthrough_bufempty_processing_1; case t_value: fallthrough_bufempty_processing_1: if (!sp->desc) { break; } if (sscanf(val, "%f", &fval) == 1) { if (sp->aux != NULL) { fval *= *(sp->aux); } dstate_setinfo(sp->desc, "%.2f", fval); } else { upslogx(LOG_ERR, "Bad float in %s: %s", var, val); dstate_setinfo(sp->desc, "%s", val); } break; case t_finstr: buffer_empty = 1; /* FIXME? Should this really fall through, or should break? */ goto fallthrough_bufempty_processing_2; case t_string: fallthrough_bufempty_processing_2: if (!sp->desc) { break; } dstate_setinfo(sp->desc, "%s", val); break; case t_status: if (strcmp(val, "00") == 0) ; else if (strcmp(val, "11") == 0) status |= sp->status; else upslogx(LOG_ERR, "Unknown status value: '%s' '%s'", var, val); break; case t_alarm: if (strcmp(val, "00") == 0) ; else if (strcmp(val, "11") == 0) status |= sp->status; else upslogx(LOG_ERR, "Unknown alarm value: '%s' '%s'", var, val); break; case t_ignore: upsdebugx(3, "Ignored value: %s %s", var, val); break; case t_list: if (!upsc_simple(sp->stats, val, "11")) upslogx(LOG_ERR, "Unknown value: %s %s", var, val); break; #if (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_PUSH_POP) && ( (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_COVERED_SWITCH_DEFAULT) || (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_UNREACHABLE_CODE) ) # pragma GCC diagnostic push #endif #ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_COVERED_SWITCH_DEFAULT # pragma GCC diagnostic ignored "-Wcovered-switch-default" #endif #ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_UNREACHABLE_CODE #pragma GCC diagnostic ignored "-Wunreachable-code" #endif /* Older CLANG (e.g. clang-3.4) seems to not support the GCC pragmas above */ #ifdef __clang__ #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wunreachable-code" #pragma clang diagnostic ignored "-Wcovered-switch-default" #endif /* All enum cases defined as of the time of coding * have been covered above. Handle later definitions, * memory corruptions and buggy inputs below... */ default: upslogx(LOG_ERR, "Unknown type for %s", var); break; #ifdef __clang__ #pragma clang diagnostic pop #endif #if (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_PUSH_POP) && ( (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_COVERED_SWITCH_DEFAULT) || (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_UNREACHABLE_CODE) ) # pragma GCC diagnostic pop #endif } return 1; } sp++; } return 0; } static float batt_charge_pct(void) { float chg=-1; /* This is only a rough estimate of charge status while charging. * When on battery something like Peukert's equation should be used */ if (batt_current >= 0) { float maxcurr = 10; /* Assume 10A max as default */ float avgcurr = 0; int i; batthist[lastbatthist] = batt_current; lastbatthist = (lastbatthist+1) % NUM_BATTHIST; if (numbatthist < NUM_BATTHIST) { numbatthist++; } for(i=0; i 0) { /* Estimate max charge current based on battery size */ maxcurr = batt_cap_nom * 0.3; } chg = maxcurr - avgcurr; chg *= (100/maxcurr); } /* Old method, assumes battery high/low-voltages provided by UPS are * applicable to battery charge, but they usually aren't */ else if (batt_volt_low > 0 && batt_volt_high > 0 && batt_volt > 0) { if (batt_volt > batt_volt_high) { chg=100; } else if (batt_volt < batt_volt_low) { chg=0; } else { chg = (batt_volt - batt_volt_low) / (batt_volt_high - batt_volt_low); chg*=100; } } else { return -1; } if (chg < 0) { chg = 0; } else if (chg > 100) { chg = 100; } return chg; } /* vim:noet:ts=8:sw=8:cindent */ nut-2.8.1/drivers/dstate.h0000644000175000017500000000705514501607135012375 00000000000000/* dstate.h - Network UPS Tools driver-side state management Copyright (C) 2003 Russell Kroll 2012-2017 Arnaud Quette 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 2 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, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef DSTATE_H_SEEN #define DSTATE_H_SEEN 1 #include "common.h" #include "timehead.h" #include "state.h" #include "attribute.h" #include "parseconf.h" #include "upshandler.h" #ifdef WIN32 # include "wincompat.h" #endif #define DS_LISTEN_BACKLOG 16 #define DS_MAX_READ 256 /* don't read forever from upsd */ #ifndef MAX_STRING_SIZE #define MAX_STRING_SIZE 128 #endif /* track client connections */ typedef struct conn_s { TYPE_FD fd; #ifdef WIN32 char buf[LARGEBUF]; OVERLAPPED read_overlapped; #endif PCONF_CTX_t ctx; struct conn_s *prev; struct conn_s *next; int nobroadcast; /* connections can request to ignore send_to_all() updates */ } conn_t; #include "main.h" /* for set_exit_flag(); uses conn_t itself */ extern struct ups_handler upsh; /* asynchronous (nonblocking) Vs synchronous (blocking) I/O * Defaults to nonblocking, for backward compatibility */ extern int do_synchronous; char * dstate_init(const char *prog, const char *devname); int dstate_poll_fds(struct timeval timeout, TYPE_FD extrafd); int dstate_setinfo(const char *var, const char *fmt, ...) __attribute__ ((__format__ (__printf__, 2, 3))); int dstate_addenum(const char *var, const char *fmt, ...) __attribute__ ((__format__ (__printf__, 2, 3))); int dstate_addrange(const char *var, const int min, const int max); void dstate_setflags(const char *var, int flags); void dstate_addflags(const char *var, const int addflags); void dstate_delflags(const char *var, const int delflags); void dstate_setaux(const char *var, long aux); const char *dstate_getinfo(const char *var); void dstate_addcmd(const char *cmdname); int dstate_delinfo_olderthan(const char *var, const st_tree_timespec_t *cutoff); int dstate_delinfo(const char *var); int dstate_delenum(const char *var, const char *val); int dstate_delrange(const char *var, const int min, const int max); int dstate_delcmd(const char *cmd); void dstate_free(void); const st_tree_t *dstate_getroot(void); const cmdlist_t *dstate_getcmdlist(void); void dstate_dataok(void); void dstate_datastale(void); int dstate_is_stale(void); /* clean out the temp space for a new pass */ void status_init(void); /* add a status element */ void status_set(const char *buf); /* write the temporary status_buf into ups.status */ void status_commit(void); /* similar functions for ups.alarm */ void alarm_init(void); void alarm_set(const char *buf); void alarm_commit(void); void device_alarm_init(void); void device_alarm_commit(const int device_number); int dstate_detect_phasecount( const char *xput_prefix, const int may_change_dstate, int *inited_phaseinfo, int *num_phases, const int may_reevaluate); void dstate_dump(void); #endif /* DSTATE_H_SEEN */ nut-2.8.1/drivers/idowell-hid.h0000644000175000017500000000217014273170601013302 00000000000000/* idowell-hid.h - subdriver to monitor iDowell USB/HID devices with NUT * * Copyright (C) * 2003 - 2009 Arnaud Quette * 2005 - 2006 Peter Selinger * 2008 - 2009 Arjen de Korte * * 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 2 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, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef IDOWELL_HID_H #define IDOWELL_HID_H #include "usbhid-ups.h" extern subdriver_t idowell_subdriver; #endif /* IDOWELL_HID_H */ nut-2.8.1/drivers/apc_modbus.c0000644000175000017500000011344214515702041013213 00000000000000/* apc_modbus.c - Driver for APC Modbus UPS * Copyright © 2023 Axel Gembe * * 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 2 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, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "main.h" #if defined NUT_MODBUS_HAS_USB #include "nut_libusb.h" #include "libhid.h" #include "hidparser.h" #endif /* defined NUT_MODBUS_HAS_USB */ #include "timehead.h" #include "nut_stdint.h" #include #include #include #define DRIVER_NAME "NUT APC Modbus driver" #define DRIVER_VERSION "0.01" #if defined NUT_MODBUS_HAS_USB /* APC */ #define APC_VENDORID 0x051D /* USB IDs device table */ static usb_device_id_t apc_modbus_usb_device_table[] = { { USB_DEVICE(APC_VENDORID, 0x0003), NULL }, /* Terminating entry */ { 0, 0, NULL } }; #endif /* defined NUT_MODBUS_HAS_USB */ /* Constants */ static const uint8_t modbus_default_slave_id = 1; static const int modbus_rtu_default_baudrate = 9600; static const char modbus_rtu_default_parity = 'N'; static const int modbus_rtu_default_databits = 8; static const int modbus_rtu_default_stopbits = 1; static const uint16_t modbus_tcp_default_port = 502; #if defined NUT_MODBUS_HAS_USB static const HIDNode_t modbus_rtu_usb_usage_rx = 0xff8600fc; static const HIDNode_t modbus_rtu_usb_usage_tx = 0xff8600fd; #endif /* defined NUT_MODBUS_HAS_USB */ /* Variables */ static modbus_t *modbus_ctx = NULL; #if defined NUT_MODBUS_HAS_USB static USBDevice_t usbdevice; static USBDeviceMatcher_t *reopen_matcher = NULL; static USBDeviceMatcher_t *regex_matcher = NULL; static USBDeviceMatcher_t *best_matcher = NULL; static int is_usb = 0; #endif /* defined NUT_MODBUS_HAS_USB */ static int is_open = 0; static double power_nominal; static double realpower_nominal; /* Function declarations */ static int _apc_modbus_read_inventory(void); /* driver description structure */ upsdrv_info_t upsdrv_info = { DRIVER_NAME, DRIVER_VERSION, "Axel Gembe \n", DRV_BETA, {NULL} }; typedef enum { APC_MODBUS_VALUE_TYPE_INT = 0, APC_MODBUS_VALUE_TYPE_UINT, APC_MODBUS_VALUE_TYPE_STRING } apc_modbus_value_types; static const apc_modbus_value_types apc_modbus_value_types_max = APC_MODBUS_VALUE_TYPE_STRING; typedef struct { apc_modbus_value_types type; const char *format; int scale; void *variable_ptr; union { int64_t int_value; uint64_t uint_value; char *string_value; } data; } apc_modbus_value_t; typedef struct { int (*apc_to_nut)(const apc_modbus_value_t *value, char *output, size_t output_len); int (*nut_to_apc)(const char *value, uint16_t *output, size_t output_len); } apc_modbus_converter_t; /* Converts a Modbus string to a C string. * See MPAO-98KJ7F_EN section 1.3.3 Strings. * * Needs to remove leading zeroes, trailing spaces and translate characters in * the range 0x20-0x7e as a different character. * Zero termination is optional, so the output buffer needs to be 1 byte * longer to add zero termination. */ static int _apc_modbus_to_string(const uint16_t *value, const size_t value_len, char *output, size_t output_len) { char *op; size_t i; if (value == NULL || output == NULL) { /* Invalid parameters */ return 0; } if ((value_len * sizeof(uint16_t)) + 1 > output_len) { /* Output buffer too small */ return 0; } op = output; /* Find first non-zero register */ for (i = 0; i < value_len; i++) { if (value[i] != 0) break; } if (i < value_len) { /* The second character could be zero, skip if it is */ if (((value[i] & 0xff00) >> 8) == 0) { *(op++) = (char)(value[i] & 0xff); i++; } /* For each remaining register, take MSB then LSB into string */ for (; i < value_len; i++) { *(op++) = (char)((value[i] & 0xff00) >> 8); *(op++) = (char)(value[i] & 0xff); } } /* Add zero termination */ *op = 0; assert(op < output + output_len); /* Find last non-zero/space */ for (op--; op > output && (*op == 0 || *op == ' '); op--); /* Cut off rest of string */ *(op + 1) = 0; /* Translate charaters outside of 0x20-0x7e range to spaces */ for (; op > output; op--) { if (*op < 0x20 || *op > 0x7e) { *op = ' '; } } return 1; } /* Converts a Modbus integer to a uint64_t. * See MPAO-98KJ7F_EN section 1.3.1 Numbers. */ static int _apc_modbus_to_uint64(const uint16_t *value, const size_t value_len, uint64_t *output) { size_t i; if (value == NULL || output == NULL) { /* Invalid parameters */ return 0; } *output = 0; for (i = 0; i < value_len; i++) { *output = (*output << 16) | value[i]; } return 1; } static int _apc_modbus_to_int64(const uint16_t *value, const size_t value_len, int64_t *output) { size_t shiftval; if (!_apc_modbus_to_uint64(value, value_len, (uint64_t*)output)) { return 0; } shiftval = (8 * (sizeof(int64_t) - (value_len * sizeof(uint16_t)))); *output <<= shiftval; *output >>= shiftval; return 1; } static int _apc_modbus_to_double(const apc_modbus_value_t *value, double *output) { int factor; if (value == NULL || output == NULL) { /* Invalid parameters */ return 0; } factor = 1 << value->scale; assert(value->type <= apc_modbus_value_types_max); switch (value->type) { case APC_MODBUS_VALUE_TYPE_INT: *output = (double)value->data.int_value / factor; break; case APC_MODBUS_VALUE_TYPE_UINT: *output = (double)value->data.uint_value / factor; break; case APC_MODBUS_VALUE_TYPE_STRING: return 0; } return 1; } static int _apc_modbus_double_to_nut(const apc_modbus_value_t *value, char *output, size_t output_len) { double double_value; const char *format; int res; if (output == NULL || output_len == 0) { /* Invalid parameters */ return 0; } if (!_apc_modbus_to_double(value, &double_value)) { return 0; } if (value->variable_ptr) { *((double*)value->variable_ptr) = double_value; } format = "%f"; if (value->format != NULL) format = value->format; #ifdef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL #pragma GCC diagnostic push #endif #ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL #pragma GCC diagnostic ignored "-Wformat-nonliteral" #endif res = snprintf(output, output_len, format, double_value); #ifdef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL #pragma GCC diagnostic pop #endif if (res < 0 || (size_t)res >= output_len) { return 0; } return 1; } static apc_modbus_converter_t _apc_modbus_double_conversion = { _apc_modbus_double_to_nut, NULL }; static int _apc_modbus_power_to_nut(const apc_modbus_value_t *value, char *output, size_t output_len) { double double_value; const char *format; int res; if (output == NULL || output_len == 0) { /* Invalid parameters */ return 0; } if (!_apc_modbus_to_double(value, &double_value)) { return 0; } if (value->variable_ptr) { /* variable_ptr points to the nominal value */ double_value = (double_value / 100.0) * *((double*)value->variable_ptr); } format = "%f"; if (value->format != NULL) format = value->format; #ifdef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL #pragma GCC diagnostic push #endif #ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL #pragma GCC diagnostic ignored "-Wformat-nonliteral" #endif res = snprintf(output, output_len, format, double_value); #ifdef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL #pragma GCC diagnostic pop #endif if (res < 0 || (size_t)res >= output_len) { return 0; } return 1; } static apc_modbus_converter_t _apc_modbus_power_conversion = { _apc_modbus_power_to_nut, NULL }; static int _apc_modbus_voltage_to_nut(const apc_modbus_value_t *value, char *output, size_t output_len) { int res; if (value == NULL || output == NULL || output_len == 0) { /* Invalid parameters */ return 0; } if (value->type != APC_MODBUS_VALUE_TYPE_UINT) { return 0; } if (value->data.uint_value == 0xffff) { /* Not applicable */ res = snprintf(output, output_len, "NA"); if (res < 0 || (size_t)res >= output_len) { return 0; } return 1; } return _apc_modbus_double_to_nut(value, output, output_len); } static apc_modbus_converter_t _apc_modbus_voltage_conversion = { _apc_modbus_voltage_to_nut, NULL }; static int _apc_modbus_efficiency_to_nut(const apc_modbus_value_t *value, char *output, size_t output_len) { char *cause; int res; if (value == NULL || output == NULL || output_len == 0) { /* Invalid parameters */ return 0; } if (value->type != APC_MODBUS_VALUE_TYPE_INT) { return 0; } switch (value->data.int_value) { case -1: cause = "NotAvailable"; break; case -2: cause = "LoadTooLow"; break; case -3: cause = "OutputOff"; break; case -4: cause = "OnBattery"; break; case -5: cause = "InBypass"; break; case -6: cause = "BatteryCharging"; break; case -7: cause = "PoorACInput"; break; case -8: cause = "BatteryDisconnected"; break; default: return _apc_modbus_double_to_nut(value, output, output_len); } res = snprintf(output, output_len, "%s", cause); if (res < 0 || (size_t)res >= output_len) { return 0; } return 1; } static apc_modbus_converter_t _apc_modbus_efficiency_conversion = { _apc_modbus_efficiency_to_nut, NULL }; static int _apc_modbus_status_change_cause_to_nut(const apc_modbus_value_t *value, char *output, size_t output_len) { char *cause; int res; if (value == NULL || output == NULL || output_len == 0) { /* Invalid parameters */ return 0; } if (value->type != APC_MODBUS_VALUE_TYPE_UINT) { return 0; } switch (value->data.uint_value) { case 0: cause = "SystemInitialization"; break; case 1: cause = "HighInputVoltage"; break; case 2: cause = "LowInputVoltage"; break; case 3: cause = "DistortedInput"; break; case 4: cause = "RapidChangeOfInputVoltage"; break; case 5: cause = "HighInputFrequency"; break; case 6: cause = "LowInputFrequency"; break; case 7: cause = "FreqAndOrPhaseDifference"; break; case 8: cause = "AcceptableInput"; break; case 9: cause = "AutomaticTest"; break; case 10: cause = "TestEnded"; break; case 11: cause = "LocalUICommand"; break; case 12: cause = "ProtocolCommand"; break; case 13: cause = "LowBatteryVoltage"; break; case 14: cause = "GeneralError"; break; case 15: cause = "PowerSystemError"; break; case 16: cause = "BatterySystemError"; break; case 17: cause = "ErrorCleared"; break; case 18: cause = "AutomaticRestart"; break; case 19: cause = "DistortedInverterOutput"; break; case 20: cause = "InverterOutputAcceptable"; break; case 21: cause = "EPOInterface"; break; case 22: cause = "InputPhaseDeltaOutOfRange"; break; case 23: cause = "InputNeutralNotConnected"; break; case 24: cause = "ATSTransfer"; break; case 25: cause = "ConfigurationChange"; break; case 26: cause = "AlertAsserted"; break; case 27: cause = "AlertCleared"; break; case 28: cause = "PlugRatingExceeded"; break; case 29: cause = "OutletGroupStateChange"; break; case 30: cause = "FailureBypassExpired"; break; default: cause = "Unknown"; break; } res = snprintf(output, output_len, "%s", cause); if (res < 0 || (size_t)res >= output_len) { return 0; } return 1; } static apc_modbus_converter_t _apc_modbus_status_change_cause_conversion = { _apc_modbus_status_change_cause_to_nut, NULL }; static int _apc_modbus_date_to_nut(const apc_modbus_value_t *value, char *output, size_t output_len) { struct tm *tm_info; time_t time_stamp; const time_t start_offset = 946684800; /* 2000-01-01 00:00 */ if (value == NULL || output == NULL || output_len == 0) { /* Invalid parameters */ return 0; } if (value->type != APC_MODBUS_VALUE_TYPE_UINT) { return 0; } time_stamp = ((int64_t)value->data.uint_value * 86400) + start_offset; tm_info = gmtime(&time_stamp); strftime(output, output_len, "%Y-%m-%d", tm_info); return 1; } static apc_modbus_converter_t _apc_modbus_date_conversion = { _apc_modbus_date_to_nut, NULL }; typedef struct { const char *nut_variable_name; size_t modbus_addr; size_t modbus_len; /* Number of uint16_t registers */ apc_modbus_value_types value_type; apc_modbus_converter_t *value_converter; const char *value_format; int value_scale; void *variable_ptr; } apc_modbus_register_t; /* Values that only need to be updated once on startup */ static apc_modbus_register_t apc_modbus_register_map_inventory[] = { { "ups.firmware", 516, 8, APC_MODBUS_VALUE_TYPE_STRING, NULL, "%s", 0, NULL }, { "ups.model", 532, 16, APC_MODBUS_VALUE_TYPE_STRING, NULL, "%s", 0, NULL }, /* also device.model, filled automatically */ { "ups.serial", 564, 8, APC_MODBUS_VALUE_TYPE_STRING, NULL, "%s", 0, NULL }, /* also device.serial, filled automatically */ { "ups.power.nominal", 588, 1, APC_MODBUS_VALUE_TYPE_UINT, &_apc_modbus_double_conversion, "%.0f", 0, &power_nominal }, { "ups.realpower.nominal", 589, 1, APC_MODBUS_VALUE_TYPE_UINT, &_apc_modbus_double_conversion, "%.0f", 0, &realpower_nominal }, { "ups.mfr.date", 591, 1, APC_MODBUS_VALUE_TYPE_UINT, &_apc_modbus_date_conversion, NULL, 0, NULL }, { "battery.date", 595, 1, APC_MODBUS_VALUE_TYPE_UINT, &_apc_modbus_date_conversion, NULL, 0, NULL }, { "ups.id", 596, 8, APC_MODBUS_VALUE_TYPE_STRING, NULL, "%s", 0, NULL }, { NULL, 0, 0, 0, NULL, NULL, 0.0f, NULL } }; static apc_modbus_register_t apc_modbus_register_map_status[] = { { "input.transfer.reason", 2, 1, APC_MODBUS_VALUE_TYPE_UINT, &_apc_modbus_status_change_cause_conversion, NULL, 0, NULL }, { NULL, 0, 0, 0, NULL, NULL, 0.0f, NULL } }; static apc_modbus_register_t apc_modbus_register_map_dynamic[] = { { "battery.runtime", 128, 2, APC_MODBUS_VALUE_TYPE_UINT, NULL, "%u", 0, NULL }, { "battery.charge", 130, 1, APC_MODBUS_VALUE_TYPE_UINT, &_apc_modbus_double_conversion, "%.2f", 9, NULL }, { "battery.voltage", 131, 1, APC_MODBUS_VALUE_TYPE_INT, &_apc_modbus_double_conversion, "%.2f", 5, NULL }, { "battery.date.maintenance", 133, 1, APC_MODBUS_VALUE_TYPE_UINT, &_apc_modbus_date_conversion, NULL, 0, NULL }, { "battery.temperature", 135, 1, APC_MODBUS_VALUE_TYPE_INT, &_apc_modbus_double_conversion, "%.2f", 7, NULL }, { "ups.load", 136, 1, APC_MODBUS_VALUE_TYPE_UINT, &_apc_modbus_double_conversion, "%.2f", 8, NULL }, { "ups.realpower", 136, 1, APC_MODBUS_VALUE_TYPE_UINT, &_apc_modbus_power_conversion, "%.2f", 8, &realpower_nominal }, { "ups.power", 138, 1, APC_MODBUS_VALUE_TYPE_UINT, &_apc_modbus_power_conversion, "%.2f", 8, &power_nominal }, { "output.current", 140, 1, APC_MODBUS_VALUE_TYPE_UINT, &_apc_modbus_double_conversion, "%.2f", 5, NULL }, { "output.voltage", 142, 1, APC_MODBUS_VALUE_TYPE_UINT, &_apc_modbus_double_conversion, "%.2f", 6, NULL }, { "output.frequency", 144, 1, APC_MODBUS_VALUE_TYPE_UINT, &_apc_modbus_double_conversion, "%.2f", 7, NULL }, { "experimental.output.energy", 145, 2, APC_MODBUS_VALUE_TYPE_UINT, NULL, "%u", 0, NULL }, { "input.voltage", 151, 1, APC_MODBUS_VALUE_TYPE_UINT, &_apc_modbus_voltage_conversion, "%.2f", 6, NULL }, { "ups.efficiency", 154, 1, APC_MODBUS_VALUE_TYPE_INT, &_apc_modbus_efficiency_conversion, "%.1f", 7, NULL }, { "ups.timer.shutdown", 155, 1, APC_MODBUS_VALUE_TYPE_INT, NULL, "%d", 0, NULL }, { "ups.timer.start", 156, 1, APC_MODBUS_VALUE_TYPE_INT, NULL, "%d", 0, NULL }, { "ups.timer.reboot", 157, 2, APC_MODBUS_VALUE_TYPE_INT, NULL, "%d", 0, NULL }, { NULL, 0, 0, 0, NULL, NULL, 0.0f, NULL } }; static apc_modbus_register_t apc_modbus_register_map_static[] = { { "input.transfer.high", 1026, 1, APC_MODBUS_VALUE_TYPE_UINT, NULL, "%u", 0, NULL }, { "input.transfer.low", 1027, 1, APC_MODBUS_VALUE_TYPE_UINT, NULL, "%u", 0, NULL }, { "ups.delay.shutdown", 1029, 1, APC_MODBUS_VALUE_TYPE_INT, NULL, "%d", 0, NULL }, { "ups.delay.start", 1030, 1, APC_MODBUS_VALUE_TYPE_INT, NULL, "%d", 0, NULL }, { "ups.delay.reboot", 1031, 2, APC_MODBUS_VALUE_TYPE_INT, NULL, "%d", 0, NULL }, { NULL, 0, 0, 0, NULL, NULL, 0.0f, NULL } }; static void _apc_modbus_close(int free_modbus) { if (modbus_ctx != NULL) { modbus_close(modbus_ctx); if (free_modbus) { modbus_free(modbus_ctx); modbus_ctx = NULL; } } is_open = 0; } #if defined NUT_MODBUS_HAS_USB static void _apc_modbus_create_reopen_matcher(void) { int r; if (reopen_matcher != NULL) { USBFreeExactMatcher(reopen_matcher); reopen_matcher = NULL; } r = USBNewExactMatcher(&reopen_matcher, &usbdevice); if (r < 0) { fatal_with_errno(EXIT_FAILURE, "USBNewExactMatcher"); } reopen_matcher->next = best_matcher; best_matcher = reopen_matcher; } #endif /* defined NUT_MODBUS_HAS_USB */ static int _apc_modbus_reopen(void) { dstate_setinfo("driver.state", "reconnect.trying"); if (modbus_connect(modbus_ctx) < 0) { upslogx(LOG_ERR, "%s: Unable to connect Modbus: %s", __func__, modbus_strerror(errno)); return 0; } #if defined NUT_MODBUS_HAS_USB /* We might have matched a new device in the modbus_connect callback. * Because of this we want a new exact matcher. */ best_matcher = best_matcher->next; _apc_modbus_create_reopen_matcher(); #endif /* defined NUT_MODBUS_HAS_USB */ usleep(1000000); modbus_flush(modbus_ctx); is_open = 1; dstate_setinfo("driver.state", "reconnect.updateinfo"); _apc_modbus_read_inventory(); dstate_setinfo("driver.state", "quiet"); return 1; } static useconds_t _apc_modbus_get_time_us(void) { struct timeval tv; gettimeofday(&tv, NULL); return ((useconds_t)tv.tv_sec * (useconds_t)1000000) + (useconds_t)tv.tv_usec; } static void _apc_modbus_interframe_delay(void) { /* 4.2.2 Modbus Message RTU Framing, interframe delay */ static useconds_t last_send_time = 0; static const useconds_t inter_frame_delay = 35000; useconds_t current_time, delta_time; current_time = _apc_modbus_get_time_us(); delta_time = current_time - last_send_time; if (delta_time > inter_frame_delay) { /* Already over the inter frame delay */ goto interframe_delay_exit; } usleep(inter_frame_delay - delta_time); interframe_delay_exit: last_send_time = current_time; } static void _apc_modbus_handle_error(modbus_t *ctx) { static int flush_retries = 0; int flush = 0; #ifdef WIN32 int wsa_error; #endif /* WIN32 */ /* * We could enable MODBUS_ERROR_RECOVERY_LINK but that would just get stuck * in libmodbus until recovery. The only indication of this is that the * program is stuck and debug prints by libmodbus, which we don't want to * enable on release. * * Instead we detect timout errors and do a sleep + flush, on every other * error or when flush didn't work we do a reconnect. */ #ifdef WIN32 wsa_error = WSAGetLastError(); if (wsa_error == WSAETIMEDOUT) { flush = 1; } #else if (errno == ETIMEDOUT) { flush = 1; } #endif /* WIN32 */ if (flush > 0 && flush_retries++ < 5) { usleep(1000000); modbus_flush(ctx); } else { flush_retries = 0; upslogx(LOG_ERR, "%s: Closing connection", __func__); /* Close without free, will retry connection on next update */ _apc_modbus_close(0); } } static int _apc_modbus_read_registers(modbus_t *ctx, int addr, int nb, uint16_t *dest) { _apc_modbus_interframe_delay(); if (modbus_read_registers(ctx, addr, nb, dest) > 0) { return 1; } else { upslogx(LOG_ERR, "%s: Read of %d:%d failed: %s (%s)", __func__, addr, addr + nb, modbus_strerror(errno), device_path); _apc_modbus_handle_error(ctx); return 0; } } static int _apc_modbus_update_value(apc_modbus_register_t *regs_info, const uint16_t *regs, const size_t regs_len) { apc_modbus_value_t value; char strbuf[33], nutvbuf[128]; if (regs_info == NULL || regs == NULL || regs_len == 0) { /* Invalid parameters */ return 0; } value.type = regs_info->value_type; value.format = regs_info->value_format; value.scale = regs_info->value_scale; value.variable_ptr = regs_info->variable_ptr; assert(regs_info->value_type <= apc_modbus_value_types_max); switch (regs_info->value_type) { case APC_MODBUS_VALUE_TYPE_STRING: _apc_modbus_to_string(regs, regs_info->modbus_len, strbuf, sizeof(strbuf)); value.data.string_value = strbuf; break; case APC_MODBUS_VALUE_TYPE_INT: _apc_modbus_to_int64(regs, regs_info->modbus_len, &value.data.int_value); break; case APC_MODBUS_VALUE_TYPE_UINT: _apc_modbus_to_uint64(regs, regs_info->modbus_len, &value.data.uint_value); break; } if (regs_info->value_converter != NULL) { /* If we have a converter, use it and set the value as a string */ if (!regs_info->value_converter->apc_to_nut(&value, nutvbuf, sizeof(nutvbuf))) { upslogx(LOG_ERR, "%s: Failed to convert register %" PRIuSIZE ":%" PRIuSIZE, __func__, regs_info->modbus_addr, regs_info->modbus_addr + regs_info->modbus_len); return 0; } dstate_setinfo(regs_info->nut_variable_name, "%s", nutvbuf); } else { #ifdef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL #pragma GCC diagnostic push #endif #ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL #pragma GCC diagnostic ignored "-Wformat-nonliteral" #endif assert(regs_info->value_type <= apc_modbus_value_types_max); switch (regs_info->value_type) { case APC_MODBUS_VALUE_TYPE_STRING: dstate_setinfo(regs_info->nut_variable_name, regs_info->value_format, value.data.string_value); break; case APC_MODBUS_VALUE_TYPE_INT: dstate_setinfo(regs_info->nut_variable_name, regs_info->value_format, value.data.int_value); break; case APC_MODBUS_VALUE_TYPE_UINT: dstate_setinfo(regs_info->nut_variable_name, regs_info->value_format, value.data.uint_value); break; } #ifdef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL #pragma GCC diagnostic pop #endif } return 1; } static int _apc_modbus_process_registers(apc_modbus_register_t* values, const uint16_t *regs, const size_t regs_len, const size_t regs_offset) { size_t i; apc_modbus_register_t *v; for (i = 0; values[i].nut_variable_name; i++) { v = &values[i]; if ((size_t)v->modbus_addr < regs_offset || (size_t)(v->modbus_addr + v->modbus_len) > regs_offset + regs_len) { continue; } _apc_modbus_update_value(v, regs + (v->modbus_addr - regs_offset), v->modbus_len); } return 1; } static int _apc_modbus_read_inventory(void) { uint16_t regbuf[88]; /* Inventory Information */ if (_apc_modbus_read_registers(modbus_ctx, 516, 88, regbuf)) { _apc_modbus_process_registers(apc_modbus_register_map_inventory, regbuf, 88, 516); } else { return 0; } return 1; } void upsdrv_initinfo(void) { if (!_apc_modbus_read_inventory()) { fatalx(EXIT_FAILURE, "Can't read inventory information from the UPS"); } dstate_setinfo("ups.mfr", "American Power Conversion"); /* also device.mfr, filled automatically */ dstate_setinfo("device.type", "ups"); } void upsdrv_updateinfo(void) { uint16_t regbuf[32]; uint64_t value; if (!is_open) { if (!_apc_modbus_reopen()) { upsdebugx(2, "Failed to reopen modbus"); dstate_datastale(); return; } } alarm_init(); status_init(); /* Status Data */ if (_apc_modbus_read_registers(modbus_ctx, 0, 27, regbuf)) { /* UPSStatus_BF, 2 registers */ _apc_modbus_to_uint64(®buf[0], 2, &value); if (value & (1 << 1)) { status_set("OL"); } if (value & (1 << 2)) { status_set("OB"); } if (value & (1 << 3)) { status_set("BYPASS"); } if (value & (1 << 4)) { status_set("OFF"); } if (value & (1 << 5)) { alarm_set("General fault"); } if (value & (1 << 6)) { alarm_set("Input not acceptable"); } if (value & (1 << 7)) { status_set("TEST"); } if (value & (1 << 13)) { status_set("HE"); /* High efficiency / ECO mode*/ } if (value & (1 << 21)) { status_set("OVER"); } /* SimpleSignalingStatus_BF, 1 register */ _apc_modbus_to_uint64(®buf[18], 1, &value); if (value & (1 << 1)) { /* ShutdownImminent */ status_set("LB"); } /* BatterySystemError_BF, 1 register */ _apc_modbus_to_uint64(®buf[18], 1, &value); if (value & (1 << 1)) { /* NeedsReplacement */ status_set("RB"); } /* RunTimeCalibrationStatus_BF, 1 register */ _apc_modbus_to_uint64(®buf[24], 1, &value); if (value & (1 << 1)) { /* InProgress */ status_set("CAL"); } _apc_modbus_process_registers(apc_modbus_register_map_status, regbuf, 27, 0); } else { dstate_datastale(); return; } /* Dynamic Data */ if (_apc_modbus_read_registers(modbus_ctx, 128, 32, regbuf)) { /* InputStatus_BF, 1 register */ _apc_modbus_to_uint64(®buf[22], 1, &value); if (value & (1 << 5)) { status_set("BOOST"); } if (value & (1 << 6)) { status_set("TRIM"); } _apc_modbus_process_registers(apc_modbus_register_map_dynamic, regbuf, 32, 128); } else { dstate_datastale(); return; } /* Static Data */ if (_apc_modbus_read_registers(modbus_ctx, 1026, 7, regbuf)) { _apc_modbus_process_registers(apc_modbus_register_map_static, regbuf, 7, 1026); } else { dstate_datastale(); return; } alarm_commit(); status_commit(); dstate_dataok(); } void upsdrv_shutdown(void) { /* TODO: replace with a proper shutdown function */ upslogx(LOG_ERR, "shutdown not supported"); set_exit_flag(-1); } void upsdrv_help(void) { } void upsdrv_makevartable(void) { #if defined NUT_MODBUS_HAS_USB nut_usb_addvars(); #endif /* defined NUT_MODBUS_HAS_USB */ #if defined NUT_MODBUS_HAS_USB addvar(VAR_VALUE, "porttype", "Modbus port type (serial, tcp, usb, default=usb)"); #else addvar(VAR_VALUE, "porttype", "Modbus port type (serial, tcp, default=serial)"); #endif /* defined NUT_MODBUS_HAS_USB */ addvar(VAR_VALUE, "slaveid", "Modbus slave id (default=1)"); addvar(VAR_VALUE, "response_timeout_ms", "Modbus response timeout in milliseconds"); /* Serial RTU parameters */ addvar(VAR_VALUE, "baudrate", "Modbus serial RTU communication speed in baud (default=9600)"); addvar(VAR_VALUE, "parity", "Modbus serial RTU parity (N=none, E=even, O=odd, default=N)"); addvar(VAR_VALUE, "databits", "Modbus serial RTU data bit count (default=8)"); addvar(VAR_VALUE, "stopbits", "Modbus serial RTU stop bit count (default=1)"); } #if defined NUT_MODBUS_HAS_USB static int _apc_modbus_usb_device_match_func(USBDevice_t *hd, void *privdata) { int status; NUT_UNUSED_VARIABLE(privdata); status = is_usb_device_supported(apc_modbus_usb_device_table, hd); switch (status) { case POSSIBLY_SUPPORTED: /* by default, reject, unless the productid option is given */ if (getval("productid")) { return 1; } return 0; case SUPPORTED: return 1; case NOT_SUPPORTED: default: return 0; } } static USBDeviceMatcher_t apc_modbus_usb_device_matcher = { &_apc_modbus_usb_device_match_func, NULL, NULL }; static void _apc_modbus_usb_lib_to_nut(const modbus_usb_device_t *device, USBDevice_t *out) { /* This makes a USBDevice_t from modbus_usb_device_t so we can use our matchers */ static char bus_buf[4], device_buf[4], bus_port_buf[4]; int res; assert(device != NULL); assert(out != NULL); memset(out, 0, sizeof(USBDevice_t)); out->VendorID = device->vid; out->ProductID = device->pid; out->Vendor = device->vendor_str; out->Product = device->product_str; out->Serial = device->serial_str; out->bcdDevice = device->bcd_device; res = snprintf(bus_buf, sizeof(bus_buf), "%03u", device->bus); if (res < 0 || (size_t)res >= sizeof(bus_buf)) { fatalx(EXIT_FAILURE, "failed to convert USB bus to string"); } out->Bus = bus_buf; res = snprintf(device_buf, sizeof(device_buf), "%03u", device->device_address); if (res < 0 || (size_t)res >= sizeof(device_buf)) { fatalx(EXIT_FAILURE, "failed to convert USB device address to string"); } out->Device = device_buf; #if (defined WITH_USB_BUSPORT) && (WITH_USB_BUSPORT) res = snprintf(bus_port_buf, sizeof(bus_port_buf), "%03u", device->bus_port); if (res < 0 || (size_t)res >= sizeof(bus_port_buf)) { fatalx(EXIT_FAILURE, "failed to convert USB bus port to string"); } out->BusPort = bus_port_buf; #endif } static int _apc_modbus_usb_callback(const modbus_usb_device_t *device) { HIDDesc_t *hid_desc; size_t i; HIDData_t *hid_cur_item, *hid_rtu_rx = NULL, *hid_rtu_tx = NULL; HIDNode_t hid_cur_usage; USBDeviceMatcher_t *current_matcher; if (device == NULL) { upslogx(LOG_ERR, "%s: NULL device passed", __func__); return -1; } _apc_modbus_usb_lib_to_nut(device, &usbdevice); current_matcher = best_matcher; while (current_matcher != NULL) { if (current_matcher->match_function(&usbdevice, current_matcher->privdata) == 1) { break; } current_matcher = current_matcher->next; } if (current_matcher == NULL) { upsdebug_with_errno(1, "%s: Failed to match!", __func__); return -1; } upsdebugx(2, "%s: Matched %s %s (USB VID/PID %04x:%04x)", __func__, device->vendor_str, device->product_str, device->vid, device->pid); if (device->hid_report_descriptor_buf == NULL) { upslogx(LOG_WARNING, "%s: No HID report descriptor, using defaults", __func__); goto usb_callback_exit; } upsdebugx(2, "%s: Checking %s %s (USB VID/PID %04x:%04x) report descriptors", __func__, device->vendor_str, device->product_str, device->vid, device->pid); hid_desc = Parse_ReportDesc(device->hid_report_descriptor_buf, (usb_ctrl_charbufsize)device->hid_report_descriptor_len); if (!hid_desc) { upsdebug_with_errno(1, "%s: Failed to parse report descriptor!", __func__); return -1; } for (i = 0; i < hid_desc->nitems; i++) { hid_cur_item = &hid_desc->item[i]; hid_cur_usage = hid_cur_item->Path.Node[hid_cur_item->Path.Size - 1]; if (hid_cur_usage == modbus_rtu_usb_usage_rx) { hid_rtu_rx = hid_cur_item; } else if (hid_cur_usage == modbus_rtu_usb_usage_tx) { hid_rtu_tx = hid_cur_item; } } if (hid_rtu_rx == NULL || hid_rtu_tx == NULL) { upsdebugx(1, "%s: No Modbus USB report descriptor found", __func__); Free_ReportDesc(hid_desc); return -1; } upsdebugx(1, "%s: Found report ids RX=0x%02x TX=0x%02x", __func__, hid_rtu_rx->ReportID, hid_rtu_tx->ReportID); modbus_rtu_usb_set_report_ids(modbus_ctx, hid_rtu_rx->ReportID, hid_rtu_tx->ReportID); Free_ReportDesc(hid_desc); usb_callback_exit: dstate_setinfo("ups.vendorid", "%04x", device->vid); dstate_setinfo("ups.productid", "%04x", device->pid); return 0; } #endif /* defined NUT_MODBUS_HAS_USB */ static int _apc_modbus_parse_host_port(const char *input, char *host, size_t host_buf_size, char *port, size_t port_buf_size, const uint16_t default_port) { const char *start = input; const char *end = input; int port_int, r; size_t host_size, port_size; if (*start == '[') { start++; end = strchr(start, ']'); if (!end) { upslogx(LOG_ERR, "%s: Invalid IPv6 notation", __func__); return 0; } } else { end = strchr(start, ':'); } if (!end) { /* Port is missing, use the default port */ r = snprintf(host, host_buf_size, "%s", start); if (r < 0 || (size_t)r >= host_buf_size) { upslogx(LOG_ERR, "%s: Buffer size too small or encoding error", __func__); return 0; } r = snprintf(port, port_buf_size, "%u", default_port); if (r < 0 || (size_t)r >= port_buf_size) { upslogx(LOG_ERR, "%s: Buffer size too small or encoding error", __func__); return 0; } return 1; } /* +1 for zero termination */ host_size = (size_t)(end - start) + 1; port_size = strlen(end + 1) + 1; if (host_size > host_buf_size || port_size > port_buf_size) { upslogx(LOG_ERR, "%s: Buffer size too small", __func__); return 0; } snprintf(host, host_size, "%s", start); snprintf(port, port_size, "%s", end + 1); port_int = atoi(port); if (port_int < 0 || port_int > 65535) { upslogx(LOG_ERR, "%s: Port out of range", __func__); return 0; } return 1; } void upsdrv_initups(void) { int r; #if defined NUT_MODBUS_HAS_USB char *regex_array[USBMATCHER_REGEXP_ARRAY_LIMIT]; int has_nonzero_regex; size_t i; #endif /* defined NUT_MODBUS_HAS_USB */ char *val; int rtu_baudrate; char rtu_parity; int rtu_databits; int rtu_stopbits; int slaveid; uint32_t response_timeout_ms; char tcp_host[256]; char tcp_port[6]; val = getval("porttype"); if (val == NULL) { #if defined NUT_MODBUS_HAS_USB val = "usb"; #else val = "serial"; #endif /* defined NUT_MODBUS_HAS_USB */ } is_open = 0; #if defined NUT_MODBUS_HAS_USB is_usb = 0; #endif /* defined NUT_MODBUS_HAS_USB */ if (!strcasecmp(val, "usb")) { #if defined NUT_MODBUS_HAS_USB is_usb = 1; /* We default to USB, this is the most common connection type and does not require additional * parameter, so we can auto-detect these. */ warn_if_bad_usb_port_filename(device_path); regex_array[0] = getval("vendorid"); regex_array[1] = getval("productid"); regex_array[2] = getval("vendor"); regex_array[3] = getval("product"); regex_array[4] = getval("serial"); regex_array[5] = getval("bus"); regex_array[6] = getval("device"); # if (defined WITH_USB_BUSPORT) && (WITH_USB_BUSPORT) regex_array[7] = getval("busport"); # else if (getval("busport")) { upslogx(LOG_WARNING, "\"busport\" is configured for the device, but is not actually handled by current build combination of NUT and libusb (ignored)"); } # endif has_nonzero_regex = 0; for (i = 0; i < SIZEOF_ARRAY(regex_array); i++) { if (regex_array[i] != NULL) { has_nonzero_regex = 1; break; } } best_matcher = &apc_modbus_usb_device_matcher; if (has_nonzero_regex > 0) { r = USBNewRegexMatcher(®ex_matcher, regex_array, REG_ICASE | REG_EXTENDED); if (r < 0) { fatal_with_errno(EXIT_FAILURE, "USBNewRegexMatcher"); } else if (r) { fatalx(EXIT_FAILURE, "invalid regular expression: %s", regex_array[r]); } regex_matcher->next = best_matcher; best_matcher = regex_matcher; } modbus_ctx = modbus_new_rtu_usb(MODBUS_USB_MODE_APC, _apc_modbus_usb_callback); #else fatalx(EXIT_FAILURE, "driver was not compiled with USB support"); #endif /* defined NUT_MODBUS_HAS_USB */ } else if (!strcasecmp(val, "tcp")) { if (!_apc_modbus_parse_host_port(device_path, tcp_host, sizeof(tcp_host), tcp_port, sizeof(tcp_port), modbus_tcp_default_port)) { fatalx(EXIT_FAILURE, "failed to parse host/port"); } modbus_ctx = modbus_new_tcp_pi(tcp_host, tcp_port); } else if (!strcasecmp(val, "serial")) { val = getval("baudrate"); rtu_baudrate = val ? atoi(val) : modbus_rtu_default_baudrate; val = getval("parity"); rtu_parity = val ? (char)toupper(val[0]) : modbus_rtu_default_parity; val = getval("databits"); rtu_databits = val ? atoi(val) : modbus_rtu_default_databits; val = getval("stopbits"); rtu_stopbits = val ? atoi(val) : modbus_rtu_default_stopbits; modbus_ctx = modbus_new_rtu(device_path, rtu_baudrate, rtu_parity, rtu_databits, rtu_stopbits); } if (modbus_ctx == NULL) { fatalx(EXIT_FAILURE, "Unable to create the libmodbus context: %s", modbus_strerror(errno)); } if (nut_debug_level > 5) { modbus_set_debug(modbus_ctx, 1); } val = getval("slaveid"); slaveid = val ? atoi(val) : modbus_default_slave_id; r = modbus_set_slave(modbus_ctx, slaveid); if (r < 0) { modbus_free(modbus_ctx); fatalx(EXIT_FAILURE, "modbus_set_slave: invalid slave id %d", slaveid); } val = getval("response_timeout_ms"); if (val != NULL) { response_timeout_ms = (uint32_t)strtoul(val, NULL, 0); #if (defined NUT_MODBUS_TIMEOUT_ARG_sec_usec_uint32) || (defined NUT_MODBUS_TIMEOUT_ARG_sec_usec_uint32_cast_timeval_fields) r = modbus_set_response_timeout(modbus_ctx, response_timeout_ms / 1000, (response_timeout_ms % 1000) * 1000); if (r < 0) { modbus_free(modbus_ctx); fatalx(EXIT_FAILURE, "modbus_set_response_timeout: error(%s)", modbus_strerror(errno)); } #elif (defined NUT_MODBUS_TIMEOUT_ARG_timeval_numeric_fields) { /* see comments above */ struct timeval to; memset(&to, 0, sizeof(struct timeval)); to.tv_sec = response_timeout_ms / 1000; to.tv_usec = (response_timeout_ms % 1000) * 1000; /* void */ modbus_set_response_timeout(modbus_ctx, &to); } /* #elif (defined NUT_MODBUS_TIMEOUT_ARG_timeval) // some un-castable type in fields */ #endif /* NUT_MODBUS_TIMEOUT_ARG_* */ } if (modbus_connect(modbus_ctx) == -1) { modbus_free(modbus_ctx); fatalx(EXIT_FAILURE, "modbus_connect: unable to connect: %s", modbus_strerror(errno)); } #if defined NUT_MODBUS_HAS_USB _apc_modbus_create_reopen_matcher(); #endif /* defined NUT_MODBUS_HAS_USB */ modbus_flush(modbus_ctx); is_open = 1; } void upsdrv_cleanup(void) { _apc_modbus_close(1); #if defined NUT_MODBUS_HAS_USB USBFreeExactMatcher(reopen_matcher); USBFreeExactMatcher(regex_matcher); #endif /* defined NUT_MODBUS_HAS_USB */ } nut-2.8.1/drivers/compaq-mib.c0000644000175000017500000004341714514200666013135 00000000000000/* compaq-mib.c - data to monitor SNMP UPS with NUT * * Copyright (C) * 2002-2012 Arnaud Quette * 2002-2006 Niels Baggesen * 2002-2006 Philip Ward * * This program was sponsored by MGE UPS SYSTEMS, and now Eaton * * This version has been tested using: * HP R5500XR UPS with management card AF401A and a single phase input * HP R/T3000 UPS with management card AF465A and a single phase input * * 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 2 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, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #include "compaq-mib.h" #define CPQPOWER_MIB_VERSION "1.67" #define DEFAULT_ONDELAY "30" #define DEFAULT_OFFDELAY "20" /* Note: RFC-1628 (UPS MIB) is also supported on these devices! */ /* SNMP OIDs set */ #define CPQPOWER_OID_UPS_MIB ".1.3.6.1.4.1.232.165.3" /* FIXME: to be verified */ #define CPQPOWER_SYSOID CPQPOWER_OID_UPS_MIB #define CPQPOWER_OID_MFR_NAME ".1.3.6.1.4.1.232.165.3.1.1.0" /* UPS-MIB::upsIdentManufacturer */ #define CPQPOWER_OID_MODEL_NAME ".1.3.6.1.4.1.232.165.3.1.2.0" /* UPS-MIB::upsIdentModel */ #define CPQPOWER_OID_FIRMREV ".1.3.6.1.4.1.232.165.3.1.3.0" /* UPS-MIB::upsIdentUPSSoftwareVersion */ #define CPQPOWER_OID_OEMCODE ".1.3.6.1.4.1.232.165.3.1.4.0" /* UPS-MIB::upsIdentAgentSoftwareVersion */ #define CPQPOWER_OID_BATT_RUNTIME ".1.3.6.1.4.1.232.165.3.2.1.0" /* UPS-MIB::upsEstimatedMinutesRemaining */ #define CPQPOWER_OID_BATT_VOLTAGE ".1.3.6.1.4.1.232.165.3.2.2.0" /* UPS-MIB::upsBatteryVoltage */ #define CPQPOWER_OID_BATT_CURRENT ".1.3.6.1.4.1.232.165.3.2.3.0" /* UPS-MIB::upsBatteryCurrent */ #define CPQPOWER_OID_BATT_CHARGE ".1.3.6.1.4.1.232.165.3.2.4.0" /* UPS-MIB::upsBattCapacity */ #define CPQPOWER_OID_BATT_STATUS ".1.3.6.1.4.1.232.165.3.2.5.0" /* UPS-MIB::upsBatteryAbmStatus */ #define CPQPOWER_OID_IN_FREQ ".1.3.6.1.4.1.232.165.3.3.1.0" /* UPS-MIB::upsInputFrequency */ #define CPQPOWER_OID_IN_LINEBADS ".1.3.6.1.4.1.232.165.3.3.2.0" /* UPS-MIB::upsInputLineBads */ #define CPQPOWER_OID_IN_LINES ".1.3.6.1.4.1.232.165.3.3.3.0" /* UPS-MIB::upsInputNumPhases */ #define CPQPOWER_OID_IN_PHASE ".1.3.6.1.4.1.232.165.3.3.4.1.1" /* UPS-MIB::upsInputPhase */ #define CPQPOWER_OID_IN_VOLTAGE ".1.3.6.1.4.1.232.165.3.3.4.1.2" /* UPS-MIB::upsInputVoltage */ #define CPQPOWER_OID_IN_CURRENT ".1.3.6.1.4.1.232.165.3.3.4.1.3" /* UPS-MIB::upsInputCurrent */ #define CPQPOWER_OID_IN_POWER ".1.3.6.1.4.1.232.165.3.3.4.1.4" /* UPS-MIB::upsInputWatts */ #define CPQPOWER_OID_LOAD_LEVEL ".1.3.6.1.4.1.232.165.3.4.1.0" /* UPS-MIB::upsOutputLoad */ #define CPQPOWER_OID_OUT_FREQUENCY ".1.3.6.1.4.1.232.165.3.4.2.0" /* UPS-MIB::upsOutputFrequency */ #define CPQPOWER_OID_OUT_LINES ".1.3.6.1.4.1.232.165.3.4.3.0" /* UPS-MIB::upsOutputNumPhases */ #define CPQPOWER_OID_OUT_PHASE ".1.3.6.1.4.1.232.165.3.4.4.1.1" /* UPS-MIB::upsOutputPhase */ #define CPQPOWER_OID_OUT_VOLTAGE ".1.3.6.1.4.1.232.165.3.4.4.1.2" /* UPS-MIB::upsOutputVoltage */ #define CPQPOWER_OID_OUT_CURRENT ".1.3.6.1.4.1.232.165.3.4.4.1.3" /* UPS-MIB::upsOutputCurrent */ #define CPQPOWER_OID_OUT_POWER ".1.3.6.1.4.1.232.165.3.4.4.1.4" /* UPS-MIB::upsOutputWatts */ #define CPQPOWER_OID_POWER_STATUS ".1.3.6.1.4.1.232.165.3.4.5.0" /* UPS-MIB::upsOutputSource */ #define CPQPOWER_OID_AMBIENT_TEMP ".1.3.6.1.4.1.232.165.3.6.1.0" /* UPS-MIB::upsEnvAmbientTemp */ #define CPQPOWER_OID_UPS_TEST_BATT ".1.3.6.1.4.1.232.165.3.7.1.0" /* UPS-MIB::upsTestBattery */ #define CPQPOWER_OID_UPS_TEST_RES ".1.3.6.1.4.1.232.165.3.7.2.0" /* UPS-MIB::upsTestBatteryStatus */ #define CPQPOWER_OID_ALARM_OB ".1.3.6.1.4.1.232.165.3.7.3.0" /* UPS-MIB::upsOnBattery */ #define CPQPOWER_OID_ALARM_LB ".1.3.6.1.4.1.232.165.3.7.4.0" /* UPS-MIB::upsLowBattery */ #define IETF_OID_AGENTREV ".1.3.6.1.2.1.33.1.1.4.0" /* UPS-MIB::upsIdentAgentSoftwareVersion.0 */ /* Not used, as no longer supported by MIB ver. 1.76 (Github issue 118) static info_lkp_t cpqpower_alarm_ob[] = { { 1, "OB", NULL, NULL }, { 0, NULL, NULL, NULL } }; */ /* Not used, as no longer supported by MIB ver. 1.76 (Github issue 118) static info_lkp_t cpqpower_alarm_lb[] = { { 1, "LB", NULL, NULL }, { 0, NULL, NULL, NULL } }; */ /* Defines for CPQPOWER_OID_POWER_STATUS (1) */ static info_lkp_t cpqpower_pwr_info[] = { { 1, "" /* other */, NULL, NULL }, { 2, "OFF" /* none */, NULL, NULL }, { 3, "OL" /* normal */, NULL, NULL }, { 4, "OL BYPASS" /* bypass */, NULL, NULL }, { 5, "OB" /* battery */, NULL, NULL }, { 6, "OL BOOST" /* booster */, NULL, NULL }, { 7, "OL TRIM" /* reducer */, NULL, NULL }, { 8, "OL" /* parallelCapacity */, NULL, NULL }, { 9, "OL" /* parallelRedundant */, NULL, NULL }, { 10, "OL" /* HighEfficiencyMode */, NULL, NULL }, { 0, NULL, NULL, NULL } } ; static info_lkp_t cpqpower_mode_info[] = { { 1, "", NULL, NULL }, { 2, "", NULL, NULL }, { 3, "normal", NULL, NULL }, { 4, "", NULL, NULL }, { 5, "", NULL, NULL }, { 6, "", NULL, NULL }, { 7, "", NULL, NULL }, { 8, "parallel capacity", NULL, NULL }, { 9, "parallel redundancy", NULL, NULL }, {10, "high efficiency", NULL, NULL }, { 0, NULL, NULL, NULL } }; static info_lkp_t cpqpower_battery_abm_status[] = { { 1, "CHRG", NULL, NULL }, { 2, "DISCHRG", NULL, NULL }, /* { 3, "Floating", NULL, NULL }, */ /* { 4, "Resting", NULL, NULL }, */ /* { 5, "Unknown", NULL, NULL }, */ { 0, NULL, NULL, NULL } } ; /* Defines for CPQPOWER_OID_UPS_TEST_RES */ static info_lkp_t cpqpower_test_res_info[] = { { 1, "Unknown", NULL, NULL }, { 2, "Done and passed", NULL, NULL }, { 3, "Done and error", NULL, NULL }, { 4, "In progress", NULL, NULL }, { 5, "Not supported", NULL, NULL }, { 6, "Inhibited", NULL, NULL }, { 7, "Scheduled", NULL, NULL }, { 0, NULL, NULL, NULL } } ; #define CPQPOWER_START_TEST "1" static info_lkp_t cpqpower_outlet_status_info[] = { { 1, "on", NULL, NULL }, { 2, "off", NULL, NULL }, { 3, "pendingOff", NULL, NULL }, /* transitional status */ { 4, "pendingOn", NULL, NULL }, /* transitional status */ { 5, "unknown", NULL, NULL }, { 0, NULL, NULL, NULL } }; /* Ugly hack: having the matching OID present means that the outlet is * switchable. So, it should not require this value lookup */ static info_lkp_t cpqpower_outlet_switchability_info[] = { { 1, "yes", NULL, NULL }, { 2, "yes", NULL, NULL }, { 3, "yes", NULL, NULL }, { 4, "yes", NULL, NULL }, { 0, NULL, NULL, NULL } }; #define CPQPOWER_OID_SD_AFTER_DELAY ".1.3.6.1.4.1.232.165.3.8.1.0" /* UPS-MIB::upsControlOutputOffDelay */ #define CPQPOWER_OFF_DO 0 /* Snmp2NUT lookup table */ static snmp_info_t cpqpower_mib[] = { /* standard MIB items */ { "device.description", ST_FLAG_STRING | ST_FLAG_RW, SU_INFOSIZE, ".1.3.6.1.2.1.1.1.0", NULL, SU_FLAG_OK, NULL }, { "device.contact", ST_FLAG_STRING | ST_FLAG_RW, SU_INFOSIZE, ".1.3.6.1.2.1.1.4.0", NULL, SU_FLAG_OK, NULL }, { "device.location", ST_FLAG_STRING | ST_FLAG_RW, SU_INFOSIZE, ".1.3.6.1.2.1.1.6.0", NULL, SU_FLAG_OK, NULL }, /* UPS page */ /* info_type, info_flags, info_len, OID, dfl, flags, oid2info, setvar */ { "ups.mfr", ST_FLAG_STRING, SU_INFOSIZE, CPQPOWER_OID_MFR_NAME, "HP/Compaq", SU_FLAG_STATIC, NULL }, { "ups.model", ST_FLAG_STRING, SU_INFOSIZE, CPQPOWER_OID_MODEL_NAME, "SNMP UPS", SU_FLAG_STATIC, NULL }, /* { "ups.model.aux", ST_FLAG_STRING, SU_INFOSIZE, CPQPOWER_OID_OEMCODE, "", SU_FLAG_STATIC, NULL },*/ { "ups.serial", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.232.165.1.2.7.0", "", SU_FLAG_STATIC | SU_FLAG_OK, NULL }, /* FIXME: split between firmware and firmware.aux ("00.01.0019;00.01.0004") * UPS Firmware Revision : 00.01.0004 * Communication Board Firmware Revision : 00.01.0019 */ /* FIXME: the 2 "firmware" entries below should be SU_FLAG_SEMI_STATIC */ { "ups.firmware", ST_FLAG_STRING, SU_INFOSIZE, CPQPOWER_OID_FIRMREV, "", 0, NULL }, { "ups.firmware.aux", ST_FLAG_STRING, SU_INFOSIZE, IETF_OID_AGENTREV, "", 0, NULL }, { "ups.load", 0, 1.0, CPQPOWER_OID_LOAD_LEVEL, "", 0, NULL }, { "ups.realpower.nominal", 0, 1.0, ".1.3.6.1.4.1.232.165.3.9.3.0", "", SU_OUTPUT_1, NULL }, { "ups.realpower", 0, 1.0, CPQPOWER_OID_OUT_POWER ".1", "", SU_OUTPUT_1, NULL }, { "ups.L1.realpower", 0, 1.0, CPQPOWER_OID_OUT_POWER ".1", "", SU_OUTPUT_3, NULL }, { "ups.L2.realpower", 0, 1.0, CPQPOWER_OID_OUT_POWER ".2", "", SU_OUTPUT_3, NULL }, { "ups.L3.realpower", 0, 1.0, CPQPOWER_OID_OUT_POWER ".3", "", SU_OUTPUT_3, NULL }, { "ups.status", ST_FLAG_STRING, SU_INFOSIZE, CPQPOWER_OID_POWER_STATUS, "OFF", SU_STATUS_PWR, cpqpower_pwr_info }, { "ups.status", ST_FLAG_STRING, SU_INFOSIZE, CPQPOWER_OID_BATT_STATUS, "", SU_STATUS_PWR, cpqpower_battery_abm_status }, /* The next two lines are no longer supported by MIB ver. 1.76 (Github issue 118) * { "ups.status", ST_FLAG_STRING, SU_INFOSIZE, CPQPOWER_OID_ALARM_OB, "", SU_STATUS_BATT, cpqpower_alarm_ob }, * { "ups.status", ST_FLAG_STRING, SU_INFOSIZE, CPQPOWER_OID_ALARM_LB, "", SU_STATUS_BATT, cpqpower_alarm_lb }, */ /* { "ups.status", ST_FLAG_STRING, SU_INFOSIZE, IETF_OID_BATT_STATUS, "", SU_STATUS_BATT, ietf_batt_info }, */ /* FIXME: this should use either .1.3.6.1.4.1.232.165.3.11.1.0 (upsTopologyType) * or .1.3.6.1.4.1.232.165.3.11.2.0 (upsTopoMachineCode) */ { "ups.type", ST_FLAG_STRING, SU_INFOSIZE, CPQPOWER_OID_POWER_STATUS, "", SU_STATUS_PWR, cpqpower_mode_info }, { "ups.test.result", ST_FLAG_STRING, SU_INFOSIZE, CPQPOWER_OID_UPS_TEST_RES, "", 0, cpqpower_test_res_info }, /* FIXME: handle ups.date and ups.time * - OID: .1.3.6.1.4.1.232.165.3.9.5.0 * - format MM/DD/YYYY HH:MM:SS */ /* FIXME: handle upsInputSource.0 (".1.3.6.1.4.1.232.165.3.3.5.0") * other(1) * none(2) * primaryUtility(3) * bypassFeed(4) * secondaryUtility(5) * generator(6) * flywheel(7) * fuelcell(8) */ { "ups.delay.shutdown", ST_FLAG_STRING | ST_FLAG_RW, 6, ".1.3.6.1.4.1.232.165.3.8.1.0", DEFAULT_OFFDELAY, SU_FLAG_ABSENT | SU_FLAG_OK, NULL }, { "ups.delay.start", ST_FLAG_STRING | ST_FLAG_RW, 6, ".1.3.6.1.4.1.232.165.3.8.2.0", DEFAULT_ONDELAY, SU_FLAG_ABSENT | SU_FLAG_OK, NULL }, { "ups.timer.shutdown", 0, 1, ".1.3.6.1.4.1.232.165.3.8.1.0", "", SU_FLAG_OK, NULL }, { "ups.timer.start", 0, 1, ".1.3.6.1.4.1.232.165.3.8.2.0", "", SU_FLAG_OK, NULL }, /* Ambient page */ { "ambient.temperature", 0, 1.0, CPQPOWER_OID_AMBIENT_TEMP, "", 0, NULL }, { "ambient.temperature.low", 0, 1.0, ".1.3.6.1.4.1.232.165.3.6.2.0", "", 0, NULL }, { "ambient.temperature.high", 0, 1.0, ".1.3.6.1.4.1.232.165.3.6.3.0", "", 0, NULL }, /* Battery page */ { "battery.charge", 0, 1.0, CPQPOWER_OID_BATT_CHARGE, "", 0, NULL }, { "battery.runtime", 0, 1.0, CPQPOWER_OID_BATT_RUNTIME, "", 0, NULL }, { "battery.voltage", 0, 0.1, CPQPOWER_OID_BATT_VOLTAGE, "", 0, NULL }, { "battery.current", 0, 0.1, CPQPOWER_OID_BATT_CURRENT, "", 0, NULL }, /* FIXME: need the new variable (for ABM) { "battery.status", 0, 0.1, ".1.3.6.1.4.1.232.165.3.2.5.0", "", 0, NULL }, */ /* Input page */ { "input.phases", 0, 1.0, CPQPOWER_OID_IN_LINES, "", 0, NULL }, { "input.frequency", 0, 0.1, CPQPOWER_OID_IN_FREQ , "", 0, NULL }, { "input.voltage.nominal", 0, 1.0, ".1.3.6.1.4.1.232.165.3.9.2.0", "", 0, NULL }, { "input.voltage", 0, 1.0, CPQPOWER_OID_IN_VOLTAGE ".1", "", SU_OUTPUT_1, NULL }, { "input.L1-N.voltage", 0, 1.0, CPQPOWER_OID_IN_VOLTAGE ".1", "", SU_INPUT_3, NULL }, { "input.L2-N.voltage", 0, 1.0, CPQPOWER_OID_IN_VOLTAGE ".2", "", SU_INPUT_3, NULL }, { "input.L3-N.voltage", 0, 1.0, CPQPOWER_OID_IN_VOLTAGE ".3", "", SU_INPUT_3, NULL }, { "input.current", 0, 1.0, CPQPOWER_OID_IN_CURRENT ".1", "", SU_OUTPUT_1, NULL }, { "input.L1.current", 0, 1.0, CPQPOWER_OID_IN_CURRENT ".1", "", SU_INPUT_3, NULL }, { "input.L2.current", 0, 1.0, CPQPOWER_OID_IN_CURRENT ".2", "", SU_INPUT_3, NULL }, { "input.L3.current", 0, 1.0, CPQPOWER_OID_IN_CURRENT ".3", "", SU_INPUT_3, NULL }, { "input.realpower", 0, 1.0, CPQPOWER_OID_IN_POWER ".1", "", SU_OUTPUT_1, NULL }, { "input.L1.realpower", 0, 1.0, CPQPOWER_OID_IN_POWER ".1", "", SU_INPUT_3, NULL }, { "input.L2.realpower", 0, 1.0, CPQPOWER_OID_IN_POWER ".2", "", SU_INPUT_3, NULL }, { "input.L3.realpower", 0, 1.0, CPQPOWER_OID_IN_POWER ".3", "", SU_INPUT_3, NULL }, { "input.quality", 0, 1.0, CPQPOWER_OID_IN_LINEBADS, "", 0, NULL }, /* Output page */ { "output.phases", 0, 1.0, CPQPOWER_OID_OUT_LINES, "", 0, NULL }, { "output.frequency.nominal", 0, 0.1, ".1.3.6.1.4.1.232.165.3.9.4.0", "", 0, NULL }, { "output.frequency", 0, 0.1, CPQPOWER_OID_OUT_FREQUENCY, "", 0, NULL }, { "output.voltage.nominal", 0, 1.0, ".1.3.6.1.4.1.232.165.3.9.1.0", "", 0, NULL }, { "output.voltage", 0, 1.0, CPQPOWER_OID_OUT_VOLTAGE ".1", "", SU_OUTPUT_1, NULL }, { "output.L1-N.voltage", 0, 1.0, CPQPOWER_OID_OUT_VOLTAGE ".1", "", SU_OUTPUT_3, NULL }, { "output.L2-N.voltage", 0, 1.0, CPQPOWER_OID_OUT_VOLTAGE ".2", "", SU_OUTPUT_3, NULL }, { "output.L3-N.voltage", 0, 1.0, CPQPOWER_OID_OUT_VOLTAGE ".3", "", SU_OUTPUT_3, NULL }, { "output.current", 0, 1.0, CPQPOWER_OID_OUT_CURRENT ".1", "", SU_OUTPUT_1, NULL }, { "output.L1.current", 0, 1.0, CPQPOWER_OID_OUT_CURRENT ".1", "", SU_OUTPUT_3, NULL }, { "output.L2.current", 0, 1.0, CPQPOWER_OID_OUT_CURRENT ".2", "", SU_OUTPUT_3, NULL }, { "output.L3.current", 0, 1.0, CPQPOWER_OID_OUT_CURRENT ".3", "", SU_OUTPUT_3, NULL }, /* FIXME: what to map with these? * Name/OID: upsConfigLowOutputVoltageLimit.0; Value (Integer): 160 * => input.transfer.low? * Name/OID: upsConfigHighOutputVoltageLimit.0; Value (Integer): 288 * => input.transfer.high? */ /* Outlet page */ { "outlet.id", 0, 1, NULL, "0", SU_FLAG_STATIC | SU_FLAG_ABSENT | SU_FLAG_OK, NULL }, { "outlet.desc", ST_FLAG_RW | ST_FLAG_STRING, 20, NULL, "All outlets", SU_FLAG_STATIC | SU_FLAG_ABSENT | SU_FLAG_OK, NULL }, { "outlet.count", 0, 1, ".1.3.6.1.4.1.232.165.3.10.1.0", "0", 0, NULL }, /* upsNumReceptacles */ /* { "outlet.current", 0, 0.001, AR_OID_UNIT_CURRENT ".0", NULL, 0, NULL, NULL }, { "outlet.voltage", 0, 0.001, AR_OID_UNIT_VOLTAGE ".0", NULL, 0, NULL, NULL }, { "outlet.realpower", 0, 1.0, AR_OID_UNIT_ACTIVEPOWER ".0", NULL, 0, NULL, NULL }, { "outlet.power", 0, 1.0, AR_OID_UNIT_APPARENTPOWER ".0", NULL, 0, NULL, NULL }, */ /* outlet template definition */ /* FIXME always true? */ { "outlet.%i.switchable", ST_FLAG_STRING, 3, ".1.3.6.1.4.1.232.165.3.10.2.1.1.%i", "yes", SU_FLAG_STATIC | SU_OUTLET, &cpqpower_outlet_switchability_info[0] }, { "outlet.%i.id", 0, 1, ".1.3.6.1.4.1.232.165.3.10.2.1.1.%i", "%i", SU_FLAG_STATIC | SU_FLAG_ABSENT | SU_FLAG_OK | SU_OUTLET, NULL }, /* { "outlet.%i.desc", ST_FLAG_RW | ST_FLAG_STRING, SU_INFOSIZE, AR_OID_OUTLET_NAME ".%i", NULL, SU_OUTLET, NULL }, */ { "outlet.%i.status", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.232.165.3.10.2.1.2.%i", NULL, SU_FLAG_OK | SU_OUTLET, &cpqpower_outlet_status_info[0] }, /* FIXME: come up with a suitable varname! * - The delay after going On Battery until the Receptacle is automatically turned Off. * A value of -1 means that this Output should never be turned Off automatically, but must be turned Off only by command. * { "outlet.%i.autoswitch.delay.shutdown", ST_FLAG_STRING | ST_FLAG_RW, 6, ".1.3.6.1.4.1.232.165.3.10.2.1.5.%i", DEFAULT_OFFDELAY, SU_FLAG_ABSENT | SU_FLAG_OK, NULL }, // upsRecepAutoOffDelay * - Seconds delay after the Outlet is signaled to turn On before the Output is Automatically turned ON. * A value of -1 means that this Output should never be turned On automatically, but only when specifically commanded to do so. * { "outlet.%i.autoswitch.delay.start", ST_FLAG_STRING | ST_FLAG_RW, 6, ".1.3.6.1.4.1.232.165.3.10.2.1.5.%i", DEFAULT_OFFDELAY, SU_FLAG_ABSENT | SU_FLAG_OK, NULL }, // upsRecepAutoOnDelay */ /* FIXME: also define .stop (as for 'shutdown.reboot') * and .delay */ { "outlet.%i.load.off", 0, 1, ".1.3.6.1.4.1.232.165.3.10.2.1.3.%i", "0", SU_TYPE_CMD | SU_OUTLET, NULL }, { "outlet.%i.load.on", 0, 1, ".1.3.6.1.4.1.232.165.3.10.2.1.4.%i", "0", SU_TYPE_CMD | SU_OUTLET, NULL }, /* FIXME: also define a .delay or map to "outlet.%i.delay.shutdown" */ { "outlet.%i.load.cycle", 0, 1, ".1.3.6.1.4.1.232.165.3.10.2.1.7.%i", "0", SU_TYPE_CMD | SU_OUTLET, NULL }, /* instant commands. */ /* We need to duplicate load.{on,off} Vs load.{on,off}.delay, since * "0" cancels the shutdown, so we put "1" (second) for immediate off! */ { "load.off", 0, 1, ".1.3.6.1.4.1.232.165.3.8.1.0", "1", SU_TYPE_CMD, NULL }, { "load.on", 0, 1, ".1.3.6.1.4.1.232.165.3.8.2.0", "1", SU_TYPE_CMD, NULL }, { "shutdown.stop", 0, 1, ".1.3.6.1.4.1.232.165.3.8.1.0", "0", SU_TYPE_CMD | SU_FLAG_OK, NULL }, /* FIXME: need ups.{timer,delay}.{start,shutdown} param counterparts! */ { "load.off.delay", 0, 1, ".1.3.6.1.4.1.232.165.3.8.1.0", DEFAULT_OFFDELAY, SU_TYPE_CMD, NULL }, { "load.on.delay", 0, 1, ".1.3.6.1.4.1.232.165.3.8.2.0", DEFAULT_ONDELAY, SU_TYPE_CMD, NULL }, /* { CMD_SHUTDOWN, 0, CPQPOWER_OFF_GRACEFUL, CPQPOWER_OID_OFF, "", 0, NULL }, */ { "shutdown.reboot", 0, 1, ".1.3.6.1.4.1.232.165.3.8.6.0", "0", SU_TYPE_CMD | SU_FLAG_OK, NULL }, { "test.battery.start", 0, 1, ".1.3.6.1.4.1.232.165.3.7.1.0", CPQPOWER_START_TEST, SU_TYPE_CMD | SU_FLAG_OK, NULL }, /* end of structure. */ { NULL, 0, 0, NULL, NULL, 0, NULL } }; mib2nut_info_t compaq = { "cpqpower", CPQPOWER_MIB_VERSION, NULL, CPQPOWER_OID_MFR_NAME, cpqpower_mib, CPQPOWER_SYSOID, NULL }; nut-2.8.1/drivers/nut-libfreeipmi.c0000644000175000017500000010446314502253356014203 00000000000000/* nut-libfreeipmi.c - NUT IPMI backend, using FreeIPMI * * Copyright (C) * 2011 - 2012 Arnaud Quette * 2011 - Albert Chu * * Based on the sample codes 'ipmi-fru-example.c', 'frulib.c' and * 'ipmimonitoring-sensors.c', from FreeIPMI * * 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 2 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, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * TODO: * add power control support (ipmipower): seems OOB only! -n, --on Power on the target hosts. -f, --off Power off the target hosts. -c, --cycle Power cycle the target hosts. -r, --reset Reset the target hosts. -s, --stat Get power status of the target hosts. --pulse Send power diagnostic interrupt to target hosts. --soft Initiate a soft-shutdown of the OS via ACPI. --on-if-off Issue a power on command instead of a power cycle or hard reset command if the remote machine's power is currently off. --wait-until-off Regularly query the remote BMC and return only after the machine has powered off. --wait-until-on Regularly query the remote BMC and return only */ #include "config.h" /* must be first */ #include #include #include "timehead.h" #include "common.h" #include #include #if HAVE_FREEIPMI_MONITORING #include #endif #include "nut-ipmi.h" #include "nut_stdint.h" #include "dstate.h" /* FreeIPMI defines */ #define IPMI_FRU_STR_BUFLEN 1024 /* haven't seen a motherboard with more than 2-3 so far, * 64 should be more than enough */ #define IPMI_FRU_CUSTOM_FIELDS 64 /* FreeIPMI contexts and configuration*/ static ipmi_ctx_t ipmi_ctx = NULL; static ipmi_monitoring_ctx_t mon_ctx = NULL; /* static struct ipmi_monitoring_ipmi_config ipmi_config; */ /* SDR management API has changed with 1.1.X and later */ #ifdef HAVE_FREEIPMI_11X_12X static ipmi_sdr_ctx_t sdr_ctx = NULL; static ipmi_fru_ctx_t fru_ctx = NULL; #define SDR_PARSE_CTX sdr_ctx #define NUT_IPMI_SDR_CACHE_DEFAULTS IPMI_SDR_CACHE_CREATE_FLAGS_DEFAULT #else static ipmi_sdr_cache_ctx_t sdr_ctx = NULL; static ipmi_sdr_parse_ctx_t sdr_parse_ctx = NULL; #define SDR_PARSE_CTX sdr_parse_ctx static ipmi_fru_parse_ctx_t fru_ctx = NULL; /* Functions remapping */ #define ipmi_sdr_ctx_create ipmi_sdr_cache_ctx_create #define ipmi_sdr_ctx_destroy ipmi_sdr_cache_ctx_destroy #define ipmi_sdr_ctx_errnum ipmi_sdr_cache_ctx_errnum #define ipmi_sdr_ctx_errormsg ipmi_sdr_cache_ctx_errormsg #define ipmi_fru_ctx_create ipmi_fru_parse_ctx_create #define ipmi_fru_ctx_destroy ipmi_fru_parse_ctx_destroy #define ipmi_fru_ctx_set_flags ipmi_fru_parse_ctx_set_flags #define ipmi_fru_ctx_strerror ipmi_fru_parse_ctx_strerror #define ipmi_fru_ctx_errnum ipmi_fru_parse_ctx_errnum #define ipmi_fru_open_device_id ipmi_fru_parse_open_device_id #define ipmi_fru_close_device_id ipmi_fru_parse_close_device_id #define ipmi_fru_ctx_errormsg ipmi_fru_parse_ctx_errormsg #define ipmi_fru_read_data_area ipmi_fru_parse_read_data_area #define ipmi_fru_next ipmi_fru_parse_next #define ipmi_fru_type_length_field_to_string ipmi_fru_parse_type_length_field_to_string #define ipmi_fru_multirecord_power_supply_information ipmi_fru_parse_multirecord_power_supply_information #define ipmi_fru_board_info_area ipmi_fru_parse_board_info_area #define ipmi_fru_field_t ipmi_fru_parse_field_t /* Constants */ #define IPMI_SDR_MAX_RECORD_LENGTH IPMI_SDR_CACHE_MAX_SDR_RECORD_LENGTH #define IPMI_SDR_ERR_CACHE_READ_CACHE_DOES_NOT_EXIST IPMI_SDR_CACHE_ERR_CACHE_READ_CACHE_DOES_NOT_EXIST #define IPMI_FRU_AREA_SIZE_MAX IPMI_FRU_PARSE_AREA_SIZE_MAX #define IPMI_FRU_FLAGS_SKIP_CHECKSUM_CHECKS IPMI_FRU_PARSE_FLAGS_SKIP_CHECKSUM_CHECKS #define IPMI_FRU_AREA_TYPE_BOARD_INFO_AREA IPMI_FRU_PARSE_AREA_TYPE_BOARD_INFO_AREA #define IPMI_FRU_AREA_TYPE_MULTIRECORD_POWER_SUPPLY_INFORMATION IPMI_FRU_PARSE_AREA_TYPE_MULTIRECORD_POWER_SUPPLY_INFORMATION #define IPMI_FRU_AREA_STRING_MAX IPMI_FRU_PARSE_AREA_STRING_MAX #define NUT_IPMI_SDR_CACHE_DEFAULTS IPMI_SDR_CACHE_CREATE_FLAGS_DEFAULT, IPMI_SDR_CACHE_VALIDATION_FLAGS_DEFAULT #endif /* HAVE_FREEIPMI_11X_12X */ /* FIXME: freeipmi auto selects a cache based on the hostname you are * connecting too, but this is probably fine for you */ #define CACHE_LOCATION "/tmp/sdrcache" /* Support functions */ static const char* libfreeipmi_getfield (uint8_t language_code, ipmi_fru_field_t *field); static void libfreeipmi_cleanup(void); static int libfreeipmi_get_psu_info (const void *areabuf, uint8_t area_length, IPMIDevice_t *ipmi_dev); static int libfreeipmi_get_board_info (const void *areabuf, uint8_t area_length, IPMIDevice_t *ipmi_dev); static int libfreeipmi_get_sensors_info (IPMIDevice_t *ipmi_dev); /******************************************************************************* * Implementation ******************************************************************************/ int nut_ipmi_open(int ipmi_id, IPMIDevice_t *ipmi_dev) { int ret = -1; uint8_t areabuf[IPMI_FRU_AREA_SIZE_MAX+1]; unsigned int area_type = 0; unsigned int area_length = 0; upsdebugx(1, "nut-libfreeipmi: nutipmi_open()..."); /* FIXME? Check arg types for ipmi_fru_open_device_id() in configure? * At this time it is uint8_t for libfreeipmi implementation of IPMI. */ if (ipmi_id > (int)UINT8_MAX) { libfreeipmi_cleanup(); fatal_with_errno(EXIT_FAILURE, "nut_ipmi_open: ipmi_id %d is too large for libfreeipmi", ipmi_id); } /* Initialize the FreeIPMI library. */ if (!(ipmi_ctx = ipmi_ctx_create ())) { /* we have to force cleanup, since exit handler is not yet installed */ libfreeipmi_cleanup(); fatal_with_errno(EXIT_FAILURE, "ipmi_ctx_create"); } if ((ret = ipmi_ctx_find_inband (ipmi_ctx, NULL, 0, /* don't disable auto-probe */ 0, 0, NULL, 0, /* workaround flags, none by default */ 0 /* flags */ )) < 0) { libfreeipmi_cleanup(); fatalx(EXIT_FAILURE, "ipmi_ctx_find_inband: %s", ipmi_ctx_errormsg (ipmi_ctx)); } if (!ret) { libfreeipmi_cleanup(); fatalx(EXIT_FAILURE, "could not find inband device"); } upsdebugx(1, "FreeIPMI initialized..."); /* Parse FRU information */ if (!(fru_ctx = ipmi_fru_ctx_create (ipmi_ctx))) { libfreeipmi_cleanup(); fatal_with_errno(EXIT_FAILURE, "ipmi_fru_ctx_create()"); } /* lots of motherboards calculate checksums incorrectly */ if (ipmi_fru_ctx_set_flags (fru_ctx, IPMI_FRU_FLAGS_SKIP_CHECKSUM_CHECKS) < 0) { libfreeipmi_cleanup(); fatalx(EXIT_FAILURE, "ipmi_fru_ctx_set_flags: %s\n", ipmi_fru_ctx_strerror (ipmi_fru_ctx_errnum (fru_ctx))); } /* Now open the requested (local) PSU */ if (ipmi_fru_open_device_id (fru_ctx, (uint8_t)ipmi_id) < 0) { libfreeipmi_cleanup(); fatalx(EXIT_FAILURE, "ipmi_fru_open_device_id: %s\n", ipmi_fru_ctx_errormsg (fru_ctx)); } /* Set IPMI identifier */ ipmi_dev->ipmi_id = ipmi_id; do { /* clear fields */ area_type = 0; area_length = 0; memset (areabuf, '\0', IPMI_FRU_AREA_SIZE_MAX + 1); /* parse FRU buffer */ if (ipmi_fru_read_data_area (fru_ctx, &area_type, &area_length, areabuf, IPMI_FRU_AREA_SIZE_MAX) < 0) { libfreeipmi_cleanup(); fatal_with_errno(EXIT_FAILURE, "ipmi_fru_read_data_area: %s\n", ipmi_fru_ctx_errormsg (fru_ctx)); } if (area_length) { if (area_length > (int)UINT8_MAX) { libfreeipmi_cleanup(); fatal_with_errno(EXIT_FAILURE, "nut_ipmi_open: got area_length %d is too large for libfreeipmi", area_length); } switch (area_type) { /* get generic board information */ case IPMI_FRU_AREA_TYPE_BOARD_INFO_AREA: if(libfreeipmi_get_board_info (areabuf, (uint8_t)area_length, ipmi_dev) < 0) { upsdebugx(1, "Can't retrieve board information"); } break; /* get specific PSU information */ case IPMI_FRU_AREA_TYPE_MULTIRECORD_POWER_SUPPLY_INFORMATION: if(libfreeipmi_get_psu_info (areabuf, (uint8_t)area_length, ipmi_dev) < 0) { upsdebugx(1, "Can't retrieve PSU information"); } break; default: upsdebugx (5, "FRU: discarding FRU Area Type Read: %02Xh", area_type); break; } } } while ((ret = ipmi_fru_next (fru_ctx)) == 1); /* check for errors */ if (ret < 0) { libfreeipmi_cleanup(); fatal_with_errno(EXIT_FAILURE, "ipmi_fru_next: %s", ipmi_fru_ctx_errormsg (fru_ctx)); } else { /* Get all related sensors information */ libfreeipmi_get_sensors_info (ipmi_dev); } /* cleanup context */ libfreeipmi_cleanup(); return (0); } void nut_ipmi_close(void) { upsdebugx(1, "nutipmi_close..."); libfreeipmi_cleanup(); } static const char* libfreeipmi_getfield (uint8_t language_code, ipmi_fru_field_t *field) { static char strbuf[IPMI_FRU_AREA_STRING_MAX + 1]; unsigned int strbuflen = IPMI_FRU_AREA_STRING_MAX; if (!field->type_length_field_length) return NULL; memset (strbuf, '\0', IPMI_FRU_AREA_STRING_MAX + 1); if (ipmi_fru_type_length_field_to_string (fru_ctx, field->type_length_field, field->type_length_field_length, language_code, strbuf, &strbuflen) < 0) { upsdebugx (2, "ipmi_fru_type_length_field_to_string: %s", ipmi_fru_ctx_errormsg (fru_ctx)); return NULL; } if (strbuflen) return strbuf; return NULL; } /* Get voltage value from the IPMI voltage code */ static float libfreeipmi_get_voltage (uint8_t voltage_code) { if (voltage_code == IPMI_FRU_VOLTAGE_12V) return 12; else if (voltage_code == IPMI_FRU_VOLTAGE_MINUS12V) return -12; else if (voltage_code == IPMI_FRU_VOLTAGE_5V) return 5; else if (voltage_code == IPMI_FRU_VOLTAGE_3_3V) return 3.3; else return 0; } /* Cleanup IPMI contexts */ static void libfreeipmi_cleanup(void) { /* cleanup */ if (fru_ctx) { ipmi_fru_close_device_id (fru_ctx); ipmi_fru_ctx_destroy (fru_ctx); } if (sdr_ctx) { ipmi_sdr_ctx_destroy (sdr_ctx); } #ifndef HAVE_FREEIPMI_11X_12X if (sdr_parse_ctx) { ipmi_sdr_parse_ctx_destroy (sdr_parse_ctx); } #endif if (ipmi_ctx) { ipmi_ctx_close (ipmi_ctx); ipmi_ctx_destroy (ipmi_ctx); } if (mon_ctx) { ipmi_monitoring_ctx_destroy (mon_ctx); } } /* Get generic board information (manufacturer and model names, serial, ...) * from IPMI FRU */ static int libfreeipmi_get_psu_info (const void *areabuf, uint8_t area_length, IPMIDevice_t *ipmi_dev) { /* FIXME: directly use ipmi_dev fields */ unsigned int overall_capacity; input_voltage_range_t low_end_input_voltage_range_1; input_voltage_range_t high_end_input_voltage_range_1; unsigned int low_end_input_frequency_range; unsigned int high_end_input_frequency_range; unsigned int voltage_1; /* code for conversion into a float */ /* FIXME: check for the interest and capability to use these data */ unsigned int peak_va; unsigned int inrush_current; unsigned int inrush_interval; input_voltage_range_t low_end_input_voltage_range_2; input_voltage_range_t high_end_input_voltage_range_2; unsigned int ac_dropout_tolerance; unsigned int predictive_fail_support; unsigned int power_factor_correction; unsigned int autoswitch; unsigned int hot_swap_support; unsigned int tachometer_pulses_per_rotation_predictive_fail_polarity; unsigned int peak_capacity; unsigned int hold_up_time; unsigned int voltage_2; unsigned int total_combined_wattage; unsigned int predictive_fail_tachometer_lower_threshold; upsdebugx(1, "entering libfreeipmi_get_psu_info()"); if (ipmi_fru_multirecord_power_supply_information (fru_ctx, areabuf, area_length, &overall_capacity, &peak_va, &inrush_current, &inrush_interval, &low_end_input_voltage_range_1, &high_end_input_voltage_range_1, &low_end_input_voltage_range_2, &high_end_input_voltage_range_2, &low_end_input_frequency_range, &high_end_input_frequency_range, &ac_dropout_tolerance, &predictive_fail_support, &power_factor_correction, &autoswitch, &hot_swap_support, &tachometer_pulses_per_rotation_predictive_fail_polarity, &peak_capacity, &hold_up_time, &voltage_1, &voltage_2, &total_combined_wattage, &predictive_fail_tachometer_lower_threshold) < 0) { fatalx(EXIT_FAILURE, "ipmi_fru_multirecord_power_supply_information: %s", ipmi_fru_ctx_errormsg (fru_ctx)); } if (overall_capacity > (int)INT_MAX) { fatalx(EXIT_FAILURE, "ipmi_fru_multirecord_power_supply_information: overall_capacity exceeds expected range: %u", overall_capacity); } ipmi_dev->overall_capacity = (int)overall_capacity; /* Voltages are in mV! */ ipmi_dev->input_minvoltage = low_end_input_voltage_range_1 / 1000; ipmi_dev->input_maxvoltage = high_end_input_voltage_range_1 / 1000; if (low_end_input_frequency_range > (int)INT_MAX) { fatalx(EXIT_FAILURE, "ipmi_fru_multirecord_power_supply_information: low_end_input_frequency_range exceeds expected range: %u", low_end_input_frequency_range); } if (high_end_input_frequency_range > (int)INT_MAX) { fatalx(EXIT_FAILURE, "ipmi_fru_multirecord_power_supply_information: high_end_input_frequency_range exceeds expected range: %u", high_end_input_frequency_range); } ipmi_dev->input_minfreq = (int)low_end_input_frequency_range; ipmi_dev->input_maxfreq = (int)high_end_input_frequency_range; if (voltage_1 > (int)UINT8_MAX) { fatalx(EXIT_FAILURE, "ipmi_fru_multirecord_power_supply_information: voltage_1 code exceeds expected range: %u", voltage_1); } ipmi_dev->voltage = libfreeipmi_get_voltage((uint8_t)voltage_1); upsdebugx(1, "libfreeipmi_get_psu_info() retrieved successfully"); return (0); } /* Get specific PSU information from IPMI FRU */ static int libfreeipmi_get_board_info (const void *areabuf, uint8_t area_length, IPMIDevice_t *ipmi_dev) { uint8_t language_code; uint32_t mfg_date_time; ipmi_fru_field_t board_manufacturer; ipmi_fru_field_t board_product_name; ipmi_fru_field_t board_serial_number; ipmi_fru_field_t board_part_number; ipmi_fru_field_t board_fru_file_id; ipmi_fru_field_t board_custom_fields[IPMI_FRU_CUSTOM_FIELDS]; const char *string = NULL; time_t timetmp; struct tm mfg_date_time_tm; char mfg_date_time_buf[IPMI_FRU_STR_BUFLEN + 1]; upsdebugx(1, "entering libfreeipmi_get_board_info()"); /* clear fields */ memset (&board_manufacturer, '\0', sizeof (ipmi_fru_field_t)); memset (&board_product_name, '\0', sizeof (ipmi_fru_field_t)); memset (&board_serial_number, '\0', sizeof (ipmi_fru_field_t)); memset (&board_fru_file_id, '\0', sizeof (ipmi_fru_field_t)); memset (&board_custom_fields[0], '\0', sizeof (ipmi_fru_field_t) * IPMI_FRU_CUSTOM_FIELDS); /* parse FRU buffer */ if (ipmi_fru_board_info_area (fru_ctx, areabuf, area_length, &language_code, &mfg_date_time, &board_manufacturer, &board_product_name, &board_serial_number, &board_part_number, &board_fru_file_id, board_custom_fields, IPMI_FRU_CUSTOM_FIELDS) < 0) { libfreeipmi_cleanup(); fatalx(EXIT_FAILURE, "ipmi_fru_board_info_area: %s", ipmi_fru_ctx_errormsg (fru_ctx)); } if (IPMI_FRU_LANGUAGE_CODE_VALID (language_code)) { upsdebugx (5, "FRU Board Language: %s", ipmi_fru_language_codes[language_code]); } else { upsdebugx (5, "FRU Board Language Code: %02Xh", language_code); } /* Posix says individual calls need not clear/set all portions of * 'struct tm', thus passing 'struct tm' between functions could * have issues. So we need to memset */ memset (&mfg_date_time_tm, '\0', sizeof (struct tm)); /* Without a standard TIME_MAX, signedness may suffer; * but we can at least check the number should fit */ #ifdef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_UNREACHABLE_CODE #pragma GCC diagnostic push #endif #ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_UNREACHABLE_CODE #pragma GCC diagnostic ignored "-Wunreachable-code" #endif #ifdef __clang__ #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wunreachable-code" #endif /* Stay ahead of possible redefinitions... */ if (sizeof(mfg_date_time) > sizeof(timetmp)) { libfreeipmi_cleanup(); fatalx(EXIT_FAILURE, "libfreeipmi_get_board_info: mfg_date_time type too large to process into a time_t"); } /* NOTE: Code until the end of method would also be "unreachable" * for compilers or static analyzers that care about this, if the * sizeof() check above fails on some architecture; build warnings * should expose that so we look for a fix - so do not just blindly * move the closing pragmas to end of method ;) */ #ifdef __clang__ #pragma clang diagnostic pop #endif #ifdef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_UNREACHABLE_CODE #pragma GCC diagnostic pop #endif timetmp = (time_t)mfg_date_time; localtime_r (&timetmp, &mfg_date_time_tm); memset (mfg_date_time_buf, '\0', IPMI_FRU_STR_BUFLEN + 1); strftime (mfg_date_time_buf, IPMI_FRU_STR_BUFLEN, "%D - %T", &mfg_date_time_tm); /* Store values */ ipmi_dev->date = xstrdup(mfg_date_time_buf); upsdebugx(2, "FRU Board Manufacturing Date/Time: %s", ipmi_dev->date); if ((string = libfreeipmi_getfield (language_code, &board_manufacturer)) != NULL) ipmi_dev->manufacturer = xstrdup(string); else ipmi_dev->manufacturer = xstrdup("Generic IPMI manufacturer"); if ((string = libfreeipmi_getfield (language_code, &board_product_name)) != NULL) ipmi_dev->product = xstrdup(string); else ipmi_dev->product = xstrdup("Generic PSU"); if ((string = libfreeipmi_getfield (language_code, &board_serial_number)) != NULL) ipmi_dev->serial = xstrdup(string); else ipmi_dev->serial = NULL; if ((string = libfreeipmi_getfield (language_code, &board_part_number)) != NULL) ipmi_dev->part = xstrdup(string); else ipmi_dev->part = NULL; return (0); } /* Get the sensors list & values, specific to the given FRU ID * Return -1 on error, or the number of sensors found otherwise */ static int libfreeipmi_get_sensors_info (IPMIDevice_t *ipmi_dev) { uint8_t sdr_record[IPMI_SDR_MAX_RECORD_LENGTH]; uint8_t record_type, logical_physical_fru_device, logical_fru_device_device_slave_address; uint8_t tmp_entity_id, tmp_entity_instance; int sdr_record_len; uint16_t record_count; int found_device_id = 0; uint16_t record_id; uint8_t entity_id = 0, entity_instance = 0; int i; if (ipmi_ctx == NULL) return (-1); /* Clear the sensors list */ ipmi_dev->sensors_count = 0; memset(ipmi_dev->sensors_id_list, 0, sizeof(ipmi_dev->sensors_id_list)); if (!(sdr_ctx = ipmi_sdr_ctx_create ())) { libfreeipmi_cleanup(); fatal_with_errno(EXIT_FAILURE, "ipmi_sdr_ctx_create()"); } #ifndef HAVE_FREEIPMI_11X_12X if (!(sdr_parse_ctx = ipmi_sdr_parse_ctx_create ())) { libfreeipmi_cleanup(); fatal_with_errno(EXIT_FAILURE, "ipmi_sdr_parse_ctx_create()"); } #endif if (ipmi_sdr_cache_open (sdr_ctx, ipmi_ctx, CACHE_LOCATION) < 0) { if (ipmi_sdr_ctx_errnum (sdr_ctx) != IPMI_SDR_ERR_CACHE_READ_CACHE_DOES_NOT_EXIST) { libfreeipmi_cleanup(); fatal_with_errno(EXIT_FAILURE, "ipmi_sdr_cache_open: %s", ipmi_sdr_ctx_errormsg (sdr_ctx)); } } if (ipmi_sdr_ctx_errnum (sdr_ctx) == IPMI_SDR_ERR_CACHE_READ_CACHE_DOES_NOT_EXIST) { if (ipmi_sdr_cache_create (sdr_ctx, ipmi_ctx, CACHE_LOCATION, NUT_IPMI_SDR_CACHE_DEFAULTS, NULL, NULL) < 0) { libfreeipmi_cleanup(); fatal_with_errno(EXIT_FAILURE, "ipmi_sdr_cache_create: %s", ipmi_sdr_ctx_errormsg (sdr_ctx)); } if (ipmi_sdr_cache_open (sdr_ctx, ipmi_ctx, CACHE_LOCATION) < 0) { if (ipmi_sdr_ctx_errnum (sdr_ctx) != IPMI_SDR_ERR_CACHE_READ_CACHE_DOES_NOT_EXIST) { libfreeipmi_cleanup(); fatal_with_errno(EXIT_FAILURE, "ipmi_sdr_cache_open: %s", ipmi_sdr_ctx_errormsg (sdr_ctx)); } } } if (ipmi_sdr_cache_record_count (sdr_ctx, &record_count) < 0) { fprintf (stderr, "ipmi_sdr_cache_record_count: %s\n", ipmi_sdr_ctx_errormsg (sdr_ctx)); goto cleanup; } upsdebugx(3, "Found %i records in SDR cache", record_count); for (i = 0; i < record_count; i++, ipmi_sdr_cache_next (sdr_ctx)) { memset (sdr_record, '\0', IPMI_SDR_MAX_RECORD_LENGTH); if ((sdr_record_len = ipmi_sdr_cache_record_read (sdr_ctx, sdr_record, IPMI_SDR_MAX_RECORD_LENGTH)) < 0) { fprintf (stderr, "ipmi_sdr_cache_record_read: %s\n", ipmi_sdr_ctx_errormsg (sdr_ctx)); goto cleanup; } if (ipmi_sdr_parse_record_id_and_type (SDR_PARSE_CTX, sdr_record, (unsigned int)sdr_record_len, NULL, &record_type) < 0) { fprintf (stderr, "ipmi_sdr_parse_record_id_and_type: %s\n", ipmi_sdr_ctx_errormsg (sdr_ctx)); goto cleanup; } upsdebugx (5, "Checking record %i (/%i)", i, record_count); if (record_type != IPMI_SDR_FORMAT_FRU_DEVICE_LOCATOR_RECORD) { upsdebugx(1, "=======> not device locator (%i)!!", record_type); continue; } if (ipmi_sdr_parse_fru_device_locator_parameters (SDR_PARSE_CTX, sdr_record, (unsigned int)sdr_record_len, NULL, &logical_fru_device_device_slave_address, NULL, NULL, &logical_physical_fru_device, NULL) < 0) { fprintf (stderr, "ipmi_sdr_parse_fru_device_locator_parameters: %s\n", ipmi_sdr_ctx_errormsg (sdr_ctx)); goto cleanup; } upsdebugx(2, "Checking device %i/%i", logical_physical_fru_device, logical_fru_device_device_slave_address); if (logical_physical_fru_device && logical_fru_device_device_slave_address == ipmi_dev->ipmi_id) { found_device_id++; if (ipmi_sdr_parse_fru_entity_id_and_instance (SDR_PARSE_CTX, sdr_record, (unsigned int)sdr_record_len, &entity_id, &entity_instance) < 0) { fprintf (stderr, "ipmi_sdr_parse_fru_entity_id_and_instance: %s\n", ipmi_sdr_ctx_errormsg (sdr_ctx)); goto cleanup; } break; } } if (!found_device_id) { fprintf (stderr, "Couldn't find device id %d\n", ipmi_dev->ipmi_id); goto cleanup; } else upsdebugx(1, "Found device id %d", ipmi_dev->ipmi_id); if (ipmi_sdr_cache_first (sdr_ctx) < 0) { fprintf (stderr, "ipmi_sdr_cache_first: %s\n", ipmi_sdr_ctx_errormsg (sdr_ctx)); goto cleanup; } for (i = 0; i < record_count; i++, ipmi_sdr_cache_next (sdr_ctx)) { /* uint8_t sdr_record[IPMI_SDR_CACHE_MAX_SDR_RECORD_LENGTH]; uint8_t record_type, tmp_entity_id, tmp_entity_instance; int sdr_record_len; */ memset (sdr_record, '\0', IPMI_SDR_MAX_RECORD_LENGTH); if ((sdr_record_len = ipmi_sdr_cache_record_read (sdr_ctx, sdr_record, IPMI_SDR_MAX_RECORD_LENGTH)) < 0) { fprintf (stderr, "ipmi_sdr_cache_record_read: %s\n", ipmi_sdr_ctx_errormsg (sdr_ctx)); goto cleanup; } if (ipmi_sdr_parse_record_id_and_type (SDR_PARSE_CTX, sdr_record, (unsigned int)sdr_record_len, &record_id, &record_type) < 0) { fprintf (stderr, "ipmi_sdr_parse_record_id_and_type: %s\n", ipmi_sdr_ctx_errormsg (sdr_ctx)); goto cleanup; } upsdebugx (5, "Checking record %i (/%i)", record_id, record_count); if (record_type != IPMI_SDR_FORMAT_FULL_SENSOR_RECORD && record_type != IPMI_SDR_FORMAT_COMPACT_SENSOR_RECORD && record_type != IPMI_SDR_FORMAT_EVENT_ONLY_RECORD) { continue; } if (ipmi_sdr_parse_entity_id_instance_type (SDR_PARSE_CTX, sdr_record, (unsigned int)sdr_record_len, &tmp_entity_id, &tmp_entity_instance, NULL) < 0) { fprintf (stderr, "ipmi_sdr_parse_entity_instance_type: %s\n", ipmi_sdr_ctx_errormsg (sdr_ctx)); goto cleanup; } if (tmp_entity_id == entity_id && tmp_entity_instance == entity_instance) { upsdebugx (1, "Found record id = %u for device id %u", record_id, ipmi_dev->ipmi_id); /* Add it to the tracked list */ ipmi_dev->sensors_id_list[ipmi_dev->sensors_count] = record_id; ipmi_dev->sensors_count++; } } cleanup: /* Cleanup */ if (sdr_ctx) { ipmi_sdr_ctx_destroy (sdr_ctx); } #ifndef HAVE_FREEIPMI_11X_12X if (sdr_parse_ctx) { ipmi_sdr_parse_ctx_destroy (sdr_parse_ctx); } #endif /* HAVE_FREEIPMI_11X_12X */ if (ipmi_dev->sensors_count > INT_MAX) { upsdebugx(1, "%s: Found %i sensors which is too many", __func__, ipmi_dev->sensors_count); } return (int)ipmi_dev->sensors_count; } /* => Nominal conditions Record ID, Sensor Name, Sensor Number, Sensor Type, Sensor State, Sensor Reading, Sensor Units, Sensor Event/Reading Type Code, Sensor Event Bitmask, Sensor Event String 52, Presence, 84, Entity Presence, Nominal, N/A, N/A, 6Fh, 1h, 'Entity Present' 57, Status, 100, Power Supply, Nominal, N/A, N/A, 6Fh, 1h, 'Presence detected' 116, Current, 148, Current, Nominal, 0.20, A, 1h, C0h, 'OK' 118, Voltage, 150, Voltage, Nominal, 236.00, V, 1h, C0h, 'OK' => Power failure conditions Record ID, Sensor Name, Sensor Number, Sensor Type, Sensor State, Sensor Reading, Sensor Units, Sensor Event/Reading Type Code, Sensor Event Bitmask, Sensor Event String 52, Presence, 84, Entity Presence, Nominal, N/A, N/A, 6Fh, 1h, 'Entity Present' 57, Status, 100, Power Supply, Critical, N/A, N/A, 6Fh, 9h, 'Presence detected' 'Power Supply input lost (AC/DC)' => PSU removed Record ID, Sensor Name, Sensor Number, Sensor Type, Sensor State, Sensor Reading, Sensor Units, Sensor Event/Reading Type Code, Sensor Event Bitmask, Sensor Event String 52, Presence, 84, Entity Presence, Critical, N/A, N/A, 6Fh, 2h, 'Entity Absent' 57, Status, 100, Power Supply, Critical, N/A, N/A, 6Fh, 8h, 'Power Supply input lost (AC/DC)' */ int nut_ipmi_monitoring_init(void) { int errnum; if (ipmi_monitoring_init (0, &errnum) < 0) { upsdebugx (1, "ipmi_monitoring_init() error: %s", ipmi_monitoring_ctx_strerror (errnum)); return -1; } if (!(mon_ctx = ipmi_monitoring_ctx_create ())) { upsdebugx (1, "ipmi_monitoring_ctx_create() failed"); return -1; } #if HAVE_FREEIPMI_MONITORING /* FIXME: replace "/tmp" by a proper place, using mkdtemp() or similar */ if (ipmi_monitoring_ctx_sdr_cache_directory (mon_ctx, "/tmp") < 0) { upsdebugx (1, "ipmi_monitoring_ctx_sdr_cache_directory() error: %s", ipmi_monitoring_ctx_errormsg (mon_ctx)); return -1; } if (ipmi_monitoring_ctx_sensor_config_file (mon_ctx, NULL) < 0) { upsdebugx (1, "ipmi_monitoring_ctx_sensor_config_file() error: %s", ipmi_monitoring_ctx_errormsg (mon_ctx)); return -1; } #endif /* HAVE_FREEIPMI_MONITORING */ return 0; } int nut_ipmi_get_sensors_status(IPMIDevice_t *ipmi_dev) { int retval = -1; #if HAVE_FREEIPMI_MONITORING /* It seems we don't need more! */ unsigned int sensor_reading_flags = IPMI_MONITORING_SENSOR_READING_FLAGS_IGNORE_NON_INTERPRETABLE_SENSORS; int sensor_count, i, str_count; int psu_status = PSU_STATUS_UNKNOWN; if (mon_ctx == NULL) { upsdebugx (1, "Monitoring context not initialized!"); return -1; } /* Monitor only the list of sensors found previously */ if ((sensor_count = ipmi_monitoring_sensor_readings_by_record_id (mon_ctx, NULL, /* hostname is NULL for In-band communication */ NULL, /* FIXME: needed? ipmi_config */ sensor_reading_flags, ipmi_dev->sensors_id_list, ipmi_dev->sensors_count, NULL, NULL)) < 0) { upsdebugx (1, "ipmi_monitoring_sensor_readings_by_record_id() error: %s", ipmi_monitoring_ctx_errormsg (mon_ctx)); return -1; } upsdebugx (1, "nut_ipmi_get_sensors_status: %i sensors to check", sensor_count); for (i = 0; i < sensor_count; i++, ipmi_monitoring_sensor_iterator_next (mon_ctx)) { int record_id, sensor_type; int sensor_bitmask_type = -1; /* int sensor_reading_type, sensor_state; */ char **sensor_bitmask_strings = NULL; void *sensor_reading = NULL; if ((record_id = ipmi_monitoring_sensor_read_record_id (mon_ctx)) < 0) { upsdebugx (1, "ipmi_monitoring_sensor_read_record_id() error: %s", ipmi_monitoring_ctx_errormsg (mon_ctx)); continue; } if ((sensor_type = ipmi_monitoring_sensor_read_sensor_type (mon_ctx)) < 0) { upsdebugx (1, "ipmi_monitoring_sensor_read_sensor_type() error: %s", ipmi_monitoring_ctx_errormsg (mon_ctx)); continue; } upsdebugx (1, "checking sensor #%i, type %i", record_id, sensor_type); /* should we consider this for ALARM? * IPMI_MONITORING_STATE_NOMINAL * IPMI_MONITORING_STATE_WARNING * IPMI_MONITORING_STATE_CRITICAL * if ((sensor_state = ipmi_monitoring_sensor_read_sensor_state (mon_ctx)) < 0) * ... */ if ((sensor_reading = ipmi_monitoring_sensor_read_sensor_reading (mon_ctx)) == NULL) { upsdebugx (1, "ipmi_monitoring_sensor_read_sensor_reading() error: %s", ipmi_monitoring_ctx_errormsg (mon_ctx)); } /* This can be needed to interpret sensor_reading format! if ((sensor_reading_type = ipmi_monitoring_sensor_read_sensor_reading_type (ctx)) < 0) { upsdebugx (1, "ipmi_monitoring_sensor_read_sensor_reading_type() error: %s", ipmi_monitoring_ctx_errormsg (mon_ctx)); } */ if ((sensor_bitmask_type = ipmi_monitoring_sensor_read_sensor_bitmask_type (mon_ctx)) < 0) { upsdebugx (1, "ipmi_monitoring_sensor_read_sensor_bitmask_type() error: %s", ipmi_monitoring_ctx_errormsg (mon_ctx)); continue; } if ((sensor_bitmask_strings = ipmi_monitoring_sensor_read_sensor_bitmask_strings (mon_ctx)) == NULL) { upsdebugx (1, "ipmi_monitoring_sensor_read_sensor_bitmask_strings() error: %s", ipmi_monitoring_ctx_errormsg (mon_ctx)); continue; } /* Only the few possibly interesting sensors are considered */ switch (sensor_type) { case IPMI_MONITORING_SENSOR_TYPE_TEMPERATURE: ipmi_dev->temperature = *((double *)sensor_reading); upsdebugx (3, "Temperature: %.2f", *((double *)sensor_reading)); dstate_setinfo("ambient.temperature", "%.2f", *((double *)sensor_reading)); retval = 0; break; case IPMI_MONITORING_SENSOR_TYPE_VOLTAGE: ipmi_dev->voltage = *((double *)sensor_reading); upsdebugx (3, "Voltage: %.2f", *((double *)sensor_reading)); dstate_setinfo("input.voltage", "%.2f", *((double *)sensor_reading)); retval = 0; break; case IPMI_MONITORING_SENSOR_TYPE_CURRENT: ipmi_dev->input_current = *((double *)sensor_reading); upsdebugx (3, "Current: %.2f", *((double *)sensor_reading)); dstate_setinfo("input.current", "%.2f", *((double *)sensor_reading)); retval = 0; break; case IPMI_MONITORING_SENSOR_TYPE_POWER_SUPPLY: /* Possible values: * 'Presence detected' * 'Power Supply input lost (AC/DC)' => maps to status:OFF */ upsdebugx (3, "Power Supply: status string"); if (sensor_bitmask_type == IPMI_MONITORING_SENSOR_BITMASK_TYPE_UNKNOWN) { upsdebugx(3, "No status string"); } str_count = 0; while (sensor_bitmask_strings[str_count]) { upsdebugx (3, "\t'%s'", sensor_bitmask_strings[str_count]); if (!strncmp("Power Supply input lost (AC/DC)", sensor_bitmask_strings[str_count], strlen("Power Supply input lost (AC/DC)"))) { /* Don't override PSU absence! */ if (psu_status != PSU_ABSENT) { psu_status = PSU_POWER_FAILURE; /* = status OFF */ } } str_count++; } break; case IPMI_MONITORING_SENSOR_TYPE_ENTITY_PRESENCE: /* Possible values: * 'Entity Present' => maps to status:OL * 'Entity Absent' (PSU has been removed!) => declare staleness */ upsdebugx (3, "Entity Presence: status string"); if (sensor_bitmask_type == IPMI_MONITORING_SENSOR_BITMASK_TYPE_UNKNOWN) { upsdebugx(3, "No status string"); } str_count = 0; while (sensor_bitmask_strings[str_count]) { upsdebugx (3, "\t'%s'", sensor_bitmask_strings[str_count]); if (!strncmp("Entity Present", sensor_bitmask_strings[str_count], strlen("Entity Present"))) { psu_status = PSU_PRESENT; } else if (!strncmp("Entity Absent", sensor_bitmask_strings[str_count], strlen("Entity Absent"))) { psu_status = PSU_ABSENT; } str_count++; } break; /* Not sure of the values of these, so get as much as possible... */ case IPMI_MONITORING_SENSOR_TYPE_POWER_UNIT: upsdebugx (3, "Power Unit: status string"); str_count = 0; while (sensor_bitmask_strings[str_count]) { upsdebugx (3, "\t'%s'", sensor_bitmask_strings[str_count]); str_count++; } break; case IPMI_MONITORING_SENSOR_TYPE_SYSTEM_ACPI_POWER_STATE: upsdebugx (3, "System ACPI Power State: status string"); str_count = 0; while (sensor_bitmask_strings[str_count]) { upsdebugx (3, "\t'%s'", sensor_bitmask_strings[str_count]); str_count++; } break; case IPMI_MONITORING_SENSOR_TYPE_BATTERY: upsdebugx (3, "Battery: status string"); str_count = 0; while (sensor_bitmask_strings[str_count]) { upsdebugx (3, "\t'%s'", sensor_bitmask_strings[str_count]); str_count++; } break; } } /* Process status if needed */ if (psu_status != PSU_STATUS_UNKNOWN) { status_init(); switch (psu_status) { case PSU_PRESENT: status_set("OL"); retval = 0; break; case PSU_ABSENT: status_set("OFF"); /* Declare stale */ retval = -1; break; case PSU_POWER_FAILURE: status_set("OFF"); retval = 0; break; } status_commit(); } #endif /* HAVE_FREEIPMI_MONITORING */ return retval; } /* --chassis-control=CONTROL Control the chassis. This command provides power-up, power-down, and reset control. Supported values: POWER-DOWN, POWER-UP, POWER-CYCLE, HARD-RESET, DIAGNOS‐ TIC-INTERRUPT, SOFT-SHUTDOWN. */ nut-2.8.1/drivers/arduino-hid.c0000644000175000017500000001163514500336654013312 00000000000000/* arduino-hid.c - subdriver to monitor Arduino USB/HID devices with NUT * * Copyright (C) * 2003 - 2012 Arnaud Quette * 2005 - 2006 Peter Selinger * 2008 - 2009 Arjen de Korte * 2013 Charles Lepple * 2021 Alex Bratchik * * Note: this subdriver was initially generated as a "stub" by the * gen-usbhid-subdriver script. It must be customized. * * 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 2 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, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "config.h" /* must be first */ #include "usbhid-ups.h" #include "arduino-hid.h" #include "main.h" /* for getval() */ #include "usb-common.h" #define ARDUINO_HID_VERSION "Arduino HID 0.2" /* FIXME: experimental flag to be put in upsdrv_info */ /* Arduino */ #define ARDUINO_VENDORID 0x2341 #define ARDUINO_VENDORID2 0x2A03 /* USB IDs device table */ static usb_device_id_t arduino_usb_device_table[] = { /* Arduino Leonardo, Leonardo ETH and Pro Micro*/ { USB_DEVICE(ARDUINO_VENDORID, 0x0036), NULL }, { USB_DEVICE(ARDUINO_VENDORID, 0x8036), NULL }, { USB_DEVICE(ARDUINO_VENDORID2, 0x0036), NULL }, { USB_DEVICE(ARDUINO_VENDORID2, 0x8036), NULL }, { USB_DEVICE(ARDUINO_VENDORID2, 0x0040), NULL }, { USB_DEVICE(ARDUINO_VENDORID2, 0x8040), NULL }, /* Terminating entry */ { 0, 0, NULL } }; static usb_communication_subdriver_t *usb = &usb_subdriver; /* --------------------------------------------------------------- */ /* Vendor-specific usage table */ /* --------------------------------------------------------------- */ /* ARDUINO usage table */ static usage_lkp_t arduino_usage_lkp[] = { { NULL, 0 } }; static usage_tables_t arduino_utab[] = { arduino_usage_lkp, hid_usage_lkp, NULL, }; /* --------------------------------------------------------------- */ /* HID2NUT lookup table */ /* --------------------------------------------------------------- */ static hid_info_t arduino_hid2nut[] = { /* USB HID PDC defaults */ { "ups.delay.start", ST_FLAG_RW | ST_FLAG_STRING, 10, "UPS.PowerSummary.DelayBeforeStartup", NULL, DEFAULT_ONDELAY, HU_FLAG_ABSENT, NULL}, { "ups.delay.shutdown", ST_FLAG_RW | ST_FLAG_STRING, 10, "UPS.PowerSummary.DelayBeforeShutdown", NULL, DEFAULT_OFFDELAY, HU_FLAG_ABSENT, NULL}, { "ups.timer.start", 0, 0, "UPS.PowerSummary.DelayBeforeStartup", NULL, "%.0f", HU_FLAG_QUICK_POLL, NULL}, { "ups.timer.shutdown", 0, 0, "UPS.PowerSummary.DelayBeforeShutdown", NULL, "%.0f", HU_FLAG_QUICK_POLL, NULL}, { "ups.timer.reboot", 0, 0, "UPS.PowerSummary.DelayBeforeReboot", NULL, "%.0f", HU_FLAG_QUICK_POLL, NULL}, /* USB HID PDC defaults */ { "load.off.delay", 0, 0, "UPS.PowerSummary.DelayBeforeShutdown", NULL, DEFAULT_OFFDELAY, HU_TYPE_CMD, NULL }, { "load.on.delay", 0, 0, "UPS.PowerSummary.DelayBeforeStartup", NULL, DEFAULT_ONDELAY, HU_TYPE_CMD, NULL }, { "shutdown.stop", 0, 0, "UPS.PowerSummary.DelayBeforeShutdown", NULL, "-1", HU_TYPE_CMD, NULL }, { "shutdown.reboot", 0, 0, "UPS.PowerSummary.DelayBeforeReboot", NULL, "10", HU_TYPE_CMD, NULL }, /* end of structure. */ { NULL, 0, 0, NULL, NULL, NULL, 0, NULL } }; static const char *arduino_format_model(HIDDevice_t *hd) { return hd->Product; } static const char *arduino_format_mfr(HIDDevice_t *hd) { return hd->Vendor ? hd->Vendor : "Arduino"; } static const char *arduino_format_serial(HIDDevice_t *hd) { return hd->Serial; } /* this function allows the subdriver to "claim" a device: return 1 if * the device is supported by this subdriver, else 0. */ static int arduino_claim(HIDDevice_t *hd) { int status = is_usb_device_supported(arduino_usb_device_table, hd); switch (status) { case POSSIBLY_SUPPORTED: /* by default, reject, unless the productid option is given */ if (getval("productid")) { usb->hid_ep_in=4; usb->hid_ep_out=5; usb->hid_rep_index = 2; return 1; } possibly_supported("Arduino", hd); return 0; case SUPPORTED: usb->hid_ep_in=4; usb->hid_ep_out=5; usb->hid_rep_index = 2; return 1; case NOT_SUPPORTED: default: return 0; } } subdriver_t arduino_subdriver = { ARDUINO_HID_VERSION, arduino_claim, arduino_utab, arduino_hid2nut, arduino_format_model, arduino_format_mfr, arduino_format_serial, fix_report_desc, }; nut-2.8.1/drivers/nutdrv_qx_voltronic-qs-hex.h0000644000175000017500000000205314273170601016435 00000000000000/* nutdrv_qx_voltronic-qs-hex.h - Subdriver for Voltronic Power UPSes with QS-Hex protocol * * Copyright (C) * 2014 Daniele Pezzini * * 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 2 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, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #ifndef NUTDRV_QX_VOLTRONIC_QS_HEX_H #define NUTDRV_QX_VOLTRONIC_QS_HEX_H #include "nutdrv_qx.h" extern subdriver_t voltronic_qs_hex_subdriver; #endif /* NUTDRV_QX_VOLTRONIC_QS_HEX_H */ nut-2.8.1/drivers/delta_ups-mib.c0000644000175000017500000005651714501607135013640 00000000000000/* delta_ups-mib.c - subdriver to monitor delta_ups SNMP devices with NUT * * Copyright (C) * 2011 - 2012 Arnaud Quette * * Note: this subdriver was initially generated as a "stub" by the * gen-snmp-subdriver.sh script. It must be customized! * * MIB reference: https://www.networkupstools.org/ups-protocols/snmp/DeltaUPSv4.mib * * 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 2 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, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "delta_ups-mib.h" #define DELTA_UPS_MIB_VERSION "0.5" #define DELTA_UPS_SYSOID ".1.3.6.1.4.1.2254.2.4" /* To create a value lookup structure (as needed on the 2nd line of the example * below), use the following kind of declaration, outside of the present snmp_info_t[]: * static info_lkp_t delta_ups_onbatt_info[] = { * { 1, "OB", NULL, NULL }, * { 2, "OL", NULL, NULL }, * { 0, NULL, NULL, NULL } * }; */ static info_lkp_t delta_ups_upstype_info[] = { { 1, "on-line", NULL, NULL }, { 2, "off-line", NULL, NULL }, { 3, "line-interactive", NULL, NULL }, { 4, "3phase", NULL, NULL }, { 5, "splite-phase", NULL, NULL }, { 0, NULL, NULL, NULL } }; static info_lkp_t delta_ups_pwr_info[] = { { 0, "OL", NULL, NULL }, /* normal */ { 1, "OB", NULL, NULL }, /* battery */ { 2, "BYPASS", NULL, NULL }, /* bypass */ { 3, "TRIM", NULL, NULL }, /* reducing */ { 4, "BOOST", NULL, NULL }, /* boosting */ { 5, "BYPASS", NULL, NULL }, /* manualBypass */ /*{ 6, "NULL", NULL, NULL },*/ /* other */ { 7, "OFF", NULL, NULL }, /* none */ { 0, NULL, NULL, NULL } } ; /* DELTA_UPS Snmp2NUT lookup table */ static snmp_info_t delta_ups_mib[] = { /* Data format: * { info_type, info_flags, info_len, OID, dfl, flags, oid2info, setvar }, * * info_type: NUT INFO_ or CMD_ element name * info_flags: flags to set in addinfo * info_len: length of strings if STR * cmd value if CMD, multiplier otherwise * OID: SNMP OID or NULL * dfl: default value * flags: snmp-ups internal flags (FIXME: ...) * oid2info: lookup table between OID and NUT values * * Example: * { "input.voltage", 0, 0.1, ".1.3.6.1.4.1.705.1.6.2.1.2.1", "", SU_INPUT_1, NULL }, * { "ups.status", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.705.1.7.3.0", "", SU_FLAG_OK | SU_STATUS_BATT, delta_ups_onbatt_info }, * * To create a value lookup structure (as needed on the 2nd line), use the * following kind of declaration, outside of the present snmp_info_t[]: * static info_lkp_t delta_ups_onbatt_info[] = { * { 1, "OB" }, * { 2, "OL" }, * { 0, NULL } * }; */ /* standard MIB items */ { "device.description", ST_FLAG_STRING | ST_FLAG_RW, SU_INFOSIZE, ".1.3.6.1.2.1.1.1.0", NULL, SU_FLAG_OK, NULL }, { "device.contact", ST_FLAG_STRING | ST_FLAG_RW, SU_INFOSIZE, ".1.3.6.1.2.1.1.4.0", NULL, SU_FLAG_OK, NULL }, { "device.location", ST_FLAG_STRING | ST_FLAG_RW, SU_INFOSIZE, ".1.3.6.1.2.1.1.6.0", NULL, SU_FLAG_OK, NULL }, /* dupsIdentManufacturer.0 = STRING: "Socomec" */ { "ups.mfr", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.2254.2.4.1.1.0", NULL, SU_FLAG_OK, NULL }, /* dupsIdentModel.0 = STRING: "NETYS RT 1/1 UPS" */ { "ups.model", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.2254.2.4.1.2.0", NULL, SU_FLAG_OK, NULL }, /* dupsIdentAgentSoftwareVersion.0 = STRING: "2.0h " */ { "ups.firmware", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.2254.2.4.1.4.0", NULL, SU_FLAG_OK, NULL }, /* dupsIdentUPSSoftwareVersion.0 = STRING: "1.1" */ { "ups.firmware.aux", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.2254.2.4.1.3.0", NULL, SU_FLAG_OK, NULL }, /* dupsType.0 = INTEGER: on-line(1) */ { "ups.type", 0, 1, ".1.3.6.1.4.1.2254.2.4.1.19.0", NULL, SU_FLAG_OK, delta_ups_upstype_info }, /* dupsOutputLoad1.0 = INTEGER: 29 */ { "ups.load", 0, 1, ".1.3.6.1.4.1.2254.2.4.5.7.0", NULL, SU_FLAG_OK, NULL }, /* dupsRatingOutputVA.0 = INTEGER: 2200 */ { "ups.power", 0, 1, ".1.3.6.1.4.1.2254.2.4.1.7.0", NULL, SU_FLAG_OK, NULL }, /* dupsRatingOutputVoltage.0 = INTEGER: 230 */ { "output.voltage.nominal", 0, 1, ".1.3.6.1.4.1.2254.2.4.1.8.0", NULL, SU_FLAG_OK, NULL }, /* dupsOutputVoltage1.0 = INTEGER: 2300 */ { "output.voltage", 0, 0.1, ".1.3.6.1.4.1.2254.2.4.5.4.0", NULL, SU_FLAG_OK, NULL }, /* dupsRatingOutputFrequency.0 = INTEGER: 50 */ { "output.frequency.nominal", 0, 1, ".1.3.6.1.4.1.2254.2.4.1.9.0", NULL, SU_FLAG_OK, NULL }, /* dupsOutputCurrent1.0 = INTEGER: 23 */ { "output.current", 0, 0.1, ".1.3.6.1.4.1.2254.2.4.5.5.0", NULL, SU_FLAG_OK, NULL }, /* dupsRatingInputVoltage.0 = INTEGER: 230 */ { "input.voltage.nominal", 0, 1, ".1.3.6.1.4.1.2254.2.4.1.10.0", NULL, SU_FLAG_OK, NULL }, /* dupsInputVoltage1.0 = INTEGER: 2280 */ { "input.voltage", 0, 0.1, ".1.3.6.1.4.1.2254.2.4.4.3.0", NULL, SU_FLAG_OK, NULL }, /* dupsRatingInputFrequency.0 = INTEGER: 50 */ { "input.frequency.nominal", 0, 1, ".1.3.6.1.4.1.2254.2.4.1.11.0", NULL, SU_FLAG_OK, NULL }, /* dupsInputFrequency1.0 = INTEGER: 499 */ { "input.frequency", 0, 0.1, ".1.3.6.1.4.1.2254.2.4.4.2.0", NULL, SU_FLAG_OK, NULL }, /* dupsOutputSource.0 = INTEGER: normal(0) */ { "ups.status", 0, 1, ".1.3.6.1.4.1.2254.2.4.5.1.0", NULL, SU_FLAG_OK, delta_ups_pwr_info }, /* Remaining unmapped variables. * Mostly the first field (string) is to be changed * Check docs/nut-names.txt for the right variable names */ #if WITH_UNMAPPED_DATA_POINTS /* dupsIdentName.0 = "" */ { "unmapped.dupsIdentName", 0, 1, ".1.3.6.1.4.1.2254.2.4.1.5.0", NULL, SU_FLAG_OK, NULL }, /* dupsAttachedDevices.0 = "" */ { "unmapped.dupsAttachedDevices", 0, 1, ".1.3.6.1.4.1.2254.2.4.1.6.0", NULL, SU_FLAG_OK, NULL }, /* dupsRatingBatteryVoltage.0 = INTEGER: 0 */ { "unmapped.dupsRatingBatteryVoltage", 0, 1, ".1.3.6.1.4.1.2254.2.4.1.12.0", NULL, SU_FLAG_OK, NULL }, /* dupsLowTransferVoltUpBound.0 = INTEGER: 0 Volt */ { "unmapped.dupsLowTransferVoltUpBound", 0, 1, ".1.3.6.1.4.1.2254.2.4.1.13.0", NULL, SU_FLAG_OK, NULL }, /* dupsLowTransferVoltLowBound.0 = INTEGER: 0 Volt */ { "unmapped.dupsLowTransferVoltLowBound", 0, 1, ".1.3.6.1.4.1.2254.2.4.1.14.0", NULL, SU_FLAG_OK, NULL }, /* dupsHighTransferVoltUpBound.0 = INTEGER: 0 Volt */ { "unmapped.dupsHighTransferVoltUpBound", 0, 1, ".1.3.6.1.4.1.2254.2.4.1.15.0", NULL, SU_FLAG_OK, NULL }, /* dupsHighTransferVoltLowBound.0 = INTEGER: 0 Volt */ { "unmapped.dupsHighTransferVoltLowBound", 0, 1, ".1.3.6.1.4.1.2254.2.4.1.16.0", NULL, SU_FLAG_OK, NULL }, /* dupsLowBattTime.0 = Wrong Type (should be INTEGER): NULL */ { "unmapped.dupsLowBattTime", 0, 1, ".1.3.6.1.4.1.2254.2.4.1.17.0", NULL, SU_FLAG_OK, NULL }, /* dupsOutletRelays.0 = INTEGER: 2 */ { "unmapped.dupsOutletRelays", 0, 1, ".1.3.6.1.4.1.2254.2.4.1.18.0", NULL, SU_FLAG_OK, NULL }, /* dupsShutdownType.0 = Wrong Type (should be INTEGER): NULL */ { "unmapped.dupsShutdownType", 0, 1, ".1.3.6.1.4.1.2254.2.4.2.1.0", NULL, SU_FLAG_OK, NULL }, /* dupsAutoReboot.0 = Wrong Type (should be INTEGER): NULL */ { "unmapped.dupsAutoReboot", 0, 1, ".1.3.6.1.4.1.2254.2.4.2.2.0", NULL, SU_FLAG_OK, NULL }, /* dupsShutdownAction.0 = INTEGER: 0 */ { "unmapped.dupsShutdownAction", 0, 1, ".1.3.6.1.4.1.2254.2.4.2.3.0", NULL, SU_FLAG_OK, NULL }, /* dupsRestartAction.0 = INTEGER: 0 */ { "unmapped.dupsRestartAction", 0, 1, ".1.3.6.1.4.1.2254.2.4.2.4.0", NULL, SU_FLAG_OK, NULL }, /* dupsSetOutletRelay.0 = INTEGER: 1 */ { "unmapped.dupsSetOutletRelay", 0, 1, ".1.3.6.1.4.1.2254.2.4.2.5.0", NULL, SU_FLAG_OK, NULL }, /* dupsRelayOffDelay.0 = INTEGER: 0 */ { "unmapped.dupsRelayOffDelay", 0, 1, ".1.3.6.1.4.1.2254.2.4.2.6.0", NULL, SU_FLAG_OK, NULL }, /* dupsRelayOnDelay.0 = INTEGER: 0 */ { "unmapped.dupsRelayOnDelay", 0, 1, ".1.3.6.1.4.1.2254.2.4.2.7.0", NULL, SU_FLAG_OK, NULL }, /* dupsConfigBuzzerAlarm.0 = INTEGER: alarm(1) */ { "unmapped.dupsConfigBuzzerAlarm", 0, 1, ".1.3.6.1.4.1.2254.2.4.3.1.0", NULL, SU_FLAG_OK, NULL }, /* dupsConfigBuzzerState.0 = INTEGER: disable(2) */ { "unmapped.dupsConfigBuzzerState", 0, 1, ".1.3.6.1.4.1.2254.2.4.3.2.0", NULL, SU_FLAG_OK, NULL }, /* dupsConfigSensitivity.0 = Wrong Type (should be INTEGER): NULL */ { "unmapped.dupsConfigSensitivity", 0, 1, ".1.3.6.1.4.1.2254.2.4.3.3.0", NULL, SU_FLAG_OK, NULL }, /* dupsConfigLowVoltageTransferPoint.0 = Wrong Type (should be INTEGER): NULL */ { "unmapped.dupsConfigLowVoltageTransferPoint", 0, 1, ".1.3.6.1.4.1.2254.2.4.3.4.0", NULL, SU_FLAG_OK, NULL }, /* dupsConfigHighVoltageTransferPoint.0 = Wrong Type (should be INTEGER): NULL */ { "unmapped.dupsConfigHighVoltageTransferPoint", 0, 1, ".1.3.6.1.4.1.2254.2.4.3.5.0", NULL, SU_FLAG_OK, NULL }, /* dupsConfigShutdownOSDelay.0 = Wrong Type (should be INTEGER): NULL */ { "unmapped.dupsConfigShutdownOSDelay", 0, 1, ".1.3.6.1.4.1.2254.2.4.3.6.0", NULL, SU_FLAG_OK, NULL }, /* dupsConfigUPSBootDelay.0 = Wrong Type (should be INTEGER): NULL */ { "unmapped.dupsConfigUPSBootDelay", 0, 1, ".1.3.6.1.4.1.2254.2.4.3.7.0", NULL, SU_FLAG_OK, NULL }, /* dupsConfigExternalBatteryPack.0 = INTEGER: 0 */ { "unmapped.dupsConfigExternalBatteryPack", 0, 1, ".1.3.6.1.4.1.2254.2.4.3.8.0", NULL, SU_FLAG_OK, NULL }, /* dupsInputNumLines.0 = INTEGER: 1 */ { "unmapped.dupsInputNumLines", 0, 1, ".1.3.6.1.4.1.2254.2.4.4.1.0", NULL, SU_FLAG_OK, NULL }, /* dupsInputCurrent1.0 = Wrong Type (should be INTEGER): NULL */ { "unmapped.dupsInputCurrent1", 0, 1, ".1.3.6.1.4.1.2254.2.4.4.4.0", NULL, SU_FLAG_OK, NULL }, /* dupsInputFrequency2.0 = Wrong Type (should be INTEGER): NULL */ { "unmapped.dupsInputFrequency2", 0, 1, ".1.3.6.1.4.1.2254.2.4.4.5.0", NULL, SU_FLAG_OK, NULL }, /* dupsInputVoltage2.0 = Wrong Type (should be INTEGER): NULL */ { "unmapped.dupsInputVoltage2", 0, 1, ".1.3.6.1.4.1.2254.2.4.4.6.0", NULL, SU_FLAG_OK, NULL }, /* dupsInputCurrent2.0 = Wrong Type (should be INTEGER): NULL */ { "unmapped.dupsInputCurrent2", 0, 1, ".1.3.6.1.4.1.2254.2.4.4.7.0", NULL, SU_FLAG_OK, NULL }, /* dupsInputFrequency3.0 = Wrong Type (should be INTEGER): NULL */ { "unmapped.dupsInputFrequency3", 0, 1, ".1.3.6.1.4.1.2254.2.4.4.8.0", NULL, SU_FLAG_OK, NULL }, /* dupsInputVoltage3.0 = Wrong Type (should be INTEGER): NULL */ { "unmapped.dupsInputVoltage3", 0, 1, ".1.3.6.1.4.1.2254.2.4.4.9.0", NULL, SU_FLAG_OK, NULL }, /* dupsInputCurrent3.0 = Wrong Type (should be INTEGER): NULL */ { "unmapped.dupsInputCurrent3", 0, 1, ".1.3.6.1.4.1.2254.2.4.4.10.0", NULL, SU_FLAG_OK, NULL }, /* dupsOutputFrequency.0 = INTEGER: 499 0.1 Hertz */ { "unmapped.dupsOutputFrequency", 0, 1, ".1.3.6.1.4.1.2254.2.4.5.2.0", NULL, SU_FLAG_OK, NULL }, /* dupsOutputNumLines.0 = INTEGER: 1 */ { "unmapped.dupsOutputNumLines", 0, 1, ".1.3.6.1.4.1.2254.2.4.5.3.0", NULL, SU_FLAG_OK, NULL }, /* dupsOutputPower1.0 = Wrong Type (should be INTEGER): NULL */ { "unmapped.dupsOutputPower1", 0, 1, ".1.3.6.1.4.1.2254.2.4.5.6.0", NULL, SU_FLAG_OK, NULL }, /* dupsOutputVoltage2.0 = Wrong Type (should be INTEGER): NULL */ { "unmapped.dupsOutputVoltage2", 0, 1, ".1.3.6.1.4.1.2254.2.4.5.8.0", NULL, SU_FLAG_OK, NULL }, /* dupsOutputCurrent2.0 = Wrong Type (should be INTEGER): NULL */ { "unmapped.dupsOutputCurrent2", 0, 1, ".1.3.6.1.4.1.2254.2.4.5.9.0", NULL, SU_FLAG_OK, NULL }, /* dupsOutputPower2.0 = Wrong Type (should be INTEGER): NULL */ { "unmapped.dupsOutputPower2", 0, 1, ".1.3.6.1.4.1.2254.2.4.5.10.0", NULL, SU_FLAG_OK, NULL }, /* dupsOutputLoad2.0 = Wrong Type (should be INTEGER): NULL */ { "unmapped.dupsOutputLoad2", 0, 1, ".1.3.6.1.4.1.2254.2.4.5.11.0", NULL, SU_FLAG_OK, NULL }, /* dupsOutputVoltage3.0 = Wrong Type (should be INTEGER): NULL */ { "unmapped.dupsOutputVoltage3", 0, 1, ".1.3.6.1.4.1.2254.2.4.5.12.0", NULL, SU_FLAG_OK, NULL }, /* dupsOutputCurrent3.0 = Wrong Type (should be INTEGER): NULL */ { "unmapped.dupsOutputCurrent3", 0, 1, ".1.3.6.1.4.1.2254.2.4.5.13.0", NULL, SU_FLAG_OK, NULL }, /* dupsOutputPower3.0 = Wrong Type (should be INTEGER): NULL */ { "unmapped.dupsOutputPower3", 0, 1, ".1.3.6.1.4.1.2254.2.4.5.14.0", NULL, SU_FLAG_OK, NULL }, /* dupsOutputLoad3.0 = Wrong Type (should be INTEGER): NULL */ { "unmapped.dupsOutputLoad3", 0, 1, ".1.3.6.1.4.1.2254.2.4.5.15.0", NULL, SU_FLAG_OK, NULL }, /* dupsBypassFrequency.0 = INTEGER: 499 0.1 Hertz */ { "unmapped.dupsBypassFrequency", 0, 1, ".1.3.6.1.4.1.2254.2.4.6.1.0", NULL, SU_FLAG_OK, NULL }, /* dupsBypassNumLines.0 = INTEGER: 1 */ { "unmapped.dupsBypassNumLines", 0, 1, ".1.3.6.1.4.1.2254.2.4.6.2.0", NULL, SU_FLAG_OK, NULL }, /* dupsBypassVoltage1.0 = INTEGER: 2280 */ { "unmapped.dupsBypassVoltage1", 0, 1, ".1.3.6.1.4.1.2254.2.4.6.3.0", NULL, SU_FLAG_OK, NULL }, /* dupsBypassCurrent1.0 = Wrong Type (should be INTEGER): NULL */ { "unmapped.dupsBypassCurrent1", 0, 1, ".1.3.6.1.4.1.2254.2.4.6.4.0", NULL, SU_FLAG_OK, NULL }, /* dupsBypassPower1.0 = Wrong Type (should be INTEGER): NULL */ { "unmapped.dupsBypassPower1", 0, 1, ".1.3.6.1.4.1.2254.2.4.6.5.0", NULL, SU_FLAG_OK, NULL }, /* dupsBypassVoltage2.0 = Wrong Type (should be INTEGER): NULL */ { "unmapped.dupsBypassVoltage2", 0, 1, ".1.3.6.1.4.1.2254.2.4.6.6.0", NULL, SU_FLAG_OK, NULL }, /* dupsBypassCurrent2.0 = Wrong Type (should be INTEGER): NULL */ { "unmapped.dupsBypassCurrent2", 0, 1, ".1.3.6.1.4.1.2254.2.4.6.7.0", NULL, SU_FLAG_OK, NULL }, /* dupsBypassPower2.0 = Wrong Type (should be INTEGER): NULL */ { "unmapped.dupsBypassPower2", 0, 1, ".1.3.6.1.4.1.2254.2.4.6.8.0", NULL, SU_FLAG_OK, NULL }, /* dupsBypassVoltage3.0 = Wrong Type (should be INTEGER): NULL */ { "unmapped.dupsBypassVoltage3", 0, 1, ".1.3.6.1.4.1.2254.2.4.6.9.0", NULL, SU_FLAG_OK, NULL }, /* dupsBypassCurrent3.0 = Wrong Type (should be INTEGER): NULL */ { "unmapped.dupsBypassCurrent3", 0, 1, ".1.3.6.1.4.1.2254.2.4.6.10.0", NULL, SU_FLAG_OK, NULL }, /* dupsBypassPower3.0 = Wrong Type (should be INTEGER): NULL */ { "unmapped.dupsBypassPower3", 0, 1, ".1.3.6.1.4.1.2254.2.4.6.11.0", NULL, SU_FLAG_OK, NULL }, /* dupsBypass.12.0 = NULL */ { "unmapped.dupsBypass", 0, 1, ".1.3.6.1.4.1.2254.2.4.6.12.0", NULL, SU_FLAG_OK, NULL }, /* dupsBypass.13.0 = NULL */ { "unmapped.dupsBypass", 0, 1, ".1.3.6.1.4.1.2254.2.4.6.13.0", NULL, SU_FLAG_OK, NULL }, /* dupsBypass.14.0 = NULL */ { "unmapped.dupsBypass", 0, 1, ".1.3.6.1.4.1.2254.2.4.6.14.0", NULL, SU_FLAG_OK, NULL }, /* dupsBatteryCondiction.0 = INTEGER: good(0) */ { "unmapped.dupsBatteryCondiction", 0, 1, ".1.3.6.1.4.1.2254.2.4.7.1.0", NULL, SU_FLAG_OK, NULL }, /* dupsBatteryStatus.0 = INTEGER: ok(0) */ { "unmapped.dupsBatteryStatus", 0, 1, ".1.3.6.1.4.1.2254.2.4.7.2.0", NULL, SU_FLAG_OK, NULL }, /* dupsBatteryCharge.0 = INTEGER: charging(1) */ { "unmapped.dupsBatteryCharge", 0, 1, ".1.3.6.1.4.1.2254.2.4.7.3.0", NULL, SU_FLAG_OK, NULL }, /* dupsSecondsOnBattery.0 = INTEGER: 0 seconds */ { "unmapped.dupsSecondsOnBattery", 0, 1, ".1.3.6.1.4.1.2254.2.4.7.4.0", NULL, SU_FLAG_OK, NULL }, /* dupsBatteryEstimatedTime.0 = Wrong Type (should be INTEGER): NULL */ { "unmapped.dupsBatteryEstimatedTime", 0, 1, ".1.3.6.1.4.1.2254.2.4.7.5.0", NULL, SU_FLAG_OK, NULL }, /* dupsBatteryVoltage.0 = INTEGER: 550 0.1 Volt DC */ { "unmapped.dupsBatteryVoltage", 0, 1, ".1.3.6.1.4.1.2254.2.4.7.6.0", NULL, SU_FLAG_OK, NULL }, /* dupsBatteryCurrent.0 = Wrong Type (should be INTEGER): NULL */ { "unmapped.dupsBatteryCurrent", 0, 1, ".1.3.6.1.4.1.2254.2.4.7.7.0", NULL, SU_FLAG_OK, NULL }, /* dupsBatteryCapacity.0 = INTEGER: 100 percent */ { "unmapped.dupsBatteryCapacity", 0, 1, ".1.3.6.1.4.1.2254.2.4.7.8.0", NULL, SU_FLAG_OK, NULL }, /* dupsTemperature.0 = INTEGER: 32 degrees Centigrade */ { "unmapped.dupsTemperature", 0, 1, ".1.3.6.1.4.1.2254.2.4.7.9.0", NULL, SU_FLAG_OK, NULL }, /* dupsLastReplaceDate.0 = Wrong Type (should be OCTET STRING): NULL */ { "unmapped.dupsLastReplaceDate", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.2254.2.4.7.10.0", NULL, SU_FLAG_OK, NULL }, /* dupsNextReplaceDate.0 = Wrong Type (should be OCTET STRING): NULL */ { "unmapped.dupsNextReplaceDate", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.2254.2.4.7.11.0", NULL, SU_FLAG_OK, NULL }, /* dupsTestType.0 = INTEGER: abort(0) */ { "unmapped.dupsTestType", 0, 1, ".1.3.6.1.4.1.2254.2.4.8.1.0", NULL, SU_FLAG_OK, NULL }, /* dupsTestResultsSummary.0 = INTEGER: noTestsInitiated(0) */ { "unmapped.dupsTestResultsSummary", 0, 1, ".1.3.6.1.4.1.2254.2.4.8.2.0", NULL, SU_FLAG_OK, NULL }, /* dupsTestResultsDetail.0 = Wrong Type (should be OCTET STRING): NULL */ { "unmapped.dupsTestResultsDetail", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.2254.2.4.8.3.0", NULL, SU_FLAG_OK, NULL }, /* dupsAlarmDisconnect.0 = INTEGER: off(0) */ { "unmapped.dupsAlarmDisconnect", 0, 1, ".1.3.6.1.4.1.2254.2.4.9.1.0", NULL, SU_FLAG_OK, NULL }, /* dupsAlarmPowerFail.0 = INTEGER: off(0) */ { "unmapped.dupsAlarmPowerFail", 0, 1, ".1.3.6.1.4.1.2254.2.4.9.2.0", NULL, SU_FLAG_OK, NULL }, /* dupsAlarmBatteryLow.0 = INTEGER: off(0) */ { "unmapped.dupsAlarmBatteryLow", 0, 1, ".1.3.6.1.4.1.2254.2.4.9.3.0", NULL, SU_FLAG_OK, NULL }, /* dupsAlarmLoadWarning.0 = Wrong Type (should be INTEGER): NULL */ { "unmapped.dupsAlarmLoadWarning", 0, 1, ".1.3.6.1.4.1.2254.2.4.9.4.0", NULL, SU_FLAG_OK, NULL }, /* dupsAlarmLoadSeverity.0 = Wrong Type (should be INTEGER): NULL */ { "unmapped.dupsAlarmLoadSeverity", 0, 1, ".1.3.6.1.4.1.2254.2.4.9.5.0", NULL, SU_FLAG_OK, NULL }, /* dupsAlarmLoadOnBypass.0 = INTEGER: off(0) */ { "unmapped.dupsAlarmLoadOnBypass", 0, 1, ".1.3.6.1.4.1.2254.2.4.9.6.0", NULL, SU_FLAG_OK, NULL }, /* dupsAlarmUPSFault.0 = INTEGER: off(0) */ { "unmapped.dupsAlarmUPSFault", 0, 1, ".1.3.6.1.4.1.2254.2.4.9.7.0", NULL, SU_FLAG_OK, NULL }, /* dupsAlarmBatteryGroundFault.0 = Wrong Type (should be INTEGER): NULL */ { "unmapped.dupsAlarmBatteryGroundFault", 0, 1, ".1.3.6.1.4.1.2254.2.4.9.8.0", NULL, SU_FLAG_OK, NULL }, /* dupsAlarmTestInProgress.0 = INTEGER: off(0) */ { "unmapped.dupsAlarmTestInProgress", 0, 1, ".1.3.6.1.4.1.2254.2.4.9.9.0", NULL, SU_FLAG_OK, NULL }, /* dupsAlarmBatteryTestFail.0 = INTEGER: off(0) */ { "unmapped.dupsAlarmBatteryTestFail", 0, 1, ".1.3.6.1.4.1.2254.2.4.9.10.0", NULL, SU_FLAG_OK, NULL }, /* dupsAlarmFuseFailure.0 = INTEGER: off(0) */ { "unmapped.dupsAlarmFuseFailure", 0, 1, ".1.3.6.1.4.1.2254.2.4.9.11.0", NULL, SU_FLAG_OK, NULL }, /* dupsAlarmOutputOverload.0 = INTEGER: off(0) */ { "unmapped.dupsAlarmOutputOverload", 0, 1, ".1.3.6.1.4.1.2254.2.4.9.12.0", NULL, SU_FLAG_OK, NULL }, /* dupsAlarmOutputOverCurrent.0 = Wrong Type (should be INTEGER): NULL */ { "unmapped.dupsAlarmOutputOverCurrent", 0, 1, ".1.3.6.1.4.1.2254.2.4.9.13.0", NULL, SU_FLAG_OK, NULL }, /* dupsAlarmInverterAbnormal.0 = INTEGER: off(0) */ { "unmapped.dupsAlarmInverterAbnormal", 0, 1, ".1.3.6.1.4.1.2254.2.4.9.14.0", NULL, SU_FLAG_OK, NULL }, /* dupsAlarmRectifierAbnormal.0 = Wrong Type (should be INTEGER): NULL */ { "unmapped.dupsAlarmRectifierAbnormal", 0, 1, ".1.3.6.1.4.1.2254.2.4.9.15.0", NULL, SU_FLAG_OK, NULL }, /* dupsAlarmReserveAbnormal.0 = Wrong Type (should be INTEGER): NULL */ { "unmapped.dupsAlarmReserveAbnormal", 0, 1, ".1.3.6.1.4.1.2254.2.4.9.16.0", NULL, SU_FLAG_OK, NULL }, /* dupsAlarmLoadOnReserve.0 = Wrong Type (should be INTEGER): NULL */ { "unmapped.dupsAlarmLoadOnReserve", 0, 1, ".1.3.6.1.4.1.2254.2.4.9.17.0", NULL, SU_FLAG_OK, NULL }, /* dupsAlarmOverTemperature.0 = INTEGER: off(0) */ { "unmapped.dupsAlarmOverTemperature", 0, 1, ".1.3.6.1.4.1.2254.2.4.9.18.0", NULL, SU_FLAG_OK, NULL }, /* dupsAlarmOutputBad.0 = INTEGER: off(0) */ { "unmapped.dupsAlarmOutputBad", 0, 1, ".1.3.6.1.4.1.2254.2.4.9.19.0", NULL, SU_FLAG_OK, NULL }, /* dupsAlarmBypassBad.0 = INTEGER: off(0) */ { "unmapped.dupsAlarmBypassBad", 0, 1, ".1.3.6.1.4.1.2254.2.4.9.20.0", NULL, SU_FLAG_OK, NULL }, /* dupsAlarmUPSOff.0 = INTEGER: off(0) */ { "unmapped.dupsAlarmUPSOff", 0, 1, ".1.3.6.1.4.1.2254.2.4.9.21.0", NULL, SU_FLAG_OK, NULL }, /* dupsAlarmChargerFail.0 = INTEGER: off(0) */ { "unmapped.dupsAlarmChargerFail", 0, 1, ".1.3.6.1.4.1.2254.2.4.9.22.0", NULL, SU_FLAG_OK, NULL }, /* dupsAlarmFanFail.0 = INTEGER: off(0) */ { "unmapped.dupsAlarmFanFail", 0, 1, ".1.3.6.1.4.1.2254.2.4.9.23.0", NULL, SU_FLAG_OK, NULL }, /* dupsAlarmEconomicMode.0 = INTEGER: off(0) */ { "unmapped.dupsAlarmEconomicMode", 0, 1, ".1.3.6.1.4.1.2254.2.4.9.24.0", NULL, SU_FLAG_OK, NULL }, /* dupsAlarmOutputOff.0 = INTEGER: off(0) */ { "unmapped.dupsAlarmOutputOff", 0, 1, ".1.3.6.1.4.1.2254.2.4.9.25.0", NULL, SU_FLAG_OK, NULL }, /* dupsAlarmSmartShutdown.0 = INTEGER: off(0) */ { "unmapped.dupsAlarmSmartShutdown", 0, 1, ".1.3.6.1.4.1.2254.2.4.9.26.0", NULL, SU_FLAG_OK, NULL }, /* dupsAlarmEmergencyPowerOff.0 = INTEGER: off(0) */ { "unmapped.dupsAlarmEmergencyPowerOff", 0, 1, ".1.3.6.1.4.1.2254.2.4.9.27.0", NULL, SU_FLAG_OK, NULL }, /* dupsAlarmUPSShutdown.0 = INTEGER: off(0) */ { "unmapped.dupsAlarmUPSShutdown", 0, 1, ".1.3.6.1.4.1.2254.2.4.9.28.0", NULL, SU_FLAG_OK, NULL }, /* dupsEnvTemperature.0 = Wrong Type (should be INTEGER): NULL */ { "unmapped.dupsEnvTemperature", 0, 1, ".1.3.6.1.4.1.2254.2.4.10.1.0", NULL, SU_FLAG_OK, NULL }, /* dupsEnvHumidity.0 = Wrong Type (should be INTEGER): NULL */ { "unmapped.dupsEnvHumidity", 0, 1, ".1.3.6.1.4.1.2254.2.4.10.2.0", NULL, SU_FLAG_OK, NULL }, /* dupsEnvSetTemperatureLimit.0 = INTEGER: 40 degrees Centigrade */ { "unmapped.dupsEnvSetTemperatureLimit", 0, 1, ".1.3.6.1.4.1.2254.2.4.10.3.0", NULL, SU_FLAG_OK, NULL }, /* dupsEnvSetHumidityLimit.0 = INTEGER: 90 percentage */ { "unmapped.dupsEnvSetHumidityLimit", 0, 1, ".1.3.6.1.4.1.2254.2.4.10.4.0", NULL, SU_FLAG_OK, NULL }, /* dupsEnvSetEnvRelay1.0 = INTEGER: normalOpen(0) */ { "unmapped.dupsEnvSetEnvRelay1", 0, 1, ".1.3.6.1.4.1.2254.2.4.10.5.0", NULL, SU_FLAG_OK, NULL }, /* dupsEnvSetEnvRelay2.0 = INTEGER: normalOpen(0) */ { "unmapped.dupsEnvSetEnvRelay2", 0, 1, ".1.3.6.1.4.1.2254.2.4.10.6.0", NULL, SU_FLAG_OK, NULL }, /* dupsEnvSetEnvRelay3.0 = INTEGER: normalOpen(0) */ { "unmapped.dupsEnvSetEnvRelay3", 0, 1, ".1.3.6.1.4.1.2254.2.4.10.7.0", NULL, SU_FLAG_OK, NULL }, /* dupsEnvSetEnvRelay4.0 = INTEGER: normalOpen(0) */ { "unmapped.dupsEnvSetEnvRelay4", 0, 1, ".1.3.6.1.4.1.2254.2.4.10.8.0", NULL, SU_FLAG_OK, NULL }, /* dupsAlarmOverEnvTemperature.0 = INTEGER: off(0) */ { "unmapped.dupsAlarmOverEnvTemperature", 0, 1, ".1.3.6.1.4.1.2254.2.4.10.9.0", NULL, SU_FLAG_OK, NULL }, /* dupsAlarmOverEnvHumidity.0 = INTEGER: off(0) */ { "unmapped.dupsAlarmOverEnvHumidity", 0, 1, ".1.3.6.1.4.1.2254.2.4.10.10.0", NULL, SU_FLAG_OK, NULL }, /* dupsAlarmEnvRelay1.0 = INTEGER: off(0) */ { "unmapped.dupsAlarmEnvRelay1", 0, 1, ".1.3.6.1.4.1.2254.2.4.10.11.0", NULL, SU_FLAG_OK, NULL }, /* dupsAlarmEnvRelay2.0 = INTEGER: off(0) */ { "unmapped.dupsAlarmEnvRelay2", 0, 1, ".1.3.6.1.4.1.2254.2.4.10.12.0", NULL, SU_FLAG_OK, NULL }, /* dupsAlarmEnvRelay3.0 = INTEGER: off(0) */ { "unmapped.dupsAlarmEnvRelay3", 0, 1, ".1.3.6.1.4.1.2254.2.4.10.13.0", NULL, SU_FLAG_OK, NULL }, /* dupsAlarmEnvRelay4.0 = INTEGER: off(0) */ { "unmapped.dupsAlarmEnvRelay4", 0, 1, ".1.3.6.1.4.1.2254.2.4.10.14.0", NULL, SU_FLAG_OK, NULL }, #endif /* #if WITH_UNMAPPED_DATA_POINTS */ /* end of structure. */ { NULL, 0, 0, NULL, NULL, 0, NULL } }; mib2nut_info_t delta_ups = { "delta_ups", DELTA_UPS_MIB_VERSION, NULL, NULL, delta_ups_mib, DELTA_UPS_SYSOID, NULL }; nut-2.8.1/drivers/generic_gpio_common.h0000644000175000017500000000671114501607135015111 00000000000000/* generic_gpio_common.h - common NUT driver definitions for GPIO attached UPS devices * * Copyright (C) * 2023 Modris Berzonis * * 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 2 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, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #ifndef GENERIC_GPIO_COMMON_H_SEEN #define GENERIC_GPIO_COMMON_H_SEEN #include #include #include /* rules commands definition */ #define RULES_CMD_NOT -2 #define RULES_CMD_AND -3 #define RULES_CMD_OR -4 #define RULES_CMD_OBR -5 #define RULES_CMD_CBR -6 #define RULES_CMD_LAST RULES_CMD_CBR /* run option definitions */ #define ROPT_REQRES 0x00000001 /* reserve GPIO lines only during request processing */ #define ROPT_EVMODE 0x00000002 /* event driven run */ /* buffer size for chipName arrays */ #define NUT_GPIO_CHIPNAMEBUF 32 #define NUT_GPIO_SUBTYPEBUF 16 typedef struct rulesint_t { /* structure to store processed rules configuration per each state */ char stateName[12]; /* NUT state name for rules in cRules */ int archVal; /* previous state value */ int currVal; /* current state value */ int subCount; /* element count in translated rules subitem */ int cRules[]; /* translated rules subitem - rules commands followed by line number(s) */ } rulesint; typedef struct gpioups_t { void *lib_data; /* pointer to driver's gpio support library data structure */ const char *chipName; /* port or file name to reference GPIO chip */ int initial; /* initialization flag - 0 on 1st entry */ int runOptions; /* run options, not yet used */ int aInfoAvailable; /* non-zero if previous state information is available */ int chipLinesCount; /* gpio chip lines count, set after sucessful open */ int upsLinesCount; /* no of lines used in rules */ int *upsLines; /* lines numbers */ int *upsLinesStates; /* lines states */ int upsMaxLine; /* maximum line number referenced in rules */ int rulesCount; /* rules subitem count: no of NUT states defined in rules*/ struct rulesint_t **rules; } gpioups; extern struct gpioups_t *gpioupsfd; void gpio_open(struct gpioups_t *gpioupsfd); void gpio_get_lines_states(struct gpioups_t *gpioupsfd); void gpio_close(struct gpioups_t *gpioupsfd); # ifdef DRIVERS_MAIN_WITHOUT_MAIN /* Methods externalized for unit-tests, otherwise private to this module */ struct gpioups_t *generic_gpio_open(const char *chipName); void generic_gpio_close(struct gpioups_t *gpioupsfd); void get_ups_rules(struct gpioups_t *upsfd, unsigned char *rulesString); void add_rule_item(struct gpioups_t *upsfd, int newValue); int get_rule_lex(unsigned char *rulesBuff, int *startPos, int *endPos); int calc_rule_states(int upsLinesStates[], int cRules[], int subCount, int sIndex); void update_ups_states(struct gpioups_t *gpioupsfd); # endif /* DRIVERS_MAIN_WITHOUT_MAIN */ #endif /* GENERIC_GPIO_COMMON_H_SEEN */ nut-2.8.1/drivers/usb-common.h0000644000175000017500000005005714501655161013172 00000000000000/* usb-common.h - prototypes for the common useful USB functions * NOTE that it aims to consolidate use of different USB-related APIs * such as libusb-0.1 and libusb-1.0 in a way that minimizes the coding * difference for majority of NUT - so typedef'ing or converting various * data types and method signatures. * * Beside your system headers (content varies between distros) you can * find some documentation online: * - libusb-1.0: * https://github.com/libusb/libusb/blob/master/libusb/libusb.h * https://libusb.sourceforge.io/api-1.0/ * https://libusb.sourceforge.io/api-1.0/libusb_api.html * https://github.com/libusb/libusb/wiki * https://nxmnpg.lemoda.net/3/libusb (one page, easy to search) * - libusb-0.1 is nowadays hard to find, original web-site and * sourceforge project were discontinued over the past years. * A rendered copy of the libusb-0.1 Developers Guide was noted at: * http://transit.iut2.upmf-grenoble.fr/doc/libusb-dev/html/index.html * http://transit.iut2.upmf-grenoble.fr/doc/libusb-dev/html/functions.html * Original SGML for that seems to be in source tarball such as * http://deb.debian.org/debian/pool/main/libu/libusb/libusb_0.1.12.orig.tar.gz * * Related (but currently not directly used) projects include: * - libusb-win32 port based on libusb-0.1 API (bug-fix-only mode, * new projects should use libusb Windows backend): * https://sourceforge.net/p/libusb-win32/wiki/Documentation/ * - (Currently not in NUT codebase scope, but might help...) * > A compatibility layer allowing applications written for * > libusb-0.1 to work with libusb-1.0. libusb-compat-0.1 * > attempts to look, feel, smell and walk like libusb-0.1. * Mostly. Details (and known differences) documented at: * https://github.com/libusb/libusb-compat-0.1 * * Also note that at least currently this does not deal with non-libusb * APIs (important when looking for method signatures in documentation, * since e.g. Linux Kernel USB subsystem uses some of libusb-0.1 method * names, but with different set, type and order of arguments!) Copyright (C) 2008 - 2016 Arnaud Quette Copyright (C) 2021 Jim Klimov 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 2 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, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef NUT_USB_COMMON_H #define NUT_USB_COMMON_H #include "config.h" /* be sure to know all about the system config */ /* Note: usb-common.h (this file) is included by nut_libusb.h, * so not looping the includes ;) */ #include "nut_stdint.h" /* for uint16_t, UINT16_MAX, PRIsize, etc. */ #include "common.h" /* for fatalx() etc. */ #if defined HAVE_LIMITS_H # include /* PATH_MAX for usb.h, among other stuff */ #endif #if defined HAVE_SYS_PARAM_H # include #endif #include #if (!WITH_LIBUSB_1_0) && (!WITH_LIBUSB_0_1) #error "configure script error: Neither WITH_LIBUSB_1_0 nor WITH_LIBUSB_0_1 is set" #endif #if (WITH_LIBUSB_1_0) && (WITH_LIBUSB_0_1) #error "configure script error: Both WITH_LIBUSB_1_0 and WITH_LIBUSB_0_1 are set" #endif /* Select version-specific libusb header file and define a sort of * "Compatibility layer" between libusb 0.1 and 1.0 */ #if WITH_LIBUSB_1_0 # include /* Simply remap libusb functions/structures from 0.1 to 1.0 */ /* Structures */ /* #define usb_dev_handle libusb_device_handle */ typedef libusb_device_handle usb_dev_handle; /* These typedefs are also named in libshut.h, so we can consistenly * handle the "ifdef SHUT_MODE" handling in libhid.c and some drivers. * These symbolic names are used in all the headers and are expected to * match binary code of object files at (monolithic) driver build time. * * The MIN/MAX definitions here are primarily to generalize range-check * code (especially if anything is done outside the libraries). * FIXME: It may make sense to constrain the limits to lowest common * denominator that should fit all of libusb-0.1, libusb-1.0 and libshut, * so that any build of the practical (driver) code knows to not exceed * any use-case. */ typedef uint8_t usb_ctrl_requesttype; #define USB_CTRL_REQUESTTYPE_MIN 0 #define USB_CTRL_REQUESTTYPE_MAX UINT8_MAX typedef uint8_t usb_ctrl_request; #define USB_CTRL_REQUEST_MIN 0 #define USB_CTRL_REQUEST_MAX UINT8_MAX typedef unsigned char usb_ctrl_endpoint; #define USB_CTRL_ENDPOINT_MIN 0 #define USB_CTRL_ENDPOINT_MAX UCHAR_MAX typedef uint16_t usb_ctrl_msgvalue; #define USB_CTRL_MSGVALUE_MIN 0 #define USB_CTRL_MSGVALUE_MAX UINT16_MAX typedef uint16_t usb_ctrl_repindex; #define USB_CTRL_REPINDEX_MIN 0 #define USB_CTRL_REPINDEX_MAX UINT16_MAX typedef uint8_t usb_ctrl_strindex; #define USB_CTRL_STRINDEX_MIN 0 #define USB_CTRL_STRINDEX_MAX UINT8_MAX typedef uint8_t usb_ctrl_descindex; #define USB_CTRL_DESCINDEX_MIN 0 #define USB_CTRL_DESCINDEX_MAX UINT8_MAX typedef unsigned char* usb_ctrl_charbuf; typedef unsigned char usb_ctrl_char; #define USB_CTRL_CHAR_MIN 0 #define USB_CTRL_CHAR_MAX UCHAR_MAX /* Here MIN/MAX should not matter much, type mostly used for casting */ typedef uint16_t usb_ctrl_charbufsize; #define USB_CTRL_CHARBUFSIZE_MIN 0 #define USB_CTRL_CHARBUFSIZE_MAX UINT16_MAX #define PRI_NUT_USB_CTRL_CHARBUFSIZE PRIu16 typedef unsigned int usb_ctrl_timeout_msec; /* in milliseconds */ /* Note: there does not seem to be a standard type * for milliseconds, like there is an useconds_t */ #define USB_CTRL_TIMEOUTMSEC_MIN 0 #define USB_CTRL_TIMEOUTMSEC_MAX UINT_MAX /* defines */ #define USB_CLASS_PER_INTERFACE LIBUSB_CLASS_PER_INTERFACE #define USB_DT_STRING LIBUSB_DT_STRING #define USB_ENDPOINT_IN LIBUSB_ENDPOINT_IN #define USB_ENDPOINT_OUT LIBUSB_ENDPOINT_OUT #define USB_RECIP_ENDPOINT LIBUSB_RECIPIENT_ENDPOINT #define USB_RECIP_INTERFACE LIBUSB_RECIPIENT_INTERFACE #define USB_REQ_SET_DESCRIPTOR LIBUSB_REQUEST_SET_DESCRIPTOR #define USB_TYPE_CLASS LIBUSB_REQUEST_TYPE_CLASS #define USB_TYPE_VENDOR LIBUSB_REQUEST_TYPE_VENDOR /* Codebase updated to use LIBUSB_* tokens: #define ERROR_ACCESS LIBUSB_ERROR_ACCESS #define ERROR_BUSY LIBUSB_ERROR_BUSY #define ERROR_IO LIBUSB_ERROR_IO #define ERROR_NO_DEVICE LIBUSB_ERROR_NO_DEVICE #define ERROR_NOT_FOUND LIBUSB_ERROR_NOT_FOUND #define ERROR_OVERFLOW LIBUSB_ERROR_OVERFLOW #define ERROR_PIPE LIBUSB_ERROR_PIPE #define ERROR_TIMEOUT LIBUSB_ERROR_TIMEOUT #define ERROR_NO_MEM LIBUSB_ERROR_NO_MEM #define ERROR_INVALID_PARAM LIBUSB_ERROR_INVALID_PARAM #define ERROR_INTERRUPTED LIBUSB_ERROR_INTERRUPTED #define ERROR_NOT_SUPPORTED LIBUSB_ERROR_NOT_SUPPORTED #define ERROR_OTHER LIBUSB_ERROR_OTHER */ /* Functions, including range-checks to convert data types of the two APIs. * Follows an example from libusb-1.0 headers that liberally cast int args * of one method to uint16_t to call another; at least we do so with checks: */ #if (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_PUSH_POP_BESIDEFUNC) && (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_UNUSED_FUNCTION) # pragma GCC diagnostic push #endif #ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_UNUSED_FUNCTION # pragma GCC diagnostic ignored "-Wunused-function" #endif /* #define usb_control_msg libusb_control_transfer */ static inline int usb_control_msg(usb_dev_handle *dev, int requesttype, int request, int value, int index, usb_ctrl_charbuf bytes, int size, int timeout) { /* Map from libusb-0.1 API => libusb-1.0 API: int LIBUSB_CALL libusb_control_transfer( libusb_device_handle *dev_handle, uint8_t request_type, uint8_t bRequest, uint16_t wValue, uint16_t wIndex, unsigned char *data, uint16_t wLength, unsigned int timeout); Note: In libusb-0.1 bytes was a (char*) but our consumer code was already fixed to use "usb_ctrl_charbuf" to match other methods. */ if (requesttype < 0 || (uintmax_t)requesttype > UINT8_MAX || request < 0 || (uintmax_t)request > UINT8_MAX || value < 0 || (uintmax_t)value > UINT16_MAX || index < 0 || (uintmax_t)index > UINT16_MAX || size < 0 || (uintmax_t)size > UINT16_MAX || timeout < 0 ) { fatalx(EXIT_FAILURE, "usb_control_msg() args out of range for libusb_control_transfer() implementation"); } return libusb_control_transfer( dev, (uint8_t)requesttype, (uint8_t)request, (uint16_t)value, (uint16_t)index, (unsigned char *)bytes, (uint16_t)size, (unsigned int) timeout ); } static inline int usb_interrupt_read(usb_dev_handle *dev, int ep, usb_ctrl_charbuf bytes, int size, int timeout) { /* NOTE: Also for routines below: Map from libusb-0.1 API => libusb-1.0 API plus change of logic per below code: int LIBUSB_CALL libusb_interrupt_transfer(libusb_device_handle *dev_handle, unsigned char endpoint, unsigned char *data, int length, int *actual_length, unsigned int timeout); Note: In libusb-0.1 bytes was a (char*) but our consumer code was already fixed to use "usb_ctrl_charbuf" to match other methods. */ int ret; if (ep < 0 || (uintmax_t)ep > UCHAR_MAX || timeout < 0 ) { fatalx(EXIT_FAILURE, "usb_interrupt_read() args out of range for libusb_interrupt_transfer() implementation"); } ret = libusb_interrupt_transfer(dev, (unsigned char)ep, (unsigned char *) bytes, size, &size, (unsigned int)timeout); /* In case of success, return the operation size, as done with libusb 0.1 */ return (ret == LIBUSB_SUCCESS)?size:ret; } static inline int usb_interrupt_write(usb_dev_handle *dev, int ep, const usb_ctrl_charbuf bytes, int size, int timeout) { /* See conversion comments above */ int ret; if (ep < 0 || (uintmax_t)ep > UCHAR_MAX || timeout < 0 ) { fatalx(EXIT_FAILURE, "usb_interrupt_write() args out of range for libusb_interrupt_transfer() implementation"); } ret = libusb_interrupt_transfer(dev, (unsigned char)ep, (unsigned char *) bytes, size, &size, (unsigned int)timeout); /* In case of success, return the operation size, as done with libusb 0.1 */ return (ret == LIBUSB_SUCCESS)?size:ret; } static inline int usb_bulk_read(usb_dev_handle *dev, int ep, usb_ctrl_charbuf bytes, int size, int timeout) { /* See conversion comments above */ int ret; if (ep < 0 || (uintmax_t)ep > UCHAR_MAX || timeout < 0 ) { fatalx(EXIT_FAILURE, "usb_bulk_read() args out of range for libusb_interrupt_transfer() implementation"); } ret = libusb_interrupt_transfer(dev, (unsigned char)ep, (unsigned char *) bytes, size, &size, (unsigned int)timeout); /* In case of success, return the operation size, as done with libusb 0.1 */ return (ret == LIBUSB_SUCCESS)?size:ret; } static inline int usb_bulk_write(usb_dev_handle *dev, int ep, usb_ctrl_charbuf bytes, int size, int timeout) { /* See conversion comments above */ int ret; if (ep < 0 || (uintmax_t)ep > UCHAR_MAX || timeout < 0 ) { fatalx(EXIT_FAILURE, "usb_bulk_write() args out of range for libusb_interrupt_transfer() implementation"); } ret = libusb_interrupt_transfer(dev, (unsigned char)ep, (unsigned char *) bytes, size, &size, (unsigned int)timeout); /* In case of success, return the operation size, as done with libusb 0.1 */ return (ret == LIBUSB_SUCCESS)?size:ret; } static inline int usb_get_string(usb_dev_handle *dev, int index, int langid, usb_ctrl_charbuf buf, size_t buflen) { /* Map from libusb-0.1 API (originally "char* buf") => libusb-1.0 API: int libusb_get_string_descriptor(libusb_device_handle *dev_handle, uint8_t desc_index, uint16_t langid, unsigned char *data, int length) */ if (index < 0 || (uintmax_t)index > UINT8_MAX || langid < 0 || (uintmax_t)langid > UINT16_MAX || (uintmax_t)buflen > INT_MAX ) { fatalx(EXIT_FAILURE, "usb_get_string() args out of range for libusb_get_string_descriptor() implementation"); } return libusb_get_string_descriptor( dev, (uint8_t)index, (uint16_t)langid, (unsigned char *)buf, (int) buflen ); } static inline int usb_get_string_simple(usb_dev_handle *dev, int index, usb_ctrl_charbuf buf, size_t buflen) { /* Map from libusb-0.1 API (originally "char* buf") => libusb-1.0 API: int LIBUSB_CALL libusb_get_string_descriptor_ascii(libusb_device_handle *dev_handle, uint8_t desc_index, unsigned char *data, int length); */ if (index < 0 || (uintmax_t)index > UINT8_MAX || (uintmax_t)buflen > INT_MAX ) { fatalx(EXIT_FAILURE, "usb_get_string_simple() args out of range for libusb_get_string_descriptor_ascii() implementation"); } return libusb_get_string_descriptor_ascii( dev, (uint8_t)index, (unsigned char *)buf, (int) buflen ); } #if (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_PUSH_POP_BESIDEFUNC) && (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_UNUSED_FUNCTION) # pragma GCC diagnostic pop #endif /* Functions for which simple mappings seem to suffice (no build warnings emitted): */ #define usb_claim_interface libusb_claim_interface #define usb_clear_halt libusb_clear_halt #define usb_close libusb_close #define usb_set_configuration libusb_set_configuration #define usb_release_interface libusb_release_interface #define usb_reset libusb_reset_device /* FIXME: some original libusb1.c code cast the (int) argument * as (enum libusb_error) - should we force that in the macro? */ #define nut_usb_strerror(a) libusb_strerror(a) #endif /* WITH_LIBUSB_1_0 */ /* Note: Checked above that in practice we handle some one libusb API */ #if WITH_LIBUSB_0_1 # ifdef HAVE_USB_H # include # else # ifdef HAVE_LUSB0_USB_H # include # else # error "configure script error: Neither HAVE_USB_H nor HAVE_LUSB0_USB_H is set for the WITH_LIBUSB_0_1 build" # endif # endif /* Structures */ /* See detailed comments above, in libusb-1.0 definitions * FIXME: It may make sense to constrain the limits to lowest common * denominator that should fit all of libusb-0.1, libusb-1.0 and libshut, * so that any build of the practical (driver) code knows to not exceed * any use-case. */ /* no typedef for usb_dev_handle - part of libusb-0.1 API names */ typedef int usb_ctrl_requesttype; #define USB_CTRL_REQUESTTYPE_MIN INT_MIN #define USB_CTRL_REQUESTTYPE_MAX INT_MAX typedef int usb_ctrl_request; #define USB_CTRL_REQUEST_MIN INT_MIN #define USB_CTRL_REQUEST_MAX INT_MAX typedef int usb_ctrl_endpoint; #define USB_CTRL_ENDPOINT_MIN INT_MIN #define USB_CTRL_ENDPOINT_MAX INT_MAX typedef int usb_ctrl_msgvalue; #define USB_CTRL_MSGVALUE_MIN INT_MIN #define USB_CTRL_MSGVALUE_MAX INT_MAX typedef int usb_ctrl_repindex; #define USB_CTRL_REPINDEX_MIN INT_MIN #define USB_CTRL_REPINDEX_MAX INT_MAX typedef int usb_ctrl_strindex; #define USB_CTRL_STRINDEX_MIN INT_MIN #define USB_CTRL_STRINDEX_MAX INT_MAX typedef int usb_ctrl_descindex; #define USB_CTRL_DESCINDEX_MIN INT_MIN #define USB_CTRL_DESCINDEX_MAX INT_MAX /* Here MIN/MAX should not matter much, type mostly used for casting */ typedef char* usb_ctrl_charbuf; typedef char usb_ctrl_char; #define USB_CTRL_CHAR_MIN CHAR_MIN #define USB_CTRL_CHAR_MAX CHAR_MAX typedef int usb_ctrl_charbufsize; #define USB_CTRL_CHARBUFSIZE_MIN INT_MIN #define USB_CTRL_CHARBUFSIZE_MAX INT_MAX /* There is no PRIi :) So we define directly by spec */ #define PRI_NUT_USB_CTRL_CHARBUFSIZE "i" typedef int usb_ctrl_timeout_msec; /* in milliseconds */ #define USB_CTRL_TIMEOUTMSEC_MIN INT_MIN #define USB_CTRL_TIMEOUTMSEC_MAX INT_MAX /* defines */ #define LIBUSB_ERROR_ACCESS -EACCES #define LIBUSB_ERROR_BUSY -EBUSY #define LIBUSB_ERROR_IO -EIO #define LIBUSB_ERROR_NO_DEVICE -ENODEV #define LIBUSB_ERROR_NOT_FOUND -ENOENT #define LIBUSB_ERROR_OVERFLOW -EOVERFLOW #define LIBUSB_ERROR_PIPE -EPIPE #define LIBUSB_ERROR_TIMEOUT -ETIMEDOUT #define LIBUSB_ERROR_NO_MEM -ENOMEM #define LIBUSB_ERROR_INVALID_PARAM -EINVAL #define LIBUSB_ERROR_INTERRUPTED -EINTR #define LIBUSB_ERROR_NOT_SUPPORTED -ENOSYS #define LIBUSB_ERROR_OTHER -ERANGE /* Functions for which simple mappings seem to suffice (no build warnings emitted): */ #define nut_usb_strerror(a) usb_strerror() #endif /* WITH_LIBUSB_0_1 */ /* USB standard timeout [ms] */ #define USB_TIMEOUT 5000 #if (defined WITH_USB_BUSPORT) && (WITH_USB_BUSPORT) # define USBMATCHER_REGEXP_ARRAY_LIMIT 8 #else # define USBMATCHER_REGEXP_ARRAY_LIMIT 7 #endif /*! * USBDevice_t: Describe a USB device. This structure contains exactly * the 7 pieces of information by which a USB device identifies * itself, so it serves as a kind of "fingerprint" of the device. This * information must be matched exactly when reopening a device, and * therefore must not be "improved" or updated by a client * program. Vendor, Product, and Serial can be NULL if the * corresponding string did not exist or could not be retrieved. */ typedef struct USBDevice_s { /* These 5 data points are common properties of an USB device: */ uint16_t VendorID; /*!< Device's Vendor ID */ uint16_t ProductID; /*!< Device's Product ID */ char *Vendor; /*!< Device's Vendor Name */ char *Product; /*!< Device's Product Name */ char *Serial; /*!< Product serial number */ /* These data points can be determined by the driver for some devices or by libusb to detail its connection topology: */ char *Bus; /*!< Bus name, e.g. "003" */ uint16_t bcdDevice; /*!< Device release number */ char *Device; /*!< Device name on the bus, e.g. "001" */ #if (defined WITH_USB_BUSPORT) && (WITH_USB_BUSPORT) char *BusPort; /*!< Port name, e.g. "001" */ #endif } USBDevice_t; /*! * USBDeviceMatcher_t: A "USB matcher" is a callback function that * inputs a USBDevice_t structure, and returns 1 for a match and 0 * for a non-match. Thus, a matcher provides a criterion for * selecting a USB device. The callback function further is * expected to return -1 on error with errno set, and -2 on other * errors. Matchers can be connected in a linked list via the * "next" field. */ typedef struct USBDeviceMatcher_s { int (*match_function)(USBDevice_t *device, void *privdata); void *privdata; struct USBDeviceMatcher_s *next; } USBDeviceMatcher_t; /* constructors and destructors for specific types of matchers. An exact matcher matches a specific usb_device_t structure (except for the Bus component, which is ignored). A regex matcher matches devices based on a set of regular expressions. The USBNew* functions return a matcher on success, or -1 on error with errno set. Note that the "USBFree*" functions only free the current matcher, not any others that are linked via "next" fields. */ int USBNewExactMatcher(USBDeviceMatcher_t **matcher, USBDevice_t *hd); int USBNewRegexMatcher(USBDeviceMatcher_t **matcher, char **regex, int cflags); void USBFreeExactMatcher(USBDeviceMatcher_t *matcher); void USBFreeRegexMatcher(USBDeviceMatcher_t *matcher); /* dummy USB function and macro, inspired from the Linux kernel * this allows USB information extraction */ #define USB_DEVICE(vendorID, productID) vendorID, productID typedef struct { uint16_t vendorID; uint16_t productID; void *(*fun)(USBDevice_t *); /* handler for specific processing */ } usb_device_id_t; #define NOT_SUPPORTED 0 #define POSSIBLY_SUPPORTED 1 #define SUPPORTED 2 /* Function used to match a VendorID/ProductID pair against a list of * supported devices. Return values: * NOT_SUPPORTED (0), POSSIBLY_SUPPORTED (1) or SUPPORTED (2) */ int is_usb_device_supported(usb_device_id_t *usb_device_id_list, USBDevice_t *device); void nut_usb_addvars(void); /* Tell the users that port="auto" should be used for USB, * and other values are quietly ignored. Implemented once * here, to use in several USB-capable drivers. */ void warn_if_bad_usb_port_filename(const char *fn); #endif /* NUT_USB_COMMON_H */ nut-2.8.1/drivers/cyberpower-mib.h0000644000175000017500000000030014501607135014021 00000000000000#ifndef CYBERPOWER_MIB_H #define CYBERPOWER_MIB_H #include "main.h" #include "snmp-ups.h" extern mib2nut_info_t cyberpower; extern mib2nut_info_t cyberpower2; #endif /* CYBERPOWER_MIB_H */ nut-2.8.1/drivers/belkin-hid.h0000644000175000017500000000220214500336654013110 00000000000000/* belkin-hid.h - data to monitor Belkin UPS Systems USB/HID devices with NUT * * Copyright (C) * 2003 - 2005 Arnaud Quette * 2005 Peter Selinger * * Sponsored by MGE UPS SYSTEMS * * 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 2 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, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #ifndef BELKIN_HID_H #define BELKIN_HID_H #include "usbhid-ups.h" extern subdriver_t belkin_subdriver; #endif /* BELKIN_HID_H */ nut-2.8.1/drivers/raritan-px2-mib.c0000644000175000017500000012307214501607135014016 00000000000000/* raritan-px2-mib.c - subdriver to monitor RARITAN PX2 SNMP devices with NUT * * Copyright (C) * 2011 - 2012 Arnaud Quette * 2016 Arnaud Quette * * Based on initial work and data from Opengear * * 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 2 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, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "raritan-px2-mib.h" #define RARITAN_PX2_MIB_VERSION "0.4" #define RARITAN_PX2_MIB_SYSOID ".1.3.6.1.4.1.13742.6" #define RARITAN_PX2_OID_MODEL_NAME ".1.3.6.1.4.1.13742.6.3.2.1.1.3.1" /* info elements */ /* FIXME: triage between status and alarms, and make it compliant! */ static info_lkp_t raritanpx2_outlet_status_info[] = { { -1, "unavailable", NULL, NULL }, { 0, "open", NULL, NULL }, { 1, "closed", NULL, NULL }, { 2, "belowLowerCritical", NULL, NULL }, { 3, "belowLowerWarning", NULL, NULL }, { 4, "normal", NULL, NULL }, { 5, "aboveUpperWarning", NULL, NULL }, { 6, "aboveUpperCritical", NULL, NULL }, { 7, "on", NULL, NULL }, { 8, "off", NULL, NULL }, { 9, "detected", NULL, NULL }, { 10, "notDetected", NULL, NULL }, { 11, "alarmed", NULL, NULL }, { 12, "ok", NULL, NULL }, { 13, "marginal", NULL, NULL }, { 14, "fail", NULL, NULL }, { 15, "yes", NULL, NULL }, { 16, "no", NULL, NULL }, { 17, "standby", NULL, NULL }, { 18, "one", NULL, NULL }, { 19, "two", NULL, NULL }, { 20, "inSync", NULL, NULL }, { 21, "outOfSync", NULL, NULL }, { 0, "NULL", NULL, NULL } }; static info_lkp_t raritanpx2_outlet_switchability_info[] = { { -1, "yes", NULL, NULL }, { 1, "yes", NULL, NULL }, { 2, "no", NULL, NULL }, { 0, NULL, NULL, NULL } }; /* PDU2-MIB Snmp2NUT lookup table */ static snmp_info_t raritan_px2_mib[] = { /* standard MIB items */ { "device.description", ST_FLAG_STRING | ST_FLAG_RW, SU_INFOSIZE, ".1.3.6.1.2.1.1.1.0", NULL, SU_FLAG_OK, NULL }, { "device.contact", ST_FLAG_STRING | ST_FLAG_RW, SU_INFOSIZE, ".1.3.6.1.2.1.1.4.0", NULL, SU_FLAG_OK, NULL }, { "device.location", ST_FLAG_STRING | ST_FLAG_RW, SU_INFOSIZE, ".1.3.6.1.2.1.1.6.0", NULL, SU_FLAG_OK, NULL }, /* pduManufacturer.1 = STRING: Raritan */ { "device.mfr", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.13742.6.3.2.1.1.2.1", "Raritan", SU_FLAG_STATIC | SU_FLAG_OK, NULL }, /* pduModel.1 = STRING: PX2-5475 */ { "device.model", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.13742.6.3.2.1.1.3.1", "Raritan PX2 SNMP PDU device", SU_FLAG_STATIC | SU_FLAG_OK, NULL }, /* pduSerialNumber.1 = STRING: QFC3950619 */ { "device.serial", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.13742.6.3.2.1.1.4.1", NULL, SU_FLAG_STATIC | SU_FLAG_OK, NULL }, { "device.type", ST_FLAG_STRING, SU_INFOSIZE, NULL, "pdu", SU_FLAG_STATIC | SU_FLAG_ABSENT | SU_FLAG_OK, NULL }, /* pxMACAddress.1 = STRING: 0:d:5d:b:49:0 */ { "device.macaddr", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.13742.6.3.2.2.1.11.1", NULL, SU_FLAG_STATIC | SU_FLAG_OK, NULL }, /* boardVersion.1.mainController.1 = STRING: 0x01 */ /* FIXME: not compliant! to be RFC'ed */ { "device.revision", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.13742.6.3.2.3.1.4.1.1.1", "", SU_FLAG_STATIC | SU_FLAG_OK, NULL }, /* FIXME: move to device collection! */ /* Wrong OID! * { "ups.mfr.date", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.13742.6.3.2.3.1.6.1.1.1", "", SU_FLAG_OK | SU_FLAG_STATIC, NULL },*/ /* boardFirmwareVersion.1.mainController.1 = STRING: 2.4.3.5-40298 */ { "ups.firmware", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.13742.6.3.2.3.1.6.1.1.1", "", SU_FLAG_STATIC | SU_FLAG_OK, NULL }, /* pduName.1 = STRING: my PX */ { "ups.id", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.13742.6.3.2.2.1.13.1", "", SU_FLAG_STATIC | SU_FLAG_OK, NULL }, { "ups.model", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.13742.6.3.2.1.1.3.1", "Raritan PX2 SNMP PDU device", SU_FLAG_STATIC | SU_FLAG_OK, NULL }, /* Input data: * Units are given in inletSensorUnits.1.1.%i * Value should be scaled by inletSensorDecimalDigits.1.1.%i * For example, if the value is 1 and inletSensorDecimalDigits is 2, then actual value is 0.01. */ /* measurementsInletSensorValue.1.1.rmsCurrent = Gauge32: 10 (A) */ { "input.load", 0, 0.1, ".1.3.6.1.4.1.13742.6.5.2.3.1.4.1.1.1", NULL, SU_FLAG_OK, NULL }, /* measurementsInletSensorValue.1.1.rmsVoltage = Gauge32: 119 (V) */ { "input.voltage", 0, 1, ".1.3.6.1.4.1.13742.6.5.2.3.1.4.1.1.4", NULL, SU_FLAG_OK, NULL }, /* measurementsInletSensorValue.1.1.activePower = Gauge32: 10 (W) */ { "input.realpower", 0, 1, ".1.3.6.1.4.1.13742.6.5.2.3.1.4.1.1.5", NULL, SU_FLAG_OK, NULL }, /* measurementsInletSensorValue.1.1.apparentPower = Gauge32: 122 (VA) */ { "input.power", 0, 1, ".1.3.6.1.4.1.13742.6.5.2.3.1.4.1.1.6", NULL, SU_FLAG_OK, NULL }, /* measurementsInletSensorValue.1.1.powerFactor = Gauge32: 8 (none) */ /* FIXME: need RFC! */ { "input.powerfactor", 0, 0.01, ".1.3.6.1.4.1.13742.6.5.2.3.1.4.1.1.7", NULL, SU_FLAG_OK, NULL }, /* measurementsInletSensorValue.1.1.activeEnergy = Gauge32: 193359 (wattHour) */ /* { "unmapped.measurementsInletSensorValue", 0, 1, ".1.3.6.1.4.1.13742.6.5.2.3.1.4.1.1.8", NULL, SU_FLAG_OK, NULL }, */ /* inletPlug.1.1 = INTEGER: plugIEC320C20(6) */ /* FIXME: need RFC (input.type | [input.]inlet.type...) and standardization * { "unmapped.inletPlug", 0, 1, ".1.3.6.1.4.1.13742.6.3.3.3.1.4.1.1", NULL, SU_FLAG_OK, NULL },*/ /* outletCount.1 = INTEGER: 24 */ { "outlet.count", 0, 1, ".1.3.6.1.4.1.13742.6.3.2.2.1.4.1", "0", SU_FLAG_STATIC | SU_FLAG_OK, NULL }, /* outlet template definition * Indexes start from 1, ie outlet.1 => .1 */ /* Note: the first definition is used to determine the base index (ie 0 or 1) */ /* outletName.1.%i = STRING: */ { "outlet.%i.desc", ST_FLAG_RW | ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.13742.6.3.5.3.1.3.1.%i", NULL, SU_OUTLET, NULL }, /* outletSwitchingState.1.%i = INTEGER: on(7) */ { "outlet.%i.status", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.13742.6.4.1.2.1.3.1.%i", NULL, SU_OUTLET, &raritanpx2_outlet_status_info[0] }, /* outletLabel.1.%i = STRING: 1 */ { "outlet.%i.id", 0, 1, ".1.3.6.1.4.1.13742.6.3.5.3.1.2.1.%i", "%i", SU_FLAG_STATIC | SU_OUTLET | SU_FLAG_OK, NULL }, /* outletReceptacle.1.1 = INTEGER: receptacleNEMA520R(37) */ /* FIXME: need RFC and standardization * { "outlet.%i.type", 0, 1, ".1.3.6.1.4.1.13742.6.3.5.3.1.4.1.%i", NULL, SU_OUTLET | SU_FLAG_OK, NULL }, */ /* RMS Current (divide by 10). e.g. 5 == 0.5A */ /* measurementsOutletSensorValue.1.%i.rmsCurrent = Gauge32: 10 */ { "outlet.%i.current", 0, 0.1, ".1.3.6.1.4.1.13742.6.5.4.3.1.4.1.%i.1", NULL, SU_OUTLET | SU_FLAG_OK, NULL }, /* measurementsOutletSensorValue.1.%i.rmsVoltage = Gauge32: 119 */ { "outlet.%i.voltage", 0, 1, ".1.3.6.1.4.1.13742.6.5.4.3.1.4.1.%i.4", "%i", SU_OUTLET | SU_FLAG_OK, NULL }, /* measurementsOutletSensorValue.1.%i.activePower = Gauge32: 10 */ { "outlet.%i.power", 0, 1, ".1.3.6.1.4.1.13742.6.5.4.3.1.4.1.%i.5", "%i", SU_OUTLET | SU_FLAG_OK, NULL }, /* measurementsOutletSensorValue.1.%i.apparentPower = Gauge32: 122 */ { "outlet.%i.realpower", 0, 1, ".1.3.6.1.4.1.13742.6.5.4.3.1.4.1.%i.6", "%i", SU_OUTLET | SU_FLAG_OK, NULL }, /* measurementsOutletSensorValue.1.%i.powerFactor = Gauge32: 8 */ { "outlet.%i.powerfactor", 0, 1, ".1.3.6.1.4.1.13742.6.5.4.3.1.4.1.%i.7", "%i", SU_OUTLET | SU_FLAG_OK, NULL }, /* measurementsOutletSensorValue.1.1.activeEnergy = Gauge32: 89890 */ /* FIXME: * { "unmapped.measurementsOutletSensorValue", 0, 1, ".1.3.6.1.4.1.13742.6.5.4.3.1.4.1.1.8", NULL, SU_FLAG_OK, NULL }, */ /* measurementsOutletSensorValue.1.1.onOff = Gauge32: 0 */ /* FIXME: * { "unmapped.measurementsOutletSensorValue", 0, 1, ".1.3.6.1.4.1.13742.6.5.4.3.1.4.1.1.14", NULL, SU_FLAG_OK, NULL }, */ /* outletSwitchable.1.%i = INTEGER: true(1) */ { "outlet.%i.switchable", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.13742.6.3.5.3.1.28.1.%i", "no", SU_FLAG_STATIC | SU_OUTLET | SU_FLAG_OK, &raritanpx2_outlet_switchability_info[0] }, /* instant commands. */ /* switchingOperation.1.1 = INTEGER: on(1) */ { "outlet.%i.load.off", 0, 1, ".1.3.6.1.4.1.13742.6.4.1.2.1.2.1.%i", "0", SU_TYPE_CMD | SU_OUTLET, NULL }, { "outlet.%i.load.on", 0, 1, ".1.3.6.1.4.1.13742.6.4.1.2.1.2.1.%i", "1", SU_TYPE_CMD | SU_OUTLET, NULL }, { "outlet.%i.load.cycle", 0, 1, ".1.3.6.1.4.1.13742.6.4.1.2.1.2.1.%i", "2", SU_TYPE_CMD | SU_OUTLET, NULL }, #if WITH_UNMAPPED_DATA_POINTS || (defined DEBUG) /* pduCount.0 = INTEGER: 1 */ /* FIXME: part of daisychain support, RFC device.count */ { "device.count", 0, 1, ".1.3.6.1.4.1.13742.6.3.1.0", NULL, SU_FLAG_OK, NULL }, #if WITH_UNMAPPED_DATA_POINTS /* pduRatedVoltage.1 = STRING: 100-120V */ { "unmapped.pduRatedVoltage", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.13742.6.3.2.1.1.5.1", NULL, SU_FLAG_OK, NULL }, /* pduRatedCurrent.1 = STRING: 16A */ { "unmapped.pduRatedCurrent", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.13742.6.3.2.1.1.6.1", NULL, SU_FLAG_OK, NULL }, /* pduRatedFrequency.1 = STRING: 50/60Hz */ { "unmapped.pduRatedFrequency", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.13742.6.3.2.1.1.7.1", NULL, SU_FLAG_OK, NULL }, /* pduRatedVA.1 = STRING: 1.6-1.9kVA */ { "unmapped.pduRatedVA", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.13742.6.3.2.1.1.8.1", NULL, SU_FLAG_OK, NULL }, /* pduImage.1 = STRING: */ { "unmapped.pduImage", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.13742.6.3.2.1.1.9.1", NULL, SU_FLAG_OK, NULL }, /* inletCount.1 = INTEGER: 1 */ { "unmapped.inletCount", 0, 1, ".1.3.6.1.4.1.13742.6.3.2.2.1.2.1", NULL, SU_FLAG_OK, NULL }, /* overCurrentProtectorCount.1 = INTEGER: 0 */ { "unmapped.overCurrentProtectorCount", 0, 1, ".1.3.6.1.4.1.13742.6.3.2.2.1.3.1", NULL, SU_FLAG_OK, NULL }, /* inletControllerCount.1 = INTEGER: 0 */ { "unmapped.inletControllerCount", 0, 1, ".1.3.6.1.4.1.13742.6.3.2.2.1.5.1", NULL, SU_FLAG_OK, NULL }, /* outletControllerCount.1 = INTEGER: 6 */ { "unmapped.outletControllerCount", 0, 1, ".1.3.6.1.4.1.13742.6.3.2.2.1.6.1", NULL, SU_FLAG_OK, NULL }, /* externalSensorCount.1 = INTEGER: 16 */ { "unmapped.externalSensorCount", 0, 1, ".1.3.6.1.4.1.13742.6.3.2.2.1.7.1", NULL, SU_FLAG_OK, NULL }, /* pxIPAddress.1 = IpAddress: 192.168.20.188 */ { "unmapped.pxIPAddress", 0, 1, ".1.3.6.1.4.1.13742.6.3.2.2.1.8.1", NULL, SU_FLAG_OK, NULL }, /* netmask.1 = IpAddress: 255.255.255.0 */ { "unmapped.netmask", 0, 1, ".1.3.6.1.4.1.13742.6.3.2.2.1.9.1", NULL, SU_FLAG_OK, NULL }, /* gateway.1 = IpAddress: 192.168.20.254 */ { "unmapped.gateway", 0, 1, ".1.3.6.1.4.1.13742.6.3.2.2.1.10.1", NULL, SU_FLAG_OK, NULL }, /* utcOffset.1 = STRING: -5:00 */ { "unmapped.utcOffset", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.13742.6.3.2.2.1.12.1", NULL, SU_FLAG_OK, NULL }, /* externalSensorsZCoordinateUnits.1 = INTEGER: rackUnits(0) */ { "unmapped.externalSensorsZCoordinateUnits", 0, 1, ".1.3.6.1.4.1.13742.6.3.2.2.1.34.1", NULL, SU_FLAG_OK, NULL }, /* unitDeviceCapabilities.1 = BITS: 00 00 00 00 00 00 */ { "unmapped.unitDeviceCapabilities", 0, 1, ".1.3.6.1.4.1.13742.6.3.2.2.1.35.1", NULL, SU_FLAG_OK, NULL }, /* outletSequencingDelay.1 = Gauge32: 200 */ { "unmapped.outletSequencingDelay", 0, 1, ".1.3.6.1.4.1.13742.6.3.2.2.1.36.1", NULL, SU_FLAG_OK, NULL }, /* globalOutletPowerCyclingPowerOffPeriod.1 = Gauge32: 10 */ { "unmapped.globalOutletPowerCyclingPowerOffPeriod", 0, 1, ".1.3.6.1.4.1.13742.6.3.2.2.1.37.1", NULL, SU_FLAG_OK, NULL }, /* globalOutletStateOnStartup.1 = INTEGER: lastKnownState(2) */ { "unmapped.globalOutletStateOnStartup", 0, 1, ".1.3.6.1.4.1.13742.6.3.2.2.1.38.1", NULL, SU_FLAG_OK, NULL }, /* outletPowerupSequence.1 = STRING: 1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24 */ { "unmapped.outletPowerupSequence", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.13742.6.3.2.2.1.39.1", NULL, SU_FLAG_OK, NULL }, /* pduPowerCyclingPowerOffPeriod.1 = Gauge32: 3 */ { "unmapped.pduPowerCyclingPowerOffPeriod", 0, 1, ".1.3.6.1.4.1.13742.6.3.2.2.1.40.1", NULL, SU_FLAG_OK, NULL }, /* pduDaisychainMemberType.1 = INTEGER: standalone(0) */ { "unmapped.pduDaisychainMemberType", 0, 1, ".1.3.6.1.4.1.13742.6.3.2.2.1.41.1", NULL, SU_FLAG_OK, NULL }, /* managedExternalSensorCount.1 = INTEGER: 0 */ { "unmapped.managedExternalSensorCount", 0, 1, ".1.3.6.1.4.1.13742.6.3.2.2.1.42.1", NULL, SU_FLAG_OK, NULL }, /* pxInetAddressType.1 = INTEGER: ipv4(1) */ { "unmapped.pxInetAddressType", 0, 1, ".1.3.6.1.4.1.13742.6.3.2.2.1.50.1", NULL, SU_FLAG_OK, NULL }, /* pxInetIPAddress.1 = Hex-STRING: C0 A8 14 BC */ { "unmapped.pxInetIPAddress", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.13742.6.3.2.2.1.51.1", NULL, SU_FLAG_OK, NULL }, /* pxInetNetmask.1 = Hex-STRING: FF FF FF 00 */ { "unmapped.pxInetNetmask", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.13742.6.3.2.2.1.52.1", NULL, SU_FLAG_OK, NULL }, /* pxInetGateway.1 = Hex-STRING: C0 A8 14 FE */ { "unmapped.pxInetGateway", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.13742.6.3.2.2.1.53.1", NULL, SU_FLAG_OK, NULL }, /* loadShedding.1 = INTEGER: false(2) */ { "unmapped.loadShedding", 0, 1, ".1.3.6.1.4.1.13742.6.3.2.2.1.55.1", NULL, SU_FLAG_OK, NULL }, /* serverCount.1 = INTEGER: 8 */ { "unmapped.serverCount", 0, 1, ".1.3.6.1.4.1.13742.6.3.2.2.1.56.1", NULL, SU_FLAG_OK, NULL }, /* inrushGuardDelay.1 = Gauge32: 200 */ { "unmapped.inrushGuardDelay", 0, 1, ".1.3.6.1.4.1.13742.6.3.2.2.1.57.1", NULL, SU_FLAG_OK, NULL }, /* cascadedDeviceConnected.1 = INTEGER: false(2) */ { "unmapped.cascadedDeviceConnected", 0, 1, ".1.3.6.1.4.1.13742.6.3.2.2.1.58.1", NULL, SU_FLAG_OK, NULL }, /* synchronizeWithNTPServer.1 = INTEGER: false(2) */ { "unmapped.synchronizeWithNTPServer", 0, 1, ".1.3.6.1.4.1.13742.6.3.2.2.1.59.1", NULL, SU_FLAG_OK, NULL }, /* useDHCPProvidedNTPServer.1 = INTEGER: true(1) */ { "unmapped.useDHCPProvidedNTPServer", 0, 1, ".1.3.6.1.4.1.13742.6.3.2.2.1.60.1", NULL, SU_FLAG_OK, NULL }, /* firstNTPServerAddressType.1 = INTEGER: unknown(0) */ { "unmapped.firstNTPServerAddressType", 0, 1, ".1.3.6.1.4.1.13742.6.3.2.2.1.61.1", NULL, SU_FLAG_OK, NULL }, /* firstNTPServerAddress.1 = "" */ { "unmapped.firstNTPServerAddress", 0, 1, ".1.3.6.1.4.1.13742.6.3.2.2.1.62.1", NULL, SU_FLAG_OK, NULL }, /* secondNTPServerAddressType.1 = INTEGER: unknown(0) */ { "unmapped.secondNTPServerAddressType", 0, 1, ".1.3.6.1.4.1.13742.6.3.2.2.1.63.1", NULL, SU_FLAG_OK, NULL }, /* secondNTPServerAddress.1 = "" */ { "unmapped.secondNTPServerAddress", 0, 1, ".1.3.6.1.4.1.13742.6.3.2.2.1.64.1", NULL, SU_FLAG_OK, NULL }, /* wireCount.1 = INTEGER: 0 */ { "unmapped.wireCount", 0, 1, ".1.3.6.1.4.1.13742.6.3.2.2.1.65.1", NULL, SU_FLAG_OK, NULL }, /* transferSwitchCount.1 = INTEGER: 0 */ { "unmapped.transferSwitchCount", 0, 1, ".1.3.6.1.4.1.13742.6.3.2.2.1.66.1", NULL, SU_FLAG_OK, NULL }, /* boardVersion.1.outletController.{1-6} = STRING: 60 */ { "unmapped.boardVersion", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.13742.6.3.2.3.1.4.1.3.1", NULL, SU_FLAG_OK, NULL }, /* boardFirmwareVersion.1.outletController.{1-6} = STRING: 1F */ { "unmapped.boardFirmwareVersion", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.13742.6.3.2.3.1.6.1.3.1", NULL, SU_FLAG_OK, NULL }, /* boardFirmwareTimeStamp.1.mainController.1 = Gauge32: 0 */ { "unmapped.boardFirmwareTimeStamp", 0, 1, ".1.3.6.1.4.1.13742.6.3.2.3.1.8.1.1.1", NULL, SU_FLAG_OK, NULL }, /* dataLogging.1 = INTEGER: true(1) */ { "unmapped.dataLogging", 0, 1, ".1.3.6.1.4.1.13742.6.3.2.4.1.1.1", NULL, SU_FLAG_OK, NULL }, /* measurementPeriod.1 = INTEGER: 1 */ { "unmapped.measurementPeriod", 0, 1, ".1.3.6.1.4.1.13742.6.3.2.4.1.2.1", NULL, SU_FLAG_OK, NULL }, /* measurementsPerLogEntry.1 = INTEGER: 60 */ { "unmapped.measurementsPerLogEntry", 0, 1, ".1.3.6.1.4.1.13742.6.3.2.4.1.3.1", NULL, SU_FLAG_OK, NULL }, /* logSize.1 = INTEGER: 120 */ { "unmapped.logSize", 0, 1, ".1.3.6.1.4.1.13742.6.3.2.4.1.4.1", NULL, SU_FLAG_OK, NULL }, /* dataLoggingEnableForAllSensors.1 = INTEGER: false(2) */ { "unmapped.dataLoggingEnableForAllSensors", 0, 1, ".1.3.6.1.4.1.13742.6.3.2.4.1.5.1", NULL, SU_FLAG_OK, NULL }, /* inletLabel.1.1 = STRING: I1 */ { "unmapped.inletLabel", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.13742.6.3.3.3.1.2.1.1", NULL, SU_FLAG_OK, NULL }, /* inletName.1.1 = STRING: */ { "unmapped.inletName", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.13742.6.3.3.3.1.3.1.1", NULL, SU_FLAG_OK, NULL }, /* inletPoleCount.1.1 = INTEGER: 2 */ { "unmapped.inletPoleCount", 0, 1, ".1.3.6.1.4.1.13742.6.3.3.3.1.5.1.1", NULL, SU_FLAG_OK, NULL }, /* inletRatedVoltage.1.1 = STRING: 100-120V */ { "unmapped.inletRatedVoltage", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.13742.6.3.3.3.1.6.1.1", NULL, SU_FLAG_OK, NULL }, /* inletRatedCurrent.1.1 = STRING: 16A */ { "unmapped.inletRatedCurrent", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.13742.6.3.3.3.1.7.1.1", NULL, SU_FLAG_OK, NULL }, /* inletDeviceCapabilities.1.1 = BITS: 9F 00 00 00 00 00 rmsCurrent(0) rmsVoltage(3) activePower(4) apparentPower(5) powerFactor(6) activeEnergy(7) */ { "unmapped.inletDeviceCapabilities", 0, 1, ".1.3.6.1.4.1.13742.6.3.3.3.1.10.1.1", NULL, SU_FLAG_OK, NULL }, /* inletPoleCapabilities.1.1 = BITS: 00 00 00 00 00 00 */ { "unmapped.inletPoleCapabilities", 0, 1, ".1.3.6.1.4.1.13742.6.3.3.3.1.11.1.1", NULL, SU_FLAG_OK, NULL }, /* inletPlugDescriptor.1.1 = STRING: IEC 60320 C20 */ { "unmapped.inletPlugDescriptor", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.13742.6.3.3.3.1.12.1.1", NULL, SU_FLAG_OK, NULL }, /* inletSensorLogAvailable.1.1.rmsCurrent = INTEGER: true(1) */ { "unmapped.inletSensorLogAvailable", 0, 1, ".1.3.6.1.4.1.13742.6.3.3.4.1.4.1.1.1", NULL, SU_FLAG_OK, NULL }, /* inletSensorLogAvailable.1.1.rmsVoltage = INTEGER: true(1) */ { "unmapped.inletSensorLogAvailable", 0, 1, ".1.3.6.1.4.1.13742.6.3.3.4.1.4.1.1.4", NULL, SU_FLAG_OK, NULL }, /* inletSensorLogAvailable.1.1.activePower = INTEGER: true(1) */ { "unmapped.inletSensorLogAvailable", 0, 1, ".1.3.6.1.4.1.13742.6.3.3.4.1.4.1.1.5", NULL, SU_FLAG_OK, NULL }, /* inletSensorLogAvailable.1.1.apparentPower = INTEGER: true(1) */ { "unmapped.inletSensorLogAvailable", 0, 1, ".1.3.6.1.4.1.13742.6.3.3.4.1.4.1.1.6", NULL, SU_FLAG_OK, NULL }, /* inletSensorLogAvailable.1.1.powerFactor = INTEGER: true(1) */ { "unmapped.inletSensorLogAvailable", 0, 1, ".1.3.6.1.4.1.13742.6.3.3.4.1.4.1.1.7", NULL, SU_FLAG_OK, NULL }, /* inletSensorLogAvailable.1.1.activeEnergy = INTEGER: true(1) */ { "unmapped.inletSensorLogAvailable", 0, 1, ".1.3.6.1.4.1.13742.6.3.3.4.1.4.1.1.8", NULL, SU_FLAG_OK, NULL }, /* inletSensorUnits.1.1.rmsCurrent = INTEGER: amp(2) */ { "unmapped.inletSensorUnits", 0, 1, ".1.3.6.1.4.1.13742.6.3.3.4.1.6.1.1.1", NULL, SU_FLAG_OK, NULL }, /* inletSensorUnits.1.1.rmsVoltage = INTEGER: volt(1) */ { "unmapped.inletSensorUnits", 0, 1, ".1.3.6.1.4.1.13742.6.3.3.4.1.6.1.1.4", NULL, SU_FLAG_OK, NULL }, /* inletSensorUnits.1.1.activePower = INTEGER: watt(3) */ { "unmapped.inletSensorUnits", 0, 1, ".1.3.6.1.4.1.13742.6.3.3.4.1.6.1.1.5", NULL, SU_FLAG_OK, NULL }, /* inletSensorUnits.1.1.apparentPower = INTEGER: voltamp(4) */ { "unmapped.inletSensorUnits", 0, 1, ".1.3.6.1.4.1.13742.6.3.3.4.1.6.1.1.6", NULL, SU_FLAG_OK, NULL }, /* inletSensorUnits.1.1.powerFactor = INTEGER: none(-1) */ { "unmapped.inletSensorUnits", 0, 1, ".1.3.6.1.4.1.13742.6.3.3.4.1.6.1.1.7", NULL, SU_FLAG_OK, NULL }, /* inletSensorUnits.1.1.activeEnergy = INTEGER: wattHour(5) */ { "unmapped.inletSensorUnits", 0, 1, ".1.3.6.1.4.1.13742.6.3.3.4.1.6.1.1.8", NULL, SU_FLAG_OK, NULL }, /* inletSensorDecimalDigits.1.1.rmsCurrent = Gauge32: 1 */ { "unmapped.inletSensorDecimalDigits", 0, 1, ".1.3.6.1.4.1.13742.6.3.3.4.1.7.1.1.1", NULL, SU_FLAG_OK, NULL }, /* inletSensorDecimalDigits.1.1.rmsVoltage = Gauge32: 0 */ { "unmapped.inletSensorDecimalDigits", 0, 1, ".1.3.6.1.4.1.13742.6.3.3.4.1.7.1.1.4", NULL, SU_FLAG_OK, NULL }, /* inletSensorDecimalDigits.1.1.activePower = Gauge32: 0 */ { "unmapped.inletSensorDecimalDigits", 0, 1, ".1.3.6.1.4.1.13742.6.3.3.4.1.7.1.1.5", NULL, SU_FLAG_OK, NULL }, /* inletSensorDecimalDigits.1.1.apparentPower = Gauge32: 0 */ { "unmapped.inletSensorDecimalDigits", 0, 1, ".1.3.6.1.4.1.13742.6.3.3.4.1.7.1.1.6", NULL, SU_FLAG_OK, NULL }, /* inletSensorDecimalDigits.1.1.powerFactor = Gauge32: 2 */ { "unmapped.inletSensorDecimalDigits", 0, 1, ".1.3.6.1.4.1.13742.6.3.3.4.1.7.1.1.7", NULL, SU_FLAG_OK, NULL }, /* inletSensorDecimalDigits.1.1.activeEnergy = Gauge32: 0 */ { "unmapped.inletSensorDecimalDigits", 0, 1, ".1.3.6.1.4.1.13742.6.3.3.4.1.7.1.1.8", NULL, SU_FLAG_OK, NULL }, /* inletSensorAccuracy.1.1.rmsCurrent = Gauge32: 100 */ { "unmapped.inletSensorAccuracy", 0, 1, ".1.3.6.1.4.1.13742.6.3.3.4.1.8.1.1.1", NULL, SU_FLAG_OK, NULL }, /* inletSensorAccuracy.1.1.rmsVoltage = Gauge32: 100 */ { "unmapped.inletSensorAccuracy", 0, 1, ".1.3.6.1.4.1.13742.6.3.3.4.1.8.1.1.4", NULL, SU_FLAG_OK, NULL }, /* inletSensorAccuracy.1.1.activePower = Gauge32: 300 */ { "unmapped.inletSensorAccuracy", 0, 1, ".1.3.6.1.4.1.13742.6.3.3.4.1.8.1.1.5", NULL, SU_FLAG_OK, NULL }, /* inletSensorAccuracy.1.1.apparentPower = Gauge32: 200 */ { "unmapped.inletSensorAccuracy", 0, 1, ".1.3.6.1.4.1.13742.6.3.3.4.1.8.1.1.6", NULL, SU_FLAG_OK, NULL }, /* inletSensorAccuracy.1.1.powerFactor = Gauge32: 500 */ { "unmapped.inletSensorAccuracy", 0, 1, ".1.3.6.1.4.1.13742.6.3.3.4.1.8.1.1.7", NULL, SU_FLAG_OK, NULL }, /* inletSensorAccuracy.1.1.activeEnergy = Gauge32: 100 */ { "unmapped.inletSensorAccuracy", 0, 1, ".1.3.6.1.4.1.13742.6.3.3.4.1.8.1.1.8", NULL, SU_FLAG_OK, NULL }, /* inletSensorResolution.1.1.rmsCurrent = Gauge32: 1 */ { "unmapped.inletSensorResolution", 0, 1, ".1.3.6.1.4.1.13742.6.3.3.4.1.9.1.1.1", NULL, SU_FLAG_OK, NULL }, /* inletSensorResolution.1.1.rmsVoltage = Gauge32: 1 */ { "unmapped.inletSensorResolution", 0, 1, ".1.3.6.1.4.1.13742.6.3.3.4.1.9.1.1.4", NULL, SU_FLAG_OK, NULL }, /* inletSensorResolution.1.1.activePower = Gauge32: 1 */ { "unmapped.inletSensorResolution", 0, 1, ".1.3.6.1.4.1.13742.6.3.3.4.1.9.1.1.5", NULL, SU_FLAG_OK, NULL }, /* inletSensorResolution.1.1.apparentPower = Gauge32: 1 */ { "unmapped.inletSensorResolution", 0, 1, ".1.3.6.1.4.1.13742.6.3.3.4.1.9.1.1.6", NULL, SU_FLAG_OK, NULL }, /* inletSensorResolution.1.1.powerFactor = Gauge32: 1 */ { "unmapped.inletSensorResolution", 0, 1, ".1.3.6.1.4.1.13742.6.3.3.4.1.9.1.1.7", NULL, SU_FLAG_OK, NULL }, /* inletSensorResolution.1.1.activeEnergy = Gauge32: 1 */ { "unmapped.inletSensorResolution", 0, 1, ".1.3.6.1.4.1.13742.6.3.3.4.1.9.1.1.8", NULL, SU_FLAG_OK, NULL }, /* inletSensorTolerance.1.1.rmsCurrent = Gauge32: 120 */ { "unmapped.inletSensorTolerance", 0, 1, ".1.3.6.1.4.1.13742.6.3.3.4.1.10.1.1.1", NULL, SU_FLAG_OK, NULL }, /* inletSensorTolerance.1.1.rmsVoltage = Gauge32: 5 */ { "unmapped.inletSensorTolerance", 0, 1, ".1.3.6.1.4.1.13742.6.3.3.4.1.10.1.1.4", NULL, SU_FLAG_OK, NULL }, /* inletSensorTolerance.1.1.activePower = Gauge32: 120 */ { "unmapped.inletSensorTolerance", 0, 1, ".1.3.6.1.4.1.13742.6.3.3.4.1.10.1.1.5", NULL, SU_FLAG_OK, NULL }, /* inletSensorTolerance.1.1.apparentPower = Gauge32: 120 */ { "unmapped.inletSensorTolerance", 0, 1, ".1.3.6.1.4.1.13742.6.3.3.4.1.10.1.1.6", NULL, SU_FLAG_OK, NULL }, /* inletSensorTolerance.1.1.powerFactor = Gauge32: 50 */ { "unmapped.inletSensorTolerance", 0, 1, ".1.3.6.1.4.1.13742.6.3.3.4.1.10.1.1.7", NULL, SU_FLAG_OK, NULL }, /* inletSensorTolerance.1.1.activeEnergy = Gauge32: 120 */ { "unmapped.inletSensorTolerance", 0, 1, ".1.3.6.1.4.1.13742.6.3.3.4.1.10.1.1.8", NULL, SU_FLAG_OK, NULL }, /* inletSensorMaximum.1.1.rmsCurrent = Gauge32: 7680 */ { "unmapped.inletSensorMaximum", 0, 1, ".1.3.6.1.4.1.13742.6.3.3.4.1.11.1.1.1", NULL, SU_FLAG_OK, NULL }, /* inletSensorMaximum.1.1.rmsVoltage = Gauge32: 264 */ { "unmapped.inletSensorMaximum", 0, 1, ".1.3.6.1.4.1.13742.6.3.3.4.1.11.1.1.4", NULL, SU_FLAG_OK, NULL }, /* inletSensorMaximum.1.1.activePower = Gauge32: 202752 */ { "unmapped.inletSensorMaximum", 0, 1, ".1.3.6.1.4.1.13742.6.3.3.4.1.11.1.1.5", NULL, SU_FLAG_OK, NULL }, /* inletSensorMaximum.1.1.apparentPower = Gauge32: 202752 */ { "unmapped.inletSensorMaximum", 0, 1, ".1.3.6.1.4.1.13742.6.3.3.4.1.11.1.1.6", NULL, SU_FLAG_OK, NULL }, /* inletSensorMaximum.1.1.powerFactor = Gauge32: 100 */ { "unmapped.inletSensorMaximum", 0, 1, ".1.3.6.1.4.1.13742.6.3.3.4.1.11.1.1.7", NULL, SU_FLAG_OK, NULL }, /* inletSensorMaximum.1.1.activeEnergy = Gauge32: 4294967295 */ { "unmapped.inletSensorMaximum", 0, 1, ".1.3.6.1.4.1.13742.6.3.3.4.1.11.1.1.8", NULL, SU_FLAG_OK, NULL }, /* inletSensorMinimum.1.1.rmsCurrent = Gauge32: 0 */ { "unmapped.inletSensorMinimum", 0, 1, ".1.3.6.1.4.1.13742.6.3.3.4.1.12.1.1.1", NULL, SU_FLAG_OK, NULL }, /* inletSensorMinimum.1.1.rmsVoltage = Gauge32: 0 */ { "unmapped.inletSensorMinimum", 0, 1, ".1.3.6.1.4.1.13742.6.3.3.4.1.12.1.1.4", NULL, SU_FLAG_OK, NULL }, /* inletSensorMinimum.1.1.activePower = Gauge32: 0 */ { "unmapped.inletSensorMinimum", 0, 1, ".1.3.6.1.4.1.13742.6.3.3.4.1.12.1.1.5", NULL, SU_FLAG_OK, NULL }, /* inletSensorMinimum.1.1.apparentPower = Gauge32: 0 */ { "unmapped.inletSensorMinimum", 0, 1, ".1.3.6.1.4.1.13742.6.3.3.4.1.12.1.1.6", NULL, SU_FLAG_OK, NULL }, /* inletSensorMinimum.1.1.powerFactor = Gauge32: 0 */ { "unmapped.inletSensorMinimum", 0, 1, ".1.3.6.1.4.1.13742.6.3.3.4.1.12.1.1.7", NULL, SU_FLAG_OK, NULL }, /* inletSensorMinimum.1.1.activeEnergy = Gauge32: 0 */ { "unmapped.inletSensorMinimum", 0, 1, ".1.3.6.1.4.1.13742.6.3.3.4.1.12.1.1.8", NULL, SU_FLAG_OK, NULL }, /* inletSensorHysteresis.1.1.rmsCurrent = Gauge32: 10 */ { "unmapped.inletSensorHysteresis", 0, 1, ".1.3.6.1.4.1.13742.6.3.3.4.1.13.1.1.1", NULL, SU_FLAG_OK, NULL }, /* inletSensorHysteresis.1.1.rmsVoltage = Gauge32: 2 */ { "unmapped.inletSensorHysteresis", 0, 1, ".1.3.6.1.4.1.13742.6.3.3.4.1.13.1.1.4", NULL, SU_FLAG_OK, NULL }, /* inletSensorHysteresis.1.1.activePower = Gauge32: 0 */ { "unmapped.inletSensorHysteresis", 0, 1, ".1.3.6.1.4.1.13742.6.3.3.4.1.13.1.1.5", NULL, SU_FLAG_OK, NULL }, /* inletSensorHysteresis.1.1.apparentPower = Gauge32: 0 */ { "unmapped.inletSensorHysteresis", 0, 1, ".1.3.6.1.4.1.13742.6.3.3.4.1.13.1.1.6", NULL, SU_FLAG_OK, NULL }, /* inletSensorHysteresis.1.1.powerFactor = Gauge32: 0 */ { "unmapped.inletSensorHysteresis", 0, 1, ".1.3.6.1.4.1.13742.6.3.3.4.1.13.1.1.7", NULL, SU_FLAG_OK, NULL }, /* inletSensorHysteresis.1.1.activeEnergy = Gauge32: 0 */ { "unmapped.inletSensorHysteresis", 0, 1, ".1.3.6.1.4.1.13742.6.3.3.4.1.13.1.1.8", NULL, SU_FLAG_OK, NULL }, /* inletSensorStateChangeDelay.1.1.rmsCurrent = Gauge32: 0 */ { "unmapped.inletSensorStateChangeDelay", 0, 1, ".1.3.6.1.4.1.13742.6.3.3.4.1.14.1.1.1", NULL, SU_FLAG_OK, NULL }, /* inletSensorStateChangeDelay.1.1.rmsVoltage = Gauge32: 0 */ { "unmapped.inletSensorStateChangeDelay", 0, 1, ".1.3.6.1.4.1.13742.6.3.3.4.1.14.1.1.4", NULL, SU_FLAG_OK, NULL }, /* inletSensorStateChangeDelay.1.1.activePower = Gauge32: 0 */ { "unmapped.inletSensorStateChangeDelay", 0, 1, ".1.3.6.1.4.1.13742.6.3.3.4.1.14.1.1.5", NULL, SU_FLAG_OK, NULL }, /* inletSensorStateChangeDelay.1.1.apparentPower = Gauge32: 0 */ { "unmapped.inletSensorStateChangeDelay", 0, 1, ".1.3.6.1.4.1.13742.6.3.3.4.1.14.1.1.6", NULL, SU_FLAG_OK, NULL }, /* inletSensorStateChangeDelay.1.1.powerFactor = Gauge32: 0 */ { "unmapped.inletSensorStateChangeDelay", 0, 1, ".1.3.6.1.4.1.13742.6.3.3.4.1.14.1.1.7", NULL, SU_FLAG_OK, NULL }, /* inletSensorStateChangeDelay.1.1.activeEnergy = Gauge32: 0 */ { "unmapped.inletSensorStateChangeDelay", 0, 1, ".1.3.6.1.4.1.13742.6.3.3.4.1.14.1.1.8", NULL, SU_FLAG_OK, NULL }, /* Inlet thresholds */ /* inletSensorLowerCriticalThreshold.1.1.rmsCurrent = Gauge32: 0 */ { "unmapped.inletSensorLowerCriticalThreshold", 0, 1, ".1.3.6.1.4.1.13742.6.3.3.4.1.21.1.1.1", NULL, SU_FLAG_OK, NULL }, /* inletSensorLowerCriticalThreshold.1.1.rmsVoltage = Gauge32: 94 */ { "unmapped.inletSensorLowerCriticalThreshold", 0, 1, ".1.3.6.1.4.1.13742.6.3.3.4.1.21.1.1.4", NULL, SU_FLAG_OK, NULL }, /* inletSensorLowerCriticalThreshold.1.1.activePower = Gauge32: 0 */ { "unmapped.inletSensorLowerCriticalThreshold", 0, 1, ".1.3.6.1.4.1.13742.6.3.3.4.1.21.1.1.5", NULL, SU_FLAG_OK, NULL }, /* inletSensorLowerCriticalThreshold.1.1.apparentPower = Gauge32: 0 */ { "unmapped.inletSensorLowerCriticalThreshold", 0, 1, ".1.3.6.1.4.1.13742.6.3.3.4.1.21.1.1.6", NULL, SU_FLAG_OK, NULL }, /* inletSensorLowerCriticalThreshold.1.1.powerFactor = Gauge32: 0 */ { "unmapped.inletSensorLowerCriticalThreshold", 0, 1, ".1.3.6.1.4.1.13742.6.3.3.4.1.21.1.1.7", NULL, SU_FLAG_OK, NULL }, /* inletSensorLowerCriticalThreshold.1.1.activeEnergy = Gauge32: 0 */ { "unmapped.inletSensorLowerCriticalThreshold", 0, 1, ".1.3.6.1.4.1.13742.6.3.3.4.1.21.1.1.8", NULL, SU_FLAG_OK, NULL }, /* inletSensorLowerWarningThreshold.1.1.rmsCurrent = Gauge32: 0 */ { "unmapped.inletSensorLowerWarningThreshold", 0, 1, ".1.3.6.1.4.1.13742.6.3.3.4.1.22.1.1.1", NULL, SU_FLAG_OK, NULL }, /* inletSensorLowerWarningThreshold.1.1.rmsVoltage = Gauge32: 97 */ { "unmapped.inletSensorLowerWarningThreshold", 0, 1, ".1.3.6.1.4.1.13742.6.3.3.4.1.22.1.1.4", NULL, SU_FLAG_OK, NULL }, /* inletSensorLowerWarningThreshold.1.1.activePower = Gauge32: 0 */ { "unmapped.inletSensorLowerWarningThreshold", 0, 1, ".1.3.6.1.4.1.13742.6.3.3.4.1.22.1.1.5", NULL, SU_FLAG_OK, NULL }, /* inletSensorLowerWarningThreshold.1.1.apparentPower = Gauge32: 0 */ { "unmapped.inletSensorLowerWarningThreshold", 0, 1, ".1.3.6.1.4.1.13742.6.3.3.4.1.22.1.1.6", NULL, SU_FLAG_OK, NULL }, /* inletSensorLowerWarningThreshold.1.1.powerFactor = Gauge32: 0 */ { "unmapped.inletSensorLowerWarningThreshold", 0, 1, ".1.3.6.1.4.1.13742.6.3.3.4.1.22.1.1.7", NULL, SU_FLAG_OK, NULL }, /* inletSensorLowerWarningThreshold.1.1.activeEnergy = Gauge32: 0 */ { "unmapped.inletSensorLowerWarningThreshold", 0, 1, ".1.3.6.1.4.1.13742.6.3.3.4.1.22.1.1.8", NULL, SU_FLAG_OK, NULL }, /* inletSensorUpperCriticalThreshold.1.1.rmsCurrent = Gauge32: 128 */ { "unmapped.inletSensorUpperCriticalThreshold", 0, 1, ".1.3.6.1.4.1.13742.6.3.3.4.1.23.1.1.1", NULL, SU_FLAG_OK, NULL }, /* inletSensorUpperCriticalThreshold.1.1.rmsVoltage = Gauge32: 127 */ { "unmapped.inletSensorUpperCriticalThreshold", 0, 1, ".1.3.6.1.4.1.13742.6.3.3.4.1.23.1.1.4", NULL, SU_FLAG_OK, NULL }, /* inletSensorUpperCriticalThreshold.1.1.activePower = Gauge32: 0 */ { "unmapped.inletSensorUpperCriticalThreshold", 0, 1, ".1.3.6.1.4.1.13742.6.3.3.4.1.23.1.1.5", NULL, SU_FLAG_OK, NULL }, /* inletSensorUpperCriticalThreshold.1.1.apparentPower = Gauge32: 0 */ { "unmapped.inletSensorUpperCriticalThreshold", 0, 1, ".1.3.6.1.4.1.13742.6.3.3.4.1.23.1.1.6", NULL, SU_FLAG_OK, NULL }, /* inletSensorUpperCriticalThreshold.1.1.powerFactor = Gauge32: 0 */ { "unmapped.inletSensorUpperCriticalThreshold", 0, 1, ".1.3.6.1.4.1.13742.6.3.3.4.1.23.1.1.7", NULL, SU_FLAG_OK, NULL }, /* inletSensorUpperCriticalThreshold.1.1.activeEnergy = Gauge32: 0 */ { "unmapped.inletSensorUpperCriticalThreshold", 0, 1, ".1.3.6.1.4.1.13742.6.3.3.4.1.23.1.1.8", NULL, SU_FLAG_OK, NULL }, /* inletSensorUpperWarningThreshold.1.1.rmsCurrent = Gauge32: 104 */ { "unmapped.inletSensorUpperWarningThreshold", 0, 1, ".1.3.6.1.4.1.13742.6.3.3.4.1.24.1.1.1", NULL, SU_FLAG_OK, NULL }, /* inletSensorUpperWarningThreshold.1.1.rmsVoltage = Gauge32: 124 */ { "unmapped.inletSensorUpperWarningThreshold", 0, 1, ".1.3.6.1.4.1.13742.6.3.3.4.1.24.1.1.4", NULL, SU_FLAG_OK, NULL }, /* inletSensorUpperWarningThreshold.1.1.activePower = Gauge32: 0 */ { "unmapped.inletSensorUpperWarningThreshold", 0, 1, ".1.3.6.1.4.1.13742.6.3.3.4.1.24.1.1.5", NULL, SU_FLAG_OK, NULL }, /* inletSensorUpperWarningThreshold.1.1.apparentPower = Gauge32: 0 */ { "unmapped.inletSensorUpperWarningThreshold", 0, 1, ".1.3.6.1.4.1.13742.6.3.3.4.1.24.1.1.6", NULL, SU_FLAG_OK, NULL }, /* inletSensorUpperWarningThreshold.1.1.powerFactor = Gauge32: 0 */ { "unmapped.inletSensorUpperWarningThreshold", 0, 1, ".1.3.6.1.4.1.13742.6.3.3.4.1.24.1.1.7", NULL, SU_FLAG_OK, NULL }, /* inletSensorUpperWarningThreshold.1.1.activeEnergy = Gauge32: 0 */ { "unmapped.inletSensorUpperWarningThreshold", 0, 1, ".1.3.6.1.4.1.13742.6.3.3.4.1.24.1.1.8", NULL, SU_FLAG_OK, NULL }, /* inletSensorEnabledThresholds.1.1.rmsCurrent = BITS: 30 upperWarning(2) upperCritical(3) */ { "unmapped.inletSensorEnabledThresholds", 0, 1, ".1.3.6.1.4.1.13742.6.3.3.4.1.25.1.1.1", NULL, SU_FLAG_OK, NULL }, /* inletSensorEnabledThresholds.1.1.rmsVoltage = BITS: F0 lowerCritical(0) lowerWarning(1) upperWarning(2) upperCritical(3) */ { "unmapped.inletSensorEnabledThresholds", 0, 1, ".1.3.6.1.4.1.13742.6.3.3.4.1.25.1.1.4", NULL, SU_FLAG_OK, NULL }, /* inletSensorEnabledThresholds.1.1.activePower = BITS: 00 */ { "unmapped.inletSensorEnabledThresholds", 0, 1, ".1.3.6.1.4.1.13742.6.3.3.4.1.25.1.1.5", NULL, SU_FLAG_OK, NULL }, /* inletSensorEnabledThresholds.1.1.apparentPower = BITS: 00 */ { "unmapped.inletSensorEnabledThresholds", 0, 1, ".1.3.6.1.4.1.13742.6.3.3.4.1.25.1.1.6", NULL, SU_FLAG_OK, NULL }, /* inletSensorEnabledThresholds.1.1.powerFactor = BITS: 00 */ { "unmapped.inletSensorEnabledThresholds", 0, 1, ".1.3.6.1.4.1.13742.6.3.3.4.1.25.1.1.7", NULL, SU_FLAG_OK, NULL }, /* inletSensorEnabledThresholds.1.1.activeEnergy = BITS: 00 */ { "unmapped.inletSensorEnabledThresholds", 0, 1, ".1.3.6.1.4.1.13742.6.3.3.4.1.25.1.1.8", NULL, SU_FLAG_OK, NULL }, /* outletPoleCount.1.{1-24} = INTEGER: 2 */ { "unmapped.outletPoleCount", 0, 1, ".1.3.6.1.4.1.13742.6.3.5.3.1.5.1.1", NULL, SU_FLAG_OK, NULL }, /* outletRatedVoltage.1.{1-24} = STRING: 100-120V */ { "unmapped.outletRatedVoltage", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.13742.6.3.5.3.1.6.1.1", NULL, SU_FLAG_OK, NULL }, /* outletRatedCurrent.1.{1-24} = STRING: 16A */ { "unmapped.outletRatedCurrent", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.13742.6.3.5.3.1.7.1.1", NULL, SU_FLAG_OK, NULL }, /* outletDeviceCapabilities.1.{1-24} = BITS: 9F 04 00 00 00 00 rmsCurrent(0) rmsVoltage(3) activePower(4) apparentPower(5) powerFactor(6) activeEnergy(7) onOff(13) */ { "unmapped.outletDeviceCapabilities", 0, 1, ".1.3.6.1.4.1.13742.6.3.5.3.1.10.1.1", NULL, SU_FLAG_OK, NULL }, /* outletPowerCyclingPowerOffPeriod.1.{1-24} = Gauge32: 10 */ { "unmapped.outletPowerCyclingPowerOffPeriod", 0, 1, ".1.3.6.1.4.1.13742.6.3.5.3.1.12.1.1", NULL, SU_FLAG_OK, NULL }, /* outletStateOnStartup.1.{1-24} = INTEGER: globalOutletStateOnStartup(3) */ { "unmapped.outletStateOnStartup", 0, 1, ".1.3.6.1.4.1.13742.6.3.5.3.1.13.1.1", NULL, SU_FLAG_OK, NULL }, /* outletUseGlobalPowerCyclingPowerOffPeriod.1.{1-24} = INTEGER: true(1) */ { "unmapped.outletUseGlobalPowerCyclingPowerOffPeriod", 0, 1, ".1.3.6.1.4.1.13742.6.3.5.3.1.14.1.1", NULL, SU_FLAG_OK, NULL }, /* outletReceptacleDescriptor.1.{1-24} = STRING: NEMA 5-20R */ { "unmapped.outletReceptacleDescriptor", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.13742.6.3.5.3.1.29.1.1", NULL, SU_FLAG_OK, NULL }, /* outletNonCritical.1.{1-24} = INTEGER: false(2) */ { "unmapped.outletNonCritical", 0, 1, ".1.3.6.1.4.1.13742.6.3.5.3.1.30.1.1", NULL, SU_FLAG_OK, NULL }, /* outletSequenceDelay.1.{1-24} = Gauge32: 0 */ { "unmapped.outletSequenceDelay", 0, 1, ".1.3.6.1.4.1.13742.6.3.5.3.1.32.1.%i", NULL, SU_FLAG_OK, NULL }, /* outletSensorLogAvailable.1.{1-24}.rmsCurrent = INTEGER: true(1) */ { "unmapped.outletSensorLogAvailable", 0, 1, ".1.3.6.1.4.1.13742.6.3.5.4.1.4.1.%i.1", NULL, SU_FLAG_OK, NULL }, /* outletSensorLogAvailable.1.{1-24}.rmsVoltage = INTEGER: true(1) */ { "unmapped.outletSensorLogAvailable", 0, 1, ".1.3.6.1.4.1.13742.6.3.5.4.1.4.1.%i.4", NULL, SU_FLAG_OK, NULL }, /* outletSensorLogAvailable.1.{1-24}.activePower = INTEGER: true(1) */ { "unmapped.outletSensorLogAvailable", 0, 1, ".1.3.6.1.4.1.13742.6.3.5.4.1.4.1.%i.5", NULL, SU_FLAG_OK, NULL }, /* outletSensorLogAvailable.1.{1-24}.apparentPower = INTEGER: true(1) */ { "unmapped.outletSensorLogAvailable", 0, 1, ".1.3.6.1.4.1.13742.6.3.5.4.1.4.1.%i.6", NULL, SU_FLAG_OK, NULL }, /* outletSensorLogAvailable.1.{1-24}.powerFactor = INTEGER: true(1) */ { "unmapped.outletSensorLogAvailable", 0, 1, ".1.3.6.1.4.1.13742.6.3.5.4.1.4.1.%i.7", NULL, SU_FLAG_OK, NULL }, /* outletSensorLogAvailable.1.{1-24}.activeEnergy = INTEGER: true(1) */ { "unmapped.outletSensorLogAvailable", 0, 1, ".1.3.6.1.4.1.13742.6.3.5.4.1.4.1.%i.8", NULL, SU_FLAG_OK, NULL }, /* outletSensorLogAvailable.1.{1-24}.onOff = INTEGER: true(1) */ { "unmapped.outletSensorLogAvailable", 0, 1, ".1.3.6.1.4.1.13742.6.3.5.4.1.4.1.%i.14", NULL, SU_FLAG_OK, NULL }, /* outletSensorUnits.1.{1-24}.rmsCurrent = INTEGER: amp(2) */ { "unmapped.outletSensorUnits", 0, 1, ".1.3.6.1.4.1.13742.6.3.5.4.1.6.1.%i.1", NULL, SU_FLAG_OK, NULL }, /* outletSensorUnits.1.{1-24}.rmsVoltage = INTEGER: volt(1) */ { "unmapped.outletSensorUnits", 0, 1, ".1.3.6.1.4.1.13742.6.3.5.4.1.6.1.%i.4", NULL, SU_FLAG_OK, NULL }, /* outletSensorUnits.1.{1-24}.activePower = INTEGER: watt(3) */ { "unmapped.outletSensorUnits", 0, 1, ".1.3.6.1.4.1.13742.6.3.5.4.1.6.1.%i.5", NULL, SU_FLAG_OK, NULL }, /* outletSensorUnits.1.{1-24}.apparentPower = INTEGER: voltamp(4) */ { "unmapped.outletSensorUnits", 0, 1, ".1.3.6.1.4.1.13742.6.3.5.4.1.6.1.%i.6", NULL, SU_FLAG_OK, NULL }, /* outletSensorUnits.1.{1-24}.powerFactor = INTEGER: none(-1) */ { "unmapped.outletSensorUnits", 0, 1, ".1.3.6.1.4.1.13742.6.3.5.4.1.6.1.%i.7", NULL, SU_FLAG_OK, NULL }, /* outletSensorUnits.1.{1-24}.activeEnergy = INTEGER: wattHour(5) */ { "unmapped.outletSensorUnits", 0, 1, ".1.3.6.1.4.1.13742.6.3.5.4.1.6.1.%i.8", NULL, SU_FLAG_OK, NULL }, /* outletSensorUnits.1.{1-24}.onOff = INTEGER: none(-1) */ { "unmapped.outletSensorUnits", 0, 1, ".1.3.6.1.4.1.13742.6.3.5.4.1.6.1.%i.14", NULL, SU_FLAG_OK, NULL }, /* outletSensorDecimalDigits.1.{1-24}.rmsCurrent = Gauge32: 1 */ { "unmapped.outletSensorDecimalDigits", 0, 1, ".1.3.6.1.4.1.13742.6.3.5.4.1.7.1.%i.1", NULL, SU_FLAG_OK, NULL }, /* outletSensorDecimalDigits.1.{1-24}.rmsVoltage = Gauge32: 0 */ { "unmapped.outletSensorDecimalDigits", 0, 1, ".1.3.6.1.4.1.13742.6.3.5.4.1.7.1.%i.4", NULL, SU_FLAG_OK, NULL }, /* outletSensorDecimalDigits.1.{1-24}.activePower = Gauge32: 0 */ { "unmapped.outletSensorDecimalDigits", 0, 1, ".1.3.6.1.4.1.13742.6.3.5.4.1.7.1.%i.5", NULL, SU_FLAG_OK, NULL }, /* outletSensorDecimalDigits.1.{1-24}.apparentPower = Gauge32: 0 */ { "unmapped.outletSensorDecimalDigits", 0, 1, ".1.3.6.1.4.1.13742.6.3.5.4.1.7.1.%i.6", NULL, SU_FLAG_OK, NULL }, /* outletSensorDecimalDigits.1.{1-24}.powerFactor = Gauge32: 2 */ { "unmapped.outletSensorDecimalDigits", 0, 1, ".1.3.6.1.4.1.13742.6.3.5.4.1.7.1.%i.7", NULL, SU_FLAG_OK, NULL }, /* outletSensorDecimalDigits.1.{1-24}.activeEnergy = Gauge32: 0 */ { "unmapped.outletSensorDecimalDigits", 0, 1, ".1.3.6.1.4.1.13742.6.3.5.4.1.7.1.%i.8", NULL, SU_FLAG_OK, NULL }, /* outletSensorDecimalDigits.1.{1-24}.onOff = Gauge32: 0 */ { "unmapped.outletSensorDecimalDigits", 0, 1, ".1.3.6.1.4.1.13742.6.3.5.4.1.7.1.%i.14", NULL, SU_FLAG_OK, NULL }, /* outletSensorAccuracy.1.{1-24}.rmsCurrent = Gauge32: 100 */ { "unmapped.outletSensorAccuracy", 0, 1, ".1.3.6.1.4.1.13742.6.3.5.4.1.8.1.%i.1", NULL, SU_FLAG_OK, NULL }, /* outletSensorAccuracy.1.{1-24}.rmsVoltage = Gauge32: 100 */ { "unmapped.outletSensorAccuracy", 0, 1, ".1.3.6.1.4.1.13742.6.3.5.4.1.8.1.%i.4", NULL, SU_FLAG_OK, NULL }, /* outletSensorAccuracy.1.{1-24}.activePower = Gauge32: 300 */ { "unmapped.outletSensorAccuracy", 0, 1, ".1.3.6.1.4.1.13742.6.3.5.4.1.8.1.%i.5", NULL, SU_FLAG_OK, NULL }, /* outletSensorAccuracy.1.{1-24}.apparentPower = Gauge32: 200 */ { "unmapped.outletSensorAccuracy", 0, 1, ".1.3.6.1.4.1.13742.6.3.5.4.1.8.1.%i.6", NULL, SU_FLAG_OK, NULL }, /* outletSensorAccuracy.1.{1-24}.powerFactor = Gauge32: 100 */ { "unmapped.outletSensorAccuracy", 0, 1, ".1.3.6.1.4.1.13742.6.3.5.4.1.8.1.%i.7", NULL, SU_FLAG_OK, NULL }, /* outletSensorAccuracy.1.{1-24}.activeEnergy = Gauge32: 100 */ { "unmapped.outletSensorAccuracy", 0, 1, ".1.3.6.1.4.1.13742.6.3.5.4.1.8.1.%i.8", NULL, SU_FLAG_OK, NULL }, /* outletSensorAccuracy.1.{1-24}.onOff = Gauge32: 0 */ { "unmapped.outletSensorAccuracy", 0, 1, ".1.3.6.1.4.1.13742.6.3.5.4.1.8.1.%i.14", NULL, SU_FLAG_OK, NULL }, /* outletSensorResolution.1.{1-24}.rmsCurrent = Gauge32: 1 */ { "unmapped.outletSensorResolution", 0, 1, ".1.3.6.1.4.1.13742.6.3.5.4.1.9.1.%i.1", NULL, SU_FLAG_OK, NULL }, /* outletSensorResolution.1.{1-24}.rmsVoltage = Gauge32: 1 */ { "unmapped.outletSensorResolution", 0, 1, ".1.3.6.1.4.1.13742.6.3.5.4.1.9.1.%i.4", NULL, SU_FLAG_OK, NULL }, /* outletSensorResolution.1.{1-24}.activePower = Gauge32: 1 */ { "unmapped.outletSensorResolution", 0, 1, ".1.3.6.1.4.1.13742.6.3.5.4.1.9.1.%i.5", NULL, SU_FLAG_OK, NULL }, /* outletSensorResolution.1.{1-24}.apparentPower = Gauge32: 1 */ { "unmapped.outletSensorResolution", 0, 1, ".1.3.6.1.4.1.13742.6.3.5.4.1.9.1.%i.6", NULL, SU_FLAG_OK, NULL }, /* outletSensorResolution.1.{1-24}.powerFactor = Gauge32: 1 */ { "unmapped.outletSensorResolution", 0, 1, ".1.3.6.1.4.1.13742.6.3.5.4.1.9.1.%i.7", NULL, SU_FLAG_OK, NULL }, /* outletSensorResolution.1.{1-24}.activeEnergy = Gauge32: 1 */ { "unmapped.outletSensorResolution", 0, 1, ".1.3.6.1.4.1.13742.6.3.5.4.1.9.1.%i.8", NULL, SU_FLAG_OK, NULL }, /* outletSensorResolution.1.{1-24}.onOff = Gauge32: 0 */ { "unmapped.outletSensorResolution", 0, 1, ".1.3.6.1.4.1.13742.6.3.5.4.1.9.1.%i.14", NULL, SU_FLAG_OK, NULL }, /* end of interesting data * the rest is 18MB of verbose log and satellite data */ /* Note: All reliabilityXXX data were removed */ #endif /* WITH_UNMAPPED_DATA_POINTS */ #endif /* DEBUG || WITH_UNMAPPED_DATA_POINTS */ /* end of structure. */ { NULL, 0, 0, NULL, NULL, 0, NULL } }; mib2nut_info_t raritan_px2 = { "raritan-px2", RARITAN_PX2_MIB_VERSION, NULL, RARITAN_PX2_OID_MODEL_NAME, raritan_px2_mib, RARITAN_PX2_MIB_SYSOID, NULL }; nut-2.8.1/drivers/apc-pdu-mib.h0000644000175000017500000000212314377374134013211 00000000000000/* powernet-mib-mib.h - subdriver to monitor PowerNet-MIB SNMP devices with NUT * * Copyright (C) * 2011 - 2012 Arnaud Quette * * 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 2 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, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef APC_PDU_MIB_H #define APC_PDU_MIB_H #include "main.h" #include "snmp-ups.h" extern mib2nut_info_t apc_pdu_rpdu; extern mib2nut_info_t apc_pdu_rpdu2; extern mib2nut_info_t apc_pdu_msp; #endif /* APC_PDU_MIB_H */ nut-2.8.1/drivers/openups-hid.h0000644000175000017500000000241014273170601013331 00000000000000/* openups-hid.h - subdriver to monitor Minibox openUPS USB/HID devices with NUT * * Copyright (C) * 2003 - 2009 Arnaud Quette * 2005 - 2006 Peter Selinger * 2008 - 2009 Arjen de Korte * 2012 Nicu Pavel * * 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 2 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, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef OPENUPS_HID_H #define OPENUPS_HID_H #include "usbhid-ups.h" /* Don't put non-extern definitions here - this file gets included by usbhid-ups.c */ extern subdriver_t openups_subdriver; #endif /* OPENUPS_HID_H */ nut-2.8.1/drivers/xppc-mib.c0000644000175000017500000001246714500336654012632 00000000000000/* xppc-mib.c - subdriver to monitor XPPC SNMP devices with NUT * * Copyright (C) * 2011 - 2012 Arnaud Quette * 2014 Charles Lepple * * Note: this subdriver was initially generated as a "stub" by the * scripts/subdriver/gen-snmp-subdriver.sh script. * * 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 2 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, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "xppc-mib.h" #define XPPC_MIB_VERSION "0.4" #define XPPC_SYSOID ".1.3.6.1.4.1.935" /* To create a value lookup structure (as needed on the 2nd line of the example * below), use the following kind of declaration, outside of the present snmp_info_t[]: * static info_lkp_t xpcc_onbatt_info[] = { * { 1, "OB", NULL, NULL }, * { 2, "OL", NULL, NULL }, * { 0, NULL, NULL, NULL } * }; */ /* upsBaseBatteryStatus */ static info_lkp_t xpcc_onbatt_info[] = { { 1, "", NULL, NULL }, /* unknown */ { 2, "", NULL, NULL }, /* batteryNormal */ { 3, "LB", NULL, NULL }, /* batteryLow */ { 0, NULL, NULL, NULL } }; /* upsBaseOutputStatus OBJECT-TYPE SYNTAX INTEGER { unknown(1), onLine(2), onBattery(3), onBoost(4), sleeping(5), onBypass(6), rebooting(7), standBy(8), onBuck(9) } */ static info_lkp_t xpcc_power_info[] = { { 1, "", NULL, NULL }, /* unknown */ { 2, "OL", NULL, NULL }, /* onLine */ { 3, "OB", NULL, NULL }, /* onBattery */ { 4, "OL BOOST", NULL, NULL }, /* onBoost */ { 5, "OFF", NULL, NULL }, /* sleeping */ { 6, "BYPASS", NULL, NULL }, /* onBypass */ { 7, "", NULL, NULL }, /* rebooting */ { 8, "OFF", NULL, NULL }, /* standBy */ { 9, "OL TRIM", NULL, NULL }, /* onBuck */ { 0, NULL, NULL, NULL } }; /* XPPC Snmp2NUT lookup table */ static snmp_info_t xppc_mib[] = { /* Data format: * { info_type, info_flags, info_len, OID, dfl, flags, oid2info, setvar }, * * info_type: NUT INFO_ or CMD_ element name * info_flags: flags to set in addinfo * info_len: length of strings if STR * cmd value if CMD, multiplier otherwise * OID: SNMP OID or NULL * dfl: default value * flags: snmp-ups internal flags (FIXME: ...) * oid2info: lookup table between OID and NUT values * * Example: * { "input.voltage", 0, 0.1, ".1.3.6.1.4.1.705.1.6.2.1.2.1", "", SU_INPUT_1, NULL }, * { "ups.status", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.705.1.7.3.0", "", SU_FLAG_OK | SU_STATUS_BATT, xpcc_onbatt_info }, * * To create a value lookup structure (as needed on the 2nd line), use the * following kind of declaration, outside of the present snmp_info_t[]: * static info_lkp_t xpcc_onbatt_info[] = { * { 1, "OB" }, * { 2, "OL" }, * { 0, NULL } * }; */ /* standard MIB items */ { "device.description", ST_FLAG_STRING | ST_FLAG_RW, SU_INFOSIZE, ".1.3.6.1.2.1.1.1.0", NULL, SU_FLAG_OK, NULL }, { "device.contact", ST_FLAG_STRING | ST_FLAG_RW, SU_INFOSIZE, ".1.3.6.1.2.1.1.4.0", NULL, SU_FLAG_OK, NULL }, { "device.location", ST_FLAG_STRING | ST_FLAG_RW, SU_INFOSIZE, ".1.3.6.1.2.1.1.6.0", NULL, SU_FLAG_OK, NULL }, { "ups.mfr", ST_FLAG_STRING, SU_INFOSIZE, NULL, "Tripp Lite / Phoenixtec", SU_FLAG_STATIC | SU_FLAG_ABSENT | SU_FLAG_OK, NULL }, /* upsBaseIdentModel.0 = STRING: "Intelligent" */ { "ups.model", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.935.1.1.1.1.1.1.0", "Generic Phoenixtec SNMP device", SU_FLAG_OK, NULL }, /* upsBaseBatteryStatus.0 = INTEGER: batteryNormal(2) */ { "ups.status", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.935.1.1.1.2.1.1.0", "", SU_STATUS_BATT | SU_TYPE_INT | SU_FLAG_OK, xpcc_onbatt_info }, /* upsSmartBatteryCapacity.0 = INTEGER: 100 */ { "battery.charge", 0, 1, ".1.3.6.1.4.1.935.1.1.1.2.2.1.0", NULL, SU_TYPE_INT | SU_FLAG_OK, NULL }, /* upsSmartBatteryTemperature.0 = INTEGER: 260 */ { "ups.temperature", 0, 0.1, ".1.3.6.1.4.1.935.1.1.1.2.2.3.0", NULL, SU_TYPE_INT | SU_FLAG_OK, NULL }, /* upsSmartInputLineVoltage.0 = INTEGER: 1998 */ { "input.voltage", 0, 0.1, ".1.3.6.1.4.1.935.1.1.1.3.2.1.0", NULL, SU_TYPE_INT | SU_FLAG_OK, NULL }, /* upsBaseOutputStatus.0 = INTEGER: onLine(2) */ { "ups.status", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.935.1.1.1.4.1.1.0", "", SU_TYPE_INT | SU_STATUS_PWR, xpcc_power_info }, /* upsSmartOutputVoltage.0 = INTEGER: 2309 */ { "output.voltage", 0, 0.1, ".1.3.6.1.4.1.935.1.1.1.4.2.1.0", NULL, SU_TYPE_INT | SU_FLAG_OK, NULL }, /* upsSmartOutputFrequency.0 = INTEGER: 500 */ { "output.frequency", 0, 0.1, ".1.3.6.1.4.1.935.1.1.1.4.2.2.0", NULL, SU_TYPE_INT | SU_FLAG_OK, NULL }, /* upsSmartOutputLoad.0 = INTEGER: 7 */ { "ups.load", 0, 1, ".1.3.6.1.4.1.935.1.1.1.4.2.3.0", NULL, SU_TYPE_INT | SU_FLAG_OK, NULL }, /* end of structure. */ { NULL, 0, 0, NULL, NULL, 0, NULL } }; mib2nut_info_t xppc = { "xppc", XPPC_MIB_VERSION, NULL, NULL, xppc_mib, XPPC_SYSOID, NULL }; nut-2.8.1/drivers/asem.c0000644000175000017500000003364514501607135012035 00000000000000/* asem.c - driver for ASEM PB 1300 hardware, accessible through i2c. Copyright (C) 2014 Giuseppe Corbelli 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 2 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, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ASEM SPA contributed with support and documentation. Copan Italia SPA funded the development. There are 2 versions of the charger. Older one is based on Max1667, newer one is a custom solution. Both are on address 0x09. To be compatible with both versions just read bit 15 of address 0x13 to have online/on battery status. Battery monitor is a BQ2060 at address 0x0B. Beware that the SystemIO memory used by the i2c controller is reserved by ACPI. On Linux, as of 3.5.x kernel only a native driver (i2c_i801) is available, so you need to boot with acpi_enforce_resources=lax option. */ #include "main.h" #include #include #include /* Depends on i2c-dev.h, Linux only * Linux I2C userland is a bit of a mess until distros refresh to * the i2c-tools 4.x release that profides i2c/smbus.h for userspace * instead of (re)using linux/i2c-dev.h, which conflicts with a * kernel header of the same name. * * See: * https://i2c.wiki.kernel.org/index.php/Plans_for_I2C_Tools_4 */ #if HAVE_LINUX_SMBUS_H # include #endif #if HAVE_LINUX_I2C_DEV_H # include /* for I2C_SLAVE */ # if !HAVE_LINUX_SMBUS_H # ifndef I2C_FUNC_I2C # include # endif # endif #endif #include #ifndef __STR__ # define __STR__(x) #x #endif #ifndef __XSTR__ # define __XSTR__(x) __STR__(x) #endif #define DRIVER_NAME "ASEM" #define DRIVER_VERSION "0.12" /* Valid on ASEM PB1300 UPS */ #define BQ2060_ADDRESS 0x0B #define CHARGER_ADDRESS 0x09 #define CMD_DEVICENAME 0x21 #define LOW_BATTERY_THRESHOLD 25 #define HIGH_BATTERY_THRESHOLD 75 #define ACCESS_DEVICE(fd, address) \ if (ioctl(fd, I2C_SLAVE, address) < 0) { \ fatal_with_errno(EXIT_FAILURE, "Failed to acquire bus access and/or talk to i2c slave 0x%02X", address); \ } static unsigned long lb_threshold = LOW_BATTERY_THRESHOLD; static unsigned long hb_threshold = HIGH_BATTERY_THRESHOLD; static char *valid_devicename_data[] = { "ASEM SPA", NULL }; upsdrv_info_t upsdrv_info = { DRIVER_NAME, DRIVER_VERSION, "Giuseppe Corbelli ", DRV_EXPERIMENTAL, {NULL} }; void upsdrv_initinfo(void) { __s32 i2c_status; __u8 buffer[10]; unsigned short year, month, day; #if (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_PUSH_POP) && (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_EXTRA_SEMI_STMT) # pragma GCC diagnostic push #endif #ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_EXTRA_SEMI_STMT # pragma GCC diagnostic ignored "-Wextra-semi-stmt" #endif /* Current definition of this macro ends with a brace; * we keep the useless trailing ";" for readability */ ACCESS_DEVICE(upsfd, BQ2060_ADDRESS); #if (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_PUSH_POP) && (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_EXTRA_SEMI_STMT) # pragma GCC diagnostic pop #endif /* Set capacity mode in mA(h) */ i2c_status = i2c_smbus_read_word_data(upsfd, 0x03); if (i2c_status == -1) { fatal_with_errno(EXIT_FAILURE, "Could not read BatteryMode word data"); } /* Clear 15th bit */ i2c_status = i2c_smbus_write_word_data(upsfd, 0x03, i2c_status & ~0x8000); if (i2c_status == -1) { fatal_with_errno(EXIT_FAILURE, "Could not set BatteryMode word data"); } /* Device name */ memset(buffer, 0, 10); i2c_status = i2c_smbus_read_block_data(upsfd, 0x21, buffer); if (i2c_status == -1) { fatal_with_errno(EXIT_FAILURE, "Could not read DeviceName block data"); } upsdebugx(1, "UPS model %s", (char *) buffer); dstate_setinfo("ups.model", "%s", (char *) buffer); /* Manufacturing date */ i2c_status = i2c_smbus_read_word_data(upsfd, 0x1B); if (i2c_status == -1) { fatal_with_errno(EXIT_FAILURE, "Could not read ManufactureDate word data"); } /* (Year - 1980) * 512 */ year = (i2c_status >> 9) & 0x000000FF; /* Month * 32 */ month = (i2c_status >> 4) & 0x0000001F; day = i2c_status & 0x0000001F; upsdebugx(1, "UPS manufacturing date %d-%02d-%02d (%d)", year + 1980, month, day, i2c_status); dstate_setinfo("ups.mfr.date", "%d-%02d-%02d", year + 1980, month, day); /* Device chemistry */ memset(buffer, 0, 10); i2c_status = i2c_smbus_read_block_data(upsfd, 0x22, buffer); if (i2c_status == -1) { fatal_with_errno(EXIT_FAILURE, "Could not read DeviceChemistry block data"); } upsdebugx(1, "Battery chemistry %s", (char *) buffer); dstate_setinfo("battery.type", "%s", (char *) buffer); /* Serial number */ i2c_status = i2c_smbus_read_word_data(upsfd, 0x1C); if (i2c_status == -1) { fatal_with_errno(EXIT_FAILURE, "Could not read SerialNumber block data"); } upsdebugx(1, "Serial Number %d", i2c_status); dstate_setinfo("ups.serial", "%d", i2c_status); } void upsdrv_updateinfo(void) { static char online; static char discharging; static char fully_charged; static unsigned short charge_percentage; static unsigned short voltage; static unsigned short capacity; static signed short current; static __s32 i2c_status; static __s32 temperature; static __s32 runtime_to_empty; #if (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_PUSH_POP) && (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_EXTRA_SEMI_STMT) # pragma GCC diagnostic push #endif #ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_EXTRA_SEMI_STMT # pragma GCC diagnostic ignored "-Wextra-semi-stmt" #endif /* Current definition of this macro ends with a brace; * we keep the useless trailing ";" for readability */ ACCESS_DEVICE(upsfd, CHARGER_ADDRESS); #if (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_PUSH_POP) && (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_EXTRA_SEMI_STMT) # pragma GCC diagnostic pop #endif /* Charger only supplies online/offline status */ i2c_status = i2c_smbus_read_word_data(upsfd, 0x13); if (i2c_status == -1) { dstate_datastale(); upslogx(LOG_ERR, "Could not read charger status word at address 0x13"); return; } online = (i2c_status & 0x8000) != 0; upsdebugx(3, "Charger status 0x%02X, online %d", i2c_status, online); #if (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_PUSH_POP) && (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_EXTRA_SEMI_STMT) # pragma GCC diagnostic push #endif #ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_EXTRA_SEMI_STMT # pragma GCC diagnostic ignored "-Wextra-semi-stmt" #endif /* Current definition of this macro ends with a brace; * we keep the useless trailing ";" for readability */ ACCESS_DEVICE(upsfd, BQ2060_ADDRESS); #if (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_PUSH_POP) && (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_EXTRA_SEMI_STMT) # pragma GCC diagnostic pop #endif i2c_status = i2c_smbus_read_word_data(upsfd, 0x16); if (i2c_status == -1) { dstate_datastale(); upslogx(LOG_ERR, "Could not read bq2060 status word at address 0x16"); return; } upsdebugx(3, "bq2060 status 0x04%X", i2c_status); /* Busy, leave data as stale, try next time */ if (i2c_status & 0x0001) { dstate_datastale(); upslogx(LOG_NOTICE, "bq2060 is busy"); return; } /* Error, leave data as stale, try next time */ if (i2c_status & 0x000F) { dstate_datastale(); upslogx(LOG_WARNING, "bq2060 returned error code 0x%02X", i2c_status & 0x000F); return; } discharging = (i2c_status & 0x0040); fully_charged = (i2c_status & 0x0020); /* Charge percentage */ i2c_status = i2c_smbus_read_word_data(upsfd, 0x0D); if (i2c_status == -1) { dstate_datastale(); upslogx(LOG_ERR, "Could not read charge percentage from bq2060 at address 0x0D"); return; } charge_percentage = i2c_status & 0xFFFF; upsdebugx(3, "Charge percentage %03d", charge_percentage); /* Battery voltage in mV */ i2c_status = i2c_smbus_read_word_data(upsfd, 0x09); if (i2c_status == -1) { dstate_datastale(); upslogx(LOG_ERR, "Could not read voltage from bq2060 at address 0x09"); return; } voltage = i2c_status & 0x0000FFFF; upsdebugx(3, "Battery voltage %d mV", voltage); /* Temperature in °K */ temperature = i2c_smbus_read_word_data(upsfd, 0x08); if (temperature == -1) { dstate_datastale(); upslogx(LOG_ERR, "Could not read temperature from bq2060 at address 0x08"); return; } upsdebugx(3, "Temperature %4.1f K", temperature / 10.0); /* Current load in mA, positive for charge, negative for discharge */ i2c_status = i2c_smbus_read_word_data(upsfd, 0x0A); if (i2c_status == -1) { dstate_datastale(); upslogx(LOG_ERR, "Could not read current from bq2060 at address 0x0A"); return; } current = i2c_status & 0x0000FFFF; upsdebugx(3, "Current %d mA", current); /* Current capacity */ i2c_status = i2c_smbus_read_word_data(upsfd, 0x0F); if (i2c_status == -1) { dstate_datastale(); upslogx(LOG_ERR, "Could not read RemainingCapacity word data"); return; } capacity = i2c_status & 0x0000FFFF; upsdebugx(3, "Current capacity %d mAh", capacity); /* Expected runtime capacity, averaged by gauge */ runtime_to_empty = i2c_smbus_read_word_data(upsfd, 0x12); if (runtime_to_empty == -1) { dstate_datastale(); upslogx(LOG_ERR, "Could not read AverageTimeToEmpty word data"); return; } upsdebugx(3, "Expected run-time to empty %d m", runtime_to_empty); status_init(); status_set(online ? "OL" : "OB"); if (!discharging && !fully_charged) status_set("CHRG"); else if (discharging && current < 0) status_set("DISCHRG"); if (charge_percentage >= hb_threshold) status_set("HB"); else if (charge_percentage <= lb_threshold) status_set("LB"); /* In V */ dstate_setinfo("battery.voltage", "%2.3f", voltage / 1000.0); /* In mAh */ dstate_setinfo("battery.current", "%2.3f", current / 1000.0); dstate_setinfo("battery.charge", "%d", charge_percentage); /* In mAh */ dstate_setinfo("battery.capacity", "%2.3f", capacity / 1000.0); /* In °C */ dstate_setinfo("ups.temperature", "%4.1f", (temperature / 10.0) - 273.15); /* In seconds */ dstate_setinfo("battery.runtime", "%d", runtime_to_empty * 60); status_commit(); dstate_dataok(); } void upsdrv_shutdown(void) { /* tell the UPS to shut down, then return - DO NOT SLEEP HERE */ /* maybe try to detect the UPS here, but try a shutdown even if it doesn't respond at first if possible */ /* replace with a proper shutdown function */ upslogx(LOG_ERR, "shutdown not supported"); set_exit_flag(-1); /* you may have to check the line status since the commands for toggling power are frequently different for OL vs. OB */ /* OL: this must power cycle the load if possible */ /* OB: the load must remain off until the power returns */ } void upsdrv_help(void) { /* Redundant */ printf("\nASEM options\n"); printf(" HIGH/low battery thresholds\n"); printf(" lb = " __XSTR__(LOW_BATTERY_THRESHOLD) " (battery is low under this level)\n"); printf(" hb = " __XSTR__(HIGH_BATTERY_THRESHOLD) " (battery is high above this level)\n"); } /* list flags and values that you want to receive via -x */ void upsdrv_makevartable(void) { addvar(VAR_VALUE, "lb", "Low battery threshold, default " __XSTR__(LOW_BATTERY_THRESHOLD)); addvar(VAR_VALUE, "hb", "High battery threshold, default " __XSTR__(HIGH_BATTERY_THRESHOLD)); } void upsdrv_initups(void) { __s32 i2c_status; __u8 DeviceName_buffer[10]; unsigned int i; unsigned long x; char *DeviceName; char *option; upsfd = open(device_path, O_RDWR); if (upsfd < 0) { fatal_with_errno(EXIT_FAILURE, "Could not open device port '%s'", device_path); } #if (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_PUSH_POP) && (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_EXTRA_SEMI_STMT) # pragma GCC diagnostic push #endif #ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_EXTRA_SEMI_STMT # pragma GCC diagnostic ignored "-Wextra-semi-stmt" #endif /* Current definition of this macro ends with a brace; * we keep the useless trailing ";" for readability */ ACCESS_DEVICE(upsfd, BQ2060_ADDRESS); #if (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_PUSH_POP) && (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_EXTRA_SEMI_STMT) # pragma GCC diagnostic pop #endif /* Get ManufacturerName */ memset(DeviceName_buffer, 0, 10); i2c_status = i2c_smbus_read_block_data(upsfd, 0x20, DeviceName_buffer); if (i2c_status == -1) { fatal_with_errno(EXIT_FAILURE, "Could not read DeviceName block data"); } i = 0; while ( (DeviceName = valid_devicename_data[i++]) ) { if (0 == memcmp(DeviceName, DeviceName_buffer, i2c_status)) break; } if (!DeviceName) { fatal_with_errno(EXIT_FAILURE, "Device '%s' unknown", (char *) DeviceName_buffer); } upsdebugx(1, "Found device '%s' on port '%s'", (char *) DeviceName, device_path); dstate_setinfo("ups.mfr", "%s", (char *) DeviceName); option = getval("lb"); if (option) { x = strtoul(option, NULL, 0); if ((x == 0) && (errno != 0)) { upslogx(LOG_WARNING, "Invalid value specified for low battery threshold: '%s'", option); } else { lb_threshold = x; } } option = getval("hb"); if (option) { x = strtoul(option, NULL, 0); if ((x == 0) && (errno != 0)) { upslogx(LOG_WARNING, "Invalid value specified for high battery threshold: '%s'", option); } else if ((x < 1) || (x > 100)) { upslogx(LOG_WARNING, "Invalid value specified for high battery threshold: '%s' (must be 1 < hb <= 100)", option); } else { hb_threshold = x; } } /* Invalid values specified */ if (lb_threshold > hb_threshold) { upslogx(LOG_WARNING, "lb > hb specified in options. Returning to defaults."); lb_threshold = LOW_BATTERY_THRESHOLD; hb_threshold = HIGH_BATTERY_THRESHOLD; } upslogx(LOG_NOTICE, "High battery threshold is %lu, low battery threshold is %lu", lb_threshold, hb_threshold); } void upsdrv_cleanup(void) { close(upsfd); } nut-2.8.1/drivers/Makefile.am0000644000175000017500000003511714515702041012771 00000000000000# Network UPS Tools: drivers # Make sure out-of-dir dependencies exist (especially when dev-building parts): $(top_builddir)/common/libcommon.la \ $(top_builddir)/common/libparseconf.la \ $(top_builddir)/clients/libupsclient.la: dummy @cd $(@D) && $(MAKE) $(AM_MAKEFLAGS) $(@F) # by default, link programs in this directory with libcommon.la # (libtool version of the static lib, in order to access LTLIBOBJS) #FIXME: SERLIBS is only useful for LDADD_DRIVERS_SERIAL not for LDADD_COMMON LDADD_COMMON = $(top_builddir)/common/libcommon.la $(top_builddir)/common/libparseconf.la LDADD_DRIVERS = libdummy.la libdummy_upsdrvquery.la $(LDADD_COMMON) LDADD_DRIVERS_SERIAL = libdummy_serial.la $(LDADD_DRIVERS) $(SERLIBS) # most targets are serial drivers, so make this the default LDADD = $(LDADD_DRIVERS_SERIAL) # Avoid per-target CFLAGS, because this will prevent re-use of object # files. In any case, CFLAGS are only -I options, so there is no harm, # but only add them if we really use the target. AM_CFLAGS = -I$(top_srcdir)/include if WITH_USB AM_CFLAGS += $(LIBUSB_CFLAGS) endif if WITH_NEON AM_CFLAGS += $(LIBNEON_CFLAGS) endif if WITH_LIBPOWERMAN AM_CFLAGS += $(LIBPOWERMAN_CFLAGS) endif if WITH_IPMI AM_CFLAGS += $(LIBIPMI_CFLAGS) endif if WITH_GPIO AM_CFLAGS += $(LIBGPIO_CFLAGS) endif if WITH_MODBUS AM_CFLAGS += $(LIBMODBUS_CFLAGS) endif if HAVE_LIBREGEX AM_CFLAGS += $(LIBREGEX_CFLAGS) endif NUTSW_DRIVERLIST = dummy-ups clone clone-outlet apcupsd-ups skel SERIAL_DRIVERLIST = al175 bcmxcp belkin belkinunv bestfcom \ bestfortress bestuferrups bestups etapro everups \ gamatronic genericups isbmex liebert liebert-esp2 masterguard metasys \ mge-utalk microdowell microsol-apc mge-shut oneac optiups powercom rhino \ safenet nutdrv_siemens-sitop solis tripplite tripplitesu upscode2 victronups powerpanel \ blazer_ser ivtscd apcsmart apcsmart-old riello_ser sms_ser SNMP_DRIVERLIST = snmp-ups USB_LIBUSB_DRIVERLIST = usbhid-ups bcmxcp_usb tripplite_usb \ blazer_usb richcomm_usb riello_usb \ nutdrv_atcl_usb USB_DRIVERLIST = $(USB_LIBUSB_DRIVERLIST) SERIAL_USB_DRIVERLIST = \ nutdrv_qx NEONXML_DRIVERLIST = netxml-ups MACOSX_DRIVERLIST = macosx-ups MODBUS_DRIVERLIST = phoenixcontact_modbus generic_modbus huawei-ups2000 socomec_jbus adelsystem_cbi apc_modbus LINUX_I2C_DRIVERLIST = asem pijuice POWERMAN_DRIVERLIST = powerman-pdu IPMI_DRIVERLIST = nut-ipmipsu GPIO_DRIVERLIST = generic_gpio_libgpiod # distribute all drivers, even ones that are not built by default EXTRA_PROGRAMS = $(SERIAL_DRIVERLIST) $(USB_DRIVERLIST) $(SERIAL_USB_DRIVERLIST) EXTRA_PROGRAMS += $(SNMP_DRIVERLIST) $(NEONXML_DRIVERLIST) $(MACOSX_DRIVERLIST) EXTRA_PROGRAMS += $(LINUX_I2C_DRIVERLIST) EXTRA_PROGRAMS += $(NUTSW_DRIVERLIST) EXTRA_PROGRAMS += $(GPIO_DRIVERLIST) # construct the list of drivers to build if SOME_DRIVERS driverexec_PROGRAMS = $(DRIVER_BUILD_LIST) else driverexec_PROGRAMS = $(NUTSW_DRIVERLIST) if WITH_SERIAL driverexec_PROGRAMS += $(SERIAL_DRIVERLIST) $(SERIAL_USB_DRIVERLIST) else if WITH_USB driverexec_PROGRAMS += $(SERIAL_USB_DRIVERLIST) endif endif if WITH_SNMP driverexec_PROGRAMS += $(SNMP_DRIVERLIST) endif if WITH_USB driverexec_PROGRAMS += $(USB_LIBUSB_DRIVERLIST) endif if WITH_NEON driverexec_PROGRAMS += $(NEONXML_DRIVERLIST) endif if WITH_LIBPOWERMAN driverexec_PROGRAMS += $(POWERMAN_DRIVERLIST) endif if WITH_IPMI driverexec_PROGRAMS += $(IPMI_DRIVERLIST) endif if WITH_GPIO driverexec_PROGRAMS += $(GPIO_DRIVERLIST) endif if WITH_MACOSX driverexec_PROGRAMS += $(MACOSX_DRIVERLIST) endif if WITH_LINUX_I2C driverexec_PROGRAMS += $(LINUX_I2C_DRIVERLIST) endif if WITH_MODBUS driverexec_PROGRAMS += $(MODBUS_DRIVERLIST) endif else driverexec_PROGRAMS += skel endif # always build upsdrvctl sbin_PROGRAMS = upsdrvctl # ========================================================================== # Driver build details # upsdrvctl: the all-singing all-dancing driver control program upsdrvctl_SOURCES = upsdrvctl.c upsdrvctl_LDADD = $(LDADD_COMMON) libdummy_upsdrvquery.la # serial drivers: all of them use standard LDADD and CFLAGS al175_SOURCES = al175.c apcsmart_SOURCES = apcsmart.c apcsmart_tabs.c apcsmart_LDADD = $(LDADD) $(LIBREGEX_LIBS) apcsmart_old_SOURCES = apcsmart-old.c bcmxcp_SOURCES = bcmxcp.c bcmxcp_ser.c bcmxcp_LDADD = $(LDADD) -lm belkin_SOURCES = belkin.c belkinunv_SOURCES = belkinunv.c bestfcom_SOURCES = bestfcom.c bestfortress_SOURCES = bestfortress.c bestuferrups_SOURCES = bestuferrups.c bestups_SOURCES = bestups.c blazer_ser_SOURCES = blazer.c blazer_ser.c blazer_ser_LDADD = $(LDADD) -lm etapro_SOURCES = etapro.c everups_SOURCES = everups.c gamatronic_SOURCES = gamatronic.c genericups_SOURCES = genericups.c isbmex_SOURCES = isbmex.c isbmex_LDADD = $(LDADD) -lm ivtscd_SOURCES = ivtscd.c liebert_SOURCES = liebert.c liebert_esp2_SOURCES = liebert-esp2.c masterguard_SOURCES = masterguard.c metasys_SOURCES = metasys.c metasys_LDADD = $(LDADD) -lm mge_utalk_SOURCES = mge-utalk.c microdowell_SOURCES = microdowell.c microsol_apc_SOURCES = microsol-apc.c microsol-common.c microsol_apc_LDADD = $(LDADD) -lm oneac_SOURCES = oneac.c optiups_SOURCES = optiups.c powercom_SOURCES = powercom.c powercom_LDADD = $(LDADD) -lm powerpanel_SOURCES = powerpanel.c powerp-bin.c powerp-txt.c powerpanel_LDADD = $(LDADD) -lm rhino_SOURCES = rhino.c rhino_LDADD = $(LDADD) -lm safenet_SOURCES = safenet.c nutdrv_siemens_sitop_SOURCES = nutdrv_siemens_sitop.c solis_SOURCES = solis.c solis_LDADD = $(LDADD) -lm tripplite_SOURCES = tripplite.c tripplite_LDADD = $(LDADD) -lm tripplitesu_SOURCES = tripplitesu.c upscode2_SOURCES = upscode2.c upscode2_LDADD = $(LDADD) -lm victronups_SOURCES = victronups.c riello_ser_SOURCES = riello.c riello_ser.c riello_ser_LDADD = $(LDADD) -lm sms_ser_SOURCES = sms_ser.c sms_ser_LDADD = $(LDADD) -lm # non-serial drivers: these use custom LDADD and/or CFLAGS # dummy (in NUTSW_DRIVERLIST) dummy_ups_SOURCES = dummy-ups.c dummy_ups_CFLAGS = $(AM_CFLAGS) -I$(top_srcdir)/clients dummy_ups_LDADD = $(LDADD_DRIVERS) $(top_builddir)/clients/libupsclient.la if WITH_SSL dummy_ups_CFLAGS += $(LIBSSL_CFLAGS) dummy_ups_LDADD += $(LIBSSL_LIBS) endif # Clone drivers (in NUTSW_DRIVERLIST) clone_SOURCES = clone.c clone_outlet_SOURCES = clone-outlet.c # apcupsd client driver (in NUTSW_DRIVERLIST) apcupsd_ups_SOURCES = apcupsd-ups.c apcupsd_ups_CFLAGS = $(AM_CFLAGS) apcupsd_ups_LDADD = $(LDADD_DRIVERS) # sample skeleton driver (in NUTSW_DRIVERLIST) skel_SOURCES = skel.c skel_LDADD = $(LDADD_DRIVERS) # USB if WITH_LIBUSB_0_1 LIBUSB_IMPL = libusb0.c endif if WITH_LIBUSB_1_0 LIBUSB_IMPL = libusb1.c endif USBHID_UPS_SUBDRIVERS = apc-hid.c arduino-hid.c belkin-hid.c cps-hid.c explore-hid.c \ liebert-hid.c mge-hid.c powercom-hid.c tripplite-hid.c idowell-hid.c \ openups-hid.c powervar-hid.c delta_ups-hid.c ever-hid.c legrand-hid.c salicru-hid.c usbhid_ups_SOURCES = usbhid-ups.c libhid.c $(LIBUSB_IMPL) hidparser.c \ usb-common.c $(USBHID_UPS_SUBDRIVERS) usbhid_ups_LDADD = $(LDADD_DRIVERS) $(LIBUSB_LIBS) -lm tripplite_usb_SOURCES = tripplite_usb.c $(LIBUSB_IMPL) usb-common.c tripplite_usb_LDADD = $(LDADD_DRIVERS) $(LIBUSB_LIBS) -lm bcmxcp_usb_SOURCES = bcmxcp_usb.c bcmxcp.c usb-common.c bcmxcp_usb_LDADD = $(LDADD_DRIVERS) $(LIBUSB_LIBS) -lm blazer_usb_SOURCES = blazer.c blazer_usb.c $(LIBUSB_IMPL) usb-common.c blazer_usb_LDADD = $(LDADD_DRIVERS) $(LIBUSB_LIBS) -lm nutdrv_atcl_usb_SOURCES = nutdrv_atcl_usb.c usb-common.c nutdrv_atcl_usb_LDADD = $(LDADD_DRIVERS) $(LIBUSB_LIBS) richcomm_usb_SOURCES = richcomm_usb.c $(LIBUSB_IMPL) usb-common.c richcomm_usb_LDADD = $(LDADD_DRIVERS) $(LIBUSB_LIBS) riello_usb_SOURCES = riello.c riello_usb.c $(LIBUSB_IMPL) usb-common.c riello_usb_LDADD = $(LDADD_DRIVERS) $(LIBUSB_LIBS) -lm # HID-over-serial mge_shut_SOURCES = usbhid-ups.c libshut.c libhid.c hidparser.c mge-hid.c # per-target CFLAGS are necessary here mge_shut_CFLAGS = $(AM_CFLAGS) -DSHUT_MODE=1 mge_shut_LDADD = $(LDADD) -lm # SNMP # Please keep the MIB table below sorted roughly alphabetically (incidentally # by vendor too) to ease maintenance and codebase fork resynchronisations snmp_ups_SOURCES = snmp-ups.c snmp-ups-helpers.c \ apc-mib.c apc-pdu-mib.c apc-epdu-mib.c \ baytech-mib.c bestpower-mib.c \ compaq-mib.c cyberpower-mib.c \ delta_ups-mib.c \ eaton-pdu-genesis2-mib.c eaton-pdu-marlin-mib.c eaton-pdu-marlin-helpers.c \ eaton-pdu-pulizzi-mib.c eaton-pdu-revelation-mib.c eaton-pdu-nlogic-mib.c \ eaton-ats16-nmc-mib.c eaton-ats16-nm2-mib.c apc-ats-mib.c eaton-ats30-mib.c \ eaton-ups-pwnm2-mib.c eaton-ups-pxg-mib.c \ emerson-avocent-pdu-mib.c \ hpe-pdu-mib.c hpe-pdu3-cis-mib.c huawei-mib.c \ ietf-mib.c \ mge-mib.c \ netvision-mib.c \ raritan-pdu-mib.c raritan-px2-mib.c \ xppc-mib.c snmp_ups_CFLAGS = $(AM_CFLAGS) snmp_ups_CFLAGS += $(LIBNETSNMP_CFLAGS) snmp_ups_LDADD = $(LDADD_DRIVERS) $(LIBNETSNMP_LIBS) -lm # NEON XML/HTTP netxml_ups_SOURCES = netxml-ups.c mge-xml.c netxml_ups_LDADD = $(LDADD_DRIVERS) $(LIBNEON_LIBS) # Powerman powerman_pdu_SOURCES = powerman-pdu.c powerman_pdu_LDADD = $(LDADD) $(LIBPOWERMAN_LIBS) # IPMI PSU nut_ipmipsu_SOURCES = nut-ipmipsu.c if WITH_FREEIPMI nut_ipmipsu_SOURCES += nut-libfreeipmi.c endif # FIXME: Hacky hot-fix for build agents of varying OS generations: # Different versions of IPMI libs requested 'unsigned int *' or 'int *' args: #nut_ipmipsu_CFLAGS = $(AM_CFLAGS) -Wno-pointer-sign nut_ipmipsu_LDADD = $(LDADD) $(LIBIPMI_LIBS) # Mac OS X metadriver macosx_ups_LDADD = $(LDADD_DRIVERS) macosx_ups_LDFLAGS = $(LDFLAGS) -framework IOKit -framework CoreFoundation macosx_ups_SOURCES = macosx-ups.c # Modbus drivers phoenixcontact_modbus_SOURCES = phoenixcontact_modbus.c phoenixcontact_modbus_LDADD = $(LDADD_DRIVERS) $(LIBMODBUS_LIBS) generic_modbus_SOURCES = generic_modbus.c generic_modbus_LDADD = $(LDADD_DRIVERS) $(LIBMODBUS_LIBS) adelsystem_cbi_SOURCES = adelsystem_cbi.c adelsystem_cbi_LDADD = $(LDADD_DRIVERS) $(LIBMODBUS_LIBS) apc_modbus_SOURCES = apc_modbus.c $(LIBUSB_IMPL) hidparser.c usb-common.c apc_modbus_LDADD = $(LDADD_DRIVERS) $(LIBMODBUS_LIBS) $(LIBUSB_LIBS) # Huawei UPS2000 driver # (this is both a Modbus and a serial driver) huawei_ups2000_SOURCES = huawei-ups2000.c huawei_ups2000_LDADD = $(LDADD_DRIVERS_SERIAL) $(LIBMODBUS_LIBS) # Socomec JBUS driver # (this is a Modbus driver) socomec_jbus_SOURCES = socomec_jbus.c socomec_jbus_LDADD = $(LDADD_DRIVERS_SERIAL) $(LIBMODBUS_LIBS) # Linux I2C drivers asem_LDADD = $(LDADD_DRIVERS) $(LIBI2C_LIBS) asem_SOURCES = asem.c pijuice_LDADD = $(LDADD_DRIVERS) $(LIBI2C_LIBS) pijuice_SOURCES = pijuice.c # GPIO drivers generic_gpio_libgpiod_SOURCES = generic_gpio_common.c generic_gpio_libgpiod.c generic_gpio_libgpiod_LDADD = $(LDADD_DRIVERS) $(LIBGPIO_LIBS) # nutdrv_qx USB/Serial nutdrv_qx_SOURCES = nutdrv_qx.c nutdrv_qx_LDADD = $(LDADD_DRIVERS) -lm nutdrv_qx_CFLAGS = $(AM_CFLAGS) if WITH_SERIAL nutdrv_qx_CFLAGS += -DQX_SERIAL nutdrv_qx_LDADD += libdummy_serial.la $(SERLIBS) endif if WITH_USB nutdrv_qx_CFLAGS += -DQX_USB nutdrv_qx_SOURCES += $(LIBUSB_IMPL) usb-common.c nutdrv_qx_LDADD += $(LIBUSB_LIBS) endif NUTDRV_QX_SUBDRIVERS = nutdrv_qx_bestups.c nutdrv_qx_blazer-common.c \ nutdrv_qx_masterguard.c \ nutdrv_qx_mecer.c nutdrv_qx_megatec.c nutdrv_qx_megatec-old.c \ nutdrv_qx_mustek.c nutdrv_qx_q1.c nutdrv_qx_voltronic.c \ nutdrv_qx_voltronic-qs.c nutdrv_qx_voltronic-qs-hex.c nutdrv_qx_zinto.c \ nutdrv_qx_hunnox.c nutdrv_qx_ablerex.c nutdrv_qx_SOURCES += $(NUTDRV_QX_SUBDRIVERS) # ---------------------------------------------------------------------- # List of header files. The purpose of this list is not dependency # tracking (which is automatic), but to ensure these files are # distributed by "make dist". dist_noinst_HEADERS = apc-mib.h apc-iem-mib.h apc-hid.h arduino-hid.h baytech-mib.h bcmxcp.h bcmxcp_ser.h \ bcmxcp_io.h belkin.h belkin-hid.h bestpower-mib.h blazer.h cps-hid.h dstate.h \ dummy-ups.h explore-hid.h gamatronic.h genericups.h \ generic_gpio_common.h generic_gpio_libgpiod.h \ hidparser.h hidtypes.h ietf-mib.h libhid.h libshut.h nut_libusb.h liebert-hid.h \ main.h mge-hid.h mge-mib.h mge-utalk.h \ mge-xml.h microdowell.h microsol-apc.h microsol-common.h netvision-mib.h netxml-ups.h nut-ipmi.h oneac.h \ powercom.h powerpanel.h powerp-bin.h powerp-txt.h raritan-pdu-mib.h \ safenet.h serial.h sms_ser.h snmp-ups.h solis.h tripplite.h tripplite-hid.h \ upshandler.h usb-common.h usbhid-ups.h powercom-hid.h compaq-mib.h idowell-hid.h \ apcsmart.h apcsmart_tabs.h apcsmart-old.h apcupsd-ups.h cyberpower-mib.h riello.h openups-hid.h \ delta_ups-mib.h nutdrv_qx.h nutdrv_qx_bestups.h nutdrv_qx_blazer-common.h \ nutdrv_qx_masterguard.h \ nutdrv_qx_mecer.h nutdrv_qx_ablerex.h \ nutdrv_qx_megatec.h nutdrv_qx_megatec-old.h nutdrv_qx_mustek.h nutdrv_qx_q1.h nutdrv_qx_hunnox.h \ nutdrv_qx_voltronic.h nutdrv_qx_voltronic-qs.h nutdrv_qx_voltronic-qs-hex.h nutdrv_qx_zinto.h \ upsdrvquery.h \ xppc-mib.h huawei-mib.h eaton-ats16-nmc-mib.h eaton-ats16-nm2-mib.h apc-ats-mib.h raritan-px2-mib.h eaton-ats30-mib.h \ apc-pdu-mib.h apc-epdu-mib.h ever-hid.h eaton-pdu-genesis2-mib.h eaton-pdu-marlin-mib.h eaton-pdu-marlin-helpers.h \ eaton-pdu-pulizzi-mib.h eaton-pdu-revelation-mib.h emerson-avocent-pdu-mib.h eaton-ups-pwnm2-mib.h eaton-ups-pxg-mib.h legrand-hid.h \ hpe-pdu-mib.h hpe-pdu3-cis-mib.h powervar-hid.h delta_ups-hid.h generic_modbus.h salicru-hid.h adelsystem_cbi.h eaton-pdu-nlogic-mib.h # Define a dummy library so that Automake builds rules for the # corresponding object files. This library is not actually built, # as a final product. It was necessary for Automake-technical reasons, # because per-object CFLAGS can only be specified for libraries, not # for object files. This library is used during the build process, # and is not meant to be installed. EXTRA_LTLIBRARIES = libdummy.la libdummy_serial.la libdummy_upsdrvquery.la libdummy_la_SOURCES = main.c dstate.c libdummy_la_LDFLAGS = -no-undefined -static libdummy_serial_la_SOURCES = serial.c libdummy_serial_la_LDFLAGS = -no-undefined -static libdummy_upsdrvquery_la_SOURCES = upsdrvquery.c libdummy_upsdrvquery_la_LDFLAGS = -no-undefined -static # The libdummy_mockdrv.la is used for unit-tests to mock a driver # with near-production codebase but without its standard main(). # Otherwise, also not meant to be installed. EXTRA_LTLIBRARIES += libdummy_mockdrv.la libdummy_mockdrv_la_SOURCES = main.c dstate.c libdummy_mockdrv_la_CFLAGS = $(AM_CFLAGS) -DDRIVERS_MAIN_WITHOUT_MAIN=1 libdummy_mockdrv_la_LDFLAGS = -static $(top_builddir)/common/libcommon.la $(top_builddir)/common/libparseconf.la dummy: CLEANFILES = $(EXTRA_LTLIBRARIES) $(EXTRA_PROGRAMS) MAINTAINERCLEANFILES = Makefile.in .dirstamp # NOTE: Do not clean ".deps" in SUBDIRS of the main project, # the root Makefile.am takes care of that! #clean-local: # $(AM_V_at)rm -rf $(builddir)/.deps nut-2.8.1/drivers/mge-mib.c0000644000175000017500000003430014501607135012412 00000000000000/* mge-mib.c - data to monitor MGE UPS SYSTEMS SNMP devices with NUT * * Copyright (C) * 2002-2012 Arnaud Quette * 2002-2003 J.W. Hoogervorst * * Sponsored by MGE UPS SYSTEMS * MGE Office Protection Systems * Eaton * * 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 2 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, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #include "mge-mib.h" #define MGE_MIB_VERSION "0.55" /* TODO: * - MGE PDU MIB and sysOID (".1.3.6.1.4.1.705.2") */ /* SNMP OIDs set */ #define MGE_BASE_OID ".1.3.6.1.4.1.705.1" #define MGE_SYSOID MGE_BASE_OID #define MGE_OID_MODEL_NAME MGE_BASE_OID ".1.1.0" static info_lkp_t mge_lowbatt_info[] = { { 1, "LB", NULL, NULL }, { 2, "", NULL, NULL }, { 0, NULL, NULL, NULL } }; static info_lkp_t mge_onbatt_info[] = { { 1, "OB", NULL, NULL }, { 2, "OL", NULL, NULL }, { 0, NULL, NULL, NULL } }; static info_lkp_t mge_bypass_info[] = { { 1, "BYPASS", NULL, NULL }, { 2, "", NULL, NULL }, { 0, NULL, NULL, NULL } }; static info_lkp_t mge_boost_info[] = { { 1, "BOOST", NULL, NULL }, { 2, "", NULL, NULL }, { 0, NULL, NULL, NULL } }; static info_lkp_t mge_trim_info[] = { { 1, "TRIM", NULL, NULL }, { 2, "", NULL, NULL }, { 0, NULL, NULL, NULL } }; static info_lkp_t mge_overload_info[] = { { 1, "OVER", NULL, NULL }, { 2, "", NULL, NULL }, { 0, NULL, NULL, NULL } }; static info_lkp_t mge_replacebatt_info[] = { { 1, "RB", NULL, NULL }, { 2, "", NULL, NULL }, { 0, NULL, NULL, NULL } }; static info_lkp_t mge_output_util_off_info[] = { { 1, "OFF", NULL, NULL }, { 2, "", NULL, NULL }, { 0, NULL, NULL, NULL } }; static info_lkp_t mge_transfer_reason_info[] = { { 1, "", NULL, NULL }, { 2, "input voltage out of range", NULL, NULL }, { 3, "input frequency out of range", NULL, NULL }, { 4, "utility off", NULL, NULL }, { 0, NULL, NULL, NULL } }; static info_lkp_t mge_test_result_info[] = { { 1, "done and passed", NULL, NULL }, { 2, "done and warning", NULL, NULL }, { 3, "done and error", NULL, NULL }, { 4, "aborted", NULL, NULL }, { 5, "in progress", NULL, NULL }, { 6, "no test initiated", NULL, NULL }, { 0, NULL, NULL, NULL } }; static info_lkp_t mge_beeper_status_info[] = { { 1, "disabled", NULL, NULL }, { 2, "enabled", NULL, NULL }, { 3, "muted", NULL, NULL }, { 0, NULL, NULL, NULL } }; static info_lkp_t mge_yes_no_info[] = { { 1, "yes", NULL, NULL }, { 2, "no", NULL, NULL }, { 0, NULL, NULL, NULL } }; /* FIXME: the below may introduce status redundancy, that needs to be * addressed by the driver, as for usbhid-ups! */ static info_lkp_t mge_power_source_info[] = { { 1, "" /* other */, NULL, NULL }, { 2, "OFF" /* none */, NULL, NULL }, #if 0 { 3, "OL" /* normal */, NULL, NULL }, #endif { 4, "BYPASS" /* bypass */, NULL, NULL }, { 5, "OB" /* battery */, NULL, NULL }, { 6, "BOOST" /* booster */, NULL, NULL }, { 7, "TRIM" /* reducer */, NULL, NULL }, { 0, NULL, NULL, NULL } }; static info_lkp_t mge_ambient_drycontacts_info[] = { { -1, "unknown", NULL, NULL }, { 1, "closed", NULL, NULL }, { 2, "opened", NULL, NULL }, { 0, NULL, NULL, NULL } }; /* Parameters default values */ #define DEFAULT_ONDELAY "30" /* Delay between return of utility power */ /* and powering up of load, in seconds */ /* CAUTION: ondelay > offdelay */ #define DEFAULT_OFFDELAY "20" /* Delay before power off, in seconds */ #define MGE_NOTHING_VALUE "1" #define MGE_START_VALUE "2" #define MGE_STOP_VALUE "3" /* TODO: PowerShare (per plug .1, .2, .3) and deals with delays */ /* Snmp2NUT lookup table */ static snmp_info_t mge_mib[] = { /* standard MIB items */ { "device.description", ST_FLAG_STRING | ST_FLAG_RW, SU_INFOSIZE, ".1.3.6.1.2.1.1.1.0", NULL, SU_FLAG_OK, NULL }, { "device.contact", ST_FLAG_STRING | ST_FLAG_RW, SU_INFOSIZE, ".1.3.6.1.2.1.1.4.0", NULL, SU_FLAG_OK, NULL }, { "device.location", ST_FLAG_STRING | ST_FLAG_RW, SU_INFOSIZE, ".1.3.6.1.2.1.1.6.0", NULL, SU_FLAG_OK, NULL }, /* UPS page */ { "ups.mfr", ST_FLAG_STRING, SU_INFOSIZE, NULL, "EATON", SU_FLAG_STATIC | SU_FLAG_ABSENT | SU_FLAG_OK, NULL }, { "ups.model", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.705.1.1.1.0", "Generic SNMP UPS", SU_FLAG_STATIC | SU_FLAG_OK, NULL }, { "ups.serial", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.705.1.1.7.0", "", SU_FLAG_STATIC | SU_FLAG_OK, NULL }, { "ups.firmware", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.705.1.1.4.0", "", SU_FLAG_STATIC | SU_FLAG_OK, NULL }, { "ups.firmware.aux", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.705.1.12.12.0", "", SU_FLAG_STATIC | SU_FLAG_OK, NULL }, { "ups.load", 0, 1, ".1.3.6.1.4.1.705.1.7.2.1.4.1", "", SU_OUTPUT_1, NULL }, { "ups.beeper.status", ST_FLAG_STRING, SU_INFOSIZE, "1.3.6.1.2.1.33.1.9.8.0", "", 0, mge_beeper_status_info }, { "ups.L1.load", 0, 1, ".1.3.6.1.4.1.705.1.7.2.1.4.1", "", SU_OUTPUT_3, NULL }, { "ups.L2.load", 0, 1, ".1.3.6.1.4.1.705.1.7.2.1.4.2", "", SU_OUTPUT_3, NULL }, { "ups.L3.load", 0, 1, ".1.3.6.1.4.1.705.1.7.2.1.4.3", "", SU_OUTPUT_3, NULL }, { "ups.test.result", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.2.1.33.1.7.3.0", "", 0, mge_test_result_info }, { "ups.delay.shutdown", ST_FLAG_STRING | ST_FLAG_RW, 6, "1.3.6.1.2.1.33.1.8.2.0", DEFAULT_OFFDELAY, SU_FLAG_ABSENT | SU_FLAG_OK, NULL }, { "ups.delay.start", ST_FLAG_STRING | ST_FLAG_RW, 6, "1.3.6.1.2.1.33.1.8.3.0", DEFAULT_ONDELAY, SU_FLAG_ABSENT | SU_FLAG_OK, NULL }, { "ups.timer.shutdown", 0, 1, "1.3.6.1.2.1.33.1.8.2.0", "", SU_FLAG_OK, NULL }, { "ups.timer.start", 0, 1, "1.3.6.1.2.1.33.1.8.3.0", "", SU_FLAG_OK, NULL }, { "ups.timer.reboot", 0, 1, "1.3.6.1.2.1.33.1.8.4.0", "", SU_FLAG_OK, NULL }, { "ups.start.auto", ST_FLAG_RW, 1, "1.3.6.1.2.1.33.1.8.5.0", "", SU_FLAG_OK, mge_yes_no_info }, /* status data */ { "ups.status", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.705.1.5.11.0", "", SU_FLAG_OK | SU_STATUS_BATT, mge_replacebatt_info }, { "ups.status", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.705.1.5.14.0", "", SU_FLAG_OK | SU_STATUS_BATT, mge_lowbatt_info }, { "ups.status", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.705.1.5.16.0", "", SU_FLAG_OK | SU_STATUS_BATT, mge_lowbatt_info }, { "ups.status", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.705.1.7.3.0", "", SU_FLAG_OK | SU_STATUS_BATT, mge_onbatt_info }, { "ups.status", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.705.1.7.4.0", "", SU_FLAG_OK | SU_STATUS_BATT, mge_bypass_info }, { "ups.status", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.705.1.7.7.0", "", SU_FLAG_OK | SU_STATUS_BATT, mge_output_util_off_info }, { "ups.status", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.705.1.7.8.0", "", SU_FLAG_OK | SU_STATUS_BATT, mge_boost_info }, { "ups.status", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.705.1.7.10.0", "", SU_FLAG_OK | SU_STATUS_BATT, mge_overload_info }, { "ups.status", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.705.1.7.12.0", "", SU_FLAG_OK | SU_STATUS_BATT, mge_trim_info }, { "ups.status", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.2.1.33.1.4.1.0", "", SU_STATUS_PWR | SU_FLAG_OK, mge_power_source_info }, /* FIXME: Alarms * - upsmgBatteryChargerFault (.1.3.6.1.4.1.705.1.5.15.0), yes (1), no (2) * => Battery charger fail! * - upsmgBatteryFaultBattery (.1.3.6.1.4.1.705.1.5.9.0), yes (1), no (2) * => "Battery fault!" or? * - upsmgOutputOverTemp (.1.3.6.1.4.1.705.1.7.11.0), yes (1), no (2) * => "Temperature too high!" * - upsmgOutputInverterOff (.1.3.6.1.4.1.705.1.7.9.0), yes (1), no (2) * => "??" * - upsmgInputBadStatus (.1.3.6.1.4.1.705.1.6.3.0), yes (1), no (2) * => "bad volt or bad freq" */ /* Input page */ { "input.phases", 0, 1.0, ".1.3.6.1.4.1.705.1.6.1.0", "", 0, NULL }, { "input.voltage", 0, 0.1, ".1.3.6.1.4.1.705.1.6.2.1.2.1", "", SU_INPUT_1, NULL }, { "input.L1-N.voltage", 0, 0.1, ".1.3.6.1.4.1.705.1.6.2.1.2.1", "", SU_INPUT_3, NULL }, { "input.L2-N.voltage", 0, 0.1, ".1.3.6.1.4.1.705.1.6.2.1.2.2", "", SU_INPUT_3, NULL }, { "input.L3-N.voltage", 0, 0.1, ".1.3.6.1.4.1.705.1.6.2.1.2.3", "", SU_INPUT_3, NULL }, { "input.frequency", 0, 0.1, ".1.3.6.1.4.1.705.1.6.2.1.3.1", "", SU_INPUT_1, NULL }, { "input.L1.frequency", 0, 0.1, ".1.3.6.1.4.1.705.1.6.2.1.3.1", "", SU_INPUT_3, NULL }, { "input.L2.frequency", 0, 0.1, ".1.3.6.1.4.1.705.1.6.2.1.3.2", "", SU_INPUT_3, NULL }, { "input.L3.frequency", 0, 0.1, ".1.3.6.1.4.1.705.1.6.2.1.3.3", "", SU_INPUT_3, NULL }, { "input.voltage.minimum", 0, 0.1, ".1.3.6.1.4.1.705.1.6.2.1.4.1", "", SU_INPUT_1, NULL }, { "input.L1-N.voltage.minimum", 0, 0.1, ".1.3.6.1.4.1.705.1.6.2.1.4.1", "", SU_INPUT_3, NULL }, { "input.L2-N.voltage.minimum", 0, 0.1, ".1.3.6.1.4.1.705.1.6.2.1.4.2", "", SU_INPUT_3, NULL }, { "input.L3-N.voltage.minimum", 0, 0.1, ".1.3.6.1.4.1.705.1.6.2.1.4.3", "", SU_INPUT_3, NULL }, { "input.voltage.maximum", 0, 0.1, ".1.3.6.1.4.1.705.1.6.2.1.5.1", "", SU_INPUT_1, NULL }, { "input.L1-N.voltage.maximum", 0, 0.1, ".1.3.6.1.4.1.705.1.6.2.1.5.1", "", SU_INPUT_3, NULL }, { "input.L2-N.voltage.maximum", 0, 0.1, ".1.3.6.1.4.1.705.1.6.2.1.5.2", "", SU_INPUT_3, NULL }, { "input.L3-N.voltage.maximum", 0, 0.1, ".1.3.6.1.4.1.705.1.6.2.1.5.3", "", SU_INPUT_3, NULL }, { "input.current", 0, 0.1, ".1.3.6.1.4.1.705.1.6.2.1.6.1", "", SU_INPUT_1, NULL }, { "input.L1.current", 0, 0.1, ".1.3.6.1.4.1.705.1.6.2.1.6.1", "", SU_INPUT_3, NULL }, { "input.L2.current", 0, 0.1, ".1.3.6.1.4.1.705.1.6.2.1.6.2", "", SU_INPUT_3, NULL }, { "input.L3.current", 0, 0.1, ".1.3.6.1.4.1.705.1.6.2.1.6.3", "", SU_INPUT_3, NULL }, { "input.transfer.reason", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.705.1.6.4.0", "", SU_FLAG_OK, mge_transfer_reason_info }, /* Output page */ { "output.phases", 0, 1.0, ".1.3.6.1.4.1.705.1.7.1.0", "", 0, NULL }, { "output.voltage", 0, 0.1, ".1.3.6.1.4.1.705.1.7.2.1.2.1", "", SU_OUTPUT_1, NULL }, { "output.L1-N.voltage", 0, 0.1, ".1.3.6.1.4.1.705.1.7.2.1.2.1", "", SU_OUTPUT_3, NULL }, { "output.L2-N.voltage", 0, 0.1, ".1.3.6.1.4.1.705.1.7.2.1.2.2", "", SU_OUTPUT_3, NULL }, { "output.L3-N.voltage", 0, 0.1, ".1.3.6.1.4.1.705.1.7.2.1.2.3", "", SU_OUTPUT_3, NULL }, { "output.frequency", 0, 0.1, ".1.3.6.1.4.1.705.1.7.2.1.3.1", "", SU_OUTPUT_1, NULL }, { "output.L1.frequency", 0, 0.1, ".1.3.6.1.4.1.705.1.7.2.1.3.1", "", SU_OUTPUT_3, NULL }, { "output.L2.frequency", 0, 0.1, ".1.3.6.1.4.1.705.1.7.2.1.3.2", "", SU_OUTPUT_3, NULL }, { "output.L3.frequency", 0, 0.1, ".1.3.6.1.4.1.705.1.7.2.1.3.3", "", SU_OUTPUT_3, NULL }, { "output.current", 0, 0.1, ".1.3.6.1.4.1.705.1.7.2.1.5.1", "", SU_OUTPUT_1, NULL }, { "output.L1.current", 0, 0.1, ".1.3.6.1.4.1.705.1.7.2.1.5.1", "", SU_OUTPUT_3, NULL }, { "output.L2.current", 0, 0.1, ".1.3.6.1.4.1.705.1.7.2.1.5.2", "", SU_OUTPUT_3, NULL }, { "output.L3.current", 0, 0.1, ".1.3.6.1.4.1.705.1.7.2.1.5.3", "", SU_OUTPUT_3, NULL }, /* Battery page */ { "battery.charge", 0, 1, ".1.3.6.1.4.1.705.1.5.2.0", "", SU_FLAG_OK, NULL }, { "battery.runtime", 0, 1, ".1.3.6.1.4.1.705.1.5.1.0", "", SU_FLAG_OK, NULL }, { "battery.runtime.low", 0, 1, ".1.3.6.1.4.1.705.1.4.7.0", "", SU_FLAG_OK, NULL }, { "battery.charge.low", ST_FLAG_STRING | ST_FLAG_RW, 2, ".1.3.6.1.4.1.705.1.4.8.0", "", SU_TYPE_INT | SU_FLAG_OK, NULL }, { "battery.voltage", 0, 0.1, ".1.3.6.1.4.1.705.1.5.5.0", "", SU_FLAG_OK, NULL }, /* Ambient page: Environment Sensor (ref 66 846) */ { "ambient.temperature", 0, 0.1, ".1.3.6.1.4.1.705.1.8.1.0", "", SU_TYPE_INT | SU_FLAG_OK, NULL }, { "ambient.humidity", 0, 0.1, ".1.3.6.1.4.1.705.1.8.2.0", "", SU_TYPE_INT | SU_FLAG_OK, NULL }, /* upsmgEnvironmentInput1State.1 */ { "ambient.contacts.1.status", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.705.1.8.7.1.9.1", "", SU_TYPE_INT | SU_FLAG_OK, mge_ambient_drycontacts_info }, /* upsmgEnvironmentInput1State.1 */ { "ambient.contacts.2.status", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.705.1.8.7.1.10.1", "", SU_TYPE_INT | SU_FLAG_OK, mge_ambient_drycontacts_info }, /* Outlet page */ { "outlet.id", 0, 1, NULL, "0", SU_FLAG_STATIC | SU_FLAG_ABSENT | SU_FLAG_OK, NULL }, { "outlet.desc", ST_FLAG_RW | ST_FLAG_STRING, 20, NULL, "Main Outlet", SU_FLAG_STATIC | SU_FLAG_ABSENT | SU_FLAG_OK, NULL }, /* instant commands. */ { "test.battery.start", 0, 1, ".1.3.6.1.4.1.705.1.10.4.0", MGE_START_VALUE, SU_TYPE_CMD | SU_FLAG_OK, NULL }, /* Also use IETF OIDs * { "test.battery.stop", 0, 0, "1.3.6.1.2.1.33.1.7.1.0", "1.3.6.1.2.1.33.1.7.7.2", SU_TYPE_CMD, NULL }, * { "test.battery.start", 0, 0, "1.3.6.1.2.1.33.1.7.1.0", "1.3.6.1.2.1.33.1.7.7.3", SU_TYPE_CMD, NULL }, * { "test.battery.start.quick", 0, 0, "1.3.6.1.2.1.33.1.7.1.0", "1.3.6.1.2.1.33.1.7.7.4", SU_TYPE_CMD, NULL }, * { "test.battery.start.deep", 0, 0, "1.3.6.1.2.1.33.1.7.1.0", "1.3.6.1.2.1.33.1.7.7.5", SU_TYPE_CMD, NULL }, */ /* { "load.off", 0, 1, ".1.3.6.1.4.1.705.1.9.1.1.6.1", MGE_START_VALUE, SU_TYPE_CMD | SU_FLAG_OK, NULL }, * { "load.on", 0, 1, ".1.3.6.1.4.1.705.1.9.1.1.3.1", MGE_START_VALUE, SU_TYPE_CMD | SU_FLAG_OK, NULL }, * { "shutdown.return", 0, 1, ".1.3.6.1.4.1.705.1.9.1.1.9.1", MGE_START_VALUE, SU_TYPE_CMD | SU_FLAG_OK, NULL }, */ /* IETF MIB fallback */ { "beeper.disable", 0, 1, "1.3.6.1.2.1.33.1.9.8.0", "1", SU_TYPE_CMD, NULL }, { "beeper.enable", 0, 1, "1.3.6.1.2.1.33.1.9.8.0", "2", SU_TYPE_CMD, NULL }, { "beeper.mute", 0, 1, "1.3.6.1.2.1.33.1.9.8.0", "3", SU_TYPE_CMD, NULL }, /*{ "load.off", 0, 1, "1.3.6.1.2.1.33.1.8.2.0", DEFAULT_OFFDELAY, SU_TYPE_CMD, NULL }, { "load.on", 0, 1, "1.3.6.1.2.1.33.1.8.3.0", DEFAULT_ONDELAY, SU_TYPE_CMD, NULL },*/ { "load.off.delay", 0, 1, "1.3.6.1.2.1.33.1.8.2.0", NULL, SU_TYPE_CMD, NULL }, { "load.on.delay", 0, 1, "1.3.6.1.2.1.33.1.8.3.0", NULL, SU_TYPE_CMD, NULL }, /* end of structure. */ { NULL, 0, 0, NULL, NULL, 0, NULL } }; mib2nut_info_t mge = { "mge", MGE_MIB_VERSION, NULL, MGE_OID_MODEL_NAME, mge_mib, MGE_SYSOID, NULL }; nut-2.8.1/drivers/nutdrv_qx_q1.c0000644000175000017500000001410414501607135013530 00000000000000/* nutdrv_qx_q1.c - Subdriver for Q1 protocol based UPSes * * Copyright (C) * 2013 Daniele Pezzini * * 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 2 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, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * NOTE: * This subdriver implements the same protocol as the one used by the 'megatec' subdriver minus the vendor (I) and ratings (F) queries. * In the claim function: * - it doesn't even try to get 'vendor' information (I) * - it checks only status (Q1), through 'input.voltage' variable * Therefore it should be able to work even if the UPS doesn't support vendor/ratings *and* the user doesn't use the 'novendor'/'norating' flags, as long as: * - the UPS replies a Q1-compliant answer (i.e. not necessary filled with all of the Q1-required data, but at least of the right length and with not available data filled with some replacement character) * - the UPS reports a valid input.voltage (used in the claim function) * - the UPS reports valid status bits (1st, 2nd, 3rd, 6th, 7th are the mandatory ones) * */ #include "main.h" #include "nutdrv_qx.h" #include "nutdrv_qx_blazer-common.h" #include "nutdrv_qx_q1.h" #define Q1_VERSION "Q1 0.08" /* qx2nut lookup table */ static item_t q1_qx2nut[] = { /* * > [Q1\r] * < [(226.0 195.0 226.0 014 49.0 27.5 30.0 00001000\r] * 01234567890123456789012345678901234567890123456 * 0 1 2 3 4 */ { "input.voltage", 0, NULL, "Q1\r", "", 47, '(', "", 1, 5, "%.1f", 0, NULL, NULL, NULL }, { "input.voltage.fault", 0, NULL, "Q1\r", "", 47, '(', "", 7, 11, "%.1f", 0, NULL, NULL, NULL }, { "output.voltage", 0, NULL, "Q1\r", "", 47, '(', "", 13, 17, "%.1f", 0, NULL, NULL, NULL }, { "ups.load", 0, NULL, "Q1\r", "", 47, '(', "", 19, 21, "%.0f", 0, NULL, NULL, NULL }, { "input.frequency", 0, NULL, "Q1\r", "", 47, '(', "", 23, 26, "%.1f", 0, NULL, NULL, NULL }, { "battery.voltage", 0, NULL, "Q1\r", "", 47, '(', "", 28, 31, "%.2f", 0, NULL, NULL, qx_multiply_battvolt }, { "ups.temperature", 0, NULL, "Q1\r", "", 47, '(', "", 33, 36, "%.1f", 0, NULL, NULL, NULL }, /* Status bits */ { "ups.status", 0, NULL, "Q1\r", "", 47, '(', "", 38, 38, NULL, QX_FLAG_QUICK_POLL, NULL, NULL, blazer_process_status_bits }, /* Utility Fail (Immediate) */ { "ups.status", 0, NULL, "Q1\r", "", 47, '(', "", 39, 39, NULL, QX_FLAG_QUICK_POLL, NULL, NULL, blazer_process_status_bits }, /* Battery Low */ { "ups.status", 0, NULL, "Q1\r", "", 47, '(', "", 40, 40, NULL, QX_FLAG_QUICK_POLL, NULL, NULL, blazer_process_status_bits }, /* Bypass/Boost or Buck Active */ { "ups.alarm", 0, NULL, "Q1\r", "", 47, '(', "", 41, 41, NULL, 0, NULL, NULL, blazer_process_status_bits }, /* UPS Failed */ { "ups.type", 0, NULL, "Q1\r", "", 47, '(', "", 42, 42, "%s", QX_FLAG_STATIC, NULL, NULL, blazer_process_status_bits }, /* UPS Type */ { "ups.status", 0, NULL, "Q1\r", "", 47, '(', "", 43, 43, NULL, QX_FLAG_QUICK_POLL, NULL, NULL, blazer_process_status_bits }, /* Test in Progress */ { "ups.status", 0, NULL, "Q1\r", "", 47, '(', "", 44, 44, NULL, QX_FLAG_QUICK_POLL, NULL, NULL, blazer_process_status_bits }, /* Shutdown Active */ { "ups.beeper.status", 0, NULL, "Q1\r", "", 47, '(', "", 45, 45, "%s", 0, NULL, NULL, blazer_process_status_bits }, /* Beeper status */ /* Instant commands */ { "beeper.toggle", 0, NULL, "Q\r", "", 0, 0, "", 0, 0, NULL, QX_FLAG_CMD, NULL, NULL, NULL }, { "load.off", 0, NULL, "S00R0000\r", "", 0, 0, "", 0, 0, NULL, QX_FLAG_CMD, NULL, NULL, NULL }, { "load.on", 0, NULL, "C\r", "", 0, 0, "", 0, 0, NULL, QX_FLAG_CMD, NULL, NULL, NULL }, { "shutdown.return", 0, NULL, "S%s\r", "", 0, 0, "", 0, 0, NULL, QX_FLAG_CMD, NULL, NULL, blazer_process_command }, { "shutdown.stayoff", 0, NULL, "S%sR0000\r", "", 0, 0, "", 0, 0, NULL, QX_FLAG_CMD, NULL, NULL, blazer_process_command }, { "shutdown.stop", 0, NULL, "C\r", "", 0, 0, "", 0, 0, NULL, QX_FLAG_CMD, NULL, NULL, NULL }, { "test.battery.start", 0, NULL, "T%02d\r", "", 0, 0, "", 0, 0, NULL, QX_FLAG_CMD, NULL, NULL, blazer_process_command }, { "test.battery.start.deep", 0, NULL, "TL\r", "", 0, 0, "", 0, 0, NULL, QX_FLAG_CMD, NULL, NULL, NULL }, { "test.battery.start.quick", 0, NULL, "T\r", "", 0, 0, "", 0, 0, NULL, QX_FLAG_CMD, NULL, NULL, NULL }, { "test.battery.stop", 0, NULL, "CT\r", "", 0, 0, "", 0, 0, NULL, QX_FLAG_CMD, NULL, NULL, NULL }, /* Server-side settable vars */ { "ups.delay.start", ST_FLAG_RW, blazer_r_ondelay, NULL, "", 0, 0, "", 0, 0, DEFAULT_ONDELAY, QX_FLAG_ABSENT | QX_FLAG_SETVAR | QX_FLAG_RANGE, NULL, NULL, blazer_process_setvar }, { "ups.delay.shutdown", ST_FLAG_RW, blazer_r_offdelay, NULL, "", 0, 0, "", 0, 0, DEFAULT_OFFDELAY, QX_FLAG_ABSENT | QX_FLAG_SETVAR | QX_FLAG_RANGE, NULL, NULL, blazer_process_setvar }, /* End of structure. */ { NULL, 0, NULL, NULL, "", 0, 0, "", 0, 0, NULL, 0, NULL, NULL, NULL } }; /* Testing table */ #ifdef TESTING static testing_t q1_testing[] = { { "Q1\r", "(215.0 195.0 230.0 014 49.0 22.7 30.0 00000000\r", -1 }, { "Q\r", "", -1 }, { "S03\r", "", -1 }, { "C\r", "", -1 }, { "S02R0005\r", "", -1 }, { "S.5R0000\r", "", -1 }, { "T04\r", "", -1 }, { "TL\r", "", -1 }, { "T\r", "", -1 }, { "CT\r", "", -1 }, { NULL } }; #endif /* TESTING */ /* Subdriver-specific initups */ static void q1_initups(void) { blazer_initups_light(q1_qx2nut); } /* Subdriver interface */ subdriver_t q1_subdriver = { Q1_VERSION, blazer_claim_light, q1_qx2nut, q1_initups, NULL, blazer_makevartable_light, "ACK", NULL, #ifdef TESTING q1_testing, #endif /* TESTING */ }; nut-2.8.1/drivers/cps-hid.h0000644000175000017500000000204114273170601012425 00000000000000/* cps-hid.h - subdriver to monitor CPS USB/HID devices with NUT * * Copyright (C) * 2003 - 2005 Arnaud Quette * 2005 - 2006 Peter Selinger * * 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 2 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, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #ifndef CPS_HID_H #define CPS_HID_H #include "usbhid-ups.h" extern subdriver_t cps_subdriver; #endif /* CPS_HID_H */ nut-2.8.1/drivers/libhid.c0000644000175000017500000012240114501607135012330 00000000000000/*! * @file libhid.c * @brief HID Library - User API (Generic HID Access using MGE HIDParser) * * @author Copyright (C) 2003 - 2007 * Arnaud Quette && * John Stamp * Peter Selinger * Arjen de Korte * * This program is sponsored by MGE UPS SYSTEMS - opensource.mgeups.com * * The logic of this file is ripped from mge-shut driver (also from * Arnaud Quette), which is a "HID over serial link" UPS driver for * Network UPS Tools * * 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 2 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, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * * -------------------------------------------------------------------------- */ #include "config.h" /* must be the first header */ #include #ifdef HAVE_STRING_H # include #endif #ifdef HAVE_STRINGS_H # include #endif /* #include */ #include "libhid.h" #include "hidparser.h" #include "common.h" /* for xmalloc, upsdebugx prototypes */ #include "nut_stdint.h" /* Communication layers and drivers (USB and MGE SHUT) */ #if (defined SHUT_MODE) && SHUT_MODE #include "libshut.h" communication_subdriver_t *comm_driver = &shut_subdriver; #else /* !SHUT_MODE => USB */ #include "nut_libusb.h" communication_subdriver_t *comm_driver = &usb_subdriver; #endif /* SHUT_MODE / USB */ /* support functions */ static double logical_to_physical(HIDData_t *Data, long logical); static long physical_to_logical(HIDData_t *Data, double physical); static const char *hid_lookup_path(const HIDNode_t usage, usage_tables_t *utab); static long hid_lookup_usage(const char *name, usage_tables_t *utab); static int string_to_path(const char *string, HIDPath_t *path, usage_tables_t *utab); static int path_to_string(char *string, size_t size, const HIDPath_t *path, usage_tables_t *utab); static int8_t get_unit_expo(const HIDData_t *hiddata); static double exponent(double a, int8_t b); /* Tweak flag for APC Back-UPS */ size_t max_report_size = 0; /* Tweaks for Powercom, at least */ int interrupt_only = 0; size_t interrupt_size = 0; #define SMIN(a, b) ( ((intmax_t)(a) < (intmax_t)(b)) ? (a) : (b) ) #define UMIN(a, b) ( ((uintmax_t)(a) < (uintmax_t)(b)) ? (a) : (b) ) /* ---------------------------------------------------------------------- */ /* report buffering system */ /* HID data items are retrieved via "reports". Each report is identified by a report ID, which is an integer in the range 0-255. Each report can hold several items. To avoid retrieving a given report multiple times in short succession, we use a data structure called a "report buffer". The functions in this group operate on entire *reports*, not individual data items. */ void free_report_buffer(reportbuf_t *rbuf) { int i; if (!rbuf) return; for (i=0; i<256; i++) { free(rbuf->data[i]); } free(rbuf); } /* allocate a new report buffer. Return pointer on success, else NULL with errno set. The returned data structure must later be freed with free_report_buffer(). */ reportbuf_t *new_report_buffer(HIDDesc_t *arg_pDesc) { HIDData_t *pData; reportbuf_t *rbuf; int id; size_t i; if (!arg_pDesc) return NULL; rbuf = calloc(1, sizeof(*rbuf)); if (!rbuf) { return NULL; } /* now go through all items that are part of this report */ for (i=0; initems; i++) { pData = &arg_pDesc->item[i]; id = pData->ReportID; /* skip reports that already have been allocated */ if (rbuf->data[id]) continue; /* first byte holds id */ rbuf->len[id] = arg_pDesc->replen[id] + 1; /* skip zero length reports */ if (rbuf->len[id] < 1) { continue; } rbuf->data[id] = calloc(rbuf->len[id], sizeof(*(rbuf->data[id]))); if (rbuf->data[id]) continue; /* on failure, give up what we got so far */ free_report_buffer(rbuf); return NULL; } return rbuf; } /* ---------------------------------------------------------------------- */ /* the functions in this next group operate on buffered reports, but operate on individual items, not whole reports. */ /* refresh the report with the given id in the report buffer rbuf. If the report is not yet in the buffer, or if it is older than "age" seconds, then the report is freshly read from the USB device. Otherwise, it is unchanged. Return 0 on success, -1 on error with errno set. */ /* because buggy firmwares from APC return wrong report size, we either ask the report with the found report size or with the whole buffer size depending on the max_report_size flag */ static int refresh_report_buffer(reportbuf_t *rbuf, hid_dev_handle_t udev, HIDData_t *pData, time_t age) { usb_ctrl_repindex id = pData->ReportID; int ret; size_t r; if (interrupt_only || rbuf->ts[id] + age > time(NULL)) { /* buffered report is still good; nothing to do */ upsdebug_hex(3, "Report[buf]", rbuf->data[id], rbuf->len[id]); return 0; } r = max_report_size ? sizeof(rbuf->data[id]) : rbuf->len[id]; #if (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_PUSH_POP) && ( (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_TYPE_LIMITS) || (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_TAUTOLOGICAL_CONSTANT_OUT_OF_RANGE_COMPARE) || (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_TAUTOLOGICAL_UNSIGNED_ZERO_COMPARE) || (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_UNREACHABLE_CODE) || (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_TAUTOLOGICAL_TYPE_LIMIT_COMPARE) ) # pragma GCC diagnostic push #endif #ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_TYPE_LIMITS # pragma GCC diagnostic ignored "-Wtype-limits" #endif #ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_TAUTOLOGICAL_CONSTANT_OUT_OF_RANGE_COMPARE # pragma GCC diagnostic ignored "-Wtautological-constant-out-of-range-compare" #endif #ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_TAUTOLOGICAL_UNSIGNED_ZERO_COMPARE # pragma GCC diagnostic ignored "-Wtautological-unsigned-zero-compare" #endif #ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_TAUTOLOGICAL_TYPE_LIMIT_COMPARE # pragma GCC diagnostic ignored "-Wtautological-type-limit-compare" #endif #ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_UNREACHABLE_CODE #pragma GCC diagnostic ignored "-Wunreachable-code" #endif /* Older CLANG (e.g. clang-3.4) seems to not support the GCC pragmas above */ #ifdef __clang__ #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wunreachable-code" #pragma clang diagnostic ignored "-Wtautological-compare" #pragma clang diagnostic ignored "-Wtautological-constant-out-of-range-compare" #endif if ((uintmax_t)r > (uintmax_t)USB_CTRL_CHARBUFSIZE_MAX) { upsdebugx(2, "%s: suggested buffer size %" PRIuSIZE " exceeds " "USB_CTRL_CHARBUFSIZE_MAX %" PRIuMAX "; " "report will be constrained", __func__, r, (uintmax_t)USB_CTRL_CHARBUFSIZE_MAX); if ((uintmax_t)USB_CTRL_CHARBUFSIZE_MAX <= (uintmax_t)SIZE_MAX && USB_CTRL_CHARBUFSIZE_MAX > 0) { r = (size_t)USB_CTRL_CHARBUFSIZE_MAX - 1; } else { /* SIZE_MAX is obviously too much here; least common * denominator across libs can be UINT8 or UINT16. * We should never hit this codepath unless definition * above is bonkers, anyway. */ r = (size_t)UINT8_MAX - 1; } /* Avoid overflowing known buffer size, to be sure: */ r = UMIN(r, sizeof(rbuf->data[id])); if (!max_report_size) { r = UMIN(r, rbuf->len[id]); } } #ifdef __clang__ #pragma clang diagnostic pop #endif #if (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_PUSH_POP) && ( (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_TYPE_LIMITS) || (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_TAUTOLOGICAL_CONSTANT_OUT_OF_RANGE_COMPARE) || (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_TAUTOLOGICAL_UNSIGNED_ZERO_COMPARE) || (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_UNREACHABLE_CODE) || (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_TAUTOLOGICAL_TYPE_LIMIT_COMPARE) ) # pragma GCC diagnostic pop #endif ret = comm_driver->get_report(udev, id, (usb_ctrl_charbuf)rbuf->data[id], (usb_ctrl_charbufsize)r); if (ret <= 0) { return -1; } r = (size_t)ret; if (rbuf->len[id] != r) { /* e.g. if maxreportsize flag was set */ upsdebugx(2, "%s: expected %" PRIuSIZE " bytes, but got %" PRIuSIZE " instead", __func__, rbuf->len[id], r); upsdebug_hex(3, "Report[err]", (usb_ctrl_charbuf)rbuf->data[id], r); } else { upsdebug_hex(3, "Report[get]", (usb_ctrl_charbuf)rbuf->data[id], rbuf->len[id]); } /* have (valid) report */ time(&rbuf->ts[id]); return 0; } /* read the logical value for the given pData. No logical to physical conversion is performed. If age>0, the read operation is buffered if the item's age is less than "age". On success, return 0 and store the answer in *value. On failure, return -1 and set errno. */ static int get_item_buffered(reportbuf_t *rbuf, hid_dev_handle_t udev, HIDData_t *pData, long *Value, time_t age) { int id = pData->ReportID; int r; r = refresh_report_buffer(rbuf, udev, pData, age); if (r<0) { return -1; } GetValue(rbuf->data[id], pData, Value); return 0; } /* set the logical value for the given pData. No physical to logical conversion is performed. On success, return 0, and failure, return -1 and set errno. The updated value is sent to the device. */ static int set_item_buffered(reportbuf_t *rbuf, hid_dev_handle_t udev, HIDData_t *pData, long Value) { usb_ctrl_repindex id = pData->ReportID; int ret; size_t r = rbuf->len[id]; SetValue(pData, rbuf->data[id], Value); #if (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_PUSH_POP) && ( (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_TYPE_LIMITS) || (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_TAUTOLOGICAL_CONSTANT_OUT_OF_RANGE_COMPARE) || (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_TAUTOLOGICAL_UNSIGNED_ZERO_COMPARE) || (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_UNREACHABLE_CODE) || (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_TAUTOLOGICAL_TYPE_LIMIT_COMPARE) ) # pragma GCC diagnostic push #endif #ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_TYPE_LIMITS # pragma GCC diagnostic ignored "-Wtype-limits" #endif #ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_TAUTOLOGICAL_CONSTANT_OUT_OF_RANGE_COMPARE # pragma GCC diagnostic ignored "-Wtautological-constant-out-of-range-compare" #endif #ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_TAUTOLOGICAL_UNSIGNED_ZERO_COMPARE # pragma GCC diagnostic ignored "-Wtautological-unsigned-zero-compare" #endif #ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_TAUTOLOGICAL_TYPE_LIMIT_COMPARE # pragma GCC diagnostic ignored "-Wtautological-type-limit-compare" #endif #ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_UNREACHABLE_CODE #pragma GCC diagnostic ignored "-Wunreachable-code" #endif /* Older CLANG (e.g. clang-3.4) seems to not support the GCC pragmas above */ #ifdef __clang__ #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wunreachable-code" #pragma clang diagnostic ignored "-Wtautological-compare" #pragma clang diagnostic ignored "-Wtautological-constant-out-of-range-compare" #endif if ((uintmax_t)r > (uintmax_t)USB_CTRL_CHARBUFSIZE_MAX) { upsdebugx(2, "%s: suggested buffer size %" PRIuSIZE " exceeds " "USB_CTRL_CHARBUFSIZE_MAX %" PRIuMAX "; " "item setting will be constrained", __func__, r, (uintmax_t)USB_CTRL_CHARBUFSIZE_MAX); if ((uintmax_t)USB_CTRL_CHARBUFSIZE_MAX <= (uintmax_t)SIZE_MAX && USB_CTRL_CHARBUFSIZE_MAX > 0) { r = (size_t)USB_CTRL_CHARBUFSIZE_MAX - 1; } else { /* SIZE_MAX is obviously too much here; least common * denominator across libs can be UINT8 or UINT16. * We should never hit this codepath unless definition * above is bonkers, anyway. */ r = (size_t)UINT8_MAX - 1; } } #ifdef __clang__ #pragma clang diagnostic pop #endif #if (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_PUSH_POP) && ( (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_TYPE_LIMITS) || (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_TAUTOLOGICAL_CONSTANT_OUT_OF_RANGE_COMPARE) || (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_TAUTOLOGICAL_UNSIGNED_ZERO_COMPARE) || (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_UNREACHABLE_CODE) || (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_TAUTOLOGICAL_TYPE_LIMIT_COMPARE) ) # pragma GCC diagnostic pop #endif ret = comm_driver->set_report(udev, id, (usb_ctrl_charbuf)rbuf->data[id], (usb_ctrl_charbufsize)r); if (ret <= 0) { return -1; } upsdebug_hex(3, "Report[set]", rbuf->data[id], r); /* expire report */ rbuf->ts[id] = 0; return 0; } /* file a given report in the report buffer. This is used when the report has been obtained without having been explicitly requested, e.g., it arrived through an interrupt transfer. Returns 0 on success, -1 on error with errno set. */ static int file_report_buffer(reportbuf_t *rbuf, unsigned char *buf, size_t buflen) { int id = buf[0]; /* broken report descriptors are common, so store whatever we can */ memcpy(rbuf->data[id], buf, (buflen < rbuf->len[id]) ? buflen : rbuf->len[id]); if (rbuf->len[id] != buflen) { upsdebugx(2, "%s: expected %" PRIuSIZE " bytes, but got %" PRIuSIZE " instead", __func__, rbuf->len[id], buflen); upsdebug_hex(3, "Report[err]", buf, buflen); } else { upsdebug_hex(3, "Report[int]", rbuf->data[id], rbuf->len[id]); } /* have (valid) report */ time(&rbuf->ts[id]); return 0; } /* ---------------------------------------------------------------------- */ /* Units and exponents table (HID PDC, 3.2.3) */ #define NB_HID_UNITS 10 static struct { const long Type; const int8_t Expo; } HIDUnits[NB_HID_UNITS] = { { 0x00000000, 0 }, /* None */ { 0x00F0D121, 7 }, /* Voltage */ { 0x00100001, 0 }, /* Ampere */ { 0x0000D121, 7 }, /* VA */ { 0x0000D121, 7 }, /* Watts */ { 0x00001001, 0 }, /* second */ { 0x00010001, 0 }, /* K */ { 0x00000000, 0 }, /* percent */ { 0x0000F001, 0 }, /* Hertz */ { 0x00101001, 0 }, /* As */ }; /* ---------------------------------------------------------------------- */ /* CAUTION: be careful when modifying the output format of this function, * since it's used to produce sub-drivers "stub" using * scripts/subdriver/gen-usbhid-subdriver.sh */ void HIDDumpTree(hid_dev_handle_t udev, HIDDevice_t *hd, usage_tables_t *utab) { size_t i; #if (defined SHUT_MODE) && SHUT_MODE NUT_UNUSED_VARIABLE(hd); #else /* !SHUT_MODE => USB */ /* extract the VendorId for further testing */ int vendorID = hd->VendorID; int productID = hd->ProductID; #endif /* SHUT_MODE / USB */ /* Do not go further if we already know nothing will be displayed. * Some reports take a while before they timeout, so if these are * not used in the driver, they should only be fetched when we're * in debug mode */ if (nut_debug_level < 1) { return; } upsdebugx(1, "%" PRIuSIZE " HID objects found", pDesc->nitems); for (i = 0; i < pDesc->nitems; i++) { double value; HIDData_t *pData = &pDesc->item[i]; /* skip reports 254/255 for Eaton / MGE / Dell due to special handling needs */ #if (defined SHUT_MODE) && SHUT_MODE if ((pData->ReportID == 254) || (pData->ReportID == 255)) { continue; } #else /* !SHUT_MODE => USB */ if ((vendorID == 0x0463) || (vendorID == 0x047c)) { if ((pData->ReportID == 254) || (pData->ReportID == 255)) { continue; } } /* skip report 0x54 for Tripplite SU3000LCD2UHV due to firmware bug */ if ((vendorID == 0x09ae) && (productID == 0x1330)) { if (pData->ReportID == 0x54) { continue; } } #endif /* SHUT_MODE / USB */ /* Get data value */ if (HIDGetDataValue(udev, pData, &value, MAX_TS) == 1) { upsdebugx(1, "Path: %s, Type: %s, ReportID: 0x%02x, Offset: %i, Size: %i, Value: %g", HIDGetDataItem(pData, utab), HIDDataType(pData), pData->ReportID, pData->Offset, pData->Size, value); continue; } upsdebugx(1, "Path: %s, Type: %s, ReportID: 0x%02x, Offset: %i, Size: %i", HIDGetDataItem(pData, utab), HIDDataType(pData), pData->ReportID, pData->Offset, pData->Size); } fflush(stdout); } /* Returns text string which can be used to display type of data */ const char *HIDDataType(const HIDData_t *hiddata) { switch (hiddata->Type) { case ITEM_FEATURE: return "Feature"; case ITEM_INPUT: return "Input"; case ITEM_OUTPUT: return "Output"; default: return "Unknown"; } } /* Returns pointer to the corresponding HIDData_t item * or NULL if path is not found in report descriptor */ HIDData_t *HIDGetItemData(const char *hidpath, usage_tables_t *utab) { int r; HIDPath_t Path; r = string_to_path(hidpath, &Path, utab); if (r <= 0) { return NULL; } /* Get info on object (reportID, offset and size) */ return FindObject_with_Path(pDesc, &Path, interrupt_only ? ITEM_INPUT:ITEM_FEATURE); } char *HIDGetDataItem(const HIDData_t *hiddata, usage_tables_t *utab) { /* TODO: not thread safe! */ static char itemPath[128]; path_to_string(itemPath, sizeof(itemPath), &hiddata->Path, utab); return itemPath; } /* Return the physical value associated with the given HIDData path. * return 1 if OK, 0 on fail, -errno otherwise (ie disconnect). */ int HIDGetDataValue(hid_dev_handle_t udev, HIDData_t *hiddata, double *Value, time_t age) { int r; long hValue; if (hiddata == NULL) { return 0; } r = get_item_buffered(reportbuf, udev, hiddata, &hValue, age); if (r<0) { upsdebug_with_errno(1, "Can't retrieve Report %02x", hiddata->ReportID); return -errno; } *Value = hValue; /* Convert Logical Min, Max and Value into Physical */ *Value = logical_to_physical(hiddata, hValue); /* Process exponents and units */ *Value *= exponent(10, get_unit_expo(hiddata)); return 1; } /* Return the physical value associated with the given path. * return 1 if OK, 0 on fail, -errno otherwise (ie disconnect). */ int HIDGetItemValue(hid_dev_handle_t udev, const char *hidpath, double *Value, usage_tables_t *utab) { return HIDGetDataValue(udev, HIDGetItemData(hidpath, utab), Value, MAX_TS); } /* Return pointer to indexed string (empty if not found) */ char *HIDGetIndexString(hid_dev_handle_t udev, const int Index, char *buf, size_t buflen) { usb_ctrl_strindex idx; #if (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_PUSH_POP) && ( (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_TYPE_LIMITS) || (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_TAUTOLOGICAL_CONSTANT_OUT_OF_RANGE_COMPARE) || (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_TAUTOLOGICAL_UNSIGNED_ZERO_COMPARE) || (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_UNREACHABLE_CODE) || (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_TAUTOLOGICAL_TYPE_LIMIT_COMPARE) ) # pragma GCC diagnostic push #endif #ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_TYPE_LIMITS # pragma GCC diagnostic ignored "-Wtype-limits" #endif #ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_TAUTOLOGICAL_CONSTANT_OUT_OF_RANGE_COMPARE # pragma GCC diagnostic ignored "-Wtautological-constant-out-of-range-compare" #endif #ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_TAUTOLOGICAL_UNSIGNED_ZERO_COMPARE # pragma GCC diagnostic ignored "-Wtautological-unsigned-zero-compare" #endif #ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_TAUTOLOGICAL_TYPE_LIMIT_COMPARE # pragma GCC diagnostic ignored "-Wtautological-type-limit-compare" #endif #ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_UNREACHABLE_CODE #pragma GCC diagnostic ignored "-Wunreachable-code" #endif /* Older CLANG (e.g. clang-3.4) seems to not support the GCC pragmas above */ #ifdef __clang__ #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wunreachable-code" #pragma clang diagnostic ignored "-Wtautological-compare" #pragma clang diagnostic ignored "-Wtautological-constant-out-of-range-compare" #endif if ((uintmax_t)Index > (uintmax_t)USB_CTRL_STRINDEX_MAX || (intmax_t)Index < (intmax_t)USB_CTRL_STRINDEX_MIN ) { upsdebugx(2, "%s: requested index number is out of range, " "expected %" PRIdMAX " < %i < %" PRIuMAX, __func__, (intmax_t)USB_CTRL_STRINDEX_MIN, Index, (uintmax_t)USB_CTRL_STRINDEX_MAX); return NULL; } idx = (usb_ctrl_strindex)Index; if ((uintmax_t)buflen > (uintmax_t)USB_CTRL_CHARBUFSIZE_MAX) { upsdebugx(2, "%s: suggested buffer size %" PRIuSIZE " exceeds " "USB_CTRL_CHARBUFSIZE_MAX %" PRIuMAX "; " "index string will be constrained", __func__, buflen, (uintmax_t)USB_CTRL_CHARBUFSIZE_MAX); if ((uintmax_t)USB_CTRL_CHARBUFSIZE_MAX <= (uintmax_t)SIZE_MAX && USB_CTRL_CHARBUFSIZE_MAX > 0) { buflen = (size_t)USB_CTRL_CHARBUFSIZE_MAX - 1; } else { /* SIZE_MAX is obviously too much here; least common * denominator across libs can be UINT8 or UINT16. * We should never hit this codepath unless definition * above is bonkers, anyway. */ buflen = (size_t)UINT8_MAX - 1; } } #ifdef __clang__ #pragma clang diagnostic pop #endif #if (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_PUSH_POP) && ( (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_TYPE_LIMITS) || (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_TAUTOLOGICAL_CONSTANT_OUT_OF_RANGE_COMPARE) || (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_TAUTOLOGICAL_UNSIGNED_ZERO_COMPARE) || (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_UNREACHABLE_CODE) || (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_TAUTOLOGICAL_TYPE_LIMIT_COMPARE) ) # pragma GCC diagnostic pop #endif if (comm_driver->get_string(udev, idx, buf, (usb_ctrl_charbufsize)buflen) < 1) buf[0] = '\0'; return str_rtrim(buf, '\n'); } /* Return pointer to indexed string from HID path (empty if not found) */ char *HIDGetItemString(hid_dev_handle_t udev, const char *hidpath, char *buf, size_t buflen, usage_tables_t *utab) { double Index; if (HIDGetDataValue(udev, HIDGetItemData(hidpath, utab), &Index, MAX_TS) != 1) { buf[0] = '\0'; return buf; } return HIDGetIndexString(udev, Index, buf, buflen); } /* Set the given physical value for the variable associated with * path. return 1 if OK, 0 on fail, -errno otherwise (ie disconnect). */ int HIDSetDataValue(hid_dev_handle_t udev, HIDData_t *hiddata, double Value) { int r; long hValue; if (hiddata == NULL) { return 0; } /* Test if Item is settable */ /* FIXME: not constant == volatile, but * it doesn't imply that it's RW! */ if (hiddata->Attribute == ATTR_DATA_CST) { return 0; } /* Process exponents and units */ Value /= exponent(10, get_unit_expo(hiddata)); /* Convert Physical Min, Max and Value into Logical */ hValue = physical_to_logical(hiddata, Value); r = set_item_buffered(reportbuf, udev, hiddata, hValue); if (r<0) { upsdebug_with_errno(1, "Can't set Report %02x", hiddata->ReportID); return -errno; } /* flush the report buffer (data may have changed) */ memset(reportbuf->ts, 0, sizeof(reportbuf->ts)); upsdebugx(4, "Set report succeeded"); return 1; } bool_t HIDSetItemValue(hid_dev_handle_t udev, const char *hidpath, double Value, usage_tables_t *utab) { if (HIDSetDataValue(udev, HIDGetItemData(hidpath, utab), Value) != 1) return FALSE; return TRUE; } /* On success, return item count >0. When no notifications are available, * return 'error' or 'no event' code. */ int HIDGetEvents(hid_dev_handle_t udev, HIDData_t **event, int eventsize) { unsigned char buf[SMALLBUF]; int itemCount = 0; int buflen, ret; size_t i, r; HIDData_t *pData; /* needs libusb-0.1.8 to work => use ifdef and autoconf */ r = (interrupt_size > 0 && interrupt_size < sizeof(buf)) ? interrupt_size : sizeof(buf); #if (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_PUSH_POP) && ( (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_TYPE_LIMITS) || (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_TAUTOLOGICAL_CONSTANT_OUT_OF_RANGE_COMPARE) || (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_TAUTOLOGICAL_UNSIGNED_ZERO_COMPARE) || (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_UNREACHABLE_CODE) || (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_TAUTOLOGICAL_TYPE_LIMIT_COMPARE) ) # pragma GCC diagnostic push #endif #ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_TYPE_LIMITS # pragma GCC diagnostic ignored "-Wtype-limits" #endif #ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_TAUTOLOGICAL_CONSTANT_OUT_OF_RANGE_COMPARE # pragma GCC diagnostic ignored "-Wtautological-constant-out-of-range-compare" #endif #ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_TAUTOLOGICAL_UNSIGNED_ZERO_COMPARE # pragma GCC diagnostic ignored "-Wtautological-unsigned-zero-compare" #endif #ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_TAUTOLOGICAL_TYPE_LIMIT_COMPARE # pragma GCC diagnostic ignored "-Wtautological-type-limit-compare" #endif #ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_UNREACHABLE_CODE #pragma GCC diagnostic ignored "-Wunreachable-code" #endif /* Older CLANG (e.g. clang-3.4) seems to not support the GCC pragmas above */ #ifdef __clang__ #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wunreachable-code" #pragma clang diagnostic ignored "-Wtautological-compare" #pragma clang diagnostic ignored "-Wtautological-constant-out-of-range-compare" #endif if ((uintmax_t)r > (uintmax_t)USB_CTRL_CHARBUFSIZE_MAX) { /* FIXME: Should we try here, or plain abort? */ upsdebugx(2, "%s: suggested buffer size %" PRIuSIZE " exceeds " "USB_CTRL_CHARBUFSIZE_MAX %" PRIuMAX "; " "report will be constrained", __func__, r, (uintmax_t)USB_CTRL_CHARBUFSIZE_MAX); if ((uintmax_t)USB_CTRL_CHARBUFSIZE_MAX <= (uintmax_t)SIZE_MAX && USB_CTRL_CHARBUFSIZE_MAX > 0) { r = (size_t)USB_CTRL_CHARBUFSIZE_MAX - 1; } else { /* SIZE_MAX is obviously too much here; least common * denominator across libs can be UINT8 or UINT16. * We should never hit this codepath unless definition * above is bonkers, anyway. */ r = (size_t)UINT8_MAX - 1; } /* Avoid overflowing known buffer size, to be sure: */ r = UMIN(r, sizeof(buf)); } #ifdef __clang__ #pragma clang diagnostic pop #endif #if (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_PUSH_POP) && ( (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_TYPE_LIMITS) || (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_TAUTOLOGICAL_CONSTANT_OUT_OF_RANGE_COMPARE) || (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_TAUTOLOGICAL_UNSIGNED_ZERO_COMPARE) || (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_UNREACHABLE_CODE) || (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_TAUTOLOGICAL_TYPE_LIMIT_COMPARE) ) # pragma GCC diagnostic pop #endif buflen = comm_driver->get_interrupt( udev, (usb_ctrl_charbuf)buf, (usb_ctrl_charbufsize)r, 750); if (buflen <= 0) { return buflen; /* propagate "error" or "no event" code */ } ret = file_report_buffer(reportbuf, buf, (size_t)buflen); if (ret < 0) { upsdebug_with_errno(1, "%s: failed to buffer report", __func__); return -errno; } /* now read all items that are part of this report */ for (i=0; initems; i++) { pData = &pDesc->item[i]; /* Variable not part of this report */ if (pData->ReportID != buf[0]) continue; /* Not an input report */ if (pData->Type != ITEM_INPUT) continue; /* maximum number of events reached? */ if (itemCount >= eventsize) { upsdebugx(1, "%s: too many events (truncated)", __func__); break; } event[itemCount++] = pData; } if (itemCount == 0) { upsdebugx(1, "%s: unexpected input report (ignored)", __func__); } return itemCount; } /******************************************************* * Support functions *******************************************************/ static double logical_to_physical(HIDData_t *Data, long logical) { double physical; double Factor; upsdebugx(5, "PhyMax = %ld, PhyMin = %ld, LogMax = %ld, LogMin = %ld", Data->PhyMax, Data->PhyMin, Data->LogMax, Data->LogMin); /* HID spec says that if one or both are undefined, or if they are * both 0, then PhyMin = LogMin, PhyMax = LogMax. */ if (!Data->have_PhyMax || !Data->have_PhyMin || (Data->PhyMax == 0 && Data->PhyMin == 0)) { return (double)logical; } /* Paranoia */ if ((Data->PhyMax <= Data->PhyMin) || (Data->LogMax <= Data->LogMin)) { /* this should not really happen */ upsdebugx(5, "Max was not greater than Min, returning logical value as is"); return (double)logical; } Factor = (double)(Data->PhyMax - Data->PhyMin) / (Data->LogMax - Data->LogMin); /* Convert Value */ physical = (double)((logical - Data->LogMin) * Factor) + Data->PhyMin; if (physical > Data->PhyMax) { return Data->PhyMax; } if (physical < Data->PhyMin) { return Data->PhyMin; } return physical; } static long physical_to_logical(HIDData_t *Data, double physical) { long logical; double Factor; upsdebugx(5, "PhyMax = %ld, PhyMin = %ld, LogMax = %ld, LogMin = %ld", Data->PhyMax, Data->PhyMin, Data->LogMax, Data->LogMin); /* HID spec says that if one or both are undefined, or if they are * both 0, then PhyMin = LogMin, PhyMax = LogMax. */ if (!Data->have_PhyMax || !Data->have_PhyMin || (Data->PhyMax == 0 && Data->PhyMin == 0)) { return (long)physical; } /* Paranoia */ if ((Data->PhyMax <= Data->PhyMin) || (Data->LogMax <= Data->LogMin)) { /* this should not really happen */ upsdebugx(5, "Max was not greater than Min, returning physical value as is"); return (long)physical; } Factor = (double)(Data->LogMax - Data->LogMin) / (Data->PhyMax - Data->PhyMin); /* Convert Value */ logical = (long)((physical - Data->PhyMin) * Factor) + Data->LogMin; if (logical > Data->LogMax) return Data->LogMax; if (logical < Data->LogMin) return Data->LogMin; return logical; } static int8_t get_unit_expo(const HIDData_t *hiddata) { int i; int8_t unit_expo = hiddata->UnitExp; upsdebugx(5, "Unit = %08x, UnitExp = %d", (uint32_t)(hiddata->Unit), hiddata->UnitExp); for (i = 0; i < NB_HID_UNITS; i++) { if (HIDUnits[i].Type == hiddata->Unit) { unit_expo -= HIDUnits[i].Expo; break; } } upsdebugx(5, "Exponent = %d", unit_expo); return unit_expo; } /* exponent function: return a^b */ static double exponent(double a, int8_t b) { if (b>0) return (a * exponent(a, --b)); /* a * a ... */ if (b<0) return ((1/a) * exponent(a, ++b)); /* (1/a) * (1/a) ... */ return 1; } /* translate HID string path to numeric path and return path depth */ static int string_to_path(const char *string, HIDPath_t *path, usage_tables_t *utab) { int i = 0; long usage; char buf[SMALLBUF]; char *token, *last; snprintf(buf, sizeof(buf), "%s", string); for (token = strtok_r(buf, ".", &last); token != NULL; token = strtok_r(NULL, ".", &last)) { /* lookup tables first (to override defaults) */ /* Note/FIXME?: we happen to process "usage" as a "signed long" * while the HIDNode_t behind it is (currently) uint32_t. * The method below returns `-1` for entries not found; however * half of our permissible range may seem negative and be valid. */ if ((usage = hid_lookup_usage(token, utab)) != -1) { path->Node[i++] = (HIDNode_t)usage; continue; } else { /* hid_lookup_usage() logs for itself: ... -> not found in lookup table */ upsdebugx(5, "string_to_path: hid_lookup_usage failed, " "checking if token %s is a raw value", token); } /* translate unnamed path components such as "ff860024" */ if (strlen(token) == strspn(token, "1234567890abcdefABCDEF")) { long l = strtol(token, NULL, 16); /* Note: currently per hidtypes.h, HIDNode_t == uint32_t */ if (l < 0 || (uintmax_t)l > (uintmax_t)UINT32_MAX) { upsdebugx(5, "string_to_path: badvalue (pathcomp): " "%ld negative or %" PRIuMAX " too large", l, (uintmax_t)l); goto badvalue; } path->Node[i++] = (HIDNode_t)l; continue; } /* indexed collection */ if (strlen(token) == strspn(token, "[1234567890]")) { int l = atoi(token + 1); /* +1: skip the bracket */ if (l < 0 || (uintmax_t)l > (uintmax_t)UINT32_MAX) { upsdebugx(5, "string_to_path: badvalue(indexed): " "%d negative or %" PRIuMAX " too large", l, (uintmax_t)l); goto badvalue; } path->Node[i++] = 0x00ff0000 + (HIDNode_t)l; continue; } badvalue: /* Uh oh, typo in usage table? */ upsdebugx(1, "string_to_path: couldn't parse %s from %s", token, string); } if (i < 0 || i > (int)UINT8_MAX) { fatalx(EXIT_FAILURE, "Error: string_to_path(): length exceeded"); } path->Size = (uint8_t)i; /* by construct, i>=0; but anyway checked above to be sure */ upsdebugx(4, "string_to_path: depth = %d", path->Size); return i; } /* translate HID numeric path to string path and return path depth */ static int path_to_string(char *string, size_t size, const HIDPath_t *path, usage_tables_t *utab) { int i; const char *p; snprintf(string, size, "%s", ""); for (i = 0; i < path->Size; i++) { if (i > 0) snprintfcat(string, size, "."); /* lookup tables first (to override defaults) */ if ((p = hid_lookup_path(path->Node[i], utab)) != NULL) { snprintfcat(string, size, "%s", p); continue; } /* indexed collection */ if ((path->Node[i] & 0xffff0000) == 0x00ff0000) { snprintfcat(string, size, "[%i]", path->Node[i] & 0x0000ffff); continue; } /* unnamed path components such as "ff860024" */ snprintfcat(string, size, "%08x", path->Node[i]); } return i; } /* usage conversion string -> numeric * Returns -1 for error, or a (HIDNode_t) ranged code value */ static long hid_lookup_usage(const char *name, usage_tables_t *utab) { int i, j; for (i = 0; utab[i] != NULL; i++) { for (j = 0; utab[i][j].usage_name != NULL; j++) { if (strcasecmp(utab[i][j].usage_name, name)) continue; /* Note: currently per hidtypes.h, HIDNode_t == uint32_t */ upsdebugx(5, "hid_lookup_usage: %s -> %08x", name, (uint32_t)utab[i][j].usage_code); return (long)(utab[i][j].usage_code); } } upsdebugx(5, "hid_lookup_usage: %s -> not found in lookup table", name); return -1; } /* usage conversion numeric -> string */ static const char *hid_lookup_path(const HIDNode_t usage, usage_tables_t *utab) { int i, j; for (i = 0; utab[i] != NULL; i++) { for (j = 0; utab[i][j].usage_name != NULL; j++) { if (utab[i][j].usage_code != usage) continue; upsdebugx(5, "hid_lookup_path: %08x -> %s", (unsigned int)usage, utab[i][j].usage_name); return utab[i][j].usage_name; } } upsdebugx(5, "hid_lookup_path: %08x -> not found in lookup table", (unsigned int)usage); return NULL; } /* Lookup this usage name to find its code (page + index) */ /* temporary usage code lookup */ /* FIXME: put as external data, like in usb.ids (or use * this last?) */ /* Global usage table (from USB HID class definition) */ usage_lkp_t hid_usage_lkp[] = { /* Power Device Page */ { "Undefined", 0x00840000 }, { "iName", 0x00840001 }, { "PresentStatus", 0x00840002 }, { "ChangedStatus", 0x00840003 }, { "UPS", 0x00840004 }, { "PowerSupply", 0x00840005 }, /* 0x00840006-0x0084000f => Reserved */ { "BatterySystem", 0x00840010 }, { "BatterySystemID", 0x00840011 }, { "Battery", 0x00840012 }, { "BatteryID", 0x00840013 }, { "Charger", 0x00840014 }, { "ChargerID", 0x00840015 }, { "PowerConverter", 0x00840016 }, { "PowerConverterID", 0X00840017 }, { "OutletSystem", 0x00840018 }, { "OutletSystemID", 0x00840019 }, { "Input", 0x0084001a }, { "InputID", 0x0084001b }, { "Output", 0x0084001c }, { "OutputID", 0x0084001d }, { "Flow", 0x0084001e }, { "FlowID", 0x0084001f }, { "Outlet", 0x00840020 }, { "OutletID", 0x00840021 }, { "Gang", 0x00840022 }, { "GangID", 0x00840023 }, { "PowerSummary", 0x00840024 }, { "PowerSummaryID", 0x00840025 }, /* 0x00840026-0x0084002f => Reserved */ { "Voltage", 0x00840030 }, { "Current", 0x00840031 }, { "Frequency", 0x00840032 }, { "ApparentPower", 0x00840033 }, { "ActivePower", 0x00840034 }, { "PercentLoad", 0x00840035 }, { "Temperature", 0x00840036 }, { "Humidity", 0x00840037 }, { "BadCount", 0x00840038 }, /* 0x00840039-0x0084003f => Reserved */ { "ConfigVoltage", 0x00840040 }, { "ConfigCurrent", 0x00840041 }, { "ConfigFrequency", 0x00840042 }, { "ConfigApparentPower", 0x00840043 }, { "ConfigActivePower", 0x00840044 }, { "ConfigPercentLoad", 0x00840045 }, { "ConfigTemperature", 0x00840046 }, { "ConfigHumidity", 0x00840047 }, /* 0x00840048-0x0084004f => Reserved */ { "SwitchOnControl", 0x00840050 }, { "SwitchOffControl", 0x00840051 }, { "ToggleControl", 0x00840052 }, { "LowVoltageTransfer", 0x00840053 }, { "HighVoltageTransfer", 0x00840054 }, { "DelayBeforeReboot", 0x00840055 }, { "DelayBeforeStartup", 0x00840056 }, { "DelayBeforeShutdown", 0x00840057 }, { "Test", 0x00840058 }, { "ModuleReset", 0x00840059 }, { "AudibleAlarmControl", 0x0084005a }, /* 0x0084005b-0x0084005f => Reserved */ { "Present", 0x00840060 }, { "Good", 0x00840061 }, { "InternalFailure", 0x00840062 }, { "VoltageOutOfRange", 0x00840063 }, { "FrequencyOutOfRange", 0x00840064 }, { "Overload", 0x00840065 }, /* Note: the correct spelling is "Overload", not "OverLoad", * according to the official specification, "Universal Serial * Bus Usage Tables for HID Power Devices", Release 1.0, * November 1, 1997 */ { "OverCharged", 0x00840066 }, { "OverTemperature", 0x00840067 }, { "ShutdownRequested", 0x00840068 }, { "ShutdownImminent", 0x00840069 }, { "SwitchOn/Off", 0x0084006b }, { "Switchable", 0x0084006c }, { "Used", 0x0084006d }, { "Boost", 0x0084006e }, { "Buck", 0x0084006f }, { "Initialized", 0x00840070 }, { "Tested", 0x00840071 }, { "AwaitingPower", 0x00840072 }, { "CommunicationLost", 0x00840073 }, /* 0x00840074-0x008400fc => Reserved */ { "iManufacturer", 0x008400fd }, { "iProduct", 0x008400fe }, { "iSerialNumber", 0x008400ff }, /* Battery System Page */ { "Undefined", 0x00850000 }, { "SMBBatteryMode", 0x00850001 }, { "SMBBatteryStatus", 0x00850002 }, { "SMBAlarmWarning", 0x00850003 }, { "SMBChargerMode", 0x00850004 }, { "SMBChargerStatus", 0x00850005 }, { "SMBChargerSpecInfo", 0x00850006 }, { "SMBSelectorState", 0x00850007 }, { "SMBSelectorPresets", 0x00850008 }, { "SMBSelectorInfo", 0x00850009 }, /* 0x0085000A-0x0085000f => Reserved */ { "OptionalMfgFunction1", 0x00850010 }, { "OptionalMfgFunction2", 0x00850011 }, { "OptionalMfgFunction3", 0x00850012 }, { "OptionalMfgFunction4", 0x00850013 }, { "OptionalMfgFunction5", 0x00850014 }, { "ConnectionToSMBus", 0x00850015 }, { "OutputConnection", 0x00850016 }, { "ChargerConnection", 0x00850017 }, { "BatteryInsertion", 0x00850018 }, { "Usenext", 0x00850019 }, { "OKToUse", 0x0085001a }, { "BatterySupported", 0x0085001b }, { "SelectorRevision", 0x0085001c }, { "ChargingIndicator", 0x0085001d }, /* 0x0085001e-0x00850027 => Reserved */ { "ManufacturerAccess", 0x00850028 }, { "RemainingCapacityLimit", 0x00850029 }, { "RemainingTimeLimit", 0x0085002a }, { "AtRate", 0x0085002b }, { "CapacityMode", 0x0085002c }, { "BroadcastToCharger", 0x0085002d }, { "PrimaryBattery", 0x0085002e }, { "ChargeController", 0x0085002f }, /* 0x00850030-0x0085003f => Reserved */ { "TerminateCharge", 0x00850040 }, { "TerminateDischarge", 0x00850041 }, { "BelowRemainingCapacityLimit", 0x00850042 }, { "RemainingTimeLimitExpired", 0x00850043 }, { "Charging", 0x00850044 }, { "Discharging", 0x00850045 }, { "FullyCharged", 0x00850046 }, { "FullyDischarged", 0x00850047 }, { "ConditioningFlag", 0x00850048 }, { "AtRateOK", 0x00850049 }, { "SMBErrorCode", 0x0085004a }, { "NeedReplacement", 0x0085004b }, /* 0x0085004c-0x0085005f => Reserved */ { "AtRateTimeToFull", 0x00850060 }, { "AtRateTimeToEmpty", 0x00850061 }, { "AverageCurrent", 0x00850062 }, { "Maxerror", 0x00850063 }, { "RelativeStateOfCharge", 0x00850064 }, { "AbsoluteStateOfCharge", 0x00850065 }, { "RemainingCapacity", 0x00850066 }, { "FullChargeCapacity", 0x00850067 }, { "RunTimeToEmpty", 0x00850068 }, { "AverageTimeToEmpty", 0x00850069 }, { "AverageTimeToFull", 0x0085006a }, { "CycleCount", 0x0085006b }, /* 0x0085006c-0x0085007f => Reserved */ { "BattPackModelLevel", 0x00850080 }, { "InternalChargeController", 0x00850081 }, { "PrimaryBatterySupport", 0x00850082 }, { "DesignCapacity", 0x00850083 }, { "SpecificationInfo", 0x00850084 }, { "ManufacturerDate", 0x00850085 }, { "SerialNumber", 0x00850086 }, { "iManufacturerName", 0x00850087 }, { "iDevicename", 0x00850088 }, /* sic! */ { "iDeviceChemistry", 0x00850089 }, /* misspelled as "iDeviceChemistery" in spec. */ { "ManufacturerData", 0x0085008a }, { "Rechargeable", 0x0085008b }, { "WarningCapacityLimit", 0x0085008c }, { "CapacityGranularity1", 0x0085008d }, { "CapacityGranularity2", 0x0085008e }, { "iOEMInformation", 0x0085008f }, /* 0x00850090-0x008500bf => Reserved */ { "InhibitCharge", 0x008500c0 }, { "EnablePolling", 0x008500c1 }, { "ResetToZero", 0x008500c2 }, /* 0x008500c3-0x008500cf => Reserved */ { "ACPresent", 0x008500d0 }, { "BatteryPresent", 0x008500d1 }, { "PowerFail", 0x008500d2 }, { "AlarmInhibited", 0x008500d3 }, { "ThermistorUnderRange", 0x008500d4 }, { "ThermistorHot", 0x008500d5 }, { "ThermistorCold", 0x008500d6 }, { "ThermistorOverRange", 0x008500d7 }, { "VoltageOutOfRange", 0x008500d8 }, { "CurrentOutOfRange", 0x008500d9 }, { "CurrentNotRegulated", 0x008500da }, { "VoltageNotRegulated", 0x008500db }, { "MasterMode", 0x008500dc }, /* 0x008500dd-0x008500ef => Reserved */ { "ChargerSelectorSupport", 0x008500f0 }, { "ChargerSpec", 0x008500f1 }, { "Level2", 0x008500f2 }, { "Level3", 0x008500f3 }, /* 0x008500f4-0x008500ff => Reserved */ /* end of structure. */ { NULL, 0 } }; nut-2.8.1/drivers/eaton-ats16-nmc-mib.h0000644000175000017500000000216314500336654014472 00000000000000/* eaton_ats16-nmc-mib.h - subdriver to monitor Eaton ATS16 NMC SNMP devices with NUT * * Copyright (C) * 2011-2012 Arnaud Quette * 2016-2017 Eaton (author: Arnaud Quette ) * * 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 2 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, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef EATON_ATS16_NMC_MIB_H #define EATON_ATS16_NMC_MIB_H #include "main.h" #include "snmp-ups.h" extern mib2nut_info_t eaton_ats16_nmc; #endif /* EATON_ATS16_NMC_MIB_H */ nut-2.8.1/drivers/clone.c0000644000175000017500000003441114513167372012207 00000000000000/* * clone.c: UPS driver clone * * Copyright (C) 2009 - Arjen de Korte * * 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 2 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, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "config.h" #include "main.h" #include "parseconf.h" #include "attribute.h" #include "nut_stdint.h" #include #ifndef WIN32 #include #include #endif #define DRIVER_NAME "Clone UPS driver" #define DRIVER_VERSION "0.04" /* driver description structure */ upsdrv_info_t upsdrv_info = { DRIVER_NAME, DRIVER_VERSION, "Arjen de Korte ", DRV_EXPERIMENTAL, { NULL } }; static struct { struct { long start; long shutdown; } timer; char status[ST_MAX_VALUE_LEN]; } ups = { { -1, -1 }, "WAIT" }; static struct { struct { double act; double low; } charge; struct { double act; double low; } runtime; } battery = { { 0, 0 }, { 0, 0 } }; static int dumpdone = 0, online = 1, outlet = 1; static long offdelay = 120, ondelay = 30; static PCONF_CTX_t sock_ctx; static time_t last_poll = 0, last_heard = 0, last_ping = 0; #ifndef WIN32 static time_t last_connfail = 0; #else static char read_buf[SMALLBUF]; static OVERLAPPED read_overlapped; #endif static int instcmd(const char *cmdname, const char *extra); static int parse_args(size_t numargs, char **arg) { if (numargs < 1) { return 0; } if (!strcasecmp(arg[0], "PONG")) { upsdebugx(3, "Got PONG from UPS"); return 1; } if (!strcasecmp(arg[0], "DUMPDONE")) { upsdebugx(3, "UPS: dump is done"); dumpdone = 1; return 1; } if (!strcasecmp(arg[0], "DATASTALE")) { dstate_datastale(); return 1; } if (!strcasecmp(arg[0], "DATAOK")) { dstate_dataok(); return 1; } if (numargs < 2) { return 0; } /* DELINFO */ if (!strcasecmp(arg[0], "DELINFO")) { dstate_delinfo(arg[1]); return 1; } if (numargs < 3) { return 0; } /* SETINFO */ if (!strcasecmp(arg[0], "SETINFO")) { if (!strncasecmp(arg[1], "driver.", 7) || !strcasecmp(arg[1], "battery.charge.low") || !strcasecmp(arg[1], "battery.runtime.low") || !strncasecmp(arg[1], "ups.delay.", 10) || !strncasecmp(arg[1], "ups.timer.", 10)) { /* don't pass on upstream driver settings */ return 1; } if (!strcasecmp(arg[1], "ups.status")) { snprintf(ups.status, sizeof(ups.status), "%s", arg[2]); online = strstr(ups.status, "OL") ? 1 : 0; if (ups.timer.shutdown > 0) { dstate_setinfo("ups.status", "FSD %s", ups.status); return 1; } } if (!strcasecmp(arg[1], "battery.charge")) { battery.charge.act = strtod(arg[2], NULL); dstate_setinfo("battery.charge.low", "%g", battery.charge.low); dstate_setflags("battery.charge.low", ST_FLAG_RW | ST_FLAG_STRING); dstate_setaux("battery.charge.low", 3); } if (!strcasecmp(arg[1], "battery.runtime")) { battery.runtime.act = strtod(arg[2], NULL); dstate_setinfo("battery.runtime.low", "%g", battery.runtime.low); dstate_setflags("battery.runtime.low", ST_FLAG_RW | ST_FLAG_STRING); dstate_setaux("battery.runtime.low", 4); } dstate_setinfo(arg[1], "%s", arg[2]); return 1; } return 0; } static TYPE_FD sstate_connect(void) { TYPE_FD fd; #ifndef WIN32 ssize_t ret; int len; const char *dumpcmd = "DUMPALL\n"; struct sockaddr_un sa; memset(&sa, '\0', sizeof(sa)); sa.sun_family = AF_UNIX; len = snprintf(sa.sun_path, sizeof(sa.sun_path), "%s/%s", dflt_statepath(), device_path); if (len < 0) { fatalx(EXIT_FAILURE, "Can't create a unix domain socket: " "failed to prepare the pathname"); } if ((uintmax_t)len >= (uintmax_t)sizeof(sa.sun_path)) { fatalx(EXIT_FAILURE, "Can't create a unix domain socket: pathname '%s/%s' " "is too long (%" PRIuSIZE ") for 'struct sockaddr_un->sun_path' " "on this system (%" PRIuSIZE ")", dflt_statepath(), device_path, strlen(dflt_statepath()) + 1 + strlen(device_path), sizeof(sa.sun_path)); } fd = socket(AF_UNIX, SOCK_STREAM, 0); if (INVALID_FD(fd)) { upslog_with_errno(LOG_ERR, "Can't create socket for UPS [%s]", device_path); return ERROR_FD; } ret = connect(fd, (struct sockaddr *) &sa, sizeof(sa)); if (ret < 0) { time_t now; close(fd); /* rate-limit complaints - don't spam the syslog */ time(&now); if (difftime(now, last_connfail) < 60) { return ERROR_FD; } last_connfail = now; upslog_with_errno(LOG_ERR, "Can't connect to UPS [%s]", device_path); return ERROR_FD; } ret = fcntl(fd, F_GETFL, 0); if (ret < 0) { upslog_with_errno(LOG_ERR, "fcntl get on UPS [%s] failed", device_path); close(fd); return ERROR_FD; } ret = fcntl(fd, F_SETFL, ret | O_NDELAY); if (ret < 0) { upslog_with_errno(LOG_ERR, "fcntl set O_NDELAY on UPS [%s] failed", device_path); close(fd); return ERROR_FD; } /* get a dump started so we have a fresh set of data */ ret = write(fd, dumpcmd, strlen(dumpcmd)); if (ret != (int)strlen(dumpcmd)) { upslog_with_errno(LOG_ERR, "Initial write to UPS [%s] failed", device_path); close(fd); return ERROR_FD; } /* continued below... */ #else /* WIN32 */ char pipename[SMALLBUF]; const char *dumpcmd = "DUMPALL\n"; BOOL result = FALSE; snprintf(pipename, sizeof(pipename), "\\\\.\\pipe\\%s/%s", dflt_statepath(), device_path); result = WaitNamedPipe(pipename,NMPWAIT_USE_DEFAULT_WAIT); if (result == FALSE) { return ERROR_FD; } fd = CreateFile( pipename, /* pipe name */ GENERIC_READ | /* read and write access */ GENERIC_WRITE, 0, /* no sharing */ NULL, /* default security attributes FIXME */ OPEN_EXISTING, /* opens existing pipe */ FILE_FLAG_OVERLAPPED, /* enable async IO */ NULL); /* no template file */ if (fd == INVALID_HANDLE_VALUE) { upslog_with_errno(LOG_ERR, "Can't connect to UPS [%s]", device_path); return ERROR_FD; } /* get a dump started so we have a fresh set of data */ DWORD bytesWritten = 0; result = WriteFile (fd,dumpcmd,strlen(dumpcmd),&bytesWritten,NULL); if (result == 0 || bytesWritten != strlen(dumpcmd)) { upslog_with_errno(LOG_ERR, "Initial write to UPS [%s] failed", device_path); CloseHandle(fd); return ERROR_FD; } /* Start a read IO so we could wait on the event associated with it */ ReadFile(fd, read_buf, sizeof(read_buf) - 1, /*-1 to be sure to have a trailling 0 */ NULL, &(read_overlapped)); #endif /* sstate_connect() continued for both platforms: */ pconf_init(&sock_ctx, NULL); time(&last_heard); dumpdone = 0; /* set ups.status to "WAIT" while waiting for the driver response to dumpcmd */ dstate_setinfo("ups.status", "WAIT"); upslogx(LOG_INFO, "Connected to UPS [%s]", device_path); return fd; } static void sstate_disconnect(void) { if (INVALID_FD(upsfd)) { /* Already disconnected... or not yet? ;) */ return; } pconf_finish(&sock_ctx); #ifndef WIN32 close(upsfd); #else CloseHandle(upsfd); #endif upsfd = ERROR_FD; } static int sstate_sendline(const char *buf) { ssize_t ret; if (INVALID_FD(upsfd)) { return -1; /* failed */ } #ifndef WIN32 ret = write(upsfd, buf, strlen(buf)); #else DWORD bytesWritten = 0; BOOL result = FALSE; result = WriteFile (upsfd,buf,strlen(buf),&bytesWritten,NULL); if (result == 0) { ret = 0; } else { ret = (int)bytesWritten; } #endif if (ret == (int)strlen(buf)) { return 0; } upslog_with_errno(LOG_NOTICE, "Send to UPS [%s] failed", device_path); return -1; /* failed */ } static int sstate_readline(void) { int i; ssize_t ret; #ifndef WIN32 char buf[SMALLBUF]; if (INVALID_FD(upsfd)) { return -1; /* failed */ } ret = read(upsfd, buf, sizeof(buf)); if (ret < 0) { switch(errno) { case EINTR: case EAGAIN: return 0; default: upslog_with_errno(LOG_WARNING, "Read from UPS [%s] failed", device_path); return -1; } } #else if (INVALID_FD(upsfd)) { return -1; /* failed */ } /* FIXME? I do not see this buf or read_buf filled below */ char *buf = read_buf; DWORD bytesRead; GetOverlappedResult(upsfd, &read_overlapped, &bytesRead, FALSE); ret = bytesRead; #endif for (i = 0; i < ret; i++) { switch (pconf_char(&sock_ctx, buf[i])) { case 1: if (parse_args(sock_ctx.numargs, sock_ctx.arglist)) { time(&last_heard); } continue; case 0: continue; /* haven't gotten a line yet */ default: /* parse error */ upslogx(LOG_NOTICE, "Parse error on sock: %s", sock_ctx.errmsg); return -1; } } return 0; } static int sstate_dead(int maxage) { time_t now; double elapsed; /* an unconnected ups is always dead */ if (INVALID_FD(upsfd)) { upsdebugx(3, "sstate_dead: connection to driver socket for UPS [%s] lost", device_path); return -1; /* dead */ } time(&now); /* ignore DATAOK/DATASTALE unless the dump is done */ if (dumpdone && dstate_is_stale()) { upsdebugx(3, "sstate_dead: driver for UPS [%s] says data is stale", device_path); return -1; /* dead */ } elapsed = difftime(now, last_heard); /* somewhere beyond a third of the maximum time - prod it to make it talk */ if ((elapsed > (maxage / 3)) && (difftime(now, last_ping) > (maxage / 3))) { upsdebugx(3, "Send PING to UPS"); sstate_sendline("PING\n"); last_ping = now; } if (elapsed > maxage) { upsdebugx(3, "sstate_dead: didn't hear from driver for UPS [%s] for %g seconds (max %d)", device_path, elapsed, maxage); return -1; /* dead */ } return 0; } static int instcmd(const char *cmdname, const char *extra) { const char *val; val = dstate_getinfo(getval("load.status")); if (val) { if (!strcasecmp(val, "off") || !strcasecmp(val, "no")) { outlet = 0; } if (!strcasecmp(val, "on") || !strcasecmp(val, "yes")) { outlet = 1; } } if (!strcasecmp(cmdname, "shutdown.return")) { if (outlet && (ups.timer.shutdown < 0)) { ups.timer.shutdown = offdelay; dstate_setinfo("ups.status", "FSD %s", ups.status); } ups.timer.start = ondelay; return STAT_INSTCMD_HANDLED; } if (!strcasecmp(cmdname, "shutdown.stayoff")) { if (outlet && (ups.timer.shutdown < 0)) { ups.timer.shutdown = offdelay; dstate_setinfo("ups.status", "FSD %s", ups.status); } ups.timer.start = -1; return STAT_INSTCMD_HANDLED; } upslogx(LOG_NOTICE, "instcmd: unknown command [%s] [%s]", cmdname, extra); return STAT_INSTCMD_UNKNOWN; } static int setvar(const char *varname, const char *val) { if (!strcasecmp(varname, "battery.charge.low")) { battery.charge.low = strtod(val, NULL); dstate_setinfo("battery.charge.low", "%g", battery.charge.low); return STAT_SET_HANDLED; } if (!strcasecmp(varname, "battery.runtime.low")) { battery.runtime.low = strtod(val, NULL); dstate_setinfo("battery.runtime.low", "%g", battery.runtime.low); return STAT_SET_HANDLED; } upslogx(LOG_NOTICE, "setvar: unknown variable [%s]", varname); return STAT_SET_UNKNOWN; } void upsdrv_initinfo(void) { const char *val; time(&last_poll); dstate_addcmd("shutdown.return"); dstate_addcmd("shutdown.stayoff"); val = getval("offdelay"); if (val) { offdelay = strtol(val, NULL, 10); } val = getval("ondelay"); if (val) { ondelay = strtol(val, NULL, 10); } val = getval("mincharge"); if (val) { battery.charge.low = strtod(val, NULL); } val = getval("minruntime"); if (val) { battery.runtime.low = strtod(val, NULL); } dstate_setinfo("ups.delay.shutdown", "%ld", offdelay); dstate_setinfo("ups.delay.start", "%ld", ondelay); dstate_setinfo("ups.timer.shutdown", "%ld", ups.timer.shutdown); dstate_setinfo("ups.timer.start", "%ld", ups.timer.start); upsh.instcmd = instcmd; upsh.setvar = setvar; } void upsdrv_updateinfo(void) { time_t now = time(NULL); if (sstate_dead(15)) { sstate_disconnect(); extrafd = upsfd = sstate_connect(); return; } if (sstate_readline()) { sstate_disconnect(); return; } if (ups.timer.shutdown >= 0) { ups.timer.shutdown -= (suseconds_t)(difftime(now, last_poll)); if (ups.timer.shutdown < 0) { const char *val; ups.timer.shutdown = -1; outlet = 0; val = getval("load.off"); if (val) { char buf[SMALLBUF]; snprintf(buf, sizeof(buf), "INSTCMD %s\n", val); sstate_sendline(buf); } } } else if (ups.timer.start >= 0) { if (online) { ups.timer.start -= (suseconds_t)(difftime(now, last_poll)); } else { ups.timer.start = ondelay; } if (ups.timer.start < 0) { const char *val; ups.timer.start = -1; outlet = 1; val = getval("load.on"); if (val) { char buf[SMALLBUF]; snprintf(buf, sizeof(buf), "INSTCMD %s\n", val); sstate_sendline(buf); } dstate_setinfo("ups.status", "%s", ups.status); } } else if (!online && outlet) { if (battery.charge.act < battery.charge.low) { upslogx(LOG_INFO, "Battery charge low"); instcmd("shutdown.return", NULL); } else if (battery.runtime.act < battery.runtime.low) { upslogx(LOG_INFO, "Battery runtime low"); instcmd("shutdown.return", NULL); } } dstate_setinfo("ups.timer.shutdown", "%ld", ups.timer.shutdown); dstate_setinfo("ups.timer.start", "%ld", ups.timer.start); last_poll = now; } void upsdrv_shutdown(void) { /* replace with a proper shutdown function */ upslogx(LOG_ERR, "shutdown not supported"); set_exit_flag(-1); } void upsdrv_help(void) { } void upsdrv_makevartable(void) { addvar(VAR_VALUE, "offdelay", "Delay before outlet shutdown (seconds)"); addvar(VAR_VALUE, "ondelay", "Delay before outlet startup (seconds)"); addvar(VAR_VALUE, "mincharge", "Remaining battery level when UPS switches to LB (percent)"); addvar(VAR_VALUE, "minruntime", "Remaining battery runtime when UPS switches to LB (seconds)"); addvar(VAR_VALUE, "load.off", "Command to switch off outlet"); addvar(VAR_VALUE, "load.on", "Command to switch on outlet"); addvar(VAR_VALUE, "load.status", "Variable that indicates outlet is on/off"); } void upsdrv_initups(void) { extrafd = upsfd = sstate_connect(); } void upsdrv_cleanup(void) { sstate_disconnect(); } nut-2.8.1/drivers/nutdrv_qx_mustek.c0000644000175000017500000001472714501607135014532 00000000000000/* nutdrv_qx_mustek.c - Subdriver for Mustek protocol based UPSes * * Copyright (C) * 2013 Daniele Pezzini * * 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 2 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, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #include "main.h" #include "nutdrv_qx.h" #include "nutdrv_qx_blazer-common.h" #include "nutdrv_qx_mustek.h" #define MUSTEK_VERSION "Mustek 0.08" /* qx2nut lookup table */ static item_t mustek_qx2nut[] = { /* * > [QS\r] * < [(226.0 195.0 226.0 014 49.0 27.5 30.0 00001000\r] * 01234567890123456789012345678901234567890123456 * 0 1 2 3 4 */ { "input.voltage", 0, NULL, "QS\r", "", 47, '(', "", 1, 5, "%.1f", 0, NULL, NULL, NULL }, { "input.voltage.fault", 0, NULL, "QS\r", "", 47, '(', "", 7, 11, "%.1f", 0, NULL, NULL, NULL }, { "output.voltage", 0, NULL, "QS\r", "", 47, '(', "", 13, 17, "%.1f", 0, NULL, NULL, NULL }, { "ups.load", 0, NULL, "QS\r", "", 47, '(', "", 19, 21, "%.0f", 0, NULL, NULL, NULL }, { "input.frequency", 0, NULL, "QS\r", "", 47, '(', "", 23, 26, "%.1f", 0, NULL, NULL, NULL }, { "battery.voltage", 0, NULL, "QS\r", "", 47, '(', "", 28, 31, "%.2f", 0, NULL, NULL, qx_multiply_battvolt }, { "ups.temperature", 0, NULL, "QS\r", "", 47, '(', "", 33, 36, "%.1f", 0, NULL, NULL, NULL }, /* Status bits */ { "ups.status", 0, NULL, "QS\r", "", 47, '(', "", 38, 38, NULL, QX_FLAG_QUICK_POLL, NULL, NULL, blazer_process_status_bits }, /* Utility Fail (Immediate) */ { "ups.status", 0, NULL, "QS\r", "", 47, '(', "", 39, 39, NULL, QX_FLAG_QUICK_POLL, NULL, NULL, blazer_process_status_bits }, /* Battery Low */ { "ups.status", 0, NULL, "QS\r", "", 47, '(', "", 40, 40, NULL, QX_FLAG_QUICK_POLL, NULL, NULL, blazer_process_status_bits }, /* Bypass/Boost or Buck Active */ { "ups.alarm", 0, NULL, "QS\r", "", 47, '(', "", 41, 41, NULL, 0, NULL, NULL, blazer_process_status_bits }, /* UPS Failed */ { "ups.type", 0, NULL, "QS\r", "", 47, '(', "", 42, 42, "%s", QX_FLAG_STATIC, NULL, NULL, blazer_process_status_bits }, /* UPS Type */ { "ups.status", 0, NULL, "QS\r", "", 47, '(', "", 43, 43, NULL, QX_FLAG_QUICK_POLL, NULL, NULL, blazer_process_status_bits }, /* Test in Progress */ { "ups.status", 0, NULL, "QS\r", "", 47, '(', "", 44, 44, NULL, QX_FLAG_QUICK_POLL, NULL, NULL, blazer_process_status_bits }, /* Shutdown Active */ { "ups.beeper.status", 0, NULL, "QS\r", "", 47, '(', "", 45, 45, "%s", 0, NULL, NULL, blazer_process_status_bits }, /* Beeper status */ /* * > [F\r] * < [#220.0 000 024.0 50.0\r] * 0123456789012345678901 * 0 1 2 */ { "input.voltage.nominal", 0, NULL, "F\r", "", 22, '#', "", 1, 5, "%.0f", QX_FLAG_STATIC, NULL, NULL, NULL }, { "input.current.nominal", 0, NULL, "F\r", "", 22, '#', "", 7, 9, "%.1f", QX_FLAG_STATIC, NULL, NULL, NULL }, { "battery.voltage.nominal", 0, NULL, "F\r", "", 22, '#', "", 11, 15, "%.1f", QX_FLAG_STATIC, NULL, NULL, NULL }, { "input.frequency.nominal", 0, NULL, "F\r", "", 22, '#', "", 17, 20, "%.0f", QX_FLAG_STATIC, NULL, NULL, NULL }, /* * > [I\r] * < [#------------- ------ VT12046Q \r] * 012345678901234567890123456789012345678 * 0 1 2 3 */ { "device.mfr", 0, NULL, "I\r", "", 39, '#', "", 1, 15, "%s", QX_FLAG_STATIC | QX_FLAG_TRIM, NULL, NULL, NULL }, { "device.model", 0, NULL, "I\r", "", 39, '#', "", 17, 26, "%s", QX_FLAG_STATIC | QX_FLAG_TRIM, NULL, NULL, NULL }, { "ups.firmware", 0, NULL, "I\r", "", 39, '#', "", 28, 37, "%s", QX_FLAG_STATIC | QX_FLAG_TRIM, NULL, NULL, NULL }, /* Instant commands */ { "beeper.toggle", 0, NULL, "Q\r", "", 0, 0, "", 0, 0, NULL, QX_FLAG_CMD, NULL, NULL, NULL }, { "load.off", 0, NULL, "S00R0000\r", "", 0, 0, "", 0, 0, NULL, QX_FLAG_CMD, NULL, NULL, NULL }, { "load.on", 0, NULL, "C\r", "", 0, 0, "", 0, 0, NULL, QX_FLAG_CMD, NULL, NULL, NULL }, { "shutdown.return", 0, NULL, "S%s\r", "", 0, 0, "", 0, 0, NULL, QX_FLAG_CMD, NULL, NULL, blazer_process_command }, { "shutdown.stayoff", 0, NULL, "S%sR0000\r", "", 0, 0, "", 0, 0, NULL, QX_FLAG_CMD, NULL, NULL, blazer_process_command }, { "shutdown.stop", 0, NULL, "C\r", "", 0, 0, "", 0, 0, NULL, QX_FLAG_CMD, NULL, NULL, NULL }, { "test.battery.start", 0, NULL, "T%02d\r", "", 0, 0, "", 0, 0, NULL, QX_FLAG_CMD, NULL, NULL, blazer_process_command }, { "test.battery.start.deep", 0, NULL, "TL\r", "", 0, 0, "", 0, 0, NULL, QX_FLAG_CMD, NULL, NULL, NULL }, { "test.battery.start.quick", 0, NULL, "T\r", "", 0, 0, "", 0, 0, NULL, QX_FLAG_CMD, NULL, NULL, NULL }, { "test.battery.stop", 0, NULL, "CT\r", "", 0, 0, "", 0, 0, NULL, QX_FLAG_CMD, NULL, NULL, NULL }, /* Server-side settable vars */ { "ups.delay.start", ST_FLAG_RW, blazer_r_ondelay, NULL, "", 0, 0, "", 0, 0, DEFAULT_ONDELAY, QX_FLAG_ABSENT | QX_FLAG_SETVAR | QX_FLAG_RANGE, NULL, NULL, blazer_process_setvar }, { "ups.delay.shutdown", ST_FLAG_RW, blazer_r_offdelay, NULL, "", 0, 0, "", 0, 0, DEFAULT_OFFDELAY, QX_FLAG_ABSENT | QX_FLAG_SETVAR | QX_FLAG_RANGE, NULL, NULL, blazer_process_setvar }, /* End of structure. */ { NULL, 0, NULL, NULL, "", 0, 0, "", 0, 0, NULL, 0, NULL, NULL, NULL } }; /* Testing table */ #ifdef TESTING static testing_t mustek_testing[] = { { "QS\r", "(215.0 195.0 230.0 014 49.0 22.7 30.0 00000000\r", -1 }, { "F\r", "#230.0 000 024.0 50.0\r", -1 }, { "I\r", "#NOT_A_LIVE_UPS TESTING TESTING \r", -1 }, { "Q\r", "", -1 }, { "S03\r", "", -1 }, { "C\r", "", -1 }, { "S02R0005\r", "", -1 }, { "S.5R0000\r", "", -1 }, { "T04\r", "", -1 }, { "TL\r", "", -1 }, { "T\r", "", -1 }, { "CT\r", "", -1 }, { NULL } }; #endif /* TESTING */ /* Subdriver-specific initups */ static void mustek_initups(void) { blazer_initups(mustek_qx2nut); } /* Subdriver interface */ subdriver_t mustek_subdriver = { MUSTEK_VERSION, blazer_claim_light, mustek_qx2nut, mustek_initups, NULL, blazer_makevartable, "ACK", NULL, #ifdef TESTING mustek_testing, #endif /* TESTING */ }; nut-2.8.1/drivers/apc-mib.c0000644000175000017500000004736514501607135012424 00000000000000/* apc-mib.c - data to monitor APC SNMP devices (Powernet MIB) with NUT * * Copyright (C) * 2002-2003 - Dmitry Frolov * 2002-2012 - Arnaud Quette * 2012 - Chew Hong Gunn (high precision values) * * Sponsored by MGE UPS SYSTEMS * * 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 2 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, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #include "apc-mib.h" #define APCC_MIB_VERSION "1.6" #define APC_UPS_DEVICE_MODEL ".1.3.6.1.4.1.318.1.1.1.1.1.1.0" /* FIXME: Find a better oid_auto_check vs sysOID for this one? */ #define APC_UPS_SYSOID APC_UPS_DEVICE_MODEL /* Other APC sysOID: * * examples found on the Net and other sources: * 'enterprises.apc.products.system.smartUPS.smartUPS700' * - from fence agents * '.1.3.6.1.4.1.318.1.3.4.5': ApcRPDU, * '.1.3.6.1.4.1.318.1.3.4.4': ApcMSP * - from Bill Seligman * .1.3.6.1.4.1.318.1.3.2.11 * .1.3.6.1.4.1.318.1.3.2.12 * .1.3.6.1.4.1.318.1.3.27 * .1.3.6.1.4.1.318.1.3.2.7 * .1.3.6.1.4.1.318.1.3.2.8 */ /* TODO: find the right sysOID for this MIB * Ie ".1.3.6.1.4.1.318.1.1.1" or ".1.3.6.1.4.1.318" or? */ /* .1.3.6.1.4.1.318.1.1.1 * enterprise^ * apc ---------^ * products ------^ * hardware --------^ * ups ---------------^ * ref: ftp://ftp.apc.com/apc/public/software/pnetmib/mib/404/powernet404.mib */ /* info elements */ #define APCC_OID_BATT_STATUS ".1.3.6.1.4.1.318.1.1.1.2.1.1.0" /* Defines for APCC_OID_BATT_STATUS */ static info_lkp_t apcc_batt_info[] = { { 1, "", NULL, NULL }, /* unknown */ { 2, "", NULL, NULL }, /* batteryNormal */ { 3, "LB", NULL, NULL }, /* batteryLow */ { 0, NULL, NULL, NULL } } ; #define APCC_OID_POWER_STATUS ".1.3.6.1.4.1.318.1.1.1.4.1.1.0" /* Defines for APCC_OID_POWER_STATUS */ static info_lkp_t apcc_pwr_info[] = { { 1, "", NULL, NULL }, /* unknown */ { 2, "OL", NULL, NULL }, /* onLine */ { 3, "OB", NULL, NULL }, /* onBattery */ { 4, "OL BOOST", NULL, NULL }, /* onSmartBoost */ { 5, "OFF", NULL, NULL }, /* timedSleeping */ { 6, "OFF", NULL, NULL }, /* softwareBypass */ { 7, "OFF", NULL, NULL }, /* off */ { 8, "", NULL, NULL }, /* rebooting */ { 9, "BYPASS", NULL, NULL }, /* switchedBypass */ { 10, "BYPASS", NULL, NULL }, /* hardwareFailureBypass */ { 11, "OFF", NULL, NULL }, /* sleepingUntilPowerReturn */ { 12, "OL TRIM", NULL, NULL }, /* onSmartTrim */ { 0, NULL, NULL, NULL } } ; #define APCC_OID_CAL_RESULTS ".1.3.6.1.4.1.318.1.1.1.7.2.6.0" static info_lkp_t apcc_cal_info[] = { { 1, "", NULL, NULL }, /* Calibration Successful */ { 2, "", NULL, NULL }, /* Calibration not done, battery capacity below 100% */ { 3, "CAL", NULL, NULL }, /* Calibration in progress */ { 0, NULL, NULL, NULL } }; #define APCC_OID_NEEDREPLBATT ".1.3.6.1.4.1.318.1.1.1.2.2.4.0" static info_lkp_t apcc_battrepl_info[] = { { 1, "", NULL, NULL }, /* No battery needs replacing */ { 2, "RB", NULL, NULL }, /* Batteries need to be replaced */ { 0, NULL, NULL, NULL } }; #define APCC_OID_TESTDIAGRESULTS ".1.3.6.1.4.1.318.1.1.1.7.2.3.0" static info_lkp_t apcc_testdiag_results[] = { { 1, "Ok", NULL, NULL }, { 2, "Failed", NULL, NULL }, { 3, "InvalidTest", NULL, NULL }, { 4, "TestInProgress", NULL, NULL }, { 0, NULL, NULL, NULL } }; #define APCC_OID_SENSITIVITY ".1.3.6.1.4.1.318.1.1.1.5.2.7.0" static info_lkp_t apcc_sensitivity_modes[] = { { 1, "auto", NULL, NULL }, { 2, "low", NULL, NULL }, { 3, "medium", NULL, NULL }, { 4, "high", NULL, NULL }, { 0, NULL, NULL, NULL } }; #define APCC_OID_TRANSFERREASON "1.3.6.1.4.1.318.1.1.1.3.2.5.0" static info_lkp_t apcc_transfer_reasons[] = { { 1, "noTransfer", NULL, NULL }, { 2, "highLineVoltage", NULL, NULL }, { 3, "brownout", NULL, NULL }, { 4, "blackout", NULL, NULL }, { 5, "smallMomentarySag", NULL, NULL }, { 6, "deepMomentarySag", NULL, NULL }, { 7, "smallMomentarySpike", NULL, NULL }, { 8, "largeMomentarySpike", NULL, NULL }, { 9, "selfTest", NULL, NULL }, { 10, "rateOfVoltageChange", NULL, NULL } }; /* --- */ /* commands */ #define APCC_OID_REBOOT ".1.3.6.1.4.1.318.1.1.1.6.2.2" #define APCC_REBOOT_DO 2 #define APCC_REBOOT_GRACEFUL 3 #if 0 /* not used. */ #define APCC_OID_SLEEP ".1.3.6.1.4.1.318.1.1.1.6.2.3" #define APCC_SLEEP_ON "2" #define APCC_SLEEP_GRACEFUL "3" #endif static snmp_info_t apcc_mib[] = { /* standard MIB items */ { "device.description", ST_FLAG_STRING | ST_FLAG_RW, SU_INFOSIZE, ".1.3.6.1.2.1.1.1.0", NULL, SU_FLAG_OK, NULL }, { "device.contact", ST_FLAG_STRING | ST_FLAG_RW, SU_INFOSIZE, ".1.3.6.1.2.1.1.4.0", NULL, SU_FLAG_OK, NULL }, { "device.location", ST_FLAG_STRING | ST_FLAG_RW, SU_INFOSIZE, ".1.3.6.1.2.1.1.6.0", NULL, SU_FLAG_OK, NULL }, /* info elements. */ { "ups.mfr", ST_FLAG_STRING, SU_INFOSIZE, NULL, "APC", SU_FLAG_STATIC | SU_FLAG_ABSENT | SU_FLAG_OK, NULL }, { "ups.model", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.318.1.1.1.1.1.1.0", "Generic Powernet SNMP device", SU_FLAG_STATIC | SU_FLAG_OK, NULL }, { "ups.serial", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.318.1.1.1.1.2.3.0", "", SU_FLAG_STATIC | SU_FLAG_OK, NULL }, { "ups.mfr.date", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.318.1.1.1.1.2.2.0", "", SU_FLAG_OK | SU_FLAG_STATIC, NULL }, { "input.voltage", 0, 0.1, ".1.3.6.1.4.1.318.1.1.1.3.3.1.0", "", SU_FLAG_OK | SU_FLAG_NEGINVALID | SU_FLAG_UNIQUE, NULL }, { "input.voltage.maximum", 0, 0.1, ".1.3.6.1.4.1.318.1.1.1.3.3.2.0", "", SU_FLAG_OK | SU_FLAG_NEGINVALID | SU_FLAG_UNIQUE, NULL }, { "input.voltage.minimum", 0, 0.1, ".1.3.6.1.4.1.318.1.1.1.3.3.3.0", "", SU_FLAG_OK | SU_FLAG_NEGINVALID | SU_FLAG_UNIQUE, NULL }, { "input.voltage", 0, 1, ".1.3.6.1.4.1.318.1.1.1.3.2.1.0", "", SU_FLAG_OK, NULL }, { "input.voltage.maximum", 0, 1, ".1.3.6.1.4.1.318.1.1.1.3.2.2.0", "", SU_FLAG_OK, NULL }, { "input.voltage.minimum", 0, 1, ".1.3.6.1.4.1.318.1.1.1.3.2.3.0", "", SU_FLAG_OK, NULL }, { "input.phases", ST_FLAG_STRING, 2, ".1.3.6.1.4.1.318.1.1.1.9.2.2.1.2.1", "", SU_FLAG_STATIC | SU_FLAG_OK, NULL }, { "input.L1-L2.voltage", 0, 1, ".1.3.6.1.4.1.318.1.1.1.9.2.3.1.3.1.1.1", "", SU_FLAG_OK|SU_FLAG_NEGINVALID, NULL }, { "input.L2-L3.voltage", 0, 1, ".1.3.6.1.4.1.318.1.1.1.9.2.3.1.3.1.1.2", "", SU_FLAG_OK|SU_FLAG_NEGINVALID, NULL }, { "input.L3-L1.voltage", 0, 1, ".1.3.6.1.4.1.318.1.1.1.9.2.3.1.3.1.1.3", "", SU_FLAG_OK|SU_FLAG_NEGINVALID, NULL }, { "input.L1-L2.voltage.maximum", 0, 1, ".1.3.6.1.4.1.318.1.1.1.9.2.3.1.4.1.1.1", "", SU_FLAG_OK|SU_FLAG_NEGINVALID, NULL }, { "input.L2-L3.voltage.maximum", 0, 1, ".1.3.6.1.4.1.318.1.1.1.9.2.3.1.4.1.1.2", "", SU_FLAG_OK|SU_FLAG_NEGINVALID, NULL }, { "input.L3-L1.voltage.maximum", 0, 1, ".1.3.6.1.4.1.318.1.1.1.9.2.3.1.4.1.1.3", "", SU_FLAG_OK|SU_FLAG_NEGINVALID, NULL }, { "input.L1-L2.voltage.minimum", 0, 1, ".1.3.6.1.4.1.318.1.1.1.9.2.3.1.5.1.1.1", "", SU_FLAG_OK|SU_FLAG_NEGINVALID, NULL }, { "input.L2-L3.voltage.minimum", 0, 1, ".1.3.6.1.4.1.318.1.1.1.9.2.3.1.5.1.1.2", "", SU_FLAG_OK|SU_FLAG_NEGINVALID, NULL }, { "input.L3-L1.voltage.minimum", 0, 1, ".1.3.6.1.4.1.318.1.1.1.9.2.3.1.5.1.1.3", "", SU_FLAG_OK|SU_FLAG_NEGINVALID, NULL }, { "input.L1.current", 0, 0.1, ".1.3.6.1.4.1.318.1.1.1.9.2.3.1.6.1.1.1", "", SU_FLAG_OK|SU_FLAG_NEGINVALID, NULL }, { "input.L2.current", 0, 0.1, ".1.3.6.1.4.1.318.1.1.1.9.2.3.1.6.1.1.2", "", SU_FLAG_OK|SU_FLAG_NEGINVALID, NULL }, { "input.L3.current", 0, 0.1, ".1.3.6.1.4.1.318.1.1.1.9.2.3.1.6.1.1.3", "", SU_FLAG_OK|SU_FLAG_NEGINVALID, NULL }, { "input.L1.current.maximum", 0, 0.1, ".1.3.6.1.4.1.318.1.1.1.9.2.3.1.7.1.1.1", "", SU_FLAG_OK|SU_FLAG_NEGINVALID, NULL }, { "input.L2.current.maximum", 0, 0.1, ".1.3.6.1.4.1.318.1.1.1.9.2.3.1.7.1.1.2", "", SU_FLAG_OK|SU_FLAG_NEGINVALID, NULL }, { "input.L3.current.maximum", 0, 0.1, ".1.3.6.1.4.1.318.1.1.1.9.2.3.1.7.1.1.3", "", SU_FLAG_OK|SU_FLAG_NEGINVALID, NULL }, { "input.L1.current.minimum", 0, 0.1, ".1.3.6.1.4.1.318.1.1.1.9.2.3.1.8.1.1.1", "", SU_FLAG_OK|SU_FLAG_NEGINVALID, NULL }, { "input.L2.current.minimum", 0, 0.1, ".1.3.6.1.4.1.318.1.1.1.9.2.3.1.8.1.1.2", "", SU_FLAG_OK|SU_FLAG_NEGINVALID, NULL }, { "input.L3.current.minimum", 0, 0.1, ".1.3.6.1.4.1.318.1.1.1.9.2.3.1.8.1.1.3", "", SU_FLAG_OK|SU_FLAG_NEGINVALID, NULL }, { "input.frequency", 0, 0.1, ".1.3.6.1.4.1.318.1.1.1.9.2.2.1.4.1", "", SU_FLAG_OK|SU_FLAG_NEGINVALID|SU_FLAG_UNIQUE, NULL }, { "input.frequency", 0, 0.1, ".1.3.6.1.4.1.318.1.1.1.3.3.4.0", "", SU_FLAG_OK|SU_FLAG_NEGINVALID|SU_FLAG_UNIQUE, NULL }, { "input.frequency", 0, 1, ".1.3.6.1.4.1.318.1.1.1.3.2.4.0", "", SU_FLAG_OK, NULL }, { "input.transfer.low", ST_FLAG_STRING | ST_FLAG_RW, 3, ".1.3.6.1.4.1.318.1.1.1.5.2.3.0", "", SU_TYPE_INT | SU_FLAG_OK, NULL }, { "input.transfer.high", ST_FLAG_STRING | ST_FLAG_RW, 3, ".1.3.6.1.4.1.318.1.1.1.5.2.2.0", "", SU_TYPE_INT | SU_FLAG_OK, NULL }, { "input.transfer.reason", ST_FLAG_STRING, 1, APCC_OID_TRANSFERREASON, "", SU_TYPE_INT | SU_FLAG_OK, apcc_transfer_reasons }, { "input.sensitivity", ST_FLAG_STRING | ST_FLAG_RW, 1, APCC_OID_SENSITIVITY, "", SU_TYPE_INT | SU_FLAG_OK, apcc_sensitivity_modes }, { "ups.power", 0, 1, ".1.3.6.1.4.1.318.1.1.1.4.2.9.0", "", SU_FLAG_OK, NULL }, { "ups.realpower", 0, 1, ".1.3.6.1.4.1.318.1.1.1.4.2.8.0", "", SU_FLAG_OK, NULL }, { "ups.status", ST_FLAG_STRING, SU_INFOSIZE, APCC_OID_POWER_STATUS, "OFF", SU_FLAG_OK | SU_STATUS_PWR, apcc_pwr_info }, { "ups.status", ST_FLAG_STRING, SU_INFOSIZE, APCC_OID_BATT_STATUS, "", SU_FLAG_OK | SU_STATUS_BATT, apcc_batt_info }, { "ups.status", ST_FLAG_STRING, SU_INFOSIZE, APCC_OID_CAL_RESULTS, "", SU_FLAG_OK | SU_STATUS_CAL, apcc_cal_info }, { "ups.status", ST_FLAG_STRING, SU_INFOSIZE, APCC_OID_NEEDREPLBATT, "", SU_FLAG_OK | SU_STATUS_RB, apcc_battrepl_info }, { "ups.temperature", 0, 0.1, ".1.3.6.1.4.1.318.1.1.1.2.3.2.0", "", SU_FLAG_OK|SU_FLAG_UNIQUE, NULL }, { "ups.temperature", 0, 1, ".1.3.6.1.4.1.318.1.1.1.2.2.2.0", "", SU_FLAG_OK, NULL }, { "ups.load", 0, 0.1, ".1.3.6.1.4.1.318.1.1.1.4.3.3.0", "", SU_FLAG_OK|SU_FLAG_NEGINVALID|SU_FLAG_UNIQUE, NULL }, { "ups.load", 0, 1, ".1.3.6.1.4.1.318.1.1.1.4.2.3.0", "", SU_FLAG_OK, NULL }, { "ups.firmware", ST_FLAG_STRING, 16, ".1.3.6.1.4.1.318.1.1.1.1.2.1.0", "", SU_FLAG_STATIC | SU_FLAG_OK, NULL }, { "ups.delay.shutdown", ST_FLAG_RW, 3, ".1.3.6.1.4.1.318.1.1.1.5.2.10.0", "", SU_TYPE_TIME | SU_FLAG_OK, NULL }, { "ups.delay.start", ST_FLAG_RW, 3, ".1.3.6.1.4.1.318.1.1.1.5.2.9.0", "", SU_TYPE_TIME | SU_FLAG_OK, NULL }, { "battery.charge", 0, 0.1, ".1.3.6.1.4.1.318.1.1.1.2.3.1.0", "", SU_FLAG_OK|SU_FLAG_NEGINVALID|SU_FLAG_UNIQUE, NULL }, { "battery.charge", 0, 1, ".1.3.6.1.4.1.318.1.1.1.2.2.1.0", "", SU_FLAG_OK, NULL }, { "battery.charge.restart", ST_FLAG_STRING | ST_FLAG_RW, 3, ".1.3.6.1.4.1.318.1.1.1.5.2.6.0", "", SU_TYPE_INT | SU_FLAG_OK, NULL }, { "battery.runtime", 0, 1, ".1.3.6.1.4.1.318.1.1.1.2.2.3.0", "", SU_FLAG_OK, NULL }, { "battery.runtime.low", ST_FLAG_STRING | ST_FLAG_RW, 3, ".1.3.6.1.4.1.318.1.1.1.5.2.8.0", "", SU_FLAG_OK, NULL }, { "battery.voltage", 0, 0.1, ".1.3.6.1.4.1.318.1.1.1.2.3.4.0", "", SU_FLAG_OK|SU_FLAG_NEGINVALID|SU_FLAG_UNIQUE, NULL }, { "battery.voltage", 0, 1, ".1.3.6.1.4.1.318.1.1.1.2.2.8.0", "", SU_FLAG_OK, NULL }, { "battery.voltage.nominal", 0, 1, ".1.3.6.1.4.1.318.1.1.1.2.2.7.0", "", SU_FLAG_OK, NULL }, { "battery.current", 0, 0.1, ".1.3.6.1.4.1.318.1.1.1.2.3.5.0", "", SU_FLAG_OK|SU_FLAG_UNIQUE, NULL }, { "battery.current", 0, 1, ".1.3.6.1.4.1.318.1.1.1.2.2.9.0", "", SU_FLAG_OK, NULL }, { "battery.current.total", 0, 0.1, ".1.3.6.1.4.1.318.1.1.1.2.3.6.0", "", SU_FLAG_OK, NULL }, { "battery.packs", 0, 1, ".1.3.6.1.4.1.318.1.1.1.2.2.5.0", "", SU_FLAG_OK, NULL }, { "battery.packs.bad", 0, 1, ".1.3.6.1.4.1.318.1.1.1.2.2.6.0", "", SU_FLAG_OK, NULL }, { "battery.date", ST_FLAG_STRING | ST_FLAG_RW, 8, ".1.3.6.1.4.1.318.1.1.1.2.1.3.0", "", SU_FLAG_OK | SU_FLAG_STATIC, NULL }, { "ups.id", ST_FLAG_STRING | ST_FLAG_RW, 8, ".1.3.6.1.4.1.318.1.1.1.1.1.2.0", "", SU_FLAG_OK | SU_FLAG_STATIC, NULL }, { "ups.test.result", ST_FLAG_STRING, SU_INFOSIZE, APCC_OID_TESTDIAGRESULTS, "", SU_FLAG_OK, apcc_testdiag_results }, { "ups.test.date", ST_FLAG_STRING | ST_FLAG_RW, 8, ".1.3.6.1.4.1.318.1.1.1.7.2.4.0", "", SU_FLAG_OK | SU_FLAG_STATIC, NULL }, { "output.voltage", 0, 0.1, ".1.3.6.1.4.1.318.1.1.1.4.3.1.0", "", SU_FLAG_OK | SU_FLAG_UNIQUE, NULL }, { "output.voltage", 0, 1, ".1.3.6.1.4.1.318.1.1.1.4.2.1.0", "", SU_FLAG_OK, NULL }, { "output.phases", ST_FLAG_STRING, 2, ".1.3.6.1.4.1.318.1.1.1.9.3.2.1.2.1", "", SU_FLAG_STATIC | SU_FLAG_OK, NULL }, { "output.frequency", 0, 0.1, ".1.3.6.1.4.1.318.1.1.1.9.3.2.1.4.1", "", SU_FLAG_OK|SU_FLAG_NEGINVALID|SU_FLAG_UNIQUE, NULL }, { "output.frequency", 0, 0.1, ".1.3.6.1.4.1.318.1.1.1.4.3.2.0", "", SU_FLAG_OK|SU_FLAG_NEGINVALID|SU_FLAG_UNIQUE, NULL }, { "output.frequency", 0, 1, ".1.3.6.1.4.1.318.1.1.1.4.2.2.0", "", SU_FLAG_OK, NULL }, { "output.current", 0, 0.1, ".1.3.6.1.4.1.318.1.1.1.4.3.4.0", "", SU_FLAG_OK|SU_FLAG_NEGINVALID|SU_FLAG_UNIQUE, NULL }, { "output.current", 0, 1, ".1.3.6.1.4.1.318.1.1.1.4.2.4.0", "", SU_FLAG_OK, NULL }, { "output.L1-L2.voltage", 0, 1, ".1.3.6.1.4.1.318.1.1.1.9.3.3.1.3.1.1.1", "", SU_FLAG_OK|SU_FLAG_NEGINVALID, NULL }, { "output.L2-L3.voltage", 0, 1, ".1.3.6.1.4.1.318.1.1.1.9.3.3.1.3.1.1.2", "", SU_FLAG_OK|SU_FLAG_NEGINVALID, NULL }, { "output.L3-L1.voltage", 0, 1, ".1.3.6.1.4.1.318.1.1.1.9.3.3.1.3.1.1.3", "", SU_FLAG_OK|SU_FLAG_NEGINVALID, NULL }, { "output.L1.current", 0, 0.1, ".1.3.6.1.4.1.318.1.1.1.9.3.3.1.4.1.1.1", "", SU_FLAG_OK|SU_FLAG_NEGINVALID, NULL }, { "output.L2.current", 0, 0.1, ".1.3.6.1.4.1.318.1.1.1.9.3.3.1.4.1.1.2", "", SU_FLAG_OK|SU_FLAG_NEGINVALID, NULL }, { "output.L3.current", 0, 0.1, ".1.3.6.1.4.1.318.1.1.1.9.3.3.1.4.1.1.3", "", SU_FLAG_OK|SU_FLAG_NEGINVALID, NULL }, { "output.L1.current.maximum", 0, 0.1, ".1.3.6.1.4.1.318.1.1.1.9.3.3.1.5.1.1.1", "", SU_FLAG_OK|SU_FLAG_NEGINVALID, NULL }, { "output.L2.current.maximum", 0, 0.1, ".1.3.6.1.4.1.318.1.1.1.9.3.3.1.5.1.1.2", "", SU_FLAG_OK|SU_FLAG_NEGINVALID, NULL }, { "output.L3.current.maximum", 0, 0.1, ".1.3.6.1.4.1.318.1.1.1.9.3.3.1.5.1.1.3", "", SU_FLAG_OK|SU_FLAG_NEGINVALID, NULL }, { "output.L1.current.minimum", 0, 0.1, ".1.3.6.1.4.1.318.1.1.1.9.3.3.1.6.1.1.1", "", SU_FLAG_OK|SU_FLAG_NEGINVALID, NULL }, { "output.L2.current.minimum", 0, 0.1, ".1.3.6.1.4.1.318.1.1.1.9.3.3.1.6.1.1.2", "", SU_FLAG_OK|SU_FLAG_NEGINVALID, NULL }, { "output.L3.current.minimum", 0, 0.1, ".1.3.6.1.4.1.318.1.1.1.9.3.3.1.6.1.1.3", "", SU_FLAG_OK|SU_FLAG_NEGINVALID, NULL }, { "output.L1.power", 0, 1, ".1.3.6.1.4.1.318.1.1.1.9.3.3.1.7.1.1.1", "", SU_FLAG_OK|SU_FLAG_NEGINVALID, NULL }, { "output.L2.power", 0, 1, ".1.3.6.1.4.1.318.1.1.1.9.3.3.1.7.1.1.2", "", SU_FLAG_OK|SU_FLAG_NEGINVALID, NULL }, { "output.L3.power", 0, 1, ".1.3.6.1.4.1.318.1.1.1.9.3.3.1.7.1.1.3", "", SU_FLAG_OK|SU_FLAG_NEGINVALID, NULL }, { "output.L1.power.maximum", 0, 1, ".1.3.6.1.4.1.318.1.1.1.9.3.3.1.8.1.1.1", "", SU_FLAG_OK|SU_FLAG_NEGINVALID, NULL }, { "output.L2.power.maximum", 0, 1, ".1.3.6.1.4.1.318.1.1.1.9.3.3.1.8.1.1.2", "", SU_FLAG_OK|SU_FLAG_NEGINVALID, NULL }, { "output.L3.power.maximum", 0, 1, ".1.3.6.1.4.1.318.1.1.1.9.3.3.1.8.1.1.3", "", SU_FLAG_OK|SU_FLAG_NEGINVALID, NULL }, { "output.L1.power.minimum", 0, 1, ".1.3.6.1.4.1.318.1.1.1.9.3.3.1.9.1.1.1", "", SU_FLAG_OK|SU_FLAG_NEGINVALID, NULL }, { "output.L2.power.minimum", 0, 1, ".1.3.6.1.4.1.318.1.1.1.9.3.3.1.9.1.1.2", "", SU_FLAG_OK|SU_FLAG_NEGINVALID, NULL }, { "output.L3.power.minimum", 0, 1, ".1.3.6.1.4.1.318.1.1.1.9.3.3.1.9.1.1.3", "", SU_FLAG_OK|SU_FLAG_NEGINVALID, NULL }, { "output.L1.power.percent", 0, 1, ".1.3.6.1.4.1.318.1.1.1.9.3.3.1.10.1.1.1", "", SU_FLAG_OK|SU_FLAG_NEGINVALID, NULL }, { "output.L2.power.percent", 0, 1, ".1.3.6.1.4.1.318.1.1.1.9.3.3.1.10.1.1.2", "", SU_FLAG_OK|SU_FLAG_NEGINVALID, NULL }, { "output.L3.power.percent", 0, 1, ".1.3.6.1.4.1.318.1.1.1.9.3.3.1.10.1.1.3", "", SU_FLAG_OK|SU_FLAG_NEGINVALID, NULL }, { "output.L1.power.maximum.percent", 0, 1, ".1.3.6.1.4.1.318.1.1.1.9.3.3.1.11.1.1.1", "", SU_FLAG_OK|SU_FLAG_NEGINVALID, NULL }, { "output.L2.power.maximum.percent", 0, 1, ".1.3.6.1.4.1.318.1.1.1.9.3.3.1.11.1.1.2", "", SU_FLAG_OK|SU_FLAG_NEGINVALID, NULL }, { "output.L3.power.maximum.percent", 0, 1, ".1.3.6.1.4.1.318.1.1.1.9.3.3.1.11.1.1.3", "", SU_FLAG_OK|SU_FLAG_NEGINVALID, NULL }, { "output.L1.power.minimum.percent", 0, 1, ".1.3.6.1.4.1.318.1.1.1.9.3.3.1.12.1.1.1", "", SU_FLAG_OK|SU_FLAG_NEGINVALID, NULL }, { "output.L2.power.minimum.percent", 0, 1, ".1.3.6.1.4.1.318.1.1.1.9.3.3.1.12.1.1.2", "", SU_FLAG_OK|SU_FLAG_NEGINVALID, NULL }, { "output.L3.power.minimum.percent", 0, 1, ".1.3.6.1.4.1.318.1.1.1.9.3.3.1.12.1.1.3", "", SU_FLAG_OK|SU_FLAG_NEGINVALID, NULL }, { "output.voltage.nominal", ST_FLAG_STRING | ST_FLAG_RW, 3, ".1.3.6.1.4.1.318.1.1.1.5.2.1.0", "", SU_TYPE_INT | SU_FLAG_OK, NULL }, /* Measure-UPS ambient variables */ /* Environmental sensors (AP9612TH and others) */ { "ambient.temperature", 0, 1, ".1.3.6.1.4.1.318.1.1.2.1.1.0", "", SU_FLAG_OK, NULL }, { "ambient.1.temperature.alarm.high", 0, 1, ".1.3.6.1.4.1.318.1.1.10.1.2.2.1.3.1", "", SU_FLAG_OK, NULL }, { "ambient.1.temperature.alarm.low", 0, 1, ".1.3.6.1.4.1.318.1.1.10.1.2.2.1.4.1", "", SU_FLAG_OK, NULL }, { "ambient.humidity", 0, 1, ".1.3.6.1.4.1.318.1.1.2.1.2.0", "", SU_FLAG_OK, NULL }, { "ambient.1.humidity.alarm.high", 0, 1, ".1.3.6.1.4.1.318.1.1.10.1.2.2.1.6.1", "", SU_FLAG_OK, NULL }, { "ambient.1.humidity.alarm.low", 0, 1, ".1.3.6.1.4.1.318.1.1.10.1.2.2.1.7.1", "", SU_FLAG_OK, NULL }, /* IEM: integrated environment monitor probe */ { "ambient.temperature", 0, 1, APCC_OID_IEM_TEMP, "", SU_FLAG_OK, NULL }, { "ambient.humidity", 0, 1, APCC_OID_IEM_HUMID, "", SU_FLAG_OK, NULL }, /* instant commands. */ { "load.off", 0, 1, ".1.3.6.1.4.1.318.1.1.1.6.2.1.0", "2", SU_TYPE_CMD | SU_FLAG_OK, NULL }, { "load.on", 0, 1, ".1.3.6.1.4.1.318.1.1.1.6.2.6.0", "2", SU_TYPE_CMD | SU_FLAG_OK, NULL }, { "shutdown.stayoff", 0, 1, ".1.3.6.1.4.1.318.1.1.1.6.2.1.0", "3", SU_TYPE_CMD | SU_FLAG_OK, NULL }, /* { CMD_SDRET, 0, APCC_REBOOT_GRACEFUL, APCC_OID_REBOOT, "", SU_TYPE_CMD | SU_FLAG_OK, NULL }, */ { "shutdown.return", 0, 1, ".1.3.6.1.4.1.318.1.1.1.6.1.1.0", "2", SU_TYPE_CMD | SU_FLAG_OK, NULL }, { "test.failure.start", 0, 1, ".1.3.6.1.4.1.318.1.1.1.6.2.4.0", "2", SU_TYPE_CMD | SU_FLAG_OK, NULL }, { "test.panel.start", 0, 1, ".1.3.6.1.4.1.318.1.1.1.6.2.5.0", "2", SU_TYPE_CMD | SU_FLAG_OK, NULL }, { "bypass.start", 0, 1, ".1.3.6.1.4.1.318.1.1.1.6.2.7.0", "2", SU_TYPE_CMD | SU_FLAG_OK, NULL }, { "bypass.stop", 0, 1, ".1.3.6.1.4.1.318.1.1.1.6.2.7.0", "3", SU_TYPE_CMD | SU_FLAG_OK, NULL }, { "test.battery.start", 0, 1, ".1.3.6.1.4.1.318.1.1.1.7.2.2.0", "2", SU_TYPE_CMD | SU_FLAG_OK, NULL }, { "calibrate.start", 0, 1, ".1.3.6.1.4.1.318.1.1.1.7.2.5.0", "2", SU_TYPE_CMD | SU_FLAG_OK, NULL }, { "calibrate.stop", 0, 1, ".1.3.6.1.4.1.318.1.1.1.7.2.5.0", "3", SU_TYPE_CMD | SU_FLAG_OK, NULL }, { "reset.input.minmax", 0, 1, ".1.3.6.1.4.1.318.1.1.1.9.1.1.0", "2", SU_TYPE_CMD | SU_FLAG_OK, NULL }, /* end of structure. */ { NULL, 0, 0, NULL, NULL, 0, NULL } }; mib2nut_info_t apc = { "apcc", APCC_MIB_VERSION, APCC_OID_POWER_STATUS, APC_UPS_DEVICE_MODEL, apcc_mib, APC_UPS_SYSOID, NULL }; /* vim:ts=4:sw=4:et: */ nut-2.8.1/drivers/delta_ups-hid.c0000644000175000017500000003661414500336654013635 00000000000000/* delta_ups-hid.c - data mapping subdriver to monitor Delta UPS USB/HID devices with NUT * * Copyright (C) * 2003 - 2012 Arnaud Quette * 2005 - 2006 Peter Selinger * 2008 - 2009 Arjen de Korte * 2013 Charles Lepple * 2020 Luka Kovacic * 2021 Jungeon Kim * * 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 2 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, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "config.h" /* must be first */ #include "usbhid-ups.h" #include "delta_ups-hid.h" #include "main.h" /* for getval() */ #include "usb-common.h" #define DELTA_UPS_HID_VERSION "Delta UPS HID 0.6" /* Delta UPS */ #define DELTA_UPS_VENDORID 0x05dd /* USB IDs device table */ static usb_device_id_t delta_ups_usb_device_table[] = { /* Delta RT Series, Single Phase, 1/2/3 kVA */ /* Delta UPS Amplon R Series, Single Phase UPS, 1/2/3 kVA */ { USB_DEVICE(DELTA_UPS_VENDORID, 0x041b), NULL }, /* Terminating entry */ { 0, 0, NULL } }; /* --------------------------------------------------------------- */ /* Vendor-specific usage table */ /* --------------------------------------------------------------- */ /* DELTA usage table */ static usage_lkp_t delta_ups_usage_lkp[] = { { "DELTA1", 0x00000000 }, { "DELTA2", 0xff000055 }, /* { "DELTA3", 0xffff0010 }, */ { "DeltaCustom", 0xffff0010 }, { "DELTA4", 0xffff0056 }, /* { "DELTA5", 0xffff0057 }, */ { "DeltaConfigTransferLowMax", 0xffff0057 }, /* { "DELTA6", 0xffff0058 }, */ { "DeltaConfigTransferLowMin", 0xffff0058 }, /* { "DELTA7", 0xffff0059 }, */ { "DeltaConfigTransferHighMax", 0xffff0059 }, /* { "DELTA8", 0xffff005a }, */ { "DeltaConfigTransferHighMin", 0xffff005a }, { "DELTA9", 0xffff0060 }, /* { "DELTA10", 0xffff0061 }, */ { "DeltaConfigExternalBatteryPack", 0xffff0061 }, { "DELTA11", 0xffff0062 }, { "DELTA12", 0xffff0063 }, { "DELTA13", 0xffff0064 }, { "DELTA14", 0xffff0065 }, { "DELTA15", 0xffff0066 }, { "DELTA16", 0xffff0067 }, { "DELTA17", 0xffff0068 }, /* { "DELTA18", 0xffff0075 }, */ { "DeltaModelName", 0xffff0075 }, { "DELTA19", 0xffff0076 }, /* { "DELTA20", 0xffff007c }, */ { "DeltaUPSType", 0xffff007c }, { "DELTA21", 0xffff007d }, /* { "DELTA22", 0xffff0081 }, */ { "DeltaConfigStartPowerRestoreDelay", 0xffff0081 }, /* { "DELTA23", 0xffff0091 }, */ { "DeltaOutputSource", 0xffff0091 }, { "DELTA24", 0xffff0092 }, { "DELTA25", 0xffff0093 }, { "DELTA26", 0xffff0094 }, { "DELTA27", 0xffff0095 }, { "DELTA28", 0xffff0096 }, { "DELTA29", 0xffff0097 }, { "DELTA30", 0xffff0098 }, { "DELTA31", 0xffff0099 }, { "DELTA32", 0xffff009a }, /* { "DELTA33", 0xffff009b }, */ { "DeltaConfigSensitivity", 0xffff009b }, /* { "DELTA34", 0xffff009c }, */ { "DeltaConfigStartPowerRestore", 0xffff009c }, /* Terminating entry */ { NULL, 0 } }; static usage_tables_t delta_ups_utab[] = { delta_ups_usage_lkp, hid_usage_lkp, NULL, }; /* --------------------------------------------------------------- */ /* Helper lookup tables and mapping functions */ /* --------------------------------------------------------------- */ static info_lkp_t delta_ups_sensitivity_info[] = { { 0, "normal", NULL, NULL }, { 1, "reduced", NULL, NULL }, { 2, "low", NULL, NULL }, /* Terminating entry */ { 0, NULL, NULL, NULL } }; static const char *delta_ups_type_fun(double value) { static const char* upstypes[] = { "online", "offline", "line-interactive", "3-phase", "split-phase" }; int type = (int)value & 0xf; if (type == 6) { type = 4; } else if (2 < type && type <= 5) { type -= 2; } if (type < 0 || type > 4) { return NULL; } return upstypes[type]; } static info_lkp_t delta_ups_type_info[] = { { 0, NULL, delta_ups_type_fun, NULL }, { 0, NULL, NULL, NULL } }; static info_lkp_t delta_ups_output_source_info[] = { { 0, "normal", NULL, NULL }, { 1, "battery", NULL, NULL }, { 2, "bypass/reserve", NULL, NULL }, { 3, "reducing", NULL, NULL }, { 4, "boosting", NULL, NULL }, { 5, "manual bypass", NULL, NULL }, { 6, "other", NULL, NULL }, { 7, "no output", NULL, NULL }, { 8, "on eco", NULL, NULL }, { 0, NULL, NULL, NULL } }; /* --------------------------------------------------------------- */ /* HID2NUT lookup table */ /* --------------------------------------------------------------- */ static hid_info_t delta_ups_hid2nut[] = { { "input.sensitivity", ST_FLAG_RW, 0, "UPS.DeltaCustom.[1].DeltaConfigSensitivity", NULL, "%s", 0, delta_ups_sensitivity_info }, { "input.voltage.nominal", 0, 0, "UPS.PowerSummary.Input.ConfigVoltage", NULL, "%.1f", HU_FLAG_SEMI_STATIC, NULL }, { "input.voltage", 0, 0, "UPS.PowerSummary.Input.Voltage", NULL, "%.1f", HU_FLAG_QUICK_POLL, NULL }, { "input.voltage", 0, 0, "UPS.PowerConverter.Input.Voltage", NULL, "%.1f", HU_FLAG_QUICK_POLL, NULL }, { "input.transfer.low", ST_FLAG_RW, 0, "UPS.PowerConverter.Output.LowVoltageTransfer", NULL, "%.1f", 0, NULL }, { "input.transfer.high", ST_FLAG_RW, 0, "UPS.PowerConverter.Output.HighVoltageTransfer", NULL, "%.1f", 0, NULL }, { "input.transfer.low.min", 0, 0, "UPS.PowerConverter.Output.DeltaConfigTransferLowMin", NULL, "%.1f", HU_FLAG_STATIC, NULL }, { "input.transfer.low.max", 0, 0, "UPS.PowerConverter.Output.DeltaConfigTransferLowMax", NULL, "%.1f", HU_FLAG_STATIC, NULL }, { "input.transfer.high.min", 0, 0, "UPS.PowerConverter.Output.DeltaConfigTransferHighMin", NULL, "%.1f", HU_FLAG_STATIC, NULL }, { "input.transfer.high.max", 0, 0, "UPS.PowerConverter.Output.DeltaConfigTransferHighMax", NULL, "%.1f", HU_FLAG_STATIC, NULL }, /* FIXME: Check vs hardware, is this an "input" or "outlet/outpu" value after all? */ { "input.source", 0, 0, "UPS.OutletSystem.Outlet.DeltaOutputSource", NULL, "%s", 0, delta_ups_output_source_info }, { "input.frequency", 0, 0, "UPS.PowerConverter.Input.Frequency", NULL, "%.1f", HU_FLAG_QUICK_POLL, NULL }, { "battery.voltage.nominal", 0, 0, "UPS.BatterySystem.Battery.ConfigVoltage", NULL, "%.1f", HU_FLAG_STATIC, NULL }, { "battery.voltage", 0, 0, "UPS.BatterySystem.Battery.Voltage", NULL, "%.1f", HU_FLAG_QUICK_POLL, NULL }, { "battery.charge", 0, 0, "UPS.PowerSummary.RemainingCapacity", NULL, "%.0f", HU_FLAG_QUICK_POLL, NULL }, { "battery.charge", 0, 0, "UPS.BatterySystem.Battery.RemainingCapacity", NULL, "%.0f", 0, NULL }, { "battery.charge.low", ST_FLAG_RW | ST_FLAG_STRING, 5, "UPS.PowerSummary.RemainingCapacityLimit", NULL, "%.0f", HU_FLAG_SEMI_STATIC, NULL }, /* { "battery.charge.low", 0, 0, "UPS.PowerSummary.RemainingCapacityLimit", NULL, "%.0f", HU_FLAG_SEMI_STATIC, NULL }, */ { "battery.charge.warning", 0, 0, "UPS.PowerSummary.WarningCapacityLimit", NULL, "%.0f", HU_FLAG_SEMI_STATIC, NULL }, { "battery.temperature", 0, 0, "UPS.BatterySystem.Temperature", NULL, "%s", HU_FLAG_QUICK_POLL, kelvin_celsius_conversion }, { "battery.runtime", 0, 0, "UPS.PowerSummary.RunTimeToEmpty", NULL, "%.0f", HU_FLAG_QUICK_POLL, NULL }, { "battery.type", 0, 0, "UPS.PowerSummary.iDeviceChemistry", NULL, "%s", HU_FLAG_STATIC, stringid_conversion }, { "battery.capacity", 0, 0, "UPS.PowerSummary.DesignCapacity", NULL, "%.0f", HU_FLAG_SEMI_STATIC, NULL }, { "battery.capacity", 0, 0, "UPS.PowerSummary.FullChargeCapacity", NULL, "%.0f", HU_FLAG_SEMI_STATIC, NULL }, { "output.voltage.nominal", 0, 0, "UPS.Flow.ConfigVoltage", NULL, "%.1f", HU_FLAG_SEMI_STATIC, NULL }, { "output.frequency.nominal", 0, 0, "UPS.Flow.ConfigFrequency", NULL, "%.1f", HU_FLAG_SEMI_STATIC, NULL }, { "output.voltage", 0, 0, "UPS.PowerConverter.Output.Voltage", NULL, "%.1f", HU_FLAG_QUICK_POLL, NULL }, { "output.frequency", 0, 0, "UPS.PowerConverter.Output.Frequency", NULL, "%.1f", HU_FLAG_QUICK_POLL, NULL }, { "output.current", 0, 0, "UPS.PowerConverter.Output.Current", NULL, "%.1f", HU_FLAG_QUICK_POLL, NULL }, { "ups.beeper.status", 0, 0, "UPS.PowerSummary.AudibleAlarmControl", NULL, "%s", HU_FLAG_QUICK_POLL, beeper_info }, { "ups.test.result", 0, 0, "UPS.BatterySystem.Test", NULL, "%s", 0, test_read_info }, { "ups.type", 0, 0, "UPS.DeltaCustom.[1].DeltaUPSType", NULL, "%s", HU_FLAG_STATIC, delta_ups_type_info }, { "ups.start.auto", ST_FLAG_RW, 0, "UPS.DeltaCustom.[1].DeltaConfigStartPowerRestore", NULL, "%s", 0, yes_no_info }, { "ups.power.nominal", 0, 0, "UPS.Flow.ConfigApparentPower", NULL, "%.0f", HU_FLAG_STATIC, NULL }, { "ups.realpower", 0, 0, "UPS.OutletSystem.Outlet.ActivePower", NULL, "%.1f", HU_FLAG_QUICK_POLL, NULL }, { "ups.realpower", 0, 0, "UPS.PowerConverter.Output.ActivePower", NULL, "%.1f", HU_FLAG_QUICK_POLL, NULL }, { "ups.load", 0, 0, "UPS.OutletSystem.Outlet.PercentLoad", NULL, "%.1f", HU_FLAG_QUICK_POLL, NULL }, /* Per comments to PR #807 these 3 declarations are populated elsewhere, * by delta_ups_format_*() functions hooks; see: * https://github.com/networkupstools/nut/pull/807#discussion_r501496383 */ /* { "ups.mfr", 0, 0, "UPS.PowerSummary.iManufacturer", NULL, "%s", HU_FLAG_STATIC, stringid_conversion }, { "ups.model", 0, 0, "UPS.PowerSummary.iProduct", NULL, "%s", HU_FLAG_STATIC, stringid_conversion }, { "ups.serial", 0, 0, "UPS.PowerSummary.iSerialNumber", NULL, "%s", HU_FLAG_STATIC, stringid_conversion }, */ { "ups.delay.start", ST_FLAG_RW, 0, "UPS.OutletSystem.Outlet.DeltaConfigStartPowerRestoreDelay", NULL, "%.0f", 0, NULL }, /* mge-hid.c simlar configurable settings: { "ups.delay.start", ST_FLAG_RW | ST_FLAG_STRING, 10, "UPS.PowerSummary.DelayBeforeStartup", NULL, DEFAULT_ONDELAY, HU_FLAG_ABSENT, NULL }, { "ups.delay.shutdown", ST_FLAG_RW | ST_FLAG_STRING, 10, "UPS.PowerSummary.DelayBeforeShutdown", NULL, DEFAULT_OFFDELAY, HU_FLAG_ABSENT, NULL }, ... { "ups.timer.shutdown", 0, 0, "UPS.PowerSummary.DelayBeforeShutdown", NULL, "%.0f", HU_FLAG_QUICK_POLL, NULL }, */ { "ups.timer.start", 0, 0, "UPS.OutletSystem.Outlet.DelayBeforeStartup", NULL, "%.0f", HU_FLAG_QUICK_POLL, NULL }, { "ups.timer.shutdown", 0, 0, "UPS.OutletSystem.Outlet.DelayBeforeShutdown", NULL, "%.0f", HU_FLAG_QUICK_POLL, NULL }, { "ups.timer.reboot", 0, 0, "UPS.OutletSystem.Outlet.DelayBeforeReboot", NULL, "%.0f", HU_FLAG_QUICK_POLL, NULL }, { "BOOL", 0, 0, "UPS.PowerSummary.PresentStatus.Good", NULL, NULL, HU_FLAG_QUICK_POLL, off_info }, { "BOOL", 0, 0, "UPS.PowerSummary.PresentStatus.InternalFailure", NULL, NULL, HU_FLAG_QUICK_POLL, commfault_info }, { "BOOL", 0, 0, "UPS.PowerSummary.PresentStatus.ShutdownImminent", NULL, NULL, HU_FLAG_QUICK_POLL, shutdownimm_info }, { "BOOL", 0, 0, "UPS.PowerSummary.PresentStatus.ACPresent", NULL, NULL, HU_FLAG_QUICK_POLL, online_info }, { "BOOL", 0, 0, "UPS.PowerSummary.PresentStatus.BelowRemainingCapacityLimit", NULL, NULL, HU_FLAG_QUICK_POLL, lowbatt_info }, { "BOOL", 0, 0, "UPS.PowerSummary.PresentStatus.FullyCharged", NULL, NULL, HU_FLAG_QUICK_POLL, fullycharged_info }, { "BOOL", 0, 0, "UPS.PowerSummary.PresentStatus.Charging", NULL, NULL, HU_FLAG_QUICK_POLL, charging_info }, { "BOOL", 0, 0, "UPS.PowerSummary.PresentStatus.Discharging", NULL, NULL, HU_FLAG_QUICK_POLL, discharging_info }, { "BOOL", 0, 0, "UPS.PowerSummary.PresentStatus.FullyDischarged", NULL, NULL, HU_FLAG_QUICK_POLL, depleted_info }, { "BOOL", 0, 0, "UPS.PowerSummary.PresentStatus.NeedReplacement", NULL, NULL, HU_FLAG_QUICK_POLL, replacebatt_info }, { "BOOL", 0, 0, "UPS.PowerConverter.PresentStatus.VoltageOutOfRange", NULL, NULL, HU_FLAG_QUICK_POLL, vrange_info }, { "BOOL", 0, 0, "UPS.PowerConverter.PresentStatus.Buck", NULL, NULL, HU_FLAG_QUICK_POLL, trim_info }, { "BOOL", 0, 0, "UPS.PowerConverter.PresentStatus.Boost", NULL, NULL, HU_FLAG_QUICK_POLL, boost_info }, { "BOOL", 0, 0, "UPS.PowerConverter.PresentStatus.Overload", NULL, NULL, HU_FLAG_QUICK_POLL, overload_info }, { "BOOL", 0, 0, "UPS.PowerConverter.PresentStatus.Used", NULL, NULL, HU_FLAG_QUICK_POLL, nobattery_info }, { "BOOL", 0, 0, "UPS.PowerConverter.PresentStatus.OverTemperature", NULL, NULL, HU_FLAG_QUICK_POLL, overheat_info }, { "BOOL", 0, 0, "UPS.PowerConverter.PresentStatus.InternalFailure", NULL, NULL, HU_FLAG_QUICK_POLL, commfault_info }, { "BOOL", 0, 0, "UPS.PowerConverter.PresentStatus.AwaitingPower", NULL, NULL, HU_FLAG_QUICK_POLL, awaitingpower_info }, { "beeper.on", 0, 0, "UPS.PowerSummary.AudibleAlarmControl", NULL, "2", HU_TYPE_CMD, NULL }, { "beeper.off", 0, 0, "UPS.PowerSummary.AudibleAlarmControl", NULL, "3", HU_TYPE_CMD, NULL }, { "beeper.enable", 0, 0, "UPS.PowerSummary.AudibleAlarmControl", NULL, "2", HU_TYPE_CMD, NULL }, { "beeper.disable", 0, 0, "UPS.PowerSummary.AudibleAlarmControl", NULL, "1", HU_TYPE_CMD, NULL }, { "beeper.mute", 0, 0, "UPS.PowerSummary.AudibleAlarmControl", NULL, "3", HU_TYPE_CMD, NULL }, /* 10 seconds battery test */ { "test.battery.start.quick", 0, 0, "UPS.BatterySystem.Test", NULL, "1", HU_TYPE_CMD, NULL }, /* test until battery low */ { "test.battery.start.deep", 0, 0, "UPS.BatterySystem.Test", NULL, "2", HU_TYPE_CMD, NULL }, { "test.battery.stop", 0, 0, "UPS.BatterySystem.Test", NULL, "3", HU_TYPE_CMD, NULL }, { "load.on.delay", 0, 0, "UPS.OutletSystem.Outlet.DelayBeforeStartup", NULL, DEFAULT_ONDELAY, HU_TYPE_CMD, NULL }, { "load.off.delay", 0, 0, "UPS.OutletSystem.Outlet.DelayBeforeShutdown", NULL, DEFAULT_OFFDELAY, HU_TYPE_CMD, NULL }, { "shutdown.stop", 0, 0, "UPS.OutletSystem.Outlet.DelayBeforeShutdown", NULL, "-1", HU_TYPE_CMD, NULL }, { "shutdown.reboot", 0, 0, "UPS.OutletSystem.Outlet.DelayBeforeReboot", NULL, "10", HU_TYPE_CMD, NULL }, /* Terminating entry */ { NULL, 0, 0, NULL, NULL, NULL, 0, NULL } }; static const char *delta_ups_format_mfr(HIDDevice_t *hd) { return hd->Vendor ? hd->Vendor : "Delta"; } static const char *delta_ups_format_model(HIDDevice_t *hd) { static char model[SMALLBUF]; HIDGetItemString(udev, "UPS.DeltaCustom.[1].DeltaModelName", model, sizeof(model), delta_ups_utab); if (strlen(model) < 1) { return hd->Product; } return model; } static const char *delta_ups_format_serial(HIDDevice_t *hd) { return hd->Serial; } /* this function allows the subdriver to "claim" a device: return 1 if * the device is supported by this subdriver, else 0. */ static int delta_ups_claim(HIDDevice_t *hd) { int status = is_usb_device_supported(delta_ups_usb_device_table, hd); switch (status) { case SUPPORTED: return 1; case POSSIBLY_SUPPORTED: /* by default, reject, unless the productid option is given */ if (getval("productid")) { return 1; } possibly_supported("Delta", hd); return 0; case NOT_SUPPORTED: default: return 0; } } subdriver_t delta_ups_subdriver = { DELTA_UPS_HID_VERSION, delta_ups_claim, delta_ups_utab, delta_ups_hid2nut, delta_ups_format_model, delta_ups_format_mfr, delta_ups_format_serial, fix_report_desc, }; nut-2.8.1/drivers/richcomm_usb.c0000644000175000017500000005167614502253356013571 00000000000000/* * richcomm_usb.c - driver for UPS with Richcomm dry-contact to USB * solution, such as 'Sweex Manageable UPS 1000VA' * * May also work on 'Kebo UPS-650D', not tested as of 05/23/2007 * * Copyright (C) 2007 Peter van Valderen * Dirk Teurlings * Copyright (C) 2016 Eaton * * 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 2 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, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "main.h" #include "nut_libusb.h" #include "usb-common.h" #include "nut_stdint.h" /* driver version */ #define DRIVER_NAME "Richcomm dry-contact to USB driver" #define DRIVER_VERSION "0.12" /* driver description structure */ upsdrv_info_t upsdrv_info = { DRIVER_NAME, DRIVER_VERSION, "Peter van Valderen \n" "Dirk Teurlings ", DRV_EXPERIMENTAL, { NULL } }; #define STATUS_REQUESTTYPE 0x21 #define REPLY_REQUESTTYPE 0x81 #define QUERY_PACKETSIZE 4 #define REPLY_PACKETSIZE 6 #define REQUEST_VALUE 0x09 #define MESSAGE_VALUE 0x200 #define INDEX_VALUE 0 /* limit the amount of spew that goes in the syslog when we lose the UPS (from nut_usb.h) */ #define USB_ERR_LIMIT 10 /* start limiting after 10 in a row */ #define USB_ERR_RATE 10 /* then only print every 10th error */ static usb_device_id_t richcomm_usb_id[] = { /* Sweex 1000VA */ { USB_DEVICE(0x0925, 0x1234), NULL }, /* Terminating entry */ { 0, 0, NULL } }; static usb_dev_handle *udev = NULL; static USBDevice_t usbdevice; static unsigned int comm_failures = 0; static int device_match_func(USBDevice_t *device, void *privdata) { NUT_UNUSED_VARIABLE(privdata); switch (is_usb_device_supported(richcomm_usb_id, device)) { case SUPPORTED: return 1; case POSSIBLY_SUPPORTED: case NOT_SUPPORTED: default: return 0; } } static USBDeviceMatcher_t device_matcher = { &device_match_func, NULL, NULL }; #if (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_PUSH_POP_BESIDEFUNC) && ( (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_TYPE_LIMITS_BESIDEFUNC) || (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_TAUTOLOGICAL_CONSTANT_OUT_OF_RANGE_COMPARE_BESIDEFUNC) ) # pragma GCC diagnostic push #endif #ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_TYPE_LIMITS_BESIDEFUNC # pragma GCC diagnostic ignored "-Wtype-limits" #endif #ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_TAUTOLOGICAL_CONSTANT_OUT_OF_RANGE_COMPARE_BESIDEFUNC # pragma GCC diagnostic ignored "-Wtautological-constant-out-of-range-compare" #endif static int execute_and_retrieve_query(char *query, char *reply) { int ret; ret = usb_control_msg(udev, STATUS_REQUESTTYPE, REQUEST_VALUE, MESSAGE_VALUE, INDEX_VALUE, (usb_ctrl_charbuf)query, QUERY_PACKETSIZE, 1000); if (ret <= 0) { upsdebugx(3, "send: %s", ret ? nut_usb_strerror(ret) : "timeout"); return ret; } #if (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_PUSH_POP) && ( (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_TYPE_LIMITS) || (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_TAUTOLOGICAL_CONSTANT_OUT_OF_RANGE_COMPARE) ) # pragma GCC diagnostic push #endif #ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_TYPE_LIMITS # pragma GCC diagnostic ignored "-Wtype-limits" #endif #ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_TAUTOLOGICAL_CONSTANT_OUT_OF_RANGE_COMPARE # pragma GCC diagnostic ignored "-Wtautological-constant-out-of-range-compare" #endif /* Cast up within the signed/unsigned same type */ if ((unsigned int)ret >= SIZE_MAX) { #if (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_PUSH_POP) && ( (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_TYPE_LIMITS) || (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_TAUTOLOGICAL_CONSTANT_OUT_OF_RANGE_COMPARE) ) # pragma GCC diagnostic pop #endif upsdebugx(3, "send: ret=%d exceeds SIZE_MAX", ret); } upsdebug_hex(3, "send", query, (size_t)ret); ret = usb_interrupt_read(udev, REPLY_REQUESTTYPE, (usb_ctrl_charbuf)reply, REPLY_PACKETSIZE, 1000); if (ret <= 0) { upsdebugx(3, "read: %s", ret ? nut_usb_strerror(ret) : "timeout"); return ret; } #if (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_PUSH_POP) && ( (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_TYPE_LIMITS) || (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_TAUTOLOGICAL_CONSTANT_OUT_OF_RANGE_COMPARE) ) # pragma GCC diagnostic push #endif #ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_TYPE_LIMITS # pragma GCC diagnostic ignored "-Wtype-limits" #endif #ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_TAUTOLOGICAL_CONSTANT_OUT_OF_RANGE_COMPARE # pragma GCC diagnostic ignored "-Wtautological-constant-out-of-range-compare" #endif /* Cast up within the signed/unsigned same type */ if ((unsigned int)ret >= SIZE_MAX) { #if (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_PUSH_POP) && ( (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_TYPE_LIMITS) || (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_TAUTOLOGICAL_CONSTANT_OUT_OF_RANGE_COMPARE) ) # pragma GCC diagnostic pop #endif upsdebugx(3, "read: ret=%d exceeds SIZE_MAX", ret); } upsdebug_hex(3, "read", reply, (size_t)ret); return ret; } #if (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_PUSH_POP_BESIDEFUNC) && ( (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_TYPE_LIMITS_BESIDEFUNC) || (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_TAUTOLOGICAL_CONSTANT_OUT_OF_RANGE_COMPARE_BESIDEFUNC) ) # pragma GCC diagnostic pop #endif static int query_ups(char *reply) { /* * This packet is a status request to the UPS */ char query[QUERY_PACKETSIZE] = { 0x01, 0x00, 0x00, 0x30 }; return execute_and_retrieve_query(query, reply); } static void usb_comm_fail(const char *fmt, ...) { int ret; char why[SMALLBUF]; va_list ap; /* this means we're probably here because select was interrupted */ if (exit_flag != 0) { return; /* ignored, since we're about to exit anyway */ } comm_failures++; if ((comm_failures == USB_ERR_LIMIT) || ((comm_failures % USB_ERR_RATE) == 0)) { upslogx(LOG_WARNING, "Warning: excessive comm failures, limiting error reporting"); } /* once it's past the limit, only log once every USB_ERR_LIMIT calls */ if ((comm_failures > USB_ERR_LIMIT) && ((comm_failures % USB_ERR_LIMIT) != 0)) { return; } /* generic message if the caller hasn't elaborated */ if (!fmt) { upslogx(LOG_WARNING, "Communications with UPS lost - check cabling"); return; } va_start(ap, fmt); #ifdef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL #pragma GCC diagnostic push #endif #ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL #pragma GCC diagnostic ignored "-Wformat-nonliteral" #endif #ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_FORMAT_SECURITY #pragma GCC diagnostic ignored "-Wformat-security" #endif ret = vsnprintf(why, sizeof(why), fmt, ap); #ifdef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL #pragma GCC diagnostic pop #endif va_end(ap); if ((ret < 1) || (ret >= (int) sizeof(why))) { upslogx(LOG_WARNING, "usb_comm_fail: vsnprintf needed more than %d bytes", (int)sizeof(why)); } upslogx(LOG_WARNING, "Communications with UPS lost: %s", why); } static void usb_comm_good(void) { if (comm_failures == 0) { return; } upslogx(LOG_NOTICE, "Communications with UPS re-established"); comm_failures = 0; } /* * Callback that is called by usb_device_open() that handles USB device * settings prior to accepting the devide. At the very least claim the * device here. Detaching the kernel driver will be handled by the * caller, don't do this here. Return < 0 on error, 0 or higher on * success. */ static int driver_callback(usb_dev_handle *handle, USBDevice_t *device) { #if WITH_LIBUSB_1_0 int ret = 0; #endif NUT_UNUSED_VARIABLE(device); if (usb_set_configuration(handle, 1) < 0) { upsdebugx(5, "Can't set USB configuration"); return -1; } #ifdef WIN usb_set_configuration(handle, 0); #endif if (usb_claim_interface(handle, 0) < 0) { upsdebugx(5, "Can't claim USB interface"); return -1; } #if WITH_LIBUSB_0_1 if (usb_set_altinterface(handle, 0) < 0) { upsdebugx(5, "Can't set USB alternate interface"); return -1; } #elif WITH_LIBUSB_1_0 if ((ret = libusb_set_interface_alt_setting(handle, 0, 0)) < 0) { upsdebugx(5, "Can't set USB alternate interface: %s", nut_usb_strerror(ret)); return -1; } #endif /* WITH_LIBUSB_1_0 */ if (usb_clear_halt(handle, 0x81) < 0) { upsdebugx(5, "Can't reset USB endpoint"); return -1; } return 1; } static int usb_device_close(usb_dev_handle *handle) { int ret = 0; if (!handle) { return 0; } /* usb_release_interface() sometimes blocks and goes * into uninterruptible sleep. So don't do it. */ /* usb_release_interface(handle, 0); */ #if WITH_LIBUSB_1_0 libusb_close(handle); libusb_exit(NULL); #else ret = usb_close(handle); #endif return ret; } static int usb_device_open(usb_dev_handle **handlep, USBDevice_t *device, USBDeviceMatcher_t *matcher, int (*callback)(usb_dev_handle *handle, USBDevice_t *device)) { int ret = 0; uint8_t iManufacturer = 0, iProduct = 0, iSerialNumber = 0; #if WITH_LIBUSB_1_0 libusb_device **devlist; ssize_t devcount = 0; libusb_device_handle *handle; struct libusb_device_descriptor dev_desc; uint8_t bus_num; /* TODO: consider device_addr */ int i; #else /* => WITH_LIBUSB_0_1 */ struct usb_bus *bus; #endif /* libusb base init */ #if WITH_LIBUSB_1_0 if (libusb_init(NULL) < 0) { libusb_exit(NULL); fatal_with_errno(EXIT_FAILURE, "Failed to init libusb 1.0"); } #else /* => WITH_LIBUSB_0_1 */ usb_init(); usb_find_busses(); usb_find_devices(); #endif /* WITH_LIBUSB_1_0 */ #ifndef __linux__ /* SUN_LIBUSB (confirmed to work on Solaris and FreeBSD) */ /* Causes a double free corruption in linux if device is detached! */ /* usb_device_close(*handlep); */ if (*handlep) usb_close(*handlep); #endif #if WITH_LIBUSB_1_0 devcount = libusb_get_device_list(NULL, &devlist); if (devcount <= 0) fatal_with_errno(EXIT_FAILURE, "No USB device found"); for (i = 0; i < devcount; i++) { USBDeviceMatcher_t *m; libusb_device *dev = devlist[i]; libusb_get_device_descriptor(dev, &dev_desc); ret = libusb_open(dev, &handle); *handlep = handle; #else /* => WITH_LIBUSB_0_1 */ for (bus = usb_busses; bus; bus = bus->next) { struct usb_device *dev; usb_dev_handle *handle; for (dev = bus->devices; dev; dev = dev->next) { int i; USBDeviceMatcher_t *m; upsdebugx(3, "Checking USB device [%04x:%04x] (%s/%s)", dev->descriptor.idVendor, dev->descriptor.idProduct, bus->dirname, dev->filename); /* supported vendors are now checked by the supplied matcher */ /* open the device */ *handlep = handle = usb_open(dev); #endif /* WITH_LIBUSB_1_0 */ if (!handle) { upsdebugx(4, "Failed to open USB device, skipping: %s", nut_usb_strerror(ret)); continue; } /* collect the identifying information of this device. Note that this is safe, because there's no need to claim an interface for this (and therefore we do not yet need to detach any kernel drivers). */ free(device->Vendor); free(device->Product); free(device->Serial); free(device->Bus); memset(device, 0, sizeof(*device)); #if WITH_LIBUSB_1_0 device->VendorID = dev_desc.idVendor; device->ProductID = dev_desc.idProduct; bus_num = libusb_get_bus_number(dev); device->Bus = (char *)malloc(4); if (device->Bus == NULL) { libusb_free_device_list(devlist, 1); fatal_with_errno(EXIT_FAILURE, "Out of memory"); } sprintf(device->Bus, "%03d", bus_num); iManufacturer = dev_desc.iManufacturer; iProduct = dev_desc.iProduct; iSerialNumber = dev_desc.iSerialNumber; #else /* => WITH_LIBUSB_0_1 */ device->VendorID = dev->descriptor.idVendor; device->ProductID = dev->descriptor.idProduct; device->Bus = xstrdup(bus->dirname); iManufacturer = dev->descriptor.iManufacturer; iProduct = dev->descriptor.iProduct; iSerialNumber = dev->descriptor.iSerialNumber; #endif /* WITH_LIBUSB_1_0 */ if (iManufacturer) { char buf[SMALLBUF]; ret = usb_get_string_simple(handle, iManufacturer, (usb_ctrl_charbuf)buf, sizeof(buf)); if (ret > 0) { device->Vendor = strdup(buf); if (device->Vendor == NULL) { #if WITH_LIBUSB_1_0 libusb_free_device_list(devlist, 1); #endif /* WITH_LIBUSB_1_0 */ fatal_with_errno(EXIT_FAILURE, "Out of memory"); } } } if (iProduct) { char buf[SMALLBUF]; ret = usb_get_string_simple(handle, iProduct, (usb_ctrl_charbuf)buf, sizeof(buf)); if (ret > 0) { device->Product = strdup(buf); if (device->Product == NULL) { #if WITH_LIBUSB_1_0 libusb_free_device_list(devlist, 1); #endif /* WITH_LIBUSB_1_0 */ fatal_with_errno(EXIT_FAILURE, "Out of memory"); } } } if (iSerialNumber) { char buf[SMALLBUF]; ret = usb_get_string_simple(handle, iSerialNumber, (usb_ctrl_charbuf)buf, sizeof(buf)); if (ret > 0) { device->Serial = strdup(buf); if (device->Serial == NULL) { #if WITH_LIBUSB_1_0 libusb_free_device_list(devlist, 1); #endif /* WITH_LIBUSB_1_0 */ fatal_with_errno(EXIT_FAILURE, "Out of memory"); } } } upsdebugx(4, "- VendorID : %04x", device->VendorID); upsdebugx(4, "- ProductID : %04x", device->ProductID); upsdebugx(4, "- Manufacturer : %s", device->Vendor ? device->Vendor : "unknown"); upsdebugx(4, "- Product : %s", device->Product ? device->Product : "unknown"); upsdebugx(4, "- Serial Number: %s", device->Serial ? device->Serial : "unknown"); upsdebugx(4, "- Bus : %s", device->Bus ? device->Bus : "unknown"); for (m = matcher; m; m = m->next) { switch (m->match_function(device, m->privdata)) { case 0: upsdebugx(4, "Device does not match - skipping"); goto next_device; case -1: #if WITH_LIBUSB_1_0 libusb_free_device_list(devlist, 1); #endif /* WITH_LIBUSB_1_0 */ fatal_with_errno(EXIT_FAILURE, "matcher"); #ifndef HAVE___ATTRIBUTE__NORETURN # if (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_PUSH_POP) && (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_UNREACHABLE_CODE) # pragma GCC diagnostic push # pragma GCC diagnostic ignored "-Wunreachable-code" # endif goto next_device; # if (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_PUSH_POP) && (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_UNREACHABLE_CODE) # pragma GCC diagnostic pop # endif #endif case -2: upsdebugx(4, "matcher: unspecified error"); goto next_device; } } #ifdef HAVE_LIBUSB_SET_AUTO_DETACH_KERNEL_DRIVER /* First, try the auto-detach kernel driver method * This function is not available on FreeBSD 10.1-10.3 */ if ((ret = libusb_set_auto_detach_kernel_driver(handle, 1)) < 0) upsdebugx(2, "failed to auto detach kernel driver from USB device: %s", nut_usb_strerror((enum libusb_error)ret)); else upsdebugx(2, "auto detached kernel driver from USB device"); #endif /* HAVE_LIBUSB_SET_AUTO_DETACH_KERNEL_DRIVER */ for (i = 0; i < 3; i++) { ret = callback(handle, device); if (ret >= 0) { upsdebugx(4, "USB device [%04x:%04x] opened", device->VendorID, device->ProductID); #if WITH_LIBUSB_1_0 libusb_free_device_list(devlist, 1); #endif /* WITH_LIBUSB_1_0 */ return ret; } #if WITH_LIBUSB_0_1 && (defined HAVE_USB_DETACH_KERNEL_DRIVER_NP) /* this method requires at least libusb 0.1.8: * it force device claiming by unbinding * attached driver... From libhid */ if ((ret = usb_detach_kernel_driver_np(handle, 0)) < 0) { upsdebugx(4, "failed to detach kernel driver from USB device: %s", nut_usb_strerror(ret)); } else { upsdebugx(4, "detached kernel driver from USB device..."); } #else # ifdef HAVE_LIBUSB_DETACH_KERNEL_DRIVER if ((ret = libusb_detach_kernel_driver(handle, 0)) < 0) { upsdebugx(4, "failed to detach kernel driver from USB device: %s", nut_usb_strerror(ret)); } else { upsdebugx(4, "detached kernel driver from USB device..."); } # else # ifdef HAVE_LIBUSB_DETACH_KERNEL_DRIVER_NP if ((ret = libusb_detach_kernel_driver_np(udev, 0)) < 0) { upsdebugx(4, "failed to detach kernel driver from USB device: %s", nut_usb_strerror(ret)); } else { upsdebugx(4, "detached kernel driver from USB device..."); } # endif /* HAVE_LIBUSB_DETACH_KERNEL_DRIVER_NP */ # endif /* HAVE_LIBUSB_DETACH_KERNEL_DRIVER */ #endif /* HAVE_USB_DETACH_KERNEL_DRIVER_NP or HAVE_LIBUSB_DETACH_KERNEL_DRIVER or HAVE_LIBUSB_DETACH_KERNEL_DRIVER_NP */ } #if WITH_LIBUSB_1_0 libusb_free_device_list(devlist, 1); #endif /* WITH_LIBUSB_1_0 */ fatalx(EXIT_FAILURE, "USB device [%04x:%04x] matches, but driver callback failed: %s", device->VendorID, device->ProductID, nut_usb_strerror(ret)); next_device: usb_close(handle); #if (!WITH_LIBUSB_1_0) /* => WITH_LIBUSB_0_1 */ } #endif /* WITH_LIBUSB_1_0 */ } *handlep = NULL; #if WITH_LIBUSB_1_0 libusb_free_device_list(devlist, 1); #endif /* WITH_LIBUSB_1_0 */ upsdebugx(4, "No matching USB device found"); return -1; } /* * Initialise the UPS */ void upsdrv_initups(void) { char reply[REPLY_PACKETSIZE]; int i; warn_if_bad_usb_port_filename(device_path); for (i = 0; usb_device_open(&udev, &usbdevice, &device_matcher, &driver_callback) < 0; i++) { #ifndef WIN32 if ((i < 32) && (sleep(5) == 0)) { #else /*FIXME*/ sleep(5); if ((i < 32)) { #endif usb_comm_fail("Can't open USB device, retrying ..."); continue; } fatalx(EXIT_FAILURE, "Unable to find Richcomm dry-contact to USB solution\n\n" "Things to try:\n" " - Connect UPS device to USB bus\n" " - Run this driver as another user (upsdrvctl -u or 'user=...' in ups.conf).\n" " See upsdrvctl(8) and ups.conf(5).\n\n" "Fatal error: unusable configuration"); } /* * Read rubbish data a few times; the UPS doesn't seem to respond properly * the first few times after connecting */ for (i = 0; i < 5; i++) { query_ups(reply); sleep(1); } } void upsdrv_cleanup(void) { usb_device_close(udev); free(usbdevice.Vendor); free(usbdevice.Product); free(usbdevice.Serial); free(usbdevice.Bus); } void upsdrv_initinfo(void) { dstate_setinfo("ups.mfr", "%s", "Richcomm dry-contact to USB solution"); dstate_setinfo("ups.model", "%s", usbdevice.Product ? usbdevice.Product : "unknown"); dstate_setinfo("ups.serial", "%s", usbdevice.Serial ? usbdevice.Serial : "unknown"); dstate_setinfo("ups.vendorid", "%04x", usbdevice.VendorID); dstate_setinfo("ups.productid", "%04x", usbdevice.ProductID); } void upsdrv_updateinfo(void) { char reply[REPLY_PACKETSIZE]; int ret, online, battery_normal; if (!udev) { dstate_setinfo("driver.state", "reconnect.trying"); ret = usb_device_open(&udev, &usbdevice, &device_matcher, &driver_callback); if (ret < 0) { return; } dstate_setinfo("driver.state", "reconnect.updateinfo"); } ret = query_ups(reply); if (ret < 4) { usb_comm_fail("Query to UPS failed"); dstate_datastale(); dstate_setinfo("driver.state", "reconnect.trying"); usb_device_close(udev); udev = NULL; return; } usb_comm_good(); dstate_dataok(); /* * 3rd bit of 4th byte indicates whether the UPS is on line (1) * or on battery (0) */ online = (reply[3]&4)>>2; /* * 2nd bit of 4th byte indicates battery status; normal (1) * or low (0) */ battery_normal = (reply[3]&2)>>1; status_init(); if (online) { status_set("OL"); } else { status_set("OB"); } if (!battery_normal) { status_set("LB"); } status_commit(); } /* * The shutdown feature is a bit strange on this UPS IMHO, it * switches the polarity of the 'Shutdown UPS' signal, at which * point it will automatically power down once it loses power. * * It will still, however, be possible to poll the UPS and * reverse the polarity _again_, at which point it will * start back up once power comes back. * * Maybe this is the normal way, it just seems a bit strange. * * Please note, this function doesn't power the UPS off if * line power is connected. */ void upsdrv_shutdown(void) { /* * This packet shuts down the UPS, that is, * if it is not currently on line power */ char prepare[QUERY_PACKETSIZE] = { 0x02, 0x00, 0x00, 0x00 }; /* * This should make the UPS turn itself back on once the * power comes back on; which is probably what we want */ char restart[QUERY_PACKETSIZE] = { 0x02, 0x01, 0x00, 0x00 }; char reply[REPLY_PACKETSIZE]; execute_and_retrieve_query(prepare, reply); /* * have to, the previous command seems to be * ignored if the second command comes right * behind it */ sleep(1); execute_and_retrieve_query(restart, reply); } void upsdrv_help(void) { } void upsdrv_makevartable(void) { /* allow -x vendor=X, vendorid=X, product=X, productid=X, serial=X */ /* TODO: Uncomment while addressing https://github.com/networkupstools/nut/issues/1768 nut_usb_addvars(); */ } nut-2.8.1/drivers/bcmxcp_io.h0000644000175000017500000000124614500336654013054 00000000000000/* * bcmxcp_io.h -- header for BCM/XCP IO module */ #ifndef BCMXCP_IO__ #define BCMXCP_IO__ #include "main.h" /* for usbdrv_info_t */ void send_read_command(unsigned char command); void send_write_command(unsigned char *command, size_t command_length); ssize_t get_answer(unsigned char *data, unsigned char command); ssize_t command_read_sequence(unsigned char command, unsigned char *data); ssize_t command_write_sequence(unsigned char *command, size_t command_length, unsigned char *answer); void upsdrv_initups(void); void upsdrv_cleanup(void); void upsdrv_reconnect(void); void upsdrv_comm_good(void); extern upsdrv_info_t comm_upsdrv_info; #endif /* BCMXCP_IO__ */ nut-2.8.1/drivers/blazer_usb.c0000644000175000017500000004713014502253356013235 00000000000000/* * blazer_usb.c: support for Megatec/Q1 USB protocol based UPSes * * OBSOLETION WARNING: Please to not base new development on this * codebase, instead create a new subdriver for nutdrv_qx which * generally covers all Megatec/Qx protocol family and aggregates * device support from such legacy drivers over time. * * A document describing the protocol implemented by this driver can be * found online at "https://www.networkupstools.org/protocols/megatec.html". * * Copyright (C) 2003-2009 Arjen de Korte * Copyright (C) 2011-2012 Arnaud Quette * Copyright (C) 2016 Eaton * * 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 2 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, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "main.h" #include "nut_libusb.h" #include "usb-common.h" #include "blazer.h" #ifdef WIN32 #include "wincompat.h" #endif #define DRIVER_NAME "Megatec/Q1 protocol USB driver" #define DRIVER_VERSION "0.17" /* driver description structure */ upsdrv_info_t upsdrv_info = { DRIVER_NAME, DRIVER_VERSION, "Arjen de Korte \n" \ "Arnaud Quette ", DRV_BETA, { NULL } }; #ifndef TESTING static usb_communication_subdriver_t *usb = &usb_subdriver; static usb_dev_handle *udev = NULL; static USBDevice_t usbdevice; static USBDeviceMatcher_t *reopen_matcher = NULL; static USBDeviceMatcher_t *regex_matcher = NULL; static int langid_fix = -1; static int (*subdriver_command)(const char *cmd, char *buf, size_t buflen) = NULL; static int cypress_command(const char *cmd, char *buf, size_t buflen) { char tmp[SMALLBUF]; int ret; size_t i; memset(tmp, 0, sizeof(tmp)); snprintf(tmp, sizeof(tmp), "%s", cmd); for (i = 0; i < strlen(tmp); i += (size_t)ret) { /* Write data in 8-byte chunks */ /* ret = usb->set_report(udev, 0, (unsigned char *)&tmp[i], 8); */ ret = usb_control_msg(udev, USB_ENDPOINT_OUT + USB_TYPE_CLASS + USB_RECIP_INTERFACE, 0x09, 0x200, 0, (usb_ctrl_charbuf)&tmp[i], 8, 5000); if (ret <= 0) { upsdebugx(3, "send: %s", ret ? nut_usb_strerror(ret) : "timeout"); return ret; } } upsdebugx(3, "send: %.*s", (int)strcspn(tmp, "\r"), tmp); memset(buf, 0, buflen); for (i = 0; (i <= buflen-8) && (strchr(buf, '\r') == NULL); i += (size_t)ret) { /* Read data in 8-byte chunks */ /* ret = usb->get_interrupt(udev, (unsigned char *)&buf[i], 8, 1000); */ ret = usb_interrupt_read(udev, 0x81, (usb_ctrl_charbuf)&buf[i], 8, 1000); /* * Any errors here mean that we are unable to read a reply (which * will happen after successfully writing a command to the UPS) */ if (ret <= 0) { upsdebugx(3, "read: %s", ret ? nut_usb_strerror(ret) : "timeout"); return ret; } } upsdebugx(3, "read: %.*s", (int)strcspn(buf, "\r"), buf); /* TODO: Range-check before cast */ return (int)i; } static int phoenix_command(const char *cmd, char *buf, size_t buflen) { char tmp[SMALLBUF]; int ret; size_t i; for (i = 0; i < 8; i++) { /* Read data in 8-byte chunks */ /* ret = usb->get_interrupt(udev, (unsigned char *)tmp, 8, 1000); */ ret = usb_interrupt_read(udev, 0x81, (usb_ctrl_charbuf)&tmp, 8, 1000); /* * This USB to serial implementation is crappy. In order to read correct * replies we need to flush the output buffers of the converter until we * get no more data (ie, it times out). */ switch (ret) { case LIBUSB_ERROR_PIPE: /** Pipe error or Broken pipe */ usb_clear_halt(udev, 0x81); break; case LIBUSB_ERROR_TIMEOUT: /** Operation or Connection timed out */ break; } if (ret < 0) { upsdebugx(3, "flush: %s", nut_usb_strerror(ret)); break; } upsdebug_hex(4, "dump", tmp, (size_t)ret); } memset(tmp, 0, sizeof(tmp)); snprintf(tmp, sizeof(tmp), "%s", cmd); for (i = 0; i < strlen(tmp); i += (size_t)ret) { /* Write data in 8-byte chunks */ /* ret = usb->set_report(udev, 0, (unsigned char *)&tmp[i], 8); */ ret = usb_control_msg(udev, USB_ENDPOINT_OUT + USB_TYPE_CLASS + USB_RECIP_INTERFACE, 0x09, 0x200, 0, (usb_ctrl_charbuf)&tmp[i], 8, 1000); if (ret <= 0) { upsdebugx(3, "send: %s", ret ? nut_usb_strerror(ret) : "timeout"); return ret; } } upsdebugx(3, "send: %.*s", (int)strcspn(tmp, "\r"), tmp); memset(buf, 0, buflen); for (i = 0; (i <= buflen-8) && (strchr(buf, '\r') == NULL); i += (size_t)ret) { /* Read data in 8-byte chunks */ /* ret = usb->get_interrupt(udev, (unsigned char *)&buf[i], 8, 1000); */ ret = usb_interrupt_read(udev, 0x81, (usb_ctrl_charbuf)&buf[i], 8, 1000); /* * Any errors here mean that we are unable to read a reply (which * will happen after successfully writing a command to the UPS) */ if (ret <= 0) { upsdebugx(3, "read: %s", ret ? nut_usb_strerror(ret) : "timeout"); return ret; } } upsdebugx(3, "read: %.*s", (int)strcspn(buf, "\r"), buf); /* TODO: Range-check before cast */ return (int)i; } static int ippon_command(const char *cmd, char *buf, size_t buflen) { char tmp[64]; int ret, len; size_t i; snprintf(tmp, sizeof(tmp), "%s", cmd); for (i = 0; i < strlen(tmp); i += (size_t)ret) { /* Write data in 8-byte chunks */ ret = usb_control_msg(udev, USB_ENDPOINT_OUT + USB_TYPE_CLASS + USB_RECIP_INTERFACE, 0x09, 0x2, 0, (usb_ctrl_charbuf)&tmp[i], 8, 1000); if (ret <= 0) { upsdebugx(3, "send: %s", (ret != LIBUSB_ERROR_TIMEOUT) ? nut_usb_strerror(ret) : "Connection timed out"); return ret; } } upsdebugx(3, "send: %.*s", (int)strcspn(tmp, "\r"), tmp); /* Read all 64 bytes of the reply in one large chunk */ ret = usb_interrupt_read(udev, 0x81, (usb_ctrl_charbuf)&tmp, sizeof(tmp), 1000); /* * Any errors here mean that we are unable to read a reply (which * will happen after successfully writing a command to the UPS) */ if (ret <= 0) { upsdebugx(3, "read: %s", (ret != LIBUSB_ERROR_TIMEOUT) ? nut_usb_strerror(ret) : "Connection timed out"); return ret; } /* * As Ippon will always return 64 bytes in response, we have to * calculate and return length of actual response data here. * Empty response will look like 0x00 0x0D, otherwise it will be * data string terminated by 0x0D. */ len = (int)strcspn(tmp, "\r"); upsdebugx(3, "read: %.*s", len, tmp); if (len > 0) { len ++; } snprintf(buf, buflen, "%.*s", len, tmp); return len; } static int krauler_command(const char *cmd, char *buf, size_t buflen) { /* * Still not implemented: * 0x6 T (don't know how to pass the parameter) * 0x68 and 0x69 both cause shutdown after an undefined interval */ const struct { const char *str; /* Megatec command */ const int index; /* Krauler string index for this command */ const char prefix; /* character to replace the first byte in reply */ } command[] = { { "Q1\r", 0x03, '(' }, { "F\r", 0x0d, '#' }, { "I\r", 0x0c, '#' }, { "T\r", 0x04, '\r' }, { "TL\r", 0x05, '\r' }, { "Q\r", 0x07, '\r' }, { "C\r", 0x0b, '\r' }, { "CT\r", 0x0b, '\r' }, { NULL, 0, '\0' } }; int i; upsdebugx(3, "send: %.*s", (int)strcspn(cmd, "\r"), cmd); for (i = 0; command[i].str; i++) { int retry; if (strcmp(cmd, command[i].str)) { continue; } for (retry = 0; retry < 10; retry++) { int ret; if (langid_fix != -1) { /* Apply langid_fix value */ ret = usb_get_string(udev, command[i].index, langid_fix, (usb_ctrl_charbuf)buf, buflen); } else { ret = usb_get_string_simple(udev, command[i].index, (usb_ctrl_charbuf)buf, buflen); } if (ret <= 0) { upsdebugx(3, "read: %s", ret ? nut_usb_strerror(ret) : "timeout"); return ret; } /* this may serve in the future */ upsdebugx(1, "received %d (%d)", ret, buf[0]); if (langid_fix != -1) { size_t di, si, size; /* Limit this check, at least for now */ /* Invalid receive size - message corrupted */ if (ret != buf[0]) { upsdebugx(1, "size mismatch: %d / %d", ret, buf[0]); continue; } /* Simple unicode -> ASCII inplace conversion * FIXME: this code is at least shared with mge-shut/libshut * Create a common function? */ size = (size_t)buf[0]; for (di = 0, si = 2; si < size; si += 2) { if (di >= (buflen - 1)) break; if (buf[si + 1]) /* high byte */ buf[di++] = '?'; else buf[di++] = buf[si]; } buf[di] = 0; /* with buf a char* array, practical "size" limit and * so "di" are small enough to cast to int */ ret = (int)di; } /* "UPS No Ack" has a special meaning */ if (!strcasecmp(buf, "UPS No Ack")) { upsdebugx(3, "read: %.*s", (int)strcspn(buf, "\r"), buf); continue; } /* Replace the first byte of what we received with the correct one */ buf[0] = command[i].prefix; upsdebugx(3, "read: %.*s", (int)strcspn(buf, "\r"), buf); return ret; } return 0; } /* echo the unknown command back */ upsdebugx(3, "read: %.*s", (int)strcspn(cmd, "\r"), cmd); return snprintf(buf, buflen, "%s", cmd); } static void *cypress_subdriver(USBDevice_t *device) { NUT_UNUSED_VARIABLE(device); subdriver_command = &cypress_command; return NULL; } static void *ippon_subdriver(USBDevice_t *device) { NUT_UNUSED_VARIABLE(device); subdriver_command = &ippon_command; return NULL; } static void *krauler_subdriver(USBDevice_t *device) { NUT_UNUSED_VARIABLE(device); subdriver_command = &krauler_command; return NULL; } static void *phoenix_subdriver(USBDevice_t *device) { NUT_UNUSED_VARIABLE(device); subdriver_command = &phoenix_command; return NULL; } static usb_device_id_t blazer_usb_id[] = { { USB_DEVICE(0x05b8, 0x0000), &cypress_subdriver }, /* Agiler UPS */ { USB_DEVICE(0x0001, 0x0000), &krauler_subdriver }, /* Krauler UP-M500VA */ { USB_DEVICE(0xffff, 0x0000), &krauler_subdriver }, /* Ablerex 625L USB */ { USB_DEVICE(0x0665, 0x5161), &cypress_subdriver }, /* Belkin F6C1200-UNV */ { USB_DEVICE(0x06da, 0x0002), &cypress_subdriver }, /* Online Yunto YQ450 */ { USB_DEVICE(0x06da, 0x0003), &ippon_subdriver }, /* Mustek Powermust */ { USB_DEVICE(0x06da, 0x0004), &cypress_subdriver }, /* Phoenixtec Innova 3/1 T */ { USB_DEVICE(0x06da, 0x0005), &cypress_subdriver }, /* Phoenixtec Innova RT */ { USB_DEVICE(0x06da, 0x0201), &cypress_subdriver }, /* Phoenixtec Innova T */ { USB_DEVICE(0x06da, 0x0601), &phoenix_subdriver }, /* Online Zinto A */ { USB_DEVICE(0x0f03, 0x0001), &cypress_subdriver }, /* Unitek Alpha 1200Sx */ { USB_DEVICE(0x14f0, 0x00c9), &phoenix_subdriver }, /* GE EP series */ /* Terminating entry */ { 0, 0, NULL } }; static int device_match_func(USBDevice_t *hd, void *privdata) { NUT_UNUSED_VARIABLE(privdata); if (subdriver_command) { return 1; } switch (is_usb_device_supported(blazer_usb_id, hd)) { case SUPPORTED: return 1; case POSSIBLY_SUPPORTED: case NOT_SUPPORTED: default: return 0; } } static USBDeviceMatcher_t device_matcher = { &device_match_func, NULL, NULL }; #endif /* TESTING */ /* * Generic command processing function. Send a command and read a reply. * Returns < 0 on error, 0 on timeout and the number of bytes read on * success. */ ssize_t blazer_command(const char *cmd, char *buf, size_t buflen) { #ifndef TESTING ssize_t ret; if (udev == NULL) { dstate_setinfo("driver.state", "reconnect.trying"); ret = usb->open_dev(&udev, &usbdevice, reopen_matcher, NULL); if (ret < 1) { return ret; } dstate_setinfo("driver.state", "reconnect.updateinfo"); } ret = (*subdriver_command)(cmd, buf, buflen); if (ret >= 0) { return ret; } switch (ret) { case LIBUSB_ERROR_BUSY: /* Device or resource busy */ fatal_with_errno(EXIT_FAILURE, "Got disconnected by another driver"); #ifndef HAVE___ATTRIBUTE__NORETURN exit(EXIT_FAILURE); /* Should not get here in practice, but compiler is afraid we can fall through */ #endif #if WITH_LIBUSB_0_1 /* limit to libusb 0.1 implementation */ case -EPERM: /* Operation not permitted */ fatal_with_errno(EXIT_FAILURE, "Permissions problem"); # ifndef HAVE___ATTRIBUTE__NORETURN exit(EXIT_FAILURE); /* Should not get here in practice, but compiler is afraid we can fall through */ # endif #endif /* WITH_LIBUSB_0_1 */ case LIBUSB_ERROR_PIPE: /* Broken pipe */ if (usb_clear_halt(udev, 0x81) == 0) { upsdebugx(1, "Stall condition cleared"); break; } #if (defined ETIME) && ETIME && WITH_LIBUSB_0_1 goto fallthrough_case_etime; case -ETIME: /* Timer expired */ fallthrough_case_etime: #endif if (usb_reset(udev) == 0) { upsdebugx(1, "Device reset handled"); } goto fallthrough_case_reconnect; case LIBUSB_ERROR_NO_DEVICE: /* No such device */ case LIBUSB_ERROR_ACCESS: /* Permission denied */ case LIBUSB_ERROR_IO: /* I/O error */ #if WITH_LIBUSB_0_1 /* limit to libusb 0.1 implementation */ case -ENXIO: /* No such device or address */ #endif case LIBUSB_ERROR_NOT_FOUND: /* No such file or directory */ fallthrough_case_reconnect: /* Uh oh, got to reconnect! */ dstate_setinfo("driver.state", "reconnect.trying"); usb->close_dev(udev); udev = NULL; break; case LIBUSB_ERROR_TIMEOUT: /* Connection timed out */ /* libusb-win32 does not know EPROTO and EOVERFLOW, * it only returns EIO for any IO errors */ #ifndef WIN32 case LIBUSB_ERROR_OVERFLOW: /* Value too large for defined data type */ # if EPROTO && WITH_LIBUSB_0_1 case -EPROTO: /* Protocol error */ # endif #endif default: break; } return ret; #else /* if TESTING: */ const struct { const char *command; const char *answer; } testing[] = { { "Q1\r", "(215.0 195.0 230.0 014 49.0 2.27 30.0 00101000\r" }, { "F\r", "#230.0 000 024.0 50.0\r" }, { "I\r", "#------------- ------ VT12046Q \r" }, { NULL } }; int i; memset(buf, 0, buflen); for (i = 0; testing[i].command; i++) { if (strcasecmp(cmd, testing[i].command)) { continue; } /* TODO: Range-check int vs ssize_t values */ return (ssize_t)snprintf(buf, buflen, "%s", testing[i].answer); } return (ssize_t)snprintf(buf, buflen, "%s", testing[i].command); #endif /* TESTING */ } #ifndef TESTING static const struct subdriver_t { const char *name; int (*command)(const char *cmd, char *buf, size_t buflen); } subdriver[] = { { "cypress", &cypress_command }, { "phoenix", &phoenix_command }, { "ippon", &ippon_command }, { "krauler", &krauler_command }, { NULL, NULL } }; #endif /* TESTING */ void upsdrv_help(void) { #ifndef TESTING size_t i; printf("\nAcceptable values for 'subdriver' via -x or ups.conf in this driver: "); for (i = 0; subdriver[i].name != NULL; i++) { if (i>0) printf(", "); printf("%s", subdriver[i].name); } printf("\n\n"); #endif /* TESTING */ printf("Read The Fine Manual ('man 8 blazer_usb')\n"); } void upsdrv_makevartable(void) { addvar(VAR_VALUE, "subdriver", "Serial-over-USB subdriver selection"); /* allow -x vendor=X, vendorid=X, product=X, productid=X, serial=X */ nut_usb_addvars(); addvar(VAR_VALUE, "langid_fix", "Apply the language ID workaround to the krauler subdriver (0x409 or 0x4095)"); blazer_makevartable(); } void upsdrv_initups(void) { #ifndef TESTING int ret, langid; char tbuf[255]; /* Some devices choke on size > 255 */ char *regex_array[USBMATCHER_REGEXP_ARRAY_LIMIT]; char *subdrv = getval("subdriver"); warn_if_bad_usb_port_filename(device_path); regex_array[0] = getval("vendorid"); regex_array[1] = getval("productid"); regex_array[2] = getval("vendor"); regex_array[3] = getval("product"); regex_array[4] = getval("serial"); regex_array[5] = getval("bus"); regex_array[6] = getval("device"); #if (defined WITH_USB_BUSPORT) && (WITH_USB_BUSPORT) regex_array[7] = getval("busport"); # else if (getval("busport")) { upslogx(LOG_WARNING, "\"busport\" is configured for the device, but is not actually handled by current build combination of NUT and libusb (ignored)"); } # endif /* check for language ID workaround (#1) */ if (getval("langid_fix")) { /* skip "0x" prefix and set back to hexadecimal */ unsigned int u_langid_fix; if ( (sscanf(getval("langid_fix") + 2, "%x", &u_langid_fix) != 1) || (u_langid_fix > INT_MAX) ) { upslogx(LOG_NOTICE, "Error enabling language ID workaround"); } else { langid_fix = (int)u_langid_fix; upsdebugx(2, "language ID workaround enabled (using '0x%x')", langid_fix); } } /* pick up the subdriver name if set explicitly */ if (subdrv) { int i; if (!regex_array[0] || !regex_array[1]) { fatalx(EXIT_FAILURE, "When specifying a subdriver, 'vendorid' and 'productid' are mandatory."); } for (i = 0; subdriver[i].name; i++) { if (strcasecmp(subdrv, subdriver[i].name)) { continue; } subdriver_command = subdriver[i].command; break; } if (!subdriver_command) { fatalx(EXIT_FAILURE, "Subdriver \"%s\" not found!", subdrv); } } ret = USBNewRegexMatcher(®ex_matcher, regex_array, REG_ICASE | REG_EXTENDED); switch (ret) { case -1: fatal_with_errno(EXIT_FAILURE, "USBNewRegexMatcher"); case 0: break; /* all is well */ default: fatalx(EXIT_FAILURE, "invalid regular expression: %s", regex_array[ret]); } /* link the matchers */ regex_matcher->next = &device_matcher; ret = usb->open_dev(&udev, &usbdevice, regex_matcher, NULL); if (ret < 0) { fatalx(EXIT_FAILURE, "No supported devices found. Please check your device availability with 'lsusb'\n" "and make sure you have an up-to-date version of NUT. If this does not help,\n" "try running the driver with at least 'subdriver', 'vendorid' and 'productid'\n" "options specified. Please refer to the man page for details about these options\n" "(man 8 blazer_usb).\n"); } if (!subdriver_command) { fatalx(EXIT_FAILURE, "No subdriver selected"); } /* create a new matcher for later reopening */ ret = USBNewExactMatcher(&reopen_matcher, &usbdevice); if (ret) { fatal_with_errno(EXIT_FAILURE, "USBNewExactMatcher"); } /* link the matchers */ reopen_matcher->next = regex_matcher; dstate_setinfo("ups.vendorid", "%04x", usbdevice.VendorID); dstate_setinfo("ups.productid", "%04x", usbdevice.ProductID); /* check for language ID workaround (#2) */ if (langid_fix != -1) { /* Future improvement: * Asking for the zero'th index is special - it returns a string * descriptor that contains all the language IDs supported by the * device. Typically there aren't many - often only one. The * language IDs are 16 bit numbers, and they start at the third byte * in the descriptor. See USB 2.0 specification, section 9.6.7, for * more information on this. * This should allow automatic application of the workaround */ ret = usb_get_string(udev, 0, 0, (usb_ctrl_charbuf)tbuf, sizeof(tbuf)); if (ret >= 4) { langid = (unsigned char)tbuf[2] | ((unsigned char)tbuf[3] << 8); upsdebugx(1, "First supported language ID: 0x%x (please report to the NUT maintainer!)", langid); } } #endif /* TESTING */ blazer_initups(); } void upsdrv_initinfo(void) { blazer_initinfo(); } void upsdrv_cleanup(void) { #ifndef TESTING usb->close_dev(udev); USBFreeExactMatcher(reopen_matcher); USBFreeRegexMatcher(regex_matcher); free(usbdevice.Vendor); free(usbdevice.Product); free(usbdevice.Serial); free(usbdevice.Bus); free(usbdevice.Device); #if (defined WITH_USB_BUSPORT) && (WITH_USB_BUSPORT) free(usbdevice.BusPort); # endif #endif /* TESTING */ } nut-2.8.1/drivers/usbhid-ups.h0000644000175000017500000002100414501607135013162 00000000000000/* usbhid-ups.h - Driver for serial/USB HID UPS units * * Copyright (C) * 2003-2009 Arnaud Quette * 2005-2006 Peter Selinger * 2007-2009 Arjen de Korte * * This program was sponsored by MGE UPS SYSTEMS, and now Eaton * * 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 2 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, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #ifndef USBHID_UPS_H #define USBHID_UPS_H #include #include #include #include #include "config.h" #include "libhid.h" extern hid_dev_handle_t udev; extern bool_t use_interrupt_pipe; /* Set to FALSE if interrupt reports should not be used */ /* Driver's parameters */ #define HU_VAR_LOWBATT "lowbatt" #define HU_VAR_ONDELAY "ondelay" #define HU_VAR_OFFDELAY "offdelay" #define HU_VAR_POLLFREQ "pollfreq" /* Parameters default values */ #define DEFAULT_LOWBATT "30" /* percentage of battery charge to consider the UPS in low battery state */ #define DEFAULT_ONDELAY "30" /* Delay between return of utility power */ /* and powering up of load, in seconds */ /* CAUTION: ondelay > offdelay */ #define DEFAULT_OFFDELAY "20" /* Delay before power off, in seconds */ #define DEFAULT_POLLFREQ 30 /* Polling interval, in seconds */ /* The driver will wait for Interrupt */ /* and do "light poll" in the meantime */ #ifndef MAX_STRING_SIZE #define MAX_STRING_SIZE 128 #endif /* --------------------------------------------------------------- */ /* Struct & data for lookup between HID and NUT values */ /* (From USB/HID, Power Devices Class standard) */ /* --------------------------------------------------------------- */ typedef struct { const long hid_value; /* HID value */ const char *nut_value; /* NUT value */ const char *(*fun)(double hid_value); /* optional HID to NUT mapping */ double (*nuf)(const char *nut_value); /* optional NUT to HID mapping */ } info_lkp_t; /* accessor on the status */ extern unsigned ups_status_get(void); /* declarations of public lookup tables */ /* boolean status values from UPS */ extern info_lkp_t online_info[]; extern info_lkp_t discharging_info[]; extern info_lkp_t charging_info[]; extern info_lkp_t lowbatt_info[]; extern info_lkp_t overload_info[]; extern info_lkp_t replacebatt_info[]; extern info_lkp_t trim_info[]; extern info_lkp_t boost_info[]; extern info_lkp_t bypass_auto_info[]; extern info_lkp_t bypass_manual_info[]; extern info_lkp_t off_info[]; extern info_lkp_t calibration_info[]; extern info_lkp_t nobattery_info[]; extern info_lkp_t fanfail_info[]; extern info_lkp_t shutdownimm_info[]; extern info_lkp_t overheat_info[]; extern info_lkp_t awaitingpower_info[]; extern info_lkp_t commfault_info[]; extern info_lkp_t timelimitexpired_info[]; extern info_lkp_t battvoltlo_info[]; extern info_lkp_t battvolthi_info[]; extern info_lkp_t chargerfail_info[]; extern info_lkp_t emergency_stop_info[]; extern info_lkp_t fullycharged_info[]; extern info_lkp_t depleted_info[]; /* input.transfer.reason */ extern info_lkp_t vrange_info[]; extern info_lkp_t frange_info[]; /* non specific */ extern info_lkp_t test_write_info[]; extern info_lkp_t test_read_info[]; extern info_lkp_t beeper_info[]; extern info_lkp_t yes_no_info[]; extern info_lkp_t on_off_info[]; extern info_lkp_t date_conversion[]; extern info_lkp_t hex_conversion[]; extern info_lkp_t stringid_conversion[]; extern info_lkp_t divide_by_10_conversion[]; extern info_lkp_t kelvin_celsius_conversion[]; /* ---------------------------------------------------------------------- */ /* data for processing boolean values from UPS */ #define STATUS(x) ((unsigned)1< * * 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 2 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, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ /* * Notes: * These UPSes operate at 24V DC (both input and output), instead of 110V/230V AC. * Therefore, the line input is also referred to by Siemens as 'DC'. * * The device is configured via DIP-switches. * For correct functioning in combination with NUT, set the DIP-switches to the following: * switch 1-4: choose whatever suits your situation. Any combination will work with NUT. * switch 5 ('=>' / 't'): set to OFF ('t') * switch 6-10 (delay): set to OFF (no additional delay) * switch 11 (INTERR.): set to ON * switch 12 (ON/OFF): set to ON * * These UPSes are available with serial or USB port. * Both are supported by this driver. The version with USB port simply contains * a serial-over-USB chip, so as far as this driver is concerned, all models are * actually serial models. * * The FTDI USB-to-serial converters in the USB-models are programmed with a non-standard * Product ID (mine had 0403:e0e3), but can be used with the normal ftdi_sio driver: * # modprobe ftdi_sio * # echo 0403 e0e3 > /sys/bus/usb-serial/drivers/ftdi_sio/new_id * * This can also be automated via a udev rule: * ACTION=="add", ATTRS{idVendor}=="0403", ATTRS{idProduct}=="e0e3", \ * RUN+="/sbin/modprobe ftdi_sio", \ * RUN+="/bin/sh -c 'echo 0403 e0e3 > /sys/bus/usb-serial/drivers/ftdi_sio/new_id'" * * Use the following udev rule to create a persistent device name, for example /dev/ttyUPS: * SUBSYSTEM=="tty" ATTRS{idVendor}=="0403", ATTRS{idProduct}=="e0e3" SYMLINK+="ttyUPS" */ #include "main.h" #include "serial.h" #include "nut_stdint.h" #define DRIVER_NAME "Siemens SITOP UPS500 series driver" #define DRIVER_VERSION "0.04" #define RX_BUFFER_SIZE 100 /* driver description structure */ upsdrv_info_t upsdrv_info = { DRIVER_NAME, DRIVER_VERSION, "Matthijs H. ten Berge ", DRV_EXPERIMENTAL, { NULL } }; /* The maximum number of consecutive polls in which the UPS does not provide any data: */ static unsigned int max_polls_without_data; /* The current number: */ static unsigned int nr_polls_without_data; /* receive buffer */ static char rx_buffer[RX_BUFFER_SIZE]; static size_t rx_count; static struct { int battery_alarm; int dc_input_low; int on_battery; int battery_above_85_percent; } current_ups_status; /* remove n bytes from the head of rx_buffer, shift the remaining bytes to the start */ static void rm_buffer_head(unsigned int n) { if (rx_count <= n) { /* nothing left */ rx_count = 0; return; } rx_count -= n; memmove(rx_buffer, rx_buffer + n, rx_count); } /* parse incoming data from the UPS. * return true if something new was received. */ static int check_for_new_data(void) { int new_data_received = 0; int done = 0; ssize_t num_received; while (!done) { /* Get new data from the serial port. * No extra delay, just get the chars that were already buffered. */ num_received = ser_get_buf(upsfd, rx_buffer + rx_count, RX_BUFFER_SIZE - rx_count, 0, 0); if (num_received < 0) { /* comm error */ ser_comm_fail("error %" PRIiSIZE " while reading", num_received); /* discard any remaining old data from the receive buffer: */ rx_count = 0; /* try to re-open the serial port: */ if (upsfd) { ser_close(upsfd, device_path); upsfd = 0; } upsfd = ser_open_nf(device_path); ser_set_speed_nf(upsfd, device_path, B9600); done = 1; } else if (num_received == 0) { /* no (more) new data */ done = 1; } else { rx_count += (unsigned int)num_received; /* parse received input data: */ while (rx_count >= 5) { /* all valid input messages are strings of 5 characters */ if (strncmp(rx_buffer, "BUFRD", 5) == 0) { current_ups_status.battery_alarm = 0; } else if (strncmp(rx_buffer, "ALARM", 5) == 0) { current_ups_status.battery_alarm = 1; } else if (strncmp(rx_buffer, "DC_OK", 5) == 0) { current_ups_status.dc_input_low = 0; } else if (strncmp(rx_buffer, "DC_LO", 5) == 0) { current_ups_status.dc_input_low = 1; } else if (strncmp(rx_buffer, "*****", 5) == 0) { current_ups_status.on_battery = 0; } else if (strncmp(rx_buffer, "*BAT*", 5) == 0) { current_ups_status.on_battery = 1; } else if (strncmp(rx_buffer, "BA>85", 5) == 0) { current_ups_status.battery_above_85_percent = 1; } else if (strncmp(rx_buffer, "BA<85", 5) == 0) { current_ups_status.battery_above_85_percent = 0; } else { /* nothing sensible found at the start of the rx_buffer. */ rm_buffer_head(1); continue; /* skip the code below */ } rm_buffer_head(5); new_data_received = 1; } } } return new_data_received; } static int instcmd(const char *cmdname, const char *extra) { /* Note: the UPS does not really like to receive data. * For example, sending an "R" without \n hangs the serial port. * In that situation, the UPS will no longer send any status updates. * For this reason, an additional \n is appended here. * The commands are sent twice, because the first command is sometimes * lost as well. */ if (!strcasecmp(cmdname, "shutdown.return")) { upslogx(LOG_NOTICE, "instcmd: sending command R"); ser_send_pace(upsfd, 200000, "\n\nR\n\n"); ser_send_pace(upsfd, 200000, "R\n\n"); return STAT_INSTCMD_HANDLED; } if (!strcasecmp(cmdname, "shutdown.stayoff")) { upslogx(LOG_NOTICE, "instcmd: sending command S"); ser_send_pace(upsfd, 200000, "\n\nS\n\n"); ser_send_pace(upsfd, 200000, "S\n\n"); return STAT_INSTCMD_HANDLED; } upslogx(LOG_NOTICE, "instcmd: unknown command [%s] [%s]", cmdname, extra); return STAT_INSTCMD_UNKNOWN; } void upsdrv_initinfo(void) { int max_attempts = 5; int found = 0; while (!found && max_attempts > 0) { if (check_for_new_data()) { found = 1; } else { sleep(1); /* Sleep a while, then try again */ } max_attempts--; } if (!found) { fatalx(EXIT_FAILURE, "No data received from the UPS"); } dstate_setinfo("device.mfr", "Siemens"); dstate_setinfo("device.model", "SITOP UPS500 series"); /* supported commands: */ dstate_addcmd("shutdown.stayoff"); dstate_addcmd("shutdown.return"); upsh.instcmd = instcmd; } void upsdrv_updateinfo(void) { if (check_for_new_data()) { nr_polls_without_data = 0; } else { nr_polls_without_data++; /* With unsigned int type, we can limit half-way like this: */ if (nr_polls_without_data > INT_MAX) nr_polls_without_data = INT_MAX; } if (nr_polls_without_data > max_polls_without_data) { /* data is stale */ dstate_datastale(); return; } /* This is all we know about the charge level... */ dstate_setinfo("battery.charge.approx", (current_ups_status.battery_above_85_percent) ? ">85" : "<85"); status_init(); if (current_ups_status.dc_input_low || current_ups_status.on_battery) { status_set("OB"); } else { status_set("OL"); } if (current_ups_status.battery_alarm) { status_set("LB"); } status_commit(); dstate_dataok(); ser_comm_good(); } void upsdrv_shutdown(void) { /* tell the UPS to shut down, then return - DO NOT SLEEP HERE */ instcmd("shutdown.return", NULL); } void upsdrv_help(void) { } /* list flags and values that you want to receive via -x */ void upsdrv_makevartable(void) { /* allow '-x max_polls_without_data=' */ addvar(VAR_VALUE, "max_polls_without_data", "The maximum number of consecutive polls in which the UPS does not provide any data."); } void upsdrv_initups(void) { char * maxPollsString; unsigned int parsed; upsfd = ser_open(device_path); ser_set_speed(upsfd, device_path, B9600); /* * Fast polling is preferred, because * A) the UPS spits out new data every 75 msec, * B) some models in this SITOP series have a _very_ small capacity * (< 10sec runtime), so every second might count. */ if (poll_interval > 5) { upslogx(LOG_NOTICE, "Option poll_interval is recommended to be lower than 5 (found: %" PRIdMAX ")", (intmax_t)poll_interval); } /* option max_polls_without_data: */ max_polls_without_data = 2; maxPollsString = getval("max_polls_without_data"); if (maxPollsString) { if (str_to_uint(maxPollsString, &parsed, 10) == 1) { max_polls_without_data = parsed; } else { upslog_with_errno(LOG_ERR, "Cannot parse option max_polls_without_data"); } } } void upsdrv_cleanup(void) { ser_close(upsfd, device_path); } nut-2.8.1/drivers/nutdrv_qx_zinto.c0000644000175000017500000001471514501607135014362 00000000000000/* nutdrv_qx_zinto.c - Subdriver for Zinto protocol based UPSes * * Copyright (C) * 2013 Daniele Pezzini * * 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 2 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, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #include "main.h" #include "nutdrv_qx.h" #include "nutdrv_qx_blazer-common.h" #include "nutdrv_qx_zinto.h" #define ZINTO_VERSION "Zinto 0.07" /* qx2nut lookup table */ static item_t zinto_qx2nut[] = { /* * > [Q1\r] * < [(226.0 195.0 226.0 014 49.0 27.5 30.0 00001000\r] * 01234567890123456789012345678901234567890123456 * 0 1 2 3 4 */ { "input.voltage", 0, NULL, "Q1\r", "", 47, '(', "", 1, 5, "%.1f", 0, NULL, NULL, NULL }, { "input.voltage.fault", 0, NULL, "Q1\r", "", 47, '(', "", 7, 11, "%.1f", 0, NULL, NULL, NULL }, { "output.voltage", 0, NULL, "Q1\r", "", 47, '(', "", 13, 17, "%.1f", 0, NULL, NULL, NULL }, { "ups.load", 0, NULL, "Q1\r", "", 47, '(', "", 19, 21, "%.0f", 0, NULL, NULL, NULL }, { "input.frequency", 0, NULL, "Q1\r", "", 47, '(', "", 23, 26, "%.1f", 0, NULL, NULL, NULL }, { "battery.voltage", 0, NULL, "Q1\r", "", 47, '(', "", 28, 31, "%.2f", 0, NULL, NULL, qx_multiply_battvolt }, { "ups.temperature", 0, NULL, "Q1\r", "", 47, '(', "", 33, 36, "%.1f", 0, NULL, NULL, NULL }, /* Status bits */ { "ups.status", 0, NULL, "Q1\r", "", 47, '(', "", 38, 38, NULL, QX_FLAG_QUICK_POLL, NULL, NULL, blazer_process_status_bits }, /* Utility Fail (Immediate) */ { "ups.status", 0, NULL, "Q1\r", "", 47, '(', "", 39, 39, NULL, QX_FLAG_QUICK_POLL, NULL, NULL, blazer_process_status_bits }, /* Battery Low */ { "ups.status", 0, NULL, "Q1\r", "", 47, '(', "", 40, 40, NULL, QX_FLAG_QUICK_POLL, NULL, NULL, blazer_process_status_bits }, /* Bypass/Boost or Buck Active */ { "ups.alarm", 0, NULL, "Q1\r", "", 47, '(', "", 41, 41, NULL, 0, NULL, NULL, blazer_process_status_bits }, /* UPS Failed */ { "ups.type", 0, NULL, "Q1\r", "", 47, '(', "", 42, 42, "%s", QX_FLAG_STATIC, NULL, NULL, blazer_process_status_bits }, /* UPS Type */ { "ups.status", 0, NULL, "Q1\r", "", 47, '(', "", 43, 43, NULL, QX_FLAG_QUICK_POLL, NULL, NULL, blazer_process_status_bits }, /* Test in Progress */ { "ups.status", 0, NULL, "Q1\r", "", 47, '(', "", 44, 44, NULL, QX_FLAG_QUICK_POLL, NULL, NULL, blazer_process_status_bits }, /* Shutdown Active */ { "ups.beeper.status", 0, NULL, "Q1\r", "", 47, '(', "", 45, 45, "%s", 0, NULL, NULL, blazer_process_status_bits }, /* Beeper status */ /* * > [F\r] * < [#220.0 000 024.0 50.0\r] * 0123456789012345678901 * 0 1 2 */ { "input.voltage.nominal", 0, NULL, "F\r", "", 22, '#', "", 1, 5, "%.0f", QX_FLAG_STATIC, NULL, NULL, NULL }, { "input.current.nominal", 0, NULL, "F\r", "", 22, '#', "", 7, 9, "%.1f", QX_FLAG_STATIC, NULL, NULL, NULL }, { "battery.voltage.nominal", 0, NULL, "F\r", "", 22, '#', "", 11, 15, "%.1f", QX_FLAG_STATIC, NULL, NULL, NULL }, { "input.frequency.nominal", 0, NULL, "F\r", "", 22, '#', "", 17, 20, "%.0f", QX_FLAG_STATIC, NULL, NULL, NULL }, /* * > [FW?\r] * < [#------------- ------ VT12046Q \r] * 012345678901234567890123456789012345678 * 0 1 2 3 */ { "device.mfr", 0, NULL, "FW?\r", "", 39, '#', "", 1, 15, "%s", QX_FLAG_STATIC | QX_FLAG_TRIM, NULL, NULL, NULL }, { "device.model", 0, NULL, "FW?\r", "", 39, '#', "", 17, 26, "%s", QX_FLAG_STATIC | QX_FLAG_TRIM, NULL, NULL, NULL }, { "ups.firmware", 0, NULL, "FW?\r", "", 39, '#', "", 28, 37, "%s", QX_FLAG_STATIC | QX_FLAG_TRIM, NULL, NULL, NULL }, /* Instant commands */ { "beeper.toggle", 0, NULL, "Q\r", "", 0, 0, "", 0, 0, NULL, QX_FLAG_CMD, NULL, NULL, NULL }, { "load.off", 0, NULL, "S00R0000\r", "", 0, 0, "", 0, 0, NULL, QX_FLAG_CMD, NULL, NULL, NULL }, { "load.on", 0, NULL, "C\r", "", 0, 0, "", 0, 0, NULL, QX_FLAG_CMD, NULL, NULL, NULL }, { "shutdown.return", 0, NULL, "S%s\r", "", 0, 0, "", 0, 0, NULL, QX_FLAG_CMD, NULL, NULL, blazer_process_command }, { "shutdown.stayoff", 0, NULL, "S%sR0000\r", "", 0, 0, "", 0, 0, NULL, QX_FLAG_CMD, NULL, NULL, blazer_process_command }, { "shutdown.stop", 0, NULL, "C\r", "", 0, 0, "", 0, 0, NULL, QX_FLAG_CMD, NULL, NULL, NULL }, { "test.battery.start", 0, NULL, "T%02d\r", "", 0, 0, "", 0, 0, NULL, QX_FLAG_CMD, NULL, NULL, blazer_process_command }, { "test.battery.start.deep", 0, NULL, "TL\r", "", 0, 0, "", 0, 0, NULL, QX_FLAG_CMD, NULL, NULL, NULL }, { "test.battery.start.quick", 0, NULL, "T\r", "", 0, 0, "", 0, 0, NULL, QX_FLAG_CMD, NULL, NULL, NULL }, { "test.battery.stop", 0, NULL, "CT\r", "", 0, 0, "", 0, 0, NULL, QX_FLAG_CMD, NULL, NULL, NULL }, /* Server-side settable vars */ { "ups.delay.start", ST_FLAG_RW, blazer_r_ondelay, NULL, "", 0, 0, "", 0, 0, DEFAULT_ONDELAY, QX_FLAG_ABSENT | QX_FLAG_SETVAR | QX_FLAG_RANGE, NULL, NULL, blazer_process_setvar }, { "ups.delay.shutdown", ST_FLAG_RW, blazer_r_offdelay, NULL, "", 0, 0, "", 0, 0, DEFAULT_OFFDELAY, QX_FLAG_ABSENT | QX_FLAG_SETVAR | QX_FLAG_RANGE, NULL, NULL, blazer_process_setvar }, /* End of structure. */ { NULL, 0, NULL, NULL, "", 0, 0, "", 0, 0, NULL, 0, NULL, NULL, NULL } }; /* Testing table */ #ifdef TESTING static testing_t zinto_testing[] = { { "Q1\r", "(215.0 195.0 230.0 014 49.0 22.7 30.0 00000000\r", -1 }, { "F\r", "#230.0 000 024.0 50.0\r", -1 }, { "FW?\r", "#NOT_A_LIVE_UPS TESTING TESTING \r", -1 }, { "Q\r", "", -1 }, { "S03\r", "", -1 }, { "C\r", "", -1 }, { "S02R0005\r", "", -1 }, { "S.5R0000\r", "", -1 }, { "T04\r", "", -1 }, { "TL\r", "", -1 }, { "T\r", "", -1 }, { "CT\r", "", -1 }, { NULL } }; #endif /* TESTING */ /* Subdriver-specific initups */ static void zinto_initups(void) { blazer_initups(zinto_qx2nut); } /* Subdriver interface */ subdriver_t zinto_subdriver = { ZINTO_VERSION, blazer_claim, zinto_qx2nut, zinto_initups, NULL, blazer_makevartable, "ACK", NULL, #ifdef TESTING zinto_testing, #endif /* TESTING */ }; nut-2.8.1/drivers/gamatronic.h0000644000175000017500000003130214500336654013231 00000000000000/* gamatronic.h * * SEC UPS Driver ported to the new NUT API for Gamatronic UPS Usage. * * Copyright (C) * 2001 John Marley * 2002 Jules Taplin * 2002 Eric Lawson * 2005 Arnaud Quette * 2005 Nadav Moskovitch * * 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 2 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, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #ifndef NUT_GAMATRONIC_H_SEEN #define NUT_GAMATRONIC_H_SEEN 1 #define SEC_MSG_STARTCHAR '^' #define SEC_POLLCMD 'P' #define SEC_SETCMD 'S' #define SEC_DATAMSG 'D' #define SEC_UPSMSG '*' #define SEC_ACK '1' #define SEC_NAK '0' /* commands */ #define SEC_AVAILP1 "AP1" /* Part1 of available variables */ #define SEC_AVAILP2 "AP2" /* Part1 of available variables */ #define SEC_AUTORESTART "ATR" /* Enable/disable auto restart */ #define SEC_MFR "MAN" /* UPS Manufacturer */ #define SEC_MOD "MOD" /* UPS Model */ #define SEC_NOMINAL "NOM" /* Nominal Values */ #define SEC_SHUTDOWN "PSD" /* Shutdown after delay/cancel */ #define SEC_REBOOT "RWD" /* Reboot with duration/cancel */ #define SEC_SHUTTYPE "SDA" /* Shutdown Type */ #define SEC_BATTSTAT "ST1" /* Battery Status */ #define SEC_INPUTSTAT "ST2" /* Input Status */ #define SEC_OUTPUTSTAT "ST3" /* Output Status */ #define SEC_BYPASSSTAT "ST4" /* Bypass Status */ #define SEC_ALARMSTAT "ST5" /* UPS Alarms */ #define SEC_STARTDELAY "STD" /* Startup after delay */ #define SEC_TESTRESULT "STR" /* Test Results */ #define SEC_TEST "TST" /* UPS Test/abort */ #define SEC_BAUDRATE "UBR" /* UPS Baud Rate */ #define SEC_UPSID "UID" /* UPS Identifier */ #define SEC_VERSION "VER" /* UPS Software Version */ #define FLAG_STRING 1 #define FLAG_RW 2 #define FLAG_WONLY 3 /* Dont waste time on reading commands that are read only */ #define FLAG_ALARM 4 /* If the value of a var with this flag equals to 1, then its name added to alarms list */ #define FLAG_MULTI 5 /* Multiple UNIT value instead of Dividing It */ #define FLAG_POLL 0 /* For commands that polled normaly */ #define FLAG_POLLONCE 1 /* For commands that only polled once */ /* Some baud rates for setup_serial() */ static struct { speed_t rate; /* Value like B19200 defined in termios.h; note: NOT the bitrate numerically */ size_t name; /* Actual rate... WHY is this "name" - number to print interactively? */ } baud_rates[] = { { B1200, 1200 }, { B2400, 2400 }, { B4800, 4800 }, { B9600, 9600 }, { B19200, 19200 }, }; #define SEC_NUMVARS 89 #define SEC_MAX_VARSIZE 65 /* macro for checking whether a variable is supported */ typedef struct { const char *setcmd; /* INFO_x define from shared.h */ const char *name; /* Human readable text (also in shared-tables.h) */ int unit; /* Variable should be divided by this */ const char *cmd; /* Command to send to pool/set variable */ int field; /* Which returned field variable corresponsd to */ int size; /* string length/integer max/enum count */ int poll; /* poll flag */ int flags; /* Flags for addinfo() */ char value[SEC_MAX_VARSIZE]; } sec_varlist_t; static sec_varlist_t sec_varlist[] = { { "", "", 0, "", 0, 0, 0, 0, "" }, /*setcmd name unit cmd field size poll flags value */ { "", "Awaiting Power ", 1, SEC_ALARMSTAT, 13, 2, 0, FLAG_ALARM, ""}, { "", "Bypass Bad ", 1, SEC_ALARMSTAT, 5, 2, 0, FLAG_ALARM, ""}, { "", "Charger Failure ", 1, SEC_ALARMSTAT, 8, 2, 0, FLAG_ALARM, ""}, { "", "Fan Failure ", 1, SEC_ALARMSTAT, 10, 2, 0, FLAG_ALARM, ""}, { "", "Fuse Failure ", 1, SEC_ALARMSTAT, 11, 2, 0, FLAG_ALARM, ""}, { "", "General Fault ", 1, SEC_ALARMSTAT, 12, 2, 0, FLAG_ALARM, ""}, { "", "Input Bad ", 1, SEC_ALARMSTAT, 2, 2, 0, FLAG_ALARM, ""}, { "", "Output Bad ", 1, SEC_ALARMSTAT, 3, 2, 0, FLAG_ALARM, ""}, { "", "Output Off ", 1, SEC_ALARMSTAT, 6, 2, 0, FLAG_ALARM, ""}, { "", "Overload ", 1, SEC_ALARMSTAT, 4, 2, 0, FLAG_ALARM, ""}, { "", "Shutdown Imminent ", 1, SEC_ALARMSTAT, 15, 2, 0, FLAG_ALARM, ""}, { "", "Shutdown Pending ", 1, SEC_ALARMSTAT, 14, 2, 0, FLAG_ALARM, ""}, { "", "System Off ", 1, SEC_ALARMSTAT, 9, 2, 0, FLAG_ALARM, ""}, { "", "Temperature ", 1, SEC_ALARMSTAT, 1, 2, 0, FLAG_ALARM, ""}, { "", "UPS Shutdown ", 1, SEC_ALARMSTAT, 7, 2, 0, FLAG_ALARM, ""}, { "", "Audible Alarm", 1, SEC_NOMINAL, 8, 4, FLAG_POLLONCE, FLAG_RW, ""}, { "", "Auto Restart", 1, SEC_AUTORESTART, 1, 2, FLAG_POLLONCE, FLAG_RW, ""}, { "", "Battery Charge", 1, SEC_BATTSTAT, 3, 4, 0, 0, ""}, { "", "Battery Condition", 1, SEC_BATTSTAT, 1, 3, 0, 0, ""}, { "battery.current", "Battery Current", 10, SEC_BATTSTAT, 8, 9999, 0, 0, ""}, { "battery.date", "Battery Installed", 1, SEC_NOMINAL, 11, 8, FLAG_POLLONCE, FLAG_STRING, ""}, { "", "Battery Status", 1, SEC_BATTSTAT, 2, 3, 0, 0, ""}, { "battery.temperature", "Battery Temperature", 1, SEC_BATTSTAT, 9, 99, 0, 0, ""}, { "battery.voltage", "Battery Voltage", 10, SEC_BATTSTAT, 7, 9999, 0, 0, ""}, { "", "Bypass Current 1", 10, SEC_BYPASSSTAT, 4, 9999, 0, 0, ""}, { "", "Bypass Current 2", 10, SEC_BYPASSSTAT, 7, 9999, 0, 0, ""}, { "", "Bypass Current 3", 10, SEC_BYPASSSTAT, 10, 9999, 0, 0, ""}, { "", "Bypass Frequency", 10, SEC_BYPASSSTAT, 1, 999, 0, 0, ""}, { "", "Bypass Num Lines", 1, SEC_BYPASSSTAT, 2, 9, 0, 0, ""}, { "", "Bypass Power 1", 1, SEC_BYPASSSTAT, 5, 99999, 0, 0, ""}, { "", "Bypass Power 2", 1, SEC_BYPASSSTAT, 8, 99999, 0, 0, ""}, { "", "Bypass Power 3", 1, SEC_BYPASSSTAT, 11, 99999, 0, 0, ""}, { "", "Bypass Voltage 1", 10, SEC_BYPASSSTAT, 3, 9999, 0, 0, ""}, { "", "Bypass Voltage 2", 10, SEC_BYPASSSTAT, 6, 9999, 0, 0, ""}, { "", "Bypass Voltage 3", 10, SEC_BYPASSSTAT, 9, 9999, 0, 0, ""}, { "battery.charge", "Estimated Charge", 1, SEC_BATTSTAT, 6, 999, 0, 0, ""}, { "battery.runtime.low", "Estimated Minutes", 60, SEC_BATTSTAT, 5, 999, 0, FLAG_MULTI, ""}, { "input.transfer.high", "High Volt Xfer Pt", 1, SEC_NOMINAL, 10, 999, FLAG_POLLONCE, FLAG_STRING, ""}, { "ups.id", "Identification", 1, SEC_UPSID, 1, 64, FLAG_POLLONCE, FLAG_STRING, ""}, { "", "Input Current 1", 10, SEC_INPUTSTAT, 5, 9999, 0, 0, ""}, { "", "Input Current 2", 10, SEC_INPUTSTAT, 9, 9999, 0, 0, ""}, { "", "Input Current 3", 10, SEC_INPUTSTAT, 13, 9999, 0, 0, ""}, { "input.frequency", "Input Frequency 1", 10, SEC_INPUTSTAT, 3, 999, 0, 0, ""}, { "", "Input Frequency 2", 10, SEC_INPUTSTAT, 7, 999, 0, 0, ""}, { "", "Input Frequency 3", 10, SEC_INPUTSTAT, 11, 999, 0, 0, ""}, { "", "Input Line Bads", 1, SEC_INPUTSTAT, 1, 999, 0, 0, ""}, { "", "Input Num Lines", 1, SEC_INPUTSTAT, 2, 9, 0, 0, ""}, { "", "Input Power 1", 1, SEC_INPUTSTAT, 6, 99999, 0, 0, ""}, { "", "Input Power 2", 1, SEC_INPUTSTAT, 10, 99999, 0, 0, ""}, { "", "Input Power 3", 1, SEC_INPUTSTAT, 14, 99999, 0, 0, ""}, { "input.voltage", "Input Voltage 1", 10, SEC_INPUTSTAT, 4, 9999, 0, 0, ""}, { "", "Input Voltage 2", 10, SEC_INPUTSTAT, 8, 9999, 0, 0, ""}, { "", "Input Voltage 3", 10, SEC_INPUTSTAT, 12, 9999, 0, 0, ""}, { "input.transfer.low", "Low Volt Xfer Pt", 1, SEC_NOMINAL, 9, 999, FLAG_POLLONCE, FLAG_STRING, ""}, { "ups.mfr", "Manufacturer", 1, SEC_MFR, 1, 32, FLAG_POLLONCE, FLAG_STRING, ""}, { "ups.model", "Model", 1, SEC_MOD, 1, 64, FLAG_POLLONCE, FLAG_STRING, ""}, { "", "Nominal Battery Life", 1, SEC_NOMINAL, 12, 99999, FLAG_POLLONCE, FLAG_STRING, ""}, { "", "Nominal Input Frequency", 10, SEC_NOMINAL, 2, 999, FLAG_POLLONCE, FLAG_RW, ""}, { "input.voltage.nominal", "Nominal Input Voltage", 1, SEC_NOMINAL, 1, 999, FLAG_POLLONCE, FLAG_STRING, ""}, { "", "Nominal Low Battery Time", 1, SEC_NOMINAL, 7, 99, FLAG_POLLONCE, FLAG_STRING, ""}, { "", "Nominal Output Frequency", 10, SEC_NOMINAL, 4, 999, FLAG_POLLONCE, FLAG_RW, ""}, { "", "Nominal Output Power", 1, SEC_NOMINAL, 6, 99999, FLAG_POLLONCE, FLAG_STRING, ""}, { "", "Nominal Output Voltage", 1, SEC_NOMINAL, 3, 999, FLAG_POLLONCE, FLAG_STRING, ""}, { "ups.power.nominal", "Nominal VA Rating", 1, SEC_NOMINAL, 5, 99999, FLAG_POLLONCE, FLAG_STRING, ""}, { "output.current", "Output Current 1", 10, SEC_OUTPUTSTAT, 5, 9999, 0, 0, ""}, { "", "Output Current 2", 10, SEC_OUTPUTSTAT, 9, 9999, 0, 0, ""}, { "", "Output Current 3", 10, SEC_OUTPUTSTAT, 13, 9999, 0, 0, ""}, { "output.frequency", "Output Frequency", 10, SEC_OUTPUTSTAT, 2, 999, 0, 0, ""}, { "ups.load", "Output Load 1", 1, SEC_OUTPUTSTAT, 7, 999, 0, 0, ""}, { "", "Output Load 2", 1, SEC_OUTPUTSTAT, 11, 999, 0, 0, ""}, { "", "Output Load 3", 1, SEC_OUTPUTSTAT, 15, 999, 0, 0, ""}, { "", "Output Num Lines", 1, SEC_OUTPUTSTAT, 3, 9, 0, 0, ""}, { "", "Output Power 1", 1, SEC_OUTPUTSTAT, 6, 99999, 0, 0, ""}, { "", "Output Power 2", 1, SEC_OUTPUTSTAT, 10, 99999, 0, 0, ""}, { "", "Output Power 3", 1, SEC_OUTPUTSTAT, 14, 99999, 0, 0, ""}, { "", "Output Source", 1, SEC_OUTPUTSTAT, 1, 6, 0, 0, ""}, { "output.voltage", "Output Voltage 1", 10, SEC_OUTPUTSTAT, 4, 9999, 0, 0, ""}, { "", "Output Voltage 2", 10, SEC_OUTPUTSTAT, 8, 9999, 0, 0, ""}, { "", "Output Voltage 3", 10, SEC_OUTPUTSTAT, 12, 9999, 0, 0, ""}, { "", "Reboot With Duration", 1, SEC_REBOOT, 1, 9999999, FLAG_POLLONCE, FLAG_WONLY, ""}, { "battery.runtime", "Seconds on Battery", 1, SEC_BATTSTAT, 4, 99999, 0, 0, ""}, { "", "Shutdown Type", 1, SEC_SHUTTYPE, 1, 2, FLAG_POLLONCE, FLAG_RW, ""}, { "ups.delay.shutdown", "Shutdown After Delay", 1, SEC_STARTDELAY, 1, 9999999, FLAG_POLLONCE, FLAG_WONLY, ""}, { "ups.firmware", "Software Version", 1, SEC_VERSION, 1, 32, FLAG_POLLONCE, FLAG_STRING, ""}, { "", "Startup After Delay", 1, SEC_STARTDELAY, 1, 9999999, FLAG_POLLONCE, FLAG_WONLY, ""}, { "", "Test Results Detail", 1, SEC_TESTRESULT, 2, 64, FLAG_POLLONCE, FLAG_STRING, ""}, { "", "Test Results Summary", 1, SEC_TESTRESULT, 1, 6, FLAG_POLLONCE, 0, ""}, { "", "Test Type", 1, SEC_TEST, 1, 5, FLAG_POLLONCE, FLAG_WONLY, ""}, { "", "Baud Rate", 1, SEC_BAUDRATE, 1, 19200, FLAG_POLLONCE, FLAG_RW, ""}, }; /* a type for the supported variables */ #define SEC_QUERYLIST_LEN 17 #define SEC_MAXFIELDS 16 #define SEC_POLL 1 #define SEC_POLLONCE 0 static struct { const char *command; /* sec command */ int varnum[SEC_MAXFIELDS]; /* sec variable number for each field */ int pollflag; } sec_querylist[SEC_QUERYLIST_LEN]; #define sqv(a,b) sec_querylist[a].varnum[b] #endif /* NUT_GAMATRONIC_H_SEEN */ nut-2.8.1/drivers/dummy-ups.c0000644000175000017500000005772414516530040013050 00000000000000/* dummy-ups.c - NUT simulation and device repeater driver Copyright (C) 2005 - 2015 Arnaud Quette 2014 - 2023 Jim Klimov 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 2 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, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ /* TODO list: * - separate the code between dummy and repeater/meta * - for repeater/meta: * * add support for instant commands and setvar * - for dummy: * * variable/value enforcement using cmdvartab for testing * the variable existance, and possible values * * allow variable creation on the fly (using upsrw) * * poll the "port" file for change */ #include "config.h" /* must be the first header */ #ifndef WIN32 #include #include #include #endif #include #include #include "main.h" #include "parseconf.h" #include "nut_stdint.h" #include "upsclient.h" #include "dummy-ups.h" #define DRIVER_NAME "Device simulation and repeater driver" #define DRIVER_VERSION "0.18" /* driver description structure */ upsdrv_info_t upsdrv_info = { DRIVER_NAME, DRIVER_VERSION, "Arnaud Quette ", DRV_STABLE, { NULL } }; enum drivermode { MODE_NONE = 0, /* use the embedded defintion or a definition file, parsed in a * loop again and again (often with TIMER lines to delay changes) * Default mode for files with *.seq naming pattern * (legacy-compatibility note: and other patterns except *.dev) */ MODE_DUMMY_LOOP, /* use the embedded defintion or a definition file, parsed once * * This allows to spin up a dummy device with initial readings * and retain in memory whatever SET VAR was sent by clients later. * This is also less stressful on system resources to run the dummy. * * Default mode for files with *.dev naming pattern */ MODE_DUMMY_ONCE, /* use libupsclient to repeat another UPS */ MODE_REPEATER, /* consolidate data from several UPSs (TBS) */ MODE_META }; typedef enum drivermode drivermode_t; static drivermode_t mode = MODE_NONE; /* parseconf context, for dummy mode using a file */ static PCONF_CTX_t *ctx = NULL; static time_t next_update = -1; static struct stat datafile_stat; #define MAX_STRING_SIZE 128 static int setvar(const char *varname, const char *val); static int instcmd(const char *cmdname, const char *extra); static int parse_data_file(TYPE_FD arg_upsfd); static dummy_info_t *find_info(const char *varname); static int is_valid_data(const char* varname); static int is_valid_value(const char* varname, const char *value); /* libupsclient update */ static int upsclient_update_vars(void); /* connection information */ static char *client_upsname = NULL, *hostname = NULL; static UPSCONN_t *ups = NULL; static uint16_t port; /* repeater mode parameters */ static int repeater_disable_strict_start = 0; /* Driver functions */ void upsdrv_initinfo(void) { dummy_info_t *item; switch (mode) { case MODE_DUMMY_ONCE: case MODE_DUMMY_LOOP: /* Initialise basic essential variables */ for ( item = nut_data ; item->info_type != NULL ; item++ ) { if (item->drv_flags & DU_FLAG_INIT) { dstate_setinfo(item->info_type, "%s", item->default_value); dstate_setflags(item->info_type, item->info_flags); /* Set max length for strings, if needed */ if (item->info_flags & ST_FLAG_STRING) dstate_setaux(item->info_type, (long)item->info_len); } } /* Now get user's defined variables */ if (parse_data_file(upsfd) < 0) upslogx(LOG_NOTICE, "Unable to parse the definition file %s", device_path); /* Initialize handler */ upsh.setvar = setvar; dstate_dataok(); break; case MODE_META: case MODE_REPEATER: /* Obtain the target name */ if (upscli_splitname(device_path, &client_upsname, &hostname, &port) != 0) { fatalx(EXIT_FAILURE, "Error: invalid UPS definition.\nRequired format: upsname[@hostname[:port]]"); } /* Connect to the target */ ups = xmalloc(sizeof(*ups)); if (upscli_connect(ups, hostname, port, UPSCLI_CONN_TRYSSL) < 0) { if(repeater_disable_strict_start == 1) { upslogx(LOG_WARNING, "Warning: %s", upscli_strerror(ups)); } else { fatalx(EXIT_FAILURE, "Error: %s. " "Any errors encountered starting the repeater mode result in driver termination, " "perhaps you want to set the 'repeater_disable_strict_start' option?" , upscli_strerror(ups)); } } else { upsdebugx(1, "Connected to %s@%s", client_upsname, hostname); } if (upsclient_update_vars() < 0) { /* check for an old upsd */ if (upscli_upserror(ups) == UPSCLI_ERR_UNKCOMMAND) { fatalx(EXIT_FAILURE, "Error: upsd is too old to support this query"); } if(repeater_disable_strict_start == 1) { upslogx(LOG_WARNING, "Warning: %s", upscli_strerror(ups)); } else { fatalx(EXIT_FAILURE, "Error: %s. " "Any errors encountered starting the repeater mode result in driver termination, " "perhaps you want to set the 'repeater_disable_strict_start' option?" , upscli_strerror(ups)); } } /* FIXME: commands and settable variable! */ break; case MODE_NONE: #if (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_PUSH_POP) && ( (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_COVERED_SWITCH_DEFAULT) || (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_UNREACHABLE_CODE) ) # pragma GCC diagnostic push #endif #ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_COVERED_SWITCH_DEFAULT # pragma GCC diagnostic ignored "-Wcovered-switch-default" #endif #ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_UNREACHABLE_CODE # pragma GCC diagnostic ignored "-Wunreachable-code" #endif /* Older CLANG (e.g. clang-3.4) seems to not support the GCC pragmas above */ #ifdef __clang__ # pragma clang diagnostic push # pragma clang diagnostic ignored "-Wunreachable-code" # pragma clang diagnostic ignored "-Wcovered-switch-default" #endif /* All enum cases defined as of the time of coding * have been covered above. Handle later definitions, * memory corruptions and buggy inputs below... */ default: fatalx(EXIT_FAILURE, "no suitable definition found!"); #ifdef __clang__ # pragma clang diagnostic pop #endif #if (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_PUSH_POP) && ( (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_COVERED_SWITCH_DEFAULT) || (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_UNREACHABLE_CODE) ) # pragma GCC diagnostic pop #endif } upsh.instcmd = instcmd; dstate_addcmd("load.off"); } static int prepare_filepath(char *fn, size_t buflen) { /* Note: device_path is a global variable, * the "port=..." value parsed in main.c */ if (device_path[0] == '/' #ifdef WIN32 || device_path[1] == ':' /* "C:\..." */ #endif ) { /* absolute path */ return snprintf(fn, buflen, "%s", device_path); } else if (device_path[0] == '.') { /* "./" or "../" e.g. via CLI, relative to current working * directory of the driver process... at this moment */ if (getcwd(fn, buflen)) { return snprintf(fn + strlen(fn), buflen - strlen(fn), "/%s", device_path); } else { return snprintf(fn, buflen, "%s", device_path); } } else { /* assumed to be a filename in NUT config file path * (possibly under, with direct use of dirname without dots) * Note that we do not fiddle with file-path separator, * modern Windows (at least via MinGW/MSYS2) supports * the POSIX slash. */ return snprintf(fn, buflen, "%s/%s", confpath(), device_path); } } void upsdrv_updateinfo(void) { upsdebugx(1, "upsdrv_updateinfo..."); sleep(1); switch (mode) { case MODE_DUMMY_LOOP: /* Now get user's defined variables */ if (parse_data_file(upsfd) >= 0) dstate_dataok(); break; case MODE_DUMMY_ONCE: /* less stress on the sys */ if (ctx == NULL && next_update == -1) { struct stat fs; char fn[SMALLBUF]; prepare_filepath(fn, sizeof(fn)); /* Determine if file modification timestamp has changed * since last use (so we would want to re-read it) */ #ifndef WIN32 /* Either successful stat (zero return) is OK to * fill the "fs" struct. Note that currently * "upsfd" is a no-op for files, they are re-opened * and re-parsed every time so callers can modify * the data without complications. */ if ( (INVALID_FD(upsfd) || 0 != fstat (upsfd, &fs)) && 0 != stat (fn, &fs)) #else /* Consider GetFileAttributesEx() for WIN32_FILE_ATTRIBUTE_DATA? * https://stackoverflow.com/questions/8991192/check-the-file-size-without-opening-file-in-c/8991228#8991228 */ if (0 != stat (fn, &fs)) #endif { upsdebugx(2, "%s: MODE_DUMMY_ONCE: Can't stat %s currently", __func__, fn); /* retry ASAP until we get a file */ memset(&datafile_stat, 0, sizeof(struct stat)); next_update = 1; } else { if (datafile_stat.st_mtime != fs.st_mtime) { upsdebugx(2, "%s: MODE_DUMMY_ONCE: input file was already read once " "to the end, but changed later - re-reading: %s", __func__, fn); /* updated file => retry ASAP */ next_update = 1; datafile_stat = fs; } } } if (ctx == NULL && next_update == -1) { upsdebugx(2, "%s: MODE_DUMMY_ONCE: NO-OP: input file was already read once to the end", __func__); dstate_dataok(); } else { /* initial parsing interrupted by e.g. TIMER line */ if (parse_data_file(upsfd) >= 0) dstate_dataok(); } break; case MODE_META: case MODE_REPEATER: if (upsclient_update_vars() > 0) { dstate_dataok(); } else { /* try to reconnect */ upscli_disconnect(ups); if (upscli_connect(ups, hostname, port, UPSCLI_CONN_TRYSSL) < 0) { upsdebugx(1, "Error reconnecting: %s", upscli_strerror(ups)); } else { upsdebugx(1, "Reconnected"); } } break; case MODE_NONE: #if (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_PUSH_POP) && ( (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_COVERED_SWITCH_DEFAULT) || (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_UNREACHABLE_CODE) ) # pragma GCC diagnostic push #endif #ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_COVERED_SWITCH_DEFAULT # pragma GCC diagnostic ignored "-Wcovered-switch-default" #endif #ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_UNREACHABLE_CODE # pragma GCC diagnostic ignored "-Wunreachable-code" #endif /* Older CLANG (e.g. clang-3.4) seems to not support the GCC pragmas above */ #ifdef __clang__ # pragma clang diagnostic push # pragma clang diagnostic ignored "-Wunreachable-code" # pragma clang diagnostic ignored "-Wcovered-switch-default" #endif /* All enum cases defined as of the time of coding * have been covered above. Handle later definitions, * memory corruptions and buggy inputs below... */ default: break; #ifdef __clang__ # pragma clang diagnostic pop #endif #if (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_PUSH_POP) && ( (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_COVERED_SWITCH_DEFAULT) || (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_UNREACHABLE_CODE) ) # pragma GCC diagnostic pop #endif } } void upsdrv_shutdown(void) { /* replace with a proper shutdown function */ upslogx(LOG_ERR, "shutdown not supported"); set_exit_flag(-1); } static int instcmd(const char *cmdname, const char *extra) { /* if (!strcasecmp(cmdname, "test.battery.stop")) { ser_send_buf(upsfd, ...); return STAT_INSTCMD_HANDLED; } */ /* FIXME: the below is only valid if (mode == MODE_DUMMY) * if (mode == MODE_REPEATER) => forward * if (mode == MODE_META) => ? */ upslogx(LOG_NOTICE, "instcmd: unknown command [%s] [%s]", cmdname, extra); return STAT_INSTCMD_UNKNOWN; } void upsdrv_help(void) { } void upsdrv_makevartable(void) { addvar(VAR_VALUE, "mode", "Specify mode instead of guessing it from port value (dummy = dummy-loop, dummy-once, repeater)"); /* meta */ addvar(VAR_FLAG, "repeater_disable_strict_start", "Do not terminate the driver encountering errors when starting the repeater mode"); } void upsdrv_initups(void) { const char *val; val = dstate_getinfo("driver.parameter.mode"); if (val) { if (!strcmp(val, "dummy-loop") && !strcmp(val, "dummy-once") && !strcmp(val, "dummy") && !strcmp(val, "repeater") /* && !strcmp(val, "meta") */ ) { fatalx(EXIT_FAILURE, "Unsupported mode was specified: %s", val); } } /* check the running mode... */ if ( (!val && strchr(device_path, '@')) || (val && !strcmp(val, "repeater")) /*|| (val && !strcmp(val, "meta")) */ ) { upsdebugx(1, "Repeater mode"); mode = MODE_REPEATER; dstate_setinfo("driver.parameter.mode", "repeater"); /* FIXME: if there is at least one more => MODE_META... */ } else { char fn[SMALLBUF]; mode = MODE_NONE; if (val) { if (!strcmp(val, "dummy-loop")) { upsdebugx(2, "Dummy (simulation) mode looping infinitely was explicitly requested"); mode = MODE_DUMMY_LOOP; } else if (!strcmp(val, "dummy-once")) { upsdebugx(2, "Dummy (simulation) mode with data read once was explicitly requested"); mode = MODE_DUMMY_ONCE; } else if (!strcmp(val, "dummy")) { upsdebugx(2, "Dummy (simulation) mode default (looping infinitely) was explicitly requested"); mode = MODE_DUMMY_LOOP; } } if (mode == MODE_NONE) { if (str_ends_with(device_path, ".seq")) { upsdebugx(2, "Dummy (simulation) mode with a sequence file name pattern (looping infinitely)"); mode = MODE_DUMMY_LOOP; } else if (str_ends_with(device_path, ".dev")) { upsdebugx(2, "Dummy (simulation) mode with a device data dump file name pattern (read once)"); mode = MODE_DUMMY_ONCE; } } /* Report decisions similar to those above, * just a bit shorter and at another level */ switch (mode) { case MODE_DUMMY_ONCE: upsdebugx(1, "Dummy (simulation) mode using data read once"); dstate_setinfo("driver.parameter.mode", "dummy-once"); break; case MODE_DUMMY_LOOP: upsdebugx(1, "Dummy (simulation) mode looping infinitely"); dstate_setinfo("driver.parameter.mode", "dummy-loop"); break; case MODE_NONE: case MODE_REPEATER: case MODE_META: #if (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_PUSH_POP) && ( (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_COVERED_SWITCH_DEFAULT) || (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_UNREACHABLE_CODE) ) # pragma GCC diagnostic push #endif #ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_COVERED_SWITCH_DEFAULT # pragma GCC diagnostic ignored "-Wcovered-switch-default" #endif #ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_UNREACHABLE_CODE # pragma GCC diagnostic ignored "-Wunreachable-code" #endif /* Older CLANG (e.g. clang-3.4) seems to not support the GCC pragmas above */ #ifdef __clang__ # pragma clang diagnostic push # pragma clang diagnostic ignored "-Wunreachable-code" # pragma clang diagnostic ignored "-Wcovered-switch-default" #endif /* All enum cases defined as of the time of coding * have been covered above. Handle later definitions, * memory corruptions and buggy inputs below... */ default: /* This was the only mode until MODE_DUMMY_LOOP * got split from MODE_DUMMY_ONCE in NUT v2.8.0 * so we keep the previously known mode string * and it remains default when we are not sure */ upsdebugx(1, "Dummy (simulation) mode default (looping infinitely)"); mode = MODE_DUMMY_LOOP; dstate_setinfo("driver.parameter.mode", "dummy"); break; #ifdef __clang__ # pragma clang diagnostic pop #endif #if (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_PUSH_POP) && ( (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_COVERED_SWITCH_DEFAULT) || (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_UNREACHABLE_CODE) ) # pragma GCC diagnostic pop #endif } prepare_filepath(fn, sizeof(fn)); /* Update file modification timestamp (and other data) */ #ifndef WIN32 /* Either successful stat (zero return) is OK to fill the * "datafile_stat" struct. Note that currently "upsfd" is * a no-op for files, they are re-opened and re-parsed * every time so callers can modify the data without * complications. */ if ( (INVALID_FD(upsfd) || 0 != fstat (upsfd, &datafile_stat)) && 0 != stat (fn, &datafile_stat)) #else /* Consider GetFileAttributesEx() for WIN32_FILE_ATTRIBUTE_DATA? * https://stackoverflow.com/questions/8991192/check-the-file-size-without-opening-file-in-c/8991228#8991228 */ if (0 != stat (fn, &datafile_stat)) #endif { upsdebugx(2, "%s: Can't stat %s (%s) currently", __func__, device_path, fn); } else { upsdebugx(2, "Located %s for device simulation data: %s", device_path, fn); } } if (testvar("repeater_disable_strict_start")) { repeater_disable_strict_start = 1; } } void upsdrv_cleanup(void) { if ( (mode == MODE_META) || (mode == MODE_REPEATER) ) { if (ups) { upscli_disconnect(ups); } if (ctx) { pconf_finish(ctx); free(ctx); } free(client_upsname); free(hostname); free(ups); } } static int setvar(const char *varname, const char *val) { dummy_info_t *item; upsdebugx(2, "entering setvar(%s, %s)", varname, val); /* FIXME: the below is only valid if (mode == MODE_DUMMY) * if (mode == MODE_REPEATER) => forward * if (mode == MODE_META) => ? */ if (!strncmp(varname, "ups.status", 10)) { status_init(); /* FIXME: split and check values (support multiple values), à la usbhid-ups */ status_set(val); status_commit(); return STAT_SET_HANDLED; } /* Check variable validity */ if (!is_valid_data(varname)) { upsdebugx(2, "setvar: invalid variable name (%s)", varname); return STAT_SET_UNKNOWN; } /* Check value validity */ if (!is_valid_value(varname, val)) { upsdebugx(2, "setvar: invalid value (%s) for variable (%s)", val, varname); return STAT_SET_UNKNOWN; } /* If value is empty, remove the variable (FIXME: do we need * a magic word?) */ if (strlen(val) == 0) { dstate_delinfo(varname); } else { dstate_setinfo(varname, "%s", val); if ( (item = find_info(varname)) != NULL) { dstate_setflags(item->info_type, item->info_flags); /* Set max length for strings, if needed */ if (item->info_flags & ST_FLAG_STRING) dstate_setaux(item->info_type, (long)item->info_len); } else { upsdebugx(2, "setvar: unknown variable (%s), using default flags", varname); dstate_setflags(varname, ST_FLAG_STRING | ST_FLAG_RW); dstate_setaux(varname, 32); } } return STAT_SET_HANDLED; } /*************************************************/ /* Support functions */ /*************************************************/ static int upsclient_update_vars(void) { int ret; size_t numq, numa; const char *query[4]; char **answer; query[0] = "VAR"; query[1] = client_upsname; numq = 2; ret = upscli_list_start(ups, numq, query); if (ret < 0) { upsdebugx(1, "Error: %s (%i)", upscli_strerror(ups), upscli_upserror(ups)); return ret; } while (upscli_list_next(ups, numq, query, &numa, &answer) == 1) { /* VAR */ if (numa < 4) { upsdebugx(1, "Error: insufficient data (got %" PRIuSIZE " args, need at least 4)", numa); } upsdebugx(5, "Received: %s %s %s %s", answer[0], answer[1], answer[2], answer[3]); /* do not override the driver collection */ if (strncmp(answer[2], "driver.", 7)) setvar(answer[2], answer[3]); } return 1; } /* find info element definition in info array */ static dummy_info_t *find_info(const char *varname) { dummy_info_t *item; for ( item = nut_data ; item->info_type != NULL ; item++ ) { if (!strcasecmp(item->info_type, varname)) return item; } upsdebugx(2, "find_info: unknown variable: %s", varname); return NULL; } /* check if data exists in our data table */ static int is_valid_data(const char* varname) { dummy_info_t *item; if ( (item = find_info(varname)) != NULL) { return 1; } /* FIXME: we need to have the full data set before * enforcing controls! We also need a way to automate * the update / sync process (with cmdvartab?!) */ upsdebugx(1, "Unknown data. Committing anyway..."); return 1; /* return 0;*/ } /* check if data's value validity */ static int is_valid_value(const char* varname, const char *value) { dummy_info_t *item; NUT_UNUSED_VARIABLE(value); if ( (item = find_info(varname)) != NULL) { /* FIXME: test enum or bound against value */ return 1; } /* FIXME: we need to have the full data set before * enforcing controls! We also need a way to automate * the update / sync process (with cmdvartab?) */ upsdebugx(1, "Unknown data. Committing value anyway..."); return 1; /* return 0;*/ } /* called for fatal errors in parseconf like malloc failures */ static void upsconf_err(const char *errmsg) { upslogx(LOG_ERR, "Fatal error in parseconf(ups.conf): %s", errmsg); } /* for dummy mode * parse the definition file and process its content */ static int parse_data_file(TYPE_FD arg_upsfd) { char fn[SMALLBUF]; char *ptr, var_value[MAX_STRING_SIZE]; size_t value_args = 0, counter; time_t now; NUT_UNUSED_VARIABLE(arg_upsfd); time(&now); upsdebugx(1, "entering parse_data_file()"); if (now < next_update) { upsdebugx(1, "leaving (paused)..."); return 1; } /* initialise everything, to loop back at the beginning of the file */ if (ctx == NULL) { ctx = (PCONF_CTX_t *)xmalloc(sizeof(PCONF_CTX_t)); prepare_filepath(fn, sizeof(fn)); pconf_init(ctx, upsconf_err); if (!pconf_file_begin(ctx, fn)) fatalx(EXIT_FAILURE, "Can't open dummy-ups definition file %s: %s", fn, ctx->errmsg); } /* Reset the next call time, so that we can loop back on the file * if there is no blocking action (ie TIMER) until the end of the file */ next_update = -1; /* Now start or continue parsing... */ while (pconf_file_next(ctx)) { if (pconf_parse_error(ctx)) { upsdebugx(2, "Parse error: %s:%d: %s", fn, ctx->linenum, ctx->errmsg); continue; } /* Check if we have something to process */ if (ctx->numargs < 1) continue; /* Process actions (only "TIMER" ATM) */ if (!strncmp(ctx->arglist[0], "TIMER", 5)) { /* TIMER will wait "seconds" before * continuing the parsing */ int delay = atoi (ctx->arglist[1]); time(&next_update); next_update += delay; upsdebugx(1, "suspending execution for %i seconds...", delay); break; } /* Remove ":" suffix, after the variable name */ if ((ptr = strchr(ctx->arglist[0], ':')) != NULL) *ptr = '\0'; upsdebugx(3, "parse_data_file: variable \"%s\" with %d args", ctx->arglist[0], (int)ctx->numargs); /* Skip the driver.* collection data */ if (!strncmp(ctx->arglist[0], "driver.", 7)) { upsdebugx(2, "parse_data_file: skipping %s", ctx->arglist[0]); continue; } /* From there, we get varname in arg[0], and values in other arg[1...x] */ /* special handler for status */ if (!strncmp( ctx->arglist[0], "ups.status", 10)) { status_init(); for (counter = 1, value_args = ctx->numargs ; counter < value_args ; counter++) { status_set(ctx->arglist[counter]); } status_commit(); } else { for (counter = 1, value_args = ctx->numargs ; counter < value_args ; counter++) { if (counter == 1) /* don't append the first space separator */ snprintf(var_value, sizeof(var_value), "%s", ctx->arglist[counter]); else snprintfcat(var_value, sizeof(var_value), " %s", ctx->arglist[counter]); } if (setvar(ctx->arglist[0], var_value) == STAT_SET_UNKNOWN) { upsdebugx(2, "parse_data_file: can't add \"%s\" with value \"%s\"\nError: %s", ctx->arglist[0], var_value, ctx->errmsg); } else { upsdebugx(3, "parse_data_file: added \"%s\" with value \"%s\"", ctx->arglist[0], var_value); } } } /* Cleanup parseconf if there is no pending action */ if (next_update == -1) { pconf_finish(ctx); free(ctx); ctx=NULL; } return 1; } nut-2.8.1/drivers/nutdrv_qx_masterguard.c0000644000175000017500000012100614502253356015530 00000000000000/* nutdrv_qx_masterguard.c - Subdriver for Masterguard A/E Series * * Copyright (C) * 2020-2021 Edgar Fuß , Mathematisches Institut der Universität Bonn * * 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 2 of the License, or * (at your option) any later version, or a 2-clause BSD License. * * 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, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #include "main.h" #include "nutdrv_qx.h" #include "nutdrv_qx_masterguard.h" #include #include "nut_stdint.h" #define MASTERGUARD_VERSION "Masterguard 0.02" /* series (for un-SKIP) */ static char masterguard_my_series = '?'; /* slave address for commands that require it */ static char masterguard_my_slaveaddr[3] = "??"; /* null-terminated for strtol() in claim() */ /* next slaveaddr to use after the SS command (which needs the old one) has been run */ static long masterguard_next_slaveaddr; /* output current/power computation */ static long masterguard_my_power = 0; /* battery voltage computation */ static long masterguard_my_numcells = 0; /* ranges */ static info_rw_t masterguard_r_slaveaddr[] = { { "0", NULL }, { "99", NULL }, { "" , NULL } }; static info_rw_t masterguard_r_batpacks[] = { { "0", NULL }, /* actually 1 for most models, see masterguard_model() */ { "9", NULL }, /* varies across models, see masterguard_model() */ { "" , NULL } }; static info_rw_t masterguard_r_offdelay[] = { { "0", NULL }, { "5940", NULL }, /* 99*60 */ { "" , NULL } }; static info_rw_t masterguard_r_ondelay[] = { { "0", NULL }, { "599940", NULL }, /* 9999*60 */ { "" , NULL } }; /* enums */ static info_rw_t *masterguard_e_outvolts = NULL; /* set in masterguard_output_voltages() */ /* preprocess functions */ /* set masterguard_my_slaveaddr (for masterguard_add_slaveaddr) */ static int masterguard_slaveaddr(item_t *item, char *value, const size_t valuelen) { if (strlen(item->value) != 2) { upsdebugx(2, "slaveaddr length not 2"); return -1; } memcpy(masterguard_my_slaveaddr, item->value, 2); if (valuelen >= 3) memcpy(value, item->value, 3); return 0; } /* set masterguard_my_series (for activating supported commands in masterguard_claim() */ static int masterguard_series(item_t *item, char *value, const size_t valuelen) { NUT_UNUSED_VARIABLE(valuelen); switch (item->value[0]) { case 'A': break; case 'E': break; default: upsdebugx(2, "unknown series %s", item->value); return -1; } masterguard_my_series = item->value[0]; memcpy(value, item->value, 2); return 0; } /* Convert strangely formatted model name in WH output * (spaces, -19 only after battery packs) to something readable * Also set min/max battery packs according to model */ static int masterguard_model(item_t *item, char *value, const size_t valuelen) { char *model; int rack; char min_bp, max_bp; rack = (strstr(item->value, "-19") != NULL); if (strncmp(item->value, "A 700", 6) == 0) { model = "A700"; min_bp = 0; max_bp = 0; } else if (strncmp(item->value, "A 1000", 6) == 0) { model = "A1000"; min_bp = 0; max_bp = 2; } else if (strncmp(item->value, "A 2000", 6) == 0) { model = "A2000"; min_bp = rack ? 1 : 0; max_bp = rack ? 5 : 2; } else if (strncmp(item->value, "A 3000", 6) == 0) { model = "A3000"; min_bp = rack ? 1 : 0; max_bp = rack ? 5 : 2; } else if (strncmp(item->value, "E 60", 4) == 0) { model = "E60"; min_bp = 1; max_bp = 1; /* ??? */ } else if (strncmp(item->value, "E100", 4) == 0) { model = "E100"; min_bp = 1; max_bp = 1; /* ??? */ } else if (strncmp(item->value, "E200", 4) == 0) { model = "E200"; min_bp = 1; max_bp = 1; /* ??? */ } else { upsdebugx(2, "unknown T %s", item->value); return -1; } masterguard_r_batpacks[0].value[0] = '0' + min_bp; masterguard_r_batpacks[1].value[0] = '0' + max_bp; snprintf(value, valuelen, "%s%s", model, rack ? "-19" : ""); return 0; } /* set masterguard_my_power (for power/current calculations) according to model */ static int masterguard_power(item_t *item, char *value, const size_t valuelen) { int p; if (strncmp(item->value, "A 700", 6) == 0) { p = 700; } else if (strncmp(item->value, "A 1000", 6) == 0) { p = 1000; } else if (strncmp(item->value, "A 2000", 6) == 0) { p = 2000; } else if (strncmp(item->value, "A 3000", 6) == 0) { p = 3000; } else if (strncmp(item->value, "E 60", 4) == 0) { p = 6000; } else if (strncmp(item->value, "E100", 4) == 0) { p = 10000; } else if (strncmp(item->value, "E200", 4) == 0) { p = 20000; } else { upsdebugx(2, "unknown T %s", item->value); return -1; } masterguard_my_power = p; snprintf(value, valuelen, "%d", p); return 0; } /* convert mmm.ss to seconds */ static int masterguard_mmm_ss(item_t *item, char *value, const size_t valuelen) { int m, s; if (sscanf(item->value, "%d.%d", &m, &s) != 2) { upsdebugx(2, "unparsable mmm.ss %s", item->value); return -1; } snprintf(value, valuelen, "%d", 60*m + s); return 0; } /* convert hhh to seconds */ static int masterguard_hhh(item_t *item, char *value, const size_t valuelen) { int h; if (sscanf(item->value, "%d", &h) != 1) { upsdebugx(2, "unparsable hhh %s", item->value); return -1; } snprintf(value, valuelen, "%d", 60*60*h); return 0; } /* convert TTTT:hh:mm:dd to seconds */ static int masterguard_tttt_hh_mm_ss(item_t *item, char *value, const size_t valuelen) { int t, h, m, s; if (sscanf(item->value, "%d:%d:%d:%d", &t, &h, &m, &s) != 4) { upsdebugx(2, "unparsable TTTT:hh:mm:ss %s", item->value); return -1; } snprintf(value, valuelen, "%d", 86400*t + 3600*h + 60*m + s); return 0; } /* set masterguard_my_numcells (for nominal battery voltage computation) */ static int masterguard_numcells(item_t *item, char *value, const size_t valuelen) { int v; if (sscanf(item->value, "%d", &v) != 1) { upsdebugx(2, "unparsable vvv %s", item->value); return -1; } masterguard_my_numcells = v; snprintf(value, valuelen, "%d", v); return 0; } /* compute nominal battery voltage */ static int masterguard_battvolt(item_t *item, char *value, const size_t valuelen) { float s; if (sscanf(item->value, "%f", &s) != 1) { upsdebugx(2, "unparsable ss.ss %s", item->value); return -1; } snprintf(value, valuelen, "%.2f", masterguard_my_numcells * s); return 0; } /* compute output power from load percentage */ static int masterguard_ups_power(item_t *item, char *value, const size_t valuelen) { int q; if (sscanf(item->value, "%d", &q) != 1) { upsdebugx(2, "unparsable qqq %s", item->value); return -1; } snprintf(value, valuelen, "%.0f", q / 100.0 * masterguard_my_power + 0.5); return 0; } /* helper routine, not to be called from table */ static int masterguard_output_current_fraction(item_t *item, char *value, const size_t valuelen, double fraction) { NUT_UNUSED_VARIABLE(item); snprintf(value, valuelen, "%.2f", fraction * masterguard_my_power / strtod(dstate_getinfo("output.voltage") , NULL) + 0.005); return 0; } /* compute output current from load percentage and output voltage */ static int masterguard_output_current(item_t *item, char *value, const size_t valuelen) { int q; if (sscanf(item->value, "%d", &q) != 1) { upsdebugx(2, "unparsable qqq %s", item->value); return -1; } return masterguard_output_current_fraction(item, value, valuelen, q/100.0); } /* compute nominal output current from output voltage */ static int masterguard_output_current_nominal(item_t *item, char *value, const size_t valuelen) { return masterguard_output_current_fraction(item, value, valuelen, 1.0); } /* digest status bits */ static int masterguard_status(item_t *item, char *value, const size_t valuelen) { int neg; char *s; switch (item->value[0]) { case '0': neg = 1; break; case '1': neg = 0; break; default: upsdebugx(2, "unknown flag value %c", item->value[0]); return -1; } switch (item->from) { case 53: /* B7 */ s = "OL"; neg = !neg; break; case 54: /* B6 */ s = "LB"; break; case 55: /* B5 */ s = "BYPASS"; break; case 56: /* B4 */ s = neg ? "" : "UPS Failed"; neg = 0; break; case 57: /* B3 */ s = neg ? "online" : "offline"; neg = 0; break; case 58: /* B2 */ s = "CAL"; break; case 59: /* B1 */ s = "FSD"; break; /* 60: blank */ /* 61: B0 reserved */ /* 62: T7 reserved */ case 63: /* T6 */ s = neg ? "" : "problems in parallel operation mode"; neg = 0; break; /* 64: T5 part of a parallel set */ case 65: /* T4 */ s = "RB"; break; case 66: /* T3 */ s = neg ? "" : "no battery connected"; neg = 0; break; case 67: /* T210 */ neg = 0; if (strncmp(item->value, "000", 3) == 0) { s = "no test in progress"; } else if (strncmp(item->value, "001", 3) == 0) { s = "in progress"; } else if (strncmp(item->value, "010", 3) == 0) { s = "OK"; } else if (strncmp(item->value, "011", 3) == 0) { s = "failed"; } else if (strncmp(item->value, "100", 3) == 0) { s = "not possible"; } else if (strncmp(item->value, "101", 3) == 0) { s = "aborted"; } else if (strncmp(item->value, "110", 3) == 0) { s = "autonomy time calibration in progress"; } else if (strncmp(item->value, "111", 3) == 0) { s = "unknown"; } else { upsdebugx(2, "unknown test result %s", item->value); return -1; } break; default: upsdebugx(2, "unknown flag position %d", item->from); return -1; } snprintf(value, valuelen, "%s%s", neg ? "!" : "", s); return 0; } /* convert beeper status bit to string required by NUT */ static int masterguard_beeper_status(item_t *item, char *value, const size_t valuelen) { switch (item->value[0]) { case '0': if (valuelen >= 9) strcpy(value, "disabled"); else *value = '\0'; break; case '1': if (valuelen >= 8) strcpy(value, "enabled"); else *value = '\0'; break; default: upsdebugx(2, "unknown beeper status %c", item->value[0]); return -1; } return 0; } /* parse list of available (nominal) output voltages into masterguard_w_outvolts enum */ static int masterguard_output_voltages(item_t *item, char *value, const size_t valuelen) { char sep[] = " "; char *w; size_t n = 0; strncpy(value, item->value, valuelen); /* save before strtok mangles it */ for (w = strtok(item->value, sep); w; w = strtok(NULL, sep)) { n++; upsdebugx(4, "output voltage #%" PRIuSIZE ": %s", n, w); if ((masterguard_e_outvolts = realloc(masterguard_e_outvolts, n * sizeof(info_rw_t))) == NULL) { upsdebugx(1, "output voltages: allocating #%" PRIuSIZE " failed", n); return -1; } strncpy(masterguard_e_outvolts[n - 1].value, w, SMALLBUF - 1); masterguard_e_outvolts[n - 1].preprocess = NULL; } /* need to do this seperately in case the loop is run zero times */ if ((masterguard_e_outvolts = realloc(masterguard_e_outvolts, (n + 1) * sizeof(info_rw_t))) == NULL) { upsdebugx(1, "output voltages: allocating terminator after #%" PRIuSIZE " failed", n); return -1; } masterguard_e_outvolts[n].value[0] = '\0'; masterguard_e_outvolts[n].preprocess = NULL; return 0; } /* parse fault record string into readable form */ static int masterguard_fault(item_t *item, char *value, const size_t valuelen) { char c; float f; int t, h, m, s; long l; if (sscanf(item->value, "%c %f %d:%d:%d:%d", &c, &f, &t, &h, &m, &s) != 6) { upsdebugx(1, "unparsable fault record %s", item->value); return -1; } l = 86400*t + 3600*h + 60*m + s; snprintf(value, valuelen, "%ld: ", l); switch (c) { case '0': snprintfcat(value, valuelen, "none"); break; case '1': snprintfcat(value, valuelen, "bus fault (%.0fV)", f); break; case '2': snprintfcat(value, valuelen, "inverter fault (%.0fV)", f); break; case '3': snprintfcat(value, valuelen, "overheat fault (%.0fC)", f); break; case '4': snprintfcat(value, valuelen, "battery overvoltage fault (%.2fV)", f); break; case '5': snprintfcat(value, valuelen, "battery mode overload fault (%.0f%%)", f); break; case '6': snprintfcat(value, valuelen, "bypass mode overload fault (%.0f%%)", f); break; case '7': snprintfcat(value, valuelen, "inverter mode outpt short-circuit fault (%.0fV)", f); break; case '8': snprintfcat(value, valuelen, "fan lock fault"); break; case '9': snprintfcat(value, valuelen, "battery fault (%.0fV)", f); break; case 'A': snprintfcat(value, valuelen, "charger fault"); break; case 'B': snprintfcat(value, valuelen, "EPO activated"); break; case 'C': snprintfcat(value, valuelen, "parallel error"); break; case 'D': snprintfcat(value, valuelen, "MCU communication error"); break; case 'E': case 'F': upsdebugx(1, "reserved fault id %c", c); return -1; default: upsdebugx(1, "unknown fault id %c", c); return -1; } return 0; } /* pre-command preprocessing functions */ /* add slave address (from masterguard_my_slaveaddr) to commands that require it */ static int masterguard_add_slaveaddr(item_t *item, char *command, const size_t commandlen) { size_t l; NUT_UNUSED_VARIABLE(item); NUT_UNUSED_VARIABLE(commandlen); l = strlen(command); if (strncmp(command + l - 4, ",XX\r", 4) != 0) { upsdebugx(1, "add slaveaddr: no ,XX\\r at end of command %s", command); return -1; } upsdebugx(4, "add slaveaddr %s to command %s", masterguard_my_slaveaddr, command); memcpy(command + l - 3, masterguard_my_slaveaddr, 2); return 0; } /* instant command preprocessing functions */ /* helper, not to be called directly from table */ /*!! use parameter from the value field instead of ups.delay.{shutdown,return}?? */ static int masterguard_shutdown(item_t *item, char *value, const size_t valuelen, const int stayoff) { long offdelay; char *p; const char *val, *name; char offstr[3]; NUT_UNUSED_VARIABLE(item); offdelay = strtol((val = dstate_getinfo(name = "ups.delay.shutdown")), &p, 10); if (*p != '\0') goto ill; if (offdelay < 0) { goto ill; } else if (offdelay < 60) { offstr[0] = '.'; offstr[1] = '0' + (char)offdelay / 6; } else if (offdelay <= 99*60) { int m = (int)(offdelay / 60); offstr[0] = '0' + (char)(m / 10); offstr[1] = '0' + (char)(m % 10); } else goto ill; offstr[2] = '\0'; if (stayoff) { snprintf(value, valuelen, "S%s\r", offstr); } else { long ondelay; ondelay = strtol((val = dstate_getinfo(name = "ups.delay.start")), &p, 10); if (*p != '\0') goto ill; if (ondelay < 0 || ondelay > 9999*60) goto ill; snprintf(value, valuelen, "S%sR%04ld\r", offstr, ondelay); } return 0; ill: upsdebugx(2, "shutdown: illegal %s %s", name, val); return -1; } static int masterguard_shutdown_return(item_t *item, char *value, const size_t valuelen) { return masterguard_shutdown(item, value, valuelen, 0); } static int masterguard_shutdown_stayoff(item_t *item, char *value, const size_t valuelen) { return masterguard_shutdown(item, value, valuelen, 1); } static int masterguard_test_battery(item_t *item, char *value, const size_t valuelen) { long duration; char *p; NUT_UNUSED_VARIABLE(item); if (value[0] == '\0') { upsdebugx(2, "battery test: no duration"); return -1; } duration = strtol(value, &p, 10); if (*p != '\0') goto ill; if (duration == 10) { strncpy(value, "T\r", valuelen); return 0; } if (duration < 60 || duration > 99*60) goto ill; snprintf(value, valuelen, "T%02ld\r", duration / 60); return 0; ill: upsdebugx(2, "battery test: illegal duration %s", value); return -1; } /* variable setting preprocessing functions */ /* set variable, input format specifier (d/f/s, thms) in item->dfl */ static int masterguard_setvar(item_t *item, char *value, const size_t valuelen) { char *p; char t = 's'; long i = 0; double f = 0.0; char s[80]; if (value[0] == '\0') { upsdebugx(2, "setvar: no value"); return -1; } if (!item->dfl || item->dfl[0] == '\0') { upsdebugx(2, "setvar: no dfl"); return -1; } if (item->dfl[1] == '\0') { t = item->dfl[0]; switch (t) { case 'd': i = strtol(value, &p, 10); if (*p != '\0') goto ill; break; case 'f': f = strtod(value, &p); if (*p != '\0') { goto ill; } else if (errno) { upsdebug_with_errno(2, "setvar: f value %s", value); return -1; } break; case 's': /* copy to s to avoid snprintf()ing value to itself */ if (strlen(value) >= sizeof s) goto ill; strcpy(s, value); break; default: upsdebugx(2, "setvar: unknown dfl %c", item->dfl[0]); return -1; } } else if (strncmp(item->dfl, "thms", 4) == 0) { int tt, h, m, sec; if (sscanf(item->value, "%d:%d:%d:%d", &tt, &h, &m, &sec) == 4) { if (tt < 0 || tt > 9999 || h < 0 || h > 23 || m < 0 || m > 59 || sec < 0 || sec > 59) goto ill; } else { long l; char *pl; l = strtol(value, &pl, 10); if (*pl != '\0') goto ill; sec = l % 60; l /= 60; m = l % 60; l /= 60; h = l % 24; l /= 24; if (l > 9999) goto ill; tt = (int)l; } snprintf(s, sizeof s, "%04d:%02d:%02d:%02d", tt, h, m, sec); } else { upsdebugx(2, "setvar: unknown dfl %s", item->dfl); return -1; } #ifdef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL #pragma GCC diagnostic push #endif #ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL #pragma GCC diagnostic ignored "-Wformat-nonliteral" #endif #ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_FORMAT_SECURITY #pragma GCC diagnostic ignored "-Wformat-security" #endif switch (t) { case 'd': snprintf(value, valuelen, item->command, i); break; case 'f': snprintf(value, valuelen, item->command, f); break; case 's': snprintf(value, valuelen, item->command, s); break; } #ifdef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL #pragma GCC diagnostic pop #endif return 0; ill: upsdebugx(2, "setvar: illegal %s value %s", item->dfl, value); return -1; } /* record new slave address in masterguard_next_slaveaddr; moved to masterguard_my_slaveaddr in masterguard_new_slaveaddr() after the slaveaddr-changing command finished */ static int masterguard_set_slaveaddr(item_t *item, char *value, const size_t valuelen) { char *p; masterguard_next_slaveaddr = strtol(value, &p, 10); if (*p != '\0') { upsdebugx(2, "set_slaveaddr: illegal value %s", value); return -1; } upsdebugx(3, "next slaveaddr %ld", masterguard_next_slaveaddr); return masterguard_setvar(item, value, valuelen); } /* variable setting answer preprocessing functions */ /* set my_slaveaddr to next_slaveaddr /after/ issuing the SS command (which, itself, needs the /old/ slaveaddr) */ static int masterguard_new_slaveaddr(item_t *item, const int len) { NUT_UNUSED_VARIABLE(item); upsdebugx(3, "saved slaveaddr %ld", masterguard_next_slaveaddr); if (masterguard_next_slaveaddr < 0 || masterguard_next_slaveaddr > 99) { upsdebugx(2, "%s: illegal value %ld", __func__, masterguard_next_slaveaddr); return -1; } masterguard_my_slaveaddr[0] = '0' + (char)(masterguard_next_slaveaddr / 10); masterguard_my_slaveaddr[1] = '0' + (char)(masterguard_next_slaveaddr % 10); upsdebugx(3, "new slaveaddr %s", masterguard_my_slaveaddr); return len; } /* qx2nut lookup table */ static item_t masterguard_qx2nut[] = { /* static values */ /* type flags rw command answer len leading value from to dfl qxflags precmd preans preproc */ { "device.mfr", 0, NULL, "", "", 0, '\0', "", 0, 0, "Masterguard", QX_FLAG_STATIC | QX_FLAG_ABSENT,NULL, NULL, NULL }, { "load.high", 0, NULL, "", "", 0, '\0', "", 0, 0, "140", QX_FLAG_STATIC | QX_FLAG_ABSENT,NULL, NULL, NULL }, /* battery.charge.low */ /* battery.charge.warning */ { "battery.type", 0, NULL, "", "", 0, '\0', "", 0, 0, "PbAc", QX_FLAG_STATIC | QX_FLAG_ABSENT,NULL, NULL, NULL }, /* variables */ /* * > [WH\r] * < [(XX VV.VV PP.PP TTTTTTTTTTTTTTTTTTTTTTTTTTTTTT B MMM FF.FF VVV SS.SS HHH.hh GGG.gg RRR mm nn MMM NNN FF.FF FF.FF\r] * 01234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012 * 0 1 2 3 4 5 6 7 8 9 0 1 * (00 10.06 03.09 A 700 + 0 Bat Pack-19 0 230 50.00 012 02.30 006.00 012.00 018 10 40 160 276 47.00 53.00 */ /* type flags rw command answer len leading value from to dfl qxflags precmd preans preproc */ { "ups.id", ST_FLAG_RW, masterguard_r_slaveaddr,"WH\r", "", 113, '(', "", 1, 2, "%.0f", QX_FLAG_SEMI_STATIC | QX_FLAG_RANGE, NULL, NULL, masterguard_slaveaddr }, { "ups.firmware", 0, NULL, "WH\r", "", 113, '(', "", 4, 8, "%s", QX_FLAG_STATIC, NULL, NULL, NULL }, { "ups.firmware.aux", 0, NULL, "WH\r", "", 113, '(', "", 10, 14, "%s", QX_FLAG_STATIC, NULL, NULL, NULL }, /* several values are deduced from the T field */ { "experimental.series", 0, NULL, "WH\r", "", 113, '(', "", 16, 16, "%s", QX_FLAG_STATIC | QX_FLAG_NONUT, NULL, NULL, masterguard_series }, { "device.model", 0, NULL, "WH\r", "", 113, '(', "", 16, 45, "%s", QX_FLAG_STATIC, NULL, NULL, masterguard_model }, { "ups.power.nominal", 0, NULL, "WH\r", "", 113, '(', "", 16, 45, "%s", QX_FLAG_STATIC, NULL, NULL, masterguard_power }, /* not used, use GS instead because the value is settable { "battery.packs", 0, NULL, "WH\r", "", 113, '(', "", 47, 47, "%.0f", QX_FLAG_STATIC, NULL, NULL, NULL }, */ { "input.voltage.nominal", 0, NULL, "WH\r", "", 113, '(', "", 49, 51, "%.0f", QX_FLAG_STATIC, NULL, NULL, NULL }, { "input.frequency.nominal", 0, NULL, "WH\r", "", 113, '(', "", 53, 57, "%.2f", QX_FLAG_STATIC, NULL, NULL, NULL }, { "experimental.number_of_battery_cells", 0, NULL, "WH\r", "", 113, '(', "", 59, 61, "%.0f", QX_FLAG_STATIC | QX_FLAG_NONUT, NULL, NULL, masterguard_numcells }, { "experimental.nominal_cell_voltage", 0, NULL, "WH\r", "", 113, '(', "", 63, 67, "%.2f", QX_FLAG_STATIC | QX_FLAG_NONUT, NULL, NULL, NULL }, { "battery.voltage.nominal", 0, NULL, "WH\r", "", 113, '(', "", 63, 67, "%.2f", QX_FLAG_STATIC, NULL, NULL, masterguard_battvolt}, { "experimental.runtime_half", 0, NULL, "WH\r", "", 113, '(', "", 69, 74, "%.0f", QX_FLAG_STATIC | QX_FLAG_NONUT, NULL, NULL, masterguard_mmm_ss }, { "experimental.runtime_full", 0, NULL, "WH\r", "", 113, '(', "", 76, 81, "%.0f", QX_FLAG_STATIC | QX_FLAG_NONUT, NULL, NULL, masterguard_mmm_ss }, { "experimental.recharge_time", 0, NULL, "WH\r", "", 113, '(', "", 83, 85, "%.0f", QX_FLAG_STATIC | QX_FLAG_NONUT, NULL, NULL, masterguard_hhh }, /*!! what's the difference between low/high and low.critical/high.critical?? */ { "ambient.0.temperature.low", 0, NULL, "WH\r", "", 113, '(', "", 87, 88, "%.0f", QX_FLAG_STATIC, NULL, NULL, NULL }, { "ambient.0.temperature.high", 0, NULL, "WH\r", "", 113, '(', "", 90, 91, "%.0f", QX_FLAG_STATIC, NULL, NULL, NULL }, { "input.voltage.low.critical", 0, NULL, "WH\r", "", 113, '(', "", 93, 95, "%.0f", QX_FLAG_STATIC, NULL, NULL, NULL }, { "input.voltage.high.critical",0, NULL, "WH\r", "", 113, '(', "", 97, 99, "%.0f", QX_FLAG_STATIC, NULL, NULL, NULL }, { "input.frequency.low", 0, NULL, "WH\r", "", 113, '(', "", 101, 105, "%.2f", QX_FLAG_STATIC, NULL, NULL, NULL }, { "input.frequency.high", 0, NULL, "WH\r", "", 113, '(', "", 107, 111, "%.2f", QX_FLAG_STATIC, NULL, NULL, NULL }, /* * > [Q3\r] * 76543210 76543210 * < [(XX MMM.M NNN.N PPP.P QQQ RR.R SS.SS TT.T ttt.tt CCC BBBBBBBB TTTTTTTT\r] * 01234567890123456789012345678901234567890123456789012345678901234567890 * 0 1 2 3 4 5 6 7 * (00 225.9 225.9 229.3 043 50.0 02.27 23.4 017.03 100 00000000 00000000 * (01 226.9 226.9 226.9 039 50.0 02.30 21.8 000.00 000 01100000 00011000 */ /* type flags rw command answer len leading value from to dfl qxflags precmd preans preproc */ { "input.voltage", 0, NULL, "Q3\r", "", 71, '(', "", 4, 8, "%.1f", 0, NULL, NULL, NULL }, { "experimental.input_fault_voltage", 0, NULL, "Q3\r", "", 71, '(', "", 10, 14, "%.1f", QX_FLAG_NONUT, NULL, NULL, NULL }, { "output.voltage", 0, NULL, "Q3\r", "", 71, '(', "", 16, 20, "%.1f", 0, NULL, NULL, NULL }, { "ups.load", 0, NULL, "Q3\r", "", 71, '(', "", 22, 24, "%.0f", 0, NULL, NULL, NULL }, { "ups.power", 0, NULL, "Q3\r", "", 71, '(', "", 22, 24, "%.0f", 0, NULL, NULL, masterguard_ups_power }, { "output.current", 0, NULL, "Q3\r", "", 71, '(', "", 22, 24, "%f", 0, NULL, NULL, masterguard_output_current }, { "input.frequency", 0, NULL, "Q3\r", "", 71, '(', "", 26, 29, "%.1f", 0, NULL, NULL, NULL }, { "battery.voltage", 0, NULL, "Q3\r", "", 71, '(', "", 31, 35, "%.1f", 0, NULL, NULL, masterguard_battvolt }, { "ups.temperature", 0, NULL, "Q3\r", "", 71, '(', "", 37, 40, "%.1f", 0, NULL, NULL, NULL }, /*!! report both ups.temperature and ambient.0.temperature?? */ { "ambient.0.temperature", 0, NULL, "Q3\r", "", 71, '(', "", 37, 40, "%.1f", 0, NULL, NULL, NULL }, { "battery.runtime", 0, NULL, "Q3\r", "", 71, '(', "", 42, 47, "%.0f", 0, NULL, NULL, masterguard_mmm_ss }, { "battery.charge", 0, NULL, "Q3\r", "", 71, '(', "", 49, 51, "%.0f", 0, NULL, NULL, NULL }, /* Status bits, first half (B) */ { "ups.status", 0, NULL, "Q3\r", "", 71, '(', "", 53, 53, NULL, QX_FLAG_QUICK_POLL, NULL, NULL, masterguard_status }, /* B7: Utility Fail */ { "ups.status", 0, NULL, "Q3\r", "", 71, '(', "", 54, 54, NULL, QX_FLAG_QUICK_POLL, NULL, NULL, masterguard_status }, /* B6: Battery Low */ { "ups.status", 0, NULL, "Q3\r", "", 71, '(', "", 55, 55, NULL, QX_FLAG_QUICK_POLL, NULL, NULL, masterguard_status }, /* B5: Bypass/Boost Active */ { "ups.alarm", 0, NULL, "Q3\r", "", 71, '(', "", 56, 56, NULL, QX_FLAG_QUICK_POLL, NULL, NULL, masterguard_status }, /* B4: UPS Failed */ { "ups.type", 0, NULL, "Q3\r", "", 71, '(', "", 57, 57, NULL, QX_FLAG_STATIC, NULL, NULL, masterguard_status }, /* B3: UPS Type */ { "ups.status", 0, NULL, "Q3\r", "", 71, '(', "", 58, 58, NULL, QX_FLAG_QUICK_POLL, NULL, NULL, masterguard_status }, /* B2: Test in Progress */ { "ups.status", 0, NULL, "Q3\r", "", 71, '(', "", 59, 59, NULL, QX_FLAG_QUICK_POLL, NULL, NULL, masterguard_status }, /* B1: Shutdown Active */ /* unused */ /* B0: unused */ /* Status bits, second half (T) */ /* unused */ /* T7: unused */ { "ups.alarm", 0, NULL, "Q3\r", "", 69, '(', "", 63, 63, NULL, QX_FLAG_QUICK_POLL, NULL, NULL, masterguard_status }, /* T6: problems in parallel operation mode */ /* part of a parallel set */ /* T5: is part of a parallel set */ { "ups.status", 0, NULL, "Q3\r", "", 71, '(', "", 65, 65, NULL, QX_FLAG_QUICK_POLL, NULL, NULL, masterguard_status }, /* T4: Battery: end of service life */ { "ups.alarm", 0, NULL, "Q3\r", "", 71, '(', "", 66, 66, NULL, QX_FLAG_QUICK_POLL, NULL, NULL, masterguard_status }, /* T3: battery connected */ { "ups.test.result", 0, NULL, "Q3\r", "", 71, '(', "", 67, 69, NULL, QX_FLAG_QUICK_POLL, NULL, NULL, masterguard_status }, /* T210: Test Status */ /* * > [GS,XX\r] * < [(XX,ii p a\r] * 01234567890 * 0 1 * (00,00 0 1 */ /* type flags rw command answer len leading value from to dfl qxflags precmd preans preproc */ /* ups.id obtained via WH */ { "ups.id", 0, NULL, "SS%02d--,XX\r","", 0, '\0', "", 0, 0, "d", QX_FLAG_SETVAR | QX_FLAG_RANGE, masterguard_add_slaveaddr, masterguard_new_slaveaddr, masterguard_set_slaveaddr }, { "battery.packs", ST_FLAG_RW, masterguard_r_batpacks, "GS,XX\r", "", 0, '(', "", 7, 7, "%.0f", QX_FLAG_SEMI_STATIC | QX_FLAG_RANGE, masterguard_add_slaveaddr, NULL, NULL }, { "battery.packs", 0, NULL, "SS--%1d-,XX\r","", 0, '\0', "", 0, 0, "d", QX_FLAG_SETVAR | QX_FLAG_RANGE, masterguard_add_slaveaddr, NULL, masterguard_setvar }, /*!! which QX_FLAGs to use?? (changed by instcmd) */ { "ups.beeper.status", 0, NULL, "GS,XX\r", "", 11, '(', "", 9, 9, NULL, QX_FLAG_SEMI_STATIC, masterguard_add_slaveaddr, NULL, masterguard_beeper_status }, /* set with beeper.{en,dis}able */ /* * > [GBS,XX\r] * < [(XX,CCC hhhh HHHH AAAA BBBB DDDD EEE SS.SS\r] * 0123456789012345678901234567890123456789012 * 0 1 2 3 4 * (00,100 0017 0000 0708 0712 0994 115 02.28 * (01,000 0000 0360 0708 0712 0994 076 02.30 */ /* type flags rw command answer len leading value from to dfl qxflags precmd preans preproc */ { "battery.charge", 0, NULL, "GBS,XX\r", "", 43, '(', "", 4, 6, "%.0f", 0, masterguard_add_slaveaddr, NULL, NULL }, /* * hhhh: hold time (minutes) * HHHH: recharge time to 90% (minutes) * AAAA: Ageing factor (promilles) * BBBB: Ageing factor time dependant (promilles) * DDDD: Ageing factor cyclic use (promilles) * EEE: Calibration factor (percent) * SS.SS: Actual battery cell voltage */ /* * > [GSN,XX\r] * < [(XX,SSN=SSSSSSSSSSSnnnnn\r] * 0123456789012345678901234 * 0 1 2 * (00,SSN=6A1212 2782 */ /* type flags rw command answer len leading value from to dfl qxflags precmd preans preproc */ { "device.part", 0, NULL, "GSN,XX\r", "", 25, '(', "", 8, 18, "%s", QX_FLAG_STATIC | QX_FLAG_TRIM, masterguard_add_slaveaddr, NULL, NULL }, { "device.serial", 0, NULL, "GSN,XX\r", "", 25, '(', "", 20, 23, "%s", QX_FLAG_STATIC, masterguard_add_slaveaddr, NULL, NULL }, /* * > [DRC,XX\r] * < [(XX,TTTT:hh:mm:ss\r] * 012345678901234567 * 0 1 * (00,1869:19:06:37 */ /* type flags rw command answer len leading value from to dfl qxflags precmd preans preproc */ /* this is not really the uptime, but the running time since last maintenance */ { "device.uptime", ST_FLAG_RW, NULL, "DRC,XX\r", "", 17, '(', "", 4, 16, "%.0f", QX_FLAG_SEMI_STATIC, masterguard_add_slaveaddr, NULL, masterguard_tttt_hh_mm_ss }, { "device.uptime", 0, NULL, "SRC%s,XX\r", "", 0, '\0', "", 0, 0, "thms", QX_FLAG_SETVAR, masterguard_add_slaveaddr, NULL, masterguard_setvar }, /* * > [MSO\r] * < [(220 230 240\r] * 0123456789012 * 0 1 * (220 230 240 */ /* type flags rw command answer len leading value from to dfl qxflags precmd preans preproc */ { "experimental.output_voltages", 0, NULL, "MSO\r", "", 5, '(', "", 1, 0, "%s", QX_FLAG_STATIC | QX_FLAG_NONUT, NULL, NULL, masterguard_output_voltages }, /* * > [PNV\r] * < [(PNV=nnn\r] * 012345678 * 0 * (PNV=230 */ /* type flags rw command answer len leading value from to dfl qxflags precmd preans preproc */ { "output.voltage.nominal", ST_FLAG_RW, NULL /* see claim */, "PNV\r", "", 8, '(', "", 5, 7, "%.0f", QX_FLAG_SEMI_STATIC | QX_FLAG_ENUM, NULL, NULL, NULL }, { "output.voltage.nominal", 0, NULL, "PNV=%03d\r", "", 0, '\0', "", 0, 0, "d", QX_FLAG_SETVAR, NULL, NULL, masterguard_setvar }, { "output.current.nominal", 0, NULL, "PNV\r", "", 8, '(', "", 5, 7, "%.0f", QX_FLAG_SEMI_STATIC, NULL, NULL, masterguard_output_current_nominal }, /* * > [FLT,XX\r] * < [(XX,A aaaa TTTT:hh:mm:ss B bbbb TTTT:hh:mm:ss C cccc TTTT:hh:mm:ss D dddd TTTT:hh:mm:ss E eeee TTTT:hh:mm:ss\r * 0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678 * 0 1 2 3 4 5 6 7 8 9 0 * (00,7 0043 0000:16:48:06 0 0000 0000:00:00:00 0 0000 0000:00:00:00 0 0000 0000:00:00:00 0 0000 0000:00:00:00 * (01,9 0010 1780:14:57:19 7 0046 0000:21:14:41 0 0000 0000:00:00:00 0 0000 0000:00:00:00 0 0000 0000:00:00:00 */ /* type flags rw command answer len leading value from to dfl qxflags precmd preans preproc */ { "experimental.fault_1", 0, NULL, "FLT,XX\r", "", 108, '(', "", 4, 23, "%s", QX_FLAG_NONUT, masterguard_add_slaveaddr, NULL, masterguard_fault }, { "experimental.fault_2", 0, NULL, "FLT,XX\r", "", 108, '(', "", 25, 44, "%s", QX_FLAG_NONUT, masterguard_add_slaveaddr, NULL, masterguard_fault }, { "experimental.fault_3", 0, NULL, "FLT,XX\r", "", 108, '(', "", 46, 65, "%s", QX_FLAG_NONUT, masterguard_add_slaveaddr, NULL, masterguard_fault }, { "experimental.fault_4", 0, NULL, "FLT,XX\r", "", 108, '(', "", 67, 86, "%s", QX_FLAG_NONUT, masterguard_add_slaveaddr, NULL, masterguard_fault }, { "experimental.fault_5", 0, NULL, "FLT,XX\r", "", 108, '(', "", 88, 107, "%s", QX_FLAG_NONUT, masterguard_add_slaveaddr, NULL, masterguard_fault }, /* instant commands */ /* type flags rw command answer len leading value from to dfl qxflags precmd preans preproc */ /*!! what's the difference between load.off.delay and shutdown.stayoff?? */ #if 0 { "load.off", 0, NULL, "S.0\r", "", 0, '\0', "", 0, 0, NULL, QX_FLAG_CMD, NULL, NULL, NULL }, { "load.on", 0, NULL, "C\r", "", 0, '\0', "", 0, 0, NULL, QX_FLAG_CMD, NULL, NULL, NULL }, /* load.off.delay */ /* load.on.delay */ #endif { "shutdown.return", 0, NULL, NULL, "", 0, '\0', "", 0, 0, NULL, QX_FLAG_CMD, NULL, NULL, masterguard_shutdown_return }, { "shutdown.stayoff", 0, NULL, NULL, "", 0, '\0', "", 0, 0, NULL, QX_FLAG_CMD, NULL, NULL, masterguard_shutdown_stayoff }, { "shutdown.stop", 0, NULL, "C\r", "", 0, '\0', "", 0, 0, NULL, QX_FLAG_CMD, NULL, NULL, NULL }, /* shutdown.reboot */ /* shutdown.reboot.graceful */ /* test.panel.start */ /* test.panel.stop */ /* test.failure.start */ /* test.failure.stop */ { "test.battery.start", 0, NULL, NULL, "", 0, '\0', "", 0, 0, NULL, QX_FLAG_CMD, NULL, NULL, masterguard_test_battery }, { "test.battery.start.quick", 0, NULL, "T\r", "", 0, '\0', "", 0, 0, NULL, QX_FLAG_CMD, NULL, NULL, NULL }, { "test.battery.start.deep", 0, NULL, "TUD\r", "", 0, '\0', "", 0, 0, NULL, QX_FLAG_CMD, NULL, NULL, NULL }, { "test.battery.stop", 0, NULL, "CT\r", "", 0, '\0', "", 0, 0, NULL, QX_FLAG_CMD, NULL, NULL, NULL }, /* test.system.start */ /* calibrate.start */ /* calibrate.stop */ { "bypass.start", 0, NULL, "FOFF\r", "", 0, '\0', "", 0, 0, NULL, QX_FLAG_CMD, NULL, NULL, NULL }, { "bypass.stop", 0, NULL, "FON\r", "", 0, '\0', "", 0, 0, NULL, QX_FLAG_CMD, NULL, NULL, NULL }, /* reset.input.minmax */ /* reset.watchdog */ { "beeper.enable", 0, NULL, "SS---1,XX\r", "", 0, '\0', "", 0, 0, NULL, QX_FLAG_CMD, masterguard_add_slaveaddr, NULL, NULL }, { "beeper.disable", 0, NULL, "SS---0,XX\r", "", 0, '\0', "", 0, 0, NULL, QX_FLAG_CMD, masterguard_add_slaveaddr, NULL, NULL }, /* beeper.mute */ /* beeper.toggle */ /* outlet.* */ /* server variables */ /* type flags rw command answer len leading value from to dfl qxflags precmd preans preproc */ { "ups.delay.shutdown", ST_FLAG_RW, masterguard_r_offdelay, NULL, "", 0, '\0', "", 0, 0, DEFAULT_OFFDELAY, QX_FLAG_ABSENT | QX_FLAG_SETVAR | QX_FLAG_RANGE, NULL, NULL, NULL }, { "ups.delay.start", ST_FLAG_RW, masterguard_r_ondelay, NULL, "", 0, '\0', "", 0, 0, DEFAULT_ONDELAY, QX_FLAG_ABSENT | QX_FLAG_SETVAR | QX_FLAG_RANGE, NULL, NULL, NULL }, /* end marker */ { NULL, 0, NULL, NULL, "", 0, 0, "", 0, 0, NULL, 0, NULL, NULL, NULL } }; /*!! todo untested: Sxx (.n/nn) C after S.0 unused: >G01,00 (00,00000 additional E series commands: PSR BUS* V INVDC use ups.{delay,timer}.{start,reboot,shutdown}? report ups.contacts? how to report battery.charger.status? set battery.packs.bad? how to report battery aeging/run time? how to report nominal hold time at half/full load? */ /* commands supported by A series */ static char *masterguard_commands_a[] = { "Q", "Q1", "Q3", "T", "TL", "S", "C", "CT", "WH", "M", "N", "O", "DECO", "DRC", "SRC", "FLT", "FCLR", "G", "SS", "GS", "MSO", "PNV", "FOFF", "FON", "TUD", "GBS", "SSN", "GSN", NULL }; /* commands supported by E series */ static char *masterguard_commands_e[] = { "Q", "Q1", "Q3", "PSR", "T", "TL", "S", "C", "CT", "WH", "DRC", "SRC", "FLT", "FCLR", "SS", "GS", "MSO", "PNV", "FOFF", "FON", "TUD", "GBS", "SSN", "GSN", "BUS", "V", "INVDC", "BUSP", "BUSN", NULL }; /* claim function. fetch some mandatory values, * disable unsupported commands, * set enum for supported output voltages */ static int masterguard_claim(void) { item_t *item; /* mandatory values */ char *mandatory[] = { "experimental.series", /* SKIP */ "device.model", /* minimal number of battery packs */ "ups.power.nominal", /* load computation */ "ups.id", /* slave address */ "experimental.output_voltages", /* output voltages enum */ #if 0 "battery.packs", /* battery voltage computation */ #endif NULL }; char **sp; long config_slaveaddr; char *sa; char **commands; if ((sa = getval("slave_address")) != NULL) { char *p; if (*sa == '\0') { upsdebugx(2, "claim: empty slave_address"); return 0; } config_slaveaddr = strtol(sa, &p, 10); if (*p != '\0' || config_slaveaddr < 0 || config_slaveaddr > 99) { upsdebugx(2, "claim: illegal slave_address %s", sa); return 0; } } else { config_slaveaddr = -1; } for (sp = mandatory; *sp != NULL; sp++) { char value[SMALLBUF] = ""; if ((item = find_nut_info(*sp, 0, QX_FLAG_SETVAR)) == NULL) { upsdebugx(2, "claim: cannot find %s", *sp); return 0; } /* since qx_process_answer() is not exported, there's no way * to avoid sending the same command to the UPS again */ if (qx_process(item, NULL) < 0) { upsdebugx(2, "claim: cannot process %s", *sp); return 0; } /* only call the preprocess function; don't call ups_infoval_set() * because that does a dstate_setinfo() before dstate_setflags() * is called (via qx_set_var() in qx_ups_walk() with QX_WALKMODE_INIT); * that leads to r/w vars ending up r/o. */ if (item->preprocess == NULL ) { upsdebugx(2, "claim: no preprocess function for %s", *sp); return 0; } if (item->preprocess(item, value, sizeof value)) { upsdebugx(2, "claim: failed to preprocess %s", *sp); return 0; } } if (config_slaveaddr >= 0 && config_slaveaddr != strtol(masterguard_my_slaveaddr, NULL, 10)) { upsdebugx(2, "claim: slave address mismatch: want %02ld, have %s", config_slaveaddr, masterguard_my_slaveaddr); return 0; } switch (masterguard_my_series) { case 'A': commands = masterguard_commands_a; break; case 'E': commands = masterguard_commands_e; break; default: return 0; } /* set SKIP flag for unimplemented commands */ for (item = masterguard_qx2nut; item->info_type != NULL; item++) { int match = 0; if (item->command == NULL || item->command[0] == '\0') continue; for (sp = commands; sp != NULL; sp++) { const char *p = *sp, *q = item->command; while (1) { if (*p == '\0' && (*q < 'A' || *q > 'Z')) { match = 1; break; } else if (*p == '\0' || *q < 'A' || *q > 'Z' || *p != *q) { match = 0; break; } p++; q++; } if (match) break; } if (nut_debug_level >= 3) { char cmd[10]; char *p = cmd; const char *q = item->command; while (*q >= 'A' && *q <= 'Z') { *p++ = *q++; if (p - cmd >= (ptrdiff_t)sizeof cmd - 1) break; } *p++ = '\0'; upsdebugx(3, "command %s %simplemented", cmd, match ? "" : "NOT "); } if (!match) item->qxflags |= QX_FLAG_SKIP; } /* set enum for output.voltage.nominal */ if ((item = find_nut_info("output.voltage.nominal", QX_FLAG_ENUM, QX_FLAG_SETVAR)) == NULL) { upsdebugx(2, "claim: cannot find output.voltage.nominal"); return 0; } item->info_rw = masterguard_e_outvolts; return 1; } static void masterguard_makevartable(void) { addvar(VAR_VALUE, "series", "Series (A/E)"); addvar(VAR_VALUE, "slave_address", "Slave address (UPS id) to match"); addvar(VAR_VALUE, "input_fault_voltage", "Input fault voltage (whatever that means)"); addvar(VAR_VALUE, "number_of_battery_cells", "Number of battery cells in series"); addvar(VAR_VALUE, "nominal_cell_voltage", "Nominal battery cell voltage"); addvar(VAR_VALUE, "runtime_half", "Nominal battery run time at 50% load (seconds)"); addvar(VAR_VALUE, "runtime_full", "Nominal battery run time at 100% load (seconds)"); addvar(VAR_VALUE, "recharge_time", "Nominal battery recharge time to 95% capacity (seconds)"); addvar(VAR_VALUE, "output_voltages", "Possible output voltages (volts)"); addvar(VAR_VALUE, "fault_1", "Fault record 1 (newest)"); addvar(VAR_VALUE, "fault_2", "Fault record 2"); addvar(VAR_VALUE, "fault_3", "Fault record 3"); addvar(VAR_VALUE, "fault_4", "Fault record 4"); addvar(VAR_VALUE, "fault_5", "Fault record 5 (oldest)"); } #ifdef TESTING static testing_t masterguard_testing[] = { { NULL } }; #endif /* TESTING */ subdriver_t masterguard_subdriver = { MASTERGUARD_VERSION, masterguard_claim, masterguard_qx2nut, NULL, /* initups */ NULL, /* intinfo */ masterguard_makevartable, NULL, /* accepted */ NULL, /* rejected */ #ifdef TESTING masterguard_testing, #endif /* TESTING */ }; nut-2.8.1/drivers/apc-pdu-mib.c0000644000175000017500000021767614501607135013216 00000000000000/* apc-pdu-mib.c - subdriver to monitor APC PDU using PowerNet-MIB SNMP with NUT * * Copyright (C) 2016 - Eaton * Authors: Tomas Halman * Arnaud Quette * * Based on initial work and data from Opengear * * 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 2 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, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "apc-pdu-mib.h" #define APC_PDU_MIB_VERSION "0.4" #define APC_PDU_MIB_SYSOID_RPDU ".1.3.6.1.4.1.318.1.3.4.4" #define APC_PDU_MIB_SYSOID_RPDU2 ".1.3.6.1.4.1.318.1.3.4.5" #define APC_PDU_MIB_SYSOID_MSP ".1.3.6.1.4.1.318.1.3.4.6" #define APC_PDU_DEVICE_MODEL ".1.3.6.1.4.1.318.1.1.4.1.4.0" static info_lkp_t apc_pdu_sw_outlet_status_info[] = { { 1, "on", NULL, NULL }, { 2, "off", NULL, NULL }, { 0, NULL, NULL, NULL } }; static info_lkp_t apc_pdu_sw_outlet_switchability_info[] = { { 1, "yes", NULL, NULL }, { 2, "yes", NULL, NULL }, { 0, NULL, NULL, NULL } }; /* POWERNET-MIB Snmp2NUT lookup table */ static snmp_info_t apc_pdu_mib[] = { /* Device page */ { "device.mfr", ST_FLAG_STRING, SU_INFOSIZE, NULL, "APC", SU_FLAG_STATIC | SU_FLAG_ABSENT | SU_FLAG_OK, NULL }, /* sPDUIdentModelNumber.0 = STRING: "AP7900" */ { "device.model", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.318.1.1.4.1.4.0", "Switched ePDU", SU_FLAG_STATIC | SU_FLAG_OK, NULL }, { "device.type", ST_FLAG_STRING, SU_INFOSIZE, NULL, "pdu", SU_FLAG_STATIC | SU_FLAG_ABSENT | SU_FLAG_OK, NULL }, { "device.contact", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.2.1.1.4.0", NULL, SU_FLAG_STALE | SU_FLAG_OK, NULL }, { "device.description", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.2.1.1.5.0", NULL, SU_FLAG_STALE | SU_FLAG_OK, NULL }, { "device.location", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.2.1.1.6.0", NULL, SU_FLAG_STALE | SU_FLAG_OK, NULL }, /* FIXME: to be RFC'ed */ { "device.uptime", 0, 1, ".1.3.6.1.2.1.1.3.0", NULL, SU_FLAG_OK | SU_FLAG_NEGINVALID, NULL }, /* sPDUIdentSerialNumber.0 = STRING: "5A1234E00874" */ { "device.serial", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.318.1.1.4.1.5.0", NULL, SU_FLAG_STATIC | SU_FLAG_OK, NULL }, /* sPDUIdentModelNumber.0 = STRING: "AP7900" */ { "device.part", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.318.1.1.4.1.4.0", NULL, SU_FLAG_STATIC | SU_FLAG_OK, NULL }, /* sPDUIdentHardwareRev.0 = STRING: "B2" */ { "device.version", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.318.1.1.4.1.1.0", NULL, SU_FLAG_STATIC | SU_FLAG_OK, NULL }, /* sPDUIdentFirmwareRev.0 = STRING: "v3.7.3" */ /* FIXME: to be moved to device.firmware */ { "ups.firmware", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.318.1.1.4.1.2.0", NULL, SU_FLAG_OK, NULL }, /* sPDUIdentDateOfManufacture.0 = STRING: "08/13/2012" */ /* FIXME: to be moved to the device collection! */ { "ups.date", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.318.1.1.4.1.3.0", NULL, SU_FLAG_OK, NULL }, /* Input */ /* rPDUIdentDevicePowerWatts.0 = INTEGER: 0 */ { "input.realpower", 0, 1, ".1.3.6.1.4.1.318.1.1.12.1.16.0", NULL, SU_FLAG_OK, NULL }, /* rPDULoadStatusLoad.1 = Gauge32: 0 */ { "input.current", 0, 0.1, ".1.3.6.1.4.1.318.1.1.12.2.3.1.1.2.1", NULL, SU_FLAG_OK, NULL }, /* rPDUIdentDeviceLinetoLineVoltage.0 = INTEGER: 120 */ { "input.voltage.nominal", 0, 1, ".1.3.6.1.4.1.318.1.1.12.1.15.0", NULL, SU_FLAG_OK | SU_FLAG_NEGINVALID, NULL }, /* Outlets */ { "outlet.count", 0, 1, ".1.3.6.1.4.1.318.1.1.4.4.1.0", NULL, SU_FLAG_STATIC | SU_FLAG_OK, NULL }, { "outlet.%i.id", 0, 1, ".1.3.6.1.4.1.318.1.1.4.4.2.1.1.%i", "%i", SU_FLAG_STATIC | SU_FLAG_OK | SU_OUTLET, NULL }, /* sPDUOutletCtlName.%i = STRING: "Testing Name" */ { "outlet.%i.desc", ST_FLAG_RW | ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.318.1.1.4.4.2.1.4.%i", NULL, SU_FLAG_STALE | SU_FLAG_OK | SU_OUTLET, NULL }, /* sPDUOutletCtl.1 = INTEGER: outletOn(1) */ { "outlet.%i.status", ST_FLAG_RW | ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.318.1.1.4.4.2.1.3.%i", NULL, SU_FLAG_OK | SU_OUTLET, &apc_pdu_sw_outlet_status_info[0] }, /* Also use this OID to determine switchability ; its presence means "yes" */ /* sPDUOutletCtl.1 = INTEGER: outletOn(1) */ { "outlet.%i.switchable", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.318.1.1.4.4.2.1.3.%i", "yes", SU_FLAG_STATIC | SU_FLAG_ABSENT | SU_FLAG_OK | SU_OUTLET, &apc_pdu_sw_outlet_switchability_info[0] }, #if WITH_UNMAPPED_DATA_POINTS /* keep following scan for future development */ /* sPDUMasterControlSwitch.0 = INTEGER: noCommand(6) */ { "unmapped.sPDUMasterControlSwitch", 0, 1, ".1.3.6.1.4.1.318.1.1.4.2.1.0", NULL, SU_FLAG_OK, NULL }, /* sPDUMasterState.0 = STRING: "On On On On On On On On " */ { "unmapped.sPDUMasterState", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.318.1.1.4.2.2.0", NULL, SU_FLAG_OK, NULL }, /* sPDUMasterPending.0 = STRING: "No No No No No No No No " */ { "unmapped.sPDUMasterPending", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.318.1.1.4.2.3.0", NULL, SU_FLAG_OK, NULL }, /* sPDUMasterConfigPowerOn.0 = INTEGER: 0 */ { "unmapped.sPDUMasterConfigPowerOn", 0, 1, ".1.3.6.1.4.1.318.1.1.4.3.1.0", NULL, SU_FLAG_OK, NULL }, /* sPDUMasterConfigReboot.0 = INTEGER: 0 */ { "unmapped.sPDUMasterConfigReboot", 0, 1, ".1.3.6.1.4.1.318.1.1.4.3.2.0", NULL, SU_FLAG_OK, NULL }, /* sPDUMasterConfigPDUName.0 = STRING: "RackPDU" */ { "unmapped.sPDUMasterConfigPDUName", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.318.1.1.4.3.3.0", NULL, SU_FLAG_OK, NULL }, /* sPDUOutletControlTableSize.0 = INTEGER: 8 */ /* sPDUOutletControlIndex.1 = INTEGER: 1 */ { "unmapped.sPDUOutletControlIndex", 0, 1, ".1.3.6.1.4.1.318.1.1.4.4.2.1.1.1", NULL, SU_FLAG_OK, NULL }, /* sPDUOutletControlIndex.2 = INTEGER: 2 */ { "unmapped.sPDUOutletControlIndex", 0, 1, ".1.3.6.1.4.1.318.1.1.4.4.2.1.1.2", NULL, SU_FLAG_OK, NULL }, /* sPDUOutletControlIndex.3 = INTEGER: 3 */ { "unmapped.sPDUOutletControlIndex", 0, 1, ".1.3.6.1.4.1.318.1.1.4.4.2.1.1.3", NULL, SU_FLAG_OK, NULL }, /* sPDUOutletControlIndex.4 = INTEGER: 4 */ { "unmapped.sPDUOutletControlIndex", 0, 1, ".1.3.6.1.4.1.318.1.1.4.4.2.1.1.4", NULL, SU_FLAG_OK, NULL }, /* sPDUOutletControlIndex.5 = INTEGER: 5 */ { "unmapped.sPDUOutletControlIndex", 0, 1, ".1.3.6.1.4.1.318.1.1.4.4.2.1.1.5", NULL, SU_FLAG_OK, NULL }, /* sPDUOutletControlIndex.6 = INTEGER: 6 */ { "unmapped.sPDUOutletControlIndex", 0, 1, ".1.3.6.1.4.1.318.1.1.4.4.2.1.1.6", NULL, SU_FLAG_OK, NULL }, /* sPDUOutletControlIndex.7 = INTEGER: 7 */ { "unmapped.sPDUOutletControlIndex", 0, 1, ".1.3.6.1.4.1.318.1.1.4.4.2.1.1.7", NULL, SU_FLAG_OK, NULL }, /* sPDUOutletControlIndex.8 = INTEGER: 8 */ { "unmapped.sPDUOutletControlIndex", 0, 1, ".1.3.6.1.4.1.318.1.1.4.4.2.1.1.8", NULL, SU_FLAG_OK, NULL }, /* sPDUOutletPending.1 = INTEGER: noCommandPending(2) */ { "unmapped.sPDUOutletPending", 0, 1, ".1.3.6.1.4.1.318.1.1.4.4.2.1.2.1", NULL, SU_FLAG_OK, NULL }, /* sPDUOutletPending.2 = INTEGER: noCommandPending(2) */ { "unmapped.sPDUOutletPending", 0, 1, ".1.3.6.1.4.1.318.1.1.4.4.2.1.2.2", NULL, SU_FLAG_OK, NULL }, /* sPDUOutletPending.3 = INTEGER: noCommandPending(2) */ { "unmapped.sPDUOutletPending", 0, 1, ".1.3.6.1.4.1.318.1.1.4.4.2.1.2.3", NULL, SU_FLAG_OK, NULL }, /* sPDUOutletPending.4 = INTEGER: noCommandPending(2) */ { "unmapped.sPDUOutletPending", 0, 1, ".1.3.6.1.4.1.318.1.1.4.4.2.1.2.4", NULL, SU_FLAG_OK, NULL }, /* sPDUOutletPending.5 = INTEGER: noCommandPending(2) */ { "unmapped.sPDUOutletPending", 0, 1, ".1.3.6.1.4.1.318.1.1.4.4.2.1.2.5", NULL, SU_FLAG_OK, NULL }, /* sPDUOutletPending.6 = INTEGER: noCommandPending(2) */ { "unmapped.sPDUOutletPending", 0, 1, ".1.3.6.1.4.1.318.1.1.4.4.2.1.2.6", NULL, SU_FLAG_OK, NULL }, /* sPDUOutletPending.7 = INTEGER: noCommandPending(2) */ { "unmapped.sPDUOutletPending", 0, 1, ".1.3.6.1.4.1.318.1.1.4.4.2.1.2.7", NULL, SU_FLAG_OK, NULL }, /* sPDUOutletPending.8 = INTEGER: noCommandPending(2) */ { "unmapped.sPDUOutletPending", 0, 1, ".1.3.6.1.4.1.318.1.1.4.4.2.1.2.8", NULL, SU_FLAG_OK, NULL }, /* sPDUOutletConfigTableSize.0 = INTEGER: 8 */ { "unmapped.sPDUOutletConfigTableSize", 0, 1, ".1.3.6.1.4.1.318.1.1.4.5.1.0", NULL, SU_FLAG_OK, NULL }, /* sPDUOutletConfigIndex.1 = INTEGER: 1 */ { "unmapped.sPDUOutletConfigIndex", 0, 1, ".1.3.6.1.4.1.318.1.1.4.5.2.1.1.1", NULL, SU_FLAG_OK, NULL }, /* sPDUOutletConfigIndex.2 = INTEGER: 2 */ { "unmapped.sPDUOutletConfigIndex", 0, 1, ".1.3.6.1.4.1.318.1.1.4.5.2.1.1.2", NULL, SU_FLAG_OK, NULL }, /* sPDUOutletConfigIndex.3 = INTEGER: 3 */ { "unmapped.sPDUOutletConfigIndex", 0, 1, ".1.3.6.1.4.1.318.1.1.4.5.2.1.1.3", NULL, SU_FLAG_OK, NULL }, /* sPDUOutletConfigIndex.4 = INTEGER: 4 */ { "unmapped.sPDUOutletConfigIndex", 0, 1, ".1.3.6.1.4.1.318.1.1.4.5.2.1.1.4", NULL, SU_FLAG_OK, NULL }, /* sPDUOutletConfigIndex.5 = INTEGER: 5 */ { "unmapped.sPDUOutletConfigIndex", 0, 1, ".1.3.6.1.4.1.318.1.1.4.5.2.1.1.5", NULL, SU_FLAG_OK, NULL }, /* sPDUOutletConfigIndex.6 = INTEGER: 6 */ { "unmapped.sPDUOutletConfigIndex", 0, 1, ".1.3.6.1.4.1.318.1.1.4.5.2.1.1.6", NULL, SU_FLAG_OK, NULL }, /* sPDUOutletConfigIndex.7 = INTEGER: 7 */ { "unmapped.sPDUOutletConfigIndex", 0, 1, ".1.3.6.1.4.1.318.1.1.4.5.2.1.1.7", NULL, SU_FLAG_OK, NULL }, /* sPDUOutletConfigIndex.8 = INTEGER: 8 */ { "unmapped.sPDUOutletConfigIndex", 0, 1, ".1.3.6.1.4.1.318.1.1.4.5.2.1.1.8", NULL, SU_FLAG_OK, NULL }, /* sPDUOutletPowerOnTime.1 = INTEGER: 0 */ { "unmapped.sPDUOutletPowerOnTime", 0, 1, ".1.3.6.1.4.1.318.1.1.4.5.2.1.2.1", NULL, SU_FLAG_OK, NULL }, /* sPDUOutletPowerOnTime.2 = INTEGER: 0 */ { "unmapped.sPDUOutletPowerOnTime", 0, 1, ".1.3.6.1.4.1.318.1.1.4.5.2.1.2.2", NULL, SU_FLAG_OK, NULL }, /* sPDUOutletPowerOnTime.3 = INTEGER: 0 */ { "unmapped.sPDUOutletPowerOnTime", 0, 1, ".1.3.6.1.4.1.318.1.1.4.5.2.1.2.3", NULL, SU_FLAG_OK, NULL }, /* sPDUOutletPowerOnTime.4 = INTEGER: 0 */ { "unmapped.sPDUOutletPowerOnTime", 0, 1, ".1.3.6.1.4.1.318.1.1.4.5.2.1.2.4", NULL, SU_FLAG_OK, NULL }, /* sPDUOutletPowerOnTime.5 = INTEGER: 0 */ { "unmapped.sPDUOutletPowerOnTime", 0, 1, ".1.3.6.1.4.1.318.1.1.4.5.2.1.2.5", NULL, SU_FLAG_OK, NULL }, /* sPDUOutletPowerOnTime.6 = INTEGER: 0 */ { "unmapped.sPDUOutletPowerOnTime", 0, 1, ".1.3.6.1.4.1.318.1.1.4.5.2.1.2.6", NULL, SU_FLAG_OK, NULL }, /* sPDUOutletPowerOnTime.7 = INTEGER: 0 */ { "unmapped.sPDUOutletPowerOnTime", 0, 1, ".1.3.6.1.4.1.318.1.1.4.5.2.1.2.7", NULL, SU_FLAG_OK, NULL }, /* sPDUOutletPowerOnTime.8 = INTEGER: 0 */ { "unmapped.sPDUOutletPowerOnTime", 0, 1, ".1.3.6.1.4.1.318.1.1.4.5.2.1.2.8", NULL, SU_FLAG_OK, NULL }, /* sPDUOutletName.1 = STRING: "Testing Name" */ { "unmapped.sPDUOutletName", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.318.1.1.4.5.2.1.3.1", NULL, SU_FLAG_OK, NULL }, /* sPDUOutletName.2 = STRING: "Testing 2" */ { "unmapped.sPDUOutletName", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.318.1.1.4.5.2.1.3.2", NULL, SU_FLAG_OK, NULL }, /* sPDUOutletName.3 = STRING: "Outlet 3" */ { "unmapped.sPDUOutletName", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.318.1.1.4.5.2.1.3.3", NULL, SU_FLAG_OK, NULL }, /* sPDUOutletName.4 = STRING: "Outlet 4" */ { "unmapped.sPDUOutletName", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.318.1.1.4.5.2.1.3.4", NULL, SU_FLAG_OK, NULL }, /* sPDUOutletName.5 = STRING: "Outlet 5" */ { "unmapped.sPDUOutletName", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.318.1.1.4.5.2.1.3.5", NULL, SU_FLAG_OK, NULL }, /* sPDUOutletName.6 = STRING: "Outlet 6" */ { "unmapped.sPDUOutletName", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.318.1.1.4.5.2.1.3.6", NULL, SU_FLAG_OK, NULL }, /* sPDUOutletName.7 = STRING: "Outlet 7" */ { "unmapped.sPDUOutletName", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.318.1.1.4.5.2.1.3.7", NULL, SU_FLAG_OK, NULL }, /* sPDUOutletName.8 = STRING: "Outlet 8" */ { "unmapped.sPDUOutletName", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.318.1.1.4.5.2.1.3.8", NULL, SU_FLAG_OK, NULL }, /* sPDUOutletPowerOffTime.1 = INTEGER: 0 */ { "unmapped.sPDUOutletPowerOffTime", 0, 1, ".1.3.6.1.4.1.318.1.1.4.5.2.1.4.1", NULL, SU_FLAG_OK, NULL }, /* sPDUOutletPowerOffTime.2 = INTEGER: 0 */ { "unmapped.sPDUOutletPowerOffTime", 0, 1, ".1.3.6.1.4.1.318.1.1.4.5.2.1.4.2", NULL, SU_FLAG_OK, NULL }, /* sPDUOutletPowerOffTime.3 = INTEGER: 0 */ { "unmapped.sPDUOutletPowerOffTime", 0, 1, ".1.3.6.1.4.1.318.1.1.4.5.2.1.4.3", NULL, SU_FLAG_OK, NULL }, /* sPDUOutletPowerOffTime.4 = INTEGER: 0 */ { "unmapped.sPDUOutletPowerOffTime", 0, 1, ".1.3.6.1.4.1.318.1.1.4.5.2.1.4.4", NULL, SU_FLAG_OK, NULL }, /* sPDUOutletPowerOffTime.5 = INTEGER: 0 */ { "unmapped.sPDUOutletPowerOffTime", 0, 1, ".1.3.6.1.4.1.318.1.1.4.5.2.1.4.5", NULL, SU_FLAG_OK, NULL }, /* sPDUOutletPowerOffTime.6 = INTEGER: 0 */ { "unmapped.sPDUOutletPowerOffTime", 0, 1, ".1.3.6.1.4.1.318.1.1.4.5.2.1.4.6", NULL, SU_FLAG_OK, NULL }, /* sPDUOutletPowerOffTime.7 = INTEGER: 0 */ { "unmapped.sPDUOutletPowerOffTime", 0, 1, ".1.3.6.1.4.1.318.1.1.4.5.2.1.4.7", NULL, SU_FLAG_OK, NULL }, /* sPDUOutletPowerOffTime.8 = INTEGER: 0 */ { "unmapped.sPDUOutletPowerOffTime", 0, 1, ".1.3.6.1.4.1.318.1.1.4.5.2.1.4.8", NULL, SU_FLAG_OK, NULL }, /* sPDUOutletRebootDuration.1 = INTEGER: 5 */ { "unmapped.sPDUOutletRebootDuration", 0, 1, ".1.3.6.1.4.1.318.1.1.4.5.2.1.5.1", NULL, SU_FLAG_OK, NULL }, /* sPDUOutletRebootDuration.2 = INTEGER: 5 */ { "unmapped.sPDUOutletRebootDuration", 0, 1, ".1.3.6.1.4.1.318.1.1.4.5.2.1.5.2", NULL, SU_FLAG_OK, NULL }, /* sPDUOutletRebootDuration.3 = INTEGER: 5 */ { "unmapped.sPDUOutletRebootDuration", 0, 1, ".1.3.6.1.4.1.318.1.1.4.5.2.1.5.3", NULL, SU_FLAG_OK, NULL }, /* sPDUOutletRebootDuration.4 = INTEGER: 5 */ { "unmapped.sPDUOutletRebootDuration", 0, 1, ".1.3.6.1.4.1.318.1.1.4.5.2.1.5.4", NULL, SU_FLAG_OK, NULL }, /* sPDUOutletRebootDuration.5 = INTEGER: 5 */ { "unmapped.sPDUOutletRebootDuration", 0, 1, ".1.3.6.1.4.1.318.1.1.4.5.2.1.5.5", NULL, SU_FLAG_OK, NULL }, /* sPDUOutletRebootDuration.6 = INTEGER: 5 */ { "unmapped.sPDUOutletRebootDuration", 0, 1, ".1.3.6.1.4.1.318.1.1.4.5.2.1.5.6", NULL, SU_FLAG_OK, NULL }, /* sPDUOutletRebootDuration.7 = INTEGER: 5 */ { "unmapped.sPDUOutletRebootDuration", 0, 1, ".1.3.6.1.4.1.318.1.1.4.5.2.1.5.7", NULL, SU_FLAG_OK, NULL }, /* sPDUOutletRebootDuration.8 = INTEGER: 5 */ { "unmapped.sPDUOutletRebootDuration", 0, 1, ".1.3.6.1.4.1.318.1.1.4.5.2.1.5.8", NULL, SU_FLAG_OK, NULL }, /* rPDUIdentName.0 = STRING: "RackPDU" */ { "unmapped.rPDUIdentName", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.318.1.1.12.1.1.0", NULL, SU_FLAG_OK, NULL }, /* rPDUIdentHardwareRev.0 = STRING: "B2" */ { "unmapped.rPDUIdentHardwareRev", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.318.1.1.12.1.2.0", NULL, SU_FLAG_OK, NULL }, /* rPDUIdentFirmwareRev.0 = STRING: "v3.7.3" */ { "unmapped.rPDUIdentFirmwareRev", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.318.1.1.12.1.3.0", NULL, SU_FLAG_OK, NULL }, /* rPDUIdentDateOfManufacture.0 = STRING: "08/13/2012" */ { "unmapped.rPDUIdentDateOfManufacture", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.318.1.1.12.1.4.0", NULL, SU_FLAG_OK, NULL }, /* rPDUIdentModelNumber.0 = STRING: "AP7900" */ { "unmapped.rPDUIdentModelNumber", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.318.1.1.12.1.5.0", NULL, SU_FLAG_OK, NULL }, /* rPDUIdentSerialNumber.0 = STRING: "5A1234E00874" */ { "unmapped.rPDUIdentSerialNumber", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.318.1.1.12.1.6.0", NULL, SU_FLAG_OK, NULL }, /* rPDUIdentDeviceRating.0 = INTEGER: 12 */ { "unmapped.rPDUIdentDeviceRating", 0, 1, ".1.3.6.1.4.1.318.1.1.12.1.7.0", NULL, SU_FLAG_OK, NULL }, /* rPDUIdentDeviceNumOutlets.0 = INTEGER: 8 */ { "unmapped.rPDUIdentDeviceNumOutlets", 0, 1, ".1.3.6.1.4.1.318.1.1.12.1.8.0", NULL, SU_FLAG_OK, NULL }, /* rPDUIdentDeviceNumPhases.0 = INTEGER: 1 */ { "input.phases", 0, 1, ".1.3.6.1.4.1.318.1.1.12.1.9.0", NULL, SU_FLAG_STATIC | SU_FLAG_OK, NULL }, /* rPDUIdentDeviceNumBreakers.0 = INTEGER: 0 */ { "unmapped.rPDUIdentDeviceNumBreakers", 0, 1, ".1.3.6.1.4.1.318.1.1.12.1.10.0", NULL, SU_FLAG_OK, NULL }, /* rPDUIdentDeviceBreakerRating.0 = INTEGER: 0 */ { "unmapped.rPDUIdentDeviceBreakerRating", 0, 1, ".1.3.6.1.4.1.318.1.1.12.1.11.0", NULL, SU_FLAG_OK, NULL }, /* rPDUIdentDeviceOrientation.0 = INTEGER: orientHorizontal(1) */ { "unmapped.rPDUIdentDeviceOrientation", 0, 1, ".1.3.6.1.4.1.318.1.1.12.1.12.0", NULL, SU_FLAG_OK, NULL }, /* rPDUIdentDeviceOutletLayout.0 = INTEGER: seqPhaseToNeutral(1) */ { "unmapped.rPDUIdentDeviceOutletLayout", 0, 1, ".1.3.6.1.4.1.318.1.1.12.1.13.0", NULL, SU_FLAG_OK, NULL }, /* rPDUIdentDeviceDisplayOrientation.0 = INTEGER: displayNormal(1) */ { "unmapped.rPDUIdentDeviceDisplayOrientation", 0, 1, ".1.3.6.1.4.1.318.1.1.12.1.14.0", NULL, SU_FLAG_OK, NULL }, /* rPDUIdentDeviceLinetoLineVoltage.0 = INTEGER: 120 */ { "unmapped.rPDUIdentDeviceLinetoLineVoltage", 0, 1, ".1.3.6.1.4.1.318.1.1.12.1.15.0", NULL, SU_FLAG_OK, NULL }, /* rPDUIdentDevicePowerFactor.0 = INTEGER: 1000 */ { "unmapped.rPDUIdentDevicePowerFactor", 0, 1, ".1.3.6.1.4.1.318.1.1.12.1.17.0", NULL, SU_FLAG_OK, NULL }, /* rPDUIdentDevicePowerVA.0 = INTEGER: 0 */ { "unmapped.rPDUIdentDevicePowerVA", 0, 1, ".1.3.6.1.4.1.318.1.1.12.1.18.0", NULL, SU_FLAG_OK, NULL }, /* rPDULoadDevMaxPhaseLoad.0 = INTEGER: 12 */ { "unmapped.rPDULoadDevMaxPhaseLoad", 0, 1, ".1.3.6.1.4.1.318.1.1.12.2.1.1.0", NULL, SU_FLAG_OK, NULL }, /* rPDULoadDevNumPhases.0 = INTEGER: 1 */ { "unmapped.rPDULoadDevNumPhases", 0, 1, ".1.3.6.1.4.1.318.1.1.12.2.1.2.0", NULL, SU_FLAG_OK, NULL }, /* rPDULoadDevMaxBankLoad.0 = INTEGER: 0 */ { "unmapped.rPDULoadDevMaxBankLoad", 0, 1, ".1.3.6.1.4.1.318.1.1.12.2.1.3.0", NULL, SU_FLAG_OK, NULL }, /* rPDULoadDevNumBanks.0 = INTEGER: 0 */ { "unmapped.rPDULoadDevNumBanks", 0, 1, ".1.3.6.1.4.1.318.1.1.12.2.1.4.0", NULL, SU_FLAG_OK, NULL }, /* rPDULoadDevBankTableSize.0 = INTEGER: 0 */ { "unmapped.rPDULoadDevBankTableSize", 0, 1, ".1.3.6.1.4.1.318.1.1.12.2.1.5.0", NULL, SU_FLAG_OK, NULL }, /* rPDULoadDevMaxOutletTableSize.0 = INTEGER: 0 */ { "unmapped.rPDULoadDevMaxOutletTableSize", 0, 1, ".1.3.6.1.4.1.318.1.1.12.2.1.7.0", NULL, SU_FLAG_OK, NULL }, /* rPDULoadPhaseConfigIndex.phase1 = INTEGER: phase1(1) */ { "unmapped.rPDULoadPhaseConfigIndex", 0, 1, ".1.3.6.1.4.1.318.1.1.12.2.2.1.1.1.1", NULL, SU_FLAG_OK, NULL }, /* rPDULoadPhaseConfigLowLoadThreshold.phase1 = INTEGER: 0 */ { "unmapped.rPDULoadPhaseConfigLowLoadThreshold", 0, 1, ".1.3.6.1.4.1.318.1.1.12.2.2.1.1.2.1", NULL, SU_FLAG_OK, NULL }, /* rPDULoadPhaseConfigNearOverloadThreshold.phase1 = INTEGER: 8 */ { "unmapped.rPDULoadPhaseConfigNearOverloadThreshold", 0, 1, ".1.3.6.1.4.1.318.1.1.12.2.2.1.1.3.1", NULL, SU_FLAG_OK, NULL }, /* rPDULoadPhaseConfigOverloadThreshold.phase1 = INTEGER: 12 */ { "unmapped.rPDULoadPhaseConfigOverloadThreshold", 0, 1, ".1.3.6.1.4.1.318.1.1.12.2.2.1.1.4.1", NULL, SU_FLAG_OK, NULL }, /* rPDULoadPhaseConfigAlarm.phase1 = INTEGER: noLoadAlarm(1) */ { "unmapped.rPDULoadPhaseConfigAlarm", 0, 1, ".1.3.6.1.4.1.318.1.1.12.2.2.1.1.5.1", NULL, SU_FLAG_OK, NULL }, /* rPDULoadStatusIndex.1 = INTEGER: 1 */ { "unmapped.rPDULoadStatusIndex", 0, 1, ".1.3.6.1.4.1.318.1.1.12.2.3.1.1.1.1", NULL, SU_FLAG_OK, NULL }, /* rPDULoadStatusLoadState.1 = INTEGER: phaseLoadNormal(1) */ { "unmapped.rPDULoadStatusLoadState", 0, 1, ".1.3.6.1.4.1.318.1.1.12.2.3.1.1.3.1", NULL, SU_FLAG_OK, NULL }, /* rPDULoadStatusPhaseNumber.1 = INTEGER: 1 */ { "unmapped.rPDULoadStatusPhaseNumber", 0, 1, ".1.3.6.1.4.1.318.1.1.12.2.3.1.1.4.1", NULL, SU_FLAG_OK, NULL }, /* rPDULoadStatusBankNumber.1 = INTEGER: 0 */ { "unmapped.rPDULoadStatusBankNumber", 0, 1, ".1.3.6.1.4.1.318.1.1.12.2.3.1.1.5.1", NULL, SU_FLAG_OK, NULL }, /* rPDUOutletDevCommand.0 = INTEGER: noCommandAll(1) */ { "unmapped.rPDUOutletDevCommand", 0, 1, ".1.3.6.1.4.1.318.1.1.12.3.1.1.0", NULL, SU_FLAG_OK, NULL }, /* rPDUOutletDevColdstartDelay.0 = INTEGER: 0 */ { "unmapped.rPDUOutletDevColdstartDelay", 0, 1, ".1.3.6.1.4.1.318.1.1.12.3.1.2.0", NULL, SU_FLAG_OK, NULL }, /* rPDUOutletDevNumCntrlOutlets.0 = INTEGER: 8 */ { "unmapped.rPDUOutletDevNumCntrlOutlets", 0, 1, ".1.3.6.1.4.1.318.1.1.12.3.1.3.0", NULL, SU_FLAG_OK, NULL }, /* rPDUOutletDevNumTotalOutlets.0 = INTEGER: 8 */ { "unmapped.rPDUOutletDevNumTotalOutlets", 0, 1, ".1.3.6.1.4.1.318.1.1.12.3.1.4.0", NULL, SU_FLAG_OK, NULL }, /* rPDUOutletDevMonitoredOutlets.0 = INTEGER: 0 */ { "unmapped.rPDUOutletDevMonitoredOutlets", 0, 1, ".1.3.6.1.4.1.318.1.1.12.3.1.5.0", NULL, SU_FLAG_OK, NULL }, /* rPDUOutletPhaseIndex.phase1 = INTEGER: phase1(1) */ { "unmapped.rPDUOutletPhaseIndex", 0, 1, ".1.3.6.1.4.1.318.1.1.12.3.2.1.1.1.1", NULL, SU_FLAG_OK, NULL }, /* rPDUOutletPhaseOverloadRestriction.phase1 = INTEGER: alwaysAllowTurnON(1) */ { "unmapped.rPDUOutletPhaseOverloadRestriction", 0, 1, ".1.3.6.1.4.1.318.1.1.12.3.2.1.1.2.1", NULL, SU_FLAG_OK, NULL }, /* rPDUOutletControlIndex.1 = INTEGER: 1 */ { "unmapped.rPDUOutletControlIndex", 0, 1, ".1.3.6.1.4.1.318.1.1.12.3.3.1.1.1.1", NULL, SU_FLAG_OK, NULL }, /* rPDUOutletControlIndex.2 = INTEGER: 2 */ { "unmapped.rPDUOutletControlIndex", 0, 1, ".1.3.6.1.4.1.318.1.1.12.3.3.1.1.1.2", NULL, SU_FLAG_OK, NULL }, /* rPDUOutletControlIndex.3 = INTEGER: 3 */ { "unmapped.rPDUOutletControlIndex", 0, 1, ".1.3.6.1.4.1.318.1.1.12.3.3.1.1.1.3", NULL, SU_FLAG_OK, NULL }, /* rPDUOutletControlIndex.4 = INTEGER: 4 */ { "unmapped.rPDUOutletControlIndex", 0, 1, ".1.3.6.1.4.1.318.1.1.12.3.3.1.1.1.4", NULL, SU_FLAG_OK, NULL }, /* rPDUOutletControlIndex.5 = INTEGER: 5 */ { "unmapped.rPDUOutletControlIndex", 0, 1, ".1.3.6.1.4.1.318.1.1.12.3.3.1.1.1.5", NULL, SU_FLAG_OK, NULL }, /* rPDUOutletControlIndex.6 = INTEGER: 6 */ { "unmapped.rPDUOutletControlIndex", 0, 1, ".1.3.6.1.4.1.318.1.1.12.3.3.1.1.1.6", NULL, SU_FLAG_OK, NULL }, /* rPDUOutletControlIndex.7 = INTEGER: 7 */ { "unmapped.rPDUOutletControlIndex", 0, 1, ".1.3.6.1.4.1.318.1.1.12.3.3.1.1.1.7", NULL, SU_FLAG_OK, NULL }, /* rPDUOutletControlIndex.8 = INTEGER: 8 */ { "unmapped.rPDUOutletControlIndex", 0, 1, ".1.3.6.1.4.1.318.1.1.12.3.3.1.1.1.8", NULL, SU_FLAG_OK, NULL }, /* rPDUOutletControlOutletName.1 = STRING: "Testing Name" */ { "unmapped.rPDUOutletControlOutletName", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.318.1.1.12.3.3.1.1.2.1", NULL, SU_FLAG_OK, NULL }, /* rPDUOutletControlOutletName.2 = STRING: "Testing 2" */ { "unmapped.rPDUOutletControlOutletName", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.318.1.1.12.3.3.1.1.2.2", NULL, SU_FLAG_OK, NULL }, /* rPDUOutletControlOutletName.3 = STRING: "Outlet 3" */ { "unmapped.rPDUOutletControlOutletName", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.318.1.1.12.3.3.1.1.2.3", NULL, SU_FLAG_OK, NULL }, /* rPDUOutletControlOutletName.4 = STRING: "Outlet 4" */ { "unmapped.rPDUOutletControlOutletName", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.318.1.1.12.3.3.1.1.2.4", NULL, SU_FLAG_OK, NULL }, /* rPDUOutletControlOutletName.5 = STRING: "Outlet 5" */ { "unmapped.rPDUOutletControlOutletName", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.318.1.1.12.3.3.1.1.2.5", NULL, SU_FLAG_OK, NULL }, /* rPDUOutletControlOutletName.6 = STRING: "Outlet 6" */ { "unmapped.rPDUOutletControlOutletName", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.318.1.1.12.3.3.1.1.2.6", NULL, SU_FLAG_OK, NULL }, /* rPDUOutletControlOutletName.7 = STRING: "Outlet 7" */ { "unmapped.rPDUOutletControlOutletName", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.318.1.1.12.3.3.1.1.2.7", NULL, SU_FLAG_OK, NULL }, /* rPDUOutletControlOutletName.8 = STRING: "Outlet 8" */ { "unmapped.rPDUOutletControlOutletName", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.318.1.1.12.3.3.1.1.2.8", NULL, SU_FLAG_OK, NULL }, /* rPDUOutletControlOutletPhase.1 = INTEGER: phase1(1) */ { "unmapped.rPDUOutletControlOutletPhase", 0, 1, ".1.3.6.1.4.1.318.1.1.12.3.3.1.1.3.1", NULL, SU_FLAG_OK, NULL }, /* rPDUOutletControlOutletPhase.2 = INTEGER: phase1(1) */ { "unmapped.rPDUOutletControlOutletPhase", 0, 1, ".1.3.6.1.4.1.318.1.1.12.3.3.1.1.3.2", NULL, SU_FLAG_OK, NULL }, /* rPDUOutletControlOutletPhase.3 = INTEGER: phase1(1) */ { "unmapped.rPDUOutletControlOutletPhase", 0, 1, ".1.3.6.1.4.1.318.1.1.12.3.3.1.1.3.3", NULL, SU_FLAG_OK, NULL }, /* rPDUOutletControlOutletPhase.4 = INTEGER: phase1(1) */ { "unmapped.rPDUOutletControlOutletPhase", 0, 1, ".1.3.6.1.4.1.318.1.1.12.3.3.1.1.3.4", NULL, SU_FLAG_OK, NULL }, /* rPDUOutletControlOutletPhase.5 = INTEGER: phase1(1) */ { "unmapped.rPDUOutletControlOutletPhase", 0, 1, ".1.3.6.1.4.1.318.1.1.12.3.3.1.1.3.5", NULL, SU_FLAG_OK, NULL }, /* rPDUOutletControlOutletPhase.6 = INTEGER: phase1(1) */ { "unmapped.rPDUOutletControlOutletPhase", 0, 1, ".1.3.6.1.4.1.318.1.1.12.3.3.1.1.3.6", NULL, SU_FLAG_OK, NULL }, /* rPDUOutletControlOutletPhase.7 = INTEGER: phase1(1) */ { "unmapped.rPDUOutletControlOutletPhase", 0, 1, ".1.3.6.1.4.1.318.1.1.12.3.3.1.1.3.7", NULL, SU_FLAG_OK, NULL }, /* rPDUOutletControlOutletPhase.8 = INTEGER: phase1(1) */ { "unmapped.rPDUOutletControlOutletPhase", 0, 1, ".1.3.6.1.4.1.318.1.1.12.3.3.1.1.3.8", NULL, SU_FLAG_OK, NULL }, /* rPDUOutletControlOutletCommand.1 = INTEGER: immediateOn(1) */ { "unmapped.rPDUOutletControlOutletCommand", 0, 1, ".1.3.6.1.4.1.318.1.1.12.3.3.1.1.4.1", NULL, SU_FLAG_OK, NULL }, /* rPDUOutletControlOutletCommand.2 = INTEGER: immediateOn(1) */ { "unmapped.rPDUOutletControlOutletCommand", 0, 1, ".1.3.6.1.4.1.318.1.1.12.3.3.1.1.4.2", NULL, SU_FLAG_OK, NULL }, /* rPDUOutletControlOutletCommand.3 = INTEGER: immediateOn(1) */ { "unmapped.rPDUOutletControlOutletCommand", 0, 1, ".1.3.6.1.4.1.318.1.1.12.3.3.1.1.4.3", NULL, SU_FLAG_OK, NULL }, /* rPDUOutletControlOutletCommand.4 = INTEGER: immediateOn(1) */ { "unmapped.rPDUOutletControlOutletCommand", 0, 1, ".1.3.6.1.4.1.318.1.1.12.3.3.1.1.4.4", NULL, SU_FLAG_OK, NULL }, /* rPDUOutletControlOutletCommand.5 = INTEGER: immediateOn(1) */ { "unmapped.rPDUOutletControlOutletCommand", 0, 1, ".1.3.6.1.4.1.318.1.1.12.3.3.1.1.4.5", NULL, SU_FLAG_OK, NULL }, /* rPDUOutletControlOutletCommand.6 = INTEGER: immediateOn(1) */ { "unmapped.rPDUOutletControlOutletCommand", 0, 1, ".1.3.6.1.4.1.318.1.1.12.3.3.1.1.4.6", NULL, SU_FLAG_OK, NULL }, /* rPDUOutletControlOutletCommand.7 = INTEGER: immediateOn(1) */ { "unmapped.rPDUOutletControlOutletCommand", 0, 1, ".1.3.6.1.4.1.318.1.1.12.3.3.1.1.4.7", NULL, SU_FLAG_OK, NULL }, /* rPDUOutletControlOutletCommand.8 = INTEGER: immediateOn(1) */ { "unmapped.rPDUOutletControlOutletCommand", 0, 1, ".1.3.6.1.4.1.318.1.1.12.3.3.1.1.4.8", NULL, SU_FLAG_OK, NULL }, /* rPDUOutletControlOutletBank.1 = INTEGER: 0 */ { "unmapped.rPDUOutletControlOutletBank", 0, 1, ".1.3.6.1.4.1.318.1.1.12.3.3.1.1.5.1", NULL, SU_FLAG_OK, NULL }, /* rPDUOutletControlOutletBank.2 = INTEGER: 0 */ { "unmapped.rPDUOutletControlOutletBank", 0, 1, ".1.3.6.1.4.1.318.1.1.12.3.3.1.1.5.2", NULL, SU_FLAG_OK, NULL }, /* rPDUOutletControlOutletBank.3 = INTEGER: 0 */ { "unmapped.rPDUOutletControlOutletBank", 0, 1, ".1.3.6.1.4.1.318.1.1.12.3.3.1.1.5.3", NULL, SU_FLAG_OK, NULL }, /* rPDUOutletControlOutletBank.4 = INTEGER: 0 */ { "unmapped.rPDUOutletControlOutletBank", 0, 1, ".1.3.6.1.4.1.318.1.1.12.3.3.1.1.5.4", NULL, SU_FLAG_OK, NULL }, /* rPDUOutletControlOutletBank.5 = INTEGER: 0 */ { "unmapped.rPDUOutletControlOutletBank", 0, 1, ".1.3.6.1.4.1.318.1.1.12.3.3.1.1.5.5", NULL, SU_FLAG_OK, NULL }, /* rPDUOutletControlOutletBank.6 = INTEGER: 0 */ { "unmapped.rPDUOutletControlOutletBank", 0, 1, ".1.3.6.1.4.1.318.1.1.12.3.3.1.1.5.6", NULL, SU_FLAG_OK, NULL }, /* rPDUOutletControlOutletBank.7 = INTEGER: 0 */ { "unmapped.rPDUOutletControlOutletBank", 0, 1, ".1.3.6.1.4.1.318.1.1.12.3.3.1.1.5.7", NULL, SU_FLAG_OK, NULL }, /* rPDUOutletControlOutletBank.8 = INTEGER: 0 */ { "unmapped.rPDUOutletControlOutletBank", 0, 1, ".1.3.6.1.4.1.318.1.1.12.3.3.1.1.5.8", NULL, SU_FLAG_OK, NULL }, /* rPDUOutletConfigIndex.1 = INTEGER: 1 */ { "unmapped.rPDUOutletConfigIndex", 0, 1, ".1.3.6.1.4.1.318.1.1.12.3.4.1.1.1.1", NULL, SU_FLAG_OK, NULL }, /* rPDUOutletConfigIndex.2 = INTEGER: 2 */ { "unmapped.rPDUOutletConfigIndex", 0, 1, ".1.3.6.1.4.1.318.1.1.12.3.4.1.1.1.2", NULL, SU_FLAG_OK, NULL }, /* rPDUOutletConfigIndex.3 = INTEGER: 3 */ { "unmapped.rPDUOutletConfigIndex", 0, 1, ".1.3.6.1.4.1.318.1.1.12.3.4.1.1.1.3", NULL, SU_FLAG_OK, NULL }, /* rPDUOutletConfigIndex.4 = INTEGER: 4 */ { "unmapped.rPDUOutletConfigIndex", 0, 1, ".1.3.6.1.4.1.318.1.1.12.3.4.1.1.1.4", NULL, SU_FLAG_OK, NULL }, /* rPDUOutletConfigIndex.5 = INTEGER: 5 */ { "unmapped.rPDUOutletConfigIndex", 0, 1, ".1.3.6.1.4.1.318.1.1.12.3.4.1.1.1.5", NULL, SU_FLAG_OK, NULL }, /* rPDUOutletConfigIndex.6 = INTEGER: 6 */ { "unmapped.rPDUOutletConfigIndex", 0, 1, ".1.3.6.1.4.1.318.1.1.12.3.4.1.1.1.6", NULL, SU_FLAG_OK, NULL }, /* rPDUOutletConfigIndex.7 = INTEGER: 7 */ { "unmapped.rPDUOutletConfigIndex", 0, 1, ".1.3.6.1.4.1.318.1.1.12.3.4.1.1.1.7", NULL, SU_FLAG_OK, NULL }, /* rPDUOutletConfigIndex.8 = INTEGER: 8 */ { "unmapped.rPDUOutletConfigIndex", 0, 1, ".1.3.6.1.4.1.318.1.1.12.3.4.1.1.1.8", NULL, SU_FLAG_OK, NULL }, /* rPDUOutletConfigOutletName.1 = STRING: "Testing Name" */ { "unmapped.rPDUOutletConfigOutletName", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.318.1.1.12.3.4.1.1.2.1", NULL, SU_FLAG_OK, NULL }, /* rPDUOutletConfigOutletName.2 = STRING: "Testing 2" */ { "unmapped.rPDUOutletConfigOutletName", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.318.1.1.12.3.4.1.1.2.2", NULL, SU_FLAG_OK, NULL }, /* rPDUOutletConfigOutletName.3 = STRING: "Outlet 3" */ { "unmapped.rPDUOutletConfigOutletName", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.318.1.1.12.3.4.1.1.2.3", NULL, SU_FLAG_OK, NULL }, /* rPDUOutletConfigOutletName.4 = STRING: "Outlet 4" */ { "unmapped.rPDUOutletConfigOutletName", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.318.1.1.12.3.4.1.1.2.4", NULL, SU_FLAG_OK, NULL }, /* rPDUOutletConfigOutletName.5 = STRING: "Outlet 5" */ { "unmapped.rPDUOutletConfigOutletName", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.318.1.1.12.3.4.1.1.2.5", NULL, SU_FLAG_OK, NULL }, /* rPDUOutletConfigOutletName.6 = STRING: "Outlet 6" */ { "unmapped.rPDUOutletConfigOutletName", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.318.1.1.12.3.4.1.1.2.6", NULL, SU_FLAG_OK, NULL }, /* rPDUOutletConfigOutletName.7 = STRING: "Outlet 7" */ { "unmapped.rPDUOutletConfigOutletName", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.318.1.1.12.3.4.1.1.2.7", NULL, SU_FLAG_OK, NULL }, /* rPDUOutletConfigOutletName.8 = STRING: "Outlet 8" */ { "unmapped.rPDUOutletConfigOutletName", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.318.1.1.12.3.4.1.1.2.8", NULL, SU_FLAG_OK, NULL }, /* rPDUOutletConfigOutletPhase.1 = INTEGER: phase1(1) */ { "unmapped.rPDUOutletConfigOutletPhase", 0, 1, ".1.3.6.1.4.1.318.1.1.12.3.4.1.1.3.1", NULL, SU_FLAG_OK, NULL }, /* rPDUOutletConfigOutletPhase.2 = INTEGER: phase1(1) */ { "unmapped.rPDUOutletConfigOutletPhase", 0, 1, ".1.3.6.1.4.1.318.1.1.12.3.4.1.1.3.2", NULL, SU_FLAG_OK, NULL }, /* rPDUOutletConfigOutletPhase.3 = INTEGER: phase1(1) */ { "unmapped.rPDUOutletConfigOutletPhase", 0, 1, ".1.3.6.1.4.1.318.1.1.12.3.4.1.1.3.3", NULL, SU_FLAG_OK, NULL }, /* rPDUOutletConfigOutletPhase.4 = INTEGER: phase1(1) */ { "unmapped.rPDUOutletConfigOutletPhase", 0, 1, ".1.3.6.1.4.1.318.1.1.12.3.4.1.1.3.4", NULL, SU_FLAG_OK, NULL }, /* rPDUOutletConfigOutletPhase.5 = INTEGER: phase1(1) */ { "unmapped.rPDUOutletConfigOutletPhase", 0, 1, ".1.3.6.1.4.1.318.1.1.12.3.4.1.1.3.5", NULL, SU_FLAG_OK, NULL }, /* rPDUOutletConfigOutletPhase.6 = INTEGER: phase1(1) */ { "unmapped.rPDUOutletConfigOutletPhase", 0, 1, ".1.3.6.1.4.1.318.1.1.12.3.4.1.1.3.6", NULL, SU_FLAG_OK, NULL }, /* rPDUOutletConfigOutletPhase.7 = INTEGER: phase1(1) */ { "unmapped.rPDUOutletConfigOutletPhase", 0, 1, ".1.3.6.1.4.1.318.1.1.12.3.4.1.1.3.7", NULL, SU_FLAG_OK, NULL }, /* rPDUOutletConfigOutletPhase.8 = INTEGER: phase1(1) */ { "unmapped.rPDUOutletConfigOutletPhase", 0, 1, ".1.3.6.1.4.1.318.1.1.12.3.4.1.1.3.8", NULL, SU_FLAG_OK, NULL }, /* rPDUOutletConfigPowerOnTime.1 = INTEGER: 0 */ { "unmapped.rPDUOutletConfigPowerOnTime", 0, 1, ".1.3.6.1.4.1.318.1.1.12.3.4.1.1.4.1", NULL, SU_FLAG_OK, NULL }, /* rPDUOutletConfigPowerOnTime.2 = INTEGER: 0 */ { "unmapped.rPDUOutletConfigPowerOnTime", 0, 1, ".1.3.6.1.4.1.318.1.1.12.3.4.1.1.4.2", NULL, SU_FLAG_OK, NULL }, /* rPDUOutletConfigPowerOnTime.3 = INTEGER: 0 */ { "unmapped.rPDUOutletConfigPowerOnTime", 0, 1, ".1.3.6.1.4.1.318.1.1.12.3.4.1.1.4.3", NULL, SU_FLAG_OK, NULL }, /* rPDUOutletConfigPowerOnTime.4 = INTEGER: 0 */ { "unmapped.rPDUOutletConfigPowerOnTime", 0, 1, ".1.3.6.1.4.1.318.1.1.12.3.4.1.1.4.4", NULL, SU_FLAG_OK, NULL }, /* rPDUOutletConfigPowerOnTime.5 = INTEGER: 0 */ { "unmapped.rPDUOutletConfigPowerOnTime", 0, 1, ".1.3.6.1.4.1.318.1.1.12.3.4.1.1.4.5", NULL, SU_FLAG_OK, NULL }, /* rPDUOutletConfigPowerOnTime.6 = INTEGER: 0 */ { "unmapped.rPDUOutletConfigPowerOnTime", 0, 1, ".1.3.6.1.4.1.318.1.1.12.3.4.1.1.4.6", NULL, SU_FLAG_OK, NULL }, /* rPDUOutletConfigPowerOnTime.7 = INTEGER: 0 */ { "unmapped.rPDUOutletConfigPowerOnTime", 0, 1, ".1.3.6.1.4.1.318.1.1.12.3.4.1.1.4.7", NULL, SU_FLAG_OK, NULL }, /* rPDUOutletConfigPowerOnTime.8 = INTEGER: 0 */ { "unmapped.rPDUOutletConfigPowerOnTime", 0, 1, ".1.3.6.1.4.1.318.1.1.12.3.4.1.1.4.8", NULL, SU_FLAG_OK, NULL }, /* rPDUOutletConfigPowerOffTime.1 = INTEGER: 0 */ { "unmapped.rPDUOutletConfigPowerOffTime", 0, 1, ".1.3.6.1.4.1.318.1.1.12.3.4.1.1.5.1", NULL, SU_FLAG_OK, NULL }, /* rPDUOutletConfigPowerOffTime.2 = INTEGER: 0 */ { "unmapped.rPDUOutletConfigPowerOffTime", 0, 1, ".1.3.6.1.4.1.318.1.1.12.3.4.1.1.5.2", NULL, SU_FLAG_OK, NULL }, /* rPDUOutletConfigPowerOffTime.3 = INTEGER: 0 */ { "unmapped.rPDUOutletConfigPowerOffTime", 0, 1, ".1.3.6.1.4.1.318.1.1.12.3.4.1.1.5.3", NULL, SU_FLAG_OK, NULL }, /* rPDUOutletConfigPowerOffTime.4 = INTEGER: 0 */ { "unmapped.rPDUOutletConfigPowerOffTime", 0, 1, ".1.3.6.1.4.1.318.1.1.12.3.4.1.1.5.4", NULL, SU_FLAG_OK, NULL }, /* rPDUOutletConfigPowerOffTime.5 = INTEGER: 0 */ { "unmapped.rPDUOutletConfigPowerOffTime", 0, 1, ".1.3.6.1.4.1.318.1.1.12.3.4.1.1.5.5", NULL, SU_FLAG_OK, NULL }, /* rPDUOutletConfigPowerOffTime.6 = INTEGER: 0 */ { "unmapped.rPDUOutletConfigPowerOffTime", 0, 1, ".1.3.6.1.4.1.318.1.1.12.3.4.1.1.5.6", NULL, SU_FLAG_OK, NULL }, /* rPDUOutletConfigPowerOffTime.7 = INTEGER: 0 */ { "unmapped.rPDUOutletConfigPowerOffTime", 0, 1, ".1.3.6.1.4.1.318.1.1.12.3.4.1.1.5.7", NULL, SU_FLAG_OK, NULL }, /* rPDUOutletConfigPowerOffTime.8 = INTEGER: 0 */ { "unmapped.rPDUOutletConfigPowerOffTime", 0, 1, ".1.3.6.1.4.1.318.1.1.12.3.4.1.1.5.8", NULL, SU_FLAG_OK, NULL }, /* rPDUOutletConfigRebootDuration.1 = INTEGER: 5 */ { "unmapped.rPDUOutletConfigRebootDuration", 0, 1, ".1.3.6.1.4.1.318.1.1.12.3.4.1.1.6.1", NULL, SU_FLAG_OK, NULL }, /* rPDUOutletConfigRebootDuration.2 = INTEGER: 5 */ { "unmapped.rPDUOutletConfigRebootDuration", 0, 1, ".1.3.6.1.4.1.318.1.1.12.3.4.1.1.6.2", NULL, SU_FLAG_OK, NULL }, /* rPDUOutletConfigRebootDuration.3 = INTEGER: 5 */ { "unmapped.rPDUOutletConfigRebootDuration", 0, 1, ".1.3.6.1.4.1.318.1.1.12.3.4.1.1.6.3", NULL, SU_FLAG_OK, NULL }, /* rPDUOutletConfigRebootDuration.4 = INTEGER: 5 */ { "unmapped.rPDUOutletConfigRebootDuration", 0, 1, ".1.3.6.1.4.1.318.1.1.12.3.4.1.1.6.4", NULL, SU_FLAG_OK, NULL }, /* rPDUOutletConfigRebootDuration.5 = INTEGER: 5 */ { "unmapped.rPDUOutletConfigRebootDuration", 0, 1, ".1.3.6.1.4.1.318.1.1.12.3.4.1.1.6.5", NULL, SU_FLAG_OK, NULL }, /* rPDUOutletConfigRebootDuration.6 = INTEGER: 5 */ { "unmapped.rPDUOutletConfigRebootDuration", 0, 1, ".1.3.6.1.4.1.318.1.1.12.3.4.1.1.6.6", NULL, SU_FLAG_OK, NULL }, /* rPDUOutletConfigRebootDuration.7 = INTEGER: 5 */ { "unmapped.rPDUOutletConfigRebootDuration", 0, 1, ".1.3.6.1.4.1.318.1.1.12.3.4.1.1.6.7", NULL, SU_FLAG_OK, NULL }, /* rPDUOutletConfigRebootDuration.8 = INTEGER: 5 */ { "unmapped.rPDUOutletConfigRebootDuration", 0, 1, ".1.3.6.1.4.1.318.1.1.12.3.4.1.1.6.8", NULL, SU_FLAG_OK, NULL }, /* rPDUOutletConfigOutletBank.1 = INTEGER: 0 */ { "unmapped.rPDUOutletConfigOutletBank", 0, 1, ".1.3.6.1.4.1.318.1.1.12.3.4.1.1.7.1", NULL, SU_FLAG_OK, NULL }, /* rPDUOutletConfigOutletBank.2 = INTEGER: 0 */ { "unmapped.rPDUOutletConfigOutletBank", 0, 1, ".1.3.6.1.4.1.318.1.1.12.3.4.1.1.7.2", NULL, SU_FLAG_OK, NULL }, /* rPDUOutletConfigOutletBank.3 = INTEGER: 0 */ { "unmapped.rPDUOutletConfigOutletBank", 0, 1, ".1.3.6.1.4.1.318.1.1.12.3.4.1.1.7.3", NULL, SU_FLAG_OK, NULL }, /* rPDUOutletConfigOutletBank.4 = INTEGER: 0 */ { "unmapped.rPDUOutletConfigOutletBank", 0, 1, ".1.3.6.1.4.1.318.1.1.12.3.4.1.1.7.4", NULL, SU_FLAG_OK, NULL }, /* rPDUOutletConfigOutletBank.5 = INTEGER: 0 */ { "unmapped.rPDUOutletConfigOutletBank", 0, 1, ".1.3.6.1.4.1.318.1.1.12.3.4.1.1.7.5", NULL, SU_FLAG_OK, NULL }, /* rPDUOutletConfigOutletBank.6 = INTEGER: 0 */ { "unmapped.rPDUOutletConfigOutletBank", 0, 1, ".1.3.6.1.4.1.318.1.1.12.3.4.1.1.7.6", NULL, SU_FLAG_OK, NULL }, /* rPDUOutletConfigOutletBank.7 = INTEGER: 0 */ { "unmapped.rPDUOutletConfigOutletBank", 0, 1, ".1.3.6.1.4.1.318.1.1.12.3.4.1.1.7.7", NULL, SU_FLAG_OK, NULL }, /* rPDUOutletConfigOutletBank.8 = INTEGER: 0 */ { "unmapped.rPDUOutletConfigOutletBank", 0, 1, ".1.3.6.1.4.1.318.1.1.12.3.4.1.1.7.8", NULL, SU_FLAG_OK, NULL }, /* rPDUOutletConfigMonitoredTableSize.0 = INTEGER: 0 */ { "unmapped.rPDUOutletConfigMonitoredTableSize", 0, 1, ".1.3.6.1.4.1.318.1.1.12.3.4.2.0", NULL, SU_FLAG_OK, NULL }, /* rPDUOutletStatusIndex.1 = INTEGER: 1 */ { "unmapped.rPDUOutletStatusIndex", 0, 1, ".1.3.6.1.4.1.318.1.1.12.3.5.1.1.1.1", NULL, SU_FLAG_OK, NULL }, /* rPDUOutletStatusIndex.2 = INTEGER: 2 */ { "unmapped.rPDUOutletStatusIndex", 0, 1, ".1.3.6.1.4.1.318.1.1.12.3.5.1.1.1.2", NULL, SU_FLAG_OK, NULL }, /* rPDUOutletStatusIndex.3 = INTEGER: 3 */ { "unmapped.rPDUOutletStatusIndex", 0, 1, ".1.3.6.1.4.1.318.1.1.12.3.5.1.1.1.3", NULL, SU_FLAG_OK, NULL }, /* rPDUOutletStatusIndex.4 = INTEGER: 4 */ { "unmapped.rPDUOutletStatusIndex", 0, 1, ".1.3.6.1.4.1.318.1.1.12.3.5.1.1.1.4", NULL, SU_FLAG_OK, NULL }, /* rPDUOutletStatusIndex.5 = INTEGER: 5 */ { "unmapped.rPDUOutletStatusIndex", 0, 1, ".1.3.6.1.4.1.318.1.1.12.3.5.1.1.1.5", NULL, SU_FLAG_OK, NULL }, /* rPDUOutletStatusIndex.6 = INTEGER: 6 */ { "unmapped.rPDUOutletStatusIndex", 0, 1, ".1.3.6.1.4.1.318.1.1.12.3.5.1.1.1.6", NULL, SU_FLAG_OK, NULL }, /* rPDUOutletStatusIndex.7 = INTEGER: 7 */ { "unmapped.rPDUOutletStatusIndex", 0, 1, ".1.3.6.1.4.1.318.1.1.12.3.5.1.1.1.7", NULL, SU_FLAG_OK, NULL }, /* rPDUOutletStatusIndex.8 = INTEGER: 8 */ { "unmapped.rPDUOutletStatusIndex", 0, 1, ".1.3.6.1.4.1.318.1.1.12.3.5.1.1.1.8", NULL, SU_FLAG_OK, NULL }, /* rPDUOutletStatusOutletName.1 = STRING: "Testing Name" */ { "unmapped.rPDUOutletStatusOutletName", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.318.1.1.12.3.5.1.1.2.1", NULL, SU_FLAG_OK, NULL }, /* rPDUOutletStatusOutletName.2 = STRING: "Testing 2" */ { "unmapped.rPDUOutletStatusOutletName", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.318.1.1.12.3.5.1.1.2.2", NULL, SU_FLAG_OK, NULL }, /* rPDUOutletStatusOutletName.3 = STRING: "Outlet 3" */ { "unmapped.rPDUOutletStatusOutletName", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.318.1.1.12.3.5.1.1.2.3", NULL, SU_FLAG_OK, NULL }, /* rPDUOutletStatusOutletName.4 = STRING: "Outlet 4" */ { "unmapped.rPDUOutletStatusOutletName", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.318.1.1.12.3.5.1.1.2.4", NULL, SU_FLAG_OK, NULL }, /* rPDUOutletStatusOutletName.5 = STRING: "Outlet 5" */ { "unmapped.rPDUOutletStatusOutletName", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.318.1.1.12.3.5.1.1.2.5", NULL, SU_FLAG_OK, NULL }, /* rPDUOutletStatusOutletName.6 = STRING: "Outlet 6" */ { "unmapped.rPDUOutletStatusOutletName", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.318.1.1.12.3.5.1.1.2.6", NULL, SU_FLAG_OK, NULL }, /* rPDUOutletStatusOutletName.7 = STRING: "Outlet 7" */ { "unmapped.rPDUOutletStatusOutletName", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.318.1.1.12.3.5.1.1.2.7", NULL, SU_FLAG_OK, NULL }, /* rPDUOutletStatusOutletName.8 = STRING: "Outlet 8" */ { "unmapped.rPDUOutletStatusOutletName", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.318.1.1.12.3.5.1.1.2.8", NULL, SU_FLAG_OK, NULL }, /* rPDUOutletStatusOutletPhase.1 = INTEGER: phase1(1) */ { "unmapped.rPDUOutletStatusOutletPhase", 0, 1, ".1.3.6.1.4.1.318.1.1.12.3.5.1.1.3.1", NULL, SU_FLAG_OK, NULL }, /* rPDUOutletStatusOutletPhase.2 = INTEGER: phase1(1) */ { "unmapped.rPDUOutletStatusOutletPhase", 0, 1, ".1.3.6.1.4.1.318.1.1.12.3.5.1.1.3.2", NULL, SU_FLAG_OK, NULL }, /* rPDUOutletStatusOutletPhase.3 = INTEGER: phase1(1) */ { "unmapped.rPDUOutletStatusOutletPhase", 0, 1, ".1.3.6.1.4.1.318.1.1.12.3.5.1.1.3.3", NULL, SU_FLAG_OK, NULL }, /* rPDUOutletStatusOutletPhase.4 = INTEGER: phase1(1) */ { "unmapped.rPDUOutletStatusOutletPhase", 0, 1, ".1.3.6.1.4.1.318.1.1.12.3.5.1.1.3.4", NULL, SU_FLAG_OK, NULL }, /* rPDUOutletStatusOutletPhase.5 = INTEGER: phase1(1) */ { "unmapped.rPDUOutletStatusOutletPhase", 0, 1, ".1.3.6.1.4.1.318.1.1.12.3.5.1.1.3.5", NULL, SU_FLAG_OK, NULL }, /* rPDUOutletStatusOutletPhase.6 = INTEGER: phase1(1) */ { "unmapped.rPDUOutletStatusOutletPhase", 0, 1, ".1.3.6.1.4.1.318.1.1.12.3.5.1.1.3.6", NULL, SU_FLAG_OK, NULL }, /* rPDUOutletStatusOutletPhase.7 = INTEGER: phase1(1) */ { "unmapped.rPDUOutletStatusOutletPhase", 0, 1, ".1.3.6.1.4.1.318.1.1.12.3.5.1.1.3.7", NULL, SU_FLAG_OK, NULL }, /* rPDUOutletStatusOutletPhase.8 = INTEGER: phase1(1) */ { "unmapped.rPDUOutletStatusOutletPhase", 0, 1, ".1.3.6.1.4.1.318.1.1.12.3.5.1.1.3.8", NULL, SU_FLAG_OK, NULL }, /* rPDUOutletStatusOutletState.1 = INTEGER: outletStatusOn(1) */ { "unmapped.rPDUOutletStatusOutletState", 0, 1, ".1.3.6.1.4.1.318.1.1.12.3.5.1.1.4.1", NULL, SU_FLAG_OK, NULL }, /* rPDUOutletStatusOutletState.2 = INTEGER: outletStatusOn(1) */ { "unmapped.rPDUOutletStatusOutletState", 0, 1, ".1.3.6.1.4.1.318.1.1.12.3.5.1.1.4.2", NULL, SU_FLAG_OK, NULL }, /* rPDUOutletStatusOutletState.3 = INTEGER: outletStatusOn(1) */ { "unmapped.rPDUOutletStatusOutletState", 0, 1, ".1.3.6.1.4.1.318.1.1.12.3.5.1.1.4.3", NULL, SU_FLAG_OK, NULL }, /* rPDUOutletStatusOutletState.4 = INTEGER: outletStatusOn(1) */ { "unmapped.rPDUOutletStatusOutletState", 0, 1, ".1.3.6.1.4.1.318.1.1.12.3.5.1.1.4.4", NULL, SU_FLAG_OK, NULL }, /* rPDUOutletStatusOutletState.5 = INTEGER: outletStatusOn(1) */ { "unmapped.rPDUOutletStatusOutletState", 0, 1, ".1.3.6.1.4.1.318.1.1.12.3.5.1.1.4.5", NULL, SU_FLAG_OK, NULL }, /* rPDUOutletStatusOutletState.6 = INTEGER: outletStatusOn(1) */ { "unmapped.rPDUOutletStatusOutletState", 0, 1, ".1.3.6.1.4.1.318.1.1.12.3.5.1.1.4.6", NULL, SU_FLAG_OK, NULL }, /* rPDUOutletStatusOutletState.7 = INTEGER: outletStatusOn(1) */ { "unmapped.rPDUOutletStatusOutletState", 0, 1, ".1.3.6.1.4.1.318.1.1.12.3.5.1.1.4.7", NULL, SU_FLAG_OK, NULL }, /* rPDUOutletStatusOutletState.8 = INTEGER: outletStatusOn(1) */ { "unmapped.rPDUOutletStatusOutletState", 0, 1, ".1.3.6.1.4.1.318.1.1.12.3.5.1.1.4.8", NULL, SU_FLAG_OK, NULL }, /* rPDUOutletStatusCommandPending.1 = INTEGER: outletStatusNoCommandPending(2) */ { "unmapped.rPDUOutletStatusCommandPending", 0, 1, ".1.3.6.1.4.1.318.1.1.12.3.5.1.1.5.1", NULL, SU_FLAG_OK, NULL }, /* rPDUOutletStatusCommandPending.2 = INTEGER: outletStatusNoCommandPending(2) */ { "unmapped.rPDUOutletStatusCommandPending", 0, 1, ".1.3.6.1.4.1.318.1.1.12.3.5.1.1.5.2", NULL, SU_FLAG_OK, NULL }, /* rPDUOutletStatusCommandPending.3 = INTEGER: outletStatusNoCommandPending(2) */ { "unmapped.rPDUOutletStatusCommandPending", 0, 1, ".1.3.6.1.4.1.318.1.1.12.3.5.1.1.5.3", NULL, SU_FLAG_OK, NULL }, /* rPDUOutletStatusCommandPending.4 = INTEGER: outletStatusNoCommandPending(2) */ { "unmapped.rPDUOutletStatusCommandPending", 0, 1, ".1.3.6.1.4.1.318.1.1.12.3.5.1.1.5.4", NULL, SU_FLAG_OK, NULL }, /* rPDUOutletStatusCommandPending.5 = INTEGER: outletStatusNoCommandPending(2) */ { "unmapped.rPDUOutletStatusCommandPending", 0, 1, ".1.3.6.1.4.1.318.1.1.12.3.5.1.1.5.5", NULL, SU_FLAG_OK, NULL }, /* rPDUOutletStatusCommandPending.6 = INTEGER: outletStatusNoCommandPending(2) */ { "unmapped.rPDUOutletStatusCommandPending", 0, 1, ".1.3.6.1.4.1.318.1.1.12.3.5.1.1.5.6", NULL, SU_FLAG_OK, NULL }, /* rPDUOutletStatusCommandPending.7 = INTEGER: outletStatusNoCommandPending(2) */ { "unmapped.rPDUOutletStatusCommandPending", 0, 1, ".1.3.6.1.4.1.318.1.1.12.3.5.1.1.5.7", NULL, SU_FLAG_OK, NULL }, /* rPDUOutletStatusCommandPending.8 = INTEGER: outletStatusNoCommandPending(2) */ { "unmapped.rPDUOutletStatusCommandPending", 0, 1, ".1.3.6.1.4.1.318.1.1.12.3.5.1.1.5.8", NULL, SU_FLAG_OK, NULL }, /* rPDUOutletStatusOutletBank.1 = INTEGER: 0 */ { "unmapped.rPDUOutletStatusOutletBank", 0, 1, ".1.3.6.1.4.1.318.1.1.12.3.5.1.1.6.1", NULL, SU_FLAG_OK, NULL }, /* rPDUOutletStatusOutletBank.2 = INTEGER: 0 */ { "unmapped.rPDUOutletStatusOutletBank", 0, 1, ".1.3.6.1.4.1.318.1.1.12.3.5.1.1.6.2", NULL, SU_FLAG_OK, NULL }, /* rPDUOutletStatusOutletBank.3 = INTEGER: 0 */ { "unmapped.rPDUOutletStatusOutletBank", 0, 1, ".1.3.6.1.4.1.318.1.1.12.3.5.1.1.6.3", NULL, SU_FLAG_OK, NULL }, /* rPDUOutletStatusOutletBank.4 = INTEGER: 0 */ { "unmapped.rPDUOutletStatusOutletBank", 0, 1, ".1.3.6.1.4.1.318.1.1.12.3.5.1.1.6.4", NULL, SU_FLAG_OK, NULL }, /* rPDUOutletStatusOutletBank.5 = INTEGER: 0 */ { "unmapped.rPDUOutletStatusOutletBank", 0, 1, ".1.3.6.1.4.1.318.1.1.12.3.5.1.1.6.5", NULL, SU_FLAG_OK, NULL }, /* rPDUOutletStatusOutletBank.6 = INTEGER: 0 */ { "unmapped.rPDUOutletStatusOutletBank", 0, 1, ".1.3.6.1.4.1.318.1.1.12.3.5.1.1.6.6", NULL, SU_FLAG_OK, NULL }, /* rPDUOutletStatusOutletBank.7 = INTEGER: 0 */ { "unmapped.rPDUOutletStatusOutletBank", 0, 1, ".1.3.6.1.4.1.318.1.1.12.3.5.1.1.6.7", NULL, SU_FLAG_OK, NULL }, /* rPDUOutletStatusOutletBank.8 = INTEGER: 0 */ { "unmapped.rPDUOutletStatusOutletBank", 0, 1, ".1.3.6.1.4.1.318.1.1.12.3.5.1.1.6.8", NULL, SU_FLAG_OK, NULL }, /* rPDUOutletStatusLoad.1 = Gauge32: 0 */ { "unmapped.rPDUOutletStatusLoad", 0, 1, ".1.3.6.1.4.1.318.1.1.12.3.5.1.1.7.1", NULL, SU_FLAG_OK, NULL }, /* rPDUOutletStatusLoad.2 = Gauge32: 0 */ { "unmapped.rPDUOutletStatusLoad", 0, 1, ".1.3.6.1.4.1.318.1.1.12.3.5.1.1.7.2", NULL, SU_FLAG_OK, NULL }, /* rPDUOutletStatusLoad.3 = Gauge32: 0 */ { "unmapped.rPDUOutletStatusLoad", 0, 1, ".1.3.6.1.4.1.318.1.1.12.3.5.1.1.7.3", NULL, SU_FLAG_OK, NULL }, /* rPDUOutletStatusLoad.4 = Gauge32: 0 */ { "unmapped.rPDUOutletStatusLoad", 0, 1, ".1.3.6.1.4.1.318.1.1.12.3.5.1.1.7.4", NULL, SU_FLAG_OK, NULL }, /* rPDUOutletStatusLoad.5 = Gauge32: 0 */ { "unmapped.rPDUOutletStatusLoad", 0, 1, ".1.3.6.1.4.1.318.1.1.12.3.5.1.1.7.5", NULL, SU_FLAG_OK, NULL }, /* rPDUOutletStatusLoad.6 = Gauge32: 0 */ { "unmapped.rPDUOutletStatusLoad", 0, 1, ".1.3.6.1.4.1.318.1.1.12.3.5.1.1.7.6", NULL, SU_FLAG_OK, NULL }, /* rPDUOutletStatusLoad.7 = Gauge32: 0 */ { "unmapped.rPDUOutletStatusLoad", 0, 1, ".1.3.6.1.4.1.318.1.1.12.3.5.1.1.7.7", NULL, SU_FLAG_OK, NULL }, /* rPDUOutletStatusLoad.8 = Gauge32: 0 */ { "unmapped.rPDUOutletStatusLoad", 0, 1, ".1.3.6.1.4.1.318.1.1.12.3.5.1.1.7.8", NULL, SU_FLAG_OK, NULL }, /* rPDUPowerSupply1Status.0 = INTEGER: powerSupplyOneOk(1) */ { "unmapped.rPDUPowerSupply1Status", 0, 1, ".1.3.6.1.4.1.318.1.1.12.4.1.1.0", NULL, SU_FLAG_OK, NULL }, /* rPDUPowerSupply2Status.0 = INTEGER: powerSupplyTwoOk(1) */ { "unmapped.rPDUPowerSupply2Status", 0, 1, ".1.3.6.1.4.1.318.1.1.12.4.1.2.0", NULL, SU_FLAG_OK, NULL }, /* rPDUPowerSupplyAlarm.0 = INTEGER: allAvailablePowerSuppliesOK(1) */ { "unmapped.rPDUPowerSupplyAlarm", 0, 1, ".1.3.6.1.4.1.318.1.1.12.4.1.3.0", NULL, SU_FLAG_OK, NULL }, /* rPDUStatusBankTableSize.0 = INTEGER: 0 */ { "unmapped.rPDUStatusBankTableSize", 0, 1, ".1.3.6.1.4.1.318.1.1.12.5.1.0", NULL, SU_FLAG_OK, NULL }, /* rPDUStatusPhaseTableSize.0 = INTEGER: 1 */ { "unmapped.rPDUStatusPhaseTableSize", 0, 1, ".1.3.6.1.4.1.318.1.1.12.5.3.0", NULL, SU_FLAG_OK, NULL }, /* rPDUStatusPhaseIndex.1 = INTEGER: 1 */ { "unmapped.rPDUStatusPhaseIndex", 0, 1, ".1.3.6.1.4.1.318.1.1.12.5.4.1.1.1", NULL, SU_FLAG_OK, NULL }, /* rPDUStatusPhaseNumber.1 = INTEGER: 1 */ { "unmapped.rPDUStatusPhaseNumber", 0, 1, ".1.3.6.1.4.1.318.1.1.12.5.4.1.2.1", NULL, SU_FLAG_OK, NULL }, /* rPDUStatusPhaseState.1 = INTEGER: phaseLoadNormal(1) */ { "unmapped.rPDUStatusPhaseState", 0, 1, ".1.3.6.1.4.1.318.1.1.12.5.4.1.3.1", NULL, SU_FLAG_OK, NULL }, /* rPDUStatusOutletTableSize.0 = INTEGER: 0 */ { "unmapped.rPDUStatusOutletTableSize", 0, 1, ".1.3.6.1.4.1.318.1.1.12.5.5.0", NULL, SU_FLAG_OK, NULL }, /* experimental.2.1.0 = INTEGER: 1 */ { "unmapped.experimental", 0, 1, ".1.3.6.1.4.1.318.1.4.2.1.0", NULL, SU_FLAG_OK, NULL }, /* experimental.2.2.1.1.1 = INTEGER: 1 */ { "unmapped.experimental", 0, 1, ".1.3.6.1.4.1.318.1.4.2.2.1.1.1", NULL, SU_FLAG_OK, NULL }, /* experimental.2.2.1.2.1 = STRING: "Rack PDU_ISX" */ { "unmapped.experimental", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.318.1.4.2.2.1.2.1", NULL, SU_FLAG_OK, NULL }, /* experimental.2.2.1.3.1 = STRING: "5A1234E00874" */ { "unmapped.experimental", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.318.1.4.2.2.1.3.1", NULL, SU_FLAG_OK, NULL }, /* experimental.2.2.1.4.1 = INTEGER: 2 */ { "unmapped.experimental", 0, 1, ".1.3.6.1.4.1.318.1.4.2.2.1.4.1", NULL, SU_FLAG_OK, NULL }, /* experimental.2.2.1.5.1 = STRING: "Rack PDU" */ { "unmapped.experimental", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.318.1.4.2.2.1.5.1", NULL, SU_FLAG_OK, NULL }, /* experimental.2.2.1.6.1 = STRING: "1" */ { "unmapped.experimental", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.318.1.4.2.2.1.6.1", NULL, SU_FLAG_OK, NULL }, /* experimental.2.2.1.7.1 = STRING: "Unknown" */ { "unmapped.experimental", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.318.1.4.2.2.1.7.1", NULL, SU_FLAG_OK, NULL }, /* experimental.2.2.1.8.1 = INTEGER: 255 */ { "unmapped.experimental", 0, 1, ".1.3.6.1.4.1.318.1.4.2.2.1.8.1", NULL, SU_FLAG_OK, NULL }, /* experimental.2.2.1.9.1 = STRING: "RackPDU" */ { "unmapped.experimental", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.318.1.4.2.2.1.9.1", NULL, SU_FLAG_OK, NULL }, /* experimental.2.2.1.10.1 = INTEGER: 255 */ { "unmapped.experimental", 0, 1, ".1.3.6.1.4.1.318.1.4.2.2.1.10.1", NULL, SU_FLAG_OK, NULL }, /* experimental.2.2.1.11.1 = INTEGER: 1 */ { "unmapped.experimental", 0, 1, ".1.3.6.1.4.1.318.1.4.2.2.1.11.1", NULL, SU_FLAG_OK, NULL }, /* experimental.2.2.1.12.1 = STRING: "0" */ { "unmapped.experimental", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.318.1.4.2.2.1.12.1", NULL, SU_FLAG_OK, NULL }, /* experimental.2.2.1.13.1 = INTEGER: 1 */ { "unmapped.experimental", 0, 1, ".1.3.6.1.4.1.318.1.4.2.2.1.13.1", NULL, SU_FLAG_OK, NULL }, /* experimental.2.2.1.14.1 = STRING: "SB-1" */ { "unmapped.experimental", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.318.1.4.2.2.1.14.1", NULL, SU_FLAG_OK, NULL }, /* experimental.2.3.0 = INTEGER: 2 */ { "unmapped.experimental", 0, 1, ".1.3.6.1.4.1.318.1.4.2.3.0", NULL, SU_FLAG_OK, NULL }, /* experimental.2.4.1.1.1 = INTEGER: 1 */ { "unmapped.experimental", 0, 1, ".1.3.6.1.4.1.318.1.4.2.4.1.1.1", NULL, SU_FLAG_OK, NULL }, /* experimental.2.4.1.1.2 = INTEGER: 2 */ { "unmapped.experimental", 0, 1, ".1.3.6.1.4.1.318.1.4.2.4.1.1.2", NULL, SU_FLAG_OK, NULL }, /* experimental.2.4.1.2.1 = STRING: "5A1234E00874" */ { "unmapped.experimental", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.318.1.4.2.4.1.2.1", NULL, SU_FLAG_OK, NULL }, /* experimental.2.4.1.2.2 = STRING: "5A1234E00874" */ { "unmapped.experimental", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.318.1.4.2.4.1.2.2", NULL, SU_FLAG_OK, NULL }, /* experimental.2.4.1.3.1 = STRING: "apc_hw02_aos_373.bin" */ { "unmapped.experimental", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.318.1.4.2.4.1.3.1", NULL, SU_FLAG_OK, NULL }, /* experimental.2.4.1.3.2 = STRING: "apc_hw02_rpdu_373.bin" */ { "unmapped.experimental", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.318.1.4.2.4.1.3.2", NULL, SU_FLAG_OK, NULL }, /* experimental.2.4.1.4.1 = STRING: "v3.7.3" */ { "unmapped.experimental", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.318.1.4.2.4.1.4.1", NULL, SU_FLAG_OK, NULL }, /* experimental.2.4.1.4.2 = STRING: "v3.7.3" */ { "unmapped.experimental", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.318.1.4.2.4.1.4.2", NULL, SU_FLAG_OK, NULL }, /* experimental.2.5.0 = INTEGER: 19 */ { "unmapped.experimental", 0, 1, ".1.3.6.1.4.1.318.1.4.2.5.0", NULL, SU_FLAG_OK, NULL }, /* experimental.2.6.1.1.1 = INTEGER: 1 */ { "unmapped.experimental", 0, 1, ".1.3.6.1.4.1.318.1.4.2.6.1.1.1", NULL, SU_FLAG_OK, NULL }, /* experimental.2.6.1.1.2 = INTEGER: 2 */ { "unmapped.experimental", 0, 1, ".1.3.6.1.4.1.318.1.4.2.6.1.1.2", NULL, SU_FLAG_OK, NULL }, /* experimental.2.6.1.1.3 = INTEGER: 3 */ { "unmapped.experimental", 0, 1, ".1.3.6.1.4.1.318.1.4.2.6.1.1.3", NULL, SU_FLAG_OK, NULL }, /* experimental.2.6.1.1.4 = INTEGER: 4 */ { "unmapped.experimental", 0, 1, ".1.3.6.1.4.1.318.1.4.2.6.1.1.4", NULL, SU_FLAG_OK, NULL }, /* experimental.2.6.1.1.5 = INTEGER: 5 */ { "unmapped.experimental", 0, 1, ".1.3.6.1.4.1.318.1.4.2.6.1.1.5", NULL, SU_FLAG_OK, NULL }, /* experimental.2.6.1.1.6 = INTEGER: 6 */ { "unmapped.experimental", 0, 1, ".1.3.6.1.4.1.318.1.4.2.6.1.1.6", NULL, SU_FLAG_OK, NULL }, /* experimental.2.6.1.1.7 = INTEGER: 7 */ { "unmapped.experimental", 0, 1, ".1.3.6.1.4.1.318.1.4.2.6.1.1.7", NULL, SU_FLAG_OK, NULL }, /* experimental.2.6.1.1.8 = INTEGER: 8 */ { "unmapped.experimental", 0, 1, ".1.3.6.1.4.1.318.1.4.2.6.1.1.8", NULL, SU_FLAG_OK, NULL }, /* experimental.2.6.1.1.9 = INTEGER: 9 */ { "unmapped.experimental", 0, 1, ".1.3.6.1.4.1.318.1.4.2.6.1.1.9", NULL, SU_FLAG_OK, NULL }, /* experimental.2.6.1.1.10 = INTEGER: 10 */ { "unmapped.experimental", 0, 1, ".1.3.6.1.4.1.318.1.4.2.6.1.1.10", NULL, SU_FLAG_OK, NULL }, /* experimental.2.6.1.1.11 = INTEGER: 11 */ { "unmapped.experimental", 0, 1, ".1.3.6.1.4.1.318.1.4.2.6.1.1.11", NULL, SU_FLAG_OK, NULL }, /* experimental.2.6.1.1.12 = INTEGER: 12 */ { "unmapped.experimental", 0, 1, ".1.3.6.1.4.1.318.1.4.2.6.1.1.12", NULL, SU_FLAG_OK, NULL }, /* experimental.2.6.1.1.13 = INTEGER: 13 */ { "unmapped.experimental", 0, 1, ".1.3.6.1.4.1.318.1.4.2.6.1.1.13", NULL, SU_FLAG_OK, NULL }, /* experimental.2.6.1.1.14 = INTEGER: 14 */ { "unmapped.experimental", 0, 1, ".1.3.6.1.4.1.318.1.4.2.6.1.1.14", NULL, SU_FLAG_OK, NULL }, /* experimental.2.6.1.1.15 = INTEGER: 15 */ { "unmapped.experimental", 0, 1, ".1.3.6.1.4.1.318.1.4.2.6.1.1.15", NULL, SU_FLAG_OK, NULL }, /* experimental.2.6.1.1.16 = INTEGER: 16 */ { "unmapped.experimental", 0, 1, ".1.3.6.1.4.1.318.1.4.2.6.1.1.16", NULL, SU_FLAG_OK, NULL }, /* experimental.2.6.1.1.17 = INTEGER: 17 */ { "unmapped.experimental", 0, 1, ".1.3.6.1.4.1.318.1.4.2.6.1.1.17", NULL, SU_FLAG_OK, NULL }, /* experimental.2.6.1.1.18 = INTEGER: 18 */ { "unmapped.experimental", 0, 1, ".1.3.6.1.4.1.318.1.4.2.6.1.1.18", NULL, SU_FLAG_OK, NULL }, /* experimental.2.6.1.1.19 = INTEGER: 19 */ { "unmapped.experimental", 0, 1, ".1.3.6.1.4.1.318.1.4.2.6.1.1.19", NULL, SU_FLAG_OK, NULL }, /* experimental.2.6.1.2.1 = INTEGER: 1 */ { "unmapped.experimental", 0, 1, ".1.3.6.1.4.1.318.1.4.2.6.1.2.1", NULL, SU_FLAG_OK, NULL }, /* experimental.2.6.1.2.2 = INTEGER: 2 */ { "unmapped.experimental", 0, 1, ".1.3.6.1.4.1.318.1.4.2.6.1.2.2", NULL, SU_FLAG_OK, NULL }, /* experimental.2.6.1.2.3 = INTEGER: 3 */ { "unmapped.experimental", 0, 1, ".1.3.6.1.4.1.318.1.4.2.6.1.2.3", NULL, SU_FLAG_OK, NULL }, /* experimental.2.6.1.2.4 = INTEGER: 4 */ { "unmapped.experimental", 0, 1, ".1.3.6.1.4.1.318.1.4.2.6.1.2.4", NULL, SU_FLAG_OK, NULL }, /* experimental.2.6.1.2.5 = INTEGER: 5 */ { "unmapped.experimental", 0, 1, ".1.3.6.1.4.1.318.1.4.2.6.1.2.5", NULL, SU_FLAG_OK, NULL }, /* experimental.2.6.1.2.6 = INTEGER: 6 */ { "unmapped.experimental", 0, 1, ".1.3.6.1.4.1.318.1.4.2.6.1.2.6", NULL, SU_FLAG_OK, NULL }, /* experimental.2.6.1.2.7 = INTEGER: 7 */ { "unmapped.experimental", 0, 1, ".1.3.6.1.4.1.318.1.4.2.6.1.2.7", NULL, SU_FLAG_OK, NULL }, /* experimental.2.6.1.2.8 = INTEGER: 8 */ { "unmapped.experimental", 0, 1, ".1.3.6.1.4.1.318.1.4.2.6.1.2.8", NULL, SU_FLAG_OK, NULL }, /* experimental.2.6.1.2.9 = INTEGER: 9 */ { "unmapped.experimental", 0, 1, ".1.3.6.1.4.1.318.1.4.2.6.1.2.9", NULL, SU_FLAG_OK, NULL }, /* experimental.2.6.1.2.10 = INTEGER: 10 */ { "unmapped.experimental", 0, 1, ".1.3.6.1.4.1.318.1.4.2.6.1.2.10", NULL, SU_FLAG_OK, NULL }, /* experimental.2.6.1.2.11 = INTEGER: 11 */ { "unmapped.experimental", 0, 1, ".1.3.6.1.4.1.318.1.4.2.6.1.2.11", NULL, SU_FLAG_OK, NULL }, /* experimental.2.6.1.2.12 = INTEGER: 12 */ { "unmapped.experimental", 0, 1, ".1.3.6.1.4.1.318.1.4.2.6.1.2.12", NULL, SU_FLAG_OK, NULL }, /* experimental.2.6.1.2.13 = INTEGER: 13 */ { "unmapped.experimental", 0, 1, ".1.3.6.1.4.1.318.1.4.2.6.1.2.13", NULL, SU_FLAG_OK, NULL }, /* experimental.2.6.1.2.14 = INTEGER: 14 */ { "unmapped.experimental", 0, 1, ".1.3.6.1.4.1.318.1.4.2.6.1.2.14", NULL, SU_FLAG_OK, NULL }, /* experimental.2.6.1.2.15 = INTEGER: 15 */ { "unmapped.experimental", 0, 1, ".1.3.6.1.4.1.318.1.4.2.6.1.2.15", NULL, SU_FLAG_OK, NULL }, /* experimental.2.6.1.2.16 = INTEGER: 16 */ { "unmapped.experimental", 0, 1, ".1.3.6.1.4.1.318.1.4.2.6.1.2.16", NULL, SU_FLAG_OK, NULL }, /* experimental.2.6.1.2.17 = INTEGER: 17 */ { "unmapped.experimental", 0, 1, ".1.3.6.1.4.1.318.1.4.2.6.1.2.17", NULL, SU_FLAG_OK, NULL }, /* experimental.2.6.1.2.18 = INTEGER: 18 */ { "unmapped.experimental", 0, 1, ".1.3.6.1.4.1.318.1.4.2.6.1.2.18", NULL, SU_FLAG_OK, NULL }, /* experimental.2.6.1.2.19 = INTEGER: 19 */ { "unmapped.experimental", 0, 1, ".1.3.6.1.4.1.318.1.4.2.6.1.2.19", NULL, SU_FLAG_OK, NULL }, /* experimental.2.6.1.3.1 = STRING: "0" */ { "unmapped.experimental", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.318.1.4.2.6.1.3.1", NULL, SU_FLAG_OK, NULL }, /* experimental.2.6.1.3.2 = STRING: "0" */ { "unmapped.experimental", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.318.1.4.2.6.1.3.2", NULL, SU_FLAG_OK, NULL }, /* experimental.2.6.1.3.3 = STRING: "0" */ { "unmapped.experimental", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.318.1.4.2.6.1.3.3", NULL, SU_FLAG_OK, NULL }, /* experimental.2.6.1.3.4 = STRING: "0" */ { "unmapped.experimental", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.318.1.4.2.6.1.3.4", NULL, SU_FLAG_OK, NULL }, /* experimental.2.6.1.3.5 = STRING: "0" */ { "unmapped.experimental", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.318.1.4.2.6.1.3.5", NULL, SU_FLAG_OK, NULL }, /* experimental.2.6.1.3.6 = STRING: "0" */ { "unmapped.experimental", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.318.1.4.2.6.1.3.6", NULL, SU_FLAG_OK, NULL }, /* experimental.2.6.1.3.7 = STRING: "0" */ { "unmapped.experimental", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.318.1.4.2.6.1.3.7", NULL, SU_FLAG_OK, NULL }, /* experimental.2.6.1.3.8 = STRING: "0" */ { "unmapped.experimental", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.318.1.4.2.6.1.3.8", NULL, SU_FLAG_OK, NULL }, /* experimental.2.6.1.3.9 = STRING: "0" */ { "unmapped.experimental", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.318.1.4.2.6.1.3.9", NULL, SU_FLAG_OK, NULL }, /* experimental.2.6.1.3.10 = STRING: "0" */ { "unmapped.experimental", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.318.1.4.2.6.1.3.10", NULL, SU_FLAG_OK, NULL }, /* experimental.2.6.1.3.11 = STRING: "0" */ { "unmapped.experimental", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.318.1.4.2.6.1.3.11", NULL, SU_FLAG_OK, NULL }, /* experimental.2.6.1.3.12 = STRING: "0" */ { "unmapped.experimental", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.318.1.4.2.6.1.3.12", NULL, SU_FLAG_OK, NULL }, /* experimental.2.6.1.3.13 = STRING: "0" */ { "unmapped.experimental", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.318.1.4.2.6.1.3.13", NULL, SU_FLAG_OK, NULL }, /* experimental.2.6.1.3.14 = STRING: "0" */ { "unmapped.experimental", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.318.1.4.2.6.1.3.14", NULL, SU_FLAG_OK, NULL }, /* experimental.2.6.1.3.15 = STRING: "0" */ { "unmapped.experimental", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.318.1.4.2.6.1.3.15", NULL, SU_FLAG_OK, NULL }, /* experimental.2.6.1.3.16 = STRING: "0" */ { "unmapped.experimental", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.318.1.4.2.6.1.3.16", NULL, SU_FLAG_OK, NULL }, /* experimental.2.6.1.3.17 = STRING: "0" */ { "unmapped.experimental", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.318.1.4.2.6.1.3.17", NULL, SU_FLAG_OK, NULL }, /* experimental.2.6.1.3.18 = STRING: "0" */ { "unmapped.experimental", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.318.1.4.2.6.1.3.18", NULL, SU_FLAG_OK, NULL }, /* experimental.2.6.1.3.19 = STRING: "0" */ { "unmapped.experimental", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.318.1.4.2.6.1.3.19", NULL, SU_FLAG_OK, NULL }, /* experimental.2.6.1.4.1 = STRING: "MTYx" */ { "unmapped.experimental", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.318.1.4.2.6.1.4.1", NULL, SU_FLAG_OK, NULL }, /* experimental.2.6.1.4.2 = STRING: "MjM=" */ { "unmapped.experimental", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.318.1.4.2.6.1.4.2", NULL, SU_FLAG_OK, NULL }, /* experimental.2.6.1.4.3 = STRING: "ODA=" */ { "unmapped.experimental", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.318.1.4.2.6.1.4.3", NULL, SU_FLAG_OK, NULL }, /* experimental.2.6.1.4.4 = STRING: "OTk1MA==" */ { "unmapped.experimental", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.318.1.4.2.6.1.4.4", NULL, SU_FLAG_OK, NULL }, /* experimental.2.6.1.4.5 = STRING: "OTk1MA==" */ { "unmapped.experimental", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.318.1.4.2.6.1.4.5", NULL, SU_FLAG_OK, NULL }, /* experimental.2.6.1.4.6 = STRING: "NDQz" */ { "unmapped.experimental", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.318.1.4.2.6.1.4.6", NULL, SU_FLAG_OK, NULL }, /* experimental.2.6.1.4.7 = STRING: "MjI=" */ { "unmapped.experimental", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.318.1.4.2.6.1.4.7", NULL, SU_FLAG_OK, NULL }, /* experimental.2.6.1.4.8 = STRING: "MjI=" */ { "unmapped.experimental", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.318.1.4.2.6.1.4.8", NULL, SU_FLAG_OK, NULL }, /* experimental.2.6.1.4.9 = STRING: "MTIz" */ { "unmapped.experimental", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.318.1.4.2.6.1.4.9", NULL, SU_FLAG_OK, NULL }, /* experimental.2.6.1.4.10 = STRING: "MjU=" */ { "unmapped.experimental", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.318.1.4.2.6.1.4.10", NULL, SU_FLAG_OK, NULL }, /* experimental.2.6.1.4.11 = STRING: "MjE=" */ { "unmapped.experimental", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.318.1.4.2.6.1.4.11", NULL, SU_FLAG_OK, NULL }, /* experimental.2.6.1.4.12 = STRING: "MjE=" */ { "unmapped.experimental", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.318.1.4.2.6.1.4.12", NULL, SU_FLAG_OK, NULL }, /* experimental.2.6.1.4.13 = STRING: "Njg=" */ { "unmapped.experimental", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.318.1.4.2.6.1.4.13", NULL, SU_FLAG_OK, NULL }, /* experimental.2.6.1.4.14 = STRING: "NTQ2" */ { "unmapped.experimental", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.318.1.4.2.6.1.4.14", NULL, SU_FLAG_OK, NULL }, /* experimental.2.6.1.4.15 = STRING: "MTgxMg==" */ { "unmapped.experimental", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.318.1.4.2.6.1.4.15", NULL, SU_FLAG_OK, NULL }, /* experimental.2.6.1.4.16 = STRING: "MTYx" */ { "unmapped.experimental", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.318.1.4.2.6.1.4.16", NULL, SU_FLAG_OK, NULL }, /* experimental.2.6.1.4.17 = STRING: "MjE=" */ { "unmapped.experimental", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.318.1.4.2.6.1.4.17", NULL, SU_FLAG_OK, NULL }, /* experimental.2.6.1.4.18 = STRING: "MjE=" */ { "unmapped.experimental", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.318.1.4.2.6.1.4.18", NULL, SU_FLAG_OK, NULL }, /* experimental.2.6.1.4.19 = STRING: "OTk1MQ==" */ { "unmapped.experimental", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.318.1.4.2.6.1.4.19", NULL, SU_FLAG_OK, NULL }, /* experimental.2.6.1.5.1 = INTEGER: 2 */ { "unmapped.experimental", 0, 1, ".1.3.6.1.4.1.318.1.4.2.6.1.5.1", NULL, SU_FLAG_OK, NULL }, /* experimental.2.6.1.5.2 = INTEGER: 2 */ { "unmapped.experimental", 0, 1, ".1.3.6.1.4.1.318.1.4.2.6.1.5.2", NULL, SU_FLAG_OK, NULL }, /* experimental.2.6.1.5.3 = INTEGER: 2 */ { "unmapped.experimental", 0, 1, ".1.3.6.1.4.1.318.1.4.2.6.1.5.3", NULL, SU_FLAG_OK, NULL }, /* experimental.2.6.1.5.4 = INTEGER: 2 */ { "unmapped.experimental", 0, 1, ".1.3.6.1.4.1.318.1.4.2.6.1.5.4", NULL, SU_FLAG_OK, NULL }, /* experimental.2.6.1.5.5 = INTEGER: 2 */ { "unmapped.experimental", 0, 1, ".1.3.6.1.4.1.318.1.4.2.6.1.5.5", NULL, SU_FLAG_OK, NULL }, /* experimental.2.6.1.5.6 = INTEGER: 1 */ { "unmapped.experimental", 0, 1, ".1.3.6.1.4.1.318.1.4.2.6.1.5.6", NULL, SU_FLAG_OK, NULL }, /* experimental.2.6.1.5.7 = INTEGER: 1 */ { "unmapped.experimental", 0, 1, ".1.3.6.1.4.1.318.1.4.2.6.1.5.7", NULL, SU_FLAG_OK, NULL }, /* experimental.2.6.1.5.8 = INTEGER: 1 */ { "unmapped.experimental", 0, 1, ".1.3.6.1.4.1.318.1.4.2.6.1.5.8", NULL, SU_FLAG_OK, NULL }, /* experimental.2.6.1.5.9 = INTEGER: 1 */ { "unmapped.experimental", 0, 1, ".1.3.6.1.4.1.318.1.4.2.6.1.5.9", NULL, SU_FLAG_OK, NULL }, /* experimental.2.6.1.5.10 = INTEGER: 2 */ { "unmapped.experimental", 0, 1, ".1.3.6.1.4.1.318.1.4.2.6.1.5.10", NULL, SU_FLAG_OK, NULL }, /* experimental.2.6.1.5.11 = INTEGER: 2 */ { "unmapped.experimental", 0, 1, ".1.3.6.1.4.1.318.1.4.2.6.1.5.11", NULL, SU_FLAG_OK, NULL }, /* experimental.2.6.1.5.12 = INTEGER: 2 */ { "unmapped.experimental", 0, 1, ".1.3.6.1.4.1.318.1.4.2.6.1.5.12", NULL, SU_FLAG_OK, NULL }, /* experimental.2.6.1.5.13 = INTEGER: 1 */ { "unmapped.experimental", 0, 1, ".1.3.6.1.4.1.318.1.4.2.6.1.5.13", NULL, SU_FLAG_OK, NULL }, /* experimental.2.6.1.5.14 = INTEGER: 1 */ { "unmapped.experimental", 0, 1, ".1.3.6.1.4.1.318.1.4.2.6.1.5.14", NULL, SU_FLAG_OK, NULL }, /* experimental.2.6.1.5.15 = INTEGER: 1 */ { "unmapped.experimental", 0, 1, ".1.3.6.1.4.1.318.1.4.2.6.1.5.15", NULL, SU_FLAG_OK, NULL }, /* experimental.2.6.1.5.16 = INTEGER: 1 */ { "unmapped.experimental", 0, 1, ".1.3.6.1.4.1.318.1.4.2.6.1.5.16", NULL, SU_FLAG_OK, NULL }, /* experimental.2.6.1.5.17 = INTEGER: 1 */ { "unmapped.experimental", 0, 1, ".1.3.6.1.4.1.318.1.4.2.6.1.5.17", NULL, SU_FLAG_OK, NULL }, /* experimental.2.6.1.5.18 = INTEGER: 1 */ { "unmapped.experimental", 0, 1, ".1.3.6.1.4.1.318.1.4.2.6.1.5.18", NULL, SU_FLAG_OK, NULL }, /* experimental.2.6.1.5.19 = INTEGER: 1 */ { "unmapped.experimental", 0, 1, ".1.3.6.1.4.1.318.1.4.2.6.1.5.19", NULL, SU_FLAG_OK, NULL }, /* experimental.2.7.0 = INTEGER: 1 */ { "unmapped.experimental", 0, 1, ".1.3.6.1.4.1.318.1.4.2.7.0", NULL, SU_FLAG_OK, NULL }, /* experimental.2.8.1.1.1 = INTEGER: 1 */ { "unmapped.experimental", 0, 1, ".1.3.6.1.4.1.318.1.4.2.8.1.1.1", NULL, SU_FLAG_OK, NULL }, /* experimental.2.8.1.2.1 = STRING: "power" */ { "unmapped.experimental", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.318.1.4.2.8.1.2.1", NULL, SU_FLAG_OK, NULL }, /* experimental.2.8.1.3.1 = STRING: "pdu" */ { "unmapped.experimental", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.318.1.4.2.8.1.3.1", NULL, SU_FLAG_OK, NULL }, /* experimental.2.8.1.4.1 = STRING: "rpdu" */ { "unmapped.experimental", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.318.1.4.2.8.1.4.1", NULL, SU_FLAG_OK, NULL }, /* experimental.2.8.1.5.1 = STRING: "version7" */ { "unmapped.experimental", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.318.1.4.2.8.1.5.1", NULL, SU_FLAG_OK, NULL }, /* experimental.2.8.1.6.1 = INTEGER: 1 */ { "unmapped.experimental", 0, 1, ".1.3.6.1.4.1.318.1.4.2.8.1.6.1", NULL, SU_FLAG_OK, NULL }, /* experimental.2.9.0 = INTEGER: 0 */ { "unmapped.experimental", 0, 1, ".1.3.6.1.4.1.318.1.4.2.9.0", NULL, SU_FLAG_OK, NULL }, /* experimental.2.10.0 = INTEGER: 0 */ { "unmapped.experimental", 0, 1, ".1.3.6.1.4.1.318.1.4.2.10.0", NULL, SU_FLAG_OK, NULL }, /* experimental.2.12.0 = INTEGER: 1 */ { "unmapped.experimental", 0, 1, ".1.3.6.1.4.1.318.1.4.2.12.0", NULL, SU_FLAG_OK, NULL }, /* experimental.4.1.0 = INTEGER: 0 */ { "unmapped.experimental", 0, 1, ".1.3.6.1.4.1.318.1.4.4.1.0", NULL, SU_FLAG_OK, NULL }, /* experimental.4.3.0 = STRING: ",<1 digit type identifier>" */ { "unmapped.experimental", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.318.1.4.4.3.0", NULL, SU_FLAG_OK, NULL }, /* experimental.4.4.0 = INTEGER: 0 */ { "unmapped.experimental", 0, 1, ".1.3.6.1.4.1.318.1.4.4.4.0", NULL, SU_FLAG_OK, NULL }, /* experimental.5.1.0 = INTEGER: 12 */ { "unmapped.experimental", 0, 1, ".1.3.6.1.4.1.318.1.4.5.1.0", NULL, SU_FLAG_OK, NULL }, /* experimental.5.2.1.1.1 = INTEGER: 1 */ { "unmapped.experimental", 0, 1, ".1.3.6.1.4.1.318.1.4.5.2.1.1.1", NULL, SU_FLAG_OK, NULL }, /* experimental.5.2.1.1.2 = INTEGER: 2 */ { "unmapped.experimental", 0, 1, ".1.3.6.1.4.1.318.1.4.5.2.1.1.2", NULL, SU_FLAG_OK, NULL }, /* experimental.5.2.1.1.3 = INTEGER: 3 */ { "unmapped.experimental", 0, 1, ".1.3.6.1.4.1.318.1.4.5.2.1.1.3", NULL, SU_FLAG_OK, NULL }, /* experimental.5.2.1.1.4 = INTEGER: 4 */ { "unmapped.experimental", 0, 1, ".1.3.6.1.4.1.318.1.4.5.2.1.1.4", NULL, SU_FLAG_OK, NULL }, /* experimental.5.2.1.1.5 = INTEGER: 5 */ { "unmapped.experimental", 0, 1, ".1.3.6.1.4.1.318.1.4.5.2.1.1.5", NULL, SU_FLAG_OK, NULL }, /* experimental.5.2.1.1.6 = INTEGER: 6 */ { "unmapped.experimental", 0, 1, ".1.3.6.1.4.1.318.1.4.5.2.1.1.6", NULL, SU_FLAG_OK, NULL }, /* experimental.5.2.1.1.7 = INTEGER: 7 */ { "unmapped.experimental", 0, 1, ".1.3.6.1.4.1.318.1.4.5.2.1.1.7", NULL, SU_FLAG_OK, NULL }, /* experimental.5.2.1.1.8 = INTEGER: 8 */ { "unmapped.experimental", 0, 1, ".1.3.6.1.4.1.318.1.4.5.2.1.1.8", NULL, SU_FLAG_OK, NULL }, /* experimental.5.2.1.1.9 = INTEGER: 9 */ { "unmapped.experimental", 0, 1, ".1.3.6.1.4.1.318.1.4.5.2.1.1.9", NULL, SU_FLAG_OK, NULL }, /* experimental.5.2.1.1.10 = INTEGER: 10 */ { "unmapped.experimental", 0, 1, ".1.3.6.1.4.1.318.1.4.5.2.1.1.10", NULL, SU_FLAG_OK, NULL }, /* experimental.5.2.1.1.11 = INTEGER: 11 */ { "unmapped.experimental", 0, 1, ".1.3.6.1.4.1.318.1.4.5.2.1.1.11", NULL, SU_FLAG_OK, NULL }, /* experimental.5.2.1.1.12 = INTEGER: 12 */ { "unmapped.experimental", 0, 1, ".1.3.6.1.4.1.318.1.4.5.2.1.1.12", NULL, SU_FLAG_OK, NULL }, /* experimental.5.2.1.2.1 = INTEGER: 3841 */ { "unmapped.experimental", 0, 1, ".1.3.6.1.4.1.318.1.4.5.2.1.2.1", NULL, SU_FLAG_OK, NULL }, /* experimental.5.2.1.2.2 = INTEGER: 3843 */ { "unmapped.experimental", 0, 1, ".1.3.6.1.4.1.318.1.4.5.2.1.2.2", NULL, SU_FLAG_OK, NULL }, /* experimental.5.2.1.2.3 = INTEGER: 3845 */ { "unmapped.experimental", 0, 1, ".1.3.6.1.4.1.318.1.4.5.2.1.2.3", NULL, SU_FLAG_OK, NULL }, /* experimental.5.2.1.2.4 = INTEGER: 3848 */ { "unmapped.experimental", 0, 1, ".1.3.6.1.4.1.318.1.4.5.2.1.2.4", NULL, SU_FLAG_OK, NULL }, /* experimental.5.2.1.2.5 = INTEGER: 3862 */ { "unmapped.experimental", 0, 1, ".1.3.6.1.4.1.318.1.4.5.2.1.2.5", NULL, SU_FLAG_OK, NULL }, /* experimental.5.2.1.2.6 = INTEGER: 3864 */ { "unmapped.experimental", 0, 1, ".1.3.6.1.4.1.318.1.4.5.2.1.2.6", NULL, SU_FLAG_OK, NULL }, /* experimental.5.2.1.2.7 = INTEGER: 3856 */ { "unmapped.experimental", 0, 1, ".1.3.6.1.4.1.318.1.4.5.2.1.2.7", NULL, SU_FLAG_OK, NULL }, /* experimental.5.2.1.2.8 = INTEGER: 3858 */ { "unmapped.experimental", 0, 1, ".1.3.6.1.4.1.318.1.4.5.2.1.2.8", NULL, SU_FLAG_OK, NULL }, /* experimental.5.2.1.2.9 = INTEGER: 3860 */ { "unmapped.experimental", 0, 1, ".1.3.6.1.4.1.318.1.4.5.2.1.2.9", NULL, SU_FLAG_OK, NULL }, /* experimental.5.2.1.2.10 = INTEGER: 3871 */ { "unmapped.experimental", 0, 1, ".1.3.6.1.4.1.318.1.4.5.2.1.2.10", NULL, SU_FLAG_OK, NULL }, /* experimental.5.2.1.2.11 = INTEGER: 3873 */ { "unmapped.experimental", 0, 1, ".1.3.6.1.4.1.318.1.4.5.2.1.2.11", NULL, SU_FLAG_OK, NULL }, /* experimental.5.2.1.2.12 = INTEGER: 3875 */ { "unmapped.experimental", 0, 1, ".1.3.6.1.4.1.318.1.4.5.2.1.2.12", NULL, SU_FLAG_OK, NULL }, /* experimental.6.1.1.0 = Hex-STRING: 07 00 00 00 */ { "unmapped.experimental", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.318.1.4.6.1.1.0", NULL, SU_FLAG_OK, NULL }, /* experimental.7.1.0 = INTEGER: 4 */ { "unmapped.experimental", 0, 1, ".1.3.6.1.4.1.318.1.4.7.1.0", NULL, SU_FLAG_OK, NULL }, /* experimental.7.3.0 = INTEGER: 4 */ { "unmapped.experimental", 0, 1, ".1.3.6.1.4.1.318.1.4.7.3.0", NULL, SU_FLAG_OK, NULL }, /* experimental.7.4.0 = INTEGER: 3 */ { "unmapped.experimental", 0, 1, ".1.3.6.1.4.1.318.1.4.7.4.0", NULL, SU_FLAG_OK, NULL }, /* experimental.7.5.0 = INTEGER: 3 */ { "unmapped.experimental", 0, 1, ".1.3.6.1.4.1.318.1.4.7.5.0", NULL, SU_FLAG_OK, NULL }, #endif /* if WITH_UNMAPPED_DATA_POINTS */ /* end of structure. */ { NULL, 0, 0, NULL, NULL, 0, NULL } }; mib2nut_info_t apc_pdu_rpdu = { "apc_pdu", APC_PDU_MIB_VERSION, NULL, APC_PDU_DEVICE_MODEL, apc_pdu_mib, APC_PDU_MIB_SYSOID_RPDU, NULL }; mib2nut_info_t apc_pdu_rpdu2 = { "apc_pdu", APC_PDU_MIB_VERSION, NULL, APC_PDU_DEVICE_MODEL, apc_pdu_mib, APC_PDU_MIB_SYSOID_RPDU2, NULL }; mib2nut_info_t apc_pdu_msp = { "apc_pdu", APC_PDU_MIB_VERSION, NULL, APC_PDU_DEVICE_MODEL, apc_pdu_mib, APC_PDU_MIB_SYSOID_MSP, NULL }; nut-2.8.1/drivers/ivtscd.c0000644000175000017500000001406614501607135012400 00000000000000/* * ivtscd.c - model specific routines for the IVT Solar Controller driver * * Copyright (C) 2009 Arjen de Korte * * 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 2 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, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "config.h" #include "main.h" #include "serial.h" #include "nut_stdint.h" #include "attribute.h" #define DRIVER_NAME "IVT Solar Controller driver" #define DRIVER_VERSION "0.04" /* driver description structure */ upsdrv_info_t upsdrv_info = { DRIVER_NAME, DRIVER_VERSION, "Arjen de Korte ", DRV_EXPERIMENTAL, { NULL } }; static struct { struct { float act; float low; float min; float nom; float max; } voltage; struct { float min; float act; float max; } current; float temperature; } battery; static ssize_t ivt_status(void) { char reply[SMALLBUF]; int i, j = 0; ssize_t ret; ser_flush_io(upsfd); /* * send: F\n */ ret = ser_send(upsfd, "F"); if (ret < 0) { upsdebug_with_errno(3, "send"); return -1; } if (ret == 0) { upsdebug_with_errno(3, "send: timeout"); return -1; } upsdebugx(3, "send: F"); sleep(1); /* allow controller some time to digest this */ /* * read: R:12,57;- 1,1;20;12,57;13,18;- 2,1; 1,5;\n */ ret = ser_get_buf(upsfd, reply, sizeof(reply), 1, 0); if (ret < 0) { upsdebug_with_errno(3, "read"); return -1; } if (ret == 0) { upsdebugx(3, "read: timeout"); return -1; } upsdebugx(3, "read: %.*s", (int)strcspn(reply, "\r\n"), reply); upsdebug_hex(4, " \\_", reply, (size_t)ret); for (i = 0; i < ret; i++) { switch(reply[i]) { case ',': /* convert ',' to '.' */ reply[j++] = '.'; break; case ' ': /* skip over white space */ case '\0': /* skip over null characters */ break; default: /* leave the rest as is */ reply[j++] = reply[i]; break; } } reply[j++] = '\0'; ret = sscanf(reply, "R:%f;%f;%f;%f;%f;%f;%f;", &battery.voltage.act, &battery.current.act, &battery.temperature, &battery.voltage.min, &battery.voltage.max, &battery.current.min, &battery.current.max); upsdebugx(3, "Parsed %" PRIiSIZE " parameters from reply", ret); return ret; } static int instcmd(const char *cmdname, const char *extra) { if (!strcasecmp(cmdname, "reset.input.minmax")) { ser_send(upsfd, "L"); return STAT_INSTCMD_HANDLED; } upslogx(LOG_NOTICE, "instcmd: unknown command [%s] [%s]", cmdname, extra); return STAT_INSTCMD_UNKNOWN; } void upsdrv_initinfo(void) { if (ivt_status() < 7) { fatal_with_errno(EXIT_FAILURE, "IVT Solar Controller not detected"); } /* set the device general information */ dstate_setinfo("device.mfr", "IVT"); dstate_setinfo("device.model", "Solar Controller Device"); dstate_setinfo("device.type", "scd"); dstate_addcmd("reset.input.minmax"); upsh.instcmd = instcmd; } void upsdrv_updateinfo(void) { if (ivt_status() < 7) { dstate_datastale(); return; } dstate_setinfo("battery.voltage", "%.2f", battery.voltage.act); dstate_setinfo("battery.voltage.minimum", "%.2f", battery.voltage.min); dstate_setinfo("battery.voltage.maximum", "%.2f", battery.voltage.max); dstate_setinfo("battery.current", "%.1f", battery.current.act); dstate_setinfo("battery.current.minimum", "%.1f", battery.current.min); dstate_setinfo("battery.current.maximum", "%.1f", battery.current.max); dstate_setinfo("battery.temperature", "%.0f", battery.temperature); status_init(); if (battery.current.act > 0) { status_set("OL"); /* charging */ } else { status_set("OB"); /* discharging */ } if (battery.voltage.act < battery.voltage.low) { status_set("LB"); } status_commit(); dstate_dataok(); } void upsdrv_shutdown(void) { while (1) { if (ivt_status() < 7) { continue; } if (battery.voltage.act < battery.voltage.nom) { continue; } /* Hmmm, why was this an exit-case before? fatalx(EXIT_SUCCESS...) */ upslogx(LOG_ERR, "Power is back!"); set_exit_flag(-2); /* EXIT_SUCCESS */ return; } } void upsdrv_help(void) { } void upsdrv_makevartable(void) { } void upsdrv_initups(void) { struct termios tio; const char *val; upsfd = ser_open(device_path); ser_set_speed(upsfd, device_path, B1200); if (tcgetattr(upsfd, &tio)) { fatal_with_errno(EXIT_FAILURE, "tcgetattr"); } /* * Use canonical mode input processing (to read reply line) */ tio.c_lflag |= ICANON; /* Canonical input (erase and kill processing) */ tio.c_iflag |= IGNCR; /* Ignore CR */ tio.c_iflag |= IGNBRK; /* Ignore break condition */ tio.c_oflag |= ONLCR; /* Map NL to CR-NL on output */ tio.c_cc[VEOF] = _POSIX_VDISABLE; tio.c_cc[VEOL] = _POSIX_VDISABLE; tio.c_cc[VERASE] = _POSIX_VDISABLE; tio.c_cc[VINTR] = _POSIX_VDISABLE; tio.c_cc[VKILL] = _POSIX_VDISABLE; tio.c_cc[VQUIT] = _POSIX_VDISABLE; tio.c_cc[VSUSP] = _POSIX_VDISABLE; tio.c_cc[VSTART] = _POSIX_VDISABLE; tio.c_cc[VSTOP] = _POSIX_VDISABLE; if (tcsetattr(upsfd, TCSANOW, &tio)) { fatal_with_errno(EXIT_FAILURE, "tcsetattr"); } /* * Set DTR and clear RTS to provide power for the serial interface. */ ser_set_dtr(upsfd, 1); ser_set_rts(upsfd, 0); val = dstate_getinfo("battery.voltage.nominal"); battery.voltage.nom = (val) ? strtod(val, NULL) : 12.00; val = dstate_getinfo("battery.voltage.low"); battery.voltage.low = (val) ? strtod(val, NULL) : 10.80; if (battery.voltage.nom <= battery.voltage.low) { fatalx(EXIT_FAILURE, "Nominal battery voltage must be higher than low battery voltage!"); } } void upsdrv_cleanup(void) { ser_set_dtr(upsfd, 0); ser_close(upsfd, device_path); } nut-2.8.1/drivers/libusb0.c0000644000175000017500000006724514502253356012456 00000000000000/*! * @file libusb0.c * @brief HID Library - Generic USB communication sub driver (using libusb 0.1) * * @author Copyright (C) * 2003 - 2007 Arnaud Quette * 2005 - 2007 Peter Selinger * * This program is sponsored by MGE UPS SYSTEMS - opensource.mgeups.com * * The logic of this file is ripped from mge-shut driver (also from * Arnaud Quette), which is a "HID over serial link" UPS driver for * Network UPS Tools * * 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 2 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, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * * -------------------------------------------------------------------------- */ #include "config.h" /* for HAVE_USB_DETACH_KERNEL_DRIVER_NP flag */ #include "common.h" /* for xmalloc, upsdebugx prototypes */ #include "usb-common.h" #include "nut_libusb.h" #ifdef WIN32 #include "wincompat.h" #endif #define USB_DRIVER_NAME "USB communication driver (libusb 0.1)" #define USB_DRIVER_VERSION "0.45" /* driver description structure */ upsdrv_info_t comm_upsdrv_info = { USB_DRIVER_NAME, USB_DRIVER_VERSION, NULL, 0, { NULL } }; #define MAX_REPORT_SIZE 0x1800 #define MAX_RETRY 3 #if (!HAVE_STRCASESTR) && (HAVE_STRSTR && HAVE_STRLWR && HAVE_STRDUP) /* Only used in this file of all NUT codebase, so not in str.{c,h} * where it happens to conflict with netsnmp-provided variant for * some of our build products. */ static char *strcasestr(const char *haystack, const char *needle); #endif static void libusb_close(usb_dev_handle *udev); /*! Add USB-related driver variables with addvar() and dstate_setinfo(). * This removes some code duplication across the USB drivers. */ void nut_usb_addvars(void) { /* allow -x vendor=X, vendorid=X, product=X, productid=X, serial=X */ addvar(VAR_VALUE, "vendor", "Regular expression to match UPS Manufacturer string"); addvar(VAR_VALUE, "product", "Regular expression to match UPS Product string"); addvar(VAR_VALUE, "serial", "Regular expression to match UPS Serial number"); addvar(VAR_VALUE, "vendorid", "Regular expression to match UPS Manufacturer numerical ID (4 digits hexadecimal)"); addvar(VAR_VALUE, "productid", "Regular expression to match UPS Product numerical ID (4 digits hexadecimal)"); addvar(VAR_VALUE, "bus", "Regular expression to match USB bus name"); addvar(VAR_VALUE, "device", "Regular expression to match USB device name"); /* Not supported by libusb0, but let's not crash config * parsing on unknown keywords due to such nuances! :) */ addvar(VAR_VALUE, "busport", "Regular expression to match USB bus port name" " (tolerated but ignored in this build)" ); /* Warning: this feature is inherently non-deterministic! * If you only care to know that at least one of your no-name UPSes is online, * this option can help. If you must really know which one, it will not! */ addvar(VAR_FLAG, "allow_duplicates", "If you have several UPS devices which may not be uniquely " "identified by options above, allow each driver instance with this " "option to take the first match if available, or try another " "(association of driver to device may vary between runs)"); addvar(VAR_VALUE, "usb_set_altinterface", "Force redundant call to usb_set_altinterface() (value=bAlternateSetting; default=0)"); dstate_setinfo("driver.version.usb", "libusb-0.1 (or compat)"); } /* From usbutils: workaround libusb (0.1) API goofs: * "byte" should never be sign extended; * using "char" is trouble. * Likewise, sizes should never be negative. */ /* static inline int typesafe_control_msg(usb_dev_handle *dev, unsigned char requesttype, unsigned char request, int value, int index, unsigned char *bytes, unsigned size, int timeout) { return usb_control_msg(dev, requesttype, request, value, index, (char *) bytes, (int) size, timeout); } */ static inline int typesafe_control_msg( usb_dev_handle *dev, unsigned char requesttype, unsigned char request, int value, int index, usb_ctrl_charbuf bytes, usb_ctrl_charbufsize size, usb_ctrl_timeout_msec timeout) { return usb_control_msg(dev, requesttype, request, value, index, (char *) bytes, (int) size, timeout); } /* invoke matcher against device */ static inline int matches(USBDeviceMatcher_t *matcher, USBDevice_t *device) { if (!matcher) { return 1; } return matcher->match_function(device, matcher->privdata); } /*! If needed, set the USB alternate interface. * * In NUT 2.7.2 and earlier, the following call was made unconditionally: * usb_set_altinterface(udev, 0); * * Although harmless on Linux and *BSD, this extra call prevents old Tripp Lite * devices from working on Mac OS X (presumably the OS is already setting * altinterface to 0). */ static int nut_usb_set_altinterface(usb_dev_handle *udev) { int altinterface = 0, ret = 0; char *alt_string, *endp = NULL; if(testvar("usb_set_altinterface")) { alt_string = getval("usb_set_altinterface"); if(alt_string) { altinterface = (int)strtol(alt_string, &endp, 10); if(endp && !(endp[0] == 0)) { upslogx(LOG_WARNING, "%s: '%s' is not a valid number", __func__, alt_string); } if(altinterface < 0 || altinterface > 255) { upslogx(LOG_WARNING, "%s: setting bAlternateInterface to %d will probably not work", __func__, altinterface); } } /* set default interface */ upsdebugx(2, "%s: calling usb_set_altinterface(udev, %d)", __func__, altinterface); ret = usb_set_altinterface(udev, altinterface); if(ret != 0) { upslogx(LOG_WARNING, "%s: usb_set_altinterface(udev, %d) returned %d (%s)", __func__, altinterface, ret, usb_strerror() ); } upslogx(LOG_NOTICE, "%s: usb_set_altinterface() should not be necessary - " "please email the nut-upsdev list with information about your UPS.", __func__); } else { upsdebugx(3, "%s: skipped usb_set_altinterface(udev, 0)", __func__); } return ret; } #define usb_control_msg typesafe_control_msg /* On success, fill in the curDevice structure and return the report * descriptor length. On failure, return -1. * Note: When callback is not NULL, the report descriptor will be * passed to this function together with the udev and USBDevice_t * information. This callback should return a value > 0 if the device * is accepted, or < 1 if not. If it isn't accepted, the next device * (if any) will be tried, until there are no more devices left. */ static int libusb_open(usb_dev_handle **udevp, USBDevice_t *curDevice, USBDeviceMatcher_t *matcher, int (*callback)(usb_dev_handle *udev, USBDevice_t *hd, usb_ctrl_charbuf rdbuf, usb_ctrl_charbufsize rdlen) ) { int retries; usb_ctrl_charbufsize rdlen1, rdlen2; /* report descriptor length, method 1+2 */ USBDeviceMatcher_t *m; struct usb_device *dev; struct usb_bus *bus; usb_dev_handle *udev; struct usb_interface_descriptor *iface; int ret, res; usb_ctrl_char buf[20]; usb_ctrl_char *p; char string[256]; int i; int count_open_EACCESS = 0; int count_open_errors = 0; int count_open_attempts = 0; /* report descriptor */ usb_ctrl_char rdbuf[MAX_REPORT_SIZE]; usb_ctrl_charbufsize rdlen; struct usb_bus *busses; /* libusb base init */ usb_init(); usb_find_busses(); usb_find_devices(); #ifdef WIN32 busses = usb_get_busses(); #else /* libusb built-in; not sure why original NUT for WIN32 * code differed or if it is actually better? Or why * this was not tackled in a few other files for USB?.. */ busses = usb_busses; #endif #ifndef __linux__ /* SUN_LIBUSB (confirmed to work on Solaris and FreeBSD) */ /* Causes a double free corruption in linux if device is detached! */ libusb_close(*udevp); #endif upsdebugx(3, "usb_busses=%p", (void*)usb_busses); for (bus = busses; bus; bus = bus->next) { for (dev = bus->devices; dev; dev = dev->next) { /* int if_claimed = 0; */ count_open_attempts++; upsdebugx(2, "Checking device (%04X/%04X) (%s/%s)", dev->descriptor.idVendor, dev->descriptor.idProduct, bus->dirname, dev->filename); /* supported vendors are now checked by the supplied matcher */ /* open the device */ *udevp = udev = usb_open(dev); if (!udev) { /* It seems that with libusb-0.1 API we * can only evaluate the string value of * usb_strerror() return values - in the * library source there is magic about * tracking errors in their string buffer * or as a printable errno, and no reliably * usable way to learn of an EACCESS or * other situation diagnostics otherwise. * So we have to search for sub-strings * and hope for locale to be right... */ char *libusb_error = usb_strerror(); upsdebugx(1, "Failed to open device (%04X/%04X), skipping: %s", dev->descriptor.idVendor, dev->descriptor.idProduct, libusb_error); count_open_errors++; if (strcasestr(libusb_error, "Access denied") || strcasestr(libusb_error, "insufficient permissions") ) { count_open_EACCESS++; } continue; } /* collect the identifying information of this device. Note that this is safe, because there's no need to claim an interface for this (and therefore we do not yet need to detach any kernel drivers). */ free(curDevice->Vendor); free(curDevice->Product); free(curDevice->Serial); free(curDevice->Bus); free(curDevice->Device); #if (defined WITH_USB_BUSPORT) && (WITH_USB_BUSPORT) free(curDevice->BusPort); #endif memset(curDevice, '\0', sizeof(*curDevice)); /* Keep the list of items in sync with those matched by * drivers/libusb1.c and tools/nut-scanner/scan_usb.c: */ curDevice->VendorID = dev->descriptor.idVendor; curDevice->ProductID = dev->descriptor.idProduct; curDevice->Bus = xstrdup(bus->dirname); curDevice->Device = xstrdup(dev->filename); curDevice->bcdDevice = dev->descriptor.bcdDevice; #if (defined WITH_USB_BUSPORT) && (WITH_USB_BUSPORT) curDevice->BusPort = (char *)malloc(4); if (curDevice->BusPort == NULL) { fatal_with_errno(EXIT_FAILURE, "Out of memory"); } upsdebugx(2, "%s: NOTE: BusPort is always zero with libusb0", __func__); sprintf(curDevice->BusPort, "%03d", 0); #endif if (dev->descriptor.iManufacturer) { retries = MAX_RETRY; while (retries > 0) { ret = usb_get_string_simple(udev, dev->descriptor.iManufacturer, string, sizeof(string)); if (ret > 0) { curDevice->Vendor = xstrdup(string); break; } retries--; upsdebugx(1, "%s get iManufacturer failed, retrying...", __func__); } } if (dev->descriptor.iProduct) { retries = MAX_RETRY; while (retries > 0) { ret = usb_get_string_simple(udev, dev->descriptor.iProduct, string, sizeof(string)); if (ret > 0) { curDevice->Product = xstrdup(string); break; } retries--; upsdebugx(1, "%s get iProduct failed, retrying...", __func__); } } if (dev->descriptor.iSerialNumber) { retries = MAX_RETRY; while (retries > 0) { ret = usb_get_string_simple(udev, dev->descriptor.iSerialNumber, string, sizeof(string)); if (ret > 0) { curDevice->Serial = xstrdup(string); break; } retries--; upsdebugx(1, "%s get iSerialNumber failed, retrying...", __func__); } } upsdebugx(2, "- VendorID: %04x", curDevice->VendorID); upsdebugx(2, "- ProductID: %04x", curDevice->ProductID); upsdebugx(2, "- Manufacturer: %s", curDevice->Vendor ? curDevice->Vendor : "unknown"); upsdebugx(2, "- Product: %s", curDevice->Product ? curDevice->Product : "unknown"); upsdebugx(2, "- Serial Number: %s", curDevice->Serial ? curDevice->Serial : "unknown"); upsdebugx(2, "- Bus: %s", curDevice->Bus ? curDevice->Bus : "unknown"); upsdebugx(2, "- Device: %s", curDevice->Device ? curDevice->Device : "unknown"); #if (defined WITH_USB_BUSPORT) && (WITH_USB_BUSPORT) upsdebugx(2, "- Bus Port: %s", curDevice->BusPort ? curDevice->BusPort : "unknown"); #endif upsdebugx(2, "- Device release number: %04x", curDevice->bcdDevice); /* FIXME: extend to Eaton OEMs (HP, IBM, ...) */ if ((curDevice->VendorID == 0x463) && (curDevice->bcdDevice == 0x0202)) { usb_subdriver.hid_desc_index = 1; } upsdebugx(2, "Trying to match device"); for (m = matcher; m; m=m->next) { ret = matches(m, curDevice); if (ret==0) { upsdebugx(2, "Device does not match - skipping"); goto next_device; } else if (ret==-1) { fatal_with_errno(EXIT_FAILURE, "matcher"); #ifndef HAVE___ATTRIBUTE__NORETURN # if (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_PUSH_POP) && (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_UNREACHABLE_CODE) # pragma GCC diagnostic push # pragma GCC diagnostic ignored "-Wunreachable-code" # endif goto next_device; # if (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_PUSH_POP) && (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_UNREACHABLE_CODE) # pragma GCC diagnostic pop # endif #endif } else if (ret==-2) { upsdebugx(2, "matcher: unspecified error"); goto next_device; } } /* If we got here, none of the matchers said * that the device is not what we want. */ upsdebugx(2, "Device matches"); /* Now we have matched the device we wanted. Claim it. */ #ifdef HAVE_USB_DETACH_KERNEL_DRIVER_NP /* this method requires at least libusb 0.1.8: * it force device claiming by unbinding * attached driver... From libhid */ retries = MAX_RETRY; #ifdef WIN32 usb_set_configuration(udev, 1); #endif while ((ret = usb_claim_interface(udev, usb_subdriver.hid_rep_index)) < 0) { upsdebugx(2, "failed to claim USB device: %s", usb_strerror()); if (ret == LIBUSB_ERROR_BUSY && testvar("allow_duplicates")) { upsdebugx(2, "Configured to allow_duplicates so looking for another similar device"); goto next_device; } if (usb_detach_kernel_driver_np(udev, usb_subdriver.hid_rep_index) < 0) { upsdebugx(2, "failed to detach kernel driver from USB device: %s", usb_strerror()); } else { upsdebugx(2, "detached kernel driver from USB device..."); } if (retries-- > 0) { continue; } fatalx(EXIT_FAILURE, "Can't claim USB device [%04x:%04x]@%d/%d: %s", curDevice->VendorID, curDevice->ProductID, usb_subdriver.hid_rep_index, usb_subdriver.hid_desc_index, usb_strerror()); } #else if ((ret = usb_claim_interface(udev, usb_subdriver.hid_rep_index)) < 0) { if (ret == LIBUSB_ERROR_BUSY && testvar("allow_duplicates")) { upsdebugx(2, "Configured to allow_duplicates so looking for another similar device"); goto next_device; } fatalx(EXIT_FAILURE, "Can't claim USB device [%04x:%04x]@%d/%d: %s", curDevice->VendorID, curDevice->ProductID, usb_subdriver.hid_rep_index, usb_subdriver.hid_desc_index, usb_strerror()); } #endif /* if_claimed = 1; */ nut_usb_set_altinterface(udev); if (!callback) { return 1; } if (!dev->config) { /* ?? this should never happen */ upsdebugx(2, " Couldn't retrieve descriptors"); goto next_device; } rdlen1 = -1; rdlen2 = -1; /* Get HID descriptor */ /* FIRST METHOD: ask for HID descriptor directly. */ /* res = usb_get_descriptor(udev, USB_DT_HID, hid_desc_index, buf, 0x9); */ res = usb_control_msg(udev, USB_ENDPOINT_IN + 1, USB_REQ_GET_DESCRIPTOR, (USB_DT_HID << 8) + usb_subdriver.hid_desc_index, usb_subdriver.hid_rep_index, buf, 0x9, USB_TIMEOUT); if (res < 0) { upsdebugx(2, "Unable to get HID descriptor (%s)", usb_strerror()); } else if (res < 9) { upsdebugx(2, "HID descriptor too short (expected %d, got %d)", 9, res); } else { upsdebugx(2, "Retrieved HID descriptor (expected %d, got %d)", 9, res); upsdebug_hex(3, "HID descriptor, method 1", buf, 9); rdlen1 = ((uint8_t)buf[7]) | (((uint8_t)buf[8]) << 8); } if (rdlen1 < -1) { upsdebugx(2, "Warning: HID descriptor, method 1 failed"); } upsdebugx(3, "HID descriptor length (method 1) %" PRI_NUT_USB_CTRL_CHARBUFSIZE, rdlen1); /* SECOND METHOD: find HID descriptor among "extra" bytes of interface descriptor, i.e., bytes tucked onto the end of descriptor 2. */ /* Note: on some broken UPS's (e.g. Tripp Lite Smart1000LCD), only this second method gives the correct result */ /* for now, we always assume configuration 0, interface 0, altsetting 0, as above. */ iface = &dev->config[0].interface[usb_subdriver.hid_rep_index].altsetting[0]; for (i=0; iextralen; i+=iface->extra[i]) { upsdebugx(4, "i=%d, extra[i]=%02x, extra[i+1]=%02x", i, iface->extra[i], iface->extra[i+1]); if (i+9 <= iface->extralen && iface->extra[i] >= 9 && iface->extra[i+1] == 0x21 ) { p = (usb_ctrl_char *)&iface->extra[i]; upsdebug_hex(3, "HID descriptor, method 2", p, 9); rdlen2 = ((uint8_t)p[7]) | (((uint8_t)p[8]) << 8); break; } } if (rdlen2 < -1) { upsdebugx(2, "Warning: HID descriptor, method 2 failed"); } upsdebugx(3, "HID descriptor length (method 2) %" PRI_NUT_USB_CTRL_CHARBUFSIZE, rdlen2); /* when available, always choose the second value, as it seems to be more reliable (it is the one reported e.g. by lsusb). Note: if the need arises, can change this to use the maximum of the two values instead. */ if ((curDevice->VendorID == 0x463) && (curDevice->bcdDevice == 0x0202)) { upsdebugx(1, "Eaton device v2.02. Using full report descriptor"); rdlen = rdlen1; } else { rdlen = rdlen2 >= 0 ? rdlen2 : rdlen1; } if (rdlen < 0) { upsdebugx(2, "Unable to retrieve any HID descriptor"); goto next_device; } if (rdlen1 >= 0 && rdlen2 >= 0 && rdlen1 != rdlen2) { upsdebugx(2, "Warning: two different HID descriptors retrieved " "(Reportlen = %" PRI_NUT_USB_CTRL_CHARBUFSIZE " vs. %" PRI_NUT_USB_CTRL_CHARBUFSIZE ")", rdlen1, rdlen2); } upsdebugx(2, "HID descriptor length %" PRI_NUT_USB_CTRL_CHARBUFSIZE, rdlen); if ((uintmax_t)rdlen > sizeof(rdbuf)) { upsdebugx(2, "HID descriptor too long %" PRI_NUT_USB_CTRL_CHARBUFSIZE " (max %" PRIuSIZE ")", rdlen, sizeof(rdbuf)); goto next_device; } /* Note: rdlen is safe to cast to unsigned below, * since the <0 case was ruled out above */ /* res = usb_get_descriptor(udev, USB_DT_REPORT, hid_desc_index, bigbuf, rdlen); */ res = usb_control_msg(udev, USB_ENDPOINT_IN + 1, USB_REQ_GET_DESCRIPTOR, (USB_DT_REPORT << 8) + usb_subdriver.hid_desc_index, usb_subdriver.hid_rep_index, rdbuf, rdlen, USB_TIMEOUT); if (res < 0) { upsdebug_with_errno(2, "Unable to get Report descriptor"); goto next_device; } if (res < rdlen) { #ifndef WIN32 upsdebugx(2, "Warning: report descriptor too short " "(expected %" PRI_NUT_USB_CTRL_CHARBUFSIZE ", got %d)", rdlen, res); #else /* https://github.com/networkupstools/nut/issues/1690#issuecomment-1455206002 */ upsdebugx(0, "Warning: report descriptor too short " "(expected %" PRI_NUT_USB_CTRL_CHARBUFSIZE ", got %d)", rdlen, res); upsdebugx(0, "Please check your Windows Device Manager: " "perhaps the UPS was recognized by default OS\n" "driver such as HID UPS Battery (hidbatt.sys, " "hidusb.sys or similar). It could have been\n" "\"restored\" by Windows Update. You can try " "https://zadig.akeo.ie/ to handle it with\n" "either WinUSB, libusb0.sys or libusbK.sys."); #endif /* WIN32 */ rdlen = res; /* correct rdlen if necessary */ } res = callback(udev, curDevice, rdbuf, rdlen); if (res < 1) { upsdebugx(2, "Caller doesn't like this device"); goto next_device; } upsdebugx(2, "Report descriptor retrieved (Reportlen = %" PRI_NUT_USB_CTRL_CHARBUFSIZE ")", rdlen); upsdebugx(2, "Found HID device"); fflush(stdout); return rdlen; next_device: /* usb_release_interface() sometimes blocks * and goes into uninterruptible sleep. * So don't do it. */ /* if (if_claimed) usb_release_interface(udev, 0); */ usb_close(udev); } } *udevp = NULL; upsdebugx(2, "libusb0: No appropriate HID device found"); fflush(stdout); if (count_open_attempts == 0) { upslogx(LOG_WARNING, "libusb0: Could not open any HID devices: " "no USB buses found"); } else if (count_open_errors > 0 && count_open_errors == count_open_EACCESS ) { upslogx(LOG_WARNING, "libusb0: Could not open any HID devices: " "insufficient permissions on everything"); } return -1; } /* * Error handler for usb_get/set_* functions. Return value > 0 success, * 0 unknown or temporary failure (ignored), < 0 permanent failure (reconnect) */ static int libusb_strerror(const int ret, const char *desc) { if (ret > 0) { return ret; } switch(ret) { case -EBUSY: /* Device or resource busy */ case -EPERM: /* Operation not permitted */ case -ENODEV: /* No such device */ case -EACCES: /* Permission denied */ case -EIO: /* I/O error */ case -ENXIO: /* No such device or address */ case -ENOENT: /* No such file or directory */ case -EPIPE: /* Broken pipe */ case -ENOSYS: /* Function not implemented */ upslogx(LOG_DEBUG, "%s: %s", desc, usb_strerror()); return ret; case -ETIMEDOUT: /* Connection timed out */ upsdebugx(2, "%s: Connection timed out", desc); return 0; /* libusb-win32 does not know EPROTO and EOVERFLOW, * it only returns EIO for any IO errors */ #ifndef WIN32 case -EOVERFLOW: /* Value too large for defined data type */ # ifdef EPROTO case -EPROTO: /* Protocol error */ # endif upsdebugx(2, "%s: %s", desc, usb_strerror()); return 0; #endif /* WIN32 */ default: /* Undetermined, log only */ upslogx(LOG_DEBUG, "%s: %s", desc, usb_strerror()); return 0; } } /* return the report of ID=type in report * return -1 on failure, report length on success */ /* Expected evaluated types for the API: * static int libusb_get_report(usb_dev_handle *udev, * int ReportId, unsigned char *raw_buf, int ReportSize) */ static int libusb_get_report( usb_dev_handle *udev, usb_ctrl_repindex ReportId, usb_ctrl_charbuf raw_buf, usb_ctrl_charbufsize ReportSize) { int ret; upsdebugx(4, "Entering libusb_get_report"); if (!udev) { return 0; } ret = usb_control_msg(udev, USB_ENDPOINT_IN + USB_TYPE_CLASS + USB_RECIP_INTERFACE, 0x01, /* HID_REPORT_GET */ ReportId+(0x03<<8), /* HID_REPORT_TYPE_FEATURE */ usb_subdriver.hid_rep_index, raw_buf, ReportSize, USB_TIMEOUT); #ifdef WIN32 errno = -ret; #endif /* Ignore "protocol stall" (for unsupported request) on control endpoint */ if (ret == -EPIPE) { return 0; } return libusb_strerror(ret, __func__); } /* Expected evaluated types for the API: * static int libusb_set_report(usb_dev_handle *udev, * int ReportId, unsigned char *raw_buf, int ReportSize) */ static int libusb_set_report( usb_dev_handle *udev, usb_ctrl_repindex ReportId, usb_ctrl_charbuf raw_buf, usb_ctrl_charbufsize ReportSize) { int ret; if (!udev) { return 0; } ret = usb_control_msg(udev, USB_ENDPOINT_OUT + USB_TYPE_CLASS + USB_RECIP_INTERFACE, 0x09, /* HID_REPORT_SET = 0x09*/ ReportId+(0x03<<8), /* HID_REPORT_TYPE_FEATURE */ usb_subdriver.hid_rep_index, raw_buf, ReportSize, USB_TIMEOUT); #ifdef WIN32 errno = -ret; #endif /* Ignore "protocol stall" (for unsupported request) on control endpoint */ if (ret == -EPIPE) { return 0; } return libusb_strerror(ret, __func__); } /* Expected evaluated types for the API: * static int libusb_get_string(usb_dev_handle *udev, * int StringIdx, char *buf, size_t buflen) */ static int libusb_get_string( usb_dev_handle *udev, usb_ctrl_strindex StringIdx, char *buf, usb_ctrl_charbufsize buflen) { int ret; #if (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_PUSH_POP) && ( (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_TYPE_LIMITS) || (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_TAUTOLOGICAL_CONSTANT_OUT_OF_RANGE_COMPARE) || (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_TAUTOLOGICAL_UNSIGNED_ZERO_COMPARE) ) # pragma GCC diagnostic push #endif #ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_TYPE_LIMITS # pragma GCC diagnostic ignored "-Wtype-limits" #endif #ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_TAUTOLOGICAL_CONSTANT_OUT_OF_RANGE_COMPARE # pragma GCC diagnostic ignored "-Wtautological-constant-out-of-range-compare" #endif #ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_TAUTOLOGICAL_UNSIGNED_ZERO_COMPARE # pragma GCC diagnostic ignored "-Wtautological-unsigned-zero-compare" #endif /* * usb.h:int usb_get_string_simple(usb_dev_handle *dev, int index, * usb.h- char *buf, size_t buflen); */ if (!udev || StringIdx < 0 || (uintmax_t)StringIdx > INT_MAX || buflen < 0 || (uintmax_t)buflen > (uintmax_t)SIZE_MAX ) { #if (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_PUSH_POP) && ( (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_TYPE_LIMITS) || (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_TAUTOLOGICAL_CONSTANT_OUT_OF_RANGE_COMPARE) || (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_TAUTOLOGICAL_UNSIGNED_ZERO_COMPARE) ) # pragma GCC diagnostic pop #endif return -1; } ret = usb_get_string_simple(udev, StringIdx, buf, (size_t)buflen); #ifdef WIN32 errno = -ret; #endif return libusb_strerror(ret, __func__); } /* Expected evaluated types for the API: * static int libusb_get_interrupt(usb_dev_handle *udev, * unsigned char *buf, int bufsize, int timeout) */ static int libusb_get_interrupt( usb_dev_handle *udev, usb_ctrl_charbuf buf, usb_ctrl_charbufsize bufsize, usb_ctrl_timeout_msec timeout) { int ret; if (!udev) { return -1; } /* Interrupt EP is USB_ENDPOINT_IN with offset defined in hid_ep_in, which is 0 by default, unless overridden in subdriver. */ ret = usb_interrupt_read(udev, USB_ENDPOINT_IN + usb_subdriver.hid_ep_in, (char *)buf, bufsize, timeout); #ifdef WIN32 errno = -ret; #endif /* Clear stall condition */ if (ret == -EPIPE) { ret = usb_clear_halt(udev, 0x81); } return libusb_strerror(ret, __func__); } static void libusb_close(usb_dev_handle *udev) { if (!udev) { return; } /* usb_release_interface() sometimes blocks and goes * into uninterruptible sleep. So don't do it. */ /* usb_release_interface(udev, 0); */ usb_close(udev); } #if (!HAVE_STRCASESTR) && (HAVE_STRSTR && HAVE_STRLWR && HAVE_STRDUP) static char *strcasestr(const char *haystack, const char *needle) { /* work around "const char *" and guarantee the original is not * touched... not efficient but we have few uses for this method */ char * dH = NULL, *dN = NULL, *lH = NULL, *lN = NULL, *first = NULL; dH = strdup(haystack); if (dH == NULL) goto err; dN = strdup(needle); if (dN == NULL) goto err; lH = strlwr(dH); if (lH == NULL) goto err; lN = strlwr(dN); if (lN == NULL) goto err; first = strstr(lH, lN); err: if (dH != NULL) free(dH); if (dN != NULL) free(dN); /* Does this implementation of strlwr() change original buffer? */ if (lH != dH && lH != NULL) free(lH); if (lN != dN && lN != NULL) free(lN); if (first == NULL) { return NULL; } /* Pointer to first char of the needle found in original haystack */ return (char *)(haystack + (first - lH)); } #endif usb_communication_subdriver_t usb_subdriver = { USB_DRIVER_NAME, USB_DRIVER_VERSION, libusb_open, libusb_close, libusb_get_report, libusb_set_report, libusb_get_string, libusb_get_interrupt, LIBUSB_DEFAULT_INTERFACE, LIBUSB_DEFAULT_DESC_INDEX, LIBUSB_DEFAULT_HID_EP_IN, LIBUSB_DEFAULT_HID_EP_OUT }; nut-2.8.1/drivers/powercom-hid.h0000644000175000017500000000217614273170601013504 00000000000000/* powercom-hid.h - subdriver to monitor PowerCOM USB/HID devices with NUT * * Copyright (C) * 2003 - 2009 Arnaud Quette * 2005 - 2006 Peter Selinger * 2008 - 2009 Arjen de Korte * * 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 2 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, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef POWERCOM_HID_H #define POWERCOM_HID_H #include "usbhid-ups.h" extern subdriver_t powercom_subdriver; #endif /* POWERCOM_HID_H */ nut-2.8.1/drivers/libshut.h0000644000175000017500000001607214501607135012562 00000000000000/*! * @file libshut.h * @brief HID Library - Generic serial SHUT backend for Generic HID Access (using MGE HIDParser) * SHUT stands for Serial HID UPS Transfer, and was created by MGE UPS SYSTEMS * * @author Copyright (C) 2006 - 2007 * Arnaud Quette * * This program is sponsored by MGE UPS SYSTEMS - opensource.mgeups.com * * 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 2 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, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * * -------------------------------------------------------------------------- */ #ifndef NUT_LIBSHUT_H_SEEN #define NUT_LIBSHUT_H_SEEN 1 #include "main.h" /* for subdrv_info_t and TYPE_FD_SER via "common.h" */ #include "nut_stdint.h" /* for uint16_t, size_t, PRIuSIZE etc. */ extern upsdrv_info_t comm_upsdrv_info; /* These typedefs are also named in usb-common.h (=> nut_libusb.h), adhering * to one or another libusb API version. For consistency of "ifdef SHUT_MODE" * handling in libhid.c and some drivers, these symbolic names are used in * all the headers and are expected to match binary code of object files at * (monolithic) driver build time. * * The MIN/MAX definitions here are primarily to generalize range-check * code (especially if anything is done outside the libraries). * FIXME: It may make sense to constrain the limits to lowest common * denominator that should fit all of libusb-0.1, libusb-1.0 and libshut, * so that any build of the practical (driver) code knows to not exceed * any use-case. * * Types below were mined from existing method signatures; see also the * my_hid_descriptor struct in libshut.c for practical fixed-size types. */ /* Essentially for SHUT codebase the usb_dev_handle is the file descriptor * type, usually an "int" - as in ser_get_char() etc. on Unix-like platforms, * but a complex structure which includes a HANDLE field in Win32 builds. */ typedef TYPE_FD_SER usb_dev_handle; /* Originally "int" cast to "uint8_t" in shut_control_msg(), * and "unsigned char" in shut_get_descriptor() */ typedef unsigned char usb_ctrl_requesttype; #define USB_CTRL_REQUESTTYPE_MIN 0 #define USB_CTRL_REQUESTTYPE_MAX UCHAR_MAX typedef int usb_ctrl_request; #define USB_CTRL_REQUEST_MIN INT_MIN #define USB_CTRL_REQUEST_MAX INT_MAX typedef int usb_ctrl_endpoint; #define USB_CTRL_ENDPOINT_MIN INT_MIN #define USB_CTRL_ENDPOINT_MAX INT_MAX typedef int usb_ctrl_msgvalue; #define USB_CTRL_MSGVALUE_MIN INT_MIN #define USB_CTRL_MSGVALUE_MAX INT_MAX typedef int usb_ctrl_repindex; #define USB_CTRL_REPINDEX_MIN INT_MIN #define USB_CTRL_REPINDEX_MAX INT_MAX typedef int usb_ctrl_strindex; #define USB_CTRL_STRINDEX_MIN INT_MIN #define USB_CTRL_STRINDEX_MAX INT_MAX typedef unsigned char usb_ctrl_descindex; #define USB_CTRL_DESCINDEX_MIN 0 #define USB_CTRL_DESCINDEX_MAX UCHAR_MAX /* Here MIN/MAX should not matter much, type mostly used for casting */ typedef unsigned char* usb_ctrl_charbuf; typedef unsigned char usb_ctrl_char; #define USB_CTRL_CHAR_MIN 0 #define USB_CTRL_CHAR_MAX UCHAR_MAX typedef size_t usb_ctrl_charbufsize; /*typedef int usb_ctrl_charbufsize;*/ #define USB_CTRL_CHARBUFSIZE_MIN 0 #define USB_CTRL_CHARBUFSIZE_MAX SIZE_MAX #define PRI_NUT_USB_CTRL_CHARBUFSIZE PRIuSIZE typedef int usb_ctrl_timeout_msec; /* in milliseconds */ #define USB_CTRL_TIMEOUTMSEC_MIN INT_MIN #define USB_CTRL_TIMEOUTMSEC_MAX INT_MAX /* Same error-code definitions as in usb-common.h for libusb-0.1 API */ #define LIBUSB_ERROR_ACCESS -EACCES #define LIBUSB_ERROR_BUSY -EBUSY #define LIBUSB_ERROR_IO -EIO #define LIBUSB_ERROR_NO_DEVICE -ENODEV #define LIBUSB_ERROR_NOT_FOUND -ENOENT #define LIBUSB_ERROR_OVERFLOW -EOVERFLOW #define LIBUSB_ERROR_PIPE -EPIPE #define LIBUSB_ERROR_TIMEOUT -ETIMEDOUT #define LIBUSB_ERROR_NO_MEM -ENOMEM #define LIBUSB_ERROR_INVALID_PARAM -EINVAL #define LIBUSB_ERROR_INTERRUPTED -EINTR #define LIBUSB_ERROR_NOT_SUPPORTED -ENOSYS #define LIBUSB_ERROR_OTHER -ERANGE /*! * SHUTDevice_t: Describe a SHUT device. This structure contains exactly * the 5 or more pieces of information by which a SHUT device identifies * itself, so it serves as a kind of "fingerprint" of the device. This * information must be matched exactly when reopening a device, and * therefore must not be "improved" or updated by a client * program. Vendor, Product, and Serial can be NULL if the * corresponding string did not exist or could not be retrieved. */ typedef struct SHUTDevice_s { uint16_t VendorID; /*!< Device's Vendor ID */ uint16_t ProductID; /*!< Device's Product ID */ char* Vendor; /*!< Device's Vendor Name */ char* Product; /*!< Device's Product Name */ char* Serial; /*!< Product serial number */ char* Bus; /*!< Bus name, e.g. "003" */ uint16_t bcdDevice; /*!< Device release number */ char *Device; /*!< Device name on the bus, e.g. "001" */ #if (defined WITH_USB_BUSPORT) && (WITH_USB_BUSPORT) char *BusPort; /*!< Port name, e.g. "001" */ #endif } SHUTDevice_t; /*! * shut_communication_subdriver_s: structure to describe the communication routines */ typedef struct shut_communication_subdriver_s { const char *name; /* name of this subdriver */ const char *version; /* version of this subdriver */ int (*open_dev)(usb_dev_handle *upsfd, /* try to open the next available */ SHUTDevice_t *curDevice, /* device matching USBDeviceMatcher_t */ char *device_path, int (*callback)(usb_dev_handle upsfd, SHUTDevice_t *hd, usb_ctrl_charbuf rdbuf, usb_ctrl_charbufsize rdlen)); void (*close_dev)(usb_dev_handle upsfd); int (*get_report)(usb_dev_handle upsfd, usb_ctrl_repindex ReportId, usb_ctrl_charbuf raw_buf, usb_ctrl_charbufsize ReportSize); int (*set_report)(usb_dev_handle upsfd, usb_ctrl_repindex ReportId, usb_ctrl_charbuf raw_buf, usb_ctrl_charbufsize ReportSize); int (*get_string)(usb_dev_handle upsfd, usb_ctrl_strindex StringIdx, char *buf, usb_ctrl_charbufsize buflen); int (*get_interrupt)(usb_dev_handle upsfd, usb_ctrl_charbuf buf, usb_ctrl_charbufsize bufsize, usb_ctrl_timeout_msec timeout); } shut_communication_subdriver_t; extern shut_communication_subdriver_t shut_subdriver; /*! * Notification levels * These are however not processed currently */ #define OFF_NOTIFICATION 1 /* notification off */ #define LIGHT_NOTIFICATION 2 /* light notification */ #define COMPLETE_NOTIFICATION 3 /* complete notification for UPSs which do */ /* not support disabling it like some early */ /* Ellipse models */ #define DEFAULT_NOTIFICATION COMPLETE_NOTIFICATION #endif /* NUT_LIBSHUT_H_SEEN */ nut-2.8.1/drivers/generic_modbus.c0000644000175000017500000010444514502253356014075 00000000000000/* generic_modbus.c - Driver for generic UPS connected via modbus RIO * * Copyright (C) * 2021 Dimitris Economou * * 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 2 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, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #include "main.h" #include "generic_modbus.h" #include #include "timehead.h" #include "nut_stdint.h" #define DRIVER_NAME "NUT Generic Modbus driver" #define DRIVER_VERSION "0.04" /* variables */ static modbus_t *mbctx = NULL; /* modbus memory context */ static sigattr_t sigar[NUMOF_SIG_STATES]; /* array of ups signal attributes */ static int errcnt = 0; /* modbus access error counter */ static char *device_mfr = DEVICE_MFR; /* device manufacturer */ static char *device_model = DEVICE_MODEL; /* device model */ static int ser_baud_rate = BAUD_RATE; /* serial port baud rate */ static char ser_parity = PARITY; /* serial port parity */ static int ser_data_bit = DATA_BIT; /* serial port data bit */ static int ser_stop_bit = STOP_BIT; /* serial port stop bit */ static int rio_slave_id = MODBUS_SLAVE_ID; /* set device ID to default value */ static int FSD_pulse_duration = SHTDOWN_PULSE_DURATION; /* set the FSD pulse duration */ static uint32_t mod_resp_to_s = MODRESP_TIMEOUT_s; /* set the modbus response time out (s) */ static uint32_t mod_resp_to_us = MODRESP_TIMEOUT_us; /* set the modbus response time out (us) */ static uint32_t mod_byte_to_s = MODBYTE_TIMEOUT_s; /* set the modbus byte time out (us) */ static uint32_t mod_byte_to_us = MODBYTE_TIMEOUT_us; /* set the modbus byte time out (us) */ /* get config vars set by -x or defined in ups.conf driver section */ void get_config_vars(void); /* create a new modbus context based on connection type (serial or TCP) */ modbus_t *modbus_new(const char *port); /* reconnect upon communication error */ void modbus_reconnect(void); /* modbus register read function */ int register_read(modbus_t *mb, int addr, regtype_t type, void *data); /* instant command triggered by upsd */ int upscmd(const char *cmd, const char *arg); /* read signal status */ int get_signal_state(devstate_t state); /* count the time elapsed since start */ long time_elapsed(struct timeval *start); int register_write(modbus_t *mb, int addr, regtype_t type, void *data); /* driver description structure */ upsdrv_info_t upsdrv_info = { DRIVER_NAME, DRIVER_VERSION, "Dimitris Economou \n", DRV_BETA, {NULL} }; /* * driver functions */ /* initialize ups driver information */ void upsdrv_initinfo(void) { upsdebugx(2, "upsdrv_initinfo"); /* set device information */ dstate_setinfo("device.mfr", "%s", device_mfr); dstate_setinfo("device.model", "%s", device_model); /* register instant commands */ if (sigar[FSD_T].addr != NOTUSED) { dstate_addcmd("load.off"); } /* set callback for instant commands */ upsh.instcmd = upscmd; } /* open serial connection and connect to modbus RIO */ void upsdrv_initups(void) { int rval; upsdebugx(2, "upsdrv_initups"); get_config_vars(); /* open communication port */ mbctx = modbus_new(device_path); if (mbctx == NULL) { fatalx(EXIT_FAILURE, "modbus_new_rtu: Unable to open communication port context"); } /* set slave ID */ rval = modbus_set_slave(mbctx, rio_slave_id); if (rval < 0) { modbus_free(mbctx); fatalx(EXIT_FAILURE, "modbus_set_slave: Invalid modbus slave ID %d", rio_slave_id); } /* connect to modbus device */ if (modbus_connect(mbctx) == -1) { modbus_free(mbctx); fatalx(EXIT_FAILURE, "modbus_connect: unable to connect: error(%s)", modbus_strerror(errno)); } /* set modbus response timeout */ #if (defined NUT_MODBUS_TIMEOUT_ARG_sec_usec_uint32) || (defined NUT_MODBUS_TIMEOUT_ARG_sec_usec_uint32_cast_timeval_fields) rval = modbus_set_response_timeout(mbctx, mod_resp_to_s, mod_resp_to_us); if (rval < 0) { modbus_free(mbctx); fatalx(EXIT_FAILURE, "modbus_set_response_timeout: error(%s)", modbus_strerror(errno)); } #elif (defined NUT_MODBUS_TIMEOUT_ARG_timeval_numeric_fields) { /* Older libmodbus API (with timeval), and we have * checked at configure time that we can put uint32_t * into its fields. They are probably "long" on many * systems as respectively time_t and suseconds_t - * but that is not guaranteed; for more details see * https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/sys_time.h.html */ struct timeval to; memset(&to, 0, sizeof(struct timeval)); to.tv_sec = mod_resp_to_s; to.tv_usec = mod_resp_to_us; /* void */ modbus_set_response_timeout(mbctx, &to); } /* #elif (defined NUT_MODBUS_TIMEOUT_ARG_timeval) // some un-castable type in fields */ #else # error "Can not use libmodbus API for timeouts" #endif /* NUT_MODBUS_TIMEOUT_ARG_* */ /* set modbus byte time out */ #if (defined NUT_MODBUS_TIMEOUT_ARG_sec_usec_uint32) || (defined NUT_MODBUS_TIMEOUT_ARG_sec_usec_uint32_cast_timeval_fields) rval = modbus_set_byte_timeout(mbctx, mod_byte_to_s, mod_byte_to_us); if (rval < 0) { modbus_free(mbctx); fatalx(EXIT_FAILURE, "modbus_set_byte_timeout: error(%s)", modbus_strerror(errno)); } #elif (defined NUT_MODBUS_TIMEOUT_ARG_timeval_numeric_fields) { /* see comments above */ struct timeval to; memset(&to, 0, sizeof(struct timeval)); to.tv_sec = mod_byte_to_s; to.tv_usec = mod_byte_to_us; /* void */ modbus_set_byte_timeout(mbctx, &to); } /* #elif (defined NUT_MODBUS_TIMEOUT_ARG_timeval) // some un-castable type in fields */ #endif /* NUT_MODBUS_TIMEOUT_ARG_* */ } /* update UPS signal state */ void upsdrv_updateinfo(void) { int rval; int online = -1; /* keep online state */ errcnt = 0; upsdebugx(2, "upsdrv_updateinfo"); status_init(); /* initialize ups.status update */ alarm_init(); /* initialize ups.alarm update */ /* * update UPS status regarding MAINS state either via OL | OB. * if both statuses are mapped to contacts then only OL is evaluated. */ if (sigar[OL_T].addr != NOTUSED) { rval = get_signal_state(OL_T); upsdebugx(2, "OL value: %d", rval); if (rval == -1) { errcnt++; } else if (rval == (1 ^ sigar[OL_T].noro)) { status_set("OL"); online = 1; } else { status_set("OB"); online = 0; /* if DISCHRG state is not mapped to a contact and UPS is on * batteries set status to DISCHRG state */ if (sigar[DISCHRG_T].addr == NOTUSED) { status_set("DISCHRG"); dstate_setinfo("battery.charger.status", "discharging"); } } } else if (sigar[OB_T].addr != NOTUSED) { rval = get_signal_state(OB_T); upsdebugx(2, "OB value: %d", rval); if (rval == -1) { errcnt++; } else if (rval == (1 ^ sigar[OB_T].noro)) { status_set("OB"); online = 0; if (sigar[DISCHRG_T].addr == NOTUSED) { status_set("DISCHRG"); dstate_setinfo("battery.charger.status", "discharging"); } } else { status_set("OL"); online = 1; } } /* * update UPS status regarding CHARGING state via HB. HB is usually * mapped to "ready" contact when closed indicates a charging state > 85% */ if (sigar[HB_T].addr != NOTUSED) { rval = get_signal_state(HB_T); upsdebugx(2, "HB value: %d", rval); if (rval == -1) { errcnt++; } else if (rval == (1 ^ sigar[HB_T].noro)) { status_set("HB"); dstate_setinfo("battery.charger.status", "resting"); } else if (online == 1 && sigar[CHRG_T].addr == NOTUSED && errcnt == 0) { status_set("CHRG"); dstate_setinfo("battery.charger.status", "charging"); } else if (online == 0 && sigar[DISCHRG_T].addr == NOTUSED && errcnt == 0) { status_set("DISCHRG"); dstate_setinfo("battery.charger.status", "discharging"); } } /* * update UPS status regarding DISCHARGING state via LB. LB is mapped * to "battery low" contact. */ if (sigar[LB_T].addr != NOTUSED) { rval = get_signal_state(LB_T); upsdebugx(2, "LB value: %d", rval); if (rval == -1) { errcnt++; } else if (rval == (1 ^ sigar[LB_T].noro)) { status_set("LB"); alarm_set("Low Battery (Charge)"); } } /* * update UPS status regarding battery HEALTH state via RB. RB is mapped * to "replace battery" contact */ if (sigar[RB_T].addr != NOTUSED) { rval = get_signal_state(RB_T); upsdebugx(2, "RB value: %d", rval); if (rval == -1) { errcnt++; } else if (rval == (1 ^ sigar[RB_T].noro)) { status_set("RB"); alarm_set("Replace Battery"); } } /* * update UPS status regarding battery HEALTH state via RB. RB is mapped * to "replace battery" contact */ if (sigar[CHRG_T].addr != NOTUSED) { rval = get_signal_state(CHRG_T); upsdebugx(2, "CHRG value: %d", rval); if (rval == -1) { errcnt++; } else if (rval == (1 ^ sigar[CHRG_T].noro)) { status_set("CHRG"); dstate_setinfo("battery.charger.status", "charging"); } } else if (sigar[DISCHRG_T].addr != NOTUSED) { rval = get_signal_state(DISCHRG_T); upsdebugx(2, "DISCHRG value: %d", rval); if (rval == -1) { errcnt++; } else if (rval == (1 ^ sigar[DISCHRG_T].noro)) { status_set("DISCHRG"); dstate_setinfo("battery.charger.status", "discharging"); } } /* check for communication errors */ if (errcnt == 0) { alarm_commit(); status_commit(); dstate_dataok(); } else { upsdebugx(2,"Communication errors: %d", errcnt); dstate_datastale(); } } /* shutdown UPS */ void upsdrv_shutdown(void) { int rval; int cnt = FSD_REPEAT_CNT; /* shutdown repeat counter */ struct timeval start; long etime; /* retry sending shutdown command on error */ while ((rval = upscmd("load.off", NULL)) != STAT_INSTCMD_HANDLED && cnt > 0) { rval = gettimeofday(&start, NULL); if (rval < 0) { upslogx(LOG_ERR, "upscmd: gettimeofday: %s", strerror(errno)); } /* wait for an increasing time interval before sending shutdown command */ while ((etime = time_elapsed(&start)) < ( FSD_REPEAT_INTRV / cnt)); upsdebugx(2,"ERROR: load.off failed, wait for %lims, retries left: %d\n", etime, cnt - 1); cnt--; } switch (rval) { case STAT_INSTCMD_FAILED: case STAT_INSTCMD_INVALID: upslogx(LOG_ERR, "shutdown failed"); set_exit_flag(-1); return; case STAT_INSTCMD_UNKNOWN: upslogx(LOG_ERR, "shutdown not supported"); set_exit_flag(-1); return; default: break; } upslogx(LOG_INFO, "shutdown command executed"); } /* print driver usage info */ void upsdrv_help(void) { } /* list flags and values that you want to receive via -x */ void upsdrv_makevartable(void) { addvar(VAR_VALUE, "device_mfr", "device manufacturer"); addvar(VAR_VALUE, "device_model", "device model"); addvar(VAR_VALUE, "ser_baud_rate", "serial port baud rate"); addvar(VAR_VALUE, "ser_parity", "serial port parity"); addvar(VAR_VALUE, "ser_data_bit", "serial port data bit"); addvar(VAR_VALUE, "ser_stop_bit", "serial port stop bit"); addvar(VAR_VALUE, "rio_slave_id", "RIO modbus slave ID"); addvar(VAR_VALUE, "mod_resp_to_s", "modbus response timeout (s)"); addvar(VAR_VALUE, "mod_resp_to_us", "modbus response timeout (us)"); addvar(VAR_VALUE, "mod_byte_to_s", "modbus byte timeout (s)"); addvar(VAR_VALUE, "mod_byte_to_us", "modbus byte timeout (us)"); addvar(VAR_VALUE, "OL_addr", "modbus address for OL state"); addvar(VAR_VALUE, "OB_addr", "modbus address for OB state"); addvar(VAR_VALUE, "LB_addr", "modbus address for LB state"); addvar(VAR_VALUE, "HB_addr", "modbus address for HB state"); addvar(VAR_VALUE, "RB_addr", "modbus address for RB state"); addvar(VAR_VALUE, "CHRG_addr", "modbus address for CHRG state"); addvar(VAR_VALUE, "DISCHRG_addr", "modbus address for DISCHRG state"); addvar(VAR_VALUE, "FSD_addr", "modbus address for FSD command"); addvar(VAR_VALUE, "OL_regtype", "modbus register type for OL state"); addvar(VAR_VALUE, "OB_regtype", "modbus register type for OB state"); addvar(VAR_VALUE, "LB_regtype", "modbus register type for LB state"); addvar(VAR_VALUE, "HB_regtype", "modbus register type for HB state"); addvar(VAR_VALUE, "RB_regtype", "modbus register type for RB state"); addvar(VAR_VALUE, "CHRG_regtype", "modbus register type for CHRG state"); addvar(VAR_VALUE, "DISCHRG_regtype", "modbus register type for DISCHRG state"); addvar(VAR_VALUE, "FSD_regtype", "modbus register type for FSD command"); addvar(VAR_VALUE, "OL_noro", "NO/NC configuration for OL state"); addvar(VAR_VALUE, "OB_noro", "NO/NC configuration for OB state"); addvar(VAR_VALUE, "LB_noro", "NO/NC configuration for LB state"); addvar(VAR_VALUE, "HB_noro", "NO/NC configuration for HB state"); addvar(VAR_VALUE, "RB_noro", "NO/NC configuration for RB state"); addvar(VAR_VALUE, "CHRG_noro", "NO/NC configuration for CHRG state"); addvar(VAR_VALUE, "DISCHRG_noro", "NO/NC configuration for DISCHRG state"); addvar(VAR_VALUE, "FSD_noro", "NO/NC configuration for FSD state"); addvar(VAR_VALUE, "FSD_pulse_duration", "FSD pulse duration"); } /* close modbus connection and free modbus context allocated memory */ void upsdrv_cleanup(void) { if (mbctx != NULL) { modbus_close(mbctx); modbus_free(mbctx); } } /* * driver support functions */ /* Read a modbus register */ int register_read(modbus_t *mb, int addr, regtype_t type, void *data) { int rval = -1; /* register bit masks */ uint16_t mask8 = 0x000F; uint16_t mask16 = 0x00FF; switch (type) { case COIL: rval = modbus_read_bits(mb, addr, 1, (uint8_t *)data); *(uint16_t *)data = *(uint16_t *)data & mask8; break; case INPUT_B: rval = modbus_read_input_bits(mb, addr, 1, (uint8_t *)data); *(uint16_t *)data = *(uint16_t *)data & mask8; break; case INPUT_R: rval = modbus_read_input_registers(mb, addr, 1, (uint16_t *)data); *(uint16_t *)data = *(uint16_t *)data & mask16; break; case HOLDING: rval = modbus_read_registers(mb, addr, 1, (uint16_t *)data); *(uint16_t *)data = *(uint16_t *)data & mask16; break; #if (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_PUSH_POP) && ( (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_COVERED_SWITCH_DEFAULT) || (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_UNREACHABLE_CODE) ) # pragma GCC diagnostic push #endif #ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_COVERED_SWITCH_DEFAULT # pragma GCC diagnostic ignored "-Wcovered-switch-default" #endif #ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_UNREACHABLE_CODE # pragma GCC diagnostic ignored "-Wunreachable-code" #endif /* Older CLANG (e.g. clang-3.4) seems to not support the GCC pragmas above */ #ifdef __clang__ # pragma clang diagnostic push # pragma clang diagnostic ignored "-Wunreachable-code" # pragma clang diagnostic ignored "-Wcovered-switch-default" #endif /* All enum cases defined as of the time of coding * have been covered above. Handle later definitions, * memory corruptions and buggy inputs below... */ default: upsdebugx(2,"ERROR: register_read: invalid register type %d\n", type); break; #ifdef __clang__ # pragma clang diagnostic pop #endif #if (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_PUSH_POP) && ( (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_COVERED_SWITCH_DEFAULT) || (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_UNREACHABLE_CODE) ) # pragma GCC diagnostic pop #endif } if (rval == -1) { upslogx(LOG_ERR,"ERROR:(%s) modbus_read: addr:0x%x, type:%8s, path:%s\n", modbus_strerror(errno), addr, (type == COIL) ? "COIL" : (type == INPUT_B) ? "INPUT_B" : (type == INPUT_R) ? "INPUT_R" : "HOLDING", device_path ); /* on BROKEN PIPE error try to reconnect */ if (errno == EPIPE) { upsdebugx(2, "register_read: error(%s)", modbus_strerror(errno)); modbus_reconnect(); } } upsdebugx(3, "register addr: 0x%x, register type: %d read: %u",addr, type, *(unsigned int *)data); return rval; } /* write a modbus register */ int register_write(modbus_t *mb, int addr, regtype_t type, void *data) { int rval = -1; /* register bit masks */ uint16_t mask8 = 0x000F; uint16_t mask16 = 0x00FF; switch (type) { case COIL: *(uint16_t *)data = *(uint16_t *)data & mask8; rval = modbus_write_bit(mb, addr, *(uint8_t *)data); break; case HOLDING: *(uint16_t *)data = *(uint16_t *)data & mask16; rval = modbus_write_register(mb, addr, *(uint16_t *)data); break; case INPUT_B: case INPUT_R: #if (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_PUSH_POP) && (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_COVERED_SWITCH_DEFAULT) # pragma GCC diagnostic push # pragma GCC diagnostic ignored "-Wcovered-switch-default" #endif /* All enum cases defined as of the time of coding * have been covered above. Handle later definitions, * memory corruptions and buggy inputs below... */ default: #if (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_PUSH_POP) && (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_COVERED_SWITCH_DEFAULT) # pragma GCC diagnostic pop #endif upsdebugx(2,"ERROR: register_write: invalid register type %d\n", type); break; } if (rval == -1) { upslogx(LOG_ERR,"ERROR:(%s) modbus_read: addr:0x%x, type:%8s, path:%s\n", modbus_strerror(errno), addr, (type == COIL) ? "COIL" : (type == INPUT_B) ? "INPUT_B" : (type == INPUT_R) ? "INPUT_R" : "HOLDING", device_path ); /* on BROKEN PIPE error try to reconnect */ if (errno == EPIPE) { upsdebugx(2, "register_write: error(%s)", modbus_strerror(errno)); modbus_reconnect(); } } upsdebugx(3, "register addr: 0x%x, register type: %d read: %u",addr, type, *(unsigned int *)data); return rval; } /* returns the time elapsed since start in milliseconds */ long time_elapsed(struct timeval *start) { long rval; struct timeval end; rval = gettimeofday(&end, NULL); if (rval < 0) { upslogx(LOG_ERR, "time_elapsed: %s", strerror(errno)); } if (start->tv_usec < end.tv_usec) { suseconds_t nsec = (end.tv_usec - start->tv_usec) / 1000000 + 1; end.tv_usec -= 1000000 * nsec; end.tv_sec += nsec; } if (start->tv_usec - end.tv_usec > 1000000) { suseconds_t nsec = (start->tv_usec - end.tv_usec) / 1000000; end.tv_usec += 1000000 * nsec; end.tv_sec -= nsec; } rval = (end.tv_sec - start->tv_sec) * 1000 + (end.tv_usec - start->tv_usec) / 1000; return rval; } /* instant command triggered by upsd */ int upscmd(const char *cmd, const char *arg) { int rval; int data; struct timeval start; long etime; if (!strcasecmp(cmd, "load.off")) { if (sigar[FSD_T].addr != NOTUSED && (sigar[FSD_T].type == COIL || sigar[FSD_T].type == HOLDING) ) { data = 1 ^ sigar[FSD_T].noro; rval = register_write(mbctx, sigar[FSD_T].addr, sigar[FSD_T].type, &data); if (rval == -1) { upslogx(2, "ERROR:(%s) modbus_write_register: addr:0x%08x, regtype: %d, path:%s\n", modbus_strerror(errno), sigar[FSD_T].addr, sigar[FSD_T].type, device_path ); upslogx(LOG_NOTICE, "load.off: failed (communication error) [%s] [%s]", cmd, arg); rval = STAT_INSTCMD_FAILED; } else { upsdebugx(2, "load.off: addr: 0x%x, data: %d", sigar[FSD_T].addr, data); rval = STAT_INSTCMD_HANDLED; } /* if pulse has been defined and rising edge was successful */ if (FSD_pulse_duration != NOTUSED && rval == STAT_INSTCMD_HANDLED) { rval = gettimeofday(&start, NULL); if (rval < 0) { upslogx(LOG_ERR, "upscmd: gettimeofday: %s", strerror(errno)); } /* wait for FSD_pulse_duration ms */ while ((etime = time_elapsed(&start)) < FSD_pulse_duration); data = 0 ^ sigar[FSD_T].noro; rval = register_write(mbctx, sigar[FSD_T].addr, sigar[FSD_T].type, &data); if (rval == -1) { upslogx(LOG_ERR, "ERROR:(%s) modbus_write_register: addr:0x%08x, regtype: %d, path:%s\n", modbus_strerror(errno), sigar[FSD_T].addr, sigar[FSD_T].type, device_path ); upslogx(LOG_NOTICE, "load.off: failed (communication error) [%s] [%s]", cmd, arg); rval = STAT_INSTCMD_FAILED; } else { upsdebugx(2, "load.off: addr: 0x%x, data: %d, elapsed time: %lims", sigar[FSD_T].addr, data, etime ); rval = STAT_INSTCMD_HANDLED; } } } else { upslogx(LOG_NOTICE,"load.off: failed (FSD address undefined or invalid register type) [%s] [%s]", cmd, arg ); rval = STAT_INSTCMD_FAILED; } } else { upslogx(LOG_NOTICE, "instcmd: unknown command [%s] [%s]", cmd, arg); rval = STAT_INSTCMD_UNKNOWN; } return rval; } /* read signal state from modbus RIO, returns 0|1 state or -1 on communication error */ int get_signal_state(devstate_t state) { int rval = -1; int reg_val; regtype_t rtype = 0; /* register type */ int addr = -1; /* register address */ /* assign register address and type */ switch (state) { case OL_T: addr = sigar[OL_T].addr; rtype = sigar[OL_T].type; break; case OB_T: addr = sigar[OB_T].addr; rtype = sigar[OB_T].type; break; case LB_T: addr = sigar[LB_T].addr; rtype = sigar[LB_T].type; break; case HB_T: addr = sigar[HB_T].addr; rtype = sigar[HB_T].type; break; case RB_T: addr = sigar[RB_T].addr; rtype = sigar[RB_T].type; break; case CHRG_T: addr = sigar[CHRG_T].addr; rtype = sigar[CHRG_T].type; break; case DISCHRG_T: addr = sigar[DISCHRG_T].addr; rtype = sigar[DISCHRG_T].type; break; case BYPASS_T: case CAL_T: case FSD_T: case OFF_T: case OVER_T: case TRIM_T: case BOOST_T: #if (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_PUSH_POP) && (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_COVERED_SWITCH_DEFAULT) # pragma GCC diagnostic push # pragma GCC diagnostic ignored "-Wcovered-switch-default" #endif /* All enum cases defined as of the time of coding * have been covered above. Handle later definitions, * memory corruptions and buggy inputs below... */ default: #if (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_PUSH_POP) && (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_COVERED_SWITCH_DEFAULT) # pragma GCC diagnostic pop #endif break; } rval = register_read(mbctx, addr, rtype, ®_val); if (rval > -1) { rval = reg_val; } upsdebugx(3, "get_signal_state: state: %d", reg_val); return rval; } /* get driver configuration parameters */ void get_config_vars(void) { int i; /* local index */ /* initialize sigar table */ for (i = 0; i < NUMOF_SIG_STATES; i++) { sigar[i].addr = NOTUSED; sigar[i].noro = 0; /* ON corresponds to 1 (closed contact) */ } /* check if device manufacturer is set ang get the value */ if (testvar("device_mfr")) { device_mfr = getval("device_mfr"); } upsdebugx(2, "device_mfr %s", device_mfr); /* check if device model is set ang get the value */ if (testvar("device_model")) { device_model = getval("device_model"); } upsdebugx(2, "device_model %s", device_model); /* check if serial baud rate is set ang get the value */ if (testvar("ser_baud_rate")) { ser_baud_rate = (int)strtol(getval("ser_baud_rate"), NULL, 10); } upsdebugx(2, "ser_baud_rate %d", ser_baud_rate); /* check if serial parity is set ang get the value */ if (testvar("ser_parity")) { /* Dereference the char* we get */ char *sp = getval("ser_parity"); if (sp) { /* TODO? Sanity-check the char we get? */ ser_parity = *sp; } else { upsdebugx(2, "Could not determine ser_parity, will keep default"); } } upsdebugx(2, "ser_parity %c", ser_parity); /* check if serial data bit is set ang get the value */ if (testvar("ser_data_bit")) { ser_data_bit = (int)strtol(getval("ser_data_bit"), NULL, 10); } upsdebugx(2, "ser_data_bit %d", ser_data_bit); /* check if serial stop bit is set ang get the value */ if (testvar("ser_stop_bit")) { ser_stop_bit = (int)strtol(getval("ser_stop_bit"), NULL, 10); } upsdebugx(2, "ser_stop_bit %d", ser_stop_bit); /* check if device ID is set ang get the value */ if (testvar("rio_slave_id")) { rio_slave_id = (int)strtol(getval("rio_slave_id"), NULL, 10); } upsdebugx(2, "rio_slave_id %d", rio_slave_id); /* check if response time out (s) is set ang get the value */ if (testvar("mod_resp_to_s")) { mod_resp_to_s = (uint32_t)strtol(getval("mod_resp_to_s"), NULL, 10); } upsdebugx(2, "mod_resp_to_s %d", mod_resp_to_s); /* check if response time out (us) is set ang get the value */ if (testvar("mod_resp_to_us")) { mod_resp_to_us = (uint32_t) strtol(getval("mod_resp_to_us"), NULL, 10); if (mod_resp_to_us > 999999) { fatalx(EXIT_FAILURE, "get_config_vars: Invalid mod_resp_to_us %d", mod_resp_to_us); } } upsdebugx(2, "mod_resp_to_us %d", mod_resp_to_us); /* check if byte time out (s) is set ang get the value */ if (testvar("mod_byte_to_s")) { mod_byte_to_s = (uint32_t)strtol(getval("mod_byte_to_s"), NULL, 10); } upsdebugx(2, "mod_byte_to_s %d", mod_byte_to_s); /* check if byte time out (us) is set ang get the value */ if (testvar("mod_byte_to_us")) { mod_byte_to_us = (uint32_t) strtol(getval("mod_byte_to_us"), NULL, 10); if (mod_byte_to_us > 999999) { fatalx(EXIT_FAILURE, "get_config_vars: Invalid mod_byte_to_us %d", mod_byte_to_us); } } upsdebugx(2, "mod_byte_to_us %d", mod_byte_to_us); /* check if OL address is set and get the value */ if (testvar("OL_addr")) { sigar[OL_T].addr = (int)strtol(getval("OL_addr"), NULL, 0); if (testvar("OL_noro")) { sigar[OL_T].noro = (int)strtol(getval("OL_noro"), NULL, 10); if (sigar[OL_T].noro != 1) { sigar[OL_T].noro = 0; } } } /* check if OL register type is set and get the value otherwise set to INPUT_B */ if (testvar("OL_regtype")) { sigar[OL_T].type = (unsigned int)strtol(getval("OL_regtype"), NULL, 10); if (sigar[OL_T].type < COIL || sigar[OL_T].type > HOLDING) { sigar[OL_T].type = INPUT_B; } } else { sigar[OL_T].type = INPUT_B; } /* check if OB address is set and get the value */ if (testvar("OB_addr")) { sigar[OB_T].addr = (int)strtol(getval("OB_addr"), NULL, 0); } if (testvar("OB_noro")) { sigar[OB_T].noro = (int)strtol(getval("OB_noro"), NULL, 10); if (sigar[OB_T].noro != 1) { sigar[OB_T].noro = 0; } } /* check if OB register type is set and get the value otherwise set to INPUT_B */ if (testvar("OB_regtype")) { sigar[OB_T].type = (unsigned int)strtol(getval("OB_regtype"), NULL, 10); if (sigar[OB_T].type < COIL || sigar[OB_T].type > HOLDING) { sigar[OB_T].type = INPUT_B; } } else { sigar[OB_T].type = INPUT_B; } /* check if LB address is set and get the value */ if (testvar("LB_addr")) { sigar[LB_T].addr = (int)strtol(getval("LB_addr"), NULL, 0); if (testvar("LB_noro")) { sigar[LB_T].noro = (int)strtol(getval("LB_noro"), NULL, 10); if (sigar[LB_T].noro != 1) { sigar[LB_T].noro = 0; } } } /* check if LB register type is set and get the value otherwise set to INPUT_B */ if (testvar("LB_regtype")) { sigar[LB_T].type = (unsigned int)strtol(getval("OB_regtype"), NULL, 10); if (sigar[LB_T].type < COIL || sigar[LB_T].type > HOLDING) { sigar[LB_T].type = INPUT_B; } } else { sigar[LB_T].type = INPUT_B; } /* check if HB address is set and get the value */ if (testvar("HB_addr")) { sigar[HB_T].addr = (int)strtol(getval("HB_addr"), NULL, 0); if (testvar("HB_noro")) { sigar[HB_T].noro = (int)strtol(getval("HB_noro"), NULL, 10); if (sigar[HB_T].noro != 1) { sigar[HB_T].noro = 0; } } } /* check if HB register type is set and get the value otherwise set to INPUT_B */ if (testvar("HB_regtype")) { sigar[HB_T].type = (unsigned int)strtol(getval("HB_regtype"), NULL, 10); if (sigar[HB_T].type < COIL || sigar[HB_T].type > HOLDING) { sigar[HB_T].type = INPUT_B; } } else { sigar[HB_T].type = INPUT_B; } /* check if RB address is set and get the value */ if (testvar("RB_addr")) { sigar[RB_T].addr = (int)strtol(getval("RB_addr"), NULL, 0); if (testvar("RB_noro")) { sigar[RB_T].noro = (int)strtol(getval("RB_noro"), NULL, 10); if (sigar[RB_T].noro != 1) { sigar[RB_T].noro = 0; } } } /* check if RB register type is set and get the value otherwise set to INPUT_B */ if (testvar("RB_regtype")) { sigar[RB_T].type = (unsigned int)strtol(getval("RB_regtype"), NULL, 10); if (sigar[RB_T].type < COIL || sigar[RB_T].type > HOLDING) { sigar[RB_T].type = INPUT_B; } } else { sigar[RB_T].type = INPUT_B; } /* check if CHRG address is set and get the value */ if (testvar("CHRG_addr")) { sigar[CHRG_T].addr = (int)strtol(getval("CHRG_addr"), NULL, 0); if (testvar("CHRG_noro")) { sigar[CHRG_T].noro = (int)strtol(getval("CHRG_noro"), NULL, 10); if (sigar[CHRG_T].noro != 1) { sigar[CHRG_T].noro = 0; } } } /* check if CHRG register type is set and get the value otherwise set to INPUT_B */ if (testvar("CHRG_regtype")) { sigar[CHRG_T].type = (unsigned int)strtol(getval("CHRG_regtype"), NULL, 10); if (sigar[CHRG_T].type < COIL || sigar[CHRG_T].type > HOLDING) { sigar[CHRG_T].type = INPUT_B; } } else { sigar[CHRG_T].type = INPUT_B; } /* check if DISCHRG address is set and get the value */ if (testvar("DISCHRG_addr")) { sigar[DISCHRG_T].addr = (int)strtol(getval("DISCHRG_addr"), NULL, 0); if (testvar("DISCHRG_noro")) { sigar[DISCHRG_T].noro = (int)strtol(getval("DISCHRG_noro"), NULL, 10); if (sigar[DISCHRG_T].noro != 1) { sigar[DISCHRG_T].noro = 0; } } } /* check if DISCHRG register type is set and get the value otherwise set to INPUT_B */ if (testvar("DISCHRG_regtype")) { sigar[DISCHRG_T].type = (unsigned int)strtol(getval("DISCHRG_regtype"), NULL, 10); if (sigar[DISCHRG_T].type < COIL || sigar[DISCHRG_T].type > HOLDING) { sigar[DISCHRG_T].type = INPUT_B; } } else { sigar[DISCHRG_T].type = INPUT_B; } /* check if FSD address is set and get the value */ if (testvar("FSD_addr")) { sigar[FSD_T].addr = (int)strtol(getval("FSD_addr"), NULL, 0); if (testvar("FSD_noro")) { sigar[FSD_T].noro = (int)strtol(getval("FSD_noro"), NULL, 10); if (sigar[FSD_T].noro != 1) { sigar[FSD_T].noro = 0; } } } /* check if FSD register type is set and get the value otherwise set to COIL */ if (testvar("FSD_regtype")) { sigar[FSD_T].type = (unsigned int)strtol(getval("FSD_regtype"), NULL, 10); if (sigar[FSD_T].type < COIL || sigar[FSD_T].type > HOLDING) { sigar[FSD_T].type = COIL; } } else { sigar[FSD_T].type = COIL; } /* check if FSD pulse duration is set and get the value */ if (testvar("FSD_pulse_duration")) { FSD_pulse_duration = (int) strtol(getval("FSD_pulse_duration"), NULL, 10); } upsdebugx(2, "FSD_pulse_duration %d", FSD_pulse_duration); /* debug loop over signal array */ for (i = 0; i < NUMOF_SIG_STATES; i++) { if (sigar[i].addr != NOTUSED) { char *signame; switch (i) { case OL_T: signame = "OL"; break; case OB_T: signame = "OB"; break; case LB_T: signame = "LB"; break; case HB_T: signame = "HB"; break; case RB_T: signame = "RB"; break; case FSD_T: signame = "FSD"; break; case CHRG_T: signame = "CHRG"; break; case DISCHRG_T: signame = "DISCHRG"; break; default: signame = "NOTUSED"; break; } upsdebugx(2, "%s, addr:0x%x, type:%d", signame, sigar[i].addr, sigar[i].type); } } } /* create a new modbus context based on connection type (serial or TCP) */ modbus_t *modbus_new(const char *port) { modbus_t *mb; char *sp; if (strstr(port, "/dev/tty") != NULL) { mb = modbus_new_rtu(port, ser_baud_rate, ser_parity, ser_data_bit, ser_stop_bit); if (mb == NULL) { upslogx(LOG_ERR, "modbus_new_rtu: Unable to open serial port context\n"); } } else if ((sp = strchr(port, ':')) != NULL) { char *tcp_port = xmalloc(sizeof(sp)); strcpy(tcp_port, sp + 1); *sp = '\0'; mb = modbus_new_tcp(port, (int)strtoul(tcp_port, NULL, 10)); if (mb == NULL) { upslogx(LOG_ERR, "modbus_new_tcp: Unable to connect to %s\n", port); } free(tcp_port); } else { mb = modbus_new_tcp(port, 502); if (mb == NULL) { upslogx(LOG_ERR, "modbus_new_tcp: Unable to connect to %s\n", port); } } return mb; } /* reconnect to modbus server upon connection error */ void modbus_reconnect(void) { int rval; upsdebugx(2, "modbus_reconnect, trying to reconnect to modbus server"); dstate_setinfo("driver.state", "reconnect.trying"); /* clear current modbus context */ modbus_close(mbctx); modbus_free(mbctx); /* open communication port */ mbctx = modbus_new(device_path); if (mbctx == NULL) { fatalx(EXIT_FAILURE, "modbus_new_rtu: Unable to open communication port context"); } /* set slave ID */ rval = modbus_set_slave(mbctx, rio_slave_id); if (rval < 0) { modbus_free(mbctx); fatalx(EXIT_FAILURE, "modbus_set_slave: Invalid modbus slave ID %d", rio_slave_id); } /* connect to modbus device */ if (modbus_connect(mbctx) == -1) { modbus_free(mbctx); fatalx(EXIT_FAILURE, "modbus_connect: unable to connect: %s", modbus_strerror(errno)); } /* set modbus response timeout */ #if (defined NUT_MODBUS_TIMEOUT_ARG_sec_usec_uint32) || (defined NUT_MODBUS_TIMEOUT_ARG_sec_usec_uint32_cast_timeval_fields) rval = modbus_set_response_timeout(mbctx, mod_resp_to_s, mod_resp_to_us); if (rval < 0) { modbus_free(mbctx); fatalx(EXIT_FAILURE, "modbus_set_response_timeout: error(%s)", modbus_strerror(errno)); } #elif (defined NUT_MODBUS_TIMEOUT_ARG_timeval_numeric_fields) { /* see comments above */ struct timeval to; memset(&to, 0, sizeof(struct timeval)); to.tv_sec = mod_resp_to_s; to.tv_usec = mod_resp_to_us; /* void */ modbus_set_response_timeout(mbctx, &to); } /* #elif (defined NUT_MODBUS_TIMEOUT_ARG_timeval) // some un-castable type in fields */ #endif /* NUT_MODBUS_TIMEOUT_ARG_* */ /* set modbus byte timeout */ #if (defined NUT_MODBUS_TIMEOUT_ARG_sec_usec_uint32) || (defined NUT_MODBUS_TIMEOUT_ARG_sec_usec_uint32_cast_timeval_fields) rval = modbus_set_byte_timeout(mbctx, mod_byte_to_s, mod_byte_to_us); if (rval < 0) { modbus_free(mbctx); fatalx(EXIT_FAILURE, "modbus_set_byte_timeout: error(%s)", modbus_strerror(errno)); } #elif (defined NUT_MODBUS_TIMEOUT_ARG_timeval_numeric_fields) { /* see comments above */ struct timeval to; memset(&to, 0, sizeof(struct timeval)); to.tv_sec = mod_byte_to_s; to.tv_usec = mod_byte_to_us; /* void */ modbus_set_byte_timeout(mbctx, &to); } /* #elif (defined NUT_MODBUS_TIMEOUT_ARG_timeval) // some un-castable type in fields */ #endif /* NUT_MODBUS_TIMEOUT_ARG_* */ dstate_setinfo("driver.state", "quiet"); } nut-2.8.1/drivers/eaton-pdu-revelation-mib.c0000644000175000017500000002153714500336654015720 00000000000000/* eaton-pdu-revelation-mib.c - data to monitor Eaton ePDUs branded as: * G1 Aphel based ePDUs (Complex) - Revelation * * Copyright (C) 2008 - 2017 * Arnaud Quette * Arnaud Quette * Copyright (C) 2015 - 2017 * Jim Klimov * * Supported by Eaton * and previously MGE Office Protection Systems * * 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 2 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, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #include "eaton-pdu-revelation-mib.h" #define EATON_APHEL_REVELATION_MIB_VERSION "0.52" /* APHEL PDU-MIB - Revelation MIB (Managed ePDU) * ********************************************* */ #define AR_BASE_OID ".1.3.6.1.4.1.534.6.6.6" #define APHEL2_SYSOID AR_BASE_OID #define APHEL2_OID_MODEL_NAME AR_OID_MODEL_NAME #define AR_OID_MODEL_NAME AR_BASE_OID ".1.1.12.0" #define AR_OID_DEVICE_NAME AR_BASE_OID ".1.1.13.0" #define AR_OID_FIRMREV AR_BASE_OID ".1.1.1.0" #define AR_OID_SERIAL AR_BASE_OID ".1.1.2.0" #define AR_OID_UNIT_MACADDR AR_BASE_OID ".1.1.6.0" #define AR_OID_UNIT_CURRENT AR_BASE_OID ".1.3.1.1" #define AR_OID_UNIT_VOLTAGE AR_BASE_OID ".1.3.1.2" #define AR_OID_UNIT_ACTIVEPOWER AR_BASE_OID ".1.3.1.3" #define AR_OID_UNIT_APPARENTPOWER AR_BASE_OID ".1.3.1.4" #define AR_OID_UNIT_CPUTEMPERATURE AR_BASE_OID ".1.3.1.5.0" #define AR_OID_OUTLET_INDEX AR_BASE_OID ".1.2.2.1.1" #define AR_OID_OUTLET_NAME AR_BASE_OID ".1.2.2.1.2" #define AR_OID_OUTLET_STATUS AR_BASE_OID ".1.2.2.1.3" static info_lkp_t revelation_outlet_status_info[] = { { -1, "error", NULL, NULL }, { 0, "off", NULL, NULL }, { 1, "on", NULL, NULL }, { 2, "cycling", NULL, NULL }, /* transitional status */ { 0, NULL, NULL, NULL } }; /* Ugly hack: having the matching OID present means that the outlet is * switchable. So, it should not require this value lookup */ static info_lkp_t revelation_outlet_switchability_info[] = { { -1, "yes", NULL, NULL }, { 0, "yes", NULL, NULL }, { 1, "yes", NULL, NULL }, { 2, "yes", NULL, NULL }, { 0, NULL, NULL, NULL } }; #define DO_OFF "0" #define DO_ON "1" #define DO_CYCLE "2" #define AR_OID_OUTLET_COUNT AR_BASE_OID ".1.2.1.0" #define AR_OID_OUTLET_CURRENT AR_BASE_OID ".1.2.2.1.4" #define AR_OID_OUTLET_MAXCURRENT AR_BASE_OID ".1.2.2.1.5" #define AR_OID_OUTLET_VOLTAGE AR_BASE_OID ".1.2.2.1.6" #define AR_OID_OUTLET_ACTIVEPOWER AR_BASE_OID ".1.2.2.1.7" #define AR_OID_OUTLET_APPARENTPOWER AR_BASE_OID ".1.2.2.1.8" #define AR_OID_OUTLET_POWERFACTOR AR_BASE_OID ".1.2.2.1.9" /* Snmp2NUT lookup table for Eaton Revelation MIB */ static snmp_info_t eaton_aphel_revelation_mib[] = { /* standard MIB items */ { "device.description", ST_FLAG_STRING | ST_FLAG_RW, SU_INFOSIZE, ".1.3.6.1.2.1.1.1.0", NULL, SU_FLAG_OK, NULL }, { "device.contact", ST_FLAG_STRING | ST_FLAG_RW, SU_INFOSIZE, ".1.3.6.1.2.1.1.4.0", NULL, SU_FLAG_OK, NULL }, { "device.location", ST_FLAG_STRING | ST_FLAG_RW, SU_INFOSIZE, ".1.3.6.1.2.1.1.6.0", NULL, SU_FLAG_OK, NULL }, /* Device collection */ { "device.mfr", ST_FLAG_STRING, SU_INFOSIZE, NULL, "EATON | Powerware", SU_FLAG_STATIC | SU_FLAG_ABSENT | SU_FLAG_OK, NULL }, { "device.model", ST_FLAG_STRING, SU_INFOSIZE, AR_OID_MODEL_NAME, "Eaton Powerware ePDU Managed", SU_FLAG_STATIC | SU_FLAG_OK, NULL }, { "device.serial", ST_FLAG_STRING, SU_INFOSIZE, AR_OID_SERIAL, "", SU_FLAG_STATIC | SU_FLAG_OK, NULL }, { "device.type", ST_FLAG_STRING, SU_INFOSIZE, NULL, "pdu", SU_FLAG_STATIC | SU_FLAG_ABSENT | SU_FLAG_OK, NULL }, { "device.macaddr", ST_FLAG_STRING, SU_INFOSIZE, AR_OID_UNIT_MACADDR, "", SU_FLAG_STATIC | SU_FLAG_OK, NULL }, /* hardwareRev.0 = Integer: 26 */ /* FIXME: not compliant! to be RFC'ed */ { "device.revision", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.534.6.6.6.1.1.7.0", "", SU_FLAG_STATIC | SU_FLAG_OK, NULL }, /* UPS collection */ { "ups.mfr", ST_FLAG_STRING, SU_INFOSIZE, NULL, "EATON | Powerware", SU_FLAG_STATIC | SU_FLAG_ABSENT | SU_FLAG_OK, NULL }, { "ups.model", ST_FLAG_STRING, SU_INFOSIZE, AR_OID_MODEL_NAME, "Generic SNMP PDU", SU_FLAG_STATIC | SU_FLAG_OK, NULL }, { "ups.id", ST_FLAG_STRING, SU_INFOSIZE, AR_OID_DEVICE_NAME, "unknown", SU_FLAG_STATIC | SU_FLAG_OK, NULL }, { "ups.serial", ST_FLAG_STRING, SU_INFOSIZE, AR_OID_SERIAL, "", SU_FLAG_STATIC | SU_FLAG_OK, NULL }, { "ups.firmware", ST_FLAG_STRING, SU_INFOSIZE, AR_OID_FIRMREV, "", SU_FLAG_STATIC | SU_FLAG_OK, NULL }, { "ups.type", ST_FLAG_STRING, SU_INFOSIZE, NULL, "pdu", SU_FLAG_STATIC | SU_FLAG_ABSENT | SU_FLAG_OK, NULL }, { "ups.temperature", 0, 1, AR_OID_UNIT_CPUTEMPERATURE, NULL, 0, NULL }, /* Outlet collection */ { "outlet.id", 0, 1, NULL, "0", SU_FLAG_STATIC | SU_FLAG_ABSENT | SU_FLAG_OK, NULL }, { "outlet.desc", ST_FLAG_RW | ST_FLAG_STRING, 20, NULL, "All outlets", SU_FLAG_STATIC | SU_FLAG_ABSENT | SU_FLAG_OK, NULL }, { "outlet.count", 0, 1, AR_OID_OUTLET_COUNT, "0", 0, NULL }, { "outlet.current", 0, 0.001, AR_OID_UNIT_CURRENT ".0", NULL, 0, NULL }, { "outlet.voltage", 0, 0.001, AR_OID_UNIT_VOLTAGE ".0", NULL, 0, NULL }, { "outlet.realpower", 0, 1.0, AR_OID_UNIT_ACTIVEPOWER ".0", NULL, 0, NULL }, { "outlet.power", 0, 1.0, AR_OID_UNIT_APPARENTPOWER ".0", NULL, 0, NULL }, /* outlet template definition * Caution: the index of the data start at 0, while the name is +1 * ie outlet.1 => .0 */ { "outlet.%i.switchable", 0, 1, AR_OID_OUTLET_STATUS ".%i", "yes", SU_FLAG_STATIC | SU_OUTLET, &revelation_outlet_switchability_info[0] }, { "outlet.%i.id", 0, 1, NULL, "%i", SU_FLAG_STATIC | SU_FLAG_ABSENT | SU_FLAG_OK | SU_OUTLET, NULL }, { "outlet.%i.desc", ST_FLAG_RW | ST_FLAG_STRING, SU_INFOSIZE, AR_OID_OUTLET_NAME ".%i", NULL, SU_OUTLET, NULL }, { "outlet.%i.status", ST_FLAG_STRING, SU_INFOSIZE, AR_OID_OUTLET_STATUS ".%i", NULL, SU_FLAG_OK | SU_OUTLET, &revelation_outlet_status_info[0] }, { "outlet.%i.current", 0, 0.001, AR_OID_OUTLET_CURRENT ".%i", NULL, SU_OUTLET, NULL }, { "outlet.%i.current.maximum", 0, 0.001, AR_OID_OUTLET_MAXCURRENT ".%i", NULL, SU_OUTLET, NULL }, { "outlet.%i.realpower", 0, 1.0, AR_OID_OUTLET_ACTIVEPOWER ".%i", NULL, SU_OUTLET, NULL }, { "outlet.%i.voltage", 0, 1.0, AR_OID_OUTLET_VOLTAGE ".%i", NULL, SU_OUTLET, NULL }, { "outlet.%i.powerfactor", 0, 0.01, AR_OID_OUTLET_POWERFACTOR ".%i", NULL, SU_OUTLET, NULL }, { "outlet.%i.power", 0, 1.0, AR_OID_OUTLET_APPARENTPOWER ".%i", NULL, SU_OUTLET, NULL }, /* FIXME: * - delay for startup/shutdown sequence * - support for multiple Ambient sensors ( max. 8), starting at index '0' * ambient.%i.temperature => .1.3.6.1.4.1.534.6.6.6.2.2.1.3.%i * ambient.%i.humidity => .1.3.6.1.4.1.534.6.6.6.2.4.1.3.%i */ /* Ambient collection */ /* We use critical levels, for both temperature and humidity, * since warning levels are also available! */ { "ambient.temperature", 0, 1.0, ".1.3.6.1.4.1.534.6.6.6.2.2.1.3.0", NULL, SU_FLAG_OK, NULL }, { "ambient.temperature.low", 0, 1.0, "1.3.6.1.4.1.534.6.6.6.2.2.1.6.0", NULL, SU_FLAG_OK, NULL }, { "ambient.temperature.high", 0, 1.0, "1.3.6.1.4.1.534.6.6.6.2.2.1.7.0", NULL, SU_FLAG_OK, NULL }, { "ambient.humidity", 0, 1.0, ".1.3.6.1.4.1.534.6.6.6.2.4.1.3.0", NULL, SU_FLAG_OK, NULL }, { "ambient.humidity.low", 0, 1.0, ".1.3.6.1.4.1.534.6.6.6.2.4.1.6.0", NULL, SU_FLAG_OK, NULL }, { "ambient.humidity.high", 0, 1.0, ".1.3.6.1.4.1.534.6.6.6.2.4.1.7.0", NULL, SU_FLAG_OK, NULL }, /* instant commands. */ /* Note that load.cycle might be replaced by / mapped on shutdown.reboot */ /* no counterpart found! { "outlet.load.off", 0, DO_OFF, AR_OID_OUTLET_STATUS ".0", NULL, SU_TYPE_CMD, NULL }, { "outlet.load.on", 0, DO_ON, AR_OID_OUTLET_STATUS ".0", NULL, SU_TYPE_CMD, NULL }, { "outlet.load.cycle", 0, DO_CYCLE, AR_OID_OUTLET_STATUS ".0", NULL, SU_TYPE_CMD, NULL }, */ { "outlet.%i.load.off", 0, 1, AR_OID_OUTLET_STATUS ".%i", DO_OFF, SU_TYPE_CMD | SU_OUTLET, NULL }, { "outlet.%i.load.on", 0, 1, AR_OID_OUTLET_STATUS ".%i", DO_ON, SU_TYPE_CMD | SU_OUTLET, NULL }, { "outlet.%i.load.cycle", 0, 1, AR_OID_OUTLET_STATUS ".%i", DO_CYCLE, SU_TYPE_CMD | SU_OUTLET, NULL }, /* end of structure. */ { NULL, 0, 0, NULL, NULL, 0, NULL } }; mib2nut_info_t aphel_revelation = { "aphel_revelation", EATON_APHEL_REVELATION_MIB_VERSION, NULL, APHEL2_OID_MODEL_NAME, eaton_aphel_revelation_mib, APHEL2_SYSOID, NULL }; nut-2.8.1/drivers/openups-hid.c0000644000175000017500000003256314515702041013336 00000000000000/* openups-hid.c - subdriver to monitor Minibox openUPS USB/HID devices with NUT * * Copyright (C) * 2003 - 2012 Arnaud Quette * 2005 - 2006 Peter Selinger * 2008 - 2009 Arjen de Korte * 2012 Nicu Pavel * * 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 2 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, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "config.h" /* must be first */ #include "usbhid-ups.h" #include "openups-hid.h" #include "main.h" /* for getval() */ #include "usb-common.h" #define OPENUPS_HID_VERSION "openUPS HID 0.5" /* Minibox */ #define OPENUPS_VENDORID 0x04d8 /* constants for converting HID read values to real values */ static const double vin_scale_d004 = 0.03545 * 100; static const double vout_scale_d004 = 0.02571 * 100; /* static const double vbat_scale = 0.00857 * 100; */ static const double ccharge_scale_d004 = 0.8274 / 10; static const double cdischarge_scale_d004 = 16.113 / 10; static double vin_scale = 1; static double vout_scale= 1; static double ccharge_scale = 1; static double cdischarge_scale = 1; static char openups_scratch_buf[20]; static void *get_voltage_multiplier(USBDevice_t *device) { switch(device->ProductID) { case 0xd004: vin_scale = vin_scale_d004; vout_scale= vout_scale_d004; ccharge_scale= ccharge_scale_d004; cdischarge_scale= cdischarge_scale_d004; break; case 0xd005: vin_scale = 0.1; vout_scale = 0.1; ccharge_scale = 0.1; /* unverified */ cdischarge_scale = 0.1; /* unverified */ break; } upsdebugx(1, "vin_scale = %g; vout_scale = %g\n", vin_scale, vout_scale); return NULL; } /* USB IDs device table */ static /* const */ usb_device_id_t openups_usb_device_table[] = { /* openUPS Intelligent UPS (minimum required firmware 1.4) */ {USB_DEVICE(OPENUPS_VENDORID, 0xd004), get_voltage_multiplier}, {USB_DEVICE(OPENUPS_VENDORID, 0xd005), get_voltage_multiplier}, /* Terminating entry */ { 0, 0, NULL } }; /* Thermistor table used for temperature lookups * taken from the windows monitoring application */ static const unsigned int therm_tbl[] = { (unsigned int)0x31, (unsigned int)0x40, (unsigned int)0x53, (unsigned int)0x68, (unsigned int)0x82, (unsigned int)0xA0, (unsigned int)0xC3, (unsigned int)0xE9, (unsigned int)0x113, (unsigned int)0x13F, (unsigned int)0x16E, (unsigned int)0x19F, (unsigned int)0x1CF, (unsigned int)0x200, (unsigned int)0x22F, (unsigned int)0x25C, (unsigned int)0x286, (unsigned int)0x2AE, (unsigned int)0x2D3, (unsigned int)0x2F4, (unsigned int)0x312, (unsigned int)0x32D, (unsigned int)0x345, (unsigned int)0x35A, (unsigned int)0x36D, (unsigned int)0x37E, (unsigned int)0x38C, (unsigned int)0x399, (unsigned int)0x3A5, (unsigned int)0x3AF, (unsigned int)0x3B7, (unsigned int)0x3BF, (unsigned int)0x3C6, (unsigned int)0x3CC }; static const unsigned int therm_tbl_size = SIZEOF_ARRAY(therm_tbl); static const char *openups_charging_fun(double value); static const char *openups_discharging_fun(double value); static const char *openups_online_fun(double value); static const char *openups_nobattery_fun(double value); static const char *openups_off_fun(double value); static const char *openups_scale_vin_fun(double value); static const char *openups_scale_vout_fun(double value); /* static const char *openups_scale_vbat_fun(double value); */ static const char *openups_scale_ccharge_fun(double value); static const char *openups_scale_cdischarge_fun(double value); static const char *openups_temperature_fun(double value); static info_lkp_t openups_charging_info[] = { {0, NULL, openups_charging_fun, NULL } }; static info_lkp_t openups_discharging_info[] = { {0, NULL, openups_discharging_fun, NULL } }; static info_lkp_t openups_online_info[] = { {0, NULL, openups_online_fun, NULL } }; static info_lkp_t openups_nobattery_info[] = { {0, NULL, openups_nobattery_fun, NULL } }; static info_lkp_t openups_off_info[] = { {0, NULL, openups_off_fun, NULL } }; static info_lkp_t openups_vin_info[] = { {0, NULL, openups_scale_vin_fun, NULL } }; static info_lkp_t openups_vout_info[] = { {0, NULL, openups_scale_vout_fun, NULL } }; /* static info_lkp_t openups_vbat_info[] = { {0, NULL, openups_scale_vbat_fun, NULL } };*/ static info_lkp_t openups_ccharge_info[] = { {0, NULL, openups_scale_ccharge_fun, NULL } }; static info_lkp_t openups_cdischarge_info[] = { {0, NULL, openups_scale_cdischarge_fun, NULL } }; static info_lkp_t openups_temperature_info[] = { {0, NULL, openups_temperature_fun, NULL } }; static const char *openups_charging_fun(double value) { return value ? "chrg" : "!chrg"; } static const char *openups_discharging_fun(double value) { return value ? "dischrg" : "!dischrg"; } static const char *openups_online_fun(double value) { return value ? "online" : "!online"; } static const char *openups_nobattery_fun(double value) { return value ? "nobattery" : "!nobattery"; } static const char *openups_off_fun(double value) { return value ? "!off" : "off"; } static const char *openups_scale_vin_fun(double value) { snprintf(openups_scratch_buf, sizeof(openups_scratch_buf), "%.2f", value * vin_scale); return openups_scratch_buf; } static const char *openups_scale_vout_fun(double value) { snprintf(openups_scratch_buf, sizeof(openups_scratch_buf), "%.2f", value * vout_scale); return openups_scratch_buf; } /* static const char *openups_scale_vbat_fun(double value) { snprintf(openups_scratch_buf, sizeof(openups_scratch_buf), "%.2f", value * vbat_scale); return openups_scratch_buf; }*/ static const char *openups_scale_ccharge_fun(double value) { snprintf(openups_scratch_buf, sizeof(openups_scratch_buf), "%.3f", value * ccharge_scale); return openups_scratch_buf; } static const char *openups_scale_cdischarge_fun(double value) { snprintf(openups_scratch_buf, sizeof(openups_scratch_buf), "%.3f", value * cdischarge_scale); return openups_scratch_buf; } static const char *openups_temperature_fun(double value) { int i; int pos = 0; unsigned int thermistor = value * 100; if (thermistor <= therm_tbl[0]) { snprintf(openups_scratch_buf, sizeof(openups_scratch_buf), "%d", -40); } else { if (thermistor >= therm_tbl[therm_tbl_size - 1]) { snprintf(openups_scratch_buf, sizeof(openups_scratch_buf), "%d", 125); } else { for (i = therm_tbl_size - 1; i >= 0; i--) { if (thermistor >= therm_tbl[i]) { pos = i; break; } } if (thermistor == therm_tbl[pos]) { snprintf(openups_scratch_buf, sizeof(openups_scratch_buf), "%d", pos * 5 - 40); } else { int t1 = pos * 5 - 40; int t2 = (pos + 1) * 5 - 40; unsigned int d1 = therm_tbl[pos]; unsigned int d2 = therm_tbl[pos + 1]; double temp = (double) (thermistor - d1) * (t2 - t1) / (d2 - d1) + t1; snprintf(openups_scratch_buf, sizeof(openups_scratch_buf), "%.2f", temp); } } } return openups_scratch_buf; } /* --------------------------------------------------------------- */ /* Vendor-specific usage table */ /* --------------------------------------------------------------- */ /* OPENUPS usage table */ static usage_lkp_t openups_usage_lkp[] = { {"Cell1", 0x00000001}, /* Battery cell 1 on J6 pin 1 */ {"Cell2", 0x00000002}, /* Battery cell 2 on J6 pin 2 */ {"Cell3", 0x00000003}, /* Battery cell 3 on J6 pin 3 */ {"Cell4", 0x00000004}, /* Battery cell 4 on J6 pin 4 */ {"Cell5", 0x00000005}, /* Battery cell 5 on J6 pin 5 */ {"Cell6", 0x00000006}, /* Battery cell 6 on J4 pin 1 */ /* Usage table for windows monitoring app only updates when * certain request codes are written to USB endpoint */ /*{ "OpenUPSExtra", 0xff000001 }, */ {NULL, 0} }; static usage_tables_t openups_utab[] = { openups_usage_lkp, hid_usage_lkp, NULL, }; /* --------------------------------------------------------------- */ /* HID2NUT lookup table */ /* --------------------------------------------------------------- */ static hid_info_t openups_hid2nut[] = { {"ups.serial", 0, 0, "UPS.PowerSummary.iSerialNumber", NULL, "%s", 0, stringid_conversion}, /* Battery */ {"battery.type", 0, 0, "UPS.PowerSummary.iDeviceChemistry", NULL, "%s", HU_FLAG_STATIC, stringid_conversion}, {"battery.mfr.date", 0, 0, "UPS.PowerSummary.iOEMInformation", NULL, "%s", HU_FLAG_STATIC, stringid_conversion}, {"battery.voltage", 0, 0, "UPS.PowerSummary.Voltage", NULL, "%.2f", HU_FLAG_QUICK_POLL, NULL}, /* { "battery.voltage.nominal", 0, 0, "UPS.PowerSummary.ConfigVoltage", NULL, NULL, HU_FLAG_QUICK_POLL, openups_vbat_info }, */ {"battery.current", 0, 0, "UPS.PowerSummary.Current", NULL, "%.3f", HU_FLAG_QUICK_POLL, NULL}, {"battery.capacity", 0, 0, "UPS.PowerSummary.DesignCapacity", NULL, "%.0f", HU_FLAG_STATIC, NULL}, {"battery.charge", 0, 0, "UPS.PowerSummary.RemainingCapacity", NULL, "%.0f", HU_FLAG_QUICK_POLL, NULL}, {"battery.charge.low", 0, 0, "UPS.PowerSummary.RemainingCapacityLimit", NULL, "%.0f", HU_FLAG_QUICK_POLL, NULL}, {"battery.charge.warning", 0, 0, "UPS.PowerSummary.WarningCapacityLimit", NULL, "%.0f", 0, NULL}, {"battery.runtime", 0, 0, "UPS.PowerSummary.RunTimeToEmpty", NULL, "%.0f", HU_FLAG_QUICK_POLL, NULL}, {"battery.temperature", 0, 0, "UPS.PowerSummary.Temperature", NULL, NULL, HU_FLAG_QUICK_POLL, openups_temperature_info}, /* {"battery.cell1.voltage", 0, 0, "UPS.PowerSummary.Battery.Cell1", NULL, NULL, HU_FLAG_QUICK_POLL, openups_vbat_info}, {"battery.cell2.voltage", 0, 0, "UPS.PowerSummary.Battery.Cell2", NULL, NULL, HU_FLAG_QUICK_POLL, openups_vbat_info}, {"battery.cell3.voltage", 0, 0, "UPS.PowerSummary.Battery.Cell3", NULL, NULL, HU_FLAG_QUICK_POLL, openups_vbat_info}, {"battery.cell4.voltage", 0, 0, "UPS.PowerSummary.Battery.Cell4", NULL, NULL, HU_FLAG_QUICK_POLL, openups_vbat_info}, {"battery.cell5.voltage", 0, 0, "UPS.PowerSummary.Battery.Cell5", NULL, NULL, HU_FLAG_QUICK_POLL, openups_vbat_info}, {"battery.cell6.voltage", 0, 0, "UPS.PowerSummary.Battery.Cell6", NULL, NULL, HU_FLAG_QUICK_POLL, openups_vbat_info}, */ /* Output */ {"output.voltage", 0, 0, "UPS.PowerSummary.Output.Voltage", NULL, NULL, HU_FLAG_QUICK_POLL, openups_vout_info}, {"output.current", 0, 0, "UPS.PowerSummary.Output.Current", NULL, NULL, HU_FLAG_QUICK_POLL, openups_cdischarge_info}, /* Input */ {"input.voltage", 0, 0, "UPS.PowerSummary.Input.Voltage", NULL, NULL, HU_FLAG_QUICK_POLL, openups_vin_info}, {"input.current", 0, 0, "UPS.PowerSummary.Input.Current", NULL, NULL, HU_FLAG_QUICK_POLL, openups_ccharge_info}, /* Status */ {"BOOL", 0, 0, "UPS.PowerSummary.PresentStatus.Good", NULL, NULL, HU_FLAG_QUICK_POLL, openups_off_info}, {"BOOL", 0, 0, "UPS.PowerSummary.PresentStatus.InternalFailure", NULL, NULL, HU_FLAG_QUICK_POLL, commfault_info}, {"BOOL", 0, 0, "UPS.PowerSummary.PresentStatus.Overload", NULL, NULL, HU_FLAG_QUICK_POLL, overload_info}, {"BOOL", 0, 0, "UPS.PowerSummary.PresentStatus.OverTemperature", NULL, NULL, HU_FLAG_QUICK_POLL, overheat_info}, {"BOOL", 0, 0, "UPS.PowerSummary.PresentStatus.ShutdownImminent", NULL, NULL, HU_FLAG_QUICK_POLL, shutdownimm_info}, {"BOOL", 0, 0, "UPS.PowerSummary.PresentStatus.BelowRemainingCapacityLimit", NULL, NULL, HU_FLAG_QUICK_POLL, lowbatt_info}, {"BOOL", 0, 0, "UPS.PowerSummary.PresentStatus.RemainingTimeLimitExpired", NULL, NULL, HU_FLAG_QUICK_POLL, timelimitexpired_info}, {"BOOL", 0, 0, "UPS.PowerSummary.PresentStatus.Charging", NULL, NULL, HU_FLAG_QUICK_POLL, openups_charging_info}, {"BOOL", 0, 0, "UPS.PowerSummary.PresentStatus.Discharging", NULL, NULL, HU_FLAG_QUICK_POLL, openups_discharging_info}, {"BOOL", 0, 0, "UPS.PowerSummary.PresentStatus.NeedReplacement", NULL, NULL, 0, replacebatt_info}, {"BOOL", 0, 0, "UPS.PowerSummary.PresentStatus.ACPresent", NULL, NULL, HU_FLAG_QUICK_POLL, openups_online_info}, {"BOOL", 0, 0, "UPS.PowerSummary.PresentStatus.BatteryPresent", NULL, NULL, HU_FLAG_QUICK_POLL, openups_nobattery_info}, /* end of structure. */ {NULL, 0, 0, NULL, NULL, NULL, 0, NULL} }; static const char *openups_format_model(HIDDevice_t * hd) { return hd->Product; } static const char *openups_format_mfr(HIDDevice_t * hd) { return hd->Vendor ? hd->Vendor : "openUPS"; } static const char *openups_format_serial(HIDDevice_t * hd) { return hd->Serial; } /* this function allows the subdriver to "claim" a device: return 1 if * the device is supported by this subdriver, else 0. */ static int openups_claim(HIDDevice_t * hd) { int status = is_usb_device_supported(openups_usb_device_table, hd); switch (status) { case POSSIBLY_SUPPORTED: /* by default, reject, unless the productid option is given */ if (getval("productid")) { return 1; } possibly_supported("openUPS", hd); return 0; case SUPPORTED: return 1; case NOT_SUPPORTED: default: return 0; } } subdriver_t openups_subdriver = { OPENUPS_HID_VERSION, openups_claim, openups_utab, openups_hid2nut, openups_format_model, openups_format_mfr, openups_format_serial, fix_report_desc, }; nut-2.8.1/drivers/masterguard.c0000644000175000017500000003404214501607135013416 00000000000000/* masterguard.c - support for Masterguard models Copyright (C) 2001 Michael Spanier masterguard.c created on 15.8.2001 OBSOLETION WARNING: Please to not base new development on this codebase, instead create a new subdriver for nutdrv_qx which generally covers all Megatec/Qx protocol family and aggregates device support from such legacy drivers over time. 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 2 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, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "main.h" #include "serial.h" #include "nut_stdint.h" #define DRIVER_NAME "MASTERGUARD UPS driver" #define DRIVER_VERSION "0.26" /* driver description structure */ upsdrv_info_t upsdrv_info = { DRIVER_NAME, DRIVER_VERSION, "Michael Spanier ", DRV_STABLE, { NULL } }; #define UPSDELAY 3 #define MAXTRIES 10 #define UPS_PACE 100 /* 100 us between chars on write */ #define Q1 1 #define Q3 2 #define DEBUG 1 static int type; static char name[31]; static char firmware[6]; /******************************************************************** * * Helper function to split a sting into words by splitting at the * SPACE character. * * Adds up to maxlen characters to the char word. * Returns NULL on reaching the end of the string. * ********************************************************************/ static char *StringSplit( char *source, char *word, size_t maxlen ) { size_t i; size_t len; size_t wc=0; word[0] = '\0'; len = strlen( source ); for( i = 0; i < len && wc < maxlen; i++ ) { if( source[i] == ' ' ) { word[wc] = '\0'; return source + i + 1; } word[wc] = source[i]; wc++; } word[wc] = '\0'; return NULL; } /******************************************************************** * * Helper function to drop all whitespaces within a string. * * "word" must be large enought to hold "source", for the worst case * "word" has to be exacly the size of "source". * ********************************************************************/ static void StringStrip( char *source, char *word ) { size_t wc=0; size_t i; size_t len; word[0] = '\0'; len = strlen( source ); for( i = 0; i < len; i++ ) { if( source[i] == ' ' ) continue; if( source[i] == '\n' ) continue; if( source[i] == '\t' ) continue; word[wc] = source[i]; wc++; } word[wc] = '\0'; } /******************************************************************** * * Function parses the status flags which occure in the Q1 and Q3 * command. Sets the INFO_STATUS value ( OL, OB, ... ) * ********************************************************************/ static void parseFlags( char *flags ) { status_init(); if( flags[0] == '1' ) status_set("OB"); else status_set("OL"); if( flags[1] == '1' ) status_set("LB"); if( flags[2] == '1' ) status_set("BOOST"); /* this has no mapping */ #if 0 if( flags[3] == '1' ) setinfo( INFO_ALRM_GENERAL, "1" ); #endif #if 0 /* and these are... ? */ if( flags[5] == '1' ) status_set("TIP"); if( flags[6] == '1' ) status_set("SD"); #endif status_commit(); if( DEBUG ) printf( "Status is %s\n", dstate_getinfo("ups.status")); } /******************************************************************** * * Function parses the response of the query1 ( "Q1" ) command. * Also sets various values (IPFreq ... ) * ********************************************************************/ static void query1( char *buf ) { #define WORDMAXLEN 255 char value[WORDMAXLEN]; char word[WORDMAXLEN]; char *newPOS; char *oldPOS; int count = 0; if( DEBUG ) printf( "Q1 Buffer is : %s\n" , buf + 1 ); oldPOS = buf + 1; newPOS = oldPOS; do { newPOS = StringSplit( oldPOS, word, WORDMAXLEN ); StringStrip( word, value); oldPOS = newPOS; if( DEBUG ) { printf( "value=%s\n", value ); fflush( stdout ); } switch( count ) { case 0: /* IP Voltage */ dstate_setinfo("input.voltage", "%s", value ); break; case 1: /* IP Fault Voltage */ break; case 2: /* OP Voltage */ dstate_setinfo("output.voltage", "%s", value); break; case 3: /* OP Load*/ dstate_setinfo("ups.load", "%s", value ); break; case 4: /* IP Frequency */ dstate_setinfo("input.frequency", "%s", value); break; case 5: /* Battery Cell Voltage */ dstate_setinfo("battery.voltage", "%s", value); break; case 6: /* UPS Temperature */ dstate_setinfo("ups.temperature", "%s", value ); break; case 7: /* Flags */ parseFlags( value ); break; default: /* Should never be reached */ break; } count ++; oldPOS = newPOS; } while( newPOS != NULL ); } /******************************************************************** * * Function parses the response of the query3 ( "Q3" ) command. * Also sets various values (IPFreq ... ) * ********************************************************************/ static void query3( char *buf ) { #define WORDMAXLEN 255 char value[WORDMAXLEN]; char word[WORDMAXLEN]; char *newPOS; char *oldPOS; int count = 0; if( DEBUG ) printf( "Q3 Buffer is : %s\n" , buf+1 ); oldPOS = buf + 1; newPOS = oldPOS; do { newPOS = StringSplit( oldPOS, word, WORDMAXLEN ); StringStrip( word, value); oldPOS = newPOS; /* Shortcut */ if( newPOS == NULL ) break; if( DEBUG ) { printf( "value=%s\n", value ); fflush( stdout ); } switch( count ) { case 0: /* UPS ID */ break; case 1: /* Input Voltage */ dstate_setinfo("input.voltage", "%s", value ); break; case 2: /* Input Fault Voltage */ break; case 3: /* Output Voltage */ dstate_setinfo("output.voltage", "%s", value); break; case 4: /* Output Current */ dstate_setinfo("output.current", "%s", value ); break; case 5: /* Input Frequency */ dstate_setinfo("input.frequency", "%s", value); break; case 6: /* Battery Cell Voltage */ dstate_setinfo("battery.voltage", "%s", value); break; case 7: /* Temperature */ dstate_setinfo("ups.temperature", "%s", value ); break; case 8: /* Estimated Runtime */ dstate_setinfo("battery.runtime", "%s", value); break; case 9: /* Charge Status */ dstate_setinfo("battery.charge", "%s", value); break; case 10: /* Flags */ parseFlags( value ); break; case 11: /* Flags2 */ break; default: /* This should never be reached */ /* printf( "DEFAULT\n" ); */ break; } count ++; oldPOS = newPOS; } while( newPOS != NULL ); } /******************************************************************** * * Function to parse the WhoAmI response of the UPS. Also sets the * values of the firmware version and the UPS identification. * ********************************************************************/ static void parseWH( char *buf ) { strncpy( name, buf + 16, 30 ); name[30] = '\0'; strncpy( firmware, buf + 4, 5 ); firmware[5] = '\0'; if( DEBUG ) printf( "Name = %s, Firmware Version = %s\n", name, firmware ); } /******************************************************************** * * Function to parse the old and possible broken WhoAmI response * and set the values for the firmware Version and the identification * of the UPS. * ********************************************************************/ static void parseOldWH( char *buf ) { strncpy( name, buf + 4, 12 ); name[12] = '\0'; strncpy( firmware, buf, 4 ); firmware[4] = '\0'; if( DEBUG ) printf( "Name = %s, Firmware Version = %s\n", name, firmware ); } /******************************************************************** * * Function to fake a WhoAmI response of a UPS that returns NAK. * ********************************************************************/ static void fakeWH(void) { strcpy( name, "GenericUPS" ); strcpy( firmware, "unkn" ); if( DEBUG ) printf( "Name = %s, Firmware Version = %s\n", name, firmware ); } static ssize_t ups_ident( void ) { char buf[255]; ssize_t ret; /* Check presence of Q1 */ ret = ser_send_pace(upsfd, UPS_PACE, "%s", "Q1\x0D" ); ret = ser_get_line(upsfd, buf, sizeof(buf), '\r', "", 3, 0); ret = (ssize_t)strlen( buf ); if( ret != 46 ) { /* No Q1 response found */ type = 0; return -1; } else { if( DEBUG ) printf( "Found Q1\n" ); type = Q1; } /* Check presence of Q3 */ ret = ser_send_pace(upsfd, UPS_PACE, "%s", "Q3\x0D" ); ret = ser_get_line(upsfd, buf, sizeof(buf), '\r', "", 3, 0); ret = (ssize_t)strlen( buf ); if( ret == 70 ) { if( DEBUG ) printf( "Found Q3\n" ); type = Q1 | Q3; } /* Check presence of WH ( Who am I ) */ ret = ser_send_pace(upsfd, UPS_PACE, "%s", "WH\x0D" ); ret = ser_get_line(upsfd, buf, sizeof(buf), '\r', "", 3, 0); ret = (ssize_t)strlen( buf ); if( ret == 112 ) { if( DEBUG ) printf( "WH found\n" ); parseWH( buf ); } else if( ret == 53 ) { if( DEBUG ) printf( "Old (broken) WH found\n" ); parseOldWH( buf ); } else if( ret == 3 && strcmp(buf, "NAK") == 0 ) { if( DEBUG ) printf( "WH was NAKed\n" ); fakeWH( ); } else if( ret > 0 ) { if( DEBUG ) printf( "WH says <%s> with length %" PRIiSIZE "\n", buf, ret ); upslog_with_errno( LOG_INFO, "New WH String found. Please report to maintainer\n" ); } return 1; } /******************************************************************** * * * * ********************************************************************/ void upsdrv_help( void ) { } /******************************************************************** * * Function to initialize the fields of the ups driver. * ********************************************************************/ void upsdrv_initinfo(void) { dstate_setinfo("ups.mfr", "MASTERGUARD"); dstate_setinfo("ups.model", "unknown"); /* dstate_addcmd("test.battery.stop"); dstate_addcmd("test.battery.start"); */ if( strlen( name ) > 0 ) dstate_setinfo("ups.model", "%s", name); if( strlen( firmware ) > 0 ) dstate_setinfo("ups.firmware", "%s", firmware); } /******************************************************************** * * This is the main function. It gets called if the driver wants * to update the ups status and the information. * ********************************************************************/ void upsdrv_updateinfo(void) { char buf[255]; ssize_t ret; int lenRSP=0; if( DEBUG ) printf( "update info\n" ); /* Q3 found ? */ if( type & Q3 ) { ser_send_pace(upsfd, UPS_PACE, "%s", "Q3\x0D" ); lenRSP = 70; } /* Q1 found ? */ else if( type & Q1 ) { ser_send_pace(upsfd, UPS_PACE, "%s", "Q1\x0D" ); lenRSP = 46; } /* Should never be reached */ else { fatalx(EXIT_FAILURE, "Error, no Query mode defined. Please file bug against driver."); } sleep( UPSDELAY ); buf[0] = '\0'; ret = ser_get_line(upsfd, buf, sizeof(buf), '\r', "", 3, 0); ret = (ssize_t)strlen( buf ); if( ret != lenRSP ) { if( DEBUG ) printf( "buf = %s len = %" PRIiSIZE "\n", buf, ret ); upslog_with_errno( LOG_ERR, "Error in UPS response " ); dstate_datastale(); return; } /* Parse the response from the UPS */ if( type & Q3 ) { query3( buf ); dstate_dataok(); return; } if( type & Q1 ) { query1( buf ); dstate_dataok(); return; } } /******************************************************************** * * Called if the driver wants to shutdown the UPS. * ( also used by the "-k" command line switch ) * * This cuts the utility from the UPS after 20 seconds and restores * the utility one minute _after_ the utility to the UPS has restored * ********************************************************************/ void upsdrv_shutdown(void) { /* ups will come up within a minute if utility is restored */ ser_send_pace(upsfd, UPS_PACE, "%s", "S.2R0001\x0D" ); } /******************************************************************** * * Populate the command line switches. * * CS: Cancel the shutdown process * ********************************************************************/ void upsdrv_makevartable(void) { addvar( VAR_FLAG, "CS", "Cancel Shutdown" ); } /******************************************************************** * * This is the first function called by the UPS driver. * Detects the UPS and handles the command line args. * ********************************************************************/ void upsdrv_initups(void) { int count = 0; int fail = 0; int good = 0; upsdebugx(0, "Please note that this driver is deprecated and will not receive\n" "new development. If it works for managing your devices - fine,\n" "but if you are running it to try setting up a new device, please\n" "consider the newer nutdrv_qx instead, which should handle all 'Qx'\n" "protocol variants for NUT. (Please also report if your device works\n" "with this driver, but nutdrv_qx would not actually support it with\n" "any subdriver!)\n"); /* setup serial port */ upsfd = ser_open(device_path); ser_set_speed(upsfd, device_path, B2400); name[0] = '\0'; firmware[0] = '\0'; /* probe ups type */ do { count++; if( ups_ident( ) != 1 ) fail++; /* at least two good identifications */ if( (count - fail) == 2 ) { good = 1; break; } } while( (count * 2016 Arnaud Quette * * 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 2 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, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef RARITAN_PX2_MIB_H #define RARITAN_PX2_MIB_H #include "main.h" #include "snmp-ups.h" extern mib2nut_info_t raritan_px2; #endif /* RARITAN_PX2_MIB_H */ nut-2.8.1/drivers/ever-hid.h0000644000175000017500000000232014500336654012606 00000000000000/* everhid-hid.h - subdriver to monitor Everhid USB/HID devices with NUT * * Copyright (C) * 2003 - 2009 Arnaud Quette * 2005 - 2006 Peter Selinger * 2008 - 2009 Arjen de Korte * 2017 EVER Power Systems [https://ever.eu/] * 2020 - 2022 Jim Klimov * * 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 2 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, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef EVER_HID_H #define EVER_HID_H #include "usbhid-ups.h" extern subdriver_t ever_subdriver; #endif /* EVER_HID_H */ nut-2.8.1/drivers/nut_libusb.h0000644000175000017500000001162714501607135013257 00000000000000/*! * @file nut_libusb.h * @brief HID Library - Generic USB backend for Generic HID Access (using MGE HIDParser) * * @author Copyright (C) * 2003 - 2016 Arnaud Quette * 2005 Peter Selinger * 2021 Jim Klimov * * This program is sponsored by MGE UPS SYSTEMS - opensource.mgeups.com * * The logic of this file is ripped from mge-shut driver (also from * Arnaud Quette), which is a "HID over serial link" UPS driver for * Network UPS Tools * * 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 2 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, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * * -------------------------------------------------------------------------- */ #ifndef NUT_LIBUSB_H_SEEN #define NUT_LIBUSB_H_SEEN 1 #include "main.h" /* for subdrv_info_t */ #include "usb-common.h" /* for USBDevice_t and USBDeviceMatcher_t, * and for libusb headers and 0.1/1.0 mapping */ /* Used in drivers/libusb*.c sources: */ #define LIBUSB_DEFAULT_INTERFACE 0 #define LIBUSB_DEFAULT_DESC_INDEX 0 #define LIBUSB_DEFAULT_HID_EP_IN 1 #define LIBUSB_DEFAULT_HID_EP_OUT 1 extern upsdrv_info_t comm_upsdrv_info; /*! * usb_communication_subdriver_s: structure to describe the communication routines * @name: can be either "shut" for Serial HID UPS Transfer (from MGE) or "usb" */ typedef struct usb_communication_subdriver_s { const char *name; /* name of this subdriver */ const char *version; /* version of this subdriver */ int (*open_dev)(usb_dev_handle **sdevp, /* try to open the next available */ USBDevice_t *curDevice, /* device matching USBDeviceMatcher_t */ USBDeviceMatcher_t *matcher, int (*callback)(usb_dev_handle *udev, USBDevice_t *hd, usb_ctrl_charbuf rdbuf, usb_ctrl_charbufsize rdlen)); void (*close_dev)(usb_dev_handle *sdev); int (*get_report)(usb_dev_handle *sdev, usb_ctrl_repindex ReportId, usb_ctrl_charbuf raw_buf, usb_ctrl_charbufsize ReportSize); int (*set_report)(usb_dev_handle *sdev, usb_ctrl_repindex ReportId, usb_ctrl_charbuf raw_buf, usb_ctrl_charbufsize ReportSize); int (*get_string)(usb_dev_handle *sdev, usb_ctrl_strindex StringIdx, char *buf, usb_ctrl_charbufsize buflen); int (*get_interrupt)(usb_dev_handle *sdev, usb_ctrl_charbuf buf, usb_ctrl_charbufsize bufsize, usb_ctrl_timeout_msec timeout); /* Used for Powervar UPS or similar cases to make sure * we use the right interface in the Composite device. * In a few cases our libusb*.c sets the value for specific * VID/PID combinations, in others the subdrivers do so. * FIXME: The numeric value here seems to fit and * gets used in several contexts, it may be cleaner * to separate them eventually. Usages in NUT were * seen as following libusb API (1.0 and 0.1) args, * along with some hints from libusb sources/headers: * libusb-1.0: * libusb_claim_interface - "int interface_number" * libusb_detach_kernel_driver - "int interface_number" * libusb_get_config_descriptor - "uint8_t config_index" ("the index of the configuration you wish to retrieve") * libusb_control_transfer - "uint16_t wIndex" ("the index field for the setup packet"; "should be given in host-endian byte order") * libusb-0.1: // The parameters mirror the types of the same name in the USB specification * usb_claim_interface - "int interface" * usb_control_msg - "int index" * (_np = non-portable => only on some systems, like FreeBSD) * usb_detach_kernel_driver_np - "int interface" */ usb_ctrl_repindex hid_rep_index; /* number of the interface we use in a composite USB device; see comments above */ /* All devices use HID descriptor at index 0. * However, some UPS like newer Eaton units have * a light HID descriptor at index 0, and * the full version is at index 1 (in which * case, bcdDevice == 0x0202) */ usb_ctrl_descindex hid_desc_index; /* HID descriptor is at this index (non-trivial for composite USB devices); see comments above */ usb_ctrl_endpoint hid_ep_in; /* Input interrupt endpoint. Default is 1 */ usb_ctrl_endpoint hid_ep_out; /* Output interrupt endpoint. Default is 1 */ } usb_communication_subdriver_t; extern usb_communication_subdriver_t usb_subdriver; #endif /* NUT_LIBUSB_H_SEEN */ nut-2.8.1/drivers/nut-ipmipsu.c0000644000175000017500000001521414501607135013372 00000000000000/* nut-ipmipsu.c - Driver for IPMI Power Supply Units (PSU) * * Copyright (C) * 2011 - 2012 Arnaud Quette * * 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 2 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, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * TODO list: * - PSU sensor monitoring (how to find the right one?) * - dump all value at init, so that we can check for other interesting data */ #include "main.h" #include "nut-ipmi.h" #define DRIVER_NAME "IPMI PSU driver" #define DRIVER_VERSION "0.32" /* driver description structure */ upsdrv_info_t upsdrv_info = { DRIVER_NAME, DRIVER_VERSION, "Arnaud Quette \n", DRV_EXPERIMENTAL, { NULL } }; /* Note on device.status * OL: present and providing power * OFF: present but not providing power (power cable removed) * stale: not present (PSU removed) * => should we prefer RB, MISSING, ABSENT, ??? */ /* Abstract structure to allow different IPMI implementation * We currently use FreeIPMI, but OpenIPMI and others are serious * candidates! */ static IPMIDevice_t ipmi_dev; /* Currently used to store FRU ID, but will probably evolve... */ static int ipmi_id = -1; void upsdrv_initinfo(void) { /* try to detect the PSU here - call fatal_with_errno(EXIT_FAILURE, ) if it fails */ upsdebugx(1, "upsdrv_initinfo..."); /* print what we detected during IPMI open */ upsdebugx(1, "Detected a PSU: %s/%s", ipmi_dev.manufacturer ? ipmi_dev.manufacturer : "unknown", ipmi_dev.product ? ipmi_dev.product : "unknown"); dstate_setinfo ("device.type", "psu"); /* Publish information from the IPMI structure */ if (ipmi_dev.manufacturer) dstate_setinfo("device.mfr", "%s", ipmi_dev.manufacturer); if (ipmi_dev.product) dstate_setinfo("device.model", "%s", ipmi_dev.product); if (ipmi_dev.serial) dstate_setinfo("device.serial", "%s", ipmi_dev.serial); if (ipmi_dev.part) dstate_setinfo("device.part", "%s", ipmi_dev.part); if (ipmi_dev.date) dstate_setinfo("device.mfr.date", "%s", ipmi_dev.date); /* FIXME: move to device.id */ dstate_setinfo("ups.id", "%i", ipmi_id); /* FIXME: move to device.realpower.nominal */ if (ipmi_dev.overall_capacity != -1) dstate_setinfo("ups.realpower.nominal", "%i", ipmi_dev.overall_capacity); /* FIXME: Did older FreeIPMI with "unsigned int" voltage ranges * have a way to report invalid readings? */ #ifdef HAVE_FREEIPMI_11X_12X if (ipmi_dev.input_minvoltage != -1) #endif dstate_setinfo("input.voltage.minimum", "%i", ipmi_dev.input_minvoltage); #ifdef HAVE_FREEIPMI_11X_12X if (ipmi_dev.input_maxvoltage != -1) #endif dstate_setinfo("input.voltage.maximum", "%i", ipmi_dev.input_maxvoltage); if (ipmi_dev.input_minfreq != -1) dstate_setinfo("input.frequency.low", "%i", ipmi_dev.input_minfreq); if (ipmi_dev.input_maxfreq != -1) dstate_setinfo("input.frequency.high", "%i", ipmi_dev.input_maxfreq); /* FIXME: move to device.voltage */ if (ipmi_dev.voltage != -1) dstate_setinfo("ups.voltage", "%i", ipmi_dev.voltage); if (nut_ipmi_monitoring_init() != 0) fatalx(EXIT_FAILURE, "Can't initialize IPMI monitoring"); if (nut_ipmi_get_sensors_status(&ipmi_dev) != 0) { upsdebugx(1, "Error while updating sensors values"); dstate_datastale(); } else { dstate_dataok(); } /* upsh.instcmd = instcmd; */ } void upsdrv_updateinfo(void) { upsdebugx(1, "upsdrv_updateinfo..."); /* FIXME: implement sensors monitoring */ if (nut_ipmi_get_sensors_status(&ipmi_dev) != 0) { upsdebugx(1, "Error while updating sensors values"); dstate_datastale(); } else { dstate_dataok(); } /* * poll_interval = 2; */ } void upsdrv_shutdown(void) { /* replace with a proper shutdown function */ upslogx(LOG_ERR, "shutdown not supported"); set_exit_flag(-1); } /* static int instcmd(const char *cmdname, const char *extra) { if (!strcasecmp(cmdname, "test.battery.stop")) { ser_send_buf(upsfd, ...); return STAT_INSTCMD_HANDLED; } upslogx(LOG_NOTICE, "instcmd: unknown command [%s]", cmdname); return STAT_INSTCMD_UNKNOWN; } */ /* static int setvar(const char *varname, const char *val) { if (!strcasecmp(varname, "ups.test.interval")) { ser_send_buf(upsfd, ...); return STAT_SET_HANDLED; } upslogx(LOG_NOTICE, "setvar: unknown variable [%s]", varname); return STAT_SET_UNKNOWN; } */ void upsdrv_help(void) { } /* list flags and values that you want to receive via -x */ void upsdrv_makevartable(void) { /* FIXME: need more params. addvar(VAR_VALUE, "username", "Remote server username"); addvar(VAR_VALUE, "password", "Remote server password"); addvar(VAR_VALUE, "authtype", "Authentication type to use during lan session activation"); addvar(VAR_VALUE, "type", "Type of the device to match ('psu' for \"Power Supply\")"); addvar(VAR_VALUE, "serial", "Serial number to match a specific device"); addvar(VAR_VALUE, "fruid", "FRU identifier to match a specific device"); */ } void upsdrv_initups(void) { upsdebugx(1, "upsdrv_initups..."); /* port can be expressed in various forms: * - inband: * "id?" for device (FRU) ID 0x? * "psu?" for PSU number ? * - out of band * "id?@host" * "host" => requires serial or ... */ if (!strncmp( device_path, "id", 2)) { ipmi_id = atoi(device_path+2); upsdebugx(2, "Device ID 0x%i", ipmi_id); } /* else... to select PSU number X */ /* Clear the interface structure */ ipmi_dev.ipmi_id = -1; ipmi_dev.manufacturer = NULL; ipmi_dev.product = NULL; ipmi_dev.serial = NULL; ipmi_dev.part = NULL; ipmi_dev.date = NULL; ipmi_dev.overall_capacity = -1; ipmi_dev.input_minvoltage = -1; ipmi_dev.input_maxvoltage = -1; ipmi_dev.input_minfreq = -1; ipmi_dev.input_maxfreq = -1; ipmi_dev.voltage = -1; ipmi_dev.sensors_count = 0; ipmi_dev.status = -1; ipmi_dev.input_voltage = -1; ipmi_dev.input_current = -1; ipmi_dev.temperature = -1; /* Open IPMI using the above */ nut_ipmi_open(ipmi_id, &ipmi_dev); /* the upsh handlers can't be done here, as they get initialized * shortly after upsdrv_initups returns to main. */ /* don't try to detect the UPS here */ } void upsdrv_cleanup(void) { upsdebugx(1, "upsdrv_cleanup..."); nut_ipmi_close(); } nut-2.8.1/drivers/isbmex.c0000644000175000017500000002306014501607135012365 00000000000000/* isbmex.c - model specific routines for SOLA/BASIC Mexico (ISBMEX) models Copyright (C) 2005 Ricardo Martinezgarza Copyright (C) 2002 Edscott Wilson Garcia Copyright (C) 1999 Russell Kroll 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 2 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, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "main.h" #include "serial.h" #include /* for sqrt */ #include #define DRIVER_NAME "ISBMEX UPS driver" #define DRIVER_VERSION "0.08" /* driver description structure */ upsdrv_info_t upsdrv_info = { DRIVER_NAME, DRIVER_VERSION, "Ricardo Martinezgarza \n" \ "Edscott Wilson Garcia \n" \ "Russell Kroll ", DRV_STABLE, { NULL } }; /* FIXME: Replace with proper upsdebugx() et al */ #define xDEBUG #ifdef DEBUG #define D(x) x #else #define D(x) #endif /*#define ENDCHAR '&'*/ #define MAXTRIES 15 /* #define IGNCHARS "" */ static float lagrange(unsigned int vbyte) { float f0, f1, f2, f3, f4, f5, f6; float a, b, c, d, e, g, h; const float x0=144.0, x1=154.0, x2=184.0, x3=195.0, x4=215.0, x5=228.0, x6=249.0; const float fX0=95.1, fX1=98.3, fX2=112.6, fX3=116.5, fX4=126.0, fX5=131.0, fX6=140.3; if(vbyte < 144) return 0.0; f0 = vbyte - x0; f1 = vbyte - x1; f2 = vbyte - x2; f3 = vbyte - x3; f4 = vbyte - x4; f5 = vbyte - x5; f6 = vbyte - x6; b = (f1 * f2 * f3 * f4 * f5 * f6 * fX0)/((x0 - x1) * (x0 - x2)); b = b / ((x0 - x3) * (x0 - x4)); b = b / ((x0 - x5) * (x0 - x6)); c = (f0 * f2 * f3 * f4 * f5 * f6 * fX1)/((x1 - x0) * (x1 - x2)); c = c / ((x1 - x3) * (x1 - x4)); c = c / ((x1 - x5) * (x1 - x6)); d = (f0 * f1 * f3 * f4 * f5 * f6 * fX2)/((x2 - x0) * (x2 - x1)); d = d / ((x2 - x3) * (x2 - x4)); d = d / ((x2 - x5) * (x2 - x6)); e = (f0 * f1 * f2 * f4 * f5 * f6 * fX3)/((x3 - x0) * (x3 - x1)); e = e / ((x3 - x2) * (x3 - x4)); e = e / ((x3 - x5) * (x3 - x6)); a = (f0 * f1 * f2 * f3 * f5 * f6 * fX4)/((x4 - x0) * (x4 - x1)); a = a / ((x4 - x2) * (x4 - x3)); a = a / ((x4 - x5) * (x4 - x6)); g = (f0 * f1 * f2 * f3 * f4 * f6 * fX5)/((x5 - x0) * (x5 - x1)); g = g / ((x5 - x2) * (x5 - x3)); g = g / ((x5 - x4) * (x5 - x6)); h = (f0 * f1 * f2 * f3 * f4 * f5 * fX6)/((x6 - x0) * (x6 - x1)); h = h / ((x6 - x2) * (x6 - x3)); h = h / ((x6 - x4) * (x6 - x5)); return a + b + c + d + e + g + h; } static float interpol(float vbytes) { const int x[7]={75,83,87,98,103,118,145}; const float f[7]={96.0,102.0,105.0,113.0,116.0,124.0,140.0}; float l[7]; float t, volts; const int n=6; int i, j; if(vbytes < x[0]) return 0.0; if(vbytes > x[6]) return f[6]; for(i=0; i<=n; i++) { if((int)vbytes == x[i]) return f[i]; } for(i=0; i<=n; i++) { l[i] = 1.0; for(j=0; j<=n; j++) { if(j!=i) l[i] *= (float)(x[i] - x[j]); } l[i] = f[i] / l[i]; } t = 1.0; for(i=0; i<=n; i++) t *= (vbytes - (float)x[i]); volts = 0.0; for(i=0; i<=n; i++) volts += (l[i] * t / (vbytes - (float)x[i])); return volts; } void upsdrv_initinfo(void) { dstate_setinfo("ups.mfr", "Sola/Basic Mexico"); dstate_setinfo("ups.model", "SR-Inet 280/300/400/480/500/800/1000"); /* high/low voltage */ dstate_setinfo("input.transfer.low", "102.0"); /* defined */ dstate_setinfo("input.transfer.high", "140.0"); /* defined */ dstate_setinfo("output.voltage", "120.0"); /* defined */ /* addinfo(INFO_, "", 0, 0); */ /*printf("Using %s %s on %s\n", getdata(INFO_MFR), getdata(INFO_MODEL), device_path);*/ } static const char *getpacket(int *we_know){ #ifndef WIN32 fd_set readfds; struct timeval tv; int ret; #endif int bytes_per_packet=0; static const char *packet_id=NULL; static char buf[256]; const char *s; ssize_t r; bytes_per_packet=*we_know; D(printf("getpacket with %d\n",bytes_per_packet);) #ifndef WIN32 FD_ZERO(&readfds); FD_SET(upsfd,&readfds); /* Wait up to 2 seconds. */ tv.tv_sec = 5; tv.tv_usec = 0; ret = select(upsfd+1, &readfds, NULL, NULL, &tv); if (!ret) { s = "Nothing received from UPS. Check cable conexion"; upslogx(LOG_ERR, "%s", s); D(printf("%s\n",s);) return NULL; } r = read(upsfd,buf,255); #else r = select_read(upsfd,buf,255,5,0); if (r <= 0) { s = "Nothing received from UPS. Check cable conexion"; upslogx(LOG_ERR, "%s", s); D(printf("%s\n",s);) return NULL; } #endif D(printf("%" PRIiSIZE " bytes read: ",r);) buf[r]=0; if (bytes_per_packet && r < bytes_per_packet){ ssize_t rr; D(printf("short read...\n");) usleep(500000); #ifndef WIN32 tv.tv_sec = 2; tv.tv_usec = 0; ret = select(upsfd+1, &readfds, NULL, NULL, &tv); if (!ret) return NULL; /* Casting is okay since bytes_per_packet is small * and r is smaller, so 255-r is positive */ assert (r <= 255); rr = read(upsfd, buf+r, (size_t)(255-r)); #else rr = select_read(upsfd,buf+r,255-r,2,0); if (rr <= 0) { return NULL; } #endif r += rr; if (r < bytes_per_packet) return NULL; } if (!bytes_per_packet){ /* packet size determination */ /* if (r%10 && r%9) { printf("disregarding incomplete packet\n"); return NULL; } */ if (r%10==0) *we_know=10; else if (r%9==0) *we_know=9; return NULL; } /* by here we have bytes_per_packet and a complete packet */ /* lets check if within the complete packet we have a valid packet */ if (bytes_per_packet == 10) packet_id="&&&"; else packet_id="***"; s=strstr(buf,packet_id); /* check validity of packet */ if (!s) { s="isbmex: no valid packet signature!"; upslogx(LOG_ERR, "%s", s); D(printf("%s\n",s);) *we_know=0; return NULL; } D(if (s != buf) printf("overlapping packet received\n");) if ((int) strlen(s) < bytes_per_packet) { D(printf("incomplete packet information\n");) return NULL; } #ifdef DEBUG printf("Got signal:"); {int i;for (i=0;i",(unsigned char)s[i]);} printf("\n"); #endif return s; } void upsdrv_updateinfo(void) { static float high_volt=-1, low_volt=999; const char *buf=NULL; char buf2[17]; int i; static int bytes_per_packet=0; for (i=0;i<5;i++) { if ((buf=getpacket(&bytes_per_packet)) != NULL) break; } if (!bytes_per_packet || !buf) { dstate_datastale(); return; } /* do the parsing */ { float in_volt,battpct,acfreq; double d; D(printf("parsing (%d bytes per packet)\n",bytes_per_packet);) /* input voltage :*/ if (bytes_per_packet==9) { in_volt = lagrange((unsigned char)buf[3]); } else { in_volt = interpol(sqrt((float)((unsigned char)buf[3]*256+(unsigned char)buf[4]))); } snprintf(buf2,16,"%5.1f",in_volt); D(printf("utility=%s\n",buf2);) dstate_setinfo("input.voltage", "%s", buf2); if (in_volt >= high_volt) high_volt=in_volt; snprintf(buf2,16,"%5.1f",high_volt); D(printf("highvolt=%s\n",buf2);) dstate_setinfo("input.voltage.maximum", "%s", buf2); if (in_volt <= low_volt) low_volt=in_volt; snprintf(buf2,16,"%5.1f",low_volt); D(printf("lowvolt=%s\n",buf2);) dstate_setinfo("input.voltage.minimum", "%s", buf2); battpct = ((double)((unsigned char)buf[(bytes_per_packet==10)?5:4])-168.0)*(100.0/(215.0-168.0)); snprintf(buf2,16,"%5.1f",battpct); D(printf("battpct=%s\n",buf2);) dstate_setinfo("battery.charge", "%s", buf2); d=(unsigned char)buf[(bytes_per_packet==10)?6:5]*256 + (unsigned char)buf[(bytes_per_packet==10)?7:6]; acfreq = 1000000/d; snprintf(buf2,16,"%5.2f",acfreq); D(printf("acfreq=%s\n",buf2);) dstate_setinfo("input.frequency", "%s", buf2); D(printf("status: ");) status_init(); switch (buf[(bytes_per_packet==10)?8:7]){ case 48: break; /* normal operation */ case 49: D(printf("BOOST ");) status_set("BOOST"); break; case 50: D(printf("TRIM ");) status_set("TRIM"); break; default: break; } switch (buf[(bytes_per_packet==10)?9:8]){ case 48: D(printf("OL ");) status_set("OL"); break; case 50: D(printf("LB ");) status_set("LB"); /* break; */ /* FIXME? Can this device set independently LB and OB? */ goto fallthrough_LB_means_OB; /* FALLTHRU */ case 49: fallthrough_LB_means_OB: D(printf("OB ");) status_set("OB"); break; default: break; } D(printf("\n");) status_commit(); } dstate_dataok(); return; } void upsdrv_shutdown(void) { /* shutdown is supported on models with * contact closure. Some ISB models with serial * support support contact closure, some don't. * If yours does support it, then a 12V signal * on pin 9 does the trick (only when ups is * on OB condition) */ /* * here try to do the pin 9 trick, if it does not * work, else:*/ /* upslogx(LOG_ERR, "Shutdown only supported with the Generic Driver, type 6 and special cable"); //upslogx(LOG_ERR, "shutdown not supported"); set_exit_flag(-1); */ int i; for(i=0;i<=5;i++) { ser_send_char(upsfd, '#'); usleep(50000); } } void upsdrv_help(void) { } /* list flags and values that you want to receive via -x */ void upsdrv_makevartable(void) { } void upsdrv_initups(void) { upsfd = ser_open(device_path); ser_set_speed(upsfd, device_path, B9600); } void upsdrv_cleanup(void) { ser_close(upsfd, device_path); } nut-2.8.1/drivers/eaton-pdu-marlin-helpers.h0000644000175000017500000000227014500336654015723 00000000000000/* eaton-pdu-marlin-helpers.h - helper for subdriver to monitor certain * Eaton ePDU SNMP devices with NUT * * Copyright (C) * 2017-2019 Arnaud Quette * 2017 Jim Klimov * * 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 2 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, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef EATON_EPDU_MARLIN_HELPERS_H #define EATON_EPDU_MARLIN_HELPERS_H long marlin_device_count_fun(const char *daisy_dev_list); const char *eaton_sensor_temperature_unit_fun(void *raw_snmp_value); #endif /* EATON_EPDU_MARLIN_HELPERS_H */ nut-2.8.1/drivers/nutdrv_qx_voltronic-qs.c0000644000175000017500000002047014501607135015652 00000000000000/* nutdrv_qx_voltronic-qs.c - Subdriver for Voltronic Power UPSes with QS protocol * * Copyright (C) * 2013 Daniele Pezzini * * 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 2 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, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #include "main.h" #include "nutdrv_qx.h" #include "nutdrv_qx_blazer-common.h" #include "nutdrv_qx_voltronic-qs.h" #define VOLTRONIC_QS_VERSION "Voltronic-QS 0.09" /* Support functions */ static int voltronic_qs_claim(void); static void voltronic_qs_initups(void); /* Preprocess functions */ static int voltronic_qs_protocol(item_t *item, char *value, const size_t valuelen); /* == Ranges == */ /* Range for ups.delay.start */ static info_rw_t voltronic_qs_r_ondelay[] = { { "60", 0 }, { "599940", 0 }, { "", 0 } }; /* Range for ups.delay.shutdown */ static info_rw_t voltronic_qs_r_offdelay[] = { { "12", 0 }, { "540", 0 }, { "", 0 } }; /* == qx2nut lookup table == */ static item_t voltronic_qs_qx2nut[] = { /* Query UPS for protocol * > [M\r] * < [V\r] * 01 * 0 */ { "ups.firmware.aux", 0, NULL, "M\r", "", 2, 0, "", 0, 0, "PM-%s", QX_FLAG_STATIC, NULL, NULL, voltronic_qs_protocol }, /* Query UPS for status * > [QS\r] * < [(226.0 195.0 226.0 014 49.0 27.5 30.0 00001000\r] * 01234567890123456789012345678901234567890123456 * 0 1 2 3 4 */ { "input.voltage", 0, NULL, "QS\r", "", 47, '(', "", 1, 5, "%.1f", 0, NULL, NULL, NULL }, { "input.voltage.fault", 0, NULL, "QS\r", "", 47, '(', "", 7, 11, "%.1f", 0, NULL, NULL, NULL }, { "output.voltage", 0, NULL, "QS\r", "", 47, '(', "", 13, 17, "%.1f", 0, NULL, NULL, NULL }, { "ups.load", 0, NULL, "QS\r", "", 47, '(', "", 19, 21, "%.0f", 0, NULL, NULL, NULL }, { "output.frequency", 0, NULL, "QS\r", "", 47, '(', "", 23, 26, "%.1f", 0, NULL, NULL, NULL }, { "battery.voltage", 0, NULL, "QS\r", "", 47, '(', "", 28, 31, "%.2f", 0, NULL, NULL, qx_multiply_battvolt }, { "ups.temperature", 0, NULL, "QS\r", "", 47, '(', "", 33, 36, "%.1f", 0, NULL, NULL, NULL }, /* Status bits */ { "ups.status", 0, NULL, "QS\r", "", 47, '(', "", 38, 38, NULL, QX_FLAG_QUICK_POLL, NULL, NULL, blazer_process_status_bits }, /* Utility Fail (Immediate) */ { "ups.status", 0, NULL, "QS\r", "", 47, '(', "", 39, 39, NULL, QX_FLAG_QUICK_POLL, NULL, NULL, blazer_process_status_bits }, /* Battery Low */ { "ups.status", 0, NULL, "QS\r", "", 47, '(', "", 40, 40, NULL, QX_FLAG_QUICK_POLL, NULL, NULL, blazer_process_status_bits }, /* Bypass/Boost or Buck Active */ { "ups.alarm", 0, NULL, "QS\r", "", 47, '(', "", 41, 41, NULL, 0, NULL, NULL, blazer_process_status_bits }, /* UPS Failed */ { "ups.type", 0, NULL, "QS\r", "", 47, '(', "", 42, 42, "%s", QX_FLAG_STATIC, NULL, NULL, blazer_process_status_bits }, /* UPS Type */ { "ups.status", 0, NULL, "QS\r", "", 47, '(', "", 43, 43, NULL, QX_FLAG_QUICK_POLL, NULL, NULL, blazer_process_status_bits }, /* Test in Progress */ { "ups.status", 0, NULL, "QS\r", "", 47, '(', "", 44, 44, NULL, QX_FLAG_QUICK_POLL, NULL, NULL, blazer_process_status_bits }, /* Shutdown Active */ { "ups.beeper.status", 0, NULL, "QS\r", "", 47, '(', "", 45, 45, "%s", 0, NULL, NULL, blazer_process_status_bits }, /* Beeper status */ /* Query UPS for ratings * > [F\r] * < [#220.0 003 12.00 50.0\r] * 0123456789012345678901 * 0 1 2 */ { "output.voltage.nominal", 0, NULL, "F\r", "", 22, '#', "", 1, 5, "%.0f", QX_FLAG_STATIC, NULL, NULL, NULL }, { "output.current.nominal", 0, NULL, "F\r", "", 22, '#', "", 7, 9, "%.1f", QX_FLAG_STATIC, NULL, NULL, NULL }, { "battery.voltage.nominal", 0, NULL, "F\r", "", 22, '#', "", 11, 15, "%.1f", QX_FLAG_STATIC, NULL, NULL, NULL }, { "output.frequency.nominal", 0, NULL, "F\r", "", 22, '#', "", 17, 20, "%.0f", QX_FLAG_STATIC, NULL, NULL, NULL }, /* Instant commands */ { "beeper.toggle", 0, NULL, "Q\r", "", 0, 0, "", 1, 3, NULL, QX_FLAG_CMD, NULL, NULL, NULL }, { "load.off", 0, NULL, "S00R0000\r", "", 0, 0, "", 1, 3, NULL, QX_FLAG_CMD, NULL, NULL, NULL }, { "load.on", 0, NULL, "C\r", "", 0, 0, "", 1, 3, NULL, QX_FLAG_CMD, NULL, NULL, NULL }, { "shutdown.return", 0, NULL, "S%s\r", "", 0, 0, "", 1, 3, NULL, QX_FLAG_CMD, NULL, NULL, blazer_process_command }, { "shutdown.stayoff", 0, NULL, "S%sR0000\r", "", 0, 0, "", 1, 3, NULL, QX_FLAG_CMD, NULL, NULL, blazer_process_command }, { "shutdown.stop", 0, NULL, "C\r", "", 0, 0, "", 1, 3, NULL, QX_FLAG_CMD, NULL, NULL, NULL }, { "test.battery.start.quick", 0, NULL, "T\r", "", 0, 0, "", 1, 3, NULL, QX_FLAG_CMD, NULL, NULL, NULL }, /* Server-side settable vars */ { "ups.delay.start", ST_FLAG_RW, voltronic_qs_r_ondelay, NULL, "", 0, 0, "", 0, 0, DEFAULT_ONDELAY, QX_FLAG_ABSENT | QX_FLAG_SETVAR | QX_FLAG_RANGE, NULL, NULL, blazer_process_setvar }, { "ups.delay.shutdown", ST_FLAG_RW, voltronic_qs_r_offdelay, NULL, "", 0, 0, "", 0, 0, DEFAULT_OFFDELAY, QX_FLAG_ABSENT | QX_FLAG_SETVAR | QX_FLAG_RANGE, NULL, NULL, blazer_process_setvar }, /* End of structure. */ { NULL, 0, NULL, NULL, "", 0, 0, "", 0, 0, NULL, 0, NULL, NULL, NULL } }; /* == Testing table == */ #ifdef TESTING static testing_t voltronic_qs_testing[] = { { "QS\r", "(215.0 195.0 230.0 014 49.0 22.7 30.0 00000000\r", -1 }, { "F\r", "#220.0 003 12.00 50.0\r", -1 }, { "M\r", "V\r", -1 }, { "Q\r", "", -1 }, { "C\r", "", -1 }, { "S02R0005\r", "", -1 }, { "S.5R0000\r", "", -1 }, { "T\r", "", -1 }, { NULL } }; #endif /* TESTING */ /* == Support functions == */ /* This function allows the subdriver to "claim" a device: return 1 if the device is supported by this subdriver, else 0. */ static int voltronic_qs_claim(void) { /* We need at least M and QS to run this subdriver */ /* UPS Protocol */ item_t *item = find_nut_info("ups.firmware.aux", 0, 0); /* Don't know what happened */ if (!item) return 0; /* No reply/Unable to get value */ if (qx_process(item, NULL)) return 0; /* Unable to process value/Protocol not supported */ if (ups_infoval_set(item) != 1) return 0; item = find_nut_info("input.voltage", 0, 0); /* Don't know what happened */ if (!item) { dstate_delinfo("ups.firmware.aux"); return 0; } /* No reply/Unable to get value */ if (qx_process(item, NULL)) { dstate_delinfo("ups.firmware.aux"); return 0; } /* Unable to process value */ if (ups_infoval_set(item) != 1) { dstate_delinfo("ups.firmware.aux"); return 0; } return 1; } /* Subdriver-specific initups */ static void voltronic_qs_initups(void) { blazer_initups_light(voltronic_qs_qx2nut); } /* == Preprocess functions == */ /* Protocol used by the UPS */ static int voltronic_qs_protocol(item_t *item, char *value, const size_t valuelen) { int ret = -1; if (!strcasecmp(item->value, "V")) { upsdebugx(2, "%s: detected V protocol [%s]", __func__, item->value); ret = 0; } else if (!strcasecmp(item->value, "H")) { upsdebugx(2, "%s: detected H protocol [%s]", __func__, item->value); ret = 0; } if (ret == -1) { upsdebugx(2, "%s: invalid protocol [%s]", __func__, item->value); } else { #ifdef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL #pragma GCC diagnostic push #endif #ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL #pragma GCC diagnostic ignored "-Wformat-nonliteral" #endif #ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_FORMAT_SECURITY #pragma GCC diagnostic ignored "-Wformat-security" #endif snprintf(value, valuelen, item->dfl, item->value); #ifdef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL #pragma GCC diagnostic pop #endif } return ret; } /* == Subdriver interface == */ subdriver_t voltronic_qs_subdriver = { VOLTRONIC_QS_VERSION, voltronic_qs_claim, voltronic_qs_qx2nut, voltronic_qs_initups, NULL, blazer_makevartable_light, NULL, NULL, #ifdef TESTING voltronic_qs_testing, #endif /* TESTING */ }; nut-2.8.1/drivers/eaton-ups-pxg-mib.h0000644000175000017500000000023514501607135014356 00000000000000#ifndef POWERWARE_MIB_H #define POWERWARE_MIB_H #include "main.h" #include "snmp-ups.h" extern mib2nut_info_t eaton_pxg_ups; #endif /* POWERWARE_MIB_H */ nut-2.8.1/drivers/etapro.c0000644000175000017500000002203614501607135012372 00000000000000/* etapro.c - model specific routines for ETA UPS Copyright (C) 2002 Marek Michalkiewicz 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 2 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, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ /* This driver is for the ETA UPS (http://www.eta.com.pl/) with the "PRO" option (available at small added cost, highly recommended). All units (even without that option) should also work in "dumb" mode with the genericups driver (type 7 or 10), but in that mode shutdown only works when running on battery. Tested with ETA mini+UPS 720 PRO. Thanks to ETA for help with protocol documentation, no free UPS though (but they still can send me another one if they like me ;-). Shutdown should work even when on line, so this should help avoid power races (system remaining in halted or "ATX standby" state, requiring manual intervention). Delay from power off to power on can be set in software, currently hardcoded to 15 seconds. Instant commands CMD_OFF and CMD_ON should work (not tested yet). Be careful with CMD_OFF - it turns off the load after one second. Known issues: - larger units (>= 1000VA) have a 24V battery, so the battery voltage reported should be multiplied by 2 if the model string indicates such a larger unit. - load percentage is only measured when running on battery, and is reported as 0 when on line. This seems to be a hardware limitation of the UPS, so we can't do much about it... - UPS does not provide any remaining battery charge (or time at current load) information, but we should be able to estimate it based on battery voltage, load percentage and UPS model. - error handling not tested (we assume that the UPS is always correctly connected to the serial port). */ #include "main.h" #include "serial.h" #include "nut_stdint.h" #define DRIVER_NAME "ETA PRO driver" #define DRIVER_VERSION "0.06" /* driver description structure */ upsdrv_info_t upsdrv_info = { DRIVER_NAME, DRIVER_VERSION, "Marek Michalkiewicz ", DRV_STABLE, { NULL } }; static int etapro_get_response(const char *resp_type) { char tmp[256]; char *cp; unsigned int n, val; /* Read until a newline is found or there is no room in the buffer. Unlike ser_get_line(), don't discard the following characters because we have to handle multi-line responses. */ n = 0; while (ser_get_char(upsfd, (unsigned char *)&tmp[n], 1, 0) == 1) { if (n >= sizeof(tmp) - 1 || tmp[n] == '\n') break; n++; } tmp[n] = '\0'; if (n == 0) { upslogx(LOG_ERR, "no response from UPS"); return -1; } /* Search for start of response (skip any echoed back command). */ cp = strstr(tmp, resp_type); if (!cp || *cp == '\0' || cp[strlen(cp) - 1] != '\r') { upslogx(LOG_ERR, "bad response (%s)", tmp); return -1; } cp[strlen(cp) - 1] = '\0'; /* remove the CR */ switch (cp[1]) { /* Handle ASCII text responses directly here. */ case 'R': dstate_setinfo("ups.mfr", "%s", cp + 2); return 0; case 'S': dstate_setinfo("ups.model", "%s", cp + 2); return 0; case 'T': dstate_setinfo("ups.mfr.date", "%s", cp + 2); return 0; } /* Handle all other responses as hexadecimal numbers. */ val = 0; if (sscanf(cp + 2, "%x", &val) != 1) { upslogx(LOG_ERR, "bad response format (%s)", tmp); return -1; } if (val > INT_MAX) { upslogx(LOG_WARNING, "got value too big in response"); } return (int)val; } static void etapro_set_on_timer(int seconds) { int x; if (seconds == 0) { /* cancel the running timer */ ser_send(upsfd, "RS\r"); x = etapro_get_response("SV"); if (x == 0x30) return; /* OK */ } else { if (seconds > 0x7fff) { /* minutes */ seconds = (seconds + 59) / 60; if (seconds > 0x7fff) seconds = 0x7fff; printf("UPS on in %d minutes\n", seconds); seconds |= 0x8000; } else { printf("UPS on in %d seconds\n", seconds); } ser_send(upsfd, "RN%04X\r", seconds); x = etapro_get_response("SV"); if (x == 0x20) return; /* OK */ } upslogx(LOG_ERR, "etapro_set_on_timer: error, status=0x%02x", x); } static void etapro_set_off_timer(int seconds) { int x; if (seconds == 0) { /* cancel the running timer */ ser_send(upsfd, "RR\r"); x = etapro_get_response("SV"); if (x == 0x10) return; /* OK */ } else { if (seconds > 0x7fff) { /* minutes */ seconds /= 60; if (seconds > 0x7fff) seconds = 0x7fff; printf("UPS off in %d minutes\n", seconds); seconds |= 0x8000; } else { printf("UPS off in %d seconds\n", seconds); } ser_send(upsfd, "RO%04X\r", seconds); x = etapro_get_response("SV"); if (x == 0) return; /* OK */ } upslogx(LOG_ERR, "etapro_set_off_timer: error, status=0x%02x", x); } static int instcmd(const char *cmdname, const char *extra) { if (!strcasecmp(cmdname, "load.off")) { etapro_set_off_timer(1); return STAT_INSTCMD_HANDLED; } if (!strcasecmp(cmdname, "load.on")) { etapro_set_on_timer(1); return STAT_INSTCMD_HANDLED; } if (!strcasecmp(cmdname, "shutdown.return")) { upsdrv_shutdown(); return STAT_INSTCMD_HANDLED; } upslogx(LOG_NOTICE, "instcmd: unknown command [%s] [%s]", cmdname, extra); return STAT_INSTCMD_UNKNOWN; } void upsdrv_initinfo(void) { dstate_addcmd("load.off"); dstate_addcmd("load.on"); dstate_addcmd("shutdown.return"); /* First command after power on returns junk - ignore it. */ ser_send(upsfd, "RI\r"); sleep(1); upsdrv_updateinfo(); upsh.instcmd = instcmd; } void upsdrv_updateinfo(void) { int x, flags; double utility, outvolt, battvolt, loadpct; ser_flush_in(upsfd, "", nut_debug_level); ser_send(upsfd, "RI\r"); /* identify */ x = etapro_get_response("SR"); /* manufacturer */ if (x < 0) { dstate_datastale(); return; } x = etapro_get_response("SS"); /* model */ if (x < 0) { dstate_datastale(); return; } x = etapro_get_response("ST"); /* mfr date */ if (x < 0) { dstate_datastale(); return; } x = etapro_get_response("SU"); /* UPS ident */ if (x < 0) { dstate_datastale(); return; } ser_send(upsfd, "RP\r"); /* read measurements */ x = etapro_get_response("SO"); /* status flags */ if (x < 0) { dstate_datastale(); return; } flags = x; x = etapro_get_response("SG"); /* input voltage, 0xFF = 270V */ if (x < 0) { dstate_datastale(); return; } utility = (270.0 / 255) * x; x = etapro_get_response("SH"); /* output voltage, 0xFF = 270V */ if (x < 0) { dstate_datastale(); return; } outvolt = (270.0 / 255) * x; x = etapro_get_response("SI"); /* battery voltage, 0xFF = 14V */ if (x < 0) { dstate_datastale(); return; } /* TODO: >= 1000VA models have a 24V battery (max 28V) - check the model string returned by the RI command. */ battvolt = (14.0 / 255) * x; x = etapro_get_response("SL"); /* load (on battery), 0xFF = 150% */ if (x < 0) { dstate_datastale(); return; } loadpct = (150.0 / 255) * x; x = etapro_get_response("SN"); /* time running on battery */ if (x < 0) { dstate_datastale(); return; } /* This is the time how long the UPS has been running on battery (in seconds, reset to zero after power returns), but there seems to be no variable defined for this yet... */ status_init(); if (!(flags & 0x02)) status_set("OFF"); else if (flags & 0x01) status_set("OL"); else status_set("OB"); if (!(flags & 0x04)) status_set("LB"); /* TODO bit 3: 1 = ok, 0 = fault */ if (flags & 0x10) status_set("BOOST"); if (loadpct > 100.0) status_set("OVER"); /* Battery voltage out of range (lower than LB, or too high). */ if (flags & 0x20) status_set("RB"); /* TODO bit 6: 1 = charging, 0 = full */ status_commit(); dstate_setinfo("input.voltage", "%03.1f", utility); dstate_setinfo("output.voltage", "%03.1f", outvolt); dstate_setinfo("battery.voltage", "%02.2f", battvolt); dstate_setinfo("ups.load", "%03.1f", loadpct); dstate_dataok(); } /* TODO: delays should be tunable, the UPS supports max 32767 minutes. */ /* Shutdown command to off delay in seconds. */ #define SHUTDOWN_GRACE_TIME 10 /* Shutdown to return delay in seconds. */ #define SHUTDOWN_TO_RETURN_TIME 15 void upsdrv_shutdown(void) { etapro_set_on_timer(SHUTDOWN_GRACE_TIME + SHUTDOWN_TO_RETURN_TIME); etapro_set_off_timer(SHUTDOWN_GRACE_TIME); } void upsdrv_help(void) { } void upsdrv_makevartable(void) { } void upsdrv_initups(void) { upsfd = ser_open(device_path); ser_set_speed(upsfd, device_path, B1200); ser_set_dtr(upsfd, 0); ser_set_rts(upsfd, 1); } void upsdrv_cleanup(void) { ser_close(upsfd, device_path); } nut-2.8.1/drivers/nutdrv_qx_megatec.h0000644000175000017500000000176114273170601014625 00000000000000/* nutdrv_qx_megatec.h - Subdriver for Megatec protocol based UPSes * * Copyright (C) * 2013 Daniele Pezzini * * 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 2 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, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #ifndef NUTDRV_QX_MEGATEC_H #define NUTDRV_QX_MEGATEC_H #include "nutdrv_qx.h" extern subdriver_t megatec_subdriver; #endif /* NUTDRV_QX_MEGATECH_H */ nut-2.8.1/drivers/nutdrv_qx_voltronic-qs-hex.c0000644000175000017500000004502714500336654016445 00000000000000/* nutdrv_qx_voltronic-qs-hex.c - Subdriver for Voltronic Power UPSes with QS-Hex protocol * * Copyright (C) * 2014 Daniele Pezzini * * 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 2 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, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #include "main.h" #include "nutdrv_qx.h" #include "nutdrv_qx_blazer-common.h" #include "nutdrv_qx_voltronic-qs-hex.h" #define VOLTRONIC_QS_HEX_VERSION "Voltronic-QS-Hex 0.10" /* Support functions */ static int voltronic_qs_hex_claim(void); static void voltronic_qs_hex_initups(void); /* Answer preprocess functions */ static int voltronic_qs_hex_preprocess_qs_answer(item_t *item, const int len); static int voltronic_qs_hex_char_to_binary(const unsigned char value); /* Preprocess functions */ static int voltronic_qs_hex_protocol(item_t *item, char *value, const size_t valuelen); static int voltronic_qs_hex_input_output_voltage(item_t *item, char *value, const size_t valuelen); static int voltronic_qs_hex_load(item_t *item, char *value, const size_t valuelen); static int voltronic_qs_hex_frequency(item_t *item, char *value, const size_t valuelen); static int voltronic_qs_hex_battery_voltage(item_t *item, char *value, const size_t valuelen); static int voltronic_qs_hex_process_ratings_bits(item_t *item, char *value, const size_t valuelen); /* == Ranges == */ /* Range for ups.delay.start */ static info_rw_t voltronic_qs_hex_r_ondelay[] = { { "60", 0 }, { "599940", 0 }, { "", 0 } }; /* Range for ups.delay.shutdown */ static info_rw_t voltronic_qs_hex_r_offdelay[] = { { "12", 0 }, { "540", 0 }, { "", 0 } }; /* == qx2nut lookup table == */ static item_t voltronic_qs_hex_qx2nut[] = { /* Query UPS for protocol * > [M\r] * < [P\r] * 01 * 0 */ { "ups.firmware.aux", 0, NULL, "M\r", "", 2, 0, "", 0, 0, "PM-%s", QX_FLAG_STATIC, NULL, NULL, voltronic_qs_hex_protocol }, /* Query UPS for status * > [QS\r] * < [#6C01 35 6C01 35 03 519A 1312D0 E6 1E 00001001\r] ('P' protocol, after being preprocessed) * < [#6901 6C 6802 6C 00 5FD7 12C000 E4 1E 00001001 00000010\r] ('T' protocol, after being preprocessed) * 01234567890123456789012345678901234567890123456789012345 * 0 1 2 3 4 5 */ { "input.voltage", 0, NULL, "QS\r", "", 47, '#', "", 1, 7, "%.1f", 0, NULL, voltronic_qs_hex_preprocess_qs_answer, voltronic_qs_hex_input_output_voltage }, { "output.voltage", 0, NULL, "QS\r", "", 47, '#', "", 9, 15, "%.1f", 0, NULL, voltronic_qs_hex_preprocess_qs_answer, voltronic_qs_hex_input_output_voltage }, { "ups.load", 0, NULL, "QS\r", "", 47, '#', "", 17, 18, "%d", 0, NULL, voltronic_qs_hex_preprocess_qs_answer, voltronic_qs_hex_load }, { "output.frequency", 0, NULL, "QS\r", "", 47, '#', "", 20, 30, "%.1f", 0, NULL, voltronic_qs_hex_preprocess_qs_answer, voltronic_qs_hex_frequency }, { "battery.voltage", 0, NULL, "QS\r", "", 47, '#', "", 32, 36, "%.2f", 0, NULL, voltronic_qs_hex_preprocess_qs_answer, voltronic_qs_hex_battery_voltage }, /* Status bits */ { "ups.status", 0, NULL, "QS\r", "", 47, '#', "", 38, 38, NULL, QX_FLAG_QUICK_POLL, NULL, voltronic_qs_hex_preprocess_qs_answer, blazer_process_status_bits }, /* Utility Fail (Immediate) */ { "ups.status", 0, NULL, "QS\r", "", 47, '#', "", 39, 39, NULL, QX_FLAG_QUICK_POLL, NULL, voltronic_qs_hex_preprocess_qs_answer, blazer_process_status_bits }, /* Battery Low */ { "ups.status", 0, NULL, "QS\r", "", 47, '#', "", 40, 40, NULL, QX_FLAG_QUICK_POLL, NULL, voltronic_qs_hex_preprocess_qs_answer, blazer_process_status_bits }, /* Bypass/Boost or Buck Active */ { "ups.alarm", 0, NULL, "QS\r", "", 47, '#', "", 41, 41, NULL, 0, NULL, voltronic_qs_hex_preprocess_qs_answer, blazer_process_status_bits }, /* UPS Failed */ { "ups.type", 0, NULL, "QS\r", "", 47, '#', "", 42, 42, "%s", QX_FLAG_STATIC, NULL, voltronic_qs_hex_preprocess_qs_answer, blazer_process_status_bits }, /* UPS Type */ { "ups.status", 0, NULL, "QS\r", "", 47, '#', "", 43, 43, NULL, QX_FLAG_QUICK_POLL, NULL, voltronic_qs_hex_preprocess_qs_answer, blazer_process_status_bits }, /* Test in Progress */ { "ups.status", 0, NULL, "QS\r", "", 47, '#', "", 44, 44, NULL, QX_FLAG_QUICK_POLL, NULL, voltronic_qs_hex_preprocess_qs_answer, blazer_process_status_bits }, /* Shutdown Active */ { "ups.beeper.status", 0, NULL, "QS\r", "", 47, '#', "", 45, 45, "%s", 0, NULL, voltronic_qs_hex_preprocess_qs_answer, blazer_process_status_bits }, /* Beeper status */ /* Ratings bits */ { "output.frequency.nominal", 0, NULL, "QS\r", "", 56, '#', "", 47, 47, "%.1f", QX_FLAG_SKIP, NULL, voltronic_qs_hex_preprocess_qs_answer, voltronic_qs_hex_process_ratings_bits }, { "battery.voltage.nominal", 0, NULL, "QS\r", "", 56, '#', "", 48, 49, "%.1f", QX_FLAG_SKIP, NULL, voltronic_qs_hex_preprocess_qs_answer, voltronic_qs_hex_process_ratings_bits }, /* { "reserved.1", 0, NULL, "QS\r", "", 56, '#', "", 50, 50, "%s", QX_FLAG_SKIP, NULL, voltronic_qs_hex_preprocess_qs_answer, voltronic_qs_hex_process_ratings_bits }, *//* Reserved */ /* { "reserved.2", 0, NULL, "QS\r", "", 56, '#', "", 51, 51, "%s", QX_FLAG_SKIP, NULL, voltronic_qs_hex_preprocess_qs_answer, voltronic_qs_hex_process_ratings_bits }, *//* Reserved */ { "output.voltage.nominal", 0, NULL, "QS\r", "", 56, '#', "", 52, 54, "%.1f", QX_FLAG_SKIP, NULL, voltronic_qs_hex_preprocess_qs_answer, voltronic_qs_hex_process_ratings_bits }, /* Instant commands */ { "beeper.toggle", 0, NULL, "Q\r", "", 0, 0, "", 0, 0, NULL, QX_FLAG_CMD, NULL, NULL, NULL }, { "load.off", 0, NULL, "S00R0000\r", "", 0, 0, "", 0, 0, NULL, QX_FLAG_CMD, NULL, NULL, NULL }, { "load.on", 0, NULL, "C\r", "", 0, 0, "", 0, 0, NULL, QX_FLAG_CMD, NULL, NULL, NULL }, { "shutdown.return", 0, NULL, "S%s\r", "", 0, 0, "", 0, 0, NULL, QX_FLAG_CMD, NULL, NULL, blazer_process_command }, { "shutdown.stayoff", 0, NULL, "S%sR0000\r", "", 0, 0, "", 0, 0, NULL, QX_FLAG_CMD, NULL, NULL, blazer_process_command }, { "shutdown.stop", 0, NULL, "C\r", "", 0, 0, "", 0, 0, NULL, QX_FLAG_CMD, NULL, NULL, NULL }, { "test.battery.start.quick", 0, NULL, "T\r", "", 0, 0, "", 0, 0, NULL, QX_FLAG_CMD | QX_FLAG_SKIP, NULL, NULL, NULL }, /* Server-side settable vars */ { "ups.delay.start", ST_FLAG_RW, voltronic_qs_hex_r_ondelay, NULL, "", 0, 0, "", 0, 0, DEFAULT_ONDELAY, QX_FLAG_ABSENT | QX_FLAG_SETVAR | QX_FLAG_RANGE, NULL, NULL, blazer_process_setvar }, { "ups.delay.shutdown", ST_FLAG_RW, voltronic_qs_hex_r_offdelay, NULL, "", 0, 0, "", 0, 0, DEFAULT_OFFDELAY, QX_FLAG_ABSENT | QX_FLAG_SETVAR | QX_FLAG_RANGE, NULL, NULL, blazer_process_setvar }, /* End of structure. */ { NULL, 0, NULL, NULL, "", 0, 0, "", 0, 0, NULL, 0, NULL, NULL, NULL } }; /* == Testing table == */ #ifdef TESTING static testing_t voltronic_qs_hex_testing[] = { { "QS\r", "#\x6C\x01 \x35 \x6C\x01 \x35 \x03 \x51\x9A \x28\x02\x12\xD0 \xE6 \x1E \x09\r", 27 }, { "M\r", "P\r", -1 }, { "Q\r", "", -1 }, { "S00R0000\r", "", -1 }, { "C\r", "", -1 }, { "S02R0005\r", "", -1 }, { "S.5R0000\r", "N\r", -1 }, { "T\r", "", -1 }, { NULL } }; #endif /* TESTING */ /* == Support functions == */ /* This function allows the subdriver to "claim" a device: return 1 if the device is supported by this subdriver, else 0. */ static int voltronic_qs_hex_claim(void) { /* We need at least M and QS to run this subdriver */ /* UPS Protocol */ item_t *item = find_nut_info("ups.firmware.aux", 0, 0); /* Don't know what happened */ if (!item) return 0; /* No reply/Unable to get value */ if (qx_process(item, NULL)) return 0; /* Unable to process value/Protocol not supported */ if (ups_infoval_set(item) != 1) return 0; item = find_nut_info("input.voltage", 0, 0); /* Don't know what happened */ if (!item) { dstate_delinfo("ups.firmware.aux"); return 0; } /* No reply/Unable to get value */ if (qx_process(item, NULL)) { dstate_delinfo("ups.firmware.aux"); return 0; } /* Unable to process value */ if (ups_infoval_set(item) != 1) { dstate_delinfo("ups.firmware.aux"); return 0; } return 1; } /* Subdriver-specific initups */ static void voltronic_qs_hex_initups(void) { blazer_initups_light(voltronic_qs_hex_qx2nut); } /* == Answer preprocess functions == */ /* Preprocess the answer we got back from the UPS when queried with 'QS\r' */ static int voltronic_qs_hex_preprocess_qs_answer(item_t *item, const int len) { int i, token; char refined[SMALLBUF] = ""; if (len <= 0) return len; if (item->answer[0] != '#') { upsdebugx(4, "%s: wrong leading character [%s: 0x%0x]", __func__, item->info_type, item->answer[0]); return -1; } snprintf(refined, sizeof(refined), "%s", "#"); /* e.g.: item->answer = "#\x6C\x01 \x35 \x6C\x01 \x35 \x03 \x51\x9A \x28\x02\x12\xD0 \xE6 \x1E \x09\r" */ upsdebug_hex(4, "read", item->answer, (size_t)len); for (i = 1, token = 1; i < len; i++) { /* New token */ if (item->answer[i] == 0x20) { snprintfcat(refined, sizeof(refined), "%s", " "); token++; continue; } /* 'Unescape' raw data */ if (i < len && item->answer[i] == 0x28) { switch (item->answer[i + 1]) { case 0x00: /* Escaped because: CR */ snprintfcat(refined, sizeof(refined), "%02x", 0x0D); break; case 0x01: /* Escaped because: XON */ snprintfcat(refined, sizeof(refined), "%02x", 0x11); break; case 0x02: /* Escaped because: XOFF */ snprintfcat(refined, sizeof(refined), "%02x", 0x13); break; case 0x03: /* Escaped because: LF */ snprintfcat(refined, sizeof(refined), "%02x", 0x0A); break; case 0x04: /* Escaped because: space */ snprintfcat(refined, sizeof(refined), "%02x", 0x20); break; default: if (token != 10 && token != 11) snprintfcat(refined, sizeof(refined), "%02x", ((unsigned char *)item->answer)[i]); else snprintfcat(refined, sizeof(refined), "%08d", voltronic_qs_hex_char_to_binary(((unsigned char *)item->answer)[i])); continue; } i++; continue; } /* Trailing CR */ if (item->answer[i] == 0x0D) break; if (token != 10 && token != 11) snprintfcat(refined, sizeof(refined), "%02x", ((unsigned char *)item->answer)[i]); else snprintfcat(refined, sizeof(refined), "%08d", voltronic_qs_hex_char_to_binary(((unsigned char *)item->answer)[i])); } if ( token < 10 || token > 11 || (token == 10 && strlen(refined) != 46) || (token == 11 && strlen(refined) != 55) ) { upsdebugx(2, "noncompliant reply: %s", refined); return -1; } upsdebugx(4, "read: %s", refined); /* e.g.: item->answer = "#6C01 35 6C01 35 03 519A 1312D0 E6 1E 00001001" */ return snprintf(item->answer, sizeof(item->answer), "%s\r", refined); } /* Transform a char into its binary form (as an int) */ static int voltronic_qs_hex_char_to_binary(const unsigned char value) { unsigned char remainder = value; int ret = 0, power = 1; while (remainder) { if (remainder & 1) ret += power; power *= 10; remainder >>= 1; } return ret; } /* == Preprocess functions == */ /* Protocol used by the UPS */ static int voltronic_qs_hex_protocol(item_t *item, char *value, const size_t valuelen) { item_t *unskip; int i; const struct { const char *info_type; /* info_type of the item to be unskipped */ const unsigned long flags; /* qxflags that have to be set in the item */ const unsigned long noflags; /* qxflags that have to be absent in the item */ } items_to_be_unskipped[] = { { "test.battery.start.quick", QX_FLAG_CMD, 0 }, { "output.frequency.nominal", 0, 0 }, { "battery.voltage.nominal", 0, 0 }, { "output.voltage.nominal", 0, 0 }, { NULL, 0, 0 } }; if (strcasecmp(item->value, "P") && strcasecmp(item->value, "T")) { upsdebugx(2, "%s: invalid protocol [%s]", __func__, item->value); return -1; } #ifdef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL #pragma GCC diagnostic push #endif #ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL #pragma GCC diagnostic ignored "-Wformat-nonliteral" #endif #ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_FORMAT_SECURITY #pragma GCC diagnostic ignored "-Wformat-security" #endif snprintf(value, valuelen, item->dfl, item->value); #ifdef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL #pragma GCC diagnostic pop #endif /* Unskip items supported only by devices that implement 'T' protocol */ if (!strcasecmp(item->value, "P")) return 0; for (i = 0; items_to_be_unskipped[i].info_type; i++) { unskip = find_nut_info(items_to_be_unskipped[i].info_type, items_to_be_unskipped[i].flags, items_to_be_unskipped[i].noflags); /* Don't know what happened */ if (!unskip) return -1; unskip->qxflags &= ~QX_FLAG_SKIP; } return 0; } /* Input/Output voltage */ static int voltronic_qs_hex_input_output_voltage(item_t *item, char *value, const size_t valuelen) { long val; double ret; char *str_end; if (strspn(item->value, "0123456789ABCDEFabcdef ") != strlen(item->value)) { upsdebugx(2, "%s: non numerical value [%s: %s]", __func__, item->info_type, item->value); return -1; } val = strtol(item->value, &str_end, 16) * strtol(str_end, NULL, 16) / 51; ret = val / 256.0; #ifdef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL #pragma GCC diagnostic push #endif #ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL #pragma GCC diagnostic ignored "-Wformat-nonliteral" #endif #ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_FORMAT_SECURITY #pragma GCC diagnostic ignored "-Wformat-security" #endif snprintf(value, valuelen, item->dfl, ret); #ifdef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL #pragma GCC diagnostic pop #endif return 0; } /* Device load */ static int voltronic_qs_hex_load(item_t *item, char *value, const size_t valuelen) { if (strspn(item->value, "0123456789ABCDEFabcdef") != strlen(item->value)) { upsdebugx(2, "%s: non numerical value [%s: %s]", __func__, item->info_type, item->value); return -1; } #ifdef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL #pragma GCC diagnostic push #endif #ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL #pragma GCC diagnostic ignored "-Wformat-nonliteral" #endif #ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_FORMAT_SECURITY #pragma GCC diagnostic ignored "-Wformat-security" #endif snprintf(value, valuelen, item->dfl, strtol(item->value, NULL, 16)); #ifdef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL #pragma GCC diagnostic pop #endif return 0; } /* Output frequency */ static int voltronic_qs_hex_frequency(item_t *item, char *value, const size_t valuelen) { double val1, val2, ret; char *str_end; if (strspn(item->value, "0123456789ABCDEFabcdef ") != strlen(item->value)) { upsdebugx(2, "%s: non numerical value [%s: %s]", __func__, item->info_type, item->value); return -1; } val1 = strtol(item->value, &str_end, 16); val2 = strtol(str_end, NULL, 16); ret = val2 / val1; ret = ret > 99.9 ? 99.9 : ret; #ifdef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL #pragma GCC diagnostic push #endif #ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL #pragma GCC diagnostic ignored "-Wformat-nonliteral" #endif #ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_FORMAT_SECURITY #pragma GCC diagnostic ignored "-Wformat-security" #endif snprintf(value, valuelen, item->dfl, ret); #ifdef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL #pragma GCC diagnostic pop #endif return 0; } /* Battery voltage */ static int voltronic_qs_hex_battery_voltage(item_t *item, char *value, const size_t valuelen) { long val1, val2; char *str_end; if (strspn(item->value, "0123456789ABCDEFabcdef ") != strlen(item->value)) { upsdebugx(2, "%s: non numerical value [%s: %s]", __func__, item->info_type, item->value); return -1; } val1 = strtol(item->value, &str_end, 16); val2 = strtol(str_end, NULL, 16); #ifdef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL #pragma GCC diagnostic push #endif #ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL #pragma GCC diagnostic ignored "-Wformat-nonliteral" #endif #ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_FORMAT_SECURITY #pragma GCC diagnostic ignored "-Wformat-security" #endif snprintf(value, valuelen, item->dfl, (val1 * val2) / 510.0); #ifdef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL #pragma GCC diagnostic pop #endif return 0; } /* Ratings bits */ static int voltronic_qs_hex_process_ratings_bits(item_t *item, char *value, const size_t valuelen) { long val; double ret; if (strspn(item->value, "01") != strlen(item->value)) { upsdebugx(3, "%s: unexpected value %s@%d->%s", __func__, item->info_type, item->from, item->value); return -1; } val = strtol(item->value, NULL, 10); switch (item->from) { case 47: /* Nominal output frequency */ if (val == 0) /* 0 -> 50 Hz */ ret = 50; else /* 1 -> 60 Hz */ ret = 60; break; case 48: /* Nominal battery voltage */ if (val == 0) /* 0 -> 12 V */ ret = 12; else if (val == 1) /* 1 -> 24 V */ ret = 24; else if (val == 10) /* 10 -> 36 V */ ret = 36; else /* 11 -> 48 V */ ret = 48; break; /* case 50: *//* Reserved */ /* break;*/ /* case 51: *//* Reserved */ /* break;*/ case 52: /* Nominal output voltage */ switch (val) { case 0: ret = 110; break; case 1: ret = 120; break; case 10: ret = 220; break; case 11: ret = 230; break; case 100: ret = 240; break; default: /* Unknown */ return -1; } break; default: /* Don't know what happened */ return -1; } #ifdef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL #pragma GCC diagnostic push #endif #ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL #pragma GCC diagnostic ignored "-Wformat-nonliteral" #endif #ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_FORMAT_SECURITY #pragma GCC diagnostic ignored "-Wformat-security" #endif snprintf(value, valuelen, item->dfl, ret); #ifdef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL #pragma GCC diagnostic pop #endif return 0; } /* == Subdriver interface == */ subdriver_t voltronic_qs_hex_subdriver = { VOLTRONIC_QS_HEX_VERSION, voltronic_qs_hex_claim, voltronic_qs_hex_qx2nut, voltronic_qs_hex_initups, NULL, blazer_makevartable_light, NULL, "N\r", #ifdef TESTING voltronic_qs_hex_testing, #endif /* TESTING */ }; nut-2.8.1/drivers/nutdrv_qx_mecer.c0000644000175000017500000002611214501607135014304 00000000000000/* nutdrv_qx_mecer.c - Subdriver for Mecer/Voltronic Power P98 UPSes * * Copyright (C) * 2013 Daniele Pezzini * * 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 2 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, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #include "main.h" #include "nutdrv_qx.h" #include "nutdrv_qx_blazer-common.h" #include "nutdrv_qx_mecer.h" #define MECER_VERSION "Mecer 0.08" /* Support functions */ static int mecer_claim(void); static void mecer_initups(void); /* Preprocess functions */ static int voltronic_p98_protocol(item_t *item, char *value, const size_t valuelen); static int mecer_process_test_battery(item_t *item, char *value, const size_t valuelen); /* == qx2nut lookup table == */ static item_t mecer_qx2nut[] = { /* Query UPS for protocol (Voltronic Power UPSes) * > [QPI\r] * < [(PI98\r] * 012345 * 0 */ { "ups.firmware.aux", 0, NULL, "QPI\r", "", 6, '(', "", 1, 4, "%s", QX_FLAG_STATIC, NULL, NULL, voltronic_p98_protocol }, /* * > [Q1\r] * < [(226.0 195.0 226.0 014 49.0 27.5 30.0 00001000\r] * 01234567890123456789012345678901234567890123456 * 0 1 2 3 4 */ { "input.voltage", 0, NULL, "Q1\r", "", 47, '(', "", 1, 5, "%.1f", 0, NULL, NULL, NULL }, { "input.voltage.fault", 0, NULL, "Q1\r", "", 47, '(', "", 7, 11, "%.1f", 0, NULL, NULL, NULL }, { "output.voltage", 0, NULL, "Q1\r", "", 47, '(', "", 13, 17, "%.1f", 0, NULL, NULL, NULL }, { "ups.load", 0, NULL, "Q1\r", "", 47, '(', "", 19, 21, "%.0f", 0, NULL, NULL, NULL }, { "input.frequency", 0, NULL, "Q1\r", "", 47, '(', "", 23, 26, "%.1f", 0, NULL, NULL, NULL }, { "battery.voltage", 0, NULL, "Q1\r", "", 47, '(', "", 28, 31, "%.2f", 0, NULL, NULL, qx_multiply_battvolt }, { "ups.temperature", 0, NULL, "Q1\r", "", 47, '(', "", 33, 36, "%.1f", 0, NULL, NULL, NULL }, /* Status bits */ { "ups.status", 0, NULL, "Q1\r", "", 47, '(', "", 38, 38, NULL, QX_FLAG_QUICK_POLL, NULL, NULL, blazer_process_status_bits }, /* Utility Fail (Immediate) */ { "ups.status", 0, NULL, "Q1\r", "", 47, '(', "", 39, 39, NULL, QX_FLAG_QUICK_POLL, NULL, NULL, blazer_process_status_bits }, /* Battery Low */ { "ups.status", 0, NULL, "Q1\r", "", 47, '(', "", 40, 40, NULL, QX_FLAG_QUICK_POLL, NULL, NULL, blazer_process_status_bits }, /* Bypass/Boost or Buck Active */ { "ups.alarm", 0, NULL, "Q1\r", "", 47, '(', "", 41, 41, NULL, 0, NULL, NULL, blazer_process_status_bits }, /* UPS Failed */ { "ups.type", 0, NULL, "Q1\r", "", 47, '(', "", 42, 42, "%s", QX_FLAG_STATIC, NULL, NULL, blazer_process_status_bits }, /* UPS Type */ { "ups.status", 0, NULL, "Q1\r", "", 47, '(', "", 43, 43, NULL, QX_FLAG_QUICK_POLL, NULL, NULL, blazer_process_status_bits }, /* Test in Progress */ { "ups.status", 0, NULL, "Q1\r", "", 47, '(', "", 44, 44, NULL, QX_FLAG_QUICK_POLL, NULL, NULL, blazer_process_status_bits }, /* Shutdown Active */ { "ups.beeper.status", 0, NULL, "Q1\r", "", 47, '(', "", 45, 45, "%s", 0, NULL, NULL, blazer_process_status_bits }, /* Beeper status */ /* * > [F\r] * < [#220.0 000 024.0 50.0\r] * 0123456789012345678901 * 0 1 2 */ { "input.voltage.nominal", 0, NULL, "F\r", "", 22, '#', "", 1, 5, "%.0f", QX_FLAG_STATIC, NULL, NULL, NULL }, { "input.current.nominal", 0, NULL, "F\r", "", 22, '#', "", 7, 9, "%.1f", QX_FLAG_STATIC, NULL, NULL, NULL }, { "battery.voltage.nominal", 0, NULL, "F\r", "", 22, '#', "", 11, 15, "%.1f", QX_FLAG_STATIC, NULL, NULL, NULL }, { "input.frequency.nominal", 0, NULL, "F\r", "", 22, '#', "", 17, 20, "%.0f", QX_FLAG_STATIC, NULL, NULL, NULL }, /* * > [I\r] * < [#------------- ------ VT12046Q \r] * 012345678901234567890123456789012345678 * 0 1 2 3 */ { "device.mfr", 0, NULL, "I\r", "", 39, '#', "", 1, 15, "%s", QX_FLAG_STATIC | QX_FLAG_TRIM, NULL, NULL, NULL }, { "device.model", 0, NULL, "I\r", "", 39, '#', "", 17, 26, "%s", QX_FLAG_STATIC | QX_FLAG_TRIM, NULL, NULL, NULL }, { "ups.firmware", 0, NULL, "I\r", "", 39, '#', "", 28, 37, "%s", QX_FLAG_STATIC | QX_FLAG_TRIM, NULL, NULL, NULL }, /* Instant commands * The UPS will reply '(ACK\r' in case of success, '(NAK\r' if the command is rejected or invalid */ { "beeper.toggle", 0, NULL, "Q\r", "", 5, '(', "", 1, 3, NULL, QX_FLAG_CMD, NULL, NULL, NULL }, { "load.off", 0, NULL, "S00R0000\r", "", 5, '(', "", 1, 3, NULL, QX_FLAG_CMD, NULL, NULL, NULL }, { "load.on", 0, NULL, "C\r", "", 5, '(', "", 1, 3, NULL, QX_FLAG_CMD, NULL, NULL, NULL }, { "shutdown.return", 0, NULL, "S%s\r", "", 5, '(', "", 1, 3, NULL, QX_FLAG_CMD, NULL, NULL, blazer_process_command }, { "shutdown.stayoff", 0, NULL, "S%sR0000\r", "", 5, '(', "", 1, 3, NULL, QX_FLAG_CMD, NULL, NULL, blazer_process_command }, { "shutdown.stop", 0, NULL, "C\r", "", 5, '(', "", 1, 3, NULL, QX_FLAG_CMD, NULL, NULL, NULL }, { "test.battery.start", 0, NULL, "T%s\r", "", 5, '(', "", 1, 3, NULL, QX_FLAG_CMD, NULL, NULL, mecer_process_test_battery }, { "test.battery.start.deep", 0, NULL, "TL\r", "", 5, '(', "", 1, 3, NULL, QX_FLAG_CMD, NULL, NULL, NULL }, { "test.battery.start.quick", 0, NULL, "T\r", "", 5, '(', "", 1, 3, NULL, QX_FLAG_CMD, NULL, NULL, NULL }, { "test.battery.stop", 0, NULL, "CT\r", "", 5, '(', "", 1, 3, NULL, QX_FLAG_CMD, NULL, NULL, NULL }, /* Server-side settable vars */ { "ups.delay.start", ST_FLAG_RW, blazer_r_ondelay, NULL, "", 0, 0, "", 0, 0, DEFAULT_ONDELAY, QX_FLAG_ABSENT | QX_FLAG_SETVAR | QX_FLAG_RANGE, NULL, NULL, blazer_process_setvar }, { "ups.delay.shutdown", ST_FLAG_RW, blazer_r_offdelay, NULL, "", 0, 0, "", 0, 0, DEFAULT_OFFDELAY, QX_FLAG_ABSENT | QX_FLAG_SETVAR | QX_FLAG_RANGE, NULL, NULL, blazer_process_setvar }, /* End of structure. */ { NULL, 0, NULL, NULL, "", 0, 0, "", 0, 0, NULL, 0, NULL, NULL, NULL } }; /* == Testing table == */ #ifdef TESTING static testing_t mecer_testing[] = { { "Q1\r", "(215.0 195.0 230.0 014 49.0 22.7 30.0 00000000\r", -1 }, { "QPI\r", "(PI98\r", -1 }, { "F\r", "#230.0 000 024.0 50.0\r", -1 }, { "I\r", "#NOT_A_LIVE_UPS TESTING TESTING \r", -1 }, { "Q\r", "(ACK\r", -1 }, { "S03\r", "(NAK\r", -1 }, { "C\r", "(NAK\r", -1 }, { "S02R0005\r", "(ACK\r", -1 }, { "S.5R0000\r", "(ACK\r", -1 }, { "T04\r", "(NAK\r", -1 }, { "TL\r", "(ACK\r", -1 }, { "T\r", "(NAK\r", -1 }, { "CT\r", "(ACK\r", -1 }, { NULL } }; #endif /* TESTING */ /* == Support functions == */ /* This function allows the subdriver to "claim" a device: return 1 if the device is supported by this subdriver, else 0. */ static int mecer_claim(void) { /* Apart from status (Q1), try to identify protocol (QPI, for Voltronic Power P98 units) or whether the UPS uses '(ACK\r'/'(NAK\r' replies */ item_t *item = find_nut_info("input.voltage", 0, 0); /* Don't know what happened */ if (!item) return 0; /* No reply/Unable to get value */ if (qx_process(item, NULL)) return 0; /* Unable to process value */ if (ups_infoval_set(item) != 1) return 0; /* UPS Protocol */ item = find_nut_info("ups.firmware.aux", 0, 0); /* Don't know what happened */ if (!item) { dstate_delinfo("input.voltage"); return 0; } /* No reply/Unable to get value/Command rejected */ if (qx_process(item, NULL)) { /* No reply/Command echoed back or rejected with something other than '(NAK\r' -> Not a '(ACK/(NAK' unit */ if (!strlen(item->answer) || strcasecmp(item->answer, "(NAK\r")) { dstate_delinfo("input.voltage"); return 0; } /* Command rejected with '(NAK\r' -> '(ACK/(NAK' unit */ /* Skip protocol query from now on */ item->qxflags |= QX_FLAG_SKIP; } else { /* Unable to process value/Command echoed back or rejected with something other than '(NAK\r'/Protocol not supported */ if (ups_infoval_set(item) != 1) { dstate_delinfo("input.voltage"); return 0; } /* Voltronic Power P98 unit */ } return 1; } /* Subdriver-specific initups */ static void mecer_initups(void) { blazer_initups(mecer_qx2nut); } /* == Preprocess functions == */ /* Protocol used by the UPS */ static int voltronic_p98_protocol(item_t *item, char *value, const size_t valuelen) { if (strcasecmp(item->value, "PI98")) { upslogx(LOG_ERR, "Protocol [%s] is not supported by this driver", item->value); return -1; } #ifdef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL #pragma GCC diagnostic push #endif #ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL #pragma GCC diagnostic ignored "-Wformat-nonliteral" #endif #ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_FORMAT_SECURITY #pragma GCC diagnostic ignored "-Wformat-security" #endif snprintf(value, valuelen, item->dfl, "Voltronic Power P98"); #ifdef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL #pragma GCC diagnostic pop #endif return 0; } /* *CMD* Preprocess 'test.battery.start' instant command */ static int mecer_process_test_battery(item_t *item, char *value, const size_t valuelen) { const char *protocol = dstate_getinfo("ups.firmware.aux"); char buf[SMALLBUF] = ""; long min, test_time; /* Voltronic P98 units -> Accepted values for test time: .2 -> .9 (.2=12sec ..), 01 -> 99 (minutes) -> range = [12..5940] */ if (protocol && !strcasecmp(protocol, "Voltronic Power P98")) min = 12; /* Other units: 01 -> 99 (minutes) -> [60..5940] */ else min = 60; if (strlen(value) != strspn(value, "0123456789")) { upslogx(LOG_ERR, "%s: non numerical value [%s]", item->info_type, value); return -1; } test_time = (strlen(value) > 0) ? strtol(value, NULL, 10) : 600; if ((test_time < min) || (test_time > 5940)) { upslogx(LOG_ERR, "%s: battery test time '%ld' out of range [%ld..5940] seconds", item->info_type, test_time, min); return -1; } /* test time < 1 minute */ if (test_time < 60) { test_time = test_time / 6; snprintf(buf, sizeof(buf), ".%ld", test_time); /* test time > 1 minute */ } else { test_time = test_time / 60; snprintf(buf, sizeof(buf), "%02ld", test_time); } #ifdef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL #pragma GCC diagnostic push #endif #ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL #pragma GCC diagnostic ignored "-Wformat-nonliteral" #endif #ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_FORMAT_SECURITY #pragma GCC diagnostic ignored "-Wformat-security" #endif snprintf(value, valuelen, item->command, buf); #ifdef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL #pragma GCC diagnostic pop #endif return 0; } /* == Subdriver interface == */ subdriver_t mecer_subdriver = { MECER_VERSION, mecer_claim, mecer_qx2nut, mecer_initups, NULL, blazer_makevartable, "ACK", "(NAK\r", #ifdef TESTING mecer_testing, #endif /* TESTING */ }; nut-2.8.1/drivers/main.c0000644000175000017500000021752614513167372012045 00000000000000/* main.c - Network UPS Tools driver core Copyright (C) 1999 Russell Kroll 2005 - 2017 Arnaud Quette 2017 Eaton (author: Emilien Kia ) 2017 - 2022 Jim Klimov 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 2 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, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "common.h" #include "main.h" #include "nut_stdint.h" #include "dstate.h" #include "attribute.h" #include "upsdrvquery.h" #ifndef WIN32 # include #endif #include #include #include /* data which may be useful to the drivers */ TYPE_FD upsfd = ERROR_FD; char *device_path = NULL; const char *progname = NULL, *upsname = NULL, *device_name = NULL; /* may be set by the driver to wake up while in dstate_poll_fds */ TYPE_FD extrafd = ERROR_FD; #ifdef WIN32 static HANDLE mutex = INVALID_HANDLE_VALUE; #endif /* for ser_open */ int do_lock_port = 1; /* for dstate->sock_connect, default to effectively * asynchronous (0) with fallback to synchronous (1) */ int do_synchronous = -1; /* for detecting -a values that don't match anything */ static int upsname_found = 0; # ifndef DRIVERS_MAIN_WITHOUT_MAIN static # endif /* DRIVERS_MAIN_WITHOUT_MAIN */ vartab_t *vartab_h = NULL; /* variables possibly set by the global part of ups.conf * user and group may be set globally or per-driver */ time_t poll_interval = 2; static char *chroot_path = NULL, *user = NULL, *group = NULL; static int user_from_cmdline = 0, group_from_cmdline = 0; /* signal handling */ int exit_flag = 0; /* reload_flag is 0 most of the time (including initial config reading), * and is briefly 1 when a reload signal is received and is being handled, * or 2 if the reload attempt is allowed to exit the current driver (e.g. * changed some ups.conf settings that can not be re-applied on the fly) * assuming it gets restarted by external framework (systemd) or caller * (like NUT driver CLI `-c reload-or-restart` handling), if needed. */ static int reload_flag = 0; #ifndef DRIVERS_MAIN_WITHOUT_MAIN /* Should this driver instance go to background (default) * or stay foregrounded (default if -D/-d options are set on * command line)? Note that debug_min in ups.conf allows for * verbosity while backgrounded by default. * Value is multi-state (FIXME: enum?): * -1 (default) Decide based on debug verbosity or dump_mode * 0 User required to background even if with -D or dump_mode, * or did not require foregrounding/dumping/debug on CLI * 1 User required to not background explicitly, * or passed -D (or -d) and current value was -1 * 2 User required to not background explicitly, * and yet to write the PID file, with -FF option */ static int foreground = -1; #endif /* DRIVERS_MAIN_WITHOUT_MAIN */ /* Users can pass a -D[...] option to enable debugging. * For the service tracing purposes, also the ups.conf * can define a debug_min value in the global or device * section, to set the minimal debug level (CLI provided * value less than that would not have effect, can only * have more). Finally, it can also be set over socket * protocol, taking precedence over other inputs. */ static int nut_debug_level_args = -1; static int nut_debug_level_global = -1; static int nut_debug_level_driver = -1; static int nut_debug_level_protocol = -1; #ifndef DRIVERS_MAIN_WITHOUT_MAIN /* everything else */ static char *pidfn = NULL; static int dump_data = 0; /* Store the update_count requested */ #endif /* DRIVERS_MAIN_WITHOUT_MAIN */ /* pre-declare some private methods used */ static void assign_debug_level(void); /* TODO: Equivalent for WIN32 - see SIGCMD_RELOAD in upd and upsmon */ static void set_reload_flag( #ifndef WIN32 int #else char * #endif sig); #ifndef DRIVERS_MAIN_WITHOUT_MAIN /* Returns a result code from INSTCMD enum values */ static int handle_reload_flag(void); #endif /* Set in do_ups_confargs() for consumers like handle_reload_flag() */ static int reload_requires_restart = -1; /* print the driver banner */ void upsdrv_banner (void) { int i; printf("Network UPS Tools - %s %s (%s)\n", upsdrv_info.name, upsdrv_info.version, UPS_VERSION); /* process sub driver(s) information */ for (i = 0; upsdrv_info.subdrv_info[i]; i++) { if (!upsdrv_info.subdrv_info[i]->name) { continue; } if (!upsdrv_info.subdrv_info[i]->version) { continue; } printf("%s %s\n", upsdrv_info.subdrv_info[i]->name, upsdrv_info.subdrv_info[i]->version); } } #ifndef DRIVERS_MAIN_WITHOUT_MAIN /* power down the attached load immediately */ static void forceshutdown(void) __attribute__((noreturn)); static void forceshutdown(void) { upslogx(LOG_NOTICE, "Initiating UPS shutdown"); /* the driver must not block in this function */ upsdrv_shutdown(); /* the driver always exits here, to not block probable ongoing shutdown */ exit(exit_flag == -1 ? EXIT_FAILURE : EXIT_SUCCESS); } /* this function only prints the usage message; it does not call exit() */ static void help_msg(void) { vartab_t *tmp; nut_report_config_flags(); printf("\nusage: %s (-a |-s ) [OPTIONS]\n", progname); printf(" -a - autoconfig using ups.conf section \n"); printf(" - note: -x after -a overrides ups.conf settings\n\n"); printf(" -s - configure directly from cmd line arguments\n"); printf(" - note: must specify all driver parameters with successive -x\n"); printf(" - note: at least 'port' variable should be set\n"); printf(" - note: to explore the current values on a device from an\n"); printf(" unprivileged user account (with sufficient media access in\n"); printf(" the OS - e.g. to query networked devices), you can specify\n"); printf(" '-d 1' argument and `export NUT_STATEPATH=/tmp` beforehand\n\n"); printf(" -V - print version, then exit\n"); printf(" -L - print parseable list of driver variables\n"); printf(" -D - raise debugging level (and stay foreground by default)\n"); printf(" -d - dump data to stdout after 'count' updates loop and exit\n"); printf(" -F - stay foregrounded even if no debugging is enabled\n"); printf(" -FF - stay foregrounded and still save the PID file\n"); printf(" -B - stay backgrounded even if debugging is bumped\n"); printf(" -q - raise log level threshold\n"); printf(" -h - display this help\n"); printf(" -k - force shutdown\n"); printf(" -c - send via signal to background process\n"); printf(" Supported commands:\n"); # ifndef WIN32 /* FIXME: port event loop from upsd/upsmon to allow messaging fellow drivers in WIN32 builds */ printf(" - reload: re-read configuration files, ignoring changed\n"); printf(" values which require a driver restart (can not be changed\n"); printf(" on the fly)\n"); # endif /* WIN32 */ /* Note: this one is beside signal-sending (goes via socket protocol): */ printf(" - reload-or-error: re-read configuration files, ignoring but\n"); printf(" counting changed values which require a driver restart (can\n"); printf(" not be changed on the fly), and return a success/fail code\n"); printf(" based on that count, so the caller can decide the fate of\n"); printf(" the currently running driver instance\n"); # ifndef WIN32 /* FIXME: port event loop from upsd/upsmon to allow messaging fellow drivers in WIN32 builds */ # ifdef SIGCMD_RELOAD_OR_RESTART printf(" - reload-or-restart: re-read configuration files (close the\n"); printf(" old driver instance device connection if needed, and have\n"); printf(" it effectively restart)\n"); # endif printf(" - reload-or-exit: re-read configuration files (exit the old\n"); printf(" driver instance if needed, so an external caller like the\n"); printf(" systemd or SMF frameworks would start another copy)\n"); /* NOTE for FIXME above: PID-signalling is non-WIN32-only for us */ printf(" -P - send the signal above to specified PID (bypassing PID file)\n"); # endif /* WIN32 */ printf(" -i - poll interval\n"); printf(" -r - chroot to \n"); printf(" -u - switch to (if started as root)\n"); printf(" -g - set pipe access to (if started as root)\n"); printf(" -x = - set driver variable to \n"); printf(" - example: -x cable=940-0095B\n\n"); if (vartab_h) { tmp = vartab_h; printf("Acceptable values for -x or ups.conf in this driver:\n\n"); while (tmp) { if (tmp->vartype == VAR_VALUE) printf("%40s : -x %s=\n", tmp->desc, tmp->var); else printf("%40s : -x %s\n", tmp->desc, tmp->var); tmp = tmp->next; } } upsdrv_help(); } #endif /* DRIVERS_MAIN_WITHOUT_MAIN */ /* store these in dstate as driver.(parameter|flag) */ # ifndef DRIVERS_MAIN_WITHOUT_MAIN static # endif /* DRIVERS_MAIN_WITHOUT_MAIN */ void dparam_setinfo(const char *var, const char *val) { char vtmp[SMALLBUF]; /* store these in dstate for debugging and other help */ if (val) { snprintf(vtmp, sizeof(vtmp), "driver.parameter.%s", var); dstate_setinfo(vtmp, "%s", val); return; } /* no value = flag */ snprintf(vtmp, sizeof(vtmp), "driver.flag.%s", var); dstate_setinfo(vtmp, "enabled"); } /* cram var [= ] data into storage */ # ifndef DRIVERS_MAIN_WITHOUT_MAIN static # endif /* DRIVERS_MAIN_WITHOUT_MAIN */ void storeval(const char *var, char *val) { vartab_t *tmp, *last; /* NOTE: (FIXME?) The override and default mechanisms here * effectively bypass both VAR_SENSITIVE protections and * the constraint of having previously defined the name by * addvar() in a driver codebase, or of having a dot in it. * See https://github.com/networkupstools/nut/issues/1891 * if this would need solving eventually. At the moment the * sensitivity impacts certain auth values for netxml-ups * and snmp-ups reading from vartab directly, and overrides * are ignored - so no practical problem to solve right now. */ if (!strncasecmp(var, "override.", 9)) { /* NOTE: No regard for VAR_SENSITIVE here */ dstate_setinfo(var+9, "%s", val); dstate_setflags(var+9, ST_FLAG_IMMUTABLE); dparam_setinfo(var, val); return; } if (!strncasecmp(var, "default.", 8)) { /* NOTE: No regard for VAR_SENSITIVE here */ dstate_setinfo(var+8, "%s", val); dparam_setinfo(var, val); return; } tmp = last = vartab_h; while (tmp) { last = tmp; /* sanity check */ if (!tmp->var) { tmp = tmp->next; continue; } /* later definitions overwrite earlier ones */ if (!strcasecmp(tmp->var, var)) { free(tmp->val); if (val) tmp->val = xstrdup(val); /* don't keep things like SNMP community strings */ if ((tmp->vartype & VAR_SENSITIVE) == 0) { dparam_setinfo(var, val); } else { upsdebugx(4, "%s: skip dparam_setinfo() " "for sensitive variable '%s'", __func__, var); } tmp->found = 1; return; } tmp = tmp->next; } /* try to help them out */ printf("\nFatal error: '%s' is not a valid %s for this driver.\n", var, val ? "variable name" : "flag"); printf("\n"); printf("Look in the man page or call this driver with -h for a list of\n"); printf("valid variable names and flags.\n"); exit(EXIT_SUCCESS); } /* retrieve the value of variable if possible */ char *getval(const char *var) { vartab_t *tmp = vartab_h; while (tmp) { if (!strcasecmp(tmp->var, var)) return(tmp->val); tmp = tmp->next; } return NULL; } /* see if has been defined, even if no value has been given to it */ int testvar(const char *var) { vartab_t *tmp = vartab_h; while (tmp) { if (!strcasecmp(tmp->var, var)) return tmp->found; tmp = tmp->next; } return 0; /* not found */ } /* See if can be (re-)loaded now: either is reloadable by definition, * or no value has been given to it yet. Returns "-1" if nothing needs to * be done and that is not a failure (e.g. value not modified so we do not * care if we may change it or not). */ int testvar_reloadable(const char *var, const char *val, int vartype) { vartab_t *tmp = vartab_h; int verdict = -2; /* FIXME: handle VAR_FLAG typed (bitmask) values specially somehow? * Either we set the flag at some point (because its name is mentioned) * or we do not (initially set - no way so far to know it got commented * away before a reload on the fly). Might load new config info into a * separate list and then compare missing points?.. */ upsdebugx(6, "%s: searching for var=%s, vartype=%d, reload_flag=%d", __func__, NUT_STRARG(var), vartype, reload_flag); while (tmp) { if (!strcasecmp(tmp->var, var)) { /* variable name is known */ upsdebugx(6, "%s: found var=%s, val='%s' => '%s', vartype=%d => %d, found=%d, reloadable=%d, reload_flag=%d", __func__, NUT_STRARG(var), NUT_STRARG(tmp->val), NUT_STRARG(val), tmp->vartype, vartype, tmp->found, tmp->reloadable, reload_flag); if (val && tmp->val) { /* a value is already known by name * and bitmask for VAR_FLAG/VAR_VALUE matches */ if ((vartype & tmp->vartype) && !strcasecmp(tmp->val, val)) { if ((tmp->vartype & VAR_FLAG) && val == NULL) { if (reload_flag) { upsdebugx(1, "%s: setting '%s' " "exists and is a flag; " "new value was not specified", __func__, var); } /* by default: apply flags initially, ignore later */ verdict = ( (!reload_flag) /* For initial config reads, legacy code trusted what it saw */ || tmp->reloadable /* set in addvar*() */ ); goto finish; } if (reload_flag) { upsdebugx(1, "%s: setting '%s' " "exists and is unmodified", __func__, var); } verdict = -1; /* no-op for caller */ goto finish; } else { /* warn loudly if we are reloading and * can not change this modified value */ upsdebugx((reload_flag ? (tmp->reloadable ? 1 : 0) : 1), "%s: setting '%s' exists and differs: " "new type bitmask %d vs. %d, " "new value '%s' vs. '%s'%s", __func__, var, vartype, tmp->vartype, val, tmp->val, ((!reload_flag || tmp->reloadable) ? "" : " (driver restart is needed to apply)") ); /* FIXME: Define a special EXIT_RELOAD or something, * for "not quite a failure"? Or close connections * and re-exec() this driver from scratch (and so to * keep MAINPID for systemd et al)? */ if (reload_flag == 2 && !tmp->reloadable) fatalx( #ifndef WIN32 (128 + SIGCMD_RELOAD_OR_EXIT) #else EXIT_SUCCESS #endif , "NUT driver reload-or-exit: setting %s was changed and requires a driver restart", var); verdict = ( (!reload_flag) /* For initial config reads, legacy code trusted what it saw */ || tmp->reloadable /* set in addvar*() */ ); /* handle reload-or-error reports */ if (verdict == 0) { if (reload_requires_restart < 1) reload_requires_restart = 1; else reload_requires_restart++; } goto finish; } } /* okay to redefine if not yet defined, or if reload is allowed, * or if initially loading the configs */ verdict = ( (!reload_flag) || ((!tmp->found) || tmp->reloadable) ); goto finish; } tmp = tmp->next; } verdict = 1; /* not found, may (re)load the definition */ finish: switch (verdict) { case -1: /* no-op for caller, same value remains */ case 1: /* value may be (re-)applied */ if (reload_requires_restart < 0) reload_requires_restart = 0; break; case 0: /* value may not be (re-)applied, but it may not have been required */ break; } upsdebugx(6, "%s: verdict for (re)loading var=%s value: %d", __func__, NUT_STRARG(var), verdict); return verdict; } /* Similar to testvar_reloadable() above which is for addvar*() defined * entries, but for less streamlined stuff defined right here in main.c. * See if value (probably saved in dstate) can be (re-)loaded now: either * it is reloadable by parameter definition, or no value has been saved * into it yet ( is NULL). * Returns "-1" if nothing needs to be done and that is not a failure * (e.g. value not modified so we do not care if we may change it or not). */ int testval_reloadable(const char *var, const char *oldval, const char *newval, int reloadable) { int verdict = -2; upsdebugx(6, "%s: var=%s, oldval=%s, newval=%s, reloadable=%d, reload_flag=%d", __func__, NUT_STRARG(var), NUT_STRARG(oldval), NUT_STRARG(newval), reloadable, reload_flag); /* Nothing saved yet? Okay to store new value! */ if (!oldval) { verdict = 1; goto finish; } /* Should not happen? Or... (commented-away etc.) */ if (!newval) { upslogx(LOG_WARNING, "%s: new setting for '%s' is NULL", __func__, var); verdict = ((!reload_flag) || reloadable); goto finish; } /* a value is already known, another is desired */ if (!strcasecmp(oldval, newval)) { if (reload_flag) { upsdebugx(1, "%s: setting '%s' " "exists and is unmodified", __func__, var); } verdict = -1; /* no-op for caller */ goto finish; } else { /* warn loudly if we are reloading and * can not change this modified value */ upsdebugx((reload_flag ? (reloadable ? 1 : 0) : 1), "%s: setting '%s' exists and differs: " "new value '%s' vs. '%s'%s", __func__, var, newval, oldval, ((!reload_flag || reloadable) ? "" : " (driver restart is needed to apply)") ); /* FIXME: Define a special EXIT_RELOAD or something, * for "not quite a failure"? Or close connections * and re-exec() this driver from scratch (and so to * keep MAINPID for systemd et al)? */ if (reload_flag == 2 && !reloadable) fatalx( #ifndef WIN32 (128 + SIGCMD_RELOAD_OR_EXIT) #else EXIT_SUCCESS #endif , "NUT driver reload-or-exit: setting %s was changed and requires a driver restart", var); /* For initial config reads, legacy code trusted what it saw */ verdict = ((!reload_flag) || reloadable); /* handle reload-or-error reports */ if (verdict == 0) { if (reload_requires_restart < 1) reload_requires_restart = 1; else reload_requires_restart++; } goto finish; } finish: switch (verdict) { case -1: /* no-op for caller, same value remains */ case 1: /* value may be (re-)applied */ if (reload_requires_restart < 0) reload_requires_restart = 0; break; case 0: /* value may not be (re-)applied, but it may not have been required */ break; } upsdebugx(6, "%s: verdict for (re)loading var=%s value: %d", __func__, NUT_STRARG(var), verdict); return verdict; } /* Similar to testvar_reloadable() above which is for addvar*() defined * entries, but for less streamlined stuff defined right here in main.c. * See if (by name saved in dstate) can be (re-)loaded now: * either it is reloadable by parameter definition, or no value has been * saved into it yet ( is NULL). * Returns "-1" if nothing needs to be done and that is not a failure * (e.g. value not modified so we do not care if we may change it or not). */ int testinfo_reloadable(const char *var, const char *infoname, const char *newval, int reloadable) { int verdict = -2; upsdebugx(6, "%s: var=%s, infoname=%s, newval=%s, reloadable=%d, reload_flag=%d", __func__, NUT_STRARG(var), NUT_STRARG(infoname), NUT_STRARG(newval), reloadable, reload_flag); /* Keep legacy behavior: not reloading, trust the initial config */ if (!reload_flag || !infoname) { verdict = 1; goto finish; } /* Suffer the overhead of lookups only if reloading */ /* FIXME: handle "driver.flag.*" prefixed values specially somehow? * Either we set the flag at some point (because its name is mentioned) * or we do not (initially set - no way so far to know it got commented * away before a reload on the fly). Might load new config info into a * separate list and then compare missing points?.. */ verdict = testval_reloadable(var, dstate_getinfo(infoname), newval, reloadable); finish: upsdebugx(6, "%s: verdict for (re)loading var=%s value: %d", __func__, NUT_STRARG(var), verdict); return verdict; } /* implement callback from driver - create the table for -x/conf entries */ static void do_addvar(int vartype, const char *name, const char *desc, int reloadable) { vartab_t *tmp, *last; tmp = last = vartab_h; while (tmp) { last = tmp; tmp = tmp->next; } tmp = xmalloc(sizeof(vartab_t)); tmp->vartype = vartype; tmp->var = xstrdup(name); tmp->val = NULL; tmp->desc = xstrdup(desc); tmp->found = 0; tmp->reloadable = reloadable; tmp->next = NULL; if (last) last->next = tmp; else vartab_h = tmp; } /* public callback from driver - create the table for -x/conf entries for reloadable values */ void addvar_reloadable(int vartype, const char *name, const char *desc) { do_addvar(vartype, name, desc, 1); } /* public callback from driver - create the table for -x/conf entries for set-once values */ void addvar(int vartype, const char *name, const char *desc) { do_addvar(vartype, name, desc, 0); } /* handle instant commands common for all drivers */ int main_instcmd(const char *cmdname, const char *extra, conn_t *conn) { char buf[SMALLBUF]; if (conn) #ifndef WIN32 snprintf(buf, sizeof(buf), "socket %d", conn->fd); #else snprintf(buf, sizeof(buf), "handle %p", conn->fd); #endif else snprintf(buf, sizeof(buf), "(null)"); upsdebugx(2, "entering main_instcmd(%s, %s) for [%s] on %s", cmdname, extra, NUT_STRARG(upsname), buf); if (!strcmp(cmdname, "driver.killpower")) { if (!strcmp("1", dstate_getinfo("driver.flag.allow_killpower"))) { upslogx(LOG_WARNING, "Requesting UPS [%s] to power off, " "as/if handled by its driver by default (may exit), " "due to socket protocol request", NUT_STRARG(upsname)); upsdrv_shutdown(); return STAT_INSTCMD_HANDLED; } else { upslogx(LOG_WARNING, "Got socket protocol request for UPS [%s] " "to power off, but driver.flag.allow_killpower does not" "permit this - request was currently ignored!", NUT_STRARG(upsname)); return STAT_INSTCMD_INVALID; } } #ifndef WIN32 /* TODO: Equivalent for WIN32 - see SIGCMD_RELOAD in upd and upsmon */ if (!strcmp(cmdname, "driver.reload")) { set_reload_flag(SIGCMD_RELOAD); /* TODO: sync mode to track that reload finished, and how? * Especially to know if there were values we can not change * on the fly, so caller may want to restart the driver itself. */ return STAT_INSTCMD_HANDLED; } if (!strcmp(cmdname, "driver.reload-or-exit")) { set_reload_flag(SIGCMD_RELOAD_OR_EXIT); return STAT_INSTCMD_HANDLED; } # ifdef SIGCMD_RELOAD_OR_RESTART if (!strcmp(cmdname, "driver.reload-or-restart")) { set_reload_flag(SIGCMD_RELOAD_OR_RESTART); return STAT_INSTCMD_HANDLED; } # endif #endif /* WIN32 */ #ifndef DRIVERS_MAIN_WITHOUT_MAIN if (!strcmp(cmdname, "driver.reload-or-error")) { /* sync-capable handling */ set_reload_flag(SIGCMD_RELOAD_OR_ERROR); /* Returns a result code from INSTCMD enum values */ return handle_reload_flag(); } #endif /* By default, the driver-specific values are * unknown to shared standard handler */ upsdebugx(2, "shared %s() does not handle command %s, " "proceeding to driver-specific handler", __func__, cmdname); return STAT_INSTCMD_UNKNOWN; } /* handle setting variables common for all drivers */ int main_setvar(const char *varname, const char *val, conn_t *conn) { char buf[SMALLBUF]; if (conn) #ifndef WIN32 snprintf(buf, sizeof(buf), "socket %d", conn->fd); #else snprintf(buf, sizeof(buf), "handle %p", conn->fd); #endif else snprintf(buf, sizeof(buf), "(null)"); upsdebugx(2, "entering main_setvar(%s, %s) for [%s] on %s", varname, val, NUT_STRARG(upsname), buf); if (!strcmp(varname, "driver.debug")) { int num; if (str_to_int(val, &num, 10)) { if (num < 0) { upsdebugx(nut_debug_level > 0 ? 1 : 0, "NOTE: Will fall back to CLI/DriverConfig/GlobalConfig debug verbosity preference now"); num = -1; } if (nut_debug_level > 0 && num == 0) upsdebugx(1, "NOTE: Will disable verbose debug now, due to socket protocol request"); nut_debug_level_protocol = num; assign_debug_level(); return STAT_SET_HANDLED; } else { goto invalid; } } if (!strcmp(varname, "driver.flag.allow_killpower")) { int num = 0; if (str_to_int(val, &num, 10)) { if (num <= 0) { num = 0; } else num = 1; } else { /* support certain strings */ if (!strncmp(val, "enable", 6) /* "enabled" matches too */ || !strcmp(val, "true") || !strcmp(val, "yes") || !strcmp(val, "on") ) num = 1; } upsdebugx(1, "%s: Setting %s=%d", __func__, varname, num); dstate_setinfo("driver.flag.allow_killpower", "%d", num); return STAT_SET_HANDLED; } /* By default, the driver-specific values are * unknown to shared standard handler */ upsdebugx(2, "shared %s() does not handle variable %s, " "proceeding to driver-specific handler", __func__, varname); return STAT_SET_UNKNOWN; invalid: upsdebugx(1, "Error: UPS [%s]: invalid %s value: %s", NUT_STRARG(upsname), varname, val); return STAT_SET_INVALID; } /* handle -x / ups.conf config details that are for this part of the code */ static int main_arg(char *var, char *val) { int do_handle = -2; /* flags for main */ upsdebugx(3, "%s: var='%s' val='%s'", __func__, var ? var : "", /* null should not happen... but... */ val ? val : ""); /* !reload_flag simply forbids changing this flag on the fly, as * it would have no effect anyway without a (serial) reconnection */ if (!strcmp(var, "nolock")) { if (reload_flag) { upsdebugx(6, "%s: SKIP: flag var='%s' can not be reloaded", __func__, var); } else { do_lock_port = 0; dstate_setinfo("driver.flag.nolock", "enabled"); } return 1; /* handled */ } /* FIXME: this one we could potentially reload, but need to figure * out that the flag line was commented away or deleted -- there is * no setting value to flip in configs here */ if (!strcmp(var, "ignorelb")) { if (reload_flag) { upsdebugx(6, "%s: SKIP: flag var='%s' currently can not be reloaded", __func__, var); } else { dstate_setinfo("driver.flag.ignorelb", "enabled"); } return 1; /* handled */ } if (!strcmp(var, "allow_killpower")) { if (reload_flag) { upsdebugx(6, "%s: SKIP: flag var='%s' currently can not be reloaded " "(but may be changed by protocol SETVAR)", __func__, var); } else { dstate_setinfo("driver.flag.allow_killpower", "1"); } return 1; /* handled */ } /* any other flags are for the driver code */ if (!val) return 0; /* unhandled, pass it through to the driver */ /* In checks below, testinfo_reloadable(..., 0) should forbid * re-population of the setting with a new value, but emit a * warning if it did change (so driver restart is needed to apply) */ /* variables for main: port */ if (!strcmp(var, "port")) { if (testinfo_reloadable(var, "driver.parameter.port", val, 0) > 0) { device_path = xstrdup(val); device_name = xbasename(device_path); dstate_setinfo("driver.parameter.port", "%s", val); } return 1; /* handled */ } /* user specified at the driver level overrides that on global level * or the built-in default */ if (!strcmp(var, "user")) { if (testval_reloadable(var, user, val, 0) > 0) { if (user_from_cmdline) { upsdebugx(0, "User '%s' specified in driver section " "was ignored due to '%s' specified on command line", val, user); } else { upsdebugx(1, "Overriding previously specified user '%s' " "with '%s' specified for driver section", user, val); free(user); user = xstrdup(val); } } return 1; /* handled */ } if (!strcmp(var, "group")) { if (testval_reloadable(var, group, val, 0) > 0) { if (group_from_cmdline) { upsdebugx(0, "Group '%s' specified in driver section " "was ignored due to '%s' specified on command line", val, group); } else { upsdebugx(1, "Overriding previously specified group '%s' " "with '%s' specified for driver section", group, val); free(group); group = xstrdup(val); } } return 1; /* handled */ } if (!strcmp(var, "sddelay")) { upslogx(LOG_INFO, "Obsolete value sddelay found in ups.conf"); return 1; /* handled */ } /* Allow per-driver overrides of the global setting * and allow to reload this, why not. * Note: having both global+driver section definitions may * cause noise, but it allows either to be commented away * and the other to take hold. Both disappearing would not * be noticed by the reload operation currently, however. */ if (!strcmp(var, "pollinterval")) { char buf[SMALLBUF]; /* log a message if value changed; skip if no good buf */ if (snprintf(buf, sizeof(buf), "%" PRIdMAX, (intmax_t)poll_interval)) { if ((do_handle = testval_reloadable(var, buf, val, 1)) == 0) { /* Should not happen, but... */ fatalx(EXIT_FAILURE, "Error: failed to check " "testval_reloadable() for pollinterval: " "old %s vs. new %s", buf, NUT_STRARG(val)); } } if (do_handle > 0) { int ipv = atoi(val); if (ipv > 0) { poll_interval = (time_t)ipv; } else { fatalx(EXIT_FAILURE, "Error: UPS [%s]: invalid pollinterval: %d", NUT_STRARG(upsname), ipv); } } /* else: no-op */ return 1; /* handled */ } /* Allow per-driver overrides of the global setting * and allow to reload this, why not. * Note: this may cause "spurious" redefinitions of the * "no" setting which is the fallback for random values. * Also note that global+driver section definitions may * cause noise, but it allows either to be commented away * and the other to take hold. Both disappearing would not * be noticed by the reload operation currently, however. */ if (!strcmp(var, "synchronous")) { if (testval_reloadable(var, ((do_synchronous==1)?"yes":((do_synchronous==0)?"no":"auto")), val, 1) > 0) { if (!strcmp(val, "yes")) do_synchronous=1; else if (!strcmp(val, "auto")) do_synchronous=-1; else do_synchronous=0; } return 1; /* handled */ } /* only for upsdrvctl - ignored here */ if (!strcmp(var, "sdorder")) return 1; /* handled */ /* only for upsd (at the moment) - ignored here */ if (!strcmp(var, "desc")) return 1; /* handled */ /* Allow each driver to specify its minimal debugging level - * admins can set more with command-line args, but can't set * less without changing config. Should help debug of services. * Note: during reload_flag!=0 handling this is reset to -1, to * catch commented-away settings, so not checking previous value. */ if (!strcmp(var, "debug_min")) { int lvl = -1; // typeof common/common.c: int nut_debug_level if ( str_to_int (val, &lvl, 10) && lvl >= 0 ) { nut_debug_level_driver = lvl; } else { upslogx(LOG_INFO, "WARNING : Invalid debug_min value found in ups.conf for the driver"); } return 1; /* handled */ } return 0; /* unhandled, pass it through to the driver */ } static void do_global_args(const char *var, const char *val) { char buf[SMALLBUF]; int do_handle = 1; upsdebugx(3, "%s: var='%s' val='%s'", __func__, var ? var : "", /* null should not happen... but... */ val ? val : ""); /* Allow to reload this, why not */ if (!strcmp(var, "pollinterval")) { /* log a message if value changed; skip if no good buf */ if (snprintf(buf, sizeof(buf), "%" PRIdMAX, (intmax_t)poll_interval)) { if ((do_handle = testval_reloadable(var, buf, val, 1)) == 0) { /* Should not happen, but... */ fatalx(EXIT_FAILURE, "Error: failed to check " "testval_reloadable() for pollinterval: " "old %s vs. new %s", buf, val); } } if (do_handle > 0) { int ipv = atoi(val); if (ipv > 0) { poll_interval = (time_t)ipv; } else { fatalx(EXIT_FAILURE, "Error: invalid pollinterval: %d", ipv); } } /* else: no-op */ return; } /* In checks below, testinfo_reloadable(..., 0) should forbid * re-population of the setting with a new value, but emit a * warning if it did change (so driver restart is needed to apply) */ if (!strcmp(var, "chroot")) { if (testval_reloadable(var, chroot_path, val, 0) > 0) { free(chroot_path); chroot_path = xstrdup(val); } return; } if (!strcmp(var, "user")) { if (testval_reloadable(var, user, val, 0) > 0) { if (user_from_cmdline) { upsdebugx(0, "User specified in global section '%s' " "was ignored due to '%s' specified on command line", val, user); } else { upsdebugx(1, "Overriding previously specified user '%s' " "with '%s' specified in global section", user, val); free(user); user = xstrdup(val); } } return; } if (!strcmp(var, "group")) { if (testval_reloadable(var, group, val, 0) > 0) { if (group_from_cmdline) { upsdebugx(0, "Group specified in global section '%s' " "was ignored due to '%s' specified on command line", val, group); } else { upsdebugx(1, "Overriding previously specified group '%s' " "with '%s' specified in global section", group, val); free(group); group = xstrdup(val); } } return; } /* Allow to reload this, why not * Note: this may cause "spurious" redefinitions of the * "no" setting which is the fallback for random values. * Also note that global+driver section definitions may * cause noise, but it allows either to be commented away * and the other to take hold. Both disappearing would not * be noticed by the reload operation currently, however. */ if (!strcmp(var, "synchronous")) { if (testval_reloadable(var, ((do_synchronous==1)?"yes":((do_synchronous==0)?"no":"auto")), val, 1) > 0) { if (!strcmp(val, "yes")) do_synchronous=1; else if (!strcmp(val, "auto")) do_synchronous=-1; else do_synchronous=0; } return; } /* Allow to specify its minimal debugging level for all drivers - * admins can set more with command-line args, but can't set * less without changing config. Should help debug of services. * Note: during reload_flag!=0 handling this is reset to -1, to * catch commented-away settings, so not checking previous value. */ if (!strcmp(var, "debug_min")) { int lvl = -1; // typeof common/common.c: int nut_debug_level if ( str_to_int (val, &lvl, 10) && lvl >= 0 ) { nut_debug_level_global = lvl; } else { upslogx(LOG_INFO, "WARNING : Invalid debug_min value found in ups.conf global settings"); } return; } /* unrecognized */ } void do_upsconf_args(char *confupsname, char *var, char *val) { char tmp[SMALLBUF]; upsdebugx(5, "%s: confupsname=%s, var=%s, val=%s", __func__, NUT_STRARG(confupsname), NUT_STRARG(var), NUT_STRARG(val)); /* handle global declarations */ if (!confupsname) { upsdebugx(5, "%s: call do_global_args()", __func__); do_global_args(var, val); return; } /* no match = not for us */ if (strcmp(confupsname, upsname) != 0) return; upsname_found = 1; upsdebugx(5, "%s: call main_arg()", __func__); if (main_arg(var, val)) return; upsdebugx(5, "%s: not a main_arg()", __func__); /* flags (no =) now get passed to the driver-level stuff */ if (!val) { upsdebugx(5, "%s: process as flag", __func__); /* also store this, but it's a bit different */ snprintf(tmp, sizeof(tmp), "driver.flag.%s", var); /* allow reloading if defined and permitted via addvar() * or not defined there (FIXME?) */ if (testvar_reloadable(var, NULL, VAR_FLAG) > 0) { dstate_setinfo(tmp, "enabled"); storeval(var, NULL); } return; } /* In checks below, testval_reloadable(..., 0) should forbid * re-population of the setting with a new value, but emit a * warning if it did change (so driver restart is needed to apply) */ /* don't let the user shoot themselves in the foot * reload should not allow changes here, but would report */ if (!strcmp(var, "driver")) { int do_handle; upsdebugx(5, "%s: this is a 'driver' setting, may we proceed?", __func__); do_handle = testval_reloadable(var, progname, val, 0); if (do_handle == -1) { upsdebugx(5, "%s: 'driver' setting already applied with this value", __func__); return; } /* Acceptable progname is only set once during start-up * val is from ups.conf */ if (!reload_flag || do_handle > 0) { /* Accomodate for libtool wrapped developer iterations * running e.g. `drivers/.libs/lt-dummy-ups` filenames */ size_t tmplen = strlen("lt-"); if (strncmp("lt-", progname, tmplen) == 0 && strcmp(val, progname + tmplen) == 0) { /* debug level may be not initialized yet, and situation * should not happen in end-user builds, so ok to yell: */ upsdebugx(0, "Seems this driver binary %s is a libtool " "wrapped build for driver %s", progname, val); /* progname points to xbasename(argv[0]) in-place; * roll the pointer forward a bit, we know we can: */ progname = progname + tmplen; } } if (strcmp(val, progname) != 0) { fatalx(EXIT_FAILURE, "Error: UPS [%s] is for driver %s, but I'm %s!\n", confupsname, val, progname); } return; } /* everything else must be for the driver */ /* allow reloading if defined and permitted via addvar() * or not defined there (FIXME?) */ upsdebugx(5, "%s: process as value", __func__); if (testvar_reloadable(var, val, VAR_VALUE) > 0) { storeval(var, val); } } static void assign_debug_level(void) { /* CLI debug level can not be smaller than debug_min specified * in ups.conf, and value specified for a driver config section * overrides the global one. Note that non-zero debug_min does * not impact foreground running mode. */ int nut_debug_level_upsconf = -1; if (nut_debug_level_protocol >= 0) { upslogx(LOG_INFO, "Applying debug level %d received during run-time " "via socket protocol, ignoring other settings", nut_debug_level_protocol); nut_debug_level = nut_debug_level_protocol; goto finish; } if (nut_debug_level_global >= 0 && nut_debug_level_driver >= 0) { /* Use nearest-defined fit */ nut_debug_level_upsconf = nut_debug_level_driver; if (reload_flag) { upslogx(LOG_INFO, "Applying debug_min=%d from ups.conf" " driver section (overriding global %d)", nut_debug_level_upsconf, nut_debug_level_global); } } else { if (nut_debug_level_global >= 0) { nut_debug_level_upsconf = nut_debug_level_global; if (reload_flag) upslogx(LOG_INFO, "Applying debug_min=%d from ups.conf" " global section", nut_debug_level_upsconf); } if (nut_debug_level_driver >= 0) { nut_debug_level_upsconf = nut_debug_level_driver; if (reload_flag) upslogx(LOG_INFO, "Applying debug_min=%d from ups.conf" " driver section", nut_debug_level_upsconf); } } if (reload_flag && nut_debug_level_upsconf <= nut_debug_level_args) { /* DEBUG_MIN is absent or commented-away in ups.conf, * or is smaller than te CLI arg '-D' count */ upslogx(LOG_INFO, "Applying debug level %d from " "original command line arguments", nut_debug_level_args); } /* at minimum, the verbosity we started with - via CLI arguments; * maybe a greater debug_min is set in current config file */ nut_debug_level = nut_debug_level_args; if (nut_debug_level_upsconf > nut_debug_level) nut_debug_level = nut_debug_level_upsconf; finish: upsdebugx(1, "debug level is '%d'", nut_debug_level); dstate_setinfo("driver.debug", "%d", nut_debug_level); dstate_setflags("driver.debug", ST_FLAG_RW | ST_FLAG_NUMBER); } #ifndef DRIVERS_MAIN_WITHOUT_MAIN /* Returns a result code from INSTCMD enum values */ static int handle_reload_flag(void) { int ret; if (!reload_flag || exit_flag) return STAT_INSTCMD_INVALID; upslogx(LOG_INFO, "Handling requested live reload of NUT driver configuration for [%s]", upsname); dstate_setinfo("driver.state", "reloading"); upsnotify(NOTIFY_STATE_RELOADING, NULL); /* If commented away or deleted in config, debug_min * should "disappear" for us (a CLI argument, if any, * would still be honoured); if it is (re-)defined in * config, then it gets considered. */ nut_debug_level_global = -1; nut_debug_level_driver = -1; /* Call actual config reloading activity, which * eventually calls back do_upsconf_args() from * this program. */ reload_requires_restart = -1; /* 0 - Do not abort drivers started with '-s TMP_UPS_NAME' */ if (read_upsconf(0) < 0) { upsdebugx(1, "%s: read_upsconf() failed fundamentally; " "is this driver running via ups.conf at all?", __func__); } upsdebugx(1, "%s: read_upsconf() for [%s] completed, restart-required verdict was: %d", __func__, upsname, reload_requires_restart); /* handle reload-or-error reports */ if (reload_requires_restart < 1) { /* -1 unchanged, 0 nobody complained and everyone confirmed */ ret = STAT_INSTCMD_HANDLED; } else { /* 1+ entries required a restart */ ret = STAT_INSTCMD_INVALID; } /* TODO: Callbacks in drivers to re-parse configs? * Currently this reloadability relies on either * explicit reload_flag aware code called from the * read_upsconf() method, or on drivers continuously * reading dstate_getinfo() and not caching once * their C variables. */ /* Re-mix currently known debug verbosity desires */ assign_debug_level(); /* Wrap it up */ reload_flag = 0; dstate_setinfo("driver.state", "quiet"); upsnotify(NOTIFY_STATE_READY, NULL); upslogx(LOG_INFO, "Completed requested live reload of NUT driver configuration for [%s]: %d", upsname, ret); return ret; } /* split -x foo=bar into 'foo' and 'bar' */ static void splitxarg(char *inbuf) { char *eqptr, *val, *buf; /* make our own copy - avoid changing argv */ buf = xstrdup(inbuf); eqptr = strchr(buf, '='); if (!eqptr) val = NULL; else { *eqptr++ = '\0'; val = eqptr; } /* see if main handles this first */ if (main_arg(buf, val)) return; /* otherwise store it for later */ storeval(buf, val); } /* dump the list from the vartable for external parsers */ static void listxarg(void) { vartab_t *tmp; tmp = vartab_h; if (!tmp) return; while (tmp) { switch (tmp->vartype) { case VAR_VALUE: printf("VALUE"); break; case VAR_FLAG: printf("FLAG"); break; default: printf("UNKNOWN"); break; } printf(" %s \"%s\"\n", tmp->var, tmp->desc); tmp = tmp->next; } } #endif /* DRIVERS_MAIN_WITHOUT_MAIN */ # ifndef DRIVERS_MAIN_WITHOUT_MAIN static # endif /* DRIVERS_MAIN_WITHOUT_MAIN */ void vartab_free(void) { vartab_t *tmp, *next; tmp = vartab_h; while (tmp) { next = tmp->next; free(tmp->var); free(tmp->val); free(tmp->desc); free(tmp); tmp = next; } } #ifndef DRIVERS_MAIN_WITHOUT_MAIN static void exit_upsdrv_cleanup(void) { dstate_setinfo("driver.state", "cleanup.upsdrv"); upsdrv_cleanup(); } static void exit_cleanup(void) { dstate_setinfo("driver.state", "cleanup.exit"); if (!dump_data) { upsnotify(NOTIFY_STATE_STOPPING, "exit_cleanup()"); } free(chroot_path); free(device_path); free(user); free(group); if (pidfn) { unlink(pidfn); free(pidfn); } dstate_free(); vartab_free(); #ifdef WIN32 if(mutex != INVALID_HANDLE_VALUE) { ReleaseMutex(mutex); CloseHandle(mutex); } #endif } #endif /* DRIVERS_MAIN_WITHOUT_MAIN */ void set_exit_flag(int sig) { switch (exit_flag) { case -2: upsdebugx(1, "%s: raising exit flag due to programmatic abort: EXIT_SUCCESS", __func__); break; case -1: upsdebugx(1, "%s: raising exit flag due to programmatic abort: EXIT_FAILURE", __func__); break; default: upsdebugx(1, "%s: raising exit flag due to signal %d", __func__, sig); } exit_flag = sig; } static void set_reload_flag( #ifndef WIN32 int #else char * #endif sig) { #ifndef WIN32 /* TODO: Equivalent for WIN32 - see SIGCMD_RELOAD in upd and upsmon */ switch (sig) { case SIGCMD_RELOAD_OR_EXIT: /* SIGUSR1 */ /* reload-or-exit (this driver instance may die) */ reload_flag = 2; break; #ifdef SIGCMD_RELOAD_OR_RESTART case SIGCMD_RELOAD_OR_RESTART: /* SIGUSR2 */ /* reload-or-restart (this driver instance may recycle itself) */ /* FIXME: Not implemented yet */ reload_flag = 3; break; #endif case SIGCMD_RELOAD: /* SIGHUP */ case SIGCMD_RELOAD_OR_ERROR: /* Not even a signal, but a socket protocol action */ default: /* reload what we can, log what needs a restart so skipped */ reload_flag = 1; } upsdebugx(1, "%s: raising reload flag due to signal %d (%s) => reload_flag=%d", __func__, sig, strsignal(sig), reload_flag); #else if (sig && !strcmp(sig, SIGCMD_RELOAD_OR_ERROR)) { /* reload what we can, log what needs a restart so skipped */ reload_flag = 1; } else { /* non-fatal reload as a fallback */ reload_flag = 1; } upsdebugx(1, "%s: raising reload flag due to command %s => reload_flag=%d", __func__, sig, reload_flag); #endif /* WIN32 */ } #ifndef WIN32 /* TODO: Equivalent for WIN32 - see SIGCMD_RELOAD in upd and upsmon */ static void handle_dstate_dump(int sig) { /* no set_dump_flag() here, make it instant */ upsdebugx(1, "%s: starting driver state dump for [%s] due to signal %d", __func__, upsname, sig); /* FIXME: upslogx() instead of printf() when backgrounded, if STDOUT got closed? */ dstate_dump(); upsdebugx(1, "%s: finished driver state dump for [%s]", __func__, upsname); } # ifndef DRIVERS_MAIN_WITHOUT_MAIN static # endif /* DRIVERS_MAIN_WITHOUT_MAIN */ void setup_signals(void) { struct sigaction sa; sigemptyset(&sa.sa_mask); sa.sa_flags = 0; /* handle shutdown signals */ sa.sa_handler = set_exit_flag; sigaction(SIGTERM, &sa, NULL); sigaction(SIGINT, &sa, NULL); sigaction(SIGQUIT, &sa, NULL); /* basic signal setup to ignore SIGPIPE */ #if (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_PUSH_POP) && (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_STRICT_PROTOTYPES) # pragma GCC diagnostic push # pragma GCC diagnostic ignored "-Wstrict-prototypes" #endif sa.sa_handler = SIG_IGN; #if (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_PUSH_POP) && (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_STRICT_PROTOTYPES) # pragma GCC diagnostic pop #endif sigaction(SIGPIPE, &sa, NULL); /* handle reloading */ sa.sa_handler = set_reload_flag; sigaction(SIGCMD_RELOAD, &sa, NULL); /* SIGHUP */ sigaction(SIGCMD_RELOAD_OR_EXIT, &sa, NULL); /* SIGUSR1 */ # ifdef SIGCMD_RELOAD_OR_RESTART /* FIXME: Want SIGCMD_RELOAD_OR_RESTART implemented */ sigaction(SIGCMD_RELOAD_OR_RESTART, &sa, NULL); /* SIGUSR2 */ # endif # ifdef SIGCMD_DATA_DUMP /* handle run-time data dump (may be limited to non-backgrounding lifetimes) */ sa.sa_handler = handle_dstate_dump; sigaction(SIGCMD_DATA_DUMP, &sa, NULL); /* SIGURG or SIGWINCH something else on obscure systems */ # endif } #endif /* WIN32*/ /* This source file is used in some unit tests to mock realistic driver * behavior - using a production driver skeleton, but their own main(). */ #ifndef DRIVERS_MAIN_WITHOUT_MAIN int main(int argc, char **argv) { struct passwd *new_uid = NULL; int i, do_forceshutdown = 0; int update_count = 0; #ifndef WIN32 int cmd = 0; pid_t oldpid = -1; #else /* FIXME: *actually* handle WIN32 builds too */ const char * cmd = NULL; #endif /* init verbosity from default in common.c (0 probably) */ nut_debug_level_args = nut_debug_level; dstate_setinfo("driver.state", "init.starting"); atexit(exit_cleanup); /* pick up a default from configure --with-user */ user = xstrdup(RUN_AS_USER); /* xstrdup: this gets freed at exit */ /* pick up a default from configure --with-group */ group = xstrdup(RUN_AS_GROUP); /* xstrdup: this gets freed at exit */ progname = xbasename(argv[0]); #ifdef WIN32 const char * drv_name; drv_name = xbasename(argv[0]); /* remove trailing .exe */ char * dot = strrchr(drv_name,'.'); if( dot != NULL ) { if(strcasecmp(dot, ".exe") == 0 ) { progname = strdup(drv_name); char * t = strrchr(progname,'.'); *t = 0; } } else { progname = strdup(drv_name); } #endif open_syslog(progname); upsdrv_banner(); if (upsdrv_info.status == DRV_EXPERIMENTAL) { printf("Warning: This is an experimental driver.\n"); printf("Some features may not function correctly.\n\n"); } /* build the driver's extra (-x) variable table */ upsdrv_makevartable(); while ((i = getopt(argc, argv, "+a:s:kFBDd:hx:Lqr:u:g:Vi:c:" #ifndef WIN32 "P:" #endif )) != -1) { switch (i) { case 'a': if (upsname) fatalx(EXIT_FAILURE, "Error: options '-a id' and '-s id' " "are mutually exclusive and single-use only."); upsname = optarg; read_upsconf(1); if (!upsname_found) fatalx(EXIT_FAILURE, "Error: Section %s not found in ups.conf", optarg); break; case 's': if (upsname) fatalx(EXIT_FAILURE, "Error: options '-a id' and '-s id' " "are mutually exclusive and single-use only."); upsname = optarg; upsname_found = 1; break; case 'F': if (foreground > 0) { /* specified twice to save PID file anyway */ foreground = 2; } else { foreground = 1; } break; case 'B': foreground = 0; break; case 'D': /* bump right here, may impact reporting of other CLI args */ nut_debug_level++; nut_debug_level_args++; break; case 'd': dump_data = atoi(optarg); break; case 'i': { /* scope */ int ipv = atoi(optarg); if (ipv > 0) { poll_interval = (time_t)ipv; } else { fatalx(EXIT_FAILURE, "Error: command-line: invalid pollinterval: %d", ipv); } } break; case 'k': do_lock_port = 0; do_forceshutdown = 1; break; /* FIXME: port event loop from upsd/upsmon to allow messaging fellow drivers in WIN32 builds */ case 'c': if (cmd) { help_msg(); fatalx(EXIT_FAILURE, "Error: only one command per run can be " "sent with option -%c. Try -h for help.", i); } if (!strncmp(optarg, "reload-or-error", strlen(optarg))) { cmd = SIGCMD_RELOAD_OR_ERROR; } #ifndef WIN32 else if (!strncmp(optarg, "reload", strlen(optarg))) { cmd = SIGCMD_RELOAD; } else # ifdef SIGCMD_RELOAD_OR_RESTART if (!strncmp(optarg, "reload-or-restart", strlen(optarg))) { cmd = SIGCMD_RELOAD_OR_RESTART; } else # endif if (!strncmp(optarg, "reload-or-exit", strlen(optarg))) { cmd = SIGCMD_RELOAD_OR_EXIT; } #endif /* WIN32 */ /* bad command given */ if (!cmd) { help_msg(); fatalx(EXIT_FAILURE, "Error: unknown argument to option -%c. Try -h for help.", i); } #ifndef WIN32 upsdebugx(1, "Will send signal %d (%s) for command '%s' " "to already-running driver %s-%s (if any) and exit", cmd, strsignal(cmd), optarg, progname, upsname); #else upsdebugx(1, "Will send request '%s' for command '%s' " "to already-running driver %s-%s (if any) and exit", cmd, optarg, progname, upsname); #endif /* WIN32 */ break; #ifndef WIN32 /* NOTE for FIXME above: PID-signalling is non-WIN32-only for us */ case 'P': if ((oldpid = parsepid(optarg)) < 0) help_msg(); break; #endif /* WIN32 */ case 'L': listxarg(); exit(EXIT_SUCCESS); case 'q': nut_log_level++; break; case 'r': chroot_path = xstrdup(optarg); break; case 'u': if (user_from_cmdline) { upsdebugx(1, "Previously specified user for drivers '%s' " "was ignored due to '%s' specified on command line" " (again?)", user, optarg); } else { upsdebugx(1, "Built-in default or configured user " "for drivers '%s' was ignored due to '%s' " "specified on command line", user, optarg); } free(user); user = xstrdup(optarg); user_from_cmdline = 1; break; case 'g': if (group_from_cmdline) { upsdebugx(1, "Previously specified group for drivers '%s' " "was ignored due to '%s' specified on command line" " (again?)", group, optarg); } else { upsdebugx(1, "Built-in default or configured group " "for drivers '%s' was ignored due to '%s' " "specified on command line", group, optarg); } free(group); group = xstrdup(optarg); group_from_cmdline = 1; break; case 'V': /* already printed the banner for program name */ nut_report_config_flags(); exit(EXIT_SUCCESS); case 'x': splitxarg(optarg); break; case 'h': help_msg(); exit(EXIT_SUCCESS); default: fatalx(EXIT_FAILURE, "Error: unknown option -%c. Try -h for help.", i); } } if (foreground < 0) { /* Guess a default */ /* Note: only care about CLI-requested debug verbosity here */ if (nut_debug_level > 0 || dump_data) { /* Only flop from default - stay foreground with debug on */ foreground = 1; } else { /* Legacy default - stay background and quiet */ foreground = 0; } } else { /* Follow explicit user -F/-B request */ upsdebugx (0, "Debug level is %d, dump data count is %s, " "but backgrounding mode requested as %s", nut_debug_level, dump_data ? "on" : "off", foreground ? "off" : "on" ); } { /* scoping */ char *s = getenv("NUT_DEBUG_LEVEL"); int l; if (s && str_to_int(s, &l, 10)) { if (l > 0 && nut_debug_level_args < 1) { upslogx(LOG_INFO, "Defaulting debug verbosity to NUT_DEBUG_LEVEL=%d " "since none was requested by command-line options", l); nut_debug_level = l; nut_debug_level_args = l; } /* else follow -D settings */ } /* else nothing to bother about */ } /* Since debug mode dumps from drivers are often posted to mailing list * or issue tracker, as well as viewed locally, it can help to know the * build options involved when troubleshooting (especially when needed * to walk through building a PR branch with candidate fix for an issue). * Reference code for such message is in common/common.c prints to log * and/or syslog when any debug level is enabled. */ nut_report_config_flags(); argc -= optind; argv += optind; if (argc > 0) { fatalx(EXIT_FAILURE, "Error: too many non-option arguments. Try -h for help."); } if (!upsname_found) { fatalx(EXIT_FAILURE, "Error: specifying '-a id' or '-s id' is now mandatory. Try -h for help."); } /* we need to get the port from somewhere, unless we are just sending a signal and exiting */ if (!device_path && !cmd) { fatalx(EXIT_FAILURE, "Error: you must specify a port name in ups.conf or in '-x port=...' argument.\n" "Try -h for help."); } assign_debug_level(); new_uid = get_user_pwent(user); if (chroot_path) chroot_start(chroot_path); become_user(new_uid); /* Only switch to statepath if we're not powering off * or not just dumping data (for discovery) */ /* This avoids case where ie /var is unmounted already */ #ifndef WIN32 if ((!do_forceshutdown) && (!dump_data)) { if (chdir(dflt_statepath())) fatal_with_errno(EXIT_FAILURE, "Can't chdir to %s", dflt_statepath()); /* Setup signals to communicate with driver which is destined for a long run. */ setup_signals(); } #endif /* WIN32 */ if (do_forceshutdown) { /* First try to handle this over socket protocol * with the running older driver instance (if any); * if this does not succeed, fall through to legacy * approach (kill sibling if needed, recapture device, * command it...) */ ssize_t cmdret = -1; struct timeval tv; /* Post the query and wait for reply */ /* FIXME: coordinate with pollfreq? */ tv.tv_sec = 15; tv.tv_usec = 0; cmdret = upsdrvquery_oneshot(progname, upsname, "SET driver.flag.allow_killpower 1\n", NULL, 0, &tv); if (cmdret >= 0) { /* FIXME: somehow mark drivers expected to loop infinitely? */ tv.tv_sec = -1; tv.tv_usec = -1; cmdret = upsdrvquery_oneshot(progname, upsname, "INSTCMD driver.killpower\n", NULL, 0, &tv); if (cmdret < 0) { upsdebugx(1, "Socket dialog with the other driver instance: %s", strerror(errno)); } else { upslogx(LOG_INFO, "Request to killpower via running driver returned code %" PRIiSIZE, cmdret); if (cmdret == 0) /* Note: many drivers would abort with * "shutdown not supported" at this * point... we would too, but later * and at a higher time/processing cost. */ exit (EXIT_SUCCESS); /* else fall through to legacy handling */ } } else { upsdebugx(1, "Socket dialog with the other driver instance: %s", strerror(errno)); } } /* Handle reload-or-error over socket protocol with * the running older driver instance */ #ifndef WIN32 if (cmd == SIGCMD_RELOAD_OR_ERROR) #else if (cmd && !strcmp(cmd, SIGCMD_RELOAD_OR_ERROR)) #endif /* WIN32 */ { /* Not a signal, but a socket protocol action */ ssize_t cmdret = -1; char buf[LARGEBUF]; struct timeval tv; /* Post the query and wait for reply */ /* FIXME: coordinate with pollfreq? */ tv.tv_sec = 15; tv.tv_usec = 0; cmdret = upsdrvquery_oneshot(progname, upsname, "INSTCMD driver.reload-or-error\n", buf, sizeof(buf), &tv); if (cmdret < 0) { upslog_with_errno(LOG_ERR, "Socket dialog with the other driver instance"); } else { /* TODO: handle buf reply contents */ upslogx(LOG_INFO, "Request to reload-or-error returned code %" PRIiSIZE, cmdret); } /* exit((cmdret == 0) ? EXIT_SUCCESS : EXIT_FAILURE); */ exit(((cmdret < 0) || (((uintmax_t)cmdret) > ((uintmax_t)INT_MAX))) ? 255 : (int)cmdret); } #ifndef WIN32 /* Setup PID file to receive signals to communicate with this driver * instance once backgrounded, and to stop a competing older instance. * Or to send it a signal deliberately. */ if (cmd || ((foreground == 0) && (!do_forceshutdown))) { char pidfnbuf[SMALLBUF]; snprintf(pidfnbuf, sizeof(pidfnbuf), "%s/%s-%s.pid", altpidpath(), progname, upsname); if (cmd) { /* Signals */ int cmdret = -1; /* Send a signal to older copy of the driver, if any */ if (oldpid < 0) { cmdret = sendsignalfn(pidfnbuf, cmd); } else { cmdret = sendsignalpid(oldpid, cmd); } switch (cmdret) { case 0: upsdebugx(1, "Signaled old daemon OK"); break; case -3: case -2: /* if starting new daemon, no competition running - * maybe OK (or failed to detect it => problem) * if signaling old daemon - certainly have a problem */ upslogx(LOG_WARNING, "Could not %s PID file '%s' " "to see if previous driver instance is " "already running!", (cmdret == -3 ? "find" : "parse"), pidfnbuf); break; case -1: case 1: /* WIN32 */ default: /* if cmd was nontrivial - speak up below, else be quiet */ upsdebugx(1, "Just failed to send signal, no daemon was running"); break; } /* We were signalling a daemon, successfully or not - exit now... * Modulo the possibility of a "reload-or-something" where we * effectively terminate the old driver and start a new one due * to configuration changes that were not reloadable. Such mode * is not implemented currently. */ if (cmdret != 0) { /* sendsignal*() above might have logged more details * for troubleshooting, e.g. about lack of PID file */ upslogx(LOG_NOTICE, "Failed to signal the currently running daemon (if any)"); # ifdef HAVE_SYSTEMD switch (cmd) { case SIGCMD_RELOAD: upslogx(LOG_NOTICE, "Try something like " "'systemctl reload nut-driver@%s.service'%s", upsname, (oldpid < 0 ? " or add '-P $PID' argument" : "")); break; case SIGCMD_RELOAD_OR_EXIT: # ifdef SIGCMD_RELOAD_OR_RESTART case SIGCMD_RELOAD_OR_RESTART: # endif upslogx(LOG_NOTICE, "Try something like " "'systemctl reload-or-restart " "nut-driver@%s.service'%s", upsname, (oldpid < 0 ? " or add '-P $PID' argument" : "")); break; default: upslogx(LOG_NOTICE, "Try something like " "'systemctl nut-driver@%s.service'%s", upsname, (oldpid < 0 ? " or add '-P $PID' argument" : "")); break; } /* ... or edit nut-server.service locally to start `upsd -FF` * and so save the PID file for ability to manage the daemon * beside the service framework, possibly confusing things... */ # else /* not HAVE_SYSTEMD */ if (oldpid < 0) { upslogx(LOG_NOTICE, "Try to add '-P $PID' argument"); } # endif /* HAVE_SYSTEMD */ } exit((cmdret == 0) ? EXIT_SUCCESS : EXIT_FAILURE); } /* Try to prevent that driver is started multiple times. If a PID file */ /* already exists, send a TERM signal to the process and try if it goes */ /* away. If not, retry a couple of times. */ for (i = 0; i < 3; i++) { struct stat st; if (stat(pidfnbuf, &st) != 0) { /* PID file not found */ break; } upslogx(LOG_WARNING, "Duplicate driver instance detected (PID file %s exists)! Terminating other driver!", pidfnbuf); if (sendsignalfn(pidfnbuf, SIGTERM) != 0) { /* Can't send signal to PID, assume invalid file */ break; } /* Allow driver some time to quit */ sleep(5); } if (i > 0) { struct stat st; if (stat(pidfnbuf, &st) == 0) { upslogx(LOG_WARNING, "Duplicate driver instance is still alive (PID file %s exists) after several termination attempts! Killing other driver!", pidfnbuf); if (sendsignalfn(pidfnbuf, SIGKILL) == 0) { sleep(5); if (sendsignalfn(pidfnbuf, 0) == 0) { upslogx(LOG_WARNING, "Duplicate driver instance is still alive (could signal the process)"); /* TODO: Should we writepid() below in this case? * Or if driver init fails, restore the old content * for that running sibling? */ } else { upslogx(LOG_WARNING, "Could not signal the other driver after kill, either its process is finally dead or owned by another user!"); } } else { upslogx(LOG_WARNING, "Could not signal the other driver, either its process is dead or owned by another user!"); } /* Note: PID file would remain here, but invalid * as far as further killers would be concerned */ } } /* Only write pid if we're not just dumping data, for discovery */ if (!dump_data) { pidfn = xstrdup(pidfnbuf); writepid(pidfn); /* before backgrounding */ } } #else /* WIN32 */ char name[SMALLBUF]; snprintf(name,sizeof(name), "%s-%s",progname,upsname); if (cmd) { /* FIXME: port event loop from upsd/upsmon to allow messaging fellow drivers in WIN32 builds */ /* Should not really get here since cmd would remain 0 until WIN32 support is implemented */ fatalx(EXIT_FAILURE, "Signal support not implemented for this platform"); } mutex = CreateMutex(NULL,TRUE,name); if(mutex == NULL ) { if( GetLastError() != ERROR_ACCESS_DENIED ) { fatalx(EXIT_FAILURE, "Can not create mutex %s : %d.\n",name,(int)GetLastError()); } } if (GetLastError() == ERROR_ALREADY_EXISTS || GetLastError() == ERROR_ACCESS_DENIED) { upslogx(LOG_WARNING, "Duplicate driver instance detected! Terminating other driver!"); for(i=0;i<10;i++) { DWORD res; sendsignal(name, COMMAND_STOP); if(mutex != NULL ) { res = WaitForSingleObject(mutex,1000); if(res==WAIT_OBJECT_0) { break; } } else { sleep(1); mutex = CreateMutex(NULL,TRUE,name); if(mutex != NULL ) { break; } } } if(i >= 10 ) { fatalx(EXIT_FAILURE, "Can not terminate the previous driver.\n"); } } #endif /* WIN32 */ /* clear out callback handler data */ memset(&upsh, '\0', sizeof(upsh)); /* note: device.type is set early to be overridden by the driver * when its a pdu! */ dstate_setinfo("device.type", "ups"); dstate_setinfo("driver.state", "init.device"); upsdrv_initups(); dstate_setinfo("driver.state", "init.quiet"); /* UPS is detected now, cleanup upon exit */ atexit(exit_upsdrv_cleanup); /* now see if things are very wrong out there */ if (upsdrv_info.status == DRV_BROKEN) { fatalx(EXIT_FAILURE, "Fatal error: broken driver. It probably needs to be converted.\n"); } if (do_forceshutdown) forceshutdown(); /* publish the top-level data: version numbers, driver name */ dstate_setinfo("driver.version", "%s", UPS_VERSION); dstate_setinfo("driver.version.internal", "%s", upsdrv_info.version); dstate_setinfo("driver.name", "%s", progname); /* * If we are not debugging, send the early startup logs generated by * upsdrv_initinfo() and upsdrv_updateinfo() to syslog, not just stderr. * Otherwise these logs are lost. */ if ((nut_debug_level == 0) && (!dump_data)) syslogbit_set(); /* get the base data established before allowing connections */ dstate_setinfo("driver.state", "init.info"); upsdrv_initinfo(); /* Note: a few drivers also call their upsdrv_updateinfo() during * their upsdrv_initinfo(), possibly to impact the initialization */ dstate_setinfo("driver.state", "init.updateinfo"); upsdrv_updateinfo(); dstate_setinfo("driver.state", "init.quiet"); if (dstate_getinfo("driver.flag.ignorelb")) { int have_lb_method = 0; if (dstate_getinfo("battery.charge") && dstate_getinfo("battery.charge.low")) { upslogx(LOG_INFO, "using 'battery.charge' to set battery low state"); have_lb_method++; } if (dstate_getinfo("battery.runtime") && dstate_getinfo("battery.runtime.low")) { upslogx(LOG_INFO, "using 'battery.runtime' to set battery low state"); have_lb_method++; } if (!have_lb_method) { fatalx(EXIT_FAILURE, "The 'ignorelb' flag is set, but there is no way to determine the\n" "battery state of charge.\n\n" "Only set this flag if both 'battery.charge' and 'battery.charge.low'\n" "and/or 'battery.runtime' and 'battery.runtime.low' are available.\n"); } } /* now we can start servicing requests */ /* Only write pid if we're not just dumping data, for discovery */ if (!dump_data) { char * sockname = dstate_init(progname, upsname); /* Normally we stick to the built-in account info, * so if they were not over-ridden - no-op here: */ if (strcmp(group, RUN_AS_GROUP) || strcmp(user, RUN_AS_USER) ) { #ifndef WIN32 int allOk = 1; /* Use file descriptor, not name, to first check and then manipulate permissions: * https://cwe.mitre.org/data/definitions/367.html * https://wiki.sei.cmu.edu/confluence/display/c/FIO01-C.+Be+careful+using+functions+that+use+file+names+for+identification */ TYPE_FD fd = ERROR_FD; /* Tune group access permission to the pipe, * so that upsd can access it (using the * specified or retained default group): */ struct group *grp = getgrnam(group); upsdebugx(1, "Group and/or user account for this driver " "was customized ('%s:%s') compared to built-in " "defaults. Fixing socket '%s' ownership/access.", user, group, sockname); if (grp == NULL) { upsdebugx(1, "WARNING: could not resolve " "group name '%s': %s", group, strerror(errno) ); allOk = 0; goto sockname_ownership_finished; } else { struct stat statbuf; mode_t mode; if (INVALID_FD((fd = open(sockname, O_RDWR | O_APPEND)))) { upsdebugx(1, "WARNING: opening socket file for stat/chown failed: %s", strerror(errno) ); allOk = 0; /* Can not proceed with ops below */ goto sockname_ownership_finished; } if (fstat(fd, &statbuf)) { upsdebugx(1, "WARNING: stat for chown failed: %s", strerror(errno) ); allOk = 0; } else { /* Here we do a portable chgrp() essentially: */ if (fchown(fd, statbuf.st_uid, grp->gr_gid)) { upsdebugx(1, "WARNING: chown failed: %s", strerror(errno) ); allOk = 0; } } /* Refresh file info */ if (fstat(fd, &statbuf)) { /* Logically we'd fail chown above if file * does not exist or is not accessible */ upsdebugx(1, "WARNING: stat for chmod failed: %s", strerror(errno) ); allOk = 0; } else { /* chmod g+rw sockname */ mode = statbuf.st_mode; mode |= S_IWGRP; mode |= S_IRGRP; if (fchmod(fd, mode)) { upsdebugx(1, "WARNING: chmod failed: %s", strerror(errno) ); allOk = 0; } } } sockname_ownership_finished: if (VALID_FD(fd)) { close(fd); fd = ERROR_FD; } if (allOk) { upsdebugx(1, "Group access for this driver successfully fixed"); } else { upsdebugx(0, "WARNING: Needed to fix group access " "to filesystem socket of this driver, but failed; " "run the driver with more debugging to see how exactly.\n" "Consumers of the socket, such as upsd data server, " "can fail to interact with the driver and represent " "the device: %s", sockname); } #else /* not WIN32 */ upsdebugx(1, "Options for alternate user/group are not implemented on this platform"); #endif /* WIN32 */ } free(sockname); } /* The poll_interval may have been changed from the default */ dstate_setinfo("driver.parameter.pollinterval", "%" PRIdMAX, (intmax_t)poll_interval); /* The synchronous option may have been changed from the default */ dstate_setinfo("driver.parameter.synchronous", "%s", (do_synchronous==1)?"yes":((do_synchronous==0)?"no":"auto")); /* remap the device.* info from ups.* for the transition period */ if (dstate_getinfo("ups.mfr") != NULL) dstate_setinfo("device.mfr", "%s", dstate_getinfo("ups.mfr")); if (dstate_getinfo("ups.model") != NULL) dstate_setinfo("device.model", "%s", dstate_getinfo("ups.model")); if (dstate_getinfo("ups.serial") != NULL) dstate_setinfo("device.serial", "%s", dstate_getinfo("ups.serial")); switch (foreground) { case 0: background(); /* We had saved a PID before backgrounding, but * it changes when backgrounding - so save again */ writepid(pidfn); break; /* >0: Keep the initial PID; don't care about "!dump_data" here * currently: let users figure out their mess (or neat hacks) */ case 2: if (!pidfn) { char pidfnbuf[SMALLBUF]; snprintf(pidfnbuf, sizeof(pidfnbuf), "%s/%s-%s.pid", altpidpath(), progname, upsname); pidfn = xstrdup(pidfnbuf); } upslogx(LOG_WARNING, "Running as foreground process, but saving a PID file anyway"); writepid(pidfn); break; default: upslogx(LOG_WARNING, "Running as foreground process, not saving a PID file"); } dstate_setinfo("driver.flag.allow_killpower", "0"); dstate_setflags("driver.flag.allow_killpower", ST_FLAG_RW | ST_FLAG_NUMBER); dstate_addcmd("driver.killpower"); #ifndef WIN32 /* TODO: Equivalent for WIN32 - see SIGCMD_RELOAD in upd and upsmon */ dstate_addcmd("driver.reload"); dstate_addcmd("driver.reload-or-exit"); # ifndef DRIVERS_MAIN_WITHOUT_MAIN dstate_addcmd("driver.reload-or-error"); # endif # ifdef SIGCMD_RELOAD_OR_RESTART dstate_addcmd("driver.reload-or-restart"); # endif #endif dstate_setinfo("driver.state", "quiet"); if (dump_data) { upsdebugx(1, "Driver initialization completed, beginning data dump (%d loops)", dump_data); } else { upsdebugx(1, "Driver initialization completed, beginning regular infinite loop"); upsnotify(NOTIFY_STATE_READY_WITH_PID, NULL); } while (!exit_flag) { struct timeval timeout; if (!dump_data) { upsnotify(NOTIFY_STATE_WATCHDOG, NULL); } gettimeofday(&timeout, NULL); timeout.tv_sec += poll_interval; dstate_setinfo("driver.state", "updateinfo"); upsdrv_updateinfo(); dstate_setinfo("driver.state", "quiet"); /* Dump the data tree (in upsc-like format) to stdout and exit */ if (dump_data) { /* Wait for 'dump_data' update loops to ensure data completion */ if (update_count == dump_data) { dstate_setinfo("driver.state", "dumping"); dstate_dump(); exit_flag = 1; } else update_count++; } else { while (!dstate_poll_fds(timeout, extrafd) && !exit_flag) { /* repeat until time is up or extrafd has data */ handle_reload_flag(); } } handle_reload_flag(); } /* if we get here, the exit flag was set by a signal handler */ /* however, avoid to "pollute" data dump output! */ if (!dump_data) { upslogx(LOG_INFO, "Signal %d: exiting", exit_flag); upsnotify(NOTIFY_STATE_STOPPING, "Signal %d: exiting", exit_flag); } exit(exit_flag == -1 ? EXIT_FAILURE : EXIT_SUCCESS); } #endif /* DRIVERS_MAIN_WITHOUT_MAIN */ nut-2.8.1/drivers/usbhid-ups.c0000644000175000017500000016427314514200703013167 00000000000000/* usbhid-ups.c - Driver for USB and serial (MGE SHUT) HID UPS units * * Copyright (C) * 2003-2022 Arnaud Quette * 2005 John Stamp * 2005-2006 Peter Selinger * 2007-2009 Arjen de Korte * 2016 Eaton / Arnaud Quette * * This program was sponsored by MGE UPS SYSTEMS, and now Eaton * * 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 2 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, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * TODO list: * - set ST_FLAG_RW according to HIDData_t->Attribute (ATTR_DATA_CST-ATTR_NVOL_VOL) */ #define DRIVER_NAME "Generic HID driver" #define DRIVER_VERSION "0.52" #define HU_VAR_WAITBEFORERECONNECT "waitbeforereconnect" #include "main.h" /* Must be first, includes "config.h" */ #include "nut_stdint.h" #include "libhid.h" #include "usbhid-ups.h" #include "hidparser.h" #include "hidtypes.h" #include "common.h" #ifdef WIN32 #include "wincompat.h" #endif /* include all known subdrivers */ #include "mge-hid.h" #if !((defined SHUT_MODE) && SHUT_MODE) /* explore stub goes first, others alphabetically */ #include "explore-hid.h" #include "apc-hid.h" #include "arduino-hid.h" #include "belkin-hid.h" #include "cps-hid.h" #include "delta_ups-hid.h" #include "ever-hid.h" #include "idowell-hid.h" #include "legrand-hid.h" #include "liebert-hid.h" #include "openups-hid.h" #include "powercom-hid.h" #include "powervar-hid.h" #include "salicru-hid.h" #include "tripplite-hid.h" #endif /* !SHUT_MODE => USB */ /* Reference list of available subdrivers */ static subdriver_t *subdriver_list[] = { #if !((defined SHUT_MODE) && SHUT_MODE) &explore_subdriver, #endif /* !SHUT_MODE => USB */ /* mge-hid.c supports both SHUT and USB */ &mge_subdriver, #if !((defined SHUT_MODE) && SHUT_MODE) &apc_subdriver, &arduino_subdriver, &belkin_subdriver, &cps_subdriver, &delta_ups_subdriver, &ever_subdriver, &idowell_subdriver, &legrand_subdriver, &liebert_subdriver, &openups_subdriver, &powercom_subdriver, &powervar_subdriver, &salicru_subdriver, &tripplite_subdriver, #endif /* !SHUT_MODE => USB */ NULL }; upsdrv_info_t upsdrv_info = { DRIVER_NAME, DRIVER_VERSION, "Arnaud Quette \n" \ "Peter Selinger \n" \ "Arjen de Korte \n" \ "John Stamp ", /*FIXME: link the subdrivers? do the same as for the mibs! */ #if !((defined SHUT_MODE) && SHUT_MODE) DRV_STABLE, #else /* SHUT_MODE */ DRV_EXPERIMENTAL, #endif /* SHUT_MODE / USB */ { &comm_upsdrv_info, NULL } }; /* Data walk modes */ typedef enum { HU_WALKMODE_INIT = 0, HU_WALKMODE_QUICK_UPDATE, HU_WALKMODE_FULL_UPDATE } walkmode_t; /* pointer to the active subdriver object (changed in callback() function) */ static subdriver_t *subdriver = NULL; /* Global vars */ static HIDDevice_t *hd = NULL; static HIDDevice_t curDevice = { 0x0000, 0x0000, NULL, NULL, NULL, NULL, 0, NULL #if (defined WITH_USB_BUSPORT) && (WITH_USB_BUSPORT) , NULL #endif }; static HIDDeviceMatcher_t *subdriver_matcher = NULL; #if !((defined SHUT_MODE) && SHUT_MODE) static HIDDeviceMatcher_t *exact_matcher = NULL; static HIDDeviceMatcher_t *regex_matcher = NULL; #endif /* !SHUT_MODE => USB */ static int pollfreq = DEFAULT_POLLFREQ; static unsigned ups_status = 0; static bool_t data_has_changed = FALSE; /* for SEMI_STATIC data polling */ #ifndef SUN_LIBUSB bool_t use_interrupt_pipe = TRUE; #else bool_t use_interrupt_pipe = FALSE; #endif static size_t interrupt_pipe_EIO_count = 0; /* How many times we had I/O errors since last reconnect? */ static time_t lastpoll; /* Timestamp the last polling */ hid_dev_handle_t udev = HID_DEV_HANDLE_CLOSED; /** * CyberPower UT series sometime need a bit of help deciding their online status. * This quirk is to enable the special handling of OL & DISCHRG at the same time * as being OB (on battery power/no mains power). Enabled by device config flag. */ static int onlinedischarge = 0; /** * Some UPS models (e.g. APC were seen to do so) report OL & DISCHRG when they * are in calibration mode. This usually happens after a few seconds reporting * an "OFF" state as well, while the hardware is switching to on-battery mode. */ static int onlinedischarge_calibration = 0; /* support functions */ static hid_info_t *find_nut_info(const char *varname); static hid_info_t *find_hid_info(const HIDData_t *hiddata); static const char *hu_find_infoval(info_lkp_t *hid2info, const double value); static long hu_find_valinfo(info_lkp_t *hid2info, const char* value); static void process_boolean_info(const char *nutvalue); static void ups_alarm_set(void); static void ups_status_set(void); static bool_t hid_ups_walk(walkmode_t mode); static int reconnect_ups(void); static int ups_infoval_set(hid_info_t *item, double value); static int callback(hid_dev_handle_t argudev, HIDDevice_t *arghd, usb_ctrl_charbuf rdbuf, usb_ctrl_charbufsize rdlen); #ifdef DEBUG static double interval(void); #endif /* global variables */ HIDDesc_t *pDesc = NULL; /* parsed Report Descriptor */ reportbuf_t *reportbuf = NULL; /* buffer for most recent reports */ int disable_fix_report_desc = 0; /* by default we apply fix-ups for broken USB encoding, etc. */ /* --------------------------------------------------------------- */ /* Struct & data for boolean processing */ /* --------------------------------------------------------------- */ /* Note: this structure holds internal status info, directly as collected from the hardware; not yet converted to official NUT status or alarms */ typedef struct { const char *status_str; /* ups status string */ const unsigned int status_mask; /* ups status mask */ } status_lkp_t; static status_lkp_t status_info[] = { /* map internal status strings to bit masks */ { "online", STATUS(ONLINE) }, { "dischrg", STATUS(DISCHRG) }, { "chrg", STATUS(CHRG) }, { "lowbatt", STATUS(LOWBATT) }, { "overload", STATUS(OVERLOAD) }, { "replacebatt", STATUS(REPLACEBATT) }, { "shutdownimm", STATUS(SHUTDOWNIMM) }, { "trim", STATUS(TRIM) }, { "boost", STATUS(BOOST) }, { "bypassauto", STATUS(BYPASSAUTO) }, { "bypassman", STATUS(BYPASSMAN) }, { "off", STATUS(OFF) }, { "cal", STATUS(CALIB) }, { "overheat", STATUS(OVERHEAT) }, { "commfault", STATUS(COMMFAULT) }, { "depleted", STATUS(DEPLETED) }, { "timelimitexp", STATUS(TIMELIMITEXP) }, { "fullycharged", STATUS(FULLYCHARGED) }, { "awaitingpower", STATUS(AWAITINGPOWER) }, { "fanfail", STATUS(FANFAIL) }, { "nobattery", STATUS(NOBATTERY) }, { "battvoltlo", STATUS(BATTVOLTLO) }, { "battvolthi", STATUS(BATTVOLTHI) }, { "chargerfail", STATUS(CHARGERFAIL) }, { "vrange", STATUS(VRANGE) }, { "frange", STATUS(FRANGE) }, { NULL, 0 }, }; /* ---------------------------------------------------------------------- */ /* value lookup tables and generic lookup functions */ /* Actual value lookup tables => should be fine for all Mfrs (TODO: validate it!) */ /* the purpose of the following status conversions is to collect information, not to interpret it. The function process_boolean_info() remembers these values by updating the global variable ups_status. Interpretation happens in ups_status_set, where they are converted to standard NUT status strings. Notice that the below conversions do not yield standard NUT status strings; this in indicated being in lower-case characters. The reason to separate the collection of information from its interpretation is that not each report received from the UPS may contain all the status flags, so they must be stored somewhere. Also, there can be more than one status flag triggering a certain condition (e.g. a certain UPS might have variables low_battery, shutdown_imminent, timelimit_exceeded, and each of these would trigger the NUT status LB. But we have to ensure that these variables don't unset each other, so they are remembered separately) */ info_lkp_t online_info[] = { { 1, "online", NULL, NULL }, { 0, "!online", NULL, NULL }, { 0, NULL, NULL, NULL } }; info_lkp_t discharging_info[] = { { 1, "dischrg", NULL, NULL }, { 0, "!dischrg", NULL, NULL }, { 0, NULL, NULL, NULL } }; info_lkp_t charging_info[] = { { 1, "chrg", NULL, NULL }, { 0, "!chrg", NULL, NULL }, { 0, NULL, NULL, NULL } }; info_lkp_t lowbatt_info[] = { { 1, "lowbatt", NULL, NULL }, { 0, "!lowbatt", NULL, NULL }, { 0, NULL, NULL, NULL } }; info_lkp_t overload_info[] = { { 1, "overload", NULL, NULL }, { 0, "!overload", NULL, NULL }, { 0, NULL, NULL, NULL } }; info_lkp_t replacebatt_info[] = { { 1, "replacebatt", NULL, NULL }, { 0, "!replacebatt", NULL, NULL }, { 0, NULL, NULL, NULL } }; info_lkp_t trim_info[] = { { 1, "trim", NULL, NULL }, { 0, "!trim", NULL, NULL }, { 0, NULL, NULL, NULL } }; info_lkp_t boost_info[] = { { 1, "boost", NULL, NULL }, { 0, "!boost", NULL, NULL }, { 0, NULL, NULL, NULL } }; info_lkp_t bypass_auto_info[] = { { 1, "bypassauto", NULL, NULL }, { 0, "!bypassauto", NULL, NULL }, { 0, NULL, NULL, NULL } }; info_lkp_t bypass_manual_info[] = { { 1, "bypassman", NULL, NULL }, { 0, "!bypassman", NULL, NULL }, { 0, NULL, NULL, NULL } }; /* note: this value is reverted (0=set, 1=not set). We report "being off" rather than "being on", so that devices that don't implement this variable are "on" by default */ info_lkp_t off_info[] = { { 0, "off", NULL, NULL }, { 1, "!off", NULL, NULL }, { 0, NULL, NULL, NULL } }; info_lkp_t calibration_info[] = { { 1, "cal", NULL, NULL }, { 0, "!cal", NULL, NULL }, { 0, NULL, NULL, NULL } }; /* note: this value is reverted (0=set, 1=not set). We report "battery not installed" rather than "battery installed", so that devices that don't implement this variable have a battery by default */ info_lkp_t nobattery_info[] = { { 1, "!nobattery", NULL, NULL }, { 0, "nobattery", NULL, NULL }, { 0, NULL, NULL, NULL } }; info_lkp_t fanfail_info[] = { { 1, "fanfail", NULL, NULL }, { 0, "!fanfail", NULL, NULL }, { 0, NULL, NULL, NULL } }; info_lkp_t shutdownimm_info[] = { { 1, "shutdownimm", NULL, NULL }, { 0, "!shutdownimm", NULL, NULL }, { 0, NULL, NULL, NULL } }; info_lkp_t overheat_info[] = { { 1, "overheat", NULL, NULL }, { 0, "!overheat", NULL, NULL }, { 0, NULL, NULL, NULL } }; info_lkp_t awaitingpower_info[] = { { 1, "awaitingpower", NULL, NULL }, { 0, "!awaitingpower", NULL, NULL }, { 0, NULL, NULL, NULL } }; info_lkp_t commfault_info[] = { { 1, "commfault", NULL, NULL }, { 0, "!commfault", NULL, NULL }, { 0, NULL, NULL, NULL } }; info_lkp_t timelimitexpired_info[] = { { 1, "timelimitexp", NULL, NULL }, { 0, "!timelimitexp", NULL, NULL }, { 0, NULL, NULL, NULL } }; info_lkp_t battvoltlo_info[] = { { 1, "battvoltlo", NULL, NULL }, { 0, "!battvoltlo", NULL, NULL }, { 0, NULL, NULL, NULL } }; info_lkp_t battvolthi_info[] = { { 1, "battvolthi", NULL, NULL }, { 0, "!battvolthi", NULL, NULL }, { 0, NULL, NULL, NULL } }; info_lkp_t chargerfail_info[] = { { 1, "chargerfail", NULL, NULL }, { 0, "!chargerfail", NULL, NULL }, { 0, NULL, NULL, NULL } }; info_lkp_t fullycharged_info[] = { /* used by CyberPower and TrippLite */ { 1, "fullycharged", NULL, NULL }, { 0, "!fullycharged", NULL, NULL }, { 0, NULL, NULL, NULL } }; info_lkp_t depleted_info[] = { { 1, "depleted", NULL, NULL }, { 0, "!depleted", NULL, NULL }, { 0, NULL, NULL, NULL } }; info_lkp_t vrange_info[] = { { 0, "!vrange", NULL, NULL }, { 1, "vrange", NULL, NULL }, { 0, NULL, NULL, NULL } }; info_lkp_t frange_info[] = { { 0, "!frange", NULL, NULL }, { 1, "frange", NULL, NULL }, { 0, NULL, NULL, NULL } }; info_lkp_t test_write_info[] = { { 0, "No test", NULL, NULL }, { 1, "Quick test", NULL, NULL }, { 2, "Deep test", NULL, NULL }, { 3, "Abort test", NULL, NULL }, { 0, NULL, NULL, NULL } }; info_lkp_t test_read_info[] = { { 1, "Done and passed", NULL, NULL }, { 2, "Done and warning", NULL, NULL }, { 3, "Done and error", NULL, NULL }, { 4, "Aborted", NULL, NULL }, { 5, "In progress", NULL, NULL }, { 6, "No test initiated", NULL, NULL }, { 7, "Test scheduled", NULL, NULL }, { 0, NULL, NULL, NULL } }; info_lkp_t beeper_info[] = { { 1, "disabled", NULL, NULL }, { 2, "enabled", NULL, NULL }, { 3, "muted", NULL, NULL }, { 0, NULL, NULL, NULL } }; info_lkp_t yes_no_info[] = { { 0, "no", NULL, NULL }, { 1, "yes", NULL, NULL }, { 0, NULL, NULL, NULL } }; info_lkp_t on_off_info[] = { { 0, "off", NULL, NULL }, { 1, "on", NULL, NULL }, { 0, NULL, NULL, NULL } }; /* returns statically allocated string - must not use it again before done with result! */ static const char *date_conversion_fun(double value) { /* Per spec https://www.usb.org/sites/default/files/pdcv11.pdf (page 38): * 4.2.6 Battery Settings -> ManufacturerDate * The date the pack was manufactured in a packed integer. * The date is packed in the following fashion: * (year – 1980)*512 + month*32 + day. */ static char buf[32]; long year, month, day; if ((long)value == 0) { return "not set"; } /* TOTHINK: About the comment below... * Does bit-shift keep the negativeness on all architectures? */ /* negative value represents pre-1980 date: */ year = 1980 + ((long)value >> 9); month = ((long)value >> 5) & 0x0f; day = (long)value & 0x1f; snprintf(buf, sizeof(buf), "%04ld/%02ld/%02ld", year, month, day); return buf; } static double date_conversion_reverse(const char* date_string) { long year, month, day; long date; sscanf(date_string, "%04ld/%02ld/%02ld", &year, &month, &day); if(year - 1980 > 127 || month > 12 || day > 31) return 0; date = (year - 1980) << 9; date += month << 5; date += day; return (double) date; } info_lkp_t date_conversion[] = { { 0, NULL, date_conversion_fun, date_conversion_reverse } }; /* returns statically allocated string - must not use it again before done with result! */ static const char *hex_conversion_fun(double value) { static char buf[20]; snprintf(buf, sizeof(buf), "%08lx", (long)value); return buf; } /* FIXME? Do we need an inverse "nuf()" here? */ info_lkp_t hex_conversion[] = { { 0, NULL, hex_conversion_fun, NULL } }; /* returns statically allocated string - must not use it again before done with result! */ static const char *stringid_conversion_fun(double value) { static char buf[20]; return HIDGetIndexString(udev, (int)value, buf, sizeof(buf)); } /* FIXME? Do we need an inverse "nuf()" here? */ info_lkp_t stringid_conversion[] = { { 0, NULL, stringid_conversion_fun, NULL } }; /* returns statically allocated string - must not use it again before done with result! */ static const char *divide_by_10_conversion_fun(double value) { static char buf[20]; snprintf(buf, sizeof(buf), "%0.1f", value * 0.1); return buf; } /* FIXME? Do we need an inverse "nuf()" here? */ info_lkp_t divide_by_10_conversion[] = { { 0, NULL, divide_by_10_conversion_fun, NULL } }; /* returns statically allocated string - must not use it again before done with result! */ static const char *kelvin_celsius_conversion_fun(double value) { static char buf[20]; /* check if the value is in the Kelvin range, to * detect buggy value (already expressed in °C), as found * on some HP implementation */ if ((value >= 273) && (value <= 373)) { /* the value is indeed in °K */ snprintf(buf, sizeof(buf), "%.1f", value - 273.15); } else { /* else, this is actually °C, not °K! */ snprintf(buf, sizeof(buf), "%.1f", value); } return buf; } /* FIXME? Do we need an inverse "nuf()" here? */ info_lkp_t kelvin_celsius_conversion[] = { { 0, NULL, kelvin_celsius_conversion_fun, NULL } }; static subdriver_t *match_function_subdriver_name(int fatal_mismatch) { char *subdrv = getval("subdriver"); subdriver_t *info = NULL; /* Pick up the subdriver name if set explicitly */ if (subdrv) { int i, flag_HAVE_LIBREGEX = 0; #if (defined HAVE_LIBREGEX && HAVE_LIBREGEX) int res; size_t len; regex_t *regex_ptr = NULL; flag_HAVE_LIBREGEX = 1; #endif upsdebugx(2, "%s: matching a subdriver by explicit " "name%s: '%s'...", __func__, flag_HAVE_LIBREGEX ? "/regex" : "", subdrv); /* First try exact match for strings like "TrippLite HID 0.85" * Not likely to hit (due to versions etc.), but worth a try :) */ for (i=0; subdriver_list[i] != NULL; i++) { if (strcmp_null(subdrv, subdriver_list[i]->name) == 0) { info = subdriver_list[i]; goto found; } } #if (defined HAVE_LIBREGEX && HAVE_LIBREGEX) /* Then try a case-insensitive regex like "tripplite.*" * if so provided by caller */ upsdebugx(2, "%s: retry matching by regex 'as is'", __func__); res = compile_regex(®ex_ptr, subdrv, REG_ICASE | REG_EXTENDED); if (res == 0 && regex_ptr != NULL) { for (i=0; subdriver_list[i] != NULL; i++) { res = match_regex(regex_ptr, subdriver_list[i]->name); if (res == 1) { free(regex_ptr); info = subdriver_list[i]; goto found; } } } if (regex_ptr) { free(regex_ptr); regex_ptr = NULL; } /* Then try a case-insensitive regex like "tripplite.*" * with automatically added ".*" */ len = strlen(subdrv); if ( (len < 3 || (subdrv[len-2] != '.' && subdrv[len-1] != '*')) && len < (LARGEBUF-3) ) { char buf[LARGEBUF]; upsdebugx(2, "%s: retry matching by regex with added '.*'", __func__); snprintf(buf, sizeof(buf), "%s.*", subdrv); res = compile_regex(®ex_ptr, buf, REG_ICASE | REG_EXTENDED); if (res == 0 && regex_ptr != NULL) { for (i=0; subdriver_list[i] != NULL; i++) { res = match_regex(regex_ptr, subdriver_list[i]->name); if (res == 1) { free(regex_ptr); info = subdriver_list[i]; goto found; } } } if (regex_ptr) { free(regex_ptr); regex_ptr = NULL; } } #endif /* HAVE_LIBREGEX */ if (fatal_mismatch) { fatalx(EXIT_FAILURE, "Configuration requested subdriver '%s' but none matched", subdrv); } else { upslogx(LOG_WARNING, "Configuration requested subdriver '%s' but none matched; " "will try USB matching by other fields", subdrv); } } /* No match (and non-fatal mismatch mode), or no * "subdriver" was specified in configuration */ return NULL; found: upsdebugx(2, "%s: found a match: %s", __func__, info->name); if (!getval("vendorid") || !getval("productid")) { if (fatal_mismatch) { fatalx(EXIT_FAILURE, "When specifying a subdriver, " "'vendorid' and 'productid' " "are mandatory."); } else { upslogx(LOG_WARNING, "When specifying a subdriver, " "'vendorid' and 'productid' " "are highly recommended."); } } return info; } /*! * subdriver matcher: only useful for USB mode * as SHUT is only supported by MGE UPS SYSTEMS units */ #if !((defined SHUT_MODE) && SHUT_MODE) static int match_function_subdriver(HIDDevice_t *d, void *privdata) { int i; NUT_UNUSED_VARIABLE(privdata); if (match_function_subdriver_name(1)) { /* This driver can handle this device. Guessing so... */ return 1; } upsdebugx(2, "%s (non-SHUT mode): matching a device...", __func__); for (i=0; subdriver_list[i] != NULL; i++) { if (subdriver_list[i]->claim(d)) { return 1; } } upsdebugx(2, "%s (non-SHUT mode): failed to match a subdriver " "to vendor and/or product ID", __func__); return 0; } static HIDDeviceMatcher_t subdriver_matcher_struct = { match_function_subdriver, NULL, NULL }; #endif /* !SHUT_MODE => USB */ /* --------------------------------------------- * driver functions implementations * --------------------------------------------- */ /* process instant command and take action. */ int instcmd(const char *cmdname, const char *extradata) { hid_info_t *hidups_item; const char *val; double value; if (!strcasecmp(cmdname, "beeper.off")) { /* compatibility mode for old command */ upslogx(LOG_WARNING, "The 'beeper.off' command has been " "renamed to 'beeper.disable'"); return instcmd("beeper.disable", NULL); } if (!strcasecmp(cmdname, "beeper.on")) { /* compatibility mode for old command */ upslogx(LOG_WARNING, "The 'beeper.on' command has been " "renamed to 'beeper.enable'"); return instcmd("beeper.enable", NULL); } upsdebugx(1, "instcmd(%s, %s)", cmdname, extradata ? extradata : "[NULL]"); /* Retrieve and check netvar & item_path */ hidups_item = find_nut_info(cmdname); /* Check for fallback if not found */ if (hidups_item == NULL) { upsdebugx(3, "%s: cmdname '%s' not found; " "checking for alternatives", __func__, cmdname); if (!strcasecmp(cmdname, "load.on")) { return instcmd("load.on.delay", "0"); } if (!strcasecmp(cmdname, "load.off")) { return instcmd("load.off.delay", "0"); } if (!strcasecmp(cmdname, "shutdown.return")) { int ret; /* Ensure "ups.start.auto" is set to "yes", * if supported */ if (dstate_getinfo("ups.start.auto")) { setvar("ups.start.auto", "yes"); } ret = instcmd("load.on.delay", dstate_getinfo("ups.delay.start")); if (ret != STAT_INSTCMD_HANDLED) { return ret; } /* Some UPS's (e.g. TrippLive AVR750U w/ 3024 protocol) don't accept * commands that arrive too rapidly, so add this arbitary wait, * which has proven to be long enough to avoid this problem in practice */ usleep(125000); return instcmd("load.off.delay", dstate_getinfo("ups.delay.shutdown")); } if (!strcasecmp(cmdname, "shutdown.stayoff")) { int ret; /* Ensure "ups.start.auto" is set to "no", if supported */ if (dstate_getinfo("ups.start.auto")) { setvar("ups.start.auto", "no"); } ret = instcmd("load.on.delay", "-1"); if (ret != STAT_INSTCMD_HANDLED) { return ret; } /* Some UPS's (e.g. TrippLive AVR750U w/ 3024 protocol) don't accept * commands that arrive too rapidly, so add this arbitary wait, * which has proven to be long enough to avoid this problem in practice */ usleep(125000); return instcmd("load.off.delay", dstate_getinfo("ups.delay.shutdown")); } upsdebugx(2, "instcmd: info element unavailable %s\n", cmdname); return STAT_INSTCMD_INVALID; } upsdebugx(3, "%s: using Path '%s'", __func__, (hidups_item->hidpath ? hidups_item->hidpath : "[NULL]") ); /* Check if the item is an instant command */ if (!(hidups_item->hidflags & HU_TYPE_CMD)) { upsdebugx(2, "instcmd: %s is not an instant command\n", cmdname); return STAT_INSTCMD_INVALID; } /* If extradata is empty, use the default value from the HID-to-NUT table */ val = extradata ? extradata : hidups_item->dfl; /* Lookup the new value if needed */ if (hidups_item->hid2info != NULL) { value = hu_find_valinfo(hidups_item->hid2info, val); } else { value = atol(val); } /* Actual variable setting */ if (HIDSetDataValue(udev, hidups_item->hiddata, value) == 1) { upsdebugx(3, "instcmd: SUCCEED\n"); /* Set the status so that SEMI_STATIC vars are polled */ data_has_changed = TRUE; return STAT_INSTCMD_HANDLED; } upsdebugx(3, "instcmd: FAILED\n"); /* TODO: HANDLED but FAILED, not UNKNOWN! */ return STAT_INSTCMD_FAILED; } /* set r/w variable to a value. */ int setvar(const char *varname, const char *val) { hid_info_t *hidups_item; double value; upsdebugx(1, "setvar(%s, %s)", varname, val); /* retrieve and check netvar & item_path */ hidups_item = find_nut_info(varname); if (hidups_item == NULL) { upsdebugx(2, "setvar: info element unavailable %s\n", varname); return STAT_SET_UNKNOWN; } /* Checking item writability and HID Path */ if (!(hidups_item->info_flags & ST_FLAG_RW)) { upsdebugx(2, "setvar: not writable %s\n", varname); return STAT_SET_UNKNOWN; } /* handle server side variable */ if (hidups_item->hidflags & HU_FLAG_ABSENT) { upsdebugx(2, "setvar: setting server side variable %s\n", varname); dstate_setinfo(hidups_item->info_type, "%s", val); return STAT_SET_HANDLED; } /* HU_FLAG_ABSENT is the only case of HID Path == NULL */ if (hidups_item->hidpath == NULL) { upsdebugx(2, "setvar: ID Path is NULL for %s\n", varname); return STAT_SET_UNKNOWN; } /* Lookup the new value if needed */ if (hidups_item->hid2info != NULL) { value = hu_find_valinfo(hidups_item->hid2info, val); } else { value = atol(val); } /* Actual variable setting */ if (HIDSetDataValue(udev, hidups_item->hiddata, value) == 1) { upsdebugx(5, "setvar: SUCCEED\n"); /* Set the status so that SEMI_STATIC vars are polled */ data_has_changed = TRUE; return STAT_SET_HANDLED; } upsdebugx(3, "setvar: FAILED\n"); /* FIXME: HANDLED but FAILED, not UNKNOWN! */ return STAT_SET_UNKNOWN; } void upsdrv_shutdown(void) { upsdebugx(1, "upsdrv_shutdown..."); /* Try to shutdown with delay */ if (instcmd("shutdown.return", NULL) == STAT_INSTCMD_HANDLED) { /* Shutdown successful */ return; } /* If the above doesn't work, try shutdown.reboot */ if (instcmd("shutdown.reboot", NULL) == STAT_INSTCMD_HANDLED) { /* Shutdown successful */ return; } /* If the above doesn't work, try load.off.delay */ if (instcmd("load.off.delay", NULL) == STAT_INSTCMD_HANDLED) { /* Shutdown successful */ return; } upslogx(LOG_ERR, "Shutdown failed!"); set_exit_flag(-1); } void upsdrv_help(void) { size_t i; printf("\nAcceptable values for 'subdriver' via -x or ups.conf " "in this driver (exact names here, case-insensitive " "sub-strings may be used, as well as regular expressions): "); for (i = 0; subdriver_list[i] != NULL; i++) { if (i>0) printf(", "); printf("\"%s\"", subdriver_list[i]->name); } printf("\n\n"); printf("Read The Fine Manual ('man 8 usbhid-ups')\n"); } void upsdrv_makevartable(void) { char temp [MAX_STRING_SIZE]; upsdebugx(1, "upsdrv_makevartable..."); snprintf(temp, sizeof(temp), "Set low battery level, in %% (default=%s)", DEFAULT_LOWBATT); addvar (VAR_VALUE, HU_VAR_LOWBATT, temp); snprintf(temp, sizeof(temp), "Set shutdown delay, in seconds (default=%s)", DEFAULT_OFFDELAY); addvar(VAR_VALUE, HU_VAR_OFFDELAY, temp); snprintf(temp, sizeof(temp), "Set startup delay, in seconds (default=%s)", DEFAULT_ONDELAY); addvar(VAR_VALUE, HU_VAR_ONDELAY, temp); snprintf(temp, sizeof(temp), "Set polling frequency, in seconds, to reduce data flow (default=%d)", DEFAULT_POLLFREQ); addvar(VAR_VALUE, HU_VAR_POLLFREQ, temp); addvar(VAR_FLAG, "pollonly", "Don't use interrupt pipe, only use polling"); addvar(VAR_FLAG, "onlinedischarge", "Set to treat discharging while online as being offline"); addvar(VAR_FLAG, "onlinedischarge_calibration", "Set to treat discharging while online as doing calibration"); addvar(VAR_FLAG, "disable_fix_report_desc", "Set to disable fix-ups for broken USB encoding, etc. which we apply by default on certain vendors/products"); #if !((defined SHUT_MODE) && SHUT_MODE) addvar(VAR_VALUE, "subdriver", "Explicit USB HID subdriver selection"); /* allow -x vendor=X, vendorid=X, product=X, productid=X, serial=X */ nut_usb_addvars(); addvar(VAR_FLAG, "explore", "Diagnostic matching of unsupported UPS"); addvar(VAR_FLAG, "maxreport", "Activate tweak for buggy APC Back-UPS firmware"); addvar(VAR_FLAG, "interruptonly", "Don't use polling, only use interrupt pipe"); addvar(VAR_VALUE, "interruptsize", "Number of bytes to read from interrupt pipe"); addvar(VAR_VALUE, HU_VAR_WAITBEFORERECONNECT, "Seconds to wait before trying to reconnect"); #else /* SHUT_MODE */ addvar(VAR_VALUE, "notification", "Set notification type (ignored, only for backward compatibility)"); #endif /* SHUT_MODE / USB */ } #define MAX_EVENT_NUM 32 void upsdrv_updateinfo(void) { hid_info_t *item; HIDData_t *event[MAX_EVENT_NUM], *found_data; int i, evtCount; double value; time_t now; upsdebugx(1, "upsdrv_updateinfo..."); time(&now); /* check for device availability to set datastale! */ if (hd == NULL) { /* don't flood reconnection attempts */ if (now < (lastpoll + poll_interval)) { return; } upsdebugx(1, "Got to reconnect!"); if (use_interrupt_pipe == TRUE && interrupt_pipe_EIO_count > 0) { upsdebugx(0, "\nReconnecting. If you saw \"nut_libusb_get_interrupt: Input/Output Error\" " "or similar message in the log above, try setting \"pollonly\" flag in \"ups.conf\" " "options section for this driver!\n"); } if (!reconnect_ups()) { lastpoll = now; dstate_datastale(); return; } hd = &curDevice; interrupt_pipe_EIO_count = 0; if (hid_ups_walk(HU_WALKMODE_INIT) == FALSE) { hd = NULL; return; } } #ifdef DEBUG interval(); #endif /* Get HID notifications on Interrupt pipe first */ if (use_interrupt_pipe == TRUE) { evtCount = HIDGetEvents(udev, event, MAX_EVENT_NUM); switch (evtCount) { case LIBUSB_ERROR_BUSY: /* Device or resource busy */ upslog_with_errno(LOG_CRIT, "Got disconnected by another driver"); goto fallthrough_reconnect; #if WITH_LIBUSB_0_1 /* limit to libusb 0.1 implementation */ case -EPERM: /* Operation not permitted */ #endif case LIBUSB_ERROR_NO_DEVICE: /* No such device */ case LIBUSB_ERROR_ACCESS: /* Permission denied */ #if WITH_LIBUSB_0_1 /* limit to libusb 0.1 implementation */ case -ENXIO: /* No such device or address */ #endif case LIBUSB_ERROR_NOT_FOUND: /* No such file or directory */ case LIBUSB_ERROR_NO_MEM: /* Insufficient memory */ fallthrough_reconnect: /* Uh oh, got to reconnect! */ dstate_setinfo("driver.state", "reconnect.trying"); hd = NULL; return; case LIBUSB_ERROR_IO: /* I/O error */ /* Uh oh, got to reconnect, with a special suggestion! */ dstate_setinfo("driver.state", "reconnect.trying"); interrupt_pipe_EIO_count++; hd = NULL; return; default: upsdebugx(1, "Got %i HID objects...", (evtCount >= 0) ? evtCount : 0); break; } } else { evtCount = 0; upsdebugx(1, "Not using interrupt pipe..."); } /* Process pending events (HID notifications on Interrupt pipe) */ for (i = 0; i < evtCount; i++) { if (HIDGetDataValue(udev, event[i], &value, poll_interval) != 1) continue; if (nut_debug_level >= 2) { upsdebugx(2, "Path: %s, Type: %s, ReportID: 0x%02x, " "Offset: %i, Size: %i, Value: %g", HIDGetDataItem(event[i], subdriver->utab), HIDDataType(event[i]), event[i]->ReportID, event[i]->Offset, event[i]->Size, value); } /* Skip Input reports, if we don't use the Feature report */ found_data = FindObject_with_Path(pDesc, &(event[i]->Path), interrupt_only ? ITEM_INPUT:ITEM_FEATURE); if (!found_data && !interrupt_only) { found_data = FindObject_with_Path(pDesc, &(event[i]->Path), ITEM_INPUT); } if (!found_data) { upsdebugx(2, "Could not find event as either ITEM_INPUT or ITEM_FEATURE?"); continue; } item = find_hid_info(found_data); if (!item) { upsdebugx(3, "NUT doesn't use this HID object"); continue; } ups_infoval_set(item, value); } #ifdef DEBUG upsdebugx(1, "took %.3f seconds handling interrupt reports...\n", interval()); #endif /* clear status buffer before beginning */ status_init(); /* Do a full update (polling) every pollfreq * or upon data change (ie setvar/instcmd) */ if ((now > (lastpoll + pollfreq)) || (data_has_changed == TRUE)) { upsdebugx(1, "Full update..."); alarm_init(); if (hid_ups_walk(HU_WALKMODE_FULL_UPDATE) == FALSE) return; lastpoll = now; data_has_changed = FALSE; ups_alarm_set(); alarm_commit(); } else { upsdebugx(1, "Quick update..."); /* Quick poll data only to see if the UPS is still connected */ if (hid_ups_walk(HU_WALKMODE_QUICK_UPDATE) == FALSE) return; } ups_status_set(); status_commit(); dstate_dataok(); #ifdef DEBUG upsdebugx(1, "took %.3f seconds handling feature reports...\n", interval()); #endif } void upsdrv_initinfo(void) { char *val; upsdebugx(1, "upsdrv_initinfo..."); dstate_setinfo("driver.version.data", "%s", subdriver->name); /* init polling frequency */ val = getval(HU_VAR_POLLFREQ); if (val) { pollfreq = atoi(val); } dstate_setinfo("driver.parameter.pollfreq", "%d", pollfreq); /* ignore (broken) interrupt pipe */ if (testvar("pollonly")) { use_interrupt_pipe = FALSE; } time(&lastpoll); /* install handlers */ upsh.setvar = setvar; upsh.instcmd = instcmd; } void upsdrv_initups(void) { int ret; char *val; #if (defined SHUT_MODE) && SHUT_MODE /*! * SHUT is a serial protocol, so it needs * only the device path */ upsdebugx(1, "upsdrv_initups (SHUT)..."); subdriver_matcher = device_path; #else /* !SHUT_MODE => USB */ char *regex_array[USBMATCHER_REGEXP_ARRAY_LIMIT]; upsdebugx(1, "upsdrv_initups (non-SHUT)..."); upsdebugx(2, "Initializing an USB-connected UPS with library %s " \ "(NUT subdriver name='%s' ver='%s')", dstate_getinfo("driver.version.usb"), comm_driver->name, comm_driver->version ); warn_if_bad_usb_port_filename(device_path); subdriver_matcher = &subdriver_matcher_struct; /* enforce use of the "vendorid" option if "explore" is given */ if (testvar("explore") && getval("vendorid")==NULL) { fatalx(EXIT_FAILURE, "must specify \"vendorid\" when using \"explore\""); } /* Activate maxreport tweak */ if (testvar("maxreport")) { max_report_size = 1; } /* process the UPS selection options */ regex_array[0] = getval("vendorid"); regex_array[1] = getval("productid"); regex_array[2] = getval("vendor"); regex_array[3] = getval("product"); regex_array[4] = getval("serial"); regex_array[5] = getval("bus"); regex_array[6] = getval("device"); #if (defined WITH_USB_BUSPORT) && (WITH_USB_BUSPORT) regex_array[7] = getval("busport"); #else if (getval("busport")) { upslogx(LOG_WARNING, "\"busport\" is configured for the device, but is not actually handled by current build combination of NUT and libusb (ignored)"); } #endif ret = USBNewRegexMatcher(®ex_matcher, regex_array, REG_ICASE | REG_EXTENDED); switch(ret) { case 0: break; case -1: fatal_with_errno(EXIT_FAILURE, "HIDNewRegexMatcher()"); #ifndef HAVE___ATTRIBUTE__NORETURN exit(EXIT_FAILURE); /* Should not get here in practice, but * compiler is afraid we can fall through */ #endif default: fatalx(EXIT_FAILURE, "invalid regular expression: %s", regex_array[ret]); #ifndef HAVE___ATTRIBUTE__NORETURN exit(EXIT_FAILURE); /* Should not get here in practice, but * compiler is afraid we can fall through */ #endif } /* link the matchers */ subdriver_matcher->next = regex_matcher; #endif /* SHUT_MODE / USB */ /* Search for the first supported UPS matching the regular expression (USB) or device_path (SHUT) */ ret = comm_driver->open_dev(&udev, &curDevice, subdriver_matcher, &callback); if (ret < 1) fatalx(EXIT_FAILURE, "No matching HID UPS found"); hd = &curDevice; upsdebugx(1, "Detected a UPS: %s/%s", hd->Vendor ? hd->Vendor : "unknown", hd->Product ? hd->Product : "unknown"); /* Activate Powercom tweaks */ if (testvar("interruptonly")) { interrupt_only = 1; } /* Activate Cyberpower tweaks */ if (testvar("onlinedischarge")) { onlinedischarge = 1; } if (testvar("onlinedischarge_calibration")) { onlinedischarge_calibration = 1; } if (testvar("disable_fix_report_desc")) { disable_fix_report_desc = 1; } val = getval("interruptsize"); if (val) { int ipv = atoi(val); if (ipv > 0) { interrupt_size = (unsigned int)ipv; } else { fatalx(EXIT_FAILURE, "Error: invalid interruptsize: %d", ipv); } } if (hid_ups_walk(HU_WALKMODE_INIT) == FALSE) { fatalx(EXIT_FAILURE, "Can't initialize data from HID UPS"); } if (dstate_getinfo("battery.charge.low")) { /* Retrieve user defined battery settings */ val = getval(HU_VAR_LOWBATT); if (val) { dstate_setinfo("battery.charge.low", "%ld", strtol(val, NULL, 10)); } } if (dstate_getinfo("ups.delay.start")) { /* Retrieve user defined delay settings */ val = getval(HU_VAR_ONDELAY); if (val) { dstate_setinfo("ups.delay.start", "%ld", strtol(val, NULL, 10)); } } if (dstate_getinfo("ups.delay.shutdown")) { /* Retrieve user defined delay settings */ val = getval(HU_VAR_OFFDELAY); if (val) { dstate_setinfo("ups.delay.shutdown", "%ld", strtol(val, NULL, 10)); } } if (find_nut_info("load.off.delay")) { /* Adds default with a delay value of '0' (= immediate) */ dstate_addcmd("load.off"); } if (find_nut_info("load.on.delay")) { /* Adds default with a delay value of '0' (= immediate) */ dstate_addcmd("load.on"); } if (find_nut_info("load.off.delay") && find_nut_info("load.on.delay")) { /* Add composite instcmds (require setting multiple HID values) */ dstate_addcmd("shutdown.return"); dstate_addcmd("shutdown.stayoff"); } } void upsdrv_cleanup(void) { upsdebugx(1, "upsdrv_cleanup..."); comm_driver->close_dev(udev); Free_ReportDesc(pDesc); free_report_buffer(reportbuf); #if !((defined SHUT_MODE) && SHUT_MODE) USBFreeExactMatcher(exact_matcher); USBFreeRegexMatcher(regex_matcher); free(curDevice.Vendor); free(curDevice.Product); free(curDevice.Serial); free(curDevice.Bus); free(curDevice.Device); # if (defined WITH_USB_BUSPORT) && (WITH_USB_BUSPORT) free(curDevice.BusPort); # endif #endif /* !SHUT_MODE => USB */ } /********************************************************************** * Support functions *********************************************************************/ void possibly_supported(const char *mfr, HIDDevice_t *arghd) { upsdebugx(0, "This %s device (%04x:%04x) is not (or perhaps not yet) supported\n" "by usbhid-ups. Please make sure you have an up-to-date version of NUT. If\n" "this does not fix the problem, try running the driver with the\n" "'-x productid=%04x' option. Please report your results to the NUT user's\n" "mailing list .\n", mfr, arghd->VendorID, arghd->ProductID, arghd->ProductID); } /* Update ups_status to remember this status item. Interpretation is done in ups_status_set(). */ static void process_boolean_info(const char *nutvalue) { status_lkp_t *status_item; int clear = 0; upsdebugx(5, "process_boolean_info: %s", nutvalue); if (*nutvalue == '!') { nutvalue++; clear = 1; } for (status_item = status_info; status_item->status_str != NULL ; status_item++) { if (strcasecmp(status_item->status_str, nutvalue)) continue; if (clear) { ups_status &= ~status_item->status_mask; } else { ups_status |= status_item->status_mask; } return; } upsdebugx(5, "Warning: %s not in list of known values", nutvalue); } static int callback( hid_dev_handle_t argudev, HIDDevice_t *arghd, usb_ctrl_charbuf rdbuf, usb_ctrl_charbufsize rdlen) { int i; const char *mfr = NULL, *model = NULL, *serial = NULL; #if !((defined SHUT_MODE) && SHUT_MODE) int ret; #endif /* !SHUT_MODE => USB */ upsdebugx(2, "Report Descriptor size = %" PRI_NUT_USB_CTRL_CHARBUFSIZE, rdlen); #if (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_PUSH_POP) && ( (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_TYPE_LIMITS) || (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_TAUTOLOGICAL_CONSTANT_OUT_OF_RANGE_COMPARE) || (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_TAUTOLOGICAL_UNSIGNED_ZERO_COMPARE) ) # pragma GCC diagnostic push #endif #ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_TYPE_LIMITS # pragma GCC diagnostic ignored "-Wtype-limits" #endif #ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_TAUTOLOGICAL_CONSTANT_OUT_OF_RANGE_COMPARE # pragma GCC diagnostic ignored "-Wtautological-constant-out-of-range-compare" #endif #ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_TAUTOLOGICAL_UNSIGNED_ZERO_COMPARE # pragma GCC diagnostic ignored "-Wtautological-unsigned-zero-compare" #endif if ((uintmax_t)rdlen < (uintmax_t)SIZE_MAX) { upsdebug_hex(3, "Report Descriptor", rdbuf, (size_t)rdlen); } #if (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_PUSH_POP) && ( (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_TYPE_LIMITS) || (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_TAUTOLOGICAL_CONSTANT_OUT_OF_RANGE_COMPARE) || (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_TAUTOLOGICAL_UNSIGNED_ZERO_COMPARE) ) # pragma GCC diagnostic pop #endif /* Save the global "hd" for this driver instance */ hd = arghd; udev = argudev; /* Parse Report Descriptor */ Free_ReportDesc(pDesc); pDesc = Parse_ReportDesc(rdbuf, rdlen); if (!pDesc) { upsdebug_with_errno(1, "Failed to parse report descriptor!"); return 0; } /* prepare report buffer */ free_report_buffer(reportbuf); reportbuf = new_report_buffer(pDesc); if (!reportbuf) { upsdebug_with_errno(1, "Failed to allocate report buffer!"); Free_ReportDesc(pDesc); return 0; } /* select the subdriver for this device */ subdriver = match_function_subdriver_name(0); if (!subdriver) { for (i=0; subdriver_list[i] != NULL; i++) { if (subdriver_list[i]->claim(hd)) { break; } } subdriver = subdriver_list[i]; } if (!subdriver) { upsdebugx(1, "Manufacturer not supported!"); return 0; } upslogx(2, "Using subdriver: %s", subdriver->name); if (subdriver->fix_report_desc(arghd, pDesc)) { upsdebugx(2, "Report Descriptor Fixed"); } HIDDumpTree(udev, arghd, subdriver->utab); #if !((defined SHUT_MODE) && SHUT_MODE) /* create a new matcher for later matching */ USBFreeExactMatcher(exact_matcher); ret = USBNewExactMatcher(&exact_matcher, hd); if (ret) { upsdebug_with_errno(1, "USBNewExactMatcher()"); return 0; } regex_matcher->next = exact_matcher; #endif /* !SHUT_MODE => USB */ /* apply subdriver specific formatting */ mfr = subdriver->format_mfr(hd); model = subdriver->format_model(hd); serial = subdriver->format_serial(hd); if (mfr != NULL) { dstate_setinfo("ups.mfr", "%s", mfr); } else { dstate_delinfo("ups.mfr"); } if (model != NULL) { dstate_setinfo("ups.model", "%s", model); } else { dstate_delinfo("ups.model"); } if (serial != NULL) { dstate_setinfo("ups.serial", "%s", serial); } else { dstate_delinfo("ups.serial"); } dstate_setinfo("ups.vendorid", "%04x", hd->VendorID); dstate_setinfo("ups.productid", "%04x", hd->ProductID); return 1; } #ifdef DEBUG static double interval(void) { struct timeval now; static struct timeval last; double ret; gettimeofday(&now, NULL); ret = now.tv_sec - last.tv_sec + ((double)(now.tv_usec - last.tv_usec)) / 1000000; last = now; return ret; } #endif /* default subdriver function which doesn't attempt to fix * any issues in the parsed HID Report Descriptor */ int fix_report_desc(HIDDevice_t *arg_pDev, HIDDesc_t *arg_pDesc) { NUT_UNUSED_VARIABLE(arg_pDev); NUT_UNUSED_VARIABLE(arg_pDesc); /* Implementations should honor the user's toggle: * if (disable_fix_report_desc) return 0; */ return 0; } /* walk ups variables and set elements of the info array. */ static bool_t hid_ups_walk(walkmode_t mode) { hid_info_t *item; double value; int retcode; #if !((defined SHUT_MODE) && SHUT_MODE) /* extract the VendorId for further testing */ int vendorID = curDevice.VendorID; int productID = curDevice.ProductID; #endif /* !SHUT_MODE => USB */ /* 3 modes: HU_WALKMODE_INIT, HU_WALKMODE_QUICK_UPDATE * and HU_WALKMODE_FULL_UPDATE */ /* Device data walk ----------------------------- */ for (item = subdriver->hid2nut; item->info_type != NULL; item++) { #if (defined SHUT_MODE) && SHUT_MODE /* Check if we are asked to stop (reactivity++) in SHUT mode. * In USB mode, looping through this takes well under a second, * so any effort to improve reactivity here is wasted. */ if (exit_flag != 0) return TRUE; #endif /* SHUT_MODE */ /* filter data according to mode */ switch (mode) { /* Device capabilities enumeration */ case HU_WALKMODE_INIT: /* Apparently, we are reconnecting, so * NUT-to-HID translation is already good */ if (item->hiddata != NULL) break; /* Create the NUT-to-HID mapping */ item->hiddata = HIDGetItemData(item->hidpath, subdriver->utab); if (item->hiddata == NULL) continue; /* Special case for handling server side variables */ if (item->hidflags & HU_FLAG_ABSENT) { /* already set */ if (dstate_getinfo(item->info_type)) continue; dstate_setinfo(item->info_type, "%s", item->dfl); dstate_setflags(item->info_type, item->info_flags); /* Set max length for strings, if needed */ if (item->info_flags & ST_FLAG_STRING) dstate_setaux(item->info_type, item->info_len); continue; } /* Allow duplicates for these NUT variables... */ if (!strncmp(item->info_type, "ups.alarm", 9)) { break; } /* ...this one doesn't exist yet... */ if (dstate_getinfo(item->info_type) == NULL) { break; } /* ...but this one does, so don't use it! */ item->hiddata = NULL; continue; case HU_WALKMODE_QUICK_UPDATE: /* Quick update only deals with status and alarms! */ if (!(item->hidflags & HU_FLAG_QUICK_POLL)) continue; break; case HU_WALKMODE_FULL_UPDATE: /* These don't need polling after initinfo() */ if (item->hidflags & (HU_FLAG_ABSENT | HU_TYPE_CMD | HU_FLAG_STATIC)) continue; /* These need to be polled after user changes (setvar / instcmd) */ if ( (item->hidflags & HU_FLAG_SEMI_STATIC) && (data_has_changed == FALSE) ) continue; break; #if (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_PUSH_POP) && ( (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_COVERED_SWITCH_DEFAULT) || (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_UNREACHABLE_CODE) ) # pragma GCC diagnostic push #endif #ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_COVERED_SWITCH_DEFAULT # pragma GCC diagnostic ignored "-Wcovered-switch-default" #endif #ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_UNREACHABLE_CODE # pragma GCC diagnostic ignored "-Wunreachable-code" #endif /* Older CLANG (e.g. clang-3.4) seems to not support the GCC pragmas above */ #ifdef __clang__ # pragma clang diagnostic push # pragma clang diagnostic ignored "-Wcovered-switch-default" # pragma clang diagnostic ignored "-Wunreachable-code" #endif /* All enum cases defined as of the time of coding * have been covered above. Handle later definitions, * memory corruptions and buggy inputs below... */ default: fatalx(EXIT_FAILURE, "hid_ups_walk: unknown update mode!"); } #ifdef __clang__ # pragma clang diagnostic pop #endif #if (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_PUSH_POP) && ( (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_COVERED_SWITCH_DEFAULT) || (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_UNREACHABLE_CODE) ) # pragma GCC diagnostic pop #endif #if !((defined SHUT_MODE) && SHUT_MODE) /* skip report 0x54 for Tripplite SU3000LCD2UHV due to firmware bug */ if ((vendorID == 0x09ae) && (productID == 0x1330)) { if (item->hiddata && (item->hiddata->ReportID == 0x54)) { continue; } } #endif /* !SHUT_MODE => USB */ retcode = HIDGetDataValue(udev, item->hiddata, &value, poll_interval); switch (retcode) { case LIBUSB_ERROR_BUSY: /* Device or resource busy */ upslog_with_errno(LOG_CRIT, "Got disconnected by another driver"); goto fallthrough_reconnect; #if WITH_LIBUSB_0_1 /* limit to libusb 0.1 implementation */ case -EPERM: /* Operation not permitted */ #endif case LIBUSB_ERROR_NO_DEVICE: /* No such device */ case LIBUSB_ERROR_ACCESS: /* Permission denied */ #if WITH_LIBUSB_0_1 /* limit to libusb 0.1 implementation */ case -ENXIO: /* No such device or address */ #endif case LIBUSB_ERROR_NOT_FOUND: /* No such file or directory */ case LIBUSB_ERROR_NO_MEM: /* Insufficient memory */ fallthrough_reconnect: /* Uh oh, got to reconnect! */ dstate_setinfo("driver.state", "reconnect.trying"); hd = NULL; return FALSE; case LIBUSB_ERROR_IO: /* I/O error */ /* Uh oh, got to reconnect, with a special suggestion! */ dstate_setinfo("driver.state", "reconnect.trying"); interrupt_pipe_EIO_count++; hd = NULL; return FALSE; case 1: break; /* Found! */ case 0: continue; case LIBUSB_ERROR_TIMEOUT: /* Connection timed out */ /* libusb win32 does not know EPROTO and EOVERFLOW, * it only returns EIO for any IO errors */ #ifndef WIN32 case LIBUSB_ERROR_OVERFLOW: /* Value too large for defined data type */ # if EPROTO && WITH_LIBUSB_0_1 case -EPROTO: /* Protocol error */ # endif #endif case LIBUSB_ERROR_PIPE: /* Broken pipe */ default: /* Don't know what happened, try again later... */ upsdebugx(1, "HIDGetDataValue unknown retcode '%i'", retcode); continue; } upsdebugx(2, "Path: %s, Type: %s, ReportID: 0x%02x, " "Offset: %i, Size: %i, Value: %g", item->hidpath, HIDDataType(item->hiddata), item->hiddata->ReportID, item->hiddata->Offset, item->hiddata->Size, value); if (item->hidflags & HU_TYPE_CMD) { upsdebugx(3, "Adding command '%s' using Path '%s'", item->info_type, item->hidpath); dstate_addcmd(item->info_type); continue; } /* Process the value we got back (set status bits and * set the value of other parameters) */ if (ups_infoval_set(item, value) != 1) continue; if (mode == HU_WALKMODE_INIT) { info_lkp_t *info_lkp; dstate_setflags(item->info_type, item->info_flags); /* Set max length for strings */ if (item->info_flags & ST_FLAG_STRING) { dstate_setaux(item->info_type, item->info_len); } /* Set enumerated values, only if the data has ST_FLAG_RW */ if (!(item->hidflags & HU_FLAG_ENUM) || !(item->info_flags & ST_FLAG_RW)) { continue; } /* Loop on all existing values */ for (info_lkp = item->hid2info; info_lkp != NULL && info_lkp->nut_value != NULL; info_lkp++) { /* Check if this value is supported */ if (hu_find_infoval(item->hid2info, info_lkp->hid_value) != NULL) { dstate_addenum(item->info_type, "%s", info_lkp->nut_value); } } } } return TRUE; } static int reconnect_ups(void) { int ret; char *val; int wait_before_reconnect = 0; dstate_setinfo("driver.state", "reconnect.trying"); /* Init time to wait before trying to reconnect (seconds) */ val = getval(HU_VAR_WAITBEFORERECONNECT); if (val) { wait_before_reconnect = atoi(val); } /* Try to close the previous handle */ if (udev == HID_DEV_HANDLE_CLOSED) { upsdebugx(4, "Not closing comm_driver previous handle: already closed"); } else { upsdebugx(4, "Closing comm_driver previous handle"); comm_driver->close_dev(udev); udev = HID_DEV_HANDLE_CLOSED; } upsdebugx(4, "==================================================================="); if (wait_before_reconnect > 0 ) { upsdebugx(4, " device has been disconnected, trying to reconnect in %i seconds", wait_before_reconnect); sleep(wait_before_reconnect); upsdebugx(4, " trying to reconnect"); } else { upsdebugx(4, " device has been disconnected, try to reconnect"); } upsdebugx(4, "==================================================================="); upsdebugx(4, "Opening comm_driver ..."); ret = comm_driver->open_dev(&udev, &curDevice, subdriver_matcher, NULL); upsdebugx(4, "Opening comm_driver returns ret=%i", ret); if (ret > 0) { return 1; } dstate_setinfo("driver.state", "quiet"); return 0; } /* Convert the local status information to NUT format and set NUT alarms. */ static void ups_alarm_set(void) { if (ups_status & STATUS(REPLACEBATT)) { alarm_set("Replace battery!"); } if (ups_status & STATUS(SHUTDOWNIMM)) { alarm_set("Shutdown imminent!"); } if (ups_status & STATUS(FANFAIL)) { alarm_set("Fan failure!"); } if (ups_status & STATUS(NOBATTERY)) { alarm_set("No battery installed!"); } if (ups_status & STATUS(BATTVOLTLO)) { alarm_set("Battery voltage too low!"); } if (ups_status & STATUS(BATTVOLTHI)) { alarm_set("Battery voltage too high!"); } if (ups_status & STATUS(CHARGERFAIL)) { alarm_set("Battery charger fail!"); } if (ups_status & STATUS(OVERHEAT)) { alarm_set("Temperature too high!"); /* overheat; Belkin, TrippLite */ } if (ups_status & STATUS(COMMFAULT)) { alarm_set("Internal UPS fault!"); /* UPS fault; Belkin, TrippLite */ } if (ups_status & STATUS(AWAITINGPOWER)) { alarm_set("Awaiting power!"); /* awaiting power; Belkin, TrippLite */ } if (ups_status & STATUS(BYPASSAUTO)) { alarm_set("Automatic bypass mode!"); } if (ups_status & STATUS(BYPASSMAN)) { alarm_set("Manual bypass mode!"); } } /* Return the current value of ups_status */ unsigned ups_status_get(void) { return ups_status; } /* Convert the local status information to NUT format and set NUT status. */ static void ups_status_set(void) { if (ups_status & STATUS(VRANGE)) { dstate_setinfo("input.transfer.reason", "input voltage out of range"); } else if (ups_status & STATUS(FRANGE)) { dstate_setinfo("input.transfer.reason", "input frequency out of range"); } else { dstate_delinfo("input.transfer.reason"); } /* Report calibration mode first, because it looks like OFF or OB * for many implementations (literally, it is a temporary OB state * managed by the UPS hardware to become OL later... if it guesses * correctly when to do so), and may cause false alarms for us to * raise FSD urgently. So we first let upsmon know it is just a drill. */ if (ups_status & STATUS(CALIB)) { status_set("CAL"); /* calibration */ } if (!(ups_status & STATUS(ONLINE))) { status_set("OB"); /* on battery */ } else if ((ups_status & STATUS(DISCHRG))) { /* if online but discharging */ if (onlinedischarge_calibration) { /* if we treat OL+DISCHRG as calibrating */ status_set("CAL"); /* calibration */ } if (onlinedischarge) { /* if we treat OL+DISCHRG as being offline */ status_set("OB"); /* on battery */ } if (!onlinedischarge && !onlinedischarge_calibration) { if (!(ups_status & STATUS(CALIB))) { /* if in OL+DISCHRG unknowingly, warn user */ upslogx(LOG_WARNING, "%s: seems that UPS [%s] is in OL+DISCHRG state now. " "Is it calibrating (perhaps you want to set 'onlinedischarge_calibration' option)? " "Note that some UPS models (e.g. CyberPower UT series) emit OL+DISCHRG when " "in fact offline/on-battery (perhaps you want to set 'onlinedischarge' option).", __func__, upsname); } /* if we're calibrating */ status_set("OL"); /* on line */ } } else if ((ups_status & STATUS(ONLINE))) { /* if simply online */ status_set("OL"); } if ((ups_status & STATUS(DISCHRG)) && !(ups_status & STATUS(DEPLETED))) { status_set("DISCHRG"); /* discharging */ } if ((ups_status & STATUS(CHRG)) && !(ups_status & STATUS(FULLYCHARGED))) { status_set("CHRG"); /* charging */ } if (ups_status & (STATUS(LOWBATT) | STATUS(TIMELIMITEXP) | STATUS(SHUTDOWNIMM))) { status_set("LB"); /* low battery */ } if (ups_status & STATUS(OVERLOAD)) { status_set("OVER"); /* overload */ } if (ups_status & STATUS(REPLACEBATT)) { status_set("RB"); /* replace batt */ } if (ups_status & STATUS(TRIM)) { status_set("TRIM"); /* SmartTrim */ } if (ups_status & STATUS(BOOST)) { status_set("BOOST"); /* SmartBoost */ } if (ups_status & (STATUS(BYPASSAUTO) | STATUS(BYPASSMAN))) { status_set("BYPASS"); /* on bypass */ } if (ups_status & STATUS(OFF)) { status_set("OFF"); /* ups is off */ } } /* find info element definition in info array * by NUT varname. */ static hid_info_t *find_nut_info(const char *varname) { hid_info_t *hidups_item; for (hidups_item = subdriver->hid2nut; hidups_item->info_type != NULL ; hidups_item++) { if (strcasecmp(hidups_item->info_type, varname)) continue; if (hidups_item->hiddata != NULL) return hidups_item; } upsdebugx(2, "find_nut_info: unknown info type: %s", varname); return NULL; } /* find info element definition in info array * by HID data pointer. */ static hid_info_t *find_hid_info(const HIDData_t *hiddata) { hid_info_t *hidups_item; if(!hiddata) { upsdebugx(2, "%s: hiddata == NULL", __func__); return NULL; } for (hidups_item = subdriver->hid2nut; hidups_item->info_type != NULL ; hidups_item++) { /* Skip server side vars */ if (hidups_item->hidflags & HU_FLAG_ABSENT) continue; if (hidups_item->hiddata == hiddata) return hidups_item; } return NULL; } /* find the HID Item value matching that NUT value */ /* useful for set with value lookup... */ static long hu_find_valinfo(info_lkp_t *hid2info, const char* value) { info_lkp_t *info_lkp; /* if a conversion function is defined, use 'value' as argument for it */ if (hid2info->nuf != NULL) { double hid_value; hid_value = hid2info->nuf(value); upsdebugx(5, "hu_find_valinfo: found %g (value: %s)", hid_value, value); return hid_value; } for (info_lkp = hid2info; info_lkp->nut_value != NULL; info_lkp++) { if (!(strcmp(info_lkp->nut_value, value))) { upsdebugx(5, "hu_find_valinfo: found %s (value: %ld)", info_lkp->nut_value, info_lkp->hid_value); return info_lkp->hid_value; } } upsdebugx(3, "hu_find_valinfo: no matching HID value for this INFO_* value (%s)", value); return -1; } /* find the NUT value matching that HID Item value */ static const char *hu_find_infoval(info_lkp_t *hid2info, const double value) { info_lkp_t *info_lkp; /* if a conversion function is defined, use 'value' as argument for it */ if (hid2info->fun != NULL) { return hid2info->fun(value); } /* use 'value' as an index for a lookup in an array */ for (info_lkp = hid2info; info_lkp->nut_value != NULL; info_lkp++) { if (info_lkp->hid_value == (long)value) { upsdebugx(5, "hu_find_infoval: found %s (value: %ld)", info_lkp->nut_value, (long)value); return info_lkp->nut_value; } } upsdebugx(3, "hu_find_infoval: no matching INFO_* value for this HID value (%g)", value); return NULL; } /* return -1 on failure, 0 for a status update and 1 in all other cases */ static int ups_infoval_set(hid_info_t *item, double value) { const char *nutvalue; /* need lookup'ed translation? */ if (item->hid2info != NULL){ if ((nutvalue = hu_find_infoval(item->hid2info, value)) == NULL) { upsdebugx(5, "Lookup [%g] failed for [%s]", value, item->info_type); return -1; } /* deal with boolean items */ if (!strncmp(item->info_type, "BOOL", 4)) { process_boolean_info(nutvalue); return 0; } /* deal with alarm items */ if (!strncmp(item->info_type, "ups.alarm", 9)) { alarm_set(nutvalue); return 0; } dstate_setinfo(item->info_type, "%s", nutvalue); } else { #ifdef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL #pragma GCC diagnostic push #endif #ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL #pragma GCC diagnostic ignored "-Wformat-nonliteral" #endif #ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_FORMAT_SECURITY #pragma GCC diagnostic ignored "-Wformat-security" #endif dstate_setinfo(item->info_type, item->dfl, value); #ifdef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL #pragma GCC diagnostic pop #endif } return 1; } nut-2.8.1/tests/0000755000175000017500000000000014520277777010515 500000000000000nut-2.8.1/tests/cpputest-client.cpp0000644000175000017500000003173014501607135014250 00000000000000/* cpputest-client - CppUnit libnutclient active test Module for NUT `cpputest` runner, to check client-server interactions as part of NIT (NUT Integration Testing) suite and similar scenarios. This is an "active" NUT client talking to an `upsd` on $NUT_PORT, as opposed to nutclienttest.cpp which unit-tests the class API etc. in isolated-binary fashion. Copyright (C) 2022 Jim Klimov 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 2 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, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "common.h" /* Current CPPUnit offends the honor of C++98 */ #if (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_PUSH_POP) && (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_EXIT_TIME_DESTRUCTORS || defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_GLOBAL_CONSTRUCTORS) #pragma GCC diagnostic push # ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_GLOBAL_CONSTRUCTORS # pragma GCC diagnostic ignored "-Wglobal-constructors" # endif # ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_EXIT_TIME_DESTRUCTORS # pragma GCC diagnostic ignored "-Wexit-time-destructors" # endif #endif #include #include #include #include #include namespace nut { class NutActiveClientTest : public CppUnit::TestFixture { /* Note: is "friend" of nut::TcpClient class * to test a few of its protected methods */ CPPUNIT_TEST_SUITE( NutActiveClientTest ); CPPUNIT_TEST( test_query_ver ); CPPUNIT_TEST( test_list_ups ); CPPUNIT_TEST( test_list_ups_clients ); CPPUNIT_TEST( test_auth_user ); CPPUNIT_TEST( test_auth_primary ); CPPUNIT_TEST_SUITE_END(); private: /* Fed by caller via envvars: */ uint16_t NUT_PORT = 0; std::string NUT_USER = ""; std::string NUT_PASS = ""; std::string NUT_PRIMARY_DEVICE = ""; std::string NUT_SETVAR_DEVICE = ""; public: void setUp() override; void tearDown() override; void test_query_ver(); void test_list_ups(); void test_list_ups_clients(); void test_auth_user(); void test_auth_primary(); }; // Registers the fixture into the 'registry' CPPUNIT_TEST_SUITE_REGISTRATION( NutActiveClientTest ); } // namespace nut {} #ifndef _NUTCLIENTTEST_BUILD # define _NUTCLIENTTEST_BUILD 1 #endif #include "../clients/nutclient.h" #include "../clients/nutclientmem.h" namespace nut { extern "C" { strarr stringset_to_strarr(const std::set& strset); strarr stringvector_to_strarr(const std::vector& strset); } // extern "C" void NutActiveClientTest::setUp() { /* NUT_PORT etc. are provided by external test suite driver */ char * s; s = std::getenv("NUT_PORT"); if (s) { long l = atol(s); if (l < 1 || l > 65535) { throw std::runtime_error("NUT_PORT specified by caller is out of range"); } NUT_PORT = static_cast(l); } else { throw std::runtime_error("NUT_PORT not specified by caller, NIT should call this test"); } s = std::getenv("NUT_USER"); if (s) { NUT_USER = s; } // else stays empty s = std::getenv("NUT_PASS"); if (s) { NUT_PASS = s; } // else stays empty s = std::getenv("NUT_PRIMARY_DEVICE"); if (s) { NUT_PRIMARY_DEVICE = s; } // else stays empty s = std::getenv("NUT_SETVAR_DEVICE"); if (s) { NUT_SETVAR_DEVICE = s; } // else stays empty } void NutActiveClientTest::tearDown() { } void NutActiveClientTest::test_query_ver() { nut::TcpClient c("localhost", NUT_PORT); std::string s; std::cerr << "[D] C++ NUT Client lib test running against Data Server at: " << c.getHost() << ':' << c.getPort() << std::endl; CPPUNIT_ASSERT_MESSAGE( "TcpClient is not connected after constructor", c.isConnected()); /* Note: generic client code can not use protected methods * like low-level sendQuery(), list(), get() and some more, * but this NutActiveClientTest is a friend of TcpClient: */ s = c.sendQuery("VER"); std::cerr << "[D] Got Data Server VER: " << s << std::endl; try { s = c.sendQuery("PROTVER"); std::cerr << "[D] Got PROTVER: " << s << std::endl; } catch(nut::NutException& ex) { std::cerr << "[D] Did not get PROTVER: " << ex.what() << std::endl; } try { s = c.sendQuery("NETVER"); std::cerr << "[D] Got NETVER (obsolete): " << s << std::endl; } catch(nut::NutException& ex) { std::cerr << "[D] Did not get NETVER (obsolete): " << ex.what() << std::endl; } try { c.logout(); } catch(nut::NutException& ex) { std::cerr << "[D] Could not get LOGOUT: " << ex.what() << std::endl; } try { c.disconnect(); } catch(nut::NutException& ex) { /* NUT_UNUSED_VARIABLE(ex); */ std::cerr << "[D] Could not get disconnect(): " << ex.what() << std::endl; } } void NutActiveClientTest::test_list_ups() { nut::TcpClient c("localhost", NUT_PORT); std::set devs; bool noException = true; try { devs = c.getDeviceNames(); std::cerr << "[D] Got device list (" << devs.size() << "): ["; for (std::set::iterator it = devs.begin(); it != devs.end(); it++ ) { if (it != devs.begin()) { std::cerr << ", "; } std::cerr << '"' << *it << '"'; } std::cerr << "]" << std::endl; } catch(nut::NutException& ex) { std::cerr << "[D] Could not device list: " << ex.what() << std::endl; noException = false; } c.logout(); c.disconnect(); CPPUNIT_ASSERT_MESSAGE( "Failed to list UPS with TcpClient: threw NutException", noException); } void NutActiveClientTest::test_list_ups_clients() { nut::TcpClient c("localhost", NUT_PORT); std::map> deviceClients; bool noException = true; try { c.authenticate(NUT_USER, NUT_PASS); std::cerr << "[D] Authenticated without exceptions" << std::endl; /* Note: no high hopes here, credentials are checked by server * when running critical commands, not at auth request itself */ } catch(nut::NutException& ex) { std::cerr << "[D] Could not authenticate as a simple user: " << ex.what() << std::endl; /* no failure here */ } try { c.deviceLogin(NUT_PRIMARY_DEVICE); } catch(nut::NutException& ex) { std::cerr << "[D] Could not log into primary device (envvars not set?) so test below should return empty client lists: " << ex.what() << std::endl; /* no failure here */ } try { deviceClients = c.listDeviceClients(); std::cerr << "[D] Got device client list (" << deviceClients.size() << "): ["; for (std::map>::iterator itM = deviceClients.begin(); itM != deviceClients.end(); itM++ ) { if (itM != deviceClients.begin()) { std::cerr << "," << std::endl; } std::cerr << "{ \"" << itM->first << "\" : "; for (std::set::iterator it = itM->second.begin(); it != itM->second.end(); it++ ) { if (it != itM->second.begin()) { std::cerr << ", "; } std::cerr << '"' << *it << '"'; } std::cerr << " }"; } std::cerr << " ]" << std::endl; } catch(nut::NutException& ex) { std::cerr << "[D] Could not device client list: " << ex.what() << std::endl; noException = false; } c.logout(); c.disconnect(); CPPUNIT_ASSERT_MESSAGE( "Failed to list UPS with TcpClient: threw NutException", noException); } void NutActiveClientTest::test_auth_user() { if (NUT_USER.empty()) { std::cerr << "[D] SKIPPING test_auth_user()" << std::endl; return; } nut::TcpClient c("localhost", NUT_PORT); bool noException = true; try { c.authenticate(NUT_USER, NUT_PASS); std::cerr << "[D] Authenticated without exceptions" << std::endl; /* Note: no high hopes here, credentials are checked by server * when running critical commands, not at auth request itself */ } catch(nut::NutException& ex) { std::cerr << "[D] Could not authenticate as a simple user: " << ex.what() << std::endl; noException = false; } if (!NUT_SETVAR_DEVICE.empty()) { try { TrackingResult tres; TrackingID tid; int i; std::string nutVar = "ups.status"; /* Has a risk of flip-flop with NIT dummy setup */ std::string s1 = c.getDeviceVariableValue(NUT_SETVAR_DEVICE, nutVar)[0]; std::string sTest = s1 + "-test"; std::cerr << "[D] Got initial device '" << NUT_SETVAR_DEVICE << "' variable '" << nutVar << "' value: " << s1 << std::endl; CPPUNIT_ASSERT_MESSAGE( "Did not expect empty value here", !s1.empty()); tid = c.setDeviceVariable(NUT_SETVAR_DEVICE, nutVar, sTest); while ( (tres = c.getTrackingResult(tid)) == PENDING) { usleep(100); } if (tres != SUCCESS) { std::cerr << "[D] Failed to set device variable: " << "tracking result is " << tres << std::endl; noException = false; } /* Check what we got after set */ /* Note that above we told the server to tell the driver * to set a dstate entry; below we ask the server to ask * the driver and relay the answer to us. The dummy-ups * driver may also be in a sleeping state between cycles. * Data propagation may be not instantaneous, so we loop * for a while to see the expected value (or give up). */ std::string s2; for (i = 0; i < 100 ; i++) { s2 = c.getDeviceVariableValue(NUT_SETVAR_DEVICE, nutVar)[0]; if (s2 == sTest) break; usleep(100000); } std::cerr << "[D] Read back: " << s2 << " after " << (100 * i) << "msec" << std::endl; /* Fix it back */ tid = c.setDeviceVariable(NUT_SETVAR_DEVICE, nutVar, s1); while ( (tres = c.getTrackingResult(tid)) == PENDING) { usleep(100); } if (tres != SUCCESS) { std::cerr << "[D] Failed to set device variable: " << "tracking result is " << tres << std::endl; noException = false; } std::string s3; for (i = 0; i < 100 ; i++) { s3 = c.getDeviceVariableValue(NUT_SETVAR_DEVICE, nutVar)[0]; if (s3 == s1) break; usleep(100000); } std::cerr << "[D] Read back: " << s3 << " after " << (100 * i) << "msec" << std::endl; if (s3 != s1) { std::cerr << "[D] Final device variable value '" << s3 << "' differs from original '" << s1 << "'" << std::endl; noException = false; } if (s2 == s1) { std::cerr << "[D] Tweaked device variable value '" << s2 << "' does not differ from original '" << s1 << "'" << std::endl; noException = false; } if (noException) { std::cerr << "[D] Tweaked device variable value OK" << std::endl; } } catch(nut::NutException& ex) { std::cerr << "[D] Failed to set device variable: " << ex.what() << std::endl; noException = false; } } else { std::cerr << "[D] SKIPPING test_auth_user() active test " << "(got no NUT_SETVAR_DEVICE to poke)" << std::endl; } c.logout(); c.disconnect(); CPPUNIT_ASSERT_MESSAGE( "Failed to auth as user with TcpClient or tweak device variable", noException); } void NutActiveClientTest::test_auth_primary() { if (NUT_USER.empty() || NUT_PRIMARY_DEVICE.empty()) { std::cerr << "[D] SKIPPING test_auth_primary()" << std::endl; return; } nut::TcpClient c("localhost", NUT_PORT); bool noException = true; try { c.authenticate(NUT_USER, NUT_PASS); std::cerr << "[D] Authenticated without exceptions" << std::endl; } catch(nut::NutException& ex) { std::cerr << "[D] Could not authenticate as an upsmon primary user: " << ex.what() << std::endl; noException = false; } try { Device d = c.getDevice(NUT_PRIMARY_DEVICE); bool gotPrimary = false; bool gotMaster = false; try { c.deviceMaster(NUT_PRIMARY_DEVICE); gotMaster = true; std::cerr << "[D] Elevated as MASTER without exceptions" << std::endl; } catch(nut::NutException& ex) { std::cerr << "[D] Could not elevate as MASTER for " << "NUT_PRIMARY_DEVICE " << NUT_PRIMARY_DEVICE << ": " << ex.what() << std::endl; } try { c.devicePrimary(NUT_PRIMARY_DEVICE); gotPrimary = true; std::cerr << "[D] Elevated as PRIMARY without exceptions" << std::endl; } catch(nut::NutException& ex) { std::cerr << "[D] Could not elevate as PRIMARY for " << "NUT_PRIMARY_DEVICE " << NUT_PRIMARY_DEVICE << ": " << ex.what() << std::endl; } if (!gotMaster && !gotPrimary) noException = false; } catch(nut::NutException& ex) { std::cerr << "[D] NUT_PRIMARY_DEVICE " << NUT_PRIMARY_DEVICE << " not found on Data Server: " << ex.what() << std::endl; noException = false; } c.logout(); c.disconnect(); CPPUNIT_ASSERT_MESSAGE( "Failed to auth as user with TcpClient: threw NutException", noException); } } // namespace nut {} #if (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_PUSH_POP) && (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_EXIT_TIME_DESTRUCTORS || defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_GLOBAL_CONSTRUCTORS) #pragma GCC diagnostic pop #endif nut-2.8.1/tests/NIT/0000755000175000017500000000000014520277777011147 500000000000000nut-2.8.1/tests/NIT/Makefile.in0000644000175000017500000004631114520274663013130 00000000000000# Makefile.in generated by automake 1.16.5 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2021 Free Software Foundation, Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. @SET_MAKE@ VPATH = @srcdir@ am__is_gnu_make = { \ if test -z '$(MAKELEVEL)'; then \ false; \ elif test -n '$(MAKE_HOST)'; then \ true; \ elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \ true; \ else \ false; \ fi; \ } am__make_running_with_option = \ case $${target_option-} in \ ?) ;; \ *) echo "am__make_running_with_option: internal error: invalid" \ "target option '$${target_option-}' specified" >&2; \ exit 1;; \ esac; \ has_opt=no; \ sane_makeflags=$$MAKEFLAGS; \ if $(am__is_gnu_make); then \ sane_makeflags=$$MFLAGS; \ else \ case $$MAKEFLAGS in \ *\\[\ \ ]*) \ bs=\\; \ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ esac; \ fi; \ skip_next=no; \ strip_trailopt () \ { \ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ }; \ for flg in $$sane_makeflags; do \ test $$skip_next = yes && { skip_next=no; continue; }; \ case $$flg in \ *=*|--*) continue;; \ -*I) strip_trailopt 'I'; skip_next=yes;; \ -*I?*) strip_trailopt 'I';; \ -*O) strip_trailopt 'O'; skip_next=yes;; \ -*O?*) strip_trailopt 'O';; \ -*l) strip_trailopt 'l'; skip_next=yes;; \ -*l?*) strip_trailopt 'l';; \ -[dEDm]) skip_next=yes;; \ -[JT]) skip_next=yes;; \ esac; \ case $$flg in \ *$$target_option*) has_opt=yes; break;; \ esac; \ done; \ test $$has_opt = yes am__make_dryrun = (target_option=n; $(am__make_running_with_option)) am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkglibexecdir = $(libexecdir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ target_triplet = @target@ subdir = tests/NIT ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/m4/ax_c___attribute__.m4 \ $(top_srcdir)/m4/ax_c_pragmas.m4 \ $(top_srcdir)/m4/ax_check_compile_flag.m4 \ $(top_srcdir)/m4/ax_compare_version.m4 \ $(top_srcdir)/m4/ax_realpath.m4 \ $(top_srcdir)/m4/ax_run_or_link_ifelse.m4 \ $(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \ $(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \ $(top_srcdir)/m4/lt~obsolete.m4 \ $(top_srcdir)/m4/nut_arg_with.m4 \ $(top_srcdir)/m4/nut_check_asciidoc.m4 \ $(top_srcdir)/m4/nut_check_aspell.m4 \ $(top_srcdir)/m4/nut_check_cppcheck.m4 \ $(top_srcdir)/m4/nut_check_headers_windows.m4 \ $(top_srcdir)/m4/nut_check_libavahi.m4 \ $(top_srcdir)/m4/nut_check_libfreeipmi.m4 \ $(top_srcdir)/m4/nut_check_libgd.m4 \ $(top_srcdir)/m4/nut_check_libgpiod.m4 \ $(top_srcdir)/m4/nut_check_libltdl.m4 \ $(top_srcdir)/m4/nut_check_libmodbus.m4 \ $(top_srcdir)/m4/nut_check_libneon.m4 \ $(top_srcdir)/m4/nut_check_libnetsnmp.m4 \ $(top_srcdir)/m4/nut_check_libnss.m4 \ $(top_srcdir)/m4/nut_check_libopenssl.m4 \ $(top_srcdir)/m4/nut_check_libpowerman.m4 \ $(top_srcdir)/m4/nut_check_libregex.m4 \ $(top_srcdir)/m4/nut_check_libsystemd.m4 \ $(top_srcdir)/m4/nut_check_libusb.m4 \ $(top_srcdir)/m4/nut_check_libwrap.m4 \ $(top_srcdir)/m4/nut_check_os.m4 \ $(top_srcdir)/m4/nut_check_pkgconfig.m4 \ $(top_srcdir)/m4/nut_check_python.m4 \ $(top_srcdir)/m4/nut_check_socketlib.m4 \ $(top_srcdir)/m4/nut_compiler_family.m4 \ $(top_srcdir)/m4/nut_func_getnameinfo_argtypes.m4 \ $(top_srcdir)/m4/nut_report_feature.m4 \ $(top_srcdir)/m4/nut_stash_warnings.m4 \ $(top_srcdir)/m4/nut_type_socklen_t.m4 \ $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/include/config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = AM_V_P = $(am__v_P_@AM_V@) am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) am__v_P_0 = false am__v_P_1 = : AM_V_GEN = $(am__v_GEN_@AM_V@) am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) am__v_GEN_0 = @echo " GEN " $@; am__v_GEN_1 = AM_V_at = $(am__v_at_@AM_V@) am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) am__v_at_0 = @ am__v_at_1 = SOURCES = DIST_SOURCES = am__can_run_installinfo = \ case $$AM_UPDATE_INFO_DIR in \ n|no|NO) false;; \ *) (install-info --version) >/dev/null 2>&1;; \ esac am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) am__DIST_COMMON = $(srcdir)/Makefile.in README DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) A2X = @A2X@ ACLOCAL = @ACLOCAL@ ALTPIDPATH = @ALTPIDPATH@ AMTAR = @AMTAR@ AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ AR = @AR@ ASCIIDOC = @ASCIIDOC@ ASPELL = @ASPELL@ ASPELL_FILTER_LIB_PATH = @ASPELL_FILTER_LIB_PATH@ ASPELL_FILTER_SHARE_PATH = @ASPELL_FILTER_SHARE_PATH@ ASPELL_FILTER_TEX_PATH = @ASPELL_FILTER_TEX_PATH@ AUGPARSE = @AUGPARSE@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ BINDIR = @BINDIR@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CONFIG_FLAGS = @CONFIG_FLAGS@ CONFPATH = @CONFPATH@ CPP = @CPP@ CPPCHECK = @CPPCHECK@ CPPFLAGS = @CPPFLAGS@ CPPUNIT_CFLAGS = @CPPUNIT_CFLAGS@ CPPUNIT_LIBS = @CPPUNIT_LIBS@ CSCOPE = @CSCOPE@ CTAGS = @CTAGS@ CXX = @CXX@ CXXCPP = @CXXCPP@ CXXDEPMODE = @CXXDEPMODE@ CXXFLAGS = @CXXFLAGS@ CYGPATH_W = @CYGPATH_W@ DBLATEX = @DBLATEX@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ DEPLOYED_UPSC = @DEPLOYED_UPSC@ DEPLOYED_UPSD = @DEPLOYED_UPSD@ DLLTOOL = @DLLTOOL@ DOC_BUILD_LIST = @DOC_BUILD_LIST@ DOC_CHECK_LIST = @DOC_CHECK_LIST@ DRIVER_BUILD_LIST = @DRIVER_BUILD_LIST@ DRIVER_INSTALL_TARGET = @DRIVER_INSTALL_TARGET@ DRIVER_MAN_LIST = @DRIVER_MAN_LIST@ DRIVER_MAN_LIST_PAGES = @DRIVER_MAN_LIST_PAGES@ DRVPATH = @DRVPATH@ DSYMUTIL = @DSYMUTIL@ DUMPBIN = @DUMPBIN@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ ETAGS = @ETAGS@ EXEEXT = @EXEEXT@ FGREP = @FGREP@ FORCE_NUT_VERSION = @FORCE_NUT_VERSION@ GDLIB_CONFIG = @GDLIB_CONFIG@ GREP = @GREP@ HAVE_SYS_SOCKET_H = @HAVE_SYS_SOCKET_H@ HAVE_WINSOCK2_H = @HAVE_WINSOCK2_H@ HAVE_WS2TCPIP_H = @HAVE_WS2TCPIP_H@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ LD = @LD@ LDFLAGS = @LDFLAGS@ LIBAVAHI_CFLAGS = @LIBAVAHI_CFLAGS@ LIBAVAHI_LIBS = @LIBAVAHI_LIBS@ LIBDIR = @LIBDIR@ LIBGD_CFLAGS = @LIBGD_CFLAGS@ LIBGD_LDFLAGS = @LIBGD_LDFLAGS@ LIBGPIO_CFLAGS = @LIBGPIO_CFLAGS@ LIBGPIO_LIBS = @LIBGPIO_LIBS@ LIBI2C_LIBS = @LIBI2C_LIBS@ LIBIPMI_CFLAGS = @LIBIPMI_CFLAGS@ LIBIPMI_LIBS = @LIBIPMI_LIBS@ LIBLTDL_CFLAGS = @LIBLTDL_CFLAGS@ LIBLTDL_LIBS = @LIBLTDL_LIBS@ LIBMODBUS_CFLAGS = @LIBMODBUS_CFLAGS@ LIBMODBUS_LIBS = @LIBMODBUS_LIBS@ LIBNEON_CFLAGS = @LIBNEON_CFLAGS@ LIBNEON_LIBS = @LIBNEON_LIBS@ LIBNETSNMP_CFLAGS = @LIBNETSNMP_CFLAGS@ LIBNETSNMP_LIBS = @LIBNETSNMP_LIBS@ LIBOBJS = @LIBOBJS@ LIBPOWERMAN_CFLAGS = @LIBPOWERMAN_CFLAGS@ LIBPOWERMAN_LIBS = @LIBPOWERMAN_LIBS@ LIBREGEX_LIBS = @LIBREGEX_LIBS@ LIBS = @LIBS@ LIBSSL_CFLAGS = @LIBSSL_CFLAGS@ LIBSSL_LIBS = @LIBSSL_LIBS@ LIBSSL_REQUIRES = @LIBSSL_REQUIRES@ LIBSYSTEMD_CFLAGS = @LIBSYSTEMD_CFLAGS@ LIBSYSTEMD_LIBS = @LIBSYSTEMD_LIBS@ LIBTOOL = @LIBTOOL@ LIBTOOL_DEPS = @LIBTOOL_DEPS@ LIBUSB_CFLAGS = @LIBUSB_CFLAGS@ LIBUSB_CONFIG = @LIBUSB_CONFIG@ LIBUSB_LIBS = @LIBUSB_LIBS@ LIBWRAP_CFLAGS = @LIBWRAP_CFLAGS@ LIBWRAP_LIBS = @LIBWRAP_LIBS@ LIPO = @LIPO@ LN_S = @LN_S@ LN_S_R = @LN_S_R@ LTLIBOBJS = @LTLIBOBJS@ LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@ MAINT = @MAINT@ MAKEINFO = @MAKEINFO@ MANIFEST_TOOL = @MANIFEST_TOOL@ MKDIR_P = @MKDIR_P@ MSGFMT = @MSGFMT@ NETLIBS = @NETLIBS@ NET_SNMP_CONFIG = @NET_SNMP_CONFIG@ NM = @NM@ NMEDIT = @NMEDIT@ NUT_DATADIR = @NUT_DATADIR@ NUT_LIBEXECDIR = @NUT_LIBEXECDIR@ NUT_NETVERSION = @NUT_NETVERSION@ NUT_SOURCE_GITREV = @NUT_SOURCE_GITREV@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ OS_NAME = @OS_NAME@ OTOOL = @OTOOL@ OTOOL64 = @OTOOL64@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_SEPARATOR = @PATH_SEPARATOR@ PIDPATH = @PIDPATH@ PKGCONFIGDIR = @PKGCONFIGDIR@ PKG_CONFIG = @PKG_CONFIG@ PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@ PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ PORT = @PORT@ POWERDOWNFLAG = @POWERDOWNFLAG@ PREFIX = @PREFIX@ PYTHON = @PYTHON@ PYTHON2 = @PYTHON2@ PYTHON2_SITE_PACKAGES = @PYTHON2_SITE_PACKAGES@ PYTHON3 = @PYTHON3@ PYTHON3_SITE_PACKAGES = @PYTHON3_SITE_PACKAGES@ PYTHON_SITE_PACKAGES = @PYTHON_SITE_PACKAGES@ RANLIB = @RANLIB@ REALPATH = @REALPATH@ RUN_AS_GROUP = @RUN_AS_GROUP@ RUN_AS_USER = @RUN_AS_USER@ SBINDIR = @SBINDIR@ SED = @SED@ SEMLIBS = @SEMLIBS@ SERLIBS = @SERLIBS@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ SOURCE_HIGHLIGHT = @SOURCE_HIGHLIGHT@ STATEPATH = @STATEPATH@ STRIP = @STRIP@ SUN_LIBUSB = @SUN_LIBUSB@ SYSTEMD_ANALYZE_PROGRAM = @SYSTEMD_ANALYZE_PROGRAM@ SYSTEMD_DAEMON_ARGS_DRIVER = @SYSTEMD_DAEMON_ARGS_DRIVER@ SYSTEMD_DAEMON_ARGS_UPSD = @SYSTEMD_DAEMON_ARGS_UPSD@ SYSTEMD_DAEMON_ARGS_UPSMON = @SYSTEMD_DAEMON_ARGS_UPSMON@ SYSTEMD_DAEMON_NOTIFYACCESS_DRIVER = @SYSTEMD_DAEMON_NOTIFYACCESS_DRIVER@ SYSTEMD_DAEMON_NOTIFYACCESS_UPSD = @SYSTEMD_DAEMON_NOTIFYACCESS_UPSD@ SYSTEMD_DAEMON_NOTIFYACCESS_UPSMON = @SYSTEMD_DAEMON_NOTIFYACCESS_UPSMON@ SYSTEMD_DAEMON_TYPE_DRIVER = @SYSTEMD_DAEMON_TYPE_DRIVER@ SYSTEMD_DAEMON_TYPE_UPSD = @SYSTEMD_DAEMON_TYPE_UPSD@ SYSTEMD_DAEMON_TYPE_UPSMON = @SYSTEMD_DAEMON_TYPE_UPSMON@ SYSTEMD_DAEMON_WATCHDOG_DRIVER = @SYSTEMD_DAEMON_WATCHDOG_DRIVER@ SYSTEMD_DAEMON_WATCHDOG_UPSD = @SYSTEMD_DAEMON_WATCHDOG_UPSD@ SYSTEMD_DAEMON_WATCHDOG_UPSMON = @SYSTEMD_DAEMON_WATCHDOG_UPSMON@ SYSTEMD_TMPFILES_PROGRAM = @SYSTEMD_TMPFILES_PROGRAM@ TREE_VERSION = @TREE_VERSION@ VALGRIND = @VALGRIND@ VERSION = @VERSION@ WINDMC = @WINDMC@ WINDRES = @WINDRES@ WORDS_BIGENDIAN = @WORDS_BIGENDIAN@ XMLLINT = @XMLLINT@ XSLTPROC = @XSLTPROC@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_AR = @ac_ct_AR@ ac_ct_CC = @ac_ct_CC@ ac_ct_CXX = @ac_ct_CXX@ ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__tar = @am__tar@ am__untar = @am__untar@ auglensdir = @auglensdir@ bindir = @bindir@ build = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ cgiexecdir = @cgiexecdir@ datadir = @datadir@ datarootdir = @datarootdir@ devddir = @devddir@ docdir = @docdir@ driverexecdir = @driverexecdir@ dummy_PKG_CONFIG = @dummy_PKG_CONFIG@ dummy_PKG_CONFIG_CFLAGS = @dummy_PKG_CONFIG_CFLAGS@ dummy_PKG_CONFIG_LIBS = @dummy_PKG_CONFIG_LIBS@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ hotplugdir = @hotplugdir@ htmldir = @htmldir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libdir = @libdir@ libexecdir = @libexecdir@ localedir = @localedir@ localstatedir = @localstatedir@ mandir = @mandir@ mkdir_p = @mkdir_p@ now = @now@ nut_with_nut_monitor = @nut_with_nut_monitor@ nut_with_nut_monitor_desktop = @nut_with_nut_monitor_desktop@ nut_with_nut_monitor_dir = @nut_with_nut_monitor_dir@ nut_with_nut_monitor_py2gtk2 = @nut_with_nut_monitor_py2gtk2@ nut_with_nut_monitor_py3qt5 = @nut_with_nut_monitor_py3qt5@ nut_with_pynut = @nut_with_pynut@ nut_with_pynut_py = @nut_with_pynut_py@ nut_with_pynut_py2 = @nut_with_pynut_py2@ nut_with_pynut_py3 = @nut_with_pynut_py3@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ pkgconfigdir = @pkgconfigdir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ runstatedir = @runstatedir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ sysconfdir = @sysconfdir@ systemdshutdowndir = @systemdshutdowndir@ systemdsystemunitdir = @systemdsystemunitdir@ systemdtmpfilesdir = @systemdtmpfilesdir@ target = @target@ target_alias = @target_alias@ target_cpu = @target_cpu@ target_os = @target_os@ target_vendor = @target_vendor@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ udevdir = @udevdir@ EXTRA_DIST = nit.sh README MAINTAINERCLEANFILES = Makefile.in .dirstamp all: all-am .SUFFIXES: $(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu tests/NIT/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --gnu tests/NIT/Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): mostlyclean-libtool: -rm -f *.lo clean-libtool: -rm -rf .libs _libs tags TAGS: ctags CTAGS: cscope cscopelist: distdir: $(BUILT_SOURCES) $(MAKE) $(AM_MAKEFLAGS) distdir-am distdir-am: $(DISTFILES) @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ dist_files=`for file in $$list; do echo $$file; done | \ sed -e "s|^$$srcdirstrip/||;t" \ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ case $$dist_files in \ */*) $(MKDIR_P) `echo "$$dist_files" | \ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ sort -u` ;; \ esac; \ for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d "$(distdir)/$$file"; then \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ else \ test -f "$(distdir)/$$file" \ || cp -p $$d/$$file "$(distdir)/$$file" \ || exit 1; \ fi; \ done check-am: all-am check: check-am all-am: Makefile installdirs: install: install-am install-exec: install-exec-am install-data: install-data-am uninstall: uninstall-am install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-am install-strip: if test -z '$(STRIP)'; then \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ install; \ else \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ fi mostlyclean-generic: clean-generic: distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." -test -z "$(MAINTAINERCLEANFILES)" || rm -f $(MAINTAINERCLEANFILES) clean: clean-am clean-am: clean-generic clean-libtool clean-local mostlyclean-am distclean: distclean-am -rm -f Makefile distclean-am: clean-am distclean-generic dvi: dvi-am dvi-am: html: html-am html-am: info: info-am info-am: install-data-am: install-dvi: install-dvi-am install-dvi-am: install-exec-am: install-html: install-html-am install-html-am: install-info: install-info-am install-info-am: install-man: install-pdf: install-pdf-am install-pdf-am: install-ps: install-ps-am install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-am -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-am mostlyclean-am: mostlyclean-generic mostlyclean-libtool pdf: pdf-am pdf-am: ps: ps-am ps-am: uninstall-am: .MAKE: install-am install-strip .PHONY: all all-am check check-am clean clean-generic clean-libtool \ clean-local cscopelist-am ctags-am distclean distclean-generic \ distclean-libtool distdir dvi dvi-am html html-am info info-am \ install install-am install-data install-data-am install-dvi \ install-dvi-am install-exec install-exec-am install-html \ install-html-am install-info install-info-am install-man \ install-pdf install-pdf-am install-ps install-ps-am \ install-strip installcheck installcheck-am installdirs \ maintainer-clean maintainer-clean-generic mostlyclean \ mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \ tags-am uninstall uninstall-am .PRECIOUS: Makefile @WITH_CHECK_NIT_TRUE@check: check-NIT @WITH_CHECK_NIT_FALSE@check: @WITH_CHECK_NIT_FALSE@ @echo "NO-OP: $@ in `pwd` is inactive by default. Run 'configure --enable-check-NIT' or 'make check-NIT' explicitly" >&2 # Run in builddir, use script from srcdir # Avoid running "$<" - not all make implementations handle that check-NIT: $(abs_srcdir)/nit.sh "$(abs_srcdir)/nit.sh" # Make sure pre-requisites for NIT are fresh as we iterate check-NIT-devel: $(abs_srcdir)/nit.sh @cd .. && ( $(MAKE) -s cppnit$(EXEEXT) || echo "OPTIONAL C++ test client test will be skipped" ) @cd "$(top_builddir)/clients" && $(MAKE) -s upsc$(EXEEXT) upsrw$(EXEEXT) upsmon$(EXEEXT) @cd "$(top_builddir)/server" && $(MAKE) -s upsd$(EXEEXT) @cd "$(top_builddir)/drivers" && $(MAKE) -s dummy-ups$(EXEEXT) @$(MAKE) check-NIT clean-local: $(AM_V_at)rm -rf tmp # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: nut-2.8.1/tests/NIT/nit.sh0000755000175000017500000014344114520272372012211 00000000000000#!/bin/sh # NUT Integration Testing suite, assumes the codebase was built and # arranges running of the binaries to test driver-client-server # ability to start and their interactions. # # Note: currently it is a PoC-quality mess that gets the job done # but could be refactored for better maintainability and generic # approach. Part of the goal was to let this script set up the # sandbox to run tests which could be defined in other files. # # WARNING: Current working directory when starting the script should be # the location where it may create temporary data (e.g. the BUILDDIR). # Caller can export envvars to impact the script behavior, e.g.: # DEBUG=true to print debug messages, running processes, etc. # DEBUG_SLEEP=60 to sleep after tests, with driver+server running # NUT_DEBUG_MIN=3 to set (minimum) debug level for drivers, upsd... # NUT_PORT=12345 custom port for upsd to listen and clients to query # # Design note: written with dumbed-down POSIX shell syntax, to # properly work in whatever different OSes have (bash, dash, # ksh, busybox sh...) # # Copyright # 2022-2023 Jim Klimov # # License: GPLv2+ TZ=UTC LANG=C LC_ALL=C export TZ LANG LC_ALL NUT_QUIET_INIT_SSL="true" export NUT_QUIET_INIT_SSL NUT_QUIET_INIT_UPSNOTIFY="true" export NUT_QUIET_INIT_UPSNOTIFY NUT_DEBUG_PID="true" export NUT_DEBUG_PID log_separator() { echo "" >&2 echo "================================" >&2 } shouldDebug() { [ -n "$DEBUG" ] || [ -n "$DEBUG_SLEEP" ] } log_debug() { if shouldDebug ; then echo "`TZ=UTC LANG=C date` [DEBUG] $@" >&2 fi } log_info() { echo "`TZ=UTC LANG=C date` [INFO] $@" >&2 } log_warn() { echo "`TZ=UTC LANG=C date` [WARNING] $@" >&2 } log_error() { echo "`TZ=UTC LANG=C date` [ERROR] $@" >&2 } report_NUT_PORT() { # Try to say which processes deal with current NUT_PORT [ -n "${NUT_PORT}" ] || return log_info "Trying to report users of NUT_PORT=${NUT_PORT}" # Note: on Solarish systems, `netstat -anp` does not report PID info (netstat -an ; netstat -anp || sockstat -l) 2>/dev/null | grep -w "${NUT_PORT}" \ || (lsof -i :"${NUT_PORT}") 2>/dev/null \ || true [ -z "${PID_UPSD}" ] || log_info "UPSD was last known to start as PID ${PID_UPSD}" } isBusy_NUT_PORT() { # Try to say if current NUT_PORT is busy (0 = true) # or available (non-0 = false) [ -n "${NUT_PORT}" ] || return log_debug "Trying to report if NUT_PORT=${NUT_PORT} is used" if [ -s /proc/net/tcp ] || [ -s /proc/net/tcp6 ]; then # Assume Linux - hex-encoded # IPv4: # sl local_address rem_address st tx_queue rx_queue tr tm->when retrnsmt uid timeout inode # 0: 0100007F:EE48 00000000:0000 0A 00000000:00000000 00:00000000 00000000 0 0 48881 1 00000000ec238d02 100 0 0 10 0 # ^^^ 1.0.0.127 - note reversed byte order! # IPv6: # sl local_address remote_address st tx_queue rx_queue tr tm->when retrnsmt uid timeout inode # 0: 00000000000000000000000000000000:1F46 00000000000000000000000000000000:0000 0A 00000000:00000000 00:00000000 00000000 33 0 37451 1 00000000fa3c0c15 100 0 0 10 0 NUT_PORT_HEX="`printf '%04X' "${NUT_PORT}"`" NUT_PORT_HITS="`cat /proc/net/tcp /proc/net/tcp6 2>/dev/null | awk '{print $2}' | grep -E ":${NUT_PORT_HEX}\$"`" \ && [ -n "$NUT_PORT_HITS" ] && return 0 # We had a way to check, and the way said port is available return 1 fi (netstat -an || sockstat -l) 2>/dev/null | grep -E "[:.]${NUT_PORT}(\t| |\$)" > /dev/null && return (lsof -i :"${NUT_PORT}") 2>/dev/null && return # Not busy... or no tools to confirm? if (command -v netstat || command -v sockstat || command -v lsof) 2>/dev/null >/dev/null ; then # at least one tool is present, so not busy return 1 fi # If the current shell interpreter is bash, it can do a bit of networking: if [ -n "${BASH_VERSION-}" ]; then # NOTE: Probing host names we use in upsd.conf # See generatecfg_upsd_trivial() for a more carefully made list ( # Hide this looped noise: # ./nit.sh: connect: Connection refused # ./nit.sh: line 112: /dev/tcp/localhost/35050: Connection refused if shouldDebug ; then : ; else exec 2>/dev/null fi for H in "localhost" "127.0.0.1" "::1"; do if echo "HELP" > "/dev/tcp/${H}/${NUT_PORT}" ; then # Successfully connected - port isBusy return 0 fi done return 1 ) && return 0 log_warn "isBusy_NUT_PORT() tried with BASH-specific query, and port does not seem busy (or something else errored out)" fi # Assume not busy to not preclude testing in 100% of the cases log_warn "isBusy_NUT_PORT() can not say definitively, tools for checking NUT_PORT=$NUT_PORT are not available" return 1 } die() { echo "[FATAL] $@" >&2 exit 1 } # By default, keep stdout hidden but report the errors: [ -n "$RUNCMD_QUIET_OUT" ] || RUNCMD_QUIET_OUT=true [ -n "$RUNCMD_QUIET_ERR" ] || RUNCMD_QUIET_ERR=false runcmd() { # Re-uses a couple of files in test scratch area NUT_STATEPATH # to store the stderr and stdout of the launched program. # Prints the captured output back and returns the exit code. [ -n "${NUT_STATEPATH}" -a -d "${NUT_STATEPATH}" -a -w "${NUT_STATEPATH}" ] \ || die "runcmd() called when NUT_STATEPATH was not yet set up" # Values from variables below may be used until next runcmd(): CMDRES=0 CMDOUT="" CMDERR="" "$@" > "${NUT_STATEPATH}/runcmd.out" 2>"${NUT_STATEPATH}/runcmd.err" || CMDRES=$? CMDOUT="`cat "${NUT_STATEPATH}/runcmd.out"`" CMDERR="`cat "${NUT_STATEPATH}/runcmd.err"`" [ "$RUNCMD_QUIET_OUT" = true ] || { [ -z "$CMDOUT" ] || echo "$CMDOUT" ; } [ "$RUNCMD_QUIET_ERR" = true ] || { [ -z "$CMDERR" ] || echo "$CMDERR" >&2 ; } return $CMDRES } # Note: current directory is assumed to be writeable for temporary # data, e.g. the $(builddir) from the Makefile. Static resources # from the source codebase are where the script resides, e.g. # the $(srcdir) from the Makefile. If we are not in the source # tree, tests would use binaries in PATH (e.g. packaged install). BUILDDIR="`pwd`" TOP_BUILDDIR="" case "${BUILDDIR}" in */tests/NIT) TOP_BUILDDIR="`cd "${BUILDDIR}"/../.. && pwd`" ;; *) log_info "Current directory '${BUILDDIR}' is not a .../tests/NIT" ;; esac if test ! -w "${BUILDDIR}" ; then log_error "BUILDDIR='${BUILDDIR}' is not writeable, tests may fail below" fi SRCDIR="`dirname "$0"`" SRCDIR="`cd "$SRCDIR" && pwd`" TOP_SRCDIR="" case "${SRCDIR}" in */tests/NIT) TOP_SRCDIR="`cd "${SRCDIR}"/../.. && pwd`" ;; *) log_info "Script source directory '${SRCDIR}' is not a .../tests/NIT" ;; esac # No fuss about LD_LIBRARY_PATH: for most of the (client) binaries that # need it, the PATH entries below would contain libtool wrapper scripts; # for other builds we use system default or caller's env. One exception # so far is nut-scanner that needs to know where libupsclient.so is... PATH_ADD="${BUILDDIR}" if [ x"${SRCDIR}" != x"${BUILDDIR}" ]; then PATH_ADD="${PATH_ADD}:${SRCDIR}" fi if [ x"${TOP_BUILDDIR}" != x ]; then PATH_ADD="${PATH_ADD}:${TOP_BUILDDIR}/clients:${TOP_BUILDDIR}/drivers:${TOP_BUILDDIR}/server:${TOP_BUILDDIR}/tools:${TOP_BUILDDIR}/tools/nut-scanner" fi if [ x"${TOP_SRCDIR}" != x ]; then PATH_ADD="${PATH_ADD}:${TOP_SRCDIR}/clients:${TOP_SRCDIR}/drivers:${TOP_SRCDIR}/server:${TOP_SRCDIR}/tools:${TOP_SRCDIR}/tools/nut-scanner" fi PATH="${PATH_ADD}:${PATH}" export PATH unset PATH_ADD log_debug "Using PATH='$PATH'" LD_LIBRARY_PATH_ORIG="${LD_LIBRARY_PATH-}" LD_LIBRARY_PATH_CLIENT="" if [ x"${TOP_BUILDDIR}" != x ]; then LD_LIBRARY_PATH_CLIENT="${TOP_BUILDDIR}/clients:${TOP_BUILDDIR}/clients/.libs" fi if [ x"${LD_LIBRARY_PATH_CLIENT}" != x ]; then if [ -n "${LD_LIBRARY_PATH_ORIG-}" ]; then LD_LIBRARY_PATH_CLIENT="${LD_LIBRARY_PATH_CLIENT}:${LD_LIBRARY_PATH_ORIG}" fi else LD_LIBRARY_PATH_CLIENT="${LD_LIBRARY_PATH_ORIG}" fi for PROG in upsd upsc dummy-ups upsmon ; do (command -v ${PROG}) || die "Useless setup: ${PROG} not found in PATH: ${PATH}" done PID_UPSD="" PID_DUMMYUPS="" PID_DUMMYUPS1="" PID_DUMMYUPS2="" TESTDIR="$BUILDDIR/tmp" # Technically the limit is sizeof(sockaddr.sun_path) for complete socket # pathname, which varies 104-108 chars max on systems seen in CI farm; # we reserve 17 chars for "/dummy-ups-dummy" longest filename. if [ `echo "$TESTDIR" | wc -c` -gt 80 ]; then log_info "'$TESTDIR' is too long to store AF_UNIX socket files, will mktemp" if ( [ -n "${TMPDIR-}" ] && [ -d "${TMPDIR-}" ] && [ -w "${TMPDIR-}" ] ) ; then : else if [ -d /dev/shm ] && [ -w /dev/shm ]; then TMPDIR=/dev/shm ; else TMPDIR=/tmp ; fi fi TESTDIR="`mktemp -d "${TMPDIR}/nit-tmp.$$.XXXXXX"`" || die "Failed to mktemp" else rm -rf "${TESTDIR}" || true fi log_info "Using '$TESTDIR' for generated configs and state files" mkdir -p "${TESTDIR}/etc" "${TESTDIR}/run" && chmod 750 "${TESTDIR}/run" \ || die "Failed to create temporary FS structure for the NIT" if [ "`id -u`" = 0 ]; then log_info "Test script was started by 'root' - expanding permissions for '${TESTDIR}/run' so unprivileged daemons may create pipes and PID files there" chmod 777 "${TESTDIR}/run" fi stop_daemons() { if [ -n "$PID_UPSD$PID_DUMMYUPS$PID_DUMMYUPS1$PID_DUMMYUPS2" ] ; then log_info "Stopping test daemons" kill -15 $PID_UPSD $PID_DUMMYUPS $PID_DUMMYUPS1 $PID_DUMMYUPS2 2>/dev/null || return 0 wait $PID_UPSD $PID_DUMMYUPS $PID_DUMMYUPS1 $PID_DUMMYUPS2 || true fi PID_UPSD="" PID_DUMMYUPS="" PID_DUMMYUPS1="" PID_DUMMYUPS2="" } trap 'RES=$?; stop_daemons; if [ "${TESTDIR}" != "${BUILDDIR}/tmp" ] ; then rm -rf "${TESTDIR}" ; fi; exit $RES;' 0 1 2 3 15 NUT_STATEPATH="${TESTDIR}/run" NUT_ALTPIDPATH="${TESTDIR}/run" NUT_CONFPATH="${TESTDIR}/etc" export NUT_STATEPATH NUT_ALTPIDPATH NUT_CONFPATH # TODO: Find a portable way to (check and) grab a random unprivileged port? if [ -n "${NUT_PORT-}" ] && [ "$NUT_PORT" -gt 0 ] && [ "$NUT_PORT" -lt 65536 ] ; then if isBusy_NUT_PORT ; then log_warn "NUT_PORT=$NUT_PORT requested by caller seems occupied; tests may fail below" fi else COUNTDOWN=60 while [ "$COUNTDOWN" -gt 0 ] ; do DELTA1="`date +%S`" || DELTA1=0 DELTA2="`expr $$ % 99`" || DELTA2=0 NUT_PORT="`expr 34931 + $DELTA1 + $DELTA2`" \ && [ "$NUT_PORT" -gt 0 ] && [ "$NUT_PORT" -lt 65536 ] \ || NUT_PORT=34931 if isBusy_NUT_PORT ; then : ; else break fi log_warn "Selected NUT_PORT=$NUT_PORT seems occupied; will try another in a few seconds" COUNTDOWN="`expr "$COUNTDOWN" - 1`" [ "$COUNTDOWN" = 0 ] || sleep 2 done if [ "$COUNTDOWN" = 0 ] ; then COUNTDOWN=60 DELTA1=1025 while [ "$COUNTDOWN" -gt 0 ] ; do DELTA2="`expr $RANDOM % 64000`" \ && [ "$DELTA2" -ge 0 ] || die "Can not pick random port" NUT_PORT="`expr $DELTA1 + $DELTA2`" if isBusy_NUT_PORT ; then : ; else break fi # Loop quickly, no sleep here COUNTDOWN="`expr "$COUNTDOWN" - 1`" done if [ "$COUNTDOWN" = 0 ] ; then die "Can not pick random port" fi fi fi export NUT_PORT # Help track collisions in log, if someone else starts a test in same directory log_info "Using NUT_PORT=${NUT_PORT} for this test run" ### upsd.conf: ################################################## generatecfg_upsd_trivial() { # Populate the configs for the run cat > "$NUT_CONFPATH/upsd.conf" << EOF STATEPATH "$NUT_STATEPATH" LISTEN localhost $NUT_PORT EOF [ $? = 0 ] || die "Failed to populate temporary FS structure for the NIT: upsd.conf" if [ "`id -u`" = 0 ]; then log_info "Test script was started by 'root' - expanding permissions for '$NUT_CONFPATH/upsd.conf' so unprivileged daemons (after de-elevation) may read it" chmod 644 "$NUT_CONFPATH/upsd.conf" else chmod 640 "$NUT_CONFPATH/upsd.conf" fi # Some systems listining on symbolic "localhost" actually # only bind to IPv6, and Python telnetlib resolves IPv4 # and fails its connection tests. Others fare well with # both addresses in one command. for LH in 127.0.0.1 '::1' ; do if ( ( cat /etc/hosts || getent hosts ) | grep "$LH" \ || ping -c 1 "$LH" ) 2>/dev/null >/dev/null ; then echo "LISTEN $LH $NUT_PORT" >> "$NUT_CONFPATH/upsd.conf" fi done if [ -n "${NUT_DEBUG_MIN-}" ] ; then echo "DEBUG_MIN ${NUT_DEBUG_MIN}" >> "$NUT_CONFPATH/upsd.conf" || exit fi } generatecfg_upsd_nodev() { generatecfg_upsd_trivial echo "ALLOW_NO_DEVICE true" >> "$NUT_CONFPATH/upsd.conf" \ || die "Failed to populate temporary FS structure for the NIT: upsd.conf" } ### upsd.users: ################################################## TESTPASS_ADMIN='mypass' TESTPASS_TESTER='pass words' TESTPASS_UPSMON_PRIMARY='P@ssW0rdAdm' TESTPASS_UPSMON_SECONDARY='P@ssW0rd' generatecfg_upsdusers_trivial() { cat > "$NUT_CONFPATH/upsd.users" << EOF [admin] password = $TESTPASS_ADMIN actions = SET instcmds = ALL [tester] password = "${TESTPASS_TESTER}" instcmds = test.battery.start instcmds = test.battery.stop [dummy-admin-m] password = "${TESTPASS_UPSMON_PRIMARY}" upsmon master [dummy-admin] password = "${TESTPASS_UPSMON_PRIMARY}" upsmon primary [dummy-user-s] password = "${TESTPASS_UPSMON_SECONDARY}" upsmon slave [dummy-user] password = "${TESTPASS_UPSMON_SECONDARY}" upsmon secondary EOF [ $? = 0 ] || die "Failed to populate temporary FS structure for the NIT: upsd.users" if [ "`id -u`" = 0 ]; then log_info "Test script was started by 'root' - expanding permissions for '$NUT_CONFPATH/upsd.users' so unprivileged daemons (after de-elevation) may read it" chmod 644 "$NUT_CONFPATH/upsd.users" else chmod 640 "$NUT_CONFPATH/upsd.users" fi } ### upsmon.conf: ################################################## generatecfg_upsmon_trivial() { # Populate the configs for the run ( echo 'MINSUPPLIES 0' > "$NUT_CONFPATH/upsmon.conf" || exit echo 'SHUTDOWNCMD "echo TESTING_DUMMY_SHUTDOWN_NOW"' >> "$NUT_CONFPATH/upsmon.conf" || exit if [ -n "${NUT_DEBUG_MIN-}" ] ; then echo "DEBUG_MIN ${NUT_DEBUG_MIN}" >> "$NUT_CONFPATH/upsmon.conf" || exit fi ) || die "Failed to populate temporary FS structure for the NIT: upsmon.conf" if [ "`id -u`" = 0 ]; then log_info "Test script was started by 'root' - expanding permissions for '$NUT_CONFPATH/upsmon.conf' so unprivileged daemons (after de-elevation) may read it" chmod 644 "$NUT_CONFPATH/upsmon.conf" else chmod 640 "$NUT_CONFPATH/upsmon.conf" fi } generatecfg_upsmon_master() { generatecfg_upsmon_trivial echo "MONITOR 'dummy@localhost:$NUT_PORT' 0 'dummy-admin-m' '${TESTPASS_UPSMON_PRIMARY}' master" >> "$NUT_CONFPATH/upsmon.conf" \ || die "Failed to populate temporary FS structure for the NIT: upsmon.conf" } generatecfg_upsmon_primary() { generatecfg_upsmon_trivial echo "MONITOR 'dummy@localhost:$NUT_PORT' 0 'dummy-admin' '${TESTPASS_UPSMON_PRIMARY}' primary" >> "$NUT_CONFPATH/upsmon.conf" \ || die "Failed to populate temporary FS structure for the NIT: upsmon.conf" } generatecfg_upsmon_slave() { generatecfg_upsmon_trivial echo "MONITOR 'dummy@localhost:$NUT_PORT' 0 'dummy-user-s' '${TESTPASS_UPSMON_SECONDARY}' slave" >> "$NUT_CONFPATH/upsmon.conf" \ || die "Failed to populate temporary FS structure for the NIT: upsmon.conf" } generatecfg_upsmon_secondary() { generatecfg_upsmon_trivial echo "MONITOR 'dummy@localhost:$NUT_PORT' 0 'dummy-user' '${TESTPASS_UPSMON_SECONDARY}' secondary" >> "$NUT_CONFPATH/upsmon.conf" \ || die "Failed to populate temporary FS structure for the NIT: upsmon.conf" } ### ups.conf: ################################################## generatecfg_ups_trivial() { # Populate the configs for the run ( echo 'maxretry = 3' > "$NUT_CONFPATH/ups.conf" || exit if [ x"${TOP_BUILDDIR}" != x ]; then echo "driverpath = \"${TOP_BUILDDIR}/drivers\"" >> "$NUT_CONFPATH/ups.conf" || exit fi if [ -n "${NUT_DEBUG_MIN-}" ] ; then echo "debug_min = ${NUT_DEBUG_MIN}" >> "$NUT_CONFPATH/ups.conf" || exit fi ) || die "Failed to populate temporary FS structure for the NIT: ups.conf" if [ "`id -u`" = 0 ]; then log_info "Test script was started by 'root' - expanding permissions for '$NUT_CONFPATH/ups.conf' so unprivileged daemons (after de-elevation) may read it" chmod 644 "$NUT_CONFPATH/ups.conf" else chmod 640 "$NUT_CONFPATH/ups.conf" fi } generatecfg_ups_dummy() { generatecfg_ups_trivial cat > "$NUT_CONFPATH/dummy.seq" << EOF ups.status: OB TIMER 5 ups.status: OL TIMER 5 EOF [ $? = 0 ] || die "Failed to populate temporary FS structure for the NIT: dummy.seq" cat >> "$NUT_CONFPATH/ups.conf" << EOF [dummy] driver = dummy-ups desc = "Crash Dummy" port = dummy.seq #mode = dummy-loop EOF [ $? = 0 ] || die "Failed to populate temporary FS structure for the NIT: ups.conf" if [ x"${TOP_SRCDIR}" != x ]; then cp "${TOP_SRCDIR}/data/evolution500.seq" "${TOP_SRCDIR}/data/epdu-managed.dev" "$NUT_CONFPATH/" cat >> "$NUT_CONFPATH/ups.conf" << EOF [UPS1] driver = dummy-ups desc = "Example event sequence" port = evolution500.seq [UPS2] driver = dummy-ups desc = "Example ePDU data dump" port = epdu-managed.dev mode = dummy-once EOF [ $? = 0 ] || die "Failed to populate temporary FS structure for the NIT: ups.conf" # HACK: Avoid empty ups.status that may be present in example docs # FIXME: Might we actually want that value (un-)set for tests?.. # TODO: Check if the problem was with dummy-ups looping? [#1385] # Avoid "sed -i", it behaves differently on some platforms # and is completely absent on others [#1736 and earlier] for F in "$NUT_CONFPATH/"*.dev "$NUT_CONFPATH/"*.seq ; do sed -e 's,^ups.status: *$,ups.status: OL BOOST,' "$F" > "$F.bak" mv -f "$F.bak" "$F" grep -E '^ups.status:' "$F" >/dev/null || { echo "ups.status: OL BOOST" >> "$F"; } done fi } ##################################################### isPidAlive() { [ -n "$1" ] && [ "$1" -gt 0 ] || return [ -d "/proc/$1" ] || kill -0 "$1" 2>/dev/null } FAILED=0 FAILED_FUNCS="" PASSED=0 testcase_upsd_no_configs_at_all() { log_separator log_info "[testcase_upsd_no_configs_at_all] Test UPSD without configs at all" upsd -F if [ "$?" = 0 ]; then log_error "[testcase_upsd_no_configs_at_all] upsd should fail without configs" FAILED="`expr $FAILED + 1`" FAILED_FUNCS="$FAILED_FUNCS testcase_upsd_no_configs_at_all" else log_info "[testcase_upsd_no_configs_at_all] PASSED: upsd failed to start in wrong conditions" PASSED="`expr $PASSED + 1`" fi } testcase_upsd_no_configs_driver_file() { log_separator log_info "[testcase_upsd_no_configs_driver_file] Test UPSD without driver config file" generatecfg_upsd_trivial upsd -F if [ "$?" = 0 ]; then log_error "[testcase_upsd_no_configs_driver_file] upsd should fail without driver config file" FAILED="`expr $FAILED + 1`" FAILED_FUNCS="$FAILED_FUNCS testcase_upsd_no_configs_driver_file" else log_info "[testcase_upsd_no_configs_driver_file] PASSED: upsd failed to start in wrong conditions" PASSED="`expr $PASSED + 1`" fi } testcase_upsd_no_configs_in_driver_file() { log_separator log_info "[testcase_upsd_no_configs_in_driver_file] Test UPSD without drivers defined in config file" generatecfg_upsd_trivial generatecfg_ups_trivial upsd -F if [ "$?" = 0 ]; then log_error "[testcase_upsd_no_configs_in_driver_file] upsd should fail without drivers defined in config file" FAILED="`expr $FAILED + 1`" FAILED_FUNCS="$FAILED_FUNCS testcase_upsd_no_configs_in_driver_file" else log_info "[testcase_upsd_no_configs_in_driver_file] PASSED: upsd failed to start in wrong conditions" PASSED="`expr $PASSED + 1`" fi } testcase_upsd_allow_no_device() { log_separator log_info "[testcase_upsd_allow_no_device] Test UPSD allowed to run without driver configs" generatecfg_upsd_nodev generatecfg_upsdusers_trivial generatecfg_ups_trivial if shouldDebug ; then ls -la "$NUT_CONFPATH/" || true fi upsd -F & PID_UPSD="$!" log_debug "[testcase_upsd_allow_no_device] Tried to start UPSD as PID $PID_UPSD" sleep 2 COUNTDOWN=60 while [ "$COUNTDOWN" -gt 0 ]; do if isPidAlive "$PID_UPSD"; then break ; fi # FIXME: If we are here, even once, then PID_UPSD which we # knew has already disappeared... wait() for its exit-code? sleep 1 COUNTDOWN="`expr $COUNTDOWN - 1`" done if [ "$COUNTDOWN" -le 50 ] ; then # Should not get to this, except on very laggy systems maybe log_warn "[testcase_upsd_allow_no_device] Had to wait a few retries for the UPSD process to appear" fi res_testcase_upsd_allow_no_device=0 if [ "$COUNTDOWN" -gt 0 ] \ && isPidAlive "$PID_UPSD" \ ; then log_info "[testcase_upsd_allow_no_device] OK, upsd is running" PASSED="`expr $PASSED + 1`" log_separator log_info "[testcase_upsd_allow_no_device] Query listing from UPSD by UPSC (no devices configured yet) to test that UPSD responds to UPSC" if runcmd upsc -l localhost:$NUT_PORT ; then : else # Note: avoid exact matching for stderr, because it can have Init SSL messages etc. if echo "$CMDERR" | grep "Error: Server disconnected" >/dev/null ; then log_warn "[testcase_upsd_allow_no_device] Retry once to rule out laggy systems" sleep 3 runcmd upsc -l localhost:$NUT_PORT fi if echo "$CMDERR" | grep "Error: Server disconnected" >/dev/null ; then log_warn "[testcase_upsd_allow_no_device] Retry once more to rule out very laggy systems" sleep 15 runcmd upsc -l localhost:$NUT_PORT fi [ "$CMDRES" = 0 ] || die "[testcase_upsd_allow_no_device] upsd does not respond on port ${NUT_PORT} ($?): $CMDOUT" fi if [ -n "$CMDOUT" ] ; then log_error "[testcase_upsd_allow_no_device] got reply for upsc listing when none was expected: $CMDOUT" FAILED="`expr $FAILED + 1`" FAILED_FUNCS="$FAILED_FUNCS testcase_upsd_allow_no_device" res_testcase_upsd_allow_no_device=1 else log_info "[testcase_upsd_allow_no_device] OK, empty response as expected" PASSED="`expr $PASSED + 1`" fi else log_error "[testcase_upsd_allow_no_device] upsd was expected to be running although no devices are defined; is ups.conf populated?" ls -la "$NUT_CONFPATH/" || true FAILED="`expr $FAILED + 1`" FAILED_FUNCS="$FAILED_FUNCS testcase_upsd_allow_no_device" res_testcase_upsd_allow_no_device=1 report_NUT_PORT fi log_info "[testcase_upsd_allow_no_device] stopping upsd: $PID_UPSD" UPSD_RES=0 kill -15 $PID_UPSD wait $PID_UPSD || UPSD_RES=$? if [ "$res_testcase_upsd_allow_no_device" = 0 ] ; then log_info "[testcase_upsd_allow_no_device] upsd exit-code was: $UPSD_RES" else log_error "[testcase_upsd_allow_no_device] upsd exit-code was: $UPSD_RES" fi if [ "$UPSD_RES" != 0 ]; then return $UPSD_RES fi return $res_testcase_upsd_allow_no_device } testgroup_upsd_invalid_configs() { testcase_upsd_no_configs_at_all testcase_upsd_no_configs_driver_file testcase_upsd_no_configs_in_driver_file } testgroup_upsd_questionable_configs() { testcase_upsd_allow_no_device } ######################################################### ### Tests in a common sandbox with driver(s) + server ### ######################################################### SANDBOX_CONFIG_GENERATED=false sandbox_generate_configs() { if $SANDBOX_CONFIG_GENERATED ; then return ; fi log_info "Generating configs for sandbox" generatecfg_upsd_nodev generatecfg_upsdusers_trivial generatecfg_ups_dummy SANDBOX_CONFIG_GENERATED=true } sandbox_forget_configs() { SANDBOX_CONFIG_GENERATED=false if [ -z "${DEBUG_SLEEP-}" ] ; then stop_daemons fi } sandbox_start_upsd() { if isPidAlive "$PID_UPSD" ; then return 0 fi sandbox_generate_configs log_info "Starting UPSD for sandbox" upsd -F & PID_UPSD="$!" log_debug "Tried to start UPSD as PID $PID_UPSD" sleep 5 } sandbox_start_drivers() { if isPidAlive "$PID_DUMMYUPS" \ && { [ x"${TOP_SRCDIR}" != x ] && isPidAlive "$PID_DUMMYUPS1" && isPidAlive "$PID_DUMMYUPS2" \ || [ x"${TOP_SRCDIR}" = x ] ; } \ ; then # All drivers expected for this environment are already running return 0 fi sandbox_generate_configs log_info "Starting dummy-ups driver(s) for sandbox" #upsdrvctl -F start dummy & dummy-ups -a dummy -F & PID_DUMMYUPS="$!" log_debug "Tried to start dummy-ups driver for 'dummy' as PID $PID_DUMMYUPS" if [ x"${TOP_SRCDIR}" != x ]; then dummy-ups -a UPS1 -F & PID_DUMMYUPS1="$!" log_debug "Tried to start dummy-ups driver for 'UPS1' as PID $PID_DUMMYUPS1" dummy-ups -a UPS2 -F & PID_DUMMYUPS2="$!" log_debug "Tried to start dummy-ups driver for 'UPS2' as PID $PID_DUMMYUPS2" fi sleep 5 if shouldDebug ; then (ps -ef || ps -xawwu) 2>/dev/null | grep -E '(ups|nut|dummy|'"`basename "$0"`"')' | grep -vE '(ssh|startups|grep)' || true fi if isPidAlive "$PID_DUMMYUPS" \ && { [ x"${TOP_SRCDIR}" != x ] && isPidAlive "$PID_DUMMYUPS1" && isPidAlive "$PID_DUMMYUPS2" \ || [ x"${TOP_SRCDIR}" = x ] ; } \ ; then # All drivers expected for this environment are already running log_info "Starting dummy-ups driver(s) for sandbox - all expected processes are running" return 0 else log_error "Starting dummy-ups driver(s) for sandbox - finished, but something seems to not be running" return 1 fi } testcase_sandbox_start_upsd_alone() { log_separator log_info "[testcase_sandbox_start_upsd_alone] Test starting UPSD but not a driver before it" sandbox_start_upsd EXPECTED_UPSLIST='dummy' if [ x"${TOP_SRCDIR}" != x ]; then EXPECTED_UPSLIST="$EXPECTED_UPSLIST UPS1 UPS2" # For windows runners (strip CR if any): EXPECTED_UPSLIST="`echo "$EXPECTED_UPSLIST" | tr -d '\r'`" fi log_info "[testcase_sandbox_start_upsd_alone] Query listing from UPSD by UPSC (driver not running yet)" res_testcase_sandbox_start_upsd_alone=0 runcmd upsc -l localhost:$NUT_PORT || die "[testcase_sandbox_start_upsd_alone] upsd does not respond on port ${NUT_PORT} ($?): $CMDOUT" # For windows runners (printf can do wonders, so strip CR if any): if [ x"${TOP_SRCDIR}" != x ]; then CMDOUT="`echo "$CMDOUT" | tr -d '\r'`" fi if [ x"$CMDOUT" != x"$EXPECTED_UPSLIST" ] ; then log_error "[testcase_sandbox_start_upsd_alone] got this reply for upsc listing when '$EXPECTED_UPSLIST' was expected: '$CMDOUT'" FAILED="`expr $FAILED + 1`" FAILED_FUNCS="$FAILED_FUNCS testcase_sandbox_start_upsd_alone" res_testcase_sandbox_start_upsd_alone=1 else PASSED="`expr $PASSED + 1`" fi log_info "[testcase_sandbox_start_upsd_alone] Query driver state from UPSD by UPSC (driver not running yet)" runcmd upsc dummy@localhost:$NUT_PORT && { log_error "upsc was supposed to answer with error exit code: $CMDOUT" FAILED="`expr $FAILED + 1`" FAILED_FUNCS="$FAILED_FUNCS testcase_sandbox_start_upsd_alone" res_testcase_sandbox_start_upsd_alone=1 } # Note: avoid exact matching for stderr, because it can have Init SSL messages etc. if echo "$CMDERR" | grep 'Error: Driver not connected' >/dev/null ; then PASSED="`expr $PASSED + 1`" else log_error "[testcase_sandbox_start_upsd_alone] got some other reply for upsc query when 'Error: Driver not connected' was expected on stderr: '$CMDOUT'" FAILED="`expr $FAILED + 1`" FAILED_FUNCS="$FAILED_FUNCS testcase_sandbox_start_upsd_alone" res_testcase_sandbox_start_upsd_alone=1 fi if [ "$res_testcase_sandbox_start_upsd_alone" = 0 ]; then log_info "[testcase_sandbox_start_upsd_alone] PASSED: got just the failures expected for data server alone (driver not running yet)" else log_error "[testcase_sandbox_start_upsd_alone] got some unexpected failures, see above" fi return $res_testcase_sandbox_start_upsd_alone } testcase_sandbox_start_upsd_after_drivers() { # Historically this is a fallback from testcase_sandbox_start_drivers_after_upsd log_info "[testcase_sandbox_start_upsd_after_drivers] Test starting UPSD after drivers" kill -15 $PID_UPSD 2>/dev/null wait $PID_UPSD upsd -F & PID_UPSD="$!" log_debug "[testcase_sandbox_start_upsd_after_drivers] Tried to start UPSD as PID $PID_UPSD" sandbox_start_drivers sandbox_start_upsd sleep 5 COUNTDOWN=90 while [ "$COUNTDOWN" -gt 0 ]; do # For query errors or known wait, keep looping runcmd upsc dummy@localhost:$NUT_PORT \ && case "$CMDOUT" in *"ups.status: WAIT"*) ;; *) log_info "Got output:" ; echo "$CMDOUT" ; break ;; esac sleep 1 COUNTDOWN="`expr $COUNTDOWN - 1`" done if [ "$COUNTDOWN" -le 88 ] ; then log_warn "[testcase_sandbox_start_upsd_after_drivers] Had to wait a few retries for the dummy driver to connect" fi if [ "$COUNTDOWN" -le 1 ] ; then report_NUT_PORT die "[testcase_sandbox_start_upsd_after_drivers] upsd does not respond on port ${NUT_PORT} ($?)" fi log_info "[testcase_sandbox_start_upsd_after_drivers] PASSED: upsd responds on port ${NUT_PORT}" } testcase_sandbox_start_drivers_after_upsd() { #sandbox_start_upsd testcase_sandbox_start_upsd_alone sandbox_start_drivers log_info "[testcase_sandbox_start_drivers_after_upsd] Query driver state from UPSD by UPSC after driver startup" # Timing issues: upsd starts, we wait 10 sec, drivers start and init, # at 20 sec upsd does not see them yet, at 30 sec the sockets connect # but info does not come yet => may be "driver stale", finally at # 40+(drv)/50+(upsd) sec a DUMPALL is processed (regular 30-sec loop?) - # so tightly near a minute until we have sturdy replies. COUNTDOWN=90 while [ "$COUNTDOWN" -gt 0 ]; do # For query errors or known wait, keep looping. May get: # driver.state: updateinfo # ups.status: WAIT runcmd upsc dummy@localhost:$NUT_PORT \ && case "$CMDOUT" in *"ups.status: WAIT"*) ;; *) log_info "[testcase_sandbox_start_drivers_after_upsd] Got output:" ; echo "$CMDOUT" ; break ;; esac sleep 1 COUNTDOWN="`expr $COUNTDOWN - 1`" done if [ "$COUNTDOWN" -le 88 ] ; then log_warn "[testcase_sandbox_start_drivers_after_upsd] Had to wait a few retries for the dummy driver to connect" fi if [ "$COUNTDOWN" -le 1 ] ; then # Should not get to this, except on very laggy systems maybe log_error "[testcase_sandbox_start_drivers_after_upsd] Query failed, retrying with UPSD started after drivers" testcase_sandbox_start_upsd_after_drivers fi if [ x"${TOP_SRCDIR}" != x ]; then log_info "[testcase_sandbox_start_drivers_after_upsd] Wait for dummy UPSes with larger data sets to initialize" for U in UPS1 UPS2 ; do COUNTDOWN=90 # TODO: Convert to runcmd()? OUT="" while [ x"$OUT" = x"ups.status: WAIT" ] ; do OUT="`upsc $U@localhost:$NUT_PORT ups.status`" || break [ x"$OUT" = x"ups.status: WAIT" ] || { log_info "[testcase_sandbox_start_drivers_after_upsd] Got output:"; echo "$OUT"; break; } sleep 1 COUNTDOWN="`expr $COUNTDOWN - 1`" # Systemic error, e.g. could not create socket file? [ "$COUNTDOWN" -lt 1 ] && die "[testcase_sandbox_start_drivers_after_upsd] Dummy driver did not start or respond in time" done if [ "$COUNTDOWN" -le 88 ] ; then log_warn "[testcase_sandbox_start_drivers_after_upsd] Had to wait a few retries for the $U driver to connect" fi done fi log_info "[testcase_sandbox_start_drivers_after_upsd] PASSED: Expected drivers are now responding via UPSD" } testcase_sandbox_upsc_query_model() { log_info "[testcase_sandbox_upsc_query_model] Query model from dummy device" runcmd upsc dummy@localhost:$NUT_PORT device.model || die "[testcase_sandbox_upsc_query_model] upsd does not respond on port ${NUT_PORT} ($?): $CMDOUT" if [ x"$CMDOUT" != x"Dummy UPS" ] ; then log_error "[testcase_sandbox_upsc_query_model] got this reply for upsc query when 'Dummy UPS' was expected: $CMDOUT" FAILED="`expr $FAILED + 1`" FAILED_FUNCS="$FAILED_FUNCS testcase_sandbox_upsc_query_model" else PASSED="`expr $PASSED + 1`" log_info "[testcase_sandbox_upsc_query_model] PASSED: got expected model from dummy device: $CMDOUT" fi } testcase_sandbox_upsc_query_bogus() { log_info "[testcase_sandbox_upsc_query_bogus] Query driver state from UPSD by UPSC for bogus info" runcmd upsc dummy@localhost:$NUT_PORT ups.bogus.value && { log_error "[testcase_sandbox_upsc_query_bogus] upsc was supposed to answer with error exit code: $CMDOUT" FAILED="`expr $FAILED + 1`" FAILED_FUNCS="$FAILED_FUNCS testcase_sandbox_upsc_query_bogus" } # Note: avoid exact matching for stderr, because it can have Init SSL messages etc. if echo "$CMDERR" | grep 'Error: Variable not supported by UPS' >/dev/null ; then PASSED="`expr $PASSED + 1`" log_info "[testcase_sandbox_upsc_query_bogus] PASSED: got expected reply to bogus query" else log_error "[testcase_sandbox_upsc_query_bogus] got some other reply for upsc query when 'Error: Variable not supported by UPS' was expected on stderr: stderr:'$CMDERR' / stdout:'$CMDOUT'" FAILED="`expr $FAILED + 1`" FAILED_FUNCS="$FAILED_FUNCS testcase_sandbox_upsc_query_bogus" fi } testcase_sandbox_upsc_query_timer() { log_separator log_info "[testcase_sandbox_upsc_query_timer] Test that dummy-ups TIMER action changes the reported state" # Driver is set up to flip ups.status every 5 sec, so check every 3 # TODO: Any need to convert to runcmd()? OUT1="`upsc dummy@localhost:$NUT_PORT ups.status`" || die "[testcase_sandbox_upsc_query_timer] upsd does not respond on port ${NUT_PORT} ($?): $OUT1" ; sleep 3 OUT2="`upsc dummy@localhost:$NUT_PORT ups.status`" || die "[testcase_sandbox_upsc_query_timer] upsd does not respond on port ${NUT_PORT} ($?): $OUT2" OUT3="" OUT4="" if [ x"$OUT1" = x"$OUT2" ]; then sleep 3 OUT3="`upsc dummy@localhost:$NUT_PORT ups.status`" || die "[testcase_sandbox_upsc_query_timer] upsd does not respond on port ${NUT_PORT} ($?): $OUT3" if [ x"$OUT2" = x"$OUT3" ]; then sleep 3 OUT4="`upsc dummy@localhost:$NUT_PORT ups.status`" || die "[testcase_sandbox_upsc_query_timer] upsd does not respond on port ${NUT_PORT} ($?): $OUT4" fi fi if echo "$OUT1$OUT2$OUT3$OUT4" | grep "OB" && echo "$OUT1$OUT2$OUT3$OUT4" | grep "OL" ; then log_info "[testcase_sandbox_upsc_query_timer] PASSED: ups.status flips over time" PASSED="`expr $PASSED + 1`" else log_error "[testcase_sandbox_upsc_query_timer] ups.status did not flip over time" FAILED="`expr $FAILED + 1`" FAILED_FUNCS="$FAILED_FUNCS testcase_sandbox_upsc_query_timer" fi } isTestablePython() { # We optionally make python module (if interpreter is found): if [ x"${TOP_BUILDDIR}" = x ] \ || [ ! -x "${TOP_BUILDDIR}/scripts/python/module/test_nutclient.py" ] \ ; then return 1 fi PY_SHEBANG="`head -1 "${TOP_BUILDDIR}/scripts/python/module/test_nutclient.py"`" if [ x"${PY_SHEBANG}" = x"#!no" ] ; then return 1 fi return 0 } testcase_sandbox_python_without_credentials() { isTestablePython || return 0 log_separator log_info "[testcase_sandbox_python_without_credentials] Call Python module test suite: PyNUT (NUT Python bindings) without login credentials" if ( unset NUT_USER || true unset NUT_PASS || true "${TOP_BUILDDIR}/scripts/python/module/test_nutclient.py" ) ; then log_info "[testcase_sandbox_python_without_credentials] PASSED: PyNUT did not complain" PASSED="`expr $PASSED + 1`" else log_error "[testcase_sandbox_python_without_credentials] PyNUT complained, check above" FAILED="`expr $FAILED + 1`" FAILED_FUNCS="$FAILED_FUNCS testcase_sandbox_python_without_credentials" fi } testcase_sandbox_python_with_credentials() { isTestablePython || return 0 # That script says it expects data/evolution500.seq (as the UPS1 dummy) # but the dummy data does not currently let issue the commands and # setvars tested from python script. log_separator log_info "[testcase_sandbox_python_with_credentials] Call Python module test suite: PyNUT (NUT Python bindings) with login credentials" if ( NUT_USER='admin' NUT_PASS="${TESTPASS_ADMIN}" export NUT_USER NUT_PASS "${TOP_BUILDDIR}/scripts/python/module/test_nutclient.py" ) ; then log_info "[testcase_sandbox_python_with_credentials] PASSED: PyNUT did not complain" PASSED="`expr $PASSED + 1`" else log_error "[testcase_sandbox_python_with_credentials] PyNUT complained, check above" FAILED="`expr $FAILED + 1`" FAILED_FUNCS="$FAILED_FUNCS testcase_sandbox_python_with_credentials" fi } testcase_sandbox_python_with_upsmon_credentials() { isTestablePython || return 0 log_separator log_info "[testcase_sandbox_python_with_upsmon_credentials] Call Python module test suite: PyNUT (NUT Python bindings) with upsmon role login credentials" if ( NUT_USER='dummy-admin' NUT_PASS="${TESTPASS_UPSMON_PRIMARY}" export NUT_USER NUT_PASS "${TOP_BUILDDIR}/scripts/python/module/test_nutclient.py" ) ; then log_info "[testcase_sandbox_python_with_upsmon_credentials] PASSED: PyNUT did not complain" PASSED="`expr $PASSED + 1`" else log_error "[testcase_sandbox_python_with_upsmon_credentials] PyNUT complained, check above" FAILED="`expr $FAILED + 1`" FAILED_FUNCS="$FAILED_FUNCS testcase_sandbox_python_with_upsmon_credentials" fi } testcases_sandbox_python() { isTestablePython || return 0 testcase_sandbox_python_without_credentials testcase_sandbox_python_with_credentials testcase_sandbox_python_with_upsmon_credentials } #################################### isTestableCppNIT() { # We optionally make and here can run C++ client tests: if [ x"${TOP_BUILDDIR}" = x ] \ || [ ! -x "${TOP_BUILDDIR}/tests/cppnit" ] \ ; then log_warn "SKIP: ${TOP_BUILDDIR}/tests/cppnit: Not found" return 1 fi return 0 } testcase_sandbox_cppnit_without_creds() { isTestableCppNIT || return 0 log_separator log_info "[testcase_sandbox_cppnit_without_creds] Call libnutclient test suite: cppnit without login credentials" if ( unset NUT_USER || true unset NUT_PASS || true "${TOP_BUILDDIR}/tests/cppnit" ) ; then log_info "[testcase_sandbox_cppnit_without_creds] PASSED: cppnit did not complain" PASSED="`expr $PASSED + 1`" else log_error "[testcase_sandbox_cppnit_without_creds] cppnit complained, check above" FAILED="`expr $FAILED + 1`" FAILED_FUNCS="$FAILED_FUNCS testcase_sandbox_cppnit_without_creds" fi } testcase_sandbox_cppnit_simple_admin() { isTestableCppNIT || return 0 log_separator log_info "[testcase_sandbox_cppnit_simple_admin] Call libnutclient test suite: cppnit with login credentials: simple admin" if ( NUT_USER='admin' NUT_PASS="${TESTPASS_ADMIN}" if [ x"${TOP_SRCDIR}" != x ]; then # Avoid dummies with TIMER flip-flops NUT_SETVAR_DEVICE='UPS2' else # Risks failure when lauching sub-test at the wrong second NUT_SETVAR_DEVICE='dummy' fi unset NUT_PRIMARY_DEVICE export NUT_USER NUT_PASS NUT_SETVAR_DEVICE "${TOP_BUILDDIR}/tests/cppnit" ) ; then log_info "[testcase_sandbox_cppnit_simple_admin] PASSED: cppnit did not complain" PASSED="`expr $PASSED + 1`" else log_error "[testcase_sandbox_cppnit_simple_admin] cppnit complained, check above" FAILED="`expr $FAILED + 1`" FAILED_FUNCS="$FAILED_FUNCS testcase_sandbox_cppnit_simple_admin" fi } testcase_sandbox_cppnit_upsmon_primary() { isTestableCppNIT || return 0 log_separator log_info "[testcase_sandbox_cppnit_upsmon_primary] Call libnutclient test suite: cppnit with login credentials: upsmon-primary" if ( NUT_USER='dummy-admin' NUT_PASS="${TESTPASS_UPSMON_PRIMARY}" NUT_PRIMARY_DEVICE='dummy' unset NUT_SETVAR_DEVICE export NUT_USER NUT_PASS NUT_PRIMARY_DEVICE "${TOP_BUILDDIR}/tests/cppnit" ) ; then log_info "[testcase_sandbox_cppnit_upsmon_primary] PASSED: cppnit did not complain" PASSED="`expr $PASSED + 1`" else log_error "[testcase_sandbox_cppnit_upsmon_primary] cppnit complained, check above" FAILED="`expr $FAILED + 1`" FAILED_FUNCS="$FAILED_FUNCS testcase_sandbox_cppnit_upsmon_primary" fi } testcase_sandbox_cppnit_upsmon_master() { isTestableCppNIT || return 0 log_separator log_info "[testcase_sandbox_cppnit_upsmon_master] Call libnutclient test suite: cppnit with login credentials: upsmon-master" if ( NUT_USER='dummy-admin-m' NUT_PASS="${TESTPASS_UPSMON_PRIMARY}" NUT_PRIMARY_DEVICE='dummy' unset NUT_SETVAR_DEVICE export NUT_USER NUT_PASS NUT_PRIMARY_DEVICE "${TOP_BUILDDIR}/tests/cppnit" ) ; then log_info "[testcase_sandbox_cppnit_upsmon_master] PASSED: cppnit did not complain" PASSED="`expr $PASSED + 1`" else log_error "[testcase_sandbox_cppnit_upsmon_master] cppnit complained, check above" FAILED="`expr $FAILED + 1`" FAILED_FUNCS="$FAILED_FUNCS testcase_sandbox_cppnit_upsmon_master" fi } testcases_sandbox_cppnit() { isTestableCppNIT || return 0 testcase_sandbox_cppnit_without_creds testcase_sandbox_cppnit_upsmon_primary testcase_sandbox_cppnit_upsmon_master testcase_sandbox_cppnit_simple_admin } #################################### isTestableNutScanner() { # We optionally make and here can run nut-scanner (as NUT client) # tests, which tangentially tests the C client library: if [ x"${TOP_BUILDDIR}" = x ] \ || [ ! -x "${TOP_BUILDDIR}/tools/nut-scanner/nut-scanner" ] \ ; then log_warn "SKIP: ${TOP_BUILDDIR}/tools/nut-scanner/nut-scanner: Not found" return 1 fi return 0 } testcase_sandbox_nutscanner_list() { isTestableNutScanner || return 0 log_separator log_info "[testcase_sandbox_nutscanner_list] Call libupsclient test suite: nut-scanner on localhost:${NUT_PORT}" log_info "[testcase_sandbox_nutscanner_list] Preparing LD_LIBRARY_PATH='${LD_LIBRARY_PATH_CLIENT}'" # Note: for some reason `LD_LIBRARY_PATH=... runcmd ...` loses it :\ LD_LIBRARY_PATH="${LD_LIBRARY_PATH_CLIENT}" export LD_LIBRARY_PATH # NOTE: Currently mask mode is IPv4 only runcmd "${TOP_BUILDDIR}/tools/nut-scanner/nut-scanner" -m 127.0.0.1/32 -O -p "${NUT_PORT}" \ && test -n "$CMDOUT" \ || runcmd "${TOP_BUILDDIR}/tools/nut-scanner/nut-scanner" -s localhost -O -p "${NUT_PORT}" LD_LIBRARY_PATH="${LD_LIBRARY_PATH_ORIG}" export LD_LIBRARY_PATH log_info "[testcase_sandbox_nutscanner_list] findings from nut-scanner:" echo "$CMDOUT" log_info "[testcase_sandbox_nutscanner_list] inspecting these findings from nut-scanner..." # Note: the reported "driver" string is not too helpful as a "nutclient". # In practice this could be a "dummy-ups" repeater or "clone" driver, # or some of the config elements needed for upsmon (lacking creds/role) if ( test -n "$CMDOUT" \ && echo "$CMDOUT" | grep -E '^\[nutdev1\]$' \ && echo "$CMDOUT" | grep 'port = "dummy@' \ || return if [ "${NUT_PORT}" = 3493 ] || [ x"$NUT_PORT" = x ]; then log_info "[testcase_sandbox_nutscanner_list] Note: not testing for suffixed port number" >&2 else echo "$CMDOUT" | grep -E 'dummy@.*'":${NUT_PORT}" \ || { log_error "[testcase_sandbox_nutscanner_list] dummy@... not found" >&2 return 1 } fi if [ x"${TOP_SRCDIR}" = x ]; then log_info "[testcase_sandbox_nutscanner_list] Note: only testing one dummy device" >&2 else echo "$CMDOUT" | grep -E '^\[nutdev2\]$' \ && echo "$CMDOUT" | grep 'port = "UPS1@' \ && echo "$CMDOUT" | grep -E '^\[nutdev3\]$' \ && echo "$CMDOUT" | grep 'port = "UPS2@' \ || { log_error "[testcase_sandbox_nutscanner_list] something about UPS1/UPS2 not found" >&2 return 1 } fi if [ x"${TOP_SRCDIR}" = x ]; then PORTS_WANT=1 else PORTS_WANT=3 fi PORTS_SEEN="`echo "$CMDOUT" | grep -Ec 'port *='`" if [ "$PORTS_WANT" != "$PORTS_SEEN" ]; then log_error "[testcase_sandbox_nutscanner_list] Too many 'port=' lines: want $PORTS_WANT != seen $PORTS_SEEN" >&2 return 1 fi ) >/dev/null ; then log_info "[testcase_sandbox_nutscanner_list] PASSED: nut-scanner found all expected devices" PASSED="`expr $PASSED + 1`" else if ( echo "$CMDERR" | grep -E "Cannot load NUT library.*libupsclient.*found.*NUT search disabled" ) ; then log_warn "[testcase_sandbox_nutscanner_list] SKIP: ${TOP_BUILDDIR}/tools/nut-scanner/nut-scanner: $CMDERR" else log_error "[testcase_sandbox_nutscanner_list] nut-scanner complained or did not return all expected data, check above" FAILED="`expr $FAILED + 1`" FAILED_FUNCS="$FAILED_FUNCS testcase_sandbox_nutscanner_list" fi fi } testcases_sandbox_nutscanner() { isTestableNutScanner || return 0 testcase_sandbox_nutscanner_list } #################################### # TODO: Some upsmon tests? #################################### testgroup_sandbox() { testcase_sandbox_start_drivers_after_upsd testcase_sandbox_upsc_query_model testcase_sandbox_upsc_query_bogus testcase_sandbox_upsc_query_timer testcases_sandbox_python testcases_sandbox_cppnit testcases_sandbox_nutscanner log_separator sandbox_forget_configs } testgroup_sandbox_python() { # Arrange for quick test iterations testcase_sandbox_start_drivers_after_upsd testcases_sandbox_python log_separator sandbox_forget_configs } testgroup_sandbox_cppnit() { # Arrange for quick test iterations testcase_sandbox_start_drivers_after_upsd testcases_sandbox_cppnit log_separator sandbox_forget_configs } testgroup_sandbox_cppnit_simple_admin() { # Arrange for quick test iterations testcase_sandbox_start_drivers_after_upsd testcase_sandbox_cppnit_simple_admin log_separator sandbox_forget_configs } testgroup_sandbox_nutscanner() { # Arrange for quick test iterations testcase_sandbox_start_drivers_after_upsd testcases_sandbox_nutscanner log_separator sandbox_forget_configs } ################################################################ case "${NIT_CASE}" in cppnit) testgroup_sandbox_cppnit ;; python) testgroup_sandbox_python ;; nutscanner|nut-scanner) testgroup_sandbox_nutscanner ;; testcase_*|testgroup_*|testcases_*|testgroups_*) log_warn "========================================================" log_warn "You asked to run just a specific testcase* or testgroup*" log_warn "Be sure to have previously run with DEBUG_SLEEP and" log_warn " have exported the NUT_PORT upsd is listening on!" log_warn "========================================================" "${NIT_CASE}" ;; "") # Default test groups: testgroup_upsd_invalid_configs testgroup_upsd_questionable_configs testgroup_sandbox ;; *) die "Unsupported NIT_CASE='$NIT_CASE' was requested" ;; esac log_separator log_info "OVERALL: PASSED=$PASSED FAILED=$FAILED" if [ -n "$FAILED_FUNCS" ]; then for F in $FAILED_FUNCS ; do echo "$F" ; done | sort | uniq -c fi # Allow to leave the sandbox daemons running for a while, # to experiment with them interactively: if [ -n "${DEBUG_SLEEP-}" ] ; then if [ "${DEBUG_SLEEP-}" -gt 0 ] ; then : ; else DEBUG_SLEEP=60 fi log_separator log_info "Sleeping now as asked (for ${DEBUG_SLEEP} seconds starting `date -u`), so you can play with the driver and server running; hint: export NUT_PORT=$NUT_PORT" log_separator sleep "${DEBUG_SLEEP}" log_info "Sleep finished" log_separator fi stop_daemons if [ "$PASSED" = 0 ] || [ "$FAILED" != 0 ] ; then die "Some test scenarios failed!" else log_info "SUCCESS" fi nut-2.8.1/tests/NIT/Makefile.am0000644000175000017500000000155414501607135013110 00000000000000EXTRA_DIST = nit.sh README if WITH_CHECK_NIT check: check-NIT else check: @echo "NO-OP: $@ in `pwd` is inactive by default. Run 'configure --enable-check-NIT' or 'make check-NIT' explicitly" >&2 endif # Run in builddir, use script from srcdir # Avoid running "$<" - not all make implementations handle that check-NIT: $(abs_srcdir)/nit.sh "$(abs_srcdir)/nit.sh" # Make sure pre-requisites for NIT are fresh as we iterate check-NIT-devel: $(abs_srcdir)/nit.sh @cd .. && ( $(MAKE) -s cppnit$(EXEEXT) || echo "OPTIONAL C++ test client test will be skipped" ) @cd "$(top_builddir)/clients" && $(MAKE) -s upsc$(EXEEXT) upsrw$(EXEEXT) upsmon$(EXEEXT) @cd "$(top_builddir)/server" && $(MAKE) -s upsd$(EXEEXT) @cd "$(top_builddir)/drivers" && $(MAKE) -s dummy-ups$(EXEEXT) @$(MAKE) check-NIT MAINTAINERCLEANFILES = Makefile.in .dirstamp clean-local: $(AM_V_at)rm -rf tmp nut-2.8.1/tests/NIT/README0000644000175000017500000000156614501607135011737 00000000000000NUT Integration Testing suite ============================= This suite aims to simplify running `upsd`, a `dummy-ups` driver and a few clients to query them, as part of regular `make check` routine or separately with existing binaries (should not impact any existing installation data, processes or communications). WARNING: Current working directory when starting the script should be the location where it may create temporary data (e.g. the BUILDDIR). See also link:https://git.launchpad.net/ubuntu/+source/nut/tree/debian/tests/test-nut.py[The NUT testing script] available in the link:https://code.edge.launchpad.net/qa-regression-testing[Ubuntu QA Regression Testing suite] and link:https://salsa.debian.org/debian/nut/-/tree/debian/debian/tests[Debian packaging recipe] doing a similar job with NUT installed from packages and configuring it via files in standard path names. nut-2.8.1/tests/generic_gpio_utest.h0000644000175000017500000000241314501607135014444 00000000000000/* generic_gpio_utest.h - unit tests for gpiod based NUT driver definitions * for GPIO attached UPS devices * * Copyright (C) * 2023 Modris Berzonis * 2023 Jim Klimov * * 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 2 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, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #ifndef GENERIC_GPIO_UTEST_H #define GENERIC_GPIO_UTEST_H #include "generic_gpio_common.h" #include "generic_gpio_libgpiod.h" void setNextLinesReadToFail(void); void getWithoutUnderscores(char *var); int get_test_status(struct gpioups_t *result, int on_fail_path); #endif /* GENERIC_GPIO_UTEST_H */ nut-2.8.1/tests/example.cpp0000644000175000017500000000430214500336654012557 00000000000000/* example - CppUnit unit test example Copyright (C) 2012 Emilien Kia 2020 Jim Klimov 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 2 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, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "common.h" /* Current CPPUnit offends the honor of C++98 */ #if (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_PUSH_POP) && (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_EXIT_TIME_DESTRUCTORS || defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_GLOBAL_CONSTRUCTORS) #pragma GCC diagnostic push # ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_GLOBAL_CONSTRUCTORS # pragma GCC diagnostic ignored "-Wglobal-constructors" # endif # ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_EXIT_TIME_DESTRUCTORS # pragma GCC diagnostic ignored "-Wexit-time-destructors" # endif #endif #include class ExampleTest : public CppUnit::TestFixture { CPPUNIT_TEST_SUITE( ExampleTest ); CPPUNIT_TEST( testOne ); CPPUNIT_TEST_SUITE_END(); public: void setUp() override; void tearDown() override; void testOne(); }; // Registers the fixture into the 'registry' CPPUNIT_TEST_SUITE_REGISTRATION( ExampleTest ); void ExampleTest::setUp() { } void ExampleTest::tearDown() { } void ExampleTest::testOne() { // Set up int i = 1; float f = 1.0; // Process int cast = static_cast(f); // Check CPPUNIT_ASSERT_EQUAL( i, cast ); } #if (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_PUSH_POP) && (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_EXIT_TIME_DESTRUCTORS || defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_GLOBAL_CONSTRUCTORS) #pragma GCC diagnostic pop #endif nut-2.8.1/tests/generic_gpio_liblocal.c0000644000175000017500000000626514506754403015073 00000000000000/* generic_gpio_libglocal.c - gpio device emulation library for GPIO attached UPS devices * * Copyright (C) * 2023 Modris Berzonis * * 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 2 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, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #include "common.h" #include #include #include "generic_gpio_utest.h" static char chipName[NUT_GPIO_CHIPNAMEBUF]; static unsigned int num_lines=0; struct gpiod_chip *gpiod_chip_open_by_name(const char *name) { strcpy(chipName, name); if(strcmp(name, "gpiochip1")) return (struct gpiod_chip *)1; else { errno = EACCES; return NULL; } } unsigned int gpiod_chip_num_lines(struct gpiod_chip *chip) { NUT_UNUSED_VARIABLE(chip); if(!strcmp(chipName, "gpiochip2")) return 2; return 32; } int gpiod_chip_get_lines(struct gpiod_chip *chip, unsigned int *offsets, unsigned int num_offsets, struct gpiod_line_bulk *bulk) { NUT_UNUSED_VARIABLE(chip); NUT_UNUSED_VARIABLE(offsets); NUT_UNUSED_VARIABLE(bulk); num_lines=num_offsets; return 0; } int gpiod_line_request_bulk(struct gpiod_line_bulk *bulk, const struct gpiod_line_request_config *config, const int *default_vals) { NUT_UNUSED_VARIABLE(bulk); NUT_UNUSED_VARIABLE(config); NUT_UNUSED_VARIABLE(default_vals); return 0; } static int gStatus = 0; static int errReqFor_line_get_value_bulk=0; void setNextLinesReadToFail(void) { errReqFor_line_get_value_bulk=1; } int gpiod_line_get_value_bulk(struct gpiod_line_bulk *bulk, int *values) { int pinPos = 1; NUT_UNUSED_VARIABLE(bulk); if(errReqFor_line_get_value_bulk) { errReqFor_line_get_value_bulk=0; errno = EPERM; return -1; } for(unsigned int i=0; i * * 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 2 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, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #include "config.h" #include "common.h" #include "nut_stdint.h" #include "nut_float.h" #include #include static int check_difftime(void) { time_t tv1, tv2; double d1, d2; int res = 0; printf("=== %s(time_t):\t", __func__); /* Often time_t is a long int, maybe signed */ tv1 = 5; printf(" tv1=%" PRIiMAX, (intmax_t)tv1); tv2 = 8; printf(" tv2=%" PRIiMAX, (intmax_t)tv2); /* like in difftime(): (double)seconds elapsed time between older tv2 and newer tv1 */ d1 = difftime(tv1, tv2); if (!d_equal(d1, -3)) res++; printf(" => diff1(tv1, tv2)=%f (%s)", d1, d_equal(d1, -3) ? "OK" : "FAIL"); d2 = difftime(tv2, tv1); if (!d_equal(d2, 3)) res++; printf(" => diff2(tv2, tv1)=%f (%s)", d2, d_equal(d2, 3) ? "OK" : "FAIL"); if (!d_equal(d1, -d2)) { printf(" => diff1 != -diff2 (FAIL)\n"); res++; } else { printf(" => diff1 == -diff2 (OK)\n"); } return res; } static int check_difftimeval(void) { struct timeval tv1, tv2; double d1, d2; int res = 0; printf("=== %s(struct timeval):\t", __func__); tv1.tv_sec = 5; tv1.tv_usec = 900000; printf(" tv1=%" PRIiMAX ".%06" PRIiMAX, (intmax_t)tv1.tv_sec, (intmax_t)tv1.tv_usec); tv2.tv_sec = 8; tv2.tv_usec = 230000; printf(" tv2=%" PRIiMAX ".%06" PRIiMAX, (intmax_t)tv2.tv_sec, (intmax_t)tv2.tv_usec); /* like in difftime(): (double)seconds elapsed time between older tv2 and newer tv1 */ d1 = difftimeval(tv1, tv2); if (!d_equal(d1, -2.33)) res++; printf(" => diff1(tv1, tv2)=%f (%s)", d1, d_equal(d1, -2.33) ? "OK" : "FAIL"); d2 = difftimeval(tv2, tv1); if (!d_equal(d2, 2.33)) res++; printf(" => diff2(tv2, tv1)=%f (%s)", d2, d_equal(d2, 2.33) ? "OK" : "FAIL"); if (!d_equal(d1, -d2)) { printf(" => diff1 != -diff2 (FAIL)\n"); res++; } else { printf(" => diff1 == -diff2 (OK)\n"); } return res; } static int check_difftimespec(void) { int res = 0; #if defined(HAVE_CLOCK_GETTIME) && defined(HAVE_CLOCK_MONOTONIC) && HAVE_CLOCK_GETTIME && HAVE_CLOCK_MONOTONIC struct timespec tv1, tv2; double d1, d2; printf("=== %s(struct timespec):\t", __func__); tv1.tv_sec = 5; tv1.tv_nsec = 900000000; printf(" tv1=%" PRIiMAX ".%09" PRIiMAX, (intmax_t)tv1.tv_sec, (intmax_t)tv1.tv_nsec); tv2.tv_sec = 8; tv2.tv_nsec = 230000; printf(" tv2=%" PRIiMAX ".%09" PRIiMAX, (intmax_t)tv2.tv_sec, (intmax_t)tv2.tv_nsec); /* like in difftime(): (double)seconds elapsed time between older tv2 and newer tv1 */ d1 = difftimespec(tv1, tv2); if (!d_equal(d1, -2.10023)) res++; printf(" => diff1(tv1, tv2)=%f (%s)", d1, d_equal(d1, -2.10023) ? "OK" : "FAIL"); d2 = difftimespec(tv2, tv1); if (!d_equal(d2, 2.10023)) res++; printf(" => diff2(tv2, tv1)=%f (%s)", d2, d_equal(d2, 2.10023) ? "OK" : "FAIL"); if (!d_equal(d1, -d2)) { printf(" => diff1 != -diff2 (FAIL)\n"); res++; } else { printf(" => diff1 == -diff2 (OK)\n"); } #else printf("=== %s(struct timespec):\tSKIP: NOT IMPLEMENTED for this build (not HAVE_CLOCK_GETTIME or not HAVE_CLOCK_MONOTONIC)\n", __func__); #endif return res; } int main(void) { int ret = 0; ret += check_difftime(); ret += check_difftimeval(); ret += check_difftimespec(); return (ret != 0); } nut-2.8.1/tests/Makefile.in0000644000175000017500000024375414520274663012510 00000000000000# Makefile.in generated by automake 1.16.5 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2021 Free Software Foundation, Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. @SET_MAKE@ # Network UPS Tools: tests VPATH = @srcdir@ am__is_gnu_make = { \ if test -z '$(MAKELEVEL)'; then \ false; \ elif test -n '$(MAKE_HOST)'; then \ true; \ elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \ true; \ else \ false; \ fi; \ } am__make_running_with_option = \ case $${target_option-} in \ ?) ;; \ *) echo "am__make_running_with_option: internal error: invalid" \ "target option '$${target_option-}' specified" >&2; \ exit 1;; \ esac; \ has_opt=no; \ sane_makeflags=$$MAKEFLAGS; \ if $(am__is_gnu_make); then \ sane_makeflags=$$MFLAGS; \ else \ case $$MAKEFLAGS in \ *\\[\ \ ]*) \ bs=\\; \ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ esac; \ fi; \ skip_next=no; \ strip_trailopt () \ { \ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ }; \ for flg in $$sane_makeflags; do \ test $$skip_next = yes && { skip_next=no; continue; }; \ case $$flg in \ *=*|--*) continue;; \ -*I) strip_trailopt 'I'; skip_next=yes;; \ -*I?*) strip_trailopt 'I';; \ -*O) strip_trailopt 'O'; skip_next=yes;; \ -*O?*) strip_trailopt 'O';; \ -*l) strip_trailopt 'l'; skip_next=yes;; \ -*l?*) strip_trailopt 'l';; \ -[dEDm]) skip_next=yes;; \ -[JT]) skip_next=yes;; \ esac; \ case $$flg in \ *$$target_option*) has_opt=yes; break;; \ esac; \ done; \ test $$has_opt = yes am__make_dryrun = (target_option=n; $(am__make_running_with_option)) am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkglibexecdir = $(libexecdir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ target_triplet = @target@ TESTS = $(am__append_3) nuttimetest$(EXEEXT) $(am__EXEEXT_1) \ $(am__EXEEXT_2) $(am__EXEEXT_4) check_PROGRAMS = $(am__EXEEXT_5) $(am__EXEEXT_6) @REQUIRE_NUT_STRARG_TRUE@am__append_1 = nutlogtest-nofail.sh @REQUIRE_NUT_STRARG_TRUE@am__append_2 = nutlogtest-nofail.sh nutlogtest$(EXEEXT) nutlogtest # NOTE: Keep the line above empty! @REQUIRE_NUT_STRARG_FALSE@am__append_3 = nutlogtest$(EXEEXT) @WITH_USB_TRUE@am__append_4 = getvaluetest @WITH_USB_FALSE@am__append_5 = getvaluetest.c hidparser.c @WITH_GPIO_TRUE@am__append_6 = gpiotest @WITH_GPIO_FALSE@am__append_7 = generic_gpio_utest.c generic_gpio_liblocal.c # Note: per configure script this "SHOULD" also assume # that we HAVE_CXX11 - but better have it explicit @HAVE_CPPUNIT_TRUE@@HAVE_CXX11_TRUE@am__append_8 = $(TESTS_CXX11) # Note: we only build it, but do not run directly (NIT prepares the sandbox) @HAVE_CPPUNIT_TRUE@@HAVE_CXX11_TRUE@am__append_9 = cppnit # Just redistribute test source into tarball if not building tests @HAVE_CPPUNIT_FALSE@@HAVE_CXX11_TRUE@am__append_10 = $(CPPUNITTESTSRC) $(CPPCLIENTTESTSRC) $(CPPUNITTESTERSRC) # Just redistribute test source into tarball if not building C++ at all @HAVE_CXX11_FALSE@am__append_11 = $(CPPUNITTESTSRC) $(CPPCLIENTTESTSRC) $(CPPUNITTESTERSRC) subdir = tests ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/m4/ax_c___attribute__.m4 \ $(top_srcdir)/m4/ax_c_pragmas.m4 \ $(top_srcdir)/m4/ax_check_compile_flag.m4 \ $(top_srcdir)/m4/ax_compare_version.m4 \ $(top_srcdir)/m4/ax_realpath.m4 \ $(top_srcdir)/m4/ax_run_or_link_ifelse.m4 \ $(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \ $(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \ $(top_srcdir)/m4/lt~obsolete.m4 \ $(top_srcdir)/m4/nut_arg_with.m4 \ $(top_srcdir)/m4/nut_check_asciidoc.m4 \ $(top_srcdir)/m4/nut_check_aspell.m4 \ $(top_srcdir)/m4/nut_check_cppcheck.m4 \ $(top_srcdir)/m4/nut_check_headers_windows.m4 \ $(top_srcdir)/m4/nut_check_libavahi.m4 \ $(top_srcdir)/m4/nut_check_libfreeipmi.m4 \ $(top_srcdir)/m4/nut_check_libgd.m4 \ $(top_srcdir)/m4/nut_check_libgpiod.m4 \ $(top_srcdir)/m4/nut_check_libltdl.m4 \ $(top_srcdir)/m4/nut_check_libmodbus.m4 \ $(top_srcdir)/m4/nut_check_libneon.m4 \ $(top_srcdir)/m4/nut_check_libnetsnmp.m4 \ $(top_srcdir)/m4/nut_check_libnss.m4 \ $(top_srcdir)/m4/nut_check_libopenssl.m4 \ $(top_srcdir)/m4/nut_check_libpowerman.m4 \ $(top_srcdir)/m4/nut_check_libregex.m4 \ $(top_srcdir)/m4/nut_check_libsystemd.m4 \ $(top_srcdir)/m4/nut_check_libusb.m4 \ $(top_srcdir)/m4/nut_check_libwrap.m4 \ $(top_srcdir)/m4/nut_check_os.m4 \ $(top_srcdir)/m4/nut_check_pkgconfig.m4 \ $(top_srcdir)/m4/nut_check_python.m4 \ $(top_srcdir)/m4/nut_check_socketlib.m4 \ $(top_srcdir)/m4/nut_compiler_family.m4 \ $(top_srcdir)/m4/nut_func_getnameinfo_argtypes.m4 \ $(top_srcdir)/m4/nut_report_feature.m4 \ $(top_srcdir)/m4/nut_stash_warnings.m4 \ $(top_srcdir)/m4/nut_type_socklen_t.m4 \ $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/include/config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = @WITH_USB_TRUE@am__EXEEXT_1 = getvaluetest$(EXEEXT) @WITH_GPIO_TRUE@am__EXEEXT_2 = gpiotest$(EXEEXT) am__EXEEXT_3 = cppunittest$(EXEEXT) @HAVE_CPPUNIT_TRUE@@HAVE_CXX11_TRUE@am__EXEEXT_4 = $(am__EXEEXT_3) am__EXEEXT_5 = $(am__append_3) nuttimetest$(EXEEXT) $(am__EXEEXT_1) \ $(am__EXEEXT_2) $(am__EXEEXT_4) @HAVE_CPPUNIT_TRUE@@HAVE_CXX11_TRUE@am__EXEEXT_6 = cppnit$(EXEEXT) am__cppnit_SOURCES_DIST = cpputest-client.cpp cpputest.cpp am__objects_1 = cppnit-cpputest-client.$(OBJEXT) am__objects_2 = cppnit-cpputest.$(OBJEXT) @HAVE_CPPUNIT_TRUE@@HAVE_CXX11_TRUE@am_cppnit_OBJECTS = \ @HAVE_CPPUNIT_TRUE@@HAVE_CXX11_TRUE@ $(am__objects_1) \ @HAVE_CPPUNIT_TRUE@@HAVE_CXX11_TRUE@ $(am__objects_2) cppnit_OBJECTS = $(am_cppnit_OBJECTS) @HAVE_CPPUNIT_TRUE@@HAVE_CXX11_TRUE@cppnit_DEPENDENCIES = $(top_builddir)/clients/libnutclient.la \ @HAVE_CPPUNIT_TRUE@@HAVE_CXX11_TRUE@ $(top_builddir)/clients/libnutclientstub.la AM_V_lt = $(am__v_lt_@AM_V@) am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@) am__v_lt_0 = --silent am__v_lt_1 = cppnit_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=link $(CXXLD) $(cppnit_CXXFLAGS) \ $(CXXFLAGS) $(cppnit_LDFLAGS) $(LDFLAGS) -o $@ am__cppunittest_SOURCES_DIST = example.cpp nutclienttest.cpp \ cpputest.cpp am__objects_3 = cppunittest-example.$(OBJEXT) \ cppunittest-nutclienttest.$(OBJEXT) am__objects_4 = cppunittest-cpputest.$(OBJEXT) @HAVE_CPPUNIT_TRUE@@HAVE_CXX11_TRUE@am_cppunittest_OBJECTS = \ @HAVE_CPPUNIT_TRUE@@HAVE_CXX11_TRUE@ $(am__objects_3) \ @HAVE_CPPUNIT_TRUE@@HAVE_CXX11_TRUE@ $(am__objects_4) cppunittest_OBJECTS = $(am_cppunittest_OBJECTS) @HAVE_CPPUNIT_TRUE@@HAVE_CXX11_TRUE@cppunittest_DEPENDENCIES = $(top_builddir)/clients/libnutclient.la \ @HAVE_CPPUNIT_TRUE@@HAVE_CXX11_TRUE@ $(top_builddir)/clients/libnutclientstub.la cppunittest_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=link $(CXXLD) $(cppunittest_CXXFLAGS) \ $(CXXFLAGS) $(cppunittest_LDFLAGS) $(LDFLAGS) -o $@ am__getvaluetest_SOURCES_DIST = getvaluetest.c @WITH_USB_TRUE@am_getvaluetest_OBJECTS = \ @WITH_USB_TRUE@ getvaluetest-getvaluetest.$(OBJEXT) @WITH_USB_TRUE@nodist_getvaluetest_OBJECTS = \ @WITH_USB_TRUE@ getvaluetest-hidparser.$(OBJEXT) getvaluetest_OBJECTS = $(am_getvaluetest_OBJECTS) \ $(nodist_getvaluetest_OBJECTS) @WITH_USB_TRUE@getvaluetest_DEPENDENCIES = \ @WITH_USB_TRUE@ $(top_builddir)/common/libcommon.la getvaluetest_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(getvaluetest_CFLAGS) \ $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@ am__gpiotest_SOURCES_DIST = generic_gpio_utest.c \ generic_gpio_liblocal.c @WITH_GPIO_TRUE@am_gpiotest_OBJECTS = \ @WITH_GPIO_TRUE@ gpiotest-generic_gpio_utest.$(OBJEXT) \ @WITH_GPIO_TRUE@ gpiotest-generic_gpio_liblocal.$(OBJEXT) @WITH_GPIO_TRUE@nodist_gpiotest_OBJECTS = \ @WITH_GPIO_TRUE@ gpiotest-generic_gpio_libgpiod.$(OBJEXT) \ @WITH_GPIO_TRUE@ gpiotest-generic_gpio_common.$(OBJEXT) gpiotest_OBJECTS = $(am_gpiotest_OBJECTS) $(nodist_gpiotest_OBJECTS) @WITH_GPIO_TRUE@gpiotest_DEPENDENCIES = \ @WITH_GPIO_TRUE@ $(top_builddir)/drivers/libdummy_mockdrv.la gpiotest_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(gpiotest_CFLAGS) \ $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@ am_nutlogtest_OBJECTS = nutlogtest.$(OBJEXT) nutlogtest_OBJECTS = $(am_nutlogtest_OBJECTS) nutlogtest_DEPENDENCIES = $(top_builddir)/common/libcommon.la am_nuttimetest_OBJECTS = nuttimetest.$(OBJEXT) nuttimetest_OBJECTS = $(am_nuttimetest_OBJECTS) nuttimetest_DEPENDENCIES = $(top_builddir)/common/libcommon.la AM_V_P = $(am__v_P_@AM_V@) am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) am__v_P_0 = false am__v_P_1 = : AM_V_GEN = $(am__v_GEN_@AM_V@) am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) am__v_GEN_0 = @echo " GEN " $@; am__v_GEN_1 = AM_V_at = $(am__v_at_@AM_V@) am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) am__v_at_0 = @ am__v_at_1 = DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)/include depcomp = $(SHELL) $(top_srcdir)/depcomp am__maybe_remake_depfiles = depfiles am__depfiles_remade = ./$(DEPDIR)/cppnit-cpputest-client.Po \ ./$(DEPDIR)/cppnit-cpputest.Po \ ./$(DEPDIR)/cppunittest-cpputest.Po \ ./$(DEPDIR)/cppunittest-example.Po \ ./$(DEPDIR)/cppunittest-nutclienttest.Po \ ./$(DEPDIR)/getvaluetest-getvaluetest.Po \ ./$(DEPDIR)/getvaluetest-hidparser.Po \ ./$(DEPDIR)/gpiotest-generic_gpio_common.Po \ ./$(DEPDIR)/gpiotest-generic_gpio_libgpiod.Po \ ./$(DEPDIR)/gpiotest-generic_gpio_liblocal.Po \ ./$(DEPDIR)/gpiotest-generic_gpio_utest.Po \ ./$(DEPDIR)/nutlogtest.Po ./$(DEPDIR)/nuttimetest.Po am__mv = mv -f COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ $(AM_CFLAGS) $(CFLAGS) AM_V_CC = $(am__v_CC_@AM_V@) am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@) am__v_CC_0 = @echo " CC " $@; am__v_CC_1 = CCLD = $(CC) LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ $(AM_LDFLAGS) $(LDFLAGS) -o $@ AM_V_CCLD = $(am__v_CCLD_@AM_V@) am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@) am__v_CCLD_0 = @echo " CCLD " $@; am__v_CCLD_1 = CXXCOMPILE = $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \ $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) LTCXXCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) \ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ $(AM_CXXFLAGS) $(CXXFLAGS) AM_V_CXX = $(am__v_CXX_@AM_V@) am__v_CXX_ = $(am__v_CXX_@AM_DEFAULT_V@) am__v_CXX_0 = @echo " CXX " $@; am__v_CXX_1 = CXXLD = $(CXX) CXXLINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=link $(CXXLD) $(AM_CXXFLAGS) \ $(CXXFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@ AM_V_CXXLD = $(am__v_CXXLD_@AM_V@) am__v_CXXLD_ = $(am__v_CXXLD_@AM_DEFAULT_V@) am__v_CXXLD_0 = @echo " CXXLD " $@; am__v_CXXLD_1 = SOURCES = $(cppnit_SOURCES) $(cppunittest_SOURCES) \ $(getvaluetest_SOURCES) $(nodist_getvaluetest_SOURCES) \ $(gpiotest_SOURCES) $(nodist_gpiotest_SOURCES) \ $(nutlogtest_SOURCES) $(nuttimetest_SOURCES) DIST_SOURCES = $(am__cppnit_SOURCES_DIST) \ $(am__cppunittest_SOURCES_DIST) \ $(am__getvaluetest_SOURCES_DIST) $(am__gpiotest_SOURCES_DIST) \ $(nutlogtest_SOURCES) $(nuttimetest_SOURCES) RECURSIVE_TARGETS = all-recursive check-recursive cscopelist-recursive \ ctags-recursive dvi-recursive html-recursive info-recursive \ install-data-recursive install-dvi-recursive \ install-exec-recursive install-html-recursive \ install-info-recursive install-pdf-recursive \ install-ps-recursive install-recursive installcheck-recursive \ installdirs-recursive pdf-recursive ps-recursive \ tags-recursive uninstall-recursive am__can_run_installinfo = \ case $$AM_UPDATE_INFO_DIR in \ n|no|NO) false;; \ *) (install-info --version) >/dev/null 2>&1;; \ esac RECURSIVE_CLEAN_TARGETS = mostlyclean-recursive clean-recursive \ distclean-recursive maintainer-clean-recursive am__recursive_targets = \ $(RECURSIVE_TARGETS) \ $(RECURSIVE_CLEAN_TARGETS) \ $(am__extra_recursive_targets) AM_RECURSIVE_TARGETS = $(am__recursive_targets:-recursive=) TAGS CTAGS \ check recheck distdir distdir-am am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) # Read a list of newline-separated strings from the standard input, # and print each of them once, without duplicates. Input order is # *not* preserved. am__uniquify_input = $(AWK) '\ BEGIN { nonempty = 0; } \ { items[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in items) print i; }; } \ ' # Make sure the list of sources is unique. This is necessary because, # e.g., the same source file might be shared among _SOURCES variables # for different programs/libraries. am__define_uniq_tagged_files = \ list='$(am__tagged_files)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | $(am__uniquify_input)` am__tty_colors_dummy = \ mgn= red= grn= lgn= blu= brg= std=; \ am__color_tests=no am__tty_colors = { \ $(am__tty_colors_dummy); \ if test "X$(AM_COLOR_TESTS)" = Xno; then \ am__color_tests=no; \ elif test "X$(AM_COLOR_TESTS)" = Xalways; then \ am__color_tests=yes; \ elif test "X$$TERM" != Xdumb && { test -t 1; } 2>/dev/null; then \ am__color_tests=yes; \ fi; \ if test $$am__color_tests = yes; then \ red=''; \ grn=''; \ lgn=''; \ blu=''; \ mgn=''; \ brg=''; \ std=''; \ fi; \ } am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; am__vpath_adj = case $$p in \ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ *) f=$$p;; \ esac; am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`; am__install_max = 40 am__nobase_strip_setup = \ srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'` am__nobase_strip = \ for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||" am__nobase_list = $(am__nobase_strip_setup); \ for p in $$list; do echo "$$p $$p"; done | \ sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \ $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \ if (++n[$$2] == $(am__install_max)) \ { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \ END { for (dir in files) print dir, files[dir] }' am__base_list = \ sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' am__uninstall_files_from_dir = { \ test -z "$$files" \ || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \ || { echo " ( cd '$$dir' && rm -f" $$files ")"; \ $(am__cd) "$$dir" && rm -f $$files; }; \ } am__recheck_rx = ^[ ]*:recheck:[ ]* am__global_test_result_rx = ^[ ]*:global-test-result:[ ]* am__copy_in_global_log_rx = ^[ ]*:copy-in-global-log:[ ]* # A command that, given a newline-separated list of test names on the # standard input, print the name of the tests that are to be re-run # upon "make recheck". am__list_recheck_tests = $(AWK) '{ \ recheck = 1; \ while ((rc = (getline line < ($$0 ".trs"))) != 0) \ { \ if (rc < 0) \ { \ if ((getline line2 < ($$0 ".log")) < 0) \ recheck = 0; \ break; \ } \ else if (line ~ /$(am__recheck_rx)[nN][Oo]/) \ { \ recheck = 0; \ break; \ } \ else if (line ~ /$(am__recheck_rx)[yY][eE][sS]/) \ { \ break; \ } \ }; \ if (recheck) \ print $$0; \ close ($$0 ".trs"); \ close ($$0 ".log"); \ }' # A command that, given a newline-separated list of test names on the # standard input, create the global log from their .trs and .log files. am__create_global_log = $(AWK) ' \ function fatal(msg) \ { \ print "fatal: making $@: " msg | "cat >&2"; \ exit 1; \ } \ function rst_section(header) \ { \ print header; \ len = length(header); \ for (i = 1; i <= len; i = i + 1) \ printf "="; \ printf "\n\n"; \ } \ { \ copy_in_global_log = 1; \ global_test_result = "RUN"; \ while ((rc = (getline line < ($$0 ".trs"))) != 0) \ { \ if (rc < 0) \ fatal("failed to read from " $$0 ".trs"); \ if (line ~ /$(am__global_test_result_rx)/) \ { \ sub("$(am__global_test_result_rx)", "", line); \ sub("[ ]*$$", "", line); \ global_test_result = line; \ } \ else if (line ~ /$(am__copy_in_global_log_rx)[nN][oO]/) \ copy_in_global_log = 0; \ }; \ if (copy_in_global_log) \ { \ rst_section(global_test_result ": " $$0); \ while ((rc = (getline line < ($$0 ".log"))) != 0) \ { \ if (rc < 0) \ fatal("failed to read from " $$0 ".log"); \ print line; \ }; \ printf "\n"; \ }; \ close ($$0 ".trs"); \ close ($$0 ".log"); \ }' # Restructured Text title. am__rst_title = { sed 's/.*/ & /;h;s/./=/g;p;x;s/ *$$//;p;g' && echo; } # Solaris 10 'make', and several other traditional 'make' implementations, # pass "-e" to $(SHELL), and POSIX 2008 even requires this. Work around it # by disabling -e (using the XSI extension "set +e") if it's set. am__sh_e_setup = case $$- in *e*) set +e;; esac # Default flags passed to test drivers. am__common_driver_flags = \ --color-tests "$$am__color_tests" \ --enable-hard-errors "$$am__enable_hard_errors" \ --expect-failure "$$am__expect_failure" # To be inserted before the command running the test. Creates the # directory for the log if needed. Stores in $dir the directory # containing $f, in $tst the test, in $log the log. Executes the # developer- defined test setup AM_TESTS_ENVIRONMENT (if any), and # passes TESTS_ENVIRONMENT. Set up options for the wrapper that # will run the test scripts (or their associated LOG_COMPILER, if # thy have one). am__check_pre = \ $(am__sh_e_setup); \ $(am__vpath_adj_setup) $(am__vpath_adj) \ $(am__tty_colors); \ srcdir=$(srcdir); export srcdir; \ case "$@" in \ */*) am__odir=`echo "./$@" | sed 's|/[^/]*$$||'`;; \ *) am__odir=.;; \ esac; \ test "x$$am__odir" = x"." || test -d "$$am__odir" \ || $(MKDIR_P) "$$am__odir" || exit $$?; \ if test -f "./$$f"; then dir=./; \ elif test -f "$$f"; then dir=; \ else dir="$(srcdir)/"; fi; \ tst=$$dir$$f; log='$@'; \ if test -n '$(DISABLE_HARD_ERRORS)'; then \ am__enable_hard_errors=no; \ else \ am__enable_hard_errors=yes; \ fi; \ case " $(XFAIL_TESTS) " in \ *[\ \ ]$$f[\ \ ]* | *[\ \ ]$$dir$$f[\ \ ]*) \ am__expect_failure=yes;; \ *) \ am__expect_failure=no;; \ esac; \ $(AM_TESTS_ENVIRONMENT) $(TESTS_ENVIRONMENT) # A shell command to get the names of the tests scripts with any registered # extension removed (i.e., equivalently, the names of the test logs, with # the '.log' extension removed). The result is saved in the shell variable # '$bases'. This honors runtime overriding of TESTS and TEST_LOGS. Sadly, # we cannot use something simpler, involving e.g., "$(TEST_LOGS:.log=)", # since that might cause problem with VPATH rewrites for suffix-less tests. # See also 'test-harness-vpath-rewrite.sh' and 'test-trs-basic.sh'. am__set_TESTS_bases = \ bases='$(TEST_LOGS)'; \ bases=`for i in $$bases; do echo $$i; done | sed 's/\.log$$//'`; \ bases=`echo $$bases` AM_TESTSUITE_SUMMARY_HEADER = ' for $(PACKAGE_STRING)' RECHECK_LOGS = $(TEST_LOGS) TEST_SUITE_LOG = test-suite.log TEST_EXTENSIONS = @EXEEXT@ .test LOG_DRIVER = $(SHELL) $(top_srcdir)/test-driver LOG_COMPILE = $(LOG_COMPILER) $(AM_LOG_FLAGS) $(LOG_FLAGS) am__set_b = \ case '$@' in \ */*) \ case '$*' in \ */*) b='$*';; \ *) b=`echo '$@' | sed 's/\.log$$//'`; \ esac;; \ *) \ b='$*';; \ esac am__test_logs1 = $(TESTS:=.log) am__test_logs2 = $(am__test_logs1:@EXEEXT@.log=.log) TEST_LOGS = $(am__test_logs2:.test.log=.log) TEST_LOG_DRIVER = $(SHELL) $(top_srcdir)/test-driver TEST_LOG_COMPILE = $(TEST_LOG_COMPILER) $(AM_TEST_LOG_FLAGS) \ $(TEST_LOG_FLAGS) DIST_SUBDIRS = $(SUBDIRS) am__DIST_COMMON = $(srcdir)/Makefile.in $(top_srcdir)/depcomp \ $(top_srcdir)/test-driver DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) am__relativize = \ dir0=`pwd`; \ sed_first='s,^\([^/]*\)/.*$$,\1,'; \ sed_rest='s,^[^/]*/*,,'; \ sed_last='s,^.*/\([^/]*\)$$,\1,'; \ sed_butlast='s,/*[^/]*$$,,'; \ while test -n "$$dir1"; do \ first=`echo "$$dir1" | sed -e "$$sed_first"`; \ if test "$$first" != "."; then \ if test "$$first" = ".."; then \ dir2=`echo "$$dir0" | sed -e "$$sed_last"`/"$$dir2"; \ dir0=`echo "$$dir0" | sed -e "$$sed_butlast"`; \ else \ first2=`echo "$$dir2" | sed -e "$$sed_first"`; \ if test "$$first2" = "$$first"; then \ dir2=`echo "$$dir2" | sed -e "$$sed_rest"`; \ else \ dir2="../$$dir2"; \ fi; \ dir0="$$dir0"/"$$first"; \ fi; \ fi; \ dir1=`echo "$$dir1" | sed -e "$$sed_rest"`; \ done; \ reldir="$$dir2" A2X = @A2X@ ACLOCAL = @ACLOCAL@ ALTPIDPATH = @ALTPIDPATH@ AMTAR = @AMTAR@ AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ AR = @AR@ ASCIIDOC = @ASCIIDOC@ ASPELL = @ASPELL@ ASPELL_FILTER_LIB_PATH = @ASPELL_FILTER_LIB_PATH@ ASPELL_FILTER_SHARE_PATH = @ASPELL_FILTER_SHARE_PATH@ ASPELL_FILTER_TEX_PATH = @ASPELL_FILTER_TEX_PATH@ AUGPARSE = @AUGPARSE@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ BINDIR = @BINDIR@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CONFIG_FLAGS = @CONFIG_FLAGS@ CONFPATH = @CONFPATH@ CPP = @CPP@ CPPCHECK = @CPPCHECK@ CPPFLAGS = @CPPFLAGS@ CPPUNIT_CFLAGS = @CPPUNIT_CFLAGS@ CPPUNIT_LIBS = @CPPUNIT_LIBS@ CSCOPE = @CSCOPE@ CTAGS = @CTAGS@ CXX = @CXX@ CXXCPP = @CXXCPP@ CXXDEPMODE = @CXXDEPMODE@ CXXFLAGS = @CXXFLAGS@ CYGPATH_W = @CYGPATH_W@ DBLATEX = @DBLATEX@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ DEPLOYED_UPSC = @DEPLOYED_UPSC@ DEPLOYED_UPSD = @DEPLOYED_UPSD@ DLLTOOL = @DLLTOOL@ DOC_BUILD_LIST = @DOC_BUILD_LIST@ DOC_CHECK_LIST = @DOC_CHECK_LIST@ DRIVER_BUILD_LIST = @DRIVER_BUILD_LIST@ DRIVER_INSTALL_TARGET = @DRIVER_INSTALL_TARGET@ DRIVER_MAN_LIST = @DRIVER_MAN_LIST@ DRIVER_MAN_LIST_PAGES = @DRIVER_MAN_LIST_PAGES@ DRVPATH = @DRVPATH@ DSYMUTIL = @DSYMUTIL@ DUMPBIN = @DUMPBIN@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ ETAGS = @ETAGS@ EXEEXT = @EXEEXT@ FGREP = @FGREP@ FORCE_NUT_VERSION = @FORCE_NUT_VERSION@ GDLIB_CONFIG = @GDLIB_CONFIG@ GREP = @GREP@ HAVE_SYS_SOCKET_H = @HAVE_SYS_SOCKET_H@ HAVE_WINSOCK2_H = @HAVE_WINSOCK2_H@ HAVE_WS2TCPIP_H = @HAVE_WS2TCPIP_H@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ LD = @LD@ LDFLAGS = @LDFLAGS@ LIBAVAHI_CFLAGS = @LIBAVAHI_CFLAGS@ LIBAVAHI_LIBS = @LIBAVAHI_LIBS@ LIBDIR = @LIBDIR@ LIBGD_CFLAGS = @LIBGD_CFLAGS@ LIBGD_LDFLAGS = @LIBGD_LDFLAGS@ LIBGPIO_CFLAGS = @LIBGPIO_CFLAGS@ LIBGPIO_LIBS = @LIBGPIO_LIBS@ LIBI2C_LIBS = @LIBI2C_LIBS@ LIBIPMI_CFLAGS = @LIBIPMI_CFLAGS@ LIBIPMI_LIBS = @LIBIPMI_LIBS@ LIBLTDL_CFLAGS = @LIBLTDL_CFLAGS@ LIBLTDL_LIBS = @LIBLTDL_LIBS@ LIBMODBUS_CFLAGS = @LIBMODBUS_CFLAGS@ LIBMODBUS_LIBS = @LIBMODBUS_LIBS@ LIBNEON_CFLAGS = @LIBNEON_CFLAGS@ LIBNEON_LIBS = @LIBNEON_LIBS@ LIBNETSNMP_CFLAGS = @LIBNETSNMP_CFLAGS@ LIBNETSNMP_LIBS = @LIBNETSNMP_LIBS@ LIBOBJS = @LIBOBJS@ LIBPOWERMAN_CFLAGS = @LIBPOWERMAN_CFLAGS@ LIBPOWERMAN_LIBS = @LIBPOWERMAN_LIBS@ LIBREGEX_LIBS = @LIBREGEX_LIBS@ LIBS = @LIBS@ LIBSSL_CFLAGS = @LIBSSL_CFLAGS@ LIBSSL_LIBS = @LIBSSL_LIBS@ LIBSSL_REQUIRES = @LIBSSL_REQUIRES@ LIBSYSTEMD_CFLAGS = @LIBSYSTEMD_CFLAGS@ LIBSYSTEMD_LIBS = @LIBSYSTEMD_LIBS@ LIBTOOL = @LIBTOOL@ LIBTOOL_DEPS = @LIBTOOL_DEPS@ LIBUSB_CFLAGS = @LIBUSB_CFLAGS@ LIBUSB_CONFIG = @LIBUSB_CONFIG@ LIBUSB_LIBS = @LIBUSB_LIBS@ LIBWRAP_CFLAGS = @LIBWRAP_CFLAGS@ LIBWRAP_LIBS = @LIBWRAP_LIBS@ LIPO = @LIPO@ LN_S = @LN_S@ LN_S_R = @LN_S_R@ LTLIBOBJS = @LTLIBOBJS@ LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@ MAINT = @MAINT@ MAKEINFO = @MAKEINFO@ MANIFEST_TOOL = @MANIFEST_TOOL@ MKDIR_P = @MKDIR_P@ MSGFMT = @MSGFMT@ NETLIBS = @NETLIBS@ NET_SNMP_CONFIG = @NET_SNMP_CONFIG@ NM = @NM@ NMEDIT = @NMEDIT@ NUT_DATADIR = @NUT_DATADIR@ NUT_LIBEXECDIR = @NUT_LIBEXECDIR@ NUT_NETVERSION = @NUT_NETVERSION@ NUT_SOURCE_GITREV = @NUT_SOURCE_GITREV@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ OS_NAME = @OS_NAME@ OTOOL = @OTOOL@ OTOOL64 = @OTOOL64@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_SEPARATOR = @PATH_SEPARATOR@ PIDPATH = @PIDPATH@ PKGCONFIGDIR = @PKGCONFIGDIR@ PKG_CONFIG = @PKG_CONFIG@ PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@ PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ PORT = @PORT@ POWERDOWNFLAG = @POWERDOWNFLAG@ PREFIX = @PREFIX@ PYTHON = @PYTHON@ PYTHON2 = @PYTHON2@ PYTHON2_SITE_PACKAGES = @PYTHON2_SITE_PACKAGES@ PYTHON3 = @PYTHON3@ PYTHON3_SITE_PACKAGES = @PYTHON3_SITE_PACKAGES@ PYTHON_SITE_PACKAGES = @PYTHON_SITE_PACKAGES@ RANLIB = @RANLIB@ REALPATH = @REALPATH@ RUN_AS_GROUP = @RUN_AS_GROUP@ RUN_AS_USER = @RUN_AS_USER@ SBINDIR = @SBINDIR@ SED = @SED@ SEMLIBS = @SEMLIBS@ SERLIBS = @SERLIBS@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ SOURCE_HIGHLIGHT = @SOURCE_HIGHLIGHT@ STATEPATH = @STATEPATH@ STRIP = @STRIP@ SUN_LIBUSB = @SUN_LIBUSB@ SYSTEMD_ANALYZE_PROGRAM = @SYSTEMD_ANALYZE_PROGRAM@ SYSTEMD_DAEMON_ARGS_DRIVER = @SYSTEMD_DAEMON_ARGS_DRIVER@ SYSTEMD_DAEMON_ARGS_UPSD = @SYSTEMD_DAEMON_ARGS_UPSD@ SYSTEMD_DAEMON_ARGS_UPSMON = @SYSTEMD_DAEMON_ARGS_UPSMON@ SYSTEMD_DAEMON_NOTIFYACCESS_DRIVER = @SYSTEMD_DAEMON_NOTIFYACCESS_DRIVER@ SYSTEMD_DAEMON_NOTIFYACCESS_UPSD = @SYSTEMD_DAEMON_NOTIFYACCESS_UPSD@ SYSTEMD_DAEMON_NOTIFYACCESS_UPSMON = @SYSTEMD_DAEMON_NOTIFYACCESS_UPSMON@ SYSTEMD_DAEMON_TYPE_DRIVER = @SYSTEMD_DAEMON_TYPE_DRIVER@ SYSTEMD_DAEMON_TYPE_UPSD = @SYSTEMD_DAEMON_TYPE_UPSD@ SYSTEMD_DAEMON_TYPE_UPSMON = @SYSTEMD_DAEMON_TYPE_UPSMON@ SYSTEMD_DAEMON_WATCHDOG_DRIVER = @SYSTEMD_DAEMON_WATCHDOG_DRIVER@ SYSTEMD_DAEMON_WATCHDOG_UPSD = @SYSTEMD_DAEMON_WATCHDOG_UPSD@ SYSTEMD_DAEMON_WATCHDOG_UPSMON = @SYSTEMD_DAEMON_WATCHDOG_UPSMON@ SYSTEMD_TMPFILES_PROGRAM = @SYSTEMD_TMPFILES_PROGRAM@ TREE_VERSION = @TREE_VERSION@ VALGRIND = @VALGRIND@ VERSION = @VERSION@ WINDMC = @WINDMC@ WINDRES = @WINDRES@ WORDS_BIGENDIAN = @WORDS_BIGENDIAN@ XMLLINT = @XMLLINT@ XSLTPROC = @XSLTPROC@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_AR = @ac_ct_AR@ ac_ct_CC = @ac_ct_CC@ ac_ct_CXX = @ac_ct_CXX@ ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__tar = @am__tar@ am__untar = @am__untar@ auglensdir = @auglensdir@ bindir = @bindir@ build = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ cgiexecdir = @cgiexecdir@ datadir = @datadir@ datarootdir = @datarootdir@ devddir = @devddir@ docdir = @docdir@ driverexecdir = @driverexecdir@ dummy_PKG_CONFIG = @dummy_PKG_CONFIG@ dummy_PKG_CONFIG_CFLAGS = @dummy_PKG_CONFIG_CFLAGS@ dummy_PKG_CONFIG_LIBS = @dummy_PKG_CONFIG_LIBS@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ hotplugdir = @hotplugdir@ htmldir = @htmldir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libdir = @libdir@ libexecdir = @libexecdir@ localedir = @localedir@ localstatedir = @localstatedir@ mandir = @mandir@ mkdir_p = @mkdir_p@ now = @now@ nut_with_nut_monitor = @nut_with_nut_monitor@ nut_with_nut_monitor_desktop = @nut_with_nut_monitor_desktop@ nut_with_nut_monitor_dir = @nut_with_nut_monitor_dir@ nut_with_nut_monitor_py2gtk2 = @nut_with_nut_monitor_py2gtk2@ nut_with_nut_monitor_py3qt5 = @nut_with_nut_monitor_py3qt5@ nut_with_pynut = @nut_with_pynut@ nut_with_pynut_py = @nut_with_pynut_py@ nut_with_pynut_py2 = @nut_with_pynut_py2@ nut_with_pynut_py3 = @nut_with_pynut_py3@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ pkgconfigdir = @pkgconfigdir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ runstatedir = @runstatedir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ sysconfdir = @sysconfdir@ systemdshutdowndir = @systemdshutdowndir@ systemdsystemunitdir = @systemdsystemunitdir@ systemdtmpfilesdir = @systemdtmpfilesdir@ target = @target@ target_alias = @target_alias@ target_cpu = @target_cpu@ target_os = @target_os@ target_vendor = @target_vendor@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ udevdir = @udevdir@ SUBDIRS = . NIT EXTRA_DIST = nut-driver-enumerator-test.sh \ nut-driver-enumerator-test--ups.conf $(am__append_5) \ $(am__append_7) generic_gpio_utest.h generic_gpio_test.txt \ $(am__append_10) $(am__append_11) CLEANFILES = *.trs *.log $(am__append_2) generic_gpio_libgpiod.c \ generic_gpio_common.c $(LINKED_SOURCE_FILES) $(TESTS) \ $(TESTS_CXX11) AM_CFLAGS = -I$(top_srcdir)/include -I$(top_srcdir)/drivers AM_CXXFLAGS = -I$(top_srcdir)/include check_SCRIPTS = $(am__append_1) nutlogtest_SOURCES = nutlogtest.c nutlogtest_LDADD = $(top_builddir)/common/libcommon.la nuttimetest_SOURCES = nuttimetest.c nuttimetest_LDADD = $(top_builddir)/common/libcommon.la # Separate the .deps of other dirs from this one LINKED_SOURCE_FILES = hidparser.c @WITH_USB_TRUE@getvaluetest_SOURCES = getvaluetest.c @WITH_USB_TRUE@nodist_getvaluetest_SOURCES = hidparser.c # Pull the right include path for chosen libusb version: @WITH_USB_TRUE@getvaluetest_CFLAGS = $(AM_CFLAGS) $(LIBUSB_CFLAGS) @WITH_USB_TRUE@getvaluetest_LDADD = $(top_builddir)/common/libcommon.la @WITH_GPIO_TRUE@gpiotest_SOURCES = generic_gpio_utest.c generic_gpio_liblocal.c @WITH_GPIO_TRUE@nodist_gpiotest_SOURCES = generic_gpio_libgpiod.c generic_gpio_common.c @WITH_GPIO_TRUE@gpiotest_LDADD = $(top_builddir)/drivers/libdummy_mockdrv.la @WITH_GPIO_TRUE@gpiotest_CFLAGS = $(AM_CFLAGS) -I$(top_srcdir)/tests -DDRIVERS_MAIN_WITHOUT_MAIN=1 ### Optional tests which can not be built everywhere # List of src files for CppUnit tests CPPUNITTESTSRC = example.cpp nutclienttest.cpp # The test driver which orchestrates running those tests above CPPUNITTESTERSRC = cpputest.cpp CPPCLIENTTESTSRC = cpputest-client.cpp TESTS_CXX11 = cppunittest @HAVE_CPPUNIT_TRUE@@HAVE_CXX11_TRUE@cppunittest_CXXFLAGS = $(AM_CXXFLAGS) $(CPPUNIT_CFLAGS) $(CPPUNIT_CXXFLAGS) $(CPPUNIT_NUT_CXXFLAGS) $(CXXFLAGS) @HAVE_CPPUNIT_TRUE@@HAVE_CXX11_TRUE@cppunittest_LDFLAGS = $(CPPUNIT_LDFLAGS) $(CPPUNIT_LIBS) @HAVE_CPPUNIT_TRUE@@HAVE_CXX11_TRUE@cppunittest_LDADD = $(top_builddir)/clients/libnutclient.la $(top_builddir)/clients/libnutclientstub.la @HAVE_CPPUNIT_TRUE@@HAVE_CXX11_TRUE@cppunittest_SOURCES = $(CPPUNITTESTSRC) $(CPPUNITTESTERSRC) @HAVE_CPPUNIT_TRUE@@HAVE_CXX11_TRUE@cppnit_CXXFLAGS = $(AM_CXXFLAGS) $(CPPUNIT_CFLAGS) $(CPPUNIT_CXXFLAGS) $(CPPUNIT_NUT_CXXFLAGS) $(CXXFLAGS) @HAVE_CPPUNIT_TRUE@@HAVE_CXX11_TRUE@cppnit_LDFLAGS = $(CPPUNIT_LDFLAGS) $(CPPUNIT_LIBS) @HAVE_CPPUNIT_TRUE@@HAVE_CXX11_TRUE@cppnit_LDADD = $(top_builddir)/clients/libnutclient.la $(top_builddir)/clients/libnutclientstub.la @HAVE_CPPUNIT_TRUE@@HAVE_CXX11_TRUE@cppnit_SOURCES = $(CPPCLIENTTESTSRC) $(CPPUNITTESTERSRC) BUILT_SOURCES = $(LINKED_SOURCE_FILES) MAINTAINERCLEANFILES = Makefile.in .dirstamp all: $(BUILT_SOURCES) $(MAKE) $(AM_MAKEFLAGS) all-recursive .SUFFIXES: .SUFFIXES: .c .cpp .lo .log .o .obj .test .test$(EXEEXT) .trs $(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu tests/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --gnu tests/Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): clean-checkPROGRAMS: @list='$(check_PROGRAMS)'; test -n "$$list" || exit 0; \ echo " rm -f" $$list; \ rm -f $$list || exit $$?; \ test -n "$(EXEEXT)" || exit 0; \ list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \ echo " rm -f" $$list; \ rm -f $$list @HAVE_CPPUNIT_TRUE@@HAVE_CXX11_TRUE@cppnit$(EXEEXT): $(cppnit_OBJECTS) $(cppnit_DEPENDENCIES) $(EXTRA_cppnit_DEPENDENCIES) @HAVE_CPPUNIT_TRUE@@HAVE_CXX11_TRUE@ @rm -f cppnit$(EXEEXT) @HAVE_CPPUNIT_TRUE@@HAVE_CXX11_TRUE@ $(AM_V_CXXLD)$(cppnit_LINK) $(cppnit_OBJECTS) $(cppnit_LDADD) $(LIBS) cppunittest$(EXEEXT): $(cppunittest_OBJECTS) $(cppunittest_DEPENDENCIES) $(EXTRA_cppunittest_DEPENDENCIES) @rm -f cppunittest$(EXEEXT) $(AM_V_CXXLD)$(cppunittest_LINK) $(cppunittest_OBJECTS) $(cppunittest_LDADD) $(LIBS) getvaluetest$(EXEEXT): $(getvaluetest_OBJECTS) $(getvaluetest_DEPENDENCIES) $(EXTRA_getvaluetest_DEPENDENCIES) @rm -f getvaluetest$(EXEEXT) $(AM_V_CCLD)$(getvaluetest_LINK) $(getvaluetest_OBJECTS) $(getvaluetest_LDADD) $(LIBS) gpiotest$(EXEEXT): $(gpiotest_OBJECTS) $(gpiotest_DEPENDENCIES) $(EXTRA_gpiotest_DEPENDENCIES) @rm -f gpiotest$(EXEEXT) $(AM_V_CCLD)$(gpiotest_LINK) $(gpiotest_OBJECTS) $(gpiotest_LDADD) $(LIBS) nutlogtest$(EXEEXT): $(nutlogtest_OBJECTS) $(nutlogtest_DEPENDENCIES) $(EXTRA_nutlogtest_DEPENDENCIES) @rm -f nutlogtest$(EXEEXT) $(AM_V_CCLD)$(LINK) $(nutlogtest_OBJECTS) $(nutlogtest_LDADD) $(LIBS) nuttimetest$(EXEEXT): $(nuttimetest_OBJECTS) $(nuttimetest_DEPENDENCIES) $(EXTRA_nuttimetest_DEPENDENCIES) @rm -f nuttimetest$(EXEEXT) $(AM_V_CCLD)$(LINK) $(nuttimetest_OBJECTS) $(nuttimetest_LDADD) $(LIBS) mostlyclean-compile: -rm -f *.$(OBJEXT) distclean-compile: -rm -f *.tab.c @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cppnit-cpputest-client.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cppnit-cpputest.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cppunittest-cpputest.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cppunittest-example.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cppunittest-nutclienttest.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/getvaluetest-getvaluetest.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/getvaluetest-hidparser.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gpiotest-generic_gpio_common.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gpiotest-generic_gpio_libgpiod.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gpiotest-generic_gpio_liblocal.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gpiotest-generic_gpio_utest.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nutlogtest.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nuttimetest.Po@am__quote@ # am--include-marker $(am__depfiles_remade): @$(MKDIR_P) $(@D) @echo '# dummy' >$@-t && $(am__mv) $@-t $@ am--depfiles: $(am__depfiles_remade) .c.o: @am__fastdepCC_TRUE@ $(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.o$$||'`;\ @am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\ @am__fastdepCC_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ $< .c.obj: @am__fastdepCC_TRUE@ $(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.obj$$||'`;\ @am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ `$(CYGPATH_W) '$<'` &&\ @am__fastdepCC_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'` .c.lo: @am__fastdepCC_TRUE@ $(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.lo$$||'`;\ @am__fastdepCC_TRUE@ $(LTCOMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\ @am__fastdepCC_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LTCOMPILE) -c -o $@ $< getvaluetest-getvaluetest.o: getvaluetest.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(getvaluetest_CFLAGS) $(CFLAGS) -MT getvaluetest-getvaluetest.o -MD -MP -MF $(DEPDIR)/getvaluetest-getvaluetest.Tpo -c -o getvaluetest-getvaluetest.o `test -f 'getvaluetest.c' || echo '$(srcdir)/'`getvaluetest.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/getvaluetest-getvaluetest.Tpo $(DEPDIR)/getvaluetest-getvaluetest.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='getvaluetest.c' object='getvaluetest-getvaluetest.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(getvaluetest_CFLAGS) $(CFLAGS) -c -o getvaluetest-getvaluetest.o `test -f 'getvaluetest.c' || echo '$(srcdir)/'`getvaluetest.c getvaluetest-getvaluetest.obj: getvaluetest.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(getvaluetest_CFLAGS) $(CFLAGS) -MT getvaluetest-getvaluetest.obj -MD -MP -MF $(DEPDIR)/getvaluetest-getvaluetest.Tpo -c -o getvaluetest-getvaluetest.obj `if test -f 'getvaluetest.c'; then $(CYGPATH_W) 'getvaluetest.c'; else $(CYGPATH_W) '$(srcdir)/getvaluetest.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/getvaluetest-getvaluetest.Tpo $(DEPDIR)/getvaluetest-getvaluetest.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='getvaluetest.c' object='getvaluetest-getvaluetest.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(getvaluetest_CFLAGS) $(CFLAGS) -c -o getvaluetest-getvaluetest.obj `if test -f 'getvaluetest.c'; then $(CYGPATH_W) 'getvaluetest.c'; else $(CYGPATH_W) '$(srcdir)/getvaluetest.c'; fi` getvaluetest-hidparser.o: hidparser.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(getvaluetest_CFLAGS) $(CFLAGS) -MT getvaluetest-hidparser.o -MD -MP -MF $(DEPDIR)/getvaluetest-hidparser.Tpo -c -o getvaluetest-hidparser.o `test -f 'hidparser.c' || echo '$(srcdir)/'`hidparser.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/getvaluetest-hidparser.Tpo $(DEPDIR)/getvaluetest-hidparser.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='hidparser.c' object='getvaluetest-hidparser.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(getvaluetest_CFLAGS) $(CFLAGS) -c -o getvaluetest-hidparser.o `test -f 'hidparser.c' || echo '$(srcdir)/'`hidparser.c getvaluetest-hidparser.obj: hidparser.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(getvaluetest_CFLAGS) $(CFLAGS) -MT getvaluetest-hidparser.obj -MD -MP -MF $(DEPDIR)/getvaluetest-hidparser.Tpo -c -o getvaluetest-hidparser.obj `if test -f 'hidparser.c'; then $(CYGPATH_W) 'hidparser.c'; else $(CYGPATH_W) '$(srcdir)/hidparser.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/getvaluetest-hidparser.Tpo $(DEPDIR)/getvaluetest-hidparser.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='hidparser.c' object='getvaluetest-hidparser.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(getvaluetest_CFLAGS) $(CFLAGS) -c -o getvaluetest-hidparser.obj `if test -f 'hidparser.c'; then $(CYGPATH_W) 'hidparser.c'; else $(CYGPATH_W) '$(srcdir)/hidparser.c'; fi` gpiotest-generic_gpio_utest.o: generic_gpio_utest.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(gpiotest_CFLAGS) $(CFLAGS) -MT gpiotest-generic_gpio_utest.o -MD -MP -MF $(DEPDIR)/gpiotest-generic_gpio_utest.Tpo -c -o gpiotest-generic_gpio_utest.o `test -f 'generic_gpio_utest.c' || echo '$(srcdir)/'`generic_gpio_utest.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/gpiotest-generic_gpio_utest.Tpo $(DEPDIR)/gpiotest-generic_gpio_utest.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='generic_gpio_utest.c' object='gpiotest-generic_gpio_utest.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(gpiotest_CFLAGS) $(CFLAGS) -c -o gpiotest-generic_gpio_utest.o `test -f 'generic_gpio_utest.c' || echo '$(srcdir)/'`generic_gpio_utest.c gpiotest-generic_gpio_utest.obj: generic_gpio_utest.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(gpiotest_CFLAGS) $(CFLAGS) -MT gpiotest-generic_gpio_utest.obj -MD -MP -MF $(DEPDIR)/gpiotest-generic_gpio_utest.Tpo -c -o gpiotest-generic_gpio_utest.obj `if test -f 'generic_gpio_utest.c'; then $(CYGPATH_W) 'generic_gpio_utest.c'; else $(CYGPATH_W) '$(srcdir)/generic_gpio_utest.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/gpiotest-generic_gpio_utest.Tpo $(DEPDIR)/gpiotest-generic_gpio_utest.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='generic_gpio_utest.c' object='gpiotest-generic_gpio_utest.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(gpiotest_CFLAGS) $(CFLAGS) -c -o gpiotest-generic_gpio_utest.obj `if test -f 'generic_gpio_utest.c'; then $(CYGPATH_W) 'generic_gpio_utest.c'; else $(CYGPATH_W) '$(srcdir)/generic_gpio_utest.c'; fi` gpiotest-generic_gpio_liblocal.o: generic_gpio_liblocal.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(gpiotest_CFLAGS) $(CFLAGS) -MT gpiotest-generic_gpio_liblocal.o -MD -MP -MF $(DEPDIR)/gpiotest-generic_gpio_liblocal.Tpo -c -o gpiotest-generic_gpio_liblocal.o `test -f 'generic_gpio_liblocal.c' || echo '$(srcdir)/'`generic_gpio_liblocal.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/gpiotest-generic_gpio_liblocal.Tpo $(DEPDIR)/gpiotest-generic_gpio_liblocal.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='generic_gpio_liblocal.c' object='gpiotest-generic_gpio_liblocal.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(gpiotest_CFLAGS) $(CFLAGS) -c -o gpiotest-generic_gpio_liblocal.o `test -f 'generic_gpio_liblocal.c' || echo '$(srcdir)/'`generic_gpio_liblocal.c gpiotest-generic_gpio_liblocal.obj: generic_gpio_liblocal.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(gpiotest_CFLAGS) $(CFLAGS) -MT gpiotest-generic_gpio_liblocal.obj -MD -MP -MF $(DEPDIR)/gpiotest-generic_gpio_liblocal.Tpo -c -o gpiotest-generic_gpio_liblocal.obj `if test -f 'generic_gpio_liblocal.c'; then $(CYGPATH_W) 'generic_gpio_liblocal.c'; else $(CYGPATH_W) '$(srcdir)/generic_gpio_liblocal.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/gpiotest-generic_gpio_liblocal.Tpo $(DEPDIR)/gpiotest-generic_gpio_liblocal.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='generic_gpio_liblocal.c' object='gpiotest-generic_gpio_liblocal.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(gpiotest_CFLAGS) $(CFLAGS) -c -o gpiotest-generic_gpio_liblocal.obj `if test -f 'generic_gpio_liblocal.c'; then $(CYGPATH_W) 'generic_gpio_liblocal.c'; else $(CYGPATH_W) '$(srcdir)/generic_gpio_liblocal.c'; fi` gpiotest-generic_gpio_libgpiod.o: generic_gpio_libgpiod.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(gpiotest_CFLAGS) $(CFLAGS) -MT gpiotest-generic_gpio_libgpiod.o -MD -MP -MF $(DEPDIR)/gpiotest-generic_gpio_libgpiod.Tpo -c -o gpiotest-generic_gpio_libgpiod.o `test -f 'generic_gpio_libgpiod.c' || echo '$(srcdir)/'`generic_gpio_libgpiod.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/gpiotest-generic_gpio_libgpiod.Tpo $(DEPDIR)/gpiotest-generic_gpio_libgpiod.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='generic_gpio_libgpiod.c' object='gpiotest-generic_gpio_libgpiod.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(gpiotest_CFLAGS) $(CFLAGS) -c -o gpiotest-generic_gpio_libgpiod.o `test -f 'generic_gpio_libgpiod.c' || echo '$(srcdir)/'`generic_gpio_libgpiod.c gpiotest-generic_gpio_libgpiod.obj: generic_gpio_libgpiod.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(gpiotest_CFLAGS) $(CFLAGS) -MT gpiotest-generic_gpio_libgpiod.obj -MD -MP -MF $(DEPDIR)/gpiotest-generic_gpio_libgpiod.Tpo -c -o gpiotest-generic_gpio_libgpiod.obj `if test -f 'generic_gpio_libgpiod.c'; then $(CYGPATH_W) 'generic_gpio_libgpiod.c'; else $(CYGPATH_W) '$(srcdir)/generic_gpio_libgpiod.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/gpiotest-generic_gpio_libgpiod.Tpo $(DEPDIR)/gpiotest-generic_gpio_libgpiod.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='generic_gpio_libgpiod.c' object='gpiotest-generic_gpio_libgpiod.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(gpiotest_CFLAGS) $(CFLAGS) -c -o gpiotest-generic_gpio_libgpiod.obj `if test -f 'generic_gpio_libgpiod.c'; then $(CYGPATH_W) 'generic_gpio_libgpiod.c'; else $(CYGPATH_W) '$(srcdir)/generic_gpio_libgpiod.c'; fi` gpiotest-generic_gpio_common.o: generic_gpio_common.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(gpiotest_CFLAGS) $(CFLAGS) -MT gpiotest-generic_gpio_common.o -MD -MP -MF $(DEPDIR)/gpiotest-generic_gpio_common.Tpo -c -o gpiotest-generic_gpio_common.o `test -f 'generic_gpio_common.c' || echo '$(srcdir)/'`generic_gpio_common.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/gpiotest-generic_gpio_common.Tpo $(DEPDIR)/gpiotest-generic_gpio_common.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='generic_gpio_common.c' object='gpiotest-generic_gpio_common.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(gpiotest_CFLAGS) $(CFLAGS) -c -o gpiotest-generic_gpio_common.o `test -f 'generic_gpio_common.c' || echo '$(srcdir)/'`generic_gpio_common.c gpiotest-generic_gpio_common.obj: generic_gpio_common.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(gpiotest_CFLAGS) $(CFLAGS) -MT gpiotest-generic_gpio_common.obj -MD -MP -MF $(DEPDIR)/gpiotest-generic_gpio_common.Tpo -c -o gpiotest-generic_gpio_common.obj `if test -f 'generic_gpio_common.c'; then $(CYGPATH_W) 'generic_gpio_common.c'; else $(CYGPATH_W) '$(srcdir)/generic_gpio_common.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/gpiotest-generic_gpio_common.Tpo $(DEPDIR)/gpiotest-generic_gpio_common.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='generic_gpio_common.c' object='gpiotest-generic_gpio_common.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(gpiotest_CFLAGS) $(CFLAGS) -c -o gpiotest-generic_gpio_common.obj `if test -f 'generic_gpio_common.c'; then $(CYGPATH_W) 'generic_gpio_common.c'; else $(CYGPATH_W) '$(srcdir)/generic_gpio_common.c'; fi` .cpp.o: @am__fastdepCXX_TRUE@ $(AM_V_CXX)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.o$$||'`;\ @am__fastdepCXX_TRUE@ $(CXXCOMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\ @am__fastdepCXX_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXXCOMPILE) -c -o $@ $< .cpp.obj: @am__fastdepCXX_TRUE@ $(AM_V_CXX)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.obj$$||'`;\ @am__fastdepCXX_TRUE@ $(CXXCOMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ `$(CYGPATH_W) '$<'` &&\ @am__fastdepCXX_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXXCOMPILE) -c -o $@ `$(CYGPATH_W) '$<'` .cpp.lo: @am__fastdepCXX_TRUE@ $(AM_V_CXX)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.lo$$||'`;\ @am__fastdepCXX_TRUE@ $(LTCXXCOMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\ @am__fastdepCXX_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Plo @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LTCXXCOMPILE) -c -o $@ $< cppnit-cpputest-client.o: cpputest-client.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(cppnit_CXXFLAGS) $(CXXFLAGS) -MT cppnit-cpputest-client.o -MD -MP -MF $(DEPDIR)/cppnit-cpputest-client.Tpo -c -o cppnit-cpputest-client.o `test -f 'cpputest-client.cpp' || echo '$(srcdir)/'`cpputest-client.cpp @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/cppnit-cpputest-client.Tpo $(DEPDIR)/cppnit-cpputest-client.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='cpputest-client.cpp' object='cppnit-cpputest-client.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(cppnit_CXXFLAGS) $(CXXFLAGS) -c -o cppnit-cpputest-client.o `test -f 'cpputest-client.cpp' || echo '$(srcdir)/'`cpputest-client.cpp cppnit-cpputest-client.obj: cpputest-client.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(cppnit_CXXFLAGS) $(CXXFLAGS) -MT cppnit-cpputest-client.obj -MD -MP -MF $(DEPDIR)/cppnit-cpputest-client.Tpo -c -o cppnit-cpputest-client.obj `if test -f 'cpputest-client.cpp'; then $(CYGPATH_W) 'cpputest-client.cpp'; else $(CYGPATH_W) '$(srcdir)/cpputest-client.cpp'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/cppnit-cpputest-client.Tpo $(DEPDIR)/cppnit-cpputest-client.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='cpputest-client.cpp' object='cppnit-cpputest-client.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(cppnit_CXXFLAGS) $(CXXFLAGS) -c -o cppnit-cpputest-client.obj `if test -f 'cpputest-client.cpp'; then $(CYGPATH_W) 'cpputest-client.cpp'; else $(CYGPATH_W) '$(srcdir)/cpputest-client.cpp'; fi` cppnit-cpputest.o: cpputest.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(cppnit_CXXFLAGS) $(CXXFLAGS) -MT cppnit-cpputest.o -MD -MP -MF $(DEPDIR)/cppnit-cpputest.Tpo -c -o cppnit-cpputest.o `test -f 'cpputest.cpp' || echo '$(srcdir)/'`cpputest.cpp @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/cppnit-cpputest.Tpo $(DEPDIR)/cppnit-cpputest.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='cpputest.cpp' object='cppnit-cpputest.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(cppnit_CXXFLAGS) $(CXXFLAGS) -c -o cppnit-cpputest.o `test -f 'cpputest.cpp' || echo '$(srcdir)/'`cpputest.cpp cppnit-cpputest.obj: cpputest.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(cppnit_CXXFLAGS) $(CXXFLAGS) -MT cppnit-cpputest.obj -MD -MP -MF $(DEPDIR)/cppnit-cpputest.Tpo -c -o cppnit-cpputest.obj `if test -f 'cpputest.cpp'; then $(CYGPATH_W) 'cpputest.cpp'; else $(CYGPATH_W) '$(srcdir)/cpputest.cpp'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/cppnit-cpputest.Tpo $(DEPDIR)/cppnit-cpputest.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='cpputest.cpp' object='cppnit-cpputest.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(cppnit_CXXFLAGS) $(CXXFLAGS) -c -o cppnit-cpputest.obj `if test -f 'cpputest.cpp'; then $(CYGPATH_W) 'cpputest.cpp'; else $(CYGPATH_W) '$(srcdir)/cpputest.cpp'; fi` cppunittest-example.o: example.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(cppunittest_CXXFLAGS) $(CXXFLAGS) -MT cppunittest-example.o -MD -MP -MF $(DEPDIR)/cppunittest-example.Tpo -c -o cppunittest-example.o `test -f 'example.cpp' || echo '$(srcdir)/'`example.cpp @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/cppunittest-example.Tpo $(DEPDIR)/cppunittest-example.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='example.cpp' object='cppunittest-example.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(cppunittest_CXXFLAGS) $(CXXFLAGS) -c -o cppunittest-example.o `test -f 'example.cpp' || echo '$(srcdir)/'`example.cpp cppunittest-example.obj: example.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(cppunittest_CXXFLAGS) $(CXXFLAGS) -MT cppunittest-example.obj -MD -MP -MF $(DEPDIR)/cppunittest-example.Tpo -c -o cppunittest-example.obj `if test -f 'example.cpp'; then $(CYGPATH_W) 'example.cpp'; else $(CYGPATH_W) '$(srcdir)/example.cpp'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/cppunittest-example.Tpo $(DEPDIR)/cppunittest-example.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='example.cpp' object='cppunittest-example.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(cppunittest_CXXFLAGS) $(CXXFLAGS) -c -o cppunittest-example.obj `if test -f 'example.cpp'; then $(CYGPATH_W) 'example.cpp'; else $(CYGPATH_W) '$(srcdir)/example.cpp'; fi` cppunittest-nutclienttest.o: nutclienttest.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(cppunittest_CXXFLAGS) $(CXXFLAGS) -MT cppunittest-nutclienttest.o -MD -MP -MF $(DEPDIR)/cppunittest-nutclienttest.Tpo -c -o cppunittest-nutclienttest.o `test -f 'nutclienttest.cpp' || echo '$(srcdir)/'`nutclienttest.cpp @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/cppunittest-nutclienttest.Tpo $(DEPDIR)/cppunittest-nutclienttest.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='nutclienttest.cpp' object='cppunittest-nutclienttest.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(cppunittest_CXXFLAGS) $(CXXFLAGS) -c -o cppunittest-nutclienttest.o `test -f 'nutclienttest.cpp' || echo '$(srcdir)/'`nutclienttest.cpp cppunittest-nutclienttest.obj: nutclienttest.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(cppunittest_CXXFLAGS) $(CXXFLAGS) -MT cppunittest-nutclienttest.obj -MD -MP -MF $(DEPDIR)/cppunittest-nutclienttest.Tpo -c -o cppunittest-nutclienttest.obj `if test -f 'nutclienttest.cpp'; then $(CYGPATH_W) 'nutclienttest.cpp'; else $(CYGPATH_W) '$(srcdir)/nutclienttest.cpp'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/cppunittest-nutclienttest.Tpo $(DEPDIR)/cppunittest-nutclienttest.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='nutclienttest.cpp' object='cppunittest-nutclienttest.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(cppunittest_CXXFLAGS) $(CXXFLAGS) -c -o cppunittest-nutclienttest.obj `if test -f 'nutclienttest.cpp'; then $(CYGPATH_W) 'nutclienttest.cpp'; else $(CYGPATH_W) '$(srcdir)/nutclienttest.cpp'; fi` cppunittest-cpputest.o: cpputest.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(cppunittest_CXXFLAGS) $(CXXFLAGS) -MT cppunittest-cpputest.o -MD -MP -MF $(DEPDIR)/cppunittest-cpputest.Tpo -c -o cppunittest-cpputest.o `test -f 'cpputest.cpp' || echo '$(srcdir)/'`cpputest.cpp @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/cppunittest-cpputest.Tpo $(DEPDIR)/cppunittest-cpputest.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='cpputest.cpp' object='cppunittest-cpputest.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(cppunittest_CXXFLAGS) $(CXXFLAGS) -c -o cppunittest-cpputest.o `test -f 'cpputest.cpp' || echo '$(srcdir)/'`cpputest.cpp cppunittest-cpputest.obj: cpputest.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(cppunittest_CXXFLAGS) $(CXXFLAGS) -MT cppunittest-cpputest.obj -MD -MP -MF $(DEPDIR)/cppunittest-cpputest.Tpo -c -o cppunittest-cpputest.obj `if test -f 'cpputest.cpp'; then $(CYGPATH_W) 'cpputest.cpp'; else $(CYGPATH_W) '$(srcdir)/cpputest.cpp'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/cppunittest-cpputest.Tpo $(DEPDIR)/cppunittest-cpputest.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='cpputest.cpp' object='cppunittest-cpputest.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(cppunittest_CXXFLAGS) $(CXXFLAGS) -c -o cppunittest-cpputest.obj `if test -f 'cpputest.cpp'; then $(CYGPATH_W) 'cpputest.cpp'; else $(CYGPATH_W) '$(srcdir)/cpputest.cpp'; fi` mostlyclean-libtool: -rm -f *.lo clean-libtool: -rm -rf .libs _libs # This directory's subdirectories are mostly independent; you can cd # into them and run 'make' without going through this Makefile. # To change the values of 'make' variables: instead of editing Makefiles, # (1) if the variable is set in 'config.status', edit 'config.status' # (which will cause the Makefiles to be regenerated when you run 'make'); # (2) otherwise, pass the desired values on the 'make' command line. $(am__recursive_targets): @fail=; \ if $(am__make_keepgoing); then \ failcom='fail=yes'; \ else \ failcom='exit 1'; \ fi; \ dot_seen=no; \ target=`echo $@ | sed s/-recursive//`; \ case "$@" in \ distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \ *) list='$(SUBDIRS)' ;; \ esac; \ for subdir in $$list; do \ echo "Making $$target in $$subdir"; \ if test "$$subdir" = "."; then \ dot_seen=yes; \ local_target="$$target-am"; \ else \ local_target="$$target"; \ fi; \ ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ || eval $$failcom; \ done; \ if test "$$dot_seen" = "no"; then \ $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \ fi; test -z "$$fail" ID: $(am__tagged_files) $(am__define_uniq_tagged_files); mkid -fID $$unique tags: tags-recursive TAGS: tags tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) set x; \ here=`pwd`; \ if ($(ETAGS) --etags-include --version) >/dev/null 2>&1; then \ include_option=--etags-include; \ empty_fix=.; \ else \ include_option=--include; \ empty_fix=; \ fi; \ list='$(SUBDIRS)'; for subdir in $$list; do \ if test "$$subdir" = .; then :; else \ test ! -f $$subdir/TAGS || \ set "$$@" "$$include_option=$$here/$$subdir/TAGS"; \ fi; \ done; \ $(am__define_uniq_tagged_files); \ shift; \ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ test -n "$$unique" || unique=$$empty_fix; \ if test $$# -gt 0; then \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ "$$@" $$unique; \ else \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ $$unique; \ fi; \ fi ctags: ctags-recursive CTAGS: ctags ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) $(am__define_uniq_tagged_files); \ test -z "$(CTAGS_ARGS)$$unique" \ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ $$unique GTAGS: here=`$(am__cd) $(top_builddir) && pwd` \ && $(am__cd) $(top_srcdir) \ && gtags -i $(GTAGS_ARGS) "$$here" cscopelist: cscopelist-recursive cscopelist-am: $(am__tagged_files) list='$(am__tagged_files)'; \ case "$(srcdir)" in \ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \ *) sdir=$(subdir)/$(srcdir) ;; \ esac; \ for i in $$list; do \ if test -f "$$i"; then \ echo "$(subdir)/$$i"; \ else \ echo "$$sdir/$$i"; \ fi; \ done >> $(top_builddir)/cscope.files distclean-tags: -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags # Recover from deleted '.trs' file; this should ensure that # "rm -f foo.log; make foo.trs" re-run 'foo.test', and re-create # both 'foo.log' and 'foo.trs'. Break the recipe in two subshells # to avoid problems with "make -n". .log.trs: rm -f $< $@ $(MAKE) $(AM_MAKEFLAGS) $< # Leading 'am--fnord' is there to ensure the list of targets does not # expand to empty, as could happen e.g. with make check TESTS=''. am--fnord $(TEST_LOGS) $(TEST_LOGS:.log=.trs): $(am__force_recheck) am--force-recheck: @: $(TEST_SUITE_LOG): $(TEST_LOGS) @$(am__set_TESTS_bases); \ am__f_ok () { test -f "$$1" && test -r "$$1"; }; \ redo_bases=`for i in $$bases; do \ am__f_ok $$i.trs && am__f_ok $$i.log || echo $$i; \ done`; \ if test -n "$$redo_bases"; then \ redo_logs=`for i in $$redo_bases; do echo $$i.log; done`; \ redo_results=`for i in $$redo_bases; do echo $$i.trs; done`; \ if $(am__make_dryrun); then :; else \ rm -f $$redo_logs && rm -f $$redo_results || exit 1; \ fi; \ fi; \ if test -n "$$am__remaking_logs"; then \ echo "fatal: making $(TEST_SUITE_LOG): possible infinite" \ "recursion detected" >&2; \ elif test -n "$$redo_logs"; then \ am__remaking_logs=yes $(MAKE) $(AM_MAKEFLAGS) $$redo_logs; \ fi; \ if $(am__make_dryrun); then :; else \ st=0; \ errmsg="fatal: making $(TEST_SUITE_LOG): failed to create"; \ for i in $$redo_bases; do \ test -f $$i.trs && test -r $$i.trs \ || { echo "$$errmsg $$i.trs" >&2; st=1; }; \ test -f $$i.log && test -r $$i.log \ || { echo "$$errmsg $$i.log" >&2; st=1; }; \ done; \ test $$st -eq 0 || exit 1; \ fi @$(am__sh_e_setup); $(am__tty_colors); $(am__set_TESTS_bases); \ ws='[ ]'; \ results=`for b in $$bases; do echo $$b.trs; done`; \ test -n "$$results" || results=/dev/null; \ all=` grep "^$$ws*:test-result:" $$results | wc -l`; \ pass=` grep "^$$ws*:test-result:$$ws*PASS" $$results | wc -l`; \ fail=` grep "^$$ws*:test-result:$$ws*FAIL" $$results | wc -l`; \ skip=` grep "^$$ws*:test-result:$$ws*SKIP" $$results | wc -l`; \ xfail=`grep "^$$ws*:test-result:$$ws*XFAIL" $$results | wc -l`; \ xpass=`grep "^$$ws*:test-result:$$ws*XPASS" $$results | wc -l`; \ error=`grep "^$$ws*:test-result:$$ws*ERROR" $$results | wc -l`; \ if test `expr $$fail + $$xpass + $$error` -eq 0; then \ success=true; \ else \ success=false; \ fi; \ br='==================='; br=$$br$$br$$br$$br; \ result_count () \ { \ if test x"$$1" = x"--maybe-color"; then \ maybe_colorize=yes; \ elif test x"$$1" = x"--no-color"; then \ maybe_colorize=no; \ else \ echo "$@: invalid 'result_count' usage" >&2; exit 4; \ fi; \ shift; \ desc=$$1 count=$$2; \ if test $$maybe_colorize = yes && test $$count -gt 0; then \ color_start=$$3 color_end=$$std; \ else \ color_start= color_end=; \ fi; \ echo "$${color_start}# $$desc $$count$${color_end}"; \ }; \ create_testsuite_report () \ { \ result_count $$1 "TOTAL:" $$all "$$brg"; \ result_count $$1 "PASS: " $$pass "$$grn"; \ result_count $$1 "SKIP: " $$skip "$$blu"; \ result_count $$1 "XFAIL:" $$xfail "$$lgn"; \ result_count $$1 "FAIL: " $$fail "$$red"; \ result_count $$1 "XPASS:" $$xpass "$$red"; \ result_count $$1 "ERROR:" $$error "$$mgn"; \ }; \ { \ echo "$(PACKAGE_STRING): $(subdir)/$(TEST_SUITE_LOG)" | \ $(am__rst_title); \ create_testsuite_report --no-color; \ echo; \ echo ".. contents:: :depth: 2"; \ echo; \ for b in $$bases; do echo $$b; done \ | $(am__create_global_log); \ } >$(TEST_SUITE_LOG).tmp || exit 1; \ mv $(TEST_SUITE_LOG).tmp $(TEST_SUITE_LOG); \ if $$success; then \ col="$$grn"; \ else \ col="$$red"; \ test x"$$VERBOSE" = x || cat $(TEST_SUITE_LOG); \ fi; \ echo "$${col}$$br$${std}"; \ echo "$${col}Testsuite summary"$(AM_TESTSUITE_SUMMARY_HEADER)"$${std}"; \ echo "$${col}$$br$${std}"; \ create_testsuite_report --maybe-color; \ echo "$$col$$br$$std"; \ if $$success; then :; else \ echo "$${col}See $(subdir)/$(TEST_SUITE_LOG)$${std}"; \ if test -n "$(PACKAGE_BUGREPORT)"; then \ echo "$${col}Please report to $(PACKAGE_BUGREPORT)$${std}"; \ fi; \ echo "$$col$$br$$std"; \ fi; \ $$success || exit 1 check-TESTS: $(check_PROGRAMS) $(check_SCRIPTS) @list='$(RECHECK_LOGS)'; test -z "$$list" || rm -f $$list @list='$(RECHECK_LOGS:.log=.trs)'; test -z "$$list" || rm -f $$list @test -z "$(TEST_SUITE_LOG)" || rm -f $(TEST_SUITE_LOG) @set +e; $(am__set_TESTS_bases); \ log_list=`for i in $$bases; do echo $$i.log; done`; \ trs_list=`for i in $$bases; do echo $$i.trs; done`; \ log_list=`echo $$log_list`; trs_list=`echo $$trs_list`; \ $(MAKE) $(AM_MAKEFLAGS) $(TEST_SUITE_LOG) TEST_LOGS="$$log_list"; \ exit $$?; recheck: all $(check_PROGRAMS) $(check_SCRIPTS) @test -z "$(TEST_SUITE_LOG)" || rm -f $(TEST_SUITE_LOG) @set +e; $(am__set_TESTS_bases); \ bases=`for i in $$bases; do echo $$i; done \ | $(am__list_recheck_tests)` || exit 1; \ log_list=`for i in $$bases; do echo $$i.log; done`; \ log_list=`echo $$log_list`; \ $(MAKE) $(AM_MAKEFLAGS) $(TEST_SUITE_LOG) \ am__force_recheck=am--force-recheck \ TEST_LOGS="$$log_list"; \ exit $$? nutlogtest.log: nutlogtest$(EXEEXT) @p='nutlogtest$(EXEEXT)'; \ b='nutlogtest'; \ $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \ --log-file $$b.log --trs-file $$b.trs \ $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \ "$$tst" $(AM_TESTS_FD_REDIRECT) nuttimetest.log: nuttimetest$(EXEEXT) @p='nuttimetest$(EXEEXT)'; \ b='nuttimetest'; \ $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \ --log-file $$b.log --trs-file $$b.trs \ $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \ "$$tst" $(AM_TESTS_FD_REDIRECT) getvaluetest.log: getvaluetest$(EXEEXT) @p='getvaluetest$(EXEEXT)'; \ b='getvaluetest'; \ $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \ --log-file $$b.log --trs-file $$b.trs \ $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \ "$$tst" $(AM_TESTS_FD_REDIRECT) gpiotest.log: gpiotest$(EXEEXT) @p='gpiotest$(EXEEXT)'; \ b='gpiotest'; \ $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \ --log-file $$b.log --trs-file $$b.trs \ $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \ "$$tst" $(AM_TESTS_FD_REDIRECT) cppunittest.log: cppunittest$(EXEEXT) @p='cppunittest$(EXEEXT)'; \ b='cppunittest'; \ $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \ --log-file $$b.log --trs-file $$b.trs \ $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \ "$$tst" $(AM_TESTS_FD_REDIRECT) .test.log: @p='$<'; \ $(am__set_b); \ $(am__check_pre) $(TEST_LOG_DRIVER) --test-name "$$f" \ --log-file $$b.log --trs-file $$b.trs \ $(am__common_driver_flags) $(AM_TEST_LOG_DRIVER_FLAGS) $(TEST_LOG_DRIVER_FLAGS) -- $(TEST_LOG_COMPILE) \ "$$tst" $(AM_TESTS_FD_REDIRECT) @am__EXEEXT_TRUE@.test$(EXEEXT).log: @am__EXEEXT_TRUE@ @p='$<'; \ @am__EXEEXT_TRUE@ $(am__set_b); \ @am__EXEEXT_TRUE@ $(am__check_pre) $(TEST_LOG_DRIVER) --test-name "$$f" \ @am__EXEEXT_TRUE@ --log-file $$b.log --trs-file $$b.trs \ @am__EXEEXT_TRUE@ $(am__common_driver_flags) $(AM_TEST_LOG_DRIVER_FLAGS) $(TEST_LOG_DRIVER_FLAGS) -- $(TEST_LOG_COMPILE) \ @am__EXEEXT_TRUE@ "$$tst" $(AM_TESTS_FD_REDIRECT) distdir: $(BUILT_SOURCES) $(MAKE) $(AM_MAKEFLAGS) distdir-am distdir-am: $(DISTFILES) @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ dist_files=`for file in $$list; do echo $$file; done | \ sed -e "s|^$$srcdirstrip/||;t" \ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ case $$dist_files in \ */*) $(MKDIR_P) `echo "$$dist_files" | \ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ sort -u` ;; \ esac; \ for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d "$(distdir)/$$file"; then \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ else \ test -f "$(distdir)/$$file" \ || cp -p $$d/$$file "$(distdir)/$$file" \ || exit 1; \ fi; \ done @list='$(DIST_SUBDIRS)'; for subdir in $$list; do \ if test "$$subdir" = .; then :; else \ $(am__make_dryrun) \ || test -d "$(distdir)/$$subdir" \ || $(MKDIR_P) "$(distdir)/$$subdir" \ || exit 1; \ dir1=$$subdir; dir2="$(distdir)/$$subdir"; \ $(am__relativize); \ new_distdir=$$reldir; \ dir1=$$subdir; dir2="$(top_distdir)"; \ $(am__relativize); \ new_top_distdir=$$reldir; \ echo " (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) top_distdir="$$new_top_distdir" distdir="$$new_distdir" \\"; \ echo " am__remove_distdir=: am__skip_length_check=: am__skip_mode_fix=: distdir)"; \ ($(am__cd) $$subdir && \ $(MAKE) $(AM_MAKEFLAGS) \ top_distdir="$$new_top_distdir" \ distdir="$$new_distdir" \ am__remove_distdir=: \ am__skip_length_check=: \ am__skip_mode_fix=: \ distdir) \ || exit 1; \ fi; \ done @HAVE_CPPUNIT_FALSE@check-local: @HAVE_CXX11_FALSE@check-local: @WITH_VALGRIND_FALSE@check-local: check-am: all-am $(MAKE) $(AM_MAKEFLAGS) $(check_PROGRAMS) $(check_SCRIPTS) $(MAKE) $(AM_MAKEFLAGS) check-TESTS check-local check: $(BUILT_SOURCES) $(MAKE) $(AM_MAKEFLAGS) check-recursive all-am: Makefile installdirs: installdirs-recursive installdirs-am: install: $(BUILT_SOURCES) $(MAKE) $(AM_MAKEFLAGS) install-recursive install-exec: $(BUILT_SOURCES) $(MAKE) $(AM_MAKEFLAGS) install-exec-recursive install-data: install-data-recursive uninstall: uninstall-recursive install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-recursive install-strip: if test -z '$(STRIP)'; then \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ install; \ else \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ fi mostlyclean-generic: -test -z "$(TEST_LOGS)" || rm -f $(TEST_LOGS) -test -z "$(TEST_LOGS:.log=.trs)" || rm -f $(TEST_LOGS:.log=.trs) -test -z "$(TEST_SUITE_LOG)" || rm -f $(TEST_SUITE_LOG) clean-generic: -test -z "$(CLEANFILES)" || rm -f $(CLEANFILES) distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." -test -z "$(BUILT_SOURCES)" || rm -f $(BUILT_SOURCES) -test -z "$(MAINTAINERCLEANFILES)" || rm -f $(MAINTAINERCLEANFILES) clean: clean-recursive clean-am: clean-checkPROGRAMS clean-generic clean-libtool \ mostlyclean-am distclean: distclean-recursive -rm -f ./$(DEPDIR)/cppnit-cpputest-client.Po -rm -f ./$(DEPDIR)/cppnit-cpputest.Po -rm -f ./$(DEPDIR)/cppunittest-cpputest.Po -rm -f ./$(DEPDIR)/cppunittest-example.Po -rm -f ./$(DEPDIR)/cppunittest-nutclienttest.Po -rm -f ./$(DEPDIR)/getvaluetest-getvaluetest.Po -rm -f ./$(DEPDIR)/getvaluetest-hidparser.Po -rm -f ./$(DEPDIR)/gpiotest-generic_gpio_common.Po -rm -f ./$(DEPDIR)/gpiotest-generic_gpio_libgpiod.Po -rm -f ./$(DEPDIR)/gpiotest-generic_gpio_liblocal.Po -rm -f ./$(DEPDIR)/gpiotest-generic_gpio_utest.Po -rm -f ./$(DEPDIR)/nutlogtest.Po -rm -f ./$(DEPDIR)/nuttimetest.Po -rm -f Makefile distclean-am: clean-am distclean-compile distclean-generic \ distclean-tags dvi: dvi-recursive dvi-am: html: html-recursive html-am: info: info-recursive info-am: install-data-am: install-dvi: install-dvi-recursive install-dvi-am: install-exec-am: install-html: install-html-recursive install-html-am: install-info: install-info-recursive install-info-am: install-man: install-pdf: install-pdf-recursive install-pdf-am: install-ps: install-ps-recursive install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-recursive -rm -f ./$(DEPDIR)/cppnit-cpputest-client.Po -rm -f ./$(DEPDIR)/cppnit-cpputest.Po -rm -f ./$(DEPDIR)/cppunittest-cpputest.Po -rm -f ./$(DEPDIR)/cppunittest-example.Po -rm -f ./$(DEPDIR)/cppunittest-nutclienttest.Po -rm -f ./$(DEPDIR)/getvaluetest-getvaluetest.Po -rm -f ./$(DEPDIR)/getvaluetest-hidparser.Po -rm -f ./$(DEPDIR)/gpiotest-generic_gpio_common.Po -rm -f ./$(DEPDIR)/gpiotest-generic_gpio_libgpiod.Po -rm -f ./$(DEPDIR)/gpiotest-generic_gpio_liblocal.Po -rm -f ./$(DEPDIR)/gpiotest-generic_gpio_utest.Po -rm -f ./$(DEPDIR)/nutlogtest.Po -rm -f ./$(DEPDIR)/nuttimetest.Po -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-recursive mostlyclean-am: mostlyclean-compile mostlyclean-generic \ mostlyclean-libtool pdf: pdf-recursive pdf-am: ps: ps-recursive ps-am: uninstall-am: .MAKE: $(am__recursive_targets) all check check-am install install-am \ install-exec install-strip .PHONY: $(am__recursive_targets) CTAGS GTAGS TAGS all all-am \ am--depfiles check check-TESTS check-am check-local clean \ clean-checkPROGRAMS clean-generic clean-libtool cscopelist-am \ ctags ctags-am distclean distclean-compile distclean-generic \ distclean-libtool distclean-tags distdir dvi dvi-am html \ html-am info info-am install install-am install-data \ install-data-am install-dvi install-dvi-am install-exec \ install-exec-am install-html install-html-am install-info \ install-info-am install-man install-pdf install-pdf-am \ install-ps install-ps-am install-strip installcheck \ installcheck-am installdirs installdirs-am maintainer-clean \ maintainer-clean-generic mostlyclean mostlyclean-compile \ mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \ recheck tags tags-am uninstall uninstall-am .PRECIOUS: Makefile all: $(TESTS) # NUT Integration Testing suite check-NIT check-NIT-devel: cd "$(builddir)/NIT" && $(MAKE) $@ @REQUIRE_NUT_STRARG_TRUE@nutlogtest-nofail.sh: nutlogtest$(EXEEXT) @REQUIRE_NUT_STRARG_TRUE@ @echo '#!/bin/sh' > $@ @REQUIRE_NUT_STRARG_TRUE@ @echo 'echo "WARNING: Your C library requires workarounds to print NULL values!" >&2' >> $@ @REQUIRE_NUT_STRARG_TRUE@ @echo 'echo "If nutlogtest below, or generally some NUT program, crashes with" >&2' >> $@ @REQUIRE_NUT_STRARG_TRUE@ @echo 'echo "a segmentation fault (especially during verbose debug) - that may be why" >&2' >> $@ @REQUIRE_NUT_STRARG_TRUE@ @echo 'SCRIPT_DIR="`dirname "$$0"`"' >> $@ @REQUIRE_NUT_STRARG_TRUE@ @echo '"$${SCRIPT_DIR}/nutlogtest" "$$@" || echo "nutlogtest FAILED but it was expected"' >> $@ @REQUIRE_NUT_STRARG_TRUE@ @chmod +x $@ # NOTE: Not using "$<" due to a legacy Sun/illumos dmake bug with resolver # of dynamic vars, see e.g. https://man.omnios.org/man1/make#BUGS hidparser.c: $(top_srcdir)/drivers/hidparser.c test -s "$@" || ln -s -f "$(top_srcdir)/drivers/hidparser.c" "$@" # NOTE: Not using "$<" due to a legacy Sun/illumos dmake bug with resolver # of dynamic vars, see e.g. https://man.omnios.org/man1/make#BUGS @WITH_GPIO_TRUE@generic_gpio_libgpiod.c: $(top_srcdir)/drivers/generic_gpio_libgpiod.c @WITH_GPIO_TRUE@ test -s "$@" || ln -s -f "$(top_srcdir)/drivers/generic_gpio_libgpiod.c" "$@" @WITH_GPIO_TRUE@generic_gpio_common.c: $(top_srcdir)/drivers/generic_gpio_common.c @WITH_GPIO_TRUE@ test -s "$@" || ln -s -f "$(top_srcdir)/drivers/generic_gpio_common.c" "$@" # Make sure out-of-dir dependencies exist (especially when dev-building parts): $(top_builddir)/drivers/libdummy_mockdrv.la \ $(top_builddir)/common/libcommon.la: dummy @cd $(@D) && $(MAKE) $(AM_MAKEFLAGS) $(@F) @HAVE_CPPUNIT_TRUE@@HAVE_CXX11_TRUE@@WITH_VALGRIND_TRUE@check-local: $(check_PROGRAMS) @HAVE_CPPUNIT_TRUE@@HAVE_CXX11_TRUE@@WITH_VALGRIND_TRUE@ RES=0; for P in $^ ; do $(VALGRIND) ./$$P || { RES=$$? ; echo "FAILED: $(VALGRIND) ./$$P" >&2; }; done; exit $$RES # Make sure out-of-dir C++ dependencies exist (especially when dev-building # only some parts of NUT): @HAVE_CPPUNIT_TRUE@@HAVE_CXX11_TRUE@$(top_builddir)/clients/libnutclient.la \ @HAVE_CPPUNIT_TRUE@@HAVE_CXX11_TRUE@$(top_builddir)/clients/libnutclientstub.la: dummy @HAVE_CPPUNIT_TRUE@@HAVE_CXX11_TRUE@ @cd $(@D) && $(MAKE) $(AM_MAKEFLAGS) $(@F) @HAVE_CPPUNIT_FALSE@@HAVE_CXX11_TRUE@cppnit: @HAVE_CPPUNIT_FALSE@@HAVE_CXX11_TRUE@ @echo "SKIP: $@ not implemented without C++11 and CPPUNIT enabled" >&2 ; exit 1 @HAVE_CXX11_FALSE@cppnit: @HAVE_CXX11_FALSE@ @echo "SKIP: $@ not implemented without C++11 and CPPUNIT enabled" >&2 ; exit 1 dummy: # NOTE: Do not clean ".deps" in SUBDIRS of the main project, # the root Makefile.am takes care of that! #clean-local: # $(AM_V_at)rm -rf $(builddir)/.deps # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: nut-2.8.1/tests/generic_gpio_test.txt0000644000175000017500000001456614501607135014663 00000000000000rules expecting_failure upsLinesCount upsMaxLine rulesCount stateName subCount ruleInt ^ -2 & -3 | -4 * rules OL=^0;OB=0;LB=3;RB=1;DISCHRG=0&^6;BYPASS=6; 1 4 6 6 OL 2 -2 0 OB 1 0 LB 1 1 RB 1 2 DISCHRG 4 0 -3 -2 3 BYPASS 1 3 * rules DISCHRG=0&^6; 1 2 6 1 DISCHRG 4 0 -3 -2 1 * rules DISCHRG=0&^6|^2; 1 3 6 1 DISCHRG 7 0 -3 -2 1 -4 -2 2 * rules ; 0 * rules = 0 * rules 0 0 * rules ^ 0 * rules OB 0 * rules OB= 0 * rules OB=; 0 * rules OB=a; 0 * rules OB=&; 0 * rules OB=^; 0 * rules OB=^a; 0 * rules OB=^=; 0 * rules OB=^&; 0 * rules OB=^|; 0 * rules OB=^2a; 0 * rules OB=^2^1; 0 * rules OB=^2&a; 0 * rules OB=^2&&; 0 * rules OB=^2&|; 0 * rules OB=^2|a; 0 * rules OB=^2|&; 0 * rules OB=^2||; 0 * rules OB=^2 0 * states DISCHRG=0&^6; 0 0 0 * states DISCHRG=0&^6; 1 0 1 * states DISCHRG=0&^6; 0 1 0 * states DISCHRG=0&^6; 1 1 0 * states OL=^0;OB=0;LB=3;RB=1;DISCHRG=0&^6;BYPASS=6; 0 0 0 0 1 0 0 0 0 0 * states OL=^0;OB=0;LB=3;RB=1;DISCHRG=0&^6;BYPASS=6; 1 0 0 0 0 1 0 0 1 0 * states OL=^0;OB=0;LB=3;RB=1;DISCHRG=0&^6;BYPASS=6; 0 1 0 0 1 0 1 0 0 0 * states OL=^0;OB=0;LB=3;RB=1;DISCHRG=0&^6;BYPASS=6; 1 1 0 0 0 1 1 0 1 0 * states OL=^0;OB=0;LB=3;RB=1;DISCHRG=0&^6;BYPASS=6; 0 0 1 0 1 0 0 1 0 0 * states OL=^0;OB=0;LB=3;RB=1;DISCHRG=0&^6;BYPASS=6; 1 0 1 0 0 1 0 1 1 0 * states OL=^0;OB=0;LB=3;RB=1;DISCHRG=0&^6;BYPASS=6; 0 1 1 0 1 0 1 1 0 0 * states OL=^0;OB=0;LB=3;RB=1;DISCHRG=0&^6;BYPASS=6; 1 1 1 0 0 1 1 1 1 0 * states OL=^0;OB=0;LB=3;RB=1;DISCHRG=0&^6;BYPASS=6; 0 0 0 1 1 0 0 0 0 1 * states OL=^0;OB=0;LB=3;RB=1;DISCHRG=0&^6;BYPASS=6; 1 0 0 1 0 1 0 0 0 1 * states OL=^0;OB=0;LB=3;RB=1;DISCHRG=0&^6;BYPASS=6; 0 1 0 1 1 0 1 0 0 1 * states OL=^0;OB=0;LB=3;RB=1;DISCHRG=0&^6;BYPASS=6; 1 1 0 1 0 1 1 0 0 1 * states OL=^0;OB=0;LB=3;RB=1;DISCHRG=0&^6;BYPASS=6; 0 0 1 1 1 0 0 1 0 1 * states OL=^0;OB=0;LB=3;RB=1;DISCHRG=0&^6;BYPASS=6; 1 0 1 1 0 1 0 1 0 1 * states OL=^0;OB=0;LB=3;RB=1;DISCHRG=0&^6;BYPASS=6; 0 1 1 1 1 0 1 1 0 1 * states OL=^0;OB=0;LB=3;RB=1;DISCHRG=0&^6;BYPASS=6; 1 1 1 1 0 1 1 1 0 1 * states OL=1; 0 0 * states OL=1; 1 1 * states OL=^1; 1 0 * states OL=^1; 0 1 * states OL=1|2; 0 0 0 * states OL=1|2; 1 0 1 * states OL=1|2; 0 1 1 * states OL=1|2; 1 1 1 * states OL=1&2; 0 0 0 * states OL=1&2; 1 0 0 * states OL=1&2; 0 1 0 * states OL=1&2; 1 1 1 * states OL=1&^2; 0 0 0 * states OL=1&^2; 1 0 1 * states OL=1&^2; 0 1 0 * states OL=1&^2; 1 1 0 * states OL=^1&2; 0 0 0 * states OL=^1&2; 1 0 0 * states OL=^1&2; 0 1 1 * states OL=^1&2; 1 1 0 * states OL=^1&^2; 0 0 1 * states OL=^1&^2; 1 0 0 * states OL=^1&^2; 0 1 0 * states OL=^1&^2; 1 1 0 * states OL=^1&^2; 1 1 0 * states TSTAO=1&2|3; 0 0 0 0 * states TSTAO=1&2|3; 1 0 0 0 * states TSTAO=1&2|3; 0 1 0 0 * states TSTAO=1&2|3; 1 1 0 1 * states TSTAO=1&2|3; 0 0 1 1 * states TSTAO=1&2|3; 1 0 1 1 * states TSTAO=1&2|3; 0 1 1 1 * states TSTAO=1&2|3; 1 1 1 1 * states TSTOA=1|2&3; 0 0 0 0 * states TSTOA=1|2&3; 1 0 0 1 * states TSTOA=1|2&3; 0 1 0 0 * states TSTOA=1|2&3; 1 1 0 1 * states TSTOA=1|2&3; 0 0 1 0 * states TSTOA=1|2&3; 1 0 1 1 * states TSTOA=1|2&3; 0 1 1 1 * states TSTOA=1|2&3; 1 1 1 1 * update OL=^0;OB=0&^6;LB=3&^6;RB=1&^6;DISCHRG=0&^6;BYPASS=6; 0 0 0 0 OL . . . * update OL=^0;OB=0&^6;LB=3&^6;RB=1&^6;DISCHRG=0&^6;BYPASS=6; 1 0 0 0 OB_DISCHRG discharging . . * update OL=^0;OB=0&^6;LB=3&^6;RB=1&^6;DISCHRG=0&^6;BYPASS=6; 0 1 0 0 OL_BYPASS . . . * update OL=^0;OB=0&^6;LB=3&^6;RB=1&^6;DISCHRG=0&^6;BYPASS=6; 1 1 0 0 BYPASS . . . * update OL=^0;OB=0&^6;LB=3&^6;RB=1&^6;DISCHRG=0&^6;BYPASS=6; 0 0 1 0 OL_LB . . . * update OL=^0;OB=0&^6;LB=3&^6;RB=1&^6;DISCHRG=0&^6;BYPASS=6; 1 0 1 0 OB_LB_DISCHRG discharging . . * update OL=^0;OB=0&^6;LB=3&^6;RB=1&^6;DISCHRG=0&^6;BYPASS=6; 0 1 1 0 OL_BYPASS . . . * update OL=^0;OB=0&^6;LB=3&^6;RB=1&^6;DISCHRG=0&^6;BYPASS=6; 1 1 1 0 BYPASS . . . * update OL=^0;OB=0&^6;LB=3&^6;RB=1&^6;DISCHRG=0&^6;BYPASS=6; 0 0 0 1 OL_RB . . . * update OL=^0;OB=0&^6;LB=3&^6;RB=1&^6;DISCHRG=0&^6;BYPASS=6; 1 0 0 1 OB_RB_DISCHRG discharging . . * update OL=^0;OB=0&^6;LB=3&^6;RB=1&^6;DISCHRG=0&^6;BYPASS=6; 0 1 0 1 OL_BYPASS . . . * update OL=^0;OB=0&^6;LB=3&^6;RB=1&^6;DISCHRG=0&^6;BYPASS=6; 1 1 0 1 BYPASS . . . * update OL=^0;OB=0&^6;LB=3&^6;RB=1&^6;DISCHRG=0&^6;BYPASS=6; 0 0 1 1 OL_LB_RB . . . * update OL=^0;OB=0&^6;LB=3&^6;RB=1&^6;DISCHRG=0&^6;BYPASS=6; 1 0 1 1 OB_LB_RB_DISCHRG discharging . . * update OL=^0;OB=0&^6;LB=3&^6;RB=1&^6;DISCHRG=0&^6;BYPASS=6; 0 1 1 1 OL_BYPASS . . . * update OL=^0;OB=0&^6;LB=3&^6;RB=1&^6;DISCHRG=0&^6;BYPASS=6; 1 1 1 1 BYPASS . . . * update OL=^0;OB=0&^6;LB=3&^6;RB=1&^6;DISCHRG=0&^6;BYPASS=6; 0 0 0 0 OL . 10 100 * update OL=^0;OB=0&^6;LB=3&^6;RB=1&^6;DISCHRG=0&^6;BYPASS=6; 1 0 0 0 OB_DISCHRG discharging 10 100 * update OL=^0;OB=0&^6;LB=3&^6;RB=1&^6;DISCHRG=0&^6;BYPASS=6; 0 1 0 0 OL_BYPASS . 10 . * update OL=^0;OB=0&^6;LB=3&^6;RB=1&^6;DISCHRG=0&^6;BYPASS=6; 1 1 0 0 BYPASS . 10 . * update OL=^0;OB=0&^6;LB=3&^6;RB=1&^6;DISCHRG=0&^6;BYPASS=6; 0 0 1 0 OL_LB . 10 10 * update OL=^0;OB=0&^6;LB=3&^6;RB=1&^6;DISCHRG=0&^6;BYPASS=6; 1 0 1 0 OB_LB_DISCHRG discharging 10 10 * update OL=^0;OB=0&^6;LB=3&^6;RB=1&^6;DISCHRG=0&^6;BYPASS=6; 0 1 1 0 OL_BYPASS . 10 . * update OL=^0;OB=0&^6;LB=3&^6;RB=1&^6;DISCHRG=0&^6;BYPASS=6; 1 1 1 0 BYPASS . 10 . * update OL=^0;OB=0&^6;LB=3&^6;RB=1&^6;DISCHRG=0&^6;BYPASS=6; 0 0 0 1 OL_RB . 10 100 * update OL=^0;OB=0&^6;LB=3&^6;RB=1&^6;DISCHRG=0&^6;BYPASS=6; 1 0 0 1 OB_RB_DISCHRG discharging 10 100 * update OL=^0;OB=0&^6;LB=3&^6;RB=1&^6;DISCHRG=0&^6;BYPASS=6; 0 1 0 1 OL_BYPASS . 10 . * update OL=^0;OB=0&^6;LB=3&^6;RB=1&^6;DISCHRG=0&^6;BYPASS=6; 1 1 0 1 BYPASS . 10 . * update OL=^0;OB=0&^6;LB=3&^6;RB=1&^6;DISCHRG=0&^6;BYPASS=6; 0 0 1 1 OL_LB_RB . 10 10 * update OL=^0;OB=0&^6;LB=3&^6;RB=1&^6;DISCHRG=0&^6;BYPASS=6; 1 0 1 1 OB_LB_RB_DISCHRG discharging 10 10 * update OL=^0;OB=0&^6;LB=3&^6;RB=1&^6;DISCHRG=0&^6;BYPASS=6; 0 1 1 1 OL_BYPASS . 10 . * update OL=^0;OB=0&^6;LB=3&^6;RB=1&^6;DISCHRG=0&^6;BYPASS=6; 1 1 1 1 BYPASS . 10 . * library OL=^0;OB=0;LB=3;RB=1;DISCHRG=0&^6;BYPASS=6; 0 gpiochip0 openclose * library OL=^0;OB=0;LB=3;RB=1;DISCHRG=0&^6;BYPASS=6; 1 gpiochip1 openclose * library OL=^0;OB=0;LB=3;RB=1;DISCHRG=0&^6;BYPASS=6; 1 gpiochip2 openclose * library OL=^0;OB=0;LB=3;RB=1;DISCHRG=0&^6;BYPASS=6; 0 gpiochip0 initinfo * library OL=^0;OB=0;LB=3;RB=1;DISCHRG=0&^6;BYPASS=6; 1 gpiochip0 initinfo * library OL=^0;OB=0;LB=3;RB=1;DISCHRG=0&^6;BYPASS=6; 0 gpiochip0 updateinfo * library OL=^0;OB=0;LB=3;RB=1;DISCHRG=0&^6;BYPASS=6; 1 gpiochip0 updateinfo * nut-2.8.1/tests/cpputest.cpp0000644000175000017500000000652414500336654013003 00000000000000/* cpputest - basic runner for unit tests Copyright (C) 2012 Emilien Kia 2020 Jim Klimov 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 2 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, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include #include #include #include #include #include #include "common.h" // Inspired by https://stackoverflow.com/a/66702001 class MyCustomProgressTestListener : public CppUnit::TextTestProgressListener { public: virtual void startTest(CppUnit::Test *test) override; }; // Implement out of class declaration to avoid // error: 'MyCustomProgressTestListener' has no out-of-line virtual method // definitions; its vtable will be emitted in every translation unit // [-Werror,-Wweak-vtables] void MyCustomProgressTestListener::startTest(CppUnit::Test *test) { //fprintf(stderr, "starting test %s\n", test->getName().c_str()); std::cerr << "starting test " << test->getName() << std::endl; } int main(int argc, char* argv[]) { bool verbose = false; if (argc > 1) { if (strcmp("-v", argv[1]) == 0 || strcmp("--verbose", argv[1]) == 0 ) { verbose = true; } } /* Get the top level suite from the registry */ std::cerr << "D: Getting test suite..." << std::endl; CppUnit::Test *suite = CppUnit::TestFactoryRegistry::getRegistry().makeTest(); /* Adds the test to the list of test to run */ std::cerr << "D: Preparing test runner..." << std::endl; CppUnit::TextUi::TestRunner runner; runner.addTest( suite ); /* Change the default outputter to a compiler error format outputter */ std::cerr << "D: Setting test runner outputter..." << std::endl; runner.setOutputter( new CppUnit::CompilerOutputter( &runner.result(), std::cerr ) ); if (verbose) { /* Add a listener to report test names */ std::cerr << "D: Setting test runner listener for test names..." << std::endl; MyCustomProgressTestListener progress; runner.eventManager().addListener(&progress); } /* Run the tests. */ bool wasSucessful = false; try { std::cerr << "D: Launching the test run..." << std::endl; wasSucessful = runner.run(); } catch ( std::invalid_argument &e ) // Test path not resolved { std::cerr << std::endl << "ERROR: " << e.what() << std::endl; wasSucessful = false; } /* Return error code 1 if the one of test failed. */ std::cerr << "D: Got to the end of test suite with code " << "'" << ( wasSucessful ? "true" : "false" ) << "'" << std::endl; return wasSucessful ? 0 : 1; } nut-2.8.1/tests/nutlogtest.c0000644000175000017500000000534014513167372013002 00000000000000/* nutlogtest - some trivial usage for upslog*() and upsdebug*() related * routines to sanity-check their code (compiler does not warn, test runs * do not crash). * * Copyright (C) * 2020-2023 Jim Klimov * * 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 2 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, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "config.h" #include "common.h" int main(void) { const char *s1 = "!NULL"; const char *s2 = NULL; #if (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_PUSH_POP) && (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_FORMAT_OVERFLOW) # pragma GCC diagnostic push # pragma GCC diagnostic ignored "-Wformat-overflow" #endif upsdebugx(0, "D: checking with libc handling of NULL (can segfault for some libc implementations):"); upsdebugx(0, "D: '%s' vs '%s'", s1, s2); /* This explicitly does not work with -Wformat, due to verbatim NULL without a var: * nutlogtest.c:20:5: error: reading through null pointer (argument 4) [-Werror=format=] * and also due to (void*) vs (char*) in naive case: * upsdebugx(0, "D: '%s' vs '%s'", NUT_STRARG(NULL), NULL); * but with casting the explicit NULL remains: * upsdebugx(0, "D: '%s' vs '%s'", NUT_STRARG((char *)NULL), (char *)NULL); */ upsdebugx(0, "D: checking with NUT_STRARG macro: '%s' vs '%s'", NUT_STRARG(s2), s2); #ifdef NUT_STRARG #undef NUT_STRARG #endif #define NUT_STRARG(x) (x?x:"") /* This explicitly does not work with -Wformat, due to a NULL in the '%s' * format string expansion (e.g. due to NUT PR #675 conversion to macros): * ../include/common.h:155:41: warning: '%s' directive argument is null [-Wformat-overflow=] * <...snip...> * nutlogtest.c:45:63: note: format string is defined here * 45 | upsdebugx(0, "D: checking with NUT_STRARG macro: '%s' vs '%s'", NUT_STRARG(s2), s2); * | ^~ */ upsdebugx(0, "D: checking that macro wrap trick works: '%s' vs '%s'", NUT_STRARG(s2), s2); #if (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_PUSH_POP) && (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_FORMAT_OVERFLOW) # pragma GCC diagnostic pop #endif return 0; } nut-2.8.1/tests/getvaluetest.c0000644000175000017500000002522114515702041013274 00000000000000/* getvaluetest - check that the bitness/endianness dependent conversions * of representation of numeric types between wire protocols and different * CPU computations produce expected results. * * See also: * https://github.com/networkupstools/nut/pull/1055 * https://github.com/networkupstools/nut/pull/1040 * https://github.com/networkupstools/nut/pull/1024 * https://github.com/networkupstools/nut/issues/1023 * * Copyright (C) * 2021 Nick Briggs * 2022 Jim Klimov * * 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 2 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, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "config.h" #include "nut_stdint.h" #include #include #include #include "hidtypes.h" #include "usb-common.h" #include "common.h" void GetValue(const unsigned char *Buf, HIDData_t *pData, long *pValue); static void Usage(char *name) { printf("%s [ ]\n", name); printf(" - string of hex digit pairs, space separated\n"); printf(" - offset of the report item value in bits, typically 0..31\n"); printf(" - size of the report item value in bits: typically 1..32\n"); printf(" - logical minimum value for report item\n"); printf(" - logical maximum value for report item\n"); printf(" - expected value\n"); printf("\n"); printf("%s \"0c 64 11 0d\" 8 16 0 65535 3345\n", name); printf("\nIf no arguments are given a builtin set of tests are run.\n"); } static void PrintBufAndData(uint8_t *buf, size_t bufSize, HIDData_t *pData) { size_t i; printf("buf \""); for (i = 0; i < bufSize - 1; i++) { printf("%02x ", buf[i]); } printf("%02x\"", buf[bufSize - 1]); printf(" offset %u size %u logmin %ld (0x%lx) logmax %ld (0x%lx)", pData->Offset, pData->Size, pData->LogMin, pData->LogMin, pData->LogMax, pData->LogMax); } static int RunBuiltInTests(char *argv[]) { int exitStatus = 0; size_t i; char *next; uint8_t reportBuf[64]; size_t bufSize; HIDData_t data; long value; static struct { char *buf; /* item data, starts with report id byte, then remaining report bytes */ uint8_t Offset; /* item offset in bits, typically 0..31 */ uint8_t Size; /* item size in bits, typically 1..32 */ long LogMin, LogMax; /* logical minimum and maximum values */ long expectedValue; /* the expected result of decoding the value in the buffer */ } testData[] = { {.buf = "00 ff ff ff ff", .Offset = 0, .Size = 32, .LogMin = -1, .LogMax = 2147483647, .expectedValue = -1}, {.buf = "00 ff", .Offset = 0, .Size = 8, .LogMin = -1, .LogMax = 127, .expectedValue = -1}, {.buf = "00 ff", .Offset = 0, .Size = 8, .LogMin = 0, .LogMax = 127, .expectedValue = 127}, {.buf = "00 ff", .Offset = 0, .Size = 8, .LogMin = 0, .LogMax = 255, .expectedValue = 255}, {.buf = "33 00 0a 08 80", .Offset = 0, .Size = 32, .LogMin = 0, .LogMax = 65535, .expectedValue = 2560}, {.buf = "00 00 08 00 00", .Offset = 0, .Size = 32, .LogMin = 0, .LogMax = 65535, .expectedValue = 2048}, {.buf = "06 00 00 08", .Offset = 0, .Size = 8, .LogMin = 0, .LogMax = 255, .expectedValue = 0}, {.buf = "06 00 00 08", .Offset = 8, .Size = 8, .LogMin = 0, .LogMax = 255, .expectedValue = 0}, {.buf = "06 00 00 08", .Offset = 16, .Size = 8, .LogMin = 0, .LogMax = 255, .expectedValue = 8}, {.buf = "16 0c 00 00 00", .Offset = 0, .Size = 1, .LogMin = 0, .LogMax = 1, .expectedValue = 0}, {.buf = "16 0c 00 00 00", .Offset = 1, .Size = 1, .LogMin = 0, .LogMax = 1, .expectedValue = 0}, {.buf = "16 0c 00 00 00", .Offset = 2, .Size = 1, .LogMin = 0, .LogMax = 1, .expectedValue = 1}, {.buf = "16 0c 00 00 00", .Offset = 3, .Size = 1, .LogMin = 0, .LogMax = 1, .expectedValue = 1}, {.buf = "16 0c 00 00 00", .Offset = 4, .Size = 1, .LogMin = 0, .LogMax = 1, .expectedValue = 0}, {.buf = "16 0c 00 00 00", .Offset = 5, .Size = 1, .LogMin = 0, .LogMax = 1, .expectedValue = 0}, {.buf = "16 0c 00 00 00", .Offset = 6, .Size = 1, .LogMin = 0, .LogMax = 1, .expectedValue = 0}, {.buf = "16 0c 00 00 00", .Offset = 7, .Size = 1, .LogMin = 0, .LogMax = 1, .expectedValue = 0}, {.buf = "16 0c 00 00 00", .Offset = 8, .Size = 1, .LogMin = 0, .LogMax = 1, .expectedValue = 0}, {.buf = "16 0c 00 00 00", .Offset = 9, .Size = 1, .LogMin = 0, .LogMax = 1, .expectedValue = 0}, {.buf = "16 0c 00 00 00", .Offset = 10, .Size = 1, .LogMin = 0, .LogMax = 1, .expectedValue = 0} }; /* See comments below about rdlen calculation emulation for tests */ usb_ctrl_char bufC[2]; signed char bufS[2]; unsigned char bufU[2]; int rdlen; NUT_UNUSED_VARIABLE(argv); for (i = 0; i < SIZEOF_ARRAY(testData); i++) { next = testData[i].buf; for (bufSize = 0; *next != 0; bufSize++) { reportBuf[bufSize] = (uint8_t) strtol(next, (char **)&next, 16); } memset((void *)&data, 0, sizeof(data)); data.Offset = testData[i].Offset; data.Size = testData[i].Size; data.LogMin = testData[i].LogMin; data.LogMax = testData[i].LogMax; GetValue(reportBuf, &data, &value); printf("Test #%" PRIiSIZE " ", i + 1); PrintBufAndData(reportBuf, bufSize, &data); if (value == testData[i].expectedValue) { printf(" value %ld PASS\n", value); } else { printf(" value %ld FAIL expected %ld\n", value, testData[i].expectedValue); exitStatus = 1; } } /* Emulate rdlen calculations in libusb{0,1}.c or * langid calculations in nutdrv_qx.c; in these * cases we take two bytes (cast from usb_ctrl_char * type, may be signed depending on used API version) * from the protocol buffer, and build a platform * dependent representation of a two-byte word. */ /* Example from issue https://github.com/networkupstools/nut/issues/1261 * where resulting length 0x01a9 should be "425" but ended up "-87" */ bufC[0] = (usb_ctrl_char)0xa9; bufC[1] = (usb_ctrl_char)0x01; bufS[0] = (signed char)0xa9; bufS[1] = (signed char)0x01; bufU[0] = (unsigned char)0xa9; bufU[1] = (unsigned char)0x01; /* Check different conversion methods and hope current build CPU, * C implementation etc. do not mess up bit-shifting vs rotation, * zeroing high bits, int type width extension et al. If something * is mismatched below, the production NUT code may need adaptations * for that platform to count stuff correctly! */ printf("\nTesting bit-shifting approaches used in codebase to get 2-byte int lengths from wire bytes:\n"); printf("(Expected correct value is '425', incorrect '-87' or other)\n"); #define REPORT_VERDICT(expected) { if (expected) { printf(" - PASS\n"); } else { printf(" - FAIL\n"); exitStatus = 1; } } rdlen = bufC[0] | (bufC[1] << 8); printf(" * reference: no casting, usb_ctrl_char :\t%d\t(depends on libusb API built against)", rdlen); REPORT_VERDICT (rdlen == 425 || rdlen == -87) rdlen = bufS[0] | (bufS[1] << 8); printf(" * reference: no casting, signed char :\t%d\t(expected '-87' here)", rdlen); REPORT_VERDICT (rdlen == -87) rdlen = bufU[0] | (bufU[1] << 8); printf(" * reference: no casting, unsigned char :\t%d\t(expected '425')", rdlen); REPORT_VERDICT (rdlen == 425) rdlen = (uint8_t)bufC[0] | ((uint8_t)bufC[1] << 8); printf(" * uint8_t casting, usb_ctrl_char :\t%d", rdlen); REPORT_VERDICT (rdlen == 425) rdlen = (uint8_t)bufS[0] | ((uint8_t)bufS[1] << 8); printf(" * uint8_t casting, signed char :\t%d", rdlen); REPORT_VERDICT (rdlen == 425) rdlen = (uint8_t)bufU[0] | ((uint8_t)bufU[1] << 8); printf(" * uint8_t casting, unsigned char :\t%d", rdlen); REPORT_VERDICT (rdlen == 425) rdlen = ((uint8_t)bufC[0]) | (((uint8_t)bufC[1]) << 8); printf(" * uint8_t casting with parentheses, usb_ctrl_char :\t%d", rdlen); REPORT_VERDICT (rdlen == 425) rdlen = ((uint8_t)bufS[0]) | (((uint8_t)bufS[1]) << 8); printf(" * uint8_t casting with parentheses, signed char :\t%d", rdlen); REPORT_VERDICT (rdlen == 425) rdlen = ((uint8_t)bufU[0]) | (((uint8_t)bufU[1]) << 8); printf(" * uint8_t casting with parentheses, unsigned char :\t%d", rdlen); REPORT_VERDICT (rdlen == 425) rdlen = ((uint16_t)(bufC[0]) & 0x00FF) | (((uint16_t)(bufC[1]) & 0x00FF) << 8); printf(" * uint16_t casting with 8-bit mask, usb_ctrl_char :\t%d", rdlen); REPORT_VERDICT (rdlen == 425) rdlen = ((uint16_t)(bufS[0]) & 0x00FF) | (((uint16_t)(bufS[1]) & 0x00FF) << 8); printf(" * uint16_t casting with 8-bit mask, signed char :\t%d", rdlen); REPORT_VERDICT (rdlen == 425) rdlen = ((uint16_t)(bufU[0]) & 0x00FF) | (((uint16_t)(bufU[1]) & 0x00FF) << 8); printf(" * uint16_t casting with 8-bit mask, unsigned char :\t%d", rdlen); REPORT_VERDICT (rdlen == 425) rdlen = 256 * (uint8_t)(bufC[1]) + (uint8_t)(bufC[0]); printf(" * uint8_t casting with multiplication, usb_ctrl_char :\t%d", rdlen); REPORT_VERDICT (rdlen == 425) rdlen = 256 * (uint8_t)(bufS[1]) + (uint8_t)(bufS[0]); printf(" * uint8_t casting with multiplication, signed char :\t%d", rdlen); REPORT_VERDICT (rdlen == 425) rdlen = 256 * (uint8_t)(bufU[1]) + (uint8_t)(bufU[0]); printf(" * uint8_t casting with multiplication, unsigned char :\t%d", rdlen); REPORT_VERDICT (rdlen == 425) return (exitStatus); } static int RunCommandLineTest(char *argv[]) { uint8_t reportBuf[64]; size_t bufSize; char *start, *end; HIDData_t data; long value, expectedValue; start = argv[1]; end = NULL; for (bufSize = 0; *start != 0; bufSize++) { reportBuf[bufSize] = (uint8_t) strtol(start, (char **)&end, 16); if (start == end) break; start = end; } memset((void *)&data, 0, sizeof(data)); data.Offset = (uint8_t) atoi(argv[2]); data.Size = (uint8_t) atoi(argv[3]); data.LogMin = strtol(argv[4], 0, 0); data.LogMax = strtol(argv[5], 0, 0); expectedValue = strtol(argv[6], 0, 0); GetValue(reportBuf, &data, &value); printf("Test #0 "); PrintBufAndData(reportBuf, bufSize, &data); if (value == expectedValue) { printf(" value %ld PASS\n", value); return (0); } else { printf(" value %ld FAIL expected %ld\n", value, expectedValue); return (1); } } int main (int argc, char *argv[]) { int status; switch (argc) { case 1: status = RunBuiltInTests(argv); break; case 7: status = RunCommandLineTest(argv); break; default: Usage(argv[0]); status = 2; } return(status); } nut-2.8.1/tests/generic_gpio_utest.c0000644000175000017500000003126014513167372014450 00000000000000/* generic_gpio_utest.c - gpio NUT driver code test tool * * Copyright (C) * 2023 Modris Berzonis * * 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 2 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, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #include "config.h" #include "main.h" #include "dstate.h" #include "attribute.h" #include "nut_stdint.h" #include "generic_gpio_utest.h" #include #include #include extern struct gpioups_t *gpioupsfd; static int done=0; static int test_with_exit; static jmp_buf env_buffer; static FILE * testData; static int fEof; static int cases_passed; static int cases_failed; static char * pass_fail[2] = {"pass", "fail"}; void getWithoutUnderscores(char *var) { fEof=fscanf(testData, "%s", var); for(int i=0; var[i]; i++) { if(var[i]=='_') var[i]=' '; } } #define MFR "CyberPower" #define MODEL "CyberShield CSN27U12V" #define DESCRIPTION "modem and DNS server UPS" int get_test_status(struct gpioups_t *result, int on_fail_path) { int expecting_failure; int upsLinesCount; /* no of lines used in rules */ int upsMaxLine; /* maximum line number referenced in rules */ int rulesCount; /* rules subitem count: no of NUT states defined in rules*/ char stateName[12]; /* NUT state name for rules in cRules */ int subCount; /* element count in translated rules subitem */ int ruleInt; int i, j; fEof = fscanf(testData, "%d", &expecting_failure); if (on_fail_path) { if(expecting_failure) cases_failed++; else cases_passed++; return expecting_failure; } if (!expecting_failure) { cases_failed++; printf("expecting case to fail\n"); return 1; } fEof = fscanf(testData, "%d", &upsLinesCount); if (result->upsLinesCount!=upsLinesCount) { cases_failed++; printf("expecting upsLinesCount %d, got %d\n", upsLinesCount, result->upsLinesCount); return 1; } fEof = fscanf(testData, "%d", &upsMaxLine); if (result->upsMaxLine!=upsMaxLine) { cases_failed++; printf("expecting rulesCount %d, got %d\n", upsMaxLine, result->upsMaxLine); return 1; } fEof = fscanf(testData, "%d", &rulesCount); if (result->rulesCount!=rulesCount) { cases_failed++; printf("expecting rulesCount %d, got %d\n", rulesCount, result->rulesCount); return 1; } for (i=0; irulesCount; i++) { fEof=fscanf(testData, "%s", stateName); if(!strcmp(result->rules[i]->stateName,stateName)) { cases_failed++; printf("expecting stateName %s, got %s for rule %d\n", stateName, result->rules[i]->stateName, i); return 1; } fEof=fscanf(testData, "%d", &subCount); if(result->rules[i]->subCount!=subCount) { cases_failed++; printf("expecting subCount %d, got %d for rule %d\n", result->rules[i]->subCount, subCount, i); return 1; } for (j=0; jrules[i]->cRules[j]!=ruleInt) { cases_failed++; printf("expecting cRule %d, got %d for rule %d subRule %d\n", ruleInt, result->rules[i]->cRules[j], i, j); return 1; } } } cases_passed++; return 0; } void exit(int code) { if (!done) { longjmp(env_buffer, 1); } else { _exit(code); } } int main(int argc, char **argv) { int jmp_result; char rules[128]; char testType[128]; char testDescFileNameBuf[LARGEBUF]; char *testDescFileName = "generic_gpio_test.txt"; unsigned int i; test_with_exit=0; if(argc==2) { testDescFileName=argv[1]; } testData = fopen (testDescFileName, "r"); if(!testData) { if (!strchr(testDescFileName, '/')) { /* "srcdir" may be set by automake test harness, see * https://www.gnu.org/software/automake/manual/1.12.2/html_node/Scripts_002dbased-Testsuites.html */ char *testDescFileDir = getenv("srcdir"); if (testDescFileDir) { printf("failed to open test description file %s " "in current working directory, " "retrying with srcdir %s\n", testDescFileName, testDescFileDir); if (snprintf(testDescFileNameBuf, sizeof(testDescFileNameBuf), "%s/%s", testDescFileDir, testDescFileName) > 0 ) { testDescFileName = testDescFileNameBuf; testData = fopen (testDescFileName, "r"); } } } if(!testData) { done = 1; printf("failed to open test description file %s\n", testDescFileName); exit(EXIT_FAILURE); } } cases_passed=0; cases_failed=0; fEof = 1; for (i=0; fEof!=EOF; i++) { char fmt[16]; #ifdef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL #pragma GCC diagnostic push #endif #ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL #pragma GCC diagnostic ignored "-Wformat-nonliteral" #endif #ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_FORMAT_SECURITY #pragma GCC diagnostic ignored "-Wformat-security" #endif /* To avoid safety warnings, must provide a limit * here (bufsize - 1), and use fixed format strings * because scanf() does not support asterisk for * width specifier; have to create it on the fly. */ snprintf(fmt, sizeof(fmt), "%%%" PRIuSIZE "s", sizeof(rules)-1); do { fEof=fscanf(testData, fmt, rules); } while(strcmp("*", rules)); snprintf(fmt, sizeof(fmt), "%%%" PRIuSIZE "s", sizeof(testType)-1); fEof=fscanf(testData, fmt, testType); snprintf(fmt, sizeof(fmt), "%%%" PRIuSIZE "s", sizeof(rules)-1); fEof=fscanf(testData, fmt, rules); #ifdef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL #pragma GCC diagnostic pop #endif if(fEof!=EOF) { if(!strcmp(testType, "rules")) { struct gpioups_t *upsfdtest=xcalloc(sizeof(*upsfdtest),1); jmp_result = setjmp(env_buffer); if(jmp_result) { /* test case exiting */ generic_gpio_close(upsfdtest); printf("%s %s test rule %u [%s]\n", pass_fail[get_test_status(upsfdtest, 1)], testType, i, rules); } else { /* run test case */ get_ups_rules(upsfdtest, (unsigned char *)rules); generic_gpio_close(upsfdtest); printf("%s %s test rule %u [%s]\n", pass_fail[get_test_status(upsfdtest, 0)], testType, i, rules); } } if(!strcmp(testType, "states")) { int expectedStateValue; int calculatedStateValue; struct gpioups_t *upsfdtest=xcalloc(sizeof(*upsfdtest),1); int j; get_ups_rules(upsfdtest, (unsigned char *)rules); upsfdtest->upsLinesStates=xcalloc(sizeof(int),upsfdtest->upsLinesCount); for (j=0; j < upsfdtest->upsLinesCount; j++) { fEof=fscanf(testData, "%d", &upsfdtest->upsLinesStates[j]); } for (j=0; j < upsfdtest->rulesCount; j++) { fEof=fscanf(testData, "%d", &expectedStateValue); calculatedStateValue=calc_rule_states(upsfdtest->upsLinesStates, upsfdtest->rules[j]->cRules, upsfdtest->rules[j]->subCount, 0); if (expectedStateValue==calculatedStateValue) { printf("%s %s test rule %u [%s]\n", pass_fail[0], testType, i, rules); cases_passed++; } else { printf("%s %s test rule %u [%s] %s", pass_fail[1], testType, i, rules, upsfdtest->rules[j]->stateName); for(int k=0; kupsLinesCount; k++) { printf(" %d", upsfdtest->upsLinesStates[k]); } printf("\n"); cases_failed++; } } generic_gpio_close(upsfdtest); } if(!strcmp(testType, "update")) { char upsStatus[256]; char chargeStatus[256]; char chargeLow[256]; char charge[256]; struct gpioups_t *upsfdtest=xcalloc(sizeof(*upsfdtest),1); int j; /* "volatile" trickery to avoid the likes of: * error: variable 'failed' might be clobbered by 'longjmp' or 'vfork' [-Werror=clobbered] * due to presence of setjmp(). */ int volatile failed = 0; const char * volatile currUpsStatus = NULL; const char * volatile currChargerStatus = NULL; const char * volatile currCharge = NULL; get_ups_rules(upsfdtest, (unsigned char *)rules); upsfdtest->upsLinesStates=xcalloc(sizeof(int),upsfdtest->upsLinesCount); for (j = 0; j < upsfdtest->upsLinesCount; j++) { fEof=fscanf(testData, "%d", &upsfdtest->upsLinesStates[j]); } getWithoutUnderscores(upsStatus); getWithoutUnderscores(chargeStatus); getWithoutUnderscores(chargeLow); getWithoutUnderscores(charge); if (strcmp(chargeLow, ".")) dstate_setinfo("battery.charge.low", "%s", chargeLow); jmp_result = setjmp(env_buffer); if (jmp_result) { failed=1; generic_gpio_close(upsfdtest); } else { update_ups_states(upsfdtest); currUpsStatus=dstate_getinfo("ups.status"); currChargerStatus=dstate_getinfo("battery.charger.status"); currCharge=dstate_getinfo("battery.charge"); if(strcmp(currUpsStatus, upsStatus)) failed=1; if( strcmp(chargeStatus,".") && (!currChargerStatus || strcmp(currChargerStatus, chargeStatus))) failed=1; if(!strcmp(chargeStatus,".") && currChargerStatus!=NULL) failed=1; if( strcmp(chargeLow,".") && strcmp(charge,".") && (!currCharge || strcmp(currCharge, charge))) failed=1; if(!strcmp(chargeLow,".") && !strcmp(charge,".") && currCharge!=NULL) failed=1; generic_gpio_close(upsfdtest); } printf("%s %s test rule %u [%s] ([%s] %s %s (%s)) ([%s] %s %s)\n", pass_fail[failed], testType, i, rules, upsStatus, chargeStatus, charge, chargeLow, NUT_STRARG(currUpsStatus), NUT_STRARG(currChargerStatus), NUT_STRARG(currCharge)); if (!failed) { cases_passed++; } else { cases_failed++; } vartab_free(); vartab_h = NULL; } if(!strcmp(testType, "library")) { char chipNameLocal[NUT_GPIO_CHIPNAMEBUF]; int expecting_failure, failed; char subType[NUT_GPIO_SUBTYPEBUF]; fEof=fscanf(testData, "%d", &expecting_failure); #ifdef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL #pragma GCC diagnostic push #endif #ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL #pragma GCC diagnostic ignored "-Wformat-nonliteral" #endif #ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_FORMAT_SECURITY #pragma GCC diagnostic ignored "-Wformat-security" #endif /* To avoid safety warnings, must provide a limit * here (bufsize - 1), and use fixed format strings * because scanf() does not support asterisk for * width specifier; have to create it on the fly. */ snprintf(fmt, sizeof(fmt), "%%%us", NUT_GPIO_CHIPNAMEBUF-1); fEof=fscanf(testData, fmt, chipNameLocal); snprintf(fmt, sizeof(fmt), "%%%us", NUT_GPIO_SUBTYPEBUF-1); fEof=fscanf(testData, fmt, subType); #ifdef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL #pragma GCC diagnostic pop #endif jmp_result = setjmp(env_buffer); failed = expecting_failure; if(jmp_result) { /* test case exiting */ if(expecting_failure) failed=0; upsdrv_cleanup(); } else { if(expecting_failure) failed=1; device_path = chipNameLocal; if(strcmp(subType, "initinfo") || !expecting_failure) { addvar(VAR_VALUE, "rules", ""); storeval("rules", rules); } addvar(VAR_VALUE, "mfr", MFR); storeval("mfr", MFR); addvar(VAR_VALUE, "model", MODEL); storeval("model", MODEL); dstate_setinfo("device.description", DESCRIPTION); upsdrv_initups(); if(!strcmp(subType, "initinfo")) { upsdrv_makevartable(); if(expecting_failure) setNextLinesReadToFail(); upsdrv_initinfo(); if(!dstate_getinfo("device.mfr") || strcmp(dstate_getinfo("device.mfr"), MFR) || !dstate_getinfo("device.model") || strcmp(dstate_getinfo("device.model"), MODEL) || !dstate_getinfo("device.description") || strcmp(dstate_getinfo("device.description"), DESCRIPTION)) failed=1; } if(!strcmp(subType, "updateinfo")) { int k; for(k=0; kupsLinesCount; k++) { gpioupsfd->upsLinesStates[k]=-1; } if(expecting_failure) setNextLinesReadToFail(); upsdrv_updateinfo(); for(k=0; kupsLinesCount && failed!=1; k++) { if(gpioupsfd->upsLinesStates[k]<0) failed=1; } } upsdrv_cleanup(); } printf("%s %s %s test rule %u [%s] %s %d\n", pass_fail[failed], testType, subType, i, rules, chipNameLocal, expecting_failure); if (!failed) { cases_passed++; } else { cases_failed++; } vartab_free(); vartab_h = NULL; } } } printf("test_rules completed. Total cases %d, passed %d, failed %d\n", cases_passed+cases_failed, cases_passed, cases_failed); fclose(testData); done = 1; } nut-2.8.1/tests/Makefile.am0000644000175000017500000001301514514200703012443 00000000000000# Network UPS Tools: tests SUBDIRS = . NIT all: $(TESTS) EXTRA_DIST = nut-driver-enumerator-test.sh nut-driver-enumerator-test--ups.conf TESTS = CLEANFILES = *.trs *.log AM_CFLAGS = -I$(top_srcdir)/include -I$(top_srcdir)/drivers AM_CXXFLAGS = -I$(top_srcdir)/include check_PROGRAMS = $(TESTS) check_SCRIPTS = # NUT Integration Testing suite check-NIT check-NIT-devel: cd "$(builddir)/NIT" && $(MAKE) $@ nutlogtest_SOURCES = nutlogtest.c nutlogtest_LDADD = $(top_builddir)/common/libcommon.la if REQUIRE_NUT_STRARG check_SCRIPTS += nutlogtest-nofail.sh CLEANFILES += nutlogtest-nofail.sh nutlogtest$(EXEEXT) nutlogtest nutlogtest-nofail.sh: nutlogtest$(EXEEXT) @echo '#!/bin/sh' > $@ @echo 'echo "WARNING: Your C library requires workarounds to print NULL values!" >&2' >> $@ @echo 'echo "If nutlogtest below, or generally some NUT program, crashes with" >&2' >> $@ @echo 'echo "a segmentation fault (especially during verbose debug) - that may be why" >&2' >> $@ @echo 'SCRIPT_DIR="`dirname "$$0"`"' >> $@ @echo '"$${SCRIPT_DIR}/nutlogtest" "$$@" || echo "nutlogtest FAILED but it was expected"' >> $@ @chmod +x $@ # NOTE: Keep the line above empty! else TESTS += nutlogtest$(EXEEXT) endif TESTS += nuttimetest nuttimetest_SOURCES = nuttimetest.c nuttimetest_LDADD = $(top_builddir)/common/libcommon.la # Separate the .deps of other dirs from this one LINKED_SOURCE_FILES = hidparser.c # NOTE: Not using "$<" due to a legacy Sun/illumos dmake bug with resolver # of dynamic vars, see e.g. https://man.omnios.org/man1/make#BUGS hidparser.c: $(top_srcdir)/drivers/hidparser.c test -s "$@" || ln -s -f "$(top_srcdir)/drivers/hidparser.c" "$@" if WITH_USB TESTS += getvaluetest getvaluetest_SOURCES = getvaluetest.c nodist_getvaluetest_SOURCES = hidparser.c # Pull the right include path for chosen libusb version: getvaluetest_CFLAGS = $(AM_CFLAGS) $(LIBUSB_CFLAGS) getvaluetest_LDADD = $(top_builddir)/common/libcommon.la else EXTRA_DIST += getvaluetest.c hidparser.c endif if WITH_GPIO TESTS += gpiotest # NOTE: Not using "$<" due to a legacy Sun/illumos dmake bug with resolver # of dynamic vars, see e.g. https://man.omnios.org/man1/make#BUGS generic_gpio_libgpiod.c: $(top_srcdir)/drivers/generic_gpio_libgpiod.c test -s "$@" || ln -s -f "$(top_srcdir)/drivers/generic_gpio_libgpiod.c" "$@" generic_gpio_common.c: $(top_srcdir)/drivers/generic_gpio_common.c test -s "$@" || ln -s -f "$(top_srcdir)/drivers/generic_gpio_common.c" "$@" gpiotest_SOURCES = generic_gpio_utest.c generic_gpio_liblocal.c nodist_gpiotest_SOURCES = generic_gpio_libgpiod.c generic_gpio_common.c gpiotest_LDADD = $(top_builddir)/drivers/libdummy_mockdrv.la gpiotest_CFLAGS = $(AM_CFLAGS) -I$(top_srcdir)/tests -DDRIVERS_MAIN_WITHOUT_MAIN=1 else EXTRA_DIST += generic_gpio_utest.c generic_gpio_liblocal.c endif CLEANFILES += generic_gpio_libgpiod.c generic_gpio_common.c EXTRA_DIST += generic_gpio_utest.h generic_gpio_test.txt # Make sure out-of-dir dependencies exist (especially when dev-building parts): $(top_builddir)/drivers/libdummy_mockdrv.la \ $(top_builddir)/common/libcommon.la: dummy @cd $(@D) && $(MAKE) $(AM_MAKEFLAGS) $(@F) ### Optional tests which can not be built everywhere # List of src files for CppUnit tests CPPUNITTESTSRC = example.cpp nutclienttest.cpp # The test driver which orchestrates running those tests above CPPUNITTESTERSRC = cpputest.cpp CPPCLIENTTESTSRC = cpputest-client.cpp TESTS_CXX11 = cppunittest if HAVE_CXX11 if HAVE_CPPUNIT # Note: per configure script this "SHOULD" also assume # that we HAVE_CXX11 - but better have it explicit TESTS += $(TESTS_CXX11) # Note: we only build it, but do not run directly (NIT prepares the sandbox) check_PROGRAMS += cppnit if WITH_VALGRIND check-local: $(check_PROGRAMS) RES=0; for P in $^ ; do $(VALGRIND) ./$$P || { RES=$$? ; echo "FAILED: $(VALGRIND) ./$$P" >&2; }; done; exit $$RES endif cppunittest_CXXFLAGS = $(AM_CXXFLAGS) $(CPPUNIT_CFLAGS) $(CPPUNIT_CXXFLAGS) $(CPPUNIT_NUT_CXXFLAGS) $(CXXFLAGS) cppunittest_LDFLAGS = $(CPPUNIT_LDFLAGS) $(CPPUNIT_LIBS) cppunittest_LDADD = $(top_builddir)/clients/libnutclient.la $(top_builddir)/clients/libnutclientstub.la cppunittest_SOURCES = $(CPPUNITTESTSRC) $(CPPUNITTESTERSRC) cppnit_CXXFLAGS = $(AM_CXXFLAGS) $(CPPUNIT_CFLAGS) $(CPPUNIT_CXXFLAGS) $(CPPUNIT_NUT_CXXFLAGS) $(CXXFLAGS) cppnit_LDFLAGS = $(CPPUNIT_LDFLAGS) $(CPPUNIT_LIBS) cppnit_LDADD = $(top_builddir)/clients/libnutclient.la $(top_builddir)/clients/libnutclientstub.la cppnit_SOURCES = $(CPPCLIENTTESTSRC) $(CPPUNITTESTERSRC) # Make sure out-of-dir C++ dependencies exist (especially when dev-building # only some parts of NUT): $(top_builddir)/clients/libnutclient.la \ $(top_builddir)/clients/libnutclientstub.la: dummy @cd $(@D) && $(MAKE) $(AM_MAKEFLAGS) $(@F) else !HAVE_CPPUNIT # Just redistribute test source into tarball if not building tests EXTRA_DIST += $(CPPUNITTESTSRC) $(CPPCLIENTTESTSRC) $(CPPUNITTESTERSRC) cppnit: @echo "SKIP: $@ not implemented without C++11 and CPPUNIT enabled" >&2 ; exit 1 endif !HAVE_CPPUNIT else !HAVE_CXX11 # Just redistribute test source into tarball if not building C++ at all EXTRA_DIST += $(CPPUNITTESTSRC) $(CPPCLIENTTESTSRC) $(CPPUNITTESTERSRC) cppnit: @echo "SKIP: $@ not implemented without C++11 and CPPUNIT enabled" >&2 ; exit 1 endif !HAVE_CXX11 dummy: BUILT_SOURCES = $(LINKED_SOURCE_FILES) CLEANFILES += $(LINKED_SOURCE_FILES) CLEANFILES += $(TESTS) $(TESTS_CXX11) MAINTAINERCLEANFILES = Makefile.in .dirstamp # NOTE: Do not clean ".deps" in SUBDIRS of the main project, # the root Makefile.am takes care of that! #clean-local: # $(AM_V_at)rm -rf $(builddir)/.deps nut-2.8.1/tests/nut-driver-enumerator-test--ups.conf0000644000175000017500000000264614377374134017424 00000000000000# This is an ups.conf file for nut-driver-enumerator-test.sh # It is intentionally written in different samples of markup, # do not clean it up ;) maxstartdelay=180 globalflag [dummy1] driver = dummy-ups port = file1.dev desc = "This is ups-1" [epdu-2] # This is an ePDU driver=netxml-ups port="http://172.16.1.2" synchronous=yes [epdu-2-snmp] driver=snmp-ups port=172.16.1.2 synchronous=no [usb_3] driver = "usbhid-ups" port = "auto" [serial.4] driver = serial-ups driverflag port = /dev/ttyS1 # some path [dummy-proxy] driver = "dummy-ups " port = remoteUPS@RemoteHost.local [dummy-proxy-localhost] driver = 'dummy-ups ' port = "localUPS@127.0.0.1" [valueHasEquals] driver = dummy=ups port = file1.dev # key = val, right? [valueHasHashtag] driver = dummy-ups port = file#1.dev [valueHasQuotedHashtag] driver = dummy-ups port = "file#1.dev" [qx-serial] driver=nutdrv_qx port = /dev/ttyb [qx-usb1] driver=nutdrv_qx port = auto [qx-usb2] driver=nutdrv_qx port = /dev/usb/8 [sectionWithComment]# Some comment driver=nutdrv_qx#comment port = /dev/usb/8 desc="value with [brackets]" [brackets with spaces are not sections] # but rather an invalid mess as binary parser may think [sectionWithCommentWhitespace] # Some comment with a space and tab driver=nutdrv_qx # comment port = /dev/usb/8 # comment commentedDriverFlag # This flag gotta mean something nut-2.8.1/tests/nutclienttest.cpp0000644000175000017500000003263114500336654014037 00000000000000/* nutclienttest - CppUnit nutclient unit test Copyright (C) 2016 Emilien Kia Copyright (C) 2020 - 2021 Jim Klimov 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 2 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, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "common.h" /* Current CPPUnit offends the honor of C++98 */ #if (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_PUSH_POP) && (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_EXIT_TIME_DESTRUCTORS || defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_GLOBAL_CONSTRUCTORS) #pragma GCC diagnostic push # ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_GLOBAL_CONSTRUCTORS # pragma GCC diagnostic ignored "-Wglobal-constructors" # endif # ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_EXIT_TIME_DESTRUCTORS # pragma GCC diagnostic ignored "-Wexit-time-destructors" # endif #endif #include namespace nut { class NutClientTest : public CppUnit::TestFixture { CPPUNIT_TEST_SUITE( NutClientTest ); CPPUNIT_TEST( test_strarr_alloc ); CPPUNIT_TEST( test_stringset_to_strarr ); CPPUNIT_TEST( test_stringvector_to_strarr ); CPPUNIT_TEST( test_copy_constructor_dev ); CPPUNIT_TEST( test_copy_assignment_dev ); CPPUNIT_TEST( test_copy_constructor_cmd ); CPPUNIT_TEST( test_copy_assignment_cmd ); CPPUNIT_TEST( test_copy_constructor_var ); CPPUNIT_TEST( test_copy_assignment_var ); CPPUNIT_TEST( test_nutclientstub_dev ); CPPUNIT_TEST_SUITE_END(); public: void setUp() override; void tearDown() override; void test_strarr_alloc(); void test_stringset_to_strarr(); void test_stringvector_to_strarr(); void test_copy_constructor_dev(); void test_copy_assignment_dev(); void test_copy_constructor_cmd(); void test_copy_assignment_cmd(); void test_copy_constructor_var(); void test_copy_assignment_var(); void test_nutclientstub_dev(); }; // Registers the fixture into the 'registry' CPPUNIT_TEST_SUITE_REGISTRATION( NutClientTest ); } // namespace nut {} #ifndef _NUTCLIENTTEST_BUILD # define _NUTCLIENTTEST_BUILD 1 #endif #include "../clients/nutclient.h" #include "../clients/nutclientmem.h" namespace nut { extern "C" { strarr stringset_to_strarr(const std::set& strset); strarr stringvector_to_strarr(const std::vector& strset); } // extern "C" void NutClientTest::setUp() { } void NutClientTest::tearDown() { } void NutClientTest::test_strarr_alloc() { bool noException = true; strarr arr = nullptr; try { arr = strarr_alloc(5); } catch(nut::NutException& ex) { NUT_UNUSED_VARIABLE(ex); noException = false; } CPPUNIT_ASSERT_MESSAGE( "Failed strarr_alloc(...): throw exception", noException); CPPUNIT_ASSERT_MESSAGE( "Failed strarr_alloc(...): result is null", arr != nullptr); strarr_free(arr); } void NutClientTest::test_stringset_to_strarr() { std::set strset; strset.insert("test"); strset.insert("hello"); strset.insert("world"); strarr arr = stringset_to_strarr(strset); CPPUNIT_ASSERT_MESSAGE( "stringset_to_strarr(...) result is null", arr != nullptr); std::set res; char** ptr = arr; while(*ptr != nullptr) { res.insert(std::string(*ptr)); ptr++; } CPPUNIT_ASSERT_EQUAL_MESSAGE( "stringset_to_strarr(...) result has not 3 items", static_cast(3), res.size()); CPPUNIT_ASSERT_MESSAGE( "stringset_to_strarr(...) result has not item \"test\"", res.find("test") != res.end()); CPPUNIT_ASSERT_MESSAGE( "stringset_to_strarr(...) result has not item \"hello\"", res.find("hello") != res.end()); CPPUNIT_ASSERT_MESSAGE( "stringset_to_strarr(...) result has not item \"world\"", res.find("world") != res.end()); strarr_free(arr); } void NutClientTest::test_stringvector_to_strarr() { std::vector strset; strset.push_back("test"); strset.push_back("hello"); strset.push_back("world"); strarr arr = stringvector_to_strarr(strset); CPPUNIT_ASSERT_MESSAGE( "stringvector_to_strarr(...) result is null", arr != nullptr); char** ptr = arr; CPPUNIT_ASSERT_EQUAL_MESSAGE( "stringvector_to_strarr(...) result has not item 0==\"test\"", std::string("test"), std::string(*ptr)); ++ptr; CPPUNIT_ASSERT_EQUAL_MESSAGE( "stringvector_to_strarr(...) result has not item 1==\"hello\"", std::string("hello"), std::string(*ptr)); ++ptr; CPPUNIT_ASSERT_EQUAL_MESSAGE( "stringvector_to_strarr(...) result has not item 2==\"world\"", std::string("world"), std::string(*ptr)); ++ptr; /* https://stackoverflow.com/a/12565009/4715872 * Can not compare nullptr_t and another data type (char*) * with CPPUNIT template assertEquals() */ CPPUNIT_ASSERT_MESSAGE( "stringvector_to_strarr(...) result has not only 3 items", nullptr == *ptr); strarr_free(arr); } void NutClientTest::test_copy_constructor_dev() { nut::TcpClient c; nut::Device i(&c, "ups1"); nut::Device j(i); CPPUNIT_ASSERT_EQUAL_MESSAGE( "Failed to assign value of Device variable j by initializing from i", i, j); } void NutClientTest::test_copy_assignment_dev() { nut::TcpClient c; nut::Device i(&c, "ups1"); nut::Device j(nullptr, "ups2"); CPPUNIT_ASSERT_ASSERTION_FAIL_MESSAGE( "Device variables i and j were initialized differently " "but claim to be equal", CPPUNIT_ASSERT_EQUAL(i, j) ); j = i; CPPUNIT_ASSERT_EQUAL_MESSAGE( "Failed to assign value of Device Command j by equating to i", i, j); } void NutClientTest::test_copy_constructor_cmd() { nut::TcpClient c; nut::Device d(nullptr, "ups1"); nut::Command i(&d, "cmd1"); nut::Command j(i); CPPUNIT_ASSERT_EQUAL_MESSAGE( "Failed to assign value of Command variable j by initializing from i", i, j); } void NutClientTest::test_copy_assignment_cmd() { nut::TcpClient c; nut::Device d(nullptr, "ups1"); nut::Command i(&d, "var1"); nut::Command j(nullptr, "var2"); CPPUNIT_ASSERT_ASSERTION_FAIL_MESSAGE( "Command variables i and j were initialized differently " "but claim to be equal", CPPUNIT_ASSERT_EQUAL(i, j) ); j = i; CPPUNIT_ASSERT_EQUAL_MESSAGE( "Failed to assign value of Command variable j by equating to i", i, j); } void NutClientTest::test_copy_constructor_var() { nut::TcpClient c; nut::Device d(nullptr, "ups1"); nut::Variable i(&d, "var1"); nut::Variable j(i); CPPUNIT_ASSERT_EQUAL_MESSAGE( "Failed to assign value of Variable variable j by initializing from i", i, j); } void NutClientTest::test_copy_assignment_var() { nut::TcpClient c; nut::Device d(nullptr, "ups1"); nut::Variable i(&d, "var1"); nut::Variable j(nullptr, "var2"); CPPUNIT_ASSERT_ASSERTION_FAIL_MESSAGE( "Variable variables i and j were initialized differently " "but claim to be equal", CPPUNIT_ASSERT_EQUAL(i, j) ); j = i; CPPUNIT_ASSERT_EQUAL_MESSAGE( "Failed to assign value of Variable variable j by equating to i", i, j); } void NutClientTest::test_nutclientstub_dev() { bool noException = true; nut::MemClientStub c; nut::Device d(nullptr, "ups_1"); try { // set mono value c.setDeviceVariable("ups_1", "name_1", "value_1"); // get mono value ListValue values = c.getDeviceVariableValue("ups_1", "name_1"); CPPUNIT_ASSERT_MESSAGE( "Failed stub tcp client: mono wrong values number", values.size() == 1); CPPUNIT_ASSERT_MESSAGE( "Failed stub tcp client: mono bad value", values[0] == std::string("value_1")); // set multi value ListValue values_multi = { "multi_1", "multi_2" }; c.setDeviceVariable("ups_1", "name_multi_1", values_multi); // get multi value values = c.getDeviceVariableValue("ups_1", "name_multi_1"); CPPUNIT_ASSERT_MESSAGE( "Failed stub tcp client: multi wrong values number", values.size() == 2); CPPUNIT_ASSERT_MESSAGE( "Failed stub tcp client: multi first bad value", values[0] == std::string("multi_1")); CPPUNIT_ASSERT_MESSAGE( "Failed stub tcp client: multi second bad value", values[1] == std::string("multi_2")); // get object values ListObject objects = c.getDeviceVariableValues("ups_1"); CPPUNIT_ASSERT_MESSAGE( "Failed stub tcp client: objects wrong values number", objects.size() == 2); CPPUNIT_ASSERT_MESSAGE( "Failed stub tcp client: objects mono wrong values number", objects["name_1"].size() == 1); CPPUNIT_ASSERT_MESSAGE( "Failed stub tcp client: objects mono bad value", objects["name_1"][0] == std::string("value_1")); CPPUNIT_ASSERT_MESSAGE( "Failed stub tcp client: objects multi wrong values number", objects["name_multi_1"].size() == 2); CPPUNIT_ASSERT_MESSAGE( "Failed stub tcp client: objects mono bad value", objects["name_multi_1"][0] == std::string("multi_1")); CPPUNIT_ASSERT_MESSAGE( "Failed stub tcp client: objects mono bad value", objects["name_multi_1"][1] == std::string("multi_2")); // get device values std::set devices_name = { "ups_1" }; ListDevice devices = c.getDevicesVariableValues(devices_name); CPPUNIT_ASSERT_MESSAGE( "Failed stub tcp client: devices wrong values number", devices.size() == 1); CPPUNIT_ASSERT_MESSAGE( "Failed stub tcp client: devices mono wrong values number", devices["ups_1"]["name_1"].size() == 1); CPPUNIT_ASSERT_MESSAGE( "Failed stub tcp client: devices mono bad value", devices["ups_1"]["name_1"][0] == std::string("value_1")); CPPUNIT_ASSERT_MESSAGE( "Failed stub tcp client: devices multi wrong values number", devices["ups_1"]["name_multi_1"].size() == 2); CPPUNIT_ASSERT_MESSAGE( "Failed stub tcp client: devices mono bad value", devices["ups_1"]["name_multi_1"][0] == std::string("multi_1")); CPPUNIT_ASSERT_MESSAGE( "Failed stub tcp client: devices mono bad value", devices["ups_1"]["name_multi_1"][1] == std::string("multi_2")); } catch(nut::NutException& ex) { NUT_UNUSED_VARIABLE(ex); noException = false; } CPPUNIT_ASSERT_MESSAGE( "Failed stub tcp client: throw exception", noException); // List of functions not implemented (should return exception) noException = true; try { std::set cmd = c.getDeviceCommandNames("ups-1"); CPPUNIT_ASSERT_MESSAGE( "Variable not use", cmd.size() == 0); } catch(nut::NutException& ex) { NUT_UNUSED_VARIABLE(ex); noException = false; } CPPUNIT_ASSERT_MESSAGE( "Failed stub tcp client: throw no exception", !noException); noException = true; try { std::string desc = c.getDeviceCommandDescription("ups-1", "cmd-1"); CPPUNIT_ASSERT_MESSAGE( "Variable not use", desc.empty()); } catch(nut::NutException& ex) { NUT_UNUSED_VARIABLE(ex); noException = false; } CPPUNIT_ASSERT_MESSAGE( "Failed stub tcp client: throw no exception", !noException); noException = true; try { TrackingID id = c.executeDeviceCommand("ups-1", "cmd-1", "param-1"); CPPUNIT_ASSERT_MESSAGE( "Variable not use", id.empty()); } catch(nut::NutException& ex) { NUT_UNUSED_VARIABLE(ex); noException = false; } CPPUNIT_ASSERT_MESSAGE( "Failed stub tcp client: throw no exception", !noException); noException = true; try { c.deviceLogin("ups-1"); } catch(nut::NutException& ex) { NUT_UNUSED_VARIABLE(ex); noException = false; } CPPUNIT_ASSERT_MESSAGE( "Failed stub tcp client: throw no exception", !noException); noException = true; try { c.deviceMaster("ups-1"); } catch(nut::NutException& ex) { NUT_UNUSED_VARIABLE(ex); noException = false; } CPPUNIT_ASSERT_MESSAGE( "Failed stub tcp client: throw no exception", !noException); noException = true; try { c.deviceForcedShutdown("ups-1"); } catch(nut::NutException& ex) { NUT_UNUSED_VARIABLE(ex); noException = false; } CPPUNIT_ASSERT_MESSAGE( "Failed stub tcp client: throw no exception", !noException); noException = true; try { c.deviceGetNumLogins("ups-1"); } catch(nut::NutException& ex) { NUT_UNUSED_VARIABLE(ex); noException = false; } CPPUNIT_ASSERT_MESSAGE( "Failed stub tcp client: throw no exception", !noException); noException = true; try { TrackingResult result = c.getTrackingResult("track-1"); CPPUNIT_ASSERT_MESSAGE( "Variable not use", result == TrackingResult::SUCCESS); } catch(nut::NutException& ex) { NUT_UNUSED_VARIABLE(ex); noException = false; } CPPUNIT_ASSERT_MESSAGE( "Failed stub tcp client: throw no exception", !noException); noException = true; try { bool status = c.isFeatureEnabled(Feature("feature-1")); CPPUNIT_ASSERT_MESSAGE( "Variable not use", !status); } catch(nut::NutException& ex) { NUT_UNUSED_VARIABLE(ex); noException = false; } CPPUNIT_ASSERT_MESSAGE( "Failed stub tcp client: throw no exception", !noException); noException = true; try { c.setFeature(Feature("feature-1"), true); } catch(nut::NutException& ex) { NUT_UNUSED_VARIABLE(ex); noException = false; } CPPUNIT_ASSERT_MESSAGE( "Failed stub tcp client: throw no exception", !noException); } } // namespace nut {} #if (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_PUSH_POP) && (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_EXIT_TIME_DESTRUCTORS || defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_GLOBAL_CONSTRUCTORS) #pragma GCC diagnostic pop #endif nut-2.8.1/tests/nut-driver-enumerator-test.sh0000755000175000017500000002712714500336654016224 00000000000000#!/bin/sh # Copyright (C) 2018 Eaton # # 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 2 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, write to the Free Software Foundation, Inc., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. # #! \file nut-driver-enumerator-test.sh # \author Jim Klimov # \brief Self-test for nut-driver-enumerator.sh utility # \details Automated sanity test for nut-driver-enumerator.sh(.in) # using different shells (per $SHELL_PROGS) and CLI requests # for regression and compatibility tests as well as for TDD # fueled by pre-decided expected outcomes. ### Use a standard locale setup so sorting in expected results is not confused LANG=C LC_ALL=C TZ=UTC export LANG LC_ALL TZ ### Note: These are relative to where the selftest script lives, ### not the NUT top_srcdir etc. They can be exported by a Makefile. [ -n "${BUILDDIR-}" ] || BUILDDIR="`dirname $0`" [ -n "${SRCDIR-}" ] || SRCDIR="`dirname $0`" [ -n "${SHELL_PROGS-}" ] || SHELL_PROGS="/bin/sh" case "${DEBUG-}" in [Yy]|[Yy][Ee][Ss]) DEBUG=yes ;; [Tt][Rr][Aa][Cc][Ee]) DEBUG=trace ;; *) DEBUG="" ;; esac SYSTEMD_CONFPATH="${BUILDDIR}/selftest-rw/systemd-units" export SYSTEMD_CONFPATH NUT_CONFPATH="${BUILDDIR}/selftest-rw/nut" export NUT_CONFPATH [ -n "${UPSCONF-}" ] || UPSCONF="${SRCDIR}/nut-driver-enumerator-test--ups.conf" [ ! -s "${UPSCONF-}" ] && echo "FATAL : testing ups.conf not found as '$UPSCONF'" >&2 && exit 1 export UPSCONF if [ ! -n "${NDE-}" ] ; then for NDE in \ "${BUILDDIR}/../scripts/upsdrvsvcctl/nut-driver-enumerator.sh" \ "${SRCDIR}/../scripts/upsdrvsvcctl/nut-driver-enumerator.sh.in" \ ; do [ -s "$NDE" ] && break ; done fi [ ! -s "${NDE-}" ] && echo "FATAL : testing nut-driver-enumerator.sh implementation not found as '$NDE'" >&2 && exit 1 # TODO : Add tests that generate configuration files for units #mkdir -p "${NUT_CONFPATH}" "${SYSTEMD_CONFPATH}" || exit FAIL_COUNT=0 GOOD_COUNT=0 callNDE() { case "$DEBUG" in yes) time $USE_SHELL $NDE "$@" ;; trace) time $USE_SHELL -x $NDE "$@" ;; *) $USE_SHELL $NDE "$@" 2>/dev/null ;; esac } run_testcase() { # First 3 args are required as defined below; the rest are # CLI arg(s) to nut-driver-enumerator.sh CASE_DESCR="$1" EXPECT_CODE="$2" EXPECT_TEXT="$3" shift 3 printf "Testing : SHELL='%s'\tCASE='%s'\t" "$USE_SHELL" "$CASE_DESCR" OUT="`callNDE "$@"`" ; RESCODE=$? printf "Got : RESCODE='%s'\t" "$RESCODE" RES=0 if [ "$RESCODE" = "$EXPECT_CODE" ]; then printf "STATUS_CODE='MATCHED'\t" GOOD_COUNT="`expr $GOOD_COUNT + 1`" else printf "STATUS_CODE='MISMATCH' expect_code=%s received_code=%s\t" "$EXPECT_CODE" "$RESCODE" >&2 FAIL_COUNT="`expr $FAIL_COUNT + 1`" RES="`expr $RES + 1`" fi if [ "$OUT" = "$EXPECT_TEXT" ]; then printf "STATUS_TEXT='MATCHED'\n" GOOD_COUNT="`expr $GOOD_COUNT + 1`" else printf "STATUS_TEXT='MISMATCH'\n" printf '\t--- expected ---\n%s\n\t--- received ---\n%s\n\t--- MISMATCH ABOVE\n\n' "$EXPECT_TEXT" "$OUT" >&2 # Give a nice output to help track the problem: ( rm -f "/tmp/.nde.text.expected.$$" "/tmp/.nde.text.actual.$$" \ && echo "$EXPECT_TEXT" > "/tmp/.nde.text.expected.$$" \ && echo "$OUT" > "/tmp/.nde.text.actual.$$" \ && diff -u "/tmp/.nde.text.expected.$$" "/tmp/.nde.text.actual.$$" ) 2>/dev/null || true rm -f "/tmp/.nde.text.expected.$$" "/tmp/.nde.text.actual.$$" FAIL_COUNT="`expr $FAIL_COUNT + 1`" RES="`expr $RES + 2`" fi if [ "$RES" != 0 ] || [ -n "$DEBUG" ] ; then echo "" ; fi return $RES } ################################################################## # Note: expectations in test cases below are tightly connected # # to both the current code in the script and content of the test # # configuration file. # ################################################################## testcase_bogus_args() { run_testcase "Reject unknown args" 1 "" \ --some-bogus-arg } testcase_list_all_devices() { # We expect a list of unbracketed names from the device sections # Note: unlike other outputs, this list is alphabetically sorted run_testcase "List all device names from sections" 0 \ "dummy-proxy dummy-proxy-localhost dummy1 epdu-2 epdu-2-snmp qx-serial qx-usb1 qx-usb2 sectionWithComment sectionWithCommentWhitespace serial.4 usb_3 valueHasEquals valueHasHashtag valueHasQuotedHashtag" \ --list-devices } testcase_show_all_configs() { # We expect whitespace trimmed, comment-only lines removed run_testcase "Show all configs" 0 \ 'maxstartdelay=180 globalflag [dummy1] driver=dummy-ups port=file1.dev desc="This is ups-1" [epdu-2] driver=netxml-ups port=http://172.16.1.2 synchronous=yes [epdu-2-snmp] driver=snmp-ups port=172.16.1.2 synchronous=no [usb_3] driver=usbhid-ups port=auto [serial.4] driver=serial-ups driverflag port=/dev/ttyS1 # some path [dummy-proxy] driver="dummy-ups " port=remoteUPS@RemoteHost.local [dummy-proxy-localhost] driver='"'dummy-ups '"' port=localUPS@127.0.0.1 [valueHasEquals] driver=dummy=ups port=file1.dev # key = val, right? [valueHasHashtag] driver=dummy-ups port=file#1.dev [valueHasQuotedHashtag] driver=dummy-ups port=file#1.dev [qx-serial] driver=nutdrv_qx port=/dev/ttyb [qx-usb1] driver=nutdrv_qx port=auto [qx-usb2] driver=nutdrv_qx port=/dev/usb/8 [sectionWithComment] driver=nutdrv_qx#comment port=/dev/usb/8 desc="value with [brackets]" [brackets with spaces are not sections] # but rather an invalid mess as binary parser may think [sectionWithCommentWhitespace] driver=nutdrv_qx # comment port=/dev/usb/8 # comment commentedDriverFlag # This flag gotta mean something' \ --show-all-configs } testcase_upslist_debug() { # We expect a list of names, ports and decided MEDIA type (for dependencies) run_testcase "List decided MEDIA and config checksums for all devices" 0 \ "INST: 68b329da9893e34099c7d8ad5cb9c940~[]: DRV='' PORT='' MEDIA='' SECTIONMD5='9a1f372a850f1ee3ab1fc08b185783e0' INST: 010cf0aed6dd49865bb49b70267946f5~[dummy-proxy]: DRV='dummy-ups ' PORT='remoteUPS@RemoteHost.local' MEDIA='network' SECTIONMD5='aff543fc07d7fbf83e81001b181c8b97' INST: 1ea79c6eea3681ba73cc695f3253e605~[dummy-proxy-localhost]: DRV='dummy-ups ' PORT='localUPS@127.0.0.1' MEDIA='network-localhost' SECTIONMD5='73e6b7e3e3b73558dc15253d8cca51b2' INST: 76b645e28b0b53122b4428f4ab9eb4b9~[dummy1]: DRV='dummy-ups' PORT='file1.dev' MEDIA='' SECTIONMD5='9e0a326b67e00d455494f8b4258a01f1' INST: a293d65e62e89d6cc3ac6cb88bc312b8~[epdu-2]: DRV='netxml-ups' PORT='http://172.16.1.2' MEDIA='network' SECTIONMD5='0d9a0147dcf87c7c720e341170f69ed4' INST: 9a5561464ff8c78dd7cb544740ce2adc~[epdu-2-snmp]: DRV='snmp-ups' PORT='172.16.1.2' MEDIA='network' SECTIONMD5='2631b6c21140cea0dd30bb88b942ce3f' INST: 16adbdafb22d9fdff1d09038520eb32e~[qx-serial]: DRV='nutdrv_qx' PORT='/dev/ttyb' MEDIA='serial' SECTIONMD5='e3e6e586fbe5b3c0a89432f4b993f4ad' INST: a21bd2b786228b9619f6adba6db8fa83~[qx-usb1]: DRV='nutdrv_qx' PORT='auto' MEDIA='usb' SECTIONMD5='a6139c5da35bef89dc5b96e2296f5369' INST: 0066605e07c66043a17eccecbeea1ac5~[qx-usb2]: DRV='nutdrv_qx' PORT='/dev/usb/8' MEDIA='usb' SECTIONMD5='5722dd9c21d07a1f5bcb516dbc458deb' INST: 1280a731e03116f77290e51dd2a2f37e~[sectionWithComment]: DRV='nutdrv_qx#comment' PORT='/dev/usb/8' MEDIA='' SECTIONMD5='be30e15e17d0579c85eecaf176b4a064' INST: 770abd5659061a29ed3ae4f7c0b00915~[sectionWithCommentWhitespace]: DRV='nutdrv_qx # comment' PORT='/dev/usb/8 # comment' MEDIA='' SECTIONMD5='c757822a331521cdc97310d0241eba28' INST: efdb1b4698215fdca36b9bc06d24661d~[serial.4]: DRV='serial-ups' PORT='/dev/ttyS1 # some path' MEDIA='' SECTIONMD5='9c485f733aa6d6c85c1724f162929443' INST: f4a1c33db201c2ca897a3337993c10fc~[usb_3]: DRV='usbhid-ups' PORT='auto' MEDIA='usb' SECTIONMD5='1f6a24becde9bd31c9852610658ef84a' INST: 8e5686f92a5ba11901996c813e7bb23d~[valueHasEquals]: DRV='dummy=ups' PORT='file1.dev # key = val, right?' MEDIA='' SECTIONMD5='2f04d65da53e3b13771bb65422f0f4c0' INST: 99da99b1e301e84f34f349443aac545b~[valueHasHashtag]: DRV='dummy-ups' PORT='file#1.dev' MEDIA='' SECTIONMD5='6029bda216de0cf1e81bd55ebd4a0fff' INST: d50c3281f9b68a94bf9df72a115fbb5c~[valueHasQuotedHashtag]: DRV='dummy-ups' PORT='file#1.dev' MEDIA='' SECTIONMD5='af59c3c0caaa68dcd796d7145ae403ee'" \ upslist_debug # FIXME : in [valueHasEquals] and [serial.4] the PORT value is quite bogus # with its embedded comments. Check vs. binary config parser, whether in # unquoted case only first token is the valid value, and how comments are # handled in general? # FIXME : in [valueHasHashtag] the line after "#" should likely be dropped # (check in binary config parser first) while in [valueHasQuotedHashtag] # it should stay. } testcase_getValue() { run_testcase "Query a configuration key (SDP)" 0 \ "file1.dev" \ --show-device-config-value dummy1 port run_testcase "Query a configuration key (other)" 0 \ "yes" \ --show-device-config-value epdu-2 synchronous run_testcase "Query a configuration key (originally quoted)" 0 \ 'This is ups-1' \ --show-device-config-value dummy1 desc run_testcase "Query a configuration flag (driver)" 0 \ "driverflag" \ --show-config-value 'serial.4' driverflag run_testcase "Query a missing configuration flag (driver)" 1 \ "" \ --show-config-value 'valueHasQuotedHashtag' nosuchflag run_testcase "Query multiple configuration keys (originally quoted)" 0 \ 'This is ups-1 file1.dev' \ --show-device-config-value dummy1 desc port run_testcase "Query multiple configuration keys with some missing (originally quoted)" 1 \ 'This is ups-1 file1.dev' \ --show-device-config-value dummy1 desc unknownkey port } testcase_globalSection() { run_testcase "Display global config" 0 \ "maxstartdelay=180 globalflag" \ --show-config '' run_testcase "Query a configuration key (global)" 0 \ "180" \ --show-config-value '' maxstartdelay run_testcase "Query a configuration flag (global)" 0 \ "globalflag" \ --show-config-value '' globalflag run_testcase "Query a missing configuration flag (global)" 1 \ "" \ --show-config-value '' nosuchflag } # Combine the cases above into a stack testsuite() { testcase_bogus_args testcase_list_all_devices testcase_show_all_configs testcase_getValue testcase_globalSection # This one can take a while, put it last testcase_upslist_debug } # If no args... for USE_SHELL in $SHELL_PROGS ; do case "$USE_SHELL" in busybox|busybox_sh) USE_SHELL="busybox sh" ;; esac testsuite done # End of loop over shells echo "Test suite for nut-driver-enumerator has completed with $FAIL_COUNT failed cases and $GOOD_COUNT good cases" >&2 [ "$FAIL_COUNT" = 0 ] || { echo "As a developer, you may want to export DEBUG=trace or export DEBUG=yes and re-run the test; also make sure you meant the nut-driver-enumerator.sh implementation as NDE='$NDE'" >&2 ; exit 1; } nut-2.8.1/AUTHORS0000644000175000017500000001214114515702041010317 00000000000000# The NUT AUTHORS file. Don't be shy. If you have contributed to this # project in some way, send me a patch to add yourself to this file. # # Everyone deserves credit, including those who haven't added any code. # Ideas, clues, and helping out on the mailing lists all count too. # # This is a blatant ripoff of the fields found in the Linux kernel's CREDITS # file. If we need more data, those fields can always be added later. # # N = name, E = email, W = web address, D = description, P = PGP info, # S = snailmail address, etc. # # This file is supposed to be roughly alpha-sorted by the last name, but # if you want to hide at the bottom, that's fine by me. Just clarify # your preference when submitting changes to this file. N: Axel Gembe E: axel@gembe.net W: http://axel.gembe.net/ D: Added APC Modbus support P: rsa4096/43109AAC 11E6 515C B8A4 26C6 07C1 36A4 1CB3 AA21 4310 9AAC N: Stephen Brown E: steve@datalimbo.net W: http://www.datalimbo.net/ D: Hacked genericups to add TrippLite Lan2.x support (Internet Office 700) N: Bill Carlson E: wcarlson@wkks.org W: http://wkks.org/ D: Fixed the GD/configure problem N: Ben Collver E: collver@softhome.net W: http://superfluous.oddbox.org D: Beginning support for HPUX 10.20 and Windows 2000 N: Luca Filipozzi E: lfilipoz@debian.org D: Original Debian maintainer for nut package. Minor patches to source. N: Matthew Gabeler-Lee E: msg2@po.cwru.edu W: http://cheetah.cwru.edu D: Added custom formatting to upslog D: Helped get apcsmart working with old SmartUPS models N: David Goncalves E: david@lestat.st W: http://www.lestat.st D: Python client support (PyNUT module and NUT-Monitor application) N: Bruno Hall D: Contributed UPS compatibility information N: Bo Kersey - VirCIO - Managed Server Solutions E: bo@vircio.com W: http://www.vircio.com/ D: Provided a Best Fortress for development of a Best driver (bestups) N: Russell Kroll E: rkroll@exploits.org W: https://www.networkupstools.org/ D: Original NUT author and coordinator P: 1024D/9DC0E77E 6A5C 7D2D 7945 C022 6104 D421 D61D C97F 9DC0 E77E N: Rick Lyons E: rick@powerup.com.au D: Support for Liebert UPSes using MultiLink cable N: Jeremy Maccelari E: visualn@iafrica.com, jeremy@visuals.co.za W: http://www.visuals.co.za D: Support for Mustek UPSes N: Philippe Marzouk E: philm@users.sourceforge.net D: Support for MGE Pulsar Ellipse UPSes ; co author of mge-shut N: Theodor A. Milkov E: zimage@delbg.com W: http://www.delbg.com/~zimage/ D: Adding support for Repotec's RPT-800A, RPT-162A to genericups driver. N: Mark Powell E: medp@primagraphics.co.uk D: Ported to SunOS4 N: Arnaud Quette E: aquette.dev@gmail.com E: arnaud.quette@mgeups.com E: aquette@debian.org W: http://arnaud.quette.free.fr/ D: Primary coordinator ; author of snmp-ups, mge-shut, usbhid-ups ; D: co author of mge-utalk, hidups, SNMP UPS Agent ; contributor to blazer, D: bestferrups, nut core, and many others ; coordination with MGE UPS D: SYSTEMS, linux-usb developers (for hidups), Net SNMP and packagers D: (Mandriva, Debian, SuSE, ...)... P: 1024D/204DDF1B 1371 07DF 3CF3 9160 7905 144B DB64 14CA 204D DF1B N: Lars Balker Rasmussen E: lbr@mjolner.dk D: Solaris and minor patches N: David Santinoli E: david@santinoli.com W: http://www.santinoli.com D: Support for Online P-series in genericups driver N: Jacob Schmier E: j.schmier@live.com D: support for Universal-Mount ON Series UPS family in oneac driver N: Peter Selinger E: selinger@users.sourceforge.net W: http://www.mathstat.dal.ca/~selinger/ D: wrote belkinunv driver, contributions to usbhid-ups P: 1024D/CA31696A 12A2 4B3C 3790 B688 E484 7A98 A68B CC37 CA31 696A N: Kirill Smelkov E: kirr@mns.spb.ru D: Author of al175 N: John Stone E: johns@megapixel.com W: http://www.megapixel.com/ D: Support for Best MicroFerrups UPS N: Technorama Ltd. E: oss-list-ups@technorama.net D: common driver core design, redundant code elimination, security fixes D: other misc patches and improvements throughout N: Jason Thomas E: jason@topic.com.au W: http://www.topic.com.au/ D: Hacked up the UPSonic Driver. N: Simon Rozman E: simon@rozman.net W: http://simon.rozman.net/ D: Hacked powercom to add Socomec Sycon Egys 420 VA support N: Len J White E: lwhite@darkfires.net N: Walt Holman E: walt_h@lorettotel.net D: Hacked up the cpsups driver for CyberPower text protocol UPSes N: Fabio Di Niro E: blaxwan@users.sourceforge.net D: Author of metasys driver, support for Meta System UPS N: Arjen de Korte E: arjen@de-korte.org D: Author of safenet driver P: 1024R/AEF3BA11 664E 032C 9DB5 CB9B 7AFE 7EC1 EE88 BC57 N: Håvard Lygre E: hklygre@online.no D: First stab at upscode2 driver for NUT 1.4 N: Niels Baggesen E: niels@baggesen.net D: upgraded the upscode2 driver to NUT-2, and extended it heavily. N: Niklas Edmundsson E: nikke@acc.umu.se D: 3-phase work, updates for upscode2 N: Olli Savia E: ops@iki.fi D: pwmib support for snmp-ups N: Kjell Claesson E: Kjell.claesson@epost.tidanet.se D: Author of bcmxcp driver, 3-phase work. N: Giuseppe Corbelli E: giuseppe.corbelli@copanitalia.com D: Author of asem driver N: zakx E: zakx@zakx.de D: Updating device support docs after unnecessarily writing a redundant D: driver first nut-2.8.1/config.sub0000755000175000017500000010511614517510735011250 00000000000000#! /bin/sh # Configuration validation subroutine script. # Copyright 1992-2022 Free Software Foundation, Inc. # shellcheck disable=SC2006,SC2268 # see below for rationale timestamp='2022-01-03' # This file 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 . # # As a special exception to the GNU General Public License, if you # distribute this file as part of a program that contains a # configuration script generated by Autoconf, you may include it under # the same distribution terms that you use for the rest of that # program. This Exception is an additional permission under section 7 # of the GNU General Public License, version 3 ("GPLv3"). # Please send patches to . # # Configuration subroutine to validate and canonicalize a configuration type. # Supply the specified configuration type as an argument. # If it is invalid, we print an error message on stderr and exit with code 1. # Otherwise, we print the canonical config type on stdout and succeed. # You can get the latest version of this script from: # https://git.savannah.gnu.org/cgit/config.git/plain/config.sub # This file is supposed to be the same for all GNU packages # and recognize all the CPU types, system types and aliases # that are meaningful with *any* GNU software. # Each package is responsible for reporting which valid configurations # it does not support. The user should be able to distinguish # a failure to support a valid configuration from a meaningless # configuration. # The goal of this file is to map all the various variations of a given # machine specification into a single specification in the form: # CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM # or in some cases, the newer four-part form: # CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM # It is wrong to echo any other type of specification. # The "shellcheck disable" line above the timestamp inhibits complaints # about features and limitations of the classic Bourne shell that were # superseded or lifted in POSIX. However, this script identifies a wide # variety of pre-POSIX systems that do not have POSIX shells at all, and # even some reasonably current systems (Solaris 10 as case-in-point) still # have a pre-POSIX /bin/sh. me=`echo "$0" | sed -e 's,.*/,,'` usage="\ Usage: $0 [OPTION] CPU-MFR-OPSYS or ALIAS Canonicalize a configuration name. Options: -h, --help print this help, then exit -t, --time-stamp print date of last modification, then exit -v, --version print version number, then exit Report bugs and patches to ." version="\ GNU config.sub ($timestamp) Copyright 1992-2022 Free Software Foundation, Inc. This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." help=" Try \`$me --help' for more information." # Parse command line while test $# -gt 0 ; do case $1 in --time-stamp | --time* | -t ) echo "$timestamp" ; exit ;; --version | -v ) echo "$version" ; exit ;; --help | --h* | -h ) echo "$usage"; exit ;; -- ) # Stop option processing shift; break ;; - ) # Use stdin as input. break ;; -* ) echo "$me: invalid option $1$help" >&2 exit 1 ;; *local*) # First pass through any local machine types. echo "$1" exit ;; * ) break ;; esac done case $# in 0) echo "$me: missing argument$help" >&2 exit 1;; 1) ;; *) echo "$me: too many arguments$help" >&2 exit 1;; esac # Split fields of configuration type # shellcheck disable=SC2162 saved_IFS=$IFS IFS="-" read field1 field2 field3 field4 <&2 exit 1 ;; *-*-*-*) basic_machine=$field1-$field2 basic_os=$field3-$field4 ;; *-*-*) # Ambiguous whether COMPANY is present, or skipped and KERNEL-OS is two # parts maybe_os=$field2-$field3 case $maybe_os in nto-qnx* | linux-* | uclinux-uclibc* \ | uclinux-gnu* | kfreebsd*-gnu* | knetbsd*-gnu* | netbsd*-gnu* \ | netbsd*-eabi* | kopensolaris*-gnu* | cloudabi*-eabi* \ | storm-chaos* | os2-emx* | rtmk-nova*) basic_machine=$field1 basic_os=$maybe_os ;; android-linux) basic_machine=$field1-unknown basic_os=linux-android ;; *) basic_machine=$field1-$field2 basic_os=$field3 ;; esac ;; *-*) # A lone config we happen to match not fitting any pattern case $field1-$field2 in decstation-3100) basic_machine=mips-dec basic_os= ;; *-*) # Second component is usually, but not always the OS case $field2 in # Prevent following clause from handling this valid os sun*os*) basic_machine=$field1 basic_os=$field2 ;; zephyr*) basic_machine=$field1-unknown basic_os=$field2 ;; # Manufacturers dec* | mips* | sequent* | encore* | pc533* | sgi* | sony* \ | att* | 7300* | 3300* | delta* | motorola* | sun[234]* \ | unicom* | ibm* | next | hp | isi* | apollo | altos* \ | convergent* | ncr* | news | 32* | 3600* | 3100* \ | hitachi* | c[123]* | convex* | sun | crds | omron* | dg \ | ultra | tti* | harris | dolphin | highlevel | gould \ | cbm | ns | masscomp | apple | axis | knuth | cray \ | microblaze* | sim | cisco \ | oki | wec | wrs | winbond) basic_machine=$field1-$field2 basic_os= ;; *) basic_machine=$field1 basic_os=$field2 ;; esac ;; esac ;; *) # Convert single-component short-hands not valid as part of # multi-component configurations. case $field1 in 386bsd) basic_machine=i386-pc basic_os=bsd ;; a29khif) basic_machine=a29k-amd basic_os=udi ;; adobe68k) basic_machine=m68010-adobe basic_os=scout ;; alliant) basic_machine=fx80-alliant basic_os= ;; altos | altos3068) basic_machine=m68k-altos basic_os= ;; am29k) basic_machine=a29k-none basic_os=bsd ;; amdahl) basic_machine=580-amdahl basic_os=sysv ;; amiga) basic_machine=m68k-unknown basic_os= ;; amigaos | amigados) basic_machine=m68k-unknown basic_os=amigaos ;; amigaunix | amix) basic_machine=m68k-unknown basic_os=sysv4 ;; apollo68) basic_machine=m68k-apollo basic_os=sysv ;; apollo68bsd) basic_machine=m68k-apollo basic_os=bsd ;; aros) basic_machine=i386-pc basic_os=aros ;; aux) basic_machine=m68k-apple basic_os=aux ;; balance) basic_machine=ns32k-sequent basic_os=dynix ;; blackfin) basic_machine=bfin-unknown basic_os=linux ;; cegcc) basic_machine=arm-unknown basic_os=cegcc ;; convex-c1) basic_machine=c1-convex basic_os=bsd ;; convex-c2) basic_machine=c2-convex basic_os=bsd ;; convex-c32) basic_machine=c32-convex basic_os=bsd ;; convex-c34) basic_machine=c34-convex basic_os=bsd ;; convex-c38) basic_machine=c38-convex basic_os=bsd ;; cray) basic_machine=j90-cray basic_os=unicos ;; crds | unos) basic_machine=m68k-crds basic_os= ;; da30) basic_machine=m68k-da30 basic_os= ;; decstation | pmax | pmin | dec3100 | decstatn) basic_machine=mips-dec basic_os= ;; delta88) basic_machine=m88k-motorola basic_os=sysv3 ;; dicos) basic_machine=i686-pc basic_os=dicos ;; djgpp) basic_machine=i586-pc basic_os=msdosdjgpp ;; ebmon29k) basic_machine=a29k-amd basic_os=ebmon ;; es1800 | OSE68k | ose68k | ose | OSE) basic_machine=m68k-ericsson basic_os=ose ;; gmicro) basic_machine=tron-gmicro basic_os=sysv ;; go32) basic_machine=i386-pc basic_os=go32 ;; h8300hms) basic_machine=h8300-hitachi basic_os=hms ;; h8300xray) basic_machine=h8300-hitachi basic_os=xray ;; h8500hms) basic_machine=h8500-hitachi basic_os=hms ;; harris) basic_machine=m88k-harris basic_os=sysv3 ;; hp300 | hp300hpux) basic_machine=m68k-hp basic_os=hpux ;; hp300bsd) basic_machine=m68k-hp basic_os=bsd ;; hppaosf) basic_machine=hppa1.1-hp basic_os=osf ;; hppro) basic_machine=hppa1.1-hp basic_os=proelf ;; i386mach) basic_machine=i386-mach basic_os=mach ;; isi68 | isi) basic_machine=m68k-isi basic_os=sysv ;; m68knommu) basic_machine=m68k-unknown basic_os=linux ;; magnum | m3230) basic_machine=mips-mips basic_os=sysv ;; merlin) basic_machine=ns32k-utek basic_os=sysv ;; mingw64) basic_machine=x86_64-pc basic_os=mingw64 ;; mingw32) basic_machine=i686-pc basic_os=mingw32 ;; mingw32ce) basic_machine=arm-unknown basic_os=mingw32ce ;; monitor) basic_machine=m68k-rom68k basic_os=coff ;; morphos) basic_machine=powerpc-unknown basic_os=morphos ;; moxiebox) basic_machine=moxie-unknown basic_os=moxiebox ;; msdos) basic_machine=i386-pc basic_os=msdos ;; msys) basic_machine=i686-pc basic_os=msys ;; mvs) basic_machine=i370-ibm basic_os=mvs ;; nacl) basic_machine=le32-unknown basic_os=nacl ;; ncr3000) basic_machine=i486-ncr basic_os=sysv4 ;; netbsd386) basic_machine=i386-pc basic_os=netbsd ;; netwinder) basic_machine=armv4l-rebel basic_os=linux ;; news | news700 | news800 | news900) basic_machine=m68k-sony basic_os=newsos ;; news1000) basic_machine=m68030-sony basic_os=newsos ;; necv70) basic_machine=v70-nec basic_os=sysv ;; nh3000) basic_machine=m68k-harris basic_os=cxux ;; nh[45]000) basic_machine=m88k-harris basic_os=cxux ;; nindy960) basic_machine=i960-intel basic_os=nindy ;; mon960) basic_machine=i960-intel basic_os=mon960 ;; nonstopux) basic_machine=mips-compaq basic_os=nonstopux ;; os400) basic_machine=powerpc-ibm basic_os=os400 ;; OSE68000 | ose68000) basic_machine=m68000-ericsson basic_os=ose ;; os68k) basic_machine=m68k-none basic_os=os68k ;; paragon) basic_machine=i860-intel basic_os=osf ;; parisc) basic_machine=hppa-unknown basic_os=linux ;; psp) basic_machine=mipsallegrexel-sony basic_os=psp ;; pw32) basic_machine=i586-unknown basic_os=pw32 ;; rdos | rdos64) basic_machine=x86_64-pc basic_os=rdos ;; rdos32) basic_machine=i386-pc basic_os=rdos ;; rom68k) basic_machine=m68k-rom68k basic_os=coff ;; sa29200) basic_machine=a29k-amd basic_os=udi ;; sei) basic_machine=mips-sei basic_os=seiux ;; sequent) basic_machine=i386-sequent basic_os= ;; sps7) basic_machine=m68k-bull basic_os=sysv2 ;; st2000) basic_machine=m68k-tandem basic_os= ;; stratus) basic_machine=i860-stratus basic_os=sysv4 ;; sun2) basic_machine=m68000-sun basic_os= ;; sun2os3) basic_machine=m68000-sun basic_os=sunos3 ;; sun2os4) basic_machine=m68000-sun basic_os=sunos4 ;; sun3) basic_machine=m68k-sun basic_os= ;; sun3os3) basic_machine=m68k-sun basic_os=sunos3 ;; sun3os4) basic_machine=m68k-sun basic_os=sunos4 ;; sun4) basic_machine=sparc-sun basic_os= ;; sun4os3) basic_machine=sparc-sun basic_os=sunos3 ;; sun4os4) basic_machine=sparc-sun basic_os=sunos4 ;; sun4sol2) basic_machine=sparc-sun basic_os=solaris2 ;; sun386 | sun386i | roadrunner) basic_machine=i386-sun basic_os= ;; sv1) basic_machine=sv1-cray basic_os=unicos ;; symmetry) basic_machine=i386-sequent basic_os=dynix ;; t3e) basic_machine=alphaev5-cray basic_os=unicos ;; t90) basic_machine=t90-cray basic_os=unicos ;; toad1) basic_machine=pdp10-xkl basic_os=tops20 ;; tpf) basic_machine=s390x-ibm basic_os=tpf ;; udi29k) basic_machine=a29k-amd basic_os=udi ;; ultra3) basic_machine=a29k-nyu basic_os=sym1 ;; v810 | necv810) basic_machine=v810-nec basic_os=none ;; vaxv) basic_machine=vax-dec basic_os=sysv ;; vms) basic_machine=vax-dec basic_os=vms ;; vsta) basic_machine=i386-pc basic_os=vsta ;; vxworks960) basic_machine=i960-wrs basic_os=vxworks ;; vxworks68) basic_machine=m68k-wrs basic_os=vxworks ;; vxworks29k) basic_machine=a29k-wrs basic_os=vxworks ;; xbox) basic_machine=i686-pc basic_os=mingw32 ;; ymp) basic_machine=ymp-cray basic_os=unicos ;; *) basic_machine=$1 basic_os= ;; esac ;; esac # Decode 1-component or ad-hoc basic machines case $basic_machine in # Here we handle the default manufacturer of certain CPU types. It is in # some cases the only manufacturer, in others, it is the most popular. w89k) cpu=hppa1.1 vendor=winbond ;; op50n) cpu=hppa1.1 vendor=oki ;; op60c) cpu=hppa1.1 vendor=oki ;; ibm*) cpu=i370 vendor=ibm ;; orion105) cpu=clipper vendor=highlevel ;; mac | mpw | mac-mpw) cpu=m68k vendor=apple ;; pmac | pmac-mpw) cpu=powerpc vendor=apple ;; # Recognize the various machine names and aliases which stand # for a CPU type and a company and sometimes even an OS. 3b1 | 7300 | 7300-att | att-7300 | pc7300 | safari | unixpc) cpu=m68000 vendor=att ;; 3b*) cpu=we32k vendor=att ;; bluegene*) cpu=powerpc vendor=ibm basic_os=cnk ;; decsystem10* | dec10*) cpu=pdp10 vendor=dec basic_os=tops10 ;; decsystem20* | dec20*) cpu=pdp10 vendor=dec basic_os=tops20 ;; delta | 3300 | motorola-3300 | motorola-delta \ | 3300-motorola | delta-motorola) cpu=m68k vendor=motorola ;; dpx2*) cpu=m68k vendor=bull basic_os=sysv3 ;; encore | umax | mmax) cpu=ns32k vendor=encore ;; elxsi) cpu=elxsi vendor=elxsi basic_os=${basic_os:-bsd} ;; fx2800) cpu=i860 vendor=alliant ;; genix) cpu=ns32k vendor=ns ;; h3050r* | hiux*) cpu=hppa1.1 vendor=hitachi basic_os=hiuxwe2 ;; hp3k9[0-9][0-9] | hp9[0-9][0-9]) cpu=hppa1.0 vendor=hp ;; hp9k2[0-9][0-9] | hp9k31[0-9]) cpu=m68000 vendor=hp ;; hp9k3[2-9][0-9]) cpu=m68k vendor=hp ;; hp9k6[0-9][0-9] | hp6[0-9][0-9]) cpu=hppa1.0 vendor=hp ;; hp9k7[0-79][0-9] | hp7[0-79][0-9]) cpu=hppa1.1 vendor=hp ;; hp9k78[0-9] | hp78[0-9]) # FIXME: really hppa2.0-hp cpu=hppa1.1 vendor=hp ;; hp9k8[67]1 | hp8[67]1 | hp9k80[24] | hp80[24] | hp9k8[78]9 | hp8[78]9 | hp9k893 | hp893) # FIXME: really hppa2.0-hp cpu=hppa1.1 vendor=hp ;; hp9k8[0-9][13679] | hp8[0-9][13679]) cpu=hppa1.1 vendor=hp ;; hp9k8[0-9][0-9] | hp8[0-9][0-9]) cpu=hppa1.0 vendor=hp ;; i*86v32) cpu=`echo "$1" | sed -e 's/86.*/86/'` vendor=pc basic_os=sysv32 ;; i*86v4*) cpu=`echo "$1" | sed -e 's/86.*/86/'` vendor=pc basic_os=sysv4 ;; i*86v) cpu=`echo "$1" | sed -e 's/86.*/86/'` vendor=pc basic_os=sysv ;; i*86sol2) cpu=`echo "$1" | sed -e 's/86.*/86/'` vendor=pc basic_os=solaris2 ;; j90 | j90-cray) cpu=j90 vendor=cray basic_os=${basic_os:-unicos} ;; iris | iris4d) cpu=mips vendor=sgi case $basic_os in irix*) ;; *) basic_os=irix4 ;; esac ;; miniframe) cpu=m68000 vendor=convergent ;; *mint | mint[0-9]* | *MiNT | *MiNT[0-9]*) cpu=m68k vendor=atari basic_os=mint ;; news-3600 | risc-news) cpu=mips vendor=sony basic_os=newsos ;; next | m*-next) cpu=m68k vendor=next case $basic_os in openstep*) ;; nextstep*) ;; ns2*) basic_os=nextstep2 ;; *) basic_os=nextstep3 ;; esac ;; np1) cpu=np1 vendor=gould ;; op50n-* | op60c-*) cpu=hppa1.1 vendor=oki basic_os=proelf ;; pa-hitachi) cpu=hppa1.1 vendor=hitachi basic_os=hiuxwe2 ;; pbd) cpu=sparc vendor=tti ;; pbb) cpu=m68k vendor=tti ;; pc532) cpu=ns32k vendor=pc532 ;; pn) cpu=pn vendor=gould ;; power) cpu=power vendor=ibm ;; ps2) cpu=i386 vendor=ibm ;; rm[46]00) cpu=mips vendor=siemens ;; rtpc | rtpc-*) cpu=romp vendor=ibm ;; sde) cpu=mipsisa32 vendor=sde basic_os=${basic_os:-elf} ;; simso-wrs) cpu=sparclite vendor=wrs basic_os=vxworks ;; tower | tower-32) cpu=m68k vendor=ncr ;; vpp*|vx|vx-*) cpu=f301 vendor=fujitsu ;; w65) cpu=w65 vendor=wdc ;; w89k-*) cpu=hppa1.1 vendor=winbond basic_os=proelf ;; none) cpu=none vendor=none ;; leon|leon[3-9]) cpu=sparc vendor=$basic_machine ;; leon-*|leon[3-9]-*) cpu=sparc vendor=`echo "$basic_machine" | sed 's/-.*//'` ;; *-*) # shellcheck disable=SC2162 saved_IFS=$IFS IFS="-" read cpu vendor <&2 exit 1 ;; esac ;; esac # Here we canonicalize certain aliases for manufacturers. case $vendor in digital*) vendor=dec ;; commodore*) vendor=cbm ;; *) ;; esac # Decode manufacturer-specific aliases for certain operating systems. if test x$basic_os != x then # First recognize some ad-hoc cases, or perhaps split kernel-os, or else just # set os. case $basic_os in gnu/linux*) kernel=linux os=`echo "$basic_os" | sed -e 's|gnu/linux|gnu|'` ;; os2-emx) kernel=os2 os=`echo "$basic_os" | sed -e 's|os2-emx|emx|'` ;; nto-qnx*) kernel=nto os=`echo "$basic_os" | sed -e 's|nto-qnx|qnx|'` ;; *-*) # shellcheck disable=SC2162 saved_IFS=$IFS IFS="-" read kernel os <&2 exit 1 ;; esac # As a final step for OS-related things, validate the OS-kernel combination # (given a valid OS), if there is a kernel. case $kernel-$os in linux-gnu* | linux-dietlibc* | linux-android* | linux-newlib* \ | linux-musl* | linux-relibc* | linux-uclibc* ) ;; uclinux-uclibc* ) ;; -dietlibc* | -newlib* | -musl* | -relibc* | -uclibc* ) # These are just libc implementations, not actual OSes, and thus # require a kernel. echo "Invalid configuration \`$1': libc \`$os' needs explicit kernel." 1>&2 exit 1 ;; kfreebsd*-gnu* | kopensolaris*-gnu*) ;; vxworks-simlinux | vxworks-simwindows | vxworks-spe) ;; nto-qnx*) ;; os2-emx) ;; *-eabi* | *-gnueabi*) ;; -*) # Blank kernel with real OS is always fine. ;; *-*) echo "Invalid configuration \`$1': Kernel \`$kernel' not known to work with OS \`$os'." 1>&2 exit 1 ;; esac # Here we handle the case where we know the os, and the CPU type, but not the # manufacturer. We pick the logical manufacturer. case $vendor in unknown) case $cpu-$os in *-riscix*) vendor=acorn ;; *-sunos*) vendor=sun ;; *-cnk* | *-aix*) vendor=ibm ;; *-beos*) vendor=be ;; *-hpux*) vendor=hp ;; *-mpeix*) vendor=hp ;; *-hiux*) vendor=hitachi ;; *-unos*) vendor=crds ;; *-dgux*) vendor=dg ;; *-luna*) vendor=omron ;; *-genix*) vendor=ns ;; *-clix*) vendor=intergraph ;; *-mvs* | *-opened*) vendor=ibm ;; *-os400*) vendor=ibm ;; s390-* | s390x-*) vendor=ibm ;; *-ptx*) vendor=sequent ;; *-tpf*) vendor=ibm ;; *-vxsim* | *-vxworks* | *-windiss*) vendor=wrs ;; *-aux*) vendor=apple ;; *-hms*) vendor=hitachi ;; *-mpw* | *-macos*) vendor=apple ;; *-*mint | *-mint[0-9]* | *-*MiNT | *-MiNT[0-9]*) vendor=atari ;; *-vos*) vendor=stratus ;; esac ;; esac echo "$cpu-$vendor-${kernel:+$kernel-}$os" exit # Local variables: # eval: (add-hook 'before-save-hook 'time-stamp) # time-stamp-start: "timestamp='" # time-stamp-format: "%:y-%02m-%02d" # time-stamp-end: "'" # End: nut-2.8.1/server/0000755000175000017500000000000014520277777010661 500000000000000nut-2.8.1/server/netlist.h0000644000175000017500000000241014500336654012415 00000000000000/* netlist.h - LIST handlers for upsd Copyright (C) 2003 Russell Kroll 2005 Arnaud Quette 2007 Peter Selinger 2013 Emilien Kia 2020 Jim Klimov 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 2 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, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef NUT_NETLIST_H_SEEN #define NUT_NETLIST_H_SEEN 1 #ifdef __cplusplus /* *INDENT-OFF* */ extern "C" { /* *INDENT-ON* */ #endif void net_list(nut_ctype_t *client, size_t numarg, const char **arg); #ifdef __cplusplus /* *INDENT-OFF* */ } /* *INDENT-ON* */ #endif #endif /* NUT_NETLIST_H_SEEN */ nut-2.8.1/server/netlist.c0000644000175000017500000001557314500336654012426 00000000000000/* netlist.c - LIST handlers for upsd Copyright (C) 2003 Russell Kroll 2012 Arnaud Quette 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 2 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, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "common.h" #include "upsd.h" #include "sstate.h" #include "state.h" #include "neterr.h" #include "netlist.h" extern upstype_t *firstups; /* for list_ups */ extern nut_ctype_t *firstclient; /* for list_clients */ static int tree_dump(st_tree_t *node, nut_ctype_t *client, const char *ups, int rw, int fsd) { int ret; if (!node) return 1; /* not an error */ if (node->left) { ret = tree_dump(node->left, client, ups, rw, fsd); if (!ret) return 0; /* write failed in child */ } if (rw) { /* only send this back if it's been flagged RW */ if (node->flags & ST_FLAG_RW) { ret = sendback(client, "RW %s %s \"%s\"\n", ups, node->var, node->val); } else { ret = 1; /* dummy */ } } else { /* normal variable list only */ /* status is always a special case */ if ((fsd == 1) && (!strcasecmp(node->var, "ups.status"))) { ret = sendback(client, "VAR %s %s \"FSD %s\"\n", ups, node->var, node->val); } else { ret = sendback(client, "VAR %s %s \"%s\"\n", ups, node->var, node->val); } } if (ret != 1) return 0; if (node->right) return tree_dump(node->right, client, ups, rw, fsd); return 1; } static void list_rw(nut_ctype_t *client, const char *upsname) { const upstype_t *ups; ups = get_ups_ptr(upsname); if (!ups) { send_err(client, NUT_ERR_UNKNOWN_UPS); return; } if (!ups_available(ups, client)) return; if (!sendback(client, "BEGIN LIST RW %s\n", upsname)) return; if (!tree_dump(ups->inforoot, client, upsname, 1, ups->fsd)) return; sendback(client, "END LIST RW %s\n", upsname); } static void list_var(nut_ctype_t *client, const char *upsname) { const upstype_t *ups; ups = get_ups_ptr(upsname); if (!ups) { send_err(client, NUT_ERR_UNKNOWN_UPS); return; } if (!ups_available(ups, client)) return; if (!sendback(client, "BEGIN LIST VAR %s\n", upsname)) return; if (!tree_dump(ups->inforoot, client, upsname, 0, ups->fsd)) return; sendback(client, "END LIST VAR %s\n", upsname); } static void list_cmd(nut_ctype_t *client, const char *upsname) { const upstype_t *ups; cmdlist_t *ctmp; ups = get_ups_ptr(upsname); if (!ups) { send_err(client, NUT_ERR_UNKNOWN_UPS); return; } if (!ups_available(ups, client)) return; if (!sendback(client, "BEGIN LIST CMD %s\n", upsname)) return; for (ctmp = ups->cmdlist; ctmp != NULL; ctmp = ctmp->next) { if (!sendback(client, "CMD %s %s\n", upsname, ctmp->name)) return; } sendback(client, "END LIST CMD %s\n", upsname); } static void list_enum(nut_ctype_t *client, const char *upsname, const char *var) { const upstype_t *ups; const st_tree_t *node; const enum_t *etmp; ups = get_ups_ptr(upsname); if (!ups) { send_err(client, NUT_ERR_UNKNOWN_UPS); return; } if (!ups_available(ups, client)) return; node = sstate_getnode(ups, var); if (!node) { send_err(client, NUT_ERR_VAR_NOT_SUPPORTED); return; } if (!sendback(client, "BEGIN LIST ENUM %s %s\n", upsname, var)) return; for (etmp = node->enum_list; etmp != NULL; etmp = etmp->next) { if (!sendback(client, "ENUM %s %s \"%s\"\n", upsname, var, etmp->val)) return; } sendback(client, "END LIST ENUM %s %s\n", upsname, var); } static void list_range(nut_ctype_t *client, const char *upsname, const char *var) { const upstype_t *ups; const st_tree_t *node; const range_t *rtmp; ups = get_ups_ptr(upsname); if (!ups) { send_err(client, NUT_ERR_UNKNOWN_UPS); return; } if (!ups_available(ups, client)) return; node = sstate_getnode(ups, var); if (!node) { send_err(client, NUT_ERR_VAR_NOT_SUPPORTED); return; } if (!sendback(client, "BEGIN LIST RANGE %s %s\n", upsname, var)) return; for (rtmp = node->range_list; rtmp != NULL; rtmp = rtmp->next) { if (!sendback(client, "RANGE %s %s \"%i\" \"%i\"\n", upsname, var, rtmp->min, rtmp->max)) return; } sendback(client, "END LIST RANGE %s %s\n", upsname, var); } static void list_ups(nut_ctype_t *client) { upstype_t *utmp; char esc[SMALLBUF]; if (!sendback(client, "BEGIN LIST UPS\n")) return; utmp = firstups; while (utmp) { int ret; if (utmp->desc) { pconf_encode(utmp->desc, esc, sizeof(esc)); ret = sendback(client, "UPS %s \"%s\"\n", utmp->name, esc); } else { ret = sendback(client, "UPS %s \"Description unavailable\"\n", utmp->name); } if (!ret) return; utmp = utmp->next; } sendback(client, "END LIST UPS\n"); } static void list_clients(nut_ctype_t *client, const char *upsname) { const upstype_t *ups; nut_ctype_t *c, *cnext; ups = get_ups_ptr(upsname); if (!ups) { send_err(client, NUT_ERR_UNKNOWN_UPS); return; } if (!sendback(client, "BEGIN LIST CLIENT %s\n", upsname)) return; if (firstclient) { int ret; /* show connected clients */ for (c = firstclient; c; c = cnext) { if (c->loginups && (!ups || !strcasecmp(c->loginups, ups->name))) { ret = sendback(client, "CLIENT %s %s\n", c->loginups, c->addr); if (!ret) return; } cnext = c->next; } } sendback(client, "END LIST CLIENT %s\n", upsname); } void net_list(nut_ctype_t *client, size_t numarg, const char **arg) { if (numarg < 1) { send_err(client, NUT_ERR_INVALID_ARGUMENT); return; } /* LIST UPS */ if (!strcasecmp(arg[0], "UPS")) { list_ups(client); return; } if (numarg < 2) { send_err(client, NUT_ERR_INVALID_ARGUMENT); return; } /* LIST VAR UPS */ if (!strcasecmp(arg[0], "VAR")) { list_var(client, arg[1]); return; } /* LIST RW UPS */ if (!strcasecmp(arg[0], "RW")) { list_rw(client, arg[1]); return; } /* LIST CMD UPS */ if (!strcasecmp(arg[0], "CMD")) { list_cmd(client, arg[1]); return; } /* LIST CLIENT UPS */ if (!strcasecmp(arg[0], "CLIENT")) { list_clients(client, arg[1]); return; } if (numarg < 3) { send_err(client, NUT_ERR_INVALID_ARGUMENT); return; } /* LIST ENUM UPS VARNAME */ if (!strcasecmp(arg[0], "ENUM")) { list_enum(client, arg[1], arg[2]); return; } /* LIST RANGE UPS VARNAME */ if (!strcasecmp(arg[0], "RANGE")) { list_range(client, arg[1], arg[2]); return; } send_err(client, NUT_ERR_INVALID_ARGUMENT); } nut-2.8.1/server/sockdebug.c0000644000175000017500000001077414501607135012704 00000000000000/* sockdebug.c - Network UPS Tools driver-server socket debugger Source variant for POSIX-compliant builds of NUT Copyright (C) 2003 Russell Kroll Copyright (C) 2023 Jim Klimov 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 2 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, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include #include #include #include #include #include #include #include "common.h" #include "parseconf.h" #include "nut_stdint.h" static PCONF_CTX_t sock_ctx; static void sock_arg(size_t numarg, char **arg) { size_t i; printf("numarg=%" PRIuSIZE " : ", numarg); for (i = 0; i < numarg; i++) printf("[%s] ", arg[i]); printf("\n"); } static int socket_connect(const char *sockfn) { int ret, fd; struct sockaddr_un sa; check_unix_socket_filename(sockfn); memset(&sa, '\0', sizeof(sa)); sa.sun_family = AF_UNIX; snprintf(sa.sun_path, sizeof(sa.sun_path), "%s", sockfn); fd = socket(AF_UNIX, SOCK_STREAM, 0); if (fd < 0) { perror("socket"); exit(EXIT_FAILURE); } ret = connect(fd, (struct sockaddr *) &sa, sizeof(sa)); if (ret < 0 && !strchr(sockfn, '/')) { snprintf(sa.sun_path, sizeof(sa.sun_path), "%s/%s", dflt_statepath(), sockfn); ret = connect(fd, (struct sockaddr *) &sa, sizeof(sa)); } if (ret < 0) { perror("connect"); exit(EXIT_FAILURE); } #if 0 ret = fcntl(fd, F_GETFL, 0); if (ret < 0) { perror("fcntl(get)"); exit(EXIT_FAILURE); } ret = fcntl(fd, F_SETFL, ret | O_NDELAY); if (ret < 0) { perror("fcntl(set)"); exit(EXIT_FAILURE); } #endif return fd; } static void read_sock(int fd) { int i, ret; char buf[SMALLBUF]; ret = read(fd, buf, sizeof(buf)); if (ret == 0) { fprintf(stderr, "read on socket returned 0\n"); exit(EXIT_FAILURE); } if (ret < 0) { perror("read sockfd"); exit(EXIT_FAILURE); } for (i = 0; i < ret; i++) { switch (pconf_char(&sock_ctx, buf[i])) { case 1: sock_arg(sock_ctx.numargs, sock_ctx.arglist); break; case -1: printf("Parse error: [%s]\n", sock_ctx.errmsg); break; } } } int main(int argc, char **argv) { const char *prog = xbasename(argv[0]); int ret, sockfd; if (argc != 2 || (argc > 1 && (!strcmp(argv[1], "-h") || !strcmp(argv[1], "--help"))) ) { fprintf(stderr, "usage: %s \n", prog); fprintf(stderr, " %s /var/state/ups/apcsmart-ttyS1\n", argv[0]); fprintf(stderr, " or %s apcsmart-ttyS1\n", argv[0]); fprintf(stderr, " for socket files placed in the standard location\n"); exit(EXIT_SUCCESS); } sockfd = socket_connect(argv[1]); printf("connected: fd %d\n", sockfd); pconf_init(&sock_ctx, NULL); for (;;) { struct timeval tv; fd_set rfds; int maxfd; tv.tv_sec = 2; tv.tv_usec = 0; FD_ZERO(&rfds); FD_SET(fileno(stdin), &rfds); FD_SET(sockfd, &rfds); /* paranoia */ maxfd = (sockfd > fileno(stdin)) ? sockfd : fileno(stdin); ret = select(maxfd + 1, &rfds, NULL, NULL, &tv); if (FD_ISSET(sockfd, &rfds)) read_sock(sockfd); if (FD_ISSET(fileno(stdin), &rfds)) { char buf[SMALLBUF]; if (!fgets(buf, sizeof(buf), stdin)) { perror("fgets from stdin"); exit(EXIT_FAILURE); } ret = write(sockfd, buf, strlen(buf)); if ((ret < 0) || (ret != (int) strlen(buf))) { perror("write to socket"); exit(EXIT_FAILURE); } } } #if (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_PUSH_POP) && (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_UNREACHABLE_CODE) # pragma GCC diagnostic push # pragma GCC diagnostic ignored "-Wunreachable-code" #endif #ifdef __clang__ # pragma clang diagnostic push # pragma clang diagnostic ignored "-Wunreachable-code" #endif /* NOTREACHED */ exit(EXIT_FAILURE); #ifdef __clang__ # pragma clang diagnostic pop #endif #if (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_PUSH_POP) && (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_UNREACHABLE_CODE) # pragma GCC diagnostic pop #endif } nut-2.8.1/server/upsd.c0000644000175000017500000015161014507361463011713 00000000000000/* upsd.c - watches ups state files and answers queries Copyright (C) 1999 Russell Kroll 2008 Arjen de Korte 2011 - 2012 Arnaud Quette 2019 Eaton (author: Arnaud Quette ) 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 2 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, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "config.h" /* must be the first header */ #include "upsd.h" #include "upstype.h" #include "conf.h" #include "netcmds.h" #include "upsconf.h" #ifndef WIN32 # include # include # include # ifdef HAVE_SYS_SIGNAL_H # include # endif # ifdef HAVE_SIGNAL_H # include /* #include */ # endif #else /* Those 2 files for support of getaddrinfo, getnameinfo and freeaddrinfo on Windows 2000 and older versions */ # include # include /* This override network system calls to adapt to Windows specificity */ # define W32_NETWORK_CALL_OVERRIDE # include "wincompat.h" # undef W32_NETWORK_CALL_OVERRIDE # include #endif #include "user.h" #include "nut_ctype.h" #include "nut_stdint.h" #include "stype.h" #include "netssl.h" #include "sstate.h" #include "desc.h" #include "neterr.h" #ifdef HAVE_WRAP #include int allow_severity = LOG_INFO; int deny_severity = LOG_WARNING; #endif /* HAVE_WRAP */ /* externally-visible settings and pointers */ upstype_t *firstups = NULL; /* default 15 seconds before data is marked stale */ int maxage = 15; /* default to 1h before cleaning up status tracking entries */ int tracking_delay = 3600; /* * Preloaded to ALLOW_NO_DEVICE from upsd.conf or environment variable * (with higher prio for envvar); defaults to disabled for legacy compat. */ int allow_no_device = 0; /* preloaded to {OPEN_MAX} in main, can be overridden via upsd.conf */ nfds_t maxconn = 0; /* preloaded to STATEPATH in main, can be overridden via upsd.conf */ char *statepath = NULL; /* preloaded to NUT_DATADIR in main(), can be overridden via upsd.conf */ char *datapath = NULL; /* everything else */ static const char *progname; nut_ctype_t *firstclient = NULL; /* static nut_ctype_t *lastclient = NULL; */ /* default is to listen on all local interfaces */ static stype_t *firstaddr = NULL; static int opt_af = AF_UNSPEC; typedef enum { DRIVER = 1, CLIENT, SERVER #ifdef WIN32 ,NAMED_PIPE #endif } handler_type_t; typedef struct { handler_type_t type; void *data; } handler_t; /* Commands and settings status tracking */ /* general enable/disable status info for commands and settings * (disabled by default) * Note that only client that requested it will have it enabled * (see nut_ctype.h) */ static int tracking_enabled = 0; /* Commands and settings status tracking structure */ typedef struct tracking_s { char *id; int status; time_t request_time; /* for cleanup */ /* doubly linked list */ struct tracking_s *prev; struct tracking_s *next; } tracking_t; static tracking_t *tracking_list = NULL; #ifndef WIN32 /* pollfd */ static struct pollfd *fds = NULL; #else static HANDLE *fds = NULL; static HANDLE mutex = INVALID_HANDLE_VALUE; #endif static handler_t *handler = NULL; /* pid file */ static char pidfn[SMALLBUF]; /* set by signal handlers */ static int reload_flag = 0, exit_flag = 0; /* Minimalistic support for UUID v4 */ /* Ref: RFC 4122 https://tools.ietf.org/html/rfc4122#section-4.1.2 */ #define UUID4_BYTESIZE 16 #ifdef HAVE_SYSTEMD # define SERVICE_UNIT_NAME "nut-server.service" #endif static const char *inet_ntopW (struct sockaddr_storage *s) { static char str[40]; switch (s->ss_family) { case AF_INET: return inet_ntop (AF_INET, &(((struct sockaddr_in *)s)->sin_addr), str, 16); case AF_INET6: return inet_ntop (AF_INET6, &(((struct sockaddr_in6 *)s)->sin6_addr), str, 40); default: errno = EAFNOSUPPORT; return NULL; } } /* return a pointer to the named ups if possible */ upstype_t *get_ups_ptr(const char *name) { upstype_t *tmp; if (!name) { return NULL; } for (tmp = firstups; tmp; tmp = tmp->next) { if (!strcasecmp(tmp->name, name)) { return tmp; } } return NULL; } /* mark the data stale if this is new, otherwise cleanup any remaining junk */ static void ups_data_stale(upstype_t *ups) { /* don't complain again if it's already known to be stale */ if (ups->stale == 1) { return; } ups->stale = 1; upslogx(LOG_NOTICE, "Data for UPS [%s] is stale - check driver", ups->name); } /* mark the data ok if this is new, otherwise do nothing */ static void ups_data_ok(upstype_t *ups) { if (ups->stale == 0) { return; } ups->stale = 0; upslogx(LOG_NOTICE, "UPS [%s] data is no longer stale", ups->name); } /* add another listening address */ void listen_add(const char *addr, const char *port) { stype_t *server; /* don't change listening addresses on reload */ if (reload_flag) { return; } /* grab some memory and add the info */ server = xcalloc(1, sizeof(*server)); server->addr = xstrdup(addr); server->port = xstrdup(port); server->sock_fd = ERROR_FD_SOCK; server->next = NULL; if (firstaddr) { stype_t *tmp; for (tmp = firstaddr; tmp->next; tmp = tmp->next); tmp->next = server; } else { firstaddr = server; } upsdebugx(3, "listen_add: added %s:%s", server->addr, server->port); } /* Close the connection if needed and free the allocated memory. * WARNING: it is up to the caller to rewrite the "next" pointer * in whoever points to this server instance (if needed)! */ static void stype_free(stype_t *server) { if (VALID_FD_SOCK(server->sock_fd)) { close(server->sock_fd); } free(server->addr); free(server->port); free(server); } /* create a listening socket for tcp connections */ static void setuptcp(stype_t *server) { #ifdef WIN32 WSADATA WSAdata; WSAStartup(2,&WSAdata); atexit((void(*)(void))WSACleanup); #endif struct addrinfo hints, *res, *ai; int v = 0, one = 1; if (VALID_FD_SOCK(server->sock_fd)) { /* Alredy bound, e.g. thanks to 'LISTEN *' handling and injection * into the list we loop over */ upsdebugx(6, "setuptcp: SKIP bind to %s port %s: entry already initialized", server->addr, server->port); return; } upsdebugx(3, "setuptcp: try to bind to %s port %s", server->addr, server->port); /* Special handling note for `LISTEN * ` directive with the * literal asterisk on systems with RFC-3493 (no relation!) support * for "IPv4-mapped addresses": it is possible (and technically * suffices) to LISTEN on "::" (aka "::0" or "0:0:0:0:0:0:0:0") and * also get an IPv4 any-address listener automatically. More so, * they would conflict and listening on one such socket precludes * listening on the other. On other systems (or with disabled * mapping so IPv6 really means "IPv6 only") we need both sockets. * NUT asks the system for "IPv6 only" mode when listening on any * sort of IPv6 addresses; it is however up to the system to implement * that ability and comply with our request. * Here we jump through some hoops: * * Try to get IPv6 any-address (unless constrained by CLI to IPv4); * * Try to get IPv4 any-address (unless constrained by CLI to IPv6), * log information for the sysadmin that it might conflict with the * IPv6 listener (IFF we have just opened one); * * Remember the one or two linked-list entries used, to release later. */ if (!strcmp(server->addr, "*")) { stype_t *serverAnyV4 = NULL, *serverAnyV6 = NULL; int canhaveAnyV4 = 0, canhaveAnyV6 = 0; /* Note: default opt_af==AF_UNSPEC so not constrained to only one protocol */ if (opt_af != AF_INET6) { /* Not constrained to IPv6 */ upsdebugx(1, "%s: handling 'LISTEN * %s' with IPv4 any-address support", __func__, server->port); serverAnyV4 = xcalloc(1, sizeof(*serverAnyV4)); serverAnyV4->addr = xstrdup("0.0.0.0"); serverAnyV4->port = xstrdup(server->port); serverAnyV4->sock_fd = ERROR_FD_SOCK; serverAnyV4->next = NULL; } if (opt_af != AF_INET) { /* Not constrained to IPv4 */ upsdebugx(1, "%s: handling 'LISTEN * %s' with IPv6 any-address support", __func__, server->port); serverAnyV6 = xcalloc(1, sizeof(*serverAnyV6)); serverAnyV6->addr = xstrdup("::0"); serverAnyV6->port = xstrdup(server->port); serverAnyV6->sock_fd = ERROR_FD_SOCK; serverAnyV6->next = NULL; } if (serverAnyV6) { setuptcp(serverAnyV6); if (VALID_FD_SOCK(serverAnyV6->sock_fd)) { canhaveAnyV6 = 1; } else { upsdebugx(3, "%s: Could not bind to %s:%s trying to handle a 'LISTEN *' directive", __func__, serverAnyV6->addr, serverAnyV6->port); } } if (serverAnyV4) { /* Try to get this listener if we can (no IPv4-mapped * IPv6 support was in force on this platform or its * configuration in some way that setsockopt(IPV6_V6ONLY) * failed to cancel). */ upsdebugx(3, "%s: try taking IPv4 'ANY'%s", __func__, canhaveAnyV6 ? " (if dual-stack IPv6 'ANY' did not grab it)" : ""); setuptcp(serverAnyV4); if (VALID_FD_SOCK(serverAnyV4->sock_fd)) { canhaveAnyV4 = 1; } else { upsdebugx(3, "%s: Could not bind to IPv4 %s:%s%s", __func__, serverAnyV4->addr, serverAnyV4->port, canhaveAnyV6 ? (" after trying to bind to IPv6: " "assuming dual-stack support on this " "system could not be disabled") : ""); } } if (!canhaveAnyV4 && !canhaveAnyV6) { fatalx(EXIT_FAILURE, "Handling of 'LISTEN * %s' directive failed to bind to 'ANY' address", server->port); } /* Finalize our findings and reset to normal operation * Note that at least one of these addresses is usable * and we keep it (and replace original "server" entry * keeping its place in the list). */ free(server->addr); free(server->port); if (canhaveAnyV4) { upsdebugx(3, "%s: remembering IPv4 'ANY' instead of 'LISTEN *'", __func__); server->addr = serverAnyV4->addr; server->port = serverAnyV4->port; server->sock_fd = serverAnyV4->sock_fd; /* ...and keep whatever server->next there was */ /* Free the ghost, all needed info was relocated */ free(serverAnyV4); } else { if (serverAnyV4) { /* Free any contents there were too */ stype_free(serverAnyV4); } } serverAnyV4 = NULL; if (canhaveAnyV6) { if (canhaveAnyV4) { /* "server" already populated by excerpts from V4, attach to it */ upsdebugx(3, "%s: also remembering IPv6 'ANY' instead of 'LISTEN *'", __func__); serverAnyV6->next = server->next; server->next = serverAnyV6; } else { /* Only retain V6 info */ upsdebugx(3, "%s: remembering IPv6 'ANY' instead of 'LISTEN *'", __func__); server->addr = serverAnyV6->addr; server->port = serverAnyV6->port; server->sock_fd = serverAnyV6->sock_fd; /* ...and keep whatever server->next there was */ /* Free the ghost, all needed info was relocated */ free(serverAnyV6); } } else { if (serverAnyV6) { /* Free any contents there were too */ stype_free(serverAnyV6); } } serverAnyV6 = NULL; return; } memset(&hints, 0, sizeof(hints)); hints.ai_flags = AI_PASSIVE; hints.ai_family = opt_af; hints.ai_socktype = SOCK_STREAM; hints.ai_protocol = IPPROTO_TCP; if ((v = getaddrinfo(server->addr, server->port, &hints, &res)) != 0) { if (v == EAI_SYSTEM) { fatal_with_errno(EXIT_FAILURE, "getaddrinfo"); } fatalx(EXIT_FAILURE, "getaddrinfo: %s", gai_strerror(v)); } for (ai = res; ai; ai = ai->ai_next) { TYPE_FD_SOCK sock_fd = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol); if (INVALID_FD_SOCK(sock_fd)) { upsdebug_with_errno(3, "setuptcp: socket"); continue; } if (setsockopt(sock_fd, SOL_SOCKET, SO_REUSEADDR, (void *)&one, sizeof(one)) != 0) { fatal_with_errno(EXIT_FAILURE, "setuptcp: setsockopt"); } /* Ordinarily we request that IPv6 listeners handle only IPv6 * and not IPv4 mapped addresses - if the OS would honour that. * TOTHINK: Does any platform need `#ifdef IPV6_V6ONLY` given * that we apparently already have AF_INET6 OS support everywhere? */ if (ai->ai_family == AF_INET6) { if (setsockopt(sock_fd, IPPROTO_IPV6, IPV6_V6ONLY, (void *)&one, sizeof(one)) != 0) { upsdebug_with_errno(3, "setuptcp: setsockopt IPV6_V6ONLY"); /* ack, ignore */ } } if (bind(sock_fd, ai->ai_addr, ai->ai_addrlen) < 0) { upsdebug_with_errno(3, "setuptcp: bind"); close(sock_fd); continue; } /* WSAEventSelect automatically set the socket to nonblocking mode */ #ifndef WIN32 if ((v = fcntl(sock_fd, F_GETFL, 0)) == -1) { fatal_with_errno(EXIT_FAILURE, "setuptcp: fcntl(get)"); } if (fcntl(sock_fd, F_SETFL, v | O_NDELAY) == -1) { fatal_with_errno(EXIT_FAILURE, "setuptcp: fcntl(set)"); } #endif if (listen(sock_fd, 16) < 0) { upsdebug_with_errno(3, "setuptcp: listen"); close(sock_fd); continue; } if (ai->ai_next) { char ipaddrbuf[SMALLBUF]; const char *ipaddr; snprintf(ipaddrbuf, sizeof(ipaddrbuf), " as "); ipaddr = inet_ntop(ai->ai_family, ai->ai_addr, ipaddrbuf + strlen(ipaddrbuf), sizeof(ipaddrbuf)); upslogx(LOG_WARNING, "setuptcp: bound to %s%s but there seem to be " "further (ignored) addresses resolved for this name", server->addr, ipaddr == NULL ? "" : ipaddrbuf); } server->sock_fd = sock_fd; break; } #ifdef WIN32 server->Event = CreateEvent(NULL, /* Security */ FALSE, /* auto-reset */ FALSE, /* initial state */ NULL); /* no name */ /* Associate socket event to the socket via its Event object */ WSAEventSelect( server->sock_fd, server->Event, FD_ACCEPT ); #endif freeaddrinfo(res); /* leave up to the caller, server_load(), to fail silently if there is * no other valid LISTEN interface */ if (INVALID_FD_SOCK(server->sock_fd)) { upslogx(LOG_ERR, "not listening on %s port %s", server->addr, server->port); } else { upslogx(LOG_INFO, "listening on %s port %s", server->addr, server->port); } return; } /* decrement the login counter for this ups */ static void declogins(const char *upsname) { upstype_t *ups; ups = get_ups_ptr(upsname); if (!ups) { upslogx(LOG_INFO, "Tried to decrement invalid ups name (%s)", upsname); return; } ups->numlogins--; if (ups->numlogins < 0) { upslogx(LOG_ERR, "Programming error: UPS [%s] has numlogins=%d", ups->name, ups->numlogins); } } /* disconnect a client connection and free all related memory */ static void client_disconnect(nut_ctype_t *client) { if (!client) { return; } upsdebugx(2, "Disconnect from %s", client->addr); shutdown(client->sock_fd, 2); close(client->sock_fd); #ifdef WIN32 CloseHandle(client->Event); #endif if (client->loginups) { declogins(client->loginups); } ssl_finish(client); pconf_finish(&client->ctx); if (client->prev) { client->prev->next = client->next; } else { /* deleting first entry */ firstclient = client->next; } if (client->next) { client->next->prev = client->prev; } else { /* deleting last entry */ /* lastclient = client->prev; */ } free(client->addr); free(client->loginups); free(client->password); free(client->username); free(client); return; } /* send the buffer of length to host * returns effectively a boolean: 0 = failed, 1 = sent ok */ int sendback(nut_ctype_t *client, const char *fmt, ...) { ssize_t res; size_t len; char ans[NUT_NET_ANSWER_MAX+1]; va_list ap; if (!client) { return 0; } va_start(ap, fmt); vsnprintf(ans, sizeof(ans), fmt, ap); va_end(ap); len = strlen(ans); /* System write() and our ssl_write() have a loophole that they write a * size_t amount of bytes and upon success return that in ssize_t value */ assert(len < SSIZE_MAX); #ifdef WITH_SSL if (client->ssl) { res = ssl_write(client, ans, len); } else #endif /* WITH_SSL */ { res = write(client->sock_fd, ans, len); } { /* scoping */ char * s = str_rtrim(ans, '\n'); upsdebugx(2, "write: [destfd=%d] [len=%" PRIuSIZE "] [%s]", client->sock_fd, len, s); } if (res < 0 || len != (size_t)res) { upslog_with_errno(LOG_NOTICE, "write() failed for %s", client->addr); client->last_heard = 0; return 0; /* failed */ } return 1; /* OK */ } /* just a simple wrapper for now */ int send_err(nut_ctype_t *client, const char *errtype) { if (!client) { return -1; } upsdebugx(4, "Sending error [%s] to client %s", errtype, client->addr); return sendback(client, "ERR %s\n", errtype); } /* disconnect anyone logged into this UPS */ void kick_login_clients(const char *upsname) { nut_ctype_t *client, *cnext; for (client = firstclient; client; client = cnext) { cnext = client->next; /* if it's not logged in, don't check it */ if (!client->loginups) { continue; } if (!strcmp(client->loginups, upsname)) { upslogx(LOG_INFO, "Kicking client %s (was on UPS [%s])\n", client->addr, upsname); client_disconnect(client); } } } /* make sure a UPS is sane - connected, with fresh data */ int ups_available(const upstype_t *ups, nut_ctype_t *client) { if (!ups) { /* Should never happen, but handle this * just in case instead of segfaulting */ upsdebugx(1, "%s: ERROR, called with a NULL ups pointer", __func__); send_err(client, NUT_ERR_FEATURE_NOT_SUPPORTED); return 0; } if (INVALID_FD(ups->sock_fd)) { send_err(client, NUT_ERR_DRIVER_NOT_CONNECTED); return 0; } if (ups->stale) { send_err(client, NUT_ERR_DATA_STALE); return 0; } /* must be OK */ return 1; } /* check flags and access for an incoming command from the network */ static void check_command(int cmdnum, nut_ctype_t *client, size_t numarg, const char **arg) { upsdebugx(6, "Entering %s: %s", __func__, numarg > 0 ? arg[0] : "<>"); if (netcmds[cmdnum].flags & FLAG_USER) { /* command requires previous authentication */ #ifdef HAVE_WRAP struct request_info req; #endif /* HAVE_WRAP */ if (!client->username) { upsdebugx(1, "%s: client not logged in yet", __func__); send_err(client, NUT_ERR_USERNAME_REQUIRED); return; } if (!client->password) { upsdebugx(1, "%s: client not logged in yet", __func__); send_err(client, NUT_ERR_PASSWORD_REQUIRED); return; } #ifdef HAVE_WRAP request_init(&req, RQ_DAEMON, progname, RQ_FILE, client->sock_fd, RQ_USER, client->username, 0); fromhost(&req); if (!hosts_access(&req)) { upsdebugx(1, "%s: while authenticating %s found that " "tcp-wrappers says access should be denied", __func__, client->username); send_err(client, NUT_ERR_ACCESS_DENIED); return; } #endif /* HAVE_WRAP */ } upsdebugx(6, "%s: Calling command handler for %s", __func__, numarg > 0 ? arg[0] : "<>"); /* looks good - call the command */ netcmds[cmdnum].func(client, (numarg < 2) ? 0 : (numarg - 1), (numarg > 1) ? &arg[1] : NULL); } /* parse requests from the network */ static void parse_net(nut_ctype_t *client) { int i; /* shouldn't happen */ if (client->ctx.numargs < 1) { send_err(client, NUT_ERR_UNKNOWN_COMMAND); return; } for (i = 0; netcmds[i].name; i++) { if (!strcasecmp(netcmds[i].name, client->ctx.arglist[0])) { check_command(i, client, client->ctx.numargs, (const char **) client->ctx.arglist); return; } } /* fallthrough = not matched by any entry in netcmds */ send_err(client, NUT_ERR_UNKNOWN_COMMAND); } /* answer incoming tcp connections */ static void client_connect(stype_t *server) { struct sockaddr_storage csock; #if defined(__hpux) && !defined(_XOPEN_SOURCE_EXTENDED) int clen; #else socklen_t clen; #endif int fd; nut_ctype_t *client; clen = sizeof(csock); fd = accept(server->sock_fd, (struct sockaddr *) &csock, &clen); if (fd < 0) { return; } client = xcalloc(1, sizeof(*client)); client->sock_fd = fd; time(&client->last_heard); client->addr = xstrdup(inet_ntopW(&csock)); client->tracking = 0; #ifdef WIN32 client->Event = CreateEvent(NULL, /* Security, */ FALSE, /* auto-reset */ FALSE, /* initial state */ NULL); /* no name */ /* Associate socket event to the socket via its Event object */ WSAEventSelect( client->sock_fd, client->Event, FD_READ ); #endif pconf_init(&client->ctx, NULL); if (firstclient) { firstclient->prev = client; client->next = firstclient; } firstclient = client; /* if (lastclient) { client->prev = lastclient; lastclient->next = client; } lastclient = client; */ upsdebugx(2, "Connect from %s", client->addr); } /* read tcp messages and handle them */ static void client_readline(nut_ctype_t *client) { char buf[SMALLBUF]; int i; ssize_t ret; #ifdef WITH_SSL if (client->ssl) { ret = ssl_read(client, buf, sizeof(buf)); } else #endif /* WITH_SSL */ { ret = read(client->sock_fd, buf, sizeof(buf)); } if (ret < 0) { upsdebug_with_errno(2, "Disconnect %s (read failure)", client->addr); client_disconnect(client); return; } if (ret == 0) { upsdebugx(2, "Disconnect %s (no data available)", client->addr); client_disconnect(client); return; } /* fragment handling code */ for (i = 0; i < ret; i++) { /* add to the receive queue one by one */ switch (pconf_char(&client->ctx, buf[i])) { case 1: time(&client->last_heard); /* command received */ parse_net(client); continue; case 0: continue; /* haven't gotten a line yet */ default: /* parse error */ upslogx(LOG_NOTICE, "Parse error on sock: %s", client->ctx.errmsg); return; } } return; } void server_load(void) { stype_t *server; /* default behaviour if no LISTEN address has been specified */ if (!firstaddr) { /* Note: default opt_af==AF_UNSPEC so not constrained to only one protocol */ if (opt_af != AF_INET) { upsdebugx(1, "%s: No LISTEN configuration provided, will try IPv6 localhost", __func__); listen_add("::1", string_const(PORT)); } if (opt_af != AF_INET6) { upsdebugx(1, "%s: No LISTEN configuration provided, will try IPv4 localhost", __func__); listen_add("127.0.0.1", string_const(PORT)); } } for (server = firstaddr; server; server = server->next) { setuptcp(server); } /* check if we have at least 1 valid LISTEN interface */ if (INVALID_FD_SOCK(firstaddr->sock_fd)) { fatalx(EXIT_FAILURE, "no listening interface available"); } } void server_free(void) { stype_t *server, *snext; /* cleanup server fds */ for (server = firstaddr; server; server = snext) { snext = server->next; stype_free(server); } firstaddr = NULL; } static void client_free(void) { nut_ctype_t *client, *cnext; /* cleanup client fds */ for (client = firstclient; client; client = cnext) { cnext = client->next; client_disconnect(client); } } static void driver_free(void) { upstype_t *ups, *unext; for (ups = firstups; ups; ups = unext) { upsdebugx(1, "%s: forgetting UPS [%s] (FD %d)", __func__, ups->name, ups->sock_fd); unext = ups->next; if (VALID_FD(ups->sock_fd)) { #ifndef WIN32 close(ups->sock_fd); #else DisconnectNamedPipe(ups->sock_fd); CloseHandle(ups->sock_fd); #endif ups->sock_fd = ERROR_FD; } sstate_infofree(ups); sstate_cmdfree(ups); pconf_finish(&ups->sock_ctx); free(ups->fn); free(ups->name); free(ups->desc); free(ups); } } static void upsd_cleanup(void) { if (strlen(pidfn) > 0) { unlink(pidfn); } /* dump everything */ user_flush(); desc_free(); server_free(); client_free(); driver_free(); tracking_free(); free(statepath); free(datapath); free(certfile); free(certname); free(certpasswd); free(fds); free(handler); #ifdef WIN32 if (mutex != INVALID_HANDLE_VALUE) { ReleaseMutex(mutex); CloseHandle(mutex); } #endif } static void poll_reload(void) { #ifndef WIN32 long ret; size_t maxalloc; ret = sysconf(_SC_OPEN_MAX); if ((intmax_t)ret < (intmax_t)maxconn) { fatalx(EXIT_FAILURE, "Your system limits the maximum number of connections to %ld\n" "but you requested %" PRIdMAX ". The server won't start until this\n" "problem is resolved.\n", ret, (intmax_t)maxconn); } if (1 > maxconn) { fatalx(EXIT_FAILURE, "You requested %" PRIdMAX " as maximum number of connections.\n" "The server won't start until this problem is resolved.\n", (intmax_t)maxconn); } /* How many items can we stuff into the array? */ maxalloc = SIZE_MAX / sizeof(void *); if ((uintmax_t)maxalloc < (uintmax_t)maxconn) { fatalx(EXIT_FAILURE, "You requested %" PRIdMAX " as maximum number of connections, but we can only allocate %" PRIuSIZE ".\n" "The server won't start until this problem is resolved.\n", (intmax_t)maxconn, maxalloc); } /* The checks above effectively limit that maxconn is in size_t range */ fds = xrealloc(fds, (size_t)maxconn * sizeof(*fds)); handler = xrealloc(handler, (size_t)maxconn * sizeof(*handler)); #else fds = xrealloc(fds, (size_t)MAXIMUM_WAIT_OBJECTS * sizeof(*fds)); handler = xrealloc(handler, (size_t)MAXIMUM_WAIT_OBJECTS * sizeof(*handler)); #endif } /* instant command and setvar status tracking */ /* allocate a new status tracking entry */ int tracking_add(const char *id) { tracking_t *item; if ((!tracking_enabled) || (!id)) return 0; item = xcalloc(1, sizeof(*item)); item->id = xstrdup(id); item->status = STAT_PENDING; time(&item->request_time); if (tracking_list) { tracking_list->prev = item; item->next = tracking_list; } tracking_list = item; return 1; } /* set status of a specific tracking entry */ int tracking_set(const char *id, const char *value) { tracking_t *item, *next_item; /* sanity checks */ if ((!tracking_list) || (!id) || (!value)) return 0; for (item = tracking_list; item; item = next_item) { next_item = item->next; if (!strcasecmp(item->id, id)) { item->status = atoi(value); return 1; } } return 0; /* id not found! */ } /* free a specific tracking entry */ int tracking_del(const char *id) { tracking_t *item, *next_item; /* sanity check */ if ((!tracking_list) || (!id)) return 0; upsdebugx(3, "%s: deleting id %s", __func__, id); for (item = tracking_list; item; item = next_item) { next_item = item->next; if (strcasecmp(item->id, id)) continue; if (item->prev) item->prev->next = item->next; else /* deleting first entry */ tracking_list = item->next; if (item->next) item->next->prev = item->prev; free(item->id); free(item); return 1; } return 0; /* id not found! */ } /* free all status tracking entries */ void tracking_free(void) { tracking_t *item, *next_item; /* sanity check */ if (!tracking_list) return; upsdebugx(3, "%s", __func__); for (item = tracking_list; item; item = next_item) { next_item = item->next; tracking_del(item->id); } } /* cleanup status tracking entries according to their age and tracking_delay */ void tracking_cleanup(void) { tracking_t *item, *next_item; time_t now; /* sanity check */ if (!tracking_list) return; time(&now); upsdebugx(3, "%s", __func__); for (item = tracking_list; item; item = next_item) { next_item = item->next; if (difftime(now, item->request_time) > tracking_delay) { tracking_del(item->id); } } } /* get status of a specific tracking entry */ char *tracking_get(const char *id) { tracking_t *item, *next_item; /* sanity checks */ if ((!tracking_list) || (!id)) return "ERR UNKNOWN"; for (item = tracking_list; item; item = next_item) { next_item = item->next; if (strcasecmp(item->id, id)) continue; switch (item->status) { case STAT_PENDING: return "PENDING"; case STAT_HANDLED: return "SUCCESS"; case STAT_UNKNOWN: return "ERR UNKNOWN"; case STAT_INVALID: return "ERR INVALID-ARGUMENT"; case STAT_FAILED: return "ERR FAILED"; } } return "ERR UNKNOWN"; /* id not found! */ } /* enable general status tracking (tracking_enabled) and return its value (1). */ int tracking_enable(void) { tracking_enabled = 1; return tracking_enabled; } /* disable general status tracking only if no client use it anymore. * return the new value for tracking_enabled */ int tracking_disable(void) { nut_ctype_t *client, *cnext; for (client = firstclient; client; client = cnext) { cnext = client->next; if (client->tracking == 1) return 1; } return 0; } /* return current general status of tracking (tracking_enabled). */ int tracking_is_enabled(void) { return tracking_enabled; } /* UUID v4 basic implementation * Note: 'dest' must be at least `UUID4_LEN` long */ int nut_uuid_v4(char *uuid_str) { size_t i; uint8_t nut_uuid[UUID4_BYTESIZE]; if (!uuid_str) return 0; for (i = 0; i < UUID4_BYTESIZE; i++) nut_uuid[i] = (uint8_t)rand() + (uint8_t)rand(); /* set variant and version */ nut_uuid[6] = (nut_uuid[6] & 0x0F) | 0x40; nut_uuid[8] = (nut_uuid[8] & 0x3F) | 0x80; return snprintf(uuid_str, UUID4_LEN, "%02X%02X%02X%02X-%02X%02X-%02X%02X-%02X%02X-%02X%02X%02X%02X%02X%02X", nut_uuid[0], nut_uuid[1], nut_uuid[2], nut_uuid[3], nut_uuid[4], nut_uuid[5], nut_uuid[6], nut_uuid[7], nut_uuid[8], nut_uuid[9], nut_uuid[10], nut_uuid[11], nut_uuid[12], nut_uuid[13], nut_uuid[14], nut_uuid[15]); } static void set_exit_flag(int sig) { exit_flag = sig; } static void set_reload_flag(int sig) { NUT_UNUSED_VARIABLE(sig); reload_flag = 1; } /* service requests and check on new data */ static void mainloop(void) { #ifndef WIN32 int ret; nfds_t i; #else DWORD ret; pipe_conn_t * conn; #endif nfds_t nfds = 0; upstype_t *ups; nut_ctype_t *client, *cnext; stype_t *server; time_t now; upsnotify(NOTIFY_STATE_WATCHDOG, NULL); time(&now); if (reload_flag) { upsnotify(NOTIFY_STATE_RELOADING, NULL); conf_reload(); poll_reload(); reload_flag = 0; upsnotify(NOTIFY_STATE_READY, NULL); } /* cleanup instcmd/setvar status tracking entries if needed */ tracking_cleanup(); #ifndef WIN32 /* scan through driver sockets */ for (ups = firstups; ups && (nfds < maxconn); ups = ups->next) { /* see if we need to (re)connect to the socket */ if (INVALID_FD(ups->sock_fd)) { upsdebugx(1, "%s: UPS [%s] is not currently connected, " "trying to reconnect", __func__, ups->name); ups->sock_fd = sstate_connect(ups); if (INVALID_FD(ups->sock_fd)) { upsdebugx(1, "%s: UPS [%s] is still not connected (FD %d)", __func__, ups->name, ups->sock_fd); } else { upsdebugx(1, "%s: UPS [%s] is now connected as FD %d", __func__, ups->name, ups->sock_fd); } continue; } /* throw some warnings if it's not feeding us data any more */ if (sstate_dead(ups, maxage)) { ups_data_stale(ups); } else { ups_data_ok(ups); } fds[nfds].fd = ups->sock_fd; fds[nfds].events = POLLIN; handler[nfds].type = DRIVER; handler[nfds].data = ups; nfds++; } /* scan through client sockets */ for (client = firstclient; client; client = cnext) { cnext = client->next; if (difftime(now, client->last_heard) > 60) { /* shed clients after 1 minute of inactivity */ /* FIXME: create an upsd.conf parameter (CLIENT_INACTIVITY_DELAY) */ client_disconnect(client); continue; } if (nfds >= maxconn) { /* ignore clients that we are unable to handle */ continue; } fds[nfds].fd = client->sock_fd; fds[nfds].events = POLLIN; handler[nfds].type = CLIENT; handler[nfds].data = client; nfds++; } /* scan through server sockets */ for (server = firstaddr; server && (nfds < maxconn); server = server->next) { if (server->sock_fd < 0) { continue; } fds[nfds].fd = server->sock_fd; fds[nfds].events = POLLIN; handler[nfds].type = SERVER; handler[nfds].data = server; nfds++; } upsdebugx(2, "%s: polling %" PRIdMAX " filedescriptors", __func__, (intmax_t)nfds); ret = poll(fds, nfds, 2000); if (ret == 0) { upsdebugx(2, "%s: no data available", __func__); return; } if (ret < 0) { upslog_with_errno(LOG_ERR, "%s", __func__); return; } for (i = 0; i < nfds; i++) { if (fds[i].revents & (POLLHUP|POLLERR|POLLNVAL)) { switch(handler[i].type) { case DRIVER: sstate_disconnect((upstype_t *)handler[i].data); break; case CLIENT: client_disconnect((nut_ctype_t *)handler[i].data); break; case SERVER: upsdebugx(2, "%s: server disconnected", __func__); break; #if (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_PUSH_POP) && ( (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_COVERED_SWITCH_DEFAULT) || (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_UNREACHABLE_CODE) ) # pragma GCC diagnostic push #endif #ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_COVERED_SWITCH_DEFAULT # pragma GCC diagnostic ignored "-Wcovered-switch-default" #endif #ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_UNREACHABLE_CODE # pragma GCC diagnostic ignored "-Wunreachable-code" #endif /* Older CLANG (e.g. clang-3.4) seems to not support the GCC pragmas above */ #ifdef __clang__ #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wcovered-switch-default" #pragma clang diagnostic ignored "-Wunreachable-code" #endif /* All enum cases defined as of the time of coding * have been covered above. Handle later definitions, * memory corruptions and buggy inputs below... */ default: upsdebugx(2, "%s: disconnected", __func__); break; #ifdef __clang__ #pragma clang diagnostic pop #endif #if (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_PUSH_POP) && ( (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_COVERED_SWITCH_DEFAULT) || (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_UNREACHABLE_CODE) ) # pragma GCC diagnostic pop #endif } continue; } if (fds[i].revents & POLLIN) { switch(handler[i].type) { case DRIVER: sstate_readline((upstype_t *)handler[i].data); break; case CLIENT: client_readline((nut_ctype_t *)handler[i].data); break; case SERVER: client_connect((stype_t *)handler[i].data); break; #if (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_PUSH_POP) && ( (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_COVERED_SWITCH_DEFAULT) || (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_UNREACHABLE_CODE) ) # pragma GCC diagnostic push #endif #ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_COVERED_SWITCH_DEFAULT # pragma GCC diagnostic ignored "-Wcovered-switch-default" #endif #ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_UNREACHABLE_CODE # pragma GCC diagnostic ignored "-Wunreachable-code" #endif /* Older CLANG (e.g. clang-3.4) seems to not support the GCC pragmas above */ #ifdef __clang__ #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wcovered-switch-default" #pragma clang diagnostic ignored "-Wunreachable-code" #endif /* All enum cases defined as of the time of coding * have been covered above. Handle later definitions, * memory corruptions and buggy inputs below... */ default: upsdebugx(2, "%s: has data available", __func__); break; #ifdef __clang__ #pragma clang diagnostic pop #endif #if (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_PUSH_POP) && ( (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_COVERED_SWITCH_DEFAULT) || (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_UNREACHABLE_CODE) ) # pragma GCC diagnostic pop #endif } continue; } } #else /* scan through driver sockets */ for (ups = firstups; ups && (nfds < maxconn); ups = ups->next) { /* see if we need to (re)connect to the socket */ if (INVALID_FD(ups->sock_fd)) { upsdebugx(1, "%s: UPS [%s] is not currently connected, " "trying to reconnect", __func__, ups->name); ups->sock_fd = sstate_connect(ups); if (INVALID_FD(ups->sock_fd)) { upsdebugx(1, "%s: UPS [%s] is still not connected (FD %d)", __func__, ups->name, ups->sock_fd); } else { upsdebugx(1, "%s: UPS [%s] is now connected as FD %d", __func__, ups->name, ups->sock_fd); } continue; } /* throw some warnings if it's not feeding us data any more */ if (sstate_dead(ups, maxage)) { ups_data_stale(ups); } else { ups_data_ok(ups); } /* FIXME: Is the conditional needed? We got here... */ if (VALID_FD(ups->sock_fd)) { fds[nfds] = ups->read_overlapped.hEvent; handler[nfds].type = DRIVER; handler[nfds].data = ups; nfds++; } } /* scan through client sockets */ for (client = firstclient; client; client = cnext) { cnext = client->next; if (difftime(now, client->last_heard) > 60) { /* shed clients after 1 minute of inactivity */ client_disconnect(client); continue; } if (nfds >= maxconn) { /* ignore clients that we are unable to handle */ continue; } fds[nfds] = client->Event; handler[nfds].type = CLIENT; handler[nfds].data = client; nfds++; } /* scan through server sockets */ for (server = firstaddr; server && (nfds < maxconn); server = server->next) { if (INVALID_FD_SOCK(server->sock_fd)) { continue; } fds[nfds] = server->Event; handler[nfds].type = SERVER; handler[nfds].data = server; nfds++; } /* Wait on the read IO on named pipe */ for (conn = pipe_connhead; conn; conn = conn->next) { fds[nfds] = conn->overlapped.hEvent; handler[nfds].type = NAMED_PIPE; handler[nfds].data = (void *)conn; nfds++; } /* Add the new named pipe connected event */ fds[nfds] = pipe_connection_overlapped.hEvent; handler[nfds].type = NAMED_PIPE; handler[nfds].data = NULL; nfds++; upsdebugx(2, "%s: wait for %d filedescriptors", __func__, nfds); /* https://docs.microsoft.com/en-us/windows/win32/api/synchapi/nf-synchapi-waitformultipleobjects */ ret = WaitForMultipleObjects(nfds,fds,FALSE,2000); upsdebugx(6, "%s: wait for filedescriptors done: %" PRIu64, __func__, ret); if (ret == WAIT_TIMEOUT) { upsdebugx(2, "%s: no data available", __func__); return; } if (ret == WAIT_FAILED) { DWORD err = GetLastError(); err = err; /* remove compile time warning */ upslog_with_errno(LOG_ERR, "%s", __func__); upsdebugx(2, "%s: wait failed: code 0x%" PRIx64, __func__, err); return; } #if (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_PUSH_POP) && ( (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_TYPE_LIMITS) || (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_TAUTOLOGICAL_CONSTANT_OUT_OF_RANGE_COMPARE) ) # pragma GCC diagnostic push #endif #ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_TYPE_LIMITS # pragma GCC diagnostic ignored "-Wtype-limits" #endif #ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_TAUTOLOGICAL_CONSTANT_OUT_OF_RANGE_COMPARE # pragma GCC diagnostic ignored "-Wtautological-constant-out-of-range-compare" #endif if (ret >= WAIT_ABANDONED_0 && ret <= WAIT_ABANDONED_0 + nfds - 1) { /* One abandoned mutex object that satisfied the wait? */ ret = ret - WAIT_ABANDONED_0; upsdebugx(5, "%s: got abandoned FD array item: %" PRIu64, __func__, nfds, ret); /* FIXME: Should this be handled somehow? Cleanup? Abort?.. */ } else if (ret >= WAIT_OBJECT_0 && ret <= WAIT_OBJECT_0 + nfds - 1) { /* Which one handle was triggered this time? */ /* Note: WAIT_OBJECT_0 may be currently defined as 0, * but docs insist on checking and shifting the range */ ret = ret - WAIT_OBJECT_0; upsdebugx(5, "%s: got event on FD array item: %" PRIu64, __func__, nfds, ret); } #if (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_PUSH_POP) && ( (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_TYPE_LIMITS) || (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_TAUTOLOGICAL_CONSTANT_OUT_OF_RANGE_COMPARE) ) # pragma GCC diagnostic pop #endif if (ret >= nfds) { /* Array indexes are [0..nfds-1] */ upsdebugx(2, "%s: unexpected response to query about data available: %" PRIu64, __func__, ret); return; } upsdebugx(6, "%s: requesting handler[%" PRIu64 "]", __func__, ret); upsdebugx(6, "%s: handler.type=%d handler.data=%p", __func__, handler[ret].type, handler[ret].data); switch(handler[ret].type) { case DRIVER: upsdebugx(4, "%s: calling sstate_readline() for DRIVER", __func__); sstate_readline((upstype_t *)handler[ret].data); break; case CLIENT: upsdebugx(4, "%s: calling client_readline() for CLIENT", __func__); client_readline((nut_ctype_t *)handler[ret].data); break; case SERVER: upsdebugx(4, "%s: calling client_connect() for SERVER", __func__); client_connect((stype_t *)handler[ret].data); break; case NAMED_PIPE: /* a new pipe connection has been signaled */ if (fds[ret] == pipe_connection_overlapped.hEvent) { upsdebugx(4, "%s: calling pipe_connect() for NAMED_PIPE", __func__); pipe_connect(); } /* one of the read event handle has been signaled */ else { upsdebugx(4, "%s: calling pipe_ready() for NAMED_PIPE", __func__); pipe_conn_t * conn = handler[ret].data; if ( pipe_ready(conn) ) { if (!strncmp(conn->buf, SIGCMD_STOP, sizeof(SIGCMD_STOP))) { set_exit_flag(1); } else if (!strncmp(conn->buf, SIGCMD_RELOAD, sizeof(SIGCMD_RELOAD))) { set_reload_flag(1); } else { upslogx(LOG_ERR,"Unknown signal" ); } upsdebugx(4, "%s: calling pipe_disconnect() for NAMED_PIPE", __func__); pipe_disconnect(conn); } } break; default: upsdebugx(2, "%s: has data available", __func__); break; } #endif } static void help(const char *arg_progname) __attribute__((noreturn)); static void help(const char *arg_progname) { printf("Network server for UPS data.\n\n"); printf("usage: %s [OPTIONS]\n", arg_progname); printf("\n"); printf(" -c send via signal to background process\n"); printf(" commands:\n"); printf(" - reload: reread configuration files\n"); printf(" - stop: stop process and exit\n"); #ifndef WIN32 printf(" -P send the signal above to specified PID (bypassing PID file)\n"); #endif printf(" -D raise debugging level (and stay foreground by default)\n"); printf(" -F stay foregrounded even if no debugging is enabled\n"); printf(" -FF stay foregrounded and still save the PID file\n"); printf(" -B stay backgrounded even if debugging is bumped\n"); printf(" -h display this help text\n"); printf(" -V display the version of this software\n"); printf(" -r chroots to \n"); printf(" -q raise log level threshold\n"); printf(" -u switch to (if started as root)\n"); printf(" -4 IPv4 only\n"); printf(" -6 IPv6 only\n"); nut_report_config_flags(); exit(EXIT_SUCCESS); } static void setup_signals(void) { #ifndef WIN32 struct sigaction sa; sigemptyset(&sa.sa_mask); sigaddset(&sa.sa_mask, SIGHUP); sa.sa_flags = 0; /* basic signal setup to ignore SIGPIPE */ #if (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_PUSH_POP) && (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_STRICT_PROTOTYPES) # pragma GCC diagnostic push # pragma GCC diagnostic ignored "-Wstrict-prototypes" #endif sa.sa_handler = SIG_IGN; #if (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_PUSH_POP) && (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_STRICT_PROTOTYPES) # pragma GCC diagnostic pop #endif sigaction(SIGPIPE, &sa, NULL); /* handle shutdown signals */ sa.sa_handler = set_exit_flag; sigaction(SIGINT, &sa, NULL); sigaction(SIGQUIT, &sa, NULL); sigaction(SIGTERM, &sa, NULL); /* handle reloading */ sa.sa_handler = set_reload_flag; sigaction(SIGHUP, &sa, NULL); #else pipe_create(UPSD_PIPE_NAME); #endif } void check_perms(const char *fn) { #ifndef WIN32 int ret; struct stat st; ret = stat(fn, &st); if (ret != 0) { fatal_with_errno(EXIT_FAILURE, "stat %s", fn); } /* include the x bit here in case we check a directory */ if (st.st_mode & (S_IROTH | S_IXOTH)) { upslogx(LOG_WARNING, "%s is world readable", fn); } #else NUT_UNUSED_VARIABLE(fn); #endif } int main(int argc, char **argv) { int i, cmdret = 0, foreground = -1; #ifndef WIN32 int cmd = 0; pid_t oldpid = -1; #else const char * cmd = NULL; #endif char *chroot_path = NULL; const char *user = RUN_AS_USER; struct passwd *new_uid = NULL; progname = xbasename(argv[0]); /* yes, xstrdup - the conf handlers call free on this later */ statepath = xstrdup(dflt_statepath()); #ifndef WIN32 datapath = xstrdup(NUT_DATADIR); #else datapath = getfullpath(PATH_SHARE); /* remove trailing .exe */ char * drv_name; drv_name = (char *)xbasename(argv[0]); char * name = strrchr(drv_name,'.'); if( name != NULL ) { if(strcasecmp(name, ".exe") == 0 ) { progname = strdup(drv_name); char * t = strrchr(progname,'.'); *t = 0; } } else { progname = drv_name; } #endif /* set up some things for later */ snprintf(pidfn, sizeof(pidfn), "%s/%s.pid", altpidpath(), progname); printf("Network UPS Tools %s %s\n", progname, UPS_VERSION); while ((i = getopt(argc, argv, "+h46p:qr:i:fu:Vc:P:DFB")) != -1) { switch (i) { case 'p': case 'i': fatalx(EXIT_FAILURE, "Specifying a listening addresses with '-i
' and '-p '\n" "is deprecated. Use 'LISTEN
[]' in 'upsd.conf' instead.\n" "See 'man 8 upsd.conf' for more information."); #ifndef HAVE___ATTRIBUTE__NORETURN exit(EXIT_FAILURE); /* Should not get here in practice, but compiler is afraid we can fall through */ #endif case 'q': nut_log_level++; break; case 'r': chroot_path = optarg; break; case 'u': user = optarg; break; case 'V': /* Note - we already printed the banner for program name */ nut_report_config_flags(); exit(EXIT_SUCCESS); case 'c': if (!strncmp(optarg, "reload", strlen(optarg))) { cmd = SIGCMD_RELOAD; } else if (!strncmp(optarg, "stop", strlen(optarg))) { cmd = SIGCMD_STOP; } /* bad command given */ if (cmd == 0) help(progname); break; #ifndef WIN32 case 'P': if ((oldpid = parsepid(optarg)) < 0) help(progname); break; #endif case 'D': nut_debug_level++; nut_debug_level_args++; break; case 'F': if (foreground > 0) { /* specified twice to save PID file anyway */ foreground = 2; } else { foreground = 1; } break; case 'B': foreground = 0; break; case '4': opt_af = AF_INET; break; case '6': opt_af = AF_INET6; break; case 'h': default: help(progname); } } if (foreground < 0) { if (nut_debug_level > 0) { foreground = 1; } else { foreground = 0; } } { /* scoping */ char *s = getenv("NUT_DEBUG_LEVEL"); int l; if (s && str_to_int(s, &l, 10)) { if (l > 0 && nut_debug_level_args < 1) { upslogx(LOG_INFO, "Defaulting debug verbosity to NUT_DEBUG_LEVEL=%d " "since none was requested by command-line options", l); nut_debug_level = l; nut_debug_level_args = l; } /* else follow -D settings */ } /* else nothing to bother about */ } /* Note: "cmd" may be non-trivial to command that instance by * explicit PID number or lookup in PID file (error if absent). * Otherwise, we are being asked to start and "cmd" is 0/NULL - * for probing whether a competing older instance of this program * is running (error if it is). */ #ifndef WIN32 /* If cmd == 0 we are starting and check if a previous instance * is running by sending signal '0' (i.e. 'kill 0' equivalent) */ if (oldpid < 0) { cmdret = sendsignalfn(pidfn, cmd); } else { cmdret = sendsignalpid(oldpid, cmd); } #else /* if WIN32 */ if (cmd) { /* Command the running daemon, it should be there */ cmdret = sendsignal(UPSD_PIPE_NAME, cmd); } else { /* Starting new daemon, check for competition */ mutex = CreateMutex(NULL, TRUE, UPSD_PIPE_NAME); if (mutex == NULL) { if (GetLastError() != ERROR_ACCESS_DENIED) { fatalx(EXIT_FAILURE, "Can not create mutex %s : %d.\n", UPSD_PIPE_NAME, (int)GetLastError()); } } cmdret = -1; /* unknown, maybe ok */ if (GetLastError() == ERROR_ALREADY_EXISTS || GetLastError() == ERROR_ACCESS_DENIED ) { cmdret = 0; /* known conflict */ } } #endif /* WIN32 */ switch (cmdret) { case 0: if (cmd) { upsdebugx(1, "Signaled old daemon OK"); } else { printf("Fatal error: A previous upsd instance is already running!\n"); printf("Either stop the previous instance first, or use the 'reload' command.\n"); exit(EXIT_FAILURE); } break; case -3: case -2: /* if starting new daemon, no competition running - * maybe OK (or failed to detect it => problem) * if signaling old daemon - certainly have a problem */ upslogx(LOG_WARNING, "Could not %s PID file '%s' " "to see if previous upsd instance is " "already running!", (cmdret == -3 ? "find" : "parse"), pidfn); break; case -1: case 1: /* WIN32 */ default: /* if cmd was nontrivial - speak up below, else be quiet */ upsdebugx(1, "Just failed to send signal, no daemon was running"); break; } if (cmd) { /* We were signalling a daemon, successfully or not - exit now... */ if (cmdret != 0) { /* sendsignal*() above might have logged more details * for troubleshooting, e.g. about lack of PID file */ upslogx(LOG_NOTICE, "Failed to signal the currently running daemon (if any)"); #ifndef WIN32 # ifdef HAVE_SYSTEMD switch (cmd) { case SIGCMD_RELOAD: upslogx(LOG_NOTICE, "Try 'systemctl reload %s'%s", SERVICE_UNIT_NAME, (oldpid < 0 ? " or add '-P $PID' argument" : "")); break; case SIGCMD_STOP: upslogx(LOG_NOTICE, "Try 'systemctl stop %s'%s", SERVICE_UNIT_NAME, (oldpid < 0 ? " or add '-P $PID' argument" : "")); break; default: upslogx(LOG_NOTICE, "Try 'systemctl %s'%s", SERVICE_UNIT_NAME, (oldpid < 0 ? " or add '-P $PID' argument" : "")); break; } /* ... or edit nut-server.service locally to start `upsd -FF` * and so save the PID file for ability to manage the daemon * beside the service framework, possibly confusing things... */ # else if (oldpid < 0) { upslogx(LOG_NOTICE, "Try to add '-P $PID' argument"); } # endif #endif /* not WIN32 */ } exit((cmdret == 0) ? EXIT_SUCCESS : EXIT_FAILURE); } argc -= optind; argv += optind; if (argc != 0) { help(progname); } atexit(upsd_cleanup); setup_signals(); open_syslog(progname); /* send logging to the syslog pre-background for later use */ syslogbit_set(); /* do this here, since getpwnam() might not work in the chroot */ new_uid = get_user_pwent(user); if (chroot_path) { chroot_start(chroot_path); } #ifndef WIN32 /* default to system limit (may be overridden in upsd.conf) */ /* FIXME: Check for overflows (and int size of nfds_t vs. long) - see get_max_pid_t() for example */ maxconn = (nfds_t)sysconf(_SC_OPEN_MAX); #else maxconn = 64; /*FIXME : arbitrary value, need adjustement */ #endif /* handle upsd.conf */ load_upsdconf(0); /* 0 = initial */ /* CLI debug level can not be smaller than debug_min specified * in upsd.conf. Note that non-zero debug_min does not impact * foreground running mode. */ if (nut_debug_level_global > nut_debug_level) nut_debug_level = nut_debug_level_global; upsdebugx(1, "debug level is '%d'", nut_debug_level); { /* scope */ /* As documented above, the ALLOW_NO_DEVICE can be provided via * envvars and then has higher priority than an upsd.conf setting */ const char *envvar = getenv("ALLOW_NO_DEVICE"); if ( envvar != NULL) { if ( (!strncasecmp("TRUE", envvar, 4)) || (!strncasecmp("YES", envvar, 3)) || (!strncasecmp("ON", envvar, 2)) || (!strncasecmp("1", envvar, 1)) ) { /* Admins of this server expressed a desire to serve * anything on the NUT protocol, even if nothing is * configured yet - tell the clients so, properly. */ allow_no_device = 1; } else if ( (!strncasecmp("FALSE", envvar, 5)) || (!strncasecmp("NO", envvar, 2)) || (!strncasecmp("OFF", envvar, 3)) || (!strncasecmp("0", envvar, 1)) ) { /* Admins of this server expressed a desire to serve * anything on the NUT protocol, even if nothing is * configured yet - tell the clients so, properly. */ allow_no_device = 0; } } } /* scope */ /* start server */ server_load(); become_user(new_uid); #ifndef WIN32 if (chdir(statepath)) { fatal_with_errno(EXIT_FAILURE, "Can't chdir to %s", statepath); } else { upsdebugx(1, "chdired into statepath %s for driver sockets", statepath); } #endif /* check statepath perms */ check_perms(statepath); /* handle ups.conf */ read_upsconf(1); /* 1 = may abort upon fundamental errors */ upsconf_add(0); /* 0 = initial */ poll_reload(); if (num_ups == 0) { if (allow_no_device) { upslogx(LOG_WARNING, "Normally at least one UPS must be defined in ups.conf, currently there are none (please configure the file and reload the service)"); } else { fatalx(EXIT_FAILURE, "Fatal error: at least one UPS must be defined in ups.conf"); } } else { upslogx(LOG_INFO, "Found %d UPS defined in ups.conf", num_ups); } /* try to bring in the var/cmd descriptions */ desc_load(); /* handle upsd.users */ user_load(); if (!foreground) { background(); writepid(pidfn); } else { if (foreground == 2) { upslogx(LOG_WARNING, "Running as foreground process, but saving a PID file anyway"); writepid(pidfn); } else { upslogx(LOG_WARNING, "Running as foreground process, not saving a PID file"); memset(pidfn, 0, sizeof(pidfn)); } } /* initialize SSL (keyfile must be readable by nut user) */ ssl_init(); upsnotify(NOTIFY_STATE_READY_WITH_PID, NULL); while (!exit_flag) { /* Note: mainloop() calls upsnotify(NOTIFY_STATE_WATCHDOG, NULL); */ mainloop(); } upslogx(LOG_INFO, "Signal %d: exiting", exit_flag); upsnotify(NOTIFY_STATE_STOPPING, "Signal %d: exiting", exit_flag); ssl_cleanup(); return EXIT_SUCCESS; } nut-2.8.1/server/netset.h0000644000175000017500000000240114500336654012235 00000000000000/* netset.h - SET handler for upsd Copyright (C) 2003 Russell Kroll 2005 Arnaud Quette 2007 Peter Selinger 2013 Emilien Kia 2020 Jim Klimov 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 2 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, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef NUT_NETSET_H_SEEN #define NUT_NETSET_H_SEEN 1 #ifdef __cplusplus /* *INDENT-OFF* */ extern "C" { /* *INDENT-ON* */ #endif void net_set(nut_ctype_t *client, size_t numarg, const char **arg); #ifdef __cplusplus /* *INDENT-OFF* */ } /* *INDENT-ON* */ #endif #endif /* NUT_NETSET_H_SEEN */ nut-2.8.1/server/sstate.c0000644000175000017500000003037714501607135012242 00000000000000/* sstate.c - Network UPS Tools server-side state management Copyright (C) 2003 Russell Kroll 2008 Arjen de Korte 2012 Arnaud Quette 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 2 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, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "common.h" #include "timehead.h" #include "sstate.h" #include "upsd.h" #include "upstype.h" #include "nut_stdint.h" #include #include #include #include #include #ifndef WIN32 #include #include #endif static int parse_args(upstype_t *ups, size_t numargs, char **arg) { if (numargs < 1) return 0; if (!strcasecmp(arg[0], "PONG")) { upsdebugx(3, "Got PONG from UPS [%s]", ups->name); return 1; } if (!strcasecmp(arg[0], "DUMPDONE")) { upsdebugx(3, "UPS [%s]: dump is done", ups->name); ups->dumpdone = 1; return 1; } if (!strcasecmp(arg[0], "DATASTALE")) { upsdebugx(3, "UPS [%s]: data is STALE now", ups->name); ups->data_ok = 0; return 1; } if (!strcasecmp(arg[0], "DATAOK")) { upsdebugx(3, "UPS [%s]: data is NOT STALE now", ups->name); ups->data_ok = 1; return 1; } if (numargs < 2) return 0; /* FIXME: all these should return their state_...() value! */ /* ADDCMD */ if (!strcasecmp(arg[0], "ADDCMD")) { state_addcmd(&ups->cmdlist, arg[1]); return 1; } /* DELCMD */ if (!strcasecmp(arg[0], "DELCMD")) { state_delcmd(&ups->cmdlist, arg[1]); return 1; } /* DELINFO */ if (!strcasecmp(arg[0], "DELINFO")) { state_delinfo(&ups->inforoot, arg[1]); return 1; } if (numargs < 3) return 0; /* SETFLAGS ... */ if (!strcasecmp(arg[0], "SETFLAGS")) { state_setflags(ups->inforoot, arg[1], numargs - 2, &arg[2]); return 1; } /* SETINFO */ if (!strcasecmp(arg[0], "SETINFO")) { state_setinfo(&ups->inforoot, arg[1], arg[2]); return 1; } /* ADDENUM */ if (!strcasecmp(arg[0], "ADDENUM")) { state_addenum(ups->inforoot, arg[1], arg[2]); return 1; } /* DELENUM */ if (!strcasecmp(arg[0], "DELENUM")) { state_delenum(ups->inforoot, arg[1], arg[2]); return 1; } /* SETAUX */ if (!strcasecmp(arg[0], "SETAUX")) { state_setaux(ups->inforoot, arg[1], arg[2]); return 1; } /* TRACKING */ if (!strcasecmp(arg[0], "TRACKING")) { tracking_set(arg[1], arg[2]); upsdebugx(1, "TRACKING: ID %s status %s", arg[1], arg[2]); /* log actual result of instcmd / setvar */ if (strncmp(arg[2], "PENDING", 7) != 0) { upslogx(LOG_INFO, "tracking ID: %s\tresult: %s", arg[1], tracking_get(arg[1])); } return 1; } if (numargs < 4) return 0; /* ADDRANGE */ if (!strcasecmp(arg[0], "ADDRANGE")) { state_addrange(ups->inforoot, arg[1], atoi(arg[2]), atoi(arg[3])); return 1; } /* DELRANGE */ if (!strcasecmp(arg[0], "DELRANGE")) { state_delrange(ups->inforoot, arg[1], atoi(arg[2]), atoi(arg[3])); return 1; } return 0; } /* nothing fancy - just make the driver say something back to us */ static void sendping(upstype_t *ups) { ssize_t ret; const char *cmd = "PING\n"; size_t cmdlen = strlen(cmd); if ((!ups) || INVALID_FD(ups->sock_fd)) { return; } upsdebugx(3, "Pinging UPS [%s]", ups->name); #ifndef WIN32 ret = write(ups->sock_fd, cmd, cmdlen); #else DWORD bytesWritten = 0; BOOL result = FALSE; result = WriteFile (ups->sock_fd, cmd, cmdlen, &bytesWritten, NULL); if( result == 0 ) { /* Write failed */ ret = 0; } else { ret = (ssize_t)bytesWritten; } #endif if ((ret < 1) || (ret != (ssize_t)cmdlen)) { upslog_with_errno(LOG_NOTICE, "Send ping to UPS [%s] failed", ups->name); sstate_disconnect(ups); return; } time(&ups->last_ping); } /* interface */ TYPE_FD sstate_connect(upstype_t *ups) { TYPE_FD fd; #ifndef WIN32 const char *dumpcmd = "DUMPALL\n"; size_t dumpcmdlen = strlen(dumpcmd); ssize_t ret; struct sockaddr_un sa; upsdebugx(2, "%s: preparing UNIX socket %s", __func__, NUT_STRARG(ups->fn)); check_unix_socket_filename(ups->fn); memset(&sa, '\0', sizeof(sa)); sa.sun_family = AF_UNIX; snprintf(sa.sun_path, sizeof(sa.sun_path), "%s", ups->fn); fd = socket(AF_UNIX, SOCK_STREAM, 0); if (INVALID_FD(fd)) { upslog_with_errno(LOG_ERR, "Can't create socket for UPS [%s]", ups->name); return ERROR_FD; } ret = connect(fd, (struct sockaddr *) &sa, sizeof(sa)); if (ret < 0) { time_t now; upsdebugx(2, "%s: failed to connect() UNIX socket %s (%s)", __func__, NUT_STRARG(ups->fn), sa.sun_path); close(fd); /* rate-limit complaints - don't spam the syslog */ time(&now); if (difftime(now, ups->last_connfail) < SS_CONNFAIL_INT) return ERROR_FD; ups->last_connfail = now; upslog_with_errno(LOG_ERR, "Can't connect to UPS [%s] (%s)", ups->name, ups->fn); return ERROR_FD; } ret = fcntl(fd, F_GETFL, 0); if (ret < 0) { upslog_with_errno(LOG_ERR, "fcntl get on UPS [%s] failed", ups->name); close(fd); return ERROR_FD; } ret = fcntl(fd, F_SETFL, ret | O_NDELAY); if (ret < 0) { upslog_with_errno(LOG_ERR, "fcntl set O_NDELAY on UPS [%s] failed", ups->name); close(fd); return ERROR_FD; } /* get a dump started so we have a fresh set of data */ ret = write(fd, dumpcmd, dumpcmdlen); if ((ret < 1) || (ret != (ssize_t)dumpcmdlen)) { upslog_with_errno(LOG_ERR, "Initial write to UPS [%s] failed", ups->name); close(fd); return ERROR_FD; } #else char pipename[SMALLBUF]; const char *dumpcmd = "DUMPALL\n"; BOOL result = FALSE; upsdebugx(2, "%s: preparing Windows pipe %s", __func__, NUT_STRARG(ups->fn)); snprintf(pipename, sizeof(pipename), "\\\\.\\pipe\\%s", ups->fn); result = WaitNamedPipe(pipename,NMPWAIT_USE_DEFAULT_WAIT); if (result == FALSE) { upsdebugx(2, "%s: failed to WaitNamedPipe(%s)", __func__, pipename); return ERROR_FD; } fd = CreateFile( pipename, // pipe name GENERIC_READ | // read and write access GENERIC_WRITE, 0, // no sharing NULL, // default security attributes FIXME OPEN_EXISTING, // opens existing pipe FILE_FLAG_OVERLAPPED, // enable async IO NULL); // no template file if (fd == INVALID_HANDLE_VALUE) { upslog_with_errno(LOG_ERR, "Can't connect to UPS [%s] (%s)", ups->name, ups->fn); return ERROR_FD; } /* get a dump started so we have a fresh set of data */ DWORD bytesWritten = 0; result = WriteFile (fd,dumpcmd,strlen(dumpcmd),&bytesWritten,NULL); if (result == 0 || bytesWritten != strlen(dumpcmd)) { upslog_with_errno(LOG_ERR, "Initial write to UPS [%s] failed", ups->name); CloseHandle(fd); return ERROR_FD; } /* Start a read IO so we could wait on the event associated with it */ ReadFile(fd, ups->buf, sizeof(ups->buf) - 1, /*-1 to be sure to have a trailling 0 */ NULL, &(ups->read_overlapped)); #endif /* sstate_connect() continued for both platforms: */ pconf_init(&ups->sock_ctx, NULL); ups->dumpdone = 0; ups->stale = 0; /* now is the last time we heard something from the driver */ time(&ups->last_heard); /* set ups.status to "WAIT" while waiting for the driver response to dumpcmd */ state_setinfo(&ups->inforoot, "ups.status", "WAIT"); upslogx(LOG_INFO, "Connected to UPS [%s]: %s", ups->name, ups->fn); return fd; } void sstate_disconnect(upstype_t *ups) { if ((!ups) || INVALID_FD(ups->sock_fd)) { return; } sstate_infofree(ups); sstate_cmdfree(ups); pconf_finish(&ups->sock_ctx); #ifndef WIN32 close(ups->sock_fd); #else CloseHandle(ups->sock_fd); #endif ups->sock_fd = ERROR_FD; } void sstate_readline(upstype_t *ups) { ssize_t i, ret; #ifndef WIN32 char buf[SMALLBUF]; if ((!ups) || INVALID_FD(ups->sock_fd)) { return; } ret = read(ups->sock_fd, buf, sizeof(buf)); if (ret < 0) { switch(errno) { case EINTR: case EAGAIN: return; default: upslog_with_errno(LOG_WARNING, "Read from UPS [%s] failed", ups->name); sstate_disconnect(ups); return; } } #else if ((!ups) || INVALID_FD(ups->sock_fd)) { return; } /* FIXME? I do not see either buf filled below */ char *buf = ups->buf; DWORD bytesRead; GetOverlappedResult(ups->sock_fd, &ups->read_overlapped, &bytesRead, FALSE); ret = bytesRead; #endif for (i = 0; i < ret; i++) { switch (pconf_char(&ups->sock_ctx, buf[i])) { case 1: /* set the 'last heard' time to now for later staleness checks */ if (parse_args(ups, ups->sock_ctx.numargs, ups->sock_ctx.arglist)) { time(&ups->last_heard); } continue; case 0: continue; /* haven't gotten a line yet */ default: /* parse error */ upslogx(LOG_NOTICE, "Parse error on sock: %s", ups->sock_ctx.errmsg); return; } } #ifdef WIN32 /* Restart async read */ memset(ups->buf,0,sizeof(ups->buf)); ReadFile( ups->sock_fd, ups->buf, sizeof(ups->buf)-1,NULL, &(ups->read_overlapped)); /* -1 to be sure to have a trailing 0 */ #endif } const char *sstate_getinfo(const upstype_t *ups, const char *var) { return state_getinfo(ups->inforoot, var); } int sstate_getflags(const upstype_t *ups, const char *var) { return state_getflags(ups->inforoot, var); } long sstate_getaux(const upstype_t *ups, const char *var) { return state_getaux(ups->inforoot, var); } const enum_t *sstate_getenumlist(const upstype_t *ups, const char *var) { return state_getenumlist(ups->inforoot, var); } const range_t *sstate_getrangelist(const upstype_t *ups, const char *var) { return state_getrangelist(ups->inforoot, var); } const cmdlist_t *sstate_getcmdlist(const upstype_t *ups) { return ups->cmdlist; } int sstate_dead(upstype_t *ups, int arg_maxage) { time_t now; double elapsed; /* an unconnected ups is always dead */ if ((!ups) || INVALID_FD(ups->sock_fd)) { upsdebugx(3, "sstate_dead: connection to driver socket for UPS [%s] lost", ups->name); return 1; /* dead */ } time(&now); elapsed = difftime(now, ups->last_heard); /* Somewhere beyond a third of the maximum time - prod it to make it talk * Note this helps detect drivers that died without closing the connection */ if ((elapsed > (arg_maxage / 3)) && (difftime(now, ups->last_ping) > (arg_maxage / 3))) sendping(ups); if (elapsed > arg_maxage) { upsdebugx(3, "sstate_dead: didn't hear from driver for UPS [%s] for %g seconds (max %d)", ups->name, elapsed, arg_maxage); return 1; /* dead */ } /* ignore DATAOK/DATASTALE unless the dump is done */ if ((ups->dumpdone) && (!ups->data_ok)) { upsdebugx(3, "sstate_dead: driver for UPS [%s] says data is stale", ups->name); return 1; /* dead */ } return 0; } /* release all info(tree) data used by */ void sstate_infofree(upstype_t *ups) { state_infofree(ups->inforoot); ups->inforoot = NULL; } void sstate_cmdfree(upstype_t *ups) { state_cmdfree(ups->cmdlist); ups->cmdlist = NULL; } int sstate_sendline(upstype_t *ups, const char *buf) { ssize_t ret; size_t buflen; if ((!ups) || INVALID_FD(ups->sock_fd)) { return 0; /* failed */ } buflen = strlen(buf); if (buflen >= SSIZE_MAX) { /* Can't compare buflen to ret... */ upslog_with_errno(LOG_NOTICE, "Send ping to UPS [%s] failed: buffered message too large", ups->name); return 0; /* failed */ } #ifndef WIN32 ret = write(ups->sock_fd, buf, buflen); #else DWORD bytesWritten = 0; BOOL result = FALSE; result = WriteFile (ups->sock_fd, buf, buflen, &bytesWritten, NULL); if (result == 0) { ret = 0; } else { ret = (ssize_t)bytesWritten; } #endif if (ret == (ssize_t)buflen) { return 1; } upslog_with_errno(LOG_NOTICE, "Send to UPS [%s] failed", ups->name); sstate_disconnect(ups); return 0; /* failed */ } const st_tree_t *sstate_getnode(const upstype_t *ups, const char *varname) { return state_tree_find(ups->inforoot, varname); } nut-2.8.1/server/pipedebug.c0000644000175000017500000001033514501607135012673 00000000000000/* pipe.c - Network UPS Tools driver-server pipe debugger (WIN32 builds) Copyright (C) 2012 Frederic Bohe 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 2 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, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "common.h" #include "parseconf.h" PCONF_CTX_t pipe_ctx; static void pipe_arg(int numarg, char **arg) { int i; printf("numarg=%d : ", numarg); for (i = 0; i < numarg; i++) printf("[%s] ", arg[i]); printf("\n"); fflush(stdout); } static HANDLE pipe_connect(const char *pipefn) { HANDLE fd; char pipename[SMALLBUF]; BOOL result = FALSE; snprintf(pipename, sizeof(pipename), "\\\\.\\pipe\\%s", pipefn); result = WaitNamedPipe(pipename,NMPWAIT_USE_DEFAULT_WAIT); if( result == FALSE ) { printf("WaitNamedPipe : %d\n",GetLastError()); exit(EXIT_FAILURE); } fd = CreateFile( pipename, // pipe name GENERIC_READ | // read and write access GENERIC_WRITE, 0, // no sharing NULL, // default security attributes FIXME OPEN_EXISTING, // opens existing pipe FILE_FLAG_OVERLAPPED, // enable async IO NULL); // no template file if (fd == INVALID_HANDLE_VALUE) { printf("CreateFile : %d\n",GetLastError()); exit(EXIT_FAILURE); } return fd; } static void read_buf(char * buf, DWORD num) { unsigned int i; for (i = 0; i < num; i++) { switch (pconf_char(&pipe_ctx, buf[i])) { case 1: pipe_arg(pipe_ctx.numargs, pipe_ctx.arglist); break; case -1: printf("Parse error: [%s]\n", pipe_ctx.errmsg); break; } } } DWORD WINAPI ReadThread( LPVOID lpParameter ) { HANDLE pipefd = *((HANDLE *)lpParameter); DWORD bytes_read; char pipe_buf[SMALLBUF]; OVERLAPPED pipe_overlapped; pconf_init(&pipe_ctx, NULL); memset(&pipe_overlapped,0,sizeof(pipe_overlapped)); pipe_overlapped.hEvent = CreateEvent(NULL,FALSE,FALSE,NULL); for (;;) { memset(pipe_buf,0,sizeof(pipe_buf)); ReadFile(pipefd,pipe_buf,sizeof(pipe_buf),NULL,&pipe_overlapped); GetOverlappedResult(pipefd,&pipe_overlapped,&bytes_read,TRUE); read_buf(pipe_buf,bytes_read); } } DWORD WINAPI WriteThread( LPVOID lpParameter ) { HANDLE pipefd = *((HANDLE *)lpParameter); HANDLE hStdin; DWORD bytes_read; char stdin_buf[SMALLBUF]; OVERLAPPED pipe_overlapped; hStdin = GetStdHandle(STD_INPUT_HANDLE); memset(&pipe_overlapped,0,sizeof(pipe_overlapped)); pipe_overlapped.hEvent = CreateEvent(NULL,FALSE,FALSE,NULL); for (;;) { ReadFile(hStdin,stdin_buf,sizeof(stdin_buf),&bytes_read,NULL); WriteFile(pipefd,stdin_buf,bytes_read,NULL,&pipe_overlapped); } } int main(int argc, char **argv) { const char *prog = xbasename(argv[0]); HANDLE pipefd; HANDLE thread[2]; if (argc != 2 || (argc > 1 && (!strcmp(argv[1], "-h") || !strcmp(argv[1], "--help"))) ) { fprintf(stderr, "usage: %s \n", prog); fprintf(stderr, " %s apcsmart-com1\n", argv[0]); exit(EXIT_SUCCESS); } pipefd = pipe_connect(argv[1]); printf("connected: fd %d\n", pipefd); fflush(stdout); thread[0] = CreateThread( NULL, /* security */ 0, /* stack size */ ReadThread, /* func */ &pipefd,/* func param */ 0, /* flags */ NULL ); /* thread id */ if(thread[0] == NULL) { fprintf(stderr, "CreateThread ReadThread failed\n"); exit(EXIT_FAILURE); } thread[1] = CreateThread( NULL, /* security */ 0, /* stack size */ WriteThread, /* func */ &pipefd,/* func param */ 0, /* flags */ NULL ); /* thread id */ if(thread[1] == NULL) { fprintf(stderr, "CreateThread WriteThread failed\n"); exit(EXIT_FAILURE); } WaitForMultipleObjects(2,thread,TRUE,INFINITE); /* NOTREACHED */ exit(EXIT_FAILURE); } nut-2.8.1/server/netssl.h0000644000175000017500000000347614500336654012260 00000000000000/* netssl.h - ssl support prototypes for upsd Copyright (C) 2002 Russell Kroll 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 2 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, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef NUT_NETSSL_H_SEEN #define NUT_NETSSL_H_SEEN 1 #include "nut_ctype.h" #ifdef __cplusplus /* *INDENT-OFF* */ extern "C" { /* *INDENT-ON* */ #endif extern char *certfile; extern char *certname; extern char *certpasswd; extern int disable_weak_ssl; #ifdef WITH_CLIENT_CERTIFICATE_VALIDATION extern int certrequest; #endif /* WITH_CLIENT_CERTIFICATE_VALIDATION */ /* List possible values for certrequested */ /* No request */ #define NETSSL_CERTREQ_NO 0 /* Requested (cnx failed if no certificate) */ #define NETSSL_CERTREQ_REQUEST 1 /* Required (cnx failed if no certificate or invalid CA chain) */ #define NETSSL_CERTREQ_REQUIRE 2 void ssl_init(void); void ssl_finish(nut_ctype_t *client); void ssl_cleanup(void); ssize_t ssl_read(nut_ctype_t *client, char *buf, size_t buflen); ssize_t ssl_write(nut_ctype_t *client, const char *buf, size_t buflen); void net_starttls(nut_ctype_t *client, size_t numarg, const char **arg); #ifdef __cplusplus /* *INDENT-OFF* */ } /* *INDENT-ON* */ #endif #endif /* NUT_NETSSL_H_SEEN */ nut-2.8.1/server/conf.c0000644000175000017500000003465314501607135011665 00000000000000/* conf.c - configuration handlers for upsd Copyright (C) 2001 Russell Kroll 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 2 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, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "upsd.h" #include "conf.h" #include "upsconf.h" #include "sstate.h" #include "user.h" #include "netssl.h" #include "nut_stdint.h" #include static ups_t *upstable = NULL; int num_ups = 0; /* Users can pass a -D[...] option to enable debugging. * For the service tracing purposes, also the upsd.conf * can define a debug_min value in the global section, * to set the minimal debug level (CLI provided value less * than that would not have effect, can only have more). */ int nut_debug_level_global = -1; /* Debug level specified via command line - we revert to * it when reloading if there was no DEBUG_MIN in upsd.conf */ int nut_debug_level_args = 0; /* add another UPS for monitoring from ups.conf */ static void ups_create(const char *fn, const char *name, const char *desc) { upstype_t *temp; for (temp = firstups; temp != NULL; temp = temp->next) { if (!strcasecmp(temp->name, name)) { upslogx(LOG_ERR, "UPS name [%s] is already in use!", name); return; } } /* grab some memory and add the info */ temp = xcalloc(1, sizeof(*temp)); temp->fn = xstrdup(fn); temp->name = xstrdup(name); if (desc) { temp->desc = xstrdup(desc); } temp->stale = 1; temp->retain = 1; #ifdef WIN32 memset(&temp->read_overlapped,0,sizeof(temp->read_overlapped)); memset(temp->buf,0,sizeof(temp->buf)); temp->read_overlapped.hEvent = CreateEvent(NULL, /* Security */ FALSE, /* auto-reset*/ FALSE, /* initial state = non signaled */ NULL /* no name */); if(temp->read_overlapped.hEvent == NULL ) { upslogx(LOG_ERR, "Can't create event for UPS [%s]", name); return; } #endif temp->sock_fd = sstate_connect(temp); /* preload this to the current time to avoid false staleness */ time(&temp->last_heard); temp->next = firstups; firstups = temp; num_ups++; } /* change the configuration of an existing UPS (used during reloads) */ static void ups_update(const char *fn, const char *name, const char *desc) { upstype_t *temp; temp = get_ups_ptr(name); if (!temp) { upslogx(LOG_ERR, "UPS %s disappeared during reload", name); return; } /* paranoia */ if (!temp->fn) { upslogx(LOG_ERR, "UPS %s had a NULL filename!", name); /* let's give it something quick to use later */ temp->fn = xstrdup(""); } /* when the filename changes, force a reconnect */ if (strcmp(temp->fn, fn) != 0) { upslogx(LOG_NOTICE, "Redefined UPS [%s]", name); /* release all data */ sstate_infofree(temp); sstate_cmdfree(temp); pconf_finish(&temp->sock_ctx); #ifndef WIN32 close(temp->sock_fd); #else CloseHandle(temp->sock_fd); #endif temp->sock_fd = ERROR_FD; temp->dumpdone = 0; /* now redefine the filename and wrap up */ free(temp->fn); temp->fn = xstrdup(fn); } /* update the description */ free(temp->desc); if (desc) temp->desc = xstrdup(desc); else temp->desc = NULL; /* always set this on reload */ temp->retain = 1; } /* returns 1 if "arg" was usable as a boolean value, 0 if not * saves converted meaning of "arg" into referenced "result" */ static int parse_boolean(char *arg, int *result) { if ( (!strcasecmp(arg, "true")) || (!strcasecmp(arg, "on")) || (!strcasecmp(arg, "yes")) || (!strcasecmp(arg, "1"))) { *result = 1; return 1; } if ( (!strcasecmp(arg, "false")) || (!strcasecmp(arg, "off")) || (!strcasecmp(arg, "no")) || (!strcasecmp(arg, "0"))) { *result = 0; return 1; } return 0; } /* return 1 if usable, 0 if not */ static int parse_upsd_conf_args(size_t numargs, char **arg) { /* everything below here uses up through arg[1] */ if (numargs < 2) return 0; /* DEBUG_MIN (NUM) */ /* debug_min (NUM) also acceptable, to be on par with ups.conf */ if (!strcasecmp(arg[0], "DEBUG_MIN")) { int lvl = -1; // typeof common/common.c: int nut_debug_level if ( str_to_int (arg[1], &lvl, 10) && lvl >= 0 ) { nut_debug_level_global = lvl; } else { upslogx(LOG_INFO, "DEBUG_MIN has non numeric or negative value in upsd.conf"); } return 1; } /* MAXAGE */ if (!strcmp(arg[0], "MAXAGE")) { if (isdigit((size_t)arg[1][0])) { maxage = atoi(arg[1]); return 1; } else { upslogx(LOG_ERR, "MAXAGE has non numeric value (%s)!", arg[1]); return 0; } } /* TRACKINGDELAY */ if (!strcmp(arg[0], "TRACKINGDELAY")) { if (isdigit((size_t)arg[1][0])) { tracking_delay = atoi(arg[1]); return 1; } else { upslogx(LOG_ERR, "TRACKINGDELAY has non numeric value (%s)!", arg[1]); return 0; } } /* ALLOW_NO_DEVICE */ if (!strcmp(arg[0], "ALLOW_NO_DEVICE")) { if (isdigit((size_t)arg[1][0])) { allow_no_device = (atoi(arg[1]) != 0); /* non-zero arg is true here */ return 1; } if (parse_boolean(arg[1], &allow_no_device)) return 1; upslogx(LOG_ERR, "ALLOW_NO_DEVICE has non numeric and non boolean value (%s)!", arg[1]); return 0; } /* MAXCONN */ if (!strcmp(arg[0], "MAXCONN")) { if (isdigit((size_t)arg[1][0])) { /* FIXME: Check for overflows (and int size of nfds_t vs. long) - see get_max_pid_t() for example */ maxconn = (nfds_t)atol(arg[1]); return 1; } else { upslogx(LOG_ERR, "MAXCONN has non numeric value (%s)!", arg[1]); return 0; } } /* STATEPATH */ if (!strcmp(arg[0], "STATEPATH")) { const char *sp = getenv("NUT_STATEPATH"); if (sp && strcmp(sp, arg[1])) { /* Only warn if the two strings are not equal */ upslogx(LOG_WARNING, "Ignoring STATEPATH='%s' from configuration file, " "in favor of NUT_STATEPATH='%s' environment variable", NUT_STRARG(arg[1]), NUT_STRARG(sp)); } free(statepath); statepath = xstrdup(sp ? sp : arg[1]); return 1; } /* DATAPATH */ if (!strcmp(arg[0], "DATAPATH")) { free(datapath); datapath = xstrdup(arg[1]); return 1; } #ifdef WITH_OPENSSL /* CERTFILE */ if (!strcmp(arg[0], "CERTFILE")) { free(certfile); certfile = xstrdup(arg[1]); return 1; } #elif (defined WITH_NSS) /* WITH_OPENSSL */ /* CERTPATH */ if (!strcmp(arg[0], "CERTPATH")) { free(certfile); certfile = xstrdup(arg[1]); return 1; } #ifdef WITH_CLIENT_CERTIFICATE_VALIDATION /* CERTREQUEST (0 | 1 | 2) */ if (!strcmp(arg[0], "CERTREQUEST")) { if (isdigit((size_t)arg[1][0])) { certrequest = atoi(arg[1]); return 1; } else { upslogx(LOG_ERR, "CERTREQUEST has non numeric value (%s)!", arg[1]); return 0; } } #endif /* WITH_CLIENT_CERTIFICATE_VALIDATION */ #endif /* WITH_OPENSSL | WITH_NSS */ #if defined(WITH_OPENSSL) || defined(WITH_NSS) /* DISABLE_WEAK_SSL */ if (!strcmp(arg[0], "DISABLE_WEAK_SSL")) { if (parse_boolean(arg[1], &disable_weak_ssl)) return 1; upslogx(LOG_ERR, "DISABLE_WEAK_SSL has non boolean value (%s)!", arg[1]); return 0; } #endif /* WITH_OPENSSL | WITH_NSS */ /* ACCEPT [...] */ if (!strcmp(arg[0], "ACCEPT")) { upslogx(LOG_WARNING, "ACCEPT in upsd.conf is no longer supported - switch to LISTEN"); return 1; } /* REJECT [...] */ if (!strcmp(arg[0], "REJECT")) { upslogx(LOG_WARNING, "REJECT in upsd.conf is no longer supported - switch to LISTEN"); return 1; } /* LISTEN
[] */ if (!strcmp(arg[0], "LISTEN")) { if (numargs < 3) listen_add(arg[1], string_const(PORT)); else listen_add(arg[1], arg[2]); return 1; } /* everything below here uses up through arg[2] */ if (numargs < 3) return 0; /* ACL */ if (!strcmp(arg[0], "ACL")) { upslogx(LOG_WARNING, "ACL in upsd.conf is no longer supported - switch to LISTEN"); return 1; } #ifdef WITH_NSS /* CERTIDENT */ if (!strcmp(arg[0], "CERTIDENT")) { free(certname); certname = xstrdup(arg[1]); free(certpasswd); certpasswd = xstrdup(arg[2]); return 1; } #endif /* WITH_NSS */ /* not recognized */ return 0; } /* called for fatal errors in parseconf like malloc failures */ static void upsd_conf_err(const char *errmsg) { upslogx(LOG_ERR, "Fatal error in parseconf (upsd.conf): %s", errmsg); } void load_upsdconf(int reloading) { char fn[SMALLBUF]; PCONF_CTX_t ctx; snprintf(fn, sizeof(fn), "%s/upsd.conf", confpath()); check_perms(fn); pconf_init(&ctx, upsd_conf_err); if (!pconf_file_begin(&ctx, fn)) { pconf_finish(&ctx); if (!reloading) fatalx(EXIT_FAILURE, "%s", ctx.errmsg); upslogx(LOG_ERR, "Reload failed: %s", ctx.errmsg); return; } if (reloading) { /* if upsd.conf added or changed * (or commented away) the debug_min * setting, detect that */ nut_debug_level_global = -1; } while (pconf_file_next(&ctx)) { if (pconf_parse_error(&ctx)) { upslogx(LOG_ERR, "Parse error: %s:%d: %s", fn, ctx.linenum, ctx.errmsg); continue; } if (ctx.numargs < 1) continue; if (!parse_upsd_conf_args(ctx.numargs, ctx.arglist)) { unsigned int i; char errmsg[SMALLBUF]; snprintf(errmsg, sizeof(errmsg), "upsd.conf: invalid directive"); for (i = 0; i < ctx.numargs; i++) snprintfcat(errmsg, sizeof(errmsg), " %s", ctx.arglist[i]); upslogx(LOG_WARNING, "%s", errmsg); } } if (reloading) { if (nut_debug_level_global > -1) { upslogx(LOG_INFO, "Applying debug_min=%d from upsd.conf", nut_debug_level_global); nut_debug_level = nut_debug_level_global; } else { /* DEBUG_MIN is absent or commented-away in ups.conf */ upslogx(LOG_INFO, "Applying debug level %d from " "original command line arguments", nut_debug_level_args); nut_debug_level = nut_debug_level_args; } } pconf_finish(&ctx); } /* callback during parsing of ups.conf */ void do_upsconf_args(char *upsname, char *var, char *val) { ups_t *temp; /* no "global" stuff for us */ if (!upsname) { return; } /* check if UPS is already listed */ for (temp = upstable; temp != NULL; temp = temp->next) { if (!strcmp(temp->upsname, upsname)) { break; } } /* if not listed, create a new entry and prepend it to the list */ if (temp == NULL) { temp = xcalloc(1, sizeof(*temp)); temp->upsname = xstrdup(upsname); temp->next = upstable; upstable = temp; } if (!strcmp(var, "driver")) { free(temp->driver); temp->driver = xstrdup(val); } else if (!strcmp(var, "port")) { free(temp->port); temp->port = xstrdup(val); } else if (!strcmp(var, "desc")) { free(temp->desc); temp->desc = xstrdup(val); } } /* add valid UPSes from ups.conf to the internal structures */ void upsconf_add(int reloading) { ups_t *tmp = upstable, *next; char statefn[SMALLBUF]; if (!tmp) { upslogx(LOG_WARNING, "Warning: no UPS definitions in ups.conf"); return; } while (tmp) { /* save for later, since we delete as we go along */ next = tmp->next; /* this should always be set, but better safe than sorry */ if (!tmp->upsname) { tmp = tmp->next; continue; } /* don't accept an entry that's missing items */ if ((!tmp->driver) || (!tmp->port)) { upslogx(LOG_WARNING, "Warning: ignoring incomplete configuration for UPS [%s]\n", tmp->upsname); } else { snprintf(statefn, sizeof(statefn), "%s-%s", tmp->driver, tmp->upsname); /* if a UPS exists, update it, else add it as new */ if ((reloading) && (get_ups_ptr(tmp->upsname) != NULL)) ups_update(statefn, tmp->upsname, tmp->desc); else ups_create(statefn, tmp->upsname, tmp->desc); } /* free tmp's resources */ free(tmp->driver); free(tmp->port); free(tmp->desc); free(tmp->upsname); free(tmp); tmp = next; } /* upstable should be completely gone by this point */ upstable = NULL; } /* remove a UPS from the linked list */ static void delete_ups(upstype_t *target) { upstype_t *ptr, *last; if (!target) return; ptr = last = firstups; while (ptr) { if (ptr == target) { upslogx(LOG_NOTICE, "Deleting UPS [%s]", target->name); /* make sure nobody stays logged into this thing */ kick_login_clients(target->name); /* about to delete the first ups? */ if (ptr == last) firstups = ptr->next; else last->next = ptr->next; if (VALID_FD(ptr->sock_fd)) #ifndef WIN32 close(ptr->sock_fd); #else CloseHandle(ptr->sock_fd); #endif /* release memory */ sstate_infofree(ptr); sstate_cmdfree(ptr); pconf_finish(&ptr->sock_ctx); free(ptr->fn); free(ptr->name); free(ptr->desc); free(ptr); return; } last = ptr; ptr = ptr->next; } /* shouldn't happen */ upslogx(LOG_ERR, "delete_ups: UPS not found"); } /* see if we can open a file */ static int check_file(const char *fn) { char chkfn[SMALLBUF]; FILE *f; snprintf(chkfn, sizeof(chkfn), "%s/%s", confpath(), fn); f = fopen(chkfn, "r"); if (!f) { upslog_with_errno(LOG_ERR, "Reload failed: can't open %s", chkfn); return 0; /* failed */ } fclose(f); return 1; /* OK */ } /* called after SIGHUP */ void conf_reload(void) { upstype_t *upstmp, *upsnext; upslogx(LOG_INFO, "SIGHUP: reloading configuration"); /* see if we can access upsd.conf before blowing away the config */ if (!check_file("upsd.conf")) return; /* reset retain flags on all known UPS entries */ upstmp = firstups; while (upstmp) { upstmp->retain = 0; upstmp = upstmp->next; } /* reload from ups.conf */ read_upsconf(1); /* 1 = may abort upon fundamental errors */ upsconf_add(1); /* 1 = reloading */ /* now reread upsd.conf */ load_upsdconf(1); /* 1 = reloading */ /* now delete all UPS entries that didn't get reloaded */ upstmp = firstups; while (upstmp) { /* upstmp may be deleted during this pass */ upsnext = upstmp->next; if (upstmp->retain == 0) delete_ups(upstmp); upstmp = upsnext; } /* did they actually delete the last UPS? */ if (firstups == NULL) upslogx(LOG_WARNING, "Warning: no UPSes currently defined!"); /* and also make sure upsd.users can be read... */ if (!check_file("upsd.users")) return; /* delete all users */ user_flush(); /* and finally reread from upsd.users */ user_load(); } nut-2.8.1/server/netinstcmd.h0000644000175000017500000000245414500336654013113 00000000000000/* netinstcmd.h - network instand command definitions for NUT Copyright (C) 2003 Russell Kroll 2005 Arnaud Quette 2007 Peter Selinger 2013 Emilien Kia 2020 Jim Klimov 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 2 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, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef NUT_NETINSTCMD_H_SEEN #define NUT_NETINSTCMD_H_SEEN 1 #ifdef __cplusplus /* *INDENT-OFF* */ extern "C" { /* *INDENT-ON* */ #endif void net_instcmd(nut_ctype_t *client, size_t numarg, const char **arg); #ifdef __cplusplus /* *INDENT-OFF* */ } /* *INDENT-ON* */ #endif #endif /* NUT_NETINSTCMD_H_SEEN */ nut-2.8.1/server/netuser.h0000644000175000017500000000352514500336654012430 00000000000000/* netuser.c - LOGIN/LOGOUT/USERNAME/PASSWORD/MASTER[PRIMARY] handlers for upsd Copyright (C) 2003 Russell Kroll 2005 Arnaud Quette 2007 Peter Selinger 2013 Emilien Kia 2020-2021 Jim Klimov 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 2 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, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef NUT_NETUSER_H_SEEN #define NUT_NETUSER_H_SEEN 1 #ifdef __cplusplus /* *INDENT-OFF* */ extern "C" { /* *INDENT-ON* */ #endif void net_login(nut_ctype_t *client, size_t numarg, const char **arg); void net_logout(nut_ctype_t *client, size_t numarg, const char **arg); /* NOTE: Since NUT 2.8.0 we handle master as alias for primary * Header keyword kept for building older consumers, but * the implementation will warn that it is deprecated. */ void net_master(nut_ctype_t *client, size_t numarg, const char **arg); void net_primary(nut_ctype_t *client, size_t numarg, const char **arg); void net_username(nut_ctype_t *client, size_t numarg, const char **arg); void net_password(nut_ctype_t *client, size_t numarg, const char **arg); #ifdef __cplusplus /* *INDENT-OFF* */ } /* *INDENT-ON* */ #endif #endif /* NUT_NETUSER_H_SEEN */ nut-2.8.1/server/Makefile.in0000644000175000017500000010154514520274662012642 00000000000000# Makefile.in generated by automake 1.16.5 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2021 Free Software Foundation, Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. @SET_MAKE@ # Network UPS Tools: server VPATH = @srcdir@ am__is_gnu_make = { \ if test -z '$(MAKELEVEL)'; then \ false; \ elif test -n '$(MAKE_HOST)'; then \ true; \ elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \ true; \ else \ false; \ fi; \ } am__make_running_with_option = \ case $${target_option-} in \ ?) ;; \ *) echo "am__make_running_with_option: internal error: invalid" \ "target option '$${target_option-}' specified" >&2; \ exit 1;; \ esac; \ has_opt=no; \ sane_makeflags=$$MAKEFLAGS; \ if $(am__is_gnu_make); then \ sane_makeflags=$$MFLAGS; \ else \ case $$MAKEFLAGS in \ *\\[\ \ ]*) \ bs=\\; \ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ esac; \ fi; \ skip_next=no; \ strip_trailopt () \ { \ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ }; \ for flg in $$sane_makeflags; do \ test $$skip_next = yes && { skip_next=no; continue; }; \ case $$flg in \ *=*|--*) continue;; \ -*I) strip_trailopt 'I'; skip_next=yes;; \ -*I?*) strip_trailopt 'I';; \ -*O) strip_trailopt 'O'; skip_next=yes;; \ -*O?*) strip_trailopt 'O';; \ -*l) strip_trailopt 'l'; skip_next=yes;; \ -*l?*) strip_trailopt 'l';; \ -[dEDm]) skip_next=yes;; \ -[JT]) skip_next=yes;; \ esac; \ case $$flg in \ *$$target_option*) has_opt=yes; break;; \ esac; \ done; \ test $$has_opt = yes am__make_dryrun = (target_option=n; $(am__make_running_with_option)) am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkglibexecdir = $(libexecdir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ target_triplet = @target@ @WITH_WRAP_TRUE@am__append_1 = $(LIBWRAP_CFLAGS) @WITH_SSL_TRUE@am__append_2 = $(LIBSSL_CFLAGS) @WITH_WRAP_TRUE@am__append_3 = $(LIBWRAP_LIBS) @WITH_SSL_TRUE@am__append_4 = $(LIBSSL_LIBS) sbin_PROGRAMS = upsd$(EXEEXT) EXTRA_PROGRAMS = sockdebug$(EXEEXT) @WITH_DEV_TRUE@libexec_PROGRAMS = sockdebug$(EXEEXT) subdir = server ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/m4/ax_c___attribute__.m4 \ $(top_srcdir)/m4/ax_c_pragmas.m4 \ $(top_srcdir)/m4/ax_check_compile_flag.m4 \ $(top_srcdir)/m4/ax_compare_version.m4 \ $(top_srcdir)/m4/ax_realpath.m4 \ $(top_srcdir)/m4/ax_run_or_link_ifelse.m4 \ $(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \ $(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \ $(top_srcdir)/m4/lt~obsolete.m4 \ $(top_srcdir)/m4/nut_arg_with.m4 \ $(top_srcdir)/m4/nut_check_asciidoc.m4 \ $(top_srcdir)/m4/nut_check_aspell.m4 \ $(top_srcdir)/m4/nut_check_cppcheck.m4 \ $(top_srcdir)/m4/nut_check_headers_windows.m4 \ $(top_srcdir)/m4/nut_check_libavahi.m4 \ $(top_srcdir)/m4/nut_check_libfreeipmi.m4 \ $(top_srcdir)/m4/nut_check_libgd.m4 \ $(top_srcdir)/m4/nut_check_libgpiod.m4 \ $(top_srcdir)/m4/nut_check_libltdl.m4 \ $(top_srcdir)/m4/nut_check_libmodbus.m4 \ $(top_srcdir)/m4/nut_check_libneon.m4 \ $(top_srcdir)/m4/nut_check_libnetsnmp.m4 \ $(top_srcdir)/m4/nut_check_libnss.m4 \ $(top_srcdir)/m4/nut_check_libopenssl.m4 \ $(top_srcdir)/m4/nut_check_libpowerman.m4 \ $(top_srcdir)/m4/nut_check_libregex.m4 \ $(top_srcdir)/m4/nut_check_libsystemd.m4 \ $(top_srcdir)/m4/nut_check_libusb.m4 \ $(top_srcdir)/m4/nut_check_libwrap.m4 \ $(top_srcdir)/m4/nut_check_os.m4 \ $(top_srcdir)/m4/nut_check_pkgconfig.m4 \ $(top_srcdir)/m4/nut_check_python.m4 \ $(top_srcdir)/m4/nut_check_socketlib.m4 \ $(top_srcdir)/m4/nut_compiler_family.m4 \ $(top_srcdir)/m4/nut_func_getnameinfo_argtypes.m4 \ $(top_srcdir)/m4/nut_report_feature.m4 \ $(top_srcdir)/m4/nut_stash_warnings.m4 \ $(top_srcdir)/m4/nut_type_socklen_t.m4 \ $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/include/config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = am__installdirs = "$(DESTDIR)$(libexecdir)" "$(DESTDIR)$(sbindir)" PROGRAMS = $(libexec_PROGRAMS) $(sbin_PROGRAMS) am__sockdebug_SOURCES_DIST = sockdebug.c pipedebug.c @HAVE_WINDOWS_FALSE@am_sockdebug_OBJECTS = sockdebug.$(OBJEXT) @HAVE_WINDOWS_TRUE@am_sockdebug_OBJECTS = pipedebug.$(OBJEXT) sockdebug_OBJECTS = $(am_sockdebug_OBJECTS) sockdebug_LDADD = $(LDADD) am__DEPENDENCIES_1 = @WITH_WRAP_TRUE@am__DEPENDENCIES_2 = $(am__DEPENDENCIES_1) @WITH_SSL_TRUE@am__DEPENDENCIES_3 = $(am__DEPENDENCIES_1) sockdebug_DEPENDENCIES = $(top_builddir)/common/libcommon.la \ $(top_builddir)/common/libparseconf.la $(am__DEPENDENCIES_1) \ $(am__DEPENDENCIES_2) $(am__DEPENDENCIES_3) AM_V_lt = $(am__v_lt_@AM_V@) am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@) am__v_lt_0 = --silent am__v_lt_1 = am_upsd_OBJECTS = upsd.$(OBJEXT) user.$(OBJEXT) conf.$(OBJEXT) \ netssl.$(OBJEXT) sstate.$(OBJEXT) desc.$(OBJEXT) \ netget.$(OBJEXT) netmisc.$(OBJEXT) netlist.$(OBJEXT) \ netuser.$(OBJEXT) netset.$(OBJEXT) netinstcmd.$(OBJEXT) upsd_OBJECTS = $(am_upsd_OBJECTS) upsd_LDADD = $(LDADD) upsd_DEPENDENCIES = $(top_builddir)/common/libcommon.la \ $(top_builddir)/common/libparseconf.la $(am__DEPENDENCIES_1) \ $(am__DEPENDENCIES_2) $(am__DEPENDENCIES_3) AM_V_P = $(am__v_P_@AM_V@) am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) am__v_P_0 = false am__v_P_1 = : AM_V_GEN = $(am__v_GEN_@AM_V@) am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) am__v_GEN_0 = @echo " GEN " $@; am__v_GEN_1 = AM_V_at = $(am__v_at_@AM_V@) am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) am__v_at_0 = @ am__v_at_1 = DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)/include depcomp = $(SHELL) $(top_srcdir)/depcomp am__maybe_remake_depfiles = depfiles am__depfiles_remade = ./$(DEPDIR)/conf.Po ./$(DEPDIR)/desc.Po \ ./$(DEPDIR)/netget.Po ./$(DEPDIR)/netinstcmd.Po \ ./$(DEPDIR)/netlist.Po ./$(DEPDIR)/netmisc.Po \ ./$(DEPDIR)/netset.Po ./$(DEPDIR)/netssl.Po \ ./$(DEPDIR)/netuser.Po ./$(DEPDIR)/pipedebug.Po \ ./$(DEPDIR)/sockdebug.Po ./$(DEPDIR)/sstate.Po \ ./$(DEPDIR)/upsd.Po ./$(DEPDIR)/user.Po am__mv = mv -f COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ $(AM_CFLAGS) $(CFLAGS) AM_V_CC = $(am__v_CC_@AM_V@) am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@) am__v_CC_0 = @echo " CC " $@; am__v_CC_1 = CCLD = $(CC) LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ $(AM_LDFLAGS) $(LDFLAGS) -o $@ AM_V_CCLD = $(am__v_CCLD_@AM_V@) am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@) am__v_CCLD_0 = @echo " CCLD " $@; am__v_CCLD_1 = SOURCES = $(sockdebug_SOURCES) $(upsd_SOURCES) DIST_SOURCES = $(am__sockdebug_SOURCES_DIST) $(upsd_SOURCES) am__can_run_installinfo = \ case $$AM_UPDATE_INFO_DIR in \ n|no|NO) false;; \ *) (install-info --version) >/dev/null 2>&1;; \ esac am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) # Read a list of newline-separated strings from the standard input, # and print each of them once, without duplicates. Input order is # *not* preserved. am__uniquify_input = $(AWK) '\ BEGIN { nonempty = 0; } \ { items[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in items) print i; }; } \ ' # Make sure the list of sources is unique. This is necessary because, # e.g., the same source file might be shared among _SOURCES variables # for different programs/libraries. am__define_uniq_tagged_files = \ list='$(am__tagged_files)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | $(am__uniquify_input)` am__DIST_COMMON = $(srcdir)/Makefile.in $(top_srcdir)/depcomp DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) A2X = @A2X@ ACLOCAL = @ACLOCAL@ ALTPIDPATH = @ALTPIDPATH@ AMTAR = @AMTAR@ AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ AR = @AR@ ASCIIDOC = @ASCIIDOC@ ASPELL = @ASPELL@ ASPELL_FILTER_LIB_PATH = @ASPELL_FILTER_LIB_PATH@ ASPELL_FILTER_SHARE_PATH = @ASPELL_FILTER_SHARE_PATH@ ASPELL_FILTER_TEX_PATH = @ASPELL_FILTER_TEX_PATH@ AUGPARSE = @AUGPARSE@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ BINDIR = @BINDIR@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CONFIG_FLAGS = @CONFIG_FLAGS@ CONFPATH = @CONFPATH@ CPP = @CPP@ CPPCHECK = @CPPCHECK@ CPPFLAGS = @CPPFLAGS@ CPPUNIT_CFLAGS = @CPPUNIT_CFLAGS@ CPPUNIT_LIBS = @CPPUNIT_LIBS@ CSCOPE = @CSCOPE@ CTAGS = @CTAGS@ CXX = @CXX@ CXXCPP = @CXXCPP@ CXXDEPMODE = @CXXDEPMODE@ CXXFLAGS = @CXXFLAGS@ CYGPATH_W = @CYGPATH_W@ DBLATEX = @DBLATEX@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ DEPLOYED_UPSC = @DEPLOYED_UPSC@ DEPLOYED_UPSD = @DEPLOYED_UPSD@ DLLTOOL = @DLLTOOL@ DOC_BUILD_LIST = @DOC_BUILD_LIST@ DOC_CHECK_LIST = @DOC_CHECK_LIST@ DRIVER_BUILD_LIST = @DRIVER_BUILD_LIST@ DRIVER_INSTALL_TARGET = @DRIVER_INSTALL_TARGET@ DRIVER_MAN_LIST = @DRIVER_MAN_LIST@ DRIVER_MAN_LIST_PAGES = @DRIVER_MAN_LIST_PAGES@ DRVPATH = @DRVPATH@ DSYMUTIL = @DSYMUTIL@ DUMPBIN = @DUMPBIN@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ ETAGS = @ETAGS@ EXEEXT = @EXEEXT@ FGREP = @FGREP@ FORCE_NUT_VERSION = @FORCE_NUT_VERSION@ GDLIB_CONFIG = @GDLIB_CONFIG@ GREP = @GREP@ HAVE_SYS_SOCKET_H = @HAVE_SYS_SOCKET_H@ HAVE_WINSOCK2_H = @HAVE_WINSOCK2_H@ HAVE_WS2TCPIP_H = @HAVE_WS2TCPIP_H@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ LD = @LD@ LDFLAGS = @LDFLAGS@ LIBAVAHI_CFLAGS = @LIBAVAHI_CFLAGS@ LIBAVAHI_LIBS = @LIBAVAHI_LIBS@ LIBDIR = @LIBDIR@ LIBGD_CFLAGS = @LIBGD_CFLAGS@ LIBGD_LDFLAGS = @LIBGD_LDFLAGS@ LIBGPIO_CFLAGS = @LIBGPIO_CFLAGS@ LIBGPIO_LIBS = @LIBGPIO_LIBS@ LIBI2C_LIBS = @LIBI2C_LIBS@ LIBIPMI_CFLAGS = @LIBIPMI_CFLAGS@ LIBIPMI_LIBS = @LIBIPMI_LIBS@ LIBLTDL_CFLAGS = @LIBLTDL_CFLAGS@ LIBLTDL_LIBS = @LIBLTDL_LIBS@ LIBMODBUS_CFLAGS = @LIBMODBUS_CFLAGS@ LIBMODBUS_LIBS = @LIBMODBUS_LIBS@ LIBNEON_CFLAGS = @LIBNEON_CFLAGS@ LIBNEON_LIBS = @LIBNEON_LIBS@ LIBNETSNMP_CFLAGS = @LIBNETSNMP_CFLAGS@ LIBNETSNMP_LIBS = @LIBNETSNMP_LIBS@ LIBOBJS = @LIBOBJS@ LIBPOWERMAN_CFLAGS = @LIBPOWERMAN_CFLAGS@ LIBPOWERMAN_LIBS = @LIBPOWERMAN_LIBS@ LIBREGEX_LIBS = @LIBREGEX_LIBS@ LIBS = @LIBS@ LIBSSL_CFLAGS = @LIBSSL_CFLAGS@ LIBSSL_LIBS = @LIBSSL_LIBS@ LIBSSL_REQUIRES = @LIBSSL_REQUIRES@ LIBSYSTEMD_CFLAGS = @LIBSYSTEMD_CFLAGS@ LIBSYSTEMD_LIBS = @LIBSYSTEMD_LIBS@ LIBTOOL = @LIBTOOL@ LIBTOOL_DEPS = @LIBTOOL_DEPS@ LIBUSB_CFLAGS = @LIBUSB_CFLAGS@ LIBUSB_CONFIG = @LIBUSB_CONFIG@ LIBUSB_LIBS = @LIBUSB_LIBS@ LIBWRAP_CFLAGS = @LIBWRAP_CFLAGS@ LIBWRAP_LIBS = @LIBWRAP_LIBS@ LIPO = @LIPO@ LN_S = @LN_S@ LN_S_R = @LN_S_R@ LTLIBOBJS = @LTLIBOBJS@ LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@ MAINT = @MAINT@ MAKEINFO = @MAKEINFO@ MANIFEST_TOOL = @MANIFEST_TOOL@ MKDIR_P = @MKDIR_P@ MSGFMT = @MSGFMT@ NETLIBS = @NETLIBS@ NET_SNMP_CONFIG = @NET_SNMP_CONFIG@ NM = @NM@ NMEDIT = @NMEDIT@ NUT_DATADIR = @NUT_DATADIR@ NUT_LIBEXECDIR = @NUT_LIBEXECDIR@ NUT_NETVERSION = @NUT_NETVERSION@ NUT_SOURCE_GITREV = @NUT_SOURCE_GITREV@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ OS_NAME = @OS_NAME@ OTOOL = @OTOOL@ OTOOL64 = @OTOOL64@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_SEPARATOR = @PATH_SEPARATOR@ PIDPATH = @PIDPATH@ PKGCONFIGDIR = @PKGCONFIGDIR@ PKG_CONFIG = @PKG_CONFIG@ PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@ PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ PORT = @PORT@ POWERDOWNFLAG = @POWERDOWNFLAG@ PREFIX = @PREFIX@ PYTHON = @PYTHON@ PYTHON2 = @PYTHON2@ PYTHON2_SITE_PACKAGES = @PYTHON2_SITE_PACKAGES@ PYTHON3 = @PYTHON3@ PYTHON3_SITE_PACKAGES = @PYTHON3_SITE_PACKAGES@ PYTHON_SITE_PACKAGES = @PYTHON_SITE_PACKAGES@ RANLIB = @RANLIB@ REALPATH = @REALPATH@ RUN_AS_GROUP = @RUN_AS_GROUP@ RUN_AS_USER = @RUN_AS_USER@ SBINDIR = @SBINDIR@ SED = @SED@ SEMLIBS = @SEMLIBS@ SERLIBS = @SERLIBS@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ SOURCE_HIGHLIGHT = @SOURCE_HIGHLIGHT@ STATEPATH = @STATEPATH@ STRIP = @STRIP@ SUN_LIBUSB = @SUN_LIBUSB@ SYSTEMD_ANALYZE_PROGRAM = @SYSTEMD_ANALYZE_PROGRAM@ SYSTEMD_DAEMON_ARGS_DRIVER = @SYSTEMD_DAEMON_ARGS_DRIVER@ SYSTEMD_DAEMON_ARGS_UPSD = @SYSTEMD_DAEMON_ARGS_UPSD@ SYSTEMD_DAEMON_ARGS_UPSMON = @SYSTEMD_DAEMON_ARGS_UPSMON@ SYSTEMD_DAEMON_NOTIFYACCESS_DRIVER = @SYSTEMD_DAEMON_NOTIFYACCESS_DRIVER@ SYSTEMD_DAEMON_NOTIFYACCESS_UPSD = @SYSTEMD_DAEMON_NOTIFYACCESS_UPSD@ SYSTEMD_DAEMON_NOTIFYACCESS_UPSMON = @SYSTEMD_DAEMON_NOTIFYACCESS_UPSMON@ SYSTEMD_DAEMON_TYPE_DRIVER = @SYSTEMD_DAEMON_TYPE_DRIVER@ SYSTEMD_DAEMON_TYPE_UPSD = @SYSTEMD_DAEMON_TYPE_UPSD@ SYSTEMD_DAEMON_TYPE_UPSMON = @SYSTEMD_DAEMON_TYPE_UPSMON@ SYSTEMD_DAEMON_WATCHDOG_DRIVER = @SYSTEMD_DAEMON_WATCHDOG_DRIVER@ SYSTEMD_DAEMON_WATCHDOG_UPSD = @SYSTEMD_DAEMON_WATCHDOG_UPSD@ SYSTEMD_DAEMON_WATCHDOG_UPSMON = @SYSTEMD_DAEMON_WATCHDOG_UPSMON@ SYSTEMD_TMPFILES_PROGRAM = @SYSTEMD_TMPFILES_PROGRAM@ TREE_VERSION = @TREE_VERSION@ VALGRIND = @VALGRIND@ VERSION = @VERSION@ WINDMC = @WINDMC@ WINDRES = @WINDRES@ WORDS_BIGENDIAN = @WORDS_BIGENDIAN@ XMLLINT = @XMLLINT@ XSLTPROC = @XSLTPROC@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_AR = @ac_ct_AR@ ac_ct_CC = @ac_ct_CC@ ac_ct_CXX = @ac_ct_CXX@ ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__tar = @am__tar@ am__untar = @am__untar@ auglensdir = @auglensdir@ bindir = @bindir@ build = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ cgiexecdir = @cgiexecdir@ datadir = @datadir@ datarootdir = @datarootdir@ devddir = @devddir@ docdir = @docdir@ driverexecdir = @driverexecdir@ dummy_PKG_CONFIG = @dummy_PKG_CONFIG@ dummy_PKG_CONFIG_CFLAGS = @dummy_PKG_CONFIG_CFLAGS@ dummy_PKG_CONFIG_LIBS = @dummy_PKG_CONFIG_LIBS@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ hotplugdir = @hotplugdir@ htmldir = @htmldir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libdir = @libdir@ libexecdir = @libexecdir@ localedir = @localedir@ localstatedir = @localstatedir@ mandir = @mandir@ mkdir_p = @mkdir_p@ now = @now@ nut_with_nut_monitor = @nut_with_nut_monitor@ nut_with_nut_monitor_desktop = @nut_with_nut_monitor_desktop@ nut_with_nut_monitor_dir = @nut_with_nut_monitor_dir@ nut_with_nut_monitor_py2gtk2 = @nut_with_nut_monitor_py2gtk2@ nut_with_nut_monitor_py3qt5 = @nut_with_nut_monitor_py3qt5@ nut_with_pynut = @nut_with_pynut@ nut_with_pynut_py = @nut_with_pynut_py@ nut_with_pynut_py2 = @nut_with_pynut_py2@ nut_with_pynut_py3 = @nut_with_pynut_py3@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ pkgconfigdir = @pkgconfigdir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ runstatedir = @runstatedir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ sysconfdir = @sysconfdir@ systemdshutdowndir = @systemdshutdowndir@ systemdsystemunitdir = @systemdsystemunitdir@ systemdtmpfilesdir = @systemdtmpfilesdir@ target = @target@ target_alias = @target_alias@ target_cpu = @target_cpu@ target_os = @target_os@ target_vendor = @target_vendor@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ udevdir = @udevdir@ # Avoid per-target CFLAGS, because this will prevent re-use of object # files. In any case, CFLAGS are only -I options, so there is no harm, # but only add them if we really use the target. AM_CFLAGS = -I$(top_srcdir)/include $(am__append_1) $(am__append_2) LDADD = $(top_builddir)/common/libcommon.la \ $(top_builddir)/common/libparseconf.la $(NETLIBS) \ $(am__append_3) $(am__append_4) upsd_SOURCES = upsd.c user.c conf.c netssl.c sstate.c desc.c \ netget.c netmisc.c netlist.c netuser.c netset.c netinstcmd.c \ conf.h nut_ctype.h desc.h netcmds.h neterr.h netget.h netinstcmd.h \ netlist.h netmisc.h netset.h netuser.h netssl.h sstate.h stype.h upsd.h \ upstype.h user-data.h user.h @HAVE_WINDOWS_FALSE@sockdebug_SOURCES = sockdebug.c @HAVE_WINDOWS_TRUE@sockdebug_SOURCES = pipedebug.c MAINTAINERCLEANFILES = Makefile.in .dirstamp all: all-am .SUFFIXES: .SUFFIXES: .c .lo .o .obj $(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu server/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --gnu server/Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): install-libexecPROGRAMS: $(libexec_PROGRAMS) @$(NORMAL_INSTALL) @list='$(libexec_PROGRAMS)'; test -n "$(libexecdir)" || list=; \ if test -n "$$list"; then \ echo " $(MKDIR_P) '$(DESTDIR)$(libexecdir)'"; \ $(MKDIR_P) "$(DESTDIR)$(libexecdir)" || exit 1; \ fi; \ for p in $$list; do echo "$$p $$p"; done | \ sed 's/$(EXEEXT)$$//' | \ while read p p1; do if test -f $$p \ || test -f $$p1 \ ; then echo "$$p"; echo "$$p"; else :; fi; \ done | \ sed -e 'p;s,.*/,,;n;h' \ -e 's|.*|.|' \ -e 'p;x;s,.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/' | \ sed 'N;N;N;s,\n, ,g' | \ $(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1 } \ { d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \ if ($$2 == $$4) files[d] = files[d] " " $$1; \ else { print "f", $$3 "/" $$4, $$1; } } \ END { for (d in files) print "f", d, files[d] }' | \ while read type dir files; do \ if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \ test -z "$$files" || { \ echo " $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files '$(DESTDIR)$(libexecdir)$$dir'"; \ $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files "$(DESTDIR)$(libexecdir)$$dir" || exit $$?; \ } \ ; done uninstall-libexecPROGRAMS: @$(NORMAL_UNINSTALL) @list='$(libexec_PROGRAMS)'; test -n "$(libexecdir)" || list=; \ files=`for p in $$list; do echo "$$p"; done | \ sed -e 'h;s,^.*/,,;s/$(EXEEXT)$$//;$(transform)' \ -e 's/$$/$(EXEEXT)/' \ `; \ test -n "$$list" || exit 0; \ echo " ( cd '$(DESTDIR)$(libexecdir)' && rm -f" $$files ")"; \ cd "$(DESTDIR)$(libexecdir)" && rm -f $$files clean-libexecPROGRAMS: @list='$(libexec_PROGRAMS)'; test -n "$$list" || exit 0; \ echo " rm -f" $$list; \ rm -f $$list || exit $$?; \ test -n "$(EXEEXT)" || exit 0; \ list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \ echo " rm -f" $$list; \ rm -f $$list install-sbinPROGRAMS: $(sbin_PROGRAMS) @$(NORMAL_INSTALL) @list='$(sbin_PROGRAMS)'; test -n "$(sbindir)" || list=; \ if test -n "$$list"; then \ echo " $(MKDIR_P) '$(DESTDIR)$(sbindir)'"; \ $(MKDIR_P) "$(DESTDIR)$(sbindir)" || exit 1; \ fi; \ for p in $$list; do echo "$$p $$p"; done | \ sed 's/$(EXEEXT)$$//' | \ while read p p1; do if test -f $$p \ || test -f $$p1 \ ; then echo "$$p"; echo "$$p"; else :; fi; \ done | \ sed -e 'p;s,.*/,,;n;h' \ -e 's|.*|.|' \ -e 'p;x;s,.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/' | \ sed 'N;N;N;s,\n, ,g' | \ $(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1 } \ { d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \ if ($$2 == $$4) files[d] = files[d] " " $$1; \ else { print "f", $$3 "/" $$4, $$1; } } \ END { for (d in files) print "f", d, files[d] }' | \ while read type dir files; do \ if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \ test -z "$$files" || { \ echo " $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files '$(DESTDIR)$(sbindir)$$dir'"; \ $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files "$(DESTDIR)$(sbindir)$$dir" || exit $$?; \ } \ ; done uninstall-sbinPROGRAMS: @$(NORMAL_UNINSTALL) @list='$(sbin_PROGRAMS)'; test -n "$(sbindir)" || list=; \ files=`for p in $$list; do echo "$$p"; done | \ sed -e 'h;s,^.*/,,;s/$(EXEEXT)$$//;$(transform)' \ -e 's/$$/$(EXEEXT)/' \ `; \ test -n "$$list" || exit 0; \ echo " ( cd '$(DESTDIR)$(sbindir)' && rm -f" $$files ")"; \ cd "$(DESTDIR)$(sbindir)" && rm -f $$files clean-sbinPROGRAMS: @list='$(sbin_PROGRAMS)'; test -n "$$list" || exit 0; \ echo " rm -f" $$list; \ rm -f $$list || exit $$?; \ test -n "$(EXEEXT)" || exit 0; \ list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \ echo " rm -f" $$list; \ rm -f $$list sockdebug$(EXEEXT): $(sockdebug_OBJECTS) $(sockdebug_DEPENDENCIES) $(EXTRA_sockdebug_DEPENDENCIES) @rm -f sockdebug$(EXEEXT) $(AM_V_CCLD)$(LINK) $(sockdebug_OBJECTS) $(sockdebug_LDADD) $(LIBS) upsd$(EXEEXT): $(upsd_OBJECTS) $(upsd_DEPENDENCIES) $(EXTRA_upsd_DEPENDENCIES) @rm -f upsd$(EXEEXT) $(AM_V_CCLD)$(LINK) $(upsd_OBJECTS) $(upsd_LDADD) $(LIBS) mostlyclean-compile: -rm -f *.$(OBJEXT) distclean-compile: -rm -f *.tab.c @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/conf.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/desc.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/netget.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/netinstcmd.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/netlist.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/netmisc.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/netset.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/netssl.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/netuser.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pipedebug.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sockdebug.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sstate.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/upsd.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/user.Po@am__quote@ # am--include-marker $(am__depfiles_remade): @$(MKDIR_P) $(@D) @echo '# dummy' >$@-t && $(am__mv) $@-t $@ am--depfiles: $(am__depfiles_remade) .c.o: @am__fastdepCC_TRUE@ $(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.o$$||'`;\ @am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\ @am__fastdepCC_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ $< .c.obj: @am__fastdepCC_TRUE@ $(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.obj$$||'`;\ @am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ `$(CYGPATH_W) '$<'` &&\ @am__fastdepCC_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'` .c.lo: @am__fastdepCC_TRUE@ $(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.lo$$||'`;\ @am__fastdepCC_TRUE@ $(LTCOMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\ @am__fastdepCC_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LTCOMPILE) -c -o $@ $< mostlyclean-libtool: -rm -f *.lo clean-libtool: -rm -rf .libs _libs ID: $(am__tagged_files) $(am__define_uniq_tagged_files); mkid -fID $$unique tags: tags-am TAGS: tags tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) set x; \ here=`pwd`; \ $(am__define_uniq_tagged_files); \ shift; \ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ test -n "$$unique" || unique=$$empty_fix; \ if test $$# -gt 0; then \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ "$$@" $$unique; \ else \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ $$unique; \ fi; \ fi ctags: ctags-am CTAGS: ctags ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) $(am__define_uniq_tagged_files); \ test -z "$(CTAGS_ARGS)$$unique" \ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ $$unique GTAGS: here=`$(am__cd) $(top_builddir) && pwd` \ && $(am__cd) $(top_srcdir) \ && gtags -i $(GTAGS_ARGS) "$$here" cscopelist: cscopelist-am cscopelist-am: $(am__tagged_files) list='$(am__tagged_files)'; \ case "$(srcdir)" in \ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \ *) sdir=$(subdir)/$(srcdir) ;; \ esac; \ for i in $$list; do \ if test -f "$$i"; then \ echo "$(subdir)/$$i"; \ else \ echo "$$sdir/$$i"; \ fi; \ done >> $(top_builddir)/cscope.files distclean-tags: -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags distdir: $(BUILT_SOURCES) $(MAKE) $(AM_MAKEFLAGS) distdir-am distdir-am: $(DISTFILES) @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ dist_files=`for file in $$list; do echo $$file; done | \ sed -e "s|^$$srcdirstrip/||;t" \ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ case $$dist_files in \ */*) $(MKDIR_P) `echo "$$dist_files" | \ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ sort -u` ;; \ esac; \ for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d "$(distdir)/$$file"; then \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ else \ test -f "$(distdir)/$$file" \ || cp -p $$d/$$file "$(distdir)/$$file" \ || exit 1; \ fi; \ done check-am: all-am check: check-am all-am: Makefile $(PROGRAMS) installdirs: for dir in "$(DESTDIR)$(libexecdir)" "$(DESTDIR)$(sbindir)"; do \ test -z "$$dir" || $(MKDIR_P) "$$dir"; \ done install: install-am install-exec: install-exec-am install-data: install-data-am uninstall: uninstall-am install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-am install-strip: if test -z '$(STRIP)'; then \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ install; \ else \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ fi mostlyclean-generic: clean-generic: distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." -test -z "$(MAINTAINERCLEANFILES)" || rm -f $(MAINTAINERCLEANFILES) clean: clean-am clean-am: clean-generic clean-libexecPROGRAMS clean-libtool \ clean-local clean-sbinPROGRAMS mostlyclean-am distclean: distclean-am -rm -f ./$(DEPDIR)/conf.Po -rm -f ./$(DEPDIR)/desc.Po -rm -f ./$(DEPDIR)/netget.Po -rm -f ./$(DEPDIR)/netinstcmd.Po -rm -f ./$(DEPDIR)/netlist.Po -rm -f ./$(DEPDIR)/netmisc.Po -rm -f ./$(DEPDIR)/netset.Po -rm -f ./$(DEPDIR)/netssl.Po -rm -f ./$(DEPDIR)/netuser.Po -rm -f ./$(DEPDIR)/pipedebug.Po -rm -f ./$(DEPDIR)/sockdebug.Po -rm -f ./$(DEPDIR)/sstate.Po -rm -f ./$(DEPDIR)/upsd.Po -rm -f ./$(DEPDIR)/user.Po -rm -f Makefile distclean-am: clean-am distclean-compile distclean-generic \ distclean-tags dvi: dvi-am dvi-am: html: html-am html-am: info: info-am info-am: install-data-am: install-dvi: install-dvi-am install-dvi-am: install-exec-am: install-libexecPROGRAMS install-sbinPROGRAMS install-html: install-html-am install-html-am: install-info: install-info-am install-info-am: install-man: install-pdf: install-pdf-am install-pdf-am: install-ps: install-ps-am install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-am -rm -f ./$(DEPDIR)/conf.Po -rm -f ./$(DEPDIR)/desc.Po -rm -f ./$(DEPDIR)/netget.Po -rm -f ./$(DEPDIR)/netinstcmd.Po -rm -f ./$(DEPDIR)/netlist.Po -rm -f ./$(DEPDIR)/netmisc.Po -rm -f ./$(DEPDIR)/netset.Po -rm -f ./$(DEPDIR)/netssl.Po -rm -f ./$(DEPDIR)/netuser.Po -rm -f ./$(DEPDIR)/pipedebug.Po -rm -f ./$(DEPDIR)/sockdebug.Po -rm -f ./$(DEPDIR)/sstate.Po -rm -f ./$(DEPDIR)/upsd.Po -rm -f ./$(DEPDIR)/user.Po -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-am mostlyclean-am: mostlyclean-compile mostlyclean-generic \ mostlyclean-libtool pdf: pdf-am pdf-am: ps: ps-am ps-am: uninstall-am: uninstall-libexecPROGRAMS uninstall-sbinPROGRAMS .MAKE: install-am install-strip .PHONY: CTAGS GTAGS TAGS all all-am am--depfiles check check-am clean \ clean-generic clean-libexecPROGRAMS clean-libtool clean-local \ clean-sbinPROGRAMS cscopelist-am ctags ctags-am distclean \ distclean-compile distclean-generic distclean-libtool \ distclean-tags distdir dvi dvi-am html html-am info info-am \ install install-am install-data install-data-am install-dvi \ install-dvi-am install-exec install-exec-am install-html \ install-html-am install-info install-info-am \ install-libexecPROGRAMS install-man install-pdf install-pdf-am \ install-ps install-ps-am install-sbinPROGRAMS install-strip \ installcheck installcheck-am installdirs maintainer-clean \ maintainer-clean-generic mostlyclean mostlyclean-compile \ mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \ tags tags-am uninstall uninstall-am uninstall-libexecPROGRAMS \ uninstall-sbinPROGRAMS .PRECIOUS: Makefile # Make sure out-of-dir dependencies exist (especially when dev-building parts): $(top_builddir)/common/libcommon.la \ $(top_builddir)/common/libparseconf.la: dummy @cd $(@D) && $(MAKE) $(AM_MAKEFLAGS) $(@F) dummy: # NOTE: Do not clean ".deps" in SUBDIRS of the main project, # the root Makefile.am takes care of that! clean-local: $(AM_V_at)rm -rf $(EXTRA_PROGRAMS) # $(AM_V_at)rm -rf $(builddir)/.deps # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: nut-2.8.1/server/netget.c0000644000175000017500000001367414501607135012226 00000000000000/* netget.c - GET handlers for upsd Copyright (C) 2003 Russell Kroll 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 2 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, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "common.h" #include "upsd.h" #include "sstate.h" #include "state.h" #include "desc.h" #include "neterr.h" #include "netget.h" static void get_numlogins(nut_ctype_t *client, const char *upsname) { const upstype_t *ups; ups = get_ups_ptr(upsname); if (!ups) { send_err(client, NUT_ERR_UNKNOWN_UPS); return; } if (!ups_available(ups, client)) return; sendback(client, "NUMLOGINS %s %d\n", upsname, ups->numlogins); } static void get_upsdesc(nut_ctype_t *client, const char *upsname) { const upstype_t *ups; char esc[SMALLBUF]; ups = get_ups_ptr(upsname); if (!ups) { send_err(client, NUT_ERR_UNKNOWN_UPS); return; } if (ups->desc) { pconf_encode(ups->desc, esc, sizeof(esc)); sendback(client, "UPSDESC %s \"%s\"\n", upsname, esc); } else { sendback(client, "UPSDESC %s \"Unavailable\"\n", upsname); } } static void get_desc(nut_ctype_t *client, const char *upsname, const char *var) { const upstype_t *ups; const char *desc; ups = get_ups_ptr(upsname); if (!ups) { send_err(client, NUT_ERR_UNKNOWN_UPS); return; } if (!ups_available(ups, client)) return; desc = desc_get_var(var); if (desc) sendback(client, "DESC %s %s \"%s\"\n", upsname, var, desc); else sendback(client, "DESC %s %s \"Description unavailable\"\n", upsname, var); } static void get_cmddesc(nut_ctype_t *client, const char *upsname, const char *cmd) { const upstype_t *ups; const char *desc; ups = get_ups_ptr(upsname); if (!ups) { send_err(client, NUT_ERR_UNKNOWN_UPS); return; } if (!ups_available(ups, client)) return; desc = desc_get_cmd(cmd); if (desc) sendback(client, "CMDDESC %s %s \"%s\"\n", upsname, cmd, desc); else sendback(client, "CMDDESC %s %s \"Description unavailable\"\n", upsname, cmd); } static void get_type(nut_ctype_t *client, const char *upsname, const char *var) { char buf[SMALLBUF]; const upstype_t *ups; const st_tree_t *node; ups = get_ups_ptr(upsname); if (!ups) { send_err(client, NUT_ERR_UNKNOWN_UPS); return; } if (!ups_available(ups, client)) return; node = sstate_getnode(ups, var); if (!node) { send_err(client, NUT_ERR_VAR_NOT_SUPPORTED); return; } snprintf(buf, sizeof(buf), "TYPE %s %s", upsname, var); if (node->flags & ST_FLAG_RW) snprintfcat(buf, sizeof(buf), " RW"); if (node->enum_list) { snprintfcat(buf, sizeof(buf), " ENUM"); } if (node->range_list) { snprintfcat(buf, sizeof(buf), " RANGE"); } if (node->flags & ST_FLAG_STRING) { sendback(client, "%s STRING:%ld\n", buf, node->aux); return; } /* Any variable that is not string | range | enum is just a simple * numeric value */ sendback(client, "%s NUMBER\n", buf); } static void get_var_server(nut_ctype_t *client, const char *upsname, const char *var) { if (!strcasecmp(var, "server.info")) { sendback(client, "VAR %s server.info " "\"Network UPS Tools upsd %s - " "https://www.networkupstools.org/\"\n", upsname, UPS_VERSION); return; } if (!strcasecmp(var, "server.version")) { sendback(client, "VAR %s server.version \"%s\"\n", upsname, UPS_VERSION); return; } send_err(client, NUT_ERR_VAR_NOT_SUPPORTED); } static void get_var(nut_ctype_t *client, const char *upsname, const char *var) { const upstype_t *ups; const char *val; /* ignore upsname for server.* variables */ if (!strncasecmp(var, "server.", 7)) { get_var_server(client, upsname, var); return; } ups = get_ups_ptr(upsname); if (!ups) { send_err(client, NUT_ERR_UNKNOWN_UPS); return; } if (!ups_available(ups, client)) return; val = sstate_getinfo(ups, var); if (!val) { send_err(client, NUT_ERR_VAR_NOT_SUPPORTED); return; } /* handle special case for status */ if ((!strcasecmp(var, "ups.status")) && (ups->fsd)) sendback(client, "VAR %s %s \"FSD %s\"\n", upsname, var, val); else sendback(client, "VAR %s %s \"%s\"\n", upsname, var, val); } void net_get(nut_ctype_t *client, size_t numarg, const char **arg) { if (numarg < 1) { send_err(client, NUT_ERR_INVALID_ARGUMENT); return; } /* GET TRACKING [ID] */ if (!strcasecmp(arg[0], "TRACKING")) { if (numarg < 2) { sendback(client, "%s\n", (client->tracking) ? "ON" : "OFF"); } else { if (client->tracking) sendback(client, "%s\n", tracking_get(arg[1])); else send_err(client, NUT_ERR_FEATURE_NOT_CONFIGURED); } return; } if (numarg < 2) { send_err(client, NUT_ERR_INVALID_ARGUMENT); return; } /* GET NUMLOGINS UPS */ if (!strcasecmp(arg[0], "NUMLOGINS")) { get_numlogins(client, arg[1]); return; } /* GET UPSDESC UPS */ if (!strcasecmp(arg[0], "UPSDESC")) { get_upsdesc(client, arg[1]); return; } if (numarg < 3) { send_err(client, NUT_ERR_INVALID_ARGUMENT); return; } /* GET VAR UPS VARNAME */ if (!strcasecmp(arg[0], "VAR")) { get_var(client, arg[1], arg[2]); return; } /* GET TYPE UPS VARNAME */ if (!strcasecmp(arg[0], "TYPE")) { get_type(client, arg[1], arg[2]); return; } /* GET DESC UPS VARNAME */ if (!strcasecmp(arg[0], "DESC")) { get_desc(client, arg[1], arg[2]); return; } /* GET CMDDESC UPS CMDNAME */ if (!strcasecmp(arg[0], "CMDDESC")) { get_cmddesc(client, arg[1], arg[2]); return; } send_err(client, NUT_ERR_INVALID_ARGUMENT); return; } nut-2.8.1/server/netinstcmd.c0000644000175000017500000000700314500336654013101 00000000000000/* netinstcmd.c - INSTCMD handler for upsd Copyright (C) 2003 Russell Kroll 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 2 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, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "common.h" #include "upsd.h" #include "sstate.h" #include "state.h" #include "user.h" /* for user_checkinstcmd */ #include "neterr.h" #include "netinstcmd.h" static void send_instcmd(nut_ctype_t *client, const char *upsname, const char *cmdname, const char *value, const char *tracking_id) { int found, have_tracking_id = 0; upstype_t *ups; const cmdlist_t *ctmp; char sockcmd[SMALLBUF], esc[SMALLBUF]; ups = get_ups_ptr(upsname); if (!ups) { send_err(client, NUT_ERR_UNKNOWN_UPS); return; } if (!ups_available(ups, client)) return; ctmp = sstate_getcmdlist(ups); found = 0; while (ctmp) { if (!strcasecmp(ctmp->name, cmdname)) { found = 1; break; } ctmp = ctmp->next; } if (!found) { send_err(client, NUT_ERR_CMD_NOT_SUPPORTED); return; } /* see if this user is allowed to do this command */ if (!user_checkinstcmd(client->username, client->password, cmdname)) { send_err(client, NUT_ERR_ACCESS_DENIED); return; } /* Format the base command */ snprintf(sockcmd, sizeof(sockcmd), "INSTCMD %s", cmdname); /* see if the user has also passed a value for this command */ if (value != NULL) snprintfcat(sockcmd, sizeof(sockcmd), " %s", pconf_encode(value, esc, sizeof(esc))); /* see if the user want execution tracking for this command */ if (tracking_id && *tracking_id) { snprintfcat(sockcmd, sizeof(sockcmd), " TRACKING %s", tracking_id); /* Add an entry in the tracking structure */ tracking_add(tracking_id); have_tracking_id = 1; } /* add EOL */ snprintfcat(sockcmd, sizeof(sockcmd), "\n"); upslogx(LOG_INFO, "Instant command: %s@%s did %s%s%s on %s (tracking ID: %s)", client->username, client->addr, cmdname, (value != NULL)?" with value ":"", (value != NULL)?value:"", ups->name, (have_tracking_id) ? tracking_id : "disabled"); if (!sstate_sendline(ups, sockcmd)) { upslogx(LOG_INFO, "Set command send failed"); send_err(client, NUT_ERR_INSTCMD_FAILED); return; } /* return the result, possibly including tracking_id */ if (have_tracking_id) sendback(client, "OK TRACKING %s\n", tracking_id); else sendback(client, "OK\n"); } void net_instcmd(nut_ctype_t *client, size_t numarg, const char **arg) { const char *devname = NULL; const char *cmdname = NULL; const char *cmdparam = NULL; char tracking_id[UUID4_LEN] = ""; if (numarg < 2) { send_err(client, NUT_ERR_INVALID_ARGUMENT); return; } /* INSTCMD [cmdparam] */ /* Check arguments */ devname = arg[0]; cmdname = arg[1]; if (numarg == 3) cmdparam = arg[2]; if (client->tracking) { /* Generate a tracking ID, if client requested status tracking */ nut_uuid_v4(tracking_id); } send_instcmd(client, devname, cmdname, cmdparam, tracking_id); return; } nut-2.8.1/server/netuser.c0000644000175000017500000001146714500336654012427 00000000000000/* netuser.c - LOGIN/LOGOUT/USERNAME/PASSWORD/MASTER[PRIMARY] handlers for upsd Copyright (C) 2003 Russell Kroll 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 2 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, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "common.h" #include "upsd.h" #include "sstate.h" #include "state.h" #include "neterr.h" #include "user.h" /* for user_checkaction */ #include "netuser.h" /* LOGIN */ void net_login(nut_ctype_t *client, size_t numarg, const char **arg) { upstype_t *ups; if (numarg != 1) { send_err(client, NUT_ERR_INVALID_ARGUMENT); return; } if (client->loginups != NULL) { upslogx(LOG_INFO, "Client %s@%s tried to login twice", client->username, client->addr); send_err(client, NUT_ERR_ALREADY_LOGGED_IN); return; } /* make sure we got a valid UPS name */ ups = get_ups_ptr(arg[0]); if (!ups) { send_err(client, NUT_ERR_UNKNOWN_UPS); return; } /* make sure this is a valid user */ if (!user_checkaction(client->username, client->password, "LOGIN")) { upsdebugx(3, "%s: not a valid user: %s", __func__, client->username); send_err(client, NUT_ERR_ACCESS_DENIED); return; } ups->numlogins++; client->loginups = xstrdup(ups->name); upslogx(LOG_INFO, "User %s@%s logged into UPS [%s]%s", client->username, client->addr, client->loginups, client->ssl ? " (SSL)" : ""); sendback(client, "OK\n"); } void net_logout(nut_ctype_t *client, size_t numarg, const char **arg) { NUT_UNUSED_VARIABLE(arg); if (numarg != 0) { send_err(client, NUT_ERR_INVALID_ARGUMENT); return; } if (client->loginups != NULL) { upslogx(LOG_INFO, "User %s@%s logged out from UPS [%s]%s", client->username, client->addr, client->loginups, client->ssl ? " (SSL)" : ""); } sendback(client, "OK Goodbye\n"); client->last_heard = 0; } /* NOTE: Protocol updated since NUT 2.8.0 to handle master/primary * and API bumped, to rename/alias the routine. */ static int do_net_primary(nut_ctype_t *client, size_t numarg, const char **arg) { upstype_t *ups; if (numarg != 1) { send_err(client, NUT_ERR_INVALID_ARGUMENT); return -1; } ups = get_ups_ptr(arg[0]); if (!ups) { send_err(client, NUT_ERR_UNKNOWN_UPS); return -1; } /* make sure this user is allowed to do PRIMARY or MASTER */ if (!user_checkaction(client->username, client->password, "PRIMARY") && !user_checkaction(client->username, client->password, "MASTER") ) { send_err(client, NUT_ERR_ACCESS_DENIED); return -1; } /* this is just an access level check */ /* sendback() will be worded by caller below */ return 0; } /* MASTER (deprecated) */ void net_master(nut_ctype_t *client, size_t numarg, const char **arg) { /* Allow existing binaries linked against this file to still work */ upsdebugx(1, "WARNING: Client %s@%s " "requested MASTER level for device %s - " "which is deprecated in favor of PRIMARY " "since NUT 2.8.0", client->username, client->addr, (numarg > 0) ? arg[0] : ""); if (0 == do_net_primary(client, numarg, arg)) { sendback(client, "OK MASTER-GRANTED\n"); } } /* PRIMARY (since NUT 2.8.0) */ void net_primary(nut_ctype_t *client, size_t numarg, const char **arg) { if (0 == do_net_primary(client, numarg, arg)) { sendback(client, "OK PRIMARY-GRANTED\n"); } } /* USERNAME */ void net_username(nut_ctype_t *client, size_t numarg, const char **arg) { if (numarg != 1) { send_err(client, NUT_ERR_INVALID_ARGUMENT); return; } if (client->username != NULL) { upslogx(LOG_INFO, "Client %s@%s tried to set a username twice", client->username, client->addr); send_err(client, NUT_ERR_ALREADY_SET_USERNAME); return; } client->username = xstrdup(arg[0]); sendback(client, "OK\n"); } /* PASSWORD */ void net_password(nut_ctype_t *client, size_t numarg, const char **arg) { if (numarg != 1) { send_err(client, NUT_ERR_INVALID_ARGUMENT); return; } if (client->password != NULL) { if (client->username) upslogx(LOG_INFO, "Client %s@%s tried to set a password twice", client->username, client->addr); else upslogx(LOG_INFO, "Client on %s tried to set a password twice", client->addr); send_err(client, NUT_ERR_ALREADY_SET_PASSWORD); return; } client->password = xstrdup(arg[0]); sendback(client, "OK\n"); } nut-2.8.1/server/stype.h0000644000175000017500000000252114501607135012076 00000000000000/* stype.h - server data definitions for upsd Copyright (C) 2007 Arjen de Korte 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 2 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, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef NUT_STYPE_H_SEEN #define NUT_STYPE_H_SEEN 1 #include "common.h" #ifndef WIN32 #include #endif #ifndef NI_MAXHOST #define NI_MAXHOST 1025 #endif #ifndef NI_MAXSERV #define NI_MAXSERV 32 #endif #ifdef __cplusplus /* *INDENT-OFF* */ extern "C" { /* *INDENT-ON* */ #endif typedef struct stype_s { char *addr; char *port; TYPE_FD_SOCK sock_fd; #ifdef WIN32 HANDLE Event; #endif struct stype_s *next; } stype_t; #ifdef __cplusplus /* *INDENT-OFF* */ } /* *INDENT-ON* */ #endif #endif /* NUT_STYPE_H_SEEN */ nut-2.8.1/server/user.c0000644000175000017500000002235314501607135011710 00000000000000/* user.c - user handling functions for upsd Copyright (C) 2001 Russell Kroll 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 2 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, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "config.h" /* must be the first header */ #include #ifndef WIN32 #include #include #include #endif #include "common.h" #include "parseconf.h" #include "user.h" #include "user-data.h" static ulist_t *users = NULL; static ulist_t *curr_user; /* create a new user entry */ static void user_add(const char *un) { ulist_t *tmp, *last = NULL; if (!un) { return; } for (tmp = users; tmp != NULL; tmp = tmp->next) { last = tmp; if (!strcmp(tmp->username, un)) { fprintf(stderr, "Ignoring duplicate user %s\n", un); return; } } tmp = xcalloc(1, sizeof(*tmp)); tmp->username = xstrdup(un); if (last) { last->next = tmp; } else { users = tmp; } /* remember who we're working on */ curr_user = tmp; } /* set password */ static void user_password(const char *pw) { if (!curr_user) { upslogx(LOG_WARNING, "Ignoring password definition outside " "user section"); return; } if (!pw) { return; } if (curr_user->password) { fprintf(stderr, "Ignoring duplicate password for %s\n", curr_user->username); return; } curr_user->password = xstrdup(pw); } /* attach allowed instcmds to user */ static void user_add_instcmd(const char *cmd) { instcmdlist_t *tmp, *last = NULL; if (!curr_user) { upslogx(LOG_WARNING, "Ignoring instcmd definition outside " "user section"); return; } if (!cmd) { return; } for (tmp = curr_user->firstcmd; tmp != NULL; tmp = tmp->next) { last = tmp; /* ignore duplicates */ if (!strcasecmp(tmp->cmd, cmd)) { return; } } upsdebugx(2, "user_add_instcmd: adding '%s' for %s", cmd, curr_user->username); tmp = xcalloc(1, sizeof(*tmp)); tmp->cmd = xstrdup(cmd); if (last) { last->next = tmp; } else { curr_user->firstcmd = tmp; } } static actionlist_t *addaction(actionlist_t *base, const char *action) { actionlist_t *tmp, *last = NULL; if (!action) { return base; } for (tmp = base; tmp != NULL; tmp = tmp->next) { last = tmp; } tmp = xcalloc(1, sizeof(*tmp)); tmp->action = xstrdup(action); if (last) { last->next = tmp; return base; } return tmp; } /* attach allowed actions to user */ static void user_add_action(const char *act) { if (!curr_user) { upslogx(LOG_WARNING, "Ignoring action definition outside " "user section"); return; } upsdebugx(2, "user_add_action: adding '%s' for %s", act, curr_user->username); curr_user->firstaction = addaction(curr_user->firstaction, act); } static void flushcmd(instcmdlist_t *ptr) { if (!ptr) { return; } flushcmd(ptr->next); free(ptr->cmd); free(ptr); } static void flushaction(actionlist_t *ptr) { if (!ptr) { return; } flushaction(ptr->next); free(ptr->action); free(ptr); } static void flushuser(ulist_t *ptr) { if (!ptr) { return; } flushuser(ptr->next); flushcmd(ptr->firstcmd); flushaction(ptr->firstaction); free(ptr->username); free(ptr->password); free(ptr); } /* flush all user attributes - used during reload */ void user_flush(void) { flushuser(users); users = NULL; } static int user_matchinstcmd(ulist_t *user, const char * cmd) { instcmdlist_t *tmp; for (tmp = user->firstcmd; tmp != NULL; tmp = tmp->next) { if (!strcasecmp(tmp->cmd, cmd)) { return 1; /* good */ } if (!strcasecmp(tmp->cmd, "all")) { return 1; /* good */ } } return 0; /* fail */ } int user_checkinstcmd(const char *un, const char *pw, const char *cmd) { ulist_t *tmp; if ((!un) || (!pw) || (!cmd)) { return 0; /* failed */ } for (tmp = users; tmp != NULL; tmp = tmp->next) { /* let's be paranoid before we call strcmp */ if ((!tmp->username) || (!tmp->password)) { continue; } if (strcmp(tmp->username, un)) { continue; } if (strcmp(tmp->password, pw)) { /* password mismatch */ return 0; /* fail */ } if (!user_matchinstcmd(tmp, cmd)) { return 0; /* fail */ } /* passed all checks */ return 1; /* good */ } /* username not found */ return 0; /* fail */ } static int user_matchaction(ulist_t *user, const char *action) { actionlist_t *tmp; for (tmp = user->firstaction; tmp != NULL; tmp = tmp->next) { if (!strcasecmp(tmp->action, action)) { return 1; /* good */ } } return 0; /* fail */ } int user_checkaction(const char *un, const char *pw, const char *action) { ulist_t *tmp; if ((!un) || (!pw) || (!action)) return 0; /* failed */ for (tmp = users; tmp != NULL; tmp = tmp->next) { /* let's be paranoid before we call strcmp */ if ((!tmp->username) || (!tmp->password)) { continue; } if (strcmp(tmp->username, un)) { continue; } if (strcmp(tmp->password, pw)) { upsdebugx(2, "user_checkaction: password mismatch"); return 0; /* fail */ } if (!user_matchaction(tmp, action)) { upsdebugx(2, "user_matchaction: failed"); return 0; /* fail */ } /* passed all checks */ return 1; /* good */ } /* username not found */ return 0; /* fail */ } /* handle "upsmon primary" and "upsmon secondary" for nicer configurations */ /* FIXME: Protocol update needed to handle master/primary alias (in action and in protocol) */ static void set_upsmon_type(char *type) { /* primary: login, master, fsd */ if (!strcasecmp(type, "master") || !strcasecmp(type, "primary")) { user_add_action("login"); user_add_action("master"); /* Note: this is linked to "MASTER" API command permission */ user_add_action("fsd"); return; } /* secondary: just login */ if (!strcasecmp(type, "slave") || !strcasecmp(type, "secondary")) { user_add_action("login"); return; } upslogx(LOG_WARNING, "Unknown upsmon type %s", type); } /* actually do something with the variable + value pairs */ static void parse_var(char *var, char *val) { if (!strcasecmp(var, "password")) { user_password(val); return; } if (!strcasecmp(var, "instcmds")) { user_add_instcmd(val); return; } if (!strcasecmp(var, "actions")) { user_add_action(val); return; } if (!strcasecmp(var, "allowfrom")) { upslogx(LOG_WARNING, "allowfrom in upsd.users is no longer used"); return; } /* someone did 'upsmon = type' - allow it anyway */ if (!strcasecmp(var, "upsmon")) { set_upsmon_type(val); return; } upslogx(LOG_NOTICE, "Unrecognized user setting %s", var); } /* parse first var+val pair, then flip through remaining vals */ static void parse_rest(char *var, char *fval, char **arg, size_t next, size_t left) { size_t i; /* no globals supported yet, so there's no sense in continuing */ if (!curr_user) { return; } parse_var(var, fval); if (left == 0) { return; } for (i = 0; i < left; i++) { parse_var(var, arg[next + i]); } } static void user_parse_arg(size_t numargs, char **arg) { char *ep; if ((numargs == 0) || (!arg)) { return; } /* ignore old file format */ if (!strcasecmp(arg[0], "user")) { return; } /* handle 'foo=bar' (compressed form) */ ep = strchr(arg[0], '='); if (ep) { *ep = '\0'; /* parse first var/val, plus subsequent values (if any) */ /* 0 1 2 ... */ /* foo=bar ... */ parse_rest(arg[0], ep+1, arg, 1, (numargs < 2) ? 0 : (numargs - 1)); return; } /* look for section headers - [username] */ if ((arg[0][0] == '[') && (arg[0][strlen(arg[0])-1] == ']')) { arg[0][strlen(arg[0])-1] = '\0'; user_add(&arg[0][1]); return; } if (numargs < 2) { return; } if (!strcasecmp(arg[0], "upsmon")) { set_upsmon_type(arg[1]); } /* everything after here needs arg[1] and arg[2] */ if (numargs < 3) { return; } /* handle 'foo = bar' (split form) */ if (!strcmp(arg[1], "=")) { /* 0 1 2 3 4 ... */ /* foo = bar ... */ /* parse first var/val, plus subsequent values (if any) */ parse_rest(arg[0], arg[2], arg, 3, (numargs < 4) ? 0 : (numargs - 3)); return; } /* ... unhandled ... */ } /* called for fatal errors in parseconf like malloc failures */ static void upsd_user_err(const char *errmsg) { upslogx(LOG_ERR, "Fatal error in parseconf(upsd.users): %s", errmsg); } void user_load(void) { char fn[SMALLBUF]; PCONF_CTX_t ctx; curr_user = NULL; snprintf(fn, sizeof(fn), "%s/upsd.users", confpath()); check_perms(fn); pconf_init(&ctx, upsd_user_err); if (!pconf_file_begin(&ctx, fn)) { pconf_finish(&ctx); upslogx(LOG_WARNING, "%s", ctx.errmsg); return; } while (pconf_file_next(&ctx)) { if (pconf_parse_error(&ctx)) { upslogx(LOG_ERR, "Parse error: %s:%d: %s", fn, ctx.linenum, ctx.errmsg); continue; } user_parse_arg(ctx.numargs, ctx.arglist); } pconf_finish(&ctx); } nut-2.8.1/server/user-data.h0000644000175000017500000000277214500336654012633 00000000000000/* user-data.h - structures for user.c Copyright (C) 2001 Russell Kroll 2005 Arnaud Quette 2007 Peter Selinger 2008 Arjen de Korte 2013 Emilien Kia 2020 Jim Klimov 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 2 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, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef NUT_USERDATA_H_SEEN #define NUT_USERDATA_H_SEEN 1 #ifdef __cplusplus /* *INDENT-OFF* */ extern "C" { /* *INDENT-ON* */ #endif typedef struct { char *cmd; void *next; } instcmdlist_t; typedef struct { char *action; void *next; } actionlist_t; typedef struct { char *username; char *password; instcmdlist_t *firstcmd; actionlist_t *firstaction; void *next; } ulist_t; #ifdef __cplusplus /* *INDENT-OFF* */ } /* *INDENT-ON* */ #endif #endif /* NUT_USERDATA_H_SEEN */ nut-2.8.1/server/upsd.h0000644000175000017500000000712614501607135011713 00000000000000/* upsd.h - support structures and other minor details Copyright (C) 1999 Russell Kroll 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 2 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, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ /* * Much of the content from here was also useful to the * drivers, so has been moved into include/shared-tables.h * instead of being within the daemon specific include file * */ #ifndef UPSD_H_SEEN #define UPSD_H_SEEN #include "attribute.h" #include "common.h" #ifndef WIN32 #include #include #include #endif #include "timehead.h" #include #ifdef HAVE_POLL_H # include /* nfds_t */ #else typedef unsigned long int nfds_t; #endif #include "parseconf.h" #include "nut_ctype.h" #include "upstype.h" #define NUT_NET_ANSWER_MAX SMALLBUF #ifdef __cplusplus /* *INDENT-OFF* */ extern "C" { /* *INDENT-ON* */ #endif /* prototypes from upsd.c */ upstype_t *get_ups_ptr(const char *upsname); int ups_available(const upstype_t *ups, nut_ctype_t *client); void listen_add(const char *addr, const char *port); void kick_login_clients(const char *upsname); int sendback(nut_ctype_t *client, const char *fmt, ...) __attribute__ ((__format__ (__printf__, 2, 3))); int send_err(nut_ctype_t *client, const char *errtype); void server_load(void); void server_free(void); void check_perms(const char *fn); /* return values for instcmd / setvar status tracking, * mapped on drivers/upshandler.h, apart from STAT_PENDING (initial state) */ enum { STAT_PENDING = -1, /* not yet completed */ STAT_HANDLED = 0, /* completed successfully (NUT_SUCCESS or "OK") */ STAT_UNKNOWN, /* unspecified error (NUT_ERR_UNKNOWN) */ STAT_INVALID, /* invalid command/setvar (NUT_ERR_INVALID_ARGUMENT) */ STAT_FAILED /* command/setvar failed (NUT_ERR_INSTCMD_FAILED / NUT_ERR_SET_FAILED) */ }; /* Commands and settings status tracking functions */ int tracking_add(const char *id); int tracking_set(const char *id, const char *value); int tracking_del(const char *id); void tracking_free(void); void tracking_cleanup(void); char *tracking_get(const char *id); int tracking_enable(void); int tracking_disable(void); int tracking_is_enabled(void); /* declarations from upsd.c */ extern int maxage, tracking_delay, allow_no_device; extern nfds_t maxconn; extern char *statepath, *datapath; extern upstype_t *firstups; extern nut_ctype_t *firstclient; /* map commands onto signals */ #ifndef WIN32 #define SIGCMD_STOP SIGTERM #define SIGCMD_RELOAD SIGHUP #else #define SIGCMD_STOP COMMAND_STOP #define SIGCMD_RELOAD COMMAND_RELOAD #endif /* awkward way to make a string out of a numeric constant */ #define string_const_aux(x) #x #define string_const(x) string_const_aux(x) #ifdef SHUT_RDWR #define shutdown_how SHUT_RDWR #else #define shutdown_how 2 #endif /* UUID v4 generation function * Note: 'dest' must be at least `UUID4_LEN` long */ int nut_uuid_v4(char *uuid_str); #ifdef __cplusplus /* *INDENT-OFF* */ } /* *INDENT-ON* */ #endif #endif /* UPSD_H_SEEN */ nut-2.8.1/server/desc.h0000644000175000017500000000243514500336654011660 00000000000000/* desc.h - variable/command description handling for upsd Copyright (C) 2003 Russell Kroll 2005 Arnaud Quette 2013 Emilien Kia 2020 Jim Klimov 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 2 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, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef NUT_DESC_H_SEEN #define NUT_DESC_H_SEEN 1 #ifdef __cplusplus /* *INDENT-OFF* */ extern "C" { /* *INDENT-ON* */ #endif void desc_load(void); void desc_free(void); const char *desc_get_cmd(const char *name); const char *desc_get_var(const char *name); #ifdef __cplusplus /* *INDENT-OFF* */ } /* *INDENT-ON* */ #endif #endif /* NUT_DESC_H_SEEN */ nut-2.8.1/server/netget.h0000644000175000017500000000240214500336654012222 00000000000000/* netget.h - GET handlers for upsd Copyright (C) 2003 Russell Kroll 2005 Arnaud Quette 2007 Peter Selinger 2013 Emilien Kia 2020 Jim Klimov 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 2 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, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef NUT_NETGET_H_SEEN #define NUT_NETGET_H_SEEN 1 #ifdef __cplusplus /* *INDENT-OFF* */ extern "C" { /* *INDENT-ON* */ #endif void net_get(nut_ctype_t *client, size_t numarg, const char **arg); #ifdef __cplusplus /* *INDENT-OFF* */ } /* *INDENT-ON* */ #endif #endif /* NUT_NETGET_H_SEEN */ nut-2.8.1/server/sstate.h0000644000175000017500000000450714501607135012243 00000000000000/* sstate.h - Network UPS Tools server-side state management Copyright (C) 2003 Russell Kroll 2008 Arjen de Korte 2012 Arnaud Quette 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 2 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, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef NUT_SSTATE_H_SEEN #define NUT_SSTATE_H_SEEN 1 #include "common.h" /* TYPE_FD */ #include "state.h" #include "upstype.h" #define SS_CONNFAIL_INT 300 /* complain about a dead driver every 5 mins */ #define SS_MAX_READ 256 /* don't let drivers tie us up in read() */ #ifdef __cplusplus /* *INDENT-OFF* */ extern "C" { /* *INDENT-ON* */ #endif TYPE_FD sstate_connect(upstype_t *ups); void sstate_disconnect(upstype_t *ups); void sstate_readline(upstype_t *ups); const char *sstate_getinfo(const upstype_t *ups, const char *var); int sstate_getflags(const upstype_t *ups, const char *var); long sstate_getaux(const upstype_t *ups, const char *var); const enum_t *sstate_getenumlist(const upstype_t *ups, const char *var); const range_t *sstate_getrangelist(const upstype_t *ups, const char *var); const cmdlist_t *sstate_getcmdlist(const upstype_t *ups); void sstate_makeinfolist(const upstype_t *ups, char *buf, size_t bufsize); void sstate_makerwlist(const upstype_t *ups, char *buf, size_t bufsize); void sstate_makeinstcmdlist_t(const upstype_t *ups, char *buf, size_t bufsize); int sstate_dead(upstype_t *ups, int maxage); void sstate_infofree(upstype_t *ups); void sstate_cmdfree(upstype_t *ups); int sstate_sendline(upstype_t *ups, const char *buf); const st_tree_t *sstate_getnode(const upstype_t *ups, const char *varname); #ifdef __cplusplus /* *INDENT-OFF* */ } /* *INDENT-ON* */ #endif #endif /* NUT_SSTATE_H_SEEN */ nut-2.8.1/server/netssl.c0000644000175000017500000005076014513167372012254 00000000000000/* netssl.c - Interface to OpenSSL for upsd Copyright (C) 2002 Russell Kroll 2008 Arjen de Korte based on the original implementation: Copyright (C) 2002 Technorama Ltd. 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 2 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, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include #ifndef WIN32 #include #include #else #include "wincompat.h" #endif #include "upsd.h" #include "neterr.h" #include "netssl.h" #include "nut_stdint.h" #ifdef WITH_NSS #include #include #include #if defined(NSS_VMAJOR) && (NSS_VMAJOR > 3 || (NSS_VMAJOR == 3 && defined(NSS_VMINOR) && NSS_VMINOR >= 39)) #include #include #else #include #include #endif /* NSS before 3.39 */ #include #include #include #endif /* WITH_NSS */ char *certfile = NULL; char *certname = NULL; char *certpasswd = NULL; /* Warning: in this release of NUT, this feature is disabled by default * in order to retain compatibility with "least surprise" for earlier * existing deployments. Over time it can become enabled by default. * See upsd.conf option DISABLE_WEAK_SSL to toggle this in-vivo. */ int disable_weak_ssl = 0; #ifdef WITH_CLIENT_CERTIFICATE_VALIDATION int certrequest = 0; #endif /* WITH_CLIENT_CERTIFICATE_VALIDATION */ static int ssl_initialized = 0; #ifndef WITH_SSL /* stubs for non-ssl compiles */ void net_starttls(nut_ctype_t *client, size_t numarg, const char **arg) { NUT_UNUSED_VARIABLE(client); NUT_UNUSED_VARIABLE(numarg); NUT_UNUSED_VARIABLE(arg); send_err(client, NUT_ERR_FEATURE_NOT_SUPPORTED); return; } ssize_t ssl_write(nut_ctype_t *client, const char *buf, size_t buflen) { NUT_UNUSED_VARIABLE(client); NUT_UNUSED_VARIABLE(buf); NUT_UNUSED_VARIABLE(buflen); upslogx(LOG_ERR, "ssl_write called but SSL wasn't compiled in"); return -1; } ssize_t ssl_read(nut_ctype_t *client, char *buf, size_t buflen) { NUT_UNUSED_VARIABLE(client); NUT_UNUSED_VARIABLE(buf); NUT_UNUSED_VARIABLE(buflen); upslogx(LOG_ERR, "ssl_read called but SSL wasn't compiled in"); return -1; } void ssl_init(void) { ssl_initialized = 0; /* keep gcc quiet */ } void ssl_finish(nut_ctype_t *client) { if (client->ssl) { upslogx(LOG_ERR, "ssl_finish found active SSL connection but SSL wasn't compiled in"); } } void ssl_cleanup(void) { } #else #ifdef WITH_OPENSSL static SSL_CTX *ssl_ctx = NULL; static void ssl_debug(void) { unsigned long e; char errmsg[SMALLBUF]; while ((e = ERR_get_error()) != 0) { ERR_error_string_n(e, errmsg, sizeof(errmsg)); upsdebugx(1, "ssl_debug: %s", errmsg); } } static int ssl_error(SSL *ssl, ssize_t ret) { int e; if (ret >= INT_MAX) { upslogx(LOG_ERR, "ssl_error() ret=%" PRIiSIZE " would not fit in an int", ret); return -1; } e = SSL_get_error(ssl, (int)ret); switch (e) { case SSL_ERROR_WANT_READ: upsdebugx(1, "ssl_error() ret=%" PRIiSIZE " SSL_ERROR_WANT_READ", ret); break; case SSL_ERROR_WANT_WRITE: upsdebugx(1, "ssl_error() ret=%" PRIiSIZE " SSL_ERROR_WANT_WRITE", ret); break; case SSL_ERROR_SYSCALL: if (ret == 0 && ERR_peek_error() == 0) { upsdebugx(1, "ssl_error() EOF from client"); } else { upsdebugx(1, "ssl_error() ret=%" PRIiSIZE " SSL_ERROR_SYSCALL", ret); } break; default: upsdebugx(1, "ssl_error() ret=%" PRIiSIZE " SSL_ERROR %d", ret, e); ssl_debug(); } return -1; } #elif defined(WITH_NSS) /* WITH_OPENSSL */ static CERTCertificate *cert; static SECKEYPrivateKey *privKey; static char *nss_password_callback(PK11SlotInfo *slot, PRBool retry, void *arg) { NUT_UNUSED_VARIABLE(arg); if (retry) { /* Force not inted to retrieve password many times. */ return NULL; } upslogx(LOG_INFO, "Intend to retrieve password for %s / %s: password %sconfigured", PK11_GetSlotName(slot), PK11_GetTokenName(slot), certpasswd?"":"not "); return certpasswd ? PL_strdup(certpasswd) : NULL; } static void nss_error(const char* text) { char buffer[SMALLBUF]; PRInt32 length = PR_GetErrorText(buffer); if (length > 0 && length < SMALLBUF) { upsdebugx(1, "nss_error %ld in %s : %s", (long)PR_GetError(), text, buffer); }else{ upsdebugx(1, "nss_error %ld in %s", (long)PR_GetError(), text); } } static int ssl_error(PRFileDesc *ssl, ssize_t ret) { char buffer[256]; PRInt32 length; PRErrorCode e; NUT_UNUSED_VARIABLE(ssl); NUT_UNUSED_VARIABLE(ret); e = PR_GetError(); length = PR_GetErrorText(buffer); if (length > 0 && length < 256) { upsdebugx(1, "ssl_error() ret=%d %*s", e, length, buffer); } else { upsdebugx(1, "ssl_error() ret=%d", e); } return -1; } static SECStatus AuthCertificate(CERTCertDBHandle *arg, PRFileDesc *fd, PRBool checksig, PRBool isServer) { nut_ctype_t *client = (nut_ctype_t *)SSL_RevealPinArg(fd); SECStatus status = SSL_AuthCertificate(arg, fd, checksig, isServer); upslogx(LOG_INFO, "Intend to authenticate client %s : %s.", client?client->addr:"(unnamed)", status==SECSuccess?"SUCCESS":"FAILED"); return status; } static SECStatus BadCertHandler(nut_ctype_t *arg, PRFileDesc *fd) { NUT_UNUSED_VARIABLE(fd); upslogx(LOG_WARNING, "Certificate validation failed for %s", (arg&&arg->addr)?arg->addr:""); #ifdef WITH_CLIENT_CERTIFICATE_VALIDATION /* BadCertHandler is called when the NSS certificate validation is failed. * If the certificate verification (user conf) is mandatory, reject authentication * else accept it. */ return certrequest==NETSSL_CERTREQ_REQUIRE?SECFailure:SECSuccess; #else /* WITH_CLIENT_CERTIFICATE_VALIDATION */ /* Always accept clients. */ return SECSuccess; #endif /* WITH_CLIENT_CERTIFICATE_VALIDATION */ } static void HandshakeCallback(PRFileDesc *fd, nut_ctype_t *client_data) { NUT_UNUSED_VARIABLE(fd); upslogx(LOG_INFO, "SSL handshake done successfully with client %s", client_data->addr); } #endif /* WITH_OPENSSL | WITH_NSS */ void net_starttls(nut_ctype_t *client, size_t numarg, const char **arg) { #ifdef WITH_OPENSSL int ret; #elif defined(WITH_NSS) /* WITH_OPENSSL */ SECStatus status; PRFileDesc *socket; #endif /* WITH_OPENSSL | WITH_NSS */ NUT_UNUSED_VARIABLE(numarg); NUT_UNUSED_VARIABLE(arg); if (client->ssl) { send_err(client, NUT_ERR_ALREADY_SSL_MODE); return; } client->ssl_connected = 0; if ((!certfile) || (!ssl_initialized)) { send_err(client, NUT_ERR_FEATURE_NOT_CONFIGURED); return; } #ifdef WITH_OPENSSL if (!ssl_ctx) #elif defined(WITH_NSS) /* WITH_OPENSSL */ if (!NSS_IsInitialized()) #endif /* WITH_OPENSSL | WITH_NSS */ { send_err(client, NUT_ERR_FEATURE_NOT_CONFIGURED); ssl_initialized = 0; return; } if (!sendback(client, "OK STARTTLS\n")) { return; } #ifdef WITH_OPENSSL client->ssl = SSL_new(ssl_ctx); if (!client->ssl) { upslog_with_errno(LOG_ERR, "SSL_new failed\n"); ssl_debug(); return; } if (SSL_set_fd(client->ssl, client->sock_fd) != 1) { upslog_with_errno(LOG_ERR, "SSL_set_fd failed\n"); ssl_debug(); return; } ret = SSL_accept(client->ssl); switch (ret) { case 1: client->ssl_connected = 1; upsdebugx(3, "SSL connected (%s)", SSL_get_version(client->ssl)); break; case 0: upslog_with_errno(LOG_ERR, "SSL_accept do not accept handshake."); ssl_error(client->ssl, ret); break; case -1: upslog_with_errno(LOG_ERR, "Unknown return value from SSL_accept"); ssl_error(client->ssl, ret); break; } #elif defined(WITH_NSS) /* WITH_OPENSSL */ socket = PR_ImportTCPSocket(client->sock_fd); if (socket == NULL) { upslogx(LOG_ERR, "Can not initialize SSL connection"); nss_error("net_starttls / PR_ImportTCPSocket"); return; } client->ssl = SSL_ImportFD(NULL, socket); if (client->ssl == NULL) { upslogx(LOG_ERR, "Can not initialize SSL connection"); nss_error("net_starttls / SSL_ImportFD"); return; } if (SSL_SetPKCS11PinArg(client->ssl, client) == -1) { upslogx(LOG_ERR, "Can not initialize SSL connection"); nss_error("net_starttls / SSL_SetPKCS11PinArg"); return; } #if (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_PUSH_POP) && (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_CAST_FUNCTION_TYPE_STRICT) #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wcast-function-type-strict" #endif /* Note cast to SSLAuthCertificate to prevent warning due to * bad function prototype in NSS. */ status = SSL_AuthCertificateHook(client->ssl, (SSLAuthCertificate)AuthCertificate, CERT_GetDefaultCertDB()); if (status != SECSuccess) { upslogx(LOG_ERR, "Can not initialize SSL connection"); nss_error("net_starttls / SSL_AuthCertificateHook"); return; } status = SSL_BadCertHook(client->ssl, (SSLBadCertHandler)BadCertHandler, client); if (status != SECSuccess) { upslogx(LOG_ERR, "Can not initialize SSL connection"); nss_error("net_starttls / SSL_BadCertHook"); return; } status = SSL_HandshakeCallback(client->ssl, (SSLHandshakeCallback)HandshakeCallback, client); if (status != SECSuccess) { upslogx(LOG_ERR, "Can not initialize SSL connection"); nss_error("net_starttls / SSL_HandshakeCallback"); return; } status = SSL_ConfigSecureServer(client->ssl, cert, privKey, NSS_FindCertKEAType(cert)); if (status != SECSuccess) { upslogx(LOG_ERR, "Can not initialize SSL connection"); nss_error("net_starttls / SSL_ConfigSecureServer"); return; } #if (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_PUSH_POP) && (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_CAST_FUNCTION_TYPE_STRICT) #pragma GCC diagnostic pop #endif status = SSL_ResetHandshake(client->ssl, PR_TRUE); if (status != SECSuccess) { upslogx(LOG_ERR, "Can not initialize SSL connection"); nss_error("net_starttls / SSL_ResetHandshake"); return; } /* Note: this call can generate memory leaks not resolvable * by any release function. * Probably SSL session key object allocation. */ status = SSL_ForceHandshake(client->ssl); if (status != SECSuccess) { PRErrorCode code = PR_GetError(); if (code==SSL_ERROR_NO_CERTIFICATE) { upslogx(LOG_WARNING, "Client %s do not provide certificate.", client->addr); } else { nss_error("net_starttls / SSL_ForceHandshake"); /* TODO : Close the connection. */ return; } } client->ssl_connected = 1; #endif /* WITH_OPENSSL | WITH_NSS */ } void ssl_init(void) { #ifdef WITH_NSS SECStatus status; #if defined(NSS_VMAJOR) && (NSS_VMAJOR > 3 || (NSS_VMAJOR == 3 && defined(NSS_VMINOR) && NSS_VMINOR >= 14)) SSLVersionRange range; #endif #endif /* WITH_NSS */ if (!certfile) { return; } check_perms(certfile); if (!disable_weak_ssl) upslogx(LOG_WARNING, "Warning: DISABLE_WEAK_SSL is not enabled. Please consider enabling to improve network security."); #ifdef WITH_OPENSSL #if OPENSSL_VERSION_NUMBER < 0x10100000L SSL_load_error_strings(); SSL_library_init(); ssl_ctx = SSL_CTX_new(SSLv23_server_method()); #else ssl_ctx = SSL_CTX_new(TLS_server_method()); #endif if (!ssl_ctx) { ssl_debug(); fatalx(EXIT_FAILURE, "SSL_CTX_new failed"); } SSL_CTX_set_options(ssl_ctx, SSL_OP_CIPHER_SERVER_PREFERENCE); #if OPENSSL_VERSION_NUMBER < 0x10100000L /* set minimum protocol TLSv1 */ SSL_CTX_set_options(ssl_ctx, SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3); if (disable_weak_ssl) { #if defined(SSL_OP_NO_TLSv1_2) SSL_CTX_set_options(ssl_ctx, SSL_OP_NO_TLSv1 | SSL_OP_NO_TLSv1_1); #elif defined(SSL_OP_NO_TLSv1_1) SSL_CTX_set_options(ssl_ctx, SSL_OP_NO_TLSv1); #endif } #else if (SSL_CTX_set_min_proto_version(ssl_ctx, disable_weak_ssl ? TLS1_2_VERSION : TLS1_VERSION) != 1) { ssl_debug(); fatalx(EXIT_FAILURE, "SSL_CTX_set_min_proto_version(TLS1_VERSION)"); } #endif if (SSL_CTX_use_certificate_chain_file(ssl_ctx, certfile) != 1) { ssl_debug(); fatalx(EXIT_FAILURE, "SSL_CTX_use_certificate_chain_file(%s) failed", certfile); } if (SSL_CTX_use_PrivateKey_file(ssl_ctx, certfile, SSL_FILETYPE_PEM) != 1) { ssl_debug(); fatalx(EXIT_FAILURE, "SSL_CTX_use_PrivateKey_file(%s) failed", certfile); } if (SSL_CTX_check_private_key(ssl_ctx) != 1) { ssl_debug(); fatalx(EXIT_FAILURE, "SSL_CTX_check_private_key(%s) failed", certfile); } if (SSL_CTX_set_cipher_list(ssl_ctx, "HIGH:@STRENGTH") != 1) { ssl_debug(); fatalx(EXIT_FAILURE, "SSL_CTX_set_cipher_list failed"); } SSL_CTX_set_verify(ssl_ctx, SSL_VERIFY_NONE, NULL); ssl_initialized = 1; #elif defined(WITH_NSS) /* WITH_OPENSSL */ if (!certname || certname[0]==0 ) { upslogx(LOG_ERR, "The SSL certificate name is not specified."); return; } PR_Init(PR_USER_THREAD, PR_PRIORITY_NORMAL, 0); PK11_SetPasswordFunc(nss_password_callback); if (certfile) /* Note: this call can generate memory leaks not resolvable * by any release function. * Probably NSS key module object allocation and * probably NSS key db object allocation too. */ status = NSS_Init(certfile); else status = NSS_NoDB_Init(NULL); if (status != SECSuccess) { upslogx(LOG_ERR, "Can not initialize SSL context"); nss_error("upscli_init / NSS_[NoDB]_Init"); return; } status = NSS_SetDomesticPolicy(); if (status != SECSuccess) { upslogx(LOG_ERR, "Can not initialize SSL policy"); nss_error("upscli_init / NSS_SetDomesticPolicy"); return; } /* Default server cache config */ status = SSL_ConfigServerSessionIDCache(0, 0, 0, NULL); if (status != SECSuccess) { upslogx(LOG_ERR, "Can not initialize SSL server cache"); nss_error("upscli_init / SSL_ConfigServerSessionIDCache"); return; } if (!disable_weak_ssl) { status = SSL_OptionSetDefault(SSL_ENABLE_SSL3, PR_TRUE); if (status != SECSuccess) { upslogx(LOG_ERR, "Can not enable SSLv3"); nss_error("upscli_init / SSL_OptionSetDefault(SSL_ENABLE_SSL3)"); return; } status = SSL_OptionSetDefault(SSL_ENABLE_TLS, PR_TRUE); if (status != SECSuccess) { upslogx(LOG_ERR, "Can not enable TLSv1"); nss_error("upscli_init / SSL_OptionSetDefault(SSL_ENABLE_TLS)"); return; } } else { #if defined(NSS_VMAJOR) && (NSS_VMAJOR > 3 || (NSS_VMAJOR == 3 && defined(NSS_VMINOR) && NSS_VMINOR >= 14)) status = SSL_VersionRangeGetSupported(ssl_variant_stream, &range); if (status != SECSuccess) { upslogx(LOG_ERR, "Can not get versions supported"); nss_error("upscli_init / SSL_VersionRangeGetSupported"); return; } range.min = SSL_LIBRARY_VERSION_TLS_1_1; #ifdef SSL_LIBRARY_VERSION_TLS_1_2 range.min = SSL_LIBRARY_VERSION_TLS_1_2; #endif status = SSL_VersionRangeSetDefault(ssl_variant_stream, &range); if (status != SECSuccess) { upslogx(LOG_ERR, "Can not set versions supported"); nss_error("upscli_init / SSL_VersionRangeSetDefault"); return; } /* Disable old/weak ciphers */ SSL_CipherPrefSetDefault(TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA, PR_FALSE); SSL_CipherPrefSetDefault(TLS_RSA_WITH_3DES_EDE_CBC_SHA, PR_FALSE); SSL_CipherPrefSetDefault(TLS_RSA_WITH_RC4_128_SHA, PR_FALSE); SSL_CipherPrefSetDefault(TLS_RSA_WITH_RC4_128_MD5, PR_FALSE); #else status = SSL_OptionSetDefault(SSL_ENABLE_SSL3, PR_FALSE); if (status != SECSuccess) { upslogx(LOG_ERR, "Can not disable SSLv3"); nss_error("upscli_init / SSL_OptionSetDefault(SSL_DISABLE_SSL3)"); return; } status = SSL_OptionSetDefault(SSL_ENABLE_TLS, PR_TRUE); if (status != SECSuccess) { upslogx(LOG_ERR, "Can not enable TLSv1"); nss_error("upscli_init / SSL_OptionSetDefault(SSL_ENABLE_TLS)"); return; } #endif } #ifdef WITH_CLIENT_CERTIFICATE_VALIDATION if (certrequest < NETSSL_CERTREQ_NO && certrequest > NETSSL_CERTREQ_REQUEST) { upslogx(LOG_ERR, "Invalid certificate requirement"); return; } if (certrequest == NETSSL_CERTREQ_REQUEST || certrequest == NETSSL_CERTREQ_REQUIRE ) { status = SSL_OptionSetDefault(SSL_REQUEST_CERTIFICATE, PR_TRUE); if (status != SECSuccess) { upslogx(LOG_ERR, "Can not enable certificate request"); nss_error("upscli_init / SSL_OptionSetDefault(SSL_REQUEST_CERTIFICATE)"); return; } } if (certrequest == NETSSL_CERTREQ_REQUIRE ) { status = SSL_OptionSetDefault(SSL_REQUIRE_CERTIFICATE, PR_TRUE); if (status != SECSuccess) { upslogx(LOG_ERR, "Can not enable certificate requirement"); nss_error("upscli_init / SSL_OptionSetDefault(SSL_REQUIRE_CERTIFICATE)"); return; } } #endif /* WITH_CLIENT_CERTIFICATE_VALIDATION */ cert = PK11_FindCertFromNickname(certname, NULL); if(cert==NULL) { upslogx(LOG_ERR, "Can not find server certificate"); nss_error("upscli_init / PK11_FindCertFromNickname"); return; } privKey = PK11_FindKeyByAnyCert(cert, NULL); if(privKey==NULL){ upslogx(LOG_ERR, "Can not find private key associate to server certificate"); nss_error("upscli_init / PK11_FindKeyByAnyCert"); return; } ssl_initialized = 1; #else /* WITH_OPENSSL | WITH_NSS */ upslogx(LOG_ERR, "ssl_init called but SSL wasn't compiled in"); #endif /* WITH_OPENSSL | WITH_NSS */ } #if (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_PUSH_POP_BESIDEFUNC) && ( (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_TYPE_LIMITS_BESIDEFUNC) || (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_TAUTOLOGICAL_CONSTANT_OUT_OF_RANGE_COMPARE_BESIDEFUNC) ) # pragma GCC diagnostic push #endif #ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_TYPE_LIMITS_BESIDEFUNC # pragma GCC diagnostic ignored "-Wtype-limits" #endif #ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_TAUTOLOGICAL_CONSTANT_OUT_OF_RANGE_COMPARE_BESIDEFUNC # pragma GCC diagnostic ignored "-Wtautological-constant-out-of-range-compare" #endif ssize_t ssl_read(nut_ctype_t *client, char *buf, size_t buflen) { ssize_t ret = -1; #ifdef WITH_OPENSSL int iret; #endif if (!client->ssl_connected) { return -1; } #ifdef WITH_OPENSSL /* SSL_* routines deal with int type for return and buflen * We might need to window our I/O if we exceed 2GB (in * 32-bit builds)... Not likely to exceed in 64-bit builds, * but smaller systems with 16-bits might be endangered :) */ assert(buflen <= INT_MAX); iret = SSL_read(client->ssl, buf, (int)buflen); assert(iret <= SSIZE_MAX); ret = (ssize_t)iret; #elif defined(WITH_NSS) /* WITH_OPENSSL */ /* PR_* routines deal in PRInt32 type * We might need to window our I/O if we exceed 2GB :) */ assert(buflen <= PR_INT32_MAX); ret = PR_Read(client->ssl, buf, (PRInt32)buflen); #endif /* WITH_OPENSSL | WITH_NSS */ if (ret < 1) { ssl_error(client->ssl, ret); return -1; } return ret; } ssize_t ssl_write(nut_ctype_t *client, const char *buf, size_t buflen) { ssize_t ret = -1; #ifdef WITH_OPENSSL int iret; #endif if (!client->ssl_connected) { return -1; } #ifdef WITH_OPENSSL /* SSL_* routines deal with int type for return and buflen * We might need to window our I/O if we exceed 2GB (in * 32-bit builds)... Not likely to exceed in 64-bit builds, * but smaller systems with 16-bits might be endangered :) */ assert(buflen <= INT_MAX); iret = SSL_write(client->ssl, buf, (int)buflen); assert(iret <= SSIZE_MAX); ret = (ssize_t)iret; #elif defined(WITH_NSS) /* WITH_OPENSSL */ /* PR_* routines deal in PRInt32 type * We might need to window our I/O if we exceed 2GB :) */ assert(buflen <= PR_INT32_MAX); ret = PR_Write(client->ssl, buf, (PRInt32)buflen); #endif /* WITH_OPENSSL | WITH_NSS */ upsdebugx(5, "ssl_write ret=%" PRIiSIZE, ret); return ret; } #if (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_PUSH_POP_BESIDEFUNC) && ( (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_TYPE_LIMITS_BESIDEFUNC) || (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_TAUTOLOGICAL_CONSTANT_OUT_OF_RANGE_COMPARE_BESIDEFUNC) ) # pragma GCC diagnostic pop #endif void ssl_finish(nut_ctype_t *client) { if (client->ssl) { #ifdef WITH_OPENSSL SSL_free(client->ssl); #elif defined(WITH_NSS) PR_Shutdown(client->ssl, PR_SHUTDOWN_BOTH); PR_Close(client->ssl); #endif /* WITH_OPENSSL | WITH_NSS */ client->ssl_connected = 0; client->ssl = NULL; } } void ssl_cleanup(void) { #ifdef WITH_OPENSSL if (ssl_ctx) { SSL_CTX_free(ssl_ctx); ssl_ctx = NULL; } #elif defined(WITH_NSS) /* WITH_OPENSSL */ CERT_DestroyCertificate(cert); SECKEY_DestroyPrivateKey(privKey); NSS_Shutdown(); PR_Cleanup(); /* Called to release memory arena used by NSS/NSPR. * Prevent to show all PL_ArenaAllocate mem alloc as leaks. * https://developer.mozilla.org/en/NSS_Memory_allocation */ PL_ArenaFinish(); #endif /* WITH_OPENSSL | WITH_NSS */ ssl_initialized = 0; } #endif /* WITH_SSL */ nut-2.8.1/server/neterr.h0000644000175000017500000000522614500336654012242 00000000000000/* neterr.h - network error definitions for NUT Copyright (C) 2003 Russell Kroll 2005 Arnaud Quette 2013 Emilien Kia 2020 Jim Klimov 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 2 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, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef NUT_NETERR_H_SEEN #define NUT_NETERR_H_SEEN 1 #ifdef __cplusplus /* *INDENT-OFF* */ extern "C" { /* *INDENT-ON* */ #endif /* network error definitions for consistency */ #define NUT_ERR_ACCESS_DENIED "ACCESS-DENIED" #define NUT_ERR_UNKNOWN_UPS "UNKNOWN-UPS" #define NUT_ERR_VAR_NOT_SUPPORTED "VAR-NOT-SUPPORTED" #define NUT_ERR_CMD_NOT_SUPPORTED "CMD-NOT-SUPPORTED" #define NUT_ERR_INVALID_ARGUMENT "INVALID-ARGUMENT" #define NUT_ERR_INSTCMD_FAILED "INSTCMD-FAILED" #define NUT_ERR_SET_FAILED "SET-FAILED" #define NUT_ERR_READONLY "READONLY" #define NUT_ERR_TOO_LONG "TOO-LONG" #define NUT_ERR_FEATURE_NOT_SUPPORTED "FEATURE-NOT-SUPPORTED" #define NUT_ERR_FEATURE_NOT_CONFIGURED "FEATURE-NOT-CONFIGURED" #define NUT_ERR_ALREADY_SSL_MODE "ALREADY-SSL-MODE" /* errors which are only used by top-level upsd functions */ #define NUT_ERR_DRIVER_NOT_CONNECTED "DRIVER-NOT-CONNECTED" #define NUT_ERR_DATA_STALE "DATA-STALE" #define NUT_ERR_ALREADY_LOGGED_IN "ALREADY-LOGGED-IN" #define NUT_ERR_INVALID_PASSWORD "INVALID-PASSWORD" #define NUT_ERR_ALREADY_SET_PASSWORD "ALREADY-SET-PASSWORD" #define NUT_ERR_INVALID_USERNAME "INVALID-USERNAME" #define NUT_ERR_ALREADY_SET_USERNAME "ALREADY-SET-USERNAME" #define NUT_ERR_USERNAME_REQUIRED "USERNAME-REQUIRED" #define NUT_ERR_PASSWORD_REQUIRED "PASSWORD-REQUIRED" #define NUT_ERR_UNKNOWN_COMMAND "UNKNOWN-COMMAND" /* errors which are only used with the old functions */ #define NUT_ERR_VAR_UNKNOWN "VAR-UNKNOWN" #define NUT_ERR_UNKNOWN_TYPE "UNKNOWN-TYPE" #define NUT_ERR_UNKNOWN_INSTCMD "UNKNOWN-INSTCMD" #define NUT_ERR_MISSING_ARGUMENT "MISSING-ARGUMENT" #define NUT_ERR_INVALID_VALUE "INVALID-VALUE" #ifdef __cplusplus /* *INDENT-OFF* */ } /* *INDENT-ON* */ #endif #endif /* NUT_NETERR_H_SEEN */ nut-2.8.1/server/upstype.h0000644000175000017500000000327514501607135012452 00000000000000/* upstype.h - internal UPS tracking structure details Copyright (C) 2003 Russell Kroll 2008 Arjen de Korte 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 2 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, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef NUT_UPSTYPE_H_SEEN #define NUT_UPSTYPE_H_SEEN 1 #include "parseconf.h" #include "common.h" #ifdef __cplusplus /* *INDENT-OFF* */ extern "C" { /* *INDENT-ON* */ #endif /* structure for the linked list of each UPS that we track */ typedef struct upstype_s { char *name; char *fn; char *desc; TYPE_FD sock_fd; #ifdef WIN32 char buf[SMALLBUF]; OVERLAPPED read_overlapped; #endif int stale; int dumpdone; int data_ok; time_t last_heard; time_t last_ping; time_t last_connfail; PCONF_CTX_t sock_ctx; struct st_tree_s *inforoot; struct cmdlist_s *cmdlist; int numlogins; int fsd; /* forced shutdown in effect? */ int retain; struct upstype_s *next; } upstype_t; extern upstype_t *firstups; #ifdef __cplusplus /* *INDENT-OFF* */ } /* *INDENT-ON* */ #endif #endif /* NUT_UPSTYPE_H_SEEN */ nut-2.8.1/server/netmisc.c0000644000175000017500000000462114501607135012372 00000000000000/* netmisc.c - miscellaneous network handlers for upsd (VER, HELP, FSD) Copyright (C) 2003 Russell Kroll 2012 Arnaud Quette 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 2 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, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "common.h" #include "upsd.h" #include "sstate.h" #include "state.h" #include "user.h" /* for user_checkaction */ #include "neterr.h" #include "netmisc.h" void net_ver(nut_ctype_t *client, size_t numarg, const char **arg) { NUT_UNUSED_VARIABLE(arg); if (numarg != 0) { send_err(client, NUT_ERR_INVALID_ARGUMENT); return; } sendback(client, "Network UPS Tools upsd %s - https://www.networkupstools.org/\n", UPS_VERSION); } void net_netver(nut_ctype_t *client, size_t numarg, const char **arg) { NUT_UNUSED_VARIABLE(arg); if (numarg != 0) { send_err(client, NUT_ERR_INVALID_ARGUMENT); return; } sendback(client, "%s\n", NUT_NETVERSION); } void net_help(nut_ctype_t *client, size_t numarg, const char **arg) { NUT_UNUSED_VARIABLE(arg); if (numarg != 0) { send_err(client, NUT_ERR_INVALID_ARGUMENT); return; } sendback(client, "Commands: HELP VER GET LIST SET INSTCMD LOGIN LOGOUT" " USERNAME PASSWORD STARTTLS\n"); } void net_fsd(nut_ctype_t *client, size_t numarg, const char **arg) { upstype_t *ups; if (numarg != 1) { send_err(client, NUT_ERR_INVALID_ARGUMENT); return; } ups = get_ups_ptr(arg[0]); if (!ups) { send_err(client, NUT_ERR_UNKNOWN_UPS); return; } /* make sure this user is allowed to do FSD */ if (!user_checkaction(client->username, client->password, "FSD")) { send_err(client, NUT_ERR_ACCESS_DENIED); return; } upslogx(LOG_INFO, "Client %s@%s set FSD on UPS [%s]", client->username, client->addr, ups->name); ups->fsd = 1; sendback(client, "OK FSD-SET\n"); } nut-2.8.1/server/netset.c0000644000175000017500000001302614500336654012235 00000000000000/* netset.c - SET handler for upsd Copyright (C) 2003 Russell Kroll 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 2 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, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "common.h" #include "upsd.h" #include "sstate.h" #include "state.h" #include "user.h" /* for user_checkaction */ #include "neterr.h" #include "netset.h" static void set_var(nut_ctype_t *client, const char *upsname, const char *var, const char *newval, const char *tracking_id) { upstype_t *ups; const char *val; const enum_t *etmp; const range_t *rtmp; char cmd[SMALLBUF], esc[SMALLBUF]; int have_tracking_id = 0; ups = get_ups_ptr(upsname); if (!ups) { send_err(client, NUT_ERR_UNKNOWN_UPS); return; } if (!ups_available(ups, client)) return; /* make sure this user is allowed to do SET */ if (!user_checkaction(client->username, client->password, "SET")) { send_err(client, NUT_ERR_ACCESS_DENIED); return; } val = sstate_getinfo(ups, var); if (!val) { send_err(client, NUT_ERR_VAR_NOT_SUPPORTED); return; } /* make sure this variable is writable (RW) */ if ((sstate_getflags(ups, var) & ST_FLAG_RW) == 0) { send_err(client, NUT_ERR_READONLY); return; } /* see if the new value is allowed for this variable */ if (sstate_getflags(ups, var) & ST_FLAG_STRING) { long aux; aux = sstate_getaux(ups, var); /* check for insanity from the driver */ if (aux < 1) { upslogx(LOG_WARNING, "UPS [%s]: auxdata for %s is invalid", ups->name, var); send_err(client, NUT_ERR_SET_FAILED); return; } /* FIXME? Should this cast to "long"? * An int-size string is quite a lot already, * even on architectures with a moderate INTMAX */ if (aux < (int) strlen(newval)) { send_err(client, NUT_ERR_TOO_LONG); return; } } /* see if it's enumerated */ etmp = sstate_getenumlist(ups, var); if (etmp) { int found = 0; while (etmp) { if (!strcmp(etmp->val, newval)) { found = 1; break; } etmp = etmp->next; } if (!found) { send_err(client, NUT_ERR_INVALID_VALUE); return; } } /* or if it's within a range */ rtmp = sstate_getrangelist(ups, var); if (rtmp) { int found = 0; int inewval = atoi(newval); while (rtmp) { if ((inewval >= rtmp->min) && (inewval <= rtmp->max)) { found = 1; break; } rtmp = rtmp->next; } if (!found) { send_err(client, NUT_ERR_INVALID_VALUE); return; } } /* must be OK now */ snprintf(cmd, sizeof(cmd), "SET %s \"%s\"", var, pconf_encode(newval, esc, sizeof(esc))); /* see if the user want execution tracking for this command */ if (tracking_id && *tracking_id) { snprintfcat(cmd, sizeof(cmd), " TRACKING %s", tracking_id); /* Add an entry in the tracking structure */ tracking_add(tracking_id); have_tracking_id = 1; } /* add EOL */ snprintfcat(cmd, sizeof(cmd), "\n"); upslogx(LOG_INFO, "Set variable: %s@%s set %s on %s to %s (tracking ID: %s)", client->username, client->addr, var, ups->name, newval, (have_tracking_id) ? tracking_id : "disabled"); if (!sstate_sendline(ups, cmd)) { upslogx(LOG_INFO, "Set command send failed"); send_err(client, NUT_ERR_SET_FAILED); return; } /* return the result, possibly including tracking_id */ if (have_tracking_id) sendback(client, "OK TRACKING %s\n", tracking_id); else sendback(client, "OK\n"); } void net_set(nut_ctype_t *client, size_t numarg, const char **arg) { char tracking_id[UUID4_LEN] = ""; /* Base verification, to ensure that we have at least the SET parameter */ if (numarg < 2) { send_err(client, NUT_ERR_INVALID_ARGUMENT); return; } /* SET VAR UPS VARNAME VALUE */ if (!strcasecmp(arg[0], "VAR")) { if (numarg < 4) { send_err(client, NUT_ERR_INVALID_ARGUMENT); return; } if (client->tracking) { /* Generate a tracking ID, if client requested status tracking */ nut_uuid_v4(tracking_id); } set_var(client, arg[1], arg[2], arg[3], tracking_id); return; } /* SET TRACKING VALUE */ if (!strcasecmp(arg[0], "TRACKING")) { if (!strcasecmp(arg[1], "ON")) { /* general enablement along with for this client */ client->tracking = tracking_enable(); } else if (!strcasecmp(arg[1], "OFF")) { /* disable status tracking for this client first */ client->tracking = 0; /* then only disable the general one if no other clients use it! * Note: don't call tracking_free() since we want info to * persist, and tracking_cleanup() takes care of cleaning */ if (tracking_disable()) { upsdebugx(2, "%s: TRACKING disabled for one client, more remain.", __func__); } else { upsdebugx(2, "%s: TRACKING disabled for last client.", __func__); } } else { send_err(client, NUT_ERR_INVALID_ARGUMENT); return; } upsdebugx(1, "%s: TRACKING general %s, client %s.", __func__, tracking_is_enabled() ? "enabled" : "disabled", client->tracking ? "enabled" : "disabled"); sendback(client, "OK\n"); return; } send_err(client, NUT_ERR_INVALID_ARGUMENT); return; } nut-2.8.1/server/Makefile.am0000644000175000017500000000302314501607135012613 00000000000000# Network UPS Tools: server # Make sure out-of-dir dependencies exist (especially when dev-building parts): $(top_builddir)/common/libcommon.la \ $(top_builddir)/common/libparseconf.la: dummy @cd $(@D) && $(MAKE) $(AM_MAKEFLAGS) $(@F) # Avoid per-target CFLAGS, because this will prevent re-use of object # files. In any case, CFLAGS are only -I options, so there is no harm, # but only add them if we really use the target. AM_CFLAGS = -I$(top_srcdir)/include if WITH_WRAP AM_CFLAGS += $(LIBWRAP_CFLAGS) endif if WITH_SSL AM_CFLAGS += $(LIBSSL_CFLAGS) endif LDADD = $(top_builddir)/common/libcommon.la $(top_builddir)/common/libparseconf.la $(NETLIBS) if WITH_WRAP LDADD += $(LIBWRAP_LIBS) endif if WITH_SSL LDADD += $(LIBSSL_LIBS) endif sbin_PROGRAMS = upsd EXTRA_PROGRAMS = sockdebug upsd_SOURCES = upsd.c user.c conf.c netssl.c sstate.c desc.c \ netget.c netmisc.c netlist.c netuser.c netset.c netinstcmd.c \ conf.h nut_ctype.h desc.h netcmds.h neterr.h netget.h netinstcmd.h \ netlist.h netmisc.h netset.h netuser.h netssl.h sstate.h stype.h upsd.h \ upstype.h user-data.h user.h if HAVE_WINDOWS sockdebug_SOURCES = pipedebug.c else !HAVE_WINDOWS sockdebug_SOURCES = sockdebug.c endif !HAVE_WINDOWS if WITH_DEV # Have it installed properly libexec_PROGRAMS = sockdebug endif dummy: MAINTAINERCLEANFILES = Makefile.in .dirstamp # NOTE: Do not clean ".deps" in SUBDIRS of the main project, # the root Makefile.am takes care of that! clean-local: $(AM_V_at)rm -rf $(EXTRA_PROGRAMS) # $(AM_V_at)rm -rf $(builddir)/.deps nut-2.8.1/server/nut_ctype.h0000644000175000017500000000363314501607135012751 00000000000000/* nut_ctype.h - client data definitions for upsd Copyright (C) 2002 Russell Kroll 2008 Arjen de Korte 2011 Arnaud Quette 2013 Emilien Kia 2020 Jim Klimov 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 2 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, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef NUT_CTYPE_H_SEEN #define NUT_CTYPE_H_SEEN 1 /* Mozilla NSS */ #ifdef WITH_NSS #include #include #endif /* OpenSSL */ #ifdef WITH_OPENSSL #include #include #endif #include "parseconf.h" #ifdef __cplusplus /* *INDENT-OFF* */ extern "C" { /* *INDENT-ON* */ #endif /* client structure */ typedef struct nut_ctype_s { char *addr; TYPE_FD_SOCK sock_fd; time_t last_heard; char *loginups; char *password; char *username; /* per client status info for commands and settings * (disabled by default) */ int tracking; #ifdef WITH_OPENSSL SSL *ssl; #elif defined(WITH_NSS) PRFileDesc *ssl; #else void *ssl; #endif int ssl_connected; PCONF_CTX_t ctx; /* doubly linked list */ struct nut_ctype_s *prev; struct nut_ctype_s *next; #ifdef WIN32 HANDLE Event; #endif } nut_ctype_t; #ifdef __cplusplus /* *INDENT-OFF* */ } /* *INDENT-ON* */ #endif #endif /* NUT_CTYPE_H_SEEN */ nut-2.8.1/server/netmisc.h0000644000175000017500000000277114500336654012407 00000000000000/* netmisc.h - miscellaneous network handlers for upsd (VER, HELP, FSD) Copyright (C) 2003 Russell Kroll 2007 Peter Selinger 2012 Arnaud Quette 2013 Emilien Kia 2020 Jim Klimov 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 2 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, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef NUT_NETMISC_H_SEEN #define NUT_NETMISC_H_SEEN 1 #ifdef __cplusplus /* *INDENT-OFF* */ extern "C" { /* *INDENT-ON* */ #endif void net_ver(nut_ctype_t *client, size_t numarg, const char **arg); void net_netver(nut_ctype_t *client, size_t numarg, const char **arg); void net_help(nut_ctype_t *client, size_t numarg, const char **arg); void net_fsd(nut_ctype_t *client, size_t numarg, const char **arg); #ifdef __cplusplus /* *INDENT-OFF* */ } /* *INDENT-ON* */ #endif #endif /* NUT_NETMISC_H_SEEN */ nut-2.8.1/server/user.h0000644000175000017500000000305514500336654011717 00000000000000/* user.c - supporting elements of user handling functions for upsd Copyright (C) 2001 Russell Kroll 2005 Arnaud Quette 2007 Peter Selinger 2008 Arjen de Korte 2013 Emilien Kia 2020 Jim Klimov 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 2 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, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef NUT_USER_H_SEEN #define NUT_USER_H_SEEN 1 #ifdef __cplusplus /* *INDENT-OFF* */ extern "C" { /* *INDENT-ON* */ #endif void user_load(void); int user_checkinstcmd(const char *un, const char *pw, const char *cmd); int user_checkaction(const char *un, const char *pw, const char *action); void user_flush(void); /* cheat - we don't want the full upsd.h included here */ void check_perms(const char *fn); #ifdef __cplusplus /* *INDENT-OFF* */ } /* *INDENT-ON* */ #endif #endif /* NUT_USER_H_SEEN */ nut-2.8.1/server/desc.c0000644000175000017500000000606314500336654011654 00000000000000/* desc.c - variable/command description handling for upsd Copyright (C) 2003 Russell Kroll 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 2 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, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "config.h" /* must be the first header */ #include #include "common.h" #include "parseconf.h" #include "desc.h" extern const char *datapath; typedef struct dlist_s { char *name; char *desc; struct dlist_s *next; } dlist_t; static dlist_t *cmd_list = NULL, *var_list = NULL; static void list_free(dlist_t *ptr) { dlist_t *next; while (ptr) { next = ptr->next; free(ptr->name); free(ptr->desc); free(ptr); ptr = next; } } static const char *list_get(const dlist_t *list, const char *name) { const dlist_t *temp; for (temp = list; temp != NULL; temp = temp->next) { if (!strcasecmp(temp->name, name)) { return temp->desc; } } return NULL; } static void desc_add(dlist_t **list, const char *name, const char *desc) { dlist_t *temp; for (temp = *list; temp != NULL; temp = temp->next) { if (!strcasecmp(temp->name, name)) { break; } } if (temp == NULL) { temp = xcalloc(1, sizeof(*temp)); temp->name = xstrdup(name); temp->next = *list; *list = temp; } free(temp->desc); temp->desc = xstrdup(desc); } static void desc_file_err(const char *errmsg) { upslogx(LOG_ERR, "Fatal error in parseconf (cmdvartab): %s", errmsg); } /* interface */ void desc_load(void) { char fn[SMALLBUF]; PCONF_CTX_t ctx; snprintf(fn, sizeof(fn), "%s/cmdvartab", datapath); pconf_init(&ctx, desc_file_err); /* this file is not required */ if (!pconf_file_begin(&ctx, fn)) { upslogx(LOG_INFO, "%s not found - disabling descriptions", fn); pconf_finish(&ctx); return; } while (pconf_file_next(&ctx)) { if (pconf_parse_error(&ctx)) { upslogx(LOG_ERR, "Parse error: %s:%d: %s", fn, ctx.linenum, ctx.errmsg); continue; } if (ctx.numargs < 3) { continue; } if (!strcmp(ctx.arglist[0], "CMDDESC")) { desc_add(&cmd_list, ctx.arglist[1], ctx.arglist[2]); continue; } if (!strcmp(ctx.arglist[0], "VARDESC")) { desc_add(&var_list, ctx.arglist[1], ctx.arglist[2]); continue; } /* unknown */ } pconf_finish(&ctx); } void desc_free(void) { list_free(cmd_list); list_free(var_list); cmd_list = var_list = NULL; } const char *desc_get_cmd(const char *name) { return list_get(cmd_list, name); } const char *desc_get_var(const char *name) { return list_get(var_list, name); } nut-2.8.1/server/netcmds.h0000644000175000017500000000453314500336654012400 00000000000000/* netcmds.h - upsd support structure details Copyright (C) 2001 Russell Kroll 2005 Arnaud Quette 2007 Peter Selinger 2010 Arjen de Korte 2012 Emilien Kia 2020 Jim Klimov 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 2 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, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef NUT_NETCMDS_H_SEEN #define NUT_NETCMDS_H_SEEN 1 #include "nut_ctype.h" #include "netssl.h" #include "netget.h" #include "netset.h" #include "netlist.h" #include "netmisc.h" #include "netuser.h" #include "netinstcmd.h" #define FLAG_USER 0x0001 /* username and password must be set */ #ifdef __cplusplus /* *INDENT-OFF* */ extern "C" { /* *INDENT-ON* */ #endif static struct { const char *name; void (*func)(nut_ctype_t *client, size_t numargs, const char **arg); int flags; } netcmds[] = { { "VER", net_ver, 0 }, { "NETVER", net_netver, 0 }, { "PROTVER", net_netver, 0 }, /* aliased since NUT 2.8.0 */ { "HELP", net_help, 0 }, { "STARTTLS", net_starttls, 0 }, { "GET", net_get, 0 }, { "LIST", net_list, 0 }, { "USERNAME", net_username, 0 }, { "PASSWORD", net_password, 0 }, { "LOGIN", net_login, FLAG_USER }, { "LOGOUT", net_logout, 0 }, /* NOTE: Protocol in NUT 2.8.0 allows to handle * master/primary to rename/alias the routine. */ { "PRIMARY", net_primary, FLAG_USER }, { "MASTER", net_master, FLAG_USER }, { "FSD", net_fsd, FLAG_USER }, { "SET", net_set, FLAG_USER }, { "INSTCMD", net_instcmd, FLAG_USER }, { NULL, (void(*)(struct nut_ctype_s *, size_t, const char **))(NULL), 0 } }; #ifdef __cplusplus /* *INDENT-OFF* */ } /* *INDENT-ON* */ #endif #endif /* NUT_NETCMDS_H_SEEN */ nut-2.8.1/server/conf.h0000644000175000017500000000321414501607135011657 00000000000000/* conf.h - supporting elements of conf parsing functions for upsd Copyright (C) 2001 Russell Kroll 2008 Arjen de Korte 2020 Jim Klimov 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 2 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, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef NUT_CONF_H_SEEN #define NUT_CONF_H_SEEN 1 #ifdef __cplusplus /* *INDENT-OFF* */ extern "C" { /* *INDENT-ON* */ #endif /* read upsd.conf */ void load_upsdconf(int reloading); /* add valid UPSes from ups.conf to the internal structures */ void upsconf_add(int reloading); /* flush existing config, then reread everything */ void conf_reload(void); typedef struct ups_s { char *upsname; char *driver; char *port; char *desc; struct ups_s *next; } ups_t; /* used for really clean shutdowns */ void delete_acls(void); void delete_access(void); extern int num_ups; extern int nut_debug_level_global; extern int nut_debug_level_args; #ifdef __cplusplus /* *INDENT-OFF* */ } /* *INDENT-ON* */ #endif #endif /* NUT_CONF_H_SEEN */ nut-2.8.1/scripts/0000755000175000017500000000000014520277777011042 500000000000000nut-2.8.1/scripts/Solaris8/0000755000175000017500000000000014520277776012545 500000000000000nut-2.8.1/scripts/Solaris8/S99upsmon0000755000175000017500000000140014517562211014217 00000000000000#! /bin/sh # Copyright (c) 1995-2000 ??? # # Author: Sandro Wefel # # Put it in /etc/rc2.d/ or /etc/rc3.d depending on runlevel # PATH=/sbin:/bin:/usr/sbin:/usr/bin export PATH UPSDPATH=/usr/local/ups/sbin NUT_QUIET_INIT_UPSNOTIFY=true export NUT_QUIET_INIT_UPSNOTIFY # See how we are called. case "$1" in 'start') if [ -x $UPSDPATH/upsmon ]; then echo "NUT Starting UPS monitor " $UPSDPATH/upsmon >/dev/console 2>&1 touch /var/lock/subsys/upsmon fi ;; 'stop') echo "NUT Stopping UPS monitor " /usr/bin/pkill -x upsmon rm -f /var/lock/subsys/upsmon ;; 'restart') $0 stop $0 start ;; *) echo "Usage: upsmon {start|stop|restart}" exit 1 ;; esac exit 0 nut-2.8.1/scripts/systemd/0000755000175000017500000000000014520277777012532 500000000000000nut-2.8.1/scripts/systemd/nut-driver@.service.in0000644000175000017500000001120514510262764016624 00000000000000# Network UPS Tools (NUT) systemd integration # Copyright (C) 2011-2023 by NUT contirbutors # Distributed under the terms of GPLv2+ # See https://networkupstools.org/ # and https://github.com/networkupstools/nut/ [Unit] Description=Network UPS Tools - device driver for %I After=local-fs.target # Note: If the "Before" line below is uncommented, the target unit # would only become initialized after the driver units are all in # a final state (active, failed, ...) and would allow nut-server # (upsd) to start up and represent those devices on the network. # With this constraint commented away, the nut-server should start # earlier, but may initially report some devices as Not connected # (they should appear when drivers complete their initialization - # e.g. snmp walks of large MIBs can take a while): #Before=nut-driver.target # Propagate stopping of the target: PartOf=nut-driver.target # Note: The choice of "network.target" allows to schedule this unit # roughly when the network stack of this OS is ready (e.g. that the # subsequent `upsd` will have a `0.0.0.0` or a `localhost` to bind # to); however this target does not ensure availability of a real # connection or final IP addresses. Drivers that require network as # a media for interaction with UPSes (snmp-ups, netxml-ups, ipmi etc.) # may want to extend this unit with `Requires=network-online.target` # instead. Also note that *generally* this should not be a problem, # since the drivers have a few retries with timeouts during startup, # and typically by the time the box gets an IP address, the driver # is still retrying to start and will succeed. # Extending the unit does not require *this* file to be edited, you # can instead drop in an additional piece of configuration, e.g. to # require that a NUT driver only starts after external networking # is configured (usable IP addresses appear in the system) you can # add a `/etc/systemd/system/nut-driver@.service.d/network.conf` with: # [Unit] # Requires=network-online.target # After=network-online.target # If your `upsd` requires specific IP addresses to be available before # starting, a `/etc/systemd/system/nut-driver.target.d/network.conf` # can be used in a similar manner. # Finally note that "nut-driver-enumerator.service" should take care of this. [Service] Environment=NUT_IGNORE_NOWAIT=true EnvironmentFile=-@CONFPATH@/nut.conf SyslogIdentifier=%N ExecStartPre=-@SYSTEMD_TMPFILES_PROGRAM@ --create @systemdtmpfilesdir@/nut-common-tmpfiles.conf ExecStart=/bin/sh -c 'NUTDEV="`@NUT_LIBEXECDIR@/nut-driver-enumerator.sh --get-device-for-service %i`" && [ -n "$NUTDEV" ] || { echo "FATAL: Could not find a NUT device section for service unit %i" >&2 ; exit 1 ; } ; exec @SBINDIR@/upsdrvctl @SYSTEMD_DAEMON_ARGS_DRIVER@ start "$NUTDEV"' # SIGHUP: simple reload (ignore values we can not change on the fly) # SIGUSR1: reload-or-exit (let systemd resuscitate the service then) ExecReload=/bin/kill -USR1 $MAINPID ExecStop=/bin/sh -c 'NUTDEV="`@NUT_LIBEXECDIR@/nut-driver-enumerator.sh --get-device-for-service %i`" && [ -n "$NUTDEV" ] || { echo "FATAL: Could not find a NUT device section for service unit %i" >&2 ; exit 1 ; } ; @SBINDIR@/upsdrvctl stop "$NUTDEV"' # Restart really always, do not stop trying: StartLimitInterval=0 Restart=always # Protract the "hold-off" interval, so if the device connection is # lost, the driver does not rapidly restart and fail too many times, # and then systemd would keep the unit failed without further retries. # Notably, this helps start "dummy-ups" drivers retranslating local # devices (so getting a chicken-and-egg problem for driver-upsd-driver # orderly series of initializations). More details in NUT issue #779. RestartSec=15s Type=@SYSTEMD_DAEMON_TYPE_DRIVER@ @SYSTEMD_DAEMON_NOTIFYACCESS_DRIVER@ # Note: if you set up with systemd notification support, you can take # advantage of watchdog mechanism. Timeouts involved are deployment # dependent (how many devices you monitor, how stressed are they and # the monitoring system, protocol used -- e.g. SNMP walks can take long), # so distributions should not pre-define this (at least not to a small # value): @SYSTEMD_DAEMON_WATCHDOG_DRIVER@ # Note: If you customize the "maxstartdelay" in ups.conf or in your # NUT compilation defaults, so it exceeds the default systemd unit # startup timeout (typically 90 sec), then make sure to set a slightly # longer systemd timeout for the nut-driver unit instances. You can # do this by populating a drop-in configuration, so it is not later # overwritten by updates to your NUT package -- create a dir+file: # /etc/systemd/system/nut-driver@.service.d/timeout.conf with lines: # [Service] # TimeoutStartSec=190s [Install] WantedBy=nut-driver.target nut-2.8.1/scripts/systemd/nut-monitor.service.in0000644000175000017500000000365014510262764016725 00000000000000# Network UPS Tools (NUT) systemd integration # Copyright (C) 2011-2023 by NUT contirbutors # Distributed under the terms of GPLv2+ # See https://networkupstools.org/ # and https://github.com/networkupstools/nut/ [Unit] Description=Network UPS Tools - power device monitor and shutdown controller # Note: do not mistake this historic misnomer for "NUT-Monitor" Python GUI client After=local-fs.target network.target nut-server.service # Note: We do not specify Requires nut-server.service because # the `upsd` daemon(s) may be running on a different machine # (connected to the UPSes) than the `upsmon` shutdown protector. # The "Wants" directive would try to start the nut-server but # would not abort if that attempt fails for whatever reason. Wants=nut-server.service # Extending the unit does not require *this* file to be edited, you # can instead drop in an additional piece of configuration, e.g. to # require the monitoring client to only start after external networking # is configured (usable IP addresses appear in the system) you can # add a `/etc/systemd/system/nut-monitor.service.d/network.conf` with: # [Unit] # Requires=network-online.target # After=network-online.target PartOf=nut.target [Service] EnvironmentFile=-@CONFPATH@/nut.conf SyslogIdentifier=%N ExecStartPre=-@SYSTEMD_TMPFILES_PROGRAM@ --create @systemdtmpfilesdir@/nut-common-tmpfiles.conf ExecStart=@SBINDIR@/upsmon @SYSTEMD_DAEMON_ARGS_UPSMON@ ExecReload=@SBINDIR@/upsmon -c reload PIDFile=@PIDPATH@/upsmon.pid # If "-FF" or background-daemon mode is used, so that PID file exists # and "upsmon -c stop" in particular can be used from command-line or # legacy scripts, it causes a clean and intentional exit of the daemon. # Then systemd should not revive it - hence restart it only on failure: Restart=on-failure Type=@SYSTEMD_DAEMON_TYPE_UPSMON@ @SYSTEMD_DAEMON_WATCHDOG_UPSMON@ @SYSTEMD_DAEMON_NOTIFYACCESS_UPSMON@ [Install] WantedBy=nut.target Alias=upsmon.service nut-2.8.1/scripts/systemd/nut.target0000644000175000017500000000106114510262764014453 00000000000000# Network UPS Tools (NUT) systemd integration # Copyright (C) 2011-2023 by NUT contirbutors # Distributed under the terms of GPLv2+ # See https://networkupstools.org/ # and https://github.com/networkupstools/nut/ [Unit] Description=Network UPS Tools - target for power device drivers, data server and monitoring client (if enabled) on this system After=local-fs.target nut-driver.target nut-server.service nut-monitor.service Wants=local-fs.target nut-driver.target nut-server.service nut-monitor.service # network.target [Install] WantedBy=multi-user.target nut-2.8.1/scripts/systemd/nut-driver-enumerator.path.in0000644000175000017500000000055414510262764020204 00000000000000# Trigger restart of nut-driver-enumerator.service whenever ups.conf is edited # Network UPS Tools (NUT) systemd integration # Copyright (C) 2011-2023 by NUT contirbutors # Distributed under the terms of GPLv2+ # See https://networkupstools.org/ # and https://github.com/networkupstools/nut/ [Path] PathModified=@CONFPATH@/ups.conf [Install] WantedBy=nut.target nut-2.8.1/scripts/systemd/nut-common-tmpfiles.conf.in0000644000175000017500000000106014520275017017621 00000000000000# Network UPS Tools (NUT) systemd integration # Distributed under the terms of GPLv2+ # See https://networkupstools.org/ # and https://github.com/networkupstools/nut/ # See also: https://github.com/networkupstools/nut/wiki/Technicalities:-Work-with-PID-and-state-file-paths#pidpath-altpidpath-statepath # State file (e.g. upsd to driver pipes) and PID file location for NUT: d @STATEPATH@ 0770 @RUN_AS_USER@ @RUN_AS_GROUP@ - - # Default PIPEFN and LOCKFN locations per upssched.conf: d @STATEPATH@/upssched 0770 @RUN_AS_USER@ @RUN_AS_GROUP@ - - X @STATEPATH@ nut-2.8.1/scripts/systemd/Makefile.in0000644000175000017500000007265114520274662014520 00000000000000# Makefile.in generated by automake 1.16.5 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2021 Free Software Foundation, Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. @SET_MAKE@ VPATH = @srcdir@ am__is_gnu_make = { \ if test -z '$(MAKELEVEL)'; then \ false; \ elif test -n '$(MAKE_HOST)'; then \ true; \ elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \ true; \ else \ false; \ fi; \ } am__make_running_with_option = \ case $${target_option-} in \ ?) ;; \ *) echo "am__make_running_with_option: internal error: invalid" \ "target option '$${target_option-}' specified" >&2; \ exit 1;; \ esac; \ has_opt=no; \ sane_makeflags=$$MAKEFLAGS; \ if $(am__is_gnu_make); then \ sane_makeflags=$$MFLAGS; \ else \ case $$MAKEFLAGS in \ *\\[\ \ ]*) \ bs=\\; \ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ esac; \ fi; \ skip_next=no; \ strip_trailopt () \ { \ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ }; \ for flg in $$sane_makeflags; do \ test $$skip_next = yes && { skip_next=no; continue; }; \ case $$flg in \ *=*|--*) continue;; \ -*I) strip_trailopt 'I'; skip_next=yes;; \ -*I?*) strip_trailopt 'I';; \ -*O) strip_trailopt 'O'; skip_next=yes;; \ -*O?*) strip_trailopt 'O';; \ -*l) strip_trailopt 'l'; skip_next=yes;; \ -*l?*) strip_trailopt 'l';; \ -[dEDm]) skip_next=yes;; \ -[JT]) skip_next=yes;; \ esac; \ case $$flg in \ *$$target_option*) has_opt=yes; break;; \ esac; \ done; \ test $$has_opt = yes am__make_dryrun = (target_option=n; $(am__make_running_with_option)) am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkglibexecdir = $(libexecdir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ target_triplet = @target@ @HAVE_SYSTEMD_TRUE@am__append_1 = nut-driver.target nut.target @HAVE_SYSTEMD_FALSE@am__append_2 = \ @HAVE_SYSTEMD_FALSE@ nut-driver@.service.in nut-monitor.service.in \ @HAVE_SYSTEMD_FALSE@ nut-server.service.in nutshutdown.in nut-driver.target nut.target \ @HAVE_SYSTEMD_FALSE@ nut-driver-enumerator.path.in nut-driver-enumerator.service.in subdir = scripts/systemd ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/m4/ax_c___attribute__.m4 \ $(top_srcdir)/m4/ax_c_pragmas.m4 \ $(top_srcdir)/m4/ax_check_compile_flag.m4 \ $(top_srcdir)/m4/ax_compare_version.m4 \ $(top_srcdir)/m4/ax_realpath.m4 \ $(top_srcdir)/m4/ax_run_or_link_ifelse.m4 \ $(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \ $(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \ $(top_srcdir)/m4/lt~obsolete.m4 \ $(top_srcdir)/m4/nut_arg_with.m4 \ $(top_srcdir)/m4/nut_check_asciidoc.m4 \ $(top_srcdir)/m4/nut_check_aspell.m4 \ $(top_srcdir)/m4/nut_check_cppcheck.m4 \ $(top_srcdir)/m4/nut_check_headers_windows.m4 \ $(top_srcdir)/m4/nut_check_libavahi.m4 \ $(top_srcdir)/m4/nut_check_libfreeipmi.m4 \ $(top_srcdir)/m4/nut_check_libgd.m4 \ $(top_srcdir)/m4/nut_check_libgpiod.m4 \ $(top_srcdir)/m4/nut_check_libltdl.m4 \ $(top_srcdir)/m4/nut_check_libmodbus.m4 \ $(top_srcdir)/m4/nut_check_libneon.m4 \ $(top_srcdir)/m4/nut_check_libnetsnmp.m4 \ $(top_srcdir)/m4/nut_check_libnss.m4 \ $(top_srcdir)/m4/nut_check_libopenssl.m4 \ $(top_srcdir)/m4/nut_check_libpowerman.m4 \ $(top_srcdir)/m4/nut_check_libregex.m4 \ $(top_srcdir)/m4/nut_check_libsystemd.m4 \ $(top_srcdir)/m4/nut_check_libusb.m4 \ $(top_srcdir)/m4/nut_check_libwrap.m4 \ $(top_srcdir)/m4/nut_check_os.m4 \ $(top_srcdir)/m4/nut_check_pkgconfig.m4 \ $(top_srcdir)/m4/nut_check_python.m4 \ $(top_srcdir)/m4/nut_check_socketlib.m4 \ $(top_srcdir)/m4/nut_compiler_family.m4 \ $(top_srcdir)/m4/nut_func_getnameinfo_argtypes.m4 \ $(top_srcdir)/m4/nut_report_feature.m4 \ $(top_srcdir)/m4/nut_stash_warnings.m4 \ $(top_srcdir)/m4/nut_type_socklen_t.m4 \ $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/include/config.h CONFIG_CLEAN_FILES = nut-common-tmpfiles.conf nut-driver@.service \ nut-monitor.service nut-server.service \ nut-driver-enumerator.service nut-driver-enumerator.path \ nutshutdown CONFIG_CLEAN_VPATH_FILES = am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; am__vpath_adj = case $$p in \ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ *) f=$$p;; \ esac; am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`; am__install_max = 40 am__nobase_strip_setup = \ srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'` am__nobase_strip = \ for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||" am__nobase_list = $(am__nobase_strip_setup); \ for p in $$list; do echo "$$p $$p"; done | \ sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \ $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \ if (++n[$$2] == $(am__install_max)) \ { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \ END { for (dir in files) print dir, files[dir] }' am__base_list = \ sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' am__uninstall_files_from_dir = { \ test -z "$$files" \ || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \ || { echo " ( cd '$$dir' && rm -f" $$files ")"; \ $(am__cd) "$$dir" && rm -f $$files; }; \ } am__installdirs = "$(DESTDIR)$(libexecdir)" "$(DESTDIR)$(sbindir)" \ "$(DESTDIR)$(systemdshutdowndir)" \ "$(DESTDIR)$(systemdsystemunitdir)" \ "$(DESTDIR)$(systemdtmpfilesdir)" SCRIPTS = $(libexec_SCRIPTS) $(sbin_SCRIPTS) \ $(systemdshutdown_SCRIPTS) AM_V_P = $(am__v_P_@AM_V@) am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) am__v_P_0 = false am__v_P_1 = : AM_V_GEN = $(am__v_GEN_@AM_V@) am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) am__v_GEN_0 = @echo " GEN " $@; am__v_GEN_1 = AM_V_at = $(am__v_at_@AM_V@) am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) am__v_at_0 = @ am__v_at_1 = SOURCES = DIST_SOURCES = am__can_run_installinfo = \ case $$AM_UPDATE_INFO_DIR in \ n|no|NO) false;; \ *) (install-info --version) >/dev/null 2>&1;; \ esac DATA = $(systemdsystemunit_DATA) $(systemdtmpfiles_DATA) am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) am__DIST_COMMON = $(srcdir)/Makefile.in \ $(srcdir)/nut-common-tmpfiles.conf.in \ $(srcdir)/nut-driver-enumerator.path.in \ $(srcdir)/nut-driver-enumerator.service.in \ $(srcdir)/nut-driver@.service.in \ $(srcdir)/nut-monitor.service.in \ $(srcdir)/nut-server.service.in $(srcdir)/nutshutdown.in \ README DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) A2X = @A2X@ ACLOCAL = @ACLOCAL@ ALTPIDPATH = @ALTPIDPATH@ AMTAR = @AMTAR@ AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ AR = @AR@ ASCIIDOC = @ASCIIDOC@ ASPELL = @ASPELL@ ASPELL_FILTER_LIB_PATH = @ASPELL_FILTER_LIB_PATH@ ASPELL_FILTER_SHARE_PATH = @ASPELL_FILTER_SHARE_PATH@ ASPELL_FILTER_TEX_PATH = @ASPELL_FILTER_TEX_PATH@ AUGPARSE = @AUGPARSE@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ BINDIR = @BINDIR@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CONFIG_FLAGS = @CONFIG_FLAGS@ CONFPATH = @CONFPATH@ CPP = @CPP@ CPPCHECK = @CPPCHECK@ CPPFLAGS = @CPPFLAGS@ CPPUNIT_CFLAGS = @CPPUNIT_CFLAGS@ CPPUNIT_LIBS = @CPPUNIT_LIBS@ CSCOPE = @CSCOPE@ CTAGS = @CTAGS@ CXX = @CXX@ CXXCPP = @CXXCPP@ CXXDEPMODE = @CXXDEPMODE@ CXXFLAGS = @CXXFLAGS@ CYGPATH_W = @CYGPATH_W@ DBLATEX = @DBLATEX@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ DEPLOYED_UPSC = @DEPLOYED_UPSC@ DEPLOYED_UPSD = @DEPLOYED_UPSD@ DLLTOOL = @DLLTOOL@ DOC_BUILD_LIST = @DOC_BUILD_LIST@ DOC_CHECK_LIST = @DOC_CHECK_LIST@ DRIVER_BUILD_LIST = @DRIVER_BUILD_LIST@ DRIVER_INSTALL_TARGET = @DRIVER_INSTALL_TARGET@ DRIVER_MAN_LIST = @DRIVER_MAN_LIST@ DRIVER_MAN_LIST_PAGES = @DRIVER_MAN_LIST_PAGES@ DRVPATH = @DRVPATH@ DSYMUTIL = @DSYMUTIL@ DUMPBIN = @DUMPBIN@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ ETAGS = @ETAGS@ EXEEXT = @EXEEXT@ FGREP = @FGREP@ FORCE_NUT_VERSION = @FORCE_NUT_VERSION@ GDLIB_CONFIG = @GDLIB_CONFIG@ GREP = @GREP@ HAVE_SYS_SOCKET_H = @HAVE_SYS_SOCKET_H@ HAVE_WINSOCK2_H = @HAVE_WINSOCK2_H@ HAVE_WS2TCPIP_H = @HAVE_WS2TCPIP_H@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ LD = @LD@ LDFLAGS = @LDFLAGS@ LIBAVAHI_CFLAGS = @LIBAVAHI_CFLAGS@ LIBAVAHI_LIBS = @LIBAVAHI_LIBS@ LIBDIR = @LIBDIR@ LIBGD_CFLAGS = @LIBGD_CFLAGS@ LIBGD_LDFLAGS = @LIBGD_LDFLAGS@ LIBGPIO_CFLAGS = @LIBGPIO_CFLAGS@ LIBGPIO_LIBS = @LIBGPIO_LIBS@ LIBI2C_LIBS = @LIBI2C_LIBS@ LIBIPMI_CFLAGS = @LIBIPMI_CFLAGS@ LIBIPMI_LIBS = @LIBIPMI_LIBS@ LIBLTDL_CFLAGS = @LIBLTDL_CFLAGS@ LIBLTDL_LIBS = @LIBLTDL_LIBS@ LIBMODBUS_CFLAGS = @LIBMODBUS_CFLAGS@ LIBMODBUS_LIBS = @LIBMODBUS_LIBS@ LIBNEON_CFLAGS = @LIBNEON_CFLAGS@ LIBNEON_LIBS = @LIBNEON_LIBS@ LIBNETSNMP_CFLAGS = @LIBNETSNMP_CFLAGS@ LIBNETSNMP_LIBS = @LIBNETSNMP_LIBS@ LIBOBJS = @LIBOBJS@ LIBPOWERMAN_CFLAGS = @LIBPOWERMAN_CFLAGS@ LIBPOWERMAN_LIBS = @LIBPOWERMAN_LIBS@ LIBREGEX_LIBS = @LIBREGEX_LIBS@ LIBS = @LIBS@ LIBSSL_CFLAGS = @LIBSSL_CFLAGS@ LIBSSL_LIBS = @LIBSSL_LIBS@ LIBSSL_REQUIRES = @LIBSSL_REQUIRES@ LIBSYSTEMD_CFLAGS = @LIBSYSTEMD_CFLAGS@ LIBSYSTEMD_LIBS = @LIBSYSTEMD_LIBS@ LIBTOOL = @LIBTOOL@ LIBTOOL_DEPS = @LIBTOOL_DEPS@ LIBUSB_CFLAGS = @LIBUSB_CFLAGS@ LIBUSB_CONFIG = @LIBUSB_CONFIG@ LIBUSB_LIBS = @LIBUSB_LIBS@ LIBWRAP_CFLAGS = @LIBWRAP_CFLAGS@ LIBWRAP_LIBS = @LIBWRAP_LIBS@ LIPO = @LIPO@ LN_S = @LN_S@ LN_S_R = @LN_S_R@ LTLIBOBJS = @LTLIBOBJS@ LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@ MAINT = @MAINT@ MAKEINFO = @MAKEINFO@ MANIFEST_TOOL = @MANIFEST_TOOL@ MKDIR_P = @MKDIR_P@ MSGFMT = @MSGFMT@ NETLIBS = @NETLIBS@ NET_SNMP_CONFIG = @NET_SNMP_CONFIG@ NM = @NM@ NMEDIT = @NMEDIT@ NUT_DATADIR = @NUT_DATADIR@ NUT_LIBEXECDIR = @NUT_LIBEXECDIR@ NUT_NETVERSION = @NUT_NETVERSION@ NUT_SOURCE_GITREV = @NUT_SOURCE_GITREV@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ OS_NAME = @OS_NAME@ OTOOL = @OTOOL@ OTOOL64 = @OTOOL64@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_SEPARATOR = @PATH_SEPARATOR@ PIDPATH = @PIDPATH@ PKGCONFIGDIR = @PKGCONFIGDIR@ PKG_CONFIG = @PKG_CONFIG@ PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@ PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ PORT = @PORT@ POWERDOWNFLAG = @POWERDOWNFLAG@ PREFIX = @PREFIX@ PYTHON = @PYTHON@ PYTHON2 = @PYTHON2@ PYTHON2_SITE_PACKAGES = @PYTHON2_SITE_PACKAGES@ PYTHON3 = @PYTHON3@ PYTHON3_SITE_PACKAGES = @PYTHON3_SITE_PACKAGES@ PYTHON_SITE_PACKAGES = @PYTHON_SITE_PACKAGES@ RANLIB = @RANLIB@ REALPATH = @REALPATH@ RUN_AS_GROUP = @RUN_AS_GROUP@ RUN_AS_USER = @RUN_AS_USER@ SBINDIR = @SBINDIR@ SED = @SED@ SEMLIBS = @SEMLIBS@ SERLIBS = @SERLIBS@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ SOURCE_HIGHLIGHT = @SOURCE_HIGHLIGHT@ STATEPATH = @STATEPATH@ STRIP = @STRIP@ SUN_LIBUSB = @SUN_LIBUSB@ SYSTEMD_ANALYZE_PROGRAM = @SYSTEMD_ANALYZE_PROGRAM@ SYSTEMD_DAEMON_ARGS_DRIVER = @SYSTEMD_DAEMON_ARGS_DRIVER@ SYSTEMD_DAEMON_ARGS_UPSD = @SYSTEMD_DAEMON_ARGS_UPSD@ SYSTEMD_DAEMON_ARGS_UPSMON = @SYSTEMD_DAEMON_ARGS_UPSMON@ SYSTEMD_DAEMON_NOTIFYACCESS_DRIVER = @SYSTEMD_DAEMON_NOTIFYACCESS_DRIVER@ SYSTEMD_DAEMON_NOTIFYACCESS_UPSD = @SYSTEMD_DAEMON_NOTIFYACCESS_UPSD@ SYSTEMD_DAEMON_NOTIFYACCESS_UPSMON = @SYSTEMD_DAEMON_NOTIFYACCESS_UPSMON@ SYSTEMD_DAEMON_TYPE_DRIVER = @SYSTEMD_DAEMON_TYPE_DRIVER@ SYSTEMD_DAEMON_TYPE_UPSD = @SYSTEMD_DAEMON_TYPE_UPSD@ SYSTEMD_DAEMON_TYPE_UPSMON = @SYSTEMD_DAEMON_TYPE_UPSMON@ SYSTEMD_DAEMON_WATCHDOG_DRIVER = @SYSTEMD_DAEMON_WATCHDOG_DRIVER@ SYSTEMD_DAEMON_WATCHDOG_UPSD = @SYSTEMD_DAEMON_WATCHDOG_UPSD@ SYSTEMD_DAEMON_WATCHDOG_UPSMON = @SYSTEMD_DAEMON_WATCHDOG_UPSMON@ SYSTEMD_TMPFILES_PROGRAM = @SYSTEMD_TMPFILES_PROGRAM@ TREE_VERSION = @TREE_VERSION@ VALGRIND = @VALGRIND@ VERSION = @VERSION@ WINDMC = @WINDMC@ WINDRES = @WINDRES@ WORDS_BIGENDIAN = @WORDS_BIGENDIAN@ XMLLINT = @XMLLINT@ XSLTPROC = @XSLTPROC@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_AR = @ac_ct_AR@ ac_ct_CC = @ac_ct_CC@ ac_ct_CXX = @ac_ct_CXX@ ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__tar = @am__tar@ am__untar = @am__untar@ auglensdir = @auglensdir@ bindir = @bindir@ build = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ cgiexecdir = @cgiexecdir@ datadir = @datadir@ datarootdir = @datarootdir@ devddir = @devddir@ docdir = @docdir@ driverexecdir = @driverexecdir@ dummy_PKG_CONFIG = @dummy_PKG_CONFIG@ dummy_PKG_CONFIG_CFLAGS = @dummy_PKG_CONFIG_CFLAGS@ dummy_PKG_CONFIG_LIBS = @dummy_PKG_CONFIG_LIBS@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ hotplugdir = @hotplugdir@ htmldir = @htmldir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libdir = @libdir@ libexecdir = @libexecdir@ localedir = @localedir@ localstatedir = @localstatedir@ mandir = @mandir@ mkdir_p = @mkdir_p@ now = @now@ nut_with_nut_monitor = @nut_with_nut_monitor@ nut_with_nut_monitor_desktop = @nut_with_nut_monitor_desktop@ nut_with_nut_monitor_dir = @nut_with_nut_monitor_dir@ nut_with_nut_monitor_py2gtk2 = @nut_with_nut_monitor_py2gtk2@ nut_with_nut_monitor_py3qt5 = @nut_with_nut_monitor_py3qt5@ nut_with_pynut = @nut_with_pynut@ nut_with_pynut_py = @nut_with_pynut_py@ nut_with_pynut_py2 = @nut_with_pynut_py2@ nut_with_pynut_py3 = @nut_with_pynut_py3@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ pkgconfigdir = @pkgconfigdir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ runstatedir = @runstatedir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ sysconfdir = @sysconfdir@ systemdshutdowndir = @systemdshutdowndir@ systemdsystemunitdir = @systemdsystemunitdir@ systemdtmpfilesdir = @systemdtmpfilesdir@ target = @target@ target_alias = @target_alias@ target_cpu = @target_cpu@ target_os = @target_os@ target_vendor = @target_vendor@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ udevdir = @udevdir@ EXTRA_DIST = README $(am__append_1) $(am__append_2) @HAVE_SYSTEMD_TRUE@systemdsystemunit_DATA = \ @HAVE_SYSTEMD_TRUE@ nut-driver-enumerator.service \ @HAVE_SYSTEMD_TRUE@ nut-driver-enumerator.path \ @HAVE_SYSTEMD_TRUE@ nut-driver@.service \ @HAVE_SYSTEMD_TRUE@ nut-monitor.service \ @HAVE_SYSTEMD_TRUE@ nut-server.service \ @HAVE_SYSTEMD_TRUE@ nut-driver.target \ @HAVE_SYSTEMD_TRUE@ nut.target @HAVE_SYSTEMD_TRUE@systemdtmpfiles_DATA = \ @HAVE_SYSTEMD_TRUE@ nut-common-tmpfiles.conf @HAVE_SYSTEMD_TRUE@systemdshutdown_SCRIPTS = nutshutdown @HAVE_SYSTEMD_TRUE@libexec_SCRIPTS = ../upsdrvsvcctl/nut-driver-enumerator.sh @HAVE_SYSTEMD_TRUE@sbin_SCRIPTS = ../upsdrvsvcctl/upsdrvsvcctl # NOTE: Do not EXTRA_DIST nut-common-tmpfiles.conf.in - it is generated per build # Generated by autogen.sh and needed to run the configure script: MAINTAINERCLEANFILES = Makefile.in .dirstamp \ nut-common-tmpfiles.conf.in all: all-am .SUFFIXES: $(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu scripts/systemd/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --gnu scripts/systemd/Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): nut-common-tmpfiles.conf: $(top_builddir)/config.status $(srcdir)/nut-common-tmpfiles.conf.in cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ nut-driver@.service: $(top_builddir)/config.status $(srcdir)/nut-driver@.service.in cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ nut-monitor.service: $(top_builddir)/config.status $(srcdir)/nut-monitor.service.in cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ nut-server.service: $(top_builddir)/config.status $(srcdir)/nut-server.service.in cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ nut-driver-enumerator.service: $(top_builddir)/config.status $(srcdir)/nut-driver-enumerator.service.in cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ nut-driver-enumerator.path: $(top_builddir)/config.status $(srcdir)/nut-driver-enumerator.path.in cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ nutshutdown: $(top_builddir)/config.status $(srcdir)/nutshutdown.in cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ install-libexecSCRIPTS: $(libexec_SCRIPTS) @$(NORMAL_INSTALL) @list='$(libexec_SCRIPTS)'; test -n "$(libexecdir)" || list=; \ if test -n "$$list"; then \ echo " $(MKDIR_P) '$(DESTDIR)$(libexecdir)'"; \ $(MKDIR_P) "$(DESTDIR)$(libexecdir)" || exit 1; \ fi; \ for p in $$list; do \ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ if test -f "$$d$$p"; then echo "$$d$$p"; echo "$$p"; else :; fi; \ done | \ sed -e 'p;s,.*/,,;n' \ -e 'h;s|.*|.|' \ -e 'p;x;s,.*/,,;$(transform)' | sed 'N;N;N;s,\n, ,g' | \ $(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1; } \ { d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \ if ($$2 == $$4) { files[d] = files[d] " " $$1; \ if (++n[d] == $(am__install_max)) { \ print "f", d, files[d]; n[d] = 0; files[d] = "" } } \ else { print "f", d "/" $$4, $$1 } } \ END { for (d in files) print "f", d, files[d] }' | \ while read type dir files; do \ if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \ test -z "$$files" || { \ echo " $(INSTALL_SCRIPT) $$files '$(DESTDIR)$(libexecdir)$$dir'"; \ $(INSTALL_SCRIPT) $$files "$(DESTDIR)$(libexecdir)$$dir" || exit $$?; \ } \ ; done uninstall-libexecSCRIPTS: @$(NORMAL_UNINSTALL) @list='$(libexec_SCRIPTS)'; test -n "$(libexecdir)" || exit 0; \ files=`for p in $$list; do echo "$$p"; done | \ sed -e 's,.*/,,;$(transform)'`; \ dir='$(DESTDIR)$(libexecdir)'; $(am__uninstall_files_from_dir) install-sbinSCRIPTS: $(sbin_SCRIPTS) @$(NORMAL_INSTALL) @list='$(sbin_SCRIPTS)'; test -n "$(sbindir)" || list=; \ if test -n "$$list"; then \ echo " $(MKDIR_P) '$(DESTDIR)$(sbindir)'"; \ $(MKDIR_P) "$(DESTDIR)$(sbindir)" || exit 1; \ fi; \ for p in $$list; do \ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ if test -f "$$d$$p"; then echo "$$d$$p"; echo "$$p"; else :; fi; \ done | \ sed -e 'p;s,.*/,,;n' \ -e 'h;s|.*|.|' \ -e 'p;x;s,.*/,,;$(transform)' | sed 'N;N;N;s,\n, ,g' | \ $(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1; } \ { d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \ if ($$2 == $$4) { files[d] = files[d] " " $$1; \ if (++n[d] == $(am__install_max)) { \ print "f", d, files[d]; n[d] = 0; files[d] = "" } } \ else { print "f", d "/" $$4, $$1 } } \ END { for (d in files) print "f", d, files[d] }' | \ while read type dir files; do \ if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \ test -z "$$files" || { \ echo " $(INSTALL_SCRIPT) $$files '$(DESTDIR)$(sbindir)$$dir'"; \ $(INSTALL_SCRIPT) $$files "$(DESTDIR)$(sbindir)$$dir" || exit $$?; \ } \ ; done uninstall-sbinSCRIPTS: @$(NORMAL_UNINSTALL) @list='$(sbin_SCRIPTS)'; test -n "$(sbindir)" || exit 0; \ files=`for p in $$list; do echo "$$p"; done | \ sed -e 's,.*/,,;$(transform)'`; \ dir='$(DESTDIR)$(sbindir)'; $(am__uninstall_files_from_dir) install-systemdshutdownSCRIPTS: $(systemdshutdown_SCRIPTS) @$(NORMAL_INSTALL) @list='$(systemdshutdown_SCRIPTS)'; test -n "$(systemdshutdowndir)" || list=; \ if test -n "$$list"; then \ echo " $(MKDIR_P) '$(DESTDIR)$(systemdshutdowndir)'"; \ $(MKDIR_P) "$(DESTDIR)$(systemdshutdowndir)" || exit 1; \ fi; \ for p in $$list; do \ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ if test -f "$$d$$p"; then echo "$$d$$p"; echo "$$p"; else :; fi; \ done | \ sed -e 'p;s,.*/,,;n' \ -e 'h;s|.*|.|' \ -e 'p;x;s,.*/,,;$(transform)' | sed 'N;N;N;s,\n, ,g' | \ $(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1; } \ { d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \ if ($$2 == $$4) { files[d] = files[d] " " $$1; \ if (++n[d] == $(am__install_max)) { \ print "f", d, files[d]; n[d] = 0; files[d] = "" } } \ else { print "f", d "/" $$4, $$1 } } \ END { for (d in files) print "f", d, files[d] }' | \ while read type dir files; do \ if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \ test -z "$$files" || { \ echo " $(INSTALL_SCRIPT) $$files '$(DESTDIR)$(systemdshutdowndir)$$dir'"; \ $(INSTALL_SCRIPT) $$files "$(DESTDIR)$(systemdshutdowndir)$$dir" || exit $$?; \ } \ ; done uninstall-systemdshutdownSCRIPTS: @$(NORMAL_UNINSTALL) @list='$(systemdshutdown_SCRIPTS)'; test -n "$(systemdshutdowndir)" || exit 0; \ files=`for p in $$list; do echo "$$p"; done | \ sed -e 's,.*/,,;$(transform)'`; \ dir='$(DESTDIR)$(systemdshutdowndir)'; $(am__uninstall_files_from_dir) mostlyclean-libtool: -rm -f *.lo clean-libtool: -rm -rf .libs _libs install-systemdsystemunitDATA: $(systemdsystemunit_DATA) @$(NORMAL_INSTALL) @list='$(systemdsystemunit_DATA)'; test -n "$(systemdsystemunitdir)" || list=; \ if test -n "$$list"; then \ echo " $(MKDIR_P) '$(DESTDIR)$(systemdsystemunitdir)'"; \ $(MKDIR_P) "$(DESTDIR)$(systemdsystemunitdir)" || exit 1; \ fi; \ for p in $$list; do \ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ echo "$$d$$p"; \ done | $(am__base_list) | \ while read files; do \ echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(systemdsystemunitdir)'"; \ $(INSTALL_DATA) $$files "$(DESTDIR)$(systemdsystemunitdir)" || exit $$?; \ done uninstall-systemdsystemunitDATA: @$(NORMAL_UNINSTALL) @list='$(systemdsystemunit_DATA)'; test -n "$(systemdsystemunitdir)" || list=; \ files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ dir='$(DESTDIR)$(systemdsystemunitdir)'; $(am__uninstall_files_from_dir) install-systemdtmpfilesDATA: $(systemdtmpfiles_DATA) @$(NORMAL_INSTALL) @list='$(systemdtmpfiles_DATA)'; test -n "$(systemdtmpfilesdir)" || list=; \ if test -n "$$list"; then \ echo " $(MKDIR_P) '$(DESTDIR)$(systemdtmpfilesdir)'"; \ $(MKDIR_P) "$(DESTDIR)$(systemdtmpfilesdir)" || exit 1; \ fi; \ for p in $$list; do \ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ echo "$$d$$p"; \ done | $(am__base_list) | \ while read files; do \ echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(systemdtmpfilesdir)'"; \ $(INSTALL_DATA) $$files "$(DESTDIR)$(systemdtmpfilesdir)" || exit $$?; \ done uninstall-systemdtmpfilesDATA: @$(NORMAL_UNINSTALL) @list='$(systemdtmpfiles_DATA)'; test -n "$(systemdtmpfilesdir)" || list=; \ files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ dir='$(DESTDIR)$(systemdtmpfilesdir)'; $(am__uninstall_files_from_dir) tags TAGS: ctags CTAGS: cscope cscopelist: distdir: $(BUILT_SOURCES) $(MAKE) $(AM_MAKEFLAGS) distdir-am distdir-am: $(DISTFILES) @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ dist_files=`for file in $$list; do echo $$file; done | \ sed -e "s|^$$srcdirstrip/||;t" \ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ case $$dist_files in \ */*) $(MKDIR_P) `echo "$$dist_files" | \ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ sort -u` ;; \ esac; \ for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d "$(distdir)/$$file"; then \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ else \ test -f "$(distdir)/$$file" \ || cp -p $$d/$$file "$(distdir)/$$file" \ || exit 1; \ fi; \ done check-am: all-am check: check-am all-am: Makefile $(SCRIPTS) $(DATA) installdirs: for dir in "$(DESTDIR)$(libexecdir)" "$(DESTDIR)$(sbindir)" "$(DESTDIR)$(systemdshutdowndir)" "$(DESTDIR)$(systemdsystemunitdir)" "$(DESTDIR)$(systemdtmpfilesdir)"; do \ test -z "$$dir" || $(MKDIR_P) "$$dir"; \ done install: install-am install-exec: install-exec-am install-data: install-data-am uninstall: uninstall-am install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-am install-strip: if test -z '$(STRIP)'; then \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ install; \ else \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ fi mostlyclean-generic: clean-generic: distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." -test -z "$(MAINTAINERCLEANFILES)" || rm -f $(MAINTAINERCLEANFILES) clean: clean-am clean-am: clean-generic clean-libtool mostlyclean-am distclean: distclean-am -rm -f Makefile distclean-am: clean-am distclean-generic dvi: dvi-am dvi-am: html: html-am html-am: info: info-am info-am: install-data-am: install-systemdshutdownSCRIPTS \ install-systemdsystemunitDATA install-systemdtmpfilesDATA install-dvi: install-dvi-am install-dvi-am: install-exec-am: install-libexecSCRIPTS install-sbinSCRIPTS install-html: install-html-am install-html-am: install-info: install-info-am install-info-am: install-man: install-pdf: install-pdf-am install-pdf-am: install-ps: install-ps-am install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-am -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-am mostlyclean-am: mostlyclean-generic mostlyclean-libtool pdf: pdf-am pdf-am: ps: ps-am ps-am: uninstall-am: uninstall-libexecSCRIPTS uninstall-sbinSCRIPTS \ uninstall-systemdshutdownSCRIPTS \ uninstall-systemdsystemunitDATA uninstall-systemdtmpfilesDATA .MAKE: install-am install-strip .PHONY: all all-am check check-am clean clean-generic clean-libtool \ cscopelist-am ctags-am distclean distclean-generic \ distclean-libtool distdir dvi dvi-am html html-am info info-am \ install install-am install-data install-data-am install-dvi \ install-dvi-am install-exec install-exec-am install-html \ install-html-am install-info install-info-am \ install-libexecSCRIPTS install-man install-pdf install-pdf-am \ install-ps install-ps-am install-sbinSCRIPTS install-strip \ install-systemdshutdownSCRIPTS install-systemdsystemunitDATA \ install-systemdtmpfilesDATA installcheck installcheck-am \ installdirs maintainer-clean maintainer-clean-generic \ mostlyclean mostlyclean-generic mostlyclean-libtool pdf pdf-am \ ps ps-am tags-am uninstall uninstall-am \ uninstall-libexecSCRIPTS uninstall-sbinSCRIPTS \ uninstall-systemdshutdownSCRIPTS \ uninstall-systemdsystemunitDATA uninstall-systemdtmpfilesDATA .PRECIOUS: Makefile # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: nut-2.8.1/scripts/systemd/nut-driver.target0000644000175000017500000000060414510262764015746 00000000000000# Network UPS Tools (NUT) systemd integration # Copyright (C) 2011-2023 by NUT contirbutors # Distributed under the terms of GPLv2+ # See https://networkupstools.org/ # and https://github.com/networkupstools/nut/ [Unit] Description=Network UPS Tools - target for power device drivers on this system After=local-fs.target # network.target PartOf=nut.target [Install] WantedBy=nut.target nut-2.8.1/scripts/systemd/nutshutdown.in0000755000175000017500000000733014510262764015377 00000000000000#!/bin/sh # Network UPS Tools (NUT) systemd-shutdown integration handler. # # NOTE: This script requires both nut-server package (or more specifically, # the drivers for your device, which may be in further packages grouped # by media/protocol and third-party dependencies), nut-client (upsmon), # and their configuration files to be present locally and on still-mounted # filesystems (may be read-only). # # Copyright (C) 2011-2023 by NUT contirbutors # Michal Hlavinka, Laurent Bigonville, Arnaud Quette, Jim Klimov et al. # # See https://networkupstools.org/ # and https://github.com/networkupstools/nut/ # # 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 2 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, write to the Free Software Foundation, Inc., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. if [ -s "@CONFPATH@/nut.conf" ]; then . "@CONFPATH@/nut.conf" || true fi [ x"${POWEROFF_QUIET-}" = xtrue ] \ || POWEROFF_QUIET="false" [ -x "@SBINDIR@/upsmon" ] || { $POWEROFF_QUIET || echo "$0: SKIP: could not locate '@SBINDIR@/upsmon''" >&2 exit 1 } # Will at most run the optional power-race avoidance sleep part [ -x "@SBINDIR@/upsdrvctl" ] || { $POWEROFF_QUIET || echo "$0: WARNING: could not locate '@SBINDIR@/upsdrvctl' - will not command any UPS devices to shut down" >&2 } if @SBINDIR@/upsmon -K >/dev/null 2>&1; then if [ -x "@SBINDIR@/upsdrvctl" ] ; then $POWEROFF_QUIET || { echo "$0: Commanding UPSes (if any) to shutdown" >&2 [ -w /dev/console ] && echo "`TZ=UTC LANG=C date`: $0: Commanding UPSes (if any) to shutdown" >/dev/console || true } @SBINDIR@/upsdrvctl shutdown || echo "$0: Something failed about UPS shutdown commands" >&2 fi if [ -n "$POWEROFF_WAIT" ] ; then # Avoid the power-race condition (if wall power returned # while we were shutting down, so some UPSes would not # shutdown and/or powercycle the load as commanded above). # Sleep "long enough" to drain the battery if the UPS is # in fact on battery, or reboot if it became alive, so # this computer is not in limbo forever. $POWEROFF_QUIET || { echo "$0: Power-race avoidance: sleeping $POWEROFF_WAIT" >&2 [ -w /dev/console ] && echo "`TZ=UTC LANG=C date`: $0: Power-race avoidance: sleeping $POWEROFF_WAIT" >/dev/console || true } # The argument may be anything compatible with /bin/sleep # (on OSes with systemd - assuming GNU coreutils or compatible, # so not necessarily a non-negative integer) /bin/sleep $POWEROFF_WAIT $POWEROFF_QUIET || { echo "$0: Power-race avoidance: sleep finished, rebooting..." >&2 [ -w /dev/console ] && echo "`TZ=UTC LANG=C date`: $0: Power-race avoidance: sleep finished, rebooting..." >/dev/console || true } # We need to pass --force twice here to bypass systemd # and execute the reboot directly ourself. /bin/systemctl reboot --force --force else $POWEROFF_QUIET || echo "$0: Power-race avoidance: POWEROFF_WAIT is not configured at this time, proceeding to shutdown" >&2 fi else $POWEROFF_QUIET || echo "$0: SKIP: Not in FSD (killpower) mode at this time" >&2 fi exit 0 nut-2.8.1/scripts/systemd/Makefile.am0000644000175000017500000000173214501607135014471 00000000000000EXTRA_DIST = README if HAVE_SYSTEMD systemdsystemunit_DATA = \ nut-driver-enumerator.service \ nut-driver-enumerator.path \ nut-driver@.service \ nut-monitor.service \ nut-server.service \ nut-driver.target \ nut.target systemdtmpfiles_DATA = \ nut-common-tmpfiles.conf EXTRA_DIST += nut-driver.target nut.target systemdshutdown_SCRIPTS = nutshutdown libexec_SCRIPTS = ../upsdrvsvcctl/nut-driver-enumerator.sh sbin_SCRIPTS = ../upsdrvsvcctl/upsdrvsvcctl else EXTRA_DIST += \ nut-driver@.service.in nut-monitor.service.in \ nut-server.service.in nutshutdown.in nut-driver.target nut.target \ nut-driver-enumerator.path.in nut-driver-enumerator.service.in # NOTE: Do not EXTRA_DIST nut-common-tmpfiles.conf.in - it is generated per build endif MAINTAINERCLEANFILES = Makefile.in .dirstamp # Generated by autogen.sh and needed to run the configure script: MAINTAINERCLEANFILES += nut-common-tmpfiles.conf.in nut-2.8.1/scripts/systemd/nut-server.service.in0000644000175000017500000000423514510262764016544 00000000000000# Network UPS Tools (NUT) systemd integration # Copyright (C) 2011-2023 by NUT contirbutors # Distributed under the terms of GPLv2+ # See https://networkupstools.org/ # and https://github.com/networkupstools/nut/ [Unit] Description=Network UPS Tools - power devices information server After=local-fs.target network.target nut-driver.target # We don't Require drivers to be successfully started! This would be # a change of behavior compared to init SysV, and could prevent from # accessing successfully started, at least to audit a system. Wants=nut-driver.target # The `upsd` is a networked service (even if bound to a `localhost`) # so it requires that the OS has some notion of networking already. # Extending the unit does not require *this* file to be edited, you # can instead drop in an additional piece of configuration, e.g. to # require that NUT data server only starts after external networking # is configured (usable IP addresses appear in the system) you can # add a `/etc/systemd/system/nut-server.service.d/network.conf` with: # [Unit] # Requires=network-online.target # After=network-online.target Requires=network.target Before=nut-monitor.service PartOf=nut.target [Service] EnvironmentFile=-@CONFPATH@/nut.conf SyslogIdentifier=%N # Note: foreground mode "-F" by default skips writing a PID file (and # needs default Type=simple); we can use "-FF" here to create the file # anyway, so that old "upsd -c reload" works rather than systemd action: ExecStartPre=-@SYSTEMD_TMPFILES_PROGRAM@ --create @systemdtmpfilesdir@/nut-common-tmpfiles.conf ExecStart=@SBINDIR@/upsd @SYSTEMD_DAEMON_ARGS_UPSD@ ExecReload=@SBINDIR@/upsd -c reload -P $MAINPID # No tracking for PIDFile path and service attribute here (it might not # even exist). # If "-FF" or background-daemon mode is used, so that PID file exists # and "upsd -c stop" in particular can be used from command-line or # legacy scripts, it causes a clean and intentional exit of the daemon. # Then systemd should not revive it - hence restart it only on failure: Restart=on-failure Type=@SYSTEMD_DAEMON_TYPE_UPSD@ @SYSTEMD_DAEMON_WATCHDOG_UPSD@ @SYSTEMD_DAEMON_NOTIFYACCESS_UPSD@ [Install] WantedBy=nut.target Alias=upsd.service nut-2.8.1/scripts/systemd/nut-driver-enumerator.service.in0000644000175000017500000000276414510262764020715 00000000000000# Network UPS Tools (NUT) systemd integration # Copyright (C) 2011-2023 by NUT contirbutors # Distributed under the terms of GPLv2+ # See https://networkupstools.org/ # and https://github.com/networkupstools/nut/ [Unit] # This unit starts early in system lifecycle to set up nut-driver instances. # End-user may also restart this unit after editing ups.conf to automatically # un-register or add new instances as appropriate. Description=Network UPS Tools - enumeration of configure-file devices into systemd unit instances After=local-fs.target Before=nut-driver.target PartOf=nut.target [Service] ### Script needs privileges to restart units #User=@RUN_AS_USER@ #Group=@RUN_AS_GROUP@ User=root SyslogIdentifier=%N # it is expected that the process has to exit before systemd starts follow-up # units; it should not be a problem for those Type=oneshot # Currently systemd does not support restarting of oneshot services, and does # not seem to guarantee that other services would only start after the script # completes, for a non-oneshot case. The script itself handles restarting of # nut-server which is the primary concerned dependency at the moment, so we # don't want it to fail the unit (when it can't restart). Environment=REPORT_RESTART_42=no EnvironmentFile=-@CONFPATH@/nut.conf ExecStartPre=-@SYSTEMD_TMPFILES_PROGRAM@ --create @systemdtmpfilesdir@/nut-common-tmpfiles.conf ExecStart=@NUT_LIBEXECDIR@/nut-driver-enumerator.sh ExecReload=@NUT_LIBEXECDIR@/nut-driver-enumerator.sh [Install] WantedBy=nut.target nut-2.8.1/scripts/systemd/README0000644000175000017500000000101514501607135013307 00000000000000This directory contains the NUT support files for systemd, the System and Service Manager. These files are automatically installed, upon detection (at configure time) of a systemd enabled system. This also uses the nut-driver-enumerator.sh (service and implementation method) and upsdrvsvcctl (tool) to manage NUT drivers as service instances located in ../upsdrvsvcctl/ source subdirectory. Contributed by Michal Hlavinka Updated 2016-2018 by Michal Hrusecky and Jim Klimov nut-2.8.1/scripts/hotplug/0000755000175000017500000000000014520277777012524 500000000000000nut-2.8.1/scripts/hotplug/Makefile.in0000644000175000017500000005637314520274662014515 00000000000000# Makefile.in generated by automake 1.16.5 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2021 Free Software Foundation, Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. @SET_MAKE@ VPATH = @srcdir@ am__is_gnu_make = { \ if test -z '$(MAKELEVEL)'; then \ false; \ elif test -n '$(MAKE_HOST)'; then \ true; \ elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \ true; \ else \ false; \ fi; \ } am__make_running_with_option = \ case $${target_option-} in \ ?) ;; \ *) echo "am__make_running_with_option: internal error: invalid" \ "target option '$${target_option-}' specified" >&2; \ exit 1;; \ esac; \ has_opt=no; \ sane_makeflags=$$MAKEFLAGS; \ if $(am__is_gnu_make); then \ sane_makeflags=$$MFLAGS; \ else \ case $$MAKEFLAGS in \ *\\[\ \ ]*) \ bs=\\; \ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ esac; \ fi; \ skip_next=no; \ strip_trailopt () \ { \ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ }; \ for flg in $$sane_makeflags; do \ test $$skip_next = yes && { skip_next=no; continue; }; \ case $$flg in \ *=*|--*) continue;; \ -*I) strip_trailopt 'I'; skip_next=yes;; \ -*I?*) strip_trailopt 'I';; \ -*O) strip_trailopt 'O'; skip_next=yes;; \ -*O?*) strip_trailopt 'O';; \ -*l) strip_trailopt 'l'; skip_next=yes;; \ -*l?*) strip_trailopt 'l';; \ -[dEDm]) skip_next=yes;; \ -[JT]) skip_next=yes;; \ esac; \ case $$flg in \ *$$target_option*) has_opt=yes; break;; \ esac; \ done; \ test $$has_opt = yes am__make_dryrun = (target_option=n; $(am__make_running_with_option)) am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkglibexecdir = $(libexecdir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ target_triplet = @target@ @WITH_HOTPLUG_FALSE@am__append_1 = libhid.usermap subdir = scripts/hotplug ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/m4/ax_c___attribute__.m4 \ $(top_srcdir)/m4/ax_c_pragmas.m4 \ $(top_srcdir)/m4/ax_check_compile_flag.m4 \ $(top_srcdir)/m4/ax_compare_version.m4 \ $(top_srcdir)/m4/ax_realpath.m4 \ $(top_srcdir)/m4/ax_run_or_link_ifelse.m4 \ $(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \ $(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \ $(top_srcdir)/m4/lt~obsolete.m4 \ $(top_srcdir)/m4/nut_arg_with.m4 \ $(top_srcdir)/m4/nut_check_asciidoc.m4 \ $(top_srcdir)/m4/nut_check_aspell.m4 \ $(top_srcdir)/m4/nut_check_cppcheck.m4 \ $(top_srcdir)/m4/nut_check_headers_windows.m4 \ $(top_srcdir)/m4/nut_check_libavahi.m4 \ $(top_srcdir)/m4/nut_check_libfreeipmi.m4 \ $(top_srcdir)/m4/nut_check_libgd.m4 \ $(top_srcdir)/m4/nut_check_libgpiod.m4 \ $(top_srcdir)/m4/nut_check_libltdl.m4 \ $(top_srcdir)/m4/nut_check_libmodbus.m4 \ $(top_srcdir)/m4/nut_check_libneon.m4 \ $(top_srcdir)/m4/nut_check_libnetsnmp.m4 \ $(top_srcdir)/m4/nut_check_libnss.m4 \ $(top_srcdir)/m4/nut_check_libopenssl.m4 \ $(top_srcdir)/m4/nut_check_libpowerman.m4 \ $(top_srcdir)/m4/nut_check_libregex.m4 \ $(top_srcdir)/m4/nut_check_libsystemd.m4 \ $(top_srcdir)/m4/nut_check_libusb.m4 \ $(top_srcdir)/m4/nut_check_libwrap.m4 \ $(top_srcdir)/m4/nut_check_os.m4 \ $(top_srcdir)/m4/nut_check_pkgconfig.m4 \ $(top_srcdir)/m4/nut_check_python.m4 \ $(top_srcdir)/m4/nut_check_socketlib.m4 \ $(top_srcdir)/m4/nut_compiler_family.m4 \ $(top_srcdir)/m4/nut_func_getnameinfo_argtypes.m4 \ $(top_srcdir)/m4/nut_report_feature.m4 \ $(top_srcdir)/m4/nut_stash_warnings.m4 \ $(top_srcdir)/m4/nut_type_socklen_t.m4 \ $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) DIST_COMMON = $(srcdir)/Makefile.am $(am__dist_hotplugusb_DATA_DIST) \ $(am__DIST_COMMON) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/include/config.h CONFIG_CLEAN_FILES = libhidups CONFIG_CLEAN_VPATH_FILES = am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; am__vpath_adj = case $$p in \ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ *) f=$$p;; \ esac; am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`; am__install_max = 40 am__nobase_strip_setup = \ srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'` am__nobase_strip = \ for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||" am__nobase_list = $(am__nobase_strip_setup); \ for p in $$list; do echo "$$p $$p"; done | \ sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \ $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \ if (++n[$$2] == $(am__install_max)) \ { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \ END { for (dir in files) print dir, files[dir] }' am__base_list = \ sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' am__uninstall_files_from_dir = { \ test -z "$$files" \ || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \ || { echo " ( cd '$$dir' && rm -f" $$files ")"; \ $(am__cd) "$$dir" && rm -f $$files; }; \ } am__installdirs = "$(DESTDIR)$(hotplugusbdir)" \ "$(DESTDIR)$(hotplugusbdir)" SCRIPTS = $(hotplugusb_SCRIPTS) AM_V_P = $(am__v_P_@AM_V@) am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) am__v_P_0 = false am__v_P_1 = : AM_V_GEN = $(am__v_GEN_@AM_V@) am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) am__v_GEN_0 = @echo " GEN " $@; am__v_GEN_1 = AM_V_at = $(am__v_at_@AM_V@) am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) am__v_at_0 = @ am__v_at_1 = SOURCES = DIST_SOURCES = am__can_run_installinfo = \ case $$AM_UPDATE_INFO_DIR in \ n|no|NO) false;; \ *) (install-info --version) >/dev/null 2>&1;; \ esac am__dist_hotplugusb_DATA_DIST = libhid.usermap DATA = $(dist_hotplugusb_DATA) am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) am__DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/libhidups.in README DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) A2X = @A2X@ ACLOCAL = @ACLOCAL@ ALTPIDPATH = @ALTPIDPATH@ AMTAR = @AMTAR@ AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ AR = @AR@ ASCIIDOC = @ASCIIDOC@ ASPELL = @ASPELL@ ASPELL_FILTER_LIB_PATH = @ASPELL_FILTER_LIB_PATH@ ASPELL_FILTER_SHARE_PATH = @ASPELL_FILTER_SHARE_PATH@ ASPELL_FILTER_TEX_PATH = @ASPELL_FILTER_TEX_PATH@ AUGPARSE = @AUGPARSE@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ BINDIR = @BINDIR@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CONFIG_FLAGS = @CONFIG_FLAGS@ CONFPATH = @CONFPATH@ CPP = @CPP@ CPPCHECK = @CPPCHECK@ CPPFLAGS = @CPPFLAGS@ CPPUNIT_CFLAGS = @CPPUNIT_CFLAGS@ CPPUNIT_LIBS = @CPPUNIT_LIBS@ CSCOPE = @CSCOPE@ CTAGS = @CTAGS@ CXX = @CXX@ CXXCPP = @CXXCPP@ CXXDEPMODE = @CXXDEPMODE@ CXXFLAGS = @CXXFLAGS@ CYGPATH_W = @CYGPATH_W@ DBLATEX = @DBLATEX@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ DEPLOYED_UPSC = @DEPLOYED_UPSC@ DEPLOYED_UPSD = @DEPLOYED_UPSD@ DLLTOOL = @DLLTOOL@ DOC_BUILD_LIST = @DOC_BUILD_LIST@ DOC_CHECK_LIST = @DOC_CHECK_LIST@ DRIVER_BUILD_LIST = @DRIVER_BUILD_LIST@ DRIVER_INSTALL_TARGET = @DRIVER_INSTALL_TARGET@ DRIVER_MAN_LIST = @DRIVER_MAN_LIST@ DRIVER_MAN_LIST_PAGES = @DRIVER_MAN_LIST_PAGES@ DRVPATH = @DRVPATH@ DSYMUTIL = @DSYMUTIL@ DUMPBIN = @DUMPBIN@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ ETAGS = @ETAGS@ EXEEXT = @EXEEXT@ FGREP = @FGREP@ FORCE_NUT_VERSION = @FORCE_NUT_VERSION@ GDLIB_CONFIG = @GDLIB_CONFIG@ GREP = @GREP@ HAVE_SYS_SOCKET_H = @HAVE_SYS_SOCKET_H@ HAVE_WINSOCK2_H = @HAVE_WINSOCK2_H@ HAVE_WS2TCPIP_H = @HAVE_WS2TCPIP_H@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ LD = @LD@ LDFLAGS = @LDFLAGS@ LIBAVAHI_CFLAGS = @LIBAVAHI_CFLAGS@ LIBAVAHI_LIBS = @LIBAVAHI_LIBS@ LIBDIR = @LIBDIR@ LIBGD_CFLAGS = @LIBGD_CFLAGS@ LIBGD_LDFLAGS = @LIBGD_LDFLAGS@ LIBGPIO_CFLAGS = @LIBGPIO_CFLAGS@ LIBGPIO_LIBS = @LIBGPIO_LIBS@ LIBI2C_LIBS = @LIBI2C_LIBS@ LIBIPMI_CFLAGS = @LIBIPMI_CFLAGS@ LIBIPMI_LIBS = @LIBIPMI_LIBS@ LIBLTDL_CFLAGS = @LIBLTDL_CFLAGS@ LIBLTDL_LIBS = @LIBLTDL_LIBS@ LIBMODBUS_CFLAGS = @LIBMODBUS_CFLAGS@ LIBMODBUS_LIBS = @LIBMODBUS_LIBS@ LIBNEON_CFLAGS = @LIBNEON_CFLAGS@ LIBNEON_LIBS = @LIBNEON_LIBS@ LIBNETSNMP_CFLAGS = @LIBNETSNMP_CFLAGS@ LIBNETSNMP_LIBS = @LIBNETSNMP_LIBS@ LIBOBJS = @LIBOBJS@ LIBPOWERMAN_CFLAGS = @LIBPOWERMAN_CFLAGS@ LIBPOWERMAN_LIBS = @LIBPOWERMAN_LIBS@ LIBREGEX_LIBS = @LIBREGEX_LIBS@ LIBS = @LIBS@ LIBSSL_CFLAGS = @LIBSSL_CFLAGS@ LIBSSL_LIBS = @LIBSSL_LIBS@ LIBSSL_REQUIRES = @LIBSSL_REQUIRES@ LIBSYSTEMD_CFLAGS = @LIBSYSTEMD_CFLAGS@ LIBSYSTEMD_LIBS = @LIBSYSTEMD_LIBS@ LIBTOOL = @LIBTOOL@ LIBTOOL_DEPS = @LIBTOOL_DEPS@ LIBUSB_CFLAGS = @LIBUSB_CFLAGS@ LIBUSB_CONFIG = @LIBUSB_CONFIG@ LIBUSB_LIBS = @LIBUSB_LIBS@ LIBWRAP_CFLAGS = @LIBWRAP_CFLAGS@ LIBWRAP_LIBS = @LIBWRAP_LIBS@ LIPO = @LIPO@ LN_S = @LN_S@ LN_S_R = @LN_S_R@ LTLIBOBJS = @LTLIBOBJS@ LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@ MAINT = @MAINT@ MAKEINFO = @MAKEINFO@ MANIFEST_TOOL = @MANIFEST_TOOL@ MKDIR_P = @MKDIR_P@ MSGFMT = @MSGFMT@ NETLIBS = @NETLIBS@ NET_SNMP_CONFIG = @NET_SNMP_CONFIG@ NM = @NM@ NMEDIT = @NMEDIT@ NUT_DATADIR = @NUT_DATADIR@ NUT_LIBEXECDIR = @NUT_LIBEXECDIR@ NUT_NETVERSION = @NUT_NETVERSION@ NUT_SOURCE_GITREV = @NUT_SOURCE_GITREV@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ OS_NAME = @OS_NAME@ OTOOL = @OTOOL@ OTOOL64 = @OTOOL64@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_SEPARATOR = @PATH_SEPARATOR@ PIDPATH = @PIDPATH@ PKGCONFIGDIR = @PKGCONFIGDIR@ PKG_CONFIG = @PKG_CONFIG@ PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@ PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ PORT = @PORT@ POWERDOWNFLAG = @POWERDOWNFLAG@ PREFIX = @PREFIX@ PYTHON = @PYTHON@ PYTHON2 = @PYTHON2@ PYTHON2_SITE_PACKAGES = @PYTHON2_SITE_PACKAGES@ PYTHON3 = @PYTHON3@ PYTHON3_SITE_PACKAGES = @PYTHON3_SITE_PACKAGES@ PYTHON_SITE_PACKAGES = @PYTHON_SITE_PACKAGES@ RANLIB = @RANLIB@ REALPATH = @REALPATH@ RUN_AS_GROUP = @RUN_AS_GROUP@ RUN_AS_USER = @RUN_AS_USER@ SBINDIR = @SBINDIR@ SED = @SED@ SEMLIBS = @SEMLIBS@ SERLIBS = @SERLIBS@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ SOURCE_HIGHLIGHT = @SOURCE_HIGHLIGHT@ STATEPATH = @STATEPATH@ STRIP = @STRIP@ SUN_LIBUSB = @SUN_LIBUSB@ SYSTEMD_ANALYZE_PROGRAM = @SYSTEMD_ANALYZE_PROGRAM@ SYSTEMD_DAEMON_ARGS_DRIVER = @SYSTEMD_DAEMON_ARGS_DRIVER@ SYSTEMD_DAEMON_ARGS_UPSD = @SYSTEMD_DAEMON_ARGS_UPSD@ SYSTEMD_DAEMON_ARGS_UPSMON = @SYSTEMD_DAEMON_ARGS_UPSMON@ SYSTEMD_DAEMON_NOTIFYACCESS_DRIVER = @SYSTEMD_DAEMON_NOTIFYACCESS_DRIVER@ SYSTEMD_DAEMON_NOTIFYACCESS_UPSD = @SYSTEMD_DAEMON_NOTIFYACCESS_UPSD@ SYSTEMD_DAEMON_NOTIFYACCESS_UPSMON = @SYSTEMD_DAEMON_NOTIFYACCESS_UPSMON@ SYSTEMD_DAEMON_TYPE_DRIVER = @SYSTEMD_DAEMON_TYPE_DRIVER@ SYSTEMD_DAEMON_TYPE_UPSD = @SYSTEMD_DAEMON_TYPE_UPSD@ SYSTEMD_DAEMON_TYPE_UPSMON = @SYSTEMD_DAEMON_TYPE_UPSMON@ SYSTEMD_DAEMON_WATCHDOG_DRIVER = @SYSTEMD_DAEMON_WATCHDOG_DRIVER@ SYSTEMD_DAEMON_WATCHDOG_UPSD = @SYSTEMD_DAEMON_WATCHDOG_UPSD@ SYSTEMD_DAEMON_WATCHDOG_UPSMON = @SYSTEMD_DAEMON_WATCHDOG_UPSMON@ SYSTEMD_TMPFILES_PROGRAM = @SYSTEMD_TMPFILES_PROGRAM@ TREE_VERSION = @TREE_VERSION@ VALGRIND = @VALGRIND@ VERSION = @VERSION@ WINDMC = @WINDMC@ WINDRES = @WINDRES@ WORDS_BIGENDIAN = @WORDS_BIGENDIAN@ XMLLINT = @XMLLINT@ XSLTPROC = @XSLTPROC@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_AR = @ac_ct_AR@ ac_ct_CC = @ac_ct_CC@ ac_ct_CXX = @ac_ct_CXX@ ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__tar = @am__tar@ am__untar = @am__untar@ auglensdir = @auglensdir@ bindir = @bindir@ build = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ cgiexecdir = @cgiexecdir@ datadir = @datadir@ datarootdir = @datarootdir@ devddir = @devddir@ docdir = @docdir@ driverexecdir = @driverexecdir@ dummy_PKG_CONFIG = @dummy_PKG_CONFIG@ dummy_PKG_CONFIG_CFLAGS = @dummy_PKG_CONFIG_CFLAGS@ dummy_PKG_CONFIG_LIBS = @dummy_PKG_CONFIG_LIBS@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ hotplugdir = @hotplugdir@ htmldir = @htmldir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libdir = @libdir@ libexecdir = @libexecdir@ localedir = @localedir@ localstatedir = @localstatedir@ mandir = @mandir@ mkdir_p = @mkdir_p@ now = @now@ nut_with_nut_monitor = @nut_with_nut_monitor@ nut_with_nut_monitor_desktop = @nut_with_nut_monitor_desktop@ nut_with_nut_monitor_dir = @nut_with_nut_monitor_dir@ nut_with_nut_monitor_py2gtk2 = @nut_with_nut_monitor_py2gtk2@ nut_with_nut_monitor_py3qt5 = @nut_with_nut_monitor_py3qt5@ nut_with_pynut = @nut_with_pynut@ nut_with_pynut_py = @nut_with_pynut_py@ nut_with_pynut_py2 = @nut_with_pynut_py2@ nut_with_pynut_py3 = @nut_with_pynut_py3@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ pkgconfigdir = @pkgconfigdir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ runstatedir = @runstatedir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ sysconfdir = @sysconfdir@ systemdshutdowndir = @systemdshutdowndir@ systemdsystemunitdir = @systemdsystemunitdir@ systemdtmpfilesdir = @systemdtmpfilesdir@ target = @target@ target_alias = @target_alias@ target_cpu = @target_cpu@ target_os = @target_os@ target_vendor = @target_vendor@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ udevdir = @udevdir@ EXTRA_DIST = README $(am__append_1) @WITH_HOTPLUG_TRUE@hotplugusbdir = $(hotplugdir)/usb @WITH_HOTPLUG_TRUE@dist_hotplugusb_DATA = libhid.usermap @WITH_HOTPLUG_TRUE@hotplugusb_SCRIPTS = libhidups # We should never remove this one, apart from a distclean-check # or stronger... # Generated by autogen.sh and needed to run the configure script # (technically, generated by tools/nut-usbinfo.pl script among # GENERATED_USB_OS_FILES): MAINTAINERCLEANFILES = Makefile.in .dirstamp libhid.usermap # Generated by configure script: DISTCLEANFILES = libhidups all: all-am .SUFFIXES: $(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu scripts/hotplug/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --gnu scripts/hotplug/Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): libhidups: $(top_builddir)/config.status $(srcdir)/libhidups.in cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ install-hotplugusbSCRIPTS: $(hotplugusb_SCRIPTS) @$(NORMAL_INSTALL) @list='$(hotplugusb_SCRIPTS)'; test -n "$(hotplugusbdir)" || list=; \ if test -n "$$list"; then \ echo " $(MKDIR_P) '$(DESTDIR)$(hotplugusbdir)'"; \ $(MKDIR_P) "$(DESTDIR)$(hotplugusbdir)" || exit 1; \ fi; \ for p in $$list; do \ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ if test -f "$$d$$p"; then echo "$$d$$p"; echo "$$p"; else :; fi; \ done | \ sed -e 'p;s,.*/,,;n' \ -e 'h;s|.*|.|' \ -e 'p;x;s,.*/,,;$(transform)' | sed 'N;N;N;s,\n, ,g' | \ $(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1; } \ { d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \ if ($$2 == $$4) { files[d] = files[d] " " $$1; \ if (++n[d] == $(am__install_max)) { \ print "f", d, files[d]; n[d] = 0; files[d] = "" } } \ else { print "f", d "/" $$4, $$1 } } \ END { for (d in files) print "f", d, files[d] }' | \ while read type dir files; do \ if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \ test -z "$$files" || { \ echo " $(INSTALL_SCRIPT) $$files '$(DESTDIR)$(hotplugusbdir)$$dir'"; \ $(INSTALL_SCRIPT) $$files "$(DESTDIR)$(hotplugusbdir)$$dir" || exit $$?; \ } \ ; done uninstall-hotplugusbSCRIPTS: @$(NORMAL_UNINSTALL) @list='$(hotplugusb_SCRIPTS)'; test -n "$(hotplugusbdir)" || exit 0; \ files=`for p in $$list; do echo "$$p"; done | \ sed -e 's,.*/,,;$(transform)'`; \ dir='$(DESTDIR)$(hotplugusbdir)'; $(am__uninstall_files_from_dir) mostlyclean-libtool: -rm -f *.lo clean-libtool: -rm -rf .libs _libs install-dist_hotplugusbDATA: $(dist_hotplugusb_DATA) @$(NORMAL_INSTALL) @list='$(dist_hotplugusb_DATA)'; test -n "$(hotplugusbdir)" || list=; \ if test -n "$$list"; then \ echo " $(MKDIR_P) '$(DESTDIR)$(hotplugusbdir)'"; \ $(MKDIR_P) "$(DESTDIR)$(hotplugusbdir)" || exit 1; \ fi; \ for p in $$list; do \ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ echo "$$d$$p"; \ done | $(am__base_list) | \ while read files; do \ echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(hotplugusbdir)'"; \ $(INSTALL_DATA) $$files "$(DESTDIR)$(hotplugusbdir)" || exit $$?; \ done uninstall-dist_hotplugusbDATA: @$(NORMAL_UNINSTALL) @list='$(dist_hotplugusb_DATA)'; test -n "$(hotplugusbdir)" || list=; \ files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ dir='$(DESTDIR)$(hotplugusbdir)'; $(am__uninstall_files_from_dir) tags TAGS: ctags CTAGS: cscope cscopelist: distdir: $(BUILT_SOURCES) $(MAKE) $(AM_MAKEFLAGS) distdir-am distdir-am: $(DISTFILES) @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ dist_files=`for file in $$list; do echo $$file; done | \ sed -e "s|^$$srcdirstrip/||;t" \ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ case $$dist_files in \ */*) $(MKDIR_P) `echo "$$dist_files" | \ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ sort -u` ;; \ esac; \ for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d "$(distdir)/$$file"; then \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ else \ test -f "$(distdir)/$$file" \ || cp -p $$d/$$file "$(distdir)/$$file" \ || exit 1; \ fi; \ done check-am: all-am check: check-am all-am: Makefile $(SCRIPTS) $(DATA) installdirs: for dir in "$(DESTDIR)$(hotplugusbdir)" "$(DESTDIR)$(hotplugusbdir)"; do \ test -z "$$dir" || $(MKDIR_P) "$$dir"; \ done install: install-am install-exec: install-exec-am install-data: install-data-am uninstall: uninstall-am install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-am install-strip: if test -z '$(STRIP)'; then \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ install; \ else \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ fi mostlyclean-generic: clean-generic: distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) -test -z "$(DISTCLEANFILES)" || rm -f $(DISTCLEANFILES) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." -test -z "$(MAINTAINERCLEANFILES)" || rm -f $(MAINTAINERCLEANFILES) clean: clean-am clean-am: clean-generic clean-libtool mostlyclean-am distclean: distclean-am -rm -f Makefile distclean-am: clean-am distclean-generic dvi: dvi-am dvi-am: html: html-am html-am: info: info-am info-am: install-data-am: install-dist_hotplugusbDATA install-hotplugusbSCRIPTS install-dvi: install-dvi-am install-dvi-am: install-exec-am: install-html: install-html-am install-html-am: install-info: install-info-am install-info-am: install-man: install-pdf: install-pdf-am install-pdf-am: install-ps: install-ps-am install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-am -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-am mostlyclean-am: mostlyclean-generic mostlyclean-libtool pdf: pdf-am pdf-am: ps: ps-am ps-am: uninstall-am: uninstall-dist_hotplugusbDATA \ uninstall-hotplugusbSCRIPTS .MAKE: install-am install-strip .PHONY: all all-am check check-am clean clean-generic clean-libtool \ cscopelist-am ctags-am distclean distclean-generic \ distclean-libtool distdir dvi dvi-am html html-am info info-am \ install install-am install-data install-data-am \ install-dist_hotplugusbDATA install-dvi install-dvi-am \ install-exec install-exec-am install-hotplugusbSCRIPTS \ install-html install-html-am install-info install-info-am \ install-man install-pdf install-pdf-am install-ps \ install-ps-am install-strip installcheck installcheck-am \ installdirs maintainer-clean maintainer-clean-generic \ mostlyclean mostlyclean-generic mostlyclean-libtool pdf pdf-am \ ps ps-am tags-am uninstall uninstall-am \ uninstall-dist_hotplugusbDATA uninstall-hotplugusbSCRIPTS .PRECIOUS: Makefile @WITH_HOTPLUG_FALSE@ # Part of dist tarball, regardless of use for current build: # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: nut-2.8.1/scripts/hotplug/libhid.usermap0000644000175000017500000006460014520277776015302 00000000000000# This file is generated and installed by the Network UPS Tools package. # # Sample entry (replace 0xVVVV and 0xPPPP with vendor ID and product ID respectively) : # libhidups 0x0003 0xVVVV 0xPPPP 0x0000 0x0000 0x00 0x00 0x00 0x00 0x00 0x00 0x00000000 # # usb module match_flags idVendor idProduct bcdDevice_lo bcdDevice_hi bDeviceClass bDeviceSubClass bDeviceProtocol bInterfaceClass bInterfaceSubClass bInterfaceProtocol driver_info # SNR-UPS-LID-XXXX UPSes libhidups 0x0003 0x0001 0x0000 0x0000 0x0000 0x00 0x00 0x00 0x00 0x00 0x00 0x00000000 # Hewlett Packard # e.g. ? libhidups 0x0003 0x03f0 0x0001 0x0000 0x0000 0x00 0x00 0x00 0x00 0x00 0x00 0x00000000 # T500 libhidups 0x0003 0x03f0 0x1f01 0x0000 0x0000 0x00 0x00 0x00 0x00 0x00 0x00 0x00000000 # T750 libhidups 0x0003 0x03f0 0x1f02 0x0000 0x0000 0x00 0x00 0x00 0x00 0x00 0x00 0x00000000 # HP T750 INTL libhidups 0x0003 0x03f0 0x1f06 0x0000 0x0000 0x00 0x00 0x00 0x00 0x00 0x00 0x00000000 # HP T1000 INTL libhidups 0x0003 0x03f0 0x1f08 0x0000 0x0000 0x00 0x00 0x00 0x00 0x00 0x00 0x00000000 # HP T1500 INTL libhidups 0x0003 0x03f0 0x1f09 0x0000 0x0000 0x00 0x00 0x00 0x00 0x00 0x00 0x00000000 # HP R/T 2200 INTL (like SMART2200RMXL2U) libhidups 0x0003 0x03f0 0x1f0a 0x0000 0x0000 0x00 0x00 0x00 0x00 0x00 0x00 0x00000000 # HP R1500 G2 and G3 INTL libhidups 0x0003 0x03f0 0x1fe0 0x0000 0x0000 0x00 0x00 0x00 0x00 0x00 0x00 0x00000000 # HP T750 G2 libhidups 0x0003 0x03f0 0x1fe1 0x0000 0x0000 0x00 0x00 0x00 0x00 0x00 0x00 0x00000000 # e.g. ? libhidups 0x0003 0x03f0 0x1fe2 0x0000 0x0000 0x00 0x00 0x00 0x00 0x00 0x00 0x00000000 # HP T1500 G3 libhidups 0x0003 0x03f0 0x1fe3 0x0000 0x0000 0x00 0x00 0x00 0x00 0x00 0x00 0x00000000 # R/T3000 libhidups 0x0003 0x03f0 0x1fe5 0x0000 0x0000 0x00 0x00 0x00 0x00 0x00 0x00 0x00000000 # R/T3000 libhidups 0x0003 0x03f0 0x1fe6 0x0000 0x0000 0x00 0x00 0x00 0x00 0x00 0x00 0x00000000 # various models libhidups 0x0003 0x03f0 0x1fe7 0x0000 0x0000 0x00 0x00 0x00 0x00 0x00 0x00 0x00000000 # various models libhidups 0x0003 0x03f0 0x1fe8 0x0000 0x0000 0x00 0x00 0x00 0x00 0x00 0x00 0x00000000 # Eaton # various models libhidups 0x0003 0x0463 0x0001 0x0000 0x0000 0x00 0x00 0x00 0x00 0x00 0x00 0x00000000 # various models libhidups 0x0003 0x0463 0xffff 0x0000 0x0000 0x00 0x00 0x00 0x00 0x00 0x00 0x00000000 # Dell # various models libhidups 0x0003 0x047c 0xffff 0x0000 0x0000 0x00 0x00 0x00 0x00 0x00 0x00 0x00000000 # ST Microelectronics # TS Shara UPSes; vendor ID 0x0483 is from ST Microelectronics - with product IDs delegated to different OEMs libhidups 0x0003 0x0483 0x0035 0x0000 0x0000 0x00 0x00 0x00 0x00 0x00 0x00 0x00000000 # USB IDs device table libhidups 0x0003 0x0483 0xa113 0x0000 0x0000 0x00 0x00 0x00 0x00 0x00 0x00 0x00000000 # IBM # 6000 VA LCD 4U Rack UPS; 5396-1Kx libhidups 0x0003 0x04b3 0x0001 0x0000 0x0000 0x00 0x00 0x00 0x00 0x00 0x00 0x00000000 # Riello (Cypress Semiconductor Corp.) # various models libhidups 0x0003 0x04b4 0x5500 0x0000 0x0000 0x00 0x00 0x00 0x00 0x00 0x00 0x00000000 # Minibox # openUPS Intelligent UPS (minimum required firmware 1.4) libhidups 0x0003 0x04d8 0xd004 0x0000 0x0000 0x00 0x00 0x00 0x00 0x00 0x00 0x00000000 # openUPS Intelligent UPS (minimum required firmware 1.4) libhidups 0x0003 0x04d8 0xd005 0x0000 0x0000 0x00 0x00 0x00 0x00 0x00 0x00 0x00000000 # Belkin # F6H375-USB libhidups 0x0003 0x050d 0x0375 0x0000 0x0000 0x00 0x00 0x00 0x00 0x00 0x00 0x00000000 # F6C550-AVR libhidups 0x0003 0x050d 0x0551 0x0000 0x0000 0x00 0x00 0x00 0x00 0x00 0x00 0x00000000 # F6C1250-TW-RK libhidups 0x0003 0x050d 0x0750 0x0000 0x0000 0x00 0x00 0x00 0x00 0x00 0x00 0x00000000 # F6C1500-TW-RK libhidups 0x0003 0x050d 0x0751 0x0000 0x0000 0x00 0x00 0x00 0x00 0x00 0x00 0x00000000 # F6C900-UNV libhidups 0x0003 0x050d 0x0900 0x0000 0x0000 0x00 0x00 0x00 0x00 0x00 0x00 0x00000000 # F6C100-UNV libhidups 0x0003 0x050d 0x0910 0x0000 0x0000 0x00 0x00 0x00 0x00 0x00 0x00 0x00000000 # F6C120-UNV libhidups 0x0003 0x050d 0x0912 0x0000 0x0000 0x00 0x00 0x00 0x00 0x00 0x00 0x00000000 # F6C800-UNV libhidups 0x0003 0x050d 0x0980 0x0000 0x0000 0x00 0x00 0x00 0x00 0x00 0x00 0x00000000 # Regulator PRO-USB libhidups 0x0003 0x050d 0x0f51 0x0000 0x0000 0x00 0x00 0x00 0x00 0x00 0x00 0x00000000 # F6C1100-UNV, F6C1200-UNV libhidups 0x0003 0x050d 0x1100 0x0000 0x0000 0x00 0x00 0x00 0x00 0x00 0x00 0x00000000 # APC # APC AP9584 Serial->USB kit libhidups 0x0003 0x051d 0x0000 0x0000 0x0000 0x00 0x00 0x00 0x00 0x00 0x00 0x00000000 # various models libhidups 0x0003 0x051d 0x0002 0x0000 0x0000 0x00 0x00 0x00 0x00 0x00 0x00 0x00000000 # USB IDs device table libhidups 0x0003 0x051d 0x0003 0x0000 0x0000 0x00 0x00 0x00 0x00 0x00 0x00 0x00000000 # various 5G models libhidups 0x0003 0x051d 0x0004 0x0000 0x0000 0x00 0x00 0x00 0x00 0x00 0x00 0x00000000 # Powerware # various models libhidups 0x0003 0x0592 0x0002 0x0000 0x0000 0x00 0x00 0x00 0x00 0x00 0x00 0x00000000 # PW 9140 libhidups 0x0003 0x0592 0x0004 0x0000 0x0000 0x00 0x00 0x00 0x00 0x00 0x00 0x00000000 # Agiler UPS libhidups 0x0003 0x05b8 0x0000 0x0000 0x0000 0x00 0x00 0x00 0x00 0x00 0x00 0x00000000 # Delta UPS # Delta UPS Amplon R Series, Single Phase UPS, 1/2/3 kVA libhidups 0x0003 0x05dd 0x041b 0x0000 0x0000 0x00 0x00 0x00 0x00 0x00 0x00 0x00000000 # Delta/Minuteman Enterprise Plus E1500RM2U libhidups 0x0003 0x05dd 0xa011 0x0000 0x0000 0x00 0x00 0x00 0x00 0x00 0x00 0x00000000 # Delta/Minuteman PRO1500RT2U libhidups 0x0003 0x05dd 0xa0a0 0x0000 0x0000 0x00 0x00 0x00 0x00 0x00 0x00 0x00000000 # Belkin F6C1200-UNV/Voltronic Power UPSes libhidups 0x0003 0x0665 0x5161 0x0000 0x0000 0x00 0x00 0x00 0x00 0x00 0x00 0x00000000 # Phoenixtec Power Co., Ltd # Online Yunto YQ450 libhidups 0x0003 0x06da 0x0002 0x0000 0x0000 0x00 0x00 0x00 0x00 0x00 0x00 0x00000000 # Mustek Powermust libhidups 0x0003 0x06da 0x0003 0x0000 0x0000 0x00 0x00 0x00 0x00 0x00 0x00 0x00000000 # Phoenixtec Innova 3/1 T libhidups 0x0003 0x06da 0x0004 0x0000 0x0000 0x00 0x00 0x00 0x00 0x00 0x00 0x00000000 # Phoenixtec Innova RT libhidups 0x0003 0x06da 0x0005 0x0000 0x0000 0x00 0x00 0x00 0x00 0x00 0x00 0x00000000 # Phoenixtec Innova T libhidups 0x0003 0x06da 0x0201 0x0000 0x0000 0x00 0x00 0x00 0x00 0x00 0x00 0x00000000 # Online Zinto A libhidups 0x0003 0x06da 0x0601 0x0000 0x0000 0x00 0x00 0x00 0x00 0x00 0x00 0x00000000 # PROTECT B / NAS libhidups 0x0003 0x06da 0xffff 0x0000 0x0000 0x00 0x00 0x00 0x00 0x00 0x00 0x00000000 # iDowell # iDowell libhidups 0x0003 0x075d 0x0300 0x0000 0x0000 0x00 0x00 0x00 0x00 0x00 0x00 0x00000000 # Cyber Power Systems # 900AVR/BC900D libhidups 0x0003 0x0764 0x0005 0x0000 0x0000 0x00 0x00 0x00 0x00 0x00 0x00 0x00000000 # Dynex DX-800U?, CP1200AVR/BC1200D, CP825AVR-G, CP1000AVRLCD, CP1000PFCLCD, CP1500C, CP550HG, etc. libhidups 0x0003 0x0764 0x0501 0x0000 0x0000 0x00 0x00 0x00 0x00 0x00 0x00 0x00000000 # OR2200LCDRM2U, OR700LCDRM1U, PR6000LCDRTXL5U libhidups 0x0003 0x0764 0x0601 0x0000 0x0000 0x00 0x00 0x00 0x00 0x00 0x00 0x00000000 # Sweex 1000VA libhidups 0x0003 0x0925 0x1234 0x0000 0x0000 0x00 0x00 0x00 0x00 0x00 0x00 0x00000000 # TrippLite # e.g. OMNIVS1000, SMART550USB, ... libhidups 0x0003 0x09ae 0x0001 0x0000 0x0000 0x00 0x00 0x00 0x00 0x00 0x00 0x00000000 # e.g. TrippLite AVR550U libhidups 0x0003 0x09ae 0x1003 0x0000 0x0000 0x00 0x00 0x00 0x00 0x00 0x00 0x00000000 # e.g. TrippLite AVR750U libhidups 0x0003 0x09ae 0x1007 0x0000 0x0000 0x00 0x00 0x00 0x00 0x00 0x00 0x00000000 # e.g. TrippLite ECO550UPS libhidups 0x0003 0x09ae 0x1008 0x0000 0x0000 0x00 0x00 0x00 0x00 0x00 0x00 0x00000000 # e.g. TrippLite ECO550UPS libhidups 0x0003 0x09ae 0x1009 0x0000 0x0000 0x00 0x00 0x00 0x00 0x00 0x00 0x00000000 # e.g. TrippLite ECO550UPS libhidups 0x0003 0x09ae 0x1010 0x0000 0x0000 0x00 0x00 0x00 0x00 0x00 0x00 0x00000000 # e.g. TrippLite SU3000LCD2UHV libhidups 0x0003 0x09ae 0x1330 0x0000 0x0000 0x00 0x00 0x00 0x00 0x00 0x00 0x00000000 # e.g. TrippLite OMNI1000LCD libhidups 0x0003 0x09ae 0x2005 0x0000 0x0000 0x00 0x00 0x00 0x00 0x00 0x00 0x00000000 # e.g. TrippLite OMNI900LCD libhidups 0x0003 0x09ae 0x2007 0x0000 0x0000 0x00 0x00 0x00 0x00 0x00 0x00 0x00000000 # e.g. ? libhidups 0x0003 0x09ae 0x2008 0x0000 0x0000 0x00 0x00 0x00 0x00 0x00 0x00 0x00000000 # e.g. TrippLite Smart1000LCD libhidups 0x0003 0x09ae 0x2009 0x0000 0x0000 0x00 0x00 0x00 0x00 0x00 0x00 0x00000000 # e.g. ? libhidups 0x0003 0x09ae 0x2010 0x0000 0x0000 0x00 0x00 0x00 0x00 0x00 0x00 0x00000000 # e.g. ? libhidups 0x0003 0x09ae 0x2011 0x0000 0x0000 0x00 0x00 0x00 0x00 0x00 0x00 0x00000000 # e.g. ? libhidups 0x0003 0x09ae 0x2012 0x0000 0x0000 0x00 0x00 0x00 0x00 0x00 0x00 0x00000000 # e.g. ? libhidups 0x0003 0x09ae 0x2013 0x0000 0x0000 0x00 0x00 0x00 0x00 0x00 0x00 0x00000000 # e.g. ? libhidups 0x0003 0x09ae 0x2014 0x0000 0x0000 0x00 0x00 0x00 0x00 0x00 0x00 0x00000000 # e.g. ? libhidups 0x0003 0x09ae 0x3008 0x0000 0x0000 0x00 0x00 0x00 0x00 0x00 0x00 0x00000000 # e.g. ? libhidups 0x0003 0x09ae 0x3009 0x0000 0x0000 0x00 0x00 0x00 0x00 0x00 0x00 0x00000000 # e.g. ? libhidups 0x0003 0x09ae 0x3010 0x0000 0x0000 0x00 0x00 0x00 0x00 0x00 0x00 0x00000000 # e.g. ? libhidups 0x0003 0x09ae 0x3011 0x0000 0x0000 0x00 0x00 0x00 0x00 0x00 0x00 0x00000000 # e.g. TrippLite smart2200RMXL2U libhidups 0x0003 0x09ae 0x3012 0x0000 0x0000 0x00 0x00 0x00 0x00 0x00 0x00 0x00000000 # e.g. ? libhidups 0x0003 0x09ae 0x3013 0x0000 0x0000 0x00 0x00 0x00 0x00 0x00 0x00 0x00000000 # e.g. ? libhidups 0x0003 0x09ae 0x3014 0x0000 0x0000 0x00 0x00 0x00 0x00 0x00 0x00 0x00000000 # e.g. ? libhidups 0x0003 0x09ae 0x3015 0x0000 0x0000 0x00 0x00 0x00 0x00 0x00 0x00 0x00000000 # e.g. TrippLite Smart1500LCD (newer unit) libhidups 0x0003 0x09ae 0x3016 0x0000 0x0000 0x00 0x00 0x00 0x00 0x00 0x00 0x00000000 # e.g. TrippLite AVR750U (newer unit) libhidups 0x0003 0x09ae 0x3024 0x0000 0x0000 0x00 0x00 0x00 0x00 0x00 0x00 0x00000000 # e.g. TrippLite SmartOnline SU1500RTXL2UA (older unit?) libhidups 0x0003 0x09ae 0x4001 0x0000 0x0000 0x00 0x00 0x00 0x00 0x00 0x00 0x00000000 # e.g. TrippLite SmartOnline SU6000RT4U? libhidups 0x0003 0x09ae 0x4002 0x0000 0x0000 0x00 0x00 0x00 0x00 0x00 0x00 0x00000000 # e.g. TrippLite SmartOnline SU1500RTXL2ua libhidups 0x0003 0x09ae 0x4003 0x0000 0x0000 0x00 0x00 0x00 0x00 0x00 0x00 0x00000000 # e.g. TrippLite SmartOnline SU1000XLA libhidups 0x0003 0x09ae 0x4004 0x0000 0x0000 0x00 0x00 0x00 0x00 0x00 0x00 0x00000000 # e.g. ? libhidups 0x0003 0x09ae 0x4005 0x0000 0x0000 0x00 0x00 0x00 0x00 0x00 0x00 0x00000000 # e.g. ? libhidups 0x0003 0x09ae 0x4006 0x0000 0x0000 0x00 0x00 0x00 0x00 0x00 0x00 0x00000000 # e.g. ? libhidups 0x0003 0x09ae 0x4007 0x0000 0x0000 0x00 0x00 0x00 0x00 0x00 0x00 0x00000000 # e.g. ? libhidups 0x0003 0x09ae 0x4008 0x0000 0x0000 0x00 0x00 0x00 0x00 0x00 0x00 0x00000000 # PowerCOM # PowerCOM Vanguard and BNT-xxxAP libhidups 0x0003 0x0d9f 0x0001 0x0000 0x0000 0x00 0x00 0x00 0x00 0x00 0x00 0x00000000 # PowerCOM Vanguard and BNT-xxxAP libhidups 0x0003 0x0d9f 0x0004 0x0000 0x0000 0x00 0x00 0x00 0x00 0x00 0x00 0x00000000 # PowerCOM IMP - IMPERIAL Series libhidups 0x0003 0x0d9f 0x00a2 0x0000 0x0000 0x00 0x00 0x00 0x00 0x00 0x00 0x00000000 # PowerCOM SKP - Smart KING Pro (all Smart series) libhidups 0x0003 0x0d9f 0x00a3 0x0000 0x0000 0x00 0x00 0x00 0x00 0x00 0x00 0x00000000 # PowerCOM WOW libhidups 0x0003 0x0d9f 0x00a4 0x0000 0x0000 0x00 0x00 0x00 0x00 0x00 0x00 0x00000000 # PowerCOM VGD - Vanguard libhidups 0x0003 0x0d9f 0x00a5 0x0000 0x0000 0x00 0x00 0x00 0x00 0x00 0x00 0x00000000 # PowerCOM BNT - Black Knight Pro libhidups 0x0003 0x0d9f 0x00a6 0x0000 0x0000 0x00 0x00 0x00 0x00 0x00 0x00 0x00000000 # Unitek Alpha 1200Sx libhidups 0x0003 0x0f03 0x0001 0x0000 0x0000 0x00 0x00 0x00 0x00 0x00 0x00 0x00000000 # Liebert # Liebert PowerSure PSA UPS libhidups 0x0003 0x10af 0x0001 0x0000 0x0000 0x00 0x00 0x00 0x00 0x00 0x00 0x00000000 # Liebert PowerSure PSI 1440 libhidups 0x0003 0x10af 0x0004 0x0000 0x0000 0x00 0x00 0x00 0x00 0x00 0x00 0x00000000 # Liebert GXT3 libhidups 0x0003 0x10af 0x0008 0x0000 0x0000 0x00 0x00 0x00 0x00 0x00 0x00 0x00000000 # GE EP series libhidups 0x0003 0x14f0 0x00c9 0x0000 0x0000 0x00 0x00 0x00 0x00 0x00 0x00 0x00000000 # Legrand # Legrand Keor SP libhidups 0x0003 0x1cb0 0x0032 0x0000 0x0000 0x00 0x00 0x00 0x00 0x00 0x00 0x00000000 # Legrand Daker DK / DK Plus libhidups 0x0003 0x1cb0 0x0035 0x0000 0x0000 0x00 0x00 0x00 0x00 0x00 0x00 0x00000000 # Legrand Keor PDU libhidups 0x0003 0x1cb0 0x0038 0x0000 0x0000 0x00 0x00 0x00 0x00 0x00 0x00 0x00000000 # Arduino # Arduino Leonardo, Leonardo ETH and Pro Micro libhidups 0x0003 0x2341 0x0036 0x0000 0x0000 0x00 0x00 0x00 0x00 0x00 0x00 0x00000000 # Arduino Leonardo, Leonardo ETH and Pro Micro libhidups 0x0003 0x2341 0x8036 0x0000 0x0000 0x00 0x00 0x00 0x00 0x00 0x00 0x00000000 # Arduino # Arduino Leonardo, Leonardo ETH and Pro Micro libhidups 0x0003 0x2a03 0x0036 0x0000 0x0000 0x00 0x00 0x00 0x00 0x00 0x00 0x00000000 # Arduino Leonardo, Leonardo ETH and Pro Micro libhidups 0x0003 0x2a03 0x0040 0x0000 0x0000 0x00 0x00 0x00 0x00 0x00 0x00 0x00000000 # Arduino Leonardo, Leonardo ETH and Pro Micro libhidups 0x0003 0x2a03 0x8036 0x0000 0x0000 0x00 0x00 0x00 0x00 0x00 0x00 0x00000000 # Arduino Leonardo, Leonardo ETH and Pro Micro libhidups 0x0003 0x2a03 0x8040 0x0000 0x0000 0x00 0x00 0x00 0x00 0x00 0x00 0x00000000 # AEG # PROTECT B / NAS libhidups 0x0003 0x2b2d 0xffff 0x0000 0x0000 0x00 0x00 0x00 0x00 0x00 0x00 0x00000000 # Ever # USB IDs device table libhidups 0x0003 0x2e51 0x0000 0x0000 0x0000 0x00 0x00 0x00 0x00 0x00 0x00 0x00000000 # USB IDs device table libhidups 0x0003 0x2e51 0xffff 0x0000 0x0000 0x00 0x00 0x00 0x00 0x00 0x00 0x00000000 # Salicru # https://www.salicru.com/sps-3000-adv-rt2.html libhidups 0x0003 0x2e66 0x0101 0x0000 0x0000 0x00 0x00 0x00 0x00 0x00 0x00 0x00000000 # SLC TWIN PRO2<=3KVA per https://github.com/networkupstools/nut/issues/450 libhidups 0x0003 0x2e66 0x0201 0x0000 0x0000 0x00 0x00 0x00 0x00 0x00 0x00 0x00000000 # SLC TWIN PRO2<=3KVA per https://github.com/networkupstools/nut/issues/450 libhidups 0x0003 0x2e66 0x0202 0x0000 0x0000 0x00 0x00 0x00 0x00 0x00 0x00 0x00000000 # SLC TWIN PRO2<=3KVA per https://github.com/networkupstools/nut/issues/450 libhidups 0x0003 0x2e66 0x0203 0x0000 0x0000 0x00 0x00 0x00 0x00 0x00 0x00 0x00000000 # https://www.salicru.com/sps-home.html libhidups 0x0003 0x2e66 0x0300 0x0000 0x0000 0x00 0x00 0x00 0x00 0x00 0x00 0x00000000 # https://www.salicru.com/sps-850-adv-t.html libhidups 0x0003 0x2e66 0x0302 0x0000 0x0000 0x00 0x00 0x00 0x00 0x00 0x00 0x00000000 # Powervar # Powervar libhidups 0x0003 0x4234 0x0002 0x0000 0x0000 0x00 0x00 0x00 0x00 0x00 0x00 0x00000000 # Ablerex 625L USB (Note: earlier best-fit was "krauler_subdriver" before PR #1135) libhidups 0x0003 0xffff 0x0000 0x0000 0x0000 0x00 0x00 0x00 0x00 0x00 0x00 0x00000000 nut-2.8.1/scripts/hotplug/libhidups.in0000644000175000017500000000067214273170601014743 00000000000000#!/bin/sh # This script changes the permissions and ownership of a USB device under # /proc/bus/usb to grant access to this device to users in the nut group. # # Ownership is set to root.@RUN_AS_GROUP@, permissions are set to 0664. # # Arguments : # ----------- # ACTION=[add|remove] # DEVICE=/proc/bus/usb/BBB/DDD # TYPE=usb if [ "$ACTION" = "add" -a "$TYPE" = "usb" ]; then chown root:@RUN_AS_GROUP@ "$DEVICE" chmod 0664 "$DEVICE" fi nut-2.8.1/scripts/hotplug/Makefile.am0000644000175000017500000000116514501607135014463 00000000000000EXTRA_DIST = README if WITH_HOTPLUG hotplugusbdir = $(hotplugdir)/usb dist_hotplugusb_DATA = libhid.usermap hotplugusb_SCRIPTS = libhidups else # Part of dist tarball, regardless of use for current build: EXTRA_DIST += libhid.usermap endif MAINTAINERCLEANFILES = Makefile.in .dirstamp # Generated by configure script: DISTCLEANFILES = libhidups # We should never remove this one, apart from a distclean-check # or stronger... # Generated by autogen.sh and needed to run the configure script # (technically, generated by tools/nut-usbinfo.pl script among # GENERATED_USB_OS_FILES): MAINTAINERCLEANFILES += libhid.usermap nut-2.8.1/scripts/hotplug/README0000644000175000017500000000220614501607135013304 00000000000000Desc: Hotplug script for NUT USB drivers File: scripts/hotplug/README Date: 8 January 2007 Auth: Arnaud Quette This document introduces Linux Hotplug script for NUT USB drivers (usbhid-ups, bcmxcp_usb and tripplite_usb). These are needed, on older Linux systems, to ensure the right privileges are set on the usb files (i.e. allowing nut user to read AND write to the UPS device). Alternative ----------- For newer 2.6 kernels with the udev mechanism, you should use the scripts in scripts/udev instead of this one. Installation ------------ For most users, these files will be automatically installed in /etc/hotplug upon "make install", if that directory exists. You can specify an alternate directory by running: ./configure --with-hotplug-dir=DIR Manual installation ------------------- These scripts can be used with Linux 2.4 to 2.6.13. - possibly change libhidups to match NUT user - copy libhidups and libhid.usermap to /etc/hotplug/usb/ - make libhidups executable with: chmod a+x /etc/hotplug/usb/libhidups - call update-usb.usermap or equivalent if needed You can then plug your UPS, and start NUT. nut-2.8.1/scripts/subdriver/0000755000175000017500000000000014520277776013046 500000000000000nut-2.8.1/scripts/subdriver/gen-snmp-subdriver.sh0000755000175000017500000004107114501607135017040 00000000000000#!/bin/bash # # an auxiliary script to produce a "stub" snmp-ups subdriver from # SNMP data from a real agent or from dump files # # Version: 0.15 # # See also: docs/snmp-subdrivers.txt # # Copyright (C) # 2011 - 2012 Arnaud Quette # 2015 - 2022 Eaton (author: Arnaud Quette ) # 2011 - 2022 Jim Klimov # # 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 2 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, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # # TODO: # - Prepend sysDescription (.1.3.6.1.2.1.1.1.0) to have some more visibility # - extend to SNMP v3 (auth.) usage() { echo "Usage: $0 [options] [file]" echo "Options:" echo " -h, --help -- show this message and quit" echo " -n name -- subdriver name (use natural capitalization)" echo " -M DIRLIST -- colon separated list of directories to also search for MIBs" echo " -k -- keep temporary files (for debugging)" echo "" echo "mode 1: get SNMP data from a real agent" echo " -H host_address -- SNMP host IP address or name" echo " -c community -- SNMP v1 community name (default: public)" echo " -s XXXX -- override SNMP OID entry point (sysOID). Ex: '.1.3.6.1.4.1.534.10'" echo "" echo "mode 2: get data from files (snmpwalk dumps of 'sysOID' subtree)" echo " -s XXXX -- SNMP OID entry point (sysOID). Ex: '.1.3.6.1.4.1.534.6.6.7'" echo " file1 file2 -- read from files instead of an host (using Net SNMP)" echo " file1: numeric SNMP walk (snmpwalk -On ... )" echo " file2: string SNMP walk (snmpwalk -Os ... )" echo "" echo "mode 3: get data from 1 file (numeric snmpwalk dump of the whole SNMP tree)" echo " The sysOID is extracted from the dump, and only the pointed subtree is used" echo " A MIB file MUST be provided, and is used to produce the string SNMP walk" echo " file1 -- read from file instead of an host (using Net SNMP)" echo " file1: numeric SNMP walk (snmpwalk -On ... )" echo "" echo "Notes:" echo " For both modes, prefer to copy the specific MIB file(s) for your device in the $0 script directory" echo " So that it is automatically taken into account for the string name resolution of OIDs" echo " Otherwise, use \"-M.\" option" echo "" echo "Example:" echo "mode 1: $0 -H 192.168.0.1 -n mibname -c mycommunity" echo "mode 2: (using sysOID .1.3.6.1.4.1.534.6.6.7)" echo " snmpwalk -On -v1 -c mycommunity 192.168.0.1 .1.3.6.1.4.1.534.6.6.7 2>/dev/null 1> numeric-walk-file" echo " snmpwalk -Os -v1 -m ALL -M+. -c mycommunity 192.168.0.1 .1.3.6.1.4.1.534.6.6.7 2>/dev/null 1> string-walk-file" echo " $0 -s .1.3.6.1.4.1.534.6.6.7 numeric-walk-file string-walk-file" echo "mode 3:" echo " snmpwalk -On -v1 -c mycommunity 192.168.0.1 .1 2>/dev/null 1> numeric-walk-file" echo " $0 numeric-walk-file" echo "" echo " You may alos need to install additional packages:" echo " - 'snmp' package (on Debian) for the base commands (snmpget, snmpwalk, snmptranslate)" echo " - 'snmp-mibs-downloader' package (on Debian) to get all standard MIBs" } # variables DRIVER="" KEEP="" HOSTNAME="" MIBS_DIRLIST="+." COMMUNITY="public" DEVICE_SYSOID="" SYSOID="" MODE=0 # constants NAME=gen-snmp-subdriver TMPDIR="${TEMPDIR:-/tmp}" SYSOID_NUMBER=".1.3.6.1.2.1.1.2.0" DEBUG="`mktemp "$TMPDIR/$NAME-DEBUG.XXXXXX"`" DFL_NUMWALKFILE="`mktemp "$TMPDIR/$NAME-NUMWALK.XXXXXX"`" DFL_STRWALKFILE="`mktemp "$TMPDIR/$NAME-STRWALK.XXXXXX"`" TMP_NUMWALKFILE="`mktemp "$TMPDIR/$NAME-TMP-NUMWALK.XXXXXX"`" TMP_STRWALKFILE="`mktemp "$TMPDIR/$NAME-TMP-STRWALK.XXXXXX"`" get_snmp_data() { # 1) get the sysOID (points the mfr specif MIB), apart if there's an override if [ -z "$SYSOID" ] then SYSOID="`snmpget -On -v1 -c "$COMMUNITY" -Ov "$HOSTNAME" "$SYSOID_NUMBER" | cut -d' ' -f2`" echo "sysOID retrieved: ${SYSOID}" else echo "Using the provided sysOID override ($SYSOID)" fi DEVICE_SYSOID="$SYSOID" OID_COUNT=0 while (test "$OID_COUNT" -eq 0) do # 2) get the content of the mfr specif MIB echo "Retrieving SNMP information. This may take some time" snmpwalk -On -v1 -c "$COMMUNITY" "$HOSTNAME" "$SYSOID" 2>/dev/null 1> "$DFL_NUMWALKFILE" snmpwalk -Os -v1 -m ALL -M"$MIBS_DIRLIST" -c "$COMMUNITY" "$HOSTNAME" "$SYSOID" 2>/dev/null 1> "$DFL_STRWALKFILE" # 3) test return value of the walk, and possibly ramp-up the path to get something. # The sysOID mechanism only works if we're pointed somehow in the right direction # i.e. doesn't work if sysOID is .1.3.6.1.4.1.705.1 and data is at .1.3.6.1.4.1.534... # Ex: sysOID = ".1.X.Y.Z" # try with ".1.X.Y.Z", if fails try with .1.X.Y", if fails try with .1.X"... OID_COUNT="`cat $NUMWALKFILE | wc -l`" if [ $OID_COUNT -eq 0 ]; then # ramp-up the provided sysOID by removing the last .x part SYSOID=${SYSOID%.*} echo "Warning: sysOID provided no data! Trying with a level up using $SYSOID" fi done return $OID_COUNT } generate_C() { # create file names, lowercase LDRIVER="`echo "$DRIVER" | tr A-Z a-z`" UDRIVER="`echo "$DRIVER" | tr a-z A-Z`" # keep dashes in name for files CFILE="$LDRIVER-mib.c" HFILE="$LDRIVER-mib.h" # but replace with underscores for the structures and defines LDRIVER="`echo "$LDRIVER" | tr - _`" UDRIVER="`echo "$UDRIVER" | tr - _`" # generate header file # NOTE: with <<-EOF leading TABs are all stripped echo "Creating $HFILE" cat > "$HFILE" <<-EOF /* ${HFILE} - subdriver to monitor ${DRIVER} SNMP devices with NUT * * Copyright (C) * 2011 - 2016 Arnaud Quette * * 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 2 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, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef ${UDRIVER}_MIB_H #define ${UDRIVER}_MIB_H #include "main.h" #include "snmp-ups.h" extern mib2nut_info_t ${LDRIVER}; #endif /* ${UDRIVER}_MIB_H */ EOF # generate source file # create heading boilerblate # NOTE: with <<-EOF leading TABs are all stripped echo "Creating $CFILE" cat > "$CFILE" <<-EOF /* ${CFILE} - subdriver to monitor ${DRIVER} SNMP devices with NUT * * Copyright (C) * 2011 - 2016 Arnaud Quette * * Note: this subdriver was initially generated as a "stub" by the * gen-snmp-subdriver script. It must be customized! * * 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 2 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, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "${HFILE}" #define ${UDRIVER}_MIB_VERSION "0.1" #define ${UDRIVER}_SYSOID "${DEVICE_SYSOID}" /* To create a value lookup structure (as needed on the 2nd line of the example * below), use the following kind of declaration, outside of the present snmp_info_t[]: * static info_lkp_t onbatt_info[] = { * { 1, "OB" }, * { 2, "OL" }, * { 0, NULL } * }; */ /* ${UDRIVER} Snmp2NUT lookup table */ static snmp_info_t ${LDRIVER}_mib[] = { /* Data format: * { info_type, info_flags, info_len, OID, dfl, flags, oid2info }, * * info_type: NUT INFO_ or CMD_ element name * info_flags: flags to set in addinfo * info_len: length of strings if ST_FLAG_STRING, multiplier otherwise * OID: SNMP OID or NULL * dfl: default value * flags: snmp-ups internal flags (FIXME: ...) * oid2info: lookup table between OID and NUT values * * Example: * { "input.voltage", 0, 0.1, ".1.3.6.1.4.1.705.1.6.2.1.2.1", "", SU_INPUT_1, NULL }, * { "ups.status", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.705.1.7.3.0", "", SU_FLAG_OK | SU_STATUS_BATT, onbatt_info }, * * To create a value lookup structure (as needed on the 2nd line), use the * following kind of declaration, outside of the present snmp_info_t[]: * static info_lkp_t onbatt_info[] = { * { 1, "OB" }, * { 2, "OL" }, * { 0, NULL } * }; */ /* standard MIB items; if the vendor MIB contains better OIDs for * this (e.g. with daisy-chain support), consider adding those here */ EOF # Same file, indented text (TABs not stripped): cat >> "$CFILE" < /dev/null if [ $? -eq 0 ]; then ST_FLAG_TYPE="ST_FLAG_STRING" SU_INFOSIZE="SU_INFOSIZE" else ST_FLAG_TYPE="0" SU_INFOSIZE="1" fi # get the matching numeric OID NUM_OID="`sed -n "${LINENB}p" "${NUMWALKFILE}" | cut -d' ' -f1`" printf "\t/* ${FULL_STR_OID} */\n\t{ \"unmapped.${STR_OID}\", ${ST_FLAG_TYPE}, ${SU_INFOSIZE}, \"${NUM_OID}\", NULL, SU_FLAG_OK, NULL },\n" done < "${STRWALKFILE}" >> "${CFILE}" # append footer (TABs not stripped): cat >> "$CFILE" <&2 exit 1 fi done # check that the needed parameters are provided, depending on the mode if [ -z "$NUMWALKFILE" ]; then # mode 1: directly get SNMP data from a real agent echo "Mode 1 selected" MODE=1 NUMWALKFILE="$DFL_NUMWALKFILE" STRWALKFILE="$DFL_STRWALKFILE" # check if Net SNMP is available if [ -z "`command -v snmpget`" -o -z "`command -v snmpwalk`" ] && \ [ -z "`which snmpget`" -o -z "`which snmpwalk`" ]; then echo "Net SNMP not found! snmpget and snmpwalk commands are required." >&2 exit 1 fi # hostname is also mandatory while [ -z "$HOSTNAME" ]; do printf "\n\tPlease enter the SNMP host IP address or name.\n" read -p "SNMP host IP name or address: " HOSTNAME < /dev/tty if echo "$HOSTNAME" | grep -E -q '[^a-zA-Z0-9.-]'; then echo "Please use only letters, digits, dash and period character" HOSTNAME="" fi done # get data from the agent get_snmp_data else # no string walk provided, so mode 3 if [ -z "$STRWALKFILE" ]; then # mode 3: get data from 1 file, # Filter according to sysOID on the specific subtree # Generate the numeric SNMP walk using this output # then use snmptranslate to get the string OIDs and generated the string SNMP walk echo "Mode 3 selected" MODE=3 RAWWALKFILE="$NUMWALKFILE" NUMWALKFILE="$DFL_NUMWALKFILE" STRWALKFILE="$DFL_STRWALKFILE" # check for actual file existence if [ ! -f "$RAWWALKFILE" ]; then echo "SNMP walk dump file is missing on disk. Try --help for more info." >&2 exit 1 fi # Extract the sysOID # Format is "1.3.6.1.2.1.1.2.0 = OID: 1.3.6.1.4.1.4555.1.1.1" DEVICE_SYSOID="`grep 1.3.6.1.2.1.1.2.0 "$RAWWALKFILE" | cut -d' ' -f4`" if [ -n "$DEVICE_SYSOID" ]; then echo "Found sysOID $DEVICE_SYSOID" else echo "SNMP sysOID is missing in file. Try --help for more info." >&2 exit 1 fi # Switch to the entry point, and extract the subtree # Extract the numeric walk echo -n "Extracting numeric SNMP walk..." grep "$DEVICE_SYSOID" "$RAWWALKFILE" | grep -E -v "1.3.6.1.2.1.1.2.0" 2>/dev/null 1> "$NUMWALKFILE" echo " done" # Create the string walk from a translation of the numeric one echo -n "Converting string SNMP walk..." while IFS=' = ' read NUM_OID OID_VALUE do STR_OID="`snmptranslate -Os -m ALL -M+. "$NUM_OID" 2>/dev/null`" # Uncomment the below line to get debug logs #echo "Got: $STR_OID = $OID_VALUE" printf "." echo "$STR_OID = $OID_VALUE" >> "$STRWALKFILE" done < "$NUMWALKFILE" echo " done" else # mode 2: get data from files echo "Mode 2 selected" MODE=2 # get sysOID value from command line, if needed while [ -z "$SYSOID" ]; do echo " Please enter the value of sysOID, as displayed by snmp-ups. For example '.1.3.6.1.4.1.2254.2.4'. You can get it using: snmpget -v1 -c XXX $SYSOID_NUMBER" read -p "Value of sysOID: " SYSOID < /dev/tty if echo "$SYSOID" | grep -E -q '[^0-9.]'; then echo "Please use only the numeric form, with dots and digits" SYSOID="" fi done # check for actual files existence if [ ! -f "$NUMWALKFILE" -o ! -f "$STRWALKFILE" ]; then echo "SNMP walk dump files are missing on disk. Try --help for more info." >&2 exit 1 fi fi fi # delete temporary files: this is called just before exiting. cleanup () { rm -f "$DEBUG $DFL_NUMWALKFILE $TMP_NUMWALKFILE $DFL_STRWALKFILE $TMP_STRWALKFILE" } if [ -n "$KEEP" ]; then trap cleanup EXIT fi # prompt use for name of driver while [ -z "$DRIVER" ]; do echo " Please enter a name for this driver. Use only letters and numbers. Use natural (upper- and lowercase) capitalization, e.g., 'Belkin', 'APC'." read -p "Name of subdriver: " DRIVER < /dev/tty if echo "$DRIVER" | grep -E -q '[^a-zA-Z0-9]'; then echo "Please use only letters and digits" DRIVER="" fi done # remove blank and "End of MIB" lines grep -E -e "^[[:space:]]?$" -e "End of MIB" -v "${NUMWALKFILE}" > "${TMP_NUMWALKFILE}" grep -E -e "^[[:space:]]?$" -e "End of MIB" -v "${STRWALKFILE}" > "${TMP_STRWALKFILE}" NUMWALKFILE="${TMP_NUMWALKFILE}" STRWALKFILE="${TMP_STRWALKFILE}" # FIXME: sanity checks (! -z contents -a same `wc -l`) NUM_OID_COUNT="`cat "$NUMWALKFILE" | wc -l`" STR_OID_COUNT="`cat "$STRWALKFILE" | wc -l`" echo "SNMP OIDs extracted = $NUM_OID_COUNT / $NUM_OID_COUNT" generate_C # Display the remaining tasks cat < debuginfo 2>&1 # # Usage: cat debuginfo | gen-usbhid-subdriver.sh # # See also: docs/hid-subdrivers.txt usage() { echo "Usage: $0 [options] [file] < debuginfo" echo "with data prepared by a driver walk:" echo " drivers/usbhid-ups -s ups -DD -u root -x vendorid=XXXX -x productid=XXXX \\" echo " -x port=auto -x explore -d1 > debuginfo 2>&1" echo "Options:" echo " -h, --help -- show this message and quit" echo " -n name -- driver name (use natural capitalization)" echo " -v XXXX -- vendor id (learned from debuginfo by default)" echo " -p XXXX -- product id (learned from debuginfo by default)" echo " -k -- keep temporary files (for debugging)" echo " file -- read from file instead of stdin" } DRIVER="" VENDORID="" PRODUCTID="" KEEP="" while [ $# -gt 0 ]; do if [ $# -gt 1 -a "$1" = "-n" ]; then DRIVER="$2" shift 2 elif [ $# -gt 1 -a "$1" = "-v" ]; then VENDORID="$2" shift 2 elif [ $# -gt 1 -a "$1" = "-p" ]; then PRODUCTID="$2" shift 2 elif [ "$1" = "-k" ]; then KEEP=yes shift elif echo "$1" | grep -qv '^-'; then FILE="$1" shift elif [ "$1" = "--help" -o "$1" = "-h" ]; then usage exit 0 else echo "Illegal option $1. Try --help for more info." >&2 exit 1 fi done # delete temporary files: this is called just before exiting. cleanup () { rm -f "$DEBUG" "$UTABLE" "$USAGES" "$SUBST" "$SEDFILE" "$NEWUTABLE" } if [ -z "$KEEP" ]; then trap cleanup EXIT fi NAME=gen-usbhid-subdriver TMPDIR="${TEMPDIR:-/tmp}" DEBUG=`mktemp "$TMPDIR/$NAME-DEBUG.XXXXXX"` UTABLE=`mktemp "$TMPDIR/$NAME-UTABLE.XXXXXX"` USAGES=`mktemp "$TMPDIR/$NAME-USAGES.XXXXXX"` SUBST=`mktemp "$TMPDIR/$NAME-SUBST.XXXXXX"` SEDFILE=`mktemp "$TMPDIR/$NAME-SEDFILE.XXXXXX"` NEWUTABLE=`mktemp "$TMPDIR/$NAME-NEWUTABLE.XXXXXX"` # save standard input to a file if [ -z "$FILE" ]; then FILE="$DEBUG" cat > "$DEBUG" fi # prompt use for name of driver while [ -z "$DRIVER" ]; do echo " Please enter a name for this driver. Use only letters and numbers. Use natural (upper- and lowercase) capitalization, e.g., 'Belkin', 'APC'." read -p "Name of subdriver: " DRIVER < /dev/tty if echo $DRIVER | grep -E -q '[^a-zA-Z0-9]'; then echo "Please use only letters and digits" DRIVER="" fi done # try to determine product and vendor id, if not specified by user [ -n "$VENDORID" ] || VENDORID=`cat "$FILE" | sed -n 's/.*- VendorID: \([0-9a-fA-F]*\).*/\1/p' | tail -1` [ -n "$PRODUCTID" ] || PRODUCTID=`cat "$FILE" | sed -n 's/.*- ProductID: \([0-9a-fA-F]*\).*/\1/p' | tail -1` # prompt for productid, vendorid if necessary if [ -z "$VENDORID" ]; then read -p "Vendor ID: " VENDORID < /dev/tty fi if [ -z "$PRODUCTID" ]; then read -p "Product ID: " PRODUCTID < /dev/tty fi LDRIVER=`echo $DRIVER | tr A-Z a-z` UDRIVER=`echo $DRIVER | tr a-z A-Z` CFILE="$LDRIVER-hid.c" HFILE="$LDRIVER-hid.h" # extract Usage Table cat "$FILE" | sed -n 's/.*Path: \([^,][^,]*\), Type:.*/\1/p' > "$UTABLE" # extract Usage codes cat "$UTABLE" | tr '.' $'\n' | sort -u > "$USAGES" # make up dummy names for unknown usages count=0 cat "$USAGES" | grep -E '[0-9a-fA-F][0-9a-fA-F][0-9a-fA-F][0-9a-fA-F][0-9a-fA-F][0-9a-fA-F][0-9a-fA-F][0-9a-fA-F]' |\ while read U; do count=`expr $count + 1` echo "$U $UDRIVER$count" done > "$SUBST" # create an sed script for substitutions cat "$SUBST" | sed 's/\(.*\) \(.*\)/s!\1!\2!g;/' > "$SEDFILE" # create modified usage table sed -f "$SEDFILE" < "$UTABLE" > "$NEWUTABLE" # generate header file echo "Creating $HFILE" cat > "$HFILE" < * 2005 - 2006 Peter Selinger * 2008 - 2009 Arjen de Korte * * 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 2 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, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef ${UDRIVER}_HID_H #define ${UDRIVER}_HID_H #include "usbhid-ups.h" extern subdriver_t ${LDRIVER}_subdriver; #endif /* ${UDRIVER}_HID_H */ EOF # generate source file echo "Creating $CFILE" cat > "$CFILE" < * 2005 - 2006 Peter Selinger * 2008 - 2009 Arjen de Korte * 2013 Charles Lepple * * TODO: Add year and name for new subdriver author (contributor) * Mention in docs/acknowledgements.txt if this is a vendor contribution * * Note: this subdriver was initially generated as a "stub" by the * gen-usbhid-subdriver script. It must be customized. * * 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 2 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, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "usbhid-ups.h" #include "${HFILE}" #include "main.h" /* for getval() */ #include "usb-common.h" #define ${UDRIVER}_HID_VERSION "${DRIVER} HID 0.1" /* FIXME: experimental flag to be put in upsdrv_info */ /* ${DRIVER} */ #define ${UDRIVER}_VENDORID 0x${VENDORID} /* USB IDs device table */ static usb_device_id_t ${LDRIVER}_usb_device_table[] = { /* ${DRIVER} */ { USB_DEVICE(${UDRIVER}_VENDORID, 0x${PRODUCTID}), NULL }, /* Terminating entry */ { 0, 0, NULL } }; /* --------------------------------------------------------------- */ /* Vendor-specific usage table */ /* --------------------------------------------------------------- */ /* ${UDRIVER} usage table */ static usage_lkp_t ${LDRIVER}_usage_lkp[] = { EOF cat "$SUBST" | sed 's/\(.*\) \(.*\)/\t{ "\2",\t0x\1 },/' >> "$CFILE" cat >> "$CFILE" <> "$CFILE" <> "$CFILE" <Product; } static const char *${LDRIVER}_format_mfr(HIDDevice_t *hd) { return hd->Vendor ? hd->Vendor : "${DRIVER}"; } static const char *${LDRIVER}_format_serial(HIDDevice_t *hd) { return hd->Serial; } /* this function allows the subdriver to "claim" a device: return 1 if * the device is supported by this subdriver, else 0. */ static int ${LDRIVER}_claim(HIDDevice_t *hd) { int status = is_usb_device_supported(${LDRIVER}_usb_device_table, hd); switch (status) { case POSSIBLY_SUPPORTED: /* by default, reject, unless the productid option is given */ if (getval("productid")) { return 1; } possibly_supported("${DRIVER}", hd); return 0; case SUPPORTED: return 1; case NOT_SUPPORTED: default: return 0; } } subdriver_t ${LDRIVER}_subdriver = { ${UDRIVER}_HID_VERSION, ${LDRIVER}_claim, ${LDRIVER}_utab, ${LDRIVER}_hid2nut, ${LDRIVER}_format_model, ${LDRIVER}_format_mfr, ${LDRIVER}_format_serial, fix_report_desc, /* may optionally be customized, see cps-hid.c for example */ }; EOF cat < ls /files/etc/nut/ nut.conf/ = (none) upsd.users/ = (none) upsmon.conf = (none) ups.conf/ = (none) upsd.conf/ = (none + or using: + augtool> match /files/etc/nut/* /files/etc/nut/nut.conf = (none) /files/etc/nut/upsd.users = (none) /files/etc/nut/upsmon.conf = (none) /files/etc/nut/ups.conf = (none) /files/etc/nut/upsd.conf = (none) NOTE: if you don't see anything, you may search for error messages by using: + augtool> ls /augeas/files/etc/nut/*/errors and augtool> get /augeas/files/etc/nut/ups.conf/error/message /augeas/files/etc/nut/ups.conf/error/message = Permission denied - create a new device entry (in ups.conf), called 'augtest': augtool> set /files/etc/nut/ups.conf/augtest/driver dummy-ups augtool> set /files/etc/nut/ups.conf/augtest/port auto augtool> save - list the devices using the 'usbhid-ups' driver: augtool> match /files/etc/nut/ups.conf/*/driver dummy-ups C ~ A library is available for C programs, along with pkg-config support. You can get the compilation and link flags using the following code in your configure script or Makefile: CFLAGS="`pkg-config --silence-errors --cflags augeas`" LDFLAGS="`pkg-config --silence-errors --libs augeas`" Here is an code sample using this library for NUT configuration: -------------------------------------------------------------------------------- augeas *a = aug_init(NULL, NULL, AUG_NONE); ret = aug_match(a, "/files/etc/nut/*", &matches_p); ret = aug_set(a, "/files/etc/nut/ups.conf/augtest/driver", "dummy-ups"); ret = aug_set(a, "/files/etc/nut/ups.conf/augtest/port", "auto"); ret = aug_save(a); -------------------------------------------------------------------------------- Python ~~~~~~ The `augeas` class abstracts access to the configuration files. $ python Python 2.5.1 (r251:54863, Apr 8 2008, 01:19:33) [GCC 4.3.0 20080404 (Red Hat 4.3.0-6)] on linux2 Type "help", "copyright", "credits" or "license" for more information. >>> import augeas >>> a = augeas.augeas() >>> a.match("/files/etc/nut/*") ['/files/etc/nut/upsd.users', '/files/etc/nut/upsmon.conf', '/files/etc/nut/ups.conf', '/files/etc/nut/upsd.conf'] >>> a.set("/files/etc/nut/ups.conf/augtest/driver", "dummy-ups") True >>> a.set("/files/etc/nut/ups.conf/augtest/port", "auto") True >>> a.save() True >>> $ grep -A 2 augtest /etc/nut/ups.conf [augtest] driver=dummy-ups port=auto Perl ~~~~ The Perl binding is available through CPAN and packages. use Config::Augeas; my $aug = Config::Augeas->new( root => $aug_root ) ; my @a = $aug->match("/files/etc/nut/*") ; my $nb = $aug->count_match("/files/etc/nut/*") ; $aug->set("/files/etc/nut/ups.conf/augtest/driver", "dummy-ups") ; $aug->set("/files/etc/nut/ups.conf/augtest/port", "auto") ; $aug->save ; Test the conformity testing module ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Existing configuration files can be tested for conformity. To do so, use: $ augparse -I ./ ./test_nut.aug Complete configuration wizard example ------------------------------------- Here is a Python example that generate a complete and usable standalone configuration: -------------------------------------------------------------------------------- import augeas device_name="dev1" driver_name="usbhid-ups" port_name="auto" a = augeas.augeas() # Generate nut.conf a.set("/files/etc/nut/nut.conf/MODE", "standalone") # Generate ups.conf # FIXME: chroot, driverpath? a.set(("/files/etc/nut/ups.conf/%s/driver" % device_name), driver_name) a.set(("/files/etc/nut/ups.conf/%s/port" % device_name), port_name) # Generate upsd.conf a.set("/files/etc/nut/upsd.conf/#comment[1]", "just to touch the file!") # Generate upsd.users user = "admin" a.set(("/files/etc/nut/upsd.users/%s/password" % user), "dummypass") a.set(("/files/etc/nut/upsd.users/%s/actions/SET" % user), "") # FIXME: instcmds lens should be fixed, as per the above rule a.set(("/files/etc/nut/upsd.users/%s/instcmds" % user), "ALL") monuser = "monuser" monpasswd = "******" a.set(("/files/etc/nut/upsd.users/%s/password" % monuser), monpasswd) a.set(("/files/etc/nut/upsd.users/%s/upsmon" % monuser), "primary") # Generate upsmon.conf a.set("/files/etc/nut/upsmon.conf/MONITOR/system/upsname", device_name) # Note: we prefer to omit localhost, not to be bound to a specific # entry in /etc/hosts, and thus be more generic #a.set("/files/etc/nut/upsmon.conf/MONITOR/system/hostname", "localhost") a.set("/files/etc/nut/upsmon.conf/MONITOR/powervalue", "1") a.set("/files/etc/nut/upsmon.conf/MONITOR/username", monuser) a.set("/files/etc/nut/upsmon.conf/MONITOR/password", monpasswd) a.set("/files/etc/nut/upsmon.conf/MONITOR/type", "primary") # FIXME: glitch on the generated content a.set("/files/etc/nut/upsmon.conf/SHUTDOWNCMD", "/sbin/shutdown -h +0") # save config a.save() a.close() -------------------------------------------------------------------------------- nut-2.8.1/scripts/augeas/nutupsconf.aug.tpl0000644000175000017500000000331214273170601015705 00000000000000(* Module: NutUpsConf Parses @CONFPATH@/ups.conf Author: Raphael Pinson Frederic Bohe Arnaud Quette About: License This file is licensed under the GPL. About: Lens Usage Sample usage of this lens in augtool * Print all drivers used > print /files/@CONFPATH@/ups.conf/*/driver About: Configuration files This lens applies to @CONFPATH@/ups.conf. See . *) module NutUpsConf = autoload ups_xfm (************************************************************************ * Group: UPS.CONF *************************************************************************) let ups_comment = IniFile.comment IniFile.comment_re IniFile.comment_default let ups_sep = IniFile.sep IniFile.sep_re IniFile.sep_default let ups_global = "chroot" | "driverpath" | "maxstartdelay" | "maxretry" | "retrydelay" | "pollinterval" | "synchronous" | "user" let ups_fields = "driver" | "port" | "sdorder" | "desc" | "nolock" | "ignorelb" | "maxstartdelay" | "synchronous" @SPECIFIC_DRV_VARS@ let ups_entry = IniFile.indented_entry (ups_global|ups_fields) ups_sep ups_comment let ups_title = IniFile.indented_title IniFile.record_re let ups_record = IniFile.record ups_title ups_entry let ups_lns = IniFile.lns ups_record ups_comment let ups_filter = (incl "@CONFPATH@/ups.conf") . Util.stdexcl let ups_xfm = transform ups_lns ups_filter nut-2.8.1/scripts/augeas/tests/0000755000175000017500000000000014520277776013450 500000000000000nut-2.8.1/scripts/augeas/tests/test_nut.aug0000644000175000017500000000744514500336654015732 00000000000000(* Tests for the Nut module *) module Test_nut = let nut_conf = " MODE=standalone " test NutNutConf.nut_lns get nut_conf = { } { "MODE" = "standalone" } let ups_conf = " [testups] driver = dummy-ups port = auto desc = \"Dummy UPS\" " test NutUpsConf.ups_lns get ups_conf = { } { "testups" { "driver" = "dummy-ups" } { "port" = "auto" } { "desc" = "\"Dummy UPS\"" } } let upsd_conf = " MAXAGE 30 TRACKINGDELAY 600 ALLOW_NO_DEVICE 1 LISTEN 0.0.0.0 3493 MAXCONN 1024 " test NutUpsdConf.upsd_lns get upsd_conf = { } { "MAXAGE" = "30" } { "TRACKINGDELAY" = "600" } { "ALLOW_NO_DEVICE" = "1" } { "LISTEN" { "interface" = "0.0.0.0" } { "port" = "3493" } } { "MAXCONN" = "1024" } let upsd_users = " [admin] password = upsman actions = SET FSD instcmds = ALL [pfy] password = duh instcmds = test.panel.start instcmds = test.panel.stop [upswired] password = blah upsmon primary [observer] password = abcd upsmon secondary " test NutUpsdUsers.upsd_users_lns get upsd_users = { } { "admin" { "password" = "upsman" } { "actions" { "SET" } { "FSD" } } { "instcmds" = "ALL" } { } } { "pfy" { "password" = "duh" } { "instcmds" = "test.panel.start" } { "instcmds" = "test.panel.stop" } { } } { "upswired" { "password" = "blah" } { "upsmon" = "primary" } { } } { "observer" { "password" = "abcd" } { "upsmon" = "secondary" } } let upsmon_conf = " MONITOR testups@localhost 1 upswired blah primary MINSUPPLIES 1 SHUTDOWNCMD /sbin/shutdown -h +0 POLLFREQ 5 POLLFREQALERT 5 HOSTSYNC 30 DEADTIME 15 POWERDOWNFLAG /etc/killpower RBWARNTIME 43200 NOCOMMWARNTIME 300 FINALDELAY 5 " test NutUpsmonConf.upsmon_lns get upsmon_conf = { } { "MONITOR" { "system" { "upsname" = "testups" } { "hostname" = "localhost" } } { "powervalue" = "1" } { "username" = "upswired" } { "password" = "blah" } { "type" = "primary" } } { } { "MINSUPPLIES" = "1" } { "SHUTDOWNCMD" = "/sbin/shutdown -h +0" } { "POLLFREQ" = "5" } { "POLLFREQALERT" = "5" } { "HOSTSYNC" = "30" } { "DEADTIME" = "15" } { "POWERDOWNFLAG" = "/etc/killpower" } { "RBWARNTIME" = "43200" } { "NOCOMMWARNTIME" = "300" } { "FINALDELAY" = "5" } let upsset_conf = " I_HAVE_SECURED_MY_CGI_DIRECTORY " test NutUpssetConf.upsset_lns get upsset_conf = { } { "auth" = "I_HAVE_SECURED_MY_CGI_DIRECTORY" } let upssched_conf = " CMDSCRIPT /upssched-cmd PIPEFN /var/state/ups/upssched/upssched.pipe LOCKFN /var/state/ups/upssched/upssched.lock AT COMMBAD * START-TIMER upsgone 10 AT COMMOK myups@localhost CANCEL-TIMER upsgone AT ONLINE * EXECUTE ups-back-on-line " test NutUpsschedConf.upssched_lns get upssched_conf = { } { "CMDSCRIPT" = "/upssched-cmd" } { "PIPEFN" = "/var/state/ups/upssched/upssched.pipe" } { "LOCKFN" = "/var/state/ups/upssched/upssched.lock" } { "AT" { "notifytype" = "COMMBAD" } { "upsname" = "*" } { "START-TIMER" { "timername" = "upsgone" } { "interval" = "10" } } } { "AT" { "notifytype" = "COMMOK" } { "upsname" = "myups@localhost" } { "CANCEL-TIMER" { "timername" = "upsgone" } } } { "AT" { "notifytype" = "ONLINE" } { "upsname" = "*" } { "EXECUTE" { "command" = "ups-back-on-line" } } } let hosts_conf = " MONITOR myups@localhost \"Local UPS\" MONITOR su2200@10.64.1.1 \"Finance department\" MONITOR matrix@shs-server.example.edu \"Sierra High School data room #1\" " test NutHostsConf.hosts_lns get hosts_conf = { } { "MONITOR" { "system" = "myups@localhost" } { "description" = "Local UPS" } } { "MONITOR" { "system" = "su2200@10.64.1.1" } { "description" = "Finance department" } } { "MONITOR" { "system" = "matrix@shs-server.example.edu" } { "description" = "Sierra High School data room #1" } } nut-2.8.1/scripts/augeas/nuthostsconf.aug.in0000644000175000017500000000236314273170601016052 00000000000000(* Module: NutHostsConf Parses @CONFPATH@/hosts.conf Author: Frederic Bohe About: License This file is licensed under the GPL. About: Lens Usage Sample usage of this lens in augtool * Print all monitored upsd > print /files@CONFPATH@/hosts.conf/MONITOR About: Configuration files This lens applies to @CONFPATH@/hosts.conf. See . *) module NutHostsConf = autoload hosts_xfm (************************************************************************ * Group: HOSTS.CONF *************************************************************************) (* general *) let del_spc = Util.del_opt_ws "" let sep_spc = Util.del_ws_spc let eol = Util.eol let word = /[^"#; \t\n]+/ let empty = Util.empty let comment = Util.comment let quoted_string = del "\"" "\"" . store /[^"\n]+/ . del "\"" "\"" let hosts_notify = [ del_spc . key "MONITOR" . sep_spc . [ label "system" . store word . sep_spc ] . [ label "description" . quoted_string ] . eol ] let hosts_lns = (hosts_notify|comment|empty)* let hosts_filter = ( incl "@CONFPATH@/hosts.conf" ) . Util.stdexcl let hosts_xfm = transform hosts_lns hosts_filter nut-2.8.1/scripts/augeas/nutupsdconf.aug.in0000644000175000017500000000526614501607135015673 00000000000000(* Module: NutUpsdConf Parses @CONFPATH@/upsd.conf Author: Raphael Pinson Frederic Bohe Arnaud Quette About: License This file is licensed under the GPL. About: Lens Usage Sample usage of this lens in augtool * Print all network interface upsd will listen to > print /files@CONFPATH@/upsd.conf/LISTEN About: Configuration files This lens applies to @CONFPATH@/upsd.conf. See . *) module NutUpsdConf = autoload upsd_xfm (************************************************************************ * Group: UPSD.CONF *************************************************************************) (* general *) let sep_spc = Util.del_ws_spc let opt_spc = Util.del_opt_ws "" let eol = Util.eol let ip = /[0-9A-Za-z\.:]+/ let num = /[0-9]+/ let word = /[^"#; \t\n]+/ let empty = Util.empty let comment = Util.comment let path = word let upsd_maxage = [ opt_spc . key "MAXAGE" . sep_spc . store num . eol ] let upsd_trackingdelay = [ opt_spc . key "TRACKINGDELAY" . sep_spc . store num . eol ] let upsd_allow_no_device = [ opt_spc . key "ALLOW_NO_DEVICE" . sep_spc . store num . eol ] let upsd_statepath = [ opt_spc . key "STATEPATH" . sep_spc . store path . eol ] let upsd_listen = [ opt_spc . key "LISTEN" . sep_spc . [ label "interface" . store ip ] . [ sep_spc . label "port" . store num]? ] let upsd_listen_list = upsd_listen . eol let upsd_maxconn = [ opt_spc . key "MAXCONN" . sep_spc . store num . eol ] let upsd_certfile = [ opt_spc . key "CERTFILE" . sep_spc . store path . eol ] (************************************************************************ * MAXAGE seconds * TRACKINGDELAY seconds * ALLOW_NO_DEVICE Boolean * STATEPATH path * LISTEN interface port * Multiple lines each with one LISTEN address (or host name) and an optional * port may be specified. The default is to bind to IPv4 and IPv6 "localhost" * addresses (subject to CLI options `-4` or `-6` constraining IP version, * or system configuration or support), if no LISTEN addresses are specified. * LISTEN 127.0.0.1 * LISTEN 192.168.50.1 * LISTEN ::1 * LISTEN 2001:0db8:1234:08d3:1319:8a2e:0370:7344 * *************************************************************************) let upsd_other = upsd_maxage | upsd_trackingdelay | upsd_allow_no_device | upsd_statepath | upsd_listen_list | upsd_maxconn | upsd_certfile let upsd_lns = (upsd_other|comment|empty)* let upsd_filter = (incl "@CONFPATH@/upsd.conf") . Util.stdexcl let upsd_xfm = transform upsd_lns upsd_filter nut-2.8.1/scripts/augeas/gen-nutupsconf-aug.py.in0000755000175000017500000000767714501607135016737 00000000000000#!@PYTHON@ # Copyright (C) 2010 - Arnaud Quette # # 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 2 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, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # This program extracts all drivers specific variables, declared # using 'addvar()' and output a complete ups.conf lens for Augeas from __future__ import print_function import sys import re import glob import codecs # Return a sorted list of unique entries, based on the input 'list' def sortUnique(list): newVarList = [] prevVar = '' # sort the list list.sort() for curVariable in list: if curVariable != prevVar: newVarList.append(curVariable) prevVar = curVariable return newVarList # Grep for 'string' pattern in the text 'list', # excluding C/C++ styles comments # Return the list of matching lines def grep(string,list): matchList = [] expr = re.compile(string) for text in list: match = expr.search(text) if match != None: # Exclude comments exprComment = re.compile('(/\*([^*]|(\*+[^*/]))*\*+/)|(//.*)') if (exprComment.search(match.string) == None): matchList.append(match.string) return matchList if __name__ == '__main__': rawCount = 0 #global finalCount variableNames = [] specificVars = "" #global inLensContent #global finalLensContent Exceptionlist = ['../../drivers/main.c', '../../drivers/skel.c'] outputFilename = 'nutupsconf.aug.in' templateFilename = 'nutupsconf.aug.tpl' dirPrefix = '' if (len(sys.argv) == 2): dirPrefix = sys.argv[1] print(dirPrefix) # 1/ Extract all specific drivers parameters, in a sorted list with unique entries # 1.1/ List all drivers implementation files for filename in glob.glob('../../drivers/*.c'): # 1.2/ Exclude main.c, which defines addvar() and skel.c (example driver) if filename not in Exceptionlist: fd = codecs.open(filename, encoding='utf-8') # 1.3/ Grep for the "addvar(..." pattern matchResults = grep ('.*addvar[\ ]*\(.*(VAR_FLAG|VAR_VALUE)*,.*', fd) # 1.4/ Extract variable names for line in matchResults: if ("Could not addvar" in line): # Debug trace e.g. in snmp-ups.c continue row = line.split(',') if len(row) >= 2: # Absence of quotes indicate that we have a #define # Let's grep in .ch related files if (row[1].find('"') == -1): for defFilename in glob.glob(filename.replace('.c', '.[ch]')): defFd = codecs.open(defFilename, encoding='utf-8') matchString = '^#define.*' + row[1].replace('"', '').lstrip() + '.*' matchResult = grep (matchString, defFd) for varDefine in matchResult: # Now search for a string defRow = re.findall(r'"([^"]*)",?', varDefine) if (len(defRow) == 1): variableNames.append(defRow[0]) else: # Remove quotes variableNames.append(row[1].replace('"', '').lstrip()) # Filter multiply defined variables variableNames = sortUnique(variableNames) # Create the formated list of specific variables for name in variableNames: specificVars += " | \"%s\"\n" %(name) # 2/ Load the template lens tplFd = codecs.open(dirPrefix + templateFilename, encoding='utf-8') # 2.1/ Search for the pattern to replace outputText = tplFd.read() outputText = outputText.replace('@SPECIFIC_DRV_VARS@', specificVars) # 3/ Output final lens outFd = codecs.open(outputFilename, mode='w', encoding='utf-8') outFd.write(outputText) nut-2.8.1/scripts/augeas/Makefile.in0000644000175000017500000006064714520274662014277 00000000000000# Makefile.in generated by automake 1.16.5 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2021 Free Software Foundation, Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. @SET_MAKE@ VPATH = @srcdir@ am__is_gnu_make = { \ if test -z '$(MAKELEVEL)'; then \ false; \ elif test -n '$(MAKE_HOST)'; then \ true; \ elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \ true; \ else \ false; \ fi; \ } am__make_running_with_option = \ case $${target_option-} in \ ?) ;; \ *) echo "am__make_running_with_option: internal error: invalid" \ "target option '$${target_option-}' specified" >&2; \ exit 1;; \ esac; \ has_opt=no; \ sane_makeflags=$$MAKEFLAGS; \ if $(am__is_gnu_make); then \ sane_makeflags=$$MFLAGS; \ else \ case $$MAKEFLAGS in \ *\\[\ \ ]*) \ bs=\\; \ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ esac; \ fi; \ skip_next=no; \ strip_trailopt () \ { \ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ }; \ for flg in $$sane_makeflags; do \ test $$skip_next = yes && { skip_next=no; continue; }; \ case $$flg in \ *=*|--*) continue;; \ -*I) strip_trailopt 'I'; skip_next=yes;; \ -*I?*) strip_trailopt 'I';; \ -*O) strip_trailopt 'O'; skip_next=yes;; \ -*O?*) strip_trailopt 'O';; \ -*l) strip_trailopt 'l'; skip_next=yes;; \ -*l?*) strip_trailopt 'l';; \ -[dEDm]) skip_next=yes;; \ -[JT]) skip_next=yes;; \ esac; \ case $$flg in \ *$$target_option*) has_opt=yes; break;; \ esac; \ done; \ test $$has_opt = yes am__make_dryrun = (target_option=n; $(am__make_running_with_option)) am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkglibexecdir = $(libexecdir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ target_triplet = @target@ subdir = scripts/augeas ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/m4/ax_c___attribute__.m4 \ $(top_srcdir)/m4/ax_c_pragmas.m4 \ $(top_srcdir)/m4/ax_check_compile_flag.m4 \ $(top_srcdir)/m4/ax_compare_version.m4 \ $(top_srcdir)/m4/ax_realpath.m4 \ $(top_srcdir)/m4/ax_run_or_link_ifelse.m4 \ $(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \ $(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \ $(top_srcdir)/m4/lt~obsolete.m4 \ $(top_srcdir)/m4/nut_arg_with.m4 \ $(top_srcdir)/m4/nut_check_asciidoc.m4 \ $(top_srcdir)/m4/nut_check_aspell.m4 \ $(top_srcdir)/m4/nut_check_cppcheck.m4 \ $(top_srcdir)/m4/nut_check_headers_windows.m4 \ $(top_srcdir)/m4/nut_check_libavahi.m4 \ $(top_srcdir)/m4/nut_check_libfreeipmi.m4 \ $(top_srcdir)/m4/nut_check_libgd.m4 \ $(top_srcdir)/m4/nut_check_libgpiod.m4 \ $(top_srcdir)/m4/nut_check_libltdl.m4 \ $(top_srcdir)/m4/nut_check_libmodbus.m4 \ $(top_srcdir)/m4/nut_check_libneon.m4 \ $(top_srcdir)/m4/nut_check_libnetsnmp.m4 \ $(top_srcdir)/m4/nut_check_libnss.m4 \ $(top_srcdir)/m4/nut_check_libopenssl.m4 \ $(top_srcdir)/m4/nut_check_libpowerman.m4 \ $(top_srcdir)/m4/nut_check_libregex.m4 \ $(top_srcdir)/m4/nut_check_libsystemd.m4 \ $(top_srcdir)/m4/nut_check_libusb.m4 \ $(top_srcdir)/m4/nut_check_libwrap.m4 \ $(top_srcdir)/m4/nut_check_os.m4 \ $(top_srcdir)/m4/nut_check_pkgconfig.m4 \ $(top_srcdir)/m4/nut_check_python.m4 \ $(top_srcdir)/m4/nut_check_socketlib.m4 \ $(top_srcdir)/m4/nut_compiler_family.m4 \ $(top_srcdir)/m4/nut_func_getnameinfo_argtypes.m4 \ $(top_srcdir)/m4/nut_report_feature.m4 \ $(top_srcdir)/m4/nut_stash_warnings.m4 \ $(top_srcdir)/m4/nut_type_socklen_t.m4 \ $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/include/config.h CONFIG_CLEAN_FILES = nutnutconf.aug nutupsdconf.aug nutupsdusers.aug \ nutupsmonconf.aug nutupsschedconf.aug nuthostsconf.aug \ nutupssetconf.aug gen-nutupsconf-aug.py nutupsconf.aug CONFIG_CLEAN_VPATH_FILES = AM_V_P = $(am__v_P_@AM_V@) am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) am__v_P_0 = false am__v_P_1 = : AM_V_GEN = $(am__v_GEN_@AM_V@) am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) am__v_GEN_0 = @echo " GEN " $@; am__v_GEN_1 = AM_V_at = $(am__v_at_@AM_V@) am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) am__v_at_0 = @ am__v_at_1 = SOURCES = DIST_SOURCES = am__can_run_installinfo = \ case $$AM_UPDATE_INFO_DIR in \ n|no|NO) false;; \ *) (install-info --version) >/dev/null 2>&1;; \ esac am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; am__vpath_adj = case $$p in \ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ *) f=$$p;; \ esac; am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`; am__install_max = 40 am__nobase_strip_setup = \ srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'` am__nobase_strip = \ for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||" am__nobase_list = $(am__nobase_strip_setup); \ for p in $$list; do echo "$$p $$p"; done | \ sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \ $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \ if (++n[$$2] == $(am__install_max)) \ { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \ END { for (dir in files) print dir, files[dir] }' am__base_list = \ sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' am__uninstall_files_from_dir = { \ test -z "$$files" \ || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \ || { echo " ( cd '$$dir' && rm -f" $$files ")"; \ $(am__cd) "$$dir" && rm -f $$files; }; \ } am__installdirs = "$(DESTDIR)$(auglensdir)" DATA = $(auglens_DATA) am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) am__DIST_COMMON = $(srcdir)/Makefile.in \ $(srcdir)/gen-nutupsconf-aug.py.in \ $(srcdir)/nuthostsconf.aug.in $(srcdir)/nutnutconf.aug.in \ $(srcdir)/nutupsconf.aug.in $(srcdir)/nutupsdconf.aug.in \ $(srcdir)/nutupsdusers.aug.in $(srcdir)/nutupsmonconf.aug.in \ $(srcdir)/nutupsschedconf.aug.in \ $(srcdir)/nutupssetconf.aug.in DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) A2X = @A2X@ ACLOCAL = @ACLOCAL@ ALTPIDPATH = @ALTPIDPATH@ AMTAR = @AMTAR@ AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ AR = @AR@ ASCIIDOC = @ASCIIDOC@ ASPELL = @ASPELL@ ASPELL_FILTER_LIB_PATH = @ASPELL_FILTER_LIB_PATH@ ASPELL_FILTER_SHARE_PATH = @ASPELL_FILTER_SHARE_PATH@ ASPELL_FILTER_TEX_PATH = @ASPELL_FILTER_TEX_PATH@ AUGPARSE = @AUGPARSE@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ BINDIR = @BINDIR@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CONFIG_FLAGS = @CONFIG_FLAGS@ CONFPATH = @CONFPATH@ CPP = @CPP@ CPPCHECK = @CPPCHECK@ CPPFLAGS = @CPPFLAGS@ CPPUNIT_CFLAGS = @CPPUNIT_CFLAGS@ CPPUNIT_LIBS = @CPPUNIT_LIBS@ CSCOPE = @CSCOPE@ CTAGS = @CTAGS@ CXX = @CXX@ CXXCPP = @CXXCPP@ CXXDEPMODE = @CXXDEPMODE@ CXXFLAGS = @CXXFLAGS@ CYGPATH_W = @CYGPATH_W@ DBLATEX = @DBLATEX@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ DEPLOYED_UPSC = @DEPLOYED_UPSC@ DEPLOYED_UPSD = @DEPLOYED_UPSD@ DLLTOOL = @DLLTOOL@ DOC_BUILD_LIST = @DOC_BUILD_LIST@ DOC_CHECK_LIST = @DOC_CHECK_LIST@ DRIVER_BUILD_LIST = @DRIVER_BUILD_LIST@ DRIVER_INSTALL_TARGET = @DRIVER_INSTALL_TARGET@ DRIVER_MAN_LIST = @DRIVER_MAN_LIST@ DRIVER_MAN_LIST_PAGES = @DRIVER_MAN_LIST_PAGES@ DRVPATH = @DRVPATH@ DSYMUTIL = @DSYMUTIL@ DUMPBIN = @DUMPBIN@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ ETAGS = @ETAGS@ EXEEXT = @EXEEXT@ FGREP = @FGREP@ FORCE_NUT_VERSION = @FORCE_NUT_VERSION@ GDLIB_CONFIG = @GDLIB_CONFIG@ GREP = @GREP@ HAVE_SYS_SOCKET_H = @HAVE_SYS_SOCKET_H@ HAVE_WINSOCK2_H = @HAVE_WINSOCK2_H@ HAVE_WS2TCPIP_H = @HAVE_WS2TCPIP_H@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ LD = @LD@ LDFLAGS = @LDFLAGS@ LIBAVAHI_CFLAGS = @LIBAVAHI_CFLAGS@ LIBAVAHI_LIBS = @LIBAVAHI_LIBS@ LIBDIR = @LIBDIR@ LIBGD_CFLAGS = @LIBGD_CFLAGS@ LIBGD_LDFLAGS = @LIBGD_LDFLAGS@ LIBGPIO_CFLAGS = @LIBGPIO_CFLAGS@ LIBGPIO_LIBS = @LIBGPIO_LIBS@ LIBI2C_LIBS = @LIBI2C_LIBS@ LIBIPMI_CFLAGS = @LIBIPMI_CFLAGS@ LIBIPMI_LIBS = @LIBIPMI_LIBS@ LIBLTDL_CFLAGS = @LIBLTDL_CFLAGS@ LIBLTDL_LIBS = @LIBLTDL_LIBS@ LIBMODBUS_CFLAGS = @LIBMODBUS_CFLAGS@ LIBMODBUS_LIBS = @LIBMODBUS_LIBS@ LIBNEON_CFLAGS = @LIBNEON_CFLAGS@ LIBNEON_LIBS = @LIBNEON_LIBS@ LIBNETSNMP_CFLAGS = @LIBNETSNMP_CFLAGS@ LIBNETSNMP_LIBS = @LIBNETSNMP_LIBS@ LIBOBJS = @LIBOBJS@ LIBPOWERMAN_CFLAGS = @LIBPOWERMAN_CFLAGS@ LIBPOWERMAN_LIBS = @LIBPOWERMAN_LIBS@ LIBREGEX_LIBS = @LIBREGEX_LIBS@ LIBS = @LIBS@ LIBSSL_CFLAGS = @LIBSSL_CFLAGS@ LIBSSL_LIBS = @LIBSSL_LIBS@ LIBSSL_REQUIRES = @LIBSSL_REQUIRES@ LIBSYSTEMD_CFLAGS = @LIBSYSTEMD_CFLAGS@ LIBSYSTEMD_LIBS = @LIBSYSTEMD_LIBS@ LIBTOOL = @LIBTOOL@ LIBTOOL_DEPS = @LIBTOOL_DEPS@ LIBUSB_CFLAGS = @LIBUSB_CFLAGS@ LIBUSB_CONFIG = @LIBUSB_CONFIG@ LIBUSB_LIBS = @LIBUSB_LIBS@ LIBWRAP_CFLAGS = @LIBWRAP_CFLAGS@ LIBWRAP_LIBS = @LIBWRAP_LIBS@ LIPO = @LIPO@ LN_S = @LN_S@ LN_S_R = @LN_S_R@ LTLIBOBJS = @LTLIBOBJS@ LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@ MAINT = @MAINT@ MAKEINFO = @MAKEINFO@ MANIFEST_TOOL = @MANIFEST_TOOL@ MKDIR_P = @MKDIR_P@ MSGFMT = @MSGFMT@ NETLIBS = @NETLIBS@ NET_SNMP_CONFIG = @NET_SNMP_CONFIG@ NM = @NM@ NMEDIT = @NMEDIT@ NUT_DATADIR = @NUT_DATADIR@ NUT_LIBEXECDIR = @NUT_LIBEXECDIR@ NUT_NETVERSION = @NUT_NETVERSION@ NUT_SOURCE_GITREV = @NUT_SOURCE_GITREV@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ OS_NAME = @OS_NAME@ OTOOL = @OTOOL@ OTOOL64 = @OTOOL64@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_SEPARATOR = @PATH_SEPARATOR@ PIDPATH = @PIDPATH@ PKGCONFIGDIR = @PKGCONFIGDIR@ PKG_CONFIG = @PKG_CONFIG@ PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@ PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ PORT = @PORT@ POWERDOWNFLAG = @POWERDOWNFLAG@ PREFIX = @PREFIX@ PYTHON = @PYTHON@ PYTHON2 = @PYTHON2@ PYTHON2_SITE_PACKAGES = @PYTHON2_SITE_PACKAGES@ PYTHON3 = @PYTHON3@ PYTHON3_SITE_PACKAGES = @PYTHON3_SITE_PACKAGES@ PYTHON_SITE_PACKAGES = @PYTHON_SITE_PACKAGES@ RANLIB = @RANLIB@ REALPATH = @REALPATH@ RUN_AS_GROUP = @RUN_AS_GROUP@ RUN_AS_USER = @RUN_AS_USER@ SBINDIR = @SBINDIR@ SED = @SED@ SEMLIBS = @SEMLIBS@ SERLIBS = @SERLIBS@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ SOURCE_HIGHLIGHT = @SOURCE_HIGHLIGHT@ STATEPATH = @STATEPATH@ STRIP = @STRIP@ SUN_LIBUSB = @SUN_LIBUSB@ SYSTEMD_ANALYZE_PROGRAM = @SYSTEMD_ANALYZE_PROGRAM@ SYSTEMD_DAEMON_ARGS_DRIVER = @SYSTEMD_DAEMON_ARGS_DRIVER@ SYSTEMD_DAEMON_ARGS_UPSD = @SYSTEMD_DAEMON_ARGS_UPSD@ SYSTEMD_DAEMON_ARGS_UPSMON = @SYSTEMD_DAEMON_ARGS_UPSMON@ SYSTEMD_DAEMON_NOTIFYACCESS_DRIVER = @SYSTEMD_DAEMON_NOTIFYACCESS_DRIVER@ SYSTEMD_DAEMON_NOTIFYACCESS_UPSD = @SYSTEMD_DAEMON_NOTIFYACCESS_UPSD@ SYSTEMD_DAEMON_NOTIFYACCESS_UPSMON = @SYSTEMD_DAEMON_NOTIFYACCESS_UPSMON@ SYSTEMD_DAEMON_TYPE_DRIVER = @SYSTEMD_DAEMON_TYPE_DRIVER@ SYSTEMD_DAEMON_TYPE_UPSD = @SYSTEMD_DAEMON_TYPE_UPSD@ SYSTEMD_DAEMON_TYPE_UPSMON = @SYSTEMD_DAEMON_TYPE_UPSMON@ SYSTEMD_DAEMON_WATCHDOG_DRIVER = @SYSTEMD_DAEMON_WATCHDOG_DRIVER@ SYSTEMD_DAEMON_WATCHDOG_UPSD = @SYSTEMD_DAEMON_WATCHDOG_UPSD@ SYSTEMD_DAEMON_WATCHDOG_UPSMON = @SYSTEMD_DAEMON_WATCHDOG_UPSMON@ SYSTEMD_TMPFILES_PROGRAM = @SYSTEMD_TMPFILES_PROGRAM@ TREE_VERSION = @TREE_VERSION@ VALGRIND = @VALGRIND@ VERSION = @VERSION@ WINDMC = @WINDMC@ WINDRES = @WINDRES@ WORDS_BIGENDIAN = @WORDS_BIGENDIAN@ XMLLINT = @XMLLINT@ XSLTPROC = @XSLTPROC@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_AR = @ac_ct_AR@ ac_ct_CC = @ac_ct_CC@ ac_ct_CXX = @ac_ct_CXX@ ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__tar = @am__tar@ am__untar = @am__untar@ auglensdir = @auglensdir@ bindir = @bindir@ build = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ cgiexecdir = @cgiexecdir@ datadir = @datadir@ datarootdir = @datarootdir@ devddir = @devddir@ docdir = @docdir@ driverexecdir = @driverexecdir@ dummy_PKG_CONFIG = @dummy_PKG_CONFIG@ dummy_PKG_CONFIG_CFLAGS = @dummy_PKG_CONFIG_CFLAGS@ dummy_PKG_CONFIG_LIBS = @dummy_PKG_CONFIG_LIBS@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ hotplugdir = @hotplugdir@ htmldir = @htmldir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libdir = @libdir@ libexecdir = @libexecdir@ localedir = @localedir@ localstatedir = @localstatedir@ mandir = @mandir@ mkdir_p = @mkdir_p@ now = @now@ nut_with_nut_monitor = @nut_with_nut_monitor@ nut_with_nut_monitor_desktop = @nut_with_nut_monitor_desktop@ nut_with_nut_monitor_dir = @nut_with_nut_monitor_dir@ nut_with_nut_monitor_py2gtk2 = @nut_with_nut_monitor_py2gtk2@ nut_with_nut_monitor_py3qt5 = @nut_with_nut_monitor_py3qt5@ nut_with_pynut = @nut_with_pynut@ nut_with_pynut_py = @nut_with_pynut_py@ nut_with_pynut_py2 = @nut_with_pynut_py2@ nut_with_pynut_py3 = @nut_with_pynut_py3@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ pkgconfigdir = @pkgconfigdir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ runstatedir = @runstatedir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ sysconfdir = @sysconfdir@ systemdshutdowndir = @systemdshutdowndir@ systemdsystemunitdir = @systemdsystemunitdir@ systemdtmpfilesdir = @systemdtmpfilesdir@ target = @target@ target_alias = @target_alias@ target_cpu = @target_cpu@ target_os = @target_os@ target_vendor = @target_vendor@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ udevdir = @udevdir@ # Part of dist tarball, regardless of use for current build: EXTRA_DIST = gen-nutupsconf-aug.py.in nutupsconf.aug.tpl README.adoc \ tests/test_nut.aug nutupsconf.aug.in # FIXME # augparse -I $(srcdir)/ $(srcdir)/tests/test_nut.aug # Now "make install" should cover delivery of Augeas lenses... # The "auglensdir" value should be set up by configure # The *.aug files are generated by rule above or by autogen.sh and/or configure @WITH_AUGLENS_TRUE@auglens_DATA = \ @WITH_AUGLENS_TRUE@ nuthostsconf.aug nutupsconf.aug nutupsdusers.aug nutupsschedconf.aug \ @WITH_AUGLENS_TRUE@ nutnutconf.aug nutupsdconf.aug nutupsmonconf.aug nutupssetconf.aug # Generated by autogen.sh and needed to run the configure script: MAINTAINERCLEANFILES = Makefile.in .dirstamp nutupsconf.aug.in \ nutupsconf.aug.in.AUTOGEN_WITHOUT CLEANFILES = *-spellchecked README # Can be re-generated by configure script and/or make: DISTCLEANFILES = gen-nutupsconf-aug.py *.aug all: all-am .SUFFIXES: $(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu scripts/augeas/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --gnu scripts/augeas/Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): nutnutconf.aug: $(top_builddir)/config.status $(srcdir)/nutnutconf.aug.in cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ nutupsdconf.aug: $(top_builddir)/config.status $(srcdir)/nutupsdconf.aug.in cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ nutupsdusers.aug: $(top_builddir)/config.status $(srcdir)/nutupsdusers.aug.in cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ nutupsmonconf.aug: $(top_builddir)/config.status $(srcdir)/nutupsmonconf.aug.in cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ nutupsschedconf.aug: $(top_builddir)/config.status $(srcdir)/nutupsschedconf.aug.in cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ nuthostsconf.aug: $(top_builddir)/config.status $(srcdir)/nuthostsconf.aug.in cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ nutupssetconf.aug: $(top_builddir)/config.status $(srcdir)/nutupssetconf.aug.in cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ gen-nutupsconf-aug.py: $(top_builddir)/config.status $(srcdir)/gen-nutupsconf-aug.py.in cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ nutupsconf.aug: $(top_builddir)/config.status $(srcdir)/nutupsconf.aug.in cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ mostlyclean-libtool: -rm -f *.lo clean-libtool: -rm -rf .libs _libs install-auglensDATA: $(auglens_DATA) @$(NORMAL_INSTALL) @list='$(auglens_DATA)'; test -n "$(auglensdir)" || list=; \ if test -n "$$list"; then \ echo " $(MKDIR_P) '$(DESTDIR)$(auglensdir)'"; \ $(MKDIR_P) "$(DESTDIR)$(auglensdir)" || exit 1; \ fi; \ for p in $$list; do \ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ echo "$$d$$p"; \ done | $(am__base_list) | \ while read files; do \ echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(auglensdir)'"; \ $(INSTALL_DATA) $$files "$(DESTDIR)$(auglensdir)" || exit $$?; \ done uninstall-auglensDATA: @$(NORMAL_UNINSTALL) @list='$(auglens_DATA)'; test -n "$(auglensdir)" || list=; \ files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ dir='$(DESTDIR)$(auglensdir)'; $(am__uninstall_files_from_dir) tags TAGS: ctags CTAGS: cscope cscopelist: distdir: $(BUILT_SOURCES) $(MAKE) $(AM_MAKEFLAGS) distdir-am distdir-am: $(DISTFILES) @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ dist_files=`for file in $$list; do echo $$file; done | \ sed -e "s|^$$srcdirstrip/||;t" \ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ case $$dist_files in \ */*) $(MKDIR_P) `echo "$$dist_files" | \ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ sort -u` ;; \ esac; \ for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d "$(distdir)/$$file"; then \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ else \ test -f "$(distdir)/$$file" \ || cp -p $$d/$$file "$(distdir)/$$file" \ || exit 1; \ fi; \ done $(MAKE) $(AM_MAKEFLAGS) \ top_distdir="$(top_distdir)" distdir="$(distdir)" \ dist-hook @HAVE_AUGPARSE_FALSE@check-local: check-am: all-am $(MAKE) $(AM_MAKEFLAGS) check-local check: check-am all-am: Makefile $(DATA) installdirs: for dir in "$(DESTDIR)$(auglensdir)"; do \ test -z "$$dir" || $(MKDIR_P) "$$dir"; \ done install: install-am install-exec: install-exec-am install-data: install-data-am uninstall: uninstall-am install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-am install-strip: if test -z '$(STRIP)'; then \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ install; \ else \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ fi mostlyclean-generic: clean-generic: -test -z "$(CLEANFILES)" || rm -f $(CLEANFILES) distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) -test -z "$(DISTCLEANFILES)" || rm -f $(DISTCLEANFILES) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." -test -z "$(MAINTAINERCLEANFILES)" || rm -f $(MAINTAINERCLEANFILES) clean: clean-am clean-am: clean-generic clean-libtool mostlyclean-am distclean: distclean-am -rm -f Makefile distclean-am: clean-am distclean-generic dvi: dvi-am dvi-am: html: html-am html-am: info: info-am info-am: install-data-am: install-auglensDATA install-dvi: install-dvi-am install-dvi-am: install-exec-am: install-html: install-html-am install-html-am: install-info: install-info-am install-info-am: install-man: install-pdf: install-pdf-am install-pdf-am: install-ps: install-ps-am install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-am -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-am mostlyclean-am: mostlyclean-generic mostlyclean-libtool pdf: pdf-am pdf-am: ps: ps-am ps-am: uninstall-am: uninstall-auglensDATA .MAKE: check-am install-am install-strip .PHONY: all all-am check check-am check-local clean clean-generic \ clean-libtool cscopelist-am ctags-am dist-hook distclean \ distclean-generic distclean-libtool distdir dvi dvi-am html \ html-am info info-am install install-am install-auglensDATA \ install-data install-data-am install-dvi install-dvi-am \ install-exec install-exec-am install-html install-html-am \ install-info install-info-am install-man install-pdf \ install-pdf-am install-ps install-ps-am install-strip \ installcheck installcheck-am installdirs maintainer-clean \ maintainer-clean-generic mostlyclean mostlyclean-generic \ mostlyclean-libtool pdf pdf-am ps ps-am tags-am uninstall \ uninstall-am uninstall-auglensDATA .PRECIOUS: Makefile # only call the script to generate Augeas ups.conf lens upon "make dist", # and if Python is present; the distributed gen-nutupsconf-aug.py.in template # is assumed to only differ from a generated gen-nutupsconf-aug.py by the # @PYTHON@ shebang. dist-hook: @if [ -n "$(PYTHON)" ] && [ x"no" != x"$(PYTHON)" ] && $(PYTHON) -c "import re,glob,codecs"; then \ echo "Regenerating Augeas ups.conf lens with '$(PYTHON)'."; \ $(PYTHON) $(distdir)/gen-nutupsconf-aug.py.in $(distdir)/; \ else \ echo "----------------------------------------------------------------------"; \ echo "Warning: Python is not available."; \ echo "Skipping regeneration of Augeas lens for ups.conf parsing." ; \ echo "----------------------------------------------------------------------"; \ fi # This needs augparse from augeas-tools @HAVE_AUGPARSE_TRUE@check-local: @HAVE_AUGPARSE_TRUE@ @echo "augparse proceeding to lenses verification job..."; \ @HAVE_AUGPARSE_TRUE@ echo "DISABLED for now due to https://github.com/networkupstools/nut/issues/657" # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: nut-2.8.1/scripts/augeas/nutupsconf.aug.in0000644000175000017500000002143014520277726015530 00000000000000(* Module: NutUpsConf Parses @CONFPATH@/ups.conf Author: Raphael Pinson Frederic Bohe Arnaud Quette About: License This file is licensed under the GPL. About: Lens Usage Sample usage of this lens in augtool * Print all drivers used > print /files/@CONFPATH@/ups.conf/*/driver About: Configuration files This lens applies to @CONFPATH@/ups.conf. See . *) module NutUpsConf = autoload ups_xfm (************************************************************************ * Group: UPS.CONF *************************************************************************) let ups_comment = IniFile.comment IniFile.comment_re IniFile.comment_default let ups_sep = IniFile.sep IniFile.sep_re IniFile.sep_default let ups_global = "chroot" | "driverpath" | "maxstartdelay" | "maxretry" | "retrydelay" | "pollinterval" | "synchronous" | "user" let ups_fields = "driver" | "port" | "sdorder" | "desc" | "nolock" | "ignorelb" | "maxstartdelay" | "synchronous" | "BYPASS" | "CHRG_addr" | "CHRG_noro" | "CHRG_regtype" | "CP" | "CS" | "DISCHRG_addr" | "DISCHRG_noro" | "DISCHRG_regtype" | "FSD_addr" | "FSD_noro" | "FSD_pulse_duration" | "FSD_regtype" | "HB_addr" | "HB_noro" | "HB_regtype" | "ID" | "LB" | "LB_addr" | "LB_noro" | "LB_regtype" | "LowBatt" | "OB_addr" | "OB_noro" | "OB_regtype" | "OL" | "OL_addr" | "OL_noro" | "OL_regtype" | "OffDelay" | "OnDelay" | "RB" | "RB_addr" | "RB_noro" | "RB_regtype" | "SD" | "advanced_eco_mode" | "advorder" | "alarm_control" | "allow_duplicates" | "authPassword" | "authProtocol" | "authtype" | "awd" | "batteryPercentage" | "battery_alarm" | "battery_max" | "battery_min" | "battery_number" | "battery_open_status_check" | "battery_voltage_reports_one_pack" | "battext" | "battvoltmult" | "baud_rate" | "baudrate" | "bus" | "busport" | "bypass_alarm" | "bypass_forbidding" | "bypass_when_off" | "cable" | "cablepower" | "chargetime" | "community" | "constant_phase_angle" | "converter_mode" | "cshdelay" | "databits" | "daysoff" | "daysweek" | "dev_slave_id" | "device" | "device_mfr" | "device_model" | "disable_fix_report_desc" | "do_convert_deci" | "dumbterm" | "eco_mode" | "explore" | "fake_lowbatt" | "fault_1" | "fault_2" | "fault_3" | "fault_4" | "fault_5" | "flash" | "frequency" | "fruid" | "full_update" | "hb" | "houroff" | "houron" | "i2c_address" | "idleload" | "ignoresab" | "input_fault_voltage" | "input_timeout" | "interruptonly" | "interruptsize" | "langid_fix" | "lb" | "limited_runtime_on_battery" | "linevoltage" | "load.off" | "load.on" | "load.status" | "loadPercentage" | "login" | "lowbatt" | "manufacturer" | "max_bypass_freq" | "max_bypass_volt" | "max_load" | "max_polls_without_data" | "maxreport" | "methodOfFlowControl" | "mfr" | "mibs" | "min_bypass_freq" | "min_bypass_volt" | "mincharge" | "minruntime" | "mod_byte_to_s" | "mod_byte_to_us" | "mod_resp_to_s" | "mod_resp_to_us" | "model" | "modelname" | "nobt" | "nohang" | "nombattvolt" | "nominal_cell_voltage" | "norating" | "noscanlangid" | "notification" | "notransferoids" | "novendor" | "nowarn_noimp" | "numOfBytesFromUPS" | "number_of_battery_cells" | "offdelay" | "oldmac" | "ondelay" | "onlinedischarge" | "onlinedischarge_calibration" | "output_pace" | "output_phase_angle" | "output_voltages" | "parity" | "password" | "pins_shutdown_mode" | "pollfreq" | "pollonly" | "porttype" | "powerup" | "prefix" | "prgshut" | "privPassword" | "privProtocol" | "product" | "productid" | "protocol" | "rebootdelay" | "recharge_time" | "repeater_disable_strict_start" | "reset_to_default" | "response_timeout_ms" | "rio_slave_id" | "rules" | "runtime_full" | "runtime_half" | "runtimecal" | "sdtime" | "sdtype" | "secLevel" | "secName" | "semistaticfreq" | "ser_baud_rate" | "ser_data_bit" | "ser_parity" | "ser_stop_bit" | "serial" | "serialnumber" | "series" | "shutdownArguments" | "shutdown_delay" | "shutdown_duration" | "shutdown_timer" | "silent" | "site_fault_detection" | "slave_address" | "slaveid" | "snmp_retries" | "snmp_timeout" | "snmp_version" | "startdelay" | "status_only" | "stayoff" | "stopbits" | "subdriver" | "subscribe" | "symmetrathreephase" | "testing" | "testtime" | "timeout" | "ttymode" | "type" | "ups.delay.shutdown" | "ups.delay.start" | "upsid" | "upstype" | "usb_set_altinterface" | "usd" | "use_crlf" | "use_pre_lf" | "username" | "validationSequence" | "vendor" | "vendorid" | "voltage" | "wait" | "waitbeforereconnect" | "work_range_type" | "wugrace" let ups_entry = IniFile.indented_entry (ups_global|ups_fields) ups_sep ups_comment let ups_title = IniFile.indented_title IniFile.record_re let ups_record = IniFile.record ups_title ups_entry let ups_lns = IniFile.lns ups_record ups_comment let ups_filter = (incl "@CONFPATH@/ups.conf") . Util.stdexcl let ups_xfm = transform ups_lns ups_filter nut-2.8.1/scripts/augeas/nutupsdusers.aug.in0000644000175000017500000000533514500336654016110 00000000000000(* Module: NutUpsdUsers Parses @CONFPATH@/upsd.users Author: Raphael Pinson Frederic Bohe About: License This file is licensed under the GPL. About: Lens Usage Sample usage of this lens in augtool * Print all users granted to send commands to UPS > /files@CONFPATH@/upsd.users/fred/actions/SET About: Configuration files This lens applies to @CONFPATH@/upsd.users. See . *) module NutUpsdUsers = autoload upsd_users_xfm (************************************************************************ * Group: UPSD.USERS *************************************************************************) (* general *) let del_spc = Util.del_opt_ws "" let sep_spc = Util.del_ws_spc let eol = Util.eol let ip = /[0-9A-Za-z\.:]+/ let num = /[0-9]+/ let word = /[^"#; \t\n]+/ let empty = Util.empty (* let netblock = /[0-9A-Za-z\.:\/]+/ *) let netblock = word let path = word let upsd_users_comment = IniFile.comment IniFile.comment_re IniFile.comment_default let upsd_users_sep = IniFile.sep IniFile.sep_re IniFile.sep_default let upsd_users_fields = "password" | "instcmds" let upsd_users_entry = IniFile.indented_entry upsd_users_fields upsd_users_sep upsd_users_comment let upsd_users_actions_entry = [ key /SET|FSD/ ] let upsd_users_actions = [ del_spc . key "actions" . upsd_users_sep . del_spc . upsd_users_actions_entry . ( sep_spc . upsd_users_actions_entry )* . ( upsd_users_comment|eol ) ] (* FIXME: NEEDED? can be all, or a list of instant commands *) let upsd_users_instcmds_entry = [ key /ALL|FSD/ ] let upsd_users_instcmds = [ del_spc . key "instcmds" . upsd_users_sep . del_spc . upsd_users_instcmds_entry . ( sep_spc . upsd_users_instcmds_entry )* . ( upsd_users_comment|eol ) ] let upsd_users_upsmon = [ del_spc . key "upsmon" . sep_spc . store /master|primary|slave|secondary/ . eol ] let upsd_users_title = IniFile.indented_title IniFile.record_re let upsd_users_record = IniFile.record upsd_users_title (upsd_users_entry|upsd_users_actions|upsd_users_upsmon) let upsd_users_lns = IniFile.lns upsd_users_record upsd_users_comment let upsd_users_filter = ( incl "@CONFPATH@/upsd.users" ) . Util.stdexcl let upsd_users_xfm = transform upsd_users_lns upsd_users_filter nut-2.8.1/scripts/augeas/nutupsschedconf.aug.in0000644000175000017500000000416314273170601016530 00000000000000(* Module: NutUpsSchedConf Parses @CONFPATH@/upssched.conf Author: Raphael Pinson Frederic Bohe About: License This file is licensed under the GPL. About: Lens Usage Sample usage of this lens in augtool * Print the command script: > print /files@CONFPATH@/upssched.conf/CMDSCRIPT About: Configuration files This lens applies to @CONFPATH@/upssched.conf. See . *) module NutUpsschedConf = autoload upssched_xfm (************************************************************************ * Group: UPSSCHED.CONF *************************************************************************) (* general *) let sep_spc = Util.del_ws_spc let eol = Util.eol let num = /[0-9]+/ let word = /[^"#; \t\n]+/ let empty = Util.empty let comment = Util.comment (* Variable: quoted_word *) let word_space = /"[^"\n]+"/ let quoted_word = /"[^" \t\n]+"/ (* Variable: word_all *) let word_all = word_space | word | quoted_word let upssched_re = "CMDSCRIPT" | "PIPEFN" | "LOCKFN" let upssched_opt = [ key upssched_re . sep_spc . store word_all . eol ] let upssched_start_timer = [ key "START-TIMER" . sep_spc . [ label "timername" . store word ] . sep_spc . [ label "interval" . store num ] ] let upssched_cancel_timer = [ key "CANCEL-TIMER" . sep_spc . [ label "timername" . store word ] . ( sep_spc . [ label "cmd" . store word_all ])* ] let upssched_execute_timer = [ key "EXECUTE" . sep_spc . [ label "command" . store word_all ] ] let upssched_command = (upssched_start_timer|upssched_cancel_timer|upssched_execute_timer) let upssched_at = [ key "AT" . sep_spc . [ label "notifytype" . store word ] . sep_spc . [ label "upsname" . store word ] . sep_spc . upssched_command . eol ] let upssched_lns = (upssched_at|upssched_opt|comment|empty)* let upssched_filter = ( incl "@CONFPATH@/upssched.conf" ) . Util.stdexcl let upssched_xfm = transform upssched_lns upssched_filter nut-2.8.1/scripts/augeas/nutupsmonconf.aug.in0000644000175000017500000000750214501613330016226 00000000000000(* Module: NutUpsmonConf Parses @CONFPATH@/upsmon.conf Author: Raphael Pinson Frederic Bohe About: License This file is licensed under the GPL. About: Lens Usage Sample usage of this lens in augtool * Print all notification messages > print /files@CONFPATH@/upsmon.conf/NOTIFYMSG About: Configuration files This lens applies to @CONFPATH@/upsmon.conf. See . *) module NutUpsmonConf = autoload upsmon_xfm (************************************************************************ * Group: UPSMON.CONF *************************************************************************) (* general *) let del_spc = Util.del_opt_ws "" let sep_spc = Util.del_ws_spc let eol = Util.eol let num = /[0-9]+/ let word = /[^"#; \t\n]+/ let empty = Util.empty let comment = Util.comment let quoted_string = del "\"" "\"" . store /[^"\n]+/ . del "\"" "\"" (* UPS identifier * [@[:]] * * There might be a cleaner way to write this * but I'm stuck with (hostname | hostname . port)? *) let hostname = [ label "hostname" . store /[^ \t\n:]+/ ] let port = [ label "port" . store num ] let identifier = [ label "upsname" . store /[^ \t\n@]+/ ] . ( ( Util.del_str "@" . hostname ) | ( Util.del_str "@" . hostname . Util.del_str ":" . port ) )? let upsmon_num_re = "DEADTIME" | "FINALDELAY" | "HOSTSYNC" | "MINSUPPLIES" | "NOCOMMWARNTIME" | "POLLFREQ" | "POLLFREQALERT" | "RBWARNTIME" let upsmon_num = [ del_spc . key upsmon_num_re . sep_spc . store num . eol ] let upsmon_word = [ del_spc . key "RUN_AS_USER" . sep_spc . store word . eol ] let upsmon_file_re = "NOTIFYCMD" | "POWERDOWNFLAG" | "SHUTDOWNCMD" let sto_to_eol = IniFile.sto_to_eol (* here we should support both quoted and not quotted * string but I can't manage to find the right way of doing this *) let upsmon_file = [ del_spc . key upsmon_file_re . sto_to_eol . eol ] (* MONITOR system powervalue username password type *) let upsmon_monitor = [ del_spc . key "MONITOR" . sep_spc . [ label "system" . identifier ] . sep_spc . [ label "powervalue" . store num ] . sep_spc . [ label "username" . store word ] . sep_spc . [ label "password" . store word ] . sep_spc . [ label "type" . store word ] . eol ] let upsmon_notify_type = "ONLINE" | "ONBATT" | "LOWBATT" | "FSD" | "COMMOK" | "COMMBAD" | "SHUTDOWN" | "REPLBATT" | "NOCOMM" | "NOPARENT" | "CAL" | "OFF" | "NOTOFF" | "BYPASS" | "NOTBYPASS" let upsmon_notify = [ del_spc . key "NOTIFYMSG" . sep_spc . [ label "type" . store upsmon_notify_type . sep_spc ] . [ label "message" . quoted_string ] . eol ] let flags = "IGNORE" | "SYSLOG" | "WALL" | "EXEC" let plus = [ del /\+*/ "" ] (*let entries = /IGNORE|SYSLOG|WALL|EXEC+/*) let record = [ seq "record" . plus . store flags ] let upsmon_notify_flag = [ counter "record" . del_spc . key "NOTIFYFLAG" . sep_spc . [ label "type" . store upsmon_notify_type . sep_spc ] . record+ . eol ] let upsmon_record = upsmon_num|upsmon_word|upsmon_file|upsmon_monitor|upsmon_notify|upsmon_notify_flag let upsmon_lns = (upsmon_record|comment|empty)* let upsmon_filter = ( incl "@CONFPATH@/upsmon.conf" ) . Util.stdexcl let upsmon_xfm = transform upsmon_lns upsmon_filter nut-2.8.1/scripts/augeas/nutupssetconf.aug.in0000644000175000017500000000220014273170601016223 00000000000000(* Module: NutUpssetConf Parses @CONFPATH@/upsset.conf Author: Raphael Pinson Frederic Bohe About: License This file is licensed under the GPL. About: Lens Usage Sample usage of this lens in augtool * Print the string declaring secured cgi directory: > print /files@CONFPATH@/upsset.conf/auth About: Configuration files This lens applies to @CONFPATH@/upsset.conf. See . *) module NutUpssetConf = autoload upsset_xfm (************************************************************************ * Group: UPSSET.CONF *************************************************************************) (* general *) let sep_spc = Util.del_opt_ws "" let eol = Util.eol let comment = Util.comment let empty = Util.empty let upsset_key_word = "I_HAVE_SECURED_MY_CGI_DIRECTORY" let upsset_key = [ label "auth" . sep_spc . store upsset_key_word . eol ] let upsset_lns = (upsset_key|comment|empty)* let upsset_filter = ( incl "@CONFPATH@/upsset.conf" ) . Util.stdexcl let upsset_xfm = transform upsset_lns upsset_filter nut-2.8.1/scripts/augeas/nutnutconf.aug.in0000644000175000017500000000216614273170601015521 00000000000000(* Module: NutNutConf Parses @CONFPATH@/nut.conf Author: Frederic Bohe About: License This file is licensed under the GPL. About: Lens Usage Sample usage of this lens in augtool * Print NUT MODE start-up configuration: > print /files@CONFPATH@/nut.conf/MODE About: Configuration files This lens applies to @CONFPATH@/nut.conf. See . *) module NutNutConf = autoload nut_xfm (************************************************************************ * Group: NUT.CONF *************************************************************************) (* general *) let def_sep = IniFile.sep IniFile.sep_re IniFile.sep_default let sep_spc = Util.del_opt_ws "" let eol = Util.eol let comment = Util.comment let empty = Util.empty let nut_possible_mode = "none" | "standalone" | "netserver" | "netclient" let nut_mode = [ sep_spc . key "MODE" . def_sep . sep_spc . store nut_possible_mode . eol ] let nut_lns = (nut_mode|comment|empty)* let nut_filter = ( incl "@CONFPATH@/nut.conf" ) . Util.stdexcl let nut_xfm = transform nut_lns nut_filter nut-2.8.1/scripts/augeas/Makefile.am0000644000175000017500000000373114501607135014247 00000000000000 EXTRA_DIST = gen-nutupsconf-aug.py.in nutupsconf.aug.tpl \ README.adoc tests/test_nut.aug PYTHON = @PYTHON@ # only call the script to generate Augeas ups.conf lens upon "make dist", # and if Python is present; the distributed gen-nutupsconf-aug.py.in template # is assumed to only differ from a generated gen-nutupsconf-aug.py by the # @PYTHON@ shebang. dist-hook: @if [ -n "$(PYTHON)" ] && [ x"no" != x"$(PYTHON)" ] && $(PYTHON) -c "import re,glob,codecs"; then \ echo "Regenerating Augeas ups.conf lens with '$(PYTHON)'."; \ $(PYTHON) $(distdir)/gen-nutupsconf-aug.py.in $(distdir)/; \ else \ echo "----------------------------------------------------------------------"; \ echo "Warning: Python is not available."; \ echo "Skipping regeneration of Augeas lens for ups.conf parsing." ; \ echo "----------------------------------------------------------------------"; \ fi # This needs augparse from augeas-tools if HAVE_AUGPARSE check-local: @echo "augparse proceeding to lenses verification job..."; \ echo "DISABLED for now due to https://github.com/networkupstools/nut/issues/657" endif # FIXME # augparse -I $(srcdir)/ $(srcdir)/tests/test_nut.aug if WITH_AUGLENS # Now "make install" should cover delivery of Augeas lenses... # The "auglensdir" value should be set up by configure # The *.aug files are generated by rule above or by autogen.sh and/or configure auglens_DATA = \ nuthostsconf.aug nutupsconf.aug nutupsdusers.aug nutupsschedconf.aug \ nutnutconf.aug nutupsdconf.aug nutupsmonconf.aug nutupssetconf.aug endif MAINTAINERCLEANFILES = Makefile.in .dirstamp CLEANFILES = *-spellchecked README # Can be re-generated by configure script and/or make: DISTCLEANFILES = gen-nutupsconf-aug.py # Generated by autogen.sh and needed to run the configure script: MAINTAINERCLEANFILES += nutupsconf.aug.in nutupsconf.aug.in.AUTOGEN_WITHOUT # Part of dist tarball, regardless of use for current build: EXTRA_DIST += nutupsconf.aug.in DISTCLEANFILES += *.aug nut-2.8.1/scripts/Windows/0000755000175000017500000000000014520277777012474 500000000000000nut-2.8.1/scripts/Windows/README.adoc0000644000175000017500000006242714520274617014202 00000000000000NUT and MS Windows ================== Introduction ------------ NUT is now also available for the Microsoft Windows platform. This methodology (and Windows support in general) are currently experimental, so pull requests are welcome to tie up some loose ends (add more prerequisites, test and fix programs, re-enable some code just commented away by ifdefs...) NOTE: It is possible to prepare a Windows machine with tools and prerequisites for building NUT natively, as detailed in `docs/config-prereqs.txt` and easily handled by NUT common `ci_build.sh` script. Most prerequisites are already packaged in that environment, but notably net-snmp is missing -- but can be built from source following this document. Possibly, the instructions below would converge there over time to keep it simple. For additional reference about prerequisite preparation and further ideas for the NUT for Windows effort, please see detailed report in the mailing list: * https://alioth-lists.debian.net/pipermail/nut-upsdev/2016-April/007171.html - [Nut-upsdev] How to build NUT Windows Port * https://alioth-lists.debian.net/pipermail/nut-upsdev/2016-April/007172.html - [Nut-upsdev] NUT Windows port sources review Cross compiling from Linux -------------------------- Fortunately, you are not forced to have a real Windows system to compile NUT. The following chapters will guide you through setting up up a link:http://mingw-w64.sourceforge.net[MinGW-w64] build environment and compiling NUT. NOTE: These instructions were re-verified (and codebase slightly amended) with an Ubuntu 21.10 container as the dedicated build environment. Support was added to NUT common `ci_build.sh` script to call the helper `build-mingw-nut.sh` from this directory when cross-building on Linux for Windows in the specially crafted sandbox (conformance is assumed), if you use one of `BUILD_TYPE=cross-windows-mingw(-64|-32|)` as this made NUT CI farm integration easier. NOTE: The Ubuntu (20.04 or newer) environment provided by WSL2 also seems suitable for semi-native builds on a Windows system, following the same instructions. However, note that some builds may be broken or complicated by antivirus software (it really dislikes someone writing into EXE files). Beside MinGW detailed below, you would need the usual dependencies to configure and build NUT (if you would bootstrap it from github sources rather than a tarball -- without a pre-generated `configure` script). Notably, `asciidoc` with its many dependencies may be required for generation of man pages into the intermediate tarball used by script referenced below. MinGW-w64 build environment ~~~~~~~~~~~~~~~~~~~~~~~~~~~ You will first need to setup a MinGW-w64 build environment. NOTE: While adding `ccache` is optional, it is quite recommended especially if you plan to iterate many builds (whether of NUT or the dependencies). At least for Ubuntu 21.10 packaging, it is integrated with `mingw-w64` tool naming out of the box. On Debian/Ubuntu and similar systems, use: # apt-get update # apt-get install mingw-w64 On Redhat and similar systems, use: # ??? You will also need pthread and mingw regex libraries, and other recommended dependencies as detailed below. [NOTE] ================================================================================ If you use script `./build-mingw-nut.sh` mentioned below, you may skip setting these environment variables when building NUT. You would however need to use them once (per `ARCH`) to provide the prerequisites below if built from source. When using the compilation approach, use the following HOST_FLAG, BUILD_FLAG and CC, CFLAGS, LDFLAGS and PREFIX: - prefer either to ------ :; export ARCH="x86_64-w64-mingw32" ------ or ------ :; export ARCH="i686-w64-mingw32" ------ (it can help to open two terminals and copy one ARCH into each and then the lines below into both of them; be sure to use separate directory trees for the unpacked build workspaces) - for either-ARCH build environment further set: ------ :; export HOST_FLAG="--host=$ARCH" :; PREFIX="/usr/$ARCH" ------ - NOTE: Technically, these instructions may apply to builds with MinGW on Windows semi-natively (e.g. to add the net-snmp libraries which are not packaged for MSYS2 MinGW currently). Generally you can use environment variables set by different launchers of MinGW terminal sessions depending on the target profile (32/64 bit, gcc/clang, libc implementation...) ** For `sudo make install` in instructions below, you may have to omit the `sudo` part if missing in your MSYS2 MinGW environment; ** For a "native build" directly for consumption in the currently configured environment, you would not use cross-build path in `PREFIX` and not set the `HOST_FLAG` value: + ------ :; export ARCH="$MINGW_CHOST" :; PREFIX="$MINGW_PREFIX" :; export HOST_FLAG="" ------ ** If you wanted a "real cross-build" for a different MinGW environment, you might want to set those (but the NUT build would then need to be told to search for headers, libraries and pkg-config data in extra locations): + ------ :; export ARCH="$MINGW_CHOST" :; PREFIX="$MINGW_PREFIX/$ARCH" :; export HOST_FLAG="--host=$ARCH" ------ ** You might want then to verify that it sets values you expect with a command like this: + ------ :; set | grep -E '^(ARCH|PREFIX|HOST_FLAG)=' #export ARCH="x86_64-w64-mingw32" #PREFIX="/mingw64/x86_64-w64-mingw32" ------ - on Debian/Ubuntu style systems also: ------ :; BUILD_FLAG="--build=`dpkg-architecture -qDEB_BUILD_GNU_TYPE`" ------ * Note that this bit is very Debian specific! Hints for Redhat-style systems are wanted. - also export the following compilation flags: ------ :; export CFLAGS="$CFLAGS -D_POSIX=1 -I${PREFIX}/include/" :; export CXXFLAGS="$CXXFLAGS -D_POSIX=1 -I${PREFIX}/include/" :; export LDFLAGS="$LDFLAGS -L${PREFIX}/lib/" :; export PKG_CONFIG_PATH="${PREFIX}"/lib/pkgconfig ------ - prepare the download and build area, e.g. to match copy-paste instructions below, it would be like: ------ :; DLDIR=~/nut-win-deps :; WSDIR="$DLDIR"/"$ARCH" :; mkdir -p "$WSDIR" "$DLDIR" ------ ================================================================================ pthread library ^^^^^^^^^^^^^^^ NOTE: The MinGW distribution in Ubuntu 21.10 already includes pthread files, so the build instructions below were not relevant for this component. On older Debian systems, you can use the following packages repository: link:https://launchpad.net/~mingw-packages/+archive/ppa[MinGW PPA] However at the moment this PPA seems to be stale and serve very old packages, so it could be better to roll your own as detailed below. On Redhat: FIXME //////////////////////////////////////////////////////////////////////////////// http://fedoraproject.org/wiki/MinGW/CrossCompilerFramework https://fedoraproject.org/wiki/Packaging:MinGW?rd=Packaging:MinGW_Future https://fedoraproject.org/wiki/Packaging:MinGW_Old //////////////////////////////////////////////////////////////////////////////// You can also compile it (where that is still needed) using: :; ( cd "$DLDIR" && wget -c http://mirrors.kernel.org/sources.redhat.com/pthreads-win32/pthreads-w32-2-8-0-release.tar.gz ) :; cd "$WSDIR" :; tar xzf "$DLDIR"/pthreads-w32-2-8-0-release.tar.gz :; cd pthreads-w32-2-8-0-release/ :; make -f GNUmakefile "CROSS=$ARCH-" $BUILD_FLAG GC-inlined :; sudo cp *.dll ${PREFIX}/pthreads/lib/ :; sudo cp *.a ${PREFIX}/lib/ :; sudo cp pthread.h sched.h semaphore.h ${PREFIX}/pthreads/include MinGW regex library ^^^^^^^^^^^^^^^^^^^ You can compile it using: :; ( cd "$DLDIR" && wget -c http://netcologne.dl.sourceforge.net/project/mingw/Other/UserContributed/regex/mingw-regex-2.5.1/mingw-libgnurx-2.5.1-src.tar.gz ) :; cd "$WSDIR" :; tar xzf "$DLDIR"/mingw-libgnurx-2.5.1-src.tar.gz :; cd mingw-libgnurx-2.5.1 :; ./configure --prefix="$PREFIX" $HOST_FLAG :; make :; sudo make install libtool (libltdl) ^^^^^^^^^^^^^^^^^ :; ( cd "$DLDIR" && wget -c https://ftpmirror.gnu.org/libtool/libtool-2.4.6.tar.gz ) :; cd "$WSDIR" :; tar xzf "$DLDIR"/libtool-2.4.6.tar.gz :; cd libtool-2.4.6 :; ./configure --prefix="$PREFIX" $HOST_FLAG :; make :; sudo make install libusb ^^^^^^ * libusb-1.0 :; ( cd "$DLDIR" && wget -c https://sourceforge.net/projects/libusb/files/libusb-1.0/libusb-1.0.26/libusb-1.0.26.tar.bz2 ) :; cd "$WSDIR" :; tar xjf "$DLDIR"/libusb-1.0.26.tar.bz2 :; cd libusb-1.0.26 :; ./configure --prefix="$PREFIX" $HOST_FLAG :; make :; sudo make install * libusb-compat-0.1 (API translation layer for older codebase, uses libusb-1.0) :; ( cd "$DLDIR" && wget -c https://github.com/libusb/libusb-compat-0.1/archive/refs/heads/master.zip -O libusb-compat-0.1-master.zip ) :; cd "$WSDIR" :; unzip "$DLDIR"/libusb-compat-0.1-master.zip :; cd libusb-compat-0.1-master :; ./bootstrap.sh :; ./configure --prefix="$PREFIX" $HOST_FLAG :; make :; sudo make install zlib ^^^^ Needed for libpng at least, but likely many others too. [NOTE] ====== On recent Debian/Ubuntu systems, you might have luck with: ------ :; sudo apt-get install libz-mingw-w64-dev ------ ====== On any system, you can build from source; however the current version has a nuance to address for mingw builds: :; ( cd "$DLDIR" && wget -c -O zlib-1.2.12.tar.gz https://github.com/madler/zlib/archive/refs/tags/v1.2.12.tar.gz ) :; cd "$WSDIR" :; tar xzf "$DLDIR"/zlib-1.2.12.tar.gz :; cd zlib-1.2.12 # Edit the `configure` script (not autotools generated) to # neuter the MINGW `leave 1` line: MINGW* | mingw*) # temporary bypass rm -f $test.[co] $test $test$shared_ext echo "Please use win32/Makefile.gcc instead." | tee -a configure.log - leave 1 + ###leave 1 LDSHARED=${LDSHARED-"$cc -shared"} LDSHAREDLIBC="" EXE='.exe' ;; :; CHOST="$ARCH" ./configure --prefix="$PREFIX" :; make :; sudo make install openssl ^^^^^^^ OpenSSL is an optional dependency for NUT itself (it or Mozilla NSS can be used to protect the networking communications), and for libneon below (OpenSSL or GnuTLS). Note the non-standard `config` script bundled along, and hoops to jump through... :; ( cd "$DLDIR" && wget -c https://www.openssl.org/source/openssl-1.1.1q.tar.gz ) :; cd "$WSDIR" :; tar xzf "$DLDIR"/openssl-1.1.1q.tar.gz :; cd openssl-1.1.1q # Build options partially lifted from OBS packaging, see: # https://build.opensuse.org/package/view_file/windows:mingw:win32/mingw32-openssl-1_1/mingw32-openssl-1_1.spec?expand=1 :; ( case "$ARCH" in *x86_64*) SYSTEM=MINGW64 ;; *i?86*) SYSTEM=MINGW32 ;; *) SYSTEM=MINGW ;; esac export SYSTEM ./config \ no-idea enable-rfc3779 zlib shared \ -fno-common \ --prefix="$PREFIX" --cross-compile-prefix="/usr/bin/$ARCH-" \ -DPURIFY -D__USE_GNU ) :; make :; sudo make install xz (liblzma) ^^^^^^^^^^^^ Needed for libxml2. :; ( cd "$DLDIR" && wget -c https://tukaani.org/xz/xz-5.2.5.tar.gz ) :; cd "$WSDIR" :; tar xzf "$DLDIR"/xz-5.2.5.tar.gz :; cd xz-5.2.5 :; ./configure --prefix="$PREFIX" $HOST_FLAG :; make :; sudo make install libxml2 ^^^^^^^ Needed for libneon. ///////////////////////////////////////////////////////////////////////////// // ...and for fontconfig ///////////////////////////////////////////////////////////////////////////// :; ( cd "$DLDIR" && wget -c https://gitlab.gnome.org/GNOME/libxml2/-/archive/v2.9.14/libxml2-v2.9.14.tar.gz ) :; cd "$WSDIR" :; tar xzf "$DLDIR"/libxml2-v2.9.14.tar.gz :; cd libxml2-v2.9.14 :; ./autogen.sh --prefix="$PREFIX" $HOST_FLAG --without-python :; make :; sudo make install gd (cgi) ^^^^^^^^ Note that for the general-case build libgd supports a huge dependency tree, so for the NUT purposes we are going for as little as possible. Initially the purpose was to have libgd installed to build/link against for the Windows target. Subsequently more dependencies were documented, but still further refinement may be needed to have it actually usable for CGI web pages rendering. Finally note that end-users would have to install a CGI-capable web server to use this feature in practice. * zlib: see above * iconv: + Seems to be directly used by `libgd` (at least queried in its `configure` script): :; ( cd "$DLDIR" && wget -c https://ftp.gnu.org/pub/gnu/libiconv/libiconv-1.17.tar.gz ) :; cd "$WSDIR" :; tar xzf "$DLDIR"/libiconv-1.17.tar.gz :; cd libiconv-1.17 :; ./configure --prefix="$PREFIX" $HOST_FLAG :; make :; sudo make install * freetype: + NOTE: For some reason it won't build in an Ubuntu 20.04 running under WSL2 -- blocks running an `apinames.exe` program that it has just built. May be a problem of the emulation layer (as it calls the EXE via `/tools/init`), and/or of the system antivirus interaction?.. :; ( cd "$DLDIR" && wget -c https://download.savannah.gnu.org/releases/freetype/freetype-2.12.1.tar.gz ) :; cd "$WSDIR" :; tar xzf "$DLDIR"/freetype-2.12.1.tar.gz :; cd freetype-2.12.1 :; ./configure --prefix="$PREFIX" $HOST_FLAG --without-brotli :; make :; sudo make install ///////////////////////////////////////////////////////////////////////////// WIP - fontconfig not usable yet due to ICU failing to cross-build Maybe an older version of either would fare better?.. * gperf is needed by fontconfig build routine as a tool usable on the build system, so a packaged install should suffice, e.g. `apt-get install gperf`. Otherwise, build one from source (and note that this may be needed e.g. for native builds on Windows, but not "just" for using a cross-binary that the build host can generate but not run natively). :; ( cd "$DLDIR" && wget -c http://ftp.gnu.org/pub/gnu/gperf/gperf-3.1.tar.gz ) :; cd "$WSDIR" :; tar xzf "$DLDIR"/gperf-3.1.tar.gz :; cd gperf-3.1 :; ./configure --prefix="$PREFIX" $HOST_FLAG :; make :; sudo make install * ICU: For a cross-build of ICU, you should first build and install a copy for the host system, then use it as a resource for the final build. Set aside a good part of an hour to get this built: :; ( cd "$DLDIR" && wget -c https://github.com/unicode-org/icu/releases/download/release-71-1/icu4c-71_1-src.tgz ) # This one is built for native host architecture and provides # some resources to ARCH builds later on: :; cd "$DLDIR" :; tar xzf icu4c-71_1-src.tgz :; rm -rf icu-native || true :; mv icu icu-native # note, no version in the pathname :; cd icu-native/source :; ./configure CFLAGS= CXXFLAGS= LDFLAGS= ARCH= :; make :; cd "$WSDIR" :; tar xzf "$DLDIR"/icu4c-71_1-src.tgz :; cd icu/source :; ./configure --prefix="$PREFIX" $HOST_FLAG --with-cross-build="$DLDIR"/icu-native/source :; make :; sudo make install * fontconfig: :; ( cd "$DLDIR" && wget -c https://www.freedesktop.org/software/fontconfig/release/fontconfig-2.14.0.tar.gz ) :; cd "$WSDIR" :; tar xzf "$DLDIR"/fontconfig-2.14.0.tar.gz :; cd fontconfig-2.14.0/ :; ./configure --prefix="$PREFIX" $HOST_FLAG --enable-libxml2 :; make :; sudo make install // for fontconfig ///////////////////////////////////////////////////////////////////////////// * libpng: :; ( cd "$DLDIR" && wget -c https://download.sourceforge.net/libpng/libpng-1.6.37.tar.gz ) :; cd "$WSDIR" :; tar xzf "$DLDIR"/libpng-1.6.37.tar.gz :; cd libpng-1.6.37 :; ./configure --prefix="$PREFIX" $HOST_FLAG :; make :; sudo make install * libgd itself: + TODO: This works for 64-bit builds, however 32-bit ones are burdened with `@8` or `@12` suffixes to symbol names, and subsequent link checks in NUT fail to find `libgd` as usable -- so CGI is not built in 32-bit mode. According to such context, this must be something about STDCALL and/or "extern C"... :; ( cd "$DLDIR" && wget -c https://github.com/libgd/libgd/releases/download/gd-2.3.3/libgd-2.3.3.tar.gz ) :; cd "$WSDIR" :; tar xzf "$DLDIR"/libgd-2.3.3.tar.gz :; cd libgd-2.3.3 :; ./configure --prefix="$PREFIX" $HOST_FLAG \ --with-png --with-freetype \ --without-tiff --without-jpeg --without-xpm \ --without-fontconfig # Note: currently we configure away almost all capabilities, # to match the dependency binaries (and/or headers) present # on the build system. Review resulting build recipes that # they DO NOT refer to system /usr/include locations! # In practice we would likely need the fontconfig pieces to work. :; make :; sudo make install libmodbus ^^^^^^^^^ :; ( cd "$DLDIR" && wget -c https://libmodbus.org/releases/libmodbus-3.1.7.tar.gz ) :; cd "$WSDIR" :; tar xzf "$DLDIR"/libmodbus-3.1.7.tar.gz :; cd libmodbus-3.1.7 :; ./configure --prefix="$PREFIX" $HOST_FLAG :; make :; sudo make install net-snmp ^^^^^^^^ :; ( cd "$DLDIR" && wget -c https://sourceforge.net/projects/net-snmp/files/net-snmp/5.9.1/net-snmp-5.9.1.tar.gz ) :; cd "$WSDIR" :; tar xzf "$DLDIR"/net-snmp-5.9.1.tar.gz :; cd net-snmp-5.9.1 :; yes "" | ./configure --prefix="$PREFIX" $HOST_FLAG \ --with-default-snmp-version=3 --disable-agent --disable-daemon \ --with-sys-contact="" --with-sys-location="" --with-logfile=none \ --with-persistent-directory="${PREFIX}/var/net-snmp" \ --disable-embedded-perl --without-perl-modules --disable-perl-cc-checks \ --enable-shared # NOTE: ./configure script may ask a few questions, or may just print # a banner that it would; hopefully all replies needed for current # version are covered above # The following long `LDFLAGS` ensure that shared `libnetsnmp-40.dll` # gets built and later installed (and siblings which NUT does not use): :; make LDFLAGS="-no-undefined -lws2_32 -lregex -Xlinker --ignore-unresolved-symbol=_app_name_long -Xlinker --ignore-unresolved-symbol=app_name_long" :; find . -type f -name '*.dll' -o -name '*.dll.a' :; sudo make install NOTE: net-snmp tends to only `make` a static-linking library for Windows by default (the shared library only appears with `LDFLAGS` proposed above). In this case consumers must link not only with `-lnetsnmp` but also its dependencies explicitly -- see `Libs.private` line in `netsnmp.pc` of your build (or installation in `${PREFIX}/lib/pkgconfig/netsnmp.pc`). Builds can extract this info with `pkg-config --libs --static netsnmp` as NUT scenarios do (for mingw, if shared-linking attempt fails). libneon ^^^^^^^ As of release 0.32.2 libneon failed to build -- neither in Windows MSYS2 nor in Linux mingw environments. Some tinkering was needed to make it happen, and was posted as https://github.com/notroj/neon/pull/84 (pull request sourced from https://github.com/jimklimov/neon/tree/fix-mingw-cross branch). Due to this, instructions below differ from others by setting up an out-of-tree build instead of a tarball download. Eventually it would hopefully suffice to fetch https://notroj.github.io/neon/neon-0.32.5.tar.gz or newer (PR was merged after libneon 0.32.4 release). NOTE: Ability to `make docs` here relies on presence of `xmlto` program. In NUT CI workers prepared according to `docs/config-prereqs.txt` this should be among dependencies for `asciidoc`; beware that with prerequisites it has quite a large installation footprint. Alternately check PR #69, or consult the makefiles for current `install` target definition to run its job without `install-docs` part (example posted below). #:; ( cd "$DLDIR" && git clone -b fix-mingw-cross https://github.com/jimklimov/neon neon-git ) :; ( cd "$DLDIR" && git clone https://github.com/notroj/neon neon-git ) :; ( cd "$DLDIR/neon-git" && ./autogen.sh ) :; cd "$WSDIR" :; rm -rf neon-git ; mkdir neon-git :; cd neon-git :; "$DLDIR"/neon-git/configure --prefix="$PREFIX" $HOST_FLAG \ --enable-shared --with-ssl=openssl :; make all docs :; sudo make install \ || sudo make install-lib install-headers install-config install-nls ###install-docs ///////////////////////////////////////////////////////////////////////////// // for avahi libpcre ^^^^^^^ Needed for glib2 (further for avahi). :; ( cd "$DLDIR" && wget -c https://github.com/PCRE2Project/pcre2/releases/download/pcre2-10.40/pcre2-10.40.tar.gz ) :; cd "$WSDIR" :; tar xzf "$DLDIR"/pcre2-10.40.tar.gz :; cd pcre2-10.40 :; ./configure --prefix="$PREFIX" $HOST_FLAG :; make all :; sudo make install :; sudo ln -s libpcre2-posix.pc ${PREFIX}/lib/pkgconfig/libpcre.pc gettext/libintl ^^^^^^^^^^^^^^^ WARNING: Currently gettext does not build, at least on WSL2 Ubuntu, fails with `undefined reference to '__imp_formatstring_ruby'`. Needed for glib2 (further for avahi). :; ( cd "$DLDIR" && wget -c https://ftp.gnu.org/pub/gnu/gettext/gettext-0.20.tar.gz ) :; cd "$WSDIR" :; tar xzf "$DLDIR"/gettext-0.20.tar.gz :; cd gettext-0.20 # Flags tweaked due to http://savannah.gnu.org/bugs/?36443 :; ./configure --prefix="$PREFIX" $HOST_FLAG \ CFLAGS="$CFLAGS -O2" CXXFLAGS="$CXXFLAGS -O2" :; make all :; sudo make install glib2 ^^^^^ WARNING: Currently glib2 does not build, at least on WSL2 Ubuntu, fails to find gettext (not built above). Needed for avahi. Requires `meson` build system, e.g. via: ------ :; sudo apt-get install meson ------ NOTE: Latest glib-2.73.3 as of this writing requires `meson >= 0.60.0` but the one provided in WSL2 Ubuntu 20.04 OS packages is older (0.53.2). In this case, try an older glib2 release, e.g. glib-2.72.1 seems compatible. Configuration options below were initially borrowed from https://build.opensuse.org/package/view_file/windows:mingw:win32/mingw32-glib2/mingw32-glib2.spec?expand=1 :; ( cd "$DLDIR" && wget -c https://gitlab.gnome.org/GNOME/glib/-/archive/2.72.1/glib-2.72.1.tar.gz ) :; cd "$WSDIR" :; tar xzf "$DLDIR"/glib-2.72.1.tar.gz :; cd glib-2.72.1 :; case "$ARCH" in *x86_64*) cp -pf .gitlab-ci/cross_file_mingw64.txt .gitlab-ci/cross_file_${ARCH}.txt ;; *i686*) sed 's,x86_64,i686,g' < .gitlab-ci/cross_file_mingw64.txt > .gitlab-ci/cross_file_${ARCH}.txt ;; esac # We do not have an ARCH-dependent pkg-config binary: :; sed "s,^pkgconfig = .*\$,pkgconfig = 'pkg-config'," \ -i .gitlab-ci/cross_file_${ARCH}.txt # With meson, config and build can be done in one shot: :; meson --prefix="$PREFIX" \ --buildtype=plain --wrap-mode=nodownload \ --auto-features=auto \ --cross-file=.gitlab-ci/cross_file_${ARCH}.txt \ . build \ --default-library=shared \ -Dman=false -Dgtk_doc=false \ -Dsystemtap=false -Ddtrace=false \ -Dinstalled_tests=false -Dlibelf=disabled :; sudo meson install avahi ^^^^^ WARNING: Currently avahi does not build, at least on WSL2 Ubuntu, fails to find glib2 (not built above). Release 0.8 (and current git as of this writing) sources use `-Wl,-z...` linking flags which are not supported by mingw `ld` tooling, and so fail to configure. [NOTE] ====== To build from Git sources or regenerate `configure` in tarball sources like shown below, you should also have `gettextize` tool before running `autogen.sh`, e.g. via: ------ :; sudo apt install intltool autopoint :; ( cd "$DLDIR" && git clone https://github.com/lathiat/avahi avahi-git ) :; ( cd "$DLDIR/avahi-git" && ./autogen.sh ) # Stock script would go on to try configuring by default, # and that bit fails in cross-env vars ------ ====== :; ( cd "$DLDIR" && wget -c https://github.com/lathiat/avahi/releases/download/v0.8/avahi-0.8.tar.gz ) :; cd "$WSDIR" :; tar xzf "$DLDIR"/avahi-0.8.tar.gz :; cd avahi-0.8 :; vi common/acx_pthread.m4 # Edit `common/acx_pthread.m4` to remove `-Wl,-z,defs` near # AC_MSG_CHECKING([whether -pthread is sufficient with -shared]) # Alternatively just edit `configure` script from the tarball. :; ./autogen.sh || true :; ./configure --prefix="$PREFIX" $HOST_FLAG :; make :; sudo make install // for avahi ///////////////////////////////////////////////////////////////////////////// Other requirements ^^^^^^^^^^^^^^^^^^ ipmi, ssl with Mozilla NSS... * https://ftp.gnu.org/gnu/freeipmi/freeipmi-1.6.9.tar.gz * https://ftp.mozilla.org/pub/security/nss/releases/NSS_3_79_RTM/src/nss-3.79-with-nspr-4.34.tar.gz Cross-building NUT with MinGW in Linux ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ After preparing at least the required dependencies above, use one of the following methods to compile NUT as: * out-of-tree from git source (easier to iterate for development, so default): (cd scripts/Windows/ && ./build-mingw-nut.sh all64) + or, depending on the build environment(s) you have prepared, + (cd scripts/Windows/ && ./build-mingw-nut.sh all32) + [NOTE] ====== This is also automated for common NUT CI build script, calling it like this: ------ # Try to guess bitness based on ARCH or CFLAGS: BUILD_TYPE=cross-windows-mingw ./ci_build.sh # Or specifically: BUILD_TYPE=cross-windows-mingw-32 ./ci_build.sh BUILD_TYPE=cross-windows-mingw-64 ./ci_build.sh ------ ====== * an existing source tarball (can be fetched from NUT website): :; export SOURCEMODE=stable ### Optionally: export VER_OPT=2.8.1 :; cd scripts/Windows/ :; ./build-mingw-nut.sh * To (re-)build from scratch with a dist tarball, e.g. testing how a stable release would fare, starting from a git checkout, use this: :; ./autogen.sh && ./configure && make dist && \ (cd scripts/Windows/ && SOURCEMODE=dist ./build-mingw-nut.sh all64) If everything goes fine, you will find a NUT installation tree in 'nut_install' sub-directory. Note the script accepts some parameters e.g. for 32/64 bit build targets. NOTE: For other ways of building and packaging, it might make sense for a packaged delivery to also `make install DESTDIR=.../nut_install` from the sources of dependency projects built above, or at least to copy the built `*.dll` files from `${PREFIX}/bin` to `nut_install/bin`. For those dependencies that are listed above, the script does this best-effort activity (does not fail if some are missing, but running the programs can fail later). nut-2.8.1/scripts/Windows/wininit.c0000644000175000017500000003523114501607135014225 00000000000000/* wininit.c - MS Windows service which replace the init script Copyright (C) 2010 Frederic Bohe 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 2 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, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifdef WIN32 #include "config.h" /* should be first */ #include "common.h" #include "winevent.h" #include "wincompat.h" #define NUT_START TRUE #define NUT_STOP FALSE typedef struct conn_s { HANDLE handle; OVERLAPPED overlapped; char buf[LARGEBUF]; struct conn_s *prev; struct conn_s *next; } conn_t; static DWORD upsd_pid = 0; static DWORD upsmon_pid = 0; static BOOL service_flag = TRUE; HANDLE svc_stop = NULL; static SERVICE_STATUS SvcStatus; static SERVICE_STATUS_HANDLE SvcStatusHandle; static void print_event(DWORD priority, const char * fmt, ...) { HANDLE EventSource; va_list ap; CHAR * buf; int ret; buf = xmalloc(LARGEBUF); va_start(ap, fmt); ret = vsnprintf(buf, LARGEBUF, fmt, ap); va_end(ap); if(ret<0) { return; } if( !service_flag ) { upslogx(LOG_ERR, "EventLog : %s\n",buf); } EventSource = RegisterEventSource(NULL, SVCNAME); if( NULL != EventSource ) { ReportEvent( EventSource, /* event log handle */ priority, /* event type */ 0, /* event category */ SVC_EVENT, /* event identifier */ NULL, /* no security identifier*/ 1, /* size of string array */ 0, /* no binary data */ (const char **)&buf, /* array of string */ NULL); /* no binary data */ DeregisterEventSource(EventSource); } if( buf ) free(buf); } /* returns PID of the newly created process or 0 on failure */ static DWORD create_process(char * command) { STARTUPINFO StartupInfo; PROCESS_INFORMATION ProcessInformation; BOOL res; DWORD LastError; memset(&StartupInfo,0,sizeof(STARTUPINFO)); StartupInfo.cb = sizeof(StartupInfo); memset(&ProcessInformation,0,sizeof(ProcessInformation)); res = CreateProcess( NULL, command, NULL, NULL, FALSE, CREATE_NEW_PROCESS_GROUP, NULL, NULL, &StartupInfo, &ProcessInformation ); LastError = GetLastError(); if( res == 0 ) { print_event(LOG_ERR, "Can't create process %s : %d", command, LastError); return 0; } return ProcessInformation.dwProcessId; } /* return PID of created process or 0 on failure */ static DWORD run_drivers() { char command[MAX_PATH]; char *path; path = getfullpath(PATH_BIN); snprintf(command,sizeof(command),"%s\\upsdrvctl.exe start",path); free(path); return create_process(command); } /* return PID of created process or 0 on failure */ static DWORD stop_drivers() { char command[MAX_PATH]; char *path; path = getfullpath(PATH_BIN); snprintf(command,sizeof(command),"%s\\upsdrvctl.exe stop",path); free(path); return create_process(command); } /* return PID of created process or 0 on failure */ static void run_upsd() { char command[MAX_PATH]; char *path; path = getfullpath(PATH_SBIN); snprintf(command,sizeof(command),"%s\\upsd.exe",path); free(path); upsd_pid = create_process(command); } static void stop_upsd() { if ( sendsignal( UPSD_PIPE_NAME, COMMAND_STOP ) ) { print_event(LOG_ERR, "Error stopping upsd (%d)",GetLastError()); } } /* return PID of created process or 0 on failure */ static void run_upsmon() { char command[MAX_PATH]; char *path; path = getfullpath(PATH_SBIN); snprintf(command,sizeof(command),"%s\\upsmon.exe",path); free(path); upsmon_pid = create_process(command); } static void stop_upsmon() { if ( sendsignal( UPSMON_PIPE_NAME, COMMAND_STOP ) ) { print_event(LOG_ERR, "Error stopping upsmon (%d)",GetLastError()); } } /* Return 0 if powerdown flag is set */ static DWORD test_powerdownflag() { char command[MAX_PATH]; char *path; STARTUPINFO StartupInfo; PROCESS_INFORMATION ProcessInformation; BOOL res; DWORD LastError; DWORD status; int i = 10; int timeout = 500; path = getfullpath(PATH_SBIN); snprintf(command,sizeof(command),"%s\\upsmon.exe -K",path); free(path); memset(&StartupInfo,0,sizeof(STARTUPINFO)); StartupInfo.cb = sizeof(StartupInfo); memset(&ProcessInformation,0,sizeof(ProcessInformation)); res = CreateProcess( NULL, command, NULL, NULL, FALSE, CREATE_NEW_PROCESS_GROUP, NULL, NULL, &StartupInfo, &ProcessInformation ); LastError = GetLastError(); if( res == 0 ) { print_event(LOG_ERR, "Can't create process %s : %d", command, LastError); return 1; } while( i > 0) { res = GetExitCodeProcess(ProcessInformation.hProcess, &status); if( res != 0) { if( status != STILL_ACTIVE) { return status; } } Sleep(timeout); i--; } return 1; } static DWORD shutdown_ups() { char command[MAX_PATH]; char *path; path = getfullpath(PATH_BIN); snprintf(command,sizeof(command),"%s\\upsdrvctl.exe shutdown",path); free(path); return create_process(command); } /* return 0 on failure */ static int parse_nutconf(BOOL start_flag) { char fn[SMALLBUF]; FILE *nutf; char buf[SMALLBUF]; char fullname[SMALLBUF]; snprintf(fn,sizeof(fn),"%s/nut.conf",confpath()); nutf = fopen(fn, "r"); if(nutf == NULL) { snprintf(buf,sizeof(buf),"Error opening %s",fn); print_event(LOG_ERR,buf); return 0; } while( fgets(buf,sizeof(buf),nutf) != NULL ) { if(buf[0] != '#') { if( strstr(buf,"standalone") != NULL || strstr(buf,"netserver") != NULL ) { if( start_flag == NUT_START ) { print_event(LOG_INFO,"Starting drivers"); run_drivers(); print_event(LOG_INFO,"Starting upsd"); run_upsd(); /* Wait a moment for the drivers to start */ Sleep(5000); print_event(LOG_INFO,"Starting upsmon"); run_upsmon(); return 1; } else { print_event(LOG_INFO,"stop upsd"); stop_upsd(); print_event(LOG_INFO,"stop drivers"); stop_drivers(); print_event(LOG_INFO,"stop upsmon"); stop_upsmon(); /* Give a chance to upsmon to write the POWERDOWNFLAG file */ Sleep(1000); if( test_powerdownflag() == 0 ) { print_event(LOG_INFO,"shutdown ups"); shutdown_ups(); } print_event(LOG_INFO,"End of NUT stop"); return 1; } } if( strstr(buf,"netclient") != NULL ) { if( start_flag == NUT_START ) { run_upsmon(); return 1; } else { stop_upsmon(); return 1; } } } } GetFullPathName(fn,sizeof(fullname),fullname,NULL); snprintf(buf,sizeof(buf),"nut disabled, please adjust the configuration to your needs. Then set MODE to a suitable value in %s to enable it.",fullname); print_event(LOG_ERR,buf); return 0; } static int SvcInstall(const char * SvcName, const char * args) { SC_HANDLE SCManager; SC_HANDLE Service; TCHAR Path[MAX_PATH]; if( !GetModuleFileName( NULL, Path, MAX_PATH ) ) { printf("Cannot install service (%d)\n", (int)GetLastError()); return EXIT_FAILURE; } if( args != NULL ) { snprintfcat(Path, sizeof(Path), " %s", args); } SCManager = OpenSCManager( NULL, /* local computer */ NULL, /* ServiceActive database */ SC_MANAGER_ALL_ACCESS); /* full access rights */ if (NULL == SCManager) { upslogx(LOG_ERR, "OpenSCManager failed (%d)\n", (int)GetLastError()); return EXIT_FAILURE; } Service = CreateService( SCManager, /* SCM database */ SvcName, /* name of service */ SvcName, /* service name to display */ SERVICE_ALL_ACCESS, /* desired access */ SERVICE_WIN32_OWN_PROCESS, /* service type */ SERVICE_AUTO_START, /* start type */ SERVICE_ERROR_NORMAL, /* error control type */ Path, /* path to service binary */ NULL, /* no load ordering group */ NULL, /* no tag identifier */ NULL, /* no dependencies */ NULL, /* LocalSystem account */ NULL); /* no password */ if (Service == NULL) { upslogx(LOG_ERR, "CreateService failed (%d)\n", (int)GetLastError()); CloseServiceHandle(SCManager); return EXIT_FAILURE; } else { upslogx(LOG_INFO, "Service installed successfully\n"); } CloseServiceHandle(Service); CloseServiceHandle(SCManager); return EXIT_SUCCESS; } static int SvcUninstall(const char * SvcName) { SC_HANDLE SCManager; SC_HANDLE Service; SCManager = OpenSCManager( NULL, /* local computer */ NULL, /* ServicesActive database */ SC_MANAGER_ALL_ACCESS); /* full access rights */ if (NULL == SCManager) { upslogx(LOG_ERR, "OpenSCManager failed (%d)\n", (int)GetLastError()); return EXIT_FAILURE; } Service = OpenService( SCManager, /* SCM database */ SvcName, /* name of service */ DELETE); /* need delete access */ if (Service == NULL) { upslogx(LOG_ERR, "OpenService failed (%d)\n", (int)GetLastError()); CloseServiceHandle(SCManager); return EXIT_FAILURE; } if (! DeleteService(Service) ) { upslogx(LOG_ERR,"DeleteService failed (%d)\n", (int)GetLastError()); } else { upslogx(LOG_ERR,"Service deleted successfully\n"); } CloseServiceHandle(Service); CloseServiceHandle(SCManager); return EXIT_SUCCESS; } static void ReportSvcStatus( DWORD CurrentState, DWORD Win32ExitCode, DWORD WaitHint) { static DWORD CheckPoint = 1; SvcStatus.dwCurrentState = CurrentState; SvcStatus.dwWin32ExitCode = Win32ExitCode; SvcStatus.dwWaitHint = WaitHint; if (CurrentState == SERVICE_START_PENDING) SvcStatus.dwControlsAccepted = 0; else SvcStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN; if ( (CurrentState == SERVICE_RUNNING) || (CurrentState == SERVICE_STOPPED) ) { SvcStatus.dwCheckPoint = 0; } else { SvcStatus.dwCheckPoint = CheckPoint++; } /* report the status of the service to the SCM */ SetServiceStatus( SvcStatusHandle, &SvcStatus ); } static void WINAPI SvcCtrlHandler( DWORD Ctrl ) { switch(Ctrl) { case SERVICE_CONTROL_STOP: case SERVICE_CONTROL_SHUTDOWN: ReportSvcStatus(SERVICE_STOP_PENDING, NO_ERROR, 0); /* Signal the service to stop */ SetEvent(svc_stop); ReportSvcStatus(SvcStatus.dwCurrentState, NO_ERROR, 0); return; case SERVICE_CONTROL_INTERROGATE: break; default: break; } } static void SvcStart(char * SvcName) { /* Register the handler function for the service */ SvcStatusHandle = RegisterServiceCtrlHandler( SvcName, SvcCtrlHandler); if( !SvcStatusHandle ) { upslogx(LOG_ERR, "RegisterServiceCtrlHandler\n"); return; } SvcStatus.dwServiceType = SERVICE_WIN32_OWN_PROCESS; SvcStatus.dwServiceSpecificExitCode = 0; /* Report initial status to the SCM */ ReportSvcStatus( SERVICE_START_PENDING, NO_ERROR, 3000 ); } static void SvcReady(void) { svc_stop = CreateEvent( NULL, /* default security attributes */ TRUE, /* manual reset event */ FALSE, /* not signaled */ NULL); /* no name */ if( svc_stop == NULL ) { ReportSvcStatus( SERVICE_STOPPED, NO_ERROR, 0); return; } ReportSvcStatus( SERVICE_RUNNING, NO_ERROR, 0); } static void close_all(void) { pipe_conn_t *conn; for (conn = pipe_connhead; conn; conn = conn->next) { pipe_disconnect(conn); } } static void WINAPI SvcMain( DWORD argc, LPTSTR *argv ) { DWORD ret; HANDLE handles[MAXIMUM_WAIT_OBJECTS]; int maxhandle = 0; pipe_conn_t *conn; DWORD priority; char * buf; NUT_UNUSED_VARIABLE(argc); NUT_UNUSED_VARIABLE(argv); if(service_flag) { SvcStart(SVCNAME); } /* A service has no console, so do has its children. */ /* So if we want to be able to send CTRL+BREAK signal we must */ /* create a console which will be inherited by children */ AllocConsole(); print_event(LOG_INFO,"Starting"); /* pipe for event log proxy */ pipe_create(EVENTLOG_PIPE_NAME); /* parse nut.conf and start relevant processes */ if ( parse_nutconf(NUT_START) == 0 ) { print_event(LOG_INFO, "exiting"); if( service_flag ) { ReportSvcStatus( SERVICE_STOPPED, NO_ERROR, 0); } return; } if(service_flag) { SvcReady(); } while (1) { maxhandle = 0; memset(&handles,0,sizeof(handles)); /* Wait on the read IO of each connections */ for (conn = pipe_connhead; conn; conn = conn->next) { handles[maxhandle] = conn->overlapped.hEvent; maxhandle++; } /* Add the new pipe connected event */ handles[maxhandle] = pipe_connection_overlapped.hEvent; maxhandle++; /* Add SCM event handler in service mode*/ if(service_flag) { handles[maxhandle] = svc_stop; maxhandle++; } ret = WaitForMultipleObjects(maxhandle,handles,FALSE,INFINITE); if (ret == WAIT_FAILED) { print_event(LOG_ERR, "Wait failed"); return; } if( handles[ret] == svc_stop && service_flag ) { parse_nutconf(NUT_STOP); if(service_flag) { print_event(LOG_INFO, "Exiting"); close_all(); ReportSvcStatus( SERVICE_STOPPED, NO_ERROR, 0); } return; } /* Retrieve the signaled connection */ for(conn = pipe_connhead; conn != NULL; conn = conn->next) { if( conn->overlapped.hEvent == handles[ret-WAIT_OBJECT_0]) { break; } } /* a new pipe connection has been signaled */ if (handles[ret] == pipe_connection_overlapped.hEvent) { pipe_connect(); } /* one of the read event handle has been signaled */ else { if( conn != NULL) { if( pipe_ready(conn) ) { buf = conn->buf; /* a frame is a DWORD indicating priority followed by an array of char (not necessarily followed by a terminal 0 */ priority =*((DWORD *)buf); buf = buf + sizeof(DWORD); print_event(priority,buf); pipe_disconnect(conn); } } } } } int main(int argc, char **argv) { int i; while ((i = getopt(argc, argv, "+IUN")) != -1) { switch (i) { case 'I': return SvcInstall(SVCNAME,NULL); case 'U': return SvcUninstall(SVCNAME); case 'N': service_flag = FALSE; upslogx(LOG_ERR, "Running in non-service mode\n"); break; default: break; } } optind = 0; SERVICE_TABLE_ENTRY DispatchTable[] = { { SVCNAME, (LPSERVICE_MAIN_FUNCTION) SvcMain }, { NULL, NULL } }; /* This call returns when the service has stopped */ if(service_flag ) { if (!StartServiceCtrlDispatcher( DispatchTable )) { print_event(LOG_ERR, "StartServiceCtrlDispatcher failed : exiting, this is a Windows service which can't be run as a regular application by default. Try -N to start it as a regular application"); } } else { SvcMain(argc,argv); } return EXIT_SUCCESS; } #else /* Just avoid: ISO C forbids an empty translation unit [-Werror=pedantic] */ int main (int argc, char ** argv); #endif /* WIN32 */ nut-2.8.1/scripts/Windows/halt.c0000644000175000017500000000342214501607135013471 00000000000000/* gcc -mwindows -mno-cygwin -o halt.exe halt.c NAME halt - stopping the system SYNOPSIS halt [-pq] DESCRIPTION The halt utility logs off the current user, flushes the file system buffers to disk, stops all processes (non-responsive processes are only forced to stop in Windows 2000), and shuts the system down. The options are as follows -p Attempt to powerdown the system. If the powerdown fails, or the system does not support software powerdown, the system will halt. -q Do not give processes a chance to shut down before halting or restarting. This option should not normally be used. AUTHOR Ben Collver Jim Klimov - slight adjustments for NUT builds */ #include "config.h" /* should be first */ #include "common.h" #include #ifndef EWX_FORCEIFHUNG #define EWX_FORCEIFHUNG 0x00000010 #endif int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) { TOKEN_PRIVILEGES privileges = {1, {{{0, 0}, SE_PRIVILEGE_ENABLED}}}; HANDLE my_token; UINT my_flags; NUT_UNUSED_VARIABLE(hInstance); NUT_UNUSED_VARIABLE(hPrevInstance); NUT_UNUSED_VARIABLE(nCmdShow); my_flags = EWX_SHUTDOWN | EWX_FORCEIFHUNG; if (strstr(lpCmdLine, "q") != NULL) { my_flags |= EWX_FORCE; } if (strstr(lpCmdLine, "p") != NULL) { my_flags |= EWX_POWEROFF; } if (!LookupPrivilegeValue( NULL, SE_SHUTDOWN_NAME, &privileges.Privileges[0].Luid)) { exit(1); } if (!OpenProcessToken( GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES, &my_token)) { exit(2); } if (!AdjustTokenPrivileges( my_token, FALSE, &privileges, sizeof(TOKEN_PRIVILEGES), NULL, NULL)) { exit(3); } CloseHandle(my_token); if (!ExitWindowsEx(my_flags, 0)) { exit(4); } exit(0); } nut-2.8.1/scripts/Windows/build-mingw-nut.sh0000755000175000017500000001522214520274617015765 00000000000000#!/bin/bash # NOTE: bash syntax (non-POSIX script) is used below! # # script to cross compile NUT for Windows from Linux using MinGW-w64 # http://mingw-w64.sourceforge.net/ #set -x SCRIPTDIR="`dirname "$0"`" SCRIPTDIR="`cd "$SCRIPTDIR" && pwd`" DLLLDD_SOURCED=true . "${SCRIPTDIR}/dllldd.sh" # default to update source then build # These paths are somewhat related: [ -n "${WINDIR-}" ] || WINDIR="$(pwd)" [ -n "${TOP_DIR-}" ] || TOP_DIR="$WINDIR/../.." # These may be located elsewhere: [ -n "${BUILD_DIR-}" ] || BUILD_DIR="$WINDIR/nut_build" [ -n "${INSTALL_DIR-}" ] || INSTALL_DIR="$WINDIR/nut_install" # This should match the tarball and directory name, # if a stable version is used: [ -n "$VER_OPT" ] || VER_OPT=2.8.1 DEBUG=true # default to 32bits build # Note: README specifies dependencies to pre-build and install; # those DLLs should correspond to same architecture selection cmd=all32 if [ -n "$1" ] ; then cmd=$1 fi [ -n "$SOURCEMODE" ] || SOURCEMODE="out-of-tree" rm -rf "$BUILD_DIR" "$INSTALL_DIR" CONFIGURE_SCRIPT="./configure" case "$SOURCEMODE" in stable) # FIXME # Stable version (download the latest stable archive) VER_OPT_SHORT="`echo "$VER_OPT" | awk -F. '{print $1"."$2}'`" if [ ! -s "nut-$VER_OPT.tar.gz" ] ; then wget "https://www.networkupstools.org/source/$VER_OPT_SHORT/nut-$VER_OPT.tar.gz" fi rm -rf "nut-$VER_OPT" tar -xzf "nut-$VER_OPT.tar.gz" mv "nut-$VER_OPT" "$BUILD_DIR" ;; dist) # In-place version (no download) cd ../.. rm -f nut-?.?.?*.tar.gz [ -s Makefile ] || { ./autogen.sh && ./configure; } make dist SRC_ARCHIVE=$(ls -1 nut-?.?.?*.tar.gz | sort -n | tail -1) cd scripts/Windows tar -xzf "../../$SRC_ARCHIVE" mv nut-?.?.?* "$BUILD_DIR" ;; out-of-tree) CONFIGURE_SCRIPT="../../../configure" cd ../.. if [ ! -x ./configure ]; then ./autogen.sh fi if [ -s Makefile ]; then make distclean fi cd scripts/Windows mkdir -p "$BUILD_DIR" ;; esac cd "$BUILD_DIR" || exit if [ -z "$INSTALL_WIN_BUNDLE" ]; then echo "NOTE: You might want to export INSTALL_WIN_BUNDLE=true to use main NUT Makefile" echo "recipe for DLL co-bundling (default: false to use logic maintained in $0" fi >&2 if [ "$cmd" == "all64" ] || [ "$cmd" == "b64" ] || [ "$cmd" == "all32" ] || [ "$cmd" == "b32" ] ; then ARCH="x86_64-w64-mingw32" if [ "$cmd" == "all32" ] || [ "$cmd" == "b32" ] ; then ARCH="i686-w64-mingw32" fi HOST_FLAG="--host=$ARCH" # --build needs to be specified, beside of --host, to avoid Warning # but this version is very Debian specific!!! # FIXME: find something more generic BUILD_FLAG="--build=`dpkg-architecture -qDEB_BUILD_GNU_TYPE`" export CC="$ARCH-gcc" export CXX="$ARCH-g++" # TODO: Detect/parameterize? # This prefix is currently valid for mingw packaging in Debian/Ubuntu. ARCH_PREFIX="/usr/$ARCH" export PATH="${ARCH_PREFIX}/bin:$PATH" # Note: _WIN32_WINNT>=0x0600 is needed for inet_ntop in mingw headers # and the value 0xffff is anyway forced into some components at least # by netsnmp cflags. export CFLAGS+=" -D_POSIX=1 -D_POSIX_C_SOURCE=200112L -I${ARCH_PREFIX}/include/ -D_WIN32_WINNT=0xffff" export CXXFLAGS+=" -D_POSIX=1 -D_POSIX_C_SOURCE=200112L -I${ARCH_PREFIX}/include/ -D_WIN32_WINNT=0xffff" export LDFLAGS+=" -L${ARCH_PREFIX}/lib/" KEEP_NUT_REPORT_FEATURE_FLAG="" if [ x"${KEEP_NUT_REPORT_FEATURE-}" = xtrue ]; then KEEP_NUT_REPORT_FEATURE_FLAG="--enable-keep_nut_report_feature" fi # Note: installation prefix here is "/" and desired INSTALL_DIR # location is passed to `make install` as DESTDIR below. $CONFIGURE_SCRIPT $HOST_FLAG $BUILD_FLAG --prefix=/ \ $KEEP_NUT_REPORT_FEATURE_FLAG \ PKG_CONFIG_PATH="${ARCH_PREFIX}/lib/pkgconfig" \ --without-pkg-config --with-all=auto \ --without-systemdsystemunitdir \ --with-pynut=app \ --with-augeas-lenses-dir=/augeas-lenses \ --enable-Werror \ || exit echo "$0: configure phase complete ($?)" >&2 make 1>/dev/null || exit echo "$0: build phase complete ($?)" >&2 if [ "x$INSTALL_WIN_BUNDLE" = xtrue ] ; then # Going forward, this should be the main mode - "legacy code" # below picked up and transplanted into main build scenarios: echo "NOTE: INSTALL_WIN_BUNDLE==true so using main NUT Makefile logic for DLL co-bundling" >&2 make install-win-bundle DESTDIR="${INSTALL_DIR}" || exit else # Legacy code from when NUT for Windows effort started; # there is no plan to maintain it much (this script is PoC): echo "NOTE: INSTALL_WIN_BUNDLE!=true so using built-in logic for DLL co-bundling" >&2 make install DESTDIR="${INSTALL_DIR}" || exit # Per docs, Windows loads DLLs from EXE file's dir or some # system locations or finally PATH, so unless the caller set # the latter, we can not load the pre-linked DLLs from ../lib: # http://msdn.microsoft.com/en-us/library/windows/desktop/ms682586(v=vs.85).aspx#standard_search_order_for_desktop_applications # Be sure upsmon can run even if at cost of some duplication # (maybe even do "cp -pf" if some system dislikes "ln"); also # on a modern Windows one could go to their installed "sbin" to # mklink .\libupsclient-3.dll ..\bin\libupsclient-3.dll (cd "$INSTALL_DIR/bin" && ln libupsclient*.dll ../sbin/) (cd "$INSTALL_DIR/cgi-bin" && ln ../bin/libupsclient*.dll ./) \ || echo "NOTE: FAILED to process OPTIONAL cgi-bin directory; was NUT CGI enabled?" >&2 echo "NOTE: Adding third-party dependency libraries for each installed program" >&2 echo " Do not worry about lack of libnut* and libups* in system locations" >&2 # Cover dependencies for nut-scanner (not pre-linked) # Note: lib*snmp*.dll not listed below, it is # statically linked into binaries that use it (cd "$INSTALL_DIR/bin" && cp -pf "${ARCH_PREFIX}/bin"/{libgnurx,libusb,libltdl}*.dll .) || true (cd "$INSTALL_DIR/bin" && cp -pf "${ARCH_PREFIX}/lib"/libwinpthread*.dll .) || true # Steam-roll over all executables/libs we have here and copy # over resolved dependencies from the cross-build environment: (cd "$INSTALL_DIR" && { dllldddir . | while read D ; do cp -pf "$D" ./bin/ ; done ; } ) || true # Hardlink libraries for sbin (alternative: all bins in one dir): (cd "$INSTALL_DIR/sbin" && { DESTDIR="$INSTALL_DIR" dllldddir . | while read D ; do ln -f ../bin/"`basename "$D"`" ./ ; done ; } ) || true # Hardlink libraries for cgi-bin if present: (cd "$INSTALL_DIR/cgi-bin" && { DESTDIR="$INSTALL_DIR" dllldddir . | while read D ; do ln -f ../bin/"`basename "$D"`" ./ ; done ; } ) \ || echo "NOTE: FAILED to process OPTIONAL cgi-bin directory; was NUT CGI enabled?" >&2 fi echo "$0: install phase complete ($?)" >&2 cd .. else echo "Usage:" echo " $0 [all64 | b64 | all32 | b32]" echo " Default: 'all32'" echo "Optionally export SOURCEMODE=[stable|dist|out-of-tree]" fi nut-2.8.1/scripts/Windows/Makefile.in0000644000175000017500000006636014520274662014462 00000000000000# Makefile.in generated by automake 1.16.5 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2021 Free Software Foundation, Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. @SET_MAKE@ # Network UPS Tools: script/Windows VPATH = @srcdir@ am__is_gnu_make = { \ if test -z '$(MAKELEVEL)'; then \ false; \ elif test -n '$(MAKE_HOST)'; then \ true; \ elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \ true; \ else \ false; \ fi; \ } am__make_running_with_option = \ case $${target_option-} in \ ?) ;; \ *) echo "am__make_running_with_option: internal error: invalid" \ "target option '$${target_option-}' specified" >&2; \ exit 1;; \ esac; \ has_opt=no; \ sane_makeflags=$$MAKEFLAGS; \ if $(am__is_gnu_make); then \ sane_makeflags=$$MFLAGS; \ else \ case $$MAKEFLAGS in \ *\\[\ \ ]*) \ bs=\\; \ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ esac; \ fi; \ skip_next=no; \ strip_trailopt () \ { \ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ }; \ for flg in $$sane_makeflags; do \ test $$skip_next = yes && { skip_next=no; continue; }; \ case $$flg in \ *=*|--*) continue;; \ -*I) strip_trailopt 'I'; skip_next=yes;; \ -*I?*) strip_trailopt 'I';; \ -*O) strip_trailopt 'O'; skip_next=yes;; \ -*O?*) strip_trailopt 'O';; \ -*l) strip_trailopt 'l'; skip_next=yes;; \ -*l?*) strip_trailopt 'l';; \ -[dEDm]) skip_next=yes;; \ -[JT]) skip_next=yes;; \ esac; \ case $$flg in \ *$$target_option*) has_opt=yes; break;; \ esac; \ done; \ test $$has_opt = yes am__make_dryrun = (target_option=n; $(am__make_running_with_option)) am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkglibexecdir = $(libexecdir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ target_triplet = @target@ @HAVE_MINGW_RESGEN_TRUE@bin_PROGRAMS = nut$(EXEEXT) halt$(EXEEXT) subdir = scripts/Windows ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/m4/ax_c___attribute__.m4 \ $(top_srcdir)/m4/ax_c_pragmas.m4 \ $(top_srcdir)/m4/ax_check_compile_flag.m4 \ $(top_srcdir)/m4/ax_compare_version.m4 \ $(top_srcdir)/m4/ax_realpath.m4 \ $(top_srcdir)/m4/ax_run_or_link_ifelse.m4 \ $(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \ $(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \ $(top_srcdir)/m4/lt~obsolete.m4 \ $(top_srcdir)/m4/nut_arg_with.m4 \ $(top_srcdir)/m4/nut_check_asciidoc.m4 \ $(top_srcdir)/m4/nut_check_aspell.m4 \ $(top_srcdir)/m4/nut_check_cppcheck.m4 \ $(top_srcdir)/m4/nut_check_headers_windows.m4 \ $(top_srcdir)/m4/nut_check_libavahi.m4 \ $(top_srcdir)/m4/nut_check_libfreeipmi.m4 \ $(top_srcdir)/m4/nut_check_libgd.m4 \ $(top_srcdir)/m4/nut_check_libgpiod.m4 \ $(top_srcdir)/m4/nut_check_libltdl.m4 \ $(top_srcdir)/m4/nut_check_libmodbus.m4 \ $(top_srcdir)/m4/nut_check_libneon.m4 \ $(top_srcdir)/m4/nut_check_libnetsnmp.m4 \ $(top_srcdir)/m4/nut_check_libnss.m4 \ $(top_srcdir)/m4/nut_check_libopenssl.m4 \ $(top_srcdir)/m4/nut_check_libpowerman.m4 \ $(top_srcdir)/m4/nut_check_libregex.m4 \ $(top_srcdir)/m4/nut_check_libsystemd.m4 \ $(top_srcdir)/m4/nut_check_libusb.m4 \ $(top_srcdir)/m4/nut_check_libwrap.m4 \ $(top_srcdir)/m4/nut_check_os.m4 \ $(top_srcdir)/m4/nut_check_pkgconfig.m4 \ $(top_srcdir)/m4/nut_check_python.m4 \ $(top_srcdir)/m4/nut_check_socketlib.m4 \ $(top_srcdir)/m4/nut_compiler_family.m4 \ $(top_srcdir)/m4/nut_func_getnameinfo_argtypes.m4 \ $(top_srcdir)/m4/nut_report_feature.m4 \ $(top_srcdir)/m4/nut_stash_warnings.m4 \ $(top_srcdir)/m4/nut_type_socklen_t.m4 \ $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/include/config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = am__installdirs = "$(DESTDIR)$(bindir)" PROGRAMS = $(bin_PROGRAMS) am__halt_SOURCES_DIST = halt.c @HAVE_MINGW_RESGEN_TRUE@am_halt_OBJECTS = halt.$(OBJEXT) halt_OBJECTS = $(am_halt_OBJECTS) halt_LDADD = $(LDADD) AM_V_lt = $(am__v_lt_@AM_V@) am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@) am__v_lt_0 = --silent am__v_lt_1 = am__nut_SOURCES_DIST = wininit.c @HAVE_MINGW_RESGEN_TRUE@am_nut_OBJECTS = wininit.$(OBJEXT) nut_OBJECTS = $(am_nut_OBJECTS) @HAVE_MINGW_RESGEN_TRUE@nut_DEPENDENCIES = ../../common/libcommon.la \ @HAVE_MINGW_RESGEN_TRUE@ winevent.o AM_V_P = $(am__v_P_@AM_V@) am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) am__v_P_0 = false am__v_P_1 = : AM_V_GEN = $(am__v_GEN_@AM_V@) am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) am__v_GEN_0 = @echo " GEN " $@; am__v_GEN_1 = AM_V_at = $(am__v_at_@AM_V@) am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) am__v_at_0 = @ am__v_at_1 = DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)/include depcomp = $(SHELL) $(top_srcdir)/depcomp am__maybe_remake_depfiles = depfiles am__depfiles_remade = ./$(DEPDIR)/halt.Po ./$(DEPDIR)/wininit.Po am__mv = mv -f COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ $(AM_CFLAGS) $(CFLAGS) AM_V_CC = $(am__v_CC_@AM_V@) am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@) am__v_CC_0 = @echo " CC " $@; am__v_CC_1 = CCLD = $(CC) LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ $(AM_LDFLAGS) $(LDFLAGS) -o $@ AM_V_CCLD = $(am__v_CCLD_@AM_V@) am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@) am__v_CCLD_0 = @echo " CCLD " $@; am__v_CCLD_1 = SOURCES = $(halt_SOURCES) $(nut_SOURCES) DIST_SOURCES = $(am__halt_SOURCES_DIST) $(am__nut_SOURCES_DIST) am__can_run_installinfo = \ case $$AM_UPDATE_INFO_DIR in \ n|no|NO) false;; \ *) (install-info --version) >/dev/null 2>&1;; \ esac am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) # Read a list of newline-separated strings from the standard input, # and print each of them once, without duplicates. Input order is # *not* preserved. am__uniquify_input = $(AWK) '\ BEGIN { nonempty = 0; } \ { items[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in items) print i; }; } \ ' # Make sure the list of sources is unique. This is necessary because, # e.g., the same source file might be shared among _SOURCES variables # for different programs/libraries. am__define_uniq_tagged_files = \ list='$(am__tagged_files)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | $(am__uniquify_input)` am__DIST_COMMON = $(srcdir)/Makefile.in $(top_srcdir)/depcomp DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) A2X = @A2X@ ACLOCAL = @ACLOCAL@ ALTPIDPATH = @ALTPIDPATH@ AMTAR = @AMTAR@ AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ AR = @AR@ ASCIIDOC = @ASCIIDOC@ ASPELL = @ASPELL@ ASPELL_FILTER_LIB_PATH = @ASPELL_FILTER_LIB_PATH@ ASPELL_FILTER_SHARE_PATH = @ASPELL_FILTER_SHARE_PATH@ ASPELL_FILTER_TEX_PATH = @ASPELL_FILTER_TEX_PATH@ AUGPARSE = @AUGPARSE@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ BINDIR = @BINDIR@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CONFIG_FLAGS = @CONFIG_FLAGS@ CONFPATH = @CONFPATH@ CPP = @CPP@ CPPCHECK = @CPPCHECK@ CPPFLAGS = @CPPFLAGS@ CPPUNIT_CFLAGS = @CPPUNIT_CFLAGS@ CPPUNIT_LIBS = @CPPUNIT_LIBS@ CSCOPE = @CSCOPE@ CTAGS = @CTAGS@ CXX = @CXX@ CXXCPP = @CXXCPP@ CXXDEPMODE = @CXXDEPMODE@ CXXFLAGS = @CXXFLAGS@ CYGPATH_W = @CYGPATH_W@ DBLATEX = @DBLATEX@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ DEPLOYED_UPSC = @DEPLOYED_UPSC@ DEPLOYED_UPSD = @DEPLOYED_UPSD@ DLLTOOL = @DLLTOOL@ DOC_BUILD_LIST = @DOC_BUILD_LIST@ DOC_CHECK_LIST = @DOC_CHECK_LIST@ DRIVER_BUILD_LIST = @DRIVER_BUILD_LIST@ DRIVER_INSTALL_TARGET = @DRIVER_INSTALL_TARGET@ DRIVER_MAN_LIST = @DRIVER_MAN_LIST@ DRIVER_MAN_LIST_PAGES = @DRIVER_MAN_LIST_PAGES@ DRVPATH = @DRVPATH@ DSYMUTIL = @DSYMUTIL@ DUMPBIN = @DUMPBIN@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ ETAGS = @ETAGS@ EXEEXT = @EXEEXT@ FGREP = @FGREP@ FORCE_NUT_VERSION = @FORCE_NUT_VERSION@ GDLIB_CONFIG = @GDLIB_CONFIG@ GREP = @GREP@ HAVE_SYS_SOCKET_H = @HAVE_SYS_SOCKET_H@ HAVE_WINSOCK2_H = @HAVE_WINSOCK2_H@ HAVE_WS2TCPIP_H = @HAVE_WS2TCPIP_H@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ LD = @LD@ LDFLAGS = @LDFLAGS@ LIBAVAHI_CFLAGS = @LIBAVAHI_CFLAGS@ LIBAVAHI_LIBS = @LIBAVAHI_LIBS@ LIBDIR = @LIBDIR@ LIBGD_CFLAGS = @LIBGD_CFLAGS@ LIBGD_LDFLAGS = @LIBGD_LDFLAGS@ LIBGPIO_CFLAGS = @LIBGPIO_CFLAGS@ LIBGPIO_LIBS = @LIBGPIO_LIBS@ LIBI2C_LIBS = @LIBI2C_LIBS@ LIBIPMI_CFLAGS = @LIBIPMI_CFLAGS@ LIBIPMI_LIBS = @LIBIPMI_LIBS@ LIBLTDL_CFLAGS = @LIBLTDL_CFLAGS@ LIBLTDL_LIBS = @LIBLTDL_LIBS@ LIBMODBUS_CFLAGS = @LIBMODBUS_CFLAGS@ LIBMODBUS_LIBS = @LIBMODBUS_LIBS@ LIBNEON_CFLAGS = @LIBNEON_CFLAGS@ LIBNEON_LIBS = @LIBNEON_LIBS@ LIBNETSNMP_CFLAGS = @LIBNETSNMP_CFLAGS@ LIBNETSNMP_LIBS = @LIBNETSNMP_LIBS@ LIBOBJS = @LIBOBJS@ LIBPOWERMAN_CFLAGS = @LIBPOWERMAN_CFLAGS@ LIBPOWERMAN_LIBS = @LIBPOWERMAN_LIBS@ LIBREGEX_LIBS = @LIBREGEX_LIBS@ LIBS = @LIBS@ LIBSSL_CFLAGS = @LIBSSL_CFLAGS@ LIBSSL_LIBS = @LIBSSL_LIBS@ LIBSSL_REQUIRES = @LIBSSL_REQUIRES@ LIBSYSTEMD_CFLAGS = @LIBSYSTEMD_CFLAGS@ LIBSYSTEMD_LIBS = @LIBSYSTEMD_LIBS@ LIBTOOL = @LIBTOOL@ LIBTOOL_DEPS = @LIBTOOL_DEPS@ LIBUSB_CFLAGS = @LIBUSB_CFLAGS@ LIBUSB_CONFIG = @LIBUSB_CONFIG@ LIBUSB_LIBS = @LIBUSB_LIBS@ LIBWRAP_CFLAGS = @LIBWRAP_CFLAGS@ LIBWRAP_LIBS = @LIBWRAP_LIBS@ LIPO = @LIPO@ LN_S = @LN_S@ LN_S_R = @LN_S_R@ LTLIBOBJS = @LTLIBOBJS@ LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@ MAINT = @MAINT@ MAKEINFO = @MAKEINFO@ MANIFEST_TOOL = @MANIFEST_TOOL@ MKDIR_P = @MKDIR_P@ MSGFMT = @MSGFMT@ NETLIBS = @NETLIBS@ NET_SNMP_CONFIG = @NET_SNMP_CONFIG@ NM = @NM@ NMEDIT = @NMEDIT@ NUT_DATADIR = @NUT_DATADIR@ NUT_LIBEXECDIR = @NUT_LIBEXECDIR@ NUT_NETVERSION = @NUT_NETVERSION@ NUT_SOURCE_GITREV = @NUT_SOURCE_GITREV@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ OS_NAME = @OS_NAME@ OTOOL = @OTOOL@ OTOOL64 = @OTOOL64@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_SEPARATOR = @PATH_SEPARATOR@ PIDPATH = @PIDPATH@ PKGCONFIGDIR = @PKGCONFIGDIR@ PKG_CONFIG = @PKG_CONFIG@ PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@ PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ PORT = @PORT@ POWERDOWNFLAG = @POWERDOWNFLAG@ PREFIX = @PREFIX@ PYTHON = @PYTHON@ PYTHON2 = @PYTHON2@ PYTHON2_SITE_PACKAGES = @PYTHON2_SITE_PACKAGES@ PYTHON3 = @PYTHON3@ PYTHON3_SITE_PACKAGES = @PYTHON3_SITE_PACKAGES@ PYTHON_SITE_PACKAGES = @PYTHON_SITE_PACKAGES@ RANLIB = @RANLIB@ REALPATH = @REALPATH@ RUN_AS_GROUP = @RUN_AS_GROUP@ RUN_AS_USER = @RUN_AS_USER@ SBINDIR = @SBINDIR@ SED = @SED@ SEMLIBS = @SEMLIBS@ SERLIBS = @SERLIBS@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ SOURCE_HIGHLIGHT = @SOURCE_HIGHLIGHT@ STATEPATH = @STATEPATH@ STRIP = @STRIP@ SUN_LIBUSB = @SUN_LIBUSB@ SYSTEMD_ANALYZE_PROGRAM = @SYSTEMD_ANALYZE_PROGRAM@ SYSTEMD_DAEMON_ARGS_DRIVER = @SYSTEMD_DAEMON_ARGS_DRIVER@ SYSTEMD_DAEMON_ARGS_UPSD = @SYSTEMD_DAEMON_ARGS_UPSD@ SYSTEMD_DAEMON_ARGS_UPSMON = @SYSTEMD_DAEMON_ARGS_UPSMON@ SYSTEMD_DAEMON_NOTIFYACCESS_DRIVER = @SYSTEMD_DAEMON_NOTIFYACCESS_DRIVER@ SYSTEMD_DAEMON_NOTIFYACCESS_UPSD = @SYSTEMD_DAEMON_NOTIFYACCESS_UPSD@ SYSTEMD_DAEMON_NOTIFYACCESS_UPSMON = @SYSTEMD_DAEMON_NOTIFYACCESS_UPSMON@ SYSTEMD_DAEMON_TYPE_DRIVER = @SYSTEMD_DAEMON_TYPE_DRIVER@ SYSTEMD_DAEMON_TYPE_UPSD = @SYSTEMD_DAEMON_TYPE_UPSD@ SYSTEMD_DAEMON_TYPE_UPSMON = @SYSTEMD_DAEMON_TYPE_UPSMON@ SYSTEMD_DAEMON_WATCHDOG_DRIVER = @SYSTEMD_DAEMON_WATCHDOG_DRIVER@ SYSTEMD_DAEMON_WATCHDOG_UPSD = @SYSTEMD_DAEMON_WATCHDOG_UPSD@ SYSTEMD_DAEMON_WATCHDOG_UPSMON = @SYSTEMD_DAEMON_WATCHDOG_UPSMON@ SYSTEMD_TMPFILES_PROGRAM = @SYSTEMD_TMPFILES_PROGRAM@ TREE_VERSION = @TREE_VERSION@ VALGRIND = @VALGRIND@ VERSION = @VERSION@ WINDMC = @WINDMC@ WINDRES = @WINDRES@ WORDS_BIGENDIAN = @WORDS_BIGENDIAN@ XMLLINT = @XMLLINT@ XSLTPROC = @XSLTPROC@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_AR = @ac_ct_AR@ ac_ct_CC = @ac_ct_CC@ ac_ct_CXX = @ac_ct_CXX@ ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__tar = @am__tar@ am__untar = @am__untar@ auglensdir = @auglensdir@ bindir = @bindir@ build = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ cgiexecdir = @cgiexecdir@ datadir = @datadir@ datarootdir = @datarootdir@ devddir = @devddir@ docdir = @docdir@ driverexecdir = @driverexecdir@ dummy_PKG_CONFIG = @dummy_PKG_CONFIG@ dummy_PKG_CONFIG_CFLAGS = @dummy_PKG_CONFIG_CFLAGS@ dummy_PKG_CONFIG_LIBS = @dummy_PKG_CONFIG_LIBS@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ hotplugdir = @hotplugdir@ htmldir = @htmldir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libdir = @libdir@ libexecdir = @libexecdir@ localedir = @localedir@ localstatedir = @localstatedir@ mandir = @mandir@ mkdir_p = @mkdir_p@ now = @now@ nut_with_nut_monitor = @nut_with_nut_monitor@ nut_with_nut_monitor_desktop = @nut_with_nut_monitor_desktop@ nut_with_nut_monitor_dir = @nut_with_nut_monitor_dir@ nut_with_nut_monitor_py2gtk2 = @nut_with_nut_monitor_py2gtk2@ nut_with_nut_monitor_py3qt5 = @nut_with_nut_monitor_py3qt5@ nut_with_pynut = @nut_with_pynut@ nut_with_pynut_py = @nut_with_pynut_py@ nut_with_pynut_py2 = @nut_with_pynut_py2@ nut_with_pynut_py3 = @nut_with_pynut_py3@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ pkgconfigdir = @pkgconfigdir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ runstatedir = @runstatedir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ sysconfdir = @sysconfdir@ systemdshutdowndir = @systemdshutdowndir@ systemdsystemunitdir = @systemdsystemunitdir@ systemdtmpfilesdir = @systemdtmpfilesdir@ target = @target@ target_alias = @target_alias@ target_cpu = @target_cpu@ target_os = @target_os@ target_vendor = @target_vendor@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ udevdir = @udevdir@ AM_CFLAGS = -I$(top_srcdir)/include EXTRA_DIST = winevent.mc build-mingw-nut.sh README.adoc @HAVE_MINGW_RESGEN_TRUE@nut_SOURCES = wininit.c @HAVE_MINGW_RESGEN_TRUE@nut_LDADD = ../../common/libcommon.la winevent.o @HAVE_MINGW_RESGEN_TRUE@halt_SOURCES = halt.c @HAVE_MINGW_RESGEN_TRUE@CLEANFILES = winevent.rc winevent.o winevent.h MAINTAINERCLEANFILES = Makefile.in .dirstamp all: all-am .SUFFIXES: .SUFFIXES: .c .lo .o .obj $(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu scripts/Windows/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --gnu scripts/Windows/Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): install-binPROGRAMS: $(bin_PROGRAMS) @$(NORMAL_INSTALL) @list='$(bin_PROGRAMS)'; test -n "$(bindir)" || list=; \ if test -n "$$list"; then \ echo " $(MKDIR_P) '$(DESTDIR)$(bindir)'"; \ $(MKDIR_P) "$(DESTDIR)$(bindir)" || exit 1; \ fi; \ for p in $$list; do echo "$$p $$p"; done | \ sed 's/$(EXEEXT)$$//' | \ while read p p1; do if test -f $$p \ || test -f $$p1 \ ; then echo "$$p"; echo "$$p"; else :; fi; \ done | \ sed -e 'p;s,.*/,,;n;h' \ -e 's|.*|.|' \ -e 'p;x;s,.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/' | \ sed 'N;N;N;s,\n, ,g' | \ $(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1 } \ { d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \ if ($$2 == $$4) files[d] = files[d] " " $$1; \ else { print "f", $$3 "/" $$4, $$1; } } \ END { for (d in files) print "f", d, files[d] }' | \ while read type dir files; do \ if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \ test -z "$$files" || { \ echo " $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files '$(DESTDIR)$(bindir)$$dir'"; \ $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files "$(DESTDIR)$(bindir)$$dir" || exit $$?; \ } \ ; done uninstall-binPROGRAMS: @$(NORMAL_UNINSTALL) @list='$(bin_PROGRAMS)'; test -n "$(bindir)" || list=; \ files=`for p in $$list; do echo "$$p"; done | \ sed -e 'h;s,^.*/,,;s/$(EXEEXT)$$//;$(transform)' \ -e 's/$$/$(EXEEXT)/' \ `; \ test -n "$$list" || exit 0; \ echo " ( cd '$(DESTDIR)$(bindir)' && rm -f" $$files ")"; \ cd "$(DESTDIR)$(bindir)" && rm -f $$files clean-binPROGRAMS: @list='$(bin_PROGRAMS)'; test -n "$$list" || exit 0; \ echo " rm -f" $$list; \ rm -f $$list || exit $$?; \ test -n "$(EXEEXT)" || exit 0; \ list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \ echo " rm -f" $$list; \ rm -f $$list halt$(EXEEXT): $(halt_OBJECTS) $(halt_DEPENDENCIES) $(EXTRA_halt_DEPENDENCIES) @rm -f halt$(EXEEXT) $(AM_V_CCLD)$(LINK) $(halt_OBJECTS) $(halt_LDADD) $(LIBS) nut$(EXEEXT): $(nut_OBJECTS) $(nut_DEPENDENCIES) $(EXTRA_nut_DEPENDENCIES) @rm -f nut$(EXEEXT) $(AM_V_CCLD)$(LINK) $(nut_OBJECTS) $(nut_LDADD) $(LIBS) mostlyclean-compile: -rm -f *.$(OBJEXT) distclean-compile: -rm -f *.tab.c @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/halt.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/wininit.Po@am__quote@ # am--include-marker $(am__depfiles_remade): @$(MKDIR_P) $(@D) @echo '# dummy' >$@-t && $(am__mv) $@-t $@ am--depfiles: $(am__depfiles_remade) .c.o: @am__fastdepCC_TRUE@ $(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.o$$||'`;\ @am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\ @am__fastdepCC_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ $< .c.obj: @am__fastdepCC_TRUE@ $(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.obj$$||'`;\ @am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ `$(CYGPATH_W) '$<'` &&\ @am__fastdepCC_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'` .c.lo: @am__fastdepCC_TRUE@ $(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.lo$$||'`;\ @am__fastdepCC_TRUE@ $(LTCOMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\ @am__fastdepCC_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LTCOMPILE) -c -o $@ $< mostlyclean-libtool: -rm -f *.lo clean-libtool: -rm -rf .libs _libs ID: $(am__tagged_files) $(am__define_uniq_tagged_files); mkid -fID $$unique tags: tags-am TAGS: tags tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) set x; \ here=`pwd`; \ $(am__define_uniq_tagged_files); \ shift; \ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ test -n "$$unique" || unique=$$empty_fix; \ if test $$# -gt 0; then \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ "$$@" $$unique; \ else \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ $$unique; \ fi; \ fi ctags: ctags-am CTAGS: ctags ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) $(am__define_uniq_tagged_files); \ test -z "$(CTAGS_ARGS)$$unique" \ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ $$unique GTAGS: here=`$(am__cd) $(top_builddir) && pwd` \ && $(am__cd) $(top_srcdir) \ && gtags -i $(GTAGS_ARGS) "$$here" cscopelist: cscopelist-am cscopelist-am: $(am__tagged_files) list='$(am__tagged_files)'; \ case "$(srcdir)" in \ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \ *) sdir=$(subdir)/$(srcdir) ;; \ esac; \ for i in $$list; do \ if test -f "$$i"; then \ echo "$(subdir)/$$i"; \ else \ echo "$$sdir/$$i"; \ fi; \ done >> $(top_builddir)/cscope.files distclean-tags: -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags distdir: $(BUILT_SOURCES) $(MAKE) $(AM_MAKEFLAGS) distdir-am distdir-am: $(DISTFILES) @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ dist_files=`for file in $$list; do echo $$file; done | \ sed -e "s|^$$srcdirstrip/||;t" \ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ case $$dist_files in \ */*) $(MKDIR_P) `echo "$$dist_files" | \ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ sort -u` ;; \ esac; \ for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d "$(distdir)/$$file"; then \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ else \ test -f "$(distdir)/$$file" \ || cp -p $$d/$$file "$(distdir)/$$file" \ || exit 1; \ fi; \ done check-am: all-am check: check-am all-am: Makefile $(PROGRAMS) installdirs: for dir in "$(DESTDIR)$(bindir)"; do \ test -z "$$dir" || $(MKDIR_P) "$$dir"; \ done install: install-am install-exec: install-exec-am install-data: install-data-am uninstall: uninstall-am install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-am install-strip: if test -z '$(STRIP)'; then \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ install; \ else \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ fi mostlyclean-generic: clean-generic: -test -z "$(CLEANFILES)" || rm -f $(CLEANFILES) distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." -test -z "$(MAINTAINERCLEANFILES)" || rm -f $(MAINTAINERCLEANFILES) clean: clean-am clean-am: clean-binPROGRAMS clean-generic clean-libtool mostlyclean-am distclean: distclean-am -rm -f ./$(DEPDIR)/halt.Po -rm -f ./$(DEPDIR)/wininit.Po -rm -f Makefile distclean-am: clean-am distclean-compile distclean-generic \ distclean-tags dvi: dvi-am dvi-am: html: html-am html-am: info: info-am info-am: install-data-am: install-dvi: install-dvi-am install-dvi-am: install-exec-am: install-binPROGRAMS install-html: install-html-am install-html-am: install-info: install-info-am install-info-am: install-man: install-pdf: install-pdf-am install-pdf-am: install-ps: install-ps-am install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-am -rm -f ./$(DEPDIR)/halt.Po -rm -f ./$(DEPDIR)/wininit.Po -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-am mostlyclean-am: mostlyclean-compile mostlyclean-generic \ mostlyclean-libtool pdf: pdf-am pdf-am: ps: ps-am ps-am: uninstall-am: uninstall-binPROGRAMS .MAKE: install-am install-strip .PHONY: CTAGS GTAGS TAGS all all-am am--depfiles check check-am clean \ clean-binPROGRAMS clean-generic clean-libtool cscopelist-am \ ctags ctags-am distclean distclean-compile distclean-generic \ distclean-libtool distclean-tags distdir dvi dvi-am html \ html-am info info-am install install-am install-binPROGRAMS \ install-data install-data-am install-dvi install-dvi-am \ install-exec install-exec-am install-html install-html-am \ install-info install-info-am install-man install-pdf \ install-pdf-am install-ps install-ps-am install-strip \ installcheck installcheck-am installdirs maintainer-clean \ maintainer-clean-generic mostlyclean mostlyclean-compile \ mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \ tags tags-am uninstall uninstall-am uninstall-binPROGRAMS .PRECIOUS: Makefile ../include/nut_version.h: FORCE (cd ../include/ && $(MAKE) $(AM_MAKEFLAGS) nut_version.h) FORCE: @HAVE_MINGW_RESGEN_TRUE@winevent.rc winevent.h: winevent.mc @HAVE_MINGW_RESGEN_TRUE@ $(WINDMC) $< @HAVE_MINGW_RESGEN_TRUE@winevent.o: winevent.rc winevent.h @HAVE_MINGW_RESGEN_TRUE@ $(WINDRES) winevent.rc winevent.o @HAVE_MINGW_RESGEN_TRUE@wininit.$(OBJEXT): winevent.h # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: nut-2.8.1/scripts/Windows/winevent.mc0000644000175000017500000000102114501607135014546 00000000000000MessageIdTypedef=DWORD SeverityNames=(Success=0x0:STATUS_SEVERITY_SUCCESS Informational=0x1:STATUS_SEVERITY_INFORMATIONAL Warning=0x2:STATUS_SEVERITY_WARNING Error=0x3:STATUS_SEVERITY_ERROR ) FacilityNames=(System=0x0:FACILITY_SYSTEM Runtime=0x2:FACILITY_RUNTIME Stubs=0x3:FACILITY_STUBS Io=0x4:FACILITY_IO_ERROR_CODE ) LanguageNames=(English=0x409:MSG00409) ; // The following are message definitions. MessageId=0x1 Severity=Error Facility=Runtime SymbolicName=SVC_EVENT Language=English %1. . nut-2.8.1/scripts/Windows/Makefile0000644000175000017500000006402314520275020014034 00000000000000# Makefile.in generated by automake 1.16.5 from Makefile.am. # scripts/Windows/Makefile. Generated from Makefile.in by configure. # Copyright (C) 1994-2021 Free Software Foundation, Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. # Network UPS Tools: script/Windows am__is_gnu_make = { \ if test -z '$(MAKELEVEL)'; then \ false; \ elif test -n '$(MAKE_HOST)'; then \ true; \ elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \ true; \ else \ false; \ fi; \ } am__make_running_with_option = \ case $${target_option-} in \ ?) ;; \ *) echo "am__make_running_with_option: internal error: invalid" \ "target option '$${target_option-}' specified" >&2; \ exit 1;; \ esac; \ has_opt=no; \ sane_makeflags=$$MAKEFLAGS; \ if $(am__is_gnu_make); then \ sane_makeflags=$$MFLAGS; \ else \ case $$MAKEFLAGS in \ *\\[\ \ ]*) \ bs=\\; \ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ esac; \ fi; \ skip_next=no; \ strip_trailopt () \ { \ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ }; \ for flg in $$sane_makeflags; do \ test $$skip_next = yes && { skip_next=no; continue; }; \ case $$flg in \ *=*|--*) continue;; \ -*I) strip_trailopt 'I'; skip_next=yes;; \ -*I?*) strip_trailopt 'I';; \ -*O) strip_trailopt 'O'; skip_next=yes;; \ -*O?*) strip_trailopt 'O';; \ -*l) strip_trailopt 'l'; skip_next=yes;; \ -*l?*) strip_trailopt 'l';; \ -[dEDm]) skip_next=yes;; \ -[JT]) skip_next=yes;; \ esac; \ case $$flg in \ *$$target_option*) has_opt=yes; break;; \ esac; \ done; \ test $$has_opt = yes am__make_dryrun = (target_option=n; $(am__make_running_with_option)) am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) pkgdatadir = $(datadir)/nut pkgincludedir = $(includedir)/nut pkglibdir = $(libdir)/nut pkglibexecdir = $(libexecdir)/nut am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = x86_64-pc-linux-gnu host_triplet = x86_64-pc-linux-gnu target_triplet = x86_64-pc-linux-gnu #bin_PROGRAMS = nut$(EXEEXT) halt$(EXEEXT) subdir = scripts/Windows ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/m4/ax_c___attribute__.m4 \ $(top_srcdir)/m4/ax_c_pragmas.m4 \ $(top_srcdir)/m4/ax_check_compile_flag.m4 \ $(top_srcdir)/m4/ax_compare_version.m4 \ $(top_srcdir)/m4/ax_realpath.m4 \ $(top_srcdir)/m4/ax_run_or_link_ifelse.m4 \ $(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \ $(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \ $(top_srcdir)/m4/lt~obsolete.m4 \ $(top_srcdir)/m4/nut_arg_with.m4 \ $(top_srcdir)/m4/nut_check_asciidoc.m4 \ $(top_srcdir)/m4/nut_check_aspell.m4 \ $(top_srcdir)/m4/nut_check_cppcheck.m4 \ $(top_srcdir)/m4/nut_check_headers_windows.m4 \ $(top_srcdir)/m4/nut_check_libavahi.m4 \ $(top_srcdir)/m4/nut_check_libfreeipmi.m4 \ $(top_srcdir)/m4/nut_check_libgd.m4 \ $(top_srcdir)/m4/nut_check_libgpiod.m4 \ $(top_srcdir)/m4/nut_check_libltdl.m4 \ $(top_srcdir)/m4/nut_check_libmodbus.m4 \ $(top_srcdir)/m4/nut_check_libneon.m4 \ $(top_srcdir)/m4/nut_check_libnetsnmp.m4 \ $(top_srcdir)/m4/nut_check_libnss.m4 \ $(top_srcdir)/m4/nut_check_libopenssl.m4 \ $(top_srcdir)/m4/nut_check_libpowerman.m4 \ $(top_srcdir)/m4/nut_check_libregex.m4 \ $(top_srcdir)/m4/nut_check_libsystemd.m4 \ $(top_srcdir)/m4/nut_check_libusb.m4 \ $(top_srcdir)/m4/nut_check_libwrap.m4 \ $(top_srcdir)/m4/nut_check_os.m4 \ $(top_srcdir)/m4/nut_check_pkgconfig.m4 \ $(top_srcdir)/m4/nut_check_python.m4 \ $(top_srcdir)/m4/nut_check_socketlib.m4 \ $(top_srcdir)/m4/nut_compiler_family.m4 \ $(top_srcdir)/m4/nut_func_getnameinfo_argtypes.m4 \ $(top_srcdir)/m4/nut_report_feature.m4 \ $(top_srcdir)/m4/nut_stash_warnings.m4 \ $(top_srcdir)/m4/nut_type_socklen_t.m4 \ $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/include/config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = am__installdirs = "$(DESTDIR)$(bindir)" PROGRAMS = $(bin_PROGRAMS) am__halt_SOURCES_DIST = halt.c #am_halt_OBJECTS = halt.$(OBJEXT) halt_OBJECTS = $(am_halt_OBJECTS) halt_LDADD = $(LDADD) AM_V_lt = $(am__v_lt_$(V)) am__v_lt_ = $(am__v_lt_$(AM_DEFAULT_VERBOSITY)) am__v_lt_0 = --silent am__v_lt_1 = am__nut_SOURCES_DIST = wininit.c #am_nut_OBJECTS = wininit.$(OBJEXT) nut_OBJECTS = $(am_nut_OBJECTS) #nut_DEPENDENCIES = ../../common/libcommon.la \ # winevent.o AM_V_P = $(am__v_P_$(V)) am__v_P_ = $(am__v_P_$(AM_DEFAULT_VERBOSITY)) am__v_P_0 = false am__v_P_1 = : AM_V_GEN = $(am__v_GEN_$(V)) am__v_GEN_ = $(am__v_GEN_$(AM_DEFAULT_VERBOSITY)) am__v_GEN_0 = @echo " GEN " $@; am__v_GEN_1 = AM_V_at = $(am__v_at_$(V)) am__v_at_ = $(am__v_at_$(AM_DEFAULT_VERBOSITY)) am__v_at_0 = @ am__v_at_1 = DEFAULT_INCLUDES = -I. -I$(top_builddir)/include depcomp = $(SHELL) $(top_srcdir)/depcomp am__maybe_remake_depfiles = depfiles am__depfiles_remade = ./$(DEPDIR)/halt.Po ./$(DEPDIR)/wininit.Po am__mv = mv -f COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ $(AM_CFLAGS) $(CFLAGS) AM_V_CC = $(am__v_CC_$(V)) am__v_CC_ = $(am__v_CC_$(AM_DEFAULT_VERBOSITY)) am__v_CC_0 = @echo " CC " $@; am__v_CC_1 = CCLD = $(CC) LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ $(AM_LDFLAGS) $(LDFLAGS) -o $@ AM_V_CCLD = $(am__v_CCLD_$(V)) am__v_CCLD_ = $(am__v_CCLD_$(AM_DEFAULT_VERBOSITY)) am__v_CCLD_0 = @echo " CCLD " $@; am__v_CCLD_1 = SOURCES = $(halt_SOURCES) $(nut_SOURCES) DIST_SOURCES = $(am__halt_SOURCES_DIST) $(am__nut_SOURCES_DIST) am__can_run_installinfo = \ case $$AM_UPDATE_INFO_DIR in \ n|no|NO) false;; \ *) (install-info --version) >/dev/null 2>&1;; \ esac am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) # Read a list of newline-separated strings from the standard input, # and print each of them once, without duplicates. Input order is # *not* preserved. am__uniquify_input = $(AWK) '\ BEGIN { nonempty = 0; } \ { items[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in items) print i; }; } \ ' # Make sure the list of sources is unique. This is necessary because, # e.g., the same source file might be shared among _SOURCES variables # for different programs/libraries. am__define_uniq_tagged_files = \ list='$(am__tagged_files)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | $(am__uniquify_input)` am__DIST_COMMON = $(srcdir)/Makefile.in $(top_srcdir)/depcomp DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) A2X = /usr/bin/a2x ACLOCAL = ${SHELL} '/home/jim/nut/missing' aclocal-1.16 ALTPIDPATH = /var/state/ups AMTAR = $${TAR-tar} AM_DEFAULT_VERBOSITY = 0 AR = /usr/bin/ar ASCIIDOC = /usr/bin/asciidoc ASPELL = /usr/bin/aspell ASPELL_FILTER_LIB_PATH = /usr/lib/aspell ASPELL_FILTER_SHARE_PATH = /usr/share/aspell ASPELL_FILTER_TEX_PATH = /usr/lib/aspell/x86_64-linux-gnu AUGPARSE = /usr/bin/augparse AUTOCONF = ${SHELL} '/home/jim/nut/missing' autoconf AUTOHEADER = ${SHELL} '/home/jim/nut/missing' autoheader AUTOMAKE = ${SHELL} '/home/jim/nut/missing' automake-1.16 AWK = gawk BINDIR = /usr/local/ups/bin CC = gcc CCDEPMODE = depmode=gcc3 CFLAGS = -isystem /usr/local/include -g -O2 -Wno-reserved-identifier -Wno-unknown-warning-option -std=gnu99 -Wno-system-headers -Wall -Wextra -Wsign-compare -pedantic -Werror CONFIG_FLAGS = --with-all --with-dev --with-doc --enable-spellcheck --enable-warnings --enable-Werror --enable-maintainer-mode CONFPATH = /usr/local/ups/etc CPP = gcc -E CPPCHECK = /usr/bin/cppcheck CPPFLAGS = CPPUNIT_CFLAGS = CPPUNIT_LIBS = -lcppunit CSCOPE = cscope CTAGS = ctags CXX = g++ CXXCPP = g++ -E CXXDEPMODE = depmode=gcc3 CXXFLAGS = -isystem /usr/local/include -g -O2 -Wno-reserved-identifier -Wno-unknown-warning-option -std=gnu++11 -Wno-system-headers -Wall -Wextra -Werror CYGPATH_W = echo DBLATEX = /usr/bin/dblatex DEFS = -DHAVE_CONFIG_H DEPDIR = .deps DEPLOYED_UPSC = DEPLOYED_UPSD = DLLTOOL = false DOC_BUILD_LIST = man html-single html-chunked pdf DOC_CHECK_LIST = check-man check-html-single check-html-chunked check-pdf DRIVER_BUILD_LIST = all DRIVER_INSTALL_TARGET = DRIVER_MAN_LIST = all DRIVER_MAN_LIST_PAGES = DRVPATH = /usr/local/ups/bin DSYMUTIL = DUMPBIN = ECHO_C = ECHO_N = -n ECHO_T = EGREP = /usr/bin/grep -E ETAGS = etags EXEEXT = FGREP = /usr/bin/grep -F FORCE_NUT_VERSION = FORCE GDLIB_CONFIG = GREP = /usr/bin/grep HAVE_SYS_SOCKET_H = 1 HAVE_WINSOCK2_H = 0 HAVE_WS2TCPIP_H = 0 INSTALL = /usr/bin/install -c INSTALL_DATA = ${INSTALL} -m 644 INSTALL_PROGRAM = ${INSTALL} INSTALL_SCRIPT = ${INSTALL} INSTALL_STRIP_PROGRAM = $(install_sh) -c -s LD = /usr/bin/ld -m elf_x86_64 LDFLAGS = LIBAVAHI_CFLAGS = -D_REENTRANT LIBAVAHI_LIBS = -lavahi-common -lavahi-core -lavahi-common -lavahi-client LIBDIR = /usr/local/ups/lib LIBGD_CFLAGS = LIBGD_LDFLAGS = -lgd LIBGPIO_CFLAGS = LIBGPIO_LIBS = -lgpiod LIBI2C_LIBS = -li2c LIBIPMI_CFLAGS = LIBIPMI_LIBS = -lfreeipmi -lipmimonitoring LIBLTDL_CFLAGS = LIBLTDL_LIBS = -lltdl LIBMODBUS_CFLAGS = -I/usr/include/modbus LIBMODBUS_LIBS = -lmodbus LIBNEON_CFLAGS = -I/usr/include/neon LIBNEON_LIBS = -lneon-gnutls LIBNETSNMP_CFLAGS = LIBNETSNMP_LIBS = -lnetsnmp LIBOBJS = LIBPOWERMAN_CFLAGS = LIBPOWERMAN_LIBS = -lpowerman LIBREGEX_LIBS = LIBS = LIBSSL_CFLAGS = LIBSSL_LIBS = -lssl -lcrypto LIBSSL_REQUIRES = openssl LIBSYSTEMD_CFLAGS = LIBSYSTEMD_LIBS = -lsystemd LIBTOOL = $(SHELL) $(top_builddir)/libtool LIBTOOL_DEPS = ././/ltmain.sh LIBUSB_CFLAGS = -I/usr/include/libusb-1.0 LIBUSB_CONFIG = /usr/bin/libusb-config LIBUSB_LIBS = -lusb-1.0 LIBWRAP_CFLAGS = LIBWRAP_LIBS = -lnsl -lwrap LIPO = LN_S = ln -s LN_S_R = ln -s -r LTLIBOBJS = LT_SYS_LIBRARY_PATH = MAINT = MAKEINFO = ${SHELL} '/home/jim/nut/missing' makeinfo MANIFEST_TOOL = : MKDIR_P = /usr/bin/mkdir -p MSGFMT = /usr/bin/msgfmt NETLIBS = NET_SNMP_CONFIG = /usr/bin/net-snmp-config NM = /usr/bin/nm -B NMEDIT = NUT_DATADIR = /usr/local/ups/share NUT_LIBEXECDIR = /usr/local/ups/libexec NUT_NETVERSION = 1.3 NUT_SOURCE_GITREV = v2.8.0-signed-2787-g4ba352d8f OBJDUMP = objdump OBJEXT = o OS_NAME = ubuntu OTOOL = OTOOL64 = PACKAGE = nut PACKAGE_BUGREPORT = https://github.com/networkupstools/nut/issues PACKAGE_NAME = nut PACKAGE_STRING = nut 2.8.1 PACKAGE_TARNAME = nut PACKAGE_URL = PACKAGE_VERSION = 2.8.1 PATH_SEPARATOR = : PIDPATH = /run PKGCONFIGDIR = /usr/local/ups/lib/pkgconfig PKG_CONFIG = /usr/bin/pkg-config PKG_CONFIG_LIBDIR = PKG_CONFIG_PATH = PORT = 3493 POWERDOWNFLAG = /etc/killpower PREFIX = /usr/local/ups PYTHON = /usr/bin/python PYTHON2 = /usr/bin/python2 PYTHON2_SITE_PACKAGES = /usr/local/lib/python2.7/dist-packages PYTHON3 = /usr/bin/python3.10 PYTHON3_SITE_PACKAGES = /usr/local/lib/python3.10/dist-packages PYTHON_SITE_PACKAGES = /usr/local/lib/python3.10/dist-packages RANLIB = ranlib REALPATH = realpath RUN_AS_GROUP = nogroup RUN_AS_USER = nobody SBINDIR = /usr/local/ups/sbin SED = /usr/bin/sed SEMLIBS = -lrt SERLIBS = SET_MAKE = SHELL = /bin/bash SOURCE_HIGHLIGHT = /usr/bin/source-highlight STATEPATH = /var/state/ups STRIP = strip SUN_LIBUSB = SYSTEMD_ANALYZE_PROGRAM = /usr/bin/systemd-analyze SYSTEMD_DAEMON_ARGS_DRIVER = -FF SYSTEMD_DAEMON_ARGS_UPSD = -FF SYSTEMD_DAEMON_ARGS_UPSMON = -F SYSTEMD_DAEMON_NOTIFYACCESS_DRIVER = NotifyAccess=all SYSTEMD_DAEMON_NOTIFYACCESS_UPSD = NotifyAccess=main SYSTEMD_DAEMON_NOTIFYACCESS_UPSMON = NotifyAccess=all SYSTEMD_DAEMON_TYPE_DRIVER = notify SYSTEMD_DAEMON_TYPE_UPSD = notify SYSTEMD_DAEMON_TYPE_UPSMON = notify SYSTEMD_DAEMON_WATCHDOG_DRIVER = #WatchdogSec=240s SYSTEMD_DAEMON_WATCHDOG_UPSD = #WatchdogSec=240s SYSTEMD_DAEMON_WATCHDOG_UPSMON = #WatchdogSec=240s SYSTEMD_TMPFILES_PROGRAM = /usr/bin/systemd-tmpfiles TREE_VERSION = 2.8 VALGRIND = /usr/bin/valgrind VERSION = 2.8.1 WINDMC = none WINDRES = none WORDS_BIGENDIAN = XMLLINT = /usr/bin/xmllint XSLTPROC = /usr/bin/xsltproc abs_builddir = /home/jim/nut/scripts/Windows abs_srcdir = /home/jim/nut/scripts/Windows abs_top_builddir = /home/jim/nut abs_top_srcdir = /home/jim/nut ac_ct_AR = ac_ct_CC = gcc ac_ct_CXX = g++ ac_ct_DUMPBIN = am__include = include am__leading_dot = . am__quote = am__tar = $${TAR-tar} chof - "$$tardir" am__untar = $${TAR-tar} xf - auglensdir = /usr/share/augeas/lenses/dist bindir = ${exec_prefix}/bin build = x86_64-pc-linux-gnu build_alias = build_cpu = x86_64 build_os = linux-gnu build_vendor = pc builddir = . cgiexecdir = ${exec_prefix}/cgi-bin datadir = ${datarootdir} datarootdir = ${prefix}/share devddir = docdir = ${datarootdir}/doc/${PACKAGE_TARNAME} driverexecdir = ${exec_prefix}/bin dummy_PKG_CONFIG = dummy_PKG_CONFIG_CFLAGS = dummy_PKG_CONFIG_LIBS = dvidir = ${docdir} exec_prefix = ${prefix} host = x86_64-pc-linux-gnu host_alias = host_cpu = x86_64 host_os = linux-gnu host_vendor = pc hotplugdir = htmldir = ${prefix}/html includedir = ${prefix}/include infodir = ${datarootdir}/info install_sh = ${SHELL} /home/jim/nut/install-sh libdir = ${exec_prefix}/lib libexecdir = ${exec_prefix}/libexec localedir = ${datarootdir}/locale localstatedir = ${prefix}/var mandir = ${datarootdir}/man mkdir_p = $(MKDIR_P) now = 2023-10-31 nut_with_nut_monitor = no nut_with_nut_monitor_desktop = nut_with_nut_monitor_dir = ${prefix}/share/nut-monitor nut_with_nut_monitor_py2gtk2 = nut_with_nut_monitor_py3qt5 = nut_with_pynut = yes nut_with_pynut_py = yes nut_with_pynut_py2 = yes nut_with_pynut_py3 = yes oldincludedir = /usr/include pdfdir = ${docdir} pkgconfigdir = ${libdir}/pkgconfig prefix = /usr/local/ups program_transform_name = s,x,x, psdir = ${docdir} runstatedir = ${localstatedir}/run sbindir = ${exec_prefix}/sbin sharedstatedir = ${prefix}/com srcdir = . sysconfdir = ${prefix}/etc systemdshutdowndir = /lib/systemd/system-shutdown systemdsystemunitdir = /lib/systemd/system systemdtmpfilesdir = /usr/lib/tmpfiles.d target = x86_64-pc-linux-gnu target_alias = target_cpu = x86_64 target_os = linux-gnu target_vendor = pc top_build_prefix = ../../ top_builddir = ../.. top_srcdir = ../.. udevdir = /lib/udev AM_CFLAGS = -I$(top_srcdir)/include EXTRA_DIST = winevent.mc build-mingw-nut.sh README.adoc #nut_SOURCES = wininit.c #nut_LDADD = ../../common/libcommon.la winevent.o #halt_SOURCES = halt.c #CLEANFILES = winevent.rc winevent.o winevent.h MAINTAINERCLEANFILES = Makefile.in .dirstamp all: all-am .SUFFIXES: .SUFFIXES: .c .lo .o .obj $(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu scripts/Windows/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --gnu scripts/Windows/Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): install-binPROGRAMS: $(bin_PROGRAMS) @$(NORMAL_INSTALL) @list='$(bin_PROGRAMS)'; test -n "$(bindir)" || list=; \ if test -n "$$list"; then \ echo " $(MKDIR_P) '$(DESTDIR)$(bindir)'"; \ $(MKDIR_P) "$(DESTDIR)$(bindir)" || exit 1; \ fi; \ for p in $$list; do echo "$$p $$p"; done | \ sed 's/$(EXEEXT)$$//' | \ while read p p1; do if test -f $$p \ || test -f $$p1 \ ; then echo "$$p"; echo "$$p"; else :; fi; \ done | \ sed -e 'p;s,.*/,,;n;h' \ -e 's|.*|.|' \ -e 'p;x;s,.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/' | \ sed 'N;N;N;s,\n, ,g' | \ $(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1 } \ { d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \ if ($$2 == $$4) files[d] = files[d] " " $$1; \ else { print "f", $$3 "/" $$4, $$1; } } \ END { for (d in files) print "f", d, files[d] }' | \ while read type dir files; do \ if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \ test -z "$$files" || { \ echo " $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files '$(DESTDIR)$(bindir)$$dir'"; \ $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files "$(DESTDIR)$(bindir)$$dir" || exit $$?; \ } \ ; done uninstall-binPROGRAMS: @$(NORMAL_UNINSTALL) @list='$(bin_PROGRAMS)'; test -n "$(bindir)" || list=; \ files=`for p in $$list; do echo "$$p"; done | \ sed -e 'h;s,^.*/,,;s/$(EXEEXT)$$//;$(transform)' \ -e 's/$$/$(EXEEXT)/' \ `; \ test -n "$$list" || exit 0; \ echo " ( cd '$(DESTDIR)$(bindir)' && rm -f" $$files ")"; \ cd "$(DESTDIR)$(bindir)" && rm -f $$files clean-binPROGRAMS: @list='$(bin_PROGRAMS)'; test -n "$$list" || exit 0; \ echo " rm -f" $$list; \ rm -f $$list || exit $$?; \ test -n "$(EXEEXT)" || exit 0; \ list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \ echo " rm -f" $$list; \ rm -f $$list halt$(EXEEXT): $(halt_OBJECTS) $(halt_DEPENDENCIES) $(EXTRA_halt_DEPENDENCIES) @rm -f halt$(EXEEXT) $(AM_V_CCLD)$(LINK) $(halt_OBJECTS) $(halt_LDADD) $(LIBS) nut$(EXEEXT): $(nut_OBJECTS) $(nut_DEPENDENCIES) $(EXTRA_nut_DEPENDENCIES) @rm -f nut$(EXEEXT) $(AM_V_CCLD)$(LINK) $(nut_OBJECTS) $(nut_LDADD) $(LIBS) mostlyclean-compile: -rm -f *.$(OBJEXT) distclean-compile: -rm -f *.tab.c include ./$(DEPDIR)/halt.Po # am--include-marker include ./$(DEPDIR)/wininit.Po # am--include-marker $(am__depfiles_remade): @$(MKDIR_P) $(@D) @echo '# dummy' >$@-t && $(am__mv) $@-t $@ am--depfiles: $(am__depfiles_remade) .c.o: $(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.o$$||'`;\ $(COMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\ $(am__mv) $$depbase.Tpo $$depbase.Po # $(AM_V_CC)source='$<' object='$@' libtool=no \ # DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) \ # $(AM_V_CC_no)$(COMPILE) -c -o $@ $< .c.obj: $(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.obj$$||'`;\ $(COMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ `$(CYGPATH_W) '$<'` &&\ $(am__mv) $$depbase.Tpo $$depbase.Po # $(AM_V_CC)source='$<' object='$@' libtool=no \ # DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) \ # $(AM_V_CC_no)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'` .c.lo: $(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.lo$$||'`;\ $(LTCOMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\ $(am__mv) $$depbase.Tpo $$depbase.Plo # $(AM_V_CC)source='$<' object='$@' libtool=yes \ # DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) \ # $(AM_V_CC_no)$(LTCOMPILE) -c -o $@ $< mostlyclean-libtool: -rm -f *.lo clean-libtool: -rm -rf .libs _libs ID: $(am__tagged_files) $(am__define_uniq_tagged_files); mkid -fID $$unique tags: tags-am TAGS: tags tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) set x; \ here=`pwd`; \ $(am__define_uniq_tagged_files); \ shift; \ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ test -n "$$unique" || unique=$$empty_fix; \ if test $$# -gt 0; then \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ "$$@" $$unique; \ else \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ $$unique; \ fi; \ fi ctags: ctags-am CTAGS: ctags ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) $(am__define_uniq_tagged_files); \ test -z "$(CTAGS_ARGS)$$unique" \ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ $$unique GTAGS: here=`$(am__cd) $(top_builddir) && pwd` \ && $(am__cd) $(top_srcdir) \ && gtags -i $(GTAGS_ARGS) "$$here" cscopelist: cscopelist-am cscopelist-am: $(am__tagged_files) list='$(am__tagged_files)'; \ case "$(srcdir)" in \ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \ *) sdir=$(subdir)/$(srcdir) ;; \ esac; \ for i in $$list; do \ if test -f "$$i"; then \ echo "$(subdir)/$$i"; \ else \ echo "$$sdir/$$i"; \ fi; \ done >> $(top_builddir)/cscope.files distclean-tags: -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags distdir: $(BUILT_SOURCES) $(MAKE) $(AM_MAKEFLAGS) distdir-am distdir-am: $(DISTFILES) @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ dist_files=`for file in $$list; do echo $$file; done | \ sed -e "s|^$$srcdirstrip/||;t" \ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ case $$dist_files in \ */*) $(MKDIR_P) `echo "$$dist_files" | \ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ sort -u` ;; \ esac; \ for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d "$(distdir)/$$file"; then \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ else \ test -f "$(distdir)/$$file" \ || cp -p $$d/$$file "$(distdir)/$$file" \ || exit 1; \ fi; \ done check-am: all-am check: check-am all-am: Makefile $(PROGRAMS) installdirs: for dir in "$(DESTDIR)$(bindir)"; do \ test -z "$$dir" || $(MKDIR_P) "$$dir"; \ done install: install-am install-exec: install-exec-am install-data: install-data-am uninstall: uninstall-am install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-am install-strip: if test -z '$(STRIP)'; then \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ install; \ else \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ fi mostlyclean-generic: clean-generic: -test -z "$(CLEANFILES)" || rm -f $(CLEANFILES) distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." -test -z "$(MAINTAINERCLEANFILES)" || rm -f $(MAINTAINERCLEANFILES) clean: clean-am clean-am: clean-binPROGRAMS clean-generic clean-libtool mostlyclean-am distclean: distclean-am -rm -f ./$(DEPDIR)/halt.Po -rm -f ./$(DEPDIR)/wininit.Po -rm -f Makefile distclean-am: clean-am distclean-compile distclean-generic \ distclean-tags dvi: dvi-am dvi-am: html: html-am html-am: info: info-am info-am: install-data-am: install-dvi: install-dvi-am install-dvi-am: install-exec-am: install-binPROGRAMS install-html: install-html-am install-html-am: install-info: install-info-am install-info-am: install-man: install-pdf: install-pdf-am install-pdf-am: install-ps: install-ps-am install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-am -rm -f ./$(DEPDIR)/halt.Po -rm -f ./$(DEPDIR)/wininit.Po -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-am mostlyclean-am: mostlyclean-compile mostlyclean-generic \ mostlyclean-libtool pdf: pdf-am pdf-am: ps: ps-am ps-am: uninstall-am: uninstall-binPROGRAMS .MAKE: install-am install-strip .PHONY: CTAGS GTAGS TAGS all all-am am--depfiles check check-am clean \ clean-binPROGRAMS clean-generic clean-libtool cscopelist-am \ ctags ctags-am distclean distclean-compile distclean-generic \ distclean-libtool distclean-tags distdir dvi dvi-am html \ html-am info info-am install install-am install-binPROGRAMS \ install-data install-data-am install-dvi install-dvi-am \ install-exec install-exec-am install-html install-html-am \ install-info install-info-am install-man install-pdf \ install-pdf-am install-ps install-ps-am install-strip \ installcheck installcheck-am installdirs maintainer-clean \ maintainer-clean-generic mostlyclean mostlyclean-compile \ mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \ tags tags-am uninstall uninstall-am uninstall-binPROGRAMS .PRECIOUS: Makefile ../include/nut_version.h: FORCE (cd ../include/ && $(MAKE) $(AM_MAKEFLAGS) nut_version.h) FORCE: #winevent.rc winevent.h: winevent.mc # $(WINDMC) $< #winevent.o: winevent.rc winevent.h # $(WINDRES) winevent.rc winevent.o #wininit.$(OBJEXT): winevent.h # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: nut-2.8.1/scripts/Windows/Makefile.am0000644000175000017500000000120614520271213014422 00000000000000# Network UPS Tools: script/Windows AM_CFLAGS = -I$(top_srcdir)/include ../include/nut_version.h: FORCE (cd ../include/ && $(MAKE) $(AM_MAKEFLAGS) nut_version.h) EXTRA_DIST = winevent.mc build-mingw-nut.sh README.adoc FORCE: if HAVE_MINGW_RESGEN winevent.rc winevent.h: winevent.mc $(WINDMC) $< winevent.o: winevent.rc winevent.h $(WINDRES) winevent.rc winevent.o wininit.$(OBJEXT): winevent.h bin_PROGRAMS = nut halt nut_SOURCES = wininit.c nut_LDADD = ../../common/libcommon.la winevent.o halt_SOURCES = halt.c CLEANFILES = winevent.rc winevent.o winevent.h endif HAVE_MINGW_RESGEN MAINTAINERCLEANFILES = Makefile.in .dirstamp nut-2.8.1/scripts/Windows/Installer/0000755000175000017500000000000014520277775014427 500000000000000nut-2.8.1/scripts/Windows/Installer/NUT-Installer.xml.in0000644000175000017500000051562114520271213020066 00000000000000 If the automatic USB driver installation fails, you can try to install a driver manually. For this go to : https://sourceforge.net/projects/libusb-win32/files/libusb-win32-releases/ After installling libusb-win32, run libUSB's Inf Wizard and choose your device. Click Next to continue [Wizard]. If you use a USB UPS, please plug it in now, so that we can try to install the relevant driver. [DlgTitleFont][ProductName] installs the following libraries, location of licenses are - Click Next to continue [Wizard]. 1. msys-1.0.dll - http://sourceforge.net/projects/mingw/files/MSYS/BaseSystem/msys-core/msys-1.0.16-1/ 2. msys-ssl-1.0.0.dll and msys-crypto-1.0.0.dll - http://sourceforge.net/projects/mingw/files/MSYS/openssl/openssl-1.0.0-1/ 3. libregex-1.dll - http://sourceforge.net/projects/mingw/files/MSYS/BaseSystem/regex/regex-1.20090805-2/ Click the Finish button to exit the [Wizard]. {\VerdanaBold13}Completing the [ProductName] [Wizard] {\VerdanaBold13}[ProductName] [Wizard] ended prematurely [ProductName] setup ended prematurely because of an error. Your system has not been modified. To install this program at a later time, please run the installation again. Click the Finish button to exit the [Wizard]. Please wait while the [Wizard] prepares to guide you through the installation. {\VerdanaBold13}Welcome to the [ProductName] [Wizard] Please wait while the [Wizard] [Progress2] [ProductName]. This may take several minutes. [DlgTitleFont][Progress1] [ProductName] {\VerdanaBold13}[ProductName] [Wizard] was interrupted [ProductName] setup was interrupted. Your system has not been modified. To install this program at a later time, please run the installation again. Click the Finish button to exit the [Wizard]. Browse to the destination folder [DlgTitleFont]Change current destination folder Are you sure you want to cancel [ProductName] installation? The following applications are using files that need to be updated by this setup. Close these applications and then click Retry to continue the installation or Cancel to exit it. Some files that need to be updated are currently in use. [DlgTitleFont]Files in Use "Yes"]]> {\rtf1\ansi\ansicpg1252\deff0\deftab720 {\fonttbl{\f0\froman\fprq2 Times New Roman;}} {\colortbl\red0\green0\blue0;} \deflang1033\horzdoc{\*\fchars }{\*\lchars } \pard\plain\f0\fs18 \par GNU GENERAL PUBLIC LICENSE \par Version 2, June 1991 \par \par Copyright (C) 1989, 1991 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. \par Preamble \par The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Lesser General Public License instead.) You can apply it to your programs, too. \par \par 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 this service 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. \par To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it. \par \par For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. 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. \par \par We protect your rights with two steps: \par (1) copyright the software, and \par (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software. \par \par Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations. \par \par Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all. \par \par The precise terms and conditions for copying, distribution and modification follow. \par \par GNU GENERAL PUBLIC LICENSE \par \par TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION \par \par 0. This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is addressed as "you". \par \par Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does. \par \par 1. You may copy and distribute 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 and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program. \par \par You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. \par \par 2. You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: \par \par a) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change. \par \par b) You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License. \par \par c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.) \par \par These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. \par \par Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program. \par \par In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. \par \par 3. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following: \par \par a) Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, \par \par b) Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, \par \par c) Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.) \par \par The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. \par \par If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code. \par \par 4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. \par \par 5. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it. \par \par 6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License. \par \par 7. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), 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 distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program. \par \par If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances. \par \par It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. \par \par This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. \par \par 8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. \par \par 9. The Free Software Foundation may publish revised and/or new versions of the 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. \par \par Each version is given a distinguishing version number. If the Program specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation. \par \par 10. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. \par \par NO WARRANTY \par \par 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, 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. \par \par 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE 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. \par \par END OF TERMS AND CONDITIONS \par \par How to Apply These Terms to Your New Programs \par \par 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. \par \par 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 convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. \par \par <one line to give the program's name and a brief idea of what it does.> Copyright (C) <year> <name of author> \par \par 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 2 of the License, or (at your option) any later version. \par \par 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. \par \par You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. \par \par Also add information on how to contact you by electronic and paper mail. \par \par If the program is interactive, make it output a short notice like this when it starts in an interactive mode: \par \par Gnomovision version 69, Copyright (C) year name of author Gnomovision 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. \par The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, the commands you use may be called something other than `show w' and `show c'; they could even be mouse-clicks or menu items--whatever suits your program. \par \par You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the program, if necessary. Here is a sample; alter the names: \par \par Yoyodyne, Inc., hereby disclaims all copyright interest in the program `Gnomovision' (which makes passes at compilers) written by James Hacker. \par \par <signature of Ty Coon>, 1 April 1989 \par Ty Coon, President of Vice \par \par This 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. \par \par } [DlgTitleFont]Re&pair [DlgTitleFont]&Remove Select the operation you wish to perform. [DlgTitleFont]Repair or Remove installation Removes [ProductName] from your computer. Repairs errors in the most recent installation state - fixes missing or corrupt files, shortcuts and registry entries. The [Wizard] will allow you to change the way [ProductName] features are installed on your computer or even to remove [ProductName] from your computer. Click Next to continue or Cancel to exit the [Wizard]. {\VerdanaBold13}Welcome to the [ProductName] [Wizard] 1]]> The [Wizard] will complete the installation of [ProductName] on your computer. Click Install to continue or Cancel to exit the [Wizard]. {\VerdanaBold13}Resuming the [ProductName] [Wizard] 1]]> Click Install to begin the installation. If you want to review or change any of your installation settings, click Back. Click Cancel to exit the wizard. The [Wizard] is ready to begin the [InstallMode] installation [DlgTitleFont]Ready to Install 1]]> 1]]> Click Remove to remove [ProductName] from your computer. If you want to review or change any of your installation settings, click Back. Click Cancel to exit the wizard. You have chosen to remove the program from your computer. [DlgTitleFont]Remove [ProductName] 1]]> 1]]> 1]]> Click Repair to repair the installation of [ProductName]. If you want to review or change any of your installation settings, click Back. Click Cancel to exit the wizard. The [Wizard] is ready to begin the repair of [ProductName]. [DlgTitleFont]Repair [ProductName] The [Wizard] will install [ProductName] on your computer. Click Next to continue or Cancel to exit the [Wizard]. {\VerdanaBold13}Welcome to the [ProductName] [Wizard] bytes GB KB MB Entire feature will be unavailable Feature will be installed when required Entire feature will be installed to run from CD Entire feature will be installed on local hard drive Entire feature will be installed to run from network Will be installed to run from CD Will be installed on local hard drive Will be installed to run from network Gathering required information... This feature will remain uninstalled This feature will be set to be installed when required This feature will be installed to run from CD This feature will be installed on the local hard drive This feature will be installed to run from the network This feature will become unavailable Will be installed when required This feature will be available to run from CD This feature will be installed on your local hard drive This feature will be available to run from the network This feature will be uninstalled completely, you won't be able to run it from CD This feature will change from run from CD state to set to be installed when required This feature will remain to be run from CD This feature will change from run from CD state to be installed on the local hard drive This feature frees up [1] on your hard drive. This feature requires [1] on your hard drive. Compiling cost for this feature... This feature will be completely removed This feature will be removed from your local hard drive, but will be set to be installed when required This feature will be removed from your local hard drive, but will be still available to run from CD This feature will remain on you local hard drive This feature will be removed from your local hard drive, but will be still available to run from the network This feature will be uninstalled completely, you won't be able to run it from the network This feature will change from run from network state to set to be installed when required This feature will change from run from network state to be installed on the local hard drive This feature will remain to be run from the network This feature frees up [1] on your hard drive. It has [2] of [3] subfeatures selected. The subfeatures free up [4] on your hard drive. This feature frees up [1] on your hard drive. It has [2] of [3] subfeatures selected. The subfeatures require [4] on your hard drive. This feature requires [1] on your hard drive. It has [2] of [3] subfeatures selected. The subfeatures free up [4] on your hard drive. This feature requires [1] on your hard drive. It has [2] of [3] subfeatures selected. The subfeatures require [4] on your hard drive. Time remaining: {[1] minutes }{[2] seconds} Available Difference Required Disk Size Volume Validating install Copying new files Copying network install files Computing space requirements Computing space requirements Computing space requirements Creating shortcuts Publishing Qualified Components Publishing Product Features Publishing product information Registering Class servers Registering extension servers Registering MIME info Registering program identifiers Allocating registry space Searching for installed applications Binding executables Searching for qualifying products Creating folders Deleting services Creating duplicate files Searching for related applications Installing ODBC components Installing new services Evaluating launch conditions Migrating feature states from related applications Moving files Patching files Updating component registration Registering COM+ Applications and Components Registering fonts Registering product Registering type libraries Registering user Removing duplicated files Updating environment strings Removing applications Removing files Removing folders Removing INI files entries Removing ODBC components Removing system registry values Removing shortcuts Searching for qualifying products Registering modules Unregistering modules Initializing ODBC directories Starting services Stopping services Unpublishing Qualified Components Unpublishing Product Features Unregister Class servers Unregistering COM+ Applications and Components Unregistering extension servers Unregistering fonts Unregistering MIME info Unregistering program identifiers Unregistering type libraries Updating environment strings Writing INI files values Writing system registry values Advertising application Generating script operations for action: Installing system catalog Publishing assembly information Unpublishing assembly information Rolling back action: Removing backup files Removing moved files Unpublishing product information {{Fatal error: }} {{Error [1]. }} Warning [1]. Info [1]. The installer has encountered an unexpected error installing this package. This may indicate a problem with this package. The error code is [1]. {{The arguments are: [2], [3], [4]}} {{Disk full: }} Action [Time]: [1]. [2] [ProductName] {[2]}{, [3]}{, [4]} Message type: [1], Argument: [2] === Logging started: [Date] [Time] === === Logging stopped: [Date] [Time] === Action start [Time]: [1]. Action ended [Time]: [1]. Return value [2]. Time remaining: {[1] minutes }{[2] seconds} Out of memory. Shut down other applications before retrying. Installer is no longer responding. Installer stopped prematurely. Please wait while Windows configures [ProductName] Gathering required information... Removing older versions of this application... Preparing to remove older versions of this application... {[ProductName] }Setup completed successfully. {[ProductName] }Setup failed. Error reading from file: [2]. {{ System error [3].}} Verify that the file exists and that you can access it. Cannot create the file '[2]'. A directory with this name already exists. Cancel the install and try installing to a different location. Please insert the disk: [2] The installer has insufficient privileges to access this directory: [2]. The installation cannot continue. Log on as administrator or contact your system administrator. Error writing to file: [2]. Verify that you have access to that directory. Error reading from file [2]. {{ System error [3].}} Verify that the file exists and that you can access it. Another application has exclusive access to the file '[2]'. Please shut down all other applications, then click Retry. There is not enough disk space to install this file: [2]. Free some disk space and click Retry, or click Cancel to exit. Source file not found: [2]. Verify that the file exists and that you can access it. Error reading from file: [3]. {{ System error [2].}} Verify that the file exists and that you can access it. Error writing to file: [3]. {{ System error [2].}} Verify that you have access to that directory. Source file not found{{(cabinet)}}: [2]. Verify that the file exists and that you can access it. Cannot create the directory '[2]'. A file with this name already exists. Please rename or remove the file and click retry, or click Cancel to exit. The volume [2] is currently unavailable. Please select another. The specified path '[2]' is unavailable. Unable to write to the specified folder: [2]. A network error occurred while attempting to read from the file: [2] An error occurred while attempting to create the directory: [2] A network error occurred while attempting to create the directory: [2] A network error occurred while attempting to open the source file cabinet: [2] The specified path is too long: [2] The Installer has insufficient privileges to modify this file: [2]. A portion of the folder path '[2]' is invalid. It is either empty or exceeds the length allowed by the system. The folder path '[2]' contains words that are not valid in folder paths. The folder path '[2]' contains an invalid character. '[2]' is not a valid short file name. Error getting file security: [3] GetLastError: [2] Invalid Drive: [2] Error applying patch to file [2]. It has probably been updated by other means, and can no longer be modified by this patch. For more information contact your patch vendor. {{System Error: [3]}} A file that is required cannot be installed because the cabinet file [2] is not digitally signed. This may indicate that the cabinet file is corrupt. A file that is required cannot be installed because the cabinet file [2] has an invalid digital signature. This may indicate that the cabinet file is corrupt.{{ Error [3] was returned by WinVerifyTrust.}} Failed to correctly copy [2] file: CRC error. Failed to correctly move [2] file: CRC error. Failed to correctly patch [2] file: CRC error. The file '[2]' cannot be installed because the file cannot be found in cabinet file '[3]'. This could indicate a network error, an error reading from the CD-ROM, or a problem with this package. The cabinet file '[2]' required for this installation is corrupt and cannot be used. This could indicate a network error, an error reading from the CD-ROM, or a problem with this package. There was an error creating a temporary file that is needed to complete this installation.{{ Folder: [3]. System error code: [2]}} Could not create key: [2]. {{ System error [3].}} Verify that you have sufficient access to that key, or contact your support personnel. Could not open key: [2]. {{ System error [3].}} Verify that you have sufficient access to that key, or contact your support personnel. Could not delete value [2] from key [3]. {{ System error [4].}} Verify that you have sufficient access to that key, or contact your support personnel. Could not delete key [2]. {{ System error [3].}} Verify that you have sufficient access to that key, or contact your support personnel. Could not read value [2] from key [3]. {{ System error [4].}} Verify that you have sufficient access to that key, or contact your support personnel. Could not write value [2] to key [3]. {{ System error [4].}} Verify that you have sufficient access to that key, or contact your support personnel. Could not get value names for key [2]. {{ System error [3].}} Verify that you have sufficient access to that key, or contact your support personnel. Could not get sub key names for key [2]. {{ System error [3].}} Verify that you have sufficient access to that key, or contact your support personnel. Could not read security information for key [2]. {{ System error [3].}} Verify that you have sufficient access to that key, or contact your support personnel. Could not increase the available registry space. [2] KB of free registry space is required for the installation of this application. Another installation is in progress. You must complete that installation before continuing this one. Error accessing secured data. Please make sure the Windows Installer is configured properly and try the install again. User '[2]' has previously initiated an install for product '[3]'. That user will need to run that install again before they can use that product. Your current install will now continue. User '[2]' has previously initiated an install for product '[3]'. That user will need to run that install again before they can use that product. Out of disk space -- Volume: '[2]'; required space: [3] KB; available space: [4] KB. Free some disk space and retry. Are you sure you want to cancel? The file [2][3] is being held in use{ by the following process: Name: [4], Id: [5], Window Title: '[6]'}. Close that application and retry. The product '[2]' is already installed, preventing the installation of this product. The two products are incompatible. There is not enough disk space on the volume '[2]' to continue the install with recovery enabled. [3] KB are required, but only [4] KB are available. Click Ignore to continue the install without saving recovery information, click Retry to check for available space again, or click Cancel to quit the installation. Could not access network location [2]. The following applications should be closed before continuing the install: Could not find any previously installed compliant products on the machine for installing this product. An error occurred while applying security settings. [2] is not a valid user or group. This could be a problem with the package, or a problem connecting to a domain controller on the network. Check your network connection and click Retry, or Cancel to end the install. {{Unable to locate the user's SID, system error [3]}} The key [2] is not valid. Verify that you entered the correct key. The installer must restart your system before configuration of [2] can continue. Click Yes to restart now or No if you plan to manually restart later. You must restart your system for the configuration changes made to [2] to take effect. Click Yes to restart now or No if you plan to manually restart later. An installation for [2] is currently suspended. You must undo the changes made by that installation to continue. Do you want to undo those changes? A previous installation for this product is in progress. You must undo the changes made by that installation to continue. Do you want to undo those changes? An installation package for the product [2] cannot be found. Try the installation again using a valid copy of the installation package '[3]'. Installation completed successfully. Installation failed. Product: [2] -- [3] You may either restore your computer to its previous state or continue the install later. Would you like to restore? An error occurred while writing installation information to disk. Check to make sure enough disk space is available, and click Retry, or Cancel to end the install. One or more of the files required to restore your computer to its previous state could not be found. Restoration will not be possible. [2] cannot install one of its required products. Contact your technical support group. {{System Error: [3].}} The older version of [2] cannot be removed. Contact your technical support group. {{System Error [3].}} Installed [2] Configured [2] Removed [2] File [2] was rejected by digital signature policy. The Windows Installer Service could not be accessed. This can occur if you are running Windows in safe mode, or if the Windows Installer is not correctly installed. Contact your support personnel for assistance. There is a problem with this Windows Installer package. A script required for this install to complete could not be run. Contact your support personnel or package vendor. {{Custom action [2] script error [3], [4]: [5] Line [6], Column [7], [8] }} There is a problem with this Windows Installer package. A program required for this install to complete could not be run. Contact your support personnel or package vendor. {{Action: [2], location: [3], command: [4] }} There is a problem with this Windows Installer package. A program run as part of the setup did not finish as expected. Contact your support personnel or package vendor. {{Action [2], location: [3], command: [4] }} There is a problem with this Windows Installer package. A DLL required for this install to complete could not be run. Contact your support personnel or package vendor. {{Action [2], entry: [3], library: [4] }} Removal completed successfully. Removal failed. Advertisement completed successfully. Advertisement failed. Configuration completed successfully. Configuration failed. You must be an Administrator to remove this application. To remove this application, you can log on as an Administrator, or contact your technical support group for assistance. The path [2] is not valid. Please specify a valid path. Out of memory. Shut down other applications before retrying. There is no disk in drive [2]. Please insert one and click Retry, or click Cancel to go back to the previously selected volume. There is no disk in drive [2]. Please insert one and click Retry, or click Cancel to return to the browse dialog and select a different volume. The folder [2] does not exist. Please enter a path to an existing folder. You have insufficient privileges to read this folder. A valid destination folder for the install could not be determined. Error attempting to read from the source install database: [2]. Scheduling reboot operation: Renaming file [2] to [3]. Must reboot to complete operation. Scheduling reboot operation: Deleting file [2]. Must reboot to complete operation. Module [2] failed to register. HRESULT [3]. Contact your support personnel. Module [2] failed to unregister. HRESULT [3]. Contact your support personnel. Failed to cache package [2]. Error: [3]. Contact your support personnel. Could not register font [2]. Verify that you have sufficient permissions to install fonts, and that the system supports this font. Could not unregister font [2]. Verify that you that you have sufficient permissions to remove fonts. Could not create Shortcut [2]. Verify that the destination folder exists and that you can access it. Could not remove Shortcut [2]. Verify that the shortcut file exists and that you can access it. Could not register type library for file [2]. Contact your support personnel. Could not unregister type library for file [2]. Contact your support personnel. Could not update the ini file [2][3]. Verify that the file exists and that you can access it. Could not schedule file [2] to replace file [3] on reboot. Verify that you have write permissions to file [3]. Error removing ODBC driver manager, ODBC error [2]: [3]. Contact your support personnel. Error installing ODBC driver manager, ODBC error [2]: [3]. Contact your support personnel. Error removing ODBC driver: [4], ODBC error [2]: [3]. Verify that you have sufficient privileges to remove ODBC drivers. Error installing ODBC driver: [4], ODBC error [2]: [3]. Verify that the file [4] exists and that you can access it. Error configuring ODBC data source: [4], ODBC error [2]: [3]. Verify that the file [4] exists and that you can access it. Service '[2]' ([3]) failed to start. Verify that you have sufficient privileges to start system services. Service '[2]' ([3]) could not be stopped. Verify that you have sufficient privileges to stop system services. Service '[2]' ([3]) could not be deleted. Verify that you have sufficient privileges to remove system services. Service '[2]' ([3]) could not be installed. Verify that you have sufficient privileges to install system services. Could not update environment variable '[2]'. Verify that you have sufficient privileges to modify environment variables. You do not have sufficient privileges to complete this installation for all users of the machine. Log on as administrator and then retry this installation. Could not set file security for file '[3]'. Error: [2]. Verify that you have sufficient privileges to modify the security permissions for this file. Component Services (COM+ 1.0) are not installed on this computer. This installation requires Component Services in order to complete successfully. Component Services are available on Windows 2000. Error registering COM+ Application. Contact your support personnel for more information. Error unregistering COM+ Application. Contact your support personnel for more information. The description for service '[2]' ([3]) could not be changed. The Windows Installer service cannot update the system file [2] because the file is protected by Windows. You may need to update your operating system for this program to work correctly. {{Package version: [3], OS Protected version: [4]}} The Windows Installer service cannot update the protected Windows file [2]. {{Package version: [3], OS Protected version: [4], SFP Error: [5]}} The Windows Installer service cannot update one or more protected Windows files. {{SFP Error: [2]. List of protected files:\r\n[3]}} User installations are disabled via policy on the machine. An error occured during the installation of assembly component [2]. HRESULT: [3]. {{assembly interface: [4], function: [5], assembly name: [6]}} TARGETDIR="" TARGETDIR="" ]]> @@@@@]]> TARGETDIR="" TARGETDIR="" LIBUSBINSTALL=1 nut-2.8.1/scripts/upower/0000755000175000017500000000000014520277776012362 500000000000000nut-2.8.1/scripts/upower/95-upower-hid.hwdb0000644000175000017500000000674314520277776015500 00000000000000############################################################################################################## # Uninterruptible Power Supplies with USB HID interfaces # # This file was automatically generated by NUT: # https://github.com/networkupstools/nut/ # # To keep up to date, monitor upstream NUT # https://github.com/networkupstools/nut/commits/master/scripts/upower/95-upower-hid.hwdb # or checkout the NUT repository and call 'tools/nut-usbinfo.pl' # Hewlett Packard usb:v03F0p0001* usb:v03F0p1F06* usb:v03F0p1F08* usb:v03F0p1F09* usb:v03F0p1F0A* usb:v03F0p1FE0* usb:v03F0p1FE1* usb:v03F0p1FE2* usb:v03F0p1FE3* usb:v03F0p1FE5* usb:v03F0p1FE6* usb:v03F0p1FE7* usb:v03F0p1FE8* UPOWER_BATTERY_TYPE=ups UPOWER_VENDOR=Hewlett Packard # Eaton usb:v0463p0001* usb:v0463pFFFF* UPOWER_BATTERY_TYPE=ups UPOWER_VENDOR=Eaton # Dell usb:v047CpFFFF* UPOWER_BATTERY_TYPE=ups UPOWER_VENDOR=Dell # ST Microelectronics usb:v0483pA113* UPOWER_BATTERY_TYPE=ups UPOWER_VENDOR=ST Microelectronics # IBM usb:v04B3p0001* UPOWER_BATTERY_TYPE=ups UPOWER_VENDOR=IBM # Minibox usb:v04D8pD004* usb:v04D8pD005* UPOWER_BATTERY_TYPE=ups UPOWER_VENDOR=Minibox # Belkin usb:v050Dp0375* usb:v050Dp0551* usb:v050Dp0750* usb:v050Dp0751* usb:v050Dp0900* usb:v050Dp0910* usb:v050Dp0912* usb:v050Dp0980* usb:v050Dp0F51* usb:v050Dp1100* UPOWER_BATTERY_TYPE=ups UPOWER_VENDOR=Belkin # APC usb:v051Dp0000* usb:v051Dp0002* usb:v051Dp0003* usb:v051Dp0004* UPOWER_BATTERY_TYPE=ups UPOWER_VENDOR=APC # Powerware usb:v0592p0004* UPOWER_BATTERY_TYPE=ups UPOWER_VENDOR=Powerware # Delta UPS usb:v05DDp041B* usb:v05DDpA011* usb:v05DDpA0A0* UPOWER_BATTERY_TYPE=ups UPOWER_VENDOR=Delta UPS # Phoenixtec Power Co., Ltd usb:v06DApFFFF* UPOWER_BATTERY_TYPE=ups UPOWER_VENDOR=Phoenixtec Power Co., Ltd # iDowell usb:v075Dp0300* UPOWER_BATTERY_TYPE=ups UPOWER_VENDOR=iDowell # Cyber Power Systems usb:v0764p0005* usb:v0764p0501* usb:v0764p0601* UPOWER_BATTERY_TYPE=ups UPOWER_VENDOR=Cyber Power Systems # TrippLite usb:v09AEp1003* usb:v09AEp1007* usb:v09AEp1008* usb:v09AEp1009* usb:v09AEp1010* usb:v09AEp1330* usb:v09AEp2005* usb:v09AEp2007* usb:v09AEp2008* usb:v09AEp2009* usb:v09AEp2010* usb:v09AEp2011* usb:v09AEp2012* usb:v09AEp2013* usb:v09AEp2014* usb:v09AEp3008* usb:v09AEp3009* usb:v09AEp3010* usb:v09AEp3011* usb:v09AEp3012* usb:v09AEp3013* usb:v09AEp3014* usb:v09AEp3015* usb:v09AEp3016* usb:v09AEp3024* usb:v09AEp4001* usb:v09AEp4002* usb:v09AEp4003* usb:v09AEp4004* usb:v09AEp4005* usb:v09AEp4006* usb:v09AEp4007* usb:v09AEp4008* UPOWER_BATTERY_TYPE=ups UPOWER_VENDOR=TrippLite # PowerCOM usb:v0D9Fp0001* usb:v0D9Fp0004* usb:v0D9Fp00A2* usb:v0D9Fp00A3* usb:v0D9Fp00A4* usb:v0D9Fp00A5* usb:v0D9Fp00A6* UPOWER_BATTERY_TYPE=ups UPOWER_VENDOR=PowerCOM # Liebert usb:v10AFp0001* usb:v10AFp0004* usb:v10AFp0008* UPOWER_BATTERY_TYPE=ups UPOWER_VENDOR=Liebert # Legrand usb:v1CB0p0032* usb:v1CB0p0038* UPOWER_BATTERY_TYPE=ups UPOWER_VENDOR=Legrand # Arduino usb:v2341p0036* usb:v2341p8036* UPOWER_BATTERY_TYPE=ups UPOWER_VENDOR=Arduino # Arduino usb:v2A03p0036* usb:v2A03p0040* usb:v2A03p8036* usb:v2A03p8040* UPOWER_BATTERY_TYPE=ups UPOWER_VENDOR=Arduino # AEG usb:v2B2DpFFFF* UPOWER_BATTERY_TYPE=ups UPOWER_VENDOR=AEG # Ever usb:v2E51p0000* usb:v2E51pFFFF* UPOWER_BATTERY_TYPE=ups UPOWER_VENDOR=Ever # Salicru usb:v2E66p0101* usb:v2E66p0201* usb:v2E66p0202* usb:v2E66p0203* usb:v2E66p0300* usb:v2E66p0302* UPOWER_BATTERY_TYPE=ups UPOWER_VENDOR=Salicru # Powervar usb:v4234p0002* UPOWER_BATTERY_TYPE=ups UPOWER_VENDOR=Powervar nut-2.8.1/scripts/upower/95-upower-hid.rules0000644000175000017500000000031714500336654015662 00000000000000# Copy some attributes from the USB device to the hiddev device SUBSYSTEM=="usbmisc", SUBSYSTEMS=="usb", KERNEL=="hiddev*", IMPORT{parent}="UPOWER_*", IMPORT{parent}="ID_VENDOR", IMPORT{parent}="ID_PRODUCT" nut-2.8.1/scripts/devd/0000755000175000017500000000000014520277777011764 500000000000000nut-2.8.1/scripts/devd/Makefile.in0000644000175000017500000005255114520274662013747 00000000000000# Makefile.in generated by automake 1.16.5 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2021 Free Software Foundation, Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. @SET_MAKE@ VPATH = @srcdir@ am__is_gnu_make = { \ if test -z '$(MAKELEVEL)'; then \ false; \ elif test -n '$(MAKE_HOST)'; then \ true; \ elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \ true; \ else \ false; \ fi; \ } am__make_running_with_option = \ case $${target_option-} in \ ?) ;; \ *) echo "am__make_running_with_option: internal error: invalid" \ "target option '$${target_option-}' specified" >&2; \ exit 1;; \ esac; \ has_opt=no; \ sane_makeflags=$$MAKEFLAGS; \ if $(am__is_gnu_make); then \ sane_makeflags=$$MFLAGS; \ else \ case $$MAKEFLAGS in \ *\\[\ \ ]*) \ bs=\\; \ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ esac; \ fi; \ skip_next=no; \ strip_trailopt () \ { \ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ }; \ for flg in $$sane_makeflags; do \ test $$skip_next = yes && { skip_next=no; continue; }; \ case $$flg in \ *=*|--*) continue;; \ -*I) strip_trailopt 'I'; skip_next=yes;; \ -*I?*) strip_trailopt 'I';; \ -*O) strip_trailopt 'O'; skip_next=yes;; \ -*O?*) strip_trailopt 'O';; \ -*l) strip_trailopt 'l'; skip_next=yes;; \ -*l?*) strip_trailopt 'l';; \ -[dEDm]) skip_next=yes;; \ -[JT]) skip_next=yes;; \ esac; \ case $$flg in \ *$$target_option*) has_opt=yes; break;; \ esac; \ done; \ test $$has_opt = yes am__make_dryrun = (target_option=n; $(am__make_running_with_option)) am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkglibexecdir = $(libexecdir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ target_triplet = @target@ @WITH_DEVD_TRUE@@WITH_USB_TRUE@am__append_1 = nut-usb.conf subdir = scripts/devd ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/m4/ax_c___attribute__.m4 \ $(top_srcdir)/m4/ax_c_pragmas.m4 \ $(top_srcdir)/m4/ax_check_compile_flag.m4 \ $(top_srcdir)/m4/ax_compare_version.m4 \ $(top_srcdir)/m4/ax_realpath.m4 \ $(top_srcdir)/m4/ax_run_or_link_ifelse.m4 \ $(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \ $(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \ $(top_srcdir)/m4/lt~obsolete.m4 \ $(top_srcdir)/m4/nut_arg_with.m4 \ $(top_srcdir)/m4/nut_check_asciidoc.m4 \ $(top_srcdir)/m4/nut_check_aspell.m4 \ $(top_srcdir)/m4/nut_check_cppcheck.m4 \ $(top_srcdir)/m4/nut_check_headers_windows.m4 \ $(top_srcdir)/m4/nut_check_libavahi.m4 \ $(top_srcdir)/m4/nut_check_libfreeipmi.m4 \ $(top_srcdir)/m4/nut_check_libgd.m4 \ $(top_srcdir)/m4/nut_check_libgpiod.m4 \ $(top_srcdir)/m4/nut_check_libltdl.m4 \ $(top_srcdir)/m4/nut_check_libmodbus.m4 \ $(top_srcdir)/m4/nut_check_libneon.m4 \ $(top_srcdir)/m4/nut_check_libnetsnmp.m4 \ $(top_srcdir)/m4/nut_check_libnss.m4 \ $(top_srcdir)/m4/nut_check_libopenssl.m4 \ $(top_srcdir)/m4/nut_check_libpowerman.m4 \ $(top_srcdir)/m4/nut_check_libregex.m4 \ $(top_srcdir)/m4/nut_check_libsystemd.m4 \ $(top_srcdir)/m4/nut_check_libusb.m4 \ $(top_srcdir)/m4/nut_check_libwrap.m4 \ $(top_srcdir)/m4/nut_check_os.m4 \ $(top_srcdir)/m4/nut_check_pkgconfig.m4 \ $(top_srcdir)/m4/nut_check_python.m4 \ $(top_srcdir)/m4/nut_check_socketlib.m4 \ $(top_srcdir)/m4/nut_compiler_family.m4 \ $(top_srcdir)/m4/nut_func_getnameinfo_argtypes.m4 \ $(top_srcdir)/m4/nut_report_feature.m4 \ $(top_srcdir)/m4/nut_stash_warnings.m4 \ $(top_srcdir)/m4/nut_type_socklen_t.m4 \ $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/include/config.h CONFIG_CLEAN_FILES = nut-usb.conf CONFIG_CLEAN_VPATH_FILES = AM_V_P = $(am__v_P_@AM_V@) am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) am__v_P_0 = false am__v_P_1 = : AM_V_GEN = $(am__v_GEN_@AM_V@) am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) am__v_GEN_0 = @echo " GEN " $@; am__v_GEN_1 = AM_V_at = $(am__v_at_@AM_V@) am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) am__v_at_0 = @ am__v_at_1 = SOURCES = DIST_SOURCES = am__can_run_installinfo = \ case $$AM_UPDATE_INFO_DIR in \ n|no|NO) false;; \ *) (install-info --version) >/dev/null 2>&1;; \ esac am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; am__vpath_adj = case $$p in \ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ *) f=$$p;; \ esac; am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`; am__install_max = 40 am__nobase_strip_setup = \ srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'` am__nobase_strip = \ for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||" am__nobase_list = $(am__nobase_strip_setup); \ for p in $$list; do echo "$$p $$p"; done | \ sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \ $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \ if (++n[$$2] == $(am__install_max)) \ { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \ END { for (dir in files) print dir, files[dir] }' am__base_list = \ sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' am__uninstall_files_from_dir = { \ test -z "$$files" \ || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \ || { echo " ( cd '$$dir' && rm -f" $$files ")"; \ $(am__cd) "$$dir" && rm -f $$files; }; \ } am__installdirs = "$(DESTDIR)$(devdconfdir)" DATA = $(devdconf_DATA) am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) am__DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/nut-usb.conf.in \ README DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) A2X = @A2X@ ACLOCAL = @ACLOCAL@ ALTPIDPATH = @ALTPIDPATH@ AMTAR = @AMTAR@ AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ AR = @AR@ ASCIIDOC = @ASCIIDOC@ ASPELL = @ASPELL@ ASPELL_FILTER_LIB_PATH = @ASPELL_FILTER_LIB_PATH@ ASPELL_FILTER_SHARE_PATH = @ASPELL_FILTER_SHARE_PATH@ ASPELL_FILTER_TEX_PATH = @ASPELL_FILTER_TEX_PATH@ AUGPARSE = @AUGPARSE@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ BINDIR = @BINDIR@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CONFIG_FLAGS = @CONFIG_FLAGS@ CONFPATH = @CONFPATH@ CPP = @CPP@ CPPCHECK = @CPPCHECK@ CPPFLAGS = @CPPFLAGS@ CPPUNIT_CFLAGS = @CPPUNIT_CFLAGS@ CPPUNIT_LIBS = @CPPUNIT_LIBS@ CSCOPE = @CSCOPE@ CTAGS = @CTAGS@ CXX = @CXX@ CXXCPP = @CXXCPP@ CXXDEPMODE = @CXXDEPMODE@ CXXFLAGS = @CXXFLAGS@ CYGPATH_W = @CYGPATH_W@ DBLATEX = @DBLATEX@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ DEPLOYED_UPSC = @DEPLOYED_UPSC@ DEPLOYED_UPSD = @DEPLOYED_UPSD@ DLLTOOL = @DLLTOOL@ DOC_BUILD_LIST = @DOC_BUILD_LIST@ DOC_CHECK_LIST = @DOC_CHECK_LIST@ DRIVER_BUILD_LIST = @DRIVER_BUILD_LIST@ DRIVER_INSTALL_TARGET = @DRIVER_INSTALL_TARGET@ DRIVER_MAN_LIST = @DRIVER_MAN_LIST@ DRIVER_MAN_LIST_PAGES = @DRIVER_MAN_LIST_PAGES@ DRVPATH = @DRVPATH@ DSYMUTIL = @DSYMUTIL@ DUMPBIN = @DUMPBIN@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ ETAGS = @ETAGS@ EXEEXT = @EXEEXT@ FGREP = @FGREP@ FORCE_NUT_VERSION = @FORCE_NUT_VERSION@ GDLIB_CONFIG = @GDLIB_CONFIG@ GREP = @GREP@ HAVE_SYS_SOCKET_H = @HAVE_SYS_SOCKET_H@ HAVE_WINSOCK2_H = @HAVE_WINSOCK2_H@ HAVE_WS2TCPIP_H = @HAVE_WS2TCPIP_H@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ LD = @LD@ LDFLAGS = @LDFLAGS@ LIBAVAHI_CFLAGS = @LIBAVAHI_CFLAGS@ LIBAVAHI_LIBS = @LIBAVAHI_LIBS@ LIBDIR = @LIBDIR@ LIBGD_CFLAGS = @LIBGD_CFLAGS@ LIBGD_LDFLAGS = @LIBGD_LDFLAGS@ LIBGPIO_CFLAGS = @LIBGPIO_CFLAGS@ LIBGPIO_LIBS = @LIBGPIO_LIBS@ LIBI2C_LIBS = @LIBI2C_LIBS@ LIBIPMI_CFLAGS = @LIBIPMI_CFLAGS@ LIBIPMI_LIBS = @LIBIPMI_LIBS@ LIBLTDL_CFLAGS = @LIBLTDL_CFLAGS@ LIBLTDL_LIBS = @LIBLTDL_LIBS@ LIBMODBUS_CFLAGS = @LIBMODBUS_CFLAGS@ LIBMODBUS_LIBS = @LIBMODBUS_LIBS@ LIBNEON_CFLAGS = @LIBNEON_CFLAGS@ LIBNEON_LIBS = @LIBNEON_LIBS@ LIBNETSNMP_CFLAGS = @LIBNETSNMP_CFLAGS@ LIBNETSNMP_LIBS = @LIBNETSNMP_LIBS@ LIBOBJS = @LIBOBJS@ LIBPOWERMAN_CFLAGS = @LIBPOWERMAN_CFLAGS@ LIBPOWERMAN_LIBS = @LIBPOWERMAN_LIBS@ LIBREGEX_LIBS = @LIBREGEX_LIBS@ LIBS = @LIBS@ LIBSSL_CFLAGS = @LIBSSL_CFLAGS@ LIBSSL_LIBS = @LIBSSL_LIBS@ LIBSSL_REQUIRES = @LIBSSL_REQUIRES@ LIBSYSTEMD_CFLAGS = @LIBSYSTEMD_CFLAGS@ LIBSYSTEMD_LIBS = @LIBSYSTEMD_LIBS@ LIBTOOL = @LIBTOOL@ LIBTOOL_DEPS = @LIBTOOL_DEPS@ LIBUSB_CFLAGS = @LIBUSB_CFLAGS@ LIBUSB_CONFIG = @LIBUSB_CONFIG@ LIBUSB_LIBS = @LIBUSB_LIBS@ LIBWRAP_CFLAGS = @LIBWRAP_CFLAGS@ LIBWRAP_LIBS = @LIBWRAP_LIBS@ LIPO = @LIPO@ LN_S = @LN_S@ LN_S_R = @LN_S_R@ LTLIBOBJS = @LTLIBOBJS@ LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@ MAINT = @MAINT@ MAKEINFO = @MAKEINFO@ MANIFEST_TOOL = @MANIFEST_TOOL@ MKDIR_P = @MKDIR_P@ MSGFMT = @MSGFMT@ NETLIBS = @NETLIBS@ NET_SNMP_CONFIG = @NET_SNMP_CONFIG@ NM = @NM@ NMEDIT = @NMEDIT@ NUT_DATADIR = @NUT_DATADIR@ NUT_LIBEXECDIR = @NUT_LIBEXECDIR@ NUT_NETVERSION = @NUT_NETVERSION@ NUT_SOURCE_GITREV = @NUT_SOURCE_GITREV@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ OS_NAME = @OS_NAME@ OTOOL = @OTOOL@ OTOOL64 = @OTOOL64@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_SEPARATOR = @PATH_SEPARATOR@ PIDPATH = @PIDPATH@ PKGCONFIGDIR = @PKGCONFIGDIR@ PKG_CONFIG = @PKG_CONFIG@ PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@ PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ PORT = @PORT@ POWERDOWNFLAG = @POWERDOWNFLAG@ PREFIX = @PREFIX@ PYTHON = @PYTHON@ PYTHON2 = @PYTHON2@ PYTHON2_SITE_PACKAGES = @PYTHON2_SITE_PACKAGES@ PYTHON3 = @PYTHON3@ PYTHON3_SITE_PACKAGES = @PYTHON3_SITE_PACKAGES@ PYTHON_SITE_PACKAGES = @PYTHON_SITE_PACKAGES@ RANLIB = @RANLIB@ REALPATH = @REALPATH@ RUN_AS_GROUP = @RUN_AS_GROUP@ RUN_AS_USER = @RUN_AS_USER@ SBINDIR = @SBINDIR@ SED = @SED@ SEMLIBS = @SEMLIBS@ SERLIBS = @SERLIBS@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ SOURCE_HIGHLIGHT = @SOURCE_HIGHLIGHT@ STATEPATH = @STATEPATH@ STRIP = @STRIP@ SUN_LIBUSB = @SUN_LIBUSB@ SYSTEMD_ANALYZE_PROGRAM = @SYSTEMD_ANALYZE_PROGRAM@ SYSTEMD_DAEMON_ARGS_DRIVER = @SYSTEMD_DAEMON_ARGS_DRIVER@ SYSTEMD_DAEMON_ARGS_UPSD = @SYSTEMD_DAEMON_ARGS_UPSD@ SYSTEMD_DAEMON_ARGS_UPSMON = @SYSTEMD_DAEMON_ARGS_UPSMON@ SYSTEMD_DAEMON_NOTIFYACCESS_DRIVER = @SYSTEMD_DAEMON_NOTIFYACCESS_DRIVER@ SYSTEMD_DAEMON_NOTIFYACCESS_UPSD = @SYSTEMD_DAEMON_NOTIFYACCESS_UPSD@ SYSTEMD_DAEMON_NOTIFYACCESS_UPSMON = @SYSTEMD_DAEMON_NOTIFYACCESS_UPSMON@ SYSTEMD_DAEMON_TYPE_DRIVER = @SYSTEMD_DAEMON_TYPE_DRIVER@ SYSTEMD_DAEMON_TYPE_UPSD = @SYSTEMD_DAEMON_TYPE_UPSD@ SYSTEMD_DAEMON_TYPE_UPSMON = @SYSTEMD_DAEMON_TYPE_UPSMON@ SYSTEMD_DAEMON_WATCHDOG_DRIVER = @SYSTEMD_DAEMON_WATCHDOG_DRIVER@ SYSTEMD_DAEMON_WATCHDOG_UPSD = @SYSTEMD_DAEMON_WATCHDOG_UPSD@ SYSTEMD_DAEMON_WATCHDOG_UPSMON = @SYSTEMD_DAEMON_WATCHDOG_UPSMON@ SYSTEMD_TMPFILES_PROGRAM = @SYSTEMD_TMPFILES_PROGRAM@ TREE_VERSION = @TREE_VERSION@ VALGRIND = @VALGRIND@ VERSION = @VERSION@ WINDMC = @WINDMC@ WINDRES = @WINDRES@ WORDS_BIGENDIAN = @WORDS_BIGENDIAN@ XMLLINT = @XMLLINT@ XSLTPROC = @XSLTPROC@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_AR = @ac_ct_AR@ ac_ct_CC = @ac_ct_CC@ ac_ct_CXX = @ac_ct_CXX@ ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__tar = @am__tar@ am__untar = @am__untar@ auglensdir = @auglensdir@ bindir = @bindir@ build = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ cgiexecdir = @cgiexecdir@ datadir = @datadir@ datarootdir = @datarootdir@ devddir = @devddir@ docdir = @docdir@ driverexecdir = @driverexecdir@ dummy_PKG_CONFIG = @dummy_PKG_CONFIG@ dummy_PKG_CONFIG_CFLAGS = @dummy_PKG_CONFIG_CFLAGS@ dummy_PKG_CONFIG_LIBS = @dummy_PKG_CONFIG_LIBS@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ hotplugdir = @hotplugdir@ htmldir = @htmldir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libdir = @libdir@ libexecdir = @libexecdir@ localedir = @localedir@ localstatedir = @localstatedir@ mandir = @mandir@ mkdir_p = @mkdir_p@ now = @now@ nut_with_nut_monitor = @nut_with_nut_monitor@ nut_with_nut_monitor_desktop = @nut_with_nut_monitor_desktop@ nut_with_nut_monitor_dir = @nut_with_nut_monitor_dir@ nut_with_nut_monitor_py2gtk2 = @nut_with_nut_monitor_py2gtk2@ nut_with_nut_monitor_py3qt5 = @nut_with_nut_monitor_py3qt5@ nut_with_pynut = @nut_with_pynut@ nut_with_pynut_py = @nut_with_pynut_py@ nut_with_pynut_py2 = @nut_with_pynut_py2@ nut_with_pynut_py3 = @nut_with_pynut_py3@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ pkgconfigdir = @pkgconfigdir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ runstatedir = @runstatedir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ sysconfdir = @sysconfdir@ systemdshutdowndir = @systemdshutdowndir@ systemdsystemunitdir = @systemdsystemunitdir@ systemdtmpfilesdir = @systemdtmpfilesdir@ target = @target@ target_alias = @target_alias@ target_cpu = @target_cpu@ target_os = @target_os@ target_vendor = @target_vendor@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ udevdir = @udevdir@ @WITH_DEVD_TRUE@devdconfdir = $(devddir) @WITH_DEVD_TRUE@devdconf_DATA = $(am__append_1) # Part of dist tarball, regardless of use for current build: EXTRA_DIST = README nut-usb.conf.in # we should never remove this one, apart from a distclean-check # or stronger... # Generated by autogen.sh and needed to run the configure script # (technically, generated by tools/nut-usbinfo.pl script among # GENERATED_USB_OS_FILES): MAINTAINERCLEANFILES = Makefile.in .dirstamp nut-usb.conf.in \ nut-usb.conf.in.AUTOGEN_WITHOUT # Generated by configure script: DISTCLEANFILES = nut-usb.conf all: all-am .SUFFIXES: $(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu scripts/devd/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --gnu scripts/devd/Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): nut-usb.conf: $(top_builddir)/config.status $(srcdir)/nut-usb.conf.in cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ mostlyclean-libtool: -rm -f *.lo clean-libtool: -rm -rf .libs _libs install-devdconfDATA: $(devdconf_DATA) @$(NORMAL_INSTALL) @list='$(devdconf_DATA)'; test -n "$(devdconfdir)" || list=; \ if test -n "$$list"; then \ echo " $(MKDIR_P) '$(DESTDIR)$(devdconfdir)'"; \ $(MKDIR_P) "$(DESTDIR)$(devdconfdir)" || exit 1; \ fi; \ for p in $$list; do \ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ echo "$$d$$p"; \ done | $(am__base_list) | \ while read files; do \ echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(devdconfdir)'"; \ $(INSTALL_DATA) $$files "$(DESTDIR)$(devdconfdir)" || exit $$?; \ done uninstall-devdconfDATA: @$(NORMAL_UNINSTALL) @list='$(devdconf_DATA)'; test -n "$(devdconfdir)" || list=; \ files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ dir='$(DESTDIR)$(devdconfdir)'; $(am__uninstall_files_from_dir) tags TAGS: ctags CTAGS: cscope cscopelist: distdir: $(BUILT_SOURCES) $(MAKE) $(AM_MAKEFLAGS) distdir-am distdir-am: $(DISTFILES) @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ dist_files=`for file in $$list; do echo $$file; done | \ sed -e "s|^$$srcdirstrip/||;t" \ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ case $$dist_files in \ */*) $(MKDIR_P) `echo "$$dist_files" | \ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ sort -u` ;; \ esac; \ for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d "$(distdir)/$$file"; then \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ else \ test -f "$(distdir)/$$file" \ || cp -p $$d/$$file "$(distdir)/$$file" \ || exit 1; \ fi; \ done check-am: all-am check: check-am all-am: Makefile $(DATA) installdirs: for dir in "$(DESTDIR)$(devdconfdir)"; do \ test -z "$$dir" || $(MKDIR_P) "$$dir"; \ done install: install-am install-exec: install-exec-am install-data: install-data-am uninstall: uninstall-am install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-am install-strip: if test -z '$(STRIP)'; then \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ install; \ else \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ fi mostlyclean-generic: clean-generic: distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) -test -z "$(DISTCLEANFILES)" || rm -f $(DISTCLEANFILES) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." -test -z "$(MAINTAINERCLEANFILES)" || rm -f $(MAINTAINERCLEANFILES) clean: clean-am clean-am: clean-generic clean-libtool mostlyclean-am distclean: distclean-am -rm -f Makefile distclean-am: clean-am distclean-generic dvi: dvi-am dvi-am: html: html-am html-am: info: info-am info-am: install-data-am: install-devdconfDATA install-dvi: install-dvi-am install-dvi-am: install-exec-am: install-html: install-html-am install-html-am: install-info: install-info-am install-info-am: install-man: install-pdf: install-pdf-am install-pdf-am: install-ps: install-ps-am install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-am -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-am mostlyclean-am: mostlyclean-generic mostlyclean-libtool pdf: pdf-am pdf-am: ps: ps-am ps-am: uninstall-am: uninstall-devdconfDATA .MAKE: install-am install-strip .PHONY: all all-am check check-am clean clean-generic clean-libtool \ cscopelist-am ctags-am distclean distclean-generic \ distclean-libtool distdir dvi dvi-am html html-am info info-am \ install install-am install-data install-data-am \ install-devdconfDATA install-dvi install-dvi-am install-exec \ install-exec-am install-html install-html-am install-info \ install-info-am install-man install-pdf install-pdf-am \ install-ps install-ps-am install-strip installcheck \ installcheck-am installdirs maintainer-clean \ maintainer-clean-generic mostlyclean mostlyclean-generic \ mostlyclean-libtool pdf pdf-am ps ps-am tags-am uninstall \ uninstall-am uninstall-devdconfDATA .PRECIOUS: Makefile # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: nut-2.8.1/scripts/devd/nut-usb.conf.in0000644000175000017500000007704214520277776014566 00000000000000# This file is generated and installed by the Network UPS Tools package. # Homepage: https://www.networkupstools.org/ # SNR-UPS-LID-XXXX UPSes - nutdrv_qx notify 100 { match "system" "USB"; match "subsystem" "DEVICE"; match "type" "ATTACH"; match "vendor" "0x0001"; match "product" "0x0000"; action "chgrp @RUN_AS_GROUP@ /dev/$cdev; chmod g+rw /dev/$cdev"; }; # Hewlett Packard # e.g. ? - usbhid-ups notify 100 { match "system" "USB"; match "subsystem" "DEVICE"; match "type" "ATTACH"; match "vendor" "0x03f0"; match "product" "0x0001"; action "chgrp @RUN_AS_GROUP@ /dev/$cdev; chmod g+rw /dev/$cdev"; }; # T500 - bcmxcp_usb notify 100 { match "system" "USB"; match "subsystem" "DEVICE"; match "type" "ATTACH"; match "vendor" "0x03f0"; match "product" "0x1f01"; action "chgrp @RUN_AS_GROUP@ /dev/$cdev; chmod g+rw /dev/$cdev"; }; # T750 - bcmxcp_usb notify 100 { match "system" "USB"; match "subsystem" "DEVICE"; match "type" "ATTACH"; match "vendor" "0x03f0"; match "product" "0x1f02"; action "chgrp @RUN_AS_GROUP@ /dev/$cdev; chmod g+rw /dev/$cdev"; }; # HP T750 INTL - usbhid-ups notify 100 { match "system" "USB"; match "subsystem" "DEVICE"; match "type" "ATTACH"; match "vendor" "0x03f0"; match "product" "0x1f06"; action "chgrp @RUN_AS_GROUP@ /dev/$cdev; chmod g+rw /dev/$cdev"; }; # HP T1000 INTL - usbhid-ups notify 100 { match "system" "USB"; match "subsystem" "DEVICE"; match "type" "ATTACH"; match "vendor" "0x03f0"; match "product" "0x1f08"; action "chgrp @RUN_AS_GROUP@ /dev/$cdev; chmod g+rw /dev/$cdev"; }; # HP T1500 INTL - usbhid-ups notify 100 { match "system" "USB"; match "subsystem" "DEVICE"; match "type" "ATTACH"; match "vendor" "0x03f0"; match "product" "0x1f09"; action "chgrp @RUN_AS_GROUP@ /dev/$cdev; chmod g+rw /dev/$cdev"; }; # HP R/T 2200 INTL (like SMART2200RMXL2U) - usbhid-ups notify 100 { match "system" "USB"; match "subsystem" "DEVICE"; match "type" "ATTACH"; match "vendor" "0x03f0"; match "product" "0x1f0a"; action "chgrp @RUN_AS_GROUP@ /dev/$cdev; chmod g+rw /dev/$cdev"; }; # HP R1500 G2 and G3 INTL - usbhid-ups notify 100 { match "system" "USB"; match "subsystem" "DEVICE"; match "type" "ATTACH"; match "vendor" "0x03f0"; match "product" "0x1fe0"; action "chgrp @RUN_AS_GROUP@ /dev/$cdev; chmod g+rw /dev/$cdev"; }; # HP T750 G2 - usbhid-ups notify 100 { match "system" "USB"; match "subsystem" "DEVICE"; match "type" "ATTACH"; match "vendor" "0x03f0"; match "product" "0x1fe1"; action "chgrp @RUN_AS_GROUP@ /dev/$cdev; chmod g+rw /dev/$cdev"; }; # e.g. ? - usbhid-ups notify 100 { match "system" "USB"; match "subsystem" "DEVICE"; match "type" "ATTACH"; match "vendor" "0x03f0"; match "product" "0x1fe2"; action "chgrp @RUN_AS_GROUP@ /dev/$cdev; chmod g+rw /dev/$cdev"; }; # HP T1500 G3 - usbhid-ups notify 100 { match "system" "USB"; match "subsystem" "DEVICE"; match "type" "ATTACH"; match "vendor" "0x03f0"; match "product" "0x1fe3"; action "chgrp @RUN_AS_GROUP@ /dev/$cdev; chmod g+rw /dev/$cdev"; }; # R/T3000 - usbhid-ups notify 100 { match "system" "USB"; match "subsystem" "DEVICE"; match "type" "ATTACH"; match "vendor" "0x03f0"; match "product" "0x1fe5"; action "chgrp @RUN_AS_GROUP@ /dev/$cdev; chmod g+rw /dev/$cdev"; }; # R/T3000 - usbhid-ups notify 100 { match "system" "USB"; match "subsystem" "DEVICE"; match "type" "ATTACH"; match "vendor" "0x03f0"; match "product" "0x1fe6"; action "chgrp @RUN_AS_GROUP@ /dev/$cdev; chmod g+rw /dev/$cdev"; }; # various models - usbhid-ups notify 100 { match "system" "USB"; match "subsystem" "DEVICE"; match "type" "ATTACH"; match "vendor" "0x03f0"; match "product" "0x1fe7"; action "chgrp @RUN_AS_GROUP@ /dev/$cdev; chmod g+rw /dev/$cdev"; }; # various models - usbhid-ups notify 100 { match "system" "USB"; match "subsystem" "DEVICE"; match "type" "ATTACH"; match "vendor" "0x03f0"; match "product" "0x1fe8"; action "chgrp @RUN_AS_GROUP@ /dev/$cdev; chmod g+rw /dev/$cdev"; }; # Eaton # various models - usbhid-ups notify 100 { match "system" "USB"; match "subsystem" "DEVICE"; match "type" "ATTACH"; match "vendor" "0x0463"; match "product" "0x0001"; action "chgrp @RUN_AS_GROUP@ /dev/$cdev; chmod g+rw /dev/$cdev"; }; # various models - usbhid-ups notify 100 { match "system" "USB"; match "subsystem" "DEVICE"; match "type" "ATTACH"; match "vendor" "0x0463"; match "product" "0xffff"; action "chgrp @RUN_AS_GROUP@ /dev/$cdev; chmod g+rw /dev/$cdev"; }; # Dell # various models - usbhid-ups notify 100 { match "system" "USB"; match "subsystem" "DEVICE"; match "type" "ATTACH"; match "vendor" "0x047c"; match "product" "0xffff"; action "chgrp @RUN_AS_GROUP@ /dev/$cdev; chmod g+rw /dev/$cdev"; }; # ST Microelectronics # TS Shara UPSes; vendor ID 0x0483 is from ST Microelectronics - with product IDs delegated to different OEMs - nutdrv_qx notify 100 { match "system" "USB"; match "subsystem" "DEVICE"; match "type" "ATTACH"; match "vendor" "0x0483"; match "product" "0x0035"; action "chgrp @RUN_AS_GROUP@ /dev/$cdev; chmod g+rw /dev/$cdev"; }; # USB IDs device table - usbhid-ups notify 100 { match "system" "USB"; match "subsystem" "DEVICE"; match "type" "ATTACH"; match "vendor" "0x0483"; match "product" "0xa113"; action "chgrp @RUN_AS_GROUP@ /dev/$cdev; chmod g+rw /dev/$cdev"; }; # IBM # 6000 VA LCD 4U Rack UPS; 5396-1Kx - usbhid-ups notify 100 { match "system" "USB"; match "subsystem" "DEVICE"; match "type" "ATTACH"; match "vendor" "0x04b3"; match "product" "0x0001"; action "chgrp @RUN_AS_GROUP@ /dev/$cdev; chmod g+rw /dev/$cdev"; }; # Riello (Cypress Semiconductor Corp.) # various models - riello_usb notify 100 { match "system" "USB"; match "subsystem" "DEVICE"; match "type" "ATTACH"; match "vendor" "0x04b4"; match "product" "0x5500"; action "chgrp @RUN_AS_GROUP@ /dev/$cdev; chmod g+rw /dev/$cdev"; }; # Minibox # openUPS Intelligent UPS (minimum required firmware 1.4) - usbhid-ups notify 100 { match "system" "USB"; match "subsystem" "DEVICE"; match "type" "ATTACH"; match "vendor" "0x04d8"; match "product" "0xd004"; action "chgrp @RUN_AS_GROUP@ /dev/$cdev; chmod g+rw /dev/$cdev"; }; # openUPS Intelligent UPS (minimum required firmware 1.4) - usbhid-ups notify 100 { match "system" "USB"; match "subsystem" "DEVICE"; match "type" "ATTACH"; match "vendor" "0x04d8"; match "product" "0xd005"; action "chgrp @RUN_AS_GROUP@ /dev/$cdev; chmod g+rw /dev/$cdev"; }; # Belkin # F6H375-USB - usbhid-ups notify 100 { match "system" "USB"; match "subsystem" "DEVICE"; match "type" "ATTACH"; match "vendor" "0x050d"; match "product" "0x0375"; action "chgrp @RUN_AS_GROUP@ /dev/$cdev; chmod g+rw /dev/$cdev"; }; # F6C550-AVR - usbhid-ups notify 100 { match "system" "USB"; match "subsystem" "DEVICE"; match "type" "ATTACH"; match "vendor" "0x050d"; match "product" "0x0551"; action "chgrp @RUN_AS_GROUP@ /dev/$cdev; chmod g+rw /dev/$cdev"; }; # F6C1250-TW-RK - usbhid-ups notify 100 { match "system" "USB"; match "subsystem" "DEVICE"; match "type" "ATTACH"; match "vendor" "0x050d"; match "product" "0x0750"; action "chgrp @RUN_AS_GROUP@ /dev/$cdev; chmod g+rw /dev/$cdev"; }; # F6C1500-TW-RK - usbhid-ups notify 100 { match "system" "USB"; match "subsystem" "DEVICE"; match "type" "ATTACH"; match "vendor" "0x050d"; match "product" "0x0751"; action "chgrp @RUN_AS_GROUP@ /dev/$cdev; chmod g+rw /dev/$cdev"; }; # F6C900-UNV - usbhid-ups notify 100 { match "system" "USB"; match "subsystem" "DEVICE"; match "type" "ATTACH"; match "vendor" "0x050d"; match "product" "0x0900"; action "chgrp @RUN_AS_GROUP@ /dev/$cdev; chmod g+rw /dev/$cdev"; }; # F6C100-UNV - usbhid-ups notify 100 { match "system" "USB"; match "subsystem" "DEVICE"; match "type" "ATTACH"; match "vendor" "0x050d"; match "product" "0x0910"; action "chgrp @RUN_AS_GROUP@ /dev/$cdev; chmod g+rw /dev/$cdev"; }; # F6C120-UNV - usbhid-ups notify 100 { match "system" "USB"; match "subsystem" "DEVICE"; match "type" "ATTACH"; match "vendor" "0x050d"; match "product" "0x0912"; action "chgrp @RUN_AS_GROUP@ /dev/$cdev; chmod g+rw /dev/$cdev"; }; # F6C800-UNV - usbhid-ups notify 100 { match "system" "USB"; match "subsystem" "DEVICE"; match "type" "ATTACH"; match "vendor" "0x050d"; match "product" "0x0980"; action "chgrp @RUN_AS_GROUP@ /dev/$cdev; chmod g+rw /dev/$cdev"; }; # Regulator PRO-USB - usbhid-ups notify 100 { match "system" "USB"; match "subsystem" "DEVICE"; match "type" "ATTACH"; match "vendor" "0x050d"; match "product" "0x0f51"; action "chgrp @RUN_AS_GROUP@ /dev/$cdev; chmod g+rw /dev/$cdev"; }; # F6C1100-UNV, F6C1200-UNV - usbhid-ups notify 100 { match "system" "USB"; match "subsystem" "DEVICE"; match "type" "ATTACH"; match "vendor" "0x050d"; match "product" "0x1100"; action "chgrp @RUN_AS_GROUP@ /dev/$cdev; chmod g+rw /dev/$cdev"; }; # APC # APC AP9584 Serial->USB kit - usbhid-ups notify 100 { match "system" "USB"; match "subsystem" "DEVICE"; match "type" "ATTACH"; match "vendor" "0x051d"; match "product" "0x0000"; action "chgrp @RUN_AS_GROUP@ /dev/$cdev; chmod g+rw /dev/$cdev"; }; # various models - usbhid-ups notify 100 { match "system" "USB"; match "subsystem" "DEVICE"; match "type" "ATTACH"; match "vendor" "0x051d"; match "product" "0x0002"; action "chgrp @RUN_AS_GROUP@ /dev/$cdev; chmod g+rw /dev/$cdev"; }; # USB IDs device table - apc_modbus notify 100 { match "system" "USB"; match "subsystem" "DEVICE"; match "type" "ATTACH"; match "vendor" "0x051d"; match "product" "0x0003"; action "chgrp @RUN_AS_GROUP@ /dev/$cdev; chmod g+rw /dev/$cdev"; }; # various 5G models - usbhid-ups notify 100 { match "system" "USB"; match "subsystem" "DEVICE"; match "type" "ATTACH"; match "vendor" "0x051d"; match "product" "0x0004"; action "chgrp @RUN_AS_GROUP@ /dev/$cdev; chmod g+rw /dev/$cdev"; }; # Powerware # various models - bcmxcp_usb notify 100 { match "system" "USB"; match "subsystem" "DEVICE"; match "type" "ATTACH"; match "vendor" "0x0592"; match "product" "0x0002"; action "chgrp @RUN_AS_GROUP@ /dev/$cdev; chmod g+rw /dev/$cdev"; }; # PW 9140 - usbhid-ups notify 100 { match "system" "USB"; match "subsystem" "DEVICE"; match "type" "ATTACH"; match "vendor" "0x0592"; match "product" "0x0004"; action "chgrp @RUN_AS_GROUP@ /dev/$cdev; chmod g+rw /dev/$cdev"; }; # Agiler UPS - nutdrv_qx notify 100 { match "system" "USB"; match "subsystem" "DEVICE"; match "type" "ATTACH"; match "vendor" "0x05b8"; match "product" "0x0000"; action "chgrp @RUN_AS_GROUP@ /dev/$cdev; chmod g+rw /dev/$cdev"; }; # Delta UPS # Delta UPS Amplon R Series, Single Phase UPS, 1/2/3 kVA - usbhid-ups notify 100 { match "system" "USB"; match "subsystem" "DEVICE"; match "type" "ATTACH"; match "vendor" "0x05dd"; match "product" "0x041b"; action "chgrp @RUN_AS_GROUP@ /dev/$cdev; chmod g+rw /dev/$cdev"; }; # Delta/Minuteman Enterprise Plus E1500RM2U - usbhid-ups notify 100 { match "system" "USB"; match "subsystem" "DEVICE"; match "type" "ATTACH"; match "vendor" "0x05dd"; match "product" "0xa011"; action "chgrp @RUN_AS_GROUP@ /dev/$cdev; chmod g+rw /dev/$cdev"; }; # Delta/Minuteman PRO1500RT2U - usbhid-ups notify 100 { match "system" "USB"; match "subsystem" "DEVICE"; match "type" "ATTACH"; match "vendor" "0x05dd"; match "product" "0xa0a0"; action "chgrp @RUN_AS_GROUP@ /dev/$cdev; chmod g+rw /dev/$cdev"; }; # Belkin F6C1200-UNV/Voltronic Power UPSes - nutdrv_qx notify 100 { match "system" "USB"; match "subsystem" "DEVICE"; match "type" "ATTACH"; match "vendor" "0x0665"; match "product" "0x5161"; action "chgrp @RUN_AS_GROUP@ /dev/$cdev; chmod g+rw /dev/$cdev"; }; # Phoenixtec Power Co., Ltd # Online Yunto YQ450 - nutdrv_qx notify 100 { match "system" "USB"; match "subsystem" "DEVICE"; match "type" "ATTACH"; match "vendor" "0x06da"; match "product" "0x0002"; action "chgrp @RUN_AS_GROUP@ /dev/$cdev; chmod g+rw /dev/$cdev"; }; # Mustek Powermust - nutdrv_qx notify 100 { match "system" "USB"; match "subsystem" "DEVICE"; match "type" "ATTACH"; match "vendor" "0x06da"; match "product" "0x0003"; action "chgrp @RUN_AS_GROUP@ /dev/$cdev; chmod g+rw /dev/$cdev"; }; # Phoenixtec Innova 3/1 T - nutdrv_qx notify 100 { match "system" "USB"; match "subsystem" "DEVICE"; match "type" "ATTACH"; match "vendor" "0x06da"; match "product" "0x0004"; action "chgrp @RUN_AS_GROUP@ /dev/$cdev; chmod g+rw /dev/$cdev"; }; # Phoenixtec Innova RT - nutdrv_qx notify 100 { match "system" "USB"; match "subsystem" "DEVICE"; match "type" "ATTACH"; match "vendor" "0x06da"; match "product" "0x0005"; action "chgrp @RUN_AS_GROUP@ /dev/$cdev; chmod g+rw /dev/$cdev"; }; # Phoenixtec Innova T - nutdrv_qx notify 100 { match "system" "USB"; match "subsystem" "DEVICE"; match "type" "ATTACH"; match "vendor" "0x06da"; match "product" "0x0201"; action "chgrp @RUN_AS_GROUP@ /dev/$cdev; chmod g+rw /dev/$cdev"; }; # Online Zinto A - nutdrv_qx notify 100 { match "system" "USB"; match "subsystem" "DEVICE"; match "type" "ATTACH"; match "vendor" "0x06da"; match "product" "0x0601"; action "chgrp @RUN_AS_GROUP@ /dev/$cdev; chmod g+rw /dev/$cdev"; }; # PROTECT B / NAS - usbhid-ups notify 100 { match "system" "USB"; match "subsystem" "DEVICE"; match "type" "ATTACH"; match "vendor" "0x06da"; match "product" "0xffff"; action "chgrp @RUN_AS_GROUP@ /dev/$cdev; chmod g+rw /dev/$cdev"; }; # iDowell # iDowell - usbhid-ups notify 100 { match "system" "USB"; match "subsystem" "DEVICE"; match "type" "ATTACH"; match "vendor" "0x075d"; match "product" "0x0300"; action "chgrp @RUN_AS_GROUP@ /dev/$cdev; chmod g+rw /dev/$cdev"; }; # Cyber Power Systems # 900AVR/BC900D - usbhid-ups notify 100 { match "system" "USB"; match "subsystem" "DEVICE"; match "type" "ATTACH"; match "vendor" "0x0764"; match "product" "0x0005"; action "chgrp @RUN_AS_GROUP@ /dev/$cdev; chmod g+rw /dev/$cdev"; }; # Dynex DX-800U?, CP1200AVR/BC1200D, CP825AVR-G, CP1000AVRLCD, CP1000PFCLCD, CP1500C, CP550HG, etc. - usbhid-ups notify 100 { match "system" "USB"; match "subsystem" "DEVICE"; match "type" "ATTACH"; match "vendor" "0x0764"; match "product" "0x0501"; action "chgrp @RUN_AS_GROUP@ /dev/$cdev; chmod g+rw /dev/$cdev"; }; # OR2200LCDRM2U, OR700LCDRM1U, PR6000LCDRTXL5U - usbhid-ups notify 100 { match "system" "USB"; match "subsystem" "DEVICE"; match "type" "ATTACH"; match "vendor" "0x0764"; match "product" "0x0601"; action "chgrp @RUN_AS_GROUP@ /dev/$cdev; chmod g+rw /dev/$cdev"; }; # Sweex 1000VA - richcomm_usb notify 100 { match "system" "USB"; match "subsystem" "DEVICE"; match "type" "ATTACH"; match "vendor" "0x0925"; match "product" "0x1234"; action "chgrp @RUN_AS_GROUP@ /dev/$cdev; chmod g+rw /dev/$cdev"; }; # TrippLite # e.g. OMNIVS1000, SMART550USB, ... - tripplite_usb notify 100 { match "system" "USB"; match "subsystem" "DEVICE"; match "type" "ATTACH"; match "vendor" "0x09ae"; match "product" "0x0001"; action "chgrp @RUN_AS_GROUP@ /dev/$cdev; chmod g+rw /dev/$cdev"; }; # e.g. TrippLite AVR550U - usbhid-ups notify 100 { match "system" "USB"; match "subsystem" "DEVICE"; match "type" "ATTACH"; match "vendor" "0x09ae"; match "product" "0x1003"; action "chgrp @RUN_AS_GROUP@ /dev/$cdev; chmod g+rw /dev/$cdev"; }; # e.g. TrippLite AVR750U - usbhid-ups notify 100 { match "system" "USB"; match "subsystem" "DEVICE"; match "type" "ATTACH"; match "vendor" "0x09ae"; match "product" "0x1007"; action "chgrp @RUN_AS_GROUP@ /dev/$cdev; chmod g+rw /dev/$cdev"; }; # e.g. TrippLite ECO550UPS - usbhid-ups notify 100 { match "system" "USB"; match "subsystem" "DEVICE"; match "type" "ATTACH"; match "vendor" "0x09ae"; match "product" "0x1008"; action "chgrp @RUN_AS_GROUP@ /dev/$cdev; chmod g+rw /dev/$cdev"; }; # e.g. TrippLite ECO550UPS - usbhid-ups notify 100 { match "system" "USB"; match "subsystem" "DEVICE"; match "type" "ATTACH"; match "vendor" "0x09ae"; match "product" "0x1009"; action "chgrp @RUN_AS_GROUP@ /dev/$cdev; chmod g+rw /dev/$cdev"; }; # e.g. TrippLite ECO550UPS - usbhid-ups notify 100 { match "system" "USB"; match "subsystem" "DEVICE"; match "type" "ATTACH"; match "vendor" "0x09ae"; match "product" "0x1010"; action "chgrp @RUN_AS_GROUP@ /dev/$cdev; chmod g+rw /dev/$cdev"; }; # e.g. TrippLite SU3000LCD2UHV - usbhid-ups notify 100 { match "system" "USB"; match "subsystem" "DEVICE"; match "type" "ATTACH"; match "vendor" "0x09ae"; match "product" "0x1330"; action "chgrp @RUN_AS_GROUP@ /dev/$cdev; chmod g+rw /dev/$cdev"; }; # e.g. TrippLite OMNI1000LCD - usbhid-ups notify 100 { match "system" "USB"; match "subsystem" "DEVICE"; match "type" "ATTACH"; match "vendor" "0x09ae"; match "product" "0x2005"; action "chgrp @RUN_AS_GROUP@ /dev/$cdev; chmod g+rw /dev/$cdev"; }; # e.g. TrippLite OMNI900LCD - usbhid-ups notify 100 { match "system" "USB"; match "subsystem" "DEVICE"; match "type" "ATTACH"; match "vendor" "0x09ae"; match "product" "0x2007"; action "chgrp @RUN_AS_GROUP@ /dev/$cdev; chmod g+rw /dev/$cdev"; }; # e.g. ? - usbhid-ups notify 100 { match "system" "USB"; match "subsystem" "DEVICE"; match "type" "ATTACH"; match "vendor" "0x09ae"; match "product" "0x2008"; action "chgrp @RUN_AS_GROUP@ /dev/$cdev; chmod g+rw /dev/$cdev"; }; # e.g. TrippLite Smart1000LCD - usbhid-ups notify 100 { match "system" "USB"; match "subsystem" "DEVICE"; match "type" "ATTACH"; match "vendor" "0x09ae"; match "product" "0x2009"; action "chgrp @RUN_AS_GROUP@ /dev/$cdev; chmod g+rw /dev/$cdev"; }; # e.g. ? - usbhid-ups notify 100 { match "system" "USB"; match "subsystem" "DEVICE"; match "type" "ATTACH"; match "vendor" "0x09ae"; match "product" "0x2010"; action "chgrp @RUN_AS_GROUP@ /dev/$cdev; chmod g+rw /dev/$cdev"; }; # e.g. ? - usbhid-ups notify 100 { match "system" "USB"; match "subsystem" "DEVICE"; match "type" "ATTACH"; match "vendor" "0x09ae"; match "product" "0x2011"; action "chgrp @RUN_AS_GROUP@ /dev/$cdev; chmod g+rw /dev/$cdev"; }; # e.g. ? - usbhid-ups notify 100 { match "system" "USB"; match "subsystem" "DEVICE"; match "type" "ATTACH"; match "vendor" "0x09ae"; match "product" "0x2012"; action "chgrp @RUN_AS_GROUP@ /dev/$cdev; chmod g+rw /dev/$cdev"; }; # e.g. ? - usbhid-ups notify 100 { match "system" "USB"; match "subsystem" "DEVICE"; match "type" "ATTACH"; match "vendor" "0x09ae"; match "product" "0x2013"; action "chgrp @RUN_AS_GROUP@ /dev/$cdev; chmod g+rw /dev/$cdev"; }; # e.g. ? - usbhid-ups notify 100 { match "system" "USB"; match "subsystem" "DEVICE"; match "type" "ATTACH"; match "vendor" "0x09ae"; match "product" "0x2014"; action "chgrp @RUN_AS_GROUP@ /dev/$cdev; chmod g+rw /dev/$cdev"; }; # e.g. ? - usbhid-ups notify 100 { match "system" "USB"; match "subsystem" "DEVICE"; match "type" "ATTACH"; match "vendor" "0x09ae"; match "product" "0x3008"; action "chgrp @RUN_AS_GROUP@ /dev/$cdev; chmod g+rw /dev/$cdev"; }; # e.g. ? - usbhid-ups notify 100 { match "system" "USB"; match "subsystem" "DEVICE"; match "type" "ATTACH"; match "vendor" "0x09ae"; match "product" "0x3009"; action "chgrp @RUN_AS_GROUP@ /dev/$cdev; chmod g+rw /dev/$cdev"; }; # e.g. ? - usbhid-ups notify 100 { match "system" "USB"; match "subsystem" "DEVICE"; match "type" "ATTACH"; match "vendor" "0x09ae"; match "product" "0x3010"; action "chgrp @RUN_AS_GROUP@ /dev/$cdev; chmod g+rw /dev/$cdev"; }; # e.g. ? - usbhid-ups notify 100 { match "system" "USB"; match "subsystem" "DEVICE"; match "type" "ATTACH"; match "vendor" "0x09ae"; match "product" "0x3011"; action "chgrp @RUN_AS_GROUP@ /dev/$cdev; chmod g+rw /dev/$cdev"; }; # e.g. TrippLite smart2200RMXL2U - usbhid-ups notify 100 { match "system" "USB"; match "subsystem" "DEVICE"; match "type" "ATTACH"; match "vendor" "0x09ae"; match "product" "0x3012"; action "chgrp @RUN_AS_GROUP@ /dev/$cdev; chmod g+rw /dev/$cdev"; }; # e.g. ? - usbhid-ups notify 100 { match "system" "USB"; match "subsystem" "DEVICE"; match "type" "ATTACH"; match "vendor" "0x09ae"; match "product" "0x3013"; action "chgrp @RUN_AS_GROUP@ /dev/$cdev; chmod g+rw /dev/$cdev"; }; # e.g. ? - usbhid-ups notify 100 { match "system" "USB"; match "subsystem" "DEVICE"; match "type" "ATTACH"; match "vendor" "0x09ae"; match "product" "0x3014"; action "chgrp @RUN_AS_GROUP@ /dev/$cdev; chmod g+rw /dev/$cdev"; }; # e.g. ? - usbhid-ups notify 100 { match "system" "USB"; match "subsystem" "DEVICE"; match "type" "ATTACH"; match "vendor" "0x09ae"; match "product" "0x3015"; action "chgrp @RUN_AS_GROUP@ /dev/$cdev; chmod g+rw /dev/$cdev"; }; # e.g. TrippLite Smart1500LCD (newer unit) - usbhid-ups notify 100 { match "system" "USB"; match "subsystem" "DEVICE"; match "type" "ATTACH"; match "vendor" "0x09ae"; match "product" "0x3016"; action "chgrp @RUN_AS_GROUP@ /dev/$cdev; chmod g+rw /dev/$cdev"; }; # e.g. TrippLite AVR750U (newer unit) - usbhid-ups notify 100 { match "system" "USB"; match "subsystem" "DEVICE"; match "type" "ATTACH"; match "vendor" "0x09ae"; match "product" "0x3024"; action "chgrp @RUN_AS_GROUP@ /dev/$cdev; chmod g+rw /dev/$cdev"; }; # e.g. TrippLite SmartOnline SU1500RTXL2UA (older unit?) - usbhid-ups notify 100 { match "system" "USB"; match "subsystem" "DEVICE"; match "type" "ATTACH"; match "vendor" "0x09ae"; match "product" "0x4001"; action "chgrp @RUN_AS_GROUP@ /dev/$cdev; chmod g+rw /dev/$cdev"; }; # e.g. TrippLite SmartOnline SU6000RT4U? - usbhid-ups notify 100 { match "system" "USB"; match "subsystem" "DEVICE"; match "type" "ATTACH"; match "vendor" "0x09ae"; match "product" "0x4002"; action "chgrp @RUN_AS_GROUP@ /dev/$cdev; chmod g+rw /dev/$cdev"; }; # e.g. TrippLite SmartOnline SU1500RTXL2ua - usbhid-ups notify 100 { match "system" "USB"; match "subsystem" "DEVICE"; match "type" "ATTACH"; match "vendor" "0x09ae"; match "product" "0x4003"; action "chgrp @RUN_AS_GROUP@ /dev/$cdev; chmod g+rw /dev/$cdev"; }; # e.g. TrippLite SmartOnline SU1000XLA - usbhid-ups notify 100 { match "system" "USB"; match "subsystem" "DEVICE"; match "type" "ATTACH"; match "vendor" "0x09ae"; match "product" "0x4004"; action "chgrp @RUN_AS_GROUP@ /dev/$cdev; chmod g+rw /dev/$cdev"; }; # e.g. ? - usbhid-ups notify 100 { match "system" "USB"; match "subsystem" "DEVICE"; match "type" "ATTACH"; match "vendor" "0x09ae"; match "product" "0x4005"; action "chgrp @RUN_AS_GROUP@ /dev/$cdev; chmod g+rw /dev/$cdev"; }; # e.g. ? - usbhid-ups notify 100 { match "system" "USB"; match "subsystem" "DEVICE"; match "type" "ATTACH"; match "vendor" "0x09ae"; match "product" "0x4006"; action "chgrp @RUN_AS_GROUP@ /dev/$cdev; chmod g+rw /dev/$cdev"; }; # e.g. ? - usbhid-ups notify 100 { match "system" "USB"; match "subsystem" "DEVICE"; match "type" "ATTACH"; match "vendor" "0x09ae"; match "product" "0x4007"; action "chgrp @RUN_AS_GROUP@ /dev/$cdev; chmod g+rw /dev/$cdev"; }; # e.g. ? - usbhid-ups notify 100 { match "system" "USB"; match "subsystem" "DEVICE"; match "type" "ATTACH"; match "vendor" "0x09ae"; match "product" "0x4008"; action "chgrp @RUN_AS_GROUP@ /dev/$cdev; chmod g+rw /dev/$cdev"; }; # PowerCOM # PowerCOM Vanguard and BNT-xxxAP - usbhid-ups notify 100 { match "system" "USB"; match "subsystem" "DEVICE"; match "type" "ATTACH"; match "vendor" "0x0d9f"; match "product" "0x0001"; action "chgrp @RUN_AS_GROUP@ /dev/$cdev; chmod g+rw /dev/$cdev"; }; # PowerCOM Vanguard and BNT-xxxAP - usbhid-ups notify 100 { match "system" "USB"; match "subsystem" "DEVICE"; match "type" "ATTACH"; match "vendor" "0x0d9f"; match "product" "0x0004"; action "chgrp @RUN_AS_GROUP@ /dev/$cdev; chmod g+rw /dev/$cdev"; }; # PowerCOM IMP - IMPERIAL Series - usbhid-ups notify 100 { match "system" "USB"; match "subsystem" "DEVICE"; match "type" "ATTACH"; match "vendor" "0x0d9f"; match "product" "0x00a2"; action "chgrp @RUN_AS_GROUP@ /dev/$cdev; chmod g+rw /dev/$cdev"; }; # PowerCOM SKP - Smart KING Pro (all Smart series) - usbhid-ups notify 100 { match "system" "USB"; match "subsystem" "DEVICE"; match "type" "ATTACH"; match "vendor" "0x0d9f"; match "product" "0x00a3"; action "chgrp @RUN_AS_GROUP@ /dev/$cdev; chmod g+rw /dev/$cdev"; }; # PowerCOM WOW - usbhid-ups notify 100 { match "system" "USB"; match "subsystem" "DEVICE"; match "type" "ATTACH"; match "vendor" "0x0d9f"; match "product" "0x00a4"; action "chgrp @RUN_AS_GROUP@ /dev/$cdev; chmod g+rw /dev/$cdev"; }; # PowerCOM VGD - Vanguard - usbhid-ups notify 100 { match "system" "USB"; match "subsystem" "DEVICE"; match "type" "ATTACH"; match "vendor" "0x0d9f"; match "product" "0x00a5"; action "chgrp @RUN_AS_GROUP@ /dev/$cdev; chmod g+rw /dev/$cdev"; }; # PowerCOM BNT - Black Knight Pro - usbhid-ups notify 100 { match "system" "USB"; match "subsystem" "DEVICE"; match "type" "ATTACH"; match "vendor" "0x0d9f"; match "product" "0x00a6"; action "chgrp @RUN_AS_GROUP@ /dev/$cdev; chmod g+rw /dev/$cdev"; }; # Unitek Alpha 1200Sx - nutdrv_qx notify 100 { match "system" "USB"; match "subsystem" "DEVICE"; match "type" "ATTACH"; match "vendor" "0x0f03"; match "product" "0x0001"; action "chgrp @RUN_AS_GROUP@ /dev/$cdev; chmod g+rw /dev/$cdev"; }; # Liebert # Liebert PowerSure PSA UPS - usbhid-ups notify 100 { match "system" "USB"; match "subsystem" "DEVICE"; match "type" "ATTACH"; match "vendor" "0x10af"; match "product" "0x0001"; action "chgrp @RUN_AS_GROUP@ /dev/$cdev; chmod g+rw /dev/$cdev"; }; # Liebert PowerSure PSI 1440 - usbhid-ups notify 100 { match "system" "USB"; match "subsystem" "DEVICE"; match "type" "ATTACH"; match "vendor" "0x10af"; match "product" "0x0004"; action "chgrp @RUN_AS_GROUP@ /dev/$cdev; chmod g+rw /dev/$cdev"; }; # Liebert GXT3 - usbhid-ups notify 100 { match "system" "USB"; match "subsystem" "DEVICE"; match "type" "ATTACH"; match "vendor" "0x10af"; match "product" "0x0008"; action "chgrp @RUN_AS_GROUP@ /dev/$cdev; chmod g+rw /dev/$cdev"; }; # GE EP series - nutdrv_qx notify 100 { match "system" "USB"; match "subsystem" "DEVICE"; match "type" "ATTACH"; match "vendor" "0x14f0"; match "product" "0x00c9"; action "chgrp @RUN_AS_GROUP@ /dev/$cdev; chmod g+rw /dev/$cdev"; }; # Legrand # Legrand Keor SP - usbhid-ups notify 100 { match "system" "USB"; match "subsystem" "DEVICE"; match "type" "ATTACH"; match "vendor" "0x1cb0"; match "product" "0x0032"; action "chgrp @RUN_AS_GROUP@ /dev/$cdev; chmod g+rw /dev/$cdev"; }; # Legrand Daker DK / DK Plus - nutdrv_qx notify 100 { match "system" "USB"; match "subsystem" "DEVICE"; match "type" "ATTACH"; match "vendor" "0x1cb0"; match "product" "0x0035"; action "chgrp @RUN_AS_GROUP@ /dev/$cdev; chmod g+rw /dev/$cdev"; }; # Legrand Keor PDU - usbhid-ups notify 100 { match "system" "USB"; match "subsystem" "DEVICE"; match "type" "ATTACH"; match "vendor" "0x1cb0"; match "product" "0x0038"; action "chgrp @RUN_AS_GROUP@ /dev/$cdev; chmod g+rw /dev/$cdev"; }; # Arduino # Arduino Leonardo, Leonardo ETH and Pro Micro - usbhid-ups notify 100 { match "system" "USB"; match "subsystem" "DEVICE"; match "type" "ATTACH"; match "vendor" "0x2341"; match "product" "0x0036"; action "chgrp @RUN_AS_GROUP@ /dev/$cdev; chmod g+rw /dev/$cdev"; }; # Arduino Leonardo, Leonardo ETH and Pro Micro - usbhid-ups notify 100 { match "system" "USB"; match "subsystem" "DEVICE"; match "type" "ATTACH"; match "vendor" "0x2341"; match "product" "0x8036"; action "chgrp @RUN_AS_GROUP@ /dev/$cdev; chmod g+rw /dev/$cdev"; }; # Arduino # Arduino Leonardo, Leonardo ETH and Pro Micro - usbhid-ups notify 100 { match "system" "USB"; match "subsystem" "DEVICE"; match "type" "ATTACH"; match "vendor" "0x2a03"; match "product" "0x0036"; action "chgrp @RUN_AS_GROUP@ /dev/$cdev; chmod g+rw /dev/$cdev"; }; # Arduino Leonardo, Leonardo ETH and Pro Micro - usbhid-ups notify 100 { match "system" "USB"; match "subsystem" "DEVICE"; match "type" "ATTACH"; match "vendor" "0x2a03"; match "product" "0x0040"; action "chgrp @RUN_AS_GROUP@ /dev/$cdev; chmod g+rw /dev/$cdev"; }; # Arduino Leonardo, Leonardo ETH and Pro Micro - usbhid-ups notify 100 { match "system" "USB"; match "subsystem" "DEVICE"; match "type" "ATTACH"; match "vendor" "0x2a03"; match "product" "0x8036"; action "chgrp @RUN_AS_GROUP@ /dev/$cdev; chmod g+rw /dev/$cdev"; }; # Arduino Leonardo, Leonardo ETH and Pro Micro - usbhid-ups notify 100 { match "system" "USB"; match "subsystem" "DEVICE"; match "type" "ATTACH"; match "vendor" "0x2a03"; match "product" "0x8040"; action "chgrp @RUN_AS_GROUP@ /dev/$cdev; chmod g+rw /dev/$cdev"; }; # AEG # PROTECT B / NAS - usbhid-ups notify 100 { match "system" "USB"; match "subsystem" "DEVICE"; match "type" "ATTACH"; match "vendor" "0x2b2d"; match "product" "0xffff"; action "chgrp @RUN_AS_GROUP@ /dev/$cdev; chmod g+rw /dev/$cdev"; }; # Ever # USB IDs device table - usbhid-ups notify 100 { match "system" "USB"; match "subsystem" "DEVICE"; match "type" "ATTACH"; match "vendor" "0x2e51"; match "product" "0x0000"; action "chgrp @RUN_AS_GROUP@ /dev/$cdev; chmod g+rw /dev/$cdev"; }; # USB IDs device table - usbhid-ups notify 100 { match "system" "USB"; match "subsystem" "DEVICE"; match "type" "ATTACH"; match "vendor" "0x2e51"; match "product" "0xffff"; action "chgrp @RUN_AS_GROUP@ /dev/$cdev; chmod g+rw /dev/$cdev"; }; # Salicru # https://www.salicru.com/sps-3000-adv-rt2.html - usbhid-ups notify 100 { match "system" "USB"; match "subsystem" "DEVICE"; match "type" "ATTACH"; match "vendor" "0x2e66"; match "product" "0x0101"; action "chgrp @RUN_AS_GROUP@ /dev/$cdev; chmod g+rw /dev/$cdev"; }; # SLC TWIN PRO2<=3KVA per https://github.com/networkupstools/nut/issues/450 - usbhid-ups notify 100 { match "system" "USB"; match "subsystem" "DEVICE"; match "type" "ATTACH"; match "vendor" "0x2e66"; match "product" "0x0201"; action "chgrp @RUN_AS_GROUP@ /dev/$cdev; chmod g+rw /dev/$cdev"; }; # SLC TWIN PRO2<=3KVA per https://github.com/networkupstools/nut/issues/450 - usbhid-ups notify 100 { match "system" "USB"; match "subsystem" "DEVICE"; match "type" "ATTACH"; match "vendor" "0x2e66"; match "product" "0x0202"; action "chgrp @RUN_AS_GROUP@ /dev/$cdev; chmod g+rw /dev/$cdev"; }; # SLC TWIN PRO2<=3KVA per https://github.com/networkupstools/nut/issues/450 - usbhid-ups notify 100 { match "system" "USB"; match "subsystem" "DEVICE"; match "type" "ATTACH"; match "vendor" "0x2e66"; match "product" "0x0203"; action "chgrp @RUN_AS_GROUP@ /dev/$cdev; chmod g+rw /dev/$cdev"; }; # https://www.salicru.com/sps-home.html - usbhid-ups notify 100 { match "system" "USB"; match "subsystem" "DEVICE"; match "type" "ATTACH"; match "vendor" "0x2e66"; match "product" "0x0300"; action "chgrp @RUN_AS_GROUP@ /dev/$cdev; chmod g+rw /dev/$cdev"; }; # https://www.salicru.com/sps-850-adv-t.html - usbhid-ups notify 100 { match "system" "USB"; match "subsystem" "DEVICE"; match "type" "ATTACH"; match "vendor" "0x2e66"; match "product" "0x0302"; action "chgrp @RUN_AS_GROUP@ /dev/$cdev; chmod g+rw /dev/$cdev"; }; # Powervar # Powervar - usbhid-ups notify 100 { match "system" "USB"; match "subsystem" "DEVICE"; match "type" "ATTACH"; match "vendor" "0x4234"; match "product" "0x0002"; action "chgrp @RUN_AS_GROUP@ /dev/$cdev; chmod g+rw /dev/$cdev"; }; # Ablerex 625L USB (Note: earlier best-fit was "krauler_subdriver" before PR #1135) - nutdrv_qx notify 100 { match "system" "USB"; match "subsystem" "DEVICE"; match "type" "ATTACH"; match "vendor" "0xffff"; match "product" "0x0000"; action "chgrp @RUN_AS_GROUP@ /dev/$cdev; chmod g+rw /dev/$cdev"; }; nut-2.8.1/scripts/devd/Makefile.am0000644000175000017500000000123414501607135013720 00000000000000 if WITH_DEVD devdconfdir = $(devddir) devdconf_DATA = if WITH_USB devdconf_DATA += nut-usb.conf endif endif EXTRA_DIST = README MAINTAINERCLEANFILES = Makefile.in .dirstamp # Generated by configure script: DISTCLEANFILES = nut-usb.conf # we should never remove this one, apart from a distclean-check # or stronger... # Generated by autogen.sh and needed to run the configure script # (technically, generated by tools/nut-usbinfo.pl script among # GENERATED_USB_OS_FILES): MAINTAINERCLEANFILES += nut-usb.conf.in MAINTAINERCLEANFILES += nut-usb.conf.in.AUTOGEN_WITHOUT # Part of dist tarball, regardless of use for current build: EXTRA_DIST += nut-usb.conf.in nut-2.8.1/scripts/devd/README0000644000175000017500000000111114501607135012536 00000000000000On FreeBSD, devd has a similar role to udev on Linux. The devd.conf file defines actions to perform when devices are plugged in. The tools/nut-usbinfo.pl script generates nut-usb.conf.in by processing USB macros in all of the drivers. In this case, the defined action for each matching UPS is to change the permissions such that the NUT drivers can access the devices without requiring root privileges. You may need to restart devd and re-plug in the UPS to trigger the actions. The format of this configuration file should work with devd on FreeBSD 9.0 and 9.1, at the very least. nut-2.8.1/scripts/Makefile.in0000644000175000017500000006232614520274662013026 00000000000000# Makefile.in generated by automake 1.16.5 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2021 Free Software Foundation, Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. @SET_MAKE@ VPATH = @srcdir@ am__is_gnu_make = { \ if test -z '$(MAKELEVEL)'; then \ false; \ elif test -n '$(MAKE_HOST)'; then \ true; \ elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \ true; \ else \ false; \ fi; \ } am__make_running_with_option = \ case $${target_option-} in \ ?) ;; \ *) echo "am__make_running_with_option: internal error: invalid" \ "target option '$${target_option-}' specified" >&2; \ exit 1;; \ esac; \ has_opt=no; \ sane_makeflags=$$MAKEFLAGS; \ if $(am__is_gnu_make); then \ sane_makeflags=$$MFLAGS; \ else \ case $$MAKEFLAGS in \ *\\[\ \ ]*) \ bs=\\; \ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ esac; \ fi; \ skip_next=no; \ strip_trailopt () \ { \ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ }; \ for flg in $$sane_makeflags; do \ test $$skip_next = yes && { skip_next=no; continue; }; \ case $$flg in \ *=*|--*) continue;; \ -*I) strip_trailopt 'I'; skip_next=yes;; \ -*I?*) strip_trailopt 'I';; \ -*O) strip_trailopt 'O'; skip_next=yes;; \ -*O?*) strip_trailopt 'O';; \ -*l) strip_trailopt 'l'; skip_next=yes;; \ -*l?*) strip_trailopt 'l';; \ -[dEDm]) skip_next=yes;; \ -[JT]) skip_next=yes;; \ esac; \ case $$flg in \ *$$target_option*) has_opt=yes; break;; \ esac; \ done; \ test $$has_opt = yes am__make_dryrun = (target_option=n; $(am__make_running_with_option)) am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkglibexecdir = $(libexecdir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ target_triplet = @target@ subdir = scripts ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/m4/ax_c___attribute__.m4 \ $(top_srcdir)/m4/ax_c_pragmas.m4 \ $(top_srcdir)/m4/ax_check_compile_flag.m4 \ $(top_srcdir)/m4/ax_compare_version.m4 \ $(top_srcdir)/m4/ax_realpath.m4 \ $(top_srcdir)/m4/ax_run_or_link_ifelse.m4 \ $(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \ $(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \ $(top_srcdir)/m4/lt~obsolete.m4 \ $(top_srcdir)/m4/nut_arg_with.m4 \ $(top_srcdir)/m4/nut_check_asciidoc.m4 \ $(top_srcdir)/m4/nut_check_aspell.m4 \ $(top_srcdir)/m4/nut_check_cppcheck.m4 \ $(top_srcdir)/m4/nut_check_headers_windows.m4 \ $(top_srcdir)/m4/nut_check_libavahi.m4 \ $(top_srcdir)/m4/nut_check_libfreeipmi.m4 \ $(top_srcdir)/m4/nut_check_libgd.m4 \ $(top_srcdir)/m4/nut_check_libgpiod.m4 \ $(top_srcdir)/m4/nut_check_libltdl.m4 \ $(top_srcdir)/m4/nut_check_libmodbus.m4 \ $(top_srcdir)/m4/nut_check_libneon.m4 \ $(top_srcdir)/m4/nut_check_libnetsnmp.m4 \ $(top_srcdir)/m4/nut_check_libnss.m4 \ $(top_srcdir)/m4/nut_check_libopenssl.m4 \ $(top_srcdir)/m4/nut_check_libpowerman.m4 \ $(top_srcdir)/m4/nut_check_libregex.m4 \ $(top_srcdir)/m4/nut_check_libsystemd.m4 \ $(top_srcdir)/m4/nut_check_libusb.m4 \ $(top_srcdir)/m4/nut_check_libwrap.m4 \ $(top_srcdir)/m4/nut_check_os.m4 \ $(top_srcdir)/m4/nut_check_pkgconfig.m4 \ $(top_srcdir)/m4/nut_check_python.m4 \ $(top_srcdir)/m4/nut_check_socketlib.m4 \ $(top_srcdir)/m4/nut_compiler_family.m4 \ $(top_srcdir)/m4/nut_func_getnameinfo_argtypes.m4 \ $(top_srcdir)/m4/nut_report_feature.m4 \ $(top_srcdir)/m4/nut_stash_warnings.m4 \ $(top_srcdir)/m4/nut_type_socklen_t.m4 \ $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/include/config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = AM_V_P = $(am__v_P_@AM_V@) am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) am__v_P_0 = false am__v_P_1 = : AM_V_GEN = $(am__v_GEN_@AM_V@) am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) am__v_GEN_0 = @echo " GEN " $@; am__v_GEN_1 = AM_V_at = $(am__v_at_@AM_V@) am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) am__v_at_0 = @ am__v_at_1 = SOURCES = DIST_SOURCES = RECURSIVE_TARGETS = all-recursive check-recursive cscopelist-recursive \ ctags-recursive dvi-recursive html-recursive info-recursive \ install-data-recursive install-dvi-recursive \ install-exec-recursive install-html-recursive \ install-info-recursive install-pdf-recursive \ install-ps-recursive install-recursive installcheck-recursive \ installdirs-recursive pdf-recursive ps-recursive \ tags-recursive uninstall-recursive am__can_run_installinfo = \ case $$AM_UPDATE_INFO_DIR in \ n|no|NO) false;; \ *) (install-info --version) >/dev/null 2>&1;; \ esac RECURSIVE_CLEAN_TARGETS = mostlyclean-recursive clean-recursive \ distclean-recursive maintainer-clean-recursive am__recursive_targets = \ $(RECURSIVE_TARGETS) \ $(RECURSIVE_CLEAN_TARGETS) \ $(am__extra_recursive_targets) AM_RECURSIVE_TARGETS = $(am__recursive_targets:-recursive=) TAGS CTAGS \ distdir distdir-am am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) # Read a list of newline-separated strings from the standard input, # and print each of them once, without duplicates. Input order is # *not* preserved. am__uniquify_input = $(AWK) '\ BEGIN { nonempty = 0; } \ { items[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in items) print i; }; } \ ' # Make sure the list of sources is unique. This is necessary because, # e.g., the same source file might be shared among _SOURCES variables # for different programs/libraries. am__define_uniq_tagged_files = \ list='$(am__tagged_files)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | $(am__uniquify_input)` DIST_SUBDIRS = $(SUBDIRS) am__DIST_COMMON = $(srcdir)/Makefile.in README DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) am__relativize = \ dir0=`pwd`; \ sed_first='s,^\([^/]*\)/.*$$,\1,'; \ sed_rest='s,^[^/]*/*,,'; \ sed_last='s,^.*/\([^/]*\)$$,\1,'; \ sed_butlast='s,/*[^/]*$$,,'; \ while test -n "$$dir1"; do \ first=`echo "$$dir1" | sed -e "$$sed_first"`; \ if test "$$first" != "."; then \ if test "$$first" = ".."; then \ dir2=`echo "$$dir0" | sed -e "$$sed_last"`/"$$dir2"; \ dir0=`echo "$$dir0" | sed -e "$$sed_butlast"`; \ else \ first2=`echo "$$dir2" | sed -e "$$sed_first"`; \ if test "$$first2" = "$$first"; then \ dir2=`echo "$$dir2" | sed -e "$$sed_rest"`; \ else \ dir2="../$$dir2"; \ fi; \ dir0="$$dir0"/"$$first"; \ fi; \ fi; \ dir1=`echo "$$dir1" | sed -e "$$sed_rest"`; \ done; \ reldir="$$dir2" A2X = @A2X@ ACLOCAL = @ACLOCAL@ ALTPIDPATH = @ALTPIDPATH@ AMTAR = @AMTAR@ AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ AR = @AR@ ASCIIDOC = @ASCIIDOC@ ASPELL = @ASPELL@ ASPELL_FILTER_LIB_PATH = @ASPELL_FILTER_LIB_PATH@ ASPELL_FILTER_SHARE_PATH = @ASPELL_FILTER_SHARE_PATH@ ASPELL_FILTER_TEX_PATH = @ASPELL_FILTER_TEX_PATH@ AUGPARSE = @AUGPARSE@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ BINDIR = @BINDIR@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CONFIG_FLAGS = @CONFIG_FLAGS@ CONFPATH = @CONFPATH@ CPP = @CPP@ CPPCHECK = @CPPCHECK@ CPPFLAGS = @CPPFLAGS@ CPPUNIT_CFLAGS = @CPPUNIT_CFLAGS@ CPPUNIT_LIBS = @CPPUNIT_LIBS@ CSCOPE = @CSCOPE@ CTAGS = @CTAGS@ CXX = @CXX@ CXXCPP = @CXXCPP@ CXXDEPMODE = @CXXDEPMODE@ CXXFLAGS = @CXXFLAGS@ CYGPATH_W = @CYGPATH_W@ DBLATEX = @DBLATEX@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ DEPLOYED_UPSC = @DEPLOYED_UPSC@ DEPLOYED_UPSD = @DEPLOYED_UPSD@ DLLTOOL = @DLLTOOL@ DOC_BUILD_LIST = @DOC_BUILD_LIST@ DOC_CHECK_LIST = @DOC_CHECK_LIST@ DRIVER_BUILD_LIST = @DRIVER_BUILD_LIST@ DRIVER_INSTALL_TARGET = @DRIVER_INSTALL_TARGET@ DRIVER_MAN_LIST = @DRIVER_MAN_LIST@ DRIVER_MAN_LIST_PAGES = @DRIVER_MAN_LIST_PAGES@ DRVPATH = @DRVPATH@ DSYMUTIL = @DSYMUTIL@ DUMPBIN = @DUMPBIN@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ ETAGS = @ETAGS@ EXEEXT = @EXEEXT@ FGREP = @FGREP@ FORCE_NUT_VERSION = @FORCE_NUT_VERSION@ GDLIB_CONFIG = @GDLIB_CONFIG@ GREP = @GREP@ HAVE_SYS_SOCKET_H = @HAVE_SYS_SOCKET_H@ HAVE_WINSOCK2_H = @HAVE_WINSOCK2_H@ HAVE_WS2TCPIP_H = @HAVE_WS2TCPIP_H@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ LD = @LD@ LDFLAGS = @LDFLAGS@ LIBAVAHI_CFLAGS = @LIBAVAHI_CFLAGS@ LIBAVAHI_LIBS = @LIBAVAHI_LIBS@ LIBDIR = @LIBDIR@ LIBGD_CFLAGS = @LIBGD_CFLAGS@ LIBGD_LDFLAGS = @LIBGD_LDFLAGS@ LIBGPIO_CFLAGS = @LIBGPIO_CFLAGS@ LIBGPIO_LIBS = @LIBGPIO_LIBS@ LIBI2C_LIBS = @LIBI2C_LIBS@ LIBIPMI_CFLAGS = @LIBIPMI_CFLAGS@ LIBIPMI_LIBS = @LIBIPMI_LIBS@ LIBLTDL_CFLAGS = @LIBLTDL_CFLAGS@ LIBLTDL_LIBS = @LIBLTDL_LIBS@ LIBMODBUS_CFLAGS = @LIBMODBUS_CFLAGS@ LIBMODBUS_LIBS = @LIBMODBUS_LIBS@ LIBNEON_CFLAGS = @LIBNEON_CFLAGS@ LIBNEON_LIBS = @LIBNEON_LIBS@ LIBNETSNMP_CFLAGS = @LIBNETSNMP_CFLAGS@ LIBNETSNMP_LIBS = @LIBNETSNMP_LIBS@ LIBOBJS = @LIBOBJS@ LIBPOWERMAN_CFLAGS = @LIBPOWERMAN_CFLAGS@ LIBPOWERMAN_LIBS = @LIBPOWERMAN_LIBS@ LIBREGEX_LIBS = @LIBREGEX_LIBS@ LIBS = @LIBS@ LIBSSL_CFLAGS = @LIBSSL_CFLAGS@ LIBSSL_LIBS = @LIBSSL_LIBS@ LIBSSL_REQUIRES = @LIBSSL_REQUIRES@ LIBSYSTEMD_CFLAGS = @LIBSYSTEMD_CFLAGS@ LIBSYSTEMD_LIBS = @LIBSYSTEMD_LIBS@ LIBTOOL = @LIBTOOL@ LIBTOOL_DEPS = @LIBTOOL_DEPS@ LIBUSB_CFLAGS = @LIBUSB_CFLAGS@ LIBUSB_CONFIG = @LIBUSB_CONFIG@ LIBUSB_LIBS = @LIBUSB_LIBS@ LIBWRAP_CFLAGS = @LIBWRAP_CFLAGS@ LIBWRAP_LIBS = @LIBWRAP_LIBS@ LIPO = @LIPO@ LN_S = @LN_S@ LN_S_R = @LN_S_R@ LTLIBOBJS = @LTLIBOBJS@ LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@ MAINT = @MAINT@ MAKEINFO = @MAKEINFO@ MANIFEST_TOOL = @MANIFEST_TOOL@ MKDIR_P = @MKDIR_P@ MSGFMT = @MSGFMT@ NETLIBS = @NETLIBS@ NET_SNMP_CONFIG = @NET_SNMP_CONFIG@ NM = @NM@ NMEDIT = @NMEDIT@ NUT_DATADIR = @NUT_DATADIR@ NUT_LIBEXECDIR = @NUT_LIBEXECDIR@ NUT_NETVERSION = @NUT_NETVERSION@ NUT_SOURCE_GITREV = @NUT_SOURCE_GITREV@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ OS_NAME = @OS_NAME@ OTOOL = @OTOOL@ OTOOL64 = @OTOOL64@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_SEPARATOR = @PATH_SEPARATOR@ PIDPATH = @PIDPATH@ PKGCONFIGDIR = @PKGCONFIGDIR@ PKG_CONFIG = @PKG_CONFIG@ PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@ PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ PORT = @PORT@ POWERDOWNFLAG = @POWERDOWNFLAG@ PREFIX = @PREFIX@ PYTHON = @PYTHON@ PYTHON2 = @PYTHON2@ PYTHON2_SITE_PACKAGES = @PYTHON2_SITE_PACKAGES@ PYTHON3 = @PYTHON3@ PYTHON3_SITE_PACKAGES = @PYTHON3_SITE_PACKAGES@ PYTHON_SITE_PACKAGES = @PYTHON_SITE_PACKAGES@ RANLIB = @RANLIB@ REALPATH = @REALPATH@ RUN_AS_GROUP = @RUN_AS_GROUP@ RUN_AS_USER = @RUN_AS_USER@ SBINDIR = @SBINDIR@ SED = @SED@ SEMLIBS = @SEMLIBS@ SERLIBS = @SERLIBS@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ SOURCE_HIGHLIGHT = @SOURCE_HIGHLIGHT@ STATEPATH = @STATEPATH@ STRIP = @STRIP@ SUN_LIBUSB = @SUN_LIBUSB@ SYSTEMD_ANALYZE_PROGRAM = @SYSTEMD_ANALYZE_PROGRAM@ SYSTEMD_DAEMON_ARGS_DRIVER = @SYSTEMD_DAEMON_ARGS_DRIVER@ SYSTEMD_DAEMON_ARGS_UPSD = @SYSTEMD_DAEMON_ARGS_UPSD@ SYSTEMD_DAEMON_ARGS_UPSMON = @SYSTEMD_DAEMON_ARGS_UPSMON@ SYSTEMD_DAEMON_NOTIFYACCESS_DRIVER = @SYSTEMD_DAEMON_NOTIFYACCESS_DRIVER@ SYSTEMD_DAEMON_NOTIFYACCESS_UPSD = @SYSTEMD_DAEMON_NOTIFYACCESS_UPSD@ SYSTEMD_DAEMON_NOTIFYACCESS_UPSMON = @SYSTEMD_DAEMON_NOTIFYACCESS_UPSMON@ SYSTEMD_DAEMON_TYPE_DRIVER = @SYSTEMD_DAEMON_TYPE_DRIVER@ SYSTEMD_DAEMON_TYPE_UPSD = @SYSTEMD_DAEMON_TYPE_UPSD@ SYSTEMD_DAEMON_TYPE_UPSMON = @SYSTEMD_DAEMON_TYPE_UPSMON@ SYSTEMD_DAEMON_WATCHDOG_DRIVER = @SYSTEMD_DAEMON_WATCHDOG_DRIVER@ SYSTEMD_DAEMON_WATCHDOG_UPSD = @SYSTEMD_DAEMON_WATCHDOG_UPSD@ SYSTEMD_DAEMON_WATCHDOG_UPSMON = @SYSTEMD_DAEMON_WATCHDOG_UPSMON@ SYSTEMD_TMPFILES_PROGRAM = @SYSTEMD_TMPFILES_PROGRAM@ TREE_VERSION = @TREE_VERSION@ VALGRIND = @VALGRIND@ VERSION = @VERSION@ WINDMC = @WINDMC@ WINDRES = @WINDRES@ WORDS_BIGENDIAN = @WORDS_BIGENDIAN@ XMLLINT = @XMLLINT@ XSLTPROC = @XSLTPROC@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_AR = @ac_ct_AR@ ac_ct_CC = @ac_ct_CC@ ac_ct_CXX = @ac_ct_CXX@ ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__tar = @am__tar@ am__untar = @am__untar@ auglensdir = @auglensdir@ bindir = @bindir@ build = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ cgiexecdir = @cgiexecdir@ datadir = @datadir@ datarootdir = @datarootdir@ devddir = @devddir@ docdir = @docdir@ driverexecdir = @driverexecdir@ dummy_PKG_CONFIG = @dummy_PKG_CONFIG@ dummy_PKG_CONFIG_CFLAGS = @dummy_PKG_CONFIG_CFLAGS@ dummy_PKG_CONFIG_LIBS = @dummy_PKG_CONFIG_LIBS@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ hotplugdir = @hotplugdir@ htmldir = @htmldir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libdir = @libdir@ libexecdir = @libexecdir@ localedir = @localedir@ localstatedir = @localstatedir@ mandir = @mandir@ mkdir_p = @mkdir_p@ now = @now@ nut_with_nut_monitor = @nut_with_nut_monitor@ nut_with_nut_monitor_desktop = @nut_with_nut_monitor_desktop@ nut_with_nut_monitor_dir = @nut_with_nut_monitor_dir@ nut_with_nut_monitor_py2gtk2 = @nut_with_nut_monitor_py2gtk2@ nut_with_nut_monitor_py3qt5 = @nut_with_nut_monitor_py3qt5@ nut_with_pynut = @nut_with_pynut@ nut_with_pynut_py = @nut_with_pynut_py@ nut_with_pynut_py2 = @nut_with_pynut_py2@ nut_with_pynut_py3 = @nut_with_pynut_py3@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ pkgconfigdir = @pkgconfigdir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ runstatedir = @runstatedir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ sysconfdir = @sysconfdir@ systemdshutdowndir = @systemdshutdowndir@ systemdsystemunitdir = @systemdsystemunitdir@ systemdtmpfilesdir = @systemdtmpfilesdir@ target = @target@ target_alias = @target_alias@ target_cpu = @target_cpu@ target_os = @target_os@ target_vendor = @target_vendor@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ udevdir = @udevdir@ EXTRA_DIST = README \ avahi/nut.service.in \ HP-UX/nut-drvctl \ HP-UX/nut-drvctl.sh \ HP-UX/nut-upsd \ HP-UX/nut-upsd.sh \ HP-UX/nut-upsmon \ HP-UX/nut-upsmon.sh \ logrotate/nutlogd \ misc/nut.bash_completion \ misc/osd-notify \ perl/Nut.pm \ RedHat/halt.patch \ RedHat/README \ RedHat/ups.in \ RedHat/upsd.in \ RedHat/upsmon.in \ Solaris8/S99upsmon \ subdriver/gen-usbhid-subdriver.sh \ subdriver/gen-snmp-subdriver.sh \ upower/95-upower-hid.hwdb \ upower/95-upower-hid.rules \ Windows/halt.c \ Windows/Makefile SUBDIRS = augeas devd hotplug python systemd udev ufw Solaris Windows upsdrvsvcctl MAINTAINERCLEANFILES = Makefile.in .dirstamp all: all-recursive .SUFFIXES: $(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu scripts/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --gnu scripts/Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): mostlyclean-libtool: -rm -f *.lo clean-libtool: -rm -rf .libs _libs # This directory's subdirectories are mostly independent; you can cd # into them and run 'make' without going through this Makefile. # To change the values of 'make' variables: instead of editing Makefiles, # (1) if the variable is set in 'config.status', edit 'config.status' # (which will cause the Makefiles to be regenerated when you run 'make'); # (2) otherwise, pass the desired values on the 'make' command line. $(am__recursive_targets): @fail=; \ if $(am__make_keepgoing); then \ failcom='fail=yes'; \ else \ failcom='exit 1'; \ fi; \ dot_seen=no; \ target=`echo $@ | sed s/-recursive//`; \ case "$@" in \ distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \ *) list='$(SUBDIRS)' ;; \ esac; \ for subdir in $$list; do \ echo "Making $$target in $$subdir"; \ if test "$$subdir" = "."; then \ dot_seen=yes; \ local_target="$$target-am"; \ else \ local_target="$$target"; \ fi; \ ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ || eval $$failcom; \ done; \ if test "$$dot_seen" = "no"; then \ $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \ fi; test -z "$$fail" ID: $(am__tagged_files) $(am__define_uniq_tagged_files); mkid -fID $$unique tags: tags-recursive TAGS: tags tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) set x; \ here=`pwd`; \ if ($(ETAGS) --etags-include --version) >/dev/null 2>&1; then \ include_option=--etags-include; \ empty_fix=.; \ else \ include_option=--include; \ empty_fix=; \ fi; \ list='$(SUBDIRS)'; for subdir in $$list; do \ if test "$$subdir" = .; then :; else \ test ! -f $$subdir/TAGS || \ set "$$@" "$$include_option=$$here/$$subdir/TAGS"; \ fi; \ done; \ $(am__define_uniq_tagged_files); \ shift; \ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ test -n "$$unique" || unique=$$empty_fix; \ if test $$# -gt 0; then \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ "$$@" $$unique; \ else \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ $$unique; \ fi; \ fi ctags: ctags-recursive CTAGS: ctags ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) $(am__define_uniq_tagged_files); \ test -z "$(CTAGS_ARGS)$$unique" \ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ $$unique GTAGS: here=`$(am__cd) $(top_builddir) && pwd` \ && $(am__cd) $(top_srcdir) \ && gtags -i $(GTAGS_ARGS) "$$here" cscopelist: cscopelist-recursive cscopelist-am: $(am__tagged_files) list='$(am__tagged_files)'; \ case "$(srcdir)" in \ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \ *) sdir=$(subdir)/$(srcdir) ;; \ esac; \ for i in $$list; do \ if test -f "$$i"; then \ echo "$(subdir)/$$i"; \ else \ echo "$$sdir/$$i"; \ fi; \ done >> $(top_builddir)/cscope.files distclean-tags: -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags distdir: $(BUILT_SOURCES) $(MAKE) $(AM_MAKEFLAGS) distdir-am distdir-am: $(DISTFILES) @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ dist_files=`for file in $$list; do echo $$file; done | \ sed -e "s|^$$srcdirstrip/||;t" \ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ case $$dist_files in \ */*) $(MKDIR_P) `echo "$$dist_files" | \ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ sort -u` ;; \ esac; \ for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d "$(distdir)/$$file"; then \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ else \ test -f "$(distdir)/$$file" \ || cp -p $$d/$$file "$(distdir)/$$file" \ || exit 1; \ fi; \ done @list='$(DIST_SUBDIRS)'; for subdir in $$list; do \ if test "$$subdir" = .; then :; else \ $(am__make_dryrun) \ || test -d "$(distdir)/$$subdir" \ || $(MKDIR_P) "$(distdir)/$$subdir" \ || exit 1; \ dir1=$$subdir; dir2="$(distdir)/$$subdir"; \ $(am__relativize); \ new_distdir=$$reldir; \ dir1=$$subdir; dir2="$(top_distdir)"; \ $(am__relativize); \ new_top_distdir=$$reldir; \ echo " (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) top_distdir="$$new_top_distdir" distdir="$$new_distdir" \\"; \ echo " am__remove_distdir=: am__skip_length_check=: am__skip_mode_fix=: distdir)"; \ ($(am__cd) $$subdir && \ $(MAKE) $(AM_MAKEFLAGS) \ top_distdir="$$new_top_distdir" \ distdir="$$new_distdir" \ am__remove_distdir=: \ am__skip_length_check=: \ am__skip_mode_fix=: \ distdir) \ || exit 1; \ fi; \ done check-am: all-am check: check-recursive all-am: Makefile installdirs: installdirs-recursive installdirs-am: install: install-recursive install-exec: install-exec-recursive install-data: install-data-recursive uninstall: uninstall-recursive install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-recursive install-strip: if test -z '$(STRIP)'; then \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ install; \ else \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ fi mostlyclean-generic: clean-generic: distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." -test -z "$(MAINTAINERCLEANFILES)" || rm -f $(MAINTAINERCLEANFILES) clean: clean-recursive clean-am: clean-generic clean-libtool mostlyclean-am distclean: distclean-recursive -rm -f Makefile distclean-am: clean-am distclean-generic distclean-tags dvi: dvi-recursive dvi-am: html: html-recursive html-am: info: info-recursive info-am: install-data-am: install-dvi: install-dvi-recursive install-dvi-am: install-exec-am: install-html: install-html-recursive install-html-am: install-info: install-info-recursive install-info-am: install-man: install-pdf: install-pdf-recursive install-pdf-am: install-ps: install-ps-recursive install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-recursive -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-recursive mostlyclean-am: mostlyclean-generic mostlyclean-libtool pdf: pdf-recursive pdf-am: ps: ps-recursive ps-am: uninstall-am: .MAKE: $(am__recursive_targets) install-am install-strip .PHONY: $(am__recursive_targets) CTAGS GTAGS TAGS all all-am check \ check-am clean clean-generic clean-libtool cscopelist-am ctags \ ctags-am distclean distclean-generic distclean-libtool \ distclean-tags distdir dvi dvi-am html html-am info info-am \ install install-am install-data install-data-am install-dvi \ install-dvi-am install-exec install-exec-am install-html \ install-html-am install-info install-info-am install-man \ install-pdf install-pdf-am install-ps install-ps-am \ install-strip installcheck installcheck-am installdirs \ installdirs-am maintainer-clean maintainer-clean-generic \ mostlyclean mostlyclean-generic mostlyclean-libtool pdf pdf-am \ ps ps-am tags tags-am uninstall uninstall-am .PRECIOUS: Makefile # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: nut-2.8.1/scripts/RedHat/0000755000175000017500000000000014520277776012210 500000000000000nut-2.8.1/scripts/RedHat/upsd.in0000644000175000017500000000544114517562211013422 00000000000000#!/bin/sh # # chkconfig: 2345 30 90 # # 2022-01-04 Jim Klimov # Updated .in template, double-quoted variable expansions # # 2003-01-31 Antonino Albanese # Removed all old statements # start programs as user nut # new style starting and stopping upsd # added reload option # use of /etc/sysconfig/ups for POWERDOWNFLAG variable retrieving # # 2002-02-07 Nigel Metheringham # made ups.conf pre-eminant, added new upsdrvctl functions, targeted for RH7.2, should # work OK on RH 6.x, 7.x # 2001-10-24 Peter Bieringer # enhancements for new style drivers and controls, tested on a RHL 7.1.93 system # # description: NUT upsd and its drivers directly monitor a ups and \ # make information from it available to other programs # processname: upsd # config: @CONFPATH@/upsd.conf # config: @CONFPATH@/ups.conf PATH="/sbin:/bin:/usr/sbin:/usr/bin" export PATH # Source function library. . /etc/rc.d/init.d/functions # POWERDOWNFLAG *must* match that in upsmon.conf # Loading POWERDOWNFLAG from /etc/sysconfig/ups DRIVERPATH="@DRVPATH@" NUT_SBINDIR="@SBINDIR@" if [ -f /etc/sysconfig/ups ]; then . /etc/sysconfig/ups else POWERDOWNFLAG="@POWERDOWNFLAG@" NUTUSER="@RUN_AS_USER@" fi UPSDCONF="@CONFPATH@/upsd.conf" UPSCONF="@CONFPATH@/ups.conf" if [ -n "$DRIVERPATH" -a -d "$DRIVERPATH" ]; then PATH="$DRIVERPATH:$PATH" fi if [ -n "$NUT_SBINDIR" -a -d "$NUT_SBINDIR" ]; then PATH="$NUT_SBINDIR:$PATH" fi # if there are no config file, bail out [ -f "$UPSDCONF" ] && [ -f "$UPSCONF" ] || exit 0 NUT_QUIET_INIT_UPSNOTIFY=true export NUT_QUIET_INIT_UPSNOTIFY runcmd() { echo -n "$1 " shift if [ "$BOOTUP" = "color" ]; then $* && echo_success || echo_failure else $* fi echo } # See how we are called. case "$1" in start) # new style drivers uses 'upsdrvctl' echo -n "NUT Starting UPS model drivers: " # starting all drivers as nut user daemon --user "$NUTUSER" "`which upsdrvctl`" start echo if [ $? -eq 0 ]; then echo -n "NUT Starting UPS daemon: " # starting as nut user daemon upsd -u "$NUTUSER" echo touch /var/lock/subsys/upsd fi ;; stop) # new style upsd stop action "NUT Stopping UPS daemon" \ upsd -c stop # new style drivers uses 'upsdrvctl' action "NUT Stopping UPS model drivers" \ upsdrvctl stop rm -f /var/lock/subsys/upsd ;; powerdown) # new style drivers runcmd "NUT powerdown of attached UPS(es)" upsdrvctl shutdown ;; restart) $0 stop $0 start ;; reload) # reloading upsd config files action "NUT Reloading config files" \ upsd -c reload ;; status) # new style drivers action "NUT: checking UPS model drivers" upsdrvctl status status upsd ;; *) echo "Usage: upsd {start|stop|powerdown|restart|reload|status}" exit 1 esac nut-2.8.1/scripts/RedHat/ups.in0000644000175000017500000000015114501607135013245 00000000000000# POWERDOWNFLAG *must* match that in upsmon.conf POWERDOWNFLAG="@POWERDOWNFLAG@" NUTUSER="@RUN_AS_USER@" nut-2.8.1/scripts/RedHat/README0000644000175000017500000000014514501607135012771 00000000000000Install ups in /etc/rc.d/init.d /etc/sysconfig/ups is used only to store the POWERDOWNFLAG variable nut-2.8.1/scripts/RedHat/upsmon.in0000644000175000017500000000243314517562211013766 00000000000000#!/bin/sh # # chkconfig: 2345 31 89 # # 2022-01-04 Jim Klimov # Updated .in template, double-quoted variable expansions # # 2003-01-31 Antonino Albanese # start program as user nut # new style stopping upsmon # added reload option # # description: upsmon talks to upsd and notifies of ups status changes \ # also shutting systems down if required. # processname: upsmon # config: @CONFPATH@/upsmon.conf PATH=/sbin:/bin:/usr/sbin:/usr/bin export PATH # Source function library. . /etc/rc.d/init.d/functions NUT_SBINDIR="@SBINDIR@" if [ -f /etc/sysconfig/ups ]; then . /etc/sysconfig/ups else POWERDOWNFLAG="@POWERDOWNFLAG@" NUTUSER="@RUN_AS_USER@" fi if [ -n "$NUT_SBINDIR" -a -d "$NUT_SBINDIR" ]; then PATH="$NUT_SBINDIR:$PATH" fi NUT_QUIET_INIT_UPSNOTIFY=true export NUT_QUIET_INIT_UPSNOTIFY # See how we are called. case "$1" in start) action "NUT Starting UPS monitor" upsmon -u "$NUTUSER" touch /var/lock/subsys/upsmon ;; stop) action "NUT Stopping UPS monitor: " \ upsmon -c stop rm -f /var/lock/subsys/upsmon ;; restart) $0 stop $0 start ;; reload) action "NUT Reloading UPS monitor: " \ upsmon -c reload ;; status) status upsmon ;; *) echo "Usage: upsmon {start|stop|restart|reload|status}" exit 1 esac nut-2.8.1/scripts/RedHat/halt.patch0000644000175000017500000000241714273170601014065 00000000000000--- /etc/rc.d/init.d/halt Thu Mar 28 00:21:19 2002 +++ halt.new Fri Jan 31 15:29:49 2003 @@ -8,8 +8,17 @@ # Modified for RHS Linux by Damien Neil # +# 2003-01-31 Antonino Albanese +# Modified ups shutdown for new NUT method +# # Set the path. PATH=/sbin:/bin:/usr/bin:/usr/sbin +# load /etc/sysconfig/ups if present I've put the POWERDOWNFLAG +# in there so noboby have to manually modify the shutdown script +if [ -f /etc/sysconfig/ups ]; then + . /etc/sysconfig/ups +fi +UPSCMD=`which upsdrvctl` export NOLOCALE=1 . /etc/init.d/functions @@ -198,10 +208,15 @@ fi if [ "$command" = halt ] ; then - if [ -r /etc/ups/upsmon.conf -a -f /etc/killpower -a -f /etc/sysconfig/ups ] ; then - . /etc/sysconfig/ups - [ "$SERVER" = "yes" -a "$MODEL" != "NONE" -a -n "$MODEL" -a -n "$DEVICE" ] && $MODEL -k $DEVICE - fi +# if [ -r /etc/ups/upsmon.conf -a -f /etc/killpower -a -f /etc/sysconfig/ups ] ; then +# . /etc/sysconfig/ups +# [ "$SERVER" = "yes" -a "$MODEL" != "NONE" -a -n "$MODEL" -a -n "$DEVICE" ] && $MODEL -k $DEVICE +# fi + if [ -n "$POWERDOWNFLAG" -a -n "$UPSCMD" ]; then + if [ -f $POWERDOWNFLAG ]; then + $UPSCMD shutdown + fi + fi fi if [ -x "/sbin/halt.local" ]; then nut-2.8.1/scripts/Aix/0000755000175000017500000000000014520277775011561 500000000000000nut-2.8.1/scripts/Aix/nut.init.in0000755000175000017500000000772414517562211013602 00000000000000#! /bin/sh # # ups: Starts the Network UPS Tools # # chkconfig: - 26 74 # description: Network UPS Tools is a collection of programs which provide a common \ # interface for monitoring and administering UPS hardware. # processname: upsd # config: /usr/local/ups/etc # config: /etc/rc.ups # ### BEGIN INIT INFO # Provides: ups # Required-Start: $syslog $network $named # Required-Stop: $local_fs # Default-Stop: 0 1 6 # Short-Description: Starts the Network UPS tools # Description: Network UPS Tools is a collection of programs which provide a common \ # interface for monitoring and administering UPS hardware. ### END INIT INFO success() { echo OK } failure() { echo FAILED } # Resolve what processes should run SERVER="no" CLIENT="no" NUT_DIR="@prefix@" NUT_SBIN_DIR="${NUT_DIR}/sbin" NUT_LIB_DIR="${NUT_DIR}/lib" NUT_RUN_DIR="@ALTPIDPATH@" CONFIG="@CONFPATH@/nut.conf" NUTUSER="@RUN_AS_USER@" NUTGROUP="@RUN_AS_GROUP@" NUT_VAR_LOCK="/var/locks/ups" NUT_QUIET_INIT_UPSNOTIFY=true export NUT_QUIET_INIT_UPSNOTIFY if [ -f "$CONFIG" ] ; then . "$CONFIG" case "$MODE" in standalone|netserver) SERVER="yes" ;; esac rpm -q nut-client >/dev/null 2>&1 && CLIENT="yes" fi do_start() { RETVAL=0 if [ ! -d "$NUT_RUN_DIR" ]; then mkdir -p "$NUT_RUN_DIR" && \ chown "root:$NUTGROUP" "$NUT_RUN_DIR" && \ chmod 770 "$NUT_RUN_DIR" RETVAL=$? fi if [ "$SERVER" = "yes" ]; then echo "Starting UPS driver controller: \c" LD_LIBRARY_PATH="${NUT_LIB_DIR}:$LD_LIBRARY_PATH" "${NUT_SBIN_DIR}"/upsdrvctl start >/dev/null 2>&1 && success || { RETVAL=$?; failure; } echo "Starting upsd: \c" LD_LIBRARY_PATH="${NUT_LIB_DIR}:$LD_LIBRARY_PATH" "${NUT_SBIN_DIR}"/upsd $UPSD_OPTIONS >/dev/null 2>&1 && success || { RETVAL=$?; failure; } fi if [ "$CLIENT" = "yes" ]; then echo "Starting UPS monitor: \c" LD_LIBRARY_PATH="${NUT_LIB_DIR}:$LD_LIBRARY_PATH" "${NUT_SBIN_DIR}"/upsmon >/dev/null 2>&1 && success || { RETVAL=$?; failure; } fi [ "$RETVAL" = 0 ] && touch "${NUT_VAR_LOCK}" return $RETVAL } do_stop() { RETVAL=0 if test -e "${NUT_RUN_DIR}"/upsmon.pid; then echo "Stopping UPS monitor: \c" PID="`cat "${NUT_RUN_DIR}"/upsmon.pid`" kill -15 $PID && success || { RETVAL=$?; failure; } rm "${NUT_RUN_DIR}"/upsmon.pid fi if [ "$SERVER" = "yes" ]; then if test -e "${NUT_RUN_DIR}"/upsd.pid; then echo "Stopping upsd: \c" PID="`cat "${NUT_RUN_DIR}"/upsd.pid`" kill -15 $PID && success || { RETVAL=$?; failure; } rm "${NUT_RUN_DIR}"/upsd.pid fi echo "Shutting down UPS driver controller: \c" "${NUT_SBIN_DIR}"/upsdrvctl stop > /dev/null 2>&1 && success || { RETVAL=$?; failure; } fi [ "$RETVAL" = 0 ] && rm -f "${NUT_VAR_LOCK}" return $RETVAL } do_restart() { do_stop waitmore=5 while [ -n "$(ls "${NUT_RUN_DIR}"/)" -a $waitmore -ge 1 ] do sleep 1 waitmore="$(expr $waitmore - 1)" done do_start } do_reload() { # FIXME: upsd and upsmon always return 0 # => can't tell if reload was successful RETVAL=0 if [ "$SERVER" = "yes" ]; then echo "Reloading upsd" LD_LIBRARY_PATH="${NUT_LIB_DIR}:$LD_LIBRARY_PATH" "${NUT_SBIN_DIR}"/upsd -c reload && success || { RETVAL=$?; failure; } fi echo "Reloading upsmon" LD_LIBRARY_PATH="${NUT_LIB_DIR}:$LD_LIBRARY_PATH" "${NUT_SBIN_DIR}"/upsmon -c reload && success || { RETVAL=$?; failure; } return $RETVAL } # See how we are called. case "$1" in start) do_start ;; stop) do_stop ;; restart) do_restart ;; try-restart) [ -f "${NUT_VAR_LOCK}" ] && do_restart || true ;; reload) do_reload ;; force-reload) do_restart ;; status) if [ "$SERVER" = "yes" ]; then if test -f "${NUT_VAR_LOCK}"; then echo "upsd is running with PID" `cat "${NUT_RUN_DIR}"/upsd.pid` fi fi if test -e "${NUT_RUN_DIR}"/upsmon.pid; then echo "upsmon is running with PID" `cat "${NUT_RUN_DIR}"/upsmon.pid` elif rpm -q nut-client >/dev/null 2>&1; then echo "upsmon isn't running" fi ;; *) echo "Usage: $0 {start|stop|restart|try-restart|reload|force-reload|status}" RETVAL=3 esac exit $RETVAL nut-2.8.1/scripts/Aix/nut-aix.spec.in0000644000175000017500000002221614501607135014334 00000000000000%define nut_id @RUN_AS_USER@ %define nut_group @RUN_AS_GROUP@ %define _prefix /usr/local/ups %define _docdir %{_datadir}/doc %define confdir %{_prefix}/etc %define rcdir /etc/rc.d %define initdir %{rcdir}/init.d %define cgidir /var/www/nut-cgi-bin %define piddir /var/run/nut Summary: Network UPS Tools Name: nut Version: @PACKAGE_VERSION@ Release: 1 Group: Applications/System License: GPLv2+ Buildroot: %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n) Url: https://www.networkupstools.org/ Source: https://www.networkupstools.org/source/@TREE_VERSION@/%{name}-%{version}.tar.gz Source1: nut.init #Source2: ups.sysconfig #Source3: nut-client.tmpfiles # FIXME: adjust according to what is available through RPM on Aix BuildRequires: libtool BuildRequires: net-snmp-devel BuildRequires: openssl-devel BuildRequires: pkgconfig # AIX BUILDERS, PLEASE NOTE: # If building with xlc version 3.6.X rather than gcc, you must ensure # you have the following PTF's installed on your system, or # you will see a runtime error that says: # "Expected but saw " # PTFS needed: U462006 U462007 U462023 U462024 U462025 U462026 U462027 # Refer to http://service.software.ibm.com/support/rs6000, or # set CC=gcc to force use of the GCC compiler. # # %define stdlib lib # %define liblink ../.. # %define DEFCC xlc %description Network UPS Tools (NUT) is a client/server monitoring system that allows computers to share uninterruptible power supply (UPS) and power distribution unit (PDU) hardware. Clients access the hardware through the server, and are notified whenever the power status changes. %package client Group: Applications/System Summary: Network UPS Tools client monitoring utilities #Requires(post): chkconfig #Requires(preun): chkconfig #Requires(pre): shadow-utils %description client This package includes the client utilities that are required to monitor a ups that the client host has access to, but where the UPS is physically attached to a different computer on the network. %package devel Group: Development/Libraries Summary: Development files for NUT Client Requires: %{name}-client = %{version}-%{release} webserver openssl-devel %description devel This package contains the development header files and libraries necessary to develop NUT client applications. %prep %setup -q %build /usr/bin/rm configure.in %configure \ --with-all \ --without-powerman \ --without-avahi \ --without-usb \ --without-ipmi \ --without-cgi \ --datadir=%{_datadir}/%{name} \ --with-user=%{nut_id} \ --with-group=%{nut_group} \ --with-statepath=%{piddir} \ --with-pidpath=%{piddir} \ --with-altpidpath=%{piddir} \ --sysconfdir=%{confdir} \ --with-cgipath=%{cgidir} \ --with-drvpath=%{_sbindir} \ --with-pkgconfig-dir=%{_libdir}/pkgconfig \ --disable-static \ --libdir=%{_libdir} \ --program-transform-name=s,^%{_target_platform}-,, \ LDFLAGS="$LDFLAGS -Wl,-brtl" \ # --with-libltdl-includes=/opt/freeware/share/libtool/libltdl/libltdl/ \ # --with-libltdl-libs=/opt/freeware/lib \ # --with-doc \ asciidoc >= 8.6.3 is required # FIXME: remove rpath? #sed -i 's|^hardcode_libdir_flag_spec=.*|hardcode_libdir_flag_spec=""|g' libtool #sed -i 's|^runpath_var=LD_RUN_PATH|runpath_var=DIE_RPATH_DIE|g' libtool make %{?_smp_mflags} %install /usr/bin/rm -rf %{buildroot} /usr/bin/mkdir -p %{buildroot}%{_sbindir} \ %{buildroot}%{piddir} \ %{buildroot}%{_libdir}/ups \ %{buildroot}%{initdir} \ %{buildroot}%{_libexecdir} make install DESTDIR=%{buildroot} install -m 755 %{SOURCE1} %{buildroot}%{initdir}/ups /usr/bin/rm -f %{buildroot}%{_libdir}/*.la # Remove ".sample" suffix from the config filenames #pushd conf; #make install DESTDIR=%{buildroot} #for file in %{buildroot}%{confdir}/*.sample #do # mv $file %{buildroot}%{confdir}/`basename $file .sample` #done #popd %pre /usr/bin/test -L %{_libdir}/ups || \ /usr/bin/mkdir -p %{_libdir}/ups /usr/bin/grep -qc %{nut_group} /etc/group || \ /usr/bin/mkgroup %{nut_group} /usr/bin/grep -qc %{nut_id} /etc/passwd || \ /usr/sbin/useradd -c "Network UPS Tools" \ -g %{nut_group} -d %{_libdir}/ups %{nut_id} /usr/bin/test -L %{piddir} || \ /usr/bin/mkdir -p %{piddir} /usr/bin/chmod 750 %{piddir} /usr/bin/chown %{nut_id}:%{nut_group} %{piddir} %post /usr/bin/test -L %{rcdir}/rc2.d/Sups || \ /usr/bin/ln -s %{initdir}/ups %{rcdir}/rc2.d/Sups /usr/bin/test -L %{rcdir}/rc2.d/Kups || \ /usr/bin/ln -s %{initdir}/ups %{rcdir}/rc2.d/Kups exit 0 %preun %{initdir}/ups stop if [ "$1" = "0" ]; then /usr/bin/rm -f %{rcdir}/rc2.d/[SK]ups fi exit 0 %postun if [ "$1" = "0" ]; then /usr/bin/grep -qc %{nut_id} /etc/passwd && \ /usr/sbin/userdel %{nut_id} /usr/bin/grep -qc %{nut_group}: /etc/group && \ /usr/sbin/rmgroup %{nut_group} /usr/bin/test -L %{piddir} && \ /usr/bin/rm -rf %{piddir} /usr/bin/test -L %{_libdir}/ups && \ /usr/bin/rm -rf %{_libdir}/ups fi exit 0 %pre client /usr/bin/grep -qc %{nut_group}: /etc/group || \ /usr/bin/mkgroup %{nut_group} /usr/bin/grep -qc %{nut_id} /etc/passwd || \ /usr/sbin/useradd -c "Network UPS Tools" \ -g %{nut_group} -d %{_libdir}/ups %{nut_id} /usr/bin/test -L %{piddir} || \ /usr/bin/mkdir -p %{piddir} /usr/bin/chmod 750 %{piddir} /usr/bin/chown %{nut_id}:%{nut_group} %{piddir} %post client /usr/bin/test -L %{rcdir}/rc2.d/Sups || \ /usr/bin/ln -s %{initdir}/ups %{rcdir}/rc2.d/Sups /usr/bin/test -L %{rcdir}/rc2.d/Kups || \ /usr/bin/ln -s %{initdir}/ups %{rcdir}/rc2.d/Kups #%{initdir}/ups start exit 0 %preun client %{initdir}/ups stop remove="no" if /usr/bin/rpm -q nut >/dev/null 2>&1; then remove="no" elif [ "$1" = "0" ]; then remove="yes" fi if [ "$remove" = "yes" ]; then /usr/bin/rm -f %{rcdir}/rc2.d/[SK]ups /usr/bin/test -L %{piddir} && \ /usr/bin/rm -rf %{piddir} fi exit 0 %postun client remove="no" if /usr/bin/rpm -q nut >/dev/null 2>&1; then remove="no" elif [ "$1" = "0" ]; then remove="yes" fi if [ "$remove" = "yes" ]; then /usr/bin/grep -qc %{nut_id} /etc/passwd && \ /usr/sbin/userdel %{nut_id} /usr/bin/grep -qc %{nut_group}: /etc/group && \ /usr/sbin/rmgroup %{nut_group} #else # %{initdir}/ups start fi exit 0 %clean /usr/bin/rm -rf %{buildroot} %files %defattr(-,root,root,-) %attr(755,root,root) %{initdir}/ups %doc COPYING ChangeLog AUTHORS MAINTAINERS README docs UPGRADING INSTALL NEWS %config(noreplace) %attr(640,root,%nut_group) %{confdir}/nut.conf.sample %config(noreplace) %attr(640,root,%nut_group) %{confdir}/ups.conf.sample %config(noreplace) %attr(640,root,%nut_group) %{confdir}/upsd.conf.sample %config(noreplace) %attr(640,root,%nut_group) %{confdir}/upsd.users.sample %dir %attr(750,%nut_id,%nut_group) %{_libdir}/ups #%ghost %{piddir} %{_sbindir}/* %{_bindir}/upslog %{_bindir}/nutconf %{_libdir}/libnutscan.so* %{_libdir}/libupsclient.so* %{_datadir}/%{name}/cmdvartab %{_datadir}/%{name}/driver.list %{_mandir}/man5/nut.conf.5 %{_mandir}/man5/ups.conf.5 %{_mandir}/man5/upsd.conf.5 %{_mandir}/man5/upsd.users.5 %{_mandir}/man8/apcsmart.8 %{_mandir}/man8/bcmxcp.8 #%{_mandir}/man8/bcmxcp_usb.8 %{_mandir}/man8/belkin.8 %{_mandir}/man8/bestfcom.8 %{_mandir}/man8/belkinunv.8 %{_mandir}/man8/bestfortress.8 %{_mandir}/man8/bestups.8 %{_mandir}/man8/bestuferrups.8 %{_mandir}/man8/blazer.8 %{_mandir}/man8/clone.8 %{_mandir}/man8/dummy-ups.8 %{_mandir}/man8/everups.8 %{_mandir}/man8/etapro.8 %{_mandir}/man8/gamatronic.8 %{_mandir}/man8/genericups.8 %{_mandir}/man8/isbmex.8 %{_mandir}/man8/ivtscd.8 %{_mandir}/man8/liebert.8 %{_mandir}/man8/liebert-esp2.8 %{_mandir}/man8/masterguard.8 %{_mandir}/man8/metasys.8 %{_mandir}/man8/microdowell.8 %{_mandir}/man8/mge-utalk.8 %{_mandir}/man8/mge-shut.8 %{_mandir}/man8/nutupsdrv.8 %{_mandir}/man8/oneac.8 %{_mandir}/man8/optiups.8 %{_mandir}/man8/powercom.8 #%{_mandir}/man8/powerman-pdu.8 %{_mandir}/man8/powerpanel.8 %{_mandir}/man8/rhino.8 #%{_mandir}/man8/richcomm_usb.8 %{_mandir}/man8/safenet.8 %{_mandir}/man8/snmp-ups.8 %{_mandir}/man8/solis.8 %{_mandir}/man8/tripplite.8 #%{_mandir}/man8/tripplite_usb.8 %{_mandir}/man8/tripplitesu.8 %{_mandir}/man8/victronups.8 %{_mandir}/man8/upscode2.8 %{_mandir}/man8/upsd.8 %{_mandir}/man8/upsdrvctl.8 %files client %doc COPYING %defattr(-,root,root) %attr(755,root,root) %{initdir}/ups %dir %{confdir} %config(noreplace) %attr(640,root,%nut_group) %{confdir}/upsmon.conf.sample %config(noreplace) %attr(640,root,%nut_group) %{confdir}/upssched.conf.sample %dir %attr(750,%nut_id,%nut_group) %{_libdir}/ups #%ghost %{piddir} %{_bindir}/upsc %{_bindir}/upscmd %{_bindir}/upsrw %{_sbindir}/upsmon %{_sbindir}/upssched %{_bindir}/upssched-cmd %{_libdir}/libupsclient.so* %{_mandir}/man5/upsmon.conf.5 %{_mandir}/man5/upssched.conf.5 %{_mandir}/man8/upsc.8 %{_mandir}/man8/upscmd.8 %{_mandir}/man8/upsrw.8 %{_mandir}/man8/upslog.8 %{_mandir}/man8/upsmon.8 %{_mandir}/man8/upssched.8 %files devel %defattr(-,root,root,-) %{_includedir}/* %{_mandir}/man3/upscli* %{_libdir}/libupsclient.so* %{_libdir}/pkgconfig/libupsclient.pc %changelog * Tue Jul 12 2014 Arnaud Quette - 2.7.2-1.master - Minor adjustments * Tue Jul 12 2011 Arnaud Quette - 2.6.5-1.trunk - derive from RHEL 2.6.1-2, and adapt for Aix 6.1 nut-2.8.1/scripts/upsdrvsvcctl/0000755000175000017500000000000014520277777013604 500000000000000nut-2.8.1/scripts/upsdrvsvcctl/upsdrvsvcctl.in0000755000175000017500000001451214377374134016617 00000000000000#!/bin/sh # # Copyright (C) 2016-2018 Eaton # # 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 2 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, write to the Free Software Foundation, Inc., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. # #! \file upsdrvsvcctl(.in) # \author Jim Klimov # \brief Manage NUT devices registered as service-unit instances # if [ -z "${SERVICE_FRAMEWORK-}" ] ; then [ -x /usr/sbin/svcadm ] && [ -x /usr/sbin/svccfg ] && [ -x /usr/bin/svcs ] && \ SERVICE_FRAMEWORK="smf" [ -z "${SERVICE_FRAMEWORK-}" ] && \ [ -x /bin/systemctl ] && \ SERVICE_FRAMEWORK="systemd" fi VERB="" CMD="" CMDARG="" ENUMERATOR="" case "$SERVICE_FRAMEWORK" in smf) CMD="/usr/sbin/svcadm" ENUMERATOR="@NUT_LIBEXECDIR@/nut-driver-enumerator.sh" ;; systemd) CMD="/bin/systemctl" ENUMERATOR="@NUT_LIBEXECDIR@/nut-driver-enumerator.sh" ;; *) echo "Unrecognized SERVICE_FRAMEWORK: $SERVICE_FRAMEWORK" >&2 ; exit ;; esac usage() { # Note: version header differs from UPS_VERSION in binaries that # might also have the git-version suffixed during build time cat << EOF Network UPS Tools - UPS driver controller ${PACKAGE_VERSION} Starts and stops UPS drivers via system service instances, see the $ENUMERATOR script for more details. usage: $0 [OPTIONS] (start | stop | shutdown) [] Options: -h display this help -t testing mode - prints actions without doing them -D raise debugging level start start all UPS drivers in ups.conf start only start driver for UPS stop stop all UPS drivers in ups.conf stop only stop driver for UPS Note: the "shutdown" options from original upsdrvctl are not currently directly supported by this service management framework wrapper; instead they are passed to the native upsdrvctl binary (your current user account should have sufficient permissions to do that all): shutdown shutdown all UPS drivers in ups.conf shutdown only shutdown UPS usage: $0 [OPTIONS] resync resync call $ENUMERATOR to update the mapping of service instances for NUT drivers to device sections in 'ups.conf' usage: $0 [OPTIONS] reconfigure reconfigure call $ENUMERATOR to remove and re-create the mapping of all service instances for NUT drivers to device sections in 'ups.conf' e.g. after a NUT package upgrade usage: $0 [OPTIONS] list [] list call $ENUMERATOR to list the mapping of service instances to device sections list (optionally return the service instance name for one device) usage: $0 [OPTIONS] show-config [] show-config output config section from ups.conf for device show-config ...or all devices if no argument was passed EOF } ACTION="" SVCINST="" DRYRUN="" DEBUG=0 # Note: DEBUG is UNUSED_PARAM so far while [ $# -gt 0 ]; do case "$1" in resync) eval $DRYRUN $ENUMERATOR ; exit $? ;; reconf|reconfigure) eval $DRYRUN $ENUMERATOR --reconfigure ; exit $? ;; list) if [ -n "$2" ] ; then eval $ENUMERATOR --get-service-for-device "$2" ; exit $? else eval $ENUMERATOR --list-services-for-devices ; exit $? fi ;; show-config) if [ -n "$2" ] ; then eval $ENUMERATOR --show-device-config "$2" ; exit $? else eval $ENUMERATOR --show-all-configs ; exit $? fi ;; start|stop) ACTION="$1" if [ -n "$2" ] ; then SVCINST="`$ENUMERATOR --get-service-for-device "$2"`" || exit shift fi ;; shutdown) echo "NOTE: Action '$1' is not implemented via services currently, will call upsdrvctl" >&2 echo "Stopping the driver service instance(s) to release exclusive resources, if any..." >&2 RES=0 $0 stop $2 @SBINDIR@/upsdrvctl shutdown $2 || RES=$? echo "Starting the driver service instance(s) so they can reconnect when the UPS returns..." >&2 $0 start $2 exit $RES ;; -t) DRYRUN="echo" ;; -h) usage; exit 0 ;; -D) DEBUG="`expr $DEBUG + 1`" ;; -r|-u) echo "Option '$1 $2' is not implemented via services currently" >&2 ; shift;; *) echo "Unrecognized argument: $1" >&2 ; exit ;; esac shift done if [ -z "$ENUMERATOR" ] || [ ! -s "$ENUMERATOR" ] || [ ! -x "$ENUMERATOR" ] ; then echo "ENUMERATOR script (nut-driver-enumerator.sh) not found!" >&2 exit 1 fi if [ -z "$ACTION" ]; then echo "No action was requested!" >&2 exit 1 fi if [ -z "$SVCINST" ]; then SVCINST="`$ENUMERATOR --list-services`" || exit fi # TODO: Support shutdown of one or all UPSes by stopping its service # and then calling the original upsdrvctl on it? case "$ACTION" in start) VERB="Starting" case "$SERVICE_FRAMEWORK" in smf) CMDARG="enable -ts" ;; systemd) CMDARG="start" ;; esac ;; stop) VERB="Stopping" case "$SERVICE_FRAMEWORK" in smf) CMDARG="disable -ts" ;; systemd) CMDARG="stop" ;; esac ;; *) echo "Unrecognized ACTION: $ACTION" >&2 ; exit ;; esac for INST in $SVCINST ; do echo "$VERB $INST ..." >&2 $DRYRUN $CMD $CMDARG "$INST" & done wait case "$SERVICE_FRAMEWORK" in smf) sleep 1 echo "Post-process clearing services that failed early..." >&2 for INST in $SVCINST ; do echo "Clearing $INST (if it got broken) ..." >&2 $DRYRUN $CMD clear "$INST" & done ;; esac wait nut-2.8.1/scripts/upsdrvsvcctl/Makefile.in0000644000175000017500000004600514520274662015564 00000000000000# Makefile.in generated by automake 1.16.5 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2021 Free Software Foundation, Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. @SET_MAKE@ VPATH = @srcdir@ am__is_gnu_make = { \ if test -z '$(MAKELEVEL)'; then \ false; \ elif test -n '$(MAKE_HOST)'; then \ true; \ elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \ true; \ else \ false; \ fi; \ } am__make_running_with_option = \ case $${target_option-} in \ ?) ;; \ *) echo "am__make_running_with_option: internal error: invalid" \ "target option '$${target_option-}' specified" >&2; \ exit 1;; \ esac; \ has_opt=no; \ sane_makeflags=$$MAKEFLAGS; \ if $(am__is_gnu_make); then \ sane_makeflags=$$MFLAGS; \ else \ case $$MAKEFLAGS in \ *\\[\ \ ]*) \ bs=\\; \ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ esac; \ fi; \ skip_next=no; \ strip_trailopt () \ { \ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ }; \ for flg in $$sane_makeflags; do \ test $$skip_next = yes && { skip_next=no; continue; }; \ case $$flg in \ *=*|--*) continue;; \ -*I) strip_trailopt 'I'; skip_next=yes;; \ -*I?*) strip_trailopt 'I';; \ -*O) strip_trailopt 'O'; skip_next=yes;; \ -*O?*) strip_trailopt 'O';; \ -*l) strip_trailopt 'l'; skip_next=yes;; \ -*l?*) strip_trailopt 'l';; \ -[dEDm]) skip_next=yes;; \ -[JT]) skip_next=yes;; \ esac; \ case $$flg in \ *$$target_option*) has_opt=yes; break;; \ esac; \ done; \ test $$has_opt = yes am__make_dryrun = (target_option=n; $(am__make_running_with_option)) am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkglibexecdir = $(libexecdir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ target_triplet = @target@ @HAVE_SYSTEMD_TRUE@am__append_1 = nut-driver-enumerator.sh upsdrvsvcctl @HAVE_SYSTEMD_FALSE@@WITH_SOLARIS_SMF_TRUE@am__append_2 = nut-driver-enumerator.sh upsdrvsvcctl subdir = scripts/upsdrvsvcctl ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/m4/ax_c___attribute__.m4 \ $(top_srcdir)/m4/ax_c_pragmas.m4 \ $(top_srcdir)/m4/ax_check_compile_flag.m4 \ $(top_srcdir)/m4/ax_compare_version.m4 \ $(top_srcdir)/m4/ax_realpath.m4 \ $(top_srcdir)/m4/ax_run_or_link_ifelse.m4 \ $(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \ $(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \ $(top_srcdir)/m4/lt~obsolete.m4 \ $(top_srcdir)/m4/nut_arg_with.m4 \ $(top_srcdir)/m4/nut_check_asciidoc.m4 \ $(top_srcdir)/m4/nut_check_aspell.m4 \ $(top_srcdir)/m4/nut_check_cppcheck.m4 \ $(top_srcdir)/m4/nut_check_headers_windows.m4 \ $(top_srcdir)/m4/nut_check_libavahi.m4 \ $(top_srcdir)/m4/nut_check_libfreeipmi.m4 \ $(top_srcdir)/m4/nut_check_libgd.m4 \ $(top_srcdir)/m4/nut_check_libgpiod.m4 \ $(top_srcdir)/m4/nut_check_libltdl.m4 \ $(top_srcdir)/m4/nut_check_libmodbus.m4 \ $(top_srcdir)/m4/nut_check_libneon.m4 \ $(top_srcdir)/m4/nut_check_libnetsnmp.m4 \ $(top_srcdir)/m4/nut_check_libnss.m4 \ $(top_srcdir)/m4/nut_check_libopenssl.m4 \ $(top_srcdir)/m4/nut_check_libpowerman.m4 \ $(top_srcdir)/m4/nut_check_libregex.m4 \ $(top_srcdir)/m4/nut_check_libsystemd.m4 \ $(top_srcdir)/m4/nut_check_libusb.m4 \ $(top_srcdir)/m4/nut_check_libwrap.m4 \ $(top_srcdir)/m4/nut_check_os.m4 \ $(top_srcdir)/m4/nut_check_pkgconfig.m4 \ $(top_srcdir)/m4/nut_check_python.m4 \ $(top_srcdir)/m4/nut_check_socketlib.m4 \ $(top_srcdir)/m4/nut_compiler_family.m4 \ $(top_srcdir)/m4/nut_func_getnameinfo_argtypes.m4 \ $(top_srcdir)/m4/nut_report_feature.m4 \ $(top_srcdir)/m4/nut_stash_warnings.m4 \ $(top_srcdir)/m4/nut_type_socklen_t.m4 \ $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/include/config.h CONFIG_CLEAN_FILES = nut-driver-enumerator.sh upsdrvsvcctl CONFIG_CLEAN_VPATH_FILES = AM_V_P = $(am__v_P_@AM_V@) am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) am__v_P_0 = false am__v_P_1 = : AM_V_GEN = $(am__v_GEN_@AM_V@) am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) am__v_GEN_0 = @echo " GEN " $@; am__v_GEN_1 = AM_V_at = $(am__v_at_@AM_V@) am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) am__v_at_0 = @ am__v_at_1 = SOURCES = DIST_SOURCES = am__can_run_installinfo = \ case $$AM_UPDATE_INFO_DIR in \ n|no|NO) false;; \ *) (install-info --version) >/dev/null 2>&1;; \ esac am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) am__DIST_COMMON = $(srcdir)/Makefile.in \ $(srcdir)/nut-driver-enumerator.sh.in \ $(srcdir)/upsdrvsvcctl.in README DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) A2X = @A2X@ ACLOCAL = @ACLOCAL@ ALTPIDPATH = @ALTPIDPATH@ AMTAR = @AMTAR@ AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ AR = @AR@ ASCIIDOC = @ASCIIDOC@ ASPELL = @ASPELL@ ASPELL_FILTER_LIB_PATH = @ASPELL_FILTER_LIB_PATH@ ASPELL_FILTER_SHARE_PATH = @ASPELL_FILTER_SHARE_PATH@ ASPELL_FILTER_TEX_PATH = @ASPELL_FILTER_TEX_PATH@ AUGPARSE = @AUGPARSE@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ BINDIR = @BINDIR@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CONFIG_FLAGS = @CONFIG_FLAGS@ CONFPATH = @CONFPATH@ CPP = @CPP@ CPPCHECK = @CPPCHECK@ CPPFLAGS = @CPPFLAGS@ CPPUNIT_CFLAGS = @CPPUNIT_CFLAGS@ CPPUNIT_LIBS = @CPPUNIT_LIBS@ CSCOPE = @CSCOPE@ CTAGS = @CTAGS@ CXX = @CXX@ CXXCPP = @CXXCPP@ CXXDEPMODE = @CXXDEPMODE@ CXXFLAGS = @CXXFLAGS@ CYGPATH_W = @CYGPATH_W@ DBLATEX = @DBLATEX@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ DEPLOYED_UPSC = @DEPLOYED_UPSC@ DEPLOYED_UPSD = @DEPLOYED_UPSD@ DLLTOOL = @DLLTOOL@ DOC_BUILD_LIST = @DOC_BUILD_LIST@ DOC_CHECK_LIST = @DOC_CHECK_LIST@ DRIVER_BUILD_LIST = @DRIVER_BUILD_LIST@ DRIVER_INSTALL_TARGET = @DRIVER_INSTALL_TARGET@ DRIVER_MAN_LIST = @DRIVER_MAN_LIST@ DRIVER_MAN_LIST_PAGES = @DRIVER_MAN_LIST_PAGES@ DRVPATH = @DRVPATH@ DSYMUTIL = @DSYMUTIL@ DUMPBIN = @DUMPBIN@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ ETAGS = @ETAGS@ EXEEXT = @EXEEXT@ FGREP = @FGREP@ FORCE_NUT_VERSION = @FORCE_NUT_VERSION@ GDLIB_CONFIG = @GDLIB_CONFIG@ GREP = @GREP@ HAVE_SYS_SOCKET_H = @HAVE_SYS_SOCKET_H@ HAVE_WINSOCK2_H = @HAVE_WINSOCK2_H@ HAVE_WS2TCPIP_H = @HAVE_WS2TCPIP_H@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ LD = @LD@ LDFLAGS = @LDFLAGS@ LIBAVAHI_CFLAGS = @LIBAVAHI_CFLAGS@ LIBAVAHI_LIBS = @LIBAVAHI_LIBS@ LIBDIR = @LIBDIR@ LIBGD_CFLAGS = @LIBGD_CFLAGS@ LIBGD_LDFLAGS = @LIBGD_LDFLAGS@ LIBGPIO_CFLAGS = @LIBGPIO_CFLAGS@ LIBGPIO_LIBS = @LIBGPIO_LIBS@ LIBI2C_LIBS = @LIBI2C_LIBS@ LIBIPMI_CFLAGS = @LIBIPMI_CFLAGS@ LIBIPMI_LIBS = @LIBIPMI_LIBS@ LIBLTDL_CFLAGS = @LIBLTDL_CFLAGS@ LIBLTDL_LIBS = @LIBLTDL_LIBS@ LIBMODBUS_CFLAGS = @LIBMODBUS_CFLAGS@ LIBMODBUS_LIBS = @LIBMODBUS_LIBS@ LIBNEON_CFLAGS = @LIBNEON_CFLAGS@ LIBNEON_LIBS = @LIBNEON_LIBS@ LIBNETSNMP_CFLAGS = @LIBNETSNMP_CFLAGS@ LIBNETSNMP_LIBS = @LIBNETSNMP_LIBS@ LIBOBJS = @LIBOBJS@ LIBPOWERMAN_CFLAGS = @LIBPOWERMAN_CFLAGS@ LIBPOWERMAN_LIBS = @LIBPOWERMAN_LIBS@ LIBREGEX_LIBS = @LIBREGEX_LIBS@ LIBS = @LIBS@ LIBSSL_CFLAGS = @LIBSSL_CFLAGS@ LIBSSL_LIBS = @LIBSSL_LIBS@ LIBSSL_REQUIRES = @LIBSSL_REQUIRES@ LIBSYSTEMD_CFLAGS = @LIBSYSTEMD_CFLAGS@ LIBSYSTEMD_LIBS = @LIBSYSTEMD_LIBS@ LIBTOOL = @LIBTOOL@ LIBTOOL_DEPS = @LIBTOOL_DEPS@ LIBUSB_CFLAGS = @LIBUSB_CFLAGS@ LIBUSB_CONFIG = @LIBUSB_CONFIG@ LIBUSB_LIBS = @LIBUSB_LIBS@ LIBWRAP_CFLAGS = @LIBWRAP_CFLAGS@ LIBWRAP_LIBS = @LIBWRAP_LIBS@ LIPO = @LIPO@ LN_S = @LN_S@ LN_S_R = @LN_S_R@ LTLIBOBJS = @LTLIBOBJS@ LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@ MAINT = @MAINT@ MAKEINFO = @MAKEINFO@ MANIFEST_TOOL = @MANIFEST_TOOL@ MKDIR_P = @MKDIR_P@ MSGFMT = @MSGFMT@ NETLIBS = @NETLIBS@ NET_SNMP_CONFIG = @NET_SNMP_CONFIG@ NM = @NM@ NMEDIT = @NMEDIT@ NUT_DATADIR = @NUT_DATADIR@ NUT_LIBEXECDIR = @NUT_LIBEXECDIR@ NUT_NETVERSION = @NUT_NETVERSION@ NUT_SOURCE_GITREV = @NUT_SOURCE_GITREV@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ OS_NAME = @OS_NAME@ OTOOL = @OTOOL@ OTOOL64 = @OTOOL64@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_SEPARATOR = @PATH_SEPARATOR@ PIDPATH = @PIDPATH@ PKGCONFIGDIR = @PKGCONFIGDIR@ PKG_CONFIG = @PKG_CONFIG@ PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@ PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ PORT = @PORT@ POWERDOWNFLAG = @POWERDOWNFLAG@ PREFIX = @PREFIX@ PYTHON = @PYTHON@ PYTHON2 = @PYTHON2@ PYTHON2_SITE_PACKAGES = @PYTHON2_SITE_PACKAGES@ PYTHON3 = @PYTHON3@ PYTHON3_SITE_PACKAGES = @PYTHON3_SITE_PACKAGES@ PYTHON_SITE_PACKAGES = @PYTHON_SITE_PACKAGES@ RANLIB = @RANLIB@ REALPATH = @REALPATH@ RUN_AS_GROUP = @RUN_AS_GROUP@ RUN_AS_USER = @RUN_AS_USER@ SBINDIR = @SBINDIR@ SED = @SED@ SEMLIBS = @SEMLIBS@ SERLIBS = @SERLIBS@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ SOURCE_HIGHLIGHT = @SOURCE_HIGHLIGHT@ STATEPATH = @STATEPATH@ STRIP = @STRIP@ SUN_LIBUSB = @SUN_LIBUSB@ SYSTEMD_ANALYZE_PROGRAM = @SYSTEMD_ANALYZE_PROGRAM@ SYSTEMD_DAEMON_ARGS_DRIVER = @SYSTEMD_DAEMON_ARGS_DRIVER@ SYSTEMD_DAEMON_ARGS_UPSD = @SYSTEMD_DAEMON_ARGS_UPSD@ SYSTEMD_DAEMON_ARGS_UPSMON = @SYSTEMD_DAEMON_ARGS_UPSMON@ SYSTEMD_DAEMON_NOTIFYACCESS_DRIVER = @SYSTEMD_DAEMON_NOTIFYACCESS_DRIVER@ SYSTEMD_DAEMON_NOTIFYACCESS_UPSD = @SYSTEMD_DAEMON_NOTIFYACCESS_UPSD@ SYSTEMD_DAEMON_NOTIFYACCESS_UPSMON = @SYSTEMD_DAEMON_NOTIFYACCESS_UPSMON@ SYSTEMD_DAEMON_TYPE_DRIVER = @SYSTEMD_DAEMON_TYPE_DRIVER@ SYSTEMD_DAEMON_TYPE_UPSD = @SYSTEMD_DAEMON_TYPE_UPSD@ SYSTEMD_DAEMON_TYPE_UPSMON = @SYSTEMD_DAEMON_TYPE_UPSMON@ SYSTEMD_DAEMON_WATCHDOG_DRIVER = @SYSTEMD_DAEMON_WATCHDOG_DRIVER@ SYSTEMD_DAEMON_WATCHDOG_UPSD = @SYSTEMD_DAEMON_WATCHDOG_UPSD@ SYSTEMD_DAEMON_WATCHDOG_UPSMON = @SYSTEMD_DAEMON_WATCHDOG_UPSMON@ SYSTEMD_TMPFILES_PROGRAM = @SYSTEMD_TMPFILES_PROGRAM@ TREE_VERSION = @TREE_VERSION@ VALGRIND = @VALGRIND@ VERSION = @VERSION@ WINDMC = @WINDMC@ WINDRES = @WINDRES@ WORDS_BIGENDIAN = @WORDS_BIGENDIAN@ XMLLINT = @XMLLINT@ XSLTPROC = @XSLTPROC@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_AR = @ac_ct_AR@ ac_ct_CC = @ac_ct_CC@ ac_ct_CXX = @ac_ct_CXX@ ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__tar = @am__tar@ am__untar = @am__untar@ auglensdir = @auglensdir@ bindir = @bindir@ build = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ cgiexecdir = @cgiexecdir@ datadir = @datadir@ datarootdir = @datarootdir@ devddir = @devddir@ docdir = @docdir@ driverexecdir = @driverexecdir@ dummy_PKG_CONFIG = @dummy_PKG_CONFIG@ dummy_PKG_CONFIG_CFLAGS = @dummy_PKG_CONFIG_CFLAGS@ dummy_PKG_CONFIG_LIBS = @dummy_PKG_CONFIG_LIBS@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ hotplugdir = @hotplugdir@ htmldir = @htmldir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libdir = @libdir@ libexecdir = @libexecdir@ localedir = @localedir@ localstatedir = @localstatedir@ mandir = @mandir@ mkdir_p = @mkdir_p@ now = @now@ nut_with_nut_monitor = @nut_with_nut_monitor@ nut_with_nut_monitor_desktop = @nut_with_nut_monitor_desktop@ nut_with_nut_monitor_dir = @nut_with_nut_monitor_dir@ nut_with_nut_monitor_py2gtk2 = @nut_with_nut_monitor_py2gtk2@ nut_with_nut_monitor_py3qt5 = @nut_with_nut_monitor_py3qt5@ nut_with_pynut = @nut_with_pynut@ nut_with_pynut_py = @nut_with_pynut_py@ nut_with_pynut_py2 = @nut_with_pynut_py2@ nut_with_pynut_py3 = @nut_with_pynut_py3@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ pkgconfigdir = @pkgconfigdir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ runstatedir = @runstatedir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ sysconfdir = @sysconfdir@ systemdshutdowndir = @systemdshutdowndir@ systemdsystemunitdir = @systemdsystemunitdir@ systemdtmpfilesdir = @systemdtmpfilesdir@ target = @target@ target_alias = @target_alias@ target_cpu = @target_cpu@ target_os = @target_os@ target_vendor = @target_vendor@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ udevdir = @udevdir@ EXTRA_DIST = README $(am__append_1) $(am__append_2) \ nut-driver-enumerator.sh.in upsdrvsvcctl.in MAINTAINERCLEANFILES = Makefile.in .dirstamp all: all-am .SUFFIXES: $(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu scripts/upsdrvsvcctl/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --gnu scripts/upsdrvsvcctl/Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): nut-driver-enumerator.sh: $(top_builddir)/config.status $(srcdir)/nut-driver-enumerator.sh.in cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ upsdrvsvcctl: $(top_builddir)/config.status $(srcdir)/upsdrvsvcctl.in cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ mostlyclean-libtool: -rm -f *.lo clean-libtool: -rm -rf .libs _libs tags TAGS: ctags CTAGS: cscope cscopelist: distdir: $(BUILT_SOURCES) $(MAKE) $(AM_MAKEFLAGS) distdir-am distdir-am: $(DISTFILES) @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ dist_files=`for file in $$list; do echo $$file; done | \ sed -e "s|^$$srcdirstrip/||;t" \ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ case $$dist_files in \ */*) $(MKDIR_P) `echo "$$dist_files" | \ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ sort -u` ;; \ esac; \ for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d "$(distdir)/$$file"; then \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ else \ test -f "$(distdir)/$$file" \ || cp -p $$d/$$file "$(distdir)/$$file" \ || exit 1; \ fi; \ done check-am: all-am check: check-am all-am: Makefile installdirs: install: install-am install-exec: install-exec-am install-data: install-data-am uninstall: uninstall-am install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-am install-strip: if test -z '$(STRIP)'; then \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ install; \ else \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ fi mostlyclean-generic: clean-generic: distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." -test -z "$(MAINTAINERCLEANFILES)" || rm -f $(MAINTAINERCLEANFILES) clean: clean-am clean-am: clean-generic clean-libtool mostlyclean-am distclean: distclean-am -rm -f Makefile distclean-am: clean-am distclean-generic dvi: dvi-am dvi-am: html: html-am html-am: info: info-am info-am: install-data-am: install-dvi: install-dvi-am install-dvi-am: install-exec-am: install-html: install-html-am install-html-am: install-info: install-info-am install-info-am: install-man: install-pdf: install-pdf-am install-pdf-am: install-ps: install-ps-am install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-am -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-am mostlyclean-am: mostlyclean-generic mostlyclean-libtool pdf: pdf-am pdf-am: ps: ps-am ps-am: uninstall-am: .MAKE: install-am install-strip .PHONY: all all-am check check-am clean clean-generic clean-libtool \ cscopelist-am ctags-am distclean distclean-generic \ distclean-libtool distdir dvi dvi-am html html-am info info-am \ install install-am install-data install-data-am install-dvi \ install-dvi-am install-exec install-exec-am install-html \ install-html-am install-info install-info-am install-man \ install-pdf install-pdf-am install-ps install-ps-am \ install-strip installcheck installcheck-am installdirs \ maintainer-clean maintainer-clean-generic mostlyclean \ mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \ tags-am uninstall uninstall-am .PRECIOUS: Makefile # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: nut-2.8.1/scripts/upsdrvsvcctl/upsdrvsvcctl0000755000175000017500000001454014520275020016173 00000000000000#!/bin/sh # # Copyright (C) 2016-2018 Eaton # # 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 2 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, write to the Free Software Foundation, Inc., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. # #! \file upsdrvsvcctl(.in) # \author Jim Klimov # \brief Manage NUT devices registered as service-unit instances # if [ -z "${SERVICE_FRAMEWORK-}" ] ; then [ -x /usr/sbin/svcadm ] && [ -x /usr/sbin/svccfg ] && [ -x /usr/bin/svcs ] && \ SERVICE_FRAMEWORK="smf" [ -z "${SERVICE_FRAMEWORK-}" ] && \ [ -x /bin/systemctl ] && \ SERVICE_FRAMEWORK="systemd" fi VERB="" CMD="" CMDARG="" ENUMERATOR="" case "$SERVICE_FRAMEWORK" in smf) CMD="/usr/sbin/svcadm" ENUMERATOR="/usr/local/ups/libexec/nut-driver-enumerator.sh" ;; systemd) CMD="/bin/systemctl" ENUMERATOR="/usr/local/ups/libexec/nut-driver-enumerator.sh" ;; *) echo "Unrecognized SERVICE_FRAMEWORK: $SERVICE_FRAMEWORK" >&2 ; exit ;; esac usage() { # Note: version header differs from UPS_VERSION in binaries that # might also have the git-version suffixed during build time cat << EOF Network UPS Tools - UPS driver controller ${PACKAGE_VERSION} Starts and stops UPS drivers via system service instances, see the $ENUMERATOR script for more details. usage: $0 [OPTIONS] (start | stop | shutdown) [] Options: -h display this help -t testing mode - prints actions without doing them -D raise debugging level start start all UPS drivers in ups.conf start only start driver for UPS stop stop all UPS drivers in ups.conf stop only stop driver for UPS Note: the "shutdown" options from original upsdrvctl are not currently directly supported by this service management framework wrapper; instead they are passed to the native upsdrvctl binary (your current user account should have sufficient permissions to do that all): shutdown shutdown all UPS drivers in ups.conf shutdown only shutdown UPS usage: $0 [OPTIONS] resync resync call $ENUMERATOR to update the mapping of service instances for NUT drivers to device sections in 'ups.conf' usage: $0 [OPTIONS] reconfigure reconfigure call $ENUMERATOR to remove and re-create the mapping of all service instances for NUT drivers to device sections in 'ups.conf' e.g. after a NUT package upgrade usage: $0 [OPTIONS] list [] list call $ENUMERATOR to list the mapping of service instances to device sections list (optionally return the service instance name for one device) usage: $0 [OPTIONS] show-config [] show-config output config section from ups.conf for device show-config ...or all devices if no argument was passed EOF } ACTION="" SVCINST="" DRYRUN="" DEBUG=0 # Note: DEBUG is UNUSED_PARAM so far while [ $# -gt 0 ]; do case "$1" in resync) eval $DRYRUN $ENUMERATOR ; exit $? ;; reconf|reconfigure) eval $DRYRUN $ENUMERATOR --reconfigure ; exit $? ;; list) if [ -n "$2" ] ; then eval $ENUMERATOR --get-service-for-device "$2" ; exit $? else eval $ENUMERATOR --list-services-for-devices ; exit $? fi ;; show-config) if [ -n "$2" ] ; then eval $ENUMERATOR --show-device-config "$2" ; exit $? else eval $ENUMERATOR --show-all-configs ; exit $? fi ;; start|stop) ACTION="$1" if [ -n "$2" ] ; then SVCINST="`$ENUMERATOR --get-service-for-device "$2"`" || exit shift fi ;; shutdown) echo "NOTE: Action '$1' is not implemented via services currently, will call upsdrvctl" >&2 echo "Stopping the driver service instance(s) to release exclusive resources, if any..." >&2 RES=0 $0 stop $2 /usr/local/ups/sbin/upsdrvctl shutdown $2 || RES=$? echo "Starting the driver service instance(s) so they can reconnect when the UPS returns..." >&2 $0 start $2 exit $RES ;; -t) DRYRUN="echo" ;; -h) usage; exit 0 ;; -D) DEBUG="`expr $DEBUG + 1`" ;; -r|-u) echo "Option '$1 $2' is not implemented via services currently" >&2 ; shift;; *) echo "Unrecognized argument: $1" >&2 ; exit ;; esac shift done if [ -z "$ENUMERATOR" ] || [ ! -s "$ENUMERATOR" ] || [ ! -x "$ENUMERATOR" ] ; then echo "ENUMERATOR script (nut-driver-enumerator.sh) not found!" >&2 exit 1 fi if [ -z "$ACTION" ]; then echo "No action was requested!" >&2 exit 1 fi if [ -z "$SVCINST" ]; then SVCINST="`$ENUMERATOR --list-services`" || exit fi # TODO: Support shutdown of one or all UPSes by stopping its service # and then calling the original upsdrvctl on it? case "$ACTION" in start) VERB="Starting" case "$SERVICE_FRAMEWORK" in smf) CMDARG="enable -ts" ;; systemd) CMDARG="start" ;; esac ;; stop) VERB="Stopping" case "$SERVICE_FRAMEWORK" in smf) CMDARG="disable -ts" ;; systemd) CMDARG="stop" ;; esac ;; *) echo "Unrecognized ACTION: $ACTION" >&2 ; exit ;; esac for INST in $SVCINST ; do echo "$VERB $INST ..." >&2 $DRYRUN $CMD $CMDARG "$INST" & done wait case "$SERVICE_FRAMEWORK" in smf) sleep 1 echo "Post-process clearing services that failed early..." >&2 for INST in $SVCINST ; do echo "Clearing $INST (if it got broken) ..." >&2 $DRYRUN $CMD clear "$INST" & done ;; esac wait nut-2.8.1/scripts/upsdrvsvcctl/nut-driver-enumerator.sh.in0000755000175000017500000016442014515702041020732 00000000000000#!/bin/sh # # NOTE: This script is intentionally written with portable shell constructs # with the aim and hope to work in different interpreters, so it is a # bit dumber and less efficient than could be achieved with the more # featured shells in the spectrum. # NOTE ALSO: The configuration parser in this script is not meant to be a # reference or 100% compliant with what the binary code uses; its aim # is to just pick out some strings relevant for tracking config changes. # # Copyright (C) 2016-2020 Eaton # Copyright (C) 2020-2023 Jim Klimov # # 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 2 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, write to the Free Software Foundation, Inc., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. # #! \file nut-driver-enumerator.sh(.in) # \author Jim Klimov # \brief Enumerate NUT devices for service-unit instance configuration # \details This script allows to enumerate UPSes in order to produce the # individual service unit instances for each defined configuration. # It assumes the user has adequate permissions to inspect and create # services (e.g. is a root or has proper RBAC profiles to do so). # It helps service frameworks such as Linux systemd and Solaris SMF. # When executed, this script looks for all configured ups.conf # sections and registered service instances, and makes these two # lists match up. It has also a mode to do this in a loop, to keep # checking for differences and applying them, on systems where it's # problematic to trigger it in response to FS event notifications. # Returns exit codes: # 0 Sections and services already match up # 42 Sections and services differed, but now match up - # now the caller should likely restart some services. # Note that the drivers' service instances were started or # stopped as required (by AUTO_START=yes) - but maybe the # upsd or upsmon services should restart. If you pass envvar # REPORT_RESTART_42=no then this codepath would return 0. # In default mode, such non-null reconfiguration should cause # the nut-driver-enumerator service to restart and this would # propagate to other NUT services that depend on it. # 13 Sections and services differed, and still do not match up # 1 Bad inputs, e.g. unrecognized service management framework # 2 Absent or unreadable ups.conf file # # NOTE: Currently found caveats that might be solved later but require # considerable effort: # * Solaris SMF constrains the syntax of valid strings for instance names # (e.g. not starting with a digit, no period chars) which blocks creation # of some UPS driver instances. This might be worked around by hashing # the device name e.g. to base64 (and un-hashing instance name when calling # upsdrvctl), but is not quite user-friendly. Also can store device name # in a service attribute while mangling the instance name to a valid subset. # Comparisons (if devices are already wrapped) becomes more complicated in # the script in either case, as well as in the service startup method. # ** The `+` `/` `=` characters from base64 are also invalid for SMF instance # name, but the first two can be sed'ed to `-` `_` and back, for example. # Some prefix word is also needed (avoid starting with a digit). # The trailing padding `=` can be dropped, and added until we get a # non-empty decode. Conversions can be done by # `echo "$string" | openssl base64 -e|-d` # * Dummy-UPS services that "proxy" another locally defined section are # essentially a circular dependency for upsd. While the system might # start-up lacking a driver, there should be some timer to re-enable # failed not-disabled drivers (would be useful in any case though). # Directory where NUT configs are located, e.g. /etc/nut or /etc/ups # Set at package configuration, compiled into daemons and drivers prefix="@prefix@" [ -n "${NUT_CONFPATH-}" ] || NUT_CONFPATH="@sysconfdir@" # Technically this should be a distribution-dependent value configured # during package build. But everyone has it the same from systemd defaults: [ -n "${SYSTEMD_CONFPATH-}" ] || SYSTEMD_CONFPATH="/etc/systemd/system" if [ -n "$ZSH_VERSION" ]; then ### Problem: loops like `for UPS in $UPSLIST` do not separate ### the UPSLIST into many tokens but use it as one string. echo "FATAL: zsh is not supported in this script" >&2 exit 1 # setopt noglob # setopt +F # IFS="`printf ' \t\r\n'`" ; export IFS fi if set | grep -E '^(shell|version|t?csh)' | grep -E 't?csh' >/dev/null ; then echo "FATAL: csh or tcsh is not supported in this script" >&2 exit 1 fi # Third-party services to depend on (can be overridden by config file) ### Note that for systemd+udev integration, it may be better to set up ### triggers in udev, see e.g. ### http://stackoverflow.com/questions/18463755/linux-start-daemon-on-connected-usb-serial-dongle ### Also can tune whether a driver "Wants" another service (would consider ### ordering if that one is enabled, but live if it is disabled), or if it ### "Requires" that (would cause that to start). DEPSVC_USB_SYSTEMD="systemd-udev.service systemd-udev-settle.service" DEPREQ_USB_SYSTEMD="Wants" DEPSVC_NET_FULL_SYSTEMD="network-online.target systemd-resolved.service ifplugd.service" DEPREQ_NET_FULL_SYSTEMD="Wants" DEPSVC_NET_LOCAL_SYSTEMD="network.target" DEPREQ_NET_LOCAL_SYSTEMD="Wants" SVCNAME_SYSTEMD="nut-driver" # Some or all of these FMRIs may be related to dynamically changing hardware # require_all) ;; # All cited services are running (online or degraded) # require_any) ;; # At least one of the cited services is running # optional_all) ;; # (All) cited services are running or would not run # # without administrative action (disabled, maintenance, # # not present, or are waiting for dependencies which do # # not start without administrative action). DEPSVC_USB_SMF="svc:/system/hotplug:default svc:/system/dbus:default svc:/system/hal:default svc:/milestone/devices:default" DEPREQ_USB_SMF="optional_all" # By default there are several physical network FMRIs shipped and at most # only one is enabled on a particular system (e.g. :default or :nwam) DEPSVC_NET_FULL_SMF="svc:/network/physical svc:/milestone/name-services" DEPREQ_NET_FULL_SMF="optional_all" DEPSVC_NET_LOCAL_SMF="svc:/network/loopback:default" DEPREQ_NET_LOCAL_SMF="optional_all" SVCNAME_SMF="svc:/system/power/nut-driver" [ -z "${NUT_DRIVER_ENUMERATOR_CONF-}" ] && \ NUT_DRIVER_ENUMERATOR_CONF="${NUT_CONFPATH}/nut-driver-enumerator.conf" [ -s "${NUT_DRIVER_ENUMERATOR_CONF}" ] && \ echo "Sourcing config file: ${NUT_DRIVER_ENUMERATOR_CONF}" && \ . "${NUT_DRIVER_ENUMERATOR_CONF}" [ -z "${UPSCONF-}" ] && \ UPSCONF="${NUT_CONFPATH}/ups.conf" # Start a freshly-registered unit? [ -z "${AUTO_START-}" ] && AUTO_START=yes # We avoid regex '\t' which gets misinterpreted by some tools TABCHAR="`printf '\t'`" || TABCHAR=' ' if [ -z "${SERVICE_FRAMEWORK-}" ] ; then [ -x /usr/sbin/svcadm ] && [ -x /usr/sbin/svccfg ] && [ -x /usr/bin/svcs ] && [ -x /usr/bin/svcprop ] && \ SERVICE_FRAMEWORK="smf" [ -z "${SERVICE_FRAMEWORK-}" ] && \ [ -x /bin/systemctl ] && \ SERVICE_FRAMEWORK="systemd" fi # Optionally use Coreutils timeout to limit the # (potentially hanging) calls to systemd tools... # Should not hurt with SMF too, if it ever misbehaves. if [ -z "${TIMEOUT_CMD+x}" ]; then # Envvar not set at all (set but empty is okay, caller wants that then) TIMEOUT_CMD="" TIMEOUT_ARGS="" if which timeout 2>/dev/null >/dev/null ; then # Systemd default timeout for unit start/stop TIMEOUT_CMD="timeout" TIMEOUT_ARGS="90s" fi fi # Cache needed bits of ups.conf to speed up later parsing. Note that these # data are needed for most operations, and populated by upslist_readFile() UPSCONF_DATA="" # Subset of normalized data above that only has sections, drivers and ports (SDP) UPSCONF_DATA_SDP="" # List of configured UPSes in the config-file UPSLIST_FILE="" # List of configured service instances for UPS drivers UPSLIST_SVCS="" # Framework-specific implementations are generally hooked here: hook_registerInstance="" hook_unregisterInstance="" hook_refreshSupervizor="" hook_listInstances="" hook_listInstances_raw="" hook_validInstanceName="" hook_validFullUnitName="" hook_validInstanceSuffixName="" hook_getSavedMD5="" hook_setSavedMD5="" hook_restart_upsd="" hook_restart_drv="" case "${SERVICE_FRAMEWORK-}" in smf) hook_registerInstance="smf_registerInstance" hook_unregisterInstance="smf_unregisterInstance" hook_refreshSupervizor="smf_refreshSupervizor" hook_listInstances="smf_listInstances" hook_listInstances_raw="smf_listInstances_raw" hook_validInstanceName="smf_validInstanceName" hook_validFullUnitName="smf_validFullUnitName" hook_validInstanceSuffixName="smf_validInstanceSuffixName" hook_getSavedMD5="smf_getSavedMD5" hook_setSavedMD5="smf_setSavedMD5" hook_restart_upsd="smf_restart_upsd" hook_restart_drv="smf_restart_drv" ;; systemd) hook_registerInstance="systemd_registerInstance" hook_unregisterInstance="systemd_unregisterInstance" hook_refreshSupervizor="systemd_refreshSupervizor" hook_listInstances="systemd_listInstances" hook_listInstances_raw="systemd_listInstances_raw" hook_validInstanceName="systemd_validInstanceName" hook_validFullUnitName="systemd_validFullUnitName" hook_validInstanceSuffixName="systemd_validInstanceSuffixName" hook_getSavedMD5="systemd_getSavedMD5" hook_setSavedMD5="systemd_setSavedMD5" hook_restart_upsd="systemd_restart_upsd" hook_restart_drv="systemd_restart_drv" ;; selftest) hook_registerInstance="selftest_NOOP" hook_unregisterInstance="selftest_NOOP" hook_refreshSupervizor="selftest_NOOP" hook_listInstances="selftest_NOOP" hook_listInstances_raw="selftest_NOOP" hook_validInstanceName="selftest_NOOP" hook_validFullUnitName="selftest_NOOP" hook_validInstanceSuffixName="selftest_NOOP" hook_getSavedMD5="selftest_NOOP" hook_setSavedMD5="selftest_NOOP" hook_restart_upsd="selftest_NOOP" hook_restart_drv="selftest_NOOP" ;; "") echo "Error detecting the service-management framework on this OS" >&2 exit 1 ;; *) echo "Error: User provided an unknown service-management framework '$SERVICE_FRAMEWORK'" >&2 exit 1 ;; esac selftest_NOOP() { echo "NO-OP: Self-testing context does not do systems configuration" >&2 return 0 } common_isFiled() { [ -n "$UPSLIST_FILE" ] && \ for UPSF in $UPSLIST_FILE ; do [ "$1" = "$UPSF" ] && return 0 [ "`$hook_validInstanceName "$UPSF"`" = "$1" ] && return 0 done return 1 } common_isRegistered() { [ -n "$UPSLIST_SVCS" ] && \ for UPSS in $UPSLIST_SVCS ; do [ "$1" = "$UPSS" ] && return 0 [ "`$hook_validInstanceName "$1"`" = "$UPSS" ] && return 0 done return 1 } upslist_equals() { # Compare pre-sorted list of DEVICES ($1) and SVCINSTs ($2) including # the possible mangling for service names. Return 0 if lists describe # exactly same set of devices and their services. # Note: This logic only checks the names, not the contents of device # sections, so re-definitions of an existing device configuration # would not trigger a service restart by itself. Such deeper check # belongs in a different routine, see upssvcconf_checksum_unchanged(). # Trivial case 0: one string is empty, another is not # Note: `echo '' | wc -l` == "1" not "0"! [ -n "$1" -a -z "$2" ] && return 1 [ -z "$1" -a -n "$2" ] && return 1 # Trivial case 1: equal strings [ "$1" = "$2" ] && return 0 # Trivial case 2: different amount of entries [ "`echo "$1" | wc -l`" = "`echo "$2" | wc -l`" ] || return $? _TMP_DEV_SVC="" for _DEV in $1 ; do DEVINST="`$hook_validInstanceName "$_DEV"`" for _SVC in $2 ; do [ "$_DEV" = "$_SVC" ] \ || [ "$DEVINST" = "$_SVC" ] \ && { [ -z "$_TMP_DEV_SVC" ] \ && _TMP_DEV_SVC="$_DEV = $_SVC" \ || _TMP_DEV_SVC="$_TMP_DEV_SVC $_DEV = $_SVC" ; } done done # Input was not empty; did anything in output fit? [ -z "$_TMP_DEV_SVC" ] && return 1 # Exit code : is the built mapping as long as the source list(s)? [ "`echo "$1" | wc -l`" = "`echo "$_TMP_DEV_SVC" | wc -l`" ] } upssvcconf_checksum_unchanged() { # $1 = dev, $2 = svc # compare checksums of the configuration section from the file and the # stashed configuration in a service instance (if any). # FIXME : optimize by caching, we likely have quite a few requests [ "`upsconf_getSection_MD5 "$1"`" = "`$hook_getSavedMD5 "$2"`" ] } upslist_checksums_unchanged() { # For each device and its corresponding unit, compare checksums of the # configuration section from the file and the stashed configuration in # a service instance. Prints a list of mismatching service names that # should get reconfigured. [ -z "$1" -o -z "$2" ] && return 1 _TMP_SVC="" for _DEV in $1 ; do DEVINST="`$hook_validInstanceName "$_DEV"`" for _SVC in $2 ; do if [ "$_DEV" = "$_SVC" ] \ || [ "$DEVINST" = "$_SVC" ] \ ; then upssvcconf_checksum_unchanged "$_DEV" "$_SVC" || \ { [ -z "$_TMP_SVC" ] \ && _TMP_SVC="$_SVC" \ || _TMP_SVC="$_TMP_SVC $_SVC" ; } fi done done [ -z "$_TMP_SVC" ] && return 0 echo "$_TMP_SVC" return 1 } upsconf_getSection_content() { # "$1" = name of ups.conf section to display in whole, from whatever # comes on stdin (file or a pre-made normalized variable) # empty "$1" means the global config (before any sections) # # NOTE (TODO?): This routine finds the one NUT device section, prints it # and returns when the section is over. It currently does not cover (in # a way allowing to do it efficiently) selection of several sections, # or storing each section content in some array or dynamic variables # (as would be better fit for portable shells) to later address them # quickly without re-parsing the file or big envvar many times. # CURR_SECTION="" SECTION_CONTENT="" RES=1 [ -n "$1" ] || RES=0 while read LINE ; do case "$LINE" in \["$1"\]) if [ "$RES" = 0 ]; then # We have already displayed a section, here is a new one, # and this routine only displays one (TODO: toggle?) break fi SECTION_CONTENT="$LINE" CURR_SECTION="$1" RES=0 continue ;; \[*\ *\]|\[*"$TABCHAR"*\]) # Note that section-name brackets should contain a single token # Fall through to add the line to contents of existing section ;; \[*\]) [ "$CURR_SECTION" = "$1" ] && break # Use a value that can not be a section name here: CURR_SECTION="[]" continue ;; "") continue ;; *) ;; # Fall through to add the line to contents of existing section esac if [ "$CURR_SECTION" = "$1" ]; then if [ -n "$SECTION_CONTENT" ]; then SECTION_CONTENT="$SECTION_CONTENT $LINE" else SECTION_CONTENT="$LINE" fi fi done if [ -n "$SECTION_CONTENT" ]; then echo "$SECTION_CONTENT" fi [ "$RES" = 0 ] || echo "ERROR: Section [$1] was not found in the '$UPSCONF' file" >&2 return $RES } upsconf_getSection() { # Use the whole output of normalization parser upslist_normalizeFile_once || return # Propagate errors upwards upsconf_getSection_content "$@" << EOF ${UPSCONF_DATA} EOF } upsconf_getSection_MD5() { calc_md5 "`upsconf_getSection "$@"`" } upsconf_getSection_SDP() { # Use the section-driver-port subset upslist_normalizeFile_once || return # Propagate errors upwards upsconf_getSection_content "$@" << EOF ${UPSCONF_DATA_SDP} EOF } upsconf_getValue() { # "$1" = name of ups.conf section, may be empty for global config # "$2..$N" = name of config key; we will echo its value ### [ -n "$1" ] || return $? [ -n "$2" ] || return $? [ -n "$GETSECTION" ] || GETSECTION="upsconf_getSection" CURR_SECTION="" # Gets set by a GETSECTION implementation RES=0 # Note: Primary aim of this egrep is to pick either assignments or flags # As a by-product it can be used to test if a particular value is set ;) SECTION_CONTENT="`$GETSECTION "$1"`" || return shift KEYS="$*" while [ "$#" -gt 0 ] ; do RES_L=0 VALUE="" LINE="`echo "$SECTION_CONTENT" | grep -E '(^'"$1"'=|^'"$1"'$)'`" \ && VALUE="$(echo "$LINE" | sed -e "s,^$1=,," -e 's,^\"\(.*\)\"$,\1,' -e "s,^'\(.*\)'$,\1,")" \ || RES_L=$? [ "$RES_L" = 0 ] || { RES="$RES_L" ; echo "ERROR: Section [$CURR_SECTION] or key '$1' in it was not found in the '$UPSCONF' file" >&2 ; } echo "$VALUE" shift done [ "$RES" = 0 ] || echo "ERROR: Section [$CURR_SECTION] or key(s) '$KEYS' in it was not found in the '$UPSCONF' file" >&2 return $RES } upsconf_getDriver() { # "$1" = name of ups.conf section; return (echo) the driver name used there # In the context this function is used, UPSCONF exists and section is there GETSECTION="upsconf_getSection_SDP" upsconf_getValue "$1" "driver" return $? } upsconf_getPort() { # "$1" = name of ups.conf section; return (echo) the "port" name used there # In the context this function is used, UPSCONF exists and section is there GETSECTION="upsconf_getSection_SDP" upsconf_getValue "$1" "port" return $? } upsconf_getDriverMedia() { # "$1" = name of ups.conf section; return (echo) name and type of driver as # needed for dependency evaluation (what services we must depend on for this # unit), newline-separated (drvnametype). Empty type for unclassified # results, assuming no known special dependencies (note that depending on # particular system's physics, both serial and network media may need USB). CURR_DRV="`upsconf_getDriver "$1"`" || return $? case "$CURR_DRV" in *netxml*|*snmp*|*ipmi*|*powerman*|*-mib*|*avahi*) printf '%s\n%s\n' "$CURR_DRV" "network" ; return ;; *apcupsd-ups*) # Relay from a nearby apcupsd network server into NUT ecosystem: CURR_PORT="`upsconf_getPort "$1"`" || CURR_PORT="" case "$CURR_PORT" in *localhost*|*127.0.0.1*|*::1*) printf '%s\n%s\n' "$CURR_DRV" "network-localhost" ; return ;; *) printf '%s\n%s\n' "$CURR_DRV" "network" ; return ;; esac ;; *apc_modbus*) CURR_PORT="`upsconf_getPort "$1"`" || CURR_PORT="" CURR_PORTTYPE="`upsconf_getValue "$1" 'porttype'`" || CURR_PORTTYPE="" case "$CURR_PORTTYPE" in *usb*) printf '%s\n%s\n' "$CURR_DRV" "usb" ; return ;; *serial*) printf '%s\n%s\n' "$CURR_DRV" "serial" ; return ;; *) # default depends on driver build (against libmodbus # version with or without support for usb) # TOTHINK: Check for presence of config values like # vendorid (USB) or baud (Serial)? They are optional # with reasonable defaults anyway... case "$CURR_PORT" in *auto*) printf '%s\n%s\n' "$CURR_DRV" "usb" ; return ;; /*) printf '%s\n%s\n' "$CURR_DRV" "serial" ; return ;; *localhost*|*127.0.0.1*|*::1*) printf '%s\n%s\n' "$CURR_DRV" "network-localhost" ; return ;; *) printf '%s\n%s\n' "$CURR_DRV" "network" ; return ;; esac # returns are above, but just in case - have a fallback: printf '%s\n%s\n' "$CURR_DRV" "" ; return ;; esac ;; *usb*) printf '%s\n%s\n' "$CURR_DRV" "usb" ; return ;; nutdrv_qx) # May be direct serial or USB CURR_PORT="`upsconf_getPort "$1"`" || CURR_PORT="" case "$CURR_PORT" in auto|/dev/*usb*|/dev/*hid*) printf '%s\n%s\n' "$CURR_DRV" "usb" ; return ;; /dev/*) # See drivers/nutdrv_qx.c :: upsdrv_initups() for a list if [ -n "`upsconf_getValue "$1" 'subdriver' 'vendorid' 'productid' 'vendor' 'product' 'serial' 'bus' 'busport' 'langid_fix'`" ] \ ; then printf '%s\n%s\n' "$CURR_DRV" "usb" ; return else printf '%s\n%s\n' "$CURR_DRV" "serial" ; return fi ;; *) printf '%s\n%s\n' "$CURR_DRV" "" ; return ;; esac ;; *dummy*|*clone*) # May be networked (proxy to remote NUT) CURR_PORT="`upsconf_getPort "$1"`" || CURR_PORT="" case "$CURR_PORT" in *@localhost|*@|*@127.0.0.1|*@::1) printf '%s\n%s\n' "$CURR_DRV" "network-localhost" ; return ;; *@*) printf '%s\n%s\n' "$CURR_DRV" "network" ; return ;; *) printf '%s\n%s\n' "$CURR_DRV" "" ; return ;; esac ;; *) printf '%s\n%s\n' "$CURR_DRV" "" ; return ;; esac } upsconf_getMedia() { _DRVMED="`upsconf_getDriverMedia "$1"`" || return echo "$_DRVMED" | tail -n +2 return 0 } upsconf_debug() { _DRV="`upsconf_getDriver "$1"`" _PRT="`upsconf_getPort "$1"`" _MED="`upsconf_getMedia "$1"`" _MD5="`upsconf_getSection_MD5 "$1"`" NAME_MD5="`calc_md5 "$1"`" echo "INST: ${NAME_MD5}~[$1]: DRV='$_DRV' PORT='$_PRT' MEDIA='$_MED' SECTIONMD5='$_MD5'" } calc_md5() { # Tries several ways to produce an MD5 of the "$1" argument _MD5="`echo "$1" | md5sum 2>/dev/null | awk '{print $1}'`" && [ -n "$_MD5" ] || \ { _MD5="`echo "$1" | openssl dgst -md5 2>/dev/null | awk '{print $NF}'`" && [ -n "$_MD5" ]; } || \ return 1 echo "$_MD5" } calc_md5_file() { # Tries several ways to produce an MD5 of the file named by "$1" argument [ -s "$1" ] || return 2 _MD5="`md5sum 2>/dev/null < "$1" | awk '{print $1}'`" && [ -n "$_MD5" ] || \ { _MD5="`openssl dgst -md5 2>/dev/null < "$1" | awk '{print $NF}'`" && [ -n "$_MD5" ]; } || \ return 1 echo "$_MD5" } smf_validFullUnitName() { case "$1" in *:*) echo "$1" ;; *) echo "$SVCNAME_SMF:$1" ;; esac } smf_validInstanceName() { echo "MD5_`calc_md5 "$1"`" } smf_validInstanceSuffixName() { case "$1" in *:*) echo "$1" | sed 's,^.*:\([^:]*\)$,\1,' ;; *) echo "$1" ;; esac } smf_registerInstance() { DEVICE="$1" SVCINST="$1" /usr/sbin/svccfg -s nut-driver add "$DEVICE" || \ { SVCINST="`smf_validInstanceName "$1"`" && \ /usr/sbin/svccfg -s nut-driver add "$SVCINST" || return ; } echo "Added instance: 'nut-driver:$SVCINST' for NUT configuration section '$DEVICE'" >&2 DEPSVC="" DEPREQ="" _MED="`upsconf_getMedia "$DEVICE"`" case "$_MED" in usb) DEPSVC="$DEPSVC_USB_SMF" DEPREQ="$DEPREQ_USB_SMF" ;; network-localhost) DEPSVC="$DEPSVC_NET_LOCAL_SMF" DEPREQ="$DEPREQ_NET_LOCAL_SMF" ;; network) DEPSVC="$DEPSVC_NET_FULL_SMF" DEPREQ="$DEPREQ_NET_FULL_SMF" ;; serial) ;; '') ;; *) echo "WARNING: Unexpected NUT media type ignored: '$_MED'" >&2 ;; esac TARGET_FMRI="nut-driver:$SVCINST" if [ -n "$DEPSVC" ]; then [ -n "$DEPREQ" ] || DEPREQ="optional_all" echo "Adding '$DEPREQ' dependency for '$SVCINST' on '$DEPSVC'..." DEPPG="nut-driver-enumerator-generated" RESTARTON="refresh" /usr/sbin/svccfg -s "$TARGET_FMRI" addpg "$DEPPG" dependency && \ /usr/sbin/svccfg -s "$TARGET_FMRI" setprop "$DEPPG"/grouping = astring: "$DEPREQ" && \ /usr/sbin/svccfg -s "$TARGET_FMRI" setprop "$DEPPG"/restart_on = astring: "$RESTARTON" && \ /usr/sbin/svccfg -s "$TARGET_FMRI" setprop "$DEPPG"/type = astring: service && \ /usr/sbin/svccfg -s "$TARGET_FMRI" setprop "$DEPPG"/entities = fmri: "($DEPSVC)" && \ echo "OK" || echo "FAILED to define the dependency" >&2 fi smf_setSavedMD5 "$SVCINST" "`upsconf_getSection_MD5 "$DEVICE"`" /usr/sbin/svcadm refresh "${TARGET_FMRI}" || return if [ "$AUTO_START" = yes ] ; then /usr/sbin/svcadm clear "${TARGET_FMRI}" 2>/dev/null || true /usr/sbin/svcadm enable "${TARGET_FMRI}" || return echo "Started instance: 'nut-driver:$SVCINST' for NUT configuration section '$DEVICE'" >&2 fi } smf_unregisterInstance() { echo "Removing instance: 'nut-driver:$1' ..." >&2 /usr/sbin/svcadm disable -ts 'nut-driver:'"$1" || false /usr/sbin/svccfg -s nut-driver delete "$1" } smf_refreshSupervizor() { : } smf_listInstances_raw() { # Newer versions have pattern matching; older SMF might not have this luxury /usr/bin/svcs -a -H -o fmri | grep -E '/nut-driver:' } smf_listInstances() { smf_listInstances_raw | sed 's/^.*://' | sort -n } smf_getSavedMD5() { # Query service instance $1 PG="nut-driver-enumerator-generated-checksum" PROP="SECTION_CHECKSUM" if [ -n "$1" ]; then TARGET_FMRI="nut-driver:$1" else # Global section TARGET_FMRI="nut-driver" PROP="SECTION_CHECKSUM_GLOBAL" fi # Note: lookups for GLOBAL cause each service instance to show up /usr/bin/svcprop -p "$PG/$PROP" "$TARGET_FMRI" | head -1 | awk '{print $NF}' } smf_setSavedMD5() { # Save checksum value $2 into service instance $1 PG="nut-driver-enumerator-generated-checksum" PROP="SECTION_CHECKSUM" if [ -n "$1" ]; then TARGET_FMRI="nut-driver:$1" else # Global section TARGET_FMRI="nut-driver" PROP="SECTION_CHECKSUM_GLOBAL" fi /usr/sbin/svccfg -s "$TARGET_FMRI" delprop "$PG" || true /usr/sbin/svccfg -s "$TARGET_FMRI" addpg "$PG" application && \ /usr/sbin/svccfg -s "$TARGET_FMRI" setprop "$PG/$PROP" = astring: "$2" [ $? = 0 ] && echo "OK" || { echo "FAILED to stash the checksum">&2 ; return 1 ; } /usr/sbin/svcadm refresh "${TARGET_FMRI}" || return } smf_restart_upsd() { echo "Reloading or restarting NUT data server to make sure it knows new configuration..." /usr/sbin/svcadm enable "nut-server" 2>/dev/null /usr/sbin/svcadm clear "nut-server" 2>/dev/null /usr/sbin/svcadm refresh "nut-server" || \ /usr/sbin/svcadm restart "nut-server" } smf_restart_drv() { echo "Reloading or restarting NUT driver instance '$1' to make sure it knows new configuration..." /usr/sbin/svcadm enable "nut-driver:$1" 2>/dev/null /usr/sbin/svcadm clear "nut-driver:$1" 2>/dev/null /usr/sbin/svcadm refresh "nut-driver:$1" || \ /usr/sbin/svcadm restart "nut-driver:$1" } systemd_validFullUnitName() { case "$1" in *@*.*) echo "$1" ;; *@*) echo "$1.service" ;; *) echo "$SVCNAME_SYSTEMD@$1.service" ;; esac } systemd_validInstanceName() { echo "MD5_`calc_md5 "$1"`" } systemd_validInstanceSuffixName() { echo "$1" | sed -e 's,^.*@,,' -e 's,\.service$,,' } systemd_registerInstance() { # Instance is registered by device section name; ultimate name in systemd may differ DEVICE="$1" SVCINST="$1" /bin/systemctl enable 'nut-driver@'"$DEVICE".service || \ { SVCINST="`systemd_validInstanceName "$1"`" && \ /bin/systemctl enable 'nut-driver@'"$SVCINST".service || return ; } echo "Enabled instance: 'nut-driver@$SVCINST' for NUT configuration section '$DEVICE'" >&2 DEPSVC="" DEPREQ="" _MED="`upsconf_getMedia "$DEVICE"`" case "$_MED" in usb) DEPSVC="$DEPSVC_USB_SYSTEMD" DEPREQ="$DEPREQ_USB_SYSTEMD" ;; network-localhost) DEPSVC="$DEPSVC_NET_LOCAL_SYSTEMD" DEPREQ="$DEPREQ_NET_LOCAL_SYSTEMD" ;; network) DEPSVC="$DEPSVC_NET_FULL_SYSTEMD" DEPREQ="$DEPREQ_NET_FULL_SYSTEMD" ;; serial) ;; '') ;; *) echo "WARNING: Unexpected NUT media type ignored: '$_MED'" >&2 ;; esac if [ -n "$DEPSVC" ]; then [ -n "$DEPREQ" ] || DEPREQ="#Wants" echo "Adding '$DEPREQ'+After dependency for '$SVCINST' on '$DEPSVC'..." mkdir -p "${SYSTEMD_CONFPATH}/nut-driver@$SVCINST.service.d" && \ cat > "${SYSTEMD_CONFPATH}/nut-driver@$SVCINST.service.d/nut-driver-enumerator-generated.conf" <&2 fi systemd_setSavedMD5 "$SVCINST" "`upsconf_getSection_MD5 "$DEVICE"`" if [ "$AUTO_START" = yes ] ; then systemd_refreshSupervizor || echo "WARNING: Somehow managed to fail systemd_refreshSupervizor()" >&2 $TIMEOUT_CMD $TIMEOUT_ARGS /bin/systemctl start --no-block 'nut-driver@'"$SVCINST".service || return echo "Started instance: 'nut-driver@$SVCINST' for NUT configuration section '$DEVICE'" >&2 fi } systemd_unregisterInstance() { echo "Removing instance: 'nut-driver@$1' ..." >&2 $TIMEOUT_CMD $TIMEOUT_ARGS /bin/systemctl stop 'nut-driver@'"$1".service || \ $TIMEOUT_CMD $TIMEOUT_ARGS /bin/systemctl stop 'nut-driver@'"$1".service || \ $TIMEOUT_CMD $TIMEOUT_ARGS /bin/systemctl stop 'nut-driver@'"$1".service || false /bin/systemctl disable 'nut-driver@'"$1".service rm -rf "${SYSTEMD_CONFPATH}/nut-driver@$1.service.d" /bin/systemctl reset-failed 'nut-driver@'"$1".service } systemd_refreshSupervizor() { /bin/systemctl daemon-reload } systemd_listInstances_raw() { /bin/systemctl show 'nut-driver@*' -p Id | grep -E '=nut-driver' | sed 's,^Id=,,' } systemd_listInstances() { systemd_listInstances_raw | sed -e 's/^.*@//' -e 's/\.service$//' | sort -n } systemd_getSavedMD5() { # Query service instance $1 or global section PROP="SECTION_CHECKSUM" [ -n "$1" ] || PROP="SECTION_CHECKSUM_GLOBAL" [ -s "${SYSTEMD_CONFPATH}/nut-driver@$1.service.d/nut-driver-enumerator-generated-checksum.conf" ] \ && grep "Environment='$PROP=" "${SYSTEMD_CONFPATH}/nut-driver@$1.service.d/nut-driver-enumerator-generated-checksum.conf" | sed -e "s,^Environment='$PROP=,," -e "s,'\$,," \ || { echo "Did not find '${SYSTEMD_CONFPATH}/nut-driver@$1.service.d/nut-driver-enumerator-generated-checksum.conf' with a $PROP" ; return 1; } } systemd_setSavedMD5() { # Save checksum value $2 into service instance $1 PROP="SECTION_CHECKSUM" [ -n "$1" ] || PROP="SECTION_CHECKSUM_GLOBAL" mkdir -p "${SYSTEMD_CONFPATH}/nut-driver@$1.service.d" && \ cat > "${SYSTEMD_CONFPATH}/nut-driver@$1.service.d/nut-driver-enumerator-generated-checksum.conf" << EOF [Service] Environment='$PROP=$2' EOF [ $? = 0 ] && echo "OK" || { echo "FAILED to stash the checksum">&2 ; return 1 ; } } systemd_restart_upsd() { # Do not restart/reload if not already running case "`/bin/systemctl is-active "nut-server"`" in active|unknown) ;; # unknown meant "starting" in our testing... failed) echo "Note: nut-server unit was 'failed' - not disabled by user, so (re)starting it (probably had no config initially)" >&2 ;; *) return 0 ;; esac echo "Reloading or restarting NUT data server to make sure it knows new configuration..." # Note: reload is a better way to go about this, so the # data service is not interrupted by re-initialization # of the daemon. But systemd/systemctl sometimes stalls... $TIMEOUT_CMD $TIMEOUT_ARGS /bin/systemctl reload-or-restart "nut-server" || \ $TIMEOUT_CMD $TIMEOUT_ARGS /bin/systemctl restart "nut-server" } systemd_restart_drv() { # Do not restart/reload if not already running case "`/bin/systemctl is-active "nut-driver@$1"`" in active|unknown) ;; *) return 0 ;; esac echo "Reloading or restarting NUT driver instance '$1' to make sure it knows new configuration..." # Full restart, e.g. in case we changed the user= in configs # however let "reload" try, in case we changed something that # can be updated "on the fly", like the "debug_min" setting. $TIMEOUT_CMD $TIMEOUT_ARGS /bin/systemctl reload-or-restart "nut-driver@$1" || \ $TIMEOUT_CMD $TIMEOUT_ARGS /bin/systemctl restart "nut-driver@$1" } upslist_normalizeFile_filter() { # See upslist_normalizeFile() detailed comments below; this routine # is a pipe worker to prepare the text into a simpler expected form. # Pick the lines which contain a bracket or assignment character, # or a single token (certain keywords come as just NUT "flags"), # trim leading and trailing whitespace, comment-only lines, and in # assignment lines trim the spaces around equality character and # quoting characters around assignment of values without whitespaces. # Any whitespace characters around a section name (single token that # starts the line and is enclosed in brackets) and a trailing comment # are dropped. Note that brackets with spaces inside, and brackets # that do not start the non-whitespace payload of the line, are not # sections. grep -E -v '(^$|^#)' | \ sed -e 's,^['"$TABCHAR"'\ ]*,,' \ -e 's,^\#.*$,,' \ -e 's,['"$TABCHAR"'\ ]*$,,' \ -e 's,^\([^=\ '"$TABCHAR"']*\)['"$TABCHAR"'\ ]*=['"$TABCHAR"'\ ]*,\1=,g' \ -e 's,=\"\([^\ '"$TABCHAR"']*\)\"$,=\1,' \ -e 's,^\(\[[^]'"$TABCHAR"'\ ]*\]\)['"$TABCHAR"'\ ]*\(#.*\)*$,\1,' \ | grep -E -v '^$' \ | grep -E '([\[\=]|^[^ '"$TABCHAR"']*$|^[^ '"$TABCHAR"']*[ '"$TABCHAR"']*#.*$)' } upslist_normalizeFile() { # Read the ups.conf file and find all defined sections (names of # configuration blocks for drivers that connect to a certain device # using specified protocol and media); normalize section contents # as detailed below, to simplify subsequent parsing and comparison. # File contents UPSCONF_DATA="" UPSCONF_DATA_SDP="" if [ -n "$UPSCONF" ] && [ -f "$UPSCONF" ] && [ -r "$UPSCONF" ]; then [ ! -s "$UPSCONF" ] \ && echo "WARNING: The '$UPSCONF' file exists but is empty" >&2 \ && return 0 # Ok to continue - we may end up removing all instances else echo "FATAL: The '$UPSCONF' file does not exist or is not readable" >&2 return 2 fi # Store a normalized version of NUT configuration file contents. # Also use a SDP subset with just section, driver and port info # for faster parsing when determining driver-required media etc. UPSCONF_DATA="$(upslist_normalizeFile_filter < "$UPSCONF")" \ && [ -n "$UPSCONF_DATA" ] \ && UPSCONF_DATA_SDP="`grep -E '^(\[.*\]|driver=|port=)' << EOF $UPSCONF_DATA EOF`" \ || { echo "Error reading the '$UPSCONF' file or it does not declare any device configurations: nothing left after normalization" >&2 UPSCONF_DATA="" UPSCONF_DATA_SDP="" } } upslist_normalizeFile_once() { # Wrapper that ensures that the parsing is only done once # (will re-parse if there were no devices listed on the # first time, though) [ -z "$UPSCONF_DATA" ] && [ -z "$UPSCONF_DATA_SDP" ] || return 0 upslist_normalizeFile } upslist_readFile() { # Use the routine above (unconditionally) to get or update the # listing of device sections known at this moment. # List of devices from the config file UPSLIST_FILE="" if [ "$DO_NORMALIZE_ONCE" = yes ]; then upslist_normalizeFile_once || return # Propagate errors upwards else upslist_normalizeFile || return # Propagate errors upwards fi if [ -n "$UPSCONF_DATA" ] ; then # Note that section-name brackets should contain a single token UPSLIST_FILE="$(echo "$UPSCONF_DATA_SDP" | grep -E '^\[[^'"$TABCHAR"'\ ]*\]$' | sed 's,^\[\(.*\)\]$,\1,' | sort -n)" \ || UPSLIST_FILE="" if [ -z "$UPSLIST_FILE" ] ; then echo "Error reading the '$UPSCONF' file or it does not declare any device configurations: no section declarations in parsed normalized contents" >&2 fi fi # Ok to continue with empty results - we may end up removing all instances } upslist_readFile_once() { # Wrapper that ensures that the parsing is only done once # (will re-parse if there were no devices listed on the # first time, though) [ -z "$UPSLIST_FILE" ] || return 0 DO_NORMALIZE_ONCE=yes upslist_readFile } upslist_readSvcs() { UPSLIST_SVCS="`$hook_listInstances`" || UPSLIST_SVCS="" if [ -z "$UPSLIST_SVCS" ] && [ "$1" != "-" ] ; then EXPLAIN="" [ -z "$1" ] || EXPLAIN=" - $1" echo "Error reading the list of ${SERVICE_FRAMEWORK-} service instances for UPS drivers, or none are defined${EXPLAIN}" >&2 # Ok to continue - we may end up defining new instances fi } upslist_debug() { for UPSF in "" $UPSLIST_FILE ; do upsconf_debug "$UPSF" done } upslist_addSvcs() { # Note: This routine registers service instances for device config sections # that are not wrapped currently. Support for redefined previously existing # sections - is attained by removing the old service instance elsewhere and # recreating it here, since any data could change including the dependency # list, etc. for UPSF in $UPSLIST_FILE ; do if ! common_isRegistered "$UPSF" ; then echo "Adding new ${SERVICE_FRAMEWORK} service instance for power device [${UPSF}]..." >&2 $hook_registerInstance "$UPSF" fi done } upslist_delSvcs() { for UPSS in $UPSLIST_SVCS ; do if ! common_isFiled "$UPSS" ; then echo "Dropping old ${SERVICE_FRAMEWORK} service instance for power device [${UPSS}] which is no longer in config file..." >&2 $hook_unregisterInstance "$UPSS" fi done } upslist_restartSvcs() { for UPSS in $UPSLIST_SVCS ; do if common_isFiled "$UPSS" ; then $hook_restart_drv "$UPSS" fi done } nut_driver_enumerator_main() { ################# MAIN PROGRAM by default # Note: do not use the read..._once() here, to ensure that the # looped daemon sees the whole picture, which can be new every time upslist_readFile || return $? #upslist_debug upslist_readSvcs "before manipulations" # Test if global config has changed since last run RESTART_ALL=no upssvcconf_checksum_unchanged "" || { echo "`date -u` : Detected changes in global section of '$UPSCONF', will restart all drivers"; RESTART_ALL=yes; } # Quickly exit if there's nothing to do; note the lists are pre-sorted # Otherwise a non-zero exit will be done below # Note: We implement testing in detail whether section definitions were # changed since last run, as a first step before checking that name # lists are still equivalent, because we need to always have the result # of the "has it changed?" check as a hit-list of something to remove, # while the check for no new device section definitions is just boolean. # We can only exit quickly if both there are no changed sections and no # new or removed sections since last run. NEW_CHECKSUM="`upslist_checksums_unchanged "$UPSLIST_FILE" "$UPSLIST_SVCS"`" \ && [ -z "$NEW_CHECKSUM" ] \ && upslist_equals "$UPSLIST_FILE" "$UPSLIST_SVCS" \ && if [ -z "$DAEMON_SLEEP" -o "${VERBOSE_LOOP}" = yes ] ; then \ echo "`date -u` : OK: No changes to reconcile between ${SERVICE_FRAMEWORK} service instances and device configurations in '$UPSCONF'" ; \ fi \ && [ "$RESTART_ALL" = no ] && return 0 if [ -n "$NEW_CHECKSUM" ]; then for UPSS in $NEW_CHECKSUM ; do CURR_DRV="`upsconf_getDriver "$UPSS"`" || CURR_DRV="" DO_UNREGISTER=yes if [ -n "$CURR_DRV" ] ; then # If reload is handled and does not complain, # we are OK to proceed without re-defining # and restarting the driver service instance. "@DRVPATH@/$CURR_DRV" -a "$UPSS" -c reload-or-error >/dev/null 2>/dev/null \ && DO_UNREGISTER=no fi if [ "$DO_UNREGISTER" = yes ] ; then echo "Dropping old ${SERVICE_FRAMEWORK} service instance ${UPSS} whose section in config file has changed..." >&2 $hook_unregisterInstance "$UPSS" else echo "Keeping ${SERVICE_FRAMEWORK} service instance ${UPSS} whose section in config file has changed: live reload sufficed" >&2 fi done upslist_readSvcs "after updating for new config section checksums" fi if [ -n "$UPSLIST_SVCS" ]; then # Drop services that are not in config file (any more?) upslist_delSvcs if [ "$RESTART_ALL" = yes ] && [ "$AUTO_START" = yes ] ; then # Here restart only existing services; new ones will (try to) # start soon after creation and upsd is handled below upslist_restartSvcs fi fi if [ "$RESTART_ALL" = yes ] ; then # Save new checksum of global config $hook_setSavedMD5 "" "`upsconf_getSection_MD5 ""`" fi if [ -n "$UPSLIST_FILE" ]; then # Add services for sections that are in config file but not yet wrapped upslist_addSvcs $hook_refreshSupervizor upslist_readSvcs "after checking for new config sections to define service instances" fi upslist_readSvcs if [ -n "$UPSLIST_SVCS" ] ; then echo "=== The currently defined service instances are:" echo "$UPSLIST_SVCS" fi if [ -n "$UPSLIST_FILE" ] ; then echo "=== The currently defined configurations in '$UPSCONF' are:" echo "$UPSLIST_FILE" fi # We had some changes to the config file; upsd must be made aware if [ "$AUTO_START" = yes ] ; then $hook_restart_upsd fi # Return 42 if there was a change applied succesfully # (but e.g. some services should restart - upsd, maybe upsmon) UPSLIST_EQ_RES=0 upslist_equals "$UPSLIST_FILE" "$UPSLIST_SVCS" || UPSLIST_EQ_RES=$? # File processing and service startups take a while; # make sure upsconf did not change while we worked... # NOTE: Check this at the last moment to minimize # the chance of still not noticing the change made # at just the wrong moment. UPSCONF_CHECKSUM_END="`calc_md5_file "$UPSCONF"`" || true if [ "$UPSCONF_CHECKSUM_END" != "$UPSCONF_CHECKSUM_START" ] ; then # NOTE: even if daemonized, the sleep between iterations # can be configured into an uncomfortably long lag, so # we should re-sync the system config in any case. echo "`date -u` : '$UPSCONF' changed while $0 $* was processing its older contents; re-running the script to pick up the late-coming changes" # Make sure the cycle does not repeat itself due to diffs # from an ages-old state of the file from when we started. UPSCONF_CHECKSUM_START="$UPSCONF_CHECKSUM_END" ( nut_driver_enumerator_main ) ; return $? # The "main" routine at the end of recursions will # do REPORT_RESTART_42 logic or the error exit-code fi if [ "$UPSLIST_EQ_RES" = 0 ] ; then echo "`date -u` : OK: No more changes to reconcile between ${SERVICE_FRAMEWORK} service instances and device configurations in '$UPSCONF'" [ "${REPORT_RESTART_42-}" = no ] && return 0 || return 42 fi return 13 } daemonize() ( # Support (SIG)HUP == signal code 1 to quickly reconfigure, # e.g. to request it while the sleep is happening or while # "main" is processing an earlier change of the file. RECONFIGURE_ASAP=false trap 'RECONFIGURE_ASAP=true' 1 # Note: this loop would die on errors with config file or # inability to ensure that it matches the list of services. # If caller did not `export REPORT_RESTART_42=no` then the # loop would exit with code 42, and probably trigger restart # of the service which wraps this daemon do topple others that # depend on it. # Note: do not quickly skip the "main" based on full-file # checksum refresh, to ensure that whatever is configured # gets applied (e.g. if user disabled some services or they # died, or some config was not applied due to coding error). while nut_driver_enumerator_main ; do if $RECONFIGURE_ASAP ; then echo "`date -u` : Trapped a SIGHUP during last run of nut_driver_enumerator_main, repeating reconfiguration quickly" >&2 else sleep $DAEMON_SLEEP & trap "kill $! ; echo 'Sleep interrupted, processing configs now!'>&2" 1 wait $! fi RECONFIGURE_ASAP=false trap 'RECONFIGURE_ASAP=true' 1 done exit $? ) # Save the checksum of ups.conf as early as possible, # to test in the end that it is still the same file. UPSCONF_CHECKSUM_START="`calc_md5_file "$UPSCONF"`" || true # By default, update wrapping of devices into services if [ $# = 0 ]; then nut_driver_enumerator_main ; exit $? fi if [ $# = 1 ] ; then [ -n "$DAEMON_SLEEP" ] || DAEMON_SLEEP=60 # Note: Not all shells have 'case ... ;&' support case "$1" in --daemon=*) DAEMON_SLEEP="`echo "$1" | sed 's,^--daemon=,,'`" ;; esac case "$1" in --daemon|--daemon=*) daemonize & exit $? ;; esac fi unset DAEMON_SLEEP usage() { cat << EOF $0 (no args) Update wrapping of devices into services $0 --daemon(=freq) Update wrapping of devices into services in an infinite loop Default freq is 60 sec $0 --reconfigure Stop and un-register all service instances and recreate them (e.g. if new dependency template was defined in a new version of this script and/or NUT package) $0 --get-service-framework Print the detected service management framework in this OS $0 --list-devices Print list of devices in NUT config $0 --list-services Print list of service instances which wrap registered NUT devices (full name of service unit) $0 --list-instances Print list of service instances which wrap registered NUT devices (just instance suffix) $0 --get-service-for-device DEV Print the full name of service unit which wraps a NUT device named "DEV" $0 --get-device-for-service SVC Print the NUT device name for full or instance-suffix name of a service unit which wraps it $0 --list-services-for-devices Print a TAB-separated list of service units and corresponding NUT device names which each such unit wraps $0 --show-configs|--show-all-configs Show the complete normalized list of device configuration blocks $0 --show-config DEV $0 --show-device-config DEV Show configuration block of the specified NUT device $0 --show-device-config-value DEV KEY [KEY...] Show single configuration key value of the specified NUT device For flags, shows the flag name if present in the section If several keys or flags are requested, their values are reported one per line in the same order (including empty lines for missing values); any missing value yields a non-zero exit code. EOF } while [ $# -gt 0 ]; do case "$1" in --help|-h|-help) usage; exit 0 ;; --get-service-framework) echo "${SERVICE_FRAMEWORK}" ; exit 0 ;; --reconfigure) upslist_readFile_once || exit $? upslist_readSvcs "before manipulations" if [ -n "$UPSLIST_SVCS" ]; then for UPSS in $UPSLIST_SVCS ; do echo "Dropping old ${SERVICE_FRAMEWORK} service instance for power device [${UPSS}] to reconfigure the service unit..." >&2 $hook_unregisterInstance "$UPSS" done upslist_readSvcs "after dropping" fi if [ -n "$UPSLIST_FILE" ]; then upslist_addSvcs upslist_readSvcs "after checking for new config sections to define service instances" fi # Save new checksum of global config $hook_setSavedMD5 "" "`upsconf_getSection_MD5 ""`" # Service units were manipulated, including saving of checksums; # refresh the service management daemon if needed $hook_refreshSupervizor if [ -n "$UPSLIST_SVCS" ] ; then echo "=== The currently defined service instances are:" echo "$UPSLIST_SVCS" fi if [ -n "$UPSLIST_FILE" ] ; then echo "=== The currently defined configurations in '$UPSCONF' are:" echo "$UPSLIST_FILE" fi # We had some changes to the config file; upsd must be made aware if [ "$AUTO_START" = yes ] ; then $hook_restart_upsd fi # Return 42 if there was a change applied succesfully # (but e.g. some services should restart - upsd, maybe upsmon) UPSLIST_EQ_RES=0 upslist_equals "$UPSLIST_FILE" "$UPSLIST_SVCS" || UPSLIST_EQ_RES=$? # File processing and service startups take a while; # make sure upsconf did not change while we worked... # NOTE: Check this at the last moment to minimize # the chance of still not noticing the change made # at just the wrong moment. UPSCONF_CHECKSUM_END="`calc_md5_file "$UPSCONF"`" || true if [ "$UPSCONF_CHECKSUM_END" != "$UPSCONF_CHECKSUM_START" ] ; then echo "`date -u` : '$UPSCONF' changed while $0 $* was processing its older contents; re-running the script to pick up the late-coming changes" $0 ; exit $? # The "main" routine will do REPORT_RESTART_42 logic too fi if [ "$UPSLIST_EQ_RES" = 0 ] ; then echo "`date -u` : OK: No more changes to reconcile between ${SERVICE_FRAMEWORK} service instances and device configurations in '$UPSCONF'" [ "${REPORT_RESTART_42-}" = no ] && exit 0 || exit 42 fi exit 13 ;; --list-devices) upslist_readFile_once && \ if [ -n "$UPSLIST_FILE" ] ; then echo "=== The currently defined configurations in '$UPSCONF' are:" >&2 echo "$UPSLIST_FILE" exit 0 fi echo "No devices detected in '$UPSCONF'" >&2 exit 1 ;; --list-services) UPSLIST_SVCS_RAW="`$hook_listInstances_raw`" && \ if [ -n "$UPSLIST_SVCS_RAW" ] ; then echo "=== The currently defined service units are:" >&2 echo "$UPSLIST_SVCS_RAW" exit 0 fi echo "No service units detected" >&2 exit 1 ;; --list-instances) upslist_readSvcs "by user request" && \ if [ -n "$UPSLIST_SVCS" ] ; then echo "=== The currently defined service instances are:" >&2 echo "$UPSLIST_SVCS" exit 0 fi echo "No service instances detected" >&2 exit 1 ;; --get-service-for-device) [ -z "$2" ] && echo "Device name argument required" >&2 && exit 1 DEV="$2" upslist_readSvcs "by user request" && [ -n "$UPSLIST_SVCS" ] \ || { echo "No service instances detected" >&2 ; exit 1; } UPSLIST_SVCS_RAW="`$hook_listInstances_raw`" && [ -n "$UPSLIST_SVCS_RAW" ] \ || { echo "No service units detected" >&2 ; exit 1; } vINST="`$hook_validInstanceName "$DEV"`" vUNITD="`$hook_validFullUnitName "$DEV"`" vUNITI="`$hook_validFullUnitName "$vINST"`" # First pass over simple verbatim names for INST in $UPSLIST_SVCS ; do if [ "$INST" = "$DEV" ] ; then for UNIT in $UPSLIST_SVCS_RAW ; do if [ "$UNIT" = "$vUNITD" ] ; then echo "$UNIT" exit 0 fi done fi done for INST in $UPSLIST_SVCS ; do if [ "$INST" = "$vINST" ] ; then for UNIT in $UPSLIST_SVCS_RAW ; do if [ "$UNIT" = "$vUNITI" ] ; then echo "$UNIT" exit 0 fi done fi done echo "No service instances detected that match device '$2'" >&2 exit 1 ;; --get-device-for-service) [ -z "$2" ] && echo "Service (instance) name argument required" >&2 && exit 1 # Instance name can be a hash or "native" NUT section name SVC="`$hook_validInstanceSuffixName "$2"`" case "$SVC" in MD5_*) ;; # fall through to the bulk of code *) upslist_readFile_once || exit $? echo "$UPSLIST_FILE" | grep -E "^$SVC\$" exit $? ;; esac FINAL_RES=0 OUT="`"$0" --list-services-for-devices`" && [ -n "$OUT" ] || FINAL_RES=$? if [ "$FINAL_RES" = 0 ]; then echo "$OUT" | grep "$SVC" | ( \ while read _SVC _DEV ; do _SVC="`$hook_validInstanceSuffixName "${_SVC}"`" || exit [ "${_SVC}" = "${SVC}" ] && echo "$_DEV" && exit 0 done ; exit 1 ) && exit 0 fi echo "No service instance '$2' was detected that matches a NUT device" >&2 exit 1 ;; --list-services-for-devices) FINAL_RES=0 upslist_readFile_once && [ -n "$UPSLIST_FILE" ] \ || { echo "No devices detected in '$UPSCONF'" >&2 ; exit 1 ; } upslist_readSvcs "by user request" && [ -n "$UPSLIST_SVCS" ] \ || { echo "No service instances detected" >&2 ; exit 1; } UPSLIST_SVCS_RAW="`$hook_listInstances_raw`" && [ -n "$UPSLIST_SVCS_RAW" ] \ || { echo "No service units detected" >&2 ; exit 1; } for DEV in $UPSLIST_FILE ; do vINST="`$hook_validInstanceName "$DEV"`" vUNITD="`$hook_validFullUnitName "$DEV"`" vUNITI="`$hook_validFullUnitName "$vINST"`" # First pass over simple verbatim names for INST in $UPSLIST_SVCS ; do if [ "$INST" = "$DEV" ] ; then for UNIT in $UPSLIST_SVCS_RAW ; do if [ "$UNIT" = "$vUNITD" ] ; then printf '%s\t%s\n' "$UNIT" "$DEV" continue 3 fi done fi done for INST in $UPSLIST_SVCS ; do if [ "$INST" = "$vINST" ] ; then for UNIT in $UPSLIST_SVCS_RAW ; do if [ "$UNIT" = "$vUNITI" ] ; then printf '%s\t%s\n' "$UNIT" "$DEV" continue 3 fi done fi done echo "WARNING: no service instances detected that match device '$DEV'" >&2 FINAL_RES=1 done exit $FINAL_RES ;; --show-configs|--show-device-configs|--show-all-configs|--show-all-device-configs) RES=0 upslist_readFile_once || RES=$? [ "$RES" != 0 ] && { echo "ERROR: upslist_readFile_once () failed with code $RES" >&2; exit $RES; } [ -n "$UPSLIST_FILE" ] \ || { echo "WARNING: No devices detected in '$UPSCONF'" >&2 ; RES=1 ; } echo "$UPSCONF_DATA" exit $RES ;; --show-config|--show-device-config) [ -z "$2" ] && echo "WARNING: Device name argument empty, will show global config" >&2 DEV="$2" upsconf_getSection "$DEV" exit $? ;; --show-config-value|--show-device-config-value) [ -z "$3" ] && echo "At least one configuration key name argument is required" >&2 && exit 1 [ -z "$2" ] && echo "WARNING: Device name argument empty, will show global config" >&2 DEV="$2" shift 2 upsconf_getValue "$DEV" "$@" exit $? ;; upsconf_debug) # Not public, not in usage() [ -z "$2" ] && echo "Device name argument required" >&2 && exit 1 upsconf_debug "$2" exit $? ;; upslist_debug) # Not public, not in usage() upslist_readFile_once || exit upslist_debug exit $? ;; *) echo "Unrecognized argument: $1" >&2 ; exit 1 ;; esac shift done nut-2.8.1/scripts/upsdrvsvcctl/nut-driver-enumerator.sh0000755000175000017500000016444014520275020020325 00000000000000#!/bin/sh # # NOTE: This script is intentionally written with portable shell constructs # with the aim and hope to work in different interpreters, so it is a # bit dumber and less efficient than could be achieved with the more # featured shells in the spectrum. # NOTE ALSO: The configuration parser in this script is not meant to be a # reference or 100% compliant with what the binary code uses; its aim # is to just pick out some strings relevant for tracking config changes. # # Copyright (C) 2016-2020 Eaton # Copyright (C) 2020-2023 Jim Klimov # # 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 2 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, write to the Free Software Foundation, Inc., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. # #! \file nut-driver-enumerator.sh(.in) # \author Jim Klimov # \brief Enumerate NUT devices for service-unit instance configuration # \details This script allows to enumerate UPSes in order to produce the # individual service unit instances for each defined configuration. # It assumes the user has adequate permissions to inspect and create # services (e.g. is a root or has proper RBAC profiles to do so). # It helps service frameworks such as Linux systemd and Solaris SMF. # When executed, this script looks for all configured ups.conf # sections and registered service instances, and makes these two # lists match up. It has also a mode to do this in a loop, to keep # checking for differences and applying them, on systems where it's # problematic to trigger it in response to FS event notifications. # Returns exit codes: # 0 Sections and services already match up # 42 Sections and services differed, but now match up - # now the caller should likely restart some services. # Note that the drivers' service instances were started or # stopped as required (by AUTO_START=yes) - but maybe the # upsd or upsmon services should restart. If you pass envvar # REPORT_RESTART_42=no then this codepath would return 0. # In default mode, such non-null reconfiguration should cause # the nut-driver-enumerator service to restart and this would # propagate to other NUT services that depend on it. # 13 Sections and services differed, and still do not match up # 1 Bad inputs, e.g. unrecognized service management framework # 2 Absent or unreadable ups.conf file # # NOTE: Currently found caveats that might be solved later but require # considerable effort: # * Solaris SMF constrains the syntax of valid strings for instance names # (e.g. not starting with a digit, no period chars) which blocks creation # of some UPS driver instances. This might be worked around by hashing # the device name e.g. to base64 (and un-hashing instance name when calling # upsdrvctl), but is not quite user-friendly. Also can store device name # in a service attribute while mangling the instance name to a valid subset. # Comparisons (if devices are already wrapped) becomes more complicated in # the script in either case, as well as in the service startup method. # ** The `+` `/` `=` characters from base64 are also invalid for SMF instance # name, but the first two can be sed'ed to `-` `_` and back, for example. # Some prefix word is also needed (avoid starting with a digit). # The trailing padding `=` can be dropped, and added until we get a # non-empty decode. Conversions can be done by # `echo "$string" | openssl base64 -e|-d` # * Dummy-UPS services that "proxy" another locally defined section are # essentially a circular dependency for upsd. While the system might # start-up lacking a driver, there should be some timer to re-enable # failed not-disabled drivers (would be useful in any case though). # Directory where NUT configs are located, e.g. /etc/nut or /etc/ups # Set at package configuration, compiled into daemons and drivers prefix="/usr/local/ups" [ -n "${NUT_CONFPATH-}" ] || NUT_CONFPATH="${prefix}/etc" # Technically this should be a distribution-dependent value configured # during package build. But everyone has it the same from systemd defaults: [ -n "${SYSTEMD_CONFPATH-}" ] || SYSTEMD_CONFPATH="/etc/systemd/system" if [ -n "$ZSH_VERSION" ]; then ### Problem: loops like `for UPS in $UPSLIST` do not separate ### the UPSLIST into many tokens but use it as one string. echo "FATAL: zsh is not supported in this script" >&2 exit 1 # setopt noglob # setopt +F # IFS="`printf ' \t\r\n'`" ; export IFS fi if set | grep -E '^(shell|version|t?csh)' | grep -E 't?csh' >/dev/null ; then echo "FATAL: csh or tcsh is not supported in this script" >&2 exit 1 fi # Third-party services to depend on (can be overridden by config file) ### Note that for systemd+udev integration, it may be better to set up ### triggers in udev, see e.g. ### http://stackoverflow.com/questions/18463755/linux-start-daemon-on-connected-usb-serial-dongle ### Also can tune whether a driver "Wants" another service (would consider ### ordering if that one is enabled, but live if it is disabled), or if it ### "Requires" that (would cause that to start). DEPSVC_USB_SYSTEMD="systemd-udev.service systemd-udev-settle.service" DEPREQ_USB_SYSTEMD="Wants" DEPSVC_NET_FULL_SYSTEMD="network-online.target systemd-resolved.service ifplugd.service" DEPREQ_NET_FULL_SYSTEMD="Wants" DEPSVC_NET_LOCAL_SYSTEMD="network.target" DEPREQ_NET_LOCAL_SYSTEMD="Wants" SVCNAME_SYSTEMD="nut-driver" # Some or all of these FMRIs may be related to dynamically changing hardware # require_all) ;; # All cited services are running (online or degraded) # require_any) ;; # At least one of the cited services is running # optional_all) ;; # (All) cited services are running or would not run # # without administrative action (disabled, maintenance, # # not present, or are waiting for dependencies which do # # not start without administrative action). DEPSVC_USB_SMF="svc:/system/hotplug:default svc:/system/dbus:default svc:/system/hal:default svc:/milestone/devices:default" DEPREQ_USB_SMF="optional_all" # By default there are several physical network FMRIs shipped and at most # only one is enabled on a particular system (e.g. :default or :nwam) DEPSVC_NET_FULL_SMF="svc:/network/physical svc:/milestone/name-services" DEPREQ_NET_FULL_SMF="optional_all" DEPSVC_NET_LOCAL_SMF="svc:/network/loopback:default" DEPREQ_NET_LOCAL_SMF="optional_all" SVCNAME_SMF="svc:/system/power/nut-driver" [ -z "${NUT_DRIVER_ENUMERATOR_CONF-}" ] && \ NUT_DRIVER_ENUMERATOR_CONF="${NUT_CONFPATH}/nut-driver-enumerator.conf" [ -s "${NUT_DRIVER_ENUMERATOR_CONF}" ] && \ echo "Sourcing config file: ${NUT_DRIVER_ENUMERATOR_CONF}" && \ . "${NUT_DRIVER_ENUMERATOR_CONF}" [ -z "${UPSCONF-}" ] && \ UPSCONF="${NUT_CONFPATH}/ups.conf" # Start a freshly-registered unit? [ -z "${AUTO_START-}" ] && AUTO_START=yes # We avoid regex '\t' which gets misinterpreted by some tools TABCHAR="`printf '\t'`" || TABCHAR=' ' if [ -z "${SERVICE_FRAMEWORK-}" ] ; then [ -x /usr/sbin/svcadm ] && [ -x /usr/sbin/svccfg ] && [ -x /usr/bin/svcs ] && [ -x /usr/bin/svcprop ] && \ SERVICE_FRAMEWORK="smf" [ -z "${SERVICE_FRAMEWORK-}" ] && \ [ -x /bin/systemctl ] && \ SERVICE_FRAMEWORK="systemd" fi # Optionally use Coreutils timeout to limit the # (potentially hanging) calls to systemd tools... # Should not hurt with SMF too, if it ever misbehaves. if [ -z "${TIMEOUT_CMD+x}" ]; then # Envvar not set at all (set but empty is okay, caller wants that then) TIMEOUT_CMD="" TIMEOUT_ARGS="" if which timeout 2>/dev/null >/dev/null ; then # Systemd default timeout for unit start/stop TIMEOUT_CMD="timeout" TIMEOUT_ARGS="90s" fi fi # Cache needed bits of ups.conf to speed up later parsing. Note that these # data are needed for most operations, and populated by upslist_readFile() UPSCONF_DATA="" # Subset of normalized data above that only has sections, drivers and ports (SDP) UPSCONF_DATA_SDP="" # List of configured UPSes in the config-file UPSLIST_FILE="" # List of configured service instances for UPS drivers UPSLIST_SVCS="" # Framework-specific implementations are generally hooked here: hook_registerInstance="" hook_unregisterInstance="" hook_refreshSupervizor="" hook_listInstances="" hook_listInstances_raw="" hook_validInstanceName="" hook_validFullUnitName="" hook_validInstanceSuffixName="" hook_getSavedMD5="" hook_setSavedMD5="" hook_restart_upsd="" hook_restart_drv="" case "${SERVICE_FRAMEWORK-}" in smf) hook_registerInstance="smf_registerInstance" hook_unregisterInstance="smf_unregisterInstance" hook_refreshSupervizor="smf_refreshSupervizor" hook_listInstances="smf_listInstances" hook_listInstances_raw="smf_listInstances_raw" hook_validInstanceName="smf_validInstanceName" hook_validFullUnitName="smf_validFullUnitName" hook_validInstanceSuffixName="smf_validInstanceSuffixName" hook_getSavedMD5="smf_getSavedMD5" hook_setSavedMD5="smf_setSavedMD5" hook_restart_upsd="smf_restart_upsd" hook_restart_drv="smf_restart_drv" ;; systemd) hook_registerInstance="systemd_registerInstance" hook_unregisterInstance="systemd_unregisterInstance" hook_refreshSupervizor="systemd_refreshSupervizor" hook_listInstances="systemd_listInstances" hook_listInstances_raw="systemd_listInstances_raw" hook_validInstanceName="systemd_validInstanceName" hook_validFullUnitName="systemd_validFullUnitName" hook_validInstanceSuffixName="systemd_validInstanceSuffixName" hook_getSavedMD5="systemd_getSavedMD5" hook_setSavedMD5="systemd_setSavedMD5" hook_restart_upsd="systemd_restart_upsd" hook_restart_drv="systemd_restart_drv" ;; selftest) hook_registerInstance="selftest_NOOP" hook_unregisterInstance="selftest_NOOP" hook_refreshSupervizor="selftest_NOOP" hook_listInstances="selftest_NOOP" hook_listInstances_raw="selftest_NOOP" hook_validInstanceName="selftest_NOOP" hook_validFullUnitName="selftest_NOOP" hook_validInstanceSuffixName="selftest_NOOP" hook_getSavedMD5="selftest_NOOP" hook_setSavedMD5="selftest_NOOP" hook_restart_upsd="selftest_NOOP" hook_restart_drv="selftest_NOOP" ;; "") echo "Error detecting the service-management framework on this OS" >&2 exit 1 ;; *) echo "Error: User provided an unknown service-management framework '$SERVICE_FRAMEWORK'" >&2 exit 1 ;; esac selftest_NOOP() { echo "NO-OP: Self-testing context does not do systems configuration" >&2 return 0 } common_isFiled() { [ -n "$UPSLIST_FILE" ] && \ for UPSF in $UPSLIST_FILE ; do [ "$1" = "$UPSF" ] && return 0 [ "`$hook_validInstanceName "$UPSF"`" = "$1" ] && return 0 done return 1 } common_isRegistered() { [ -n "$UPSLIST_SVCS" ] && \ for UPSS in $UPSLIST_SVCS ; do [ "$1" = "$UPSS" ] && return 0 [ "`$hook_validInstanceName "$1"`" = "$UPSS" ] && return 0 done return 1 } upslist_equals() { # Compare pre-sorted list of DEVICES ($1) and SVCINSTs ($2) including # the possible mangling for service names. Return 0 if lists describe # exactly same set of devices and their services. # Note: This logic only checks the names, not the contents of device # sections, so re-definitions of an existing device configuration # would not trigger a service restart by itself. Such deeper check # belongs in a different routine, see upssvcconf_checksum_unchanged(). # Trivial case 0: one string is empty, another is not # Note: `echo '' | wc -l` == "1" not "0"! [ -n "$1" -a -z "$2" ] && return 1 [ -z "$1" -a -n "$2" ] && return 1 # Trivial case 1: equal strings [ "$1" = "$2" ] && return 0 # Trivial case 2: different amount of entries [ "`echo "$1" | wc -l`" = "`echo "$2" | wc -l`" ] || return $? _TMP_DEV_SVC="" for _DEV in $1 ; do DEVINST="`$hook_validInstanceName "$_DEV"`" for _SVC in $2 ; do [ "$_DEV" = "$_SVC" ] \ || [ "$DEVINST" = "$_SVC" ] \ && { [ -z "$_TMP_DEV_SVC" ] \ && _TMP_DEV_SVC="$_DEV = $_SVC" \ || _TMP_DEV_SVC="$_TMP_DEV_SVC $_DEV = $_SVC" ; } done done # Input was not empty; did anything in output fit? [ -z "$_TMP_DEV_SVC" ] && return 1 # Exit code : is the built mapping as long as the source list(s)? [ "`echo "$1" | wc -l`" = "`echo "$_TMP_DEV_SVC" | wc -l`" ] } upssvcconf_checksum_unchanged() { # $1 = dev, $2 = svc # compare checksums of the configuration section from the file and the # stashed configuration in a service instance (if any). # FIXME : optimize by caching, we likely have quite a few requests [ "`upsconf_getSection_MD5 "$1"`" = "`$hook_getSavedMD5 "$2"`" ] } upslist_checksums_unchanged() { # For each device and its corresponding unit, compare checksums of the # configuration section from the file and the stashed configuration in # a service instance. Prints a list of mismatching service names that # should get reconfigured. [ -z "$1" -o -z "$2" ] && return 1 _TMP_SVC="" for _DEV in $1 ; do DEVINST="`$hook_validInstanceName "$_DEV"`" for _SVC in $2 ; do if [ "$_DEV" = "$_SVC" ] \ || [ "$DEVINST" = "$_SVC" ] \ ; then upssvcconf_checksum_unchanged "$_DEV" "$_SVC" || \ { [ -z "$_TMP_SVC" ] \ && _TMP_SVC="$_SVC" \ || _TMP_SVC="$_TMP_SVC $_SVC" ; } fi done done [ -z "$_TMP_SVC" ] && return 0 echo "$_TMP_SVC" return 1 } upsconf_getSection_content() { # "$1" = name of ups.conf section to display in whole, from whatever # comes on stdin (file or a pre-made normalized variable) # empty "$1" means the global config (before any sections) # # NOTE (TODO?): This routine finds the one NUT device section, prints it # and returns when the section is over. It currently does not cover (in # a way allowing to do it efficiently) selection of several sections, # or storing each section content in some array or dynamic variables # (as would be better fit for portable shells) to later address them # quickly without re-parsing the file or big envvar many times. # CURR_SECTION="" SECTION_CONTENT="" RES=1 [ -n "$1" ] || RES=0 while read LINE ; do case "$LINE" in \["$1"\]) if [ "$RES" = 0 ]; then # We have already displayed a section, here is a new one, # and this routine only displays one (TODO: toggle?) break fi SECTION_CONTENT="$LINE" CURR_SECTION="$1" RES=0 continue ;; \[*\ *\]|\[*"$TABCHAR"*\]) # Note that section-name brackets should contain a single token # Fall through to add the line to contents of existing section ;; \[*\]) [ "$CURR_SECTION" = "$1" ] && break # Use a value that can not be a section name here: CURR_SECTION="[]" continue ;; "") continue ;; *) ;; # Fall through to add the line to contents of existing section esac if [ "$CURR_SECTION" = "$1" ]; then if [ -n "$SECTION_CONTENT" ]; then SECTION_CONTENT="$SECTION_CONTENT $LINE" else SECTION_CONTENT="$LINE" fi fi done if [ -n "$SECTION_CONTENT" ]; then echo "$SECTION_CONTENT" fi [ "$RES" = 0 ] || echo "ERROR: Section [$1] was not found in the '$UPSCONF' file" >&2 return $RES } upsconf_getSection() { # Use the whole output of normalization parser upslist_normalizeFile_once || return # Propagate errors upwards upsconf_getSection_content "$@" << EOF ${UPSCONF_DATA} EOF } upsconf_getSection_MD5() { calc_md5 "`upsconf_getSection "$@"`" } upsconf_getSection_SDP() { # Use the section-driver-port subset upslist_normalizeFile_once || return # Propagate errors upwards upsconf_getSection_content "$@" << EOF ${UPSCONF_DATA_SDP} EOF } upsconf_getValue() { # "$1" = name of ups.conf section, may be empty for global config # "$2..$N" = name of config key; we will echo its value ### [ -n "$1" ] || return $? [ -n "$2" ] || return $? [ -n "$GETSECTION" ] || GETSECTION="upsconf_getSection" CURR_SECTION="" # Gets set by a GETSECTION implementation RES=0 # Note: Primary aim of this egrep is to pick either assignments or flags # As a by-product it can be used to test if a particular value is set ;) SECTION_CONTENT="`$GETSECTION "$1"`" || return shift KEYS="$*" while [ "$#" -gt 0 ] ; do RES_L=0 VALUE="" LINE="`echo "$SECTION_CONTENT" | grep -E '(^'"$1"'=|^'"$1"'$)'`" \ && VALUE="$(echo "$LINE" | sed -e "s,^$1=,," -e 's,^\"\(.*\)\"$,\1,' -e "s,^'\(.*\)'$,\1,")" \ || RES_L=$? [ "$RES_L" = 0 ] || { RES="$RES_L" ; echo "ERROR: Section [$CURR_SECTION] or key '$1' in it was not found in the '$UPSCONF' file" >&2 ; } echo "$VALUE" shift done [ "$RES" = 0 ] || echo "ERROR: Section [$CURR_SECTION] or key(s) '$KEYS' in it was not found in the '$UPSCONF' file" >&2 return $RES } upsconf_getDriver() { # "$1" = name of ups.conf section; return (echo) the driver name used there # In the context this function is used, UPSCONF exists and section is there GETSECTION="upsconf_getSection_SDP" upsconf_getValue "$1" "driver" return $? } upsconf_getPort() { # "$1" = name of ups.conf section; return (echo) the "port" name used there # In the context this function is used, UPSCONF exists and section is there GETSECTION="upsconf_getSection_SDP" upsconf_getValue "$1" "port" return $? } upsconf_getDriverMedia() { # "$1" = name of ups.conf section; return (echo) name and type of driver as # needed for dependency evaluation (what services we must depend on for this # unit), newline-separated (drvnametype). Empty type for unclassified # results, assuming no known special dependencies (note that depending on # particular system's physics, both serial and network media may need USB). CURR_DRV="`upsconf_getDriver "$1"`" || return $? case "$CURR_DRV" in *netxml*|*snmp*|*ipmi*|*powerman*|*-mib*|*avahi*) printf '%s\n%s\n' "$CURR_DRV" "network" ; return ;; *apcupsd-ups*) # Relay from a nearby apcupsd network server into NUT ecosystem: CURR_PORT="`upsconf_getPort "$1"`" || CURR_PORT="" case "$CURR_PORT" in *localhost*|*127.0.0.1*|*::1*) printf '%s\n%s\n' "$CURR_DRV" "network-localhost" ; return ;; *) printf '%s\n%s\n' "$CURR_DRV" "network" ; return ;; esac ;; *apc_modbus*) CURR_PORT="`upsconf_getPort "$1"`" || CURR_PORT="" CURR_PORTTYPE="`upsconf_getValue "$1" 'porttype'`" || CURR_PORTTYPE="" case "$CURR_PORTTYPE" in *usb*) printf '%s\n%s\n' "$CURR_DRV" "usb" ; return ;; *serial*) printf '%s\n%s\n' "$CURR_DRV" "serial" ; return ;; *) # default depends on driver build (against libmodbus # version with or without support for usb) # TOTHINK: Check for presence of config values like # vendorid (USB) or baud (Serial)? They are optional # with reasonable defaults anyway... case "$CURR_PORT" in *auto*) printf '%s\n%s\n' "$CURR_DRV" "usb" ; return ;; /*) printf '%s\n%s\n' "$CURR_DRV" "serial" ; return ;; *localhost*|*127.0.0.1*|*::1*) printf '%s\n%s\n' "$CURR_DRV" "network-localhost" ; return ;; *) printf '%s\n%s\n' "$CURR_DRV" "network" ; return ;; esac # returns are above, but just in case - have a fallback: printf '%s\n%s\n' "$CURR_DRV" "" ; return ;; esac ;; *usb*) printf '%s\n%s\n' "$CURR_DRV" "usb" ; return ;; nutdrv_qx) # May be direct serial or USB CURR_PORT="`upsconf_getPort "$1"`" || CURR_PORT="" case "$CURR_PORT" in auto|/dev/*usb*|/dev/*hid*) printf '%s\n%s\n' "$CURR_DRV" "usb" ; return ;; /dev/*) # See drivers/nutdrv_qx.c :: upsdrv_initups() for a list if [ -n "`upsconf_getValue "$1" 'subdriver' 'vendorid' 'productid' 'vendor' 'product' 'serial' 'bus' 'busport' 'langid_fix'`" ] \ ; then printf '%s\n%s\n' "$CURR_DRV" "usb" ; return else printf '%s\n%s\n' "$CURR_DRV" "serial" ; return fi ;; *) printf '%s\n%s\n' "$CURR_DRV" "" ; return ;; esac ;; *dummy*|*clone*) # May be networked (proxy to remote NUT) CURR_PORT="`upsconf_getPort "$1"`" || CURR_PORT="" case "$CURR_PORT" in *@localhost|*@|*@127.0.0.1|*@::1) printf '%s\n%s\n' "$CURR_DRV" "network-localhost" ; return ;; *@*) printf '%s\n%s\n' "$CURR_DRV" "network" ; return ;; *) printf '%s\n%s\n' "$CURR_DRV" "" ; return ;; esac ;; *) printf '%s\n%s\n' "$CURR_DRV" "" ; return ;; esac } upsconf_getMedia() { _DRVMED="`upsconf_getDriverMedia "$1"`" || return echo "$_DRVMED" | tail -n +2 return 0 } upsconf_debug() { _DRV="`upsconf_getDriver "$1"`" _PRT="`upsconf_getPort "$1"`" _MED="`upsconf_getMedia "$1"`" _MD5="`upsconf_getSection_MD5 "$1"`" NAME_MD5="`calc_md5 "$1"`" echo "INST: ${NAME_MD5}~[$1]: DRV='$_DRV' PORT='$_PRT' MEDIA='$_MED' SECTIONMD5='$_MD5'" } calc_md5() { # Tries several ways to produce an MD5 of the "$1" argument _MD5="`echo "$1" | md5sum 2>/dev/null | awk '{print $1}'`" && [ -n "$_MD5" ] || \ { _MD5="`echo "$1" | openssl dgst -md5 2>/dev/null | awk '{print $NF}'`" && [ -n "$_MD5" ]; } || \ return 1 echo "$_MD5" } calc_md5_file() { # Tries several ways to produce an MD5 of the file named by "$1" argument [ -s "$1" ] || return 2 _MD5="`md5sum 2>/dev/null < "$1" | awk '{print $1}'`" && [ -n "$_MD5" ] || \ { _MD5="`openssl dgst -md5 2>/dev/null < "$1" | awk '{print $NF}'`" && [ -n "$_MD5" ]; } || \ return 1 echo "$_MD5" } smf_validFullUnitName() { case "$1" in *:*) echo "$1" ;; *) echo "$SVCNAME_SMF:$1" ;; esac } smf_validInstanceName() { echo "MD5_`calc_md5 "$1"`" } smf_validInstanceSuffixName() { case "$1" in *:*) echo "$1" | sed 's,^.*:\([^:]*\)$,\1,' ;; *) echo "$1" ;; esac } smf_registerInstance() { DEVICE="$1" SVCINST="$1" /usr/sbin/svccfg -s nut-driver add "$DEVICE" || \ { SVCINST="`smf_validInstanceName "$1"`" && \ /usr/sbin/svccfg -s nut-driver add "$SVCINST" || return ; } echo "Added instance: 'nut-driver:$SVCINST' for NUT configuration section '$DEVICE'" >&2 DEPSVC="" DEPREQ="" _MED="`upsconf_getMedia "$DEVICE"`" case "$_MED" in usb) DEPSVC="$DEPSVC_USB_SMF" DEPREQ="$DEPREQ_USB_SMF" ;; network-localhost) DEPSVC="$DEPSVC_NET_LOCAL_SMF" DEPREQ="$DEPREQ_NET_LOCAL_SMF" ;; network) DEPSVC="$DEPSVC_NET_FULL_SMF" DEPREQ="$DEPREQ_NET_FULL_SMF" ;; serial) ;; '') ;; *) echo "WARNING: Unexpected NUT media type ignored: '$_MED'" >&2 ;; esac TARGET_FMRI="nut-driver:$SVCINST" if [ -n "$DEPSVC" ]; then [ -n "$DEPREQ" ] || DEPREQ="optional_all" echo "Adding '$DEPREQ' dependency for '$SVCINST' on '$DEPSVC'..." DEPPG="nut-driver-enumerator-generated" RESTARTON="refresh" /usr/sbin/svccfg -s "$TARGET_FMRI" addpg "$DEPPG" dependency && \ /usr/sbin/svccfg -s "$TARGET_FMRI" setprop "$DEPPG"/grouping = astring: "$DEPREQ" && \ /usr/sbin/svccfg -s "$TARGET_FMRI" setprop "$DEPPG"/restart_on = astring: "$RESTARTON" && \ /usr/sbin/svccfg -s "$TARGET_FMRI" setprop "$DEPPG"/type = astring: service && \ /usr/sbin/svccfg -s "$TARGET_FMRI" setprop "$DEPPG"/entities = fmri: "($DEPSVC)" && \ echo "OK" || echo "FAILED to define the dependency" >&2 fi smf_setSavedMD5 "$SVCINST" "`upsconf_getSection_MD5 "$DEVICE"`" /usr/sbin/svcadm refresh "${TARGET_FMRI}" || return if [ "$AUTO_START" = yes ] ; then /usr/sbin/svcadm clear "${TARGET_FMRI}" 2>/dev/null || true /usr/sbin/svcadm enable "${TARGET_FMRI}" || return echo "Started instance: 'nut-driver:$SVCINST' for NUT configuration section '$DEVICE'" >&2 fi } smf_unregisterInstance() { echo "Removing instance: 'nut-driver:$1' ..." >&2 /usr/sbin/svcadm disable -ts 'nut-driver:'"$1" || false /usr/sbin/svccfg -s nut-driver delete "$1" } smf_refreshSupervizor() { : } smf_listInstances_raw() { # Newer versions have pattern matching; older SMF might not have this luxury /usr/bin/svcs -a -H -o fmri | grep -E '/nut-driver:' } smf_listInstances() { smf_listInstances_raw | sed 's/^.*://' | sort -n } smf_getSavedMD5() { # Query service instance $1 PG="nut-driver-enumerator-generated-checksum" PROP="SECTION_CHECKSUM" if [ -n "$1" ]; then TARGET_FMRI="nut-driver:$1" else # Global section TARGET_FMRI="nut-driver" PROP="SECTION_CHECKSUM_GLOBAL" fi # Note: lookups for GLOBAL cause each service instance to show up /usr/bin/svcprop -p "$PG/$PROP" "$TARGET_FMRI" | head -1 | awk '{print $NF}' } smf_setSavedMD5() { # Save checksum value $2 into service instance $1 PG="nut-driver-enumerator-generated-checksum" PROP="SECTION_CHECKSUM" if [ -n "$1" ]; then TARGET_FMRI="nut-driver:$1" else # Global section TARGET_FMRI="nut-driver" PROP="SECTION_CHECKSUM_GLOBAL" fi /usr/sbin/svccfg -s "$TARGET_FMRI" delprop "$PG" || true /usr/sbin/svccfg -s "$TARGET_FMRI" addpg "$PG" application && \ /usr/sbin/svccfg -s "$TARGET_FMRI" setprop "$PG/$PROP" = astring: "$2" [ $? = 0 ] && echo "OK" || { echo "FAILED to stash the checksum">&2 ; return 1 ; } /usr/sbin/svcadm refresh "${TARGET_FMRI}" || return } smf_restart_upsd() { echo "Reloading or restarting NUT data server to make sure it knows new configuration..." /usr/sbin/svcadm enable "nut-server" 2>/dev/null /usr/sbin/svcadm clear "nut-server" 2>/dev/null /usr/sbin/svcadm refresh "nut-server" || \ /usr/sbin/svcadm restart "nut-server" } smf_restart_drv() { echo "Reloading or restarting NUT driver instance '$1' to make sure it knows new configuration..." /usr/sbin/svcadm enable "nut-driver:$1" 2>/dev/null /usr/sbin/svcadm clear "nut-driver:$1" 2>/dev/null /usr/sbin/svcadm refresh "nut-driver:$1" || \ /usr/sbin/svcadm restart "nut-driver:$1" } systemd_validFullUnitName() { case "$1" in *@*.*) echo "$1" ;; *@*) echo "$1.service" ;; *) echo "$SVCNAME_SYSTEMD@$1.service" ;; esac } systemd_validInstanceName() { echo "MD5_`calc_md5 "$1"`" } systemd_validInstanceSuffixName() { echo "$1" | sed -e 's,^.*@,,' -e 's,\.service$,,' } systemd_registerInstance() { # Instance is registered by device section name; ultimate name in systemd may differ DEVICE="$1" SVCINST="$1" /bin/systemctl enable 'nut-driver@'"$DEVICE".service || \ { SVCINST="`systemd_validInstanceName "$1"`" && \ /bin/systemctl enable 'nut-driver@'"$SVCINST".service || return ; } echo "Enabled instance: 'nut-driver@$SVCINST' for NUT configuration section '$DEVICE'" >&2 DEPSVC="" DEPREQ="" _MED="`upsconf_getMedia "$DEVICE"`" case "$_MED" in usb) DEPSVC="$DEPSVC_USB_SYSTEMD" DEPREQ="$DEPREQ_USB_SYSTEMD" ;; network-localhost) DEPSVC="$DEPSVC_NET_LOCAL_SYSTEMD" DEPREQ="$DEPREQ_NET_LOCAL_SYSTEMD" ;; network) DEPSVC="$DEPSVC_NET_FULL_SYSTEMD" DEPREQ="$DEPREQ_NET_FULL_SYSTEMD" ;; serial) ;; '') ;; *) echo "WARNING: Unexpected NUT media type ignored: '$_MED'" >&2 ;; esac if [ -n "$DEPSVC" ]; then [ -n "$DEPREQ" ] || DEPREQ="#Wants" echo "Adding '$DEPREQ'+After dependency for '$SVCINST' on '$DEPSVC'..." mkdir -p "${SYSTEMD_CONFPATH}/nut-driver@$SVCINST.service.d" && \ cat > "${SYSTEMD_CONFPATH}/nut-driver@$SVCINST.service.d/nut-driver-enumerator-generated.conf" <&2 fi systemd_setSavedMD5 "$SVCINST" "`upsconf_getSection_MD5 "$DEVICE"`" if [ "$AUTO_START" = yes ] ; then systemd_refreshSupervizor || echo "WARNING: Somehow managed to fail systemd_refreshSupervizor()" >&2 $TIMEOUT_CMD $TIMEOUT_ARGS /bin/systemctl start --no-block 'nut-driver@'"$SVCINST".service || return echo "Started instance: 'nut-driver@$SVCINST' for NUT configuration section '$DEVICE'" >&2 fi } systemd_unregisterInstance() { echo "Removing instance: 'nut-driver@$1' ..." >&2 $TIMEOUT_CMD $TIMEOUT_ARGS /bin/systemctl stop 'nut-driver@'"$1".service || \ $TIMEOUT_CMD $TIMEOUT_ARGS /bin/systemctl stop 'nut-driver@'"$1".service || \ $TIMEOUT_CMD $TIMEOUT_ARGS /bin/systemctl stop 'nut-driver@'"$1".service || false /bin/systemctl disable 'nut-driver@'"$1".service rm -rf "${SYSTEMD_CONFPATH}/nut-driver@$1.service.d" /bin/systemctl reset-failed 'nut-driver@'"$1".service } systemd_refreshSupervizor() { /bin/systemctl daemon-reload } systemd_listInstances_raw() { /bin/systemctl show 'nut-driver@*' -p Id | grep -E '=nut-driver' | sed 's,^Id=,,' } systemd_listInstances() { systemd_listInstances_raw | sed -e 's/^.*@//' -e 's/\.service$//' | sort -n } systemd_getSavedMD5() { # Query service instance $1 or global section PROP="SECTION_CHECKSUM" [ -n "$1" ] || PROP="SECTION_CHECKSUM_GLOBAL" [ -s "${SYSTEMD_CONFPATH}/nut-driver@$1.service.d/nut-driver-enumerator-generated-checksum.conf" ] \ && grep "Environment='$PROP=" "${SYSTEMD_CONFPATH}/nut-driver@$1.service.d/nut-driver-enumerator-generated-checksum.conf" | sed -e "s,^Environment='$PROP=,," -e "s,'\$,," \ || { echo "Did not find '${SYSTEMD_CONFPATH}/nut-driver@$1.service.d/nut-driver-enumerator-generated-checksum.conf' with a $PROP" ; return 1; } } systemd_setSavedMD5() { # Save checksum value $2 into service instance $1 PROP="SECTION_CHECKSUM" [ -n "$1" ] || PROP="SECTION_CHECKSUM_GLOBAL" mkdir -p "${SYSTEMD_CONFPATH}/nut-driver@$1.service.d" && \ cat > "${SYSTEMD_CONFPATH}/nut-driver@$1.service.d/nut-driver-enumerator-generated-checksum.conf" << EOF [Service] Environment='$PROP=$2' EOF [ $? = 0 ] && echo "OK" || { echo "FAILED to stash the checksum">&2 ; return 1 ; } } systemd_restart_upsd() { # Do not restart/reload if not already running case "`/bin/systemctl is-active "nut-server"`" in active|unknown) ;; # unknown meant "starting" in our testing... failed) echo "Note: nut-server unit was 'failed' - not disabled by user, so (re)starting it (probably had no config initially)" >&2 ;; *) return 0 ;; esac echo "Reloading or restarting NUT data server to make sure it knows new configuration..." # Note: reload is a better way to go about this, so the # data service is not interrupted by re-initialization # of the daemon. But systemd/systemctl sometimes stalls... $TIMEOUT_CMD $TIMEOUT_ARGS /bin/systemctl reload-or-restart "nut-server" || \ $TIMEOUT_CMD $TIMEOUT_ARGS /bin/systemctl restart "nut-server" } systemd_restart_drv() { # Do not restart/reload if not already running case "`/bin/systemctl is-active "nut-driver@$1"`" in active|unknown) ;; *) return 0 ;; esac echo "Reloading or restarting NUT driver instance '$1' to make sure it knows new configuration..." # Full restart, e.g. in case we changed the user= in configs # however let "reload" try, in case we changed something that # can be updated "on the fly", like the "debug_min" setting. $TIMEOUT_CMD $TIMEOUT_ARGS /bin/systemctl reload-or-restart "nut-driver@$1" || \ $TIMEOUT_CMD $TIMEOUT_ARGS /bin/systemctl restart "nut-driver@$1" } upslist_normalizeFile_filter() { # See upslist_normalizeFile() detailed comments below; this routine # is a pipe worker to prepare the text into a simpler expected form. # Pick the lines which contain a bracket or assignment character, # or a single token (certain keywords come as just NUT "flags"), # trim leading and trailing whitespace, comment-only lines, and in # assignment lines trim the spaces around equality character and # quoting characters around assignment of values without whitespaces. # Any whitespace characters around a section name (single token that # starts the line and is enclosed in brackets) and a trailing comment # are dropped. Note that brackets with spaces inside, and brackets # that do not start the non-whitespace payload of the line, are not # sections. grep -E -v '(^$|^#)' | \ sed -e 's,^['"$TABCHAR"'\ ]*,,' \ -e 's,^\#.*$,,' \ -e 's,['"$TABCHAR"'\ ]*$,,' \ -e 's,^\([^=\ '"$TABCHAR"']*\)['"$TABCHAR"'\ ]*=['"$TABCHAR"'\ ]*,\1=,g' \ -e 's,=\"\([^\ '"$TABCHAR"']*\)\"$,=\1,' \ -e 's,^\(\[[^]'"$TABCHAR"'\ ]*\]\)['"$TABCHAR"'\ ]*\(#.*\)*$,\1,' \ | grep -E -v '^$' \ | grep -E '([\[\=]|^[^ '"$TABCHAR"']*$|^[^ '"$TABCHAR"']*[ '"$TABCHAR"']*#.*$)' } upslist_normalizeFile() { # Read the ups.conf file and find all defined sections (names of # configuration blocks for drivers that connect to a certain device # using specified protocol and media); normalize section contents # as detailed below, to simplify subsequent parsing and comparison. # File contents UPSCONF_DATA="" UPSCONF_DATA_SDP="" if [ -n "$UPSCONF" ] && [ -f "$UPSCONF" ] && [ -r "$UPSCONF" ]; then [ ! -s "$UPSCONF" ] \ && echo "WARNING: The '$UPSCONF' file exists but is empty" >&2 \ && return 0 # Ok to continue - we may end up removing all instances else echo "FATAL: The '$UPSCONF' file does not exist or is not readable" >&2 return 2 fi # Store a normalized version of NUT configuration file contents. # Also use a SDP subset with just section, driver and port info # for faster parsing when determining driver-required media etc. UPSCONF_DATA="$(upslist_normalizeFile_filter < "$UPSCONF")" \ && [ -n "$UPSCONF_DATA" ] \ && UPSCONF_DATA_SDP="`grep -E '^(\[.*\]|driver=|port=)' << EOF $UPSCONF_DATA EOF`" \ || { echo "Error reading the '$UPSCONF' file or it does not declare any device configurations: nothing left after normalization" >&2 UPSCONF_DATA="" UPSCONF_DATA_SDP="" } } upslist_normalizeFile_once() { # Wrapper that ensures that the parsing is only done once # (will re-parse if there were no devices listed on the # first time, though) [ -z "$UPSCONF_DATA" ] && [ -z "$UPSCONF_DATA_SDP" ] || return 0 upslist_normalizeFile } upslist_readFile() { # Use the routine above (unconditionally) to get or update the # listing of device sections known at this moment. # List of devices from the config file UPSLIST_FILE="" if [ "$DO_NORMALIZE_ONCE" = yes ]; then upslist_normalizeFile_once || return # Propagate errors upwards else upslist_normalizeFile || return # Propagate errors upwards fi if [ -n "$UPSCONF_DATA" ] ; then # Note that section-name brackets should contain a single token UPSLIST_FILE="$(echo "$UPSCONF_DATA_SDP" | grep -E '^\[[^'"$TABCHAR"'\ ]*\]$' | sed 's,^\[\(.*\)\]$,\1,' | sort -n)" \ || UPSLIST_FILE="" if [ -z "$UPSLIST_FILE" ] ; then echo "Error reading the '$UPSCONF' file or it does not declare any device configurations: no section declarations in parsed normalized contents" >&2 fi fi # Ok to continue with empty results - we may end up removing all instances } upslist_readFile_once() { # Wrapper that ensures that the parsing is only done once # (will re-parse if there were no devices listed on the # first time, though) [ -z "$UPSLIST_FILE" ] || return 0 DO_NORMALIZE_ONCE=yes upslist_readFile } upslist_readSvcs() { UPSLIST_SVCS="`$hook_listInstances`" || UPSLIST_SVCS="" if [ -z "$UPSLIST_SVCS" ] && [ "$1" != "-" ] ; then EXPLAIN="" [ -z "$1" ] || EXPLAIN=" - $1" echo "Error reading the list of ${SERVICE_FRAMEWORK-} service instances for UPS drivers, or none are defined${EXPLAIN}" >&2 # Ok to continue - we may end up defining new instances fi } upslist_debug() { for UPSF in "" $UPSLIST_FILE ; do upsconf_debug "$UPSF" done } upslist_addSvcs() { # Note: This routine registers service instances for device config sections # that are not wrapped currently. Support for redefined previously existing # sections - is attained by removing the old service instance elsewhere and # recreating it here, since any data could change including the dependency # list, etc. for UPSF in $UPSLIST_FILE ; do if ! common_isRegistered "$UPSF" ; then echo "Adding new ${SERVICE_FRAMEWORK} service instance for power device [${UPSF}]..." >&2 $hook_registerInstance "$UPSF" fi done } upslist_delSvcs() { for UPSS in $UPSLIST_SVCS ; do if ! common_isFiled "$UPSS" ; then echo "Dropping old ${SERVICE_FRAMEWORK} service instance for power device [${UPSS}] which is no longer in config file..." >&2 $hook_unregisterInstance "$UPSS" fi done } upslist_restartSvcs() { for UPSS in $UPSLIST_SVCS ; do if common_isFiled "$UPSS" ; then $hook_restart_drv "$UPSS" fi done } nut_driver_enumerator_main() { ################# MAIN PROGRAM by default # Note: do not use the read..._once() here, to ensure that the # looped daemon sees the whole picture, which can be new every time upslist_readFile || return $? #upslist_debug upslist_readSvcs "before manipulations" # Test if global config has changed since last run RESTART_ALL=no upssvcconf_checksum_unchanged "" || { echo "`date -u` : Detected changes in global section of '$UPSCONF', will restart all drivers"; RESTART_ALL=yes; } # Quickly exit if there's nothing to do; note the lists are pre-sorted # Otherwise a non-zero exit will be done below # Note: We implement testing in detail whether section definitions were # changed since last run, as a first step before checking that name # lists are still equivalent, because we need to always have the result # of the "has it changed?" check as a hit-list of something to remove, # while the check for no new device section definitions is just boolean. # We can only exit quickly if both there are no changed sections and no # new or removed sections since last run. NEW_CHECKSUM="`upslist_checksums_unchanged "$UPSLIST_FILE" "$UPSLIST_SVCS"`" \ && [ -z "$NEW_CHECKSUM" ] \ && upslist_equals "$UPSLIST_FILE" "$UPSLIST_SVCS" \ && if [ -z "$DAEMON_SLEEP" -o "${VERBOSE_LOOP}" = yes ] ; then \ echo "`date -u` : OK: No changes to reconcile between ${SERVICE_FRAMEWORK} service instances and device configurations in '$UPSCONF'" ; \ fi \ && [ "$RESTART_ALL" = no ] && return 0 if [ -n "$NEW_CHECKSUM" ]; then for UPSS in $NEW_CHECKSUM ; do CURR_DRV="`upsconf_getDriver "$UPSS"`" || CURR_DRV="" DO_UNREGISTER=yes if [ -n "$CURR_DRV" ] ; then # If reload is handled and does not complain, # we are OK to proceed without re-defining # and restarting the driver service instance. "/usr/local/ups/bin/$CURR_DRV" -a "$UPSS" -c reload-or-error >/dev/null 2>/dev/null \ && DO_UNREGISTER=no fi if [ "$DO_UNREGISTER" = yes ] ; then echo "Dropping old ${SERVICE_FRAMEWORK} service instance ${UPSS} whose section in config file has changed..." >&2 $hook_unregisterInstance "$UPSS" else echo "Keeping ${SERVICE_FRAMEWORK} service instance ${UPSS} whose section in config file has changed: live reload sufficed" >&2 fi done upslist_readSvcs "after updating for new config section checksums" fi if [ -n "$UPSLIST_SVCS" ]; then # Drop services that are not in config file (any more?) upslist_delSvcs if [ "$RESTART_ALL" = yes ] && [ "$AUTO_START" = yes ] ; then # Here restart only existing services; new ones will (try to) # start soon after creation and upsd is handled below upslist_restartSvcs fi fi if [ "$RESTART_ALL" = yes ] ; then # Save new checksum of global config $hook_setSavedMD5 "" "`upsconf_getSection_MD5 ""`" fi if [ -n "$UPSLIST_FILE" ]; then # Add services for sections that are in config file but not yet wrapped upslist_addSvcs $hook_refreshSupervizor upslist_readSvcs "after checking for new config sections to define service instances" fi upslist_readSvcs if [ -n "$UPSLIST_SVCS" ] ; then echo "=== The currently defined service instances are:" echo "$UPSLIST_SVCS" fi if [ -n "$UPSLIST_FILE" ] ; then echo "=== The currently defined configurations in '$UPSCONF' are:" echo "$UPSLIST_FILE" fi # We had some changes to the config file; upsd must be made aware if [ "$AUTO_START" = yes ] ; then $hook_restart_upsd fi # Return 42 if there was a change applied succesfully # (but e.g. some services should restart - upsd, maybe upsmon) UPSLIST_EQ_RES=0 upslist_equals "$UPSLIST_FILE" "$UPSLIST_SVCS" || UPSLIST_EQ_RES=$? # File processing and service startups take a while; # make sure upsconf did not change while we worked... # NOTE: Check this at the last moment to minimize # the chance of still not noticing the change made # at just the wrong moment. UPSCONF_CHECKSUM_END="`calc_md5_file "$UPSCONF"`" || true if [ "$UPSCONF_CHECKSUM_END" != "$UPSCONF_CHECKSUM_START" ] ; then # NOTE: even if daemonized, the sleep between iterations # can be configured into an uncomfortably long lag, so # we should re-sync the system config in any case. echo "`date -u` : '$UPSCONF' changed while $0 $* was processing its older contents; re-running the script to pick up the late-coming changes" # Make sure the cycle does not repeat itself due to diffs # from an ages-old state of the file from when we started. UPSCONF_CHECKSUM_START="$UPSCONF_CHECKSUM_END" ( nut_driver_enumerator_main ) ; return $? # The "main" routine at the end of recursions will # do REPORT_RESTART_42 logic or the error exit-code fi if [ "$UPSLIST_EQ_RES" = 0 ] ; then echo "`date -u` : OK: No more changes to reconcile between ${SERVICE_FRAMEWORK} service instances and device configurations in '$UPSCONF'" [ "${REPORT_RESTART_42-}" = no ] && return 0 || return 42 fi return 13 } daemonize() ( # Support (SIG)HUP == signal code 1 to quickly reconfigure, # e.g. to request it while the sleep is happening or while # "main" is processing an earlier change of the file. RECONFIGURE_ASAP=false trap 'RECONFIGURE_ASAP=true' 1 # Note: this loop would die on errors with config file or # inability to ensure that it matches the list of services. # If caller did not `export REPORT_RESTART_42=no` then the # loop would exit with code 42, and probably trigger restart # of the service which wraps this daemon do topple others that # depend on it. # Note: do not quickly skip the "main" based on full-file # checksum refresh, to ensure that whatever is configured # gets applied (e.g. if user disabled some services or they # died, or some config was not applied due to coding error). while nut_driver_enumerator_main ; do if $RECONFIGURE_ASAP ; then echo "`date -u` : Trapped a SIGHUP during last run of nut_driver_enumerator_main, repeating reconfiguration quickly" >&2 else sleep $DAEMON_SLEEP & trap "kill $! ; echo 'Sleep interrupted, processing configs now!'>&2" 1 wait $! fi RECONFIGURE_ASAP=false trap 'RECONFIGURE_ASAP=true' 1 done exit $? ) # Save the checksum of ups.conf as early as possible, # to test in the end that it is still the same file. UPSCONF_CHECKSUM_START="`calc_md5_file "$UPSCONF"`" || true # By default, update wrapping of devices into services if [ $# = 0 ]; then nut_driver_enumerator_main ; exit $? fi if [ $# = 1 ] ; then [ -n "$DAEMON_SLEEP" ] || DAEMON_SLEEP=60 # Note: Not all shells have 'case ... ;&' support case "$1" in --daemon=*) DAEMON_SLEEP="`echo "$1" | sed 's,^--daemon=,,'`" ;; esac case "$1" in --daemon|--daemon=*) daemonize & exit $? ;; esac fi unset DAEMON_SLEEP usage() { cat << EOF $0 (no args) Update wrapping of devices into services $0 --daemon(=freq) Update wrapping of devices into services in an infinite loop Default freq is 60 sec $0 --reconfigure Stop and un-register all service instances and recreate them (e.g. if new dependency template was defined in a new version of this script and/or NUT package) $0 --get-service-framework Print the detected service management framework in this OS $0 --list-devices Print list of devices in NUT config $0 --list-services Print list of service instances which wrap registered NUT devices (full name of service unit) $0 --list-instances Print list of service instances which wrap registered NUT devices (just instance suffix) $0 --get-service-for-device DEV Print the full name of service unit which wraps a NUT device named "DEV" $0 --get-device-for-service SVC Print the NUT device name for full or instance-suffix name of a service unit which wraps it $0 --list-services-for-devices Print a TAB-separated list of service units and corresponding NUT device names which each such unit wraps $0 --show-configs|--show-all-configs Show the complete normalized list of device configuration blocks $0 --show-config DEV $0 --show-device-config DEV Show configuration block of the specified NUT device $0 --show-device-config-value DEV KEY [KEY...] Show single configuration key value of the specified NUT device For flags, shows the flag name if present in the section If several keys or flags are requested, their values are reported one per line in the same order (including empty lines for missing values); any missing value yields a non-zero exit code. EOF } while [ $# -gt 0 ]; do case "$1" in --help|-h|-help) usage; exit 0 ;; --get-service-framework) echo "${SERVICE_FRAMEWORK}" ; exit 0 ;; --reconfigure) upslist_readFile_once || exit $? upslist_readSvcs "before manipulations" if [ -n "$UPSLIST_SVCS" ]; then for UPSS in $UPSLIST_SVCS ; do echo "Dropping old ${SERVICE_FRAMEWORK} service instance for power device [${UPSS}] to reconfigure the service unit..." >&2 $hook_unregisterInstance "$UPSS" done upslist_readSvcs "after dropping" fi if [ -n "$UPSLIST_FILE" ]; then upslist_addSvcs upslist_readSvcs "after checking for new config sections to define service instances" fi # Save new checksum of global config $hook_setSavedMD5 "" "`upsconf_getSection_MD5 ""`" # Service units were manipulated, including saving of checksums; # refresh the service management daemon if needed $hook_refreshSupervizor if [ -n "$UPSLIST_SVCS" ] ; then echo "=== The currently defined service instances are:" echo "$UPSLIST_SVCS" fi if [ -n "$UPSLIST_FILE" ] ; then echo "=== The currently defined configurations in '$UPSCONF' are:" echo "$UPSLIST_FILE" fi # We had some changes to the config file; upsd must be made aware if [ "$AUTO_START" = yes ] ; then $hook_restart_upsd fi # Return 42 if there was a change applied succesfully # (but e.g. some services should restart - upsd, maybe upsmon) UPSLIST_EQ_RES=0 upslist_equals "$UPSLIST_FILE" "$UPSLIST_SVCS" || UPSLIST_EQ_RES=$? # File processing and service startups take a while; # make sure upsconf did not change while we worked... # NOTE: Check this at the last moment to minimize # the chance of still not noticing the change made # at just the wrong moment. UPSCONF_CHECKSUM_END="`calc_md5_file "$UPSCONF"`" || true if [ "$UPSCONF_CHECKSUM_END" != "$UPSCONF_CHECKSUM_START" ] ; then echo "`date -u` : '$UPSCONF' changed while $0 $* was processing its older contents; re-running the script to pick up the late-coming changes" $0 ; exit $? # The "main" routine will do REPORT_RESTART_42 logic too fi if [ "$UPSLIST_EQ_RES" = 0 ] ; then echo "`date -u` : OK: No more changes to reconcile between ${SERVICE_FRAMEWORK} service instances and device configurations in '$UPSCONF'" [ "${REPORT_RESTART_42-}" = no ] && exit 0 || exit 42 fi exit 13 ;; --list-devices) upslist_readFile_once && \ if [ -n "$UPSLIST_FILE" ] ; then echo "=== The currently defined configurations in '$UPSCONF' are:" >&2 echo "$UPSLIST_FILE" exit 0 fi echo "No devices detected in '$UPSCONF'" >&2 exit 1 ;; --list-services) UPSLIST_SVCS_RAW="`$hook_listInstances_raw`" && \ if [ -n "$UPSLIST_SVCS_RAW" ] ; then echo "=== The currently defined service units are:" >&2 echo "$UPSLIST_SVCS_RAW" exit 0 fi echo "No service units detected" >&2 exit 1 ;; --list-instances) upslist_readSvcs "by user request" && \ if [ -n "$UPSLIST_SVCS" ] ; then echo "=== The currently defined service instances are:" >&2 echo "$UPSLIST_SVCS" exit 0 fi echo "No service instances detected" >&2 exit 1 ;; --get-service-for-device) [ -z "$2" ] && echo "Device name argument required" >&2 && exit 1 DEV="$2" upslist_readSvcs "by user request" && [ -n "$UPSLIST_SVCS" ] \ || { echo "No service instances detected" >&2 ; exit 1; } UPSLIST_SVCS_RAW="`$hook_listInstances_raw`" && [ -n "$UPSLIST_SVCS_RAW" ] \ || { echo "No service units detected" >&2 ; exit 1; } vINST="`$hook_validInstanceName "$DEV"`" vUNITD="`$hook_validFullUnitName "$DEV"`" vUNITI="`$hook_validFullUnitName "$vINST"`" # First pass over simple verbatim names for INST in $UPSLIST_SVCS ; do if [ "$INST" = "$DEV" ] ; then for UNIT in $UPSLIST_SVCS_RAW ; do if [ "$UNIT" = "$vUNITD" ] ; then echo "$UNIT" exit 0 fi done fi done for INST in $UPSLIST_SVCS ; do if [ "$INST" = "$vINST" ] ; then for UNIT in $UPSLIST_SVCS_RAW ; do if [ "$UNIT" = "$vUNITI" ] ; then echo "$UNIT" exit 0 fi done fi done echo "No service instances detected that match device '$2'" >&2 exit 1 ;; --get-device-for-service) [ -z "$2" ] && echo "Service (instance) name argument required" >&2 && exit 1 # Instance name can be a hash or "native" NUT section name SVC="`$hook_validInstanceSuffixName "$2"`" case "$SVC" in MD5_*) ;; # fall through to the bulk of code *) upslist_readFile_once || exit $? echo "$UPSLIST_FILE" | grep -E "^$SVC\$" exit $? ;; esac FINAL_RES=0 OUT="`"$0" --list-services-for-devices`" && [ -n "$OUT" ] || FINAL_RES=$? if [ "$FINAL_RES" = 0 ]; then echo "$OUT" | grep "$SVC" | ( \ while read _SVC _DEV ; do _SVC="`$hook_validInstanceSuffixName "${_SVC}"`" || exit [ "${_SVC}" = "${SVC}" ] && echo "$_DEV" && exit 0 done ; exit 1 ) && exit 0 fi echo "No service instance '$2' was detected that matches a NUT device" >&2 exit 1 ;; --list-services-for-devices) FINAL_RES=0 upslist_readFile_once && [ -n "$UPSLIST_FILE" ] \ || { echo "No devices detected in '$UPSCONF'" >&2 ; exit 1 ; } upslist_readSvcs "by user request" && [ -n "$UPSLIST_SVCS" ] \ || { echo "No service instances detected" >&2 ; exit 1; } UPSLIST_SVCS_RAW="`$hook_listInstances_raw`" && [ -n "$UPSLIST_SVCS_RAW" ] \ || { echo "No service units detected" >&2 ; exit 1; } for DEV in $UPSLIST_FILE ; do vINST="`$hook_validInstanceName "$DEV"`" vUNITD="`$hook_validFullUnitName "$DEV"`" vUNITI="`$hook_validFullUnitName "$vINST"`" # First pass over simple verbatim names for INST in $UPSLIST_SVCS ; do if [ "$INST" = "$DEV" ] ; then for UNIT in $UPSLIST_SVCS_RAW ; do if [ "$UNIT" = "$vUNITD" ] ; then printf '%s\t%s\n' "$UNIT" "$DEV" continue 3 fi done fi done for INST in $UPSLIST_SVCS ; do if [ "$INST" = "$vINST" ] ; then for UNIT in $UPSLIST_SVCS_RAW ; do if [ "$UNIT" = "$vUNITI" ] ; then printf '%s\t%s\n' "$UNIT" "$DEV" continue 3 fi done fi done echo "WARNING: no service instances detected that match device '$DEV'" >&2 FINAL_RES=1 done exit $FINAL_RES ;; --show-configs|--show-device-configs|--show-all-configs|--show-all-device-configs) RES=0 upslist_readFile_once || RES=$? [ "$RES" != 0 ] && { echo "ERROR: upslist_readFile_once () failed with code $RES" >&2; exit $RES; } [ -n "$UPSLIST_FILE" ] \ || { echo "WARNING: No devices detected in '$UPSCONF'" >&2 ; RES=1 ; } echo "$UPSCONF_DATA" exit $RES ;; --show-config|--show-device-config) [ -z "$2" ] && echo "WARNING: Device name argument empty, will show global config" >&2 DEV="$2" upsconf_getSection "$DEV" exit $? ;; --show-config-value|--show-device-config-value) [ -z "$3" ] && echo "At least one configuration key name argument is required" >&2 && exit 1 [ -z "$2" ] && echo "WARNING: Device name argument empty, will show global config" >&2 DEV="$2" shift 2 upsconf_getValue "$DEV" "$@" exit $? ;; upsconf_debug) # Not public, not in usage() [ -z "$2" ] && echo "Device name argument required" >&2 && exit 1 upsconf_debug "$2" exit $? ;; upslist_debug) # Not public, not in usage() upslist_readFile_once || exit upslist_debug exit $? ;; *) echo "Unrecognized argument: $1" >&2 ; exit 1 ;; esac shift done nut-2.8.1/scripts/upsdrvsvcctl/Makefile.am0000644000175000017500000000043314500336654015544 00000000000000EXTRA_DIST = README if HAVE_SYSTEMD EXTRA_DIST += nut-driver-enumerator.sh upsdrvsvcctl else if WITH_SOLARIS_SMF EXTRA_DIST += nut-driver-enumerator.sh upsdrvsvcctl endif endif EXTRA_DIST += nut-driver-enumerator.sh.in upsdrvsvcctl.in MAINTAINERCLEANFILES = Makefile.in .dirstamp nut-2.8.1/scripts/upsdrvsvcctl/README0000644000175000017500000000115514377374134014401 00000000000000This directory contains the shared NUT support files for Linux systemd (the System and Service Manager) and Solaris SMF (Service Management Framework). It includes the nut-driver-enumerator.sh (service and implementation method) and upsdrvsvcctl (tool) to manage NUT drivers as service instances. These files are automatically installed into SBINDIR/upsdrvsvcctl and LIBEXECDIR/nut-driver-enumerator.sh, upon detection (at configure time) of a systemd or SMF enabled system, with Makefiles of the ../systemd/ and ../Solaris/ source directories respectively. Contributed 2016-2018 by Jim Klimov nut-2.8.1/scripts/Solaris/0000755000175000017500000000000014520277777012456 500000000000000nut-2.8.1/scripts/Solaris/nut-server.xml.in0000644000175000017500000001016314501607135015620 00000000000000 nut-2.8.1/scripts/Solaris/svc-nut-monitor.in0000755000175000017500000000245614517562211016006 00000000000000#!/sbin/sh # Trivial (better is yet to come) SMF method script to start nut services # Adapted for OpenIndiana userland from init.d script template in NUT sources # Adaptation copyright (C) 2016-2017 Jim Klimov if [ -z "$SMF_FMRI" ]; then echo "$0 must be called in SMF context!" >&2 exit 1 fi # smf(5) . /lib/svc/share/smf_include.sh || exit prefix="@prefix@" NUT_DIR="@prefix@" NUT_SBIN_DIR="${NUT_DIR}/sbin" NUT_LIB_DIR="${NUT_DIR}/lib" NUT_RUN_DIR="@ALTPIDPATH@" CONFIG="@CONFPATH@/nut.conf" NUTUSER="@RUN_AS_USER@" NUTGROUP="@RUN_AS_GROUP@" # We anticipate some tighter integration with SMF later: #NUT_QUIET_INIT_UPSNOTIFY=true #export NUT_QUIET_INIT_UPSNOTIFY if [ -f "$CONFIG" ] ; then . "$CONFIG" fi ups_start () { if [ "$MODE" = "none" ];then echo "No NUT mode set, not starting anything" >&2 exit $SMF_EXIT_ERR_CONFIG fi # Default rights inspired by NUT scripts/Solaris/postinstall.in mkdir -p "@PIDPATH@" # (for privileged processes) mkdir -p "$NUT_RUN_DIR" && \ chown "root:$NUTGROUP" "$NUT_RUN_DIR" && \ chmod 770 "$NUT_RUN_DIR" \ || exit $SMF_EXIT_ERR_FATAL LD_LIBRARY_PATH="${NUT_LIB_DIR}:$LD_LIBRARY_PATH" "${NUT_SBIN_DIR}"/upsmon #> /dev/null 2>&1 } case "$1" in 'start') ups_start ;; *) echo "" echo "Usage: '$0' {start}" echo "" exit $SMF_EXIT_ERR_CONFIG ;; esac exit $? nut-2.8.1/scripts/Solaris/nut-monitor.xml.in0000644000175000017500000000547214377374134016023 00000000000000 nut-2.8.1/scripts/Solaris/nut-driver.xml.in0000644000175000017500000001014714501607135015607 00000000000000 nut-2.8.1/scripts/Solaris/nut-driver-enumerator.xml.in0000644000175000017500000001160014377374134017774 00000000000000 nut-2.8.1/scripts/Solaris/reset-ups-usb-solaris.sh.sample0000755000175000017500000000446314501607135020374 00000000000000#!/bin/sh # Copyright (C) 2020,2022 by Jim Klimov # Licensed according to GPLv2+ for the NUT project # If your USB connection on Solaris/illumos platform gets lost regularly # and might benefit from a harsh reconnection, consider customizing this # script (or its envvar args) to your deployment and adding to crontab: # 0,5,10,15,20,25,30,35,40,45,50,55 * * * * MODE=optional /etc/nut/reset-ups-usb-solaris.sh # Comment this away in your deployment after customizing defaults; # see NUT source docs/solaris-usb.txt for details: echo "WARNING: Script $0 was not yet tailored to this deployment!" >&2 ; exit # TODO: Parse CLI args? [ -n "$MODE" ] || MODE='always' # Defaults below come from documentation example: [ -n "$DEVICE" ] || DEVICE='innotech' [ -n "$CFGADM_APID" ] || CFGADM_APID="usb10/1" # Can specify '-' to not reload OS driver: [ -n "$UGEN_DRV_ID" ] || UGEN_DRV_ID='"usb665,5161.2"' if [ "$MODE" = optional ]; then if upsc "$DEVICE" 2>&1 | grep -i 'Data stale' ; then : ; else exit 0 ; fi fi # Sanity-checks command -v svcs && command -v svcadm || { echo "ERROR: This system does not have SMF tools?" >&2 ; exit 1; } command -v cfgadm || { echo "ERROR: This system does not have cfgadm?" >&2 ; exit 1; } # upsc and upsdrvctl below are rather informational command -v upsc && command -v upsdrvctl || echo "WARNING: This system does not have NUT tools?" >&2 date svcs -p "$DEVICE" ; upsc "$DEVICE" DO_SVC=false if [ "`svcs -Hostate "$DEVICE"`" = "online" ]; then DO_SVC=true svcadm disable -ts "$DEVICE" fi upsdrvctl stop "$DEVICE" || true echo "Soft-resetting connection of '${CFGADM_APID}':" cfgadm -lv "${CFGADM_APID}" cfgadm -c disconnect -y "${CFGADM_APID}" if [ "$UGEN_DRV_ID" != '-' ] ; then rem_drv ugen ; sleep 3 fi cfgadm -c configure -y "${CFGADM_APID}"; sleep 3 if [ "$UGEN_DRV_ID" != '-' ] ; then add_drv -i "$UGEN_DRV_ID" -m '* 0666 root sys' ugen fi sleep 3 cfgadm -lv "${CFGADM_APID}" if $DO_SVC ; then svcadm enable "$DEVICE" ; fi svcadm clear "$DEVICE" 2>/dev/null dmesg | tail -n 20 date svcs -p "$DEVICE" ; upsc "$DEVICE" || { \ COUNT=60 while [ "$COUNT" -gt 0 ] ; do COUNT="`expr $COUNT - 1`" if upsc "$DEVICE" 2>&1 | grep -Ei '^ups\.status:' >/dev/null ; then break ; fi sleep 1 done svcs -p "$DEVICE" ; upsc "$DEVICE" } nut-2.8.1/scripts/Solaris/pkginfo.in0000644000175000017500000000074714501607135014353 00000000000000PKG="NUT" NAME="Network UPS Tools" ARCH="@target_cpu@" VERSION="@PACKAGE_VERSION@" CATEGORY="application" VENDOR="https://www.networkupstools.org" EMAIL=" " PSTAMP=" " DESCRIPTION="Network UPS Tools (NUT) is a client/server monitoring system that allows computers to share uninterruptible power supply (UPS) and power distribution unit (PDU) hardware. Clients access the hardware through the server, and are notified whenever the power status changes." BASEDIR="@prefix@" CLASSES="none" nut-2.8.1/scripts/Solaris/nut.xml.in0000644000175000017500000000617014377374134014332 00000000000000 nut-2.8.1/scripts/Solaris/Makefile.in0000644000175000017500000010272614520274662014441 00000000000000# Makefile.in generated by automake 1.16.5 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2021 Free Software Foundation, Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. @SET_MAKE@ VPATH = @srcdir@ am__is_gnu_make = { \ if test -z '$(MAKELEVEL)'; then \ false; \ elif test -n '$(MAKE_HOST)'; then \ true; \ elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \ true; \ else \ false; \ fi; \ } am__make_running_with_option = \ case $${target_option-} in \ ?) ;; \ *) echo "am__make_running_with_option: internal error: invalid" \ "target option '$${target_option-}' specified" >&2; \ exit 1;; \ esac; \ has_opt=no; \ sane_makeflags=$$MAKEFLAGS; \ if $(am__is_gnu_make); then \ sane_makeflags=$$MFLAGS; \ else \ case $$MAKEFLAGS in \ *\\[\ \ ]*) \ bs=\\; \ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ esac; \ fi; \ skip_next=no; \ strip_trailopt () \ { \ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ }; \ for flg in $$sane_makeflags; do \ test $$skip_next = yes && { skip_next=no; continue; }; \ case $$flg in \ *=*|--*) continue;; \ -*I) strip_trailopt 'I'; skip_next=yes;; \ -*I?*) strip_trailopt 'I';; \ -*O) strip_trailopt 'O'; skip_next=yes;; \ -*O?*) strip_trailopt 'O';; \ -*l) strip_trailopt 'l'; skip_next=yes;; \ -*l?*) strip_trailopt 'l';; \ -[dEDm]) skip_next=yes;; \ -[JT]) skip_next=yes;; \ esac; \ case $$flg in \ *$$target_option*) has_opt=yes; break;; \ esac; \ done; \ test $$has_opt = yes am__make_dryrun = (target_option=n; $(am__make_running_with_option)) am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkglibexecdir = $(libexecdir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ target_triplet = @target@ @WITH_SOLARIS_SMF_TRUE@am__append_1 = check-local-solaris-smf @WITH_SOLARIS_PKG_IPS_TRUE@am__append_2 = package-solaris-ips @WITH_SOLARIS_PKG_SVR4_TRUE@am__append_3 = package-solaris-svr4 subdir = scripts/Solaris ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/m4/ax_c___attribute__.m4 \ $(top_srcdir)/m4/ax_c_pragmas.m4 \ $(top_srcdir)/m4/ax_check_compile_flag.m4 \ $(top_srcdir)/m4/ax_compare_version.m4 \ $(top_srcdir)/m4/ax_realpath.m4 \ $(top_srcdir)/m4/ax_run_or_link_ifelse.m4 \ $(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \ $(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \ $(top_srcdir)/m4/lt~obsolete.m4 \ $(top_srcdir)/m4/nut_arg_with.m4 \ $(top_srcdir)/m4/nut_check_asciidoc.m4 \ $(top_srcdir)/m4/nut_check_aspell.m4 \ $(top_srcdir)/m4/nut_check_cppcheck.m4 \ $(top_srcdir)/m4/nut_check_headers_windows.m4 \ $(top_srcdir)/m4/nut_check_libavahi.m4 \ $(top_srcdir)/m4/nut_check_libfreeipmi.m4 \ $(top_srcdir)/m4/nut_check_libgd.m4 \ $(top_srcdir)/m4/nut_check_libgpiod.m4 \ $(top_srcdir)/m4/nut_check_libltdl.m4 \ $(top_srcdir)/m4/nut_check_libmodbus.m4 \ $(top_srcdir)/m4/nut_check_libneon.m4 \ $(top_srcdir)/m4/nut_check_libnetsnmp.m4 \ $(top_srcdir)/m4/nut_check_libnss.m4 \ $(top_srcdir)/m4/nut_check_libopenssl.m4 \ $(top_srcdir)/m4/nut_check_libpowerman.m4 \ $(top_srcdir)/m4/nut_check_libregex.m4 \ $(top_srcdir)/m4/nut_check_libsystemd.m4 \ $(top_srcdir)/m4/nut_check_libusb.m4 \ $(top_srcdir)/m4/nut_check_libwrap.m4 \ $(top_srcdir)/m4/nut_check_os.m4 \ $(top_srcdir)/m4/nut_check_pkgconfig.m4 \ $(top_srcdir)/m4/nut_check_python.m4 \ $(top_srcdir)/m4/nut_check_socketlib.m4 \ $(top_srcdir)/m4/nut_compiler_family.m4 \ $(top_srcdir)/m4/nut_func_getnameinfo_argtypes.m4 \ $(top_srcdir)/m4/nut_report_feature.m4 \ $(top_srcdir)/m4/nut_stash_warnings.m4 \ $(top_srcdir)/m4/nut_type_socklen_t.m4 \ $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/include/config.h CONFIG_CLEAN_FILES = nut-driver-enumerator.xml nut-driver.xml \ nut-monitor.xml nut-server.xml nut.xml pkginfo svc-nut-server \ svc-nut-monitor precheck.py preinstall postinstall preremove \ postremove preproto.pl nut CONFIG_CLEAN_VPATH_FILES = am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; am__vpath_adj = case $$p in \ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ *) f=$$p;; \ esac; am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`; am__install_max = 40 am__nobase_strip_setup = \ srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'` am__nobase_strip = \ for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||" am__nobase_list = $(am__nobase_strip_setup); \ for p in $$list; do echo "$$p $$p"; done | \ sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \ $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \ if (++n[$$2] == $(am__install_max)) \ { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \ END { for (dir in files) print dir, files[dir] }' am__base_list = \ sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' am__uninstall_files_from_dir = { \ test -z "$$files" \ || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \ || { echo " ( cd '$$dir' && rm -f" $$files ")"; \ $(am__cd) "$$dir" && rm -f $$files; }; \ } am__installdirs = "$(DESTDIR)$(libexecdir)" "$(DESTDIR)$(sbindir)" \ "$(DESTDIR)$(solarisinitscriptdir)" \ "$(DESTDIR)$(solarissmfmethoddir)" \ "$(DESTDIR)$(solarissmfmanifestdir)" SCRIPTS = $(libexec_SCRIPTS) $(sbin_SCRIPTS) \ $(solarisinitscript_SCRIPTS) $(solarissmfmethod_SCRIPTS) AM_V_P = $(am__v_P_@AM_V@) am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) am__v_P_0 = false am__v_P_1 = : AM_V_GEN = $(am__v_GEN_@AM_V@) am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) am__v_GEN_0 = @echo " GEN " $@; am__v_GEN_1 = AM_V_at = $(am__v_at_@AM_V@) am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) am__v_at_0 = @ am__v_at_1 = SOURCES = DIST_SOURCES = am__can_run_installinfo = \ case $$AM_UPDATE_INFO_DIR in \ n|no|NO) false;; \ *) (install-info --version) >/dev/null 2>&1;; \ esac DATA = $(solarissmfmanifest_DATA) am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) am__DIST_COMMON = $(srcdir)/Makefile.in \ $(srcdir)/nut-driver-enumerator.xml.in \ $(srcdir)/nut-driver.xml.in $(srcdir)/nut-monitor.xml.in \ $(srcdir)/nut-server.xml.in $(srcdir)/nut.in \ $(srcdir)/nut.xml.in $(srcdir)/pkginfo.in \ $(srcdir)/postinstall.in $(srcdir)/postremove.in \ $(srcdir)/precheck.py.in $(srcdir)/preinstall.in \ $(srcdir)/preproto.pl.in $(srcdir)/preremove.in \ $(srcdir)/svc-nut-monitor.in $(srcdir)/svc-nut-server.in \ README DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) A2X = @A2X@ ACLOCAL = @ACLOCAL@ ALTPIDPATH = @ALTPIDPATH@ AMTAR = @AMTAR@ AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ AR = @AR@ ASCIIDOC = @ASCIIDOC@ ASPELL = @ASPELL@ ASPELL_FILTER_LIB_PATH = @ASPELL_FILTER_LIB_PATH@ ASPELL_FILTER_SHARE_PATH = @ASPELL_FILTER_SHARE_PATH@ ASPELL_FILTER_TEX_PATH = @ASPELL_FILTER_TEX_PATH@ AUGPARSE = @AUGPARSE@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ BINDIR = @BINDIR@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CONFIG_FLAGS = @CONFIG_FLAGS@ CONFPATH = @CONFPATH@ CPP = @CPP@ CPPCHECK = @CPPCHECK@ CPPFLAGS = @CPPFLAGS@ CPPUNIT_CFLAGS = @CPPUNIT_CFLAGS@ CPPUNIT_LIBS = @CPPUNIT_LIBS@ CSCOPE = @CSCOPE@ CTAGS = @CTAGS@ CXX = @CXX@ CXXCPP = @CXXCPP@ CXXDEPMODE = @CXXDEPMODE@ CXXFLAGS = @CXXFLAGS@ CYGPATH_W = @CYGPATH_W@ DBLATEX = @DBLATEX@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ DEPLOYED_UPSC = @DEPLOYED_UPSC@ DEPLOYED_UPSD = @DEPLOYED_UPSD@ DLLTOOL = @DLLTOOL@ DOC_BUILD_LIST = @DOC_BUILD_LIST@ DOC_CHECK_LIST = @DOC_CHECK_LIST@ DRIVER_BUILD_LIST = @DRIVER_BUILD_LIST@ DRIVER_INSTALL_TARGET = @DRIVER_INSTALL_TARGET@ DRIVER_MAN_LIST = @DRIVER_MAN_LIST@ DRIVER_MAN_LIST_PAGES = @DRIVER_MAN_LIST_PAGES@ DRVPATH = @DRVPATH@ DSYMUTIL = @DSYMUTIL@ DUMPBIN = @DUMPBIN@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ ETAGS = @ETAGS@ EXEEXT = @EXEEXT@ FGREP = @FGREP@ FORCE_NUT_VERSION = @FORCE_NUT_VERSION@ GDLIB_CONFIG = @GDLIB_CONFIG@ GREP = @GREP@ HAVE_SYS_SOCKET_H = @HAVE_SYS_SOCKET_H@ HAVE_WINSOCK2_H = @HAVE_WINSOCK2_H@ HAVE_WS2TCPIP_H = @HAVE_WS2TCPIP_H@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ LD = @LD@ LDFLAGS = @LDFLAGS@ LIBAVAHI_CFLAGS = @LIBAVAHI_CFLAGS@ LIBAVAHI_LIBS = @LIBAVAHI_LIBS@ LIBDIR = @LIBDIR@ LIBGD_CFLAGS = @LIBGD_CFLAGS@ LIBGD_LDFLAGS = @LIBGD_LDFLAGS@ LIBGPIO_CFLAGS = @LIBGPIO_CFLAGS@ LIBGPIO_LIBS = @LIBGPIO_LIBS@ LIBI2C_LIBS = @LIBI2C_LIBS@ LIBIPMI_CFLAGS = @LIBIPMI_CFLAGS@ LIBIPMI_LIBS = @LIBIPMI_LIBS@ LIBLTDL_CFLAGS = @LIBLTDL_CFLAGS@ LIBLTDL_LIBS = @LIBLTDL_LIBS@ LIBMODBUS_CFLAGS = @LIBMODBUS_CFLAGS@ LIBMODBUS_LIBS = @LIBMODBUS_LIBS@ LIBNEON_CFLAGS = @LIBNEON_CFLAGS@ LIBNEON_LIBS = @LIBNEON_LIBS@ LIBNETSNMP_CFLAGS = @LIBNETSNMP_CFLAGS@ LIBNETSNMP_LIBS = @LIBNETSNMP_LIBS@ LIBOBJS = @LIBOBJS@ LIBPOWERMAN_CFLAGS = @LIBPOWERMAN_CFLAGS@ LIBPOWERMAN_LIBS = @LIBPOWERMAN_LIBS@ LIBREGEX_LIBS = @LIBREGEX_LIBS@ LIBS = @LIBS@ LIBSSL_CFLAGS = @LIBSSL_CFLAGS@ LIBSSL_LIBS = @LIBSSL_LIBS@ LIBSSL_REQUIRES = @LIBSSL_REQUIRES@ LIBSYSTEMD_CFLAGS = @LIBSYSTEMD_CFLAGS@ LIBSYSTEMD_LIBS = @LIBSYSTEMD_LIBS@ LIBTOOL = @LIBTOOL@ LIBTOOL_DEPS = @LIBTOOL_DEPS@ LIBUSB_CFLAGS = @LIBUSB_CFLAGS@ LIBUSB_CONFIG = @LIBUSB_CONFIG@ LIBUSB_LIBS = @LIBUSB_LIBS@ LIBWRAP_CFLAGS = @LIBWRAP_CFLAGS@ LIBWRAP_LIBS = @LIBWRAP_LIBS@ LIPO = @LIPO@ LN_S = @LN_S@ LN_S_R = @LN_S_R@ LTLIBOBJS = @LTLIBOBJS@ LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@ MAINT = @MAINT@ MAKEINFO = @MAKEINFO@ MANIFEST_TOOL = @MANIFEST_TOOL@ MKDIR_P = @MKDIR_P@ MSGFMT = @MSGFMT@ NETLIBS = @NETLIBS@ NET_SNMP_CONFIG = @NET_SNMP_CONFIG@ NM = @NM@ NMEDIT = @NMEDIT@ NUT_DATADIR = @NUT_DATADIR@ NUT_LIBEXECDIR = @NUT_LIBEXECDIR@ NUT_NETVERSION = @NUT_NETVERSION@ NUT_SOURCE_GITREV = @NUT_SOURCE_GITREV@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ OS_NAME = @OS_NAME@ OTOOL = @OTOOL@ OTOOL64 = @OTOOL64@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_SEPARATOR = @PATH_SEPARATOR@ PIDPATH = @PIDPATH@ PKGCONFIGDIR = @PKGCONFIGDIR@ PKG_CONFIG = @PKG_CONFIG@ PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@ PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ PORT = @PORT@ POWERDOWNFLAG = @POWERDOWNFLAG@ PREFIX = @PREFIX@ PYTHON = @PYTHON@ PYTHON2 = @PYTHON2@ PYTHON2_SITE_PACKAGES = @PYTHON2_SITE_PACKAGES@ PYTHON3 = @PYTHON3@ PYTHON3_SITE_PACKAGES = @PYTHON3_SITE_PACKAGES@ PYTHON_SITE_PACKAGES = @PYTHON_SITE_PACKAGES@ RANLIB = @RANLIB@ REALPATH = @REALPATH@ RUN_AS_GROUP = @RUN_AS_GROUP@ RUN_AS_USER = @RUN_AS_USER@ SBINDIR = @SBINDIR@ SED = @SED@ SEMLIBS = @SEMLIBS@ SERLIBS = @SERLIBS@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ SOURCE_HIGHLIGHT = @SOURCE_HIGHLIGHT@ STATEPATH = @STATEPATH@ STRIP = @STRIP@ SUN_LIBUSB = @SUN_LIBUSB@ SYSTEMD_ANALYZE_PROGRAM = @SYSTEMD_ANALYZE_PROGRAM@ SYSTEMD_DAEMON_ARGS_DRIVER = @SYSTEMD_DAEMON_ARGS_DRIVER@ SYSTEMD_DAEMON_ARGS_UPSD = @SYSTEMD_DAEMON_ARGS_UPSD@ SYSTEMD_DAEMON_ARGS_UPSMON = @SYSTEMD_DAEMON_ARGS_UPSMON@ SYSTEMD_DAEMON_NOTIFYACCESS_DRIVER = @SYSTEMD_DAEMON_NOTIFYACCESS_DRIVER@ SYSTEMD_DAEMON_NOTIFYACCESS_UPSD = @SYSTEMD_DAEMON_NOTIFYACCESS_UPSD@ SYSTEMD_DAEMON_NOTIFYACCESS_UPSMON = @SYSTEMD_DAEMON_NOTIFYACCESS_UPSMON@ SYSTEMD_DAEMON_TYPE_DRIVER = @SYSTEMD_DAEMON_TYPE_DRIVER@ SYSTEMD_DAEMON_TYPE_UPSD = @SYSTEMD_DAEMON_TYPE_UPSD@ SYSTEMD_DAEMON_TYPE_UPSMON = @SYSTEMD_DAEMON_TYPE_UPSMON@ SYSTEMD_DAEMON_WATCHDOG_DRIVER = @SYSTEMD_DAEMON_WATCHDOG_DRIVER@ SYSTEMD_DAEMON_WATCHDOG_UPSD = @SYSTEMD_DAEMON_WATCHDOG_UPSD@ SYSTEMD_DAEMON_WATCHDOG_UPSMON = @SYSTEMD_DAEMON_WATCHDOG_UPSMON@ SYSTEMD_TMPFILES_PROGRAM = @SYSTEMD_TMPFILES_PROGRAM@ TREE_VERSION = @TREE_VERSION@ VALGRIND = @VALGRIND@ VERSION = @VERSION@ WINDMC = @WINDMC@ WINDRES = @WINDRES@ WORDS_BIGENDIAN = @WORDS_BIGENDIAN@ XMLLINT = @XMLLINT@ XSLTPROC = @XSLTPROC@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_AR = @ac_ct_AR@ ac_ct_CC = @ac_ct_CC@ ac_ct_CXX = @ac_ct_CXX@ ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__tar = @am__tar@ am__untar = @am__untar@ auglensdir = @auglensdir@ bindir = @bindir@ build = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ cgiexecdir = @cgiexecdir@ datadir = @datadir@ datarootdir = @datarootdir@ devddir = @devddir@ docdir = @docdir@ driverexecdir = @driverexecdir@ dummy_PKG_CONFIG = @dummy_PKG_CONFIG@ dummy_PKG_CONFIG_CFLAGS = @dummy_PKG_CONFIG_CFLAGS@ dummy_PKG_CONFIG_LIBS = @dummy_PKG_CONFIG_LIBS@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ hotplugdir = @hotplugdir@ htmldir = @htmldir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libdir = @libdir@ libexecdir = @libexecdir@ localedir = @localedir@ localstatedir = @localstatedir@ mandir = @mandir@ mkdir_p = @mkdir_p@ now = @now@ nut_with_nut_monitor = @nut_with_nut_monitor@ nut_with_nut_monitor_desktop = @nut_with_nut_monitor_desktop@ nut_with_nut_monitor_dir = @nut_with_nut_monitor_dir@ nut_with_nut_monitor_py2gtk2 = @nut_with_nut_monitor_py2gtk2@ nut_with_nut_monitor_py3qt5 = @nut_with_nut_monitor_py3qt5@ nut_with_pynut = @nut_with_pynut@ nut_with_pynut_py = @nut_with_pynut_py@ nut_with_pynut_py2 = @nut_with_pynut_py2@ nut_with_pynut_py3 = @nut_with_pynut_py3@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ pkgconfigdir = @pkgconfigdir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ runstatedir = @runstatedir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ sysconfdir = @sysconfdir@ systemdshutdowndir = @systemdshutdowndir@ systemdsystemunitdir = @systemdsystemunitdir@ systemdtmpfilesdir = @systemdtmpfilesdir@ target = @target@ target_alias = @target_alias@ target_cpu = @target_cpu@ target_os = @target_os@ target_vendor = @target_vendor@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ udevdir = @udevdir@ EXTRA_DIST = makelocal.sh precheck.py.in preproto.pl.in README \ reset-ups-usb-solaris.sh.sample PROTOTYPE_DIR = $(DESTDIR)@prefix@ SOLARIS_CHECK_TARGETS = $(am__append_1) SOLARIS_SMF_MANIFESTS = \ nut.xml \ nut-server.xml \ nut-monitor.xml \ nut-driver.xml \ nut-driver-enumerator.xml SOLARIS_SMF_METHODSCRIPTS = \ svc-nut-server \ svc-nut-monitor # OS equivalent of /lib/svc/method and /var/svc/manifest/application # but we can just use then from this location @WITH_SOLARIS_SMF_TRUE@solarissmfmethoddir = @datadir@/solaris-smf/method @WITH_SOLARIS_SMF_TRUE@solarissmfmanifestdir = @datadir@/solaris-smf/manifest @WITH_SOLARIS_SMF_TRUE@solarissmfmethod_SCRIPTS = $(SOLARIS_SMF_METHODSCRIPTS) @WITH_SOLARIS_SMF_TRUE@solarissmfmanifest_DATA = $(SOLARIS_SMF_MANIFESTS) @WITH_SOLARIS_SMF_TRUE@libexec_SCRIPTS = ../upsdrvsvcctl/nut-driver-enumerator.sh @WITH_SOLARIS_SMF_TRUE@sbin_SCRIPTS = ../upsdrvsvcctl/upsdrvsvcctl @WITH_SOLARIS_INIT_TRUE@solarisinitscriptdir = @datadir@/solaris-init @WITH_SOLARIS_INIT_TRUE@solarisinitscript_SCRIPTS = nut reset-ups-usb-solaris.sh.sample SOLARIS_PACKAGE_TARGETS = $(am__append_2) $(am__append_3) # TODO: Reduce build dependencies (implicit!) on python and perl # by shelling the scripts used below # NOTE: This assumes the rest of the product has already been built # and installed under PROTOTYPE_DIR, but declares no explicit # dependency on that SOLARIS_PACKAGE_SVR4_HELPERSCRIPTS = makelocal.sh precheck.py preproto.pl SOLARIS_PACKAGE_SVR4_INSTALLSCRIPTS = preinstall postinstall preremove postremove SOLARIS_PACKAGE_SVR4_INSTALLDATA = pkginfo MAINTAINERCLEANFILES = Makefile.in .dirstamp all: all-am .SUFFIXES: $(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu scripts/Solaris/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --gnu scripts/Solaris/Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): nut-driver-enumerator.xml: $(top_builddir)/config.status $(srcdir)/nut-driver-enumerator.xml.in cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ nut-driver.xml: $(top_builddir)/config.status $(srcdir)/nut-driver.xml.in cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ nut-monitor.xml: $(top_builddir)/config.status $(srcdir)/nut-monitor.xml.in cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ nut-server.xml: $(top_builddir)/config.status $(srcdir)/nut-server.xml.in cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ nut.xml: $(top_builddir)/config.status $(srcdir)/nut.xml.in cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ pkginfo: $(top_builddir)/config.status $(srcdir)/pkginfo.in cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ svc-nut-server: $(top_builddir)/config.status $(srcdir)/svc-nut-server.in cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ svc-nut-monitor: $(top_builddir)/config.status $(srcdir)/svc-nut-monitor.in cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ precheck.py: $(top_builddir)/config.status $(srcdir)/precheck.py.in cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ preinstall: $(top_builddir)/config.status $(srcdir)/preinstall.in cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ postinstall: $(top_builddir)/config.status $(srcdir)/postinstall.in cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ preremove: $(top_builddir)/config.status $(srcdir)/preremove.in cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ postremove: $(top_builddir)/config.status $(srcdir)/postremove.in cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ preproto.pl: $(top_builddir)/config.status $(srcdir)/preproto.pl.in cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ nut: $(top_builddir)/config.status $(srcdir)/nut.in cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ install-libexecSCRIPTS: $(libexec_SCRIPTS) @$(NORMAL_INSTALL) @list='$(libexec_SCRIPTS)'; test -n "$(libexecdir)" || list=; \ if test -n "$$list"; then \ echo " $(MKDIR_P) '$(DESTDIR)$(libexecdir)'"; \ $(MKDIR_P) "$(DESTDIR)$(libexecdir)" || exit 1; \ fi; \ for p in $$list; do \ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ if test -f "$$d$$p"; then echo "$$d$$p"; echo "$$p"; else :; fi; \ done | \ sed -e 'p;s,.*/,,;n' \ -e 'h;s|.*|.|' \ -e 'p;x;s,.*/,,;$(transform)' | sed 'N;N;N;s,\n, ,g' | \ $(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1; } \ { d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \ if ($$2 == $$4) { files[d] = files[d] " " $$1; \ if (++n[d] == $(am__install_max)) { \ print "f", d, files[d]; n[d] = 0; files[d] = "" } } \ else { print "f", d "/" $$4, $$1 } } \ END { for (d in files) print "f", d, files[d] }' | \ while read type dir files; do \ if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \ test -z "$$files" || { \ echo " $(INSTALL_SCRIPT) $$files '$(DESTDIR)$(libexecdir)$$dir'"; \ $(INSTALL_SCRIPT) $$files "$(DESTDIR)$(libexecdir)$$dir" || exit $$?; \ } \ ; done uninstall-libexecSCRIPTS: @$(NORMAL_UNINSTALL) @list='$(libexec_SCRIPTS)'; test -n "$(libexecdir)" || exit 0; \ files=`for p in $$list; do echo "$$p"; done | \ sed -e 's,.*/,,;$(transform)'`; \ dir='$(DESTDIR)$(libexecdir)'; $(am__uninstall_files_from_dir) install-sbinSCRIPTS: $(sbin_SCRIPTS) @$(NORMAL_INSTALL) @list='$(sbin_SCRIPTS)'; test -n "$(sbindir)" || list=; \ if test -n "$$list"; then \ echo " $(MKDIR_P) '$(DESTDIR)$(sbindir)'"; \ $(MKDIR_P) "$(DESTDIR)$(sbindir)" || exit 1; \ fi; \ for p in $$list; do \ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ if test -f "$$d$$p"; then echo "$$d$$p"; echo "$$p"; else :; fi; \ done | \ sed -e 'p;s,.*/,,;n' \ -e 'h;s|.*|.|' \ -e 'p;x;s,.*/,,;$(transform)' | sed 'N;N;N;s,\n, ,g' | \ $(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1; } \ { d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \ if ($$2 == $$4) { files[d] = files[d] " " $$1; \ if (++n[d] == $(am__install_max)) { \ print "f", d, files[d]; n[d] = 0; files[d] = "" } } \ else { print "f", d "/" $$4, $$1 } } \ END { for (d in files) print "f", d, files[d] }' | \ while read type dir files; do \ if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \ test -z "$$files" || { \ echo " $(INSTALL_SCRIPT) $$files '$(DESTDIR)$(sbindir)$$dir'"; \ $(INSTALL_SCRIPT) $$files "$(DESTDIR)$(sbindir)$$dir" || exit $$?; \ } \ ; done uninstall-sbinSCRIPTS: @$(NORMAL_UNINSTALL) @list='$(sbin_SCRIPTS)'; test -n "$(sbindir)" || exit 0; \ files=`for p in $$list; do echo "$$p"; done | \ sed -e 's,.*/,,;$(transform)'`; \ dir='$(DESTDIR)$(sbindir)'; $(am__uninstall_files_from_dir) install-solarisinitscriptSCRIPTS: $(solarisinitscript_SCRIPTS) @$(NORMAL_INSTALL) @list='$(solarisinitscript_SCRIPTS)'; test -n "$(solarisinitscriptdir)" || list=; \ if test -n "$$list"; then \ echo " $(MKDIR_P) '$(DESTDIR)$(solarisinitscriptdir)'"; \ $(MKDIR_P) "$(DESTDIR)$(solarisinitscriptdir)" || exit 1; \ fi; \ for p in $$list; do \ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ if test -f "$$d$$p"; then echo "$$d$$p"; echo "$$p"; else :; fi; \ done | \ sed -e 'p;s,.*/,,;n' \ -e 'h;s|.*|.|' \ -e 'p;x;s,.*/,,;$(transform)' | sed 'N;N;N;s,\n, ,g' | \ $(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1; } \ { d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \ if ($$2 == $$4) { files[d] = files[d] " " $$1; \ if (++n[d] == $(am__install_max)) { \ print "f", d, files[d]; n[d] = 0; files[d] = "" } } \ else { print "f", d "/" $$4, $$1 } } \ END { for (d in files) print "f", d, files[d] }' | \ while read type dir files; do \ if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \ test -z "$$files" || { \ echo " $(INSTALL_SCRIPT) $$files '$(DESTDIR)$(solarisinitscriptdir)$$dir'"; \ $(INSTALL_SCRIPT) $$files "$(DESTDIR)$(solarisinitscriptdir)$$dir" || exit $$?; \ } \ ; done uninstall-solarisinitscriptSCRIPTS: @$(NORMAL_UNINSTALL) @list='$(solarisinitscript_SCRIPTS)'; test -n "$(solarisinitscriptdir)" || exit 0; \ files=`for p in $$list; do echo "$$p"; done | \ sed -e 's,.*/,,;$(transform)'`; \ dir='$(DESTDIR)$(solarisinitscriptdir)'; $(am__uninstall_files_from_dir) install-solarissmfmethodSCRIPTS: $(solarissmfmethod_SCRIPTS) @$(NORMAL_INSTALL) @list='$(solarissmfmethod_SCRIPTS)'; test -n "$(solarissmfmethoddir)" || list=; \ if test -n "$$list"; then \ echo " $(MKDIR_P) '$(DESTDIR)$(solarissmfmethoddir)'"; \ $(MKDIR_P) "$(DESTDIR)$(solarissmfmethoddir)" || exit 1; \ fi; \ for p in $$list; do \ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ if test -f "$$d$$p"; then echo "$$d$$p"; echo "$$p"; else :; fi; \ done | \ sed -e 'p;s,.*/,,;n' \ -e 'h;s|.*|.|' \ -e 'p;x;s,.*/,,;$(transform)' | sed 'N;N;N;s,\n, ,g' | \ $(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1; } \ { d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \ if ($$2 == $$4) { files[d] = files[d] " " $$1; \ if (++n[d] == $(am__install_max)) { \ print "f", d, files[d]; n[d] = 0; files[d] = "" } } \ else { print "f", d "/" $$4, $$1 } } \ END { for (d in files) print "f", d, files[d] }' | \ while read type dir files; do \ if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \ test -z "$$files" || { \ echo " $(INSTALL_SCRIPT) $$files '$(DESTDIR)$(solarissmfmethoddir)$$dir'"; \ $(INSTALL_SCRIPT) $$files "$(DESTDIR)$(solarissmfmethoddir)$$dir" || exit $$?; \ } \ ; done uninstall-solarissmfmethodSCRIPTS: @$(NORMAL_UNINSTALL) @list='$(solarissmfmethod_SCRIPTS)'; test -n "$(solarissmfmethoddir)" || exit 0; \ files=`for p in $$list; do echo "$$p"; done | \ sed -e 's,.*/,,;$(transform)'`; \ dir='$(DESTDIR)$(solarissmfmethoddir)'; $(am__uninstall_files_from_dir) mostlyclean-libtool: -rm -f *.lo clean-libtool: -rm -rf .libs _libs install-solarissmfmanifestDATA: $(solarissmfmanifest_DATA) @$(NORMAL_INSTALL) @list='$(solarissmfmanifest_DATA)'; test -n "$(solarissmfmanifestdir)" || list=; \ if test -n "$$list"; then \ echo " $(MKDIR_P) '$(DESTDIR)$(solarissmfmanifestdir)'"; \ $(MKDIR_P) "$(DESTDIR)$(solarissmfmanifestdir)" || exit 1; \ fi; \ for p in $$list; do \ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ echo "$$d$$p"; \ done | $(am__base_list) | \ while read files; do \ echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(solarissmfmanifestdir)'"; \ $(INSTALL_DATA) $$files "$(DESTDIR)$(solarissmfmanifestdir)" || exit $$?; \ done uninstall-solarissmfmanifestDATA: @$(NORMAL_UNINSTALL) @list='$(solarissmfmanifest_DATA)'; test -n "$(solarissmfmanifestdir)" || list=; \ files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ dir='$(DESTDIR)$(solarissmfmanifestdir)'; $(am__uninstall_files_from_dir) tags TAGS: ctags CTAGS: cscope cscopelist: distdir: $(BUILT_SOURCES) $(MAKE) $(AM_MAKEFLAGS) distdir-am distdir-am: $(DISTFILES) @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ dist_files=`for file in $$list; do echo $$file; done | \ sed -e "s|^$$srcdirstrip/||;t" \ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ case $$dist_files in \ */*) $(MKDIR_P) `echo "$$dist_files" | \ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ sort -u` ;; \ esac; \ for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d "$(distdir)/$$file"; then \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ else \ test -f "$(distdir)/$$file" \ || cp -p $$d/$$file "$(distdir)/$$file" \ || exit 1; \ fi; \ done check-am: all-am $(MAKE) $(AM_MAKEFLAGS) check-local check: check-am all-am: Makefile $(SCRIPTS) $(DATA) installdirs: for dir in "$(DESTDIR)$(libexecdir)" "$(DESTDIR)$(sbindir)" "$(DESTDIR)$(solarisinitscriptdir)" "$(DESTDIR)$(solarissmfmethoddir)" "$(DESTDIR)$(solarissmfmanifestdir)"; do \ test -z "$$dir" || $(MKDIR_P) "$$dir"; \ done install: install-am install-exec: install-exec-am install-data: install-data-am uninstall: uninstall-am install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-am install-strip: if test -z '$(STRIP)'; then \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ install; \ else \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ fi mostlyclean-generic: clean-generic: distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." -test -z "$(MAINTAINERCLEANFILES)" || rm -f $(MAINTAINERCLEANFILES) clean: clean-am clean-am: clean-generic clean-libtool mostlyclean-am distclean: distclean-am -rm -f Makefile distclean-am: clean-am distclean-generic dvi: dvi-am dvi-am: html: html-am html-am: info: info-am info-am: install-data-am: install-solarisinitscriptSCRIPTS \ install-solarissmfmanifestDATA install-solarissmfmethodSCRIPTS install-dvi: install-dvi-am install-dvi-am: install-exec-am: install-libexecSCRIPTS install-sbinSCRIPTS install-html: install-html-am install-html-am: install-info: install-info-am install-info-am: install-man: install-pdf: install-pdf-am install-pdf-am: install-ps: install-ps-am install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-am -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-am mostlyclean-am: mostlyclean-generic mostlyclean-libtool pdf: pdf-am pdf-am: ps: ps-am ps-am: uninstall-am: uninstall-libexecSCRIPTS uninstall-sbinSCRIPTS \ uninstall-solarisinitscriptSCRIPTS \ uninstall-solarissmfmanifestDATA \ uninstall-solarissmfmethodSCRIPTS .MAKE: check-am install-am install-strip .PHONY: all all-am check check-am check-local clean clean-generic \ clean-libtool cscopelist-am ctags-am distclean \ distclean-generic distclean-libtool distdir dvi dvi-am html \ html-am info info-am install install-am install-data \ install-data-am install-dvi install-dvi-am install-exec \ install-exec-am install-html install-html-am install-info \ install-info-am install-libexecSCRIPTS install-man install-pdf \ install-pdf-am install-ps install-ps-am install-sbinSCRIPTS \ install-solarisinitscriptSCRIPTS \ install-solarissmfmanifestDATA install-solarissmfmethodSCRIPTS \ install-strip installcheck installcheck-am installdirs \ maintainer-clean maintainer-clean-generic mostlyclean \ mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \ tags-am uninstall uninstall-am uninstall-libexecSCRIPTS \ uninstall-sbinSCRIPTS uninstall-solarisinitscriptSCRIPTS \ uninstall-solarissmfmanifestDATA \ uninstall-solarissmfmethodSCRIPTS .PRECIOUS: Makefile package: $(SOLARIS_PACKAGE_TARGETS) package-solaris-svr4: $(SOLARIS_PACKAGE_SVR4_HELPERSCRIPTS) $(SOLARIS_PACKAGE_SVR4_INSTALLSCRIPTS) $(SOLARIS_PACKAGE_SVR4_INSTALLDATA) if test -n "@auglensdir@" && test -d "$(DESTDIR)@auglensdir@" ; then \ $(MKDIR_P) "$(DESTDIR)@datadir@/augeas-lenses" && \ cd "$(DESTDIR)@auglensdir@" && \ ( cp -prf ./ "$(DESTDIR)@datadir@/augeas-lenses/" || cp -rf ./ "$(DESTDIR)@datadir@/augeas-lenses/" ) ; fi cd $(PROTOTYPE_DIR) && find . -print | pkgproto > prototype1 cp $(SOLARIS_PACKAGE_SVR4_HELPERSCRIPTS) $(SOLARIS_PACKAGE_SVR4_INSTALLSCRIPTS) $(SOLARIS_PACKAGE_SVR4_INSTALLDATA) $(PROTOTYPE_DIR) cd $(PROTOTYPE_DIR) && chmod +x $(SOLARIS_PACKAGE_SVR4_HELPERSCRIPTS) $(SOLARIS_PACKAGE_SVR4_INSTALLSCRIPTS) cd $(PROTOTYPE_DIR) && perl preproto.pl @HAVE_PYTHON_TRUE@ cd $(PROTOTYPE_DIR) && $(PYTHON) precheck.py cd $(PROTOTYPE_DIR) && rm -f prototype1 cd $(PROTOTYPE_DIR) && ./makelocal.sh cp $(PROTOTYPE_DIR)/*.gz $(builddir) UNAME_P="`uname -p`" && case "$${UNAME_P}" in \ i386|sparc) \ mv -f NUT_solaris_package.local.gz "$(abs_top_builddir)/NUT_solaris_$${UNAME_P}_package@PACKAGE_VERSION@.local.gz" ;; \ esac # TODO: Define support for IPS packaging (provide p5m files and make rules) package-solaris-ips: @echo "SKIPPED : Target $@ is not implemented yet" check-local: $(SOLARIS_CHECK_TARGETS) check-local-solaris-smf: $(SOLARIS_SMF_MANIFESTS) @[ -x /usr/sbin/svccfg ] || { echo "WARNING : Target $@ skipped due to absent /usr/sbin/svccfg" >&2; return 0; } ; \ RES=0 ; for F in $^ ; do \ echo " SVCCFG-VALIDATE $$F"; \ /usr/sbin/svccfg validate "$$F" || RES=$$? ; \ done; exit $$RES # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: nut-2.8.1/scripts/Solaris/postremove.in0000755000175000017500000000062014501607135015112 00000000000000#!/bin/sh # Postremove script for Network UPS Tools package # Remove init script from /etc/init.d - created by scripts not packaging rm -f /etc/init.d/nut rm -f /etc/rc3.d/S90nut rm -f /etc/rc3.d/K10nut # Remove nut group and user /usr/sbin/userdel "@RUN_AS_USER@" /usr/sbin/groupdel "@RUN_AS_GROUP@" # Remove /var/run/nut rm -rf "@ALTPIDPATH@" # Remove /var/state/ups rm -rf "@STATEPATH@" nut-2.8.1/scripts/Solaris/preinstall.in0000755000175000017500000000111414377374134015076 00000000000000#!/bin/sh # Preinstall script for Network UPS Tools package NUT_DIR="@prefix@" # Create group nut grep -w "@RUN_AS_GROUP@" /etc/group if [ "$?" != 0 ]; then /usr/sbin/groupadd "@RUN_AS_GROUP@" fi # Create user for installing "Network UPS Tools" grep -w "@RUN_AS_USER@" /etc/passwd if [ "$?" != 0 ]; then /usr/sbin/useradd -c "Network UPS Tools" -g "@RUN_AS_GROUP@" -G root -d "@STATEPATH@" -s /bin/false "@RUN_AS_USER@" fi res="`groups "@RUN_AS_GROUP@" | grep -w "@RUN_AS_USER@"`" || res="" if [ -z "$res" ]; then /usr/sbin/usermod -g "@RUN_AS_GROUP@" -G root "@RUN_AS_USER@" fi nut-2.8.1/scripts/Solaris/preremove.in0000755000175000017500000000564014500336654014726 00000000000000#!/bin/sh # Preremove script for Network UPS Tools package # Stop all nut services NUT_DIR="@prefix@" prefix="@prefix@" # expanded as part of some autoconf macros below # TODO/FIXME : Should "/var/run" be a configure variable? # Note that "/var/run" is transient tmpfs, so upgrade has to be done during same uptime. ACTIVE_ENUMERATOR_FMRI_FILE="/var/run/nut-driver-enumerator-fmri.prev" if test -x /usr/sbin/svcadm && test -x /usr/sbin/svccfg && test -x /usr/bin/svcs ; then # Unconfigure SMF services # First detect the first active (online, maintenance, etc.) # instance of nut-driver-enumerator so we can pass it to the # next lifetime in case of re-install of NUT and keep the # user's previously declared preference. ACTIVE_ENUMERATOR="`/usr/bin/svcs -H -o state,fmri '*/nut-driver-enumerator:*' | while read S F ; do [ "$S" != "disabled" ] && [ "$S" != "offline" ] && echo "$F" && break ; done`" if [ -n "$ACTIVE_ENUMERATOR" ]; then rm -f "${ACTIVE_ENUMERATOR_FMRI_FILE}" touch "${ACTIVE_ENUMERATOR_FMRI_FILE}" chmod 600 "${ACTIVE_ENUMERATOR_FMRI_FILE}" chown 0:0 "${ACTIVE_ENUMERATOR_FMRI_FILE}" echo "${ACTIVE_ENUMERATOR}" > "${ACTIVE_ENUMERATOR_FMRI_FILE}" fi # First tell the automagic to stop, so it does not interfere; diligently clean it out below /usr/sbin/svcadm disable nut-driver-enumerator:default || true /usr/sbin/svcadm disable nut-driver-enumerator:daemon || true for S in nut nut-monitor nut-server ; do echo "Stopping NUT service: $S..." /usr/sbin/svcadm clear "$S" 2>/dev/null /usr/sbin/svcadm disable -s "$S" echo "Removing NUT service: $S..." /usr/sbin/svccfg delete "$S" || \ /usr/sbin/svccfg -s "$S" delete || \ /usr/sbin/svccfg -s "$S" delete default done echo "Stopping NUT drivers, if any..." @SBINDIR@/upsdrvsvcctl stop @SBINDIR@/upsdrvctl -DDDDD stop sleep 5 for S in `/usr/bin/svcs -H -o fmri '*/nut-driver:*'` `/usr/bin/svcs -H -o fmri '*/nut-driver-enumerator:*'` ; do echo "Stopping NUT service: $S..." /usr/sbin/svcadm clear "$S" 2>/dev/null /usr/sbin/svcadm disable -s "$S" done sleep 5 for S in `/usr/bin/svcs -H -o fmri '*/nut-driver:*' | grep -wv default` `/usr/bin/svcs -H -o fmri '*/nut-driver-enumerator:*' | grep -wv default` ; do echo "Removing NUT service: $S..." # Note: S here is a full FMRI URL SB="`echo "$S" | sed 's,:[^:]*$,,'`" SI="`echo "$S" | sed 's,^.*:\([^:]*\)$,\1,'`" /usr/sbin/svcadm disable -s "$S" /usr/sbin/svccfg -s "$SB" delete -f "$SI" || \ /usr/sbin/svccfg delete "$S" done for S in nut-driver-enumerator nut-driver ; do echo "Removing NUT service: $S..." && \ /usr/sbin/svccfg delete "$S" || \ /usr/sbin/svccfg -s "$S" delete || \ /usr/sbin/svccfg -s "$S" delete default done else [ -x /etc/init.d/nut ] && /etc/init.d/nut stop fi if [ -n "@auglensdir@" ] && [ -d "@auglensdir@" ] && [ -d "@datarootdir@/augeas-lenses" ] ; then ( cd "@datarootdir@/augeas-lenses" && find . -type f -exec rm -f "@auglensdir@"/'{}' \; ) fi nut-2.8.1/scripts/Solaris/precheck.py.in0000755000175000017500000000331314500336654015130 00000000000000#!@PYTHON@ import sys if sys.version_info >= ( 2, 6 ): import subprocess p = subprocess.Popen(["uname", "-s"], stdout=subprocess.PIPE) platform = p.communicate()[0] if p.returncode != 0: raise Exception("FAILED to get platform from 'uname -s'!") p = subprocess.Popen(["uname", "-p"], stdout=subprocess.PIPE) architecture = p.communicate()[0] if p.returncode != 0: raise Exception("FAILED to get architecture from 'uname -p'!") else: import commands platform = commands.getoutput('uname -s') architecture = commands.getoutput('uname -p') # checkinstall script creation fp=open("checkinstall","w") # Note: same arch is relevant for different bitnesses that # can be discerned via `isainfo` further (if ever needed) fp.write("#!/bin/sh\n") fp.write("\nexpected_platform=SunOS\n") if platform == "SunOS" and architecture == "i386": fp.write("expected_architecture=i386\n") elif platform == "SunOS" and architecture == "sparc": fp.write("expected_architecture=sparc\n") fp.write("platform=\"`uname -s`\"\n") fp.write("architecture=\"`uname -p`\"\n\n") fp.write("if [ \"${platform}\" -eq \"${expected_platform}\" ]; then\n") fp.write("\tif [ \"${architecture}\" -eq \"${expected_architecture}\" ]; then\n") fp.write("\t\techo \"Checkinstall complete\"\n") fp.write("\telse\n") fp.write("\t\techo \"This is not Solaris $architecture machine: platform='${platform}' expected_platform='${expected_platform}'\"\n") fp.write("\t\texit 1\n") fp.write("\tfi\n") fp.write("else\n") fp.write("\techo \"This is not Solaris machine: architecture='${architecture}' expected_architecture='${expected_architecture}'\"\n") fp.write("\texit 1\n") fp.write("fi\n") fp.write("exit 0\n") fp.close() nut-2.8.1/scripts/Solaris/Makefile.am0000644000175000017500000000647314501607135014424 00000000000000EXTRA_DIST = makelocal.sh precheck.py.in preproto.pl.in README PROTOTYPE_DIR = $(DESTDIR)@prefix@ SOLARIS_CHECK_TARGETS = PYTHON = @PYTHON@ SOLARIS_SMF_MANIFESTS = \ nut.xml \ nut-server.xml \ nut-monitor.xml \ nut-driver.xml \ nut-driver-enumerator.xml SOLARIS_SMF_METHODSCRIPTS = \ svc-nut-server \ svc-nut-monitor if WITH_SOLARIS_SMF # OS equivalent of /lib/svc/method and /var/svc/manifest/application # but we can just use then from this location solarissmfmethoddir = @datadir@/solaris-smf/method solarissmfmanifestdir = @datadir@/solaris-smf/manifest solarissmfmethod_SCRIPTS = $(SOLARIS_SMF_METHODSCRIPTS) solarissmfmanifest_DATA = $(SOLARIS_SMF_MANIFESTS) libexec_SCRIPTS = ../upsdrvsvcctl/nut-driver-enumerator.sh sbin_SCRIPTS = ../upsdrvsvcctl/upsdrvsvcctl SOLARIS_CHECK_TARGETS += check-local-solaris-smf endif if WITH_SOLARIS_INIT solarisinitscriptdir = @datadir@/solaris-init solarisinitscript_SCRIPTS = nut reset-ups-usb-solaris.sh.sample endif EXTRA_DIST += reset-ups-usb-solaris.sh.sample SOLARIS_PACKAGE_TARGETS = if WITH_SOLARIS_PKG_IPS SOLARIS_PACKAGE_TARGETS += package-solaris-ips endif if WITH_SOLARIS_PKG_SVR4 SOLARIS_PACKAGE_TARGETS += package-solaris-svr4 endif package: $(SOLARIS_PACKAGE_TARGETS) # TODO: Reduce build dependencies (implicit!) on python and perl # by shelling the scripts used below # NOTE: This assumes the rest of the product has already been built # and installed under PROTOTYPE_DIR, but declares no explicit # dependency on that SOLARIS_PACKAGE_SVR4_HELPERSCRIPTS = makelocal.sh precheck.py preproto.pl SOLARIS_PACKAGE_SVR4_INSTALLSCRIPTS = preinstall postinstall preremove postremove SOLARIS_PACKAGE_SVR4_INSTALLDATA = pkginfo package-solaris-svr4: $(SOLARIS_PACKAGE_SVR4_HELPERSCRIPTS) $(SOLARIS_PACKAGE_SVR4_INSTALLSCRIPTS) $(SOLARIS_PACKAGE_SVR4_INSTALLDATA) if test -n "@auglensdir@" && test -d "$(DESTDIR)@auglensdir@" ; then \ $(MKDIR_P) "$(DESTDIR)@datadir@/augeas-lenses" && \ cd "$(DESTDIR)@auglensdir@" && \ ( cp -prf ./ "$(DESTDIR)@datadir@/augeas-lenses/" || cp -rf ./ "$(DESTDIR)@datadir@/augeas-lenses/" ) ; fi cd $(PROTOTYPE_DIR) && find . -print | pkgproto > prototype1 cp $(SOLARIS_PACKAGE_SVR4_HELPERSCRIPTS) $(SOLARIS_PACKAGE_SVR4_INSTALLSCRIPTS) $(SOLARIS_PACKAGE_SVR4_INSTALLDATA) $(PROTOTYPE_DIR) cd $(PROTOTYPE_DIR) && chmod +x $(SOLARIS_PACKAGE_SVR4_HELPERSCRIPTS) $(SOLARIS_PACKAGE_SVR4_INSTALLSCRIPTS) cd $(PROTOTYPE_DIR) && perl preproto.pl if HAVE_PYTHON cd $(PROTOTYPE_DIR) && $(PYTHON) precheck.py endif cd $(PROTOTYPE_DIR) && rm -f prototype1 cd $(PROTOTYPE_DIR) && ./makelocal.sh cp $(PROTOTYPE_DIR)/*.gz $(builddir) UNAME_P="`uname -p`" && case "$${UNAME_P}" in \ i386|sparc) \ mv -f NUT_solaris_package.local.gz "$(abs_top_builddir)/NUT_solaris_$${UNAME_P}_package@PACKAGE_VERSION@.local.gz" ;; \ esac # TODO: Define support for IPS packaging (provide p5m files and make rules) package-solaris-ips: @echo "SKIPPED : Target $@ is not implemented yet" check-local: $(SOLARIS_CHECK_TARGETS) check-local-solaris-smf: $(SOLARIS_SMF_MANIFESTS) @[ -x /usr/sbin/svccfg ] || { echo "WARNING : Target $@ skipped due to absent /usr/sbin/svccfg" >&2; return 0; } ; \ RES=0 ; for F in $^ ; do \ echo " SVCCFG-VALIDATE $$F"; \ /usr/sbin/svccfg validate "$$F" || RES=$$? ; \ done; exit $$RES MAINTAINERCLEANFILES = Makefile.in .dirstamp nut-2.8.1/scripts/Solaris/preproto.pl.in0000755000175000017500000000241314377374134015210 00000000000000#!/usr/bin/env perl $temp = "prototype1"; $prototype="prototype"; $pkginfo = "pkginfo"; $checkinstall = "checkinstall"; $preinstall = "preinstall"; $postinstall = "postinstall"; $preremove = "preremove"; $postremove = "postremove"; $nutuser = "@RUN_AS_USER@"; $nutgroup = "@RUN_AS_GROUP@"; open (PREPROTO,"< $temp") || die "Unable to read prototype information ($!)\n"; open (PROTO,"> $prototype") || die "Unable to write file prototype ($!)\n"; print PROTO "i pkginfo=./$pkginfo\n"; print PROTO "i checkinstall=./$checkinstall\n"; print PROTO "i preinstall=./$preinstall\n"; print PROTO "i postinstall=./$postinstall\n"; print PROTO "i preremove=./$preremove\n"; print PROTO "i postremove=./$postremove\n"; while () { # Read the prototype information from /tmp/prototype$$ chomp; $thisline = $_; if ($thisline =~ " prototype1 ") { # We don't need that line } elsif ($thisline =~ "^[fd] ") { # Change the ownership for files and directories ($dir, $none, $file, $mode, $user, $group) = split / /,$thisline; print PROTO "$dir $none $file=$file $mode $nutuser $nutgroup\n"; } else { # Symlinks and other stuff should be printed as well ofcourse print PROTO "$thisline\n"; } } #print PROTO "f $none nut $mode root $nutgroup\n"; close PROTO; close PREPROTO; nut-2.8.1/scripts/Solaris/postinstall.in0000755000175000017500000001164514501607135015274 00000000000000#!/bin/sh # Postinstall script for Network UPS Tools package NUT_DIR="@prefix@" prefix="@prefix@" # expanded as part of some autoconf macros below # TODO/FIXME : Should "/var/run" be a configure variable? # Note that "/var/run" is transient tmpfs, so upgrade has to be done during same uptime. ACTIVE_ENUMERATOR_FMRI_FILE="/var/run/nut-driver-enumerator-fmri.prev" # make sure the nut user exists and has correct memberships res="`getent group @RUN_AS_GROUP@`" || res="" if [ -z "$res" ]; then /usr/sbin/groupadd "@RUN_AS_GROUP@" fi res="`getent passwd @RUN_AS_USER@`" || res="" if [ -z "$res" ]; then /usr/sbin/useradd -c "Network UPS Tools" -g "@RUN_AS_GROUP@" -G root -d "@STATEPATH@" -s /bin/false @RUN_AS_USER@ fi res="`groups "@RUN_AS_GROUP@" | grep -w "@RUN_AS_USER@"`" || res="" if [ -z "$res" ]; then /usr/sbin/usermod -g "@RUN_AS_GROUP@" -G root "@RUN_AS_USER@" fi # make sure that conffiles are secured and have the correct ownerships if [ -d "@CONFPATH@" ] ; then chown "root:@RUN_AS_GROUP@" "@CONFPATH@" fi for file in nut.conf ups.conf upsd.conf upsmon.conf upsd.users upssched.conf nut-driver-enumerator.conf; do if [ -f "@CONFPATH@/$file" ] ; then chown "root:@RUN_AS_GROUP@" "@CONFPATH@/$file" chmod 640 "@CONFPATH@/$file" fi done # make sure that /var/run exists (for privileged processes) if [ ! -d "@PIDPATH@" ] ; then mkdir -p "@PIDPATH@" fi # make sure that /var/run/nut exists and has the correct ownerships if [ ! -d "@ALTPIDPATH@" ] ; then mkdir -p "@ALTPIDPATH@" fi if [ -d "@ALTPIDPATH@" ] ; then chown "root:@RUN_AS_GROUP@" "@ALTPIDPATH@" chmod 770 "@ALTPIDPATH@" fi # make sure that /var/state/ups exists and has the correct ownerships if [ ! -d "@STATEPATH@" ] ; then mkdir -p "@STATEPATH@" fi if [ -d "@STATEPATH@" ] ; then chown "root:@RUN_AS_GROUP@" "@STATEPATH@" chmod 770 "@STATEPATH@" fi if [ -n "@auglensdir@" ] && [ -d "@auglensdir@" ] && [ -d "@datarootdir@/augeas-lenses" ] ; then ( cd "@datarootdir@/augeas-lenses" && cp -prf ./ "@auglensdir@"/ ) fi if test -x /usr/sbin/svcadm && test -x /usr/sbin/svccfg && test -x /usr/bin/svcs ; then echo "Register SMF services..." for S in nut-driver-enumerator nut-driver nut-server nut-monitor nut ; do echo "Importing NUT service manifest: $S..." /usr/sbin/svccfg import "@datarootdir@/solaris-smf/manifest/$S.xml" done # Enable services if the system already has a configuration (e.g. upgrade) if test -s "@CONFPATH@/ups.conf" ; then echo "Stopping NUT drivers, if any (in case of upgrade)..." @SBINDIR@/upsdrvsvcctl stop @SBINDIR@/upsdrvctl -DDDDD stop sleep 5 echo "(Re-)register NUT drivers (if any)..." REPORT_RESTART_42=no AUTO_START=no "@NUT_LIBEXECDIR@/nut-driver-enumerator.sh" --reconfigure sleep 2 echo "Enable NUT drivers (if any)..." # Note: we now provide two services, a daemon that keeps checking # the config for changes and a default one that should be refreshed # manually to reconfigure nut-driver instances - and is "cheaper". # This may still fail if the daemon instance is somehow enabled (admin) PREV_ACTIVE_ENUMERATOR="" if test -s "${ACTIVE_ENUMERATOR_FMRI_FILE}" ; then PREV_ACTIVE_ENUMERATOR="`head -1 "${ACTIVE_ENUMERATOR_FMRI_FILE}"`" fi [ x"nut-driver-enumerator:default" = x"${PREV_ACTIVE_ENUMERATOR}" ] && PREV_ACTIVE_ENUMERATOR="" for ACTIVE_ENUMERATOR in ${PREV_ACTIVE_ENUMERATOR} nut-driver-enumerator:default ; do /usr/sbin/svcadm enable -s ${ACTIVE_ENUMERATOR} || \ { /usr/sbin/svcadm clear ${ACTIVE_ENUMERATOR} 2>/dev/null ; \ /usr/sbin/svcadm enable -s ${ACTIVE_ENUMERATOR} ; } && break || true done @SBINDIR@/upsdrvsvcctl start else echo "NOT ENABLING nut-driver-enumerator at this time : missing or empty @CONFPATH@/ups.conf" >&2 fi if test -s "@CONFPATH@/ups.conf" && test -e "@CONFPATH@/upsd.conf" && test -e "@CONFPATH@/upsd.users" ; then # Note on the mix of "-s" and "-e" in tests above: # it is a valid use-case for an admin to have just touched an # empty upsd.conf and so use default settings for the daemon echo "Enable NUT upsd data server..." /usr/sbin/svcadm enable -s nut-server else echo "NOT ENABLING nut-server at this time : missing at least one of : @CONFPATH@/ups.conf @CONFPATH@/upsd.conf @CONFPATH@/upsd.users" >&2 fi if test -s "@CONFPATH@/upsmon.conf" ; then echo "Enable NUT upsmon client..." /usr/sbin/svcadm enable -s nut-monitor else echo "NOT ENABLING nut-monitor at this time : missing or empty @CONFPATH@/upsmon.conf" >&2 fi echo "Enable NUT umbrella service..." /usr/sbin/svcadm enable -s nut else echo "Put init script in /etc/init.d..." cp -pf "@NUT_DATADIR@/solaris-init/nut" /etc/init.d chown root:bin /etc/init.d/nut chmod 744 /etc/init.d/nut ln -s ../init.d/nut /etc/rc3.d/S90nut > /dev/null 2>&1 ln -s ../init.d/nut /etc/rc3.d/K10nut > /dev/null 2>&1 # Start nut services #echo "Starting nut services" #$NUT_DIR/sbin/upsdrvctl start #> /dev/null 2>&1 #$NUT_DIR/sbin/upsd #> /dev/null 2>&1 #$NUT_DIR/sbin/upsmon #> /dev/null 2>&1 fi nut-2.8.1/scripts/Solaris/nut.in0000755000175000017500000000271314517562211013524 00000000000000#!/sbin/sh #init.d script to start nut services NUT_DIR="@prefix@" NUT_SBIN_DIR="${NUT_DIR}/sbin" NUT_LIB_DIR="${NUT_DIR}/lib" CONFIG="@CONFPATH@/nut.conf" # We anticipate some tighter integration with SMF later: #NUT_QUIET_INIT_UPSNOTIFY=true #export NUT_QUIET_INIT_UPSNOTIFY if [ -f "$CONFIG" ] ; then . "$CONFIG" fi ups_stop () { pkill -n upsmon pkill -n upsd LD_LIBRARY_PATH="${NUT_LIB_DIR}:$LD_LIBRARY_PATH" "${NUT_SBIN_DIR}/upsdrvctl" stop > /dev/null 2>&1 } ups_start () { if [ "$MODE" = "none" ];then echo "No NUT mode set, not starting anything" >&2 exit 1 fi if [ "$MODE" != "netclient" ] ; then LD_LIBRARY_PATH="${NUT_LIB_DIR}:$LD_LIBRARY_PATH" "${NUT_SBIN_DIR}/upsdrvctl" start #> /dev/null 2>&1 LD_LIBRARY_PATH="${NUT_LIB_DIR}:$LD_LIBRARY_PATH" "${NUT_SBIN_DIR}/upsd" #> /dev/null 2>&1 fi LD_LIBRARY_PATH="${NUT_LIB_DIR}:$LD_LIBRARY_PATH" "${NUT_SBIN_DIR}/upsmon" #> /dev/null 2>&1 } case $1 in 'start') ups_start ;; 'stop') ups_stop ;; 'restart') ups_stop while pgrep upsd > /dev/null do sleep 1 done ups_start ;; 'poweroff') LD_LIBRARY_PATH="${NUT_LIB_DIR}:$LD_LIBRARY_PATH" "${NUT_SBIN_DIR}/upsmon" -K >/dev/null 2>&1 if [ $? = 0 ]; then echo "Shutting down the UPS(es) ..." echo "WARNING: UPS shutdown is currently disabled, please uncomment it in the init-script if desired" >&2 #${NUT_SBIN_DIR}/upsdrvctl shutdown fi ;; *) echo "" echo "Usage: '$0' {start | stop | restart }" echo "" exit 64 ;; esac exit $? nut-2.8.1/scripts/Solaris/makelocal.sh0000755000175000017500000000066614377374134014670 00000000000000#!/bin/sh # Creates the package file from current-directory contents # Called by Makefile starting from installed prototype directory echo "Making Solaris SVR4 package metadata..." && \ pkgmk -o -d "`pwd`" && \ echo "Making Solaris SVR4 package archive file..." && \ ( yes "" | pkgtrans "`pwd`" "`pwd`/NUT_solaris_package.local" ) && \ echo "Compressing Solaris SVR4 package archive file..." && \ gzip "`pwd`/NUT_solaris_package.local" nut-2.8.1/scripts/Solaris/README0000644000175000017500000000357114500336654013250 00000000000000This directory contains init-scripts and SMF manifests and methods for integration of NUT services with Solaris and descendant OSes. This also includes the nut-driver-enumerator.sh (service and implementation method) and upsdrvsvcctl (tool) to manage NUT drivers as service instances, which are stored in ../upsdrvsvcctl/ subdirectory (portable codebase shared with Linux systemd). The default implementation (runs once) can be enabled with: svcadm enable nut-driver-enumerator:default Note that at the moment there is no out-of-the-box integration for triggering a restart/refresh of the nut-driver-enumerator SMF service at the very instant when the `ups.conf` file is modified, like there is with systemd path unit type. Due to this, the systems administrator is expected to either invoke `svcadm refresh nut-driver-enumerator` after changing the NUT configuration or wait until the daemonized mode, if enabled, picks up the change (should do so within a minute by default). However, a DTrace script or a tool like https://github.com/emcrisostomo/fswatch wrapped into a service might be used for equivalent effect. Alternatively, but somewhat more expensively, the same `nut-driver-enumerator.sh` script can be executed in a loop as the payload of the SMF service to keep inspecting the configuration and apply changes to the running system. It is not a common use-case to keep changing device setups, so this solution is not enforced by default ;) although a service variant is provided... Note that only one of these can be enabled at the same time: svcadm disable nut-driver-enumerator:default svcadm enable nut-driver-enumerator:daemon Init-script solution contributed by numerous authors SMF solution contributed by Jim Klimov For special notes about USB-connected device monitoring with NUT under Solaris and related operating systems, see docs/solaris-usb.txt nut-2.8.1/scripts/Solaris/svc-nut-server.in0000755000175000017500000000373014517562211015621 00000000000000#!/sbin/sh # Trivial (better is yet to come) SMF method script to start nut services # Adapted for OpenIndiana userland from init.d script template in NUT sources # Adaptation copyright (C) 2016 Jim Klimov if [ -z "$SMF_FMRI" ]; then echo "$0 must be called in SMF context!" >&2 exit 1 fi # smf(5) . /lib/svc/share/smf_include.sh || exit prefix="@prefix@" NUT_DIR="@prefix@" NUT_SBIN_DIR="$NUT_DIR/sbin" NUT_LIB_DIR="${NUT_DIR}/lib" NUT_RUN_DIR="`svcprop -p nut/NUT_RUN_DIR $SMF_FMRI`" \ && [ -n "$NUT_RUN_DIR" ] \ || NUT_RUN_DIR="@ALTPIDPATH@" CONFIG="@CONFPATH@/nut.conf" NUTUSER="`svcprop -p nut/NUTUSER $SMF_FMRI`" \ && [ -n "$NUTUSER" ] \ || NUTUSER="@RUN_AS_USER@" NUTGROUP="`svcprop -p nut/NUTGROUP $SMF_FMRI`" \ && [ -n "$NUTGROUP" ] \ || NUTGROUP="@RUN_AS_GROUP@" # We anticipate some tighter integration with SMF later: #NUT_QUIET_INIT_UPSNOTIFY=true #export NUT_QUIET_INIT_UPSNOTIFY if [ -f "$CONFIG" ] ; then . "$CONFIG" fi create_run_dir () { # Default rights inspired by NUT scripts/Solaris/postinstall.in #mkdir -p "@PIDPATH@" # (for privileged processes - not upsd) mkdir -p "$NUT_RUN_DIR" && \ chown "root:$NUTGROUP" "$NUT_RUN_DIR" && \ chmod 770 "$NUT_RUN_DIR" \ || exit $SMF_EXIT_ERR_FATAL } ups_start () { create_run_dir if [ "$MODE" = "none" ];then echo "No NUT mode set, not starting anything" >&2 exit 1 fi if [ "$MODE" != "netclient" ] ; then # In this distribution, UPS drivers are wrapped by service instances #LD_LIBRARY_PATH="${NUT_LIB_DIR}:$LD_LIBRARY_PATH" "${NUT_SBIN_DIR}/upsdrvctl" start #> /dev/null 2>&1 LD_LIBRARY_PATH="${NUT_LIB_DIR}:$LD_LIBRARY_PATH" "${NUT_SBIN_DIR}/upsd" #> /dev/null 2>&1 fi } case "$1" in 'start') ups_start ;; 'refresh'|'reload') LD_LIBRARY_PATH="${NUT_LIB_DIR}:$LD_LIBRARY_PATH" "${NUT_SBIN_DIR}/upsd" -c reload ;; "create_run_dir") # Mostly provided for the sake of nut-driver service create_run_dir ;; *) echo "" echo "Usage: '$0' {start}" echo "" exit $SMF_EXIT_ERR_CONFIG ;; esac exit $? nut-2.8.1/scripts/ufw/0000755000175000017500000000000014520277777011643 500000000000000nut-2.8.1/scripts/ufw/README.adoc0000644000175000017500000000152114501607135013327 00000000000000Uncomplicated Firewall (UFW) support ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ NUT can tightly integrate with link:http://en.wikipedia.org/wiki/Uncomplicated_Firewall[Uncomplicated Firewall] using the provided profile (nut.ufw.profile). You must first install the profile on your system: $ cp nut.ufw.profile /etc/ufw/applications.d/ To enable outside access to your local upsd, use: $ ufw allow NUT To restrict access to the network '192.168.X.Y', use: $ ufw allow from 192.168.0.0/16 to any app NUT You can also use graphical frontends, such as gui-ufw (gufw), ufw-kde or ufw-frontends. For more information, refer to: - link:http://gufw.tuxfamily.org/[UFW homepage], - link:https://launchpad.net/ufw[UFW project page], - link:https://wiki.ubuntu.com/UncomplicatedFirewall[UFW wiki], - UFW manual page, section APPLICATION INTEGRATION nut-2.8.1/scripts/ufw/nut.ufw.profile.in0000644000175000017500000000021314273170601015133 00000000000000[NUT] title=NUT - Network UPS Tools server description=NUT is a client - server system with support for UPS, PDU and PSU. ports=@PORT@/tcp nut-2.8.1/scripts/ufw/Makefile.in0000644000175000017500000004520414520274662013623 00000000000000# Makefile.in generated by automake 1.16.5 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2021 Free Software Foundation, Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. @SET_MAKE@ VPATH = @srcdir@ am__is_gnu_make = { \ if test -z '$(MAKELEVEL)'; then \ false; \ elif test -n '$(MAKE_HOST)'; then \ true; \ elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \ true; \ else \ false; \ fi; \ } am__make_running_with_option = \ case $${target_option-} in \ ?) ;; \ *) echo "am__make_running_with_option: internal error: invalid" \ "target option '$${target_option-}' specified" >&2; \ exit 1;; \ esac; \ has_opt=no; \ sane_makeflags=$$MAKEFLAGS; \ if $(am__is_gnu_make); then \ sane_makeflags=$$MFLAGS; \ else \ case $$MAKEFLAGS in \ *\\[\ \ ]*) \ bs=\\; \ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ esac; \ fi; \ skip_next=no; \ strip_trailopt () \ { \ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ }; \ for flg in $$sane_makeflags; do \ test $$skip_next = yes && { skip_next=no; continue; }; \ case $$flg in \ *=*|--*) continue;; \ -*I) strip_trailopt 'I'; skip_next=yes;; \ -*I?*) strip_trailopt 'I';; \ -*O) strip_trailopt 'O'; skip_next=yes;; \ -*O?*) strip_trailopt 'O';; \ -*l) strip_trailopt 'l'; skip_next=yes;; \ -*l?*) strip_trailopt 'l';; \ -[dEDm]) skip_next=yes;; \ -[JT]) skip_next=yes;; \ esac; \ case $$flg in \ *$$target_option*) has_opt=yes; break;; \ esac; \ done; \ test $$has_opt = yes am__make_dryrun = (target_option=n; $(am__make_running_with_option)) am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkglibexecdir = $(libexecdir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ target_triplet = @target@ subdir = scripts/ufw ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/m4/ax_c___attribute__.m4 \ $(top_srcdir)/m4/ax_c_pragmas.m4 \ $(top_srcdir)/m4/ax_check_compile_flag.m4 \ $(top_srcdir)/m4/ax_compare_version.m4 \ $(top_srcdir)/m4/ax_realpath.m4 \ $(top_srcdir)/m4/ax_run_or_link_ifelse.m4 \ $(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \ $(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \ $(top_srcdir)/m4/lt~obsolete.m4 \ $(top_srcdir)/m4/nut_arg_with.m4 \ $(top_srcdir)/m4/nut_check_asciidoc.m4 \ $(top_srcdir)/m4/nut_check_aspell.m4 \ $(top_srcdir)/m4/nut_check_cppcheck.m4 \ $(top_srcdir)/m4/nut_check_headers_windows.m4 \ $(top_srcdir)/m4/nut_check_libavahi.m4 \ $(top_srcdir)/m4/nut_check_libfreeipmi.m4 \ $(top_srcdir)/m4/nut_check_libgd.m4 \ $(top_srcdir)/m4/nut_check_libgpiod.m4 \ $(top_srcdir)/m4/nut_check_libltdl.m4 \ $(top_srcdir)/m4/nut_check_libmodbus.m4 \ $(top_srcdir)/m4/nut_check_libneon.m4 \ $(top_srcdir)/m4/nut_check_libnetsnmp.m4 \ $(top_srcdir)/m4/nut_check_libnss.m4 \ $(top_srcdir)/m4/nut_check_libopenssl.m4 \ $(top_srcdir)/m4/nut_check_libpowerman.m4 \ $(top_srcdir)/m4/nut_check_libregex.m4 \ $(top_srcdir)/m4/nut_check_libsystemd.m4 \ $(top_srcdir)/m4/nut_check_libusb.m4 \ $(top_srcdir)/m4/nut_check_libwrap.m4 \ $(top_srcdir)/m4/nut_check_os.m4 \ $(top_srcdir)/m4/nut_check_pkgconfig.m4 \ $(top_srcdir)/m4/nut_check_python.m4 \ $(top_srcdir)/m4/nut_check_socketlib.m4 \ $(top_srcdir)/m4/nut_compiler_family.m4 \ $(top_srcdir)/m4/nut_func_getnameinfo_argtypes.m4 \ $(top_srcdir)/m4/nut_report_feature.m4 \ $(top_srcdir)/m4/nut_stash_warnings.m4 \ $(top_srcdir)/m4/nut_type_socklen_t.m4 \ $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/include/config.h CONFIG_CLEAN_FILES = nut.ufw.profile CONFIG_CLEAN_VPATH_FILES = AM_V_P = $(am__v_P_@AM_V@) am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) am__v_P_0 = false am__v_P_1 = : AM_V_GEN = $(am__v_GEN_@AM_V@) am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) am__v_GEN_0 = @echo " GEN " $@; am__v_GEN_1 = AM_V_at = $(am__v_at_@AM_V@) am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) am__v_at_0 = @ am__v_at_1 = SOURCES = DIST_SOURCES = am__can_run_installinfo = \ case $$AM_UPDATE_INFO_DIR in \ n|no|NO) false;; \ *) (install-info --version) >/dev/null 2>&1;; \ esac am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) am__DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/nut.ufw.profile.in DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) A2X = @A2X@ ACLOCAL = @ACLOCAL@ ALTPIDPATH = @ALTPIDPATH@ AMTAR = @AMTAR@ AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ AR = @AR@ ASCIIDOC = @ASCIIDOC@ ASPELL = @ASPELL@ ASPELL_FILTER_LIB_PATH = @ASPELL_FILTER_LIB_PATH@ ASPELL_FILTER_SHARE_PATH = @ASPELL_FILTER_SHARE_PATH@ ASPELL_FILTER_TEX_PATH = @ASPELL_FILTER_TEX_PATH@ AUGPARSE = @AUGPARSE@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ BINDIR = @BINDIR@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CONFIG_FLAGS = @CONFIG_FLAGS@ CONFPATH = @CONFPATH@ CPP = @CPP@ CPPCHECK = @CPPCHECK@ CPPFLAGS = @CPPFLAGS@ CPPUNIT_CFLAGS = @CPPUNIT_CFLAGS@ CPPUNIT_LIBS = @CPPUNIT_LIBS@ CSCOPE = @CSCOPE@ CTAGS = @CTAGS@ CXX = @CXX@ CXXCPP = @CXXCPP@ CXXDEPMODE = @CXXDEPMODE@ CXXFLAGS = @CXXFLAGS@ CYGPATH_W = @CYGPATH_W@ DBLATEX = @DBLATEX@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ DEPLOYED_UPSC = @DEPLOYED_UPSC@ DEPLOYED_UPSD = @DEPLOYED_UPSD@ DLLTOOL = @DLLTOOL@ DOC_BUILD_LIST = @DOC_BUILD_LIST@ DOC_CHECK_LIST = @DOC_CHECK_LIST@ DRIVER_BUILD_LIST = @DRIVER_BUILD_LIST@ DRIVER_INSTALL_TARGET = @DRIVER_INSTALL_TARGET@ DRIVER_MAN_LIST = @DRIVER_MAN_LIST@ DRIVER_MAN_LIST_PAGES = @DRIVER_MAN_LIST_PAGES@ DRVPATH = @DRVPATH@ DSYMUTIL = @DSYMUTIL@ DUMPBIN = @DUMPBIN@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ ETAGS = @ETAGS@ EXEEXT = @EXEEXT@ FGREP = @FGREP@ FORCE_NUT_VERSION = @FORCE_NUT_VERSION@ GDLIB_CONFIG = @GDLIB_CONFIG@ GREP = @GREP@ HAVE_SYS_SOCKET_H = @HAVE_SYS_SOCKET_H@ HAVE_WINSOCK2_H = @HAVE_WINSOCK2_H@ HAVE_WS2TCPIP_H = @HAVE_WS2TCPIP_H@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ LD = @LD@ LDFLAGS = @LDFLAGS@ LIBAVAHI_CFLAGS = @LIBAVAHI_CFLAGS@ LIBAVAHI_LIBS = @LIBAVAHI_LIBS@ LIBDIR = @LIBDIR@ LIBGD_CFLAGS = @LIBGD_CFLAGS@ LIBGD_LDFLAGS = @LIBGD_LDFLAGS@ LIBGPIO_CFLAGS = @LIBGPIO_CFLAGS@ LIBGPIO_LIBS = @LIBGPIO_LIBS@ LIBI2C_LIBS = @LIBI2C_LIBS@ LIBIPMI_CFLAGS = @LIBIPMI_CFLAGS@ LIBIPMI_LIBS = @LIBIPMI_LIBS@ LIBLTDL_CFLAGS = @LIBLTDL_CFLAGS@ LIBLTDL_LIBS = @LIBLTDL_LIBS@ LIBMODBUS_CFLAGS = @LIBMODBUS_CFLAGS@ LIBMODBUS_LIBS = @LIBMODBUS_LIBS@ LIBNEON_CFLAGS = @LIBNEON_CFLAGS@ LIBNEON_LIBS = @LIBNEON_LIBS@ LIBNETSNMP_CFLAGS = @LIBNETSNMP_CFLAGS@ LIBNETSNMP_LIBS = @LIBNETSNMP_LIBS@ LIBOBJS = @LIBOBJS@ LIBPOWERMAN_CFLAGS = @LIBPOWERMAN_CFLAGS@ LIBPOWERMAN_LIBS = @LIBPOWERMAN_LIBS@ LIBREGEX_LIBS = @LIBREGEX_LIBS@ LIBS = @LIBS@ LIBSSL_CFLAGS = @LIBSSL_CFLAGS@ LIBSSL_LIBS = @LIBSSL_LIBS@ LIBSSL_REQUIRES = @LIBSSL_REQUIRES@ LIBSYSTEMD_CFLAGS = @LIBSYSTEMD_CFLAGS@ LIBSYSTEMD_LIBS = @LIBSYSTEMD_LIBS@ LIBTOOL = @LIBTOOL@ LIBTOOL_DEPS = @LIBTOOL_DEPS@ LIBUSB_CFLAGS = @LIBUSB_CFLAGS@ LIBUSB_CONFIG = @LIBUSB_CONFIG@ LIBUSB_LIBS = @LIBUSB_LIBS@ LIBWRAP_CFLAGS = @LIBWRAP_CFLAGS@ LIBWRAP_LIBS = @LIBWRAP_LIBS@ LIPO = @LIPO@ LN_S = @LN_S@ LN_S_R = @LN_S_R@ LTLIBOBJS = @LTLIBOBJS@ LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@ MAINT = @MAINT@ MAKEINFO = @MAKEINFO@ MANIFEST_TOOL = @MANIFEST_TOOL@ MKDIR_P = @MKDIR_P@ MSGFMT = @MSGFMT@ NETLIBS = @NETLIBS@ NET_SNMP_CONFIG = @NET_SNMP_CONFIG@ NM = @NM@ NMEDIT = @NMEDIT@ NUT_DATADIR = @NUT_DATADIR@ NUT_LIBEXECDIR = @NUT_LIBEXECDIR@ NUT_NETVERSION = @NUT_NETVERSION@ NUT_SOURCE_GITREV = @NUT_SOURCE_GITREV@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ OS_NAME = @OS_NAME@ OTOOL = @OTOOL@ OTOOL64 = @OTOOL64@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_SEPARATOR = @PATH_SEPARATOR@ PIDPATH = @PIDPATH@ PKGCONFIGDIR = @PKGCONFIGDIR@ PKG_CONFIG = @PKG_CONFIG@ PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@ PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ PORT = @PORT@ POWERDOWNFLAG = @POWERDOWNFLAG@ PREFIX = @PREFIX@ PYTHON = @PYTHON@ PYTHON2 = @PYTHON2@ PYTHON2_SITE_PACKAGES = @PYTHON2_SITE_PACKAGES@ PYTHON3 = @PYTHON3@ PYTHON3_SITE_PACKAGES = @PYTHON3_SITE_PACKAGES@ PYTHON_SITE_PACKAGES = @PYTHON_SITE_PACKAGES@ RANLIB = @RANLIB@ REALPATH = @REALPATH@ RUN_AS_GROUP = @RUN_AS_GROUP@ RUN_AS_USER = @RUN_AS_USER@ SBINDIR = @SBINDIR@ SED = @SED@ SEMLIBS = @SEMLIBS@ SERLIBS = @SERLIBS@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ SOURCE_HIGHLIGHT = @SOURCE_HIGHLIGHT@ STATEPATH = @STATEPATH@ STRIP = @STRIP@ SUN_LIBUSB = @SUN_LIBUSB@ SYSTEMD_ANALYZE_PROGRAM = @SYSTEMD_ANALYZE_PROGRAM@ SYSTEMD_DAEMON_ARGS_DRIVER = @SYSTEMD_DAEMON_ARGS_DRIVER@ SYSTEMD_DAEMON_ARGS_UPSD = @SYSTEMD_DAEMON_ARGS_UPSD@ SYSTEMD_DAEMON_ARGS_UPSMON = @SYSTEMD_DAEMON_ARGS_UPSMON@ SYSTEMD_DAEMON_NOTIFYACCESS_DRIVER = @SYSTEMD_DAEMON_NOTIFYACCESS_DRIVER@ SYSTEMD_DAEMON_NOTIFYACCESS_UPSD = @SYSTEMD_DAEMON_NOTIFYACCESS_UPSD@ SYSTEMD_DAEMON_NOTIFYACCESS_UPSMON = @SYSTEMD_DAEMON_NOTIFYACCESS_UPSMON@ SYSTEMD_DAEMON_TYPE_DRIVER = @SYSTEMD_DAEMON_TYPE_DRIVER@ SYSTEMD_DAEMON_TYPE_UPSD = @SYSTEMD_DAEMON_TYPE_UPSD@ SYSTEMD_DAEMON_TYPE_UPSMON = @SYSTEMD_DAEMON_TYPE_UPSMON@ SYSTEMD_DAEMON_WATCHDOG_DRIVER = @SYSTEMD_DAEMON_WATCHDOG_DRIVER@ SYSTEMD_DAEMON_WATCHDOG_UPSD = @SYSTEMD_DAEMON_WATCHDOG_UPSD@ SYSTEMD_DAEMON_WATCHDOG_UPSMON = @SYSTEMD_DAEMON_WATCHDOG_UPSMON@ SYSTEMD_TMPFILES_PROGRAM = @SYSTEMD_TMPFILES_PROGRAM@ TREE_VERSION = @TREE_VERSION@ VALGRIND = @VALGRIND@ VERSION = @VERSION@ WINDMC = @WINDMC@ WINDRES = @WINDRES@ WORDS_BIGENDIAN = @WORDS_BIGENDIAN@ XMLLINT = @XMLLINT@ XSLTPROC = @XSLTPROC@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_AR = @ac_ct_AR@ ac_ct_CC = @ac_ct_CC@ ac_ct_CXX = @ac_ct_CXX@ ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__tar = @am__tar@ am__untar = @am__untar@ auglensdir = @auglensdir@ bindir = @bindir@ build = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ cgiexecdir = @cgiexecdir@ datadir = @datadir@ datarootdir = @datarootdir@ devddir = @devddir@ docdir = @docdir@ driverexecdir = @driverexecdir@ dummy_PKG_CONFIG = @dummy_PKG_CONFIG@ dummy_PKG_CONFIG_CFLAGS = @dummy_PKG_CONFIG_CFLAGS@ dummy_PKG_CONFIG_LIBS = @dummy_PKG_CONFIG_LIBS@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ hotplugdir = @hotplugdir@ htmldir = @htmldir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libdir = @libdir@ libexecdir = @libexecdir@ localedir = @localedir@ localstatedir = @localstatedir@ mandir = @mandir@ mkdir_p = @mkdir_p@ now = @now@ nut_with_nut_monitor = @nut_with_nut_monitor@ nut_with_nut_monitor_desktop = @nut_with_nut_monitor_desktop@ nut_with_nut_monitor_dir = @nut_with_nut_monitor_dir@ nut_with_nut_monitor_py2gtk2 = @nut_with_nut_monitor_py2gtk2@ nut_with_nut_monitor_py3qt5 = @nut_with_nut_monitor_py3qt5@ nut_with_pynut = @nut_with_pynut@ nut_with_pynut_py = @nut_with_pynut_py@ nut_with_pynut_py2 = @nut_with_pynut_py2@ nut_with_pynut_py3 = @nut_with_pynut_py3@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ pkgconfigdir = @pkgconfigdir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ runstatedir = @runstatedir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ sysconfdir = @sysconfdir@ systemdshutdowndir = @systemdshutdowndir@ systemdsystemunitdir = @systemdsystemunitdir@ systemdtmpfilesdir = @systemdtmpfilesdir@ target = @target@ target_alias = @target_alias@ target_cpu = @target_cpu@ target_os = @target_os@ target_vendor = @target_vendor@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ udevdir = @udevdir@ EXTRA_DIST = README.adoc nut.ufw.profile.in MAINTAINERCLEANFILES = Makefile.in .dirstamp CLEANFILES = *-spellchecked README all: all-am .SUFFIXES: $(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu scripts/ufw/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --gnu scripts/ufw/Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): nut.ufw.profile: $(top_builddir)/config.status $(srcdir)/nut.ufw.profile.in cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ mostlyclean-libtool: -rm -f *.lo clean-libtool: -rm -rf .libs _libs tags TAGS: ctags CTAGS: cscope cscopelist: distdir: $(BUILT_SOURCES) $(MAKE) $(AM_MAKEFLAGS) distdir-am distdir-am: $(DISTFILES) @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ dist_files=`for file in $$list; do echo $$file; done | \ sed -e "s|^$$srcdirstrip/||;t" \ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ case $$dist_files in \ */*) $(MKDIR_P) `echo "$$dist_files" | \ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ sort -u` ;; \ esac; \ for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d "$(distdir)/$$file"; then \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ else \ test -f "$(distdir)/$$file" \ || cp -p $$d/$$file "$(distdir)/$$file" \ || exit 1; \ fi; \ done check-am: all-am check: check-am all-am: Makefile installdirs: install: install-am install-exec: install-exec-am install-data: install-data-am uninstall: uninstall-am install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-am install-strip: if test -z '$(STRIP)'; then \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ install; \ else \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ fi mostlyclean-generic: clean-generic: -test -z "$(CLEANFILES)" || rm -f $(CLEANFILES) distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." -test -z "$(MAINTAINERCLEANFILES)" || rm -f $(MAINTAINERCLEANFILES) clean: clean-am clean-am: clean-generic clean-libtool mostlyclean-am distclean: distclean-am -rm -f Makefile distclean-am: clean-am distclean-generic dvi: dvi-am dvi-am: html: html-am html-am: info: info-am info-am: install-data-am: install-dvi: install-dvi-am install-dvi-am: install-exec-am: install-html: install-html-am install-html-am: install-info: install-info-am install-info-am: install-man: install-pdf: install-pdf-am install-pdf-am: install-ps: install-ps-am install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-am -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-am mostlyclean-am: mostlyclean-generic mostlyclean-libtool pdf: pdf-am pdf-am: ps: ps-am ps-am: uninstall-am: .MAKE: install-am install-strip .PHONY: all all-am check check-am clean clean-generic clean-libtool \ cscopelist-am ctags-am distclean distclean-generic \ distclean-libtool distdir dvi dvi-am html html-am info info-am \ install install-am install-data install-data-am install-dvi \ install-dvi-am install-exec install-exec-am install-html \ install-html-am install-info install-info-am install-man \ install-pdf install-pdf-am install-ps install-ps-am \ install-strip installcheck installcheck-am installdirs \ maintainer-clean maintainer-clean-generic mostlyclean \ mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \ tags-am uninstall uninstall-am .PRECIOUS: Makefile # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: nut-2.8.1/scripts/ufw/Makefile.am0000644000175000017500000000017514501607135013602 00000000000000EXTRA_DIST = README.adoc nut.ufw.profile.in MAINTAINERCLEANFILES = Makefile.in .dirstamp CLEANFILES = *-spellchecked README nut-2.8.1/scripts/perl/0000755000175000017500000000000014520277776012003 500000000000000nut-2.8.1/scripts/perl/Nut.pm0000644000175000017500000006420014501607135013012 00000000000000# UPS::Nut - a class to talk to a UPS via the Network Utility Tools upsd. # Original author Kit Peters # Rewritten by Gabor Kiss # Idea to implement TLS:http://www.logix.cz/michal/devel/smtp-cli/smtp-client.pl # ### changelog: made debug messages slightly more descriptive, improved # ### changelog: comments in code # ### changelog: Removed timeleft() function. package UPS::Nut; use strict; use Carp; use FileHandle; use IO::Socket; use IO::Select; use Dumpvalue; my $dumper = Dumpvalue->new; # The following globals dictate whether the accessors and instant-command # functions are created. # ### changelog: tie hash interface and AUTOLOAD contributed by # ### changelog: Wayne Wylupski my $_eol = "\n"; BEGIN { use Exporter (); use vars qw ($VERSION @ISA @EXPORT @EXPORT_OK %EXPORT_TAGS); $VERSION = 1.51; @ISA = qw(Exporter IO::Socket::INET); @EXPORT = qw(); @EXPORT_OK = qw(); %EXPORT_TAGS = (); } sub new { # Author: Kit Peters my $proto = shift; my $class = ref($proto) || $proto; my %arg = @_; # hash of arguments my $self = {}; # _initialize will fill it later bless $self, $class; unless ($self->_initialize(%arg)) { # can't initialize carp "Can't initialize: $self->{err}"; return undef; } return $self; } # accessor functions. Return a value if successful, return undef # otherwise. sub BattPercent { # get battery percentage return shift->GetVar('battery.charge'); } sub LoadPercent { # get load percentage my $self = shift; my $context = shift; $context = "L$context" if $context =~ /^[123]$/; $context = ".$context" if $context; return $self->GetVar("output$context.power.percent"); } sub LineVoltage { # get line voltage my $self = shift; my $context = shift; $context = "L$context-N" if $context =~ /^[123]$/; $context = ".$context" if $context; return $self->GetVar("input$context.voltage"); } sub Status { # get status of UPS return shift->GetVar('ups.status'); } sub Temperature { # get the internal temperature of UPS return shift->GetVar('battery.temperature'); } # control functions: they control our relationship to upsd, and send # commands to upsd. sub Login { # login to upsd, so that it won't shutdown unless we say we're # ok. This should only be used if you're actually connected # to the ups that upsd is monitoring. # Author: Kit Peters # ### changelog: modified login logic a bit. Now it doesn't check to see # ### changelog: if we got OK, ERR, or something else from upsd. It # ### changelog: simply checks for a response beginning with OK from upsd. # ### changelog: Anything else is an error. # # ### changelog: uses the new _send command # my $self = shift; # myself my $user = shift; # username my $pass = shift; # password my $errmsg; # error message, sent to _debug and $self->{err} my $ans; # scalar to hold responses from upsd $self->Authenticate($user, $pass) or return; $ans = $self->_send( "LOGIN $self->{name}" ); if (defined $ans && $ans =~ /^OK/) { # Login successful. $self->_debug("LOGIN successful."); return 1; } if (defined $ans) { $errmsg = "LOGIN failed. Last message from upsd: $ans"; } else { $errmsg = "Network error: $!"; } $self->_debug($self->{err} = $errmsg); return undef; } sub Authenticate { # Announce to the UPS who we are to set up the proper # management level. See upsd.conf man page for details. # Contributor: Wayne Wylupski my $self = shift; # myself my $user = shift; # username my $pass = shift; # password my $errmsg; # error message, sent to _debug and $self->{err} my $ans; # scalar to hold responses from upsd # only attempt authentication if username and password given if (defined $user and defined $pass) { $ans = $self->_send("USERNAME $user"); if (defined $ans && $ans =~ /^OK/) { # username OK, send password $ans = $self->_send("PASSWORD $pass"); return 1 if (defined $ans && $ans =~ /^OK/); } } if (defined $ans) { $errmsg = "Authentication failed. Last message from upsd: $ans"; } else { $errmsg = "Network error: $!"; } $self->_debug($self->{err} = $errmsg); return undef; } sub Logout { # logout of upsd # Author: Kit Peters # ### changelog: uses the new _send command # my $self = shift; if ($self->{srvsock}) { # are we still connected to upsd? my $ans = $self->_send( "LOGOUT" ); close ($self->{srvsock}); delete ($self->{srvsock}); } } # internal functions. These are only used by UPS::Nut internally, so # please don't use them otherwise. If you really think an internal # function should be externalized, let me know. sub _initialize { # Author: Kit Peters my $self = shift; my %arg = @_; my $host = $arg{HOST} || 'localhost'; # Host running upsd and probably drivers my $port = $arg{PORT} || '3493'; # 3493 is IANA assigned port for NUT my $proto = $arg{PROTO} || 'tcp'; # use tcp unless user tells us to my $user = $arg{USERNAME} || undef; # username passed to upsd my $pass = $arg{PASSWORD} || undef; # password passed to upsd my $login = $arg{LOGIN} || 0; # login to upsd on init? $self->{name} = $arg{NAME} || 'default'; # UPS name in etc/ups.conf on $host $self->{timeout} = $arg{TIMEOUT} || 30; # timeout $self->{debug} = $arg{DEBUG} || 0; # debugging? $self->{debugout} = $arg{DEBUGOUT} || undef; # where to send debug messages my $srvsock = $self->{srvsock} = # establish connection to upsd IO::Socket::INET->new( PeerAddr => $host, PeerPort => $port, Proto => $proto ); unless ( defined $srvsock) { # can't connect $self->{err} = "Unable to connect via $proto to $host:$port: $!"; return undef; } $self->{select} = IO::Select->new( $srvsock ); if ($user and $pass) { # attempt login to upsd if that option is specified if ($login) { # attempt login to upsd if that option is specified $self->Login($user, $pass) or carp $self->{err}; } else { $self->Authenticate($user, $pass) or carp $self->{err}; } } # get a hash of vars for both the TIE functions as well as for # expanding vars. $self->{vars} = $self->ListVar; unless ( defined $self->{vars} ) { $self->{err} = "Network error: $!"; return undef; } return $self; } # # _send # # Sends a command to the server and retrieves the results. # If there was a network error, return undef; $! will contain the # error. sub _send { # Contributor: Wayne Wylupski my $self = shift; my $cmd = shift; my @handles; my $result; # undef by default my $socket = $self->{srvsock}; my $select = $self->{select}; @handles = IO::Select->select( undef, $select, $select, $self->{timeout} ); return undef if ( !scalar $handles[1] ); $socket->print( $cmd . $_eol ); @handles = IO::Select->select( $select, undef, $select, $self->{timeout} ); return undef if ( !scalar $handles[0]); $result = $socket->getline; return undef if ( !defined ( $result ) ); chomp $result; return $result; } sub _getline { # Contributor: Wayne Wylupski my $self = shift; my $result; # undef by default my $socket = $self->{srvsock}; my $select = $self->{select}; # Different versions of IO::Socket has different error detection routines. return undef if ( $IO::Socket::{has_error} && $select->has_error(0) ); return undef if ( $IO::Socket::{has_exception} && $select->has_exception(0) ); chomp ( $result = $socket->getline ); return $result; } # Compatibility layer sub Request { goto &GetVar; } sub GetVar { # request a variable from the UPS # Author: Kit Peters my $self = shift; # ### changelog: 8/3/2002 - KP - Request() now returns undef if not # ### changelog: connected to upsd via $srvsock # ### changelog: uses the new _send command # # Modified by Gabor Kiss according to protocol version 1.5+ my $var = shift; my $req = "GET VAR $self->{name} $var"; # build request my $ans = $self->_send( $req ); unless (defined $ans) { $self->{err} = "Network error: $!"; return undef; }; if ($ans =~ /^ERR/) { $self->{err} = "Error: $ans. Requested $var."; return undef; } elsif ($ans =~ /^VAR/) { my $checkvar; # to make sure the var we asked for is the var we got. my $retval; # returned value for requested VAR (undef, undef, $checkvar, $retval) = split(' ', $ans, 4); # get checkvar and retval from the answer if ($checkvar ne $var) { # did not get expected var $self->{err} = "requested $var, received $checkvar"; return undef; } $retval =~ s/^"(.*)"$/$1/; return $retval; # return the requested value } else { # unrecognized response $self->{err} = "Unrecognized response from upsd: $ans"; return undef; } } sub Set { # Contributor: Wayne Wylupski # ### changelog: uses the new _send command # my $self = shift; my $var = shift; (my $value = shift) =~ s/^"?(.*)"?$/"$1"/; # add quotes if missing my $req = "SET VAR $self->{name} $var $value"; # build request my $ans = $self->_send( $req ); unless (defined $ans) { $self->{err} = "Network error: $!"; return undef; }; if ($ans =~ /^ERR/) { $self->{err} = "Error: $ans"; return undef; } elsif ($ans =~ /^OK/) { return $value; } else { # unrecognized response $self->{err} = "Unrecognized response from upsd: $ans"; return undef; } } sub FSD { # set forced shutdown flag # Author: Kit Peters # ### changelog: uses the new _send command # my $self = shift; my $req = "FSD $self->{name}"; # build request my $ans = $self->_send( $req ); unless (defined $ans) { $self->{err} = "Network error: $!"; return undef; }; if ($ans =~ /^ERR/) { # can't set forced shutdown flag $self->{err} = "Can't set FSD flag. Upsd reports: $ans"; return undef; } elsif ($ans =~ /^OK FSD-SET/) { # forced shutdown flag set $self->_debug("FSD flag set successfully."); return 1; } else { $self->{err} = "Unrecognized response from upsd: $ans"; return undef; } } sub InstCmd { # send instant command to ups # Contributor: Wayne Wylupski my $self = shift; chomp (my $cmd = shift); my $req = "INSTCMD $self->{name} $cmd"; my $ans = $self->_send( $req ); unless (defined $ans) { $self->{err} = "Network error: $!"; return undef; }; if ($ans =~ /^ERR/) { # error reported from upsd $self->{err} = "Can't send instant command $cmd. Reason: $ans"; return undef; } elsif ($ans =~ /^OK/) { # command successful $self->_debug("Instant command $cmd sent successfully."); return 1; } else { # unrecognized response $self->{err} = "Can't send instant command $cmd. Unrecognized response from upsd: $ans"; return undef; } } sub ListUPS { my $self = shift; return $self->_get_list("LIST UPS", 2, 1); } sub ListVar { my $self = shift; my $vars = $self->_get_list("LIST VAR $self->{name}", 3, 2); return $vars unless @_; # return all variables return {map { $_ => $vars->{$_} } @_}; # return selected ones } sub ListRW { my $self = shift; return $self->_get_list("LIST RW $self->{name}", 3, 2); } sub ListCmd { my $self = shift; return $self->_get_list("LIST CMD $self->{name}", 2); } sub ListEnum { my $self = shift; my $var = shift; return $self->_get_list("LIST ENUM $self->{name} $var", 3); } sub _get_list { my $self = shift; my ($req, $valueidx, $keyidx) = @_; my $ans = $self->_send($req); unless (defined $ans) { $self->{err} = "Network error: $!"; return undef; }; if ($ans =~ /^ERR/) { $self->{err} = "Error: $ans"; return undef; } elsif ($ans =~ /^BEGIN LIST/) { # command successful my $retval = $keyidx ? {} : []; my $line; while ($line = $self->_getline) { last if $line =~ /^END LIST/; my @fields = split(' ', $line, $valueidx+1); (my $value = $fields[$valueidx]) =~ s/^"(.*)"$/$1/; if ($keyidx) { $retval->{$fields[$keyidx]} = $value; } else { push(@$retval, $value); } } unless ($line) { $self->{err} = "Network error: $!"; return undef; }; $self->_debug("$req command sent successfully."); return $retval; } else { # unrecognized response $self->{err} = "Can't send $req. Unrecognized response from upsd: $ans"; return undef; } } # Compatibility layer sub VarDesc { goto &GetDesc; } sub GetDesc { # Contributor: Wayne Wylupski # Modified by Gabor Kiss according to protocol version 1.5+ my $self = shift; my $var = shift; my $req = "GET DESC $self->{name} $var"; my $ans = $self->_send( $req ); unless (defined $ans) { $self->{err} = "Network error: $!"; return undef; }; if ($ans =~ /^ERR/) { $self->{err} = "Error: $ans"; return undef; } elsif ($ans =~ /^DESC/) { # command successful $self->_debug("$req command sent successfully."); (undef, undef, undef, $ans) = split(' ', $ans, 4); $ans =~ s/^"(.*)"$/$1/; return $ans; } else { # unrecognized response $self->{err} = "Can't send $req. Unrecognized response from upsd: $ans"; return undef; } } # Compatibility layer sub VarType { goto &GetType; } sub GetType { # Contributor: Wayne Wylupski # Modified by Gabor Kiss according to protocol version 1.5+ my $self = shift; my $var = shift; my $req = "GET TYPE $self->{name} $var"; my $ans = $self->_send( $req ); unless (defined $ans) { $self->{err} = "Network error: $!"; return undef; }; if ($ans =~ /^ERR/) { $self->{err} = "Error: $ans"; return undef; } elsif ($ans =~ /^TYPE/) { # command successful $self->_debug("$req command sent successfully."); (undef, undef, undef, $ans) = split(' ', $ans, 4); return $ans; } else { # unrecognized response $self->{err} = "Can't send $req. Unrecognized response from upsd: $ans"; return undef; } } # Compatibility layer sub InstCmdDesc { goto &GetCmdDesc; } sub GetCmdDesc { # Contributor: Wayne Wylupski # Modified by Gabor Kiss according to protocol version 1.5+ my $self = shift; my $cmd = shift; my $req = "GET CMDDESC $self->{name} $cmd"; my $ans = $self->_send( $req ); unless (defined $ans) { $self->{err} = "Network error: $!"; return undef; }; if ($ans =~ /^ERR/) { $self->{err} = "Error: $ans"; return undef; } elsif ($ans =~ /^DESC/) { # command successful $self->_debug("$req command sent successfully."); (undef, undef, undef, $ans) = split(' ', $ans, 4); $ans =~ s/^"(.*)"$/$1/; return $ans; } else { # unrecognized response $self->{err} = "Can't send $req. Unrecognized response from upsd: $ans"; return undef; } } sub DESTROY { # destructor, all it does is call Logout # Author: Kit Peters my $self = shift; $self->_debug("Object destroyed."); $self->Logout(); } sub _debug { # print debug messages to stdout or file # Author: Kit Peters my $self = shift; if ($self->{debug}) { chomp (my $msg = shift); my $out; # filehandle for output if ($self->{debugout}) { # if filename is given, use that $out = new FileHandle ($self->{debugout}, ">>") or warn "Error: $!"; } if ($out) { # if out was set to a filehandle, create nifty timestamp my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(); $year = sprintf("%02d", $year % 100); # Y2.1K compliant, even! my $timestamp = join '/', ($mon + 1), $mday, $year; # today $timestamp .= " "; $timestamp .= join ':', $hour, $min, $sec; print $out "$timestamp $msg\n"; } else { print "DEBUG: $msg\n"; } # otherwise, print to stdout } } sub Error { # what was the last thing that went bang? # Author: Kit Peters my $self = shift; if ($self->{err}) { return $self->{err}; } else { return "No error explanation available."; } } sub Master { # check for MASTER level access # Author: Kit Peters # ### changelog: uses the new _send command # # TODO: API change pending to replace MASTER with PRIMARY # (and backwards-compatible alias handling) my $self = shift; my $req = "MASTER $self->{name}"; # build request my $ans = $self->_send( $req ); unless (defined $ans) { $self->{err} = "Network error: $!"; return undef; }; if ($ans =~ /^OK/) { # access granted $self->_debug("MASTER level access granted. Upsd reports: $ans"); return 1; } else { # access denied, or unrecognized reponse $self->{err} = "MASTER level access denied. Upsd responded: $ans"; # ### changelog: 8/3/2002 - KP - Master() returns undef rather than 0 on # ### failure. this makes it consistent with other methods return undef; } } sub AUTOLOAD { # Contributor: Wayne Wylupski my $self = shift; my $name = $UPS::Nut::AUTOLOAD; $name =~ s/^.*:://; # for a change we will only load cmds if needed. if (!defined $self->{cmds} ) { %{$self->{cmds}} = map{ $_ =>1 } @{$self->ListCmd}; } croak "No such InstCmd: $name" if (! $self->{cmds}{$name} ); return $self->InstCmd( $name ); } #------------------------------------------------------------------------- # tie hash interface # # The variables of the array, including the hidden 'numlogins' can # be accessed as a hash array through this method. # # Example: # tie %ups, 'UPS::Nut', # NAME => "myups", # HOST => "somemachine.somewhere.com", # ... # same options as new(); # ; # # $ups{UPSIDENT} = "MyUPS"; # print $ups{MFR}, " " $ups{MODEL}, "\n"; # #------------------------------------------------------------------------- sub TIEHASH { my $class = shift || 'UPS::Nut'; return $class->new( @_ ); } sub FETCH { my $self = shift; my $key = shift; return $self->Request( $key ); } sub STORE { my $self = shift; my $key = shift; my $value = shift; return $self->Set( $key, $value ); } sub DELETE { croak "DELETE operation not supported"; } sub CLEAR { croak "CLEAR operation not supported"; } sub EXISTS { exists shift->{vars}{shift}; } sub FIRSTKEY { my $self = shift; my $a = keys %{$self->{vars}}; return scalar each %{$self->{vars}}; } sub NEXTKEY { my $self = shift; return scalar each %{$self->{vars}}; } sub UNTIE { $_[0]->Logout; } =head1 NAME Nut - a module to talk to a UPS via NUT (Network UPS Tools) upsd =head1 SYNOPSIS use UPS::Nut; $ups = new UPS::Nut( NAME => "myups", HOST => "somemachine.somewhere.com", PORT => "3493", USERNAME => "upsuser", PASSWORD => "upspasswd", TIMEOUT => 30, DEBUG => 1, DEBUGOUT => "/some/file/somewhere", ); if ($ups->Status() =~ /OB/) { print "Oh, no! Power failure!\n"; } tie %other_ups, 'UPS::Nut', NAME => "myups", HOST => "somemachine.somewhere.com", ... # same options as new(); ; print $other_ups{MFR}, " ", $other_ups{MODEL}, "\n"; =head1 DESCRIPTION This is an object-oriented (whoo!) interface between Perl and upsd from the Network UPS Tools package version 1.5 and above (https://www.networkupstools.org/). Note that it only talks to upsd for you in a Perl-ish way. It doesn't monitor the UPS continously. =head1 CONSTRUCTOR Shown with defaults: new UPS::Nut( NAME => "default", HOST => "localhost", PORT => "3493", USERNAME => "", PASSWORD => "", DEBUG => 0, DEBUGOUT => "", ); * NAME is the name of the UPS to monitor, as specified in ups.conf * HOST is the host running upsd * PORT is the port that upsd is running on * USERNAME and PASSWORD are those that you use to login to upsd. This gives you the right to do certain things, as specified in upsd.conf. * DEBUG turns on debugging output, set to 1 or 0 * DEBUGOUT is de thing you do when de s*** hits the fan. Actually, it's the filename where you want debugging output to go. If it's not specified, debugging output comes to standard output. =head1 Important notice This version of UPS::Nut is not compatible with version 0.04. It is totally rewritten in order to talk the new protocol of NUT 1.5+. You should not use this module as a drop-in replacement of previous version from 2002. Allmost all method has changed slightly. =head1 Methods Unlike in version 0.04 no methods return list values but a single reference or undef. =head2 Methods for querying UPS status =over 4 =item Getvar($varname) returns value of the specified variable. Returns undef if variable unsupported. Old method named Request() is also supported for compatibility. =item Set($varname, $value) sets the value of the specified variable. Returns undef if variable unsupported, or if variable cannot be set for some other reason. See Authenticate() if you wish to use this function. =item BattPercent() returns percentage of battery left. Returns undef if we can't get battery percentage for some reason. Same as GetVar('battery.charge'). =item LoadPercent($context) returns percentage of the load on the UPS. Returns undef if load percentage is unavailable. $context is a selector of 3 phase systems. Possibled values are 1, 2, 3, 'L1', 'L2', 'L3'. It should be omitted in case of single phase UPS. =item LineVoltage($context) returns input line (e.g. the outlet) voltage. Returns undef if line voltage is unavailable. $context is a selector of 3 phase systems. Possibled values are 1, 2, 3, 'L1', 'L2', 'L3'. It should be omitted in case of single phase UPS. =item Status() returns UPS status, one of OL or OB. OL or OB may be followed by LB, which signifies low battery state. OL or OB may also be followed by FSD, which denotes that the forced shutdown state ( see UPS::Nut->FSD() ) has been set on upsd. Returns undef if status unavailable. Same as GetVar('ups.status'). =item Temperature() returns UPS internal temperature. Returns undef if internal temperature unavailable. Same as GetVar('battery.temperature'). =back =head2 Other methods These all operate on the UPS specified in the NAME argument to the constructor. =over 4 =item Authenticate($username, $password) With NUT certain operations are only available if the user has the privilege. The program has to authenticate with one of the accounts defined in upsd.conf. =item Login($username, $password) Notify upsd that client is drawing power from the given UPS. It is automatically done if new() is called with USERNAME, PASSWORD and LOGIN parameters. =item Logout() Notify upsd that client is released UPS. (E.g. it is shutting down.) It is automatically done if connection closed. =item Master() Use this to find out whether or not we have MASTER privileges for this UPS. Returns 1 if we have MASTER privileges, returns 0 otherwise. TODO: API change pending to replace MASTER with PRIMARY (and backwards-compatible alias handling) =item ListVar($variable, ...) This is an implementation of "LIST VAR" command. Returns a hash reference to selected variable names and values supported by the UPS. If no variables given it returns all. Returns undef if "LIST VAR" failed. (Note: This method significally differs from the old ListVars() and ListRequest().) =item ListRW() Similar to ListVar() but cares only with read/writeable variables. =item ListEnum($variable) Returns a reference to the list of all possible values of $variable. List is empty if $variable is not an ENUM type. (See GetType().) Returns undef if error occurred. =item ListCmd() Returns a reference to the list of all instant commands supported by the UPS. Returns undef if these are unavailable. This method replaces the old ListInstCmds(). =item InstCmd($command) Send an instant command to the UPS. Returns 1 on success. Returns undef if the command can't be completed. =item FSD() Set the FSD (forced shutdown) flag for the UPS. This means that we're planning on shutting down the UPS very soon, so the attached load should be shut down as well. Returns 1 on success, returns undef on failure. This cannot be unset, so don't set it unless you mean it. =item Error() why did the previous operation fail? The answer is here. It will return a concise, well-written, and brilliantly insightful few words as to why whatever you just did went bang. =item GetDesc($variable) Returns textual description of $variable or undef in case of error. Old method named VarDesc() is also supported for compatibility. =item GetCmdDesc($command) This is like GetDesc() above but applies to the instant commands. Old method named InstCmdDesc() is also supported for compatibility. =item GetType($variable) Returns a string UNKNOWN or constructed one or more words of RW, ENUM and STRING:n (where n is a number). (Seems to be not working perfectly at upsd 2.2.) Old method named VarType() is also supported for compatibility. =item ListUPS() Returns a reference to hash of all available UPS names and descriptions. =back =head1 AUTOLOAD The "instant commands" are available as methods of the UPS object. They are AUTOLOADed when called. For example, if the instant command is FPTEST, then it can be called by $ups->FPTEST. =head1 TIE Interface If you wish to simply query or set values, you can tie a hash value to UPS::Nut and pass as extra options what you need to connect to the host. If you need to exercise an occasional command, you may find the return value of 'tie' useful, as in: my %ups; my $ups_obj = tie %ups, 'UPS::Nut', HOSTNAME=>"firewall"; print $ups{UPSIDENT}, "\n"; $ups_obj->Authenticate( "user", "pass" ); $ups{UPSIDENT} = "MyUPS"; =head1 AUTHOR Original version made by Kit Peters perl@clownswilleatyou.com http://www.awod.com/staff/kpeters/perl/ Rewritten by Gabor Kiss . =head1 CREDITS Developed with the kind support of A World Of Difference, Inc. Many thanks to Ryan Jessen at CyberPower Systems for much-needed assistance. Thanks to Wayne Wylupski for the code to make accessor methods for all supported vars. =head1 LICENSE This module is distributed under the same license as Perl itself. =cut 1; __END__ nut-2.8.1/scripts/python/0000755000175000017500000000000014520277777012363 500000000000000nut-2.8.1/scripts/python/module/0000755000175000017500000000000014520277777013650 500000000000000nut-2.8.1/scripts/python/module/PyNUT.py.in0000644000175000017500000004423114501607135015512 00000000000000#!@PYTHON@ # -*- coding: utf-8 -*- # Copyright (C) 2008 David Goncalves # # 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 . # 2008-01-14 David Goncalves # PyNUT is an abstraction class to access NUT (Network UPS Tools) server. # # 2008-06-09 David Goncalves # Added 'GetRWVars' and 'SetRWVar' commands. # # 2009-02-19 David Goncalves # Changed class PyNUT to PyNUTClient # # 2010-07-23 David Goncalves - Version 1.2 # Changed GetRWVars function that fails is the UPS is not # providing such vars. # # 2011-07-05 René Martín Rodríguez - Version 1.2.1 # Added support for FSD, HELP and VER commands # # 2012-02-07 René Martín Rodríguez - Version 1.2.2 # Added support for LIST CLIENTS command # # 2014-06-03 george2 - Version 1.3.0 # Added custom exception class, fixed minor bug, added Python 3 support. # # 2021-09-27 Jim Klimov - Version 1.4.0 # Revise strings used to be byte sequences as required by telnetlib # in Python 3.9, by spelling out b"STR" or str.encode('ascii'); # the change was also tested to work with Python 2.7, 3.4, 3.5 and # 3.7 (to the extent of accompanying test_nutclient.py at least). # # 2022-08-12 Jim Klimov - Version 1.5.0 # Fix ListClients() method to actually work with current NUT protocol # Added DeviceLogin() method # Added GetUPSNames() method # Fixed raised PyNUTError() exceptions to carry a Python string # (suitable for Python2 and Python3), not byte array from protocol, # so exception catchers can process them naturally (see test script). # # 2023-01-18 Jim Klimov - Version 1.6.0 # Added CheckUPSAvailable() method originally by Michal Hlavinka # from 2013-01-07 RedHat/Fedora packaging import telnetlib class PyNUTError( Exception ) : """ Base class for custom exceptions """ class PyNUTClient : """ Abstraction class to access NUT (Network UPS Tools) server """ __debug = None # Set class to debug mode (prints everything useful for debuging...) __host = None __port = None __login = None __password = None __timeout = None __srv_handler = None __version = "1.6.0" __release = "2023-01-18" def __init__( self, host="127.0.0.1", port=3493, login=None, password=None, debug=False, timeout=5 ) : """ Class initialization method host : Host to connect (default to localhost) port : Port where NUT listens for connections (default to 3493) login : Login used to connect to NUT server (default to None for no authentication) password : Password used when using authentication (default to None) debug : Boolean, put class in debug mode (prints everything on console, default to False) timeout : Timeout used to wait for network response """ self.__debug = debug if self.__debug : print( "[DEBUG] Class initialization..." ) print( "[DEBUG] -> Host = %s (port %s)" % ( host, port ) ) print( "[DEBUG] -> Login = '%s' / '%s'" % ( login, password ) ) self.__host = host self.__port = port self.__login = login self.__password = password self.__timeout = 5 self.__connect() # Try to disconnect cleanly when class is deleted ;) def __del__( self ) : """ Class destructor method """ try : self.__srv_handler.write( b"LOGOUT\n" ) except : pass def __connect( self ) : """ Connects to the defined server If login/pass was specified, the class tries to authenticate. An error is raised if something goes wrong. """ if self.__debug : print( "[DEBUG] Connecting to host" ) self.__srv_handler = telnetlib.Telnet( self.__host, self.__port ) if self.__login != None : self.__srv_handler.write( ("USERNAME %s\n" % self.__login).encode('ascii') ) result = self.__srv_handler.read_until( b"\n", self.__timeout ) if result[:2] != b"OK" : raise PyNUTError( result.replace( b"\n", b"" ).decode('ascii') ) if self.__password != None : self.__srv_handler.write( ("PASSWORD %s\n" % self.__password).encode('ascii') ) result = self.__srv_handler.read_until( b"\n", self.__timeout ) if result[:2] != b"OK" : if result == b"ERR INVALID-ARGUMENT\n" : # Quote the password (if it has whitespace etc) # TODO: Escape special chard like NUT does? self.__srv_handler.write( ("PASSWORD \"%s\"\n" % self.__password).encode('ascii') ) result = self.__srv_handler.read_until( b"\n", self.__timeout ) if result[:2] != b"OK" : raise PyNUTError( result.replace( b"\n", b"" ).decode('ascii') ) else: raise PyNUTError( result.replace( b"\n", b"" ).decode('ascii') ) def GetUPSList( self ) : """ Returns the list of available UPS from the NUT server The result is a dictionary containing 'key->val' pairs of 'UPSName' and 'UPS Description' Note that fields here are byte sequences (not locale-aware strings) which is of little concern for Python2 but is important in Python3 (e.g. when we use "str" type `ups` variables or check their "validity"). """ if self.__debug : print( "[DEBUG] GetUPSList from server" ) self.__srv_handler.write( b"LIST UPS\n" ) result = self.__srv_handler.read_until( b"\n" ) if result != b"BEGIN LIST UPS\n" : raise PyNUTError( result.replace( b"\n", b"" ).decode('ascii') ) result = self.__srv_handler.read_until( b"END LIST UPS\n" ) ups_list = {} for line in result.split( b"\n" ) : if line[:3] == b"UPS" : ups, desc = line[4:-1].split( b'"' ) ups_list[ ups.replace( b" ", b"" ) ] = desc return( ups_list ) def GetUPSNames( self ) : """ Returns the list of available UPS names from the NUT server as strings The result is a set of str objects (comparable with ups="somename" and useful as arguments to other methods). Helps work around Python2/Python3 string API changes. """ if self.__debug : print( "[DEBUG] GetUPSNames from server" ) self_ups_list = [] for b in self.GetUPSList(): self_ups_list.append(b.decode('ascii')) return self_ups_list def GetUPSVars( self, ups="" ) : """ Get all available vars from the specified UPS The result is a dictionary containing 'key->val' pairs of all available vars. """ if self.__debug : print( "[DEBUG] GetUPSVars called..." ) self.__srv_handler.write( ("LIST VAR %s\n" % ups).encode('ascii') ) result = self.__srv_handler.read_until( b"\n" ) if result != ("BEGIN LIST VAR %s\n" % ups).encode('ascii') : raise PyNUTError( result.replace( b"\n", b"" ).decode('ascii') ) ups_vars = {} result = self.__srv_handler.read_until( ("END LIST VAR %s\n" % ups).encode('ascii') ) offset = len( ("VAR %s " % ups ).encode('ascii') ) end_offset = 0 - ( len( ("END LIST VAR %s\n" % ups).encode('ascii') ) + 1 ) for current in result[:end_offset].split( b"\n" ) : var = current[ offset: ].split( b'"' )[0].replace( b" ", b"" ) data = current[ offset: ].split( b'"' )[1] ups_vars[ var ] = data return( ups_vars ) def CheckUPSAvailable( self, ups="" ) : """ Check whether UPS is reachable Just tries to contact UPS with a safe command. The result is True (reachable) or False (unreachable) """ if self.__debug : print( "[DEBUG] CheckUPSAvailable called..." ) self.__srv_handler.write( ("LIST CMD %s\n" % ups).encode('ascii') ) result = self.__srv_handler.read_until( b"\n" ) if result != ("BEGIN LIST CMD %s\n" % ups).encode('ascii') : return False self.__srv_handler.read_until( ("END LIST CMD %s\n" % ups).encode('ascii') ) return True def GetUPSCommands( self, ups="" ) : """ Get all available commands for the specified UPS The result is a dict object with command name as key and a description of the command as value """ if self.__debug : print( "[DEBUG] GetUPSCommands called..." ) self.__srv_handler.write( ("LIST CMD %s\n" % ups).encode('ascii') ) result = self.__srv_handler.read_until( b"\n" ) if result != ("BEGIN LIST CMD %s\n" % ups).encode('ascii') : raise PyNUTError( result.replace( b"\n", b"" ).decode('ascii') ) ups_cmds = {} result = self.__srv_handler.read_until( ("END LIST CMD %s\n" % ups).encode('ascii') ) offset = len( ("CMD %s " % ups).encode('ascii') ) end_offset = 0 - ( len( ("END LIST CMD %s\n" % ups).encode('ascii') ) + 1 ) for current in result[:end_offset].split( b"\n" ) : var = current[ offset: ].split( b'"' )[0].replace( b" ", b"" ) # For each var we try to get the available description try : self.__srv_handler.write( ("GET CMDDESC %s %s\n" % ( ups, var )).encode('ascii') ) temp = self.__srv_handler.read_until( b"\n" ) if temp[:7] != b"CMDDESC" : raise PyNUTError else : off = len( ("CMDDESC %s %s " % ( ups, var )).encode('ascii') ) desc = temp[off:-1].split(b'"')[1] except : desc = var ups_cmds[ var ] = desc return( ups_cmds ) def GetRWVars( self, ups="" ) : """ Get a list of all writable vars from the selected UPS The result is presented as a dictionary containing 'key->val' pairs """ if self.__debug : print( "[DEBUG] GetUPSVars from '%s'..." % ups ) self.__srv_handler.write( ("LIST RW %s\n" % ups).encode('ascii') ) result = self.__srv_handler.read_until( b"\n" ) if ( result != ("BEGIN LIST RW %s\n" % ups).encode('ascii') ) : raise PyNUTError( result.replace( b"\n", b"" ).decode('ascii') ) result = self.__srv_handler.read_until( ("END LIST RW %s\n" % ups).encode('ascii') ) offset = len( ("VAR %s" % ups).encode('ascii') ) end_offset = 0 - ( len( ("END LIST RW %s\n" % ups).encode('ascii') ) + 1 ) rw_vars = {} try : for current in result[:end_offset].split( b"\n" ) : var = current[ offset: ].split( b'"' )[0].replace( b" ", b"" ) data = current[ offset: ].split( b'"' )[1] rw_vars[ var ] = data except : pass return( rw_vars ) def SetRWVar( self, ups="", var="", value="" ): """ Set a variable to the specified value on selected UPS The variable must be a writable value (cf GetRWVars) and you must have the proper rights to set it (maybe login/password). """ self.__srv_handler.write( ("SET VAR %s %s %s\n" % ( ups, var, value )).encode('ascii') ) result = self.__srv_handler.read_until( b"\n" ) if ( result == b"OK\n" ) : return( "OK" ) else : raise PyNUTError( result.replace( b"\n", b"" ).decode('ascii') ) def RunUPSCommand( self, ups="", command="" ) : """ Send a command to the specified UPS Returns OK on success or raises an error """ if self.__debug : print( "[DEBUG] RunUPSCommand called..." ) self.__srv_handler.write( ("INSTCMD %s %s\n" % ( ups, command )).encode('ascii') ) result = self.__srv_handler.read_until( b"\n" ) if ( result == b"OK\n" ) : return( "OK" ) else : raise PyNUTError( result.replace( b"\n", b"" ).decode('ascii') ) def DeviceLogin( self, ups="") : """ Establish a login session with a device (like upsmon does) Returns OK on success or raises an error USERNAME and PASSWORD must have been specified earlier in the session (once) and upsd.conf should permit that user with one of `upsmon` role types. Note there is no "device LOGOUT" in the protocol, just one for general end of connection. """ if self.__debug : print( "[DEBUG] DeviceLogin called..." ) if ups is None or (ups not in self.GetUPSNames()): if self.__debug : print( "[DEBUG] DeviceLogin: %s is not a valid UPS" % ups ) raise PyNUTError( "ERR UNKNOWN-UPS" ) self.__srv_handler.write( ("LOGIN %s\n" % ups).encode('ascii') ) result = self.__srv_handler.read_until( b"\n" ) if ( result.startswith( ("User %s@" % self.__login).encode('ascii')) and result.endswith (("[%s]\n" % ups).encode('ascii')) ): # User dummy-user@127.0.0.1 logged into UPS [dummy] # Read next line then result = self.__srv_handler.read_until( b"\n" ) if ( result == b"OK\n" ) : return( "OK" ) else : raise PyNUTError( result.replace( b"\n", b"" ).decode('ascii') ) def FSD( self, ups="") : """ Send FSD command Returns OK on success or raises an error NOTE: API changed since NUT 2.8.0 to replace MASTER with PRIMARY (and backwards-compatible alias handling) """ if self.__debug : print( "[DEBUG] PRIMARY called..." ) self.__srv_handler.write( ("PRIMARY %s\n" % ups).encode('ascii') ) result = self.__srv_handler.read_until( b"\n" ) if ( result != b"OK PRIMARY-GRANTED\n" ) : if self.__debug : print( "[DEBUG] Retrying: MASTER called..." ) self.__srv_handler.write( ("MASTER %s\n" % ups).encode('ascii') ) result = self.__srv_handler.read_until( b"\n" ) if ( result != b"OK MASTER-GRANTED\n" ) : if self.__debug : print( "[DEBUG] Primary level functions are not available" ) raise PyNUTError( "ERR ACCESS-DENIED" ) if self.__debug : print( "[DEBUG] FSD called..." ) self.__srv_handler.write( ("FSD %s\n" % ups).encode('ascii') ) result = self.__srv_handler.read_until( b"\n" ) if ( result == b"OK FSD-SET\n" ) : return( "OK" ) else : raise PyNUTError( result.replace( b"\n", b"" ).decode('ascii') ) def help(self) : """ Send HELP command """ if self.__debug : print( "[DEBUG] HELP called..." ) self.__srv_handler.write( b"HELP\n" ) return self.__srv_handler.read_until( b"\n" ) def ver(self) : """ Send VER command """ if self.__debug : print( "[DEBUG] VER called..." ) self.__srv_handler.write( b"VER\n" ) return self.__srv_handler.read_until( b"\n" ) def ListClients( self, ups = None ) : """ Returns the list of connected clients from the NUT server The result is a dictionary containing 'key->val' pairs of 'UPSName' and a list of clients """ if self.__debug : print( "[DEBUG] ListClients from server: %s" % ups ) # If (!ups) we use this list below to recurse: self_ups_list = self.GetUPSNames() if ups and (ups not in self_ups_list): if self.__debug : print( "[DEBUG] ListClients: %s is not a valid UPS" % ups ) raise PyNUTError( "ERR UNKNOWN-UPS" ) if ups: self.__srv_handler.write( ("LIST CLIENT %s\n" % ups).encode('ascii') ) else: # NOTE: Currently NUT does not support just listing all clients # (not providing an "ups" argument) => NUT_ERR_INVALID_ARGUMENT self.__srv_handler.write( b"LIST CLIENT\n" ) result = self.__srv_handler.read_until( b"\n" ) if ( (ups and result != ("BEGIN LIST CLIENT %s\n" % ups).encode('ascii')) or (ups is None and result != b"BEGIN LIST CLIENT\n") ): if ups is None and (result == b"ERR INVALID-ARGUMENT\n") : # For ups==None, list all upses, list their clients if self.__debug : print( "[DEBUG] Recurse ListClients() because it did not specify one UPS to query" ) ups_list = {} for ups in self_ups_list : # Update "ups_list" dict with contents of recursive call return ups_list.update(self.ListClients(ups)) return( ups_list ) # had a seemingly valid arg, but no success: if self.__debug : print( "[DEBUG] ListClients from server got unexpected result: %s" % result ) raise PyNUTError( result.replace( b"\n", b"" ).decode('ascii') ) if ups : result = self.__srv_handler.read_until( ("END LIST CLIENT %s\n" % ups).encode('ascii') ) else: # Should not get here with current NUT: result = self.__srv_handler.read_until( b"END LIST CLIENT\n" ) ups_list = {} for line in result.split( b"\n" ): ###print( "[DEBUG] ListClients line: '%s'" % line ) if line[:6] == b"CLIENT" : ups, host = line[7:].split(b' ') ups.replace(b' ', b'') host.replace(b' ', b'') if not ups in ups_list: ups_list[ups] = [] ups_list[ups].append(host) return( ups_list ) nut-2.8.1/scripts/python/module/test_nutclient.py.in0000755000175000017500000001457514501607135017612 00000000000000#!@PYTHON@ # -*- coding: utf-8 -*- # This source code is provided for testing/debuging purpose ;) import PyNUT import sys import os if __name__ == "__main__" : NUT_HOST = os.getenv('NUT_HOST', '127.0.0.1') NUT_PORT = int(os.getenv('NUT_PORT', '3493')) NUT_USER = os.getenv('NUT_USER', None) NUT_PASS = os.getenv('NUT_PASS', None) # Account "unexpected" failures (more due to coding than circumstances) # e.g. lack of protected access when no credentials were passed is okay failed = [] print( "PyNUTClient test..." ) #nut = PyNUT.PyNUTClient( debug=True, port=NUT_PORT ) nut = PyNUT.PyNUTClient( login=NUT_USER, password=NUT_PASS, debug=True, host=NUT_HOST, port=NUT_PORT ) #nut = PyNUT.PyNUTClient( login="upsadmin", password="upsadmin", debug=True, port=NUT_PORT ) print( 80*"-" + "\nTesting 'GetUPSList' :") result = nut.GetUPSList( ) print( "\033[01;33m%s\033[0m\n" % result ) # [dummy] # driver = dummy-ups # desc = "Test device" # port = /src/nut/data/evolution500.seq print( 80*"-" + "\nTesting 'GetUPSVars' for 'dummy' (should be registered in upsd.conf) :") result = nut.GetUPSVars( "dummy" ) print( "\033[01;33m%s\033[0m\n" % result ) print( 80*"-" + "\nTesting 'CheckUPSAvailable' :") result = nut.CheckUPSAvailable( "dummy" ) print( "\033[01;33m%s\033[0m\n" % result ) print( 80*"-" + "\nTesting 'GetUPSCommands' :") result = nut.GetUPSCommands( "dummy" ) print( "\033[01;33m%s\033[0m\n" % result ) print( 80*"-" + "\nTesting 'GetRWVars' :") result = nut.GetRWVars( "dummy" ) print( "\033[01;33m%s\033[0m\n" % result ) print( 80*"-" + "\nTesting 'RunUPSCommand' (Test front panel) :") try : result = nut.RunUPSCommand( "UPS1", "test.panel.start" ) if (NUT_USER is None): raise AssertionError("Secure operation should have failed due to lack of credentials, but did not") except : ex = str(sys.exc_info()[1]) result = "EXCEPTION: " + ex if (NUT_USER is None and ex == 'ERR USERNAME-REQUIRED'): result = result + "\n(anticipated error: no credentials were provided)" else: if (ex != 'ERR CMD-NOT-SUPPORTED' and (NUT_USER is not None and ex != 'ERR ACCESS-DENIED') ): result = result + "\nTEST-CASE FAILED" failed.append('RunUPSCommand') print( "\033[01;33m%s\033[0m\n" % result ) print( 80*"-" + "\nTesting 'SetUPSVar' (set ups.id to test):") try : result = nut.SetRWVar( "UPS1", "ups.id", "test" ) if (NUT_USER is None): raise AssertionError("Secure operation should have failed due to lack of credentials, but did not") except : ex = str(sys.exc_info()[1]) result = "EXCEPTION: " + ex if (NUT_USER is None and ex == 'ERR USERNAME-REQUIRED'): result = result + "\n(anticipated error: no credentials were provided)" else: if (ex != 'ERR VAR-NOT-SUPPORTED' and (NUT_USER is not None and ex != 'ERR ACCESS-DENIED') ): result = result + "\nTEST-CASE FAILED" failed.append('SetUPSVar') print( "\033[01;33m%s\033[0m\n" % result ) # testing who has an upsmon-like log-in session to a device print( 80*"-" + "\nTesting 'ListClients' for 'dummy' (should be registered in upsd.conf) before test client is connected :") try : result = nut.ListClients( "dummy" ) except : ex = str(sys.exc_info()[1]) result = "EXCEPTION: " + ex result = result + "\nTEST-CASE FAILED" failed.append('ListClients-dummy-before') print( "\033[01;33m%s\033[0m\n" % result ) print( 80*"-" + "\nTesting 'ListClients' for missing device (should raise an exception) :") try : result = nut.ListClients( "MissingBogusDummy" ) except : ex = str(sys.exc_info()[1]) result = "EXCEPTION: " + ex if (ex == 'ERR UNKNOWN-UPS'): result = result + "\n(anticipated error: bogus device name was tested)" else: result = result + "\nTEST-CASE FAILED" failed.append('ListClients-MissingBogusDummy') print( "\033[01;33m%s\033[0m\n" % result ) loggedIntoDummy = False print( 80*"-" + "\nTesting 'DeviceLogin' for 'dummy' (should be registered in upsd.conf; current credentials should have an upsmon role in upsd.users) :") try : result = nut.DeviceLogin( "dummy" ) if (NUT_USER is None): raise AssertionError("Secure operation should have failed due to lack of credentials, but did not") loggedIntoDummy = True except : ex = str(sys.exc_info()[1]) result = "EXCEPTION: " + ex if (NUT_USER is None and ex == 'ERR USERNAME-REQUIRED'): result = result + "\n(anticipated error: no credentials were provided)" else: if (NUT_USER is not None and ex != 'ERR ACCESS-DENIED'): result = result + "\nTEST-CASE FAILED" failed.append('DeviceLogin-dummy') print( "\033[01;33m%s\033[0m\n" % result ) print( 80*"-" + "\nTesting 'ListClients' for None (should list all devices and sessions to them, if any -- e.g. one established above) :") try : result = nut.ListClients( ) if (type(result) is not dict): raise TypeError("ListClients() did not return a dict") else: if (loggedIntoDummy): if (len(result) < 1): raise ValueError("ListClients() returned an empty dict where at least one client was expected on b'dummy'") if (type(result[b'dummy']) is not list): raise TypeError("ListClients() did not return a dict whose b'dummy' keyed value is a list") if (len(result[b'dummy']) < 1): raise ValueError("ListClients() returned a dict where at least one client was expected on b'dummy' but none were reported") except : ex = str(sys.exc_info()[1]) result = "EXCEPTION: " + ex result = result + "\nTEST-CASE FAILED" failed.append('ListClients-dummy-after') print( "\033[01;33m%s\033[0m\n" % result ) print( 80*"-" + "\nTesting 'PyNUT' instance teardown (end of test script)" ) # No more tests AFTER this line; add them above the teardown message if (len(failed) > 0): print ( "SOME TEST CASES FAILED in an unexpected manner: %s" % failed ) sys.exit(1) nut-2.8.1/scripts/python/module/README0000644000175000017500000002654314501607135014442 00000000000000Introduction ============ The project was originally started in 2008 David Goncalves at https://www.lestat.st/informatique/projets/pynut and was soon added to the main NUT codebase and evolved there. The PyNUT module provides an abstraction class `PyNUTClient` written in Python, which allows to connect to a NUT (Network UPS Tools) server and execute different commands without an application developer needing to know the NUT communication protocol. That class was born from another project the original author had -- a graphical application to monitor and manage the UPSes connected to a NUT server. It is now known as `NUT-Monitor` and is also provided along with NT sources. With that GUI application being written in Python too, it was decided to split the project in two parts (the PyNUT class + GUI application, serving as model + view) in order to keep the two parts independent. That class was subsequently renamed to `PyNUTClient` since version 1.1 of the original project, allowing to develop other classes nearby later. Currently the module is regularly tested to work with Python interpreter versions 2.7, 3.4, 3.5 and 3.7. [NOTE] ====== Text fields returned by methods are byte sequences (not locale-aware strings), except NUT protocol error codes quoted into `PyNUTError` exceptions which are decoded into strings as originally `ascii` text. This is of little concern for Python 2, but is important in Python 3. The `ups` argument to methods is handled as a string, so conversion may be needed to compare with names returned in the lists and dictionaries, e.g.: ---- strUps = bUps.decode('ascii') bUps = strUps.encode('ascii') ---- Only the names returned by `GetUPSNames()` method specifically are converted into string type. Since Python 3 support was added just recently, module code may later be converted to use string types like `str` or `unicode` in the returned dictionaries and sets instead, if the community deems this to be more idiomatic. Examples below *do not* specify the `b'some text'` markup that would be pedantically correct (for Python 3 at least). ====== .List of methods in the class ------ class PyNUTClient : def __init__( self, host='127.0.0.1', port=3493, login=None, password=None, debug=False, timeout=5 ) : def help( self ) : def ver( self ) : def DeviceLogin( self, ups="" ) : def FSD( self, ups="" ) : def CheckUPSAvailable( self, ups="" ) : def GetRWVars( self, ups='' ) : def GetUPSCommands( self, ups='' ) : def GetUPSList( self ) : def GetUPSNames( self ) : def GetUPSVars( self, ups='' ) : def ListClients( self, ups = None ) : def RunUPSCommand( self, ups='', command='' ) : def SetRWVar( self, ups='', var='', value='' ) : ------ The module also provides the `PyNUTError` class to represent any exceptions raised by `PyNUTClient` logic. Documentation ------------- Although the original project was written in French, for the reasons of general distribution with NUT, all of its code is commented in English. While this file contains the description from https://www.lestat.st/informatique/projets/pynut the class `PyNUTClient` is compatible with the Python module PyDOC, so you can type `pydoc PyNUT` to obtain succint documentation on your current version of the module. For more examples see the provided test script and the NUT-Monitor application in the NUT sources. Commands below are listed in alphabetic order. __init__ ~~~~~~~~ When you initialize the class instance, it performs the connection to the NUT data server or raises a Python exception from the `__connect()` method called internally. help ~~~~ Sends the `HELP` command to the NUT data server and returns whatever bits of wisdom it has to offer. ver ~~~ Sends the `VER` command to the NUT data server and returns its self-reported identification such as version, product or distribution it may be bunded with. Note that the NUT client interactions should not rely on reported versions, but follow the protocol as defined. DeviceLogin ~~~~~~~~~~~ Establish a "client" session with the specified UPS. This uses credentials specified earlier to `__init__()` this class instance, and on server side (in `upsd.users` file) these credentials must have one of `upsmon` roles. The command should return `OK` if everything went well, or raise an exception in case of failure, such as invalid or insufficiently privileged credentials. Note there is no `DeviceLogout()`, just the general connection termination. FSD ~~~ Send the FSD (Forced ShutDown) command to the specified UPS. The command should return `OK` if everything went well, or raise an exception in case of failure, such as that this server does not allow to manage that UPS as a "primary" (or "master" before NUT 2.8.0). CheckUPSAvailable ~~~~~~~~~~~~~~~~~ Returns a boolean state whether the specified UPS is recognized and available (`True`), or is not (`False`). Internally, requests a listing of commands supported by the device name, and evaluates the server response. .Example ----- import PyNUT ups = PyNUT.PyNUTClient( host='serveur', login='upsadmin', password='upspass' ) result = ups.CheckUPSAvailable( ups='ups1' ) print( result ) >> True ----- See also: `GetUPSCommands()` GetRWVars ~~~~~~~~~ Returns a list of modifiable variables on the specified UPS, as a dictionary of "variable"-"current value" pairs. .Example ----- import PyNUT ups = PyNUT.PyNUTClient( host='serveur', login='upsadmin', password='upspass' ) result = ups.GetRWVars( ups='ups1' ) print( result ) >> {'battery.date': '10/25/07', 'ups.id': 'test'} ----- See also: `GetUPSVars()`, `SetRWVar()` GetUPSCommands ~~~~~~~~~~~~~~ Returns a list of commands supported by the specified UPS. Note that certain commands are not usable without first getting necessary rights on the NUT data server. The result is presented as a dictionary of "command"-"English description" pairs. .Example ----- import PyNUT ups = PyNUT.PyNUTClient( host='serveur', login='upsadmin', password='upspass' ) result = ups.GetRWVars( ups='ups1' ) print( result ) >> {'test.battery.start' : 'Start a battery test', 'calibrate.stop' : 'Stop run time calibration', 'shutdown.stayoff' : 'Turn off the load and remain off', 'test.battery.stop' : 'Stop the battery test', 'test.panel.start' : 'Start testing the UPS panel', 'calibrate.start' : 'Start run time calibration', 'load.off' : 'Turn off the load immediately', 'test.failure.start' : 'Start a simulated power failure', 'shutdown.return' : 'Turn off the load and return when power is back'} ----- See also: `RunUPSCommand()` GetUPSList ~~~~~~~~~~ Returns the list of UPSes represented by the NUT server, as a dictionary of "name"-"description" pairs. .Example ----- import PyNUT ups = PyNUT.PyNUTClient( host='serveur', login='upsadmin', password='upspass' ) result = ups.GetUPSList() print( result ) >> {'UPS1': 'Smart UPS 3000 File server', 'UPS2': 'Smart UPS 1000 Serveur de mail'} ----- GetUPSNames ~~~~~~~~~~~ Returns just the list of available UPS names from the NUT server. The result is a set of `str` objects (comparable with `ups="somename"` and useful as arguments to other methods). Helps work around Python2/Python3 string API changes (where `b'string' != 'string'` and not even a type comparable to it), and is primarily used as a helper internally in some methods. .Example ----- import PyNUT ups = PyNUT.PyNUTClient( host='serveur', login='upsadmin', password='upspass' ) result = ups.GetUPSNames() print( result ) >> ['UPS1', 'UPS2'] ----- GetUPSVars ~~~~~~~~~~ Returns a list of all variables on the specified UPS, as a dictionary of "variable"-"current value" pairs. .Example ----- import PyNUT ups = PyNUT.PyNUTClient( host='serveur', login='upsadmin', password='upspass' ) result = ups.GetUPSVars( ups='UPS1' ) print( result ) >> {'input.transfer.high' : '253', 'battery.charge' : '100.0', 'ups.mfr' : 'APC', 'battery.voltage.nominal' : '024', 'input.transfer.reason' : 'S', 'ups.test.interval' : '1209600', 'input.transfer.low' : '208', 'output.voltage' : '234.0', 'driver.version' : '2.2.1-', 'battery.charge.restart' : '00', 'ups.id' : 'test', 'driver.parameter.pollinterval' : '2', 'driver.parameter.port' : '/dev/ttyS0', 'battery.voltage' : '27.10', 'ups.test.result' : 'NO', 'ups.status' : 'OL', 'battery.date' : '10/25/07', 'ups.model' : 'Smart-UPS SC1000', 'ups.serial' : 'XXXXXXXXXXXX', 'output.voltage.nominal' : '230', 'ups.mfr.date' : '10/25/07', 'driver.version.internal' : '1.99.8', 'input.voltage' : '234.0', 'battery.runtime.low' : '120', 'input.sensitivity' : 'H', 'ups.load' : '001.9', 'driver.name' : 'apcsmart', 'input.voltage.maximum' : '234.0', 'input.frequency' : '50.00', 'ups.delay.shutdown' : '060', 'ups.delay.start' : '000', 'input.voltage.minimum' : '232.0', 'input.quality' : 'FF', 'battery.runtime' : '29040', 'ups.firmware' : '737.3.I', 'battery.alarm.threshold' : '0'} ----- See also: `GetRWVars()` ListClients ~~~~~~~~~~~ Returns the list of connected clients (such as the `NUT-Monitor` application or an `upsmon` service) from the NUT server, for a particular UPS or all of them by default. The result is a dictionary containing "upsname"-"client list" pairing 'UPSName' and a list of clients for each device if the information was retrieved from the NUT data server successfully, or an exception is raised otherwise. RunUPSCommand ~~~~~~~~~~~~~ Executes the specified command on the specified UPS. It should be one of the commands returned by the `GetUPSCommands()` function. Note that certain commands are not usable without first getting necessary rights on the NUT data server. The command should return `OK` if everything went well, or raise an exception in case of failure. .Example ----- import PyNUT ups = PyNUT.PyNUTClient( host='serveur', login='upsadmin', password='upspass' ) result = ups.RunUPSCommand( ups='UPS1', command='test.panel.start' ) print( result ) >> OK ----- See also: `GetUPSCommands()` SetRWVar ~~~~~~~~ This method adjusts the value of a writable NUT variable on the specified UPS. It should be one of the variables listed by the `GetRWVars()` method. Note that you may need to first get necessary rights on the NUT data server. The command should return `OK` if everything went well, or raise an exception in case of failure. .Example ----- import PyNUT ups = PyNUT.PyNUTClient( host='serveur', login='upsadmin', password='upspass' ) result = ups.SetRWVar( ups='UPS1', var='battery.date', value='06/17/08' ) print( result ) >> OK ----- See also: `GetRWVars()` nut-2.8.1/scripts/python/Makefile.in0000644000175000017500000011703514520274662014345 00000000000000# Makefile.in generated by automake 1.16.5 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2021 Free Software Foundation, Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. @SET_MAKE@ # Network UPS Tools: scripts/python VPATH = @srcdir@ am__is_gnu_make = { \ if test -z '$(MAKELEVEL)'; then \ false; \ elif test -n '$(MAKE_HOST)'; then \ true; \ elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \ true; \ else \ false; \ fi; \ } am__make_running_with_option = \ case $${target_option-} in \ ?) ;; \ *) echo "am__make_running_with_option: internal error: invalid" \ "target option '$${target_option-}' specified" >&2; \ exit 1;; \ esac; \ has_opt=no; \ sane_makeflags=$$MAKEFLAGS; \ if $(am__is_gnu_make); then \ sane_makeflags=$$MFLAGS; \ else \ case $$MAKEFLAGS in \ *\\[\ \ ]*) \ bs=\\; \ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ esac; \ fi; \ skip_next=no; \ strip_trailopt () \ { \ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ }; \ for flg in $$sane_makeflags; do \ test $$skip_next = yes && { skip_next=no; continue; }; \ case $$flg in \ *=*|--*) continue;; \ -*I) strip_trailopt 'I'; skip_next=yes;; \ -*I?*) strip_trailopt 'I';; \ -*O) strip_trailopt 'O'; skip_next=yes;; \ -*O?*) strip_trailopt 'O';; \ -*l) strip_trailopt 'l'; skip_next=yes;; \ -*l?*) strip_trailopt 'l';; \ -[dEDm]) skip_next=yes;; \ -[JT]) skip_next=yes;; \ esac; \ case $$flg in \ *$$target_option*) has_opt=yes; break;; \ esac; \ done; \ test $$has_opt = yes am__make_dryrun = (target_option=n; $(am__make_running_with_option)) am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkglibexecdir = $(libexecdir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ target_triplet = @target@ @WITH_NUT_MONITOR_PY2GTK2_TRUE@@WITH_NUT_MONITOR_TRUE@am__append_1 = $(NUT_MONITOR_PY2GTK2) @WITH_NUT_MONITOR_PY2GTK2_TRUE@@WITH_NUT_MONITOR_TRUE@am__append_2 = $(NUT_MONITOR_PY2GTK2_GENERATED_SCRIPT) @WITH_NUT_MONITOR_PY3QT5_TRUE@@WITH_NUT_MONITOR_TRUE@am__append_3 = $(NUT_MONITOR_PY3QT5) @WITH_NUT_MONITOR_PY3QT5_TRUE@@WITH_NUT_MONITOR_TRUE@am__append_4 = $(NUT_MONITOR_PY3QT5_GENERATED_SCRIPT) @WITH_NUT_MONITOR_TRUE@@WITH_PYNUT_APP_TRUE@am__append_5 = $(PYNUT_COMMON) $(PYNUT_GENERATED_NOEXEC) @WITH_NUT_MONITOR_TRUE@@WITH_PYNUT_APP_TRUE@am__append_6 = $(PYNUT_GENERATED_SCRIPT) subdir = scripts/python ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/m4/ax_c___attribute__.m4 \ $(top_srcdir)/m4/ax_c_pragmas.m4 \ $(top_srcdir)/m4/ax_check_compile_flag.m4 \ $(top_srcdir)/m4/ax_compare_version.m4 \ $(top_srcdir)/m4/ax_realpath.m4 \ $(top_srcdir)/m4/ax_run_or_link_ifelse.m4 \ $(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \ $(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \ $(top_srcdir)/m4/lt~obsolete.m4 \ $(top_srcdir)/m4/nut_arg_with.m4 \ $(top_srcdir)/m4/nut_check_asciidoc.m4 \ $(top_srcdir)/m4/nut_check_aspell.m4 \ $(top_srcdir)/m4/nut_check_cppcheck.m4 \ $(top_srcdir)/m4/nut_check_headers_windows.m4 \ $(top_srcdir)/m4/nut_check_libavahi.m4 \ $(top_srcdir)/m4/nut_check_libfreeipmi.m4 \ $(top_srcdir)/m4/nut_check_libgd.m4 \ $(top_srcdir)/m4/nut_check_libgpiod.m4 \ $(top_srcdir)/m4/nut_check_libltdl.m4 \ $(top_srcdir)/m4/nut_check_libmodbus.m4 \ $(top_srcdir)/m4/nut_check_libneon.m4 \ $(top_srcdir)/m4/nut_check_libnetsnmp.m4 \ $(top_srcdir)/m4/nut_check_libnss.m4 \ $(top_srcdir)/m4/nut_check_libopenssl.m4 \ $(top_srcdir)/m4/nut_check_libpowerman.m4 \ $(top_srcdir)/m4/nut_check_libregex.m4 \ $(top_srcdir)/m4/nut_check_libsystemd.m4 \ $(top_srcdir)/m4/nut_check_libusb.m4 \ $(top_srcdir)/m4/nut_check_libwrap.m4 \ $(top_srcdir)/m4/nut_check_os.m4 \ $(top_srcdir)/m4/nut_check_pkgconfig.m4 \ $(top_srcdir)/m4/nut_check_python.m4 \ $(top_srcdir)/m4/nut_check_socketlib.m4 \ $(top_srcdir)/m4/nut_compiler_family.m4 \ $(top_srcdir)/m4/nut_func_getnameinfo_argtypes.m4 \ $(top_srcdir)/m4/nut_report_feature.m4 \ $(top_srcdir)/m4/nut_stash_warnings.m4 \ $(top_srcdir)/m4/nut_type_socklen_t.m4 \ $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/include/config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; am__vpath_adj = case $$p in \ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ *) f=$$p;; \ esac; am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`; am__install_max = 40 am__nobase_strip_setup = \ srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'` am__nobase_strip = \ for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||" am__nobase_list = $(am__nobase_strip_setup); \ for p in $$list; do echo "$$p $$p"; done | \ sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \ $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \ if (++n[$$2] == $(am__install_max)) \ { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \ END { for (dir in files) print dir, files[dir] }' am__base_list = \ sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' am__uninstall_files_from_dir = { \ test -z "$$files" \ || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \ || { echo " ( cd '$$dir' && rm -f" $$files ")"; \ $(am__cd) "$$dir" && rm -f $$files; }; \ } am__installdirs = "$(DESTDIR)$(nutmonitordir)" \ "$(DESTDIR)$(pynut_py2_sitedir)" \ "$(DESTDIR)$(pynut_py3_sitedir)" \ "$(DESTDIR)$(pynut_py_sitedir)" "$(DESTDIR)$(sysbindir)" \ "$(DESTDIR)$(nutmonitordir)" "$(DESTDIR)$(pynut_py2_sitedir)" \ "$(DESTDIR)$(pynut_py3_sitedir)" \ "$(DESTDIR)$(pynut_py_sitedir)" SCRIPTS = $(nobase_nutmonitor_SCRIPTS) $(pynut_py2_site_SCRIPTS) \ $(pynut_py3_site_SCRIPTS) $(pynut_py_site_SCRIPTS) \ $(sysbin_SCRIPTS) AM_V_P = $(am__v_P_@AM_V@) am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) am__v_P_0 = false am__v_P_1 = : AM_V_GEN = $(am__v_GEN_@AM_V@) am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) am__v_GEN_0 = @echo " GEN " $@; am__v_GEN_1 = AM_V_at = $(am__v_at_@AM_V@) am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) am__v_at_0 = @ am__v_at_1 = SOURCES = DIST_SOURCES = am__can_run_installinfo = \ case $$AM_UPDATE_INFO_DIR in \ n|no|NO) false;; \ *) (install-info --version) >/dev/null 2>&1;; \ esac DATA = $(nobase_nutmonitor_DATA) $(pynut_py2_site_DATA) \ $(pynut_py3_site_DATA) $(pynut_py_site_DATA) am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) am__DIST_COMMON = $(srcdir)/Makefile.in README DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) A2X = @A2X@ ACLOCAL = @ACLOCAL@ ALTPIDPATH = @ALTPIDPATH@ AMTAR = @AMTAR@ AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ AR = @AR@ ASCIIDOC = @ASCIIDOC@ ASPELL = @ASPELL@ ASPELL_FILTER_LIB_PATH = @ASPELL_FILTER_LIB_PATH@ ASPELL_FILTER_SHARE_PATH = @ASPELL_FILTER_SHARE_PATH@ ASPELL_FILTER_TEX_PATH = @ASPELL_FILTER_TEX_PATH@ AUGPARSE = @AUGPARSE@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ BINDIR = @BINDIR@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CONFIG_FLAGS = @CONFIG_FLAGS@ CONFPATH = @CONFPATH@ CPP = @CPP@ CPPCHECK = @CPPCHECK@ CPPFLAGS = @CPPFLAGS@ CPPUNIT_CFLAGS = @CPPUNIT_CFLAGS@ CPPUNIT_LIBS = @CPPUNIT_LIBS@ CSCOPE = @CSCOPE@ CTAGS = @CTAGS@ CXX = @CXX@ CXXCPP = @CXXCPP@ CXXDEPMODE = @CXXDEPMODE@ CXXFLAGS = @CXXFLAGS@ CYGPATH_W = @CYGPATH_W@ DBLATEX = @DBLATEX@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ DEPLOYED_UPSC = @DEPLOYED_UPSC@ DEPLOYED_UPSD = @DEPLOYED_UPSD@ DLLTOOL = @DLLTOOL@ DOC_BUILD_LIST = @DOC_BUILD_LIST@ DOC_CHECK_LIST = @DOC_CHECK_LIST@ DRIVER_BUILD_LIST = @DRIVER_BUILD_LIST@ DRIVER_INSTALL_TARGET = @DRIVER_INSTALL_TARGET@ DRIVER_MAN_LIST = @DRIVER_MAN_LIST@ DRIVER_MAN_LIST_PAGES = @DRIVER_MAN_LIST_PAGES@ DRVPATH = @DRVPATH@ DSYMUTIL = @DSYMUTIL@ DUMPBIN = @DUMPBIN@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ ETAGS = @ETAGS@ EXEEXT = @EXEEXT@ FGREP = @FGREP@ FORCE_NUT_VERSION = @FORCE_NUT_VERSION@ GDLIB_CONFIG = @GDLIB_CONFIG@ GREP = @GREP@ HAVE_SYS_SOCKET_H = @HAVE_SYS_SOCKET_H@ HAVE_WINSOCK2_H = @HAVE_WINSOCK2_H@ HAVE_WS2TCPIP_H = @HAVE_WS2TCPIP_H@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ LD = @LD@ LDFLAGS = @LDFLAGS@ LIBAVAHI_CFLAGS = @LIBAVAHI_CFLAGS@ LIBAVAHI_LIBS = @LIBAVAHI_LIBS@ LIBDIR = @LIBDIR@ LIBGD_CFLAGS = @LIBGD_CFLAGS@ LIBGD_LDFLAGS = @LIBGD_LDFLAGS@ LIBGPIO_CFLAGS = @LIBGPIO_CFLAGS@ LIBGPIO_LIBS = @LIBGPIO_LIBS@ LIBI2C_LIBS = @LIBI2C_LIBS@ LIBIPMI_CFLAGS = @LIBIPMI_CFLAGS@ LIBIPMI_LIBS = @LIBIPMI_LIBS@ LIBLTDL_CFLAGS = @LIBLTDL_CFLAGS@ LIBLTDL_LIBS = @LIBLTDL_LIBS@ LIBMODBUS_CFLAGS = @LIBMODBUS_CFLAGS@ LIBMODBUS_LIBS = @LIBMODBUS_LIBS@ LIBNEON_CFLAGS = @LIBNEON_CFLAGS@ LIBNEON_LIBS = @LIBNEON_LIBS@ LIBNETSNMP_CFLAGS = @LIBNETSNMP_CFLAGS@ LIBNETSNMP_LIBS = @LIBNETSNMP_LIBS@ LIBOBJS = @LIBOBJS@ LIBPOWERMAN_CFLAGS = @LIBPOWERMAN_CFLAGS@ LIBPOWERMAN_LIBS = @LIBPOWERMAN_LIBS@ LIBREGEX_LIBS = @LIBREGEX_LIBS@ LIBS = @LIBS@ LIBSSL_CFLAGS = @LIBSSL_CFLAGS@ LIBSSL_LIBS = @LIBSSL_LIBS@ LIBSSL_REQUIRES = @LIBSSL_REQUIRES@ LIBSYSTEMD_CFLAGS = @LIBSYSTEMD_CFLAGS@ LIBSYSTEMD_LIBS = @LIBSYSTEMD_LIBS@ LIBTOOL = @LIBTOOL@ LIBTOOL_DEPS = @LIBTOOL_DEPS@ LIBUSB_CFLAGS = @LIBUSB_CFLAGS@ LIBUSB_CONFIG = @LIBUSB_CONFIG@ LIBUSB_LIBS = @LIBUSB_LIBS@ LIBWRAP_CFLAGS = @LIBWRAP_CFLAGS@ LIBWRAP_LIBS = @LIBWRAP_LIBS@ LIPO = @LIPO@ LN_S = @LN_S@ LN_S_R = @LN_S_R@ LTLIBOBJS = @LTLIBOBJS@ LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@ MAINT = @MAINT@ MAKEINFO = @MAKEINFO@ MANIFEST_TOOL = @MANIFEST_TOOL@ MKDIR_P = @MKDIR_P@ MSGFMT = @MSGFMT@ NETLIBS = @NETLIBS@ NET_SNMP_CONFIG = @NET_SNMP_CONFIG@ NM = @NM@ NMEDIT = @NMEDIT@ NUT_DATADIR = @NUT_DATADIR@ NUT_LIBEXECDIR = @NUT_LIBEXECDIR@ NUT_NETVERSION = @NUT_NETVERSION@ NUT_SOURCE_GITREV = @NUT_SOURCE_GITREV@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ OS_NAME = @OS_NAME@ OTOOL = @OTOOL@ OTOOL64 = @OTOOL64@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_SEPARATOR = @PATH_SEPARATOR@ PIDPATH = @PIDPATH@ PKGCONFIGDIR = @PKGCONFIGDIR@ PKG_CONFIG = @PKG_CONFIG@ PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@ PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ PORT = @PORT@ POWERDOWNFLAG = @POWERDOWNFLAG@ PREFIX = @PREFIX@ PYTHON = @PYTHON@ PYTHON2 = @PYTHON2@ PYTHON2_SITE_PACKAGES = @PYTHON2_SITE_PACKAGES@ PYTHON3 = @PYTHON3@ PYTHON3_SITE_PACKAGES = @PYTHON3_SITE_PACKAGES@ PYTHON_SITE_PACKAGES = @PYTHON_SITE_PACKAGES@ RANLIB = @RANLIB@ REALPATH = @REALPATH@ RUN_AS_GROUP = @RUN_AS_GROUP@ RUN_AS_USER = @RUN_AS_USER@ SBINDIR = @SBINDIR@ SED = @SED@ SEMLIBS = @SEMLIBS@ SERLIBS = @SERLIBS@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ SOURCE_HIGHLIGHT = @SOURCE_HIGHLIGHT@ STATEPATH = @STATEPATH@ STRIP = @STRIP@ SUN_LIBUSB = @SUN_LIBUSB@ SYSTEMD_ANALYZE_PROGRAM = @SYSTEMD_ANALYZE_PROGRAM@ SYSTEMD_DAEMON_ARGS_DRIVER = @SYSTEMD_DAEMON_ARGS_DRIVER@ SYSTEMD_DAEMON_ARGS_UPSD = @SYSTEMD_DAEMON_ARGS_UPSD@ SYSTEMD_DAEMON_ARGS_UPSMON = @SYSTEMD_DAEMON_ARGS_UPSMON@ SYSTEMD_DAEMON_NOTIFYACCESS_DRIVER = @SYSTEMD_DAEMON_NOTIFYACCESS_DRIVER@ SYSTEMD_DAEMON_NOTIFYACCESS_UPSD = @SYSTEMD_DAEMON_NOTIFYACCESS_UPSD@ SYSTEMD_DAEMON_NOTIFYACCESS_UPSMON = @SYSTEMD_DAEMON_NOTIFYACCESS_UPSMON@ SYSTEMD_DAEMON_TYPE_DRIVER = @SYSTEMD_DAEMON_TYPE_DRIVER@ SYSTEMD_DAEMON_TYPE_UPSD = @SYSTEMD_DAEMON_TYPE_UPSD@ SYSTEMD_DAEMON_TYPE_UPSMON = @SYSTEMD_DAEMON_TYPE_UPSMON@ SYSTEMD_DAEMON_WATCHDOG_DRIVER = @SYSTEMD_DAEMON_WATCHDOG_DRIVER@ SYSTEMD_DAEMON_WATCHDOG_UPSD = @SYSTEMD_DAEMON_WATCHDOG_UPSD@ SYSTEMD_DAEMON_WATCHDOG_UPSMON = @SYSTEMD_DAEMON_WATCHDOG_UPSMON@ SYSTEMD_TMPFILES_PROGRAM = @SYSTEMD_TMPFILES_PROGRAM@ TREE_VERSION = @TREE_VERSION@ VALGRIND = @VALGRIND@ VERSION = @VERSION@ WINDMC = @WINDMC@ WINDRES = @WINDRES@ WORDS_BIGENDIAN = @WORDS_BIGENDIAN@ XMLLINT = @XMLLINT@ XSLTPROC = @XSLTPROC@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_AR = @ac_ct_AR@ ac_ct_CC = @ac_ct_CC@ ac_ct_CXX = @ac_ct_CXX@ ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__tar = @am__tar@ am__untar = @am__untar@ auglensdir = @auglensdir@ bindir = @bindir@ build = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ cgiexecdir = @cgiexecdir@ datadir = @datadir@ datarootdir = @datarootdir@ devddir = @devddir@ docdir = @docdir@ driverexecdir = @driverexecdir@ dummy_PKG_CONFIG = @dummy_PKG_CONFIG@ dummy_PKG_CONFIG_CFLAGS = @dummy_PKG_CONFIG_CFLAGS@ dummy_PKG_CONFIG_LIBS = @dummy_PKG_CONFIG_LIBS@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ hotplugdir = @hotplugdir@ htmldir = @htmldir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libdir = @libdir@ libexecdir = @libexecdir@ localedir = @localedir@ localstatedir = @localstatedir@ mandir = @mandir@ mkdir_p = @mkdir_p@ now = @now@ # Recognize settings from configure.ac (for make install handling) nut_with_nut_monitor = @nut_with_nut_monitor@ nut_with_nut_monitor_desktop = @nut_with_nut_monitor_desktop@ nut_with_nut_monitor_dir = @nut_with_nut_monitor_dir@ nut_with_nut_monitor_py2gtk2 = @nut_with_nut_monitor_py2gtk2@ nut_with_nut_monitor_py3qt5 = @nut_with_nut_monitor_py3qt5@ # Note: this may be "desktop-file-install" to use in e.g. # packaging postinstall scripts for tighter OS integration; # note also the icon files, etc. that may want symlinks to # system-defined locations. For examples please see e.g. # https://aur.archlinux.org/cgit/aur.git/tree/PKGBUILD?h=nut-monitor #nut_with_nut_monitor_desktop = @nut_with_nut_monitor_desktop@ nut_with_pynut = @nut_with_pynut@ nut_with_pynut_py = @nut_with_pynut_py@ nut_with_pynut_py2 = @nut_with_pynut_py2@ nut_with_pynut_py3 = @nut_with_pynut_py3@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ pkgconfigdir = @pkgconfigdir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ runstatedir = @runstatedir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ sysconfdir = @sysconfdir@ systemdshutdowndir = @systemdshutdowndir@ systemdsystemunitdir = @systemdsystemunitdir@ systemdtmpfilesdir = @systemdtmpfilesdir@ target = @target@ target_alias = @target_alias@ target_cpu = @target_cpu@ target_os = @target_os@ target_vendor = @target_vendor@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ udevdir = @udevdir@ NUT_MONITOR_PY2GTK2 = \ app/ui/gui-1.3.glade \ app/nut-monitor-py2gtk2.desktop NUT_MONITOR_PY2GTK2_TEMPLATE = \ app/NUT-Monitor-py2gtk2.in NUT_MONITOR_PY2GTK2_GENERATED_SCRIPT = \ app/NUT-Monitor-py2gtk2 NUT_MONITOR_PY3QT5 = \ app/ui/aboutdialog1.ui \ app/ui/dialog1.ui \ app/ui/dialog2.ui \ app/ui/window1.ui \ app/nut-monitor-py3qt5.desktop NUT_MONITOR_PY3QT5_TEMPLATE = \ app/NUT-Monitor-py3qt5.in NUT_MONITOR_PY3QT5_GENERATED_SCRIPT = \ app/NUT-Monitor-py3qt5 NUT_MONITOR_COMMON = \ README \ app/nut-monitor.appdata.xml \ app/icons/48x48/nut-monitor.png \ app/icons/64x64/nut-monitor.png \ app/icons/256x256/nut-monitor.png \ app/icons/scalable/nut-monitor.svg \ app/README \ app/screenshots/nut-monitor-1.png \ app/screenshots/nut-monitor-2.png \ app/screenshots/nut-monitor-3.png \ app/pixmaps/on_battery.png \ app/pixmaps/on_line.png \ app/pixmaps/var-ro.png \ app/pixmaps/var-rw.png \ app/pixmaps/warning.png \ app/locale/fr/LC_MESSAGES/NUT-Monitor.mo \ app/locale/it/LC_MESSAGES/NUT-Monitor.mo \ app/locale/ru/LC_MESSAGES/NUT-Monitor.mo PYNUT_COMMON = \ module/README # Note: we both distribute and install the generated *.mo translation files # so they are listed above and not in NUT_MONITOR_COMMON_TEMPLATE NUT_MONITOR_COMMON_TEMPLATE = \ app/locale/NUT-Monitor.pot \ app/locale/fr/fr.po \ app/locale/it/it.po \ app/locale/ru/ru.po PYNUT_TEMPLATE = \ module/PyNUT.py.in \ module/test_nutclient.py.in PYNUT_GENERATED_NOEXEC = \ module/PyNUT.py PYNUT_GENERATED_SCRIPT = \ module/test_nutclient.py # For now, we have a "dispatcher" script and applet manifest, # to select a functional choice of the GUI client, if possible: NUT_MONITOR_DISPATCHER_NOEXEC = \ app/nut-monitor.desktop NUT_MONITOR_DISPATCHER_SCRIPT = \ app/NUT-Monitor ################################################################# # `make dist` tarball contents: EXTRA_DIST = $(NUT_MONITOR_DISPATCHER_NOEXEC) \ $(NUT_MONITOR_DISPATCHER_SCRIPT) $(NUT_MONITOR_COMMON) \ $(NUT_MONITOR_COMMON_TEMPLATE) $(PYNUT_COMMON) \ $(PYNUT_TEMPLATE) $(NUT_MONITOR_PY2GTK2) \ $(NUT_MONITOR_PY2GTK2_TEMPLATE) $(NUT_MONITOR_PY3QT5) \ $(NUT_MONITOR_PY3QT5_TEMPLATE) ################################################################# # `make install` handling (nobase_ to keep tree structure): # Make py2/py3-only builds, delivered preferred symlinks, etc. optional @WITH_NUT_MONITOR_TRUE@nutmonitordir = $(nut_with_nut_monitor_dir) @WITH_NUT_MONITOR_TRUE@nobase_nutmonitor_DATA = \ @WITH_NUT_MONITOR_TRUE@ $(NUT_MONITOR_DISPATCHER_NOEXEC) \ @WITH_NUT_MONITOR_TRUE@ $(NUT_MONITOR_COMMON) $(am__append_1) \ @WITH_NUT_MONITOR_TRUE@ $(am__append_3) $(am__append_5) @WITH_NUT_MONITOR_TRUE@nobase_nutmonitor_SCRIPTS = \ @WITH_NUT_MONITOR_TRUE@ $(NUT_MONITOR_DISPATCHER_SCRIPT) \ @WITH_NUT_MONITOR_TRUE@ $(am__append_2) $(am__append_4) \ @WITH_NUT_MONITOR_TRUE@ $(am__append_6) # Note lack of "$<" below - it is a non-portable GNU Make extension # The POT-Creation-Date: is removed by current python gettext builder to avoid # "spurious" changes that do not benefit (otherwise unmodified) contents; see: # https://github.com/sphinx-doc/sphinx/pull/3490 # https://github.com/sphinx-doc/sphinx/issues/3443 # Note that OUTFILE may be in builddir (not necessarily same as srcdir) @HAVE_MSGFMT_TRUE@@WITH_NUT_MONITOR_TRUE@ACT_MSGFMT = { \ @HAVE_MSGFMT_TRUE@@WITH_NUT_MONITOR_TRUE@ $(GREP) -v -E '^.?POT-Creation-Date: ' < "$${SRCFILE}" > "$${OUTFILE}.tmpsrc" && \ @HAVE_MSGFMT_TRUE@@WITH_NUT_MONITOR_TRUE@ $(MSGFMT) -o "$${OUTFILE}" "$${OUTFILE}.tmpsrc" && \ @HAVE_MSGFMT_TRUE@@WITH_NUT_MONITOR_TRUE@ rm -f "$${OUTFILE}.tmpsrc" ; \ @HAVE_MSGFMT_TRUE@@WITH_NUT_MONITOR_TRUE@} @WITH_NUT_MONITOR_TRUE@sysbindir = $(BINDIR) @WITH_NUT_MONITOR_TRUE@sysbin_SCRIPTS = NUT-Monitor # These are dumped into site-packages directly, right? @WITH_PYNUT_PY_TRUE@pynut_py_sitedir = $(PYTHON_SITE_PACKAGES) @WITH_PYNUT_PY_TRUE@pynut_py_site_DATA = $(PYNUT_GENERATED_NOEXEC) @WITH_PYNUT_PY_TRUE@pynut_py_site_SCRIPTS = $(PYNUT_GENERATED_SCRIPT) @WITH_PYNUT_PY2_TRUE@pynut_py2_sitedir = $(PYTHON2_SITE_PACKAGES) @WITH_PYNUT_PY2_TRUE@pynut_py2_site_DATA = $(PYNUT_GENERATED_NOEXEC) @WITH_PYNUT_PY2_TRUE@pynut_py2_site_SCRIPTS = $(PYNUT_GENERATED_SCRIPT) @WITH_PYNUT_PY3_TRUE@pynut_py3_sitedir = $(PYTHON3_SITE_PACKAGES) @WITH_PYNUT_PY3_TRUE@pynut_py3_site_DATA = $(PYNUT_GENERATED_NOEXEC) @WITH_PYNUT_PY3_TRUE@pynut_py3_site_SCRIPTS = $(PYNUT_GENERATED_SCRIPT) ################################################################# MAINTAINERCLEANFILES = Makefile.in .dirstamp all: all-am .SUFFIXES: $(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu scripts/python/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --gnu scripts/python/Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): install-nobase_nutmonitorSCRIPTS: $(nobase_nutmonitor_SCRIPTS) @$(NORMAL_INSTALL) @list='$(nobase_nutmonitor_SCRIPTS)'; test -n "$(nutmonitordir)" || list=; \ if test -n "$$list"; then \ echo " $(MKDIR_P) '$(DESTDIR)$(nutmonitordir)'"; \ $(MKDIR_P) "$(DESTDIR)$(nutmonitordir)" || exit 1; \ fi; \ $(am__nobase_strip_setup); \ for p in $$list; do \ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ if test -f "$$d$$p"; then echo "$$d$$p"; echo "$$p"; else :; fi; \ done | \ sed -e 'p;s,.*/,,;n' \ -e "s|$$srcdirstrip/||" -e 'h;s|[^/]*$$||; s|^$$|.|' \ -e 'p;x;s,.*/,,;$(transform)' | sed 'N;N;N;s,\n, ,g' | \ $(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1; } \ { d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \ if ($$2 == $$4) { files[d] = files[d] " " $$1; \ if (++n[d] == $(am__install_max)) { \ print "f", d, files[d]; n[d] = 0; files[d] = "" } } \ else { print "f", d "/" $$4, $$1 } } \ END { for (d in files) print "f", d, files[d] }' | \ while read type dir files; do \ case $$type in \ d) echo " $(MKDIR_P) '$(DESTDIR)$(nutmonitordir)/$$dir'"; \ $(MKDIR_P) "$(DESTDIR)$(nutmonitordir)/$$dir" || exit $$?;; \ f) \ if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \ test -z "$$files" || { \ echo " $(INSTALL_SCRIPT) $$files '$(DESTDIR)$(nutmonitordir)$$dir'"; \ $(INSTALL_SCRIPT) $$files "$(DESTDIR)$(nutmonitordir)$$dir" || exit $$?; \ } \ ;; esac \ ; done uninstall-nobase_nutmonitorSCRIPTS: @$(NORMAL_UNINSTALL) @list='$(nobase_nutmonitor_SCRIPTS)'; test -n "$(nutmonitordir)" || exit 0; \ $(am__nobase_strip_setup); \ files=`$(am__nobase_strip) \ -e 'h;s,.*/,,;$(transform);x;s|[^/]*$$||;G;s,\n,,'`; \ dir='$(DESTDIR)$(nutmonitordir)'; $(am__uninstall_files_from_dir) install-pynut_py2_siteSCRIPTS: $(pynut_py2_site_SCRIPTS) @$(NORMAL_INSTALL) @list='$(pynut_py2_site_SCRIPTS)'; test -n "$(pynut_py2_sitedir)" || list=; \ if test -n "$$list"; then \ echo " $(MKDIR_P) '$(DESTDIR)$(pynut_py2_sitedir)'"; \ $(MKDIR_P) "$(DESTDIR)$(pynut_py2_sitedir)" || exit 1; \ fi; \ for p in $$list; do \ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ if test -f "$$d$$p"; then echo "$$d$$p"; echo "$$p"; else :; fi; \ done | \ sed -e 'p;s,.*/,,;n' \ -e 'h;s|.*|.|' \ -e 'p;x;s,.*/,,;$(transform)' | sed 'N;N;N;s,\n, ,g' | \ $(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1; } \ { d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \ if ($$2 == $$4) { files[d] = files[d] " " $$1; \ if (++n[d] == $(am__install_max)) { \ print "f", d, files[d]; n[d] = 0; files[d] = "" } } \ else { print "f", d "/" $$4, $$1 } } \ END { for (d in files) print "f", d, files[d] }' | \ while read type dir files; do \ if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \ test -z "$$files" || { \ echo " $(INSTALL_SCRIPT) $$files '$(DESTDIR)$(pynut_py2_sitedir)$$dir'"; \ $(INSTALL_SCRIPT) $$files "$(DESTDIR)$(pynut_py2_sitedir)$$dir" || exit $$?; \ } \ ; done uninstall-pynut_py2_siteSCRIPTS: @$(NORMAL_UNINSTALL) @list='$(pynut_py2_site_SCRIPTS)'; test -n "$(pynut_py2_sitedir)" || exit 0; \ files=`for p in $$list; do echo "$$p"; done | \ sed -e 's,.*/,,;$(transform)'`; \ dir='$(DESTDIR)$(pynut_py2_sitedir)'; $(am__uninstall_files_from_dir) install-pynut_py3_siteSCRIPTS: $(pynut_py3_site_SCRIPTS) @$(NORMAL_INSTALL) @list='$(pynut_py3_site_SCRIPTS)'; test -n "$(pynut_py3_sitedir)" || list=; \ if test -n "$$list"; then \ echo " $(MKDIR_P) '$(DESTDIR)$(pynut_py3_sitedir)'"; \ $(MKDIR_P) "$(DESTDIR)$(pynut_py3_sitedir)" || exit 1; \ fi; \ for p in $$list; do \ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ if test -f "$$d$$p"; then echo "$$d$$p"; echo "$$p"; else :; fi; \ done | \ sed -e 'p;s,.*/,,;n' \ -e 'h;s|.*|.|' \ -e 'p;x;s,.*/,,;$(transform)' | sed 'N;N;N;s,\n, ,g' | \ $(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1; } \ { d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \ if ($$2 == $$4) { files[d] = files[d] " " $$1; \ if (++n[d] == $(am__install_max)) { \ print "f", d, files[d]; n[d] = 0; files[d] = "" } } \ else { print "f", d "/" $$4, $$1 } } \ END { for (d in files) print "f", d, files[d] }' | \ while read type dir files; do \ if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \ test -z "$$files" || { \ echo " $(INSTALL_SCRIPT) $$files '$(DESTDIR)$(pynut_py3_sitedir)$$dir'"; \ $(INSTALL_SCRIPT) $$files "$(DESTDIR)$(pynut_py3_sitedir)$$dir" || exit $$?; \ } \ ; done uninstall-pynut_py3_siteSCRIPTS: @$(NORMAL_UNINSTALL) @list='$(pynut_py3_site_SCRIPTS)'; test -n "$(pynut_py3_sitedir)" || exit 0; \ files=`for p in $$list; do echo "$$p"; done | \ sed -e 's,.*/,,;$(transform)'`; \ dir='$(DESTDIR)$(pynut_py3_sitedir)'; $(am__uninstall_files_from_dir) install-pynut_py_siteSCRIPTS: $(pynut_py_site_SCRIPTS) @$(NORMAL_INSTALL) @list='$(pynut_py_site_SCRIPTS)'; test -n "$(pynut_py_sitedir)" || list=; \ if test -n "$$list"; then \ echo " $(MKDIR_P) '$(DESTDIR)$(pynut_py_sitedir)'"; \ $(MKDIR_P) "$(DESTDIR)$(pynut_py_sitedir)" || exit 1; \ fi; \ for p in $$list; do \ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ if test -f "$$d$$p"; then echo "$$d$$p"; echo "$$p"; else :; fi; \ done | \ sed -e 'p;s,.*/,,;n' \ -e 'h;s|.*|.|' \ -e 'p;x;s,.*/,,;$(transform)' | sed 'N;N;N;s,\n, ,g' | \ $(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1; } \ { d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \ if ($$2 == $$4) { files[d] = files[d] " " $$1; \ if (++n[d] == $(am__install_max)) { \ print "f", d, files[d]; n[d] = 0; files[d] = "" } } \ else { print "f", d "/" $$4, $$1 } } \ END { for (d in files) print "f", d, files[d] }' | \ while read type dir files; do \ if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \ test -z "$$files" || { \ echo " $(INSTALL_SCRIPT) $$files '$(DESTDIR)$(pynut_py_sitedir)$$dir'"; \ $(INSTALL_SCRIPT) $$files "$(DESTDIR)$(pynut_py_sitedir)$$dir" || exit $$?; \ } \ ; done uninstall-pynut_py_siteSCRIPTS: @$(NORMAL_UNINSTALL) @list='$(pynut_py_site_SCRIPTS)'; test -n "$(pynut_py_sitedir)" || exit 0; \ files=`for p in $$list; do echo "$$p"; done | \ sed -e 's,.*/,,;$(transform)'`; \ dir='$(DESTDIR)$(pynut_py_sitedir)'; $(am__uninstall_files_from_dir) install-sysbinSCRIPTS: $(sysbin_SCRIPTS) @$(NORMAL_INSTALL) @list='$(sysbin_SCRIPTS)'; test -n "$(sysbindir)" || list=; \ if test -n "$$list"; then \ echo " $(MKDIR_P) '$(DESTDIR)$(sysbindir)'"; \ $(MKDIR_P) "$(DESTDIR)$(sysbindir)" || exit 1; \ fi; \ for p in $$list; do \ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ if test -f "$$d$$p"; then echo "$$d$$p"; echo "$$p"; else :; fi; \ done | \ sed -e 'p;s,.*/,,;n' \ -e 'h;s|.*|.|' \ -e 'p;x;s,.*/,,;$(transform)' | sed 'N;N;N;s,\n, ,g' | \ $(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1; } \ { d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \ if ($$2 == $$4) { files[d] = files[d] " " $$1; \ if (++n[d] == $(am__install_max)) { \ print "f", d, files[d]; n[d] = 0; files[d] = "" } } \ else { print "f", d "/" $$4, $$1 } } \ END { for (d in files) print "f", d, files[d] }' | \ while read type dir files; do \ if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \ test -z "$$files" || { \ echo " $(INSTALL_SCRIPT) $$files '$(DESTDIR)$(sysbindir)$$dir'"; \ $(INSTALL_SCRIPT) $$files "$(DESTDIR)$(sysbindir)$$dir" || exit $$?; \ } \ ; done uninstall-sysbinSCRIPTS: @$(NORMAL_UNINSTALL) @list='$(sysbin_SCRIPTS)'; test -n "$(sysbindir)" || exit 0; \ files=`for p in $$list; do echo "$$p"; done | \ sed -e 's,.*/,,;$(transform)'`; \ dir='$(DESTDIR)$(sysbindir)'; $(am__uninstall_files_from_dir) mostlyclean-libtool: -rm -f *.lo clean-libtool: -rm -rf .libs _libs install-nobase_nutmonitorDATA: $(nobase_nutmonitor_DATA) @$(NORMAL_INSTALL) @list='$(nobase_nutmonitor_DATA)'; test -n "$(nutmonitordir)" || list=; \ if test -n "$$list"; then \ echo " $(MKDIR_P) '$(DESTDIR)$(nutmonitordir)'"; \ $(MKDIR_P) "$(DESTDIR)$(nutmonitordir)" || exit 1; \ fi; \ $(am__nobase_list) | while read dir files; do \ xfiles=; for file in $$files; do \ if test -f "$$file"; then xfiles="$$xfiles $$file"; \ else xfiles="$$xfiles $(srcdir)/$$file"; fi; done; \ test -z "$$xfiles" || { \ test "x$$dir" = x. || { \ echo " $(MKDIR_P) '$(DESTDIR)$(nutmonitordir)/$$dir'"; \ $(MKDIR_P) "$(DESTDIR)$(nutmonitordir)/$$dir"; }; \ echo " $(INSTALL_DATA) $$xfiles '$(DESTDIR)$(nutmonitordir)/$$dir'"; \ $(INSTALL_DATA) $$xfiles "$(DESTDIR)$(nutmonitordir)/$$dir" || exit $$?; }; \ done uninstall-nobase_nutmonitorDATA: @$(NORMAL_UNINSTALL) @list='$(nobase_nutmonitor_DATA)'; test -n "$(nutmonitordir)" || list=; \ $(am__nobase_strip_setup); files=`$(am__nobase_strip)`; \ dir='$(DESTDIR)$(nutmonitordir)'; $(am__uninstall_files_from_dir) install-pynut_py2_siteDATA: $(pynut_py2_site_DATA) @$(NORMAL_INSTALL) @list='$(pynut_py2_site_DATA)'; test -n "$(pynut_py2_sitedir)" || list=; \ if test -n "$$list"; then \ echo " $(MKDIR_P) '$(DESTDIR)$(pynut_py2_sitedir)'"; \ $(MKDIR_P) "$(DESTDIR)$(pynut_py2_sitedir)" || exit 1; \ fi; \ for p in $$list; do \ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ echo "$$d$$p"; \ done | $(am__base_list) | \ while read files; do \ echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(pynut_py2_sitedir)'"; \ $(INSTALL_DATA) $$files "$(DESTDIR)$(pynut_py2_sitedir)" || exit $$?; \ done uninstall-pynut_py2_siteDATA: @$(NORMAL_UNINSTALL) @list='$(pynut_py2_site_DATA)'; test -n "$(pynut_py2_sitedir)" || list=; \ files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ dir='$(DESTDIR)$(pynut_py2_sitedir)'; $(am__uninstall_files_from_dir) install-pynut_py3_siteDATA: $(pynut_py3_site_DATA) @$(NORMAL_INSTALL) @list='$(pynut_py3_site_DATA)'; test -n "$(pynut_py3_sitedir)" || list=; \ if test -n "$$list"; then \ echo " $(MKDIR_P) '$(DESTDIR)$(pynut_py3_sitedir)'"; \ $(MKDIR_P) "$(DESTDIR)$(pynut_py3_sitedir)" || exit 1; \ fi; \ for p in $$list; do \ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ echo "$$d$$p"; \ done | $(am__base_list) | \ while read files; do \ echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(pynut_py3_sitedir)'"; \ $(INSTALL_DATA) $$files "$(DESTDIR)$(pynut_py3_sitedir)" || exit $$?; \ done uninstall-pynut_py3_siteDATA: @$(NORMAL_UNINSTALL) @list='$(pynut_py3_site_DATA)'; test -n "$(pynut_py3_sitedir)" || list=; \ files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ dir='$(DESTDIR)$(pynut_py3_sitedir)'; $(am__uninstall_files_from_dir) install-pynut_py_siteDATA: $(pynut_py_site_DATA) @$(NORMAL_INSTALL) @list='$(pynut_py_site_DATA)'; test -n "$(pynut_py_sitedir)" || list=; \ if test -n "$$list"; then \ echo " $(MKDIR_P) '$(DESTDIR)$(pynut_py_sitedir)'"; \ $(MKDIR_P) "$(DESTDIR)$(pynut_py_sitedir)" || exit 1; \ fi; \ for p in $$list; do \ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ echo "$$d$$p"; \ done | $(am__base_list) | \ while read files; do \ echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(pynut_py_sitedir)'"; \ $(INSTALL_DATA) $$files "$(DESTDIR)$(pynut_py_sitedir)" || exit $$?; \ done uninstall-pynut_py_siteDATA: @$(NORMAL_UNINSTALL) @list='$(pynut_py_site_DATA)'; test -n "$(pynut_py_sitedir)" || list=; \ files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ dir='$(DESTDIR)$(pynut_py_sitedir)'; $(am__uninstall_files_from_dir) tags TAGS: ctags CTAGS: cscope cscopelist: distdir: $(BUILT_SOURCES) $(MAKE) $(AM_MAKEFLAGS) distdir-am distdir-am: $(DISTFILES) @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ dist_files=`for file in $$list; do echo $$file; done | \ sed -e "s|^$$srcdirstrip/||;t" \ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ case $$dist_files in \ */*) $(MKDIR_P) `echo "$$dist_files" | \ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ sort -u` ;; \ esac; \ for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d "$(distdir)/$$file"; then \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ else \ test -f "$(distdir)/$$file" \ || cp -p $$d/$$file "$(distdir)/$$file" \ || exit 1; \ fi; \ done check-am: all-am check: check-am all-am: Makefile $(SCRIPTS) $(DATA) installdirs: for dir in "$(DESTDIR)$(nutmonitordir)" "$(DESTDIR)$(pynut_py2_sitedir)" "$(DESTDIR)$(pynut_py3_sitedir)" "$(DESTDIR)$(pynut_py_sitedir)" "$(DESTDIR)$(sysbindir)" "$(DESTDIR)$(nutmonitordir)" "$(DESTDIR)$(pynut_py2_sitedir)" "$(DESTDIR)$(pynut_py3_sitedir)" "$(DESTDIR)$(pynut_py_sitedir)"; do \ test -z "$$dir" || $(MKDIR_P) "$$dir"; \ done install: install-am install-exec: install-exec-am install-data: install-data-am uninstall: uninstall-am install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-am install-strip: if test -z '$(STRIP)'; then \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ install; \ else \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ fi mostlyclean-generic: clean-generic: distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." -test -z "$(MAINTAINERCLEANFILES)" || rm -f $(MAINTAINERCLEANFILES) clean: clean-am clean-am: clean-generic clean-libtool clean-local mostlyclean-am distclean: distclean-am -rm -f Makefile distclean-am: clean-am distclean-generic dvi: dvi-am dvi-am: html: html-am html-am: info: info-am info-am: install-data-am: install-nobase_nutmonitorDATA \ install-nobase_nutmonitorSCRIPTS install-pynut_py2_siteDATA \ install-pynut_py2_siteSCRIPTS install-pynut_py3_siteDATA \ install-pynut_py3_siteSCRIPTS install-pynut_py_siteDATA \ install-pynut_py_siteSCRIPTS install-sysbinSCRIPTS install-dvi: install-dvi-am install-dvi-am: install-exec-am: install-html: install-html-am install-html-am: install-info: install-info-am install-info-am: install-man: install-pdf: install-pdf-am install-pdf-am: install-ps: install-ps-am install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-am -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-am mostlyclean-am: mostlyclean-generic mostlyclean-libtool pdf: pdf-am pdf-am: ps: ps-am ps-am: uninstall-am: uninstall-nobase_nutmonitorDATA \ uninstall-nobase_nutmonitorSCRIPTS \ uninstall-pynut_py2_siteDATA uninstall-pynut_py2_siteSCRIPTS \ uninstall-pynut_py3_siteDATA uninstall-pynut_py3_siteSCRIPTS \ uninstall-pynut_py_siteDATA uninstall-pynut_py_siteSCRIPTS \ uninstall-sysbinSCRIPTS .MAKE: install-am install-strip .PHONY: all all-am check check-am clean clean-generic clean-libtool \ clean-local cscopelist-am ctags-am distclean distclean-generic \ distclean-libtool distdir dvi dvi-am html html-am info info-am \ install install-am install-data install-data-am install-dvi \ install-dvi-am install-exec install-exec-am install-html \ install-html-am install-info install-info-am install-man \ install-nobase_nutmonitorDATA install-nobase_nutmonitorSCRIPTS \ install-pdf install-pdf-am install-ps install-ps-am \ install-pynut_py2_siteDATA install-pynut_py2_siteSCRIPTS \ install-pynut_py3_siteDATA install-pynut_py3_siteSCRIPTS \ install-pynut_py_siteDATA install-pynut_py_siteSCRIPTS \ install-strip install-sysbinSCRIPTS installcheck \ installcheck-am installdirs maintainer-clean \ maintainer-clean-generic mostlyclean mostlyclean-generic \ mostlyclean-libtool pdf pdf-am ps ps-am tags-am uninstall \ uninstall-am uninstall-nobase_nutmonitorDATA \ uninstall-nobase_nutmonitorSCRIPTS \ uninstall-pynut_py2_siteDATA uninstall-pynut_py2_siteSCRIPTS \ uninstall-pynut_py3_siteDATA uninstall-pynut_py3_siteSCRIPTS \ uninstall-pynut_py_siteDATA uninstall-pynut_py_siteSCRIPTS \ uninstall-sysbinSCRIPTS .PRECIOUS: Makefile @HAVE_MSGFMT_TRUE@@WITH_NUT_MONITOR_TRUE@app/locale/fr/LC_MESSAGES/NUT-Monitor.mo: app/locale/fr/fr.po @HAVE_MSGFMT_TRUE@@WITH_NUT_MONITOR_TRUE@ @$(MKDIR_P) "$(builddir)/app/locale/fr/LC_MESSAGES" @HAVE_MSGFMT_TRUE@@WITH_NUT_MONITOR_TRUE@ SRCFILE="$^"; OUTFILE="$@"; $(ACT_MSGFMT) @HAVE_MSGFMT_TRUE@@WITH_NUT_MONITOR_TRUE@app/locale/it/LC_MESSAGES/NUT-Monitor.mo: app/locale/it/it.po @HAVE_MSGFMT_TRUE@@WITH_NUT_MONITOR_TRUE@ @$(MKDIR_P) "$(builddir)/app/locale/it/LC_MESSAGES" @HAVE_MSGFMT_TRUE@@WITH_NUT_MONITOR_TRUE@ SRCFILE="$^"; OUTFILE="$@"; $(ACT_MSGFMT) @HAVE_MSGFMT_TRUE@@WITH_NUT_MONITOR_TRUE@app/locale/ru/LC_MESSAGES/NUT-Monitor.mo: app/locale/ru/ru.po @HAVE_MSGFMT_TRUE@@WITH_NUT_MONITOR_TRUE@ @$(MKDIR_P) "$(builddir)/app/locale/ru/LC_MESSAGES" @HAVE_MSGFMT_TRUE@@WITH_NUT_MONITOR_TRUE@ SRCFILE="$^"; OUTFILE="$@"; $(ACT_MSGFMT) # Dummy redirector for /usr/bin/... presence @WITH_NUT_MONITOR_TRUE@NUT-Monitor: Makefile @WITH_NUT_MONITOR_TRUE@ @echo '#!/bin/sh' > "$@" @WITH_NUT_MONITOR_TRUE@ @echo 'exec "$(nutmonitordir)/app/NUT-Monitor" "$$@"' >> "$@" clean-local: $(AM_V_at)rm -rf *.pyc __pycache__ */*.pyc */__pycache__ */*/*.pyc */*/__pycache__ $(AM_V_at)rm -f NUT-Monitor # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: nut-2.8.1/scripts/python/app/0000755000175000017500000000000014520277777013143 500000000000000nut-2.8.1/scripts/python/app/locale/0000755000175000017500000000000014520277777014402 500000000000000nut-2.8.1/scripts/python/app/locale/it/0000755000175000017500000000000014520277777015016 500000000000000nut-2.8.1/scripts/python/app/locale/it/LC_MESSAGES/0000755000175000017500000000000014520277777016603 500000000000000nut-2.8.1/scripts/python/app/locale/it/LC_MESSAGES/NUT-Monitor.mo0000644000175000017500000001442714501607135021143 00000000000000H\a A!c{%947I/ '9 Xf vi$ bB     \ &l . ' !  2 K    ! / 7 +; g l z        * 08 i t        ! <!C^# "8H/\;WSk3| )0J'^v,k*"$x240# >HhG Vdy 9  )>"Nq T!>\qx   )%$*):FH8<E '.+6 5?%3AG,@#07B ;&=(>"2 C4/9 !1D- Please select the favorite that you want to delete from list... (no battery protection)%H hours %M minutes %S seconds%M minutes %S seconds%M minutes %S secondsNot connectedAre you sure that you want to remove this favorite ?Are you sure that you want to send '%s' to the device ?Battery charge :Battery voltage :Boost (UPS is boosting incoming voltage)Connected to '{0}' on {1}Current load :Device '%s' not found on serverDevice : Device commands :Device is running on batteriesDevice statusDevice status :Device varsDisconnected from '%s'Disconnecting from deviceEnter a name for this favorite You cannot re-use a name from another entry Enter a new value for the variable. Enter a new value for the variable. {0} = {1} (current value)Error connecting to '{0}' {1}Error connecting to '{0}' ({1})Error from '{0}' {1}Error from '{0}' ({1})Error parsing favorites, password for '%s' is not in base64 Skipping password for this entryError updating variable on '{0}' ({1})Error while creating configuration folder (%s)Error while parsing favorites file (%s)Error while saving favorites (%s)F_avoritesFailed to send '{0}' ({1})Found {0} devices on {1}GUI to manage devices connected a NUT server. For more information about NUT (Network UPS Tools) please visit the author's website. https://www.networkupstools.org Host / Port : Loaded '%s'Login / Password : Low batteriesModel :N/ANo variable modified on %s - User cancelledNoneNot availableOfflineOn batteriesOnlineOverloaded !Performing runtime calibrationRemaining time :Removed favorite '%s'Replace batteries !Saved favorites...Sent '{0}' command to {1}Temperature :Triming (UPS is triming incoming voltage)UPS load :Updated variable on %sUse authenticationValueVar nameWelcome to NUT Monitorchargingdischarginglabelnot providing power to the loadthere is too much load for deviceProject-Id-Version: NUT Monitor Report-Msgid-Bugs-To: PO-Revision-Date: 2013-10-14 22:50+0200 Last-Translator: Daniele Pezzini Language-Team: Italian Language: it MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Plural-Forms: nplurals=2; plural=(n != 1); Per favore scegli il preferito che vuoi cancellare dalla lista... (nessuna protezione dalle batterie)%H ore %M minuti %S secondi%M minuti %S secondi%M minuti %S secondiNon connessoSei sicuro di voler rimuovere questo preferito?Sei sicuro di voler inviare il comando '%s' al dispositivo?Carica della batteria :Voltaggio della batteria :Potenziamento (il gruppo di continutà sta potenziando il voltaggio in ingresso)Connesso a '{0}' su {1}Carico attuale :Il dispositivo '%s' non è stato trovato sul serverDispositivo :Comandi del dispositivo :Il dispositivo sta funzionando a batteriaStato del dispositivoStato del dispositivo :Variabili del dispositivoDisconnesso da '%s'Disconnessione dal dispositivo in corsoInserisci un nome per questo preferito Non puoi usare lo stesso nome per più preferiti Inserisci un nuovo valore per la variabile. Inserisci un nuovo valore per la variabile. {0} = {1} (valore attuale)Errore nel connettersi a '{0}' {1}Errore nel connettersi a '{0}' ({1})Errore da '{0}' {1}Errore da '{0}' ({1})Errore nel processare i preferiti, la password per '%s' non è in base64 La password per questo preferito verrà saltataErrore nell'aggiornare la variabile su '{0}' ({1})Errore nel creare la cartella di configurazione (%s)Errore nel processare il file dei preferiti (%s)Errore nel salvare i preferiti (%s)PreferitiErrore nell'inviare '{0}' ({1})Trovati {0} dispositivi su {1}Interfaccia grafica per gestire dispositivi connessi a un server di NUT. Per maggiori informazioni su NUT (Network UPS Tools) si visiti il sito dell'autore. https://www.networkupstools.org Host / Porta :Caricato '%s'Utente / Password : Batterie scaricheModello :N/DNessuna variabile modificata su %s - Operazione annullataNessunoNon disponibileSpentoA batteriaIn lineaSovraccarico!Calibrazione dell'autonomia in esecuzioneTempo rimasto :Il preferito '%s' è stato rimossoCambia le batterie!Preferiti salvati...Inviato il comando '{0}' a {1}Temperatura :Smorzamento (il gruppo di continuità sta smorzando il voltaggio in ingresso)Carico del gruppo di continutà :Aggiornata la variabile su %sUsa l'autenticazioneValoreNome della variabileBenvenuto in NUT Monitorin ricaricain scaricaetichettanon viene fornita alimentazione al caricoc'è troppo carico per il dispositivonut-2.8.1/scripts/python/app/locale/it/it.po0000644000175000017500000002256314501607135015702 00000000000000# Italian translations for PACKAGE package. # Copyright (C) 2013 THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the PACKAGE package. # Daniele Pezzini , 2013. # msgid "" msgstr "" "Project-Id-Version: NUT Monitor\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2013-10-14 22:47+0200\n" "PO-Revision-Date: 2013-10-14 22:50+0200\n" "Last-Translator: Daniele Pezzini \n" "Language-Team: Italian\n" "Language: it\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" #: NUT-Monitor:150 msgid "Var name" msgstr "Nome della variabile" #: NUT-Monitor:158 msgid "Value" msgstr "Valore" #: NUT-Monitor:205 msgid "Welcome to NUT Monitor" msgstr "Benvenuto in NUT Monitor" #: NUT-Monitor:304 #, python-brace-format msgid "Found {0} devices on {1}" msgstr "Trovati {0} dispositivi su {1}" #: NUT-Monitor:307 NUT-Monitor:664 #, python-brace-format msgid "Error connecting to '{0}' ({1})" msgstr "Errore nel connettersi a '{0}' ({1})" #: NUT-Monitor:315 msgid "Disconnecting from device" msgstr "Disconnessione dal dispositivo in corso" #: NUT-Monitor:380 msgid "Are you sure that you want to remove this favorite ?" msgstr "Sei sicuro di voler rimuovere questo preferito?" #: NUT-Monitor:388 #, python-format msgid "Removed favorite '%s'" msgstr "Il preferito '%s' è stato rimosso" #: NUT-Monitor:414 #, python-format msgid "Loaded '%s'" msgstr "Caricato '%s'" #: NUT-Monitor:422 #, python-format msgid "" "Are you sure that you want to send\n" "'%s' to the device ?" msgstr "" "Sei sicuro di voler inviare il comando\n" "'%s' al dispositivo?" #: NUT-Monitor:431 #, python-brace-format msgid "Sent '{0}' command to {1}" msgstr "Inviato il comando '{0}' a {1}" #: NUT-Monitor:434 #, python-brace-format msgid "Failed to send '{0}' ({1})" msgstr "Errore nell'inviare '{0}' ({1})" #: NUT-Monitor:452 #, python-brace-format msgid "" "Enter a new value for the variable.\n" "\n" "{0} = {1} (current value)" msgstr "" "Inserisci un nuovo valore per la variabile.\n" "\n" "{0} = {1} (valore attuale)" #: NUT-Monitor:466 #, python-format msgid "Updated variable on %s" msgstr "Aggiornata la variabile su %s" #: NUT-Monitor:474 #, python-brace-format msgid "Error updating variable on '{0}' ({1})" msgstr "Errore nell'aggiornare la variabile su '{0}' ({1})" #: NUT-Monitor:479 #, python-format msgid "No variable modified on %s - User cancelled" msgstr "Nessuna variabile modificata su %s - Operazione annullata" #: NUT-Monitor:558 #, python-format msgid "" "Error parsing favorites, password for '%s' is not in base64\n" "Skipping password for this entry" msgstr "" "Errore nel processare i preferiti, la password per '%s' non è in base64\n" "La password per questo preferito verrà saltata" #: NUT-Monitor:567 #, python-format msgid "Error while parsing favorites file (%s)" msgstr "Errore nel processare il file dei preferiti (%s)" #: NUT-Monitor:578 #, python-format msgid "Error while creating configuration folder (%s)" msgstr "Errore nel creare la cartella di configurazione (%s)" #: NUT-Monitor:590 msgid "Saved favorites..." msgstr "Preferiti salvati..." #: NUT-Monitor:593 #, python-format msgid "Error while saving favorites (%s)" msgstr "Errore nel salvare i preferiti (%s)" #: NUT-Monitor:665 #, python-brace-format msgid "" "Error connecting to '{0}'\n" "{1}" msgstr "" "Errore nel connettersi a '{0}'\n" "{1}" #: NUT-Monitor:673 NUT-Monitor:674 #, python-format msgid "Device '%s' not found on server" msgstr "Il dispositivo '%s' non è stato trovato sul server" #: NUT-Monitor:708 #, python-brace-format msgid "Connected to '{0}' on {1}" msgstr "Connesso a '{0}' su {1}" #: NUT-Monitor:740 msgid "Not connected" msgstr "Non connesso" #: NUT-Monitor:750 #, python-format msgid "Disconnected from '%s'" msgstr "Disconnesso da '%s'" #: NUT-Monitor:772 msgid "Low batteries" msgstr "Batterie scariche" #: NUT-Monitor:773 msgid "Replace batteries !" msgstr "Cambia le batterie!" #: NUT-Monitor:774 msgid "(no battery protection)" msgstr "(nessuna protezione dalle batterie)" #: NUT-Monitor:775 msgid "Performing runtime calibration" msgstr "Calibrazione dell'autonomia in esecuzione" #: NUT-Monitor:776 msgid "Offline" msgstr "Spento" #: NUT-Monitor:776 msgid "not providing power to the load" msgstr "non viene fornita alimentazione al carico" #: NUT-Monitor:777 msgid "Overloaded !" msgstr "Sovraccarico!" #: NUT-Monitor:777 msgid "there is too much load for device" msgstr "c'è troppo carico per il dispositivo" #: NUT-Monitor:778 msgid "Triming (UPS is triming incoming voltage)" msgstr "Smorzamento (il gruppo di continuità sta smorzando il voltaggio in ingresso)" #: NUT-Monitor:779 msgid "Boost (UPS is boosting incoming voltage)" msgstr "Potenziamento (il gruppo di continutà sta potenziando il voltaggio in ingresso)" #: NUT-Monitor:792 msgid "Device status :" msgstr "Stato del dispositivo :" #: NUT-Monitor:795 msgid "Online" msgstr "In linea" #: NUT-Monitor:801 msgid "On batteries" msgstr "A batteria" #: NUT-Monitor:804 msgid "Device is running on batteries" msgstr "Il dispositivo sta funzionando a batteria" #: NUT-Monitor:817 msgid "discharging" msgstr "in scarica" #: NUT-Monitor:819 msgid "charging" msgstr "in ricarica" #: NUT-Monitor:825 msgid "Model :" msgstr "Modello :" #: NUT-Monitor:829 msgid "Temperature :" msgstr "Temperatura :" #: NUT-Monitor:833 msgid "Battery voltage :" msgstr "Voltaggio della batteria :" #: NUT-Monitor:844 gui-1.3.glade.h:11 msgid "Battery charge :" msgstr "Carica della batteria :" #: NUT-Monitor:847 NUT-Monitor:856 NUT-Monitor:868 msgid "Not available" msgstr "Non disponibile" #: NUT-Monitor:853 msgid "UPS load :" msgstr "Carico del gruppo di continutà :" #: NUT-Monitor:862 msgid "%H hours %M minutes %S seconds" msgstr "%H ore %M minuti %S secondi" #: NUT-Monitor:864 msgid "%M minutes %S seconds" msgstr "%M minuti %S secondi" #: NUT-Monitor:866 msgid "%M minutes %S seconds" msgstr "%M minuti %S secondi" #: NUT-Monitor:876 #, python-brace-format msgid "Error from '{0}' ({1})" msgstr "Errore da '{0}' ({1})" #: NUT-Monitor:877 #, python-brace-format msgid "" "Error from '{0}'\n" "{1}" msgstr "" "Errore da '{0}'\n" "{1}" #: gui-1.3.glade.h:1 msgid "NUT Monitor" msgstr "" #: gui-1.3.glade.h:2 msgid "_File" msgstr "" #: gui-1.3.glade.h:3 msgid "F_avorites" msgstr "Preferiti" #: gui-1.3.glade.h:4 msgid "Host / Port : " msgstr "Host / Porta :" #: gui-1.3.glade.h:5 msgid "Device : " msgstr "Dispositivo :" #: gui-1.3.glade.h:6 msgid "None" msgstr "Nessuno" #: gui-1.3.glade.h:7 msgid "Use authentication" msgstr "Usa l'autenticazione" #: gui-1.3.glade.h:8 msgid "Login / Password : " msgstr "Utente / Password : " #: gui-1.3.glade.h:9 msgid " NUT Server " msgstr "" #: gui-1.3.glade.h:10 msgid "label" msgstr "etichetta" #: gui-1.3.glade.h:12 msgid "Current load :" msgstr "Carico attuale :" #: gui-1.3.glade.h:13 msgid "Remaining time :" msgstr "Tempo rimasto :" #: gui-1.3.glade.h:14 msgid "N/A" msgstr "N/D" #: gui-1.3.glade.h:15 msgid "Device commands :" msgstr "Comandi del dispositivo :" #: gui-1.3.glade.h:16 msgid "Device status" msgstr "Stato del dispositivo" #: gui-1.3.glade.h:17 msgid "Device vars" msgstr "Variabili del dispositivo" #: gui-1.3.glade.h:18 msgid "" "Enter a name for this favorite\n" "\n" "You cannot re-use a name from another entry\n" msgstr "" "Inserisci un nome per questo preferito\n" "\n" "Non puoi usare lo stesso nome per più preferiti\n" #: gui-1.3.glade.h:22 msgid "" "\n" "Please select the favorite that you\n" "want to delete from list...\n" msgstr "" "\n" "Per favore scegli il preferito che\n" "vuoi cancellare dalla lista...\n" #: gui-1.3.glade.h:26 msgid "" msgstr "" #: gui-1.3.glade.h:27 msgid "Enter a new value for the variable.\n" msgstr "Inserisci un nuovo valore per la variabile.\n" #: gui-1.3.glade.h:29 msgid "Copyright (c) 2010 David Goncalves" msgstr "" #: gui-1.3.glade.h:30 msgid "" "GUI to manage devices connected a NUT server.\n" "\n" "For more information about NUT (Network UPS Tools)\n" "please visit the author's website.\n" "\n" "https://www.networkupstools.org\n" msgstr "" "Interfaccia grafica per gestire dispositivi connessi a un server di NUT.\n" "\n" "Per maggiori informazioni su NUT (Network UPS Tools)\n" "si visiti il sito dell'autore.\n" "\n" "https://www.networkupstools.org\n" #: gui-1.3.glade.h:37 msgid "http://www.lestat.st" msgstr "" #: gui-1.3.glade.h:38 msgid "" "Copyright (C) 2010 David Goncalves \n" "\n" "This program is free software: you can redistribute it and/or modify\n" "it under the terms of the GNU General Public License as published by\n" "the Free Software Foundation; either version 3 of the License, or\n" "(at your option) any later version.\n" "\n" "This program is distributed in the hope that it will be useful,\n" "but WITHOUT ANY WARRANTY; without even the implied warranty of\n" "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n" "GNU General Public License for more details.\n" "\n" "You should have received a copy of the GNU General Public License\n" "along with this program. If not, see ." msgstr "" nut-2.8.1/scripts/python/app/locale/ru/0000755000175000017500000000000014520277777015030 500000000000000nut-2.8.1/scripts/python/app/locale/ru/LC_MESSAGES/0000755000175000017500000000000014520277777016615 500000000000000nut-2.8.1/scripts/python/app/locale/ru/LC_MESSAGES/NUT-Monitor.mo0000644000175000017500000002172214501607135021151 00000000000000NkA %=9Z47'/9i" @ O o y     i $o b   5 J \a & . '!< ^iD S_ s +    1G[n 0  "( 1=RX!xg&2Y"b9 Q\O-%U&V}"!:A\&9!$9'^.?0h2EKC<>).V* Z \ c y   ) / $!!B!&d!2!!U!.")H"r"""." """ # #^*#H#BICEDN<(%417.-&H*F?LGKJ+)@;!=82: 936 '$ "/A 5#M0,> Please select the favorite that you want to delete from list... NUT Server (no battery protection)%H hours %M minutes %S seconds%M minutes %S seconds%M minutes %S secondsNot connectedAre you sure that you want to remove this favorite ?Are you sure that you want to send '%s' to the device ?Battery charge :Battery voltage :Boost (UPS is boosting incoming voltage)Connected to '{0}' on {1}Copyright (C) 2010 David Goncalves 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 .Copyright (c) 2010 David GoncalvesCurrent load :Device '%s' not found on serverDevice : Device commands :Device is running on batteriesDevice statusDevice status :Device varsDisconnected from '%s'Disconnecting from deviceEnter a name for this favorite You cannot re-use a name from another entry Enter a new value for the variable. Enter a new value for the variable. {0} = {1} (current value)Error connecting to '{0}' {1}Error connecting to '{0}' ({1})Error from '{0}' {1}Error from '{0}' ({1})Error parsing favorites, password for '%s' is not in base64 Skipping password for this entryError updating variable on '{0}' ({1})Error while creating configuration folder (%s)Error while parsing favorites file (%s)Error while saving favorites (%s)F_avoritesFailed to send '{0}' ({1})Found {0} devices on {1}GUI to manage devices connected a NUT server. For more information about NUT (Network UPS Tools) please visit the author's website. https://www.networkupstools.org Host / Port : Loaded '%s'Login / Password : Low batteriesModel :N/ANUT MonitorNo variable modified on %s - User cancelledNoneNot availableOfflineOn batteriesOnlineOverloaded !Performing runtime calibrationRemaining time :Removed favorite '%s'Replace batteries !Saved favorites...Sent '{0}' command to {1}Temperature :Triming (UPS is triming incoming voltage)UPS load :Updated variable on %sUse authenticationValueVar nameWelcome to NUT Monitor_Filechargingdischarginghttp://www.lestat.stlabelnot providing power to the loadthere is too much load for deviceProject-Id-Version: NUT Monitor Report-Msgid-Bugs-To: PO-Revision-Date: 2020-10-08 23:16+0300 Last-Translator: Alexey Rodionov Language-Team: Russian Language: ru MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Укажите закладку, которую Вы хотите удалить из списка... Сервер NUT (нет защиты батареей)<Нет>%H ч.%M мин. %S сек.%M мин. %S сек.%M мин. %S сек.Не подключеноВы уверены, что хотите удалить эту закладку ?Вы уверены, что хотите отправить '%s' на устройство ?Уровень заряда батарей : Напряжение батарей :Повышение (ИБП повышает входящее напряжение)Подключено к '{0}' на {1}Copyright (C) 2010 David Goncalves 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 .Copyright (c) 2010 David GoncalvesТекущая нагрузка :Устройство '%s' не найдено на сервереУстройство : Команды устройства : Устройство работает от батарейСтатус устройстваСтатус устройства : Параметры устройстваОтключено от '%s'Отключение от устройстваВведите название для этой закладки Вы не можете повторно использовать имя другой закладки Введите новое значение параметра. Введите новое значение параметра. {0} = {1} (текущее значение)Ошибка подключения к '{0}' {1}Ошибка подключения к '{0}' ({1})Ошибка от '{0}' {1}Ошибка от '{0}' ({1})Ошибка разбора закладок, пароль для '%s' не в формате base64 Пропускаем пароль для этой записиОшибка обновления параметра на '{0}' ({1})Ошибка при создании каталога настроек (%s)Ошибка при разборе файла закладок (%s)Ошибка при сохранении закладок (%s)_ЗакладкиОшибка отправки '{0}' ({1})Найдено {0} устройств на {1}Графическая утилита управления устройствами, подключенными к серверу NUT. Для получения дополнительной информации о NUT (Network UPS Tools) пожалуйста посетите веб-сайт проекта. https://www.networkupstools.org Хост / Порт : Загружено '%s'Имя / Пароль : Низкий зарядМодель : N/ANUT MonitorПараметр на %s не изменён - отменено пользователемНетНе доступноВыключенОт батарейОт сетиПерегрузка !Выполнение калибровкиВремя автономной работы : Закладка '%s' удаленаЗамените батареи !Закладки сохранены...Отправлена команда '{0}' на {1}Температура : Отсечение (ИБП обрезает входящее напряжение)Нагрузка ИБП :Обновлён параметр на %sАутентификацияЗначениеПараметрДобро пожаловать в NUT Monitor_Файлзарядкаразрядкаhttp://www.lestat.stметкане обеспечено должного уровня питания для нагрузкислишком большая нагрузка на устройствоnut-2.8.1/scripts/python/app/locale/ru/ru.po0000644000175000017500000002634714501607135015732 00000000000000# Russian translations for NUT-Monitor. # Copyright (C) 2020 Alexey Rodionov (RED SOFT, Russia) # This file is distributed under the same license as the NUT package. # Alexey Rodionov , 2020 msgid "" msgstr "" "Project-Id-Version: NUT Monitor\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2013-10-15 20:35+0200\n" "PO-Revision-Date: 2020-10-08 23:16+0300\n" "Last-Translator: Alexey Rodionov \n" "Language-Team: Russian\n" "Language: ru\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: NUT-Monitor:150 msgid "Var name" msgstr "Параметр" #: NUT-Monitor:158 msgid "Value" msgstr "Значение" #: NUT-Monitor:205 msgid "Welcome to NUT Monitor" msgstr "Добро пожаловать в NUT Monitor" #: NUT-Monitor:304 #, python-brace-format msgid "Found {0} devices on {1}" msgstr "Найдено {0} устройств на {1}" #: NUT-Monitor:307 NUT-Monitor:664 #, python-brace-format msgid "Error connecting to '{0}' ({1})" msgstr "Ошибка подключения к '{0}' ({1})" #: NUT-Monitor:315 msgid "Disconnecting from device" msgstr "Отключение от устройства" #: NUT-Monitor:380 msgid "Are you sure that you want to remove this favorite ?" msgstr "Вы уверены, что хотите удалить эту закладку ?" #: NUT-Monitor:388 #, python-format msgid "Removed favorite '%s'" msgstr "Закладка '%s' удалена" #: NUT-Monitor:414 #, python-format msgid "Loaded '%s'" msgstr "Загружено '%s'" #: NUT-Monitor:422 #, python-format msgid "" "Are you sure that you want to send\n" "'%s' to the device ?" msgstr "" "Вы уверены, что хотите отправить\n" "'%s' на устройство ?" #: NUT-Monitor:431 #, python-brace-format msgid "Sent '{0}' command to {1}" msgstr "Отправлена команда '{0}' на {1}" #: NUT-Monitor:434 #, python-brace-format msgid "Failed to send '{0}' ({1})" msgstr "Ошибка отправки '{0}' ({1})" #: NUT-Monitor:452 #, python-brace-format msgid "" "Enter a new value for the variable.\n" "\n" "{0} = {1} (current value)" msgstr "" "Введите новое значение параметра.\n" "\n" "{0} = {1} (текущее значение)" #: NUT-Monitor:466 #, python-format msgid "Updated variable on %s" msgstr "Обновлён параметр на %s" #: NUT-Monitor:474 #, python-brace-format msgid "Error updating variable on '{0}' ({1})" msgstr "Ошибка обновления параметра на '{0}' ({1})" #: NUT-Monitor:479 #, python-format msgid "No variable modified on %s - User cancelled" msgstr "Параметр на %s не изменён - отменено пользователем" #: NUT-Monitor:558 #, python-format msgid "" "Error parsing favorites, password for '%s' is not in base64\n" "Skipping password for this entry" msgstr "" "Ошибка разбора закладок, пароль для '%s' не в формате base64\n" "Пропускаем пароль для этой записи" #: NUT-Monitor:567 #, python-format msgid "Error while parsing favorites file (%s)" msgstr "Ошибка при разборе файла закладок (%s)" #: NUT-Monitor:578 #, python-format msgid "Error while creating configuration folder (%s)" msgstr "Ошибка при создании каталога настроек (%s)" #: NUT-Monitor:590 msgid "Saved favorites..." msgstr "Закладки сохранены..." #: NUT-Monitor:593 #, python-format msgid "Error while saving favorites (%s)" msgstr "Ошибка при сохранении закладок (%s)" #: NUT-Monitor:665 #, python-brace-format msgid "" "Error connecting to '{0}'\n" "{1}" msgstr "" "Ошибка подключения к '{0}'\n" "{1}" #: NUT-Monitor:673 NUT-Monitor:674 #, python-format msgid "Device '%s' not found on server" msgstr "Устройство '%s' не найдено на сервере" #: NUT-Monitor:708 #, python-brace-format msgid "Connected to '{0}' on {1}" msgstr "Подключено к '{0}' на {1}" #: NUT-Monitor:740 msgid "Not connected" msgstr "Не подключено" #: NUT-Monitor:750 #, python-format msgid "Disconnected from '%s'" msgstr "Отключено от '%s'" #: NUT-Monitor:772 msgid "Low batteries" msgstr "Низкий заряд" #: NUT-Monitor:773 msgid "Replace batteries !" msgstr "Замените батареи !" #: NUT-Monitor:774 msgid "(no battery protection)" msgstr "(нет защиты батареей)" #: NUT-Monitor:775 msgid "Performing runtime calibration" msgstr "Выполнение калибровки" #: NUT-Monitor:776 msgid "Offline" msgstr "Выключен" #: NUT-Monitor:776 msgid "not providing power to the load" msgstr "не обеспечено должного уровня питания для нагрузки" #: NUT-Monitor:777 msgid "Overloaded !" msgstr "Перегрузка !" #: NUT-Monitor:777 msgid "there is too much load for device" msgstr "слишком большая нагрузка на устройство" #: NUT-Monitor:778 msgid "Triming (UPS is triming incoming voltage)" msgstr "Отсечение (ИБП обрезает входящее напряжение)" #: NUT-Monitor:779 msgid "Boost (UPS is boosting incoming voltage)" msgstr "Повышение (ИБП повышает входящее напряжение)" #: NUT-Monitor:792 msgid "Device status :" msgstr "Статус устройства : " #: NUT-Monitor:795 msgid "Online" msgstr "От сети" #: NUT-Monitor:801 msgid "On batteries" msgstr "От батарей" #: NUT-Monitor:804 msgid "Device is running on batteries" msgstr "Устройство работает от батарей" #: NUT-Monitor:817 msgid "discharging" msgstr "разрядка" #: NUT-Monitor:819 msgid "charging" msgstr "зарядка" #: NUT-Monitor:825 msgid "Model :" msgstr "Модель : " #: NUT-Monitor:829 msgid "Temperature :" msgstr "Температура : " #: NUT-Monitor:833 msgid "Battery voltage :" msgstr "Напряжение батарей :" #: NUT-Monitor:844 gui-1.3.glade.h:11 msgid "Battery charge :" msgstr "Уровень заряда батарей : " #: NUT-Monitor:847 NUT-Monitor:856 NUT-Monitor:868 msgid "Not available" msgstr "Не доступно" #: NUT-Monitor:853 msgid "UPS load :" msgstr "Нагрузка ИБП :" #: NUT-Monitor:862 msgid "%H hours %M minutes %S seconds" msgstr "%H ч.%M мин. %S сек." #: NUT-Monitor:864 msgid "%M minutes %S seconds" msgstr "%M мин. %S сек." #: NUT-Monitor:866 msgid "%M minutes %S seconds" msgstr "%M мин. %S сек." #: NUT-Monitor:876 #, python-brace-format msgid "Error from '{0}' ({1})" msgstr "Ошибка от '{0}' ({1})" #: NUT-Monitor:877 #, python-brace-format msgid "" "Error from '{0}'\n" "{1}" msgstr "" "Ошибка от '{0}'\n" "{1}" #: gui-1.3.glade.h:1 msgid "NUT Monitor" msgstr "NUT Monitor" #: gui-1.3.glade.h:2 msgid "_File" msgstr "_Файл" #: gui-1.3.glade.h:3 msgid "F_avorites" msgstr "_Закладки" #: gui-1.3.glade.h:4 msgid "Host / Port : " msgstr "Хост / Порт : " #: gui-1.3.glade.h:5 msgid "Device : " msgstr "Устройство : " #: gui-1.3.glade.h:6 msgid "None" msgstr "Нет" #: gui-1.3.glade.h:7 msgid "Use authentication" msgstr "Аутентификация" #: gui-1.3.glade.h:8 msgid "Login / Password : " msgstr "Имя / Пароль : " #: gui-1.3.glade.h:9 msgid " NUT Server " msgstr " Сервер NUT " #: gui-1.3.glade.h:10 msgid "label" msgstr "метка" #: gui-1.3.glade.h:12 msgid "Current load :" msgstr "Текущая нагрузка :" #: gui-1.3.glade.h:13 msgid "Remaining time :" msgstr "Время автономной работы : " #: gui-1.3.glade.h:14 msgid "N/A" msgstr "N/A" #: gui-1.3.glade.h:15 msgid "Device commands :" msgstr "Команды устройства : " #: gui-1.3.glade.h:16 msgid "Device status" msgstr "Статус устройства" #: gui-1.3.glade.h:17 msgid "Device vars" msgstr "Параметры устройства" #: gui-1.3.glade.h:18 msgid "" "Enter a name for this favorite\n" "\n" "You cannot re-use a name from another entry\n" msgstr "" "Введите название для этой закладки\n" "\n" "Вы не можете повторно использовать имя другой закладки\n" #: gui-1.3.glade.h:22 msgid "" "\n" "Please select the favorite that you\n" "want to delete from list...\n" msgstr "" "\n" "Укажите закладку, которую Вы\n" "хотите удалить из списка...\n" #: gui-1.3.glade.h:26 msgid "" msgstr "<Нет>" #: gui-1.3.glade.h:27 msgid "Enter a new value for the variable.\n" msgstr "Введите новое значение параметра.\n" #: gui-1.3.glade.h:29 msgid "Copyright (c) 2010 David Goncalves" msgstr "Copyright (c) 2010 David Goncalves" #: gui-1.3.glade.h:30 msgid "" "GUI to manage devices connected a NUT server.\n" "\n" "For more information about NUT (Network UPS Tools)\n" "please visit the author's website.\n" "\n" "https://www.networkupstools.org\n" msgstr "" "Графическая утилита управления устройствами, подключенными к серверу NUT.\n" "\n" "Для получения дополнительной информации о NUT (Network UPS Tools)\n" "пожалуйста посетите веб-сайт проекта.\n" "\n" "https://www.networkupstools.org\n" #: gui-1.3.glade.h:37 msgid "http://www.lestat.st" msgstr "http://www.lestat.st" #: gui-1.3.glade.h:38 msgid "" "Copyright (C) 2010 David Goncalves \n" "\n" "This program is free software: you can redistribute it and/or modify\n" "it under the terms of the GNU General Public License as published by\n" "the Free Software Foundation; either version 3 of the License, or\n" "(at your option) any later version.\n" "\n" "This program is distributed in the hope that it will be useful,\n" "but WITHOUT ANY WARRANTY; without even the implied warranty of\n" "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n" "GNU General Public License for more details.\n" "\n" "You should have received a copy of the GNU General Public License\n" "along with this program. If not, see ." msgstr "" "Copyright (C) 2010 David Goncalves \n" "\n" "This program is free software: you can redistribute it and/or modify\n" "it under the terms of the GNU General Public License as published by\n" "the Free Software Foundation; either version 3 of the License, or\n" "(at your option) any later version.\n" "\n" "This program is distributed in the hope that it will be useful,\n" "but WITHOUT ANY WARRANTY; without even the implied warranty of\n" "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n" "GNU General Public License for more details.\n" "\n" "You should have received a copy of the GNU General Public License\n" "along with this program. If not, see ." nut-2.8.1/scripts/python/app/locale/fr/0000755000175000017500000000000014520277777015011 500000000000000nut-2.8.1/scripts/python/app/locale/fr/fr.po0000644000175000017500000002226114501607135015663 00000000000000# Italian translations for PACKAGE package. # Copyright (C) 2013 THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the PACKAGE package. # David Goncalves , 2010. # msgid "" msgstr "" "Project-Id-Version: NUT Monitor\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2013-10-14 22:47+0200\n" "PO-Revision-Date: 2013-10-14 22:50+0200\n" "Last-Translator: David Goncalves \n" "Language-Team: French\n" "Language: fr\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n > 1);\n" #: NUT-Monitor:150 msgid "Var name" msgstr "Variable" #: NUT-Monitor:158 msgid "Value" msgstr "Valeur" #: NUT-Monitor:205 msgid "Welcome to NUT Monitor" msgstr "Bienvenue dans NUT Monitor" #: NUT-Monitor:304 #, python-brace-format msgid "Found {0} devices on {1}" msgstr "{0} périphériques trouvés sur {1}" #: NUT-Monitor:307 NUT-Monitor:664 #, python-brace-format msgid "Error connecting to '{0}' ({1})" msgstr "Erreur de connexion sur '{0}' ({1})" #: NUT-Monitor:315 msgid "Disconnecting from device" msgstr "Déconnecté" #: NUT-Monitor:380 msgid "Are you sure that you want to remove this favorite ?" msgstr "Voulez vous vraiement supprimer ce favoris?" #: NUT-Monitor:388 #, python-format msgid "Removed favorite '%s'" msgstr "Favoris '%s' supprimé" #: NUT-Monitor:414 #, python-format msgid "Loaded '%s'" msgstr "Favoris '%s' chargé" #: NUT-Monitor:422 #, python-format msgid "" "Are you sure that you want to send\n" "'%s' to the device ?" msgstr "" "Voulez vous vraiement envoyer la commande\n" "'%s' au périphérique?" #: NUT-Monitor:431 #, python-brace-format msgid "Sent '{0}' command to {1}" msgstr "Commande '{0}' envoyée à {1}" #: NUT-Monitor:434 #, python-brace-format msgid "Failed to send '{0}' ({1})" msgstr "Echec de l'envoi de '{0}' ({1})" #: NUT-Monitor:452 #, python-brace-format msgid "" "Enter a new value for the variable.\n" "\n" "{0} = {1} (current value)" msgstr "" "Veuillez saisir la nouvelle valeur de la variable.\n" "\n" "{0} = {1} (valeure actuelle)" #: NUT-Monitor:466 #, python-format msgid "Updated variable on %s" msgstr "Variable modifié sur %s" #: NUT-Monitor:474 #, python-brace-format msgid "Error updating variable on '{0}' ({1})" msgstr "Erreur de mise à jour sur '{0}' ({1})" #: NUT-Monitor:479 #, python-format msgid "No variable modified on %s - User cancelled" msgstr "Pas de modification sur %s - Opération annulée" #: NUT-Monitor:558 #, python-format msgid "" "Error parsing favorites, password for '%s' is not in base64\n" "Skipping password for this entry" msgstr "" "Erreur de lecture des favoris sur l'entrée '%s'. Codage incorrect\n" "Favoris ignoré" #: NUT-Monitor:567 #, python-format msgid "Error while parsing favorites file (%s)" msgstr "Erreur de lecture du fichier de favoris (%s)" #: NUT-Monitor:578 #, python-format msgid "Error while creating configuration folder (%s)" msgstr "Erreur de création du dossier de configuration (%s)" #: NUT-Monitor:590 msgid "Saved favorites..." msgstr "Favoris enregistrés..." #: NUT-Monitor:593 #, python-format msgid "Error while saving favorites (%s)" msgstr "Erreur d'enregistrement des favoris (%s)" #: NUT-Monitor:665 #, python-brace-format msgid "" "Error connecting to '{0}'\n" "{1}" msgstr "" "Erreur de connexion sur '{0}'\n" "{1}" #: NUT-Monitor:673 NUT-Monitor:674 #, python-format msgid "Device '%s' not found on server" msgstr "'%s' n'existe pas sur le serveur" #: NUT-Monitor:708 #, python-brace-format msgid "Connected to '{0}' on {1}" msgstr "Connecté à '{0}' sur {1}" #: NUT-Monitor:740 msgid "Not connected" msgstr "Non connecté" #: NUT-Monitor:750 #, python-format msgid "Disconnected from '%s'" msgstr "Déconnecté de '%s'" #: NUT-Monitor:772 msgid "Low batteries" msgstr "Batteries faibles" #: NUT-Monitor:773 msgid "Replace batteries !" msgstr "Remplacer les batteries!" #: NUT-Monitor:774 msgid "(no battery protection)" msgstr "(pas de protection par batteries)" #: NUT-Monitor:775 msgid "Performing runtime calibration" msgstr "Calibration des batteries" #: NUT-Monitor:776 msgid "Offline" msgstr "Hors ligne" #: NUT-Monitor:776 msgid "not providing power to the load" msgstr "alimentation coupée" #: NUT-Monitor:777 msgid "Overloaded !" msgstr "Sovraccarico!" #: NUT-Monitor:777 msgid "there is too much load for device" msgstr "la puissance demandé est trop importante" #: NUT-Monitor:778 msgid "Triming (UPS is triming incoming voltage)" msgstr "Régulation (l'onduleur limite le courant d'alimentation)" #: NUT-Monitor:779 msgid "Boost (UPS is boosting incoming voltage)" msgstr "Compensation (l'onduleur compense le courant d'alimentation)" #: NUT-Monitor:792 msgid "Device status :" msgstr "Etat du périphérique :" #: NUT-Monitor:795 msgid "Online" msgstr "En ligne" #: NUT-Monitor:801 msgid "On batteries" msgstr "Sur batteries" #: NUT-Monitor:804 msgid "Device is running on batteries" msgstr "Fonctionnement sur batteries" #: NUT-Monitor:817 msgid "discharging" msgstr "en décharge" #: NUT-Monitor:819 msgid "charging" msgstr "en charge" #: NUT-Monitor:825 msgid "Model :" msgstr "Modèle :" #: NUT-Monitor:829 msgid "Temperature :" msgstr "Température :" #: NUT-Monitor:833 msgid "Battery voltage :" msgstr "Tension batteries :" #: NUT-Monitor:844 gui-1.3.glade.h:11 msgid "Battery charge :" msgstr "Charge des batteries :" #: NUT-Monitor:847 NUT-Monitor:856 NUT-Monitor:868 msgid "Not available" msgstr "Non disponible" #: NUT-Monitor:853 msgid "UPS load :" msgstr "Consommation :" #: NUT-Monitor:862 msgid "%H hours %M minutes %S seconds" msgstr "%H heures %M minutes %S secondes" #: NUT-Monitor:864 msgid "%M minutes %S seconds" msgstr "%M minutes %S secondes" #: NUT-Monitor:866 msgid "%M minutes %S seconds" msgstr "%M minutes %S secondes" #: NUT-Monitor:876 #, python-brace-format msgid "Error from '{0}' ({1})" msgstr "Erreur sur '{0}' ({1})" #: NUT-Monitor:877 #, python-brace-format msgid "" "Error from '{0}'\n" "{1}" msgstr "" "Erreur sur '{0}'\n" "{1}" #: gui-1.3.glade.h:1 msgid "NUT Monitor" msgstr "" #: gui-1.3.glade.h:2 msgid "_File" msgstr "_Fichier" #: gui-1.3.glade.h:3 msgid "F_avorites" msgstr "F_avoris" #: gui-1.3.glade.h:4 msgid "Host / Port : " msgstr "Serveur / Port :" #: gui-1.3.glade.h:5 msgid "Device : " msgstr "Périphérique :" #: gui-1.3.glade.h:6 msgid "None" msgstr "Aucun" #: gui-1.3.glade.h:7 msgid "Use authentication" msgstr "Authentification" #: gui-1.3.glade.h:8 msgid "Login / Password : " msgstr "Login / Mot de passe :" #: gui-1.3.glade.h:9 msgid " NUT Server " msgstr " Serveur NUT " #: gui-1.3.glade.h:10 msgid "label" msgstr "" #: gui-1.3.glade.h:12 msgid "Current load :" msgstr "Puissance consommé :" #: gui-1.3.glade.h:13 msgid "Remaining time :" msgstr "Temps restant :" #: gui-1.3.glade.h:14 msgid "N/A" msgstr "N/D" #: gui-1.3.glade.h:15 msgid "Device commands :" msgstr "Commandes disponibles :" #: gui-1.3.glade.h:16 msgid "Device status" msgstr "Etat du périphérique" #: gui-1.3.glade.h:17 msgid "Device vars" msgstr "Variables" #: gui-1.3.glade.h:18 msgid "" "Enter a name for this favorite\n" "\n" "You cannot re-use a name from another entry\n" msgstr "" "Veuillez choisir un nom pour ce favoris\n" "\n" "Vous ne pouvez pas ré-utiliser un nom existant\n" #: gui-1.3.glade.h:22 msgid "" "\n" "Please select the favorite that you\n" "want to delete from list...\n" msgstr "" "\n" "Veuillez selectionner le favoris que\n" "vous souhaitez supprimer de la liste...\n" #: gui-1.3.glade.h:26 msgid "" msgstr "" #: gui-1.3.glade.h:27 msgid "Enter a new value for the variable.\n" msgstr "Nouvelle valeur de cette variable.\n" #: gui-1.3.glade.h:29 msgid "Copyright (c) 2010 David Goncalves" msgstr "" #: gui-1.3.glade.h:30 msgid "" "GUI to manage devices connected a NUT server.\n" "\n" "For more information about NUT (Network UPS Tools)\n" "please visit the author's website.\n" "\n" "https://www.networkupstools.org\n" msgstr "" "Interface pour gérer les onduleurs connectés à un serveur NUT.\n" "\n" "Pour plus d'informations sur NUT (Network UPS Tools)\n" "veuillez consulter le site de l'auteur.\n" "\n" "https://www.networkupstools.org\n" #: gui-1.3.glade.h:37 msgid "http://www.lestat.st" msgstr "" #: gui-1.3.glade.h:38 msgid "" "Copyright (C) 2010 David Goncalves \n" "\n" "This program is free software: you can redistribute it and/or modify\n" "it under the terms of the GNU General Public License as published by\n" "the Free Software Foundation; either version 3 of the License, or\n" "(at your option) any later version.\n" "\n" "This program is distributed in the hope that it will be useful,\n" "but WITHOUT ANY WARRANTY; without even the implied warranty of\n" "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n" "GNU General Public License for more details.\n" "\n" "You should have received a copy of the GNU General Public License\n" "along with this program. If not, see ." msgstr "" nut-2.8.1/scripts/python/app/locale/fr/LC_MESSAGES/0000755000175000017500000000000014520277777016576 500000000000000nut-2.8.1/scripts/python/app/locale/fr/LC_MESSAGES/NUT-Monitor.mo0000644000175000017500000001416414501607135021134 00000000000000Ida0A1 s%9417f/  :DV u i$: b_     \, & . ' ! ) 4 O h   * > L T +X         - G 0U         !9>Nx !'':E+AC.r  ! :D Yvf#t!v#R&;4b,($;#: LV0Z   *Ba@p  (5)J%+*;I9=G (/,'7 6@&4BH-A$18EC <>)? #3! D 50:"2F. Please select the favorite that you want to delete from list... NUT Server (no battery protection)%H hours %M minutes %S seconds%M minutes %S seconds%M minutes %S secondsNot connectedAre you sure that you want to remove this favorite ?Are you sure that you want to send '%s' to the device ?Battery charge :Battery voltage :Boost (UPS is boosting incoming voltage)Connected to '{0}' on {1}Current load :Device '%s' not found on serverDevice : Device commands :Device is running on batteriesDevice statusDevice status :Device varsDisconnected from '%s'Disconnecting from deviceEnter a name for this favorite You cannot re-use a name from another entry Enter a new value for the variable. Enter a new value for the variable. {0} = {1} (current value)Error connecting to '{0}' {1}Error connecting to '{0}' ({1})Error from '{0}' {1}Error from '{0}' ({1})Error parsing favorites, password for '%s' is not in base64 Skipping password for this entryError updating variable on '{0}' ({1})Error while creating configuration folder (%s)Error while parsing favorites file (%s)Error while saving favorites (%s)F_avoritesFailed to send '{0}' ({1})Found {0} devices on {1}GUI to manage devices connected a NUT server. For more information about NUT (Network UPS Tools) please visit the author's website. https://www.networkupstools.org Host / Port : Loaded '%s'Login / Password : Low batteriesModel :N/ANo variable modified on %s - User cancelledNoneNot availableOfflineOn batteriesOnlineOverloaded !Performing runtime calibrationRemaining time :Removed favorite '%s'Replace batteries !Saved favorites...Sent '{0}' command to {1}Temperature :Triming (UPS is triming incoming voltage)UPS load :Updated variable on %sUse authenticationValueVar nameWelcome to NUT Monitor_Filechargingdischargingnot providing power to the loadthere is too much load for deviceProject-Id-Version: NUT Monitor Report-Msgid-Bugs-To: PO-Revision-Date: 2013-10-14 22:50+0200 Last-Translator: David Goncalves Language-Team: French Language: fr MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Plural-Forms: nplurals=2; plural=(n > 1); Veuillez selectionner le favoris que vous souhaitez supprimer de la liste... Serveur NUT (pas de protection par batteries)%H heures %M minutes %S secondes%M minutes %S secondes%M minutes %S secondesNon connectéVoulez vous vraiement supprimer ce favoris?Voulez vous vraiement envoyer la commande '%s' au périphérique?Charge des batteries :Tension batteries :Compensation (l'onduleur compense le courant d'alimentation)Connecté à '{0}' sur {1}Puissance consommé :'%s' n'existe pas sur le serveurPériphérique :Commandes disponibles :Fonctionnement sur batteriesEtat du périphériqueEtat du périphérique :VariablesDéconnecté de '%s'DéconnectéVeuillez choisir un nom pour ce favoris Vous ne pouvez pas ré-utiliser un nom existant Nouvelle valeur de cette variable. Veuillez saisir la nouvelle valeur de la variable. {0} = {1} (valeure actuelle)Erreur de connexion sur '{0}' {1}Erreur de connexion sur '{0}' ({1})Erreur sur '{0}' {1}Erreur sur '{0}' ({1})Erreur de lecture des favoris sur l'entrée '%s'. Codage incorrect Favoris ignoréErreur de mise à jour sur '{0}' ({1})Erreur de création du dossier de configuration (%s)Erreur de lecture du fichier de favoris (%s)Erreur d'enregistrement des favoris (%s)F_avorisEchec de l'envoi de '{0}' ({1}){0} périphériques trouvés sur {1}Interface pour gérer les onduleurs connectés à un serveur NUT. Pour plus d'informations sur NUT (Network UPS Tools) veuillez consulter le site de l'auteur. https://www.networkupstools.org Serveur / Port :Favoris '%s' chargéLogin / Mot de passe :Batteries faiblesModèle :N/DPas de modification sur %s - Opération annuléeAucunNon disponibleHors ligneSur batteriesEn ligneSovraccarico!Calibration des batteriesTemps restant :Favoris '%s' suppriméRemplacer les batteries!Favoris enregistrés...Commande '{0}' envoyée à {1}Température :Régulation (l'onduleur limite le courant d'alimentation)Consommation :Variable modifié sur %sAuthentificationValeurVariableBienvenue dans NUT Monitor_Fichieren chargeen déchargealimentation coupéela puissance demandé est trop importantenut-2.8.1/scripts/python/app/locale/NUT-Monitor.pot0000644000175000017500000001555114501607135017130 00000000000000# SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the PACKAGE package. # FIRST AUTHOR , YEAR. # #, fuzzy msgid "" msgstr "" "Project-Id-Version: NUT Monitor\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2013-10-15 20:35+0200\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" "Language: \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=CHARSET\n" "Content-Transfer-Encoding: 8bit\n" #: NUT-Monitor:150 msgid "Var name" msgstr "" #: NUT-Monitor:158 msgid "Value" msgstr "" #: NUT-Monitor:205 msgid "Welcome to NUT Monitor" msgstr "" #: NUT-Monitor:304 #, python-brace-format msgid "Found {0} devices on {1}" msgstr "" #: NUT-Monitor:307 NUT-Monitor:664 #, python-brace-format msgid "Error connecting to '{0}' ({1})" msgstr "" #: NUT-Monitor:315 msgid "Disconnecting from device" msgstr "" #: NUT-Monitor:380 msgid "Are you sure that you want to remove this favorite ?" msgstr "" #: NUT-Monitor:388 #, python-format msgid "Removed favorite '%s'" msgstr "" #: NUT-Monitor:414 #, python-format msgid "Loaded '%s'" msgstr "" #: NUT-Monitor:422 #, python-format msgid "" "Are you sure that you want to send\n" "'%s' to the device ?" msgstr "" #: NUT-Monitor:431 #, python-brace-format msgid "Sent '{0}' command to {1}" msgstr "" #: NUT-Monitor:434 #, python-brace-format msgid "Failed to send '{0}' ({1})" msgstr "" #: NUT-Monitor:452 #, python-brace-format msgid "" "Enter a new value for the variable.\n" "\n" "{0} = {1} (current value)" msgstr "" #: NUT-Monitor:466 #, python-format msgid "Updated variable on %s" msgstr "" #: NUT-Monitor:474 #, python-brace-format msgid "Error updating variable on '{0}' ({1})" msgstr "" #: NUT-Monitor:479 #, python-format msgid "No variable modified on %s - User cancelled" msgstr "" #: NUT-Monitor:558 #, python-format msgid "" "Error parsing favorites, password for '%s' is not in base64\n" "Skipping password for this entry" msgstr "" #: NUT-Monitor:567 #, python-format msgid "Error while parsing favorites file (%s)" msgstr "" #: NUT-Monitor:578 #, python-format msgid "Error while creating configuration folder (%s)" msgstr "" #: NUT-Monitor:590 msgid "Saved favorites..." msgstr "" #: NUT-Monitor:593 #, python-format msgid "Error while saving favorites (%s)" msgstr "" #: NUT-Monitor:665 #, python-brace-format msgid "" "Error connecting to '{0}'\n" "{1}" msgstr "" #: NUT-Monitor:673 NUT-Monitor:674 #, python-format msgid "Device '%s' not found on server" msgstr "" #: NUT-Monitor:708 #, python-brace-format msgid "Connected to '{0}' on {1}" msgstr "" #: NUT-Monitor:740 msgid "Not connected" msgstr "" #: NUT-Monitor:750 #, python-format msgid "Disconnected from '%s'" msgstr "" #: NUT-Monitor:772 msgid "Low batteries" msgstr "" #: NUT-Monitor:773 msgid "Replace batteries !" msgstr "" #: NUT-Monitor:774 msgid "(no battery protection)" msgstr "" #: NUT-Monitor:775 msgid "Performing runtime calibration" msgstr "" #: NUT-Monitor:776 msgid "Offline" msgstr "" #: NUT-Monitor:776 msgid "not providing power to the load" msgstr "" #: NUT-Monitor:777 msgid "Overloaded !" msgstr "" #: NUT-Monitor:777 msgid "there is too much load for device" msgstr "" #: NUT-Monitor:778 msgid "Triming (UPS is triming incoming voltage)" msgstr "" #: NUT-Monitor:779 msgid "Boost (UPS is boosting incoming voltage)" msgstr "" #: NUT-Monitor:792 msgid "Device status :" msgstr "" #: NUT-Monitor:795 msgid "Online" msgstr "" #: NUT-Monitor:801 msgid "On batteries" msgstr "" #: NUT-Monitor:804 msgid "Device is running on batteries" msgstr "" #: NUT-Monitor:817 msgid "discharging" msgstr "" #: NUT-Monitor:819 msgid "charging" msgstr "" #: NUT-Monitor:825 msgid "Model :" msgstr "" #: NUT-Monitor:829 msgid "Temperature :" msgstr "" #: NUT-Monitor:833 msgid "Battery voltage :" msgstr "" #: NUT-Monitor:844 gui-1.3.glade.h:11 msgid "Battery charge :" msgstr "" #: NUT-Monitor:847 NUT-Monitor:856 NUT-Monitor:868 msgid "Not available" msgstr "" #: NUT-Monitor:853 msgid "UPS load :" msgstr "" #: NUT-Monitor:862 msgid "%H hours %M minutes %S seconds" msgstr "" #: NUT-Monitor:864 msgid "%M minutes %S seconds" msgstr "" #: NUT-Monitor:866 msgid "%M minutes %S seconds" msgstr "" #: NUT-Monitor:876 #, python-brace-format msgid "Error from '{0}' ({1})" msgstr "" #: NUT-Monitor:877 #, python-brace-format msgid "" "Error from '{0}'\n" "{1}" msgstr "" #: gui-1.3.glade.h:1 msgid "NUT Monitor" msgstr "" #: gui-1.3.glade.h:2 msgid "_File" msgstr "" #: gui-1.3.glade.h:3 msgid "F_avorites" msgstr "" #: gui-1.3.glade.h:4 msgid "Host / Port : " msgstr "" #: gui-1.3.glade.h:5 msgid "Device : " msgstr "" #: gui-1.3.glade.h:6 msgid "None" msgstr "" #: gui-1.3.glade.h:7 msgid "Use authentication" msgstr "" #: gui-1.3.glade.h:8 msgid "Login / Password : " msgstr "" #: gui-1.3.glade.h:9 msgid " NUT Server " msgstr "" #: gui-1.3.glade.h:10 msgid "label" msgstr "" #: gui-1.3.glade.h:12 msgid "Current load :" msgstr "" #: gui-1.3.glade.h:13 msgid "Remaining time :" msgstr "" #: gui-1.3.glade.h:14 msgid "N/A" msgstr "" #: gui-1.3.glade.h:15 msgid "Device commands :" msgstr "" #: gui-1.3.glade.h:16 msgid "Device status" msgstr "" #: gui-1.3.glade.h:17 msgid "Device vars" msgstr "" #: gui-1.3.glade.h:18 msgid "" "Enter a name for this favorite\n" "\n" "You cannot re-use a name from another entry\n" msgstr "" #: gui-1.3.glade.h:22 msgid "" "\n" "Please select the favorite that you\n" "want to delete from list...\n" msgstr "" #: gui-1.3.glade.h:26 msgid "" msgstr "" #: gui-1.3.glade.h:27 msgid "Enter a new value for the variable.\n" msgstr "" #: gui-1.3.glade.h:29 msgid "Copyright (c) 2010 David Goncalves" msgstr "" #: gui-1.3.glade.h:30 msgid "" "GUI to manage devices connected a NUT server.\n" "\n" "For more information about NUT (Network UPS Tools)\n" "please visit the author's website.\n" "\n" "https://www.networkupstools.org\n" msgstr "" #: gui-1.3.glade.h:37 msgid "http://www.lestat.st" msgstr "" #: gui-1.3.glade.h:38 msgid "" "Copyright (C) 2010 David Goncalves \n" "\n" "This program is free software: you can redistribute it and/or modify\n" "it under the terms of the GNU General Public License as published by\n" "the Free Software Foundation; either version 3 of the License, or\n" "(at your option) any later version.\n" "\n" "This program is distributed in the hope that it will be useful,\n" "but WITHOUT ANY WARRANTY; without even the implied warranty of\n" "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n" "GNU General Public License for more details.\n" "\n" "You should have received a copy of the GNU General Public License\n" "along with this program. If not, see ." msgstr "" nut-2.8.1/scripts/python/app/nut-monitor.desktop0000644000175000017500000000050314500336654016733 00000000000000[Desktop Entry] Name=NUT Monitor Name[fr]=Moniteur NUT Comment=Network UPS Tools GUI client Comment[fr]=Client graphique pour NUT (Network UPS Tools) Comment[it]=Client grafico per NUT (Network UPS Tools) Categories=System;Monitor;HardwareSettings;Settings Exec=NUT-Monitor Icon=nut-monitor Terminal=false Type=Application nut-2.8.1/scripts/python/app/nut-monitor-py2gtk2.desktop0000644000175000017500000000055314500336654020240 00000000000000[Desktop Entry] Name=NUT Monitor Name[fr]=Moniteur NUT Comment=Network UPS Tools GUI client (Py2Gtk2) Comment[fr]=Client graphique pour NUT (Network UPS Tools, Py2Gtk2) Comment[it]=Client grafico per NUT (Network UPS Tools, Py2Gtk2) Categories=System;Monitor;HardwareSettings;Settings;GTK Exec=NUT-Monitor-py2gtk2 Icon=nut-monitor Terminal=false Type=Application nut-2.8.1/scripts/python/app/pixmaps/0000755000175000017500000000000014520277777014624 500000000000000nut-2.8.1/scripts/python/app/pixmaps/var-rw.png0000644000175000017500000000141414273170601016447 00000000000000PNG  IHDRasRGBbKGD pHYs  tIME 2IDAT8˝KTQ9Ν;3ꌣiBcj mZh-jm*hEA*hTJ, 4i1%3V3s{Z":RC78x56Ϯq*jnjj ˲>iL}8wl `bb v8H4n>\Ȉ:nRbf.̼y0>==;J5I&cfgw4WO3 U"=-LFhF X&^CK)J@$^xAQ<='i&er*Kt8x*m¼|GsHMG 56†2zQd^xRѮav!ԯtAG]vwsY7'" -d_K)0~P [*UUdl-l\E+HА҃l|~+z=!ƖB j,75A"D0hPK h+ VUK6yOG).rqBi>Ғ kcFCPVokw3WRH Bk+܌^f9m*P] }&r~reBP\7]ʡmeO$pqIENDB`nut-2.8.1/scripts/python/app/pixmaps/var-ro.png0000644000175000017500000000116314273170601016440 00000000000000PNG  IHDRasRGBbKGD pHYs"" GtIME 6Y,IDAT8˅kSQ?&归MG:D fM\]R/Һ\L]]By@˻Ř_{s{ KqzzJE~Ph ÇRjjQ š899wuJ2Vחk2n{^\.Fh0잟;Ƙ~/l6n,I+ D}?Z=ϋ(r$ֲK>GUWO?˾}lz^OY13nwkG ;ln9o3"ׅ OVͻ\$Yx*q~1ry*iտϢ*$vPbj5U]<3UR#K(Eb:&yDA")U]G TM[5,tZD # 0"κ`oVlLA c#"ADPj?{3@=uIENDB`nut-2.8.1/scripts/python/app/pixmaps/warning.png0000644000175000017500000000573714273170601016712 00000000000000PNG  IHDR00WbKGDC pHYs oy vpAg00W IDAThYl]u9ΗH)ɲ$kHcTEC^>Zt@X(nEAm_ C -N HELXeR$y>Kd/{{_ks}{_&&z/^Ф xG;4ԕbO"߽|XFgZ//Ԍx/ 5T>p5oe`b&^,~ iygbF1P{1!XF]dh|@c0Ef… $Ȇ*\Itmkz'!Yƭkff5@1_>].45+Aֆtz×p7BsNf088uS5) .x"maSߏKX9j5`D@dEjh\mDâ ! }<aC&fJ f\S9Kia1mE'tj@: icCY,,zL?1U9ms|-M zmC#.b*`yU(5J(S C.iRD_HHHBߥ@x-lyjd)Wο39 eDR lshH´AB$.7kc -[xM k8G),Yʌ-*v H &rH[j!YYW A"01P{ otiK Yݟw"PPqVy)z^&K`*`+ >HP<$>*b `%ƀNb&ƗBRJꗽteW/~cm$/:pCM%gݥ& _u1L4`jRh .*tx6wKJiPqYU3OF5LȴYga뺱o}Tw4#o,Y Nn`A>/k=[lzInooΰ˝ OjA9P`!([) [ `8׫ y4prHy&exd[RM׈oxPy LB6Ht)s҃ 0%hV:V$X^ۤ]E xOyʭ՘&ɼQܝ,PĥhV?J,{x-{)C'dd{ێm=݂p cXH~+(fu !b3k  IKxIJ?|Sf6qڊ`an\nuuS9i7|Sj$d18,&]VPL0c`T˨M X=R]$󜊮< zIY-` ؇NZ6BitoiVgv\6q37Sڟ TJh^mm $k!ƈ~R7V0pF?#Cxkk \3:H ؝Ҽڢq7ou~{4Ai.r,>GGKśSp[plOnmX<^*V:>DֵS=T U[irXh8 TMx[Y*Ne㊱֛v:cؼ-Wى#` e`Pf^cUp9a٪U$)FT_shq e[EWy7ܑ9Lz3"_XF?*bV뉱%Wꏿ_1ϣeWTm, v^HnKt-V|>#=`*~lL){sD/SX140b;tW֧]+nvO1tSc9"8Oy/l]W?> `oK*U[=e`I KtQ(GPBuGq)gѡW%tEXtcreate-date2009-06-25T15:11:27+04:00o%tEXtdate:create2009-08-21T01:23:01+04:00{L%tEXtdate:modify2009-08-21T01:23:01+04:00 %tEXtmodify-date2009-06-25T15:11:27+04:00ޔtEXtSoftwarewww.inkscape.org<IENDB`nut-2.8.1/scripts/python/app/pixmaps/on_line.png0000644000175000017500000000507614273170601016664 00000000000000PNG  IHDR00WsRGBbKGD pHYs  #utIME :-9O IDAThOqUuάHR")EI¥C'N`P  @n>0H\sK 8`Ħ@4HJ,H (Rr\L~U9tBVz=3^UU7||}|]niٟiK<<ɓ'NL=デz(e2ƅ Ν;7~Fڽt[^z%~iFQySN,[ŋW^~ ][YYR:ٳg:}4O=y_ÇtXZZܹs29p̙3={cduu{9^.9gyGt:\r'Oߎ=qc'8?O#U+Yҟs}\enopuaђ9!yr|4Hqϱ>V%cSvoq|k U *(np|bjoA܎t;;j\ɻo_#[/a"}%?`ߑ;!pppq4Z@.r],a=P[KXdRP3zu& \0,щ5!gP̰Rݶn@G U-pg&u S!J9)7g3$I:!LfKb \im& D\@q&01*5cGPqL@A1w<d 0qw#v Q%a85`BnNR hhlfV'+dwjXsOFw[Ƥ1$`nLVD& 8fJmC$4(e* cg̤t~Kۤ$27O}q$Jjd&|Tw;H $1κOHTx07x?&s _!HZ3Hnӆ ;B!HP̝F&1(8Nư15c2ak#EyeY2*\&t !ScuZ`Q|U%v .Fg;!U֍]C{R^ !@3PA>=s9G-rK!2Jqb)vATtKB(E cyAp(1v EQ׸8 "~f255S(5 :eGeG\["ŇPP\rk%@zQBnr,%rw-PH'ٷ(F"3lD@;2)Ԕccc5tq7Oמ9 "GgA!JA1"( ?8,)єҡ@pbݒQ%)]6P _o3{hޠ䏿N:J!BObS^` k 낂DE=lifC걁)*( (onkwo:4 ( OnVnmތV4@)bReΣteF2"A][g= @$(YpVYUB8,]Y٦^Ou&X\7z07;2}bSSmk(h4wںixq5H&[`jPS5L0w ٠DHe5Guv$g,-M(ąI s|H #*NDI(&T&9'&h"Z `l5,KFEz3RUcxLp&VatZ\a&"fdlVFjH^|_ɛ_ff&ұn&IVg3-ʨl?5m@ _<ؑ}y`fw_oT9Zzg+o۵ˋ.'-q6tl']!Z[boޣTڇ#O n0[Ce "o{৭%O||U]tIENDB`nut-2.8.1/scripts/python/app/pixmaps/on_battery.png0000644000175000017500000000551614273170601017406 00000000000000PNG  IHDR00WsRGBbKGD pHYs  #utIME ; IDATh]y}.s梙,Fȷklj ۸-Q ! ~`P J&4ȍDq,i4{9#@3Ѩ>}˳ւ__Q133+/ϫ:uT駟n,,,meG.\>w\ovx;>}o8;;{z||Vx677]7_Y}bcΟ?:^x^3>>< w9<^/wB̉'h6cPUx瘛( 1D熯ܤ^crr7n}gnc @UU !e%ȰV*UUl6ɲ]p)%ztgc! fНC$Zw")%*}<k41c'716٥ּdA|<@y\-굛@Rb0gTHWtTw=(%L衭g8IwxCAbb!R*EHd#= b AفA j(-R)?zpzЪ)RR=R "AL?ZzVC0F\$Υ?'|7XE( R0 EDk`?Caa`@\ĒKpJǀ~O@znYpP%aάG  m[)9ǵm.]6s?6!XJ NUT Monitor center battery True True True _File True True gtk-about True True True True gtk-quit True True True True F_avorites True True gtk-add True False True True gtk-delete True False True True True False 0 True True 0.5 in True 2 True True True 2 3 True 1 Host / Port : GTK_FILL True 1 Device : 1 2 GTK_FILL True True 1 2 True True 5 5 3493 0 65535 1 10 0 True 2 3 GTK_FILL True None 1 2 1 2 gtk-refresh True False True True True 2 3 1 2 GTK_FILL GTK_FILL False False 0 Use authentication True True False True False 1 True False True 1 Login / Password : 0 True True 1 True True False 2 False 2 True False 4 3 0 True gtk-connect True False True True True 0 gtk-disconnect True True True 1 False 1 True NUT Server True label_item False 0 True True True 2 True True gtk-missing-image 6 False 0 True 0 in True 2 2 2 2 True True 1 0 2 label right False 0 True 0 0 2 label 1 label_item 1 0 True 4 2 4 True 1 2 Battery charge : True right GTK_FILL True 1 2 Current load : True right 1 2 GTK_FILL True 1 2 True 1 2 1 2 True 1 2 Remaining time : right 2 3 GTK_FILL True 0 in True True N/A True label_item 1 2 2 3 True 1 2 Device commands : True right 3 4 GTK_FILL True gtk-execute True True True True False False 1 1 2 3 4 False 1 True 2 Device status False tab True 2 True 0 in True 1 1 1 1 True True automatic automatic True True label_item 0 gtk-refresh True True True True False 1 1 True Device vars 1 False tab 1 1 True 2 False 2 5 True center-always normal True 2 True 0 in True 4 4 4 4 True True Enter a name for this favorite <span color="#808080">You cannot re-use a name from another entry</span> True 0 True True False 1 label_item 1 True spread gtk-add 1 True False True True True False False 0 gtk-cancel True True True True False False 1 False end 0 5 True center-always normal True 2 True 0 in True 4 4 4 4 True True Please select the favorite that you want to delete from list... True 0 True 0 <None> False 1 label_item 1 True spread gtk-delete 1 True True True True False False 0 gtk-cancel True True True True False False 1 False end 0 5 True center-always normal True 2 True 0 in True 4 4 4 4 True True 4 True gtk-edit 6 False 4 0 True Enter a new value for the variable. True 2 1 0 True True False 1 label_item 1 True spread gtk-save 1 True True True True False False 0 gtk-cancel True True True True False False 1 False end 0 5 True center-always normal NUT-Monitor 1.3.1 Copyright (c) 2010 David Goncalves GUI to manage devices connected a NUT server. For more information about NUT (Network UPS Tools) please visit the author's website. https://www.networkupstools.org http://www.lestat.st/informatique/projets/nut-monitor-en http://www.lestat.st Copyright (C) 2010 David Goncalves <david@lestat.st> 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 <http://www.gnu.org/licenses/>. David Goncalves <david@lestat.st> David Goncalves <david@lestat.st> - Français Daniele Pezzini <hyouko@gmail.com> - Italiano True 2 True spread False end 0 nut-2.8.1/scripts/python/app/ui/dialog2.ui0000644000175000017500000000440114500336654015343 00000000000000 dialog2 0 0 229 116 Dialog true QFrame::StyledPanel QFrame::Raised Please select the favorite that you want to delete from list... true None Qt::Horizontal QDialogButtonBox::Cancel|QDialogButtonBox::Ok buttonBox accepted() dialog2 accept() 248 254 157 274 buttonBox rejected() dialog2 reject() 316 260 286 274 nut-2.8.1/scripts/python/app/ui/aboutdialog1.ui0000644000175000017500000000633514501607135016401 00000000000000 aboutdialog1 About NUT-Monitor true 0 0 0 0 <h1>NUT-Monitor 1.3.1</h1> <p>GUI to manage devices connected a NUT server.</p> <p>For more information about NUT (Network UPS Tools) please visit the author's website.</p> <p style="margin-bottom: 1.5em">https://www.networkupstools.org</p> <p style=" font-size:8pt;">Copyright (c) 2010 David Goncalves</p> <p><a href="http://www.lestat.st/informatique/projets/nut-monitor-en">http://www.lestat.st</a></p> Qt::RichText Qt::AlignCenter true true Qt::LinksAccessibleByKeyboard|Qt::LinksAccessibleByMouse|Qt::TextBrowserInteraction|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse Qt::Horizontal QDialogButtonBox::Ok buttonBox accepted() aboutdialog1 accept() 248 254 157 274 buttonBox rejected() aboutdialog1 reject() 316 260 286 274 nut-2.8.1/scripts/python/app/ui/window1.ui0000644000175000017500000003536514500336654015427 00000000000000 window1 0 0 560 465 NUT Monitor ../../../../../.designer/backup../../../../../.designer/backup NUT Server Qt::AlignCenter 0 0 0 0 65535 3493 Device : None Host / Port : false &Refresh Use authentication 0 0 0 0 Login / Password : QLineEdit::Password QFrame::HLine QFrame::Sunken false C&onnect &Disconnect 0 Device status 0 0 0 0 QFrame::StyledPanel QFrame::Raised 0 0 label Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter 0 0 label Remaining time : Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter Battery charge : Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter 24 Device commands : Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter 24 Current load : Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter QFrame::StyledPanel QFrame::Raised N/A Qt::AlignCenter 0 0 QComboBox::AdjustToContents &Execute Device vars QFrame::StyledPanel QFrame::Raised &Refresh 0 0 560 24 &File F&avorites &About &Quit Ctrl+Q false &Add false &Delete nut-2.8.1/scripts/python/app/ui/dialog1.ui0000644000175000017500000000420414500336654015343 00000000000000 dialog1 0 0 297 133 Dialog true QFrame::StyledPanel QFrame::Raised Enter a name for this favorite<br><br><font color="#808080">You cannot re-use a name from another entry</font> Qt::Horizontal QDialogButtonBox::Cancel|QDialogButtonBox::Ok buttonBox accepted() dialog1 accept() 248 254 157 274 buttonBox rejected() dialog1 reject() 316 260 286 274 nut-2.8.1/scripts/python/app/icons/0000755000175000017500000000000014520277777014256 500000000000000nut-2.8.1/scripts/python/app/icons/64x64/0000755000175000017500000000000014520277777015051 500000000000000nut-2.8.1/scripts/python/app/icons/64x64/nut-monitor.png0000644000175000017500000000513514500336654017762 00000000000000PNG  IHDR@@iqbKGD IDATxˏw?zܷy8Έ A#LxXX!Xb4*2HDf3 H)8@Āt܏}ΙEU[ vܯtnսs;50 30 30 aޫ~;Wa1( _{k n3/>1UWYcs&,bw ۤ]y=ZM۩-%W|Q4m?\Oq7C\|wD;غ`/:/p?~Cv!i{uwMhHs*߸{K+{qu?aGtBE4zu``_8k4^H&!Bԇh0w׃̭<_[Ƅa@apegpvSDQ&ۀ150u0M0Mǘ[{tKE4~0cz/bj3r2v+ELjc=Pk-8ᯢ2-!h⡀QxmS*8 W)ƝIWQC]XLVF=~y.\!RX;RtdY Z;ob(* *iMu"{hM4Dy$d!R7<g2ɗlpkU-&%7\&)þLCԥy (?*PiaT~L_%a,{ /Ȩ"*X;TEp 0nfyH|jq Z7UaOxNH{=dF)@/R@Qq?hl\uSNF$e7e Cں7sGW2sJB8>lFPXDTzn}ؓ'7J頇]+kأbyâ˭Z,T<%~ߢwnw_Q { )PU{/ j pعC"O :@'IA Tw7K dHVFt:$HfW۾y?l连uLޱ~pcXXXgx$^pENoy:EK{sʲYZ\QoP kAc0&4a0A@mX(kk'y9~ <_6'$䑐oF+7TP8az#ᮻG#gΘ'Oz+++lY'ZegY8sdYNv-666իW^8y_^B=2j~;~NF} 377gۭ6 Fy1A$qkf#/cM0οvȽOC@ BBXQ+C \XX;qĩNsV V \`Q *h,Jl#K.^t)˲<3.%+NQ3wDRLefhkyHV-[D9{$UQ\,ʽfaf6P}V;?IENDB`nut-2.8.1/scripts/python/app/icons/scalable/0000755000175000017500000000000014520277777016024 500000000000000nut-2.8.1/scripts/python/app/icons/scalable/nut-monitor.svg0000644000175000017500000005556214500336654020761 00000000000000 image/svg+xml Lapo Calamandrei Battery battery recharge power acpi apm nut-2.8.1/scripts/python/app/icons/256x256/0000755000175000017500000000000014520277777015217 500000000000000nut-2.8.1/scripts/python/app/icons/256x256/nut-monitor.png0000644000175000017500000004073414500336654020134 00000000000000PNG  IHDR\rfbKGD IDATxi%yv22 $1e!"(2dʢd&a;²-Ca)bi Pc0f^UdfUVVV{_^^<ѷ2++:[2.p  >9Dx#O 0 xU2>""|c?G| ~ _$?K[$A <9'? tKA/|"ikZXB=F7 %HD* hdG:!MRDL{79A|WqRH<1\"G> `n?8VXX'mz(hH !H!E&"L\`]#t!DC0|w x~ExK_B~OO3$'qKv[Wc k>Fs A$ jH A2͈/E!FR R ty!\0ԟX «^+REq 'N%)%<5D0~{95)Pd~.|`I0$FIjq0$ >Ct?}]Cz=#Iл:[a!E)F?;5`*8"b~QFaj8PR,ZX` jp#Ay#Ⱦ(r+U]˶ w}kZo`R/1Dߐ,z~[Gy"D`+x?A .#< q}/QTy/:q$4Y X bDCdRdR4{亜"cؿQ2xy)L}љ.<#~'D<"{S"n/>D2C4U>D -cq nc°wM.ю8<;qƻ۟ AX@;CsOq ih=fb~'h͡lE_𧷾8<h|shtsYߚ9,>Gљ_FknV{|`Š9w+\)H\V@BR{2]ǧCi2B@h6(Fc q!#4˘[H4D MFᅢ@rTydv?.>f+W:͙#e08 ;*h9$-čqcΣ,`Gs |=(n?}zoޓXVGKhq߄ǰv'r<'-@\[Vu6YEufֳm4^V 7"0P, F'0 9zGsDӈgςP>D NC E `z38eCq UëΠѹV':?tG 8vg"q(f(tٿu<3>' FP7-Pg ih1kZ6-7>QK"H/kJqz(UC}3u]/x@ܜGiøz1f̰?mu&qFHo o+|s^z9"yo^c~̌c8Gqk@m[7 Ko*Ϛ&Dz 2yt$M e0HF@2|>QV9#Cx]f +[􂁛!@:D"=xbJYߝsػ"DRzfϫ̄h.=!4/믖vX. u&9a~籟\xcQx|s:8<!mEROz`J-֌8x X@LjA =GIJ?+N"1HEh?hX~Y\^QP}QfF/tn/-W^Vn%*oYwB/©_@/"\we5$2AR 5HFHG}# It$!~>@:3v>1HCM#ט1EjFzNjS'sQT!Iؚ?9kyb|03<ؚu,‡ǧY[l<5o ~ I Qb¼/L9֮e!͙ocg%&?"uDJӿ$Čwyiaf~I)O ShĠ= "0ĠO ʺr2 xtjCŅ hh~*͗ ` ϱ+` ڃN*XMm! -r,#7$geDX~Czn[_[$ 0Q!M}Au2P0#U z/@&!~:<_ OBH2imx%T$Br$$ E{gA \cPi@WS`|րcS!HYmW'D`LUT}W"2Fd78&_!ILh-|`Wu*=0%zo q[e"ϓ+pA›{ iFtf< -*g -j x U-) 0p " 1R ۇCl@*Χ*g%ʴ 91G 2Jo& t_Z4ədtޚDzf-'^<,P>e&IhF3dFte%U!~&*:"k1N-*x"O/2 z !) Grt u`ƒ3} :%d1<=u}]9'4%H uc>o?6gX 케͜3/DF'}*Ihz5 8*W-Ez$%҄ PyRǜH@ip hK%!*'_uB=O_d}- =49 :4V_*URQn~Dy\~``_scF _C~B6ǔgd% O6jK7M+|+@^IR'3+ HT"M !!Md$)Lgtxp 2{1 = D[2E @tZ[> P#. D'S"EbBm@ry\eu< =E0Ti,L>A c|+|ϗhyL.ռr$R!  $#݆F%% 1D:dx hjb{}"ddI0VLd, wܞ6le M"~OMVj?} 8)T##X B ƛ j 2L7&J4a!@)R$E$WC H&MmѮ3 K?C\Hvtl^]mȓuk^XFp2#|Xa?ws2<cs:&N6=&͢Wg 9D$Ag}Rv!.C=2݃H!=eeKe7]$6cC oӾ} rה nf;[Oi>KH[⇲0e20XG>;)^ϙ/O&"@:!LrSfzOJPaq;F>j-sm> INAs}7ԸXZuɝ r2[Y̋d/:yu="@@jw{i}6|pJ l:bOL?}z˕+FڗqAyz& AU78r%^[O(%꼅*ǚR6 jӵʲe7AjnmGz>Ӵ"D&$GP!R!z>r G+ zw"qq~oc3 o޶b(Lg髈f֥.)O۵Η8/d\`xcsϣШOw`{US+$T ~~~Ux7sŧnN$ B91Xꢅĝ{ vN{RsMMU 8a7tz&T|uU HTfo%k{-md.{[gi[9guֱ~ Ӵw);d IDATPEqS{x)Su,`@9aȭf1mi u o>O di?JwqC5s+E@]]$8!f-so:"] w=mJ$ ũ8WoH)[KŅ/-P_ ||r|*π8mjH[9hWjƈ33p*wT7L9~05KV:SUaVDXf@U=_#s(lr^XzbU)L q @-m}V]H78Q1OYo$@}3s+ܿOb]byQYM.,#e9~O^a/[G` 5obs2Ncz6%o*$*\hm6)OiQ-kpA .̌ou/ MUTw.]o4q6!XbljET3ea ߾xs\Y3Ѭ,l`ɂ$7۶:quÒۿt:Ě|TlZrW{=öP^!:7nE7Y?똙qFm9$);Ppp&!{T`1T@97`6Updo=®5Tֹ3a:Q̶Ug3%'' B},_A#J'wcy:#p-;*U]ԑ,qm\U9;i3=I<ތjS8fNƁan`e7 TE;9n9*׶rVPq*_&Z@m/ӑj@1Z 1u/\] ~W cN4gi<or(Yl{W3$Hdqހ[O{NQmSn108~:;5Uu}V,\NP? K`[@Iwj};[G}o:k;'! ΙNg@eoV t'ENm4ӿ>:q[~پdɫLW'ak;g9[@RW8SUH@^`0,+ʁ$p@ ьzhD]QѵꄲwH_{X~{&lbU,uA77q},nn?jCR=I$ l;lYsj3$ιn>۲P@&z2@C4y ]k҅b;/5 ;YfRoBʦ1m (`&Nb$IC!d~ M5Y.{31<FUjަd DO4Z4⨇uG"SE1Hl{p:7@  VK4"DU ְ;X^w mEtA<)2OP(cfo2~SuG JԷB*[ Z\U=bCDλyଋr{`|̄ o@ Y#F";_i$a//Zr?;wg3eq5z 볚̤ϝ<}13X̪{6xzeKTQ*5c6CbrY X'WtywtN?ʉ>KQ T=FPg+̾iߚf-Wō\M,Kwd ' TU?ΐuB"CzB?b@T"Vy/Q=Yv^ʎ|+(T]7~oT13Lco̿5,c/%,ZҞ~#?I٪,,YAVؼeyq /CL9>48m fS/ry7v7F=B{\?z,{%Y?1ݦ8_L2fF& rR;䟭 u4GzcV*ݞ\aiK)ބ}BQEIn"fF Zݩ  ַ]g<¢BXJW7+&v;('-VMBf[A\̎LBS+vҰݧ[bf`|ޮ.ֱ(h\U1J1]fHnMUR&J97*Z ě@9Nӎu7Dr*9-WwZ0}6Dzs K@ .fFVi&neeErx@kIV"=eJreo3b^vLo<fFhi**n.kѾGSWz\)% ]8VAݎ6!@eg/P2ϮZc\զs-t9YqPs 4K- "ʴwWhNq`\Nc J:P=S )|(Q Ը<ȗl+wk;2mJ]-}eB?Uq!uߦr_af`l*߷@C[J^JrO"|a|I4U/n= e̎ԅ~εnm ܰ~ܻcN;0PlsYDuTI9'xP`}@'B?fFBŝu1sx޴eSJy/MCp߷3\9xwIAfGjG<1]N;נ;eC<*xԋwL+\M-=Gd030(&[W5 lV~QȄ#B II^I;u{(cfz g/na[⾰^U?G?Iƃ~~#׾mS>꫺9v,~g!3#Nʇ,U`-DJ{@;wɿǎTtncf@6-a 9xo}p8OT fGx-xn}? T7=w6Q4/aD T 8$ʂ`6ՙw w,x '}8 =̌c,@ !Y Yd5]֪3[ LNxfZ'g6'_iF~Ř@`Cbޯ*xgEg >̌T{ZxrE%jbIbI |ěT\!qk, ,<'CTGNDŽ@>̌T(R F|SWc0@O2>,q{XɾRoUn0ȇC̎L f_%jf xB{@?; M*lA0A\Ƶϩ+5M]>>9 (&$Æ!]կ%D[wRkyiG6f^״A]WY{i7U3aZ2dXwB|B( ~WP]m3^q:׊ @V1ۀ8N`y׽ !@:~sE& 80F&7P$ _؆Asof;Ҁ9eJ4]|YC @*Q$󣊲 dgO䔹ӦZ B Qk< gۭRTGD)?)33xMj-s=,O7k%4ͣ{'/?RA[#-{iѱ*mUڸ?w_z!eQX_^RD06"•wd"/~zl P(`{Ao_.1,..bc$:wZ-O677m|Mܾ]vw~[gaA*;xP]ײsO]U_p͓'? KyVWװE```1 8ڭ:8B8mŅb}^:COH櫔-l(H.YUa}mO<~?+2k_*J7"烊uw۱s'׶nn]zFx}}ںVŅEZLc``la3f w\>ư.}O= .bii)v ?`0p[7{[Ei?8.[w`BAxwuDQt>.] 8Qll*@ Q.ᩧއs 3xwDi+Wk_~۷WEy:oAwL4ݯ}pz]0  Gh6;h6[X{ D4VVVyΟ'/?.ac3 RJ@/<'+O* 951;~[X>?͏tpxp)9}+++%0n.ω#@*I$M R!شM(L0d,PCN)% 2/u./֩z+?9 FVNNgss󘟟G̾ɎG4+}ow/OI@NKU_j?F#_X^^ki68<.\gGΞM_IOpii X[] qY,`qqsssU$E unmma{{ngmp0[oOOOQni>o/'do8 0vunxܩ'._/' |v 8u6O:װE4MOSB@A{{{.vvvpac`iW)ommoo`zk_L!±%?pG&i㏜;\#?k4VVEJt:hw:h;hZXwQD ٲwE.~pܝ  /w_~׮]UdC88`PIR<i/]: ..-~n=9_]F@@FB܈i7``RA0 JDhp)$FH^k/loo^L {o8 a%8/_?4יj/w"Qɫƛ/\y-$t|.< `p$VefyfsO/-.=jm6ra»"I0_۾{僃ĮIN#x#~nyyyG.>֙om6č80xC!V*wd?|u[ij璽%(6&q}k7mUBLݙ3k'N8ݞ?N686F|h%b|G|羁$iOH'htk4[{{~ݫnHZRŧJOBxv kǹӴG~:_{KK+K sf͹8;<8";FEd1oΐ#Ird$)R%@J9LӴ+R9" dv{{[[;nw"!Q#n?.&̊بGA|xD`Y?)9KVE|SmUDu*?Ep1)}>vMmH#͍yn(wyIDATtW$T*K+׹v[xó8uUmk+Yy_t i<@C"xsD`w[T(u!Y Q)`zTYi>)UI?߸slj6,/sμ}~g^8;;?60{u#-fL-UT0 0\AU~Kt>69 _TTZP~67^\y>u*U 1;lޥ,e=7UϨڡWM8ZX-=)Wu<~w(qw5By{GoܾɠsYc~ro.良OSx?S}d7ڀi2S_&B0x{+/{erR3-WgoYpTI6IPZE@B@ٿ2Mm̽\şMLvkչW`!l`% ﱃ?@| Z`qG? zcccDRl<~qgBўs.)7b؟ û~w'/6@^#yWmx,{`w|=?I9rbT-A97Y;oy<YNk~\D@SZm/82cf:8E T a~5j:A<JS>E‹?/rKQk׮}%Jѣa^' # 5N=XkaR277ϑGzZ][{{p|[7l G<}fjX| }qii'xRW"0 C 8I$^G͍fl6Mtvvfn {90_O///begjOjOQNH9Lաx7׮^$0rSy4 ܱvqSg9a{?Dڲkfώe؁؁?Y/~IENDB`nut-2.8.1/scripts/python/app/NUT-Monitor-py2gtk2.in0000755000175000017500000012662314501607135017003 00000000000000#!@PYTHON2@ # -*- coding: utf-8 -*- # 2009-12-27 David Goncalves - Version 1.2 # Total rewrite of NUT-Monitor to optimize GUI interaction. # Added favorites support (saved to user's home) # Added status icon on the notification area # # 2010-02-26 David Goncalves # Added UPS vars display and the possibility to change values # when user double-clicks on a RW var. # # 2010-05-01 David Goncalves # Added support for PyNotify (if available) # # 2010-05-05 David Goncalves # Added support for command line options # -> --start-hidden # -> --favorite # # NUT-Monitor now tries to detect if there is a NUT server # on localhost and if there is 1 UPS, connects to it. # # 2010-10-06 David Goncalves - Version 1.3 # Added localisation support # # 2015-02-14 Michal Fincham - Version 1.3.1 # Corrected unsafe permissions on ~/.nut-monitor (Debian #777706) import gtk, gtk.glade, gobject import sys import base64 import os, os.path import stat import platform import time import threading import optparse import ConfigParser import locale import gettext import PyNUT # Activate threadings on glib gobject.threads_init() class interface : DESIRED_FAVORITES_DIRECTORY_MODE = 0700 __widgets = {} __callbacks = {} __favorites = {} __favorites_file = None __favorites_path = "" __fav_menu_items = list() __window_visible = True __glade_file = None __connected = False __ups_handler = None __ups_commands = None __ups_vars = None __ups_rw_vars = None __gui_thread = None __current_ups = None def __init__( self ) : # Before anything, parse command line options if any present... opt_parser = optparse.OptionParser() opt_parser.add_option( "-H", "--start-hidden", action="store_true", default=False, dest="hidden", help="Start iconified in tray" ) opt_parser.add_option( "-F", "--favorite", dest="favorite", help="Load the specified favorite and connect to UPS" ) ( cmd_opts, args ) = opt_parser.parse_args() self.__glade_file = os.path.join( os.path.dirname( sys.argv[0] ), "ui/gui-1.3.glade" ) self.__widgets["interface"] = gtk.glade.XML( self.__glade_file, "window1", APP ) self.__widgets["main_window"] = self.__widgets["interface"].get_widget("window1") self.__widgets["status_bar"] = self.__widgets["interface"].get_widget("statusbar2") self.__widgets["ups_host_entry"] = self.__widgets["interface"].get_widget("entry1") self.__widgets["ups_port_entry"] = self.__widgets["interface"].get_widget("spinbutton1") self.__widgets["ups_refresh_button"] = self.__widgets["interface"].get_widget("button1") self.__widgets["ups_authentication_check"] = self.__widgets["interface"].get_widget("checkbutton1") self.__widgets["ups_authentication_frame"] = self.__widgets["interface"].get_widget("hbox1") self.__widgets["ups_authentication_login"] = self.__widgets["interface"].get_widget("entry2") self.__widgets["ups_authentication_password"] = self.__widgets["interface"].get_widget("entry3") self.__widgets["ups_list_combo"] = self.__widgets["interface"].get_widget("combobox1") self.__widgets["ups_commands_button"] = self.__widgets["interface"].get_widget("button8") self.__widgets["ups_connect"] = self.__widgets["interface"].get_widget("button2") self.__widgets["ups_disconnect"] = self.__widgets["interface"].get_widget("button7") self.__widgets["ups_params_box"] = self.__widgets["interface"].get_widget("vbox6") self.__widgets["ups_infos"] = self.__widgets["interface"].get_widget("notebook1") self.__widgets["ups_vars_tree"] = self.__widgets["interface"].get_widget("treeview1") self.__widgets["ups_vars_refresh"] = self.__widgets["interface"].get_widget("button9") self.__widgets["ups_status_image"] = self.__widgets["interface"].get_widget("image1") self.__widgets["ups_status_left"] = self.__widgets["interface"].get_widget("label10") self.__widgets["ups_status_right"] = self.__widgets["interface"].get_widget("label11") self.__widgets["ups_status_time"] = self.__widgets["interface"].get_widget("label15") self.__widgets["menu_favorites_root"] = self.__widgets["interface"].get_widget("menuitem3") self.__widgets["menu_favorites"] = self.__widgets["interface"].get_widget("menu2") self.__widgets["menu_favorites_add"] = self.__widgets["interface"].get_widget("menuitem4") self.__widgets["menu_favorites_del"] = self.__widgets["interface"].get_widget("menuitem5") self.__widgets["progress_battery_charge"] = self.__widgets["interface"].get_widget("progressbar1") self.__widgets["progress_battery_load"] = self.__widgets["interface"].get_widget("progressbar2") # Create the tray icon and connect it to the show/hide method... self.__widgets["status_icon"] = gtk.StatusIcon() self.__widgets["status_icon"].set_from_file( os.path.join( os.path.dirname( sys.argv[0] ), "pixmaps", "on_line.png" ) ) self.__widgets["status_icon"].set_visible( True ) self.__widgets["status_icon"].connect( "activate", self.tray_activated ) self.__widgets["ups_status_image"].set_from_file( os.path.join( os.path.dirname( sys.argv[0] ), "pixmaps", "on_line.png" ) ) # Define interface callbacks actions self.__callbacks = { "on_window1_destroy" : self.quit, "on_imagemenuitem1_activate" : self.gui_about_dialog, "on_imagemenuitem5_activate" : self.quit, "on_entry1_changed" : self.__check_gui_fields, "on_entry2_changed" : self.__check_gui_fields, "on_entry3_changed" : self.__check_gui_fields, "on_checkbutton1_toggled" : self.__check_gui_fields, "on_spinbutton1_value_changed" : self.__check_gui_fields, "on_button1_clicked" : self.__update_ups_list, "on_button2_clicked" : self.connect_to_ups, "on_button7_clicked" : self.disconnect_from_ups, "on_button9_clicked" : self.__gui_update_ups_vars_view, "on_menuitem4_activate" : self.__gui_add_favorite, "on_menuitem5_activate" : self.__gui_delete_favorite, "on_treeview1_button_press_event" : self.__gui_ups_vars_selected } # Connect the callbacks self.__widgets["interface"].signal_autoconnect( self.__callbacks ) # Remove the dummy combobox entry on UPS List and Commands self.__widgets["ups_list_combo"].remove_text( 0 ) # Set UPS vars treeview properties ----------------------------- store = gtk.ListStore( gtk.gdk.Pixbuf, gobject.TYPE_STRING, gobject.TYPE_STRING ) self.__widgets["ups_vars_tree"].set_model( store ) self.__widgets["ups_vars_tree"].set_headers_visible( True ) # Column 0 cr = gtk.CellRendererPixbuf() column = gtk.TreeViewColumn( '', cr ) column.add_attribute( cr, 'pixbuf', 0 ) self.__widgets["ups_vars_tree"].append_column( column ) # Column 1 cr = gtk.CellRendererText() cr.set_property( 'editable', False ) column = gtk.TreeViewColumn( _('Var name'), cr ) column.set_sort_column_id( 1 ) column.add_attribute( cr, 'text', 1 ) self.__widgets["ups_vars_tree"].append_column( column ) # Column 2 cr = gtk.CellRendererText() cr.set_property( 'editable', False ) column = gtk.TreeViewColumn( _('Value'), cr ) column.add_attribute( cr, 'text', 2 ) self.__widgets["ups_vars_tree"].append_column( column ) self.__widgets["ups_vars_tree"].get_model().set_sort_column_id( 1, gtk.SORT_ASCENDING ) self.__widgets["ups_vars_tree_store"] = store self.__widgets["ups_vars_tree"].set_size_request( -1, 50 ) #--------------------------------------------------------------- # UPS Commands combo box creation ------------------------------ container = self.__widgets["ups_commands_button"].get_parent() self.__widgets["ups_commands_button"].destroy() self.__widgets["ups_commands_combo"] = gtk.ComboBox() list_store = gtk.ListStore( gobject.TYPE_STRING ) self.__widgets["ups_commands_combo"].set_model( list_store ) cell_renderer = gtk.CellRendererText() cell_renderer.set_property( "xalign", 0 ) self.__widgets["ups_commands_combo"].pack_start( cell_renderer, True ) self.__widgets["ups_commands_combo"].add_attribute( cell_renderer, "markup", 0 ) container.pack_start( self.__widgets["ups_commands_combo"], True ) self.__widgets["ups_commands_combo"].set_active( 0 ) self.__widgets["ups_commands_combo"].show_all() self.__widgets["ups_commands_button"] = gtk.Button( stock=gtk.STOCK_EXECUTE ) container.pack_start( self.__widgets["ups_commands_button"], True ) self.__widgets["ups_commands_button"].show() self.__widgets["ups_commands_button"].connect( "clicked", self.__gui_send_ups_command ) self.__widgets["ups_commands_combo_store"] = list_store #--------------------------------------------------------------- if ( cmd_opts.hidden != True ) : self.__widgets["main_window"].show() # Define favorites path and load favorites if ( platform.system() == "Linux" ) : self.__favorites_path = os.path.join( os.environ.get("HOME"), ".nut-monitor" ) elif ( platform.system() == "Windows" ) : self.__favorites_path = os.path.join( os.environ.get("USERPROFILE"), "Application Data", "NUT-Monitor" ) self.__favorites_file = os.path.join( self.__favorites_path, "favorites.ini" ) self.__parse_favorites() self.gui_status_message( _("Welcome to NUT Monitor") ) if ( cmd_opts.favorite != None ) : if ( self.__favorites.has_key( cmd_opts.favorite ) ) : self.__gui_load_favorite( fav_name=cmd_opts.favorite ) self.connect_to_ups() else : # Try to scan localhost for available ups and connect to it if there is only one self.__widgets["ups_host_entry"].set_text( "localhost" ) self.__update_ups_list() if ( len( self.__widgets["ups_list_combo"].get_model() ) == 1 ) : self.connect_to_ups() # Check if correct fields are filled to enable connection to the UPS def __check_gui_fields( self, widget=None ) : # If UPS list contains something, clear it if self.__widgets["ups_list_combo"].get_active() != -1 : self.__widgets["ups_list_combo"].get_model().clear() self.__widgets["ups_connect"].set_sensitive( False ) self.__widgets["menu_favorites_add"].set_sensitive( False ) # Host/Port selection if len( self.__widgets["ups_host_entry"].get_text() ) > 0 : sensitive = True # If authentication is selected, check that we have a login and password if self.__widgets["ups_authentication_check"].get_active() : if len( self.__widgets["ups_authentication_login"].get_text() ) == 0 : sensitive = False if len( self.__widgets["ups_authentication_password"].get_text() ) == 0 : sensitive = False self.__widgets["ups_refresh_button"].set_sensitive( sensitive ) if not sensitive : self.__widgets["ups_connect"].set_sensitive( False ) self.__widgets["menu_favorites_add"].set_sensitive( False ) else : self.__widgets["ups_refresh_button"].set_sensitive( False ) self.__widgets["ups_connect"].set_sensitive( False ) self.__widgets["menu_favorites_add"].set_sensitive( False ) # Use authentication fields... if self.__widgets["ups_authentication_check"].get_active() : self.__widgets["ups_authentication_frame"].set_sensitive( True ) else : self.__widgets["ups_authentication_frame"].set_sensitive( False ) self.gui_status_message() #------------------------------------------------------------------- # This method is used to show/hide the main window when user clicks on the tray icon def tray_activated( self, widget=None, data=None ) : if self.__window_visible : self.__widgets["main_window"].hide() else : self.__widgets["main_window"].show() self.__window_visible = not self.__window_visible #------------------------------------------------------------------- # Change the status icon and tray icon def change_status_icon( self, icon="on_line", blink=False ) : self.__widgets["status_icon"].set_from_file( os.path.join( os.path.dirname( sys.argv[0] ), "pixmaps", "%s.png" % icon ) ) self.__widgets["ups_status_image"].set_from_file( os.path.join( os.path.dirname( sys.argv[0] ), "pixmaps", "%s.png" % icon ) ) self.__widgets["status_icon"].set_blinking( blink ) #------------------------------------------------------------------- # This method connects to the NUT server and retrieve availables UPSes # using connection parameters (host, port, login, pass...) def __update_ups_list( self, widget=None ) : host = self.__widgets["ups_host_entry"].get_text() port = int( self.__widgets["ups_port_entry"].get_value() ) login = None password = None if self.__widgets["ups_authentication_check"].get_active() : login = self.__widgets["ups_authentication_login"].get_text() password = self.__widgets["ups_authentication_password"].get_text() try : nut_handler = PyNUT.PyNUTClient( host=host, port=port, login=login, password=password ) upses = nut_handler.GetUPSList() ups_list = upses.keys() ups_list.sort() # If UPS list contains something, clear it self.__widgets["ups_list_combo"].get_model().clear() for current in ups_list : self.__widgets["ups_list_combo"].append_text( current ) self.__widgets["ups_list_combo"].set_active( 0 ) self.__widgets["ups_connect"].set_sensitive( True ) self.__widgets["menu_favorites_add"].set_sensitive( True ) self.gui_status_message( _("Found {0} devices on {1}").format( len( ups_list ), host ) ) except : error_msg = _("Error connecting to '{0}' ({1})").format( host, sys.exc_info()[1] ) self.gui_status_message( error_msg ) #------------------------------------------------------------------- # Quit program def quit( self, widget=None ) : # If we are connected to an UPS, disconnect first... if self.__connected : self.gui_status_message( _("Disconnecting from device") ) self.disconnect_from_ups() gtk.main_quit() #------------------------------------------------------------------- # Method called when user wants to add a new favorite entry. It # displays a dialog to enable user to select the name of the favorite def __gui_add_favorite( self, widget=None ) : dialog_interface = gtk.glade.XML( self.__glade_file, "dialog1" ) dialog = dialog_interface.get_widget( "dialog1" ) self.__widgets["favorites_dialog_button_add"] = dialog_interface.get_widget("button3") # Define interface callbacks actions callbacks = { "on_entry4_changed" : self.__gui_add_favorite_check_gui_fields } dialog_interface.signal_autoconnect( callbacks ) self.__widgets["main_window"].set_sensitive( False ) rc = dialog.run() if rc == 1 : fav_data = {} fav_data["host"] = self.__widgets["ups_host_entry"].get_text() fav_data["port"] = "%d" % self.__widgets["ups_port_entry"].get_value() fav_data["ups"] = self.__widgets["ups_list_combo"].get_active_text() fav_data["auth"] = self.__widgets["ups_authentication_check"].get_active() if fav_data["auth"] : fav_data["login"] = self.__widgets["ups_authentication_login"].get_text() fav_data["password"] = base64.b64encode( self.__widgets["ups_authentication_password"].get_text() ) fav_name = dialog_interface.get_widget("entry4").get_text() self.__favorites[ fav_name ] = fav_data self.__gui_refresh_favorites_menu() # Save all favorites self.__save_favorites() dialog.destroy() self.__widgets["main_window"].set_sensitive( True ) #------------------------------------------------------------------- # Method called when user wants to delete an entry from favorites def __gui_delete_favorite( self, widget=None ) : dialog_interface = gtk.glade.XML( self.__glade_file, "dialog2" ) dialog = dialog_interface.get_widget( "dialog2" ) # Remove the dummy combobox entry on list dialog_interface.get_widget("combobox2").remove_text( 0 ) favs = self.__favorites.keys() favs.sort() for current in favs : dialog_interface.get_widget("combobox2").append_text( current ) dialog_interface.get_widget("combobox2").set_active( 0 ) self.__widgets["main_window"].set_sensitive( False ) rc = dialog.run() fav_name = dialog_interface.get_widget("combobox2").get_active_text() dialog.destroy() self.__widgets["main_window"].set_sensitive( True ) if ( rc == 1 ) : # Remove entry, show confirmation dialog md = gtk.MessageDialog( None, gtk.DIALOG_MODAL, gtk.MESSAGE_QUESTION, gtk.BUTTONS_YES_NO, _("Are you sure that you want to remove this favorite ?") ) resp = md.run() md.destroy() if ( resp == gtk.RESPONSE_YES ) : del self.__favorites[ fav_name ] self.__gui_refresh_favorites_menu() self.__save_favorites() self.gui_status_message( _("Removed favorite '%s'") % fav_name ) #------------------------------------------------------------------- # Method called when user selects a favorite from the favorites menu def __gui_load_favorite( self, fav_name="" ) : if ( self.__favorites.has_key( fav_name ) ) : # If auth is activated, process it before other fields to avoir weird # reactions with the 'check_gui_fields' function. if ( self.__favorites[fav_name].get("auth", False ) ) : self.__widgets["ups_authentication_check"].set_active( True ) self.__widgets["ups_authentication_login"].set_text( self.__favorites[fav_name].get("login","") ) self.__widgets["ups_authentication_password"].set_text( self.__favorites[fav_name].get("password","") ) self.__widgets["ups_host_entry"].set_text( self.__favorites[fav_name].get("host","") ) self.__widgets["ups_port_entry"].set_value( float(self.__favorites[fav_name].get("port",3493.0)) ) # Clear UPS list and add current UPS name self.__widgets["ups_list_combo"].get_model().clear() self.__widgets["ups_list_combo"].append_text( self.__favorites[fav_name].get("ups","") ) self.__widgets["ups_list_combo"].set_active( 0 ) # Activate the connect button self.__widgets["ups_connect"].set_sensitive( True ) self.gui_status_message( _("Loaded '%s'") % fav_name ) #------------------------------------------------------------------- # Send the selected command to the UPS def __gui_send_ups_command( self, widget=None ) : offset = self.__widgets["ups_commands_combo"].get_active() cmd = self.__ups_commands[ offset ] md = gtk.MessageDialog( None, gtk.DIALOG_MODAL, gtk.MESSAGE_QUESTION, gtk.BUTTONS_YES_NO, _("Are you sure that you want to send\n'%s' to the device ?") % cmd ) self.__widgets["main_window"].set_sensitive( False ) resp = md.run() md.destroy() self.__widgets["main_window"].set_sensitive( True ) if ( resp == gtk.RESPONSE_YES ) : try : self.__ups_handler.RunUPSCommand( self.__current_ups, cmd ) self.gui_status_message( _("Sent '{0}' command to {1}").format( cmd, self.__current_ups ) ) except : self.gui_status_message( _("Failed to send '{0}' ({1})").format( cmd, sys.exc_info()[1] ) ) #------------------------------------------------------------------- # Method called when user clicks on the UPS vars treeview. If the user # performs a double click on a RW var, the GUI shows the update var dialog. def __gui_ups_vars_selected( self, widget, event ) : # Check if it's a double click... if ( (event.button == 1) and (event.type == gtk.gdk._2BUTTON_PRESS) ) : treeselection = self.__widgets["ups_vars_tree"].get_selection() (model,iter) = treeselection.get_selected() try : ups_var = model.get_value( iter, 1 ) if ( ups_var in self.__ups_rw_vars ) : # The selected var is RW, then we can show the update dialog dialog_interface = gtk.glade.XML( self.__glade_file, "dialog3" ) dialog = dialog_interface.get_widget( "dialog3" ) lab = dialog_interface.get_widget( "label9" ) lab.set_markup( _("Enter a new value for the variable.\n\n{0} = {1} (current value)").format( ups_var, self.__ups_rw_vars.get(ups_var)) ) str = dialog_interface.get_widget( "entry5" ) str.set_text( self.__ups_rw_vars.get(ups_var) ) self.__widgets["main_window"].set_sensitive( False ) rc = dialog.run() new_val = str.get_text() dialog.destroy() self.__widgets["main_window"].set_sensitive( True ) if ( rc == 1 ) : try : self.__ups_handler.SetRWVar( ups=self.__current_ups, var=ups_var, value=new_val ) self.gui_status_message( _("Updated variable on %s") % self.__current_ups ) # Change the value on the local dict to update the GUI self.__ups_vars[ups_var] = new_val self.__ups_rw_vars[ups_var] = new_val self.__gui_update_ups_vars_view() except : error_msg = _("Error updating variable on '{0}' ({1})").format( self.__current_ups, sys.exc_info()[1] ) self.gui_status_message( error_msg ) else : # User cancelled modification... error_msg = _("No variable modified on %s - User cancelled") % self.__current_ups self.gui_status_message( error_msg ) except : # Failed to get information from the treeview... skip action pass #------------------------------------------------------------------- # Refresh the content of the favorites menu according to the defined favorites def __gui_refresh_favorites_menu( self ) : for current in self.__fav_menu_items : current.destroy() self.__fav_menu_items = list() items = self.__favorites.keys() items.sort() for current in items : menu_item = gtk.MenuItem( current ) menu_item.show() self.__fav_menu_items.append( menu_item ) self.__widgets["menu_favorites"].append( menu_item ) menu_item.connect_object( "activate", self.__gui_load_favorite, current ) if len( items ) > 0 : self.__widgets["menu_favorites_del"].set_sensitive( True ) else : self.__widgets["menu_favorites_del"].set_sensitive( False ) #------------------------------------------------------------------- # In 'add favorites' dialog, this method compares the content of the # text widget representing the name of the new favorite with existing # ones. If they match, the 'add' button will be set to non sensitive # to avoid creating entries with the same name. def __gui_add_favorite_check_gui_fields( self, widget=None ) : fav_name = widget.get_text() if ( len( fav_name ) > 0 ) and ( fav_name not in self.__favorites.keys() ) : self.__widgets["favorites_dialog_button_add"].set_sensitive( True ) else : self.__widgets["favorites_dialog_button_add"].set_sensitive( False ) #------------------------------------------------------------------- # Load and parse favorites def __parse_favorites( self ) : if ( not os.path.exists( self.__favorites_file ) ) : # There is no favorites files, do nothing return try : if ( not stat.S_IMODE( os.stat( self.__favorites_path ).st_mode ) == self.DESIRED_FAVORITES_DIRECTORY_MODE ) : # unsafe pre-1.2 directory found os.chmod( self.__favorites_path, self.DESIRED_FAVORITES_DIRECTORY_MODE ) conf = ConfigParser.ConfigParser() conf.read( self.__favorites_file ) for current in conf.sections() : # Check if mandatory fields are present if ( conf.has_option( current, "host" ) and conf.has_option( current, "ups" ) ) : # Valid entry found, add it to the list fav_data = {} fav_data["host"] = conf.get( current, "host" ) fav_data["ups"] = conf.get( current, "ups" ) if ( conf.has_option( current, "port" ) ) : fav_data["port"] = conf.get( current, "port" ) else : fav_data["port"] = "3493" # If auth is defined the section must have login and pass defined if ( conf.has_option( current, "auth" ) ) : if( conf.has_option( current, "login" ) and conf.has_option( current, "password" ) ) : # Add the entry fav_data["auth"] = conf.getboolean( current, "auth" ) fav_data["login"] = conf.get( current, "login" ) try : fav_data["password"] = base64.decodestring( conf.get( current, "password" ) ) except : # If the password is not in base64, let the field empty print( _("Error parsing favorites, password for '%s' is not in base64\nSkipping password for this entry") % current ) fav_data["password"] = "" else : fav_data["auth"] = False self.__favorites[current] = fav_data self.__gui_refresh_favorites_menu() except : self.gui_status_message( _("Error while parsing favorites file (%s)") % sys.exc_info()[1] ) #------------------------------------------------------------------- # Save favorites to the defined favorites file using ini format def __save_favorites( self ) : # If path does not exists, try to create it if ( not os.path.exists( self.__favorites_file ) ) : try : os.makedirs( self.__favorites_path, mode=self.DESIRED_FAVORITES_DIRECTORY_MODE ) except : self.gui_status_message( _("Error while creating configuration folder (%s)") % sys.exc_info()[1] ) save_conf = ConfigParser.ConfigParser() for current in self.__favorites.keys() : save_conf.add_section( current ) for k, v in self.__favorites[ current ].iteritems() : save_conf.set( current, k, v ) try : fh = open( self.__favorites_file, "w" ) save_conf.write( fh ) fh.close() self.gui_status_message( _("Saved favorites...") ) except : self.gui_status_message( _("Error while saving favorites (%s)") % sys.exc_info()[1] ) #------------------------------------------------------------------- # Display the about dialog def gui_about_dialog( self, widget=None ) : dialog_interface = gtk.glade.XML( self.__glade_file, "aboutdialog1" ) dialog = dialog_interface.get_widget( "aboutdialog1" ) self.__widgets["main_window"].set_sensitive( False ) dialog.run() dialog.destroy() self.__widgets["main_window"].set_sensitive( True ) #------------------------------------------------------------------- # Display a message on the status bar. The message is also set as # tooltip to enable users to see long messages. def gui_status_message( self, msg="" ) : context_id = self.__widgets["status_bar"].get_context_id("Infos") self.__widgets["status_bar"].pop( context_id ) if ( platform.system() == "Windows" ) : text = msg.decode("cp1250").encode("utf8") else : text = msg message_id = self.__widgets["status_bar"].push( context_id, text.replace("\n", "") ) self.__widgets["status_bar"].set_tooltip_text( text ) #------------------------------------------------------------------- # Display a notification using PyNotify with an optional icon def gui_status_notification( self, message="", icon_file="" ) : # Try to init pynotify try : import pynotify pynotify.init( "NUT Monitor" ) if ( icon_file != "" ) : icon = "file://%s" % os.path.abspath( os.path.join( os.path.dirname( sys.argv[0] ), "pixmaps", icon_file ) ) else : icon = None notif = pynotify.Notification( "NUT Monitor", message, icon ) notif.show() except : pass #------------------------------------------------------------------- # Let GTK refresh GUI :) def refresh_gui( self ) : while gtk.events_pending() : gtk.main_iteration( False ) return( True ) #------------------------------------------------------------------- # Connect to the selected UPS using parameters (host,port,login,pass) def connect_to_ups( self, widget=None ) : host = self.__widgets["ups_host_entry"].get_text() port = int( self.__widgets["ups_port_entry"].get_value() ) login = None password = None if self.__widgets["ups_authentication_check"].get_active() : login = self.__widgets["ups_authentication_login"].get_text() password = self.__widgets["ups_authentication_password"].get_text() try : self.__ups_handler = PyNUT.PyNUTClient( host=host, port=port, login=login, password=password ) except : self.gui_status_message( _("Error connecting to '{0}' ({1})").format( host, sys.exc_info()[1] ) ) self.gui_status_notification( _("Error connecting to '{0}'\n{1}").format( host, sys.exc_info()[1] ), "warning.png" ) return # Check if selected UPS exists on server... srv_upses = self.__ups_handler.GetUPSList() self.__current_ups = self.__widgets["ups_list_combo"].get_active_text() if not srv_upses.has_key( self.__current_ups ) : self.gui_status_message( _("Device '%s' not found on server") % self.__current_ups ) self.gui_status_notification( _("Device '%s' not found on server") % self.__current_ups, "warning.png" ) return if not self.__ups_handler.CheckUPSAvailable( self.__current_ups ): self.gui_status_message( _("UPS '{0}' is not reachable").format( self.__current_ups ) ) self.gui_status_notification( _("UPS '{0}' is not reachable").format( self.__current_ups ), "warning.png" ) return self.__connected = True self.__widgets["ups_connect"].hide() self.__widgets["ups_disconnect"].show() self.__widgets["ups_infos"].show() self.__widgets["ups_params_box"].set_sensitive( False ) self.__widgets["menu_favorites_root"].set_sensitive( False ) self.__widgets["ups_params_box"].hide() commands = self.__ups_handler.GetUPSCommands( self.__current_ups ) self.__ups_commands = commands.keys() self.__ups_commands.sort() # Refresh UPS commands combo box self.__widgets["ups_commands_combo_store"].clear() for desc in self.__ups_commands : self.__widgets["ups_commands_combo_store"].append( [ "%s\n%s" % ( desc, commands[desc] ) ] ) self.__widgets["ups_commands_combo"].set_active( 0 ) # Update UPS vars manually before the thread self.__ups_vars = self.__ups_handler.GetUPSVars( self.__current_ups ) self.__ups_rw_vars = self.__ups_handler.GetRWVars( self.__current_ups ) self.__gui_update_ups_vars_view() # Try to resize the main window... self.__widgets["main_window"].resize( 1, 1 ) # Start the GUI updater thread self.__gui_thread = gui_updater( self ) self.__gui_thread.start() self.gui_status_message( _("Connected to '{0}' on {1}").format( self.__current_ups, host ) ) #------------------------------------------------------------------- # Refresh UPS vars in the treeview def __gui_update_ups_vars_view( self, widget=None ) : if self.__ups_handler : vars = self.__ups_vars rwvars = self.__ups_rw_vars self.__widgets["ups_vars_tree_store"].clear() for k,v in vars.iteritems() : if ( rwvars.has_key( k ) ) : icon_file = os.path.join( os.path.dirname( sys.argv[0] ), "pixmaps", "var-rw.png" ) else : icon_file = os.path.join( os.path.dirname( sys.argv[0] ), "pixmaps", "var-ro.png" ) icon = gtk.gdk.pixbuf_new_from_file( icon_file ) self.__widgets["ups_vars_tree_store"].append( [ icon, k, v ] ) #------------------------------------------------------------------- # Disconnect from the UPS def disconnect_from_ups( self, widget=None ) : self.__connected = False self.__widgets["ups_connect"].show() self.__widgets["ups_disconnect"].hide() self.__widgets["ups_infos"].hide() self.__widgets["ups_params_box"].set_sensitive( True ) self.__widgets["menu_favorites_root"].set_sensitive( True ) self.__widgets["status_icon"].set_tooltip_markup( _("Not connected") ) self.__widgets["ups_params_box"].show() # Try to resize the main window... self.__widgets["main_window"].resize( 1, 1 ) # Stop the GUI updater thread self.__gui_thread.stop_thread() del self.__ups_handler self.gui_status_message( _("Disconnected from '%s'") % self.__current_ups ) self.change_status_icon( "on_line", blink=False ) self.__current_ups = None #----------------------------------------------------------------------- # GUI Updater class # This class updates the main gui with data from connected UPS class gui_updater( threading.Thread ) : __parent_class = None __stop_thread = False def __init__( self, parent_class ) : threading.Thread.__init__( self ) self.__parent_class = parent_class def run( self ) : ups = self.__parent_class._interface__current_ups was_online = True # Define a dict containing different UPS status status_mapper = { "LB" : "%s" % _("Low batteries"), "RB" : "%s" % _("Replace batteries !"), "BYPASS" : "Bypass %s" % _("(no battery protection)"), "CAL" : _("Performing runtime calibration"), "OFF" : "%s (%s)" % ( _("Offline"), _("not providing power to the load") ), "OVER" : "%s (%s)" % ( _("Overloaded !"), _("there is too much load for device") ), "TRIM" : _("Triming (UPS is triming incoming voltage)"), "BOOST" : _("Boost (UPS is boosting incoming voltage)") } while not self.__stop_thread : try : vars = self.__parent_class._interface__ups_handler.GetUPSVars( ups ) self.__parent_class._interface__ups_vars = vars # Text displayed on the status frame text_left = "" text_right = "" status_text = "" text_left += "%s\n" % _("Device status :") if ( vars.get("ups.status").find("OL") != -1 ) : text_right += "%s" % _("Online") if not was_online : self.__parent_class.change_status_icon( "on_line", blink=False ) was_online = True if ( vars.get("ups.status").find("OB") != -1 ) : text_right += "%s" % _("On batteries") if was_online : self.__parent_class.change_status_icon( "on_battery", blink=True ) self.__parent_class.gui_status_notification( _("Device is running on batteries"), "on_battery.png" ) was_online = False # Check for additionnal information for k,v in status_mapper.iteritems() : if vars.get("ups.status").find(k) != -1 : if ( text_right != "" ) : text_right += " - %s" % v else : text_right += "%s" % v # CHRG and DISCHRG cannot be trated with the previous loop ;) if ( vars.get("ups.status").find("DISCHRG") != -1 ) : text_right += " - %s" % _("discharging") elif ( vars.get("ups.status").find("CHRG") != -1 ) : text_right += " - %s" % _("charging") status_text += text_right text_right += "\n" if ( vars.has_key( "ups.mfr" ) ) : text_left += "%s\n\n" % _("Model :") text_right += "%s\n%s\n" % ( vars.get("ups.mfr",""), vars.get("ups.model","") ) if ( vars.has_key( "ups.temperature" ) ) : text_left += "%s\n" % _("Temperature :") text_right += "%s\n" % int( float( vars.get( "ups.temperature", 0 ) ) ) if ( vars.has_key( "battery.voltage" ) ) : text_left += "%s\n" % _("Battery voltage :") text_right += "%sv\n" % vars.get( "battery.voltage", 0 ) self.__parent_class._interface__widgets["ups_status_left"].set_markup( text_left[:-1] ) self.__parent_class._interface__widgets["ups_status_right"].set_markup( text_right[:-1] ) # UPS load and battery charge progress bars if ( vars.has_key( "battery.charge" ) ) : charge = vars.get( "battery.charge", "0" ) self.__parent_class._interface__widgets["progress_battery_charge"].set_fraction( float( charge ) / 100.0 ) self.__parent_class._interface__widgets["progress_battery_charge"].set_text( "%s %%" % int( float( charge ) ) ) status_text += "\n%s %s%%" % ( _("Battery charge :"), int( float( charge ) ) ) else : self.__parent_class._interface__widgets["progress_battery_charge"].set_fraction( 0.0 ) self.__parent_class._interface__widgets["progress_battery_charge"].set_text( _("Not available") ) if ( vars.has_key( "ups.load" ) ) : load = vars.get( "ups.load", "0" ) self.__parent_class._interface__widgets["progress_battery_load"].set_fraction( float( load ) / 100.0 ) self.__parent_class._interface__widgets["progress_battery_load"].set_text( "%s %%" % int( float( load ) ) ) status_text += "\n%s %s%%" % ( _("UPS load :"), int( float( load ) ) ) else : self.__parent_class._interface__widgets["progress_battery_load"].set_fraction( 0.0 ) self.__parent_class._interface__widgets["progress_battery_load"].set_text( _("Not available") ) if ( vars.has_key( "battery.runtime" ) ) : autonomy = int( float( vars.get( "battery.runtime", 0 ) ) ) if ( autonomy >= 3600 ) : info = time.strftime( _("%H hours %M minutes %S seconds"), time.gmtime( autonomy ) ) elif ( autonomy > 300 ) : info = time.strftime( _("%M minutes %S seconds"), time.gmtime( autonomy ) ) else : info = time.strftime( _("%M minutes %S seconds"), time.gmtime( autonomy ) ) else : info = _("Not available") self.__parent_class._interface__widgets["ups_status_time"].set_markup( info ) # Display UPS status as tooltip for tray icon self.__parent_class._interface__widgets["status_icon"].set_tooltip_markup( status_text ) except : self.__parent_class.gui_status_message( _("Error from '{0}' ({1})").format( ups, sys.exc_info()[1] ) ) self.__parent_class.gui_status_notification( _("Error from '{0}'\n{1}").format( ups, sys.exc_info()[1] ), "warning.png" ) time.sleep( 1 ) def stop_thread( self ) : self.__stop_thread = True #----------------------------------------------------------------------- # The main program starts here :-) if __name__ == "__main__" : # Init the localisation APP = "NUT-Monitor" DIR = "locale" gettext.bindtextdomain( APP, DIR ) gettext.textdomain( APP ) _ = gettext.gettext for module in ( gettext, gtk.glade ) : module.bindtextdomain( APP, DIR ) module.textdomain( APP ) gui = interface() gtk.main() nut-2.8.1/scripts/python/app/NUT-Monitor-py3qt5.in0000755000175000017500000013236114501607135016642 00000000000000#!@PYTHON3@ # -*- coding: utf-8 -*- # 2009-12-27 David Goncalves - Version 1.2 # Total rewrite of NUT-Monitor to optimize GUI interaction. # Added favorites support (saved to user's home) # Added status icon on the notification area # # 2010-02-26 David Goncalves # Added UPS vars display and the possibility to change values # when user double-clicks on a RW var. # # 2010-05-01 David Goncalves # Added support for PyNotify (if available) # # 2010-05-05 David Goncalves # Added support for command line options # -> --start-hidden # -> --favorite # # NUT-Monitor now tries to detect if there is a NUT server # on localhost and if there is 1 UPS, connects to it. # # 2010-10-06 David Goncalves - Version 1.3 # Added localisation support # # 2015-02-14 Michal Fincham - Version 1.3.1 # Corrected unsafe permissions on ~/.nut-monitor (Debian #777706) # # 2022-02-20 Luke Dashjr - Version 2.0 # Port to Python 3 with PyQt5. import PyQt5.uic from PyQt5.QtCore import * from PyQt5.QtGui import * from PyQt5.QtWidgets import * import sys import base64 import os, os.path import stat import platform import time import threading import optparse import configparser import locale import gettext import PyNUT class interface : DESIRED_FAVORITES_DIRECTORY_MODE = 0o700 __widgets = {} __callbacks = {} __favorites = {} __favorites_file = None __favorites_path = "" __fav_menu_items = list() __window_visible = True __ui_file = None __connected = False __ups_handler = None __ups_commands = None __ups_vars = None __ups_rw_vars = None __gui_thread = None __current_ups = None def __init__( self, argv ) : # Before anything, parse command line options if any present... opt_parser = optparse.OptionParser() opt_parser.add_option( "-H", "--start-hidden", action="store_true", default=False, dest="hidden", help="Start iconified in tray" ) opt_parser.add_option( "-F", "--favorite", dest="favorite", help="Load the specified favorite and connect to UPS" ) ( cmd_opts, args ) = opt_parser.parse_args() self.__app = QApplication( argv ) self.__ui_file = self.__find_res_file( 'ui', "window1.ui" ) self.__widgets["interface"] = PyQt5.uic.loadUi( self.__ui_file ) self.__widgets["main_window"] = self.__widgets["interface"] self.__widgets["status_bar"] = self.__widgets["interface"].statusbar2 self.__widgets["ups_host_entry"] = self.__widgets["interface"].entry1 self.__widgets["ups_port_entry"] = self.__widgets["interface"].spinbutton1 self.__widgets["ups_refresh_button"] = self.__widgets["interface"].button1 self.__widgets["ups_authentication_check"] = self.__widgets["interface"].checkbutton1 self.__widgets["ups_authentication_frame"] = self.__widgets["interface"].hbox1 self.__widgets["ups_authentication_login"] = self.__widgets["interface"].entry2 self.__widgets["ups_authentication_password"] = self.__widgets["interface"].entry3 self.__widgets["ups_list_combo"] = self.__widgets["interface"].combobox1 self.__widgets["ups_commands_combo"] = self.__widgets["interface"].ups_commands_combo self.__widgets["ups_commands_button"] = self.__widgets["interface"].button8 self.__widgets["ups_connect"] = self.__widgets["interface"].button2 self.__widgets["ups_disconnect"] = self.__widgets["interface"].button7 self.__widgets["ups_params_box"] = self.__widgets["interface"].vbox6 self.__widgets["ups_infos"] = self.__widgets["interface"].notebook1 self.__widgets["ups_vars_tree"] = self.__widgets["interface"].treeview1 self.__widgets["ups_vars_refresh"] = self.__widgets["interface"].button9 self.__widgets["ups_status_image"] = self.__widgets["interface"].image1 self.__widgets["ups_status_left"] = self.__widgets["interface"].label10 self.__widgets["ups_status_right"] = self.__widgets["interface"].label11 self.__widgets["ups_status_time"] = self.__widgets["interface"].label15 self.__widgets["menu_favorites_root"] = self.__widgets["interface"].menu2 self.__widgets["menu_favorites"] = self.__widgets["interface"].menu2 self.__widgets["menu_favorites_add"] = self.__widgets["interface"].menuitem4 self.__widgets["menu_favorites_del"] = self.__widgets["interface"].menuitem5 self.__widgets["progress_battery_charge"] = self.__widgets["interface"].progressbar1 self.__widgets["progress_battery_load"] = self.__widgets["interface"].progressbar2 # Create the tray icon and connect it to the show/hide method... self.__widgets["status_icon"] = QSystemTrayIcon( QIcon( self.__find_res_file( "pixmaps", "on_line.png" ) ) ) self.__widgets["status_icon"].setVisible( True ) self.__widgets["status_icon"].activated.connect( self.tray_activated ) self.__widgets["ups_status_image"].setPixmap( QPixmap( self.__find_res_file( "pixmaps", "on_line.png" ) ) ) # Connect interface callbacks actions self.__widgets["main_window"].destroyed.connect( self.quit ) self.__widgets["interface"].imagemenuitem1.triggered.connect( self.gui_about_dialog ) self.__widgets["interface"].imagemenuitem5.triggered.connect( self.quit ) self.__widgets["ups_host_entry"].textChanged.connect( self.__check_gui_fields ) self.__widgets["ups_authentication_login"].textChanged.connect( self.__check_gui_fields ) self.__widgets["ups_authentication_password"].textChanged.connect( self.__check_gui_fields ) self.__widgets["ups_authentication_check"].stateChanged.connect( self.__check_gui_fields ) self.__widgets["ups_port_entry"].valueChanged.connect( self.__check_gui_fields ) self.__widgets["ups_refresh_button"].clicked.connect( self.__update_ups_list ) self.__widgets["ups_connect"].clicked.connect( self.connect_to_ups ) self.__widgets["ups_disconnect"].clicked.connect( self.disconnect_from_ups ) self.__widgets["ups_vars_refresh"].clicked.connect( self.__gui_update_ups_vars_view ) self.__widgets["menu_favorites_add"].triggered.connect( self.__gui_add_favorite ) self.__widgets["menu_favorites_del"].triggered.connect( self.__gui_delete_favorite ) self.__widgets["ups_vars_tree"].doubleClicked.connect( self.__gui_ups_vars_selected ) # Remove the dummy combobox entry on UPS List and Commands self.__widgets["ups_list_combo"].removeItem( 0 ) # Set UPS vars treeview properties ----------------------------- store = QStandardItemModel( 0, 3, self.__widgets["ups_vars_tree"] ) self.__widgets["ups_vars_tree"].setModel( store ) self.__widgets["ups_vars_tree"].setHeaderHidden( False ) self.__widgets["ups_vars_tree"].setRootIsDecorated( False ) # Column 0 store.setHeaderData( 0, Qt.Horizontal, '' ) # Column 1 store.setHeaderData( 1, Qt.Horizontal, _('Var name') ) # Column 2 store.setHeaderData( 2, Qt.Horizontal, _('Value') ) self.__widgets["ups_vars_tree"].header().setStretchLastSection( True ) self.__widgets["ups_vars_tree"].sortByColumn( 1, Qt.AscendingOrder ) self.__widgets["ups_vars_tree_store"] = store self.__widgets["ups_vars_tree"].setMinimumSize( 0, 50 ) #--------------------------------------------------------------- # UPS Commands combo box creation ------------------------------ ups_commands_height = self.__widgets["ups_commands_combo"].size().height() * 2 self.__widgets["ups_commands_combo"].setMinimumSize(0, ups_commands_height) self.__widgets["ups_commands_combo"].setCurrentIndex( 0 ) self.__widgets["ups_commands_button"].setMinimumSize(0, ups_commands_height) self.__widgets["ups_commands_button"].clicked.connect( self.__gui_send_ups_command ) self.__widgets["ups_commands_combo_store"] = self.__widgets["ups_commands_combo"] #--------------------------------------------------------------- self.gui_init_unconnected() if ( cmd_opts.hidden != True ) : self.__widgets["main_window"].show() # Define favorites path and load favorites if ( platform.system() == "Linux" ) : self.__favorites_path = os.path.join( os.environ.get("HOME"), ".nut-monitor" ) elif ( platform.system() == "Windows" ) : self.__favorites_path = os.path.join( os.environ.get("USERPROFILE"), "Application Data", "NUT-Monitor" ) self.__favorites_file = os.path.join( self.__favorites_path, "favorites.ini" ) self.__parse_favorites() self.gui_status_message( _("Welcome to NUT Monitor") ) if ( cmd_opts.favorite != None ) : if ( cmd_opts.favorite in self.__favorites ) : self.__gui_load_favorite( fav_name=cmd_opts.favorite ) self.connect_to_ups() else : # Try to scan localhost for available ups and connect to it if there is only one self.__widgets["ups_host_entry"].setText( "localhost" ) self.__update_ups_list() if self.__widgets["ups_list_combo"].count() == 1: self.connect_to_ups() def exec( self ) : self.__app.exec() def __find_res_file( self, ftype, filename ) : filename = os.path.join( ftype, filename ) # TODO: Skip checking application directory if installed path = os.path.join( os.path.dirname( sys.argv[0] ), filename ) if os.path.exists(path): return path path = QStandardPaths.locate(QStandardPaths.AppDataLocation, filename) if os.path.exists(path): return path raise RuntimeError("Cannot find %s resource %s" % (ftype, filename)) def __find_icon_file( self ) : filename = 'nut-monitor.png' # TODO: Skip checking application directory if installed path = os.path.join( os.path.dirname( sys.argv[0] ), "icons", "256x256", filename ) if os.path.exists(path): return path # Normally icons should be installed to OS location by packaging: path = QStandardPaths.locate(QStandardPaths.GenericDataLocation, os.path.join( "icons", "hicolor", "256x256", "apps", filename ) ) if os.path.exists(path): return path # Fall back to NUT-specific area where `make install` might put them, # e.g. /usr/share/nut/nut-monitor/icons/... or some such, if not the # same location as checked in first attempt above: path = QStandardPaths.locate(QStandardPaths.AppDataLocation, os.path.join( "icons", "hicolor", "256x256", "apps", filename ) ) if os.path.exists(path): return path # No banana! raise RuntimeError("Cannot find %s resource %s" % ('icon', filename)) # Check if correct fields are filled to enable connection to the UPS def __check_gui_fields( self, widget=None ) : # If UPS list contains something, clear it if self.__widgets["ups_list_combo"].currentIndex() != -1 : self.__widgets["ups_list_combo"].clear() self.__widgets["ups_connect"].setEnabled( False ) self.__widgets["menu_favorites_add"].setEnabled( False ) # Host/Port selection if len( self.__widgets["ups_host_entry"].text() ) > 0 : sensitive = True # If authentication is selected, check that we have a login and password if self.__widgets["ups_authentication_check"].isChecked() : if len( self.__widgets["ups_authentication_login"].text() ) == 0 : sensitive = False if len( self.__widgets["ups_authentication_password"].text() ) == 0 : sensitive = False self.__widgets["ups_refresh_button"].setEnabled( sensitive ) if not sensitive : self.__widgets["ups_connect"].setEnabled( False ) self.__widgets["menu_favorites_add"].setEnabled( False ) else : self.__widgets["ups_refresh_button"].setEnabled( False ) self.__widgets["ups_connect"].setEnabled( False ) self.__widgets["menu_favorites_add"].setEnabled( False ) # Use authentication fields... if self.__widgets["ups_authentication_check"].isChecked() : self.__widgets["ups_authentication_frame"].setEnabled( True ) else : self.__widgets["ups_authentication_frame"].setEnabled( False ) self.gui_status_message() #------------------------------------------------------------------- # This method is used to show/hide the main window when user clicks on the tray icon def tray_activated( self, widget=None, data=None ) : if self.__window_visible : self.__widgets["main_window"].hide() else : self.__widgets["main_window"].show() self.__window_visible = not self.__window_visible #------------------------------------------------------------------- # Change the status icon and tray icon def change_status_icon( self, icon="on_line", blink=False ) : self.__widgets["status_icon"].setIcon( QIcon( self.__find_res_file( "pixmaps", "%s.png" % icon ) ) ) self.__widgets["ups_status_image"].setPixmap( QPixmap( self.__find_res_file( "pixmaps", "%s.png" % icon ) ) ) # TODO self.__widgets["status_icon"].set_blinking( blink ) #------------------------------------------------------------------- # This method connects to the NUT server and retrieve availables UPSes # using connection parameters (host, port, login, pass...) def __update_ups_list( self, widget=None ) : host = self.__widgets["ups_host_entry"].text() port = int( self.__widgets["ups_port_entry"].value() ) login = None password = None if self.__widgets["ups_authentication_check"].isChecked() : login = self.__widgets["ups_authentication_login"].text() password = self.__widgets["ups_authentication_password"].text() try : nut_handler = PyNUT.PyNUTClient( host=host, port=port, login=login, password=password ) upses = nut_handler.GetUPSList() ups_list = list(key.decode('ascii') for key in upses.keys()) ups_list.sort() # If UPS list contains something, clear it self.__widgets["ups_list_combo"].clear() for current in ups_list : self.__widgets["ups_list_combo"].addItem( current ) self.__widgets["ups_list_combo"].setCurrentIndex( 0 ) self.__widgets["ups_connect"].setEnabled( True ) self.__widgets["menu_favorites_add"].setEnabled( True ) self.gui_status_message( _("Found {0} devices on {1}").format( len( ups_list ), host ) ) except : error_msg = _("Error connecting to '{0}' ({1})").format( host, sys.exc_info()[1] ) self.gui_status_message( error_msg ) #------------------------------------------------------------------- # Quit program def quit( self, widget=None ) : # If we are connected to an UPS, disconnect first... if self.__connected : self.gui_status_message( _("Disconnecting from device") ) self.disconnect_from_ups() self.__app.quit() #------------------------------------------------------------------- # Method called when user wants to add a new favorite entry. It # displays a dialog to enable user to select the name of the favorite def __gui_add_favorite( self, widget=None ) : dialog_ui_file = self.__find_res_file( 'ui', "dialog1.ui" ) dialog = PyQt5.uic.loadUi( dialog_ui_file ) # Define interface callbacks actions def check_entry(val): if self.__gui_add_favorite_check_gui_fields(val): dialog.buttonBox.button(QDialogButtonBox.Ok).setEnabled( True ) else: dialog.buttonBox.button(QDialogButtonBox.Ok).setEnabled( False ) dialog.entry4.textChanged.connect( check_entry ) self.__widgets["main_window"].setEnabled( False ) rc = dialog.exec() if rc == QDialog.Accepted : fav_data = {} fav_data["host"] = self.__widgets["ups_host_entry"].text() fav_data["port"] = "%d" % self.__widgets["ups_port_entry"].value() fav_data["ups"] = self.__widgets["ups_list_combo"].currentText() fav_data["auth"] = self.__widgets["ups_authentication_check"].isChecked() if fav_data["auth"] : fav_data["login"] = self.__widgets["ups_authentication_login"].text() fav_data["password"] = base64.b64encode( self.__widgets["ups_authentication_password"].text().encode('ascii') ).decode('ascii') fav_name = dialog.entry4.text() self.__favorites[ fav_name ] = fav_data self.__gui_refresh_favorites_menu() # Save all favorites self.__save_favorites() self.__widgets["main_window"].setEnabled( True ) #------------------------------------------------------------------- # Method called when user wants to delete an entry from favorites def __gui_delete_favorite( self, widget=None ) : dialog_ui_file = self.__find_res_file( 'ui', "dialog2.ui" ) dialog = PyQt5.uic.loadUi( dialog_ui_file ) # Remove the dummy combobox entry on list dialog.combobox2.removeItem( 0 ) favs = list(self.__favorites.keys()) favs.sort() for current in favs : dialog.combobox2.addItem( current ) dialog.combobox2.setCurrentIndex( 0 ) self.__widgets["main_window"].setEnabled( False ) rc = dialog.exec() fav_name = dialog.combobox2.currentText() self.__widgets["main_window"].setEnabled( True ) if ( rc == QDialog.Accepted ) : # Remove entry, show confirmation dialog resp = QMessageBox.question( None, self.__widgets["main_window"].windowTitle(), _("Are you sure that you want to remove this favorite ?"), QMessageBox.Yes | QMessageBox.No, QMessageBox.Yes ) if ( resp == QMessageBox.Yes ) : del self.__favorites[ fav_name ] self.__gui_refresh_favorites_menu() self.__save_favorites() self.gui_status_message( _("Removed favorite '%s'") % fav_name ) #------------------------------------------------------------------- # Method called when user selects a favorite from the favorites menu def __gui_load_favorite( self, fav_name="" ) : if ( fav_name in self.__favorites ) : # If auth is activated, process it before other fields to avoir weird # reactions with the 'check_gui_fields' function. if ( self.__favorites[fav_name].get("auth", False ) ) : self.__widgets["ups_authentication_check"].setChecked( True ) self.__widgets["ups_authentication_login"].setText( self.__favorites[fav_name].get("login","") ) self.__widgets["ups_authentication_password"].setText( self.__favorites[fav_name].get("password","") ) self.__widgets["ups_host_entry"].setText( self.__favorites[fav_name].get("host","") ) self.__widgets["ups_port_entry"].setValue( int( self.__favorites[fav_name].get( "port", 3493 ) ) ) # Clear UPS list and add current UPS name self.__widgets["ups_list_combo"].clear() self.__widgets["ups_list_combo"].addItem( self.__favorites[fav_name].get("ups","") ) self.__widgets["ups_list_combo"].setCurrentIndex( 0 ) # Activate the connect button self.__widgets["ups_connect"].setEnabled( True ) self.gui_status_message( _("Loaded '%s'") % fav_name ) #------------------------------------------------------------------- # Send the selected command to the UPS def __gui_send_ups_command( self, widget=None ) : offset = self.__widgets["ups_commands_combo"].currentIndex() cmd = self.__ups_commands[ offset ].decode('ascii') self.__widgets["main_window"].setEnabled( False ) resp = QMessageBox.question( None, self.__widgets["main_window"].windowTitle(), _("Are you sure that you want to send '%s' to the device ?") % cmd, QMessageBox.Yes | QMessageBox.No, QMessageBox.Yes ) self.__widgets["main_window"].setEnabled( True ) if ( resp == QMessageBox.Yes ) : try : self.__ups_handler.RunUPSCommand( self.__current_ups, cmd ) self.gui_status_message( _("Sent '{0}' command to {1}").format( cmd, self.__current_ups ) ) except : self.gui_status_message( _("Failed to send '{0}' ({1})").format( cmd, sys.exc_info()[1] ) ) #------------------------------------------------------------------- # Method called when user clicks on the UPS vars treeview. If the user # performs a double click on a RW var, the GUI shows the update var dialog. def __gui_ups_vars_selected( self, index ) : if True : model = self.__widgets["ups_vars_tree_store"] try : ups_var = model.data( index.siblingAtColumn(1) ).encode('ascii') if ( ups_var in self.__ups_rw_vars ) : # The selected var is RW, then we can show the update dialog cur_val = self.__ups_rw_vars.get(ups_var).decode('ascii') self.__widgets["main_window"].setEnabled( False ) new_val, rc = QInputDialog.getText( None, self.__widgets["main_window"].windowTitle(), _("Enter a new value for the variable.

{0} = {1} (current value)").format( ups_var, cur_val), QLineEdit.Normal, cur_val ) self.__widgets["main_window"].setEnabled( True ) if ( rc ) : try : self.__ups_handler.SetRWVar( ups=self.__current_ups, var=ups_var.decode('ascii'), value=new_val ) self.gui_status_message( _("Updated variable on %s") % self.__current_ups ) # Change the value on the local dict to update the GUI new_val = new_val.encode('ascii') self.__ups_vars[ups_var] = new_val self.__ups_rw_vars[ups_var] = new_val self.__gui_update_ups_vars_view() except : error_msg = _("Error updating variable on '{0}' ({1})").format( self.__current_ups, sys.exc_info()[1] ) self.gui_status_message( error_msg ) else : # User cancelled modification... error_msg = _("No variable modified on %s - User cancelled") % self.__current_ups self.gui_status_message( error_msg ) except : # Failed to get information from the treeview... skip action pass #------------------------------------------------------------------- # Refresh the content of the favorites menu according to the defined favorites def __gui_refresh_favorites_menu( self ) : for current in self.__fav_menu_items : self.__widgets["menu_favorites"].removeAction(current) self.__fav_menu_items = list() items = list(self.__favorites.keys()) items.sort() for current in items : menu_item = QAction( current ) self.__fav_menu_items.append( menu_item ) self.__widgets["menu_favorites"].addAction( menu_item ) menu_item.triggered.connect( lambda: self.__gui_load_favorite( current ) ) if len( items ) > 0 : self.__widgets["menu_favorites_del"].setEnabled( True ) else : self.__widgets["menu_favorites_del"].setEnabled( False ) #------------------------------------------------------------------- # In 'add favorites' dialog, this method compares the content of the # text widget representing the name of the new favorite with existing # ones. If they match, the 'add' button will be set to non sensitive # to avoid creating entries with the same name. def __gui_add_favorite_check_gui_fields( self, fav_name ) : if ( len( fav_name ) > 0 ) and ( fav_name not in list(self.__favorites.keys()) ) : return True else : return False #------------------------------------------------------------------- # Load and parse favorites def __parse_favorites( self ) : if ( not os.path.exists( self.__favorites_file ) ) : # There is no favorites files, do nothing return try : if ( not stat.S_IMODE( os.stat( self.__favorites_path ).st_mode ) == self.DESIRED_FAVORITES_DIRECTORY_MODE ) : # unsafe pre-1.2 directory found os.chmod( self.__favorites_path, self.DESIRED_FAVORITES_DIRECTORY_MODE ) conf = configparser.ConfigParser() conf.read( self.__favorites_file ) for current in conf.sections() : # Check if mandatory fields are present if ( conf.has_option( current, "host" ) and conf.has_option( current, "ups" ) ) : # Valid entry found, add it to the list fav_data = {} fav_data["host"] = conf.get( current, "host" ) fav_data["ups"] = conf.get( current, "ups" ) if ( conf.has_option( current, "port" ) ) : fav_data["port"] = conf.get( current, "port" ) else : fav_data["port"] = "3493" # If auth is defined the section must have login and pass defined if ( conf.has_option( current, "auth" ) ) : if( conf.has_option( current, "login" ) and conf.has_option( current, "password" ) ) : # Add the entry fav_data["auth"] = conf.getboolean( current, "auth" ) fav_data["login"] = conf.get( current, "login" ) try : fav_data["password"] = base64.decodebytes( conf.get( current, "password" ).encode('ascii') ).decode('ascii') except : # If the password is not in base64, let the field empty print(( _("Error parsing favorites, password for '%s' is not in base64\nSkipping password for this entry") % current )) fav_data["password"] = "" else : fav_data["auth"] = False self.__favorites[current] = fav_data self.__gui_refresh_favorites_menu() except : self.gui_status_message( _("Error while parsing favorites file (%s)") % sys.exc_info()[1] ) #------------------------------------------------------------------- # Save favorites to the defined favorites file using ini format def __save_favorites( self ) : # If path does not exists, try to create it if ( not os.path.exists( self.__favorites_file ) ) : try : os.makedirs( self.__favorites_path, mode=self.DESIRED_FAVORITES_DIRECTORY_MODE, exist_ok=True ) except : self.gui_status_message( _("Error while creating configuration folder (%s)") % sys.exc_info()[1] ) save_conf = configparser.ConfigParser() for current in list(self.__favorites.keys()) : save_conf.add_section( current ) for k, v in self.__favorites[ current ].items() : if isinstance( v, bool ) : v = str( v ) save_conf.set( current, k, v ) try : fh = open( self.__favorites_file, "w" ) save_conf.write( fh ) fh.close() self.gui_status_message( _("Saved favorites...") ) except : self.gui_status_message( _("Error while saving favorites (%s)") % sys.exc_info()[1] ) #------------------------------------------------------------------- # Display the about dialog def gui_about_dialog( self, widget=None ) : self.__widgets["main_window"].adjustSize() dialog_ui_file = self.__find_res_file( 'ui', "aboutdialog1.ui" ) dialog = PyQt5.uic.loadUi( dialog_ui_file ) dialog.icon.setPixmap( QPixmap( self.__find_icon_file() ) ) credits_button = QPushButton( dialog ) credits_button.setText( _("C&redits") ) credits_button.setIcon( dialog.style().standardIcon( QStyle.SP_MessageBoxInformation ) ) credits_button.clicked.connect( self.gui_about_credits ) licence_button = QPushButton( dialog ) licence_button.setText( _("&Licence") ) licence_button.clicked.connect( self.gui_about_licence ) dialog.buttonBox.addButton( credits_button, QDialogButtonBox.HelpRole ) dialog.buttonBox.addButton( licence_button, QDialogButtonBox.HelpRole ) self.__widgets["main_window"].setEnabled( False ) dialog.exec() self.__widgets["main_window"].setEnabled( True ) def gui_about_credits( self ) : QMessageBox.about( None, _("Credits"), _(""" Written by: David Goncalves Translated by: David Goncalves - Français Daniele Pezzini - Italiano """).strip() ) def gui_about_licence( self ) : QMessageBox.about( None, _("Licence"), _(""" Copyright (C) 2010 David Goncalves 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 . """).strip() ) #------------------------------------------------------------------- # Display a message on the status bar. The message is also set as # tooltip to enable users to see long messages. def gui_status_message( self, msg="" ) : text = msg message_id = self.__widgets["status_bar"].showMessage( text.replace("\n", "") ) self.__widgets["status_bar"].setToolTip( text ) #------------------------------------------------------------------- # Display a notification using QSystemTrayIcon with an optional icon def gui_status_notification( self, message="", icon_file="" ) : if ( icon_file != "" ) : icon = QIcon( os.path.abspath( self.__find_res_file( "pixmaps", icon_file ) ) ) else : icon = None self.__widgets["status_icon"].showMessage( "NUT Monitor", message, icon ) #------------------------------------------------------------------- # Connect to the selected UPS using parameters (host,port,login,pass) def connect_to_ups( self, widget=None ) : host = self.__widgets["ups_host_entry"].text() port = int( self.__widgets["ups_port_entry"].value() ) login = None password = None if self.__widgets["ups_authentication_check"].isChecked() : login = self.__widgets["ups_authentication_login"].text() password = self.__widgets["ups_authentication_password"].text() try : self.__ups_handler = PyNUT.PyNUTClient( host=host, port=port, login=login, password=password ) except : self.gui_status_message( _("Error connecting to '{0}' ({1})").format( host, sys.exc_info()[1] ) ) self.gui_status_notification( _("Error connecting to '{0}'\n{1}").format( host, sys.exc_info()[1] ), "warning.png" ) return # Check if selected UPS exists on server... srv_upses = self.__ups_handler.GetUPSList() self.__current_ups = self.__widgets["ups_list_combo"].currentText() if self.__current_ups.encode('ascii') not in srv_upses : self.gui_status_message( _("Device '%s' not found on server") % self.__current_ups ) self.gui_status_notification( _("Device '%s' not found on server") % self.__current_ups, "warning.png" ) return if not self.__ups_handler.CheckUPSAvailable( self.__current_ups ): self.gui_status_message( _("UPS '{0}' is not reachable").format( self.__current_ups ) ) self.gui_status_notification( _("UPS '{0}' is not reachable").format( self.__current_ups ), "warning.png" ) return self.__connected = True self.__widgets["ups_connect"].hide() self.__widgets["ups_disconnect"].show() self.__widgets["ups_infos"].show() self.__widgets["ups_params_box"].setEnabled( False ) self.__widgets["menu_favorites_root"].setEnabled( False ) self.__widgets["ups_params_box"].hide() commands = self.__ups_handler.GetUPSCommands( self.__current_ups ) self.__ups_commands = list(commands.keys()) self.__ups_commands.sort() # Refresh UPS commands combo box self.__widgets["ups_commands_combo_store"].clear() for desc in self.__ups_commands : # TODO: Style as "%s
%s" self.__widgets["ups_commands_combo_store"].addItem( "%s\n%s" % ( desc.decode('ascii'), commands[desc].decode('ascii') ) ) self.__widgets["ups_commands_combo"].setCurrentIndex( 0 ) # Update UPS vars manually before the thread self.__ups_vars = self.__ups_handler.GetUPSVars( self.__current_ups ) self.__ups_rw_vars = self.__ups_handler.GetRWVars( self.__current_ups ) self.__gui_update_ups_vars_view() # Try to resize the main window... # FIXME: For some reason, calling this immediately doesn't work right QTimer.singleShot(10, self.__widgets["main_window"].adjustSize) # Start the GUI updater thread self.__gui_thread = gui_updater( self ) self.__gui_thread.start() self.gui_status_message( _("Connected to '{0}' on {1}").format( self.__current_ups, host ) ) #------------------------------------------------------------------- # Refresh UPS vars in the treeview def __gui_update_ups_vars_view( self, widget=None ) : if self.__ups_handler : vars = self.__ups_vars rwvars = self.__ups_rw_vars self.__widgets["ups_vars_tree_store"].removeRows(0, self.__widgets["ups_vars_tree_store"].rowCount()) for k,v in vars.items() : if ( k in rwvars ) : icon_file = self.__find_res_file( "pixmaps", "var-rw.png" ) else : icon_file = self.__find_res_file( "pixmaps", "var-ro.png" ) icon = QIcon( icon_file ) item_icon = QStandardItem(icon, '') item_icon.setFlags(Qt.ItemIsSelectable | Qt.ItemIsEnabled | Qt.ItemNeverHasChildren) item_var_name = QStandardItem( k.decode('ascii') ) item_var_name.setFlags(Qt.ItemIsSelectable | Qt.ItemIsEnabled | Qt.ItemNeverHasChildren) item_var_val = QStandardItem( v.decode('ascii') ) item_var_val.setFlags(Qt.ItemIsSelectable | Qt.ItemIsEnabled | Qt.ItemNeverHasChildren) self.__widgets["ups_vars_tree_store"].appendRow( (item_icon, item_var_name, item_var_val) ) self.__widgets["ups_vars_tree"].resizeColumnToContents( 0 ) self.__widgets["ups_vars_tree"].resizeColumnToContents( 1 ) def gui_init_unconnected( self ) : self.__connected = False self.__widgets["ups_connect"].show() self.__widgets["ups_disconnect"].hide() self.__widgets["ups_infos"].hide() self.__widgets["ups_params_box"].setEnabled( True ) self.__widgets["menu_favorites_root"].setEnabled( True ) self.__widgets["status_icon"].setToolTip( _("Not connected") ) self.__widgets["ups_params_box"].show() # Try to resize the main window... self.__widgets["main_window"].adjustSize() #------------------------------------------------------------------- # Disconnect from the UPS def disconnect_from_ups( self, widget=None ) : self.gui_init_unconnected() # Stop the GUI updater thread self.__gui_thread.stop_thread() del self.__ups_handler self.gui_status_message( _("Disconnected from '%s'") % self.__current_ups ) self.change_status_icon( "on_line", blink=False ) self.__current_ups = None #----------------------------------------------------------------------- # GUI Updater class # This class updates the main gui with data from connected UPS class gui_updater : __parent_class = None __stop_thread = False def __init__( self, parent_class ) : threading.Thread.__init__( self ) self.__parent_class = parent_class def start( self ) : self.__timer = QTimer() self.__timer.timeout.connect(self.__update) self.__timer.start(1000) def __update( self ) : ups = self.__parent_class._interface__current_ups was_online = True # Define a dict containing different UPS status status_mapper = { b"LB" : "%s" % _("Low batteries"), b"RB" : "%s" % _("Replace batteries !"), b"BYPASS" : "Bypass %s" % _("(no battery protection)"), b"CAL" : _("Performing runtime calibration"), b"OFF" : "%s (%s)" % ( _("Offline"), _("not providing power to the load") ), b"OVER" : "%s (%s)" % ( _("Overloaded !"), _("there is too much load for device") ), b"TRIM" : _("Triming (UPS is triming incoming voltage)"), b"BOOST" : _("Boost (UPS is boosting incoming voltage)") } if not self.__stop_thread : try : vars = self.__parent_class._interface__ups_handler.GetUPSVars( ups ) self.__parent_class._interface__ups_vars = vars # Text displayed on the status frame text_left = "" text_right = "" status_text = "" text_left += "%s
" % _("Device status :") if ( vars.get(b"ups.status").find(b"OL") != -1 ) : text_right += "%s" % _("Online") if not was_online : self.__parent_class.change_status_icon( "on_line", blink=False ) was_online = True if ( vars.get(b"ups.status").find(b"OB") != -1 ) : text_right += "%s" % _("On batteries") if was_online : self.__parent_class.change_status_icon( "on_battery", blink=True ) self.__parent_class.gui_status_notification( _("Device is running on batteries"), "on_battery.png" ) was_online = False # Check for additionnal information for k,v in status_mapper.items() : if vars.get(b"ups.status").find(k) != -1 : if ( text_right != "" ) : text_right += " - %s" % v else : text_right += "%s" % v # CHRG and DISCHRG cannot be trated with the previous loop ;) if ( vars.get(b"ups.status").find(b"DISCHRG") != -1 ) : text_right += " - %s" % _("discharging") elif ( vars.get(b"ups.status").find(b"CHRG") != -1 ) : text_right += " - %s" % _("charging") status_text += text_right text_right += "
" if ( b"ups.mfr" in vars ) : text_left += "%s

" % _("Model :") text_right += "%s
%s
" % ( vars.get(b"ups.mfr",b"").decode('ascii'), vars.get(b"ups.model",b"").decode('ascii'), ) if ( b"ups.temperature" in vars ) : text_left += "%s
" % _("Temperature :") text_right += "%s
" % int( float( vars.get( b"ups.temperature", 0 ) ) ) if ( b"battery.voltage" in vars ) : text_left += "%s
" % _("Battery voltage :") text_right += "%sv
" % (vars.get( b"battery.voltage", 0 ).decode('ascii'),) self.__parent_class._interface__widgets["ups_status_left"].setText( text_left[:-4] ) self.__parent_class._interface__widgets["ups_status_right"].setText( text_right[:-4] ) # UPS load and battery charge progress bars self.__parent_class._interface__widgets["progress_battery_charge"].setRange( 0, 100 ) if ( b"battery.charge" in vars ) : charge = vars.get( b"battery.charge", "0" ) self.__parent_class._interface__widgets["progress_battery_charge"].setValue( int( float( charge ) ) ) self.__parent_class._interface__widgets["progress_battery_charge"].resetFormat() status_text += "
%s %s%%" % ( _("Battery charge :"), int( float( charge ) ) ) else : self.__parent_class._interface__widgets["progress_battery_charge"].setValue( 0 ) self.__parent_class._interface__widgets["progress_battery_charge"].setFormat( _("Not available") ) # FIXME: Some themes don't draw text, so swap it with a QLabel? self.__parent_class._interface__widgets["progress_battery_load"].setRange( 0, 100 ) if ( b"ups.load" in vars ) : load = vars.get( b"ups.load", "0" ) self.__parent_class._interface__widgets["progress_battery_load"].setValue( int( float( load ) ) ) self.__parent_class._interface__widgets["progress_battery_load"].resetFormat() status_text += "
%s %s%%" % ( _("UPS load :"), int( float( load ) ) ) else : self.__parent_class._interface__widgets["progress_battery_load"].setValue( 0 ) self.__parent_class._interface__widgets["progress_battery_load"].setFormat( _("Not available") ) # FIXME: Some themes don't draw text, so swap it with a QLabel? if ( b"battery.runtime" in vars ) : autonomy = int( float( vars.get( b"battery.runtime", 0 ) ) ) if ( autonomy >= 3600 ) : info = time.strftime( _("%H hours %M minutes %S seconds"), time.gmtime( autonomy ) ) elif ( autonomy > 300 ) : info = time.strftime( _("%M minutes %S seconds"), time.gmtime( autonomy ) ) else : info = time.strftime( _("%M minutes %S seconds"), time.gmtime( autonomy ) ) else : info = _("Not available") self.__parent_class._interface__widgets["ups_status_time"].setText( info ) # Display UPS status as tooltip for tray icon self.__parent_class._interface__widgets["status_icon"].setToolTip( status_text ) except : self.__parent_class.gui_status_message( _("Error from '{0}' ({1})").format( ups, sys.exc_info()[1] ) ) self.__parent_class.gui_status_notification( _("Error from '{0}'\n{1}").format( ups, sys.exc_info()[1] ), "warning.png" ) def stop_thread( self ) : self.__timer.stop() #----------------------------------------------------------------------- # The main program starts here :-) if __name__ == "__main__" : # Init the localisation APP = "NUT-Monitor" DIR = "locale" gettext.bindtextdomain( APP, DIR ) gettext.textdomain( APP ) _ = gettext.gettext for module in ( gettext, ) : module.bindtextdomain( APP, DIR ) module.textdomain( APP ) gui = interface(sys.argv) gui.exec() nut-2.8.1/scripts/python/app/NUT-Monitor0000755000175000017500000000400014500336654015062 00000000000000#!/bin/sh # This script wraps selection of a NUT-Monitor implementation usable # on the current system, using the historic name for users to have # a single simple call. # # Copyright (C): # 2022 Jim Klimov # # License: GPLv2+ # Currently we have issues using localization for py3qt5 variant, # so if both seem functional, the wrapper would call py2gtk2: PREFER_PY2=true # Detect which variant of NUT-Monitor we can run on the local system: PYTHON_PY2GTK2="`head -1 "$0"-py2gtk2 | sed 's,^#!,,'`" || PYTHON_PY2GTK2="" PYTHON_PY3QT5="`head -1 "$0"-py3qt5 | sed 's,^#!,,'`" || PYTHON_PY3QT5="" SCRIPTDIR="`dirname "$0"`" && SCRIPTDIR="`cd "$SCRIPTDIR" && pwd`" || SCRIPTDIR="./" if [ -n "$PYTHON_PY2GTK2" ] \ && (command -v $PYTHON_PY2GTK2) >/dev/null 2>/dev/null \ && $PYTHON_PY2GTK2 -c "import re,glob,codecs,gtk,gtk.glade,gobject,ConfigParser" >/dev/null 2>/dev/null \ ; then echo "PYTHON_PY2GTK2 is usable as: $PYTHON_PY2GTK2" >&2 else PYTHON_PY2GTK2="" fi if [ -n "$PYTHON_PY3QT5" ] \ && (command -v $PYTHON_PY3QT5) >/dev/null 2>/dev/null \ && $PYTHON_PY3QT5 -c "import re,glob,codecs,PyQt5.uic,configparser" >/dev/null 2>/dev/null \ ; then echo "PYTHON_PY3QT5 is usable as: $PYTHON_PY3QT5" >&2 else PYTHON_PY3QT5="" fi for P in "$PYTHON_PY2GTK2" "$PYTHON_PY3QT5" ; do [ -n "$P" ] || continue # If running from source tree... if ! $P -c "import PyNUT" >/dev/null 2>/dev/null \ && PYTHONPATH="${SCRIPTDIR}/../module" $P -c "import PyNUT" >/dev/null 2>/dev/null \ ; then PYTHONPATH="${SCRIPTDIR}/../module" export PYTHONPATH fi done if [ -n "$PYTHON_PY2GTK2" ] && [ -n "$PYTHON_PY3QT5" ] ; then if $PREFER_PY2 ; then exec "$0"-py2gtk2 "$@" else exec "$0"-py3qt3 "$@" fi else if [ -n "$PYTHON_PY2GTK2" ] ; then exec "$0"-py2gtk2 "$@" fi if [ -n "$PYTHON_PY3QT3" ] ; then exec "$0"-py3qt3 "$@" fi fi echo "ERROR: No usable Python interpreter version (with needed modules) was found" >&2 exit 1 nut-2.8.1/scripts/python/app/nut-monitor.appdata.xml0000644000175000017500000000431414501607135017473 00000000000000 nut-monitor.desktop nut-monitor.desktop CC0-1.0 GPL-3.0+ NUT Monitor GUI application to monitor UPS status

NUT Monitor is a GUI application to monitor UPS status, through NUT - Network UPS Tools. NUT is a client/server monitoring system that allows computers to share uninterruptible power supply (UPS) and power distribution unit (PDU) hardware. Clients access the hardware through the server, and are notified whenever the power status changes.

NUT Monitor provides the following features:

  • Automatically connects to local UPS if there is only one managed
  • Command line options to start hidden, load a favorite, ...
  • System tray (notification area) integration, including notifications
  • Favorites, to store different devices
  • Display all device variables
  • Modify writable variables on UPS and devices
  • Supports English, Russian and French localization (Python2 version only at the moment)

NUT Monitor requires that you have a running NUT system, that you can connect to, either locally or remotely. For more information on NUT: https://www.networkupstools.org/

https://www.lestat.st/_media/informatique/projets/nut-monitor/nut-monitor-1.png https://www.lestat.st/_media/informatique/projets/nut-monitor/nut-monitor-2.png https://www.lestat.st/_media/informatique/projets/nut-monitor/nut-monitor-3.png https://www.lestat.st/en/informatique/projets/nut-monitor david@lestat.st
nut-2.8.1/scripts/python/app/screenshots/0000755000175000017500000000000014520277777015503 500000000000000nut-2.8.1/scripts/python/app/screenshots/nut-monitor-1.png0000644000175000017500000013253114501607135020547 00000000000000PNG  IHDRl][1sBIT|dtEXtSoftwaregnome-screenshot> IDATxw|^ݥH "bڱbŮ+b"H{M!R"BLv=X~:KYE(bú_\,B!B>WQdR eY/_Pf3p:GB! ²p29dZVvlP?0F8d u,BqluCćjmx БnB!ıKA2 -NNGt8Mk:`H7Q!BmQ^BaY&i0u_~îG TјZAV F|l,AM-$'D`+m';= n@VF&5\NZDЌB[`M7~YRNwRio;^D_MNZx#oEd !GeYhuZ e)dI-hlA-IQƖl&!!le)20h)8,k߱ o3Hb폌ɻkwYDdR4aldg8o{vSZrۛxV>ܪ\Qy6?ep܃cm N;&=4&ۛănw3l,$gFsi{듬םn<\O~}43 SHxg$GDP?4$ců-´*ZˆV5vFЯyc>Ft:@4q:6l@NnvM^cSNPcpX+*BQzFK+>t(z=\,AKFqOhXDWZq 䳱 5a<7{Y'R*|~ :EhQQQ=ev,3NR,yg|QNdžY01N3!oNNE &qB!D͔R'l@1 kkc:vVxCp8L3[_D0 c24)]\@hbse0nP(|@ki_rrrjxf4LgL`ft|g21*UU|])MSX!9UXd5 }Nw4,)=n(\}S\T8v =# %]}Эk(toxlmi3rڽv+We&s2s1Q"\% !>6m~C\>KqsF4ۊ+ocY屋FSB巿7oAݻgNc*^5ց挛@nsW25VڤZ b;U ~Yw!Mb{[㸂ٌN@i$Om$E{| M ;zؕ;Da>K.4 ىYS^$/S`ⷩk0\ !bJΜh7&FY -N^ٜKP/ŤҎznQTGʓSRcyye {Ҫ*a;ցr70q,^y.}ZJnX%Uc7 k%WWQ5U)k/qM&nP[}CfWIzTn 5 ='H}7X ˦PETYLjH VE C'$lB!!Φ0],/@Myj&jh"471t[YlztFjFAAn qi׫u~?[.^Ph *`WY8riY:a=:yiuJz*@ Ekf4*FVL *͸L 2&V+1, 3PHtr<­X㪊]{u5cn@WeB!8T9$j٘K}UGjG{7YN…^xyw3lCK4f(nyZL0 +_-6F81fYDFFqқ|!M) 3gv:sgOb=]9qwm`|"| !Q[h+ecaBYdΟ cm߀?Mz4[I֘W ;B!ߡf2&pëqO@Y84R6g4 Q Ɯ"H;VIlFvNII8J4M󑝛GTX}1N^nnWijc(ph|WyDSĸuv}2O85ڰ~Q~1\aY JUnƦi ?AGNCÙ?gຫ杫\,U1 3r\eZwu37Q>Γɏq5 + J)^z!BR AjA(&&X>" >K(nn+BaaVZOh%V6bh]@rV~k+&ND(l>%kl nQu CXa?InU'WMaN)1>°@^:5Bv~Ӄ/76 Bfa!xZdЊ*.gHwyyaTD2E9 EA~p{3_n: 5W!Bβ,AOD !?%(~biƦ1 gxA,RSSq:%TPIK `ΝvXb !BEe <8*YɔaՐ=riIN^ !I|2)#$PӽGIs0@?cxW4@weO8ƽˬӸi [t#/hNlB)I؄M$61ZHz{ѰG @z';^=!>\Xِp>=WuE_=-YnI=s7dMz%:gX!ĿU󖭫`az}5w wxGq=ܹ|Zw'Q^^ztO]=uzJ+bl@ޜu,^ŀ^}[e@lÜ>Z2wt.wĩbӆux!4Mf"HHH@mΝNl\,6c_q]6=#_֓moegVY[,0Av[M)]p^E g+0b 0yٕwMCiEvG#t9)jb0g6‰Eցĩ"aA;!ı }NvIfg1qq8 !. Oyo {MF$Ŏ;'҆rؖJD¦(\6GGtq5,\nlI=SI6 fkFY%={9v.˗lpu禆u@q*)BRiahҼ%7#7'=ߛKtlNS5!ġE+8ŵyi6[uObϴzZgmҳmA$l\U؝e@1;o~ߌTsV/;n2ԍ>q:6!ā R 1 ]5!!93Yji#V?OdN ؉mҙsn< 7E_sۆ/LyB-N 8{pwx"Eg͈ݰwP#.}Ss>Ǖ_`!8f8L˅ihK-P) S^!q=\,!BQI&BQI&BQI&BQI&BQxgf,^/99B!ġVz*wdIhZ}i5&l۷o#Af͉*BqRE gرFT[ڄ-kO&6Cy(U5MC>4b'Bq,Ay^TziTpFh޲5֬"+k {ŭ-';FMZUyd !BRr[ŤFMgOa \WQ;QܭW5B!8V @J)'UMڜN'pڸ&lULP f5iBTkNm\%˸;tsⰨ'UP]@u,Ӭ6^ [5UbvUmDI qګ;6ӺEVX% !1GQUAsJRkZYVU=l%(WL bYc͚UY0}ueZv#BqEUS F*$a+JP4[\Vi[m߮G^y<7nDsO7lʗAHG-XPỤ*sPzYD*C}!E0= gxx"3u08g\4 O^6jnR:w97ePK̇w?IorgGǑn0ػS|율~C{*VBٴ鿑瞏f'""ߏaӹry^Ldy/VP||Ʌr63{^~3z0$G@'G^AϫBQ?zHBdhTۗ_}mFG7ܼ¡@pْ0"U:8bs%֣=)p|jNL| xUޟ=~i~pg4wa;ƽ-6{<9a-\?9n»+ޚܩ8Zn8_sȅt91n% Dp iMۚF@Ɍ7yQ9z? Zmap4s~ixz=C0''8\.[M .;;_;!UJ7*υG/WI GY%s., ݰ[JUo|燊Sn0J->'KH wi=M䭅e;#yf,T~_.~ϵF[ ?4<5{"/whg>>'/1*X_'xj\G"-/0~~ok];/?QLx=mʣOrﰴڶ|r,?p?+{oswg'iSMY.V6U)J࠮UXV*dlr奫JdžzSFAP܋_˶[% +)MD |U2)WwFa.g/3P=q|iXI޲_Y=gh%Ԋ̒<Di&zSEl O-vLd$e U8U/JhB)0ԁ^tP%^ɰWYKiQcO?OC{"=@͓eKݗBZ}Bg'f ( {۫y/짏yG5E#Ԇɇx0, M?QxxlX Aw(n) Vͤ =3{2 \ &"#[C[,*[r_Jq4J.,;_R8+RY%p?*S%y !.o >>A(*Y;\.ⱛ7fāp*_ͱt(Uۤ9DwBnVjKF~9Ym"ϼ6=AHߍ7dkX-~NJHZP"t"n˦JڡY%v+ڦNao&Yf4%kjhٺ\} !F%%TM*SAUIjRezX(Kat-˪Q\*".8vEVmLRbIIONA5 4oT(_x"kO:;מ狼V-B3VDcvAtAN)䯛Of錤~ρ4Kl$/`4|;O~ٌvU5mӈzmVQh|޻fF} gKǡޝA<⟧|he8KNg{Tqt; L6uӧO~@8EU6}Oװ_s]Y(fkwpSF#Fq+x8t ܼ >* i;1ia҇"| knb#Gxݧ^n^W:YRcibO sa>ʈeky6͸ۢӻO2û幋`g>*!D]i,4ܫM[hJi.{q_8s (*޹$zR嗯ʨG?τ [&]:wQٳgznV.u|$Jl6;6{j)˲0nw` pP(@7t44,U\,Ql6t]GØy еmiū_ueF̰Y6ϷW}iPJÁ(*sGҏj s]u]ױLkN4a岿jJPUmWr/iZ!QK)od鲥lܸs璕QG]Ӵd ^($ `0*k`aL3\p8L8MWTT@jm@AqP~/QҳVHŻ*#ُDK'nTa+RUiQ!ja3\tuЁ:҄^R}nXM8uǎHd Q|{O ]V^+.Z>퀮-]Gœ5Ud[y95[Bq6SFꑔP˔ !14/(_VJZJkZ s,u`8N$*2BFV2Z2wrԒ*7B!8TSC+˗Tm*NJٳYmjؼ~z Re#fOՊWu,[,% "D IDATB!UUW(͓*^\&M[m֢U+79fҲu[SU(Z-F!B*GPkGisPʤEVƭ6a3 y/o@!BT:.M[мe"0f aвUZj϶T!BJl! wi!BqXl6 lQ1dpb%B!2 Af.bbrUh$֫GTtnB!1K) GڮXEмyJ)\ss Us!Bqxhf':&8䢃ܜmBaAmBuH7G!u-7;kWӵ{Oe,"=mVy֒ !V۶ҩkwn Y C7XvuYV%#= [xl4 gD'2*H7G!Dn6*J)_(NvlFf͉CӥWb׮4h$mB!,eY%pu,QHQD$> t .>Mؽ{7-%aBQG-&l?*6M8$baRDEDzm#!F+JvD)0 `0prL0%Ba% B.78^O%o8 !lP$HpU=JzzK26!u19$|6hHCBkHa4q՗ѿo-k}wןb`7"&>i5qCXʛ9B!MQ{ǎfssG!|[^+/<̙ =Wޜ~x:y%;j̃GYgV|I|Μ| &;^2=7__Aۮ{aHI؄Bqs`st$Ļ&'ԽwU 3n'3aWٜ4׹1~؛:cɸz 5^F30g{1K>}.CZjV"f% f@beH=,30f<Ũ1qf&݇zek;{[Eo>Ήo{C VWg{ q 4;w6s2 䧱z|:OmAjE IpiGE)BlHt]HUS}B2-%-ԉy/o=۶4ƽmwC:EƩuQh,5WuHm${9>n*Ó1'SpLXԐ?qg4kmUnSglFH2~?z\5|ydĺ>j{uNJ*ʇE{fӾCv-IgȨGb-gi*?R`% nzD㧵yeϟd+D\_eN" ˲5:ˆdwd:ʐqBUjYr(k3~_uZDvi##7 i'g<" :>+׵D&})Ͻ{]Xi mŭ7Cq̢環eq?⩏ X'6] zH!Xô5$cG|l3fbn*M%&23sfz J"/eguVqWR\̚[":pY}KYe *heSXIs[m-J=^:g]-,0;oGr?q)I(2%kNA c&# Z]1vE:c.BF7$¬x.n(}nDӨs?n}"I&<#>G17h[L}jc>g2oj~~_oOТ晴\:CG($t7m~r7C8j@>L/ҞsႥcyУht.OwT+s5;ay_As8fUަ, u=lpAyPoLcvasIf)<ͻ:m:.hY7$`#+64׎:Eg @YI&]hi [sa|&O_AaWsY,#CG˰4KRzho|:WIx7Qn͉SW~ M!D7jgMǏԟIYb-Z&P_xa$6mO߁'.^*|䗩 XCR:Aw'ɠ/{I'S]N(mO.`]VUpj$ھWU}}ʿ?[ ]kՍ,dF@?I7\B{fȴe;k8bmkŁtFq:w|{ !$lGPՄY9͛6H&9lP[{]< 7(BFcYU]C#AB\t >9B!:=ٲoe=Bu2$zDɐh] \!D]g'IvKx̙5ܜ#Q9!Gx<4nڜXl9D\}#ݶc&!zHh٦\tpI,Bv;`unx !BnWtm߶# !B֦]G4Mò/a+*,$anB!~qܸܞ+W.a+{ B_¡62M!M!M!M!_$n vRV!u1)l".FF䁋.;eyHotv'?1]CXcӖ'$s&ϯXV*~ܸ> ǯ϶nQs78\BLV..' M|58zvi@vhZO4Mp>5+_4 dHjRS, _VfkNDcXINCA1:BG:l5̅#F &/ͧK|o4 ox{·,Cj kOc#7D+\L.>Oour_Om(|[ϙ6.R e%V3Zᩚxo+D/mfAWҗ۪ycl6噀ng1bD/P^>Wg6F!wU]Q,bvr\yB}c, Ʒ?#e\T5ώ@ ϼ7gJx$}ݯw'~<4Y|Wt&J &Ƴ !8܎ 4'M!ذA0'?eAfC]| 7d3fN]i[ әCPPż[L]k9zd.g^]51'Ь"8^~Uv \)_瓥H ]} g)7]}t1ؽxбJN1R< t֚;$Al5 Jo_̚=Rѧ" 'BgW1k4OKUR0XJ^z{p سj1{eȃ1qv |iovixar܅;XW}i W."ZKCgl Q{ :#vU)%XӶdݿigAjhkihy~/[W lACEA6/ݎJ'I0*"(ϫu +y! M sy]o`i-{*6|<L"m"+4kOmKK+o.~W}{B!c>a|yDai^6O'V(GϬns n0Cڸ|R D%Gd#'X3:Whߖ3LpVߋ blqYSe=fY>}@]xl@wJIh=YJ_w4$V0;:9n"˛ m]|*zF_T]wdyPsqhJmD7]4`f:?MN`n#zCIygN. #}EIWe0eA:69:rqӈzMkO#[?2h|v= Vm:Z@K%MBQc,&^)?>^֕M3٠\VЍ+XDHVy McNhyϗa2v@GI;me v09EEYt4KD3$9mZ {E=wV=gIL|ƀ9)r K9eIb|l_ЗōΏ#Ckb|[YW?*3"]3Լc$;e{ۯen5KpDI f7 &"g 3f 9v2K#,g/8'")Й75Q>g1h3mr٠el@" POefE@dQl,& wMIv.MY^IT!Kx8羻8~qFE}N\07'`rtvX{BkZq>8h8nQi9'7m#ol:1BY g|C^'YG1L՜αܱFS+͈BY]VI9 >jzݓIlMtәڝFah'?E>g=hcظݎf K(/:M#8 !'{ ,=w'Impesz4ɖr#1U`z \yk"Dzٙ_] $U?y_5~3ixE\3b1:h0t$LIW߫r96,r-g,*OI'tlH1B4t&^w*'La7HqûYUi[I$9t#b^ѥs|D;sfxtkpjH7}7=^޽8חF7o2KH[CiPYyX_DE_ɥ_“ܘ'IHWan"2%Qn&erb[b8Z7ugV'vggz7FBY?|=ϷkW a*ѱG)B 6iL'[7=WčoC!dY/ڴ/BM! 4,I {{{B!cpHT'm./w]6Eu{q4B@6!(#7<ћkp !G !Bq !Bq !Bq6O00 g㣨>lI6BGVTT]ZQzEAPAc/\AEAE, (%!fD/ݙ3IT0pp$<>˲px~?uQCtWqH v-I2>^gnZ*^%3mls 3bz˥w>"K3G]́LjO–3yʢ5#c q#Ex>(K䵼;|$SS@ IDAT{M([ ?5*cvE{Nrec#v%u|:1>{o}'oD;yx 5V v~* ׶ B!vnܼ\TKw=ȇ&{jfN\;.3NNmd6N+K܏15=+g R4[;| Ռt|۫F1H>fYg@c l?5zC6v@3]ra9]’XN63ӆ}h"1.i/n0^fF)=YX.O]ٵ-B{v;ieŚeѩc'bB1(ETDJ")# 7RY *QtB\aŪ,mM7k!Y_f&Tc9|[|#ne\5u/,)ߧdC±7r cX{%c~]hqэ\7;嗏)(gmY!z$d/#3}N╯qYMp~ܸc=+58e)#F Xn}s5.3 @;Ey/cn{(?phBoO $Q<4}5? <{ 5cW 9[ya!wVgeBQlG.Ͱ(jMEfyTVVPP1A 4cĦp"MW<;Y?Z&|6Gٺ 8@NۜB&-[rJQV'Wשr`aRe^g7;u*: *}:P> ֜z*ş, ؁dX_n ҫX[BX4:~(tw@1,0L]v?WwrtJc;[-P]l,ǰiesq$6 \rx#ocď7mQ1&xo<_'"Ȯ޿]LB!jہu\Z )娠CLytޒfDƠ4 JcX\/O_pE)1^n_Aju8-3t鐌)gbū K'N-]F$D VQ,L(PA\zPFsCPv)IYilͭk߇"O1}Qs S16ktK҇|2e'\ډRXd:-F*YdgbNXFmGbv4I";ѳo'-t{Ɖ|RpPo1 20{{vsӔ};$6<|BʣȥL%t>!R_%x P(RxxxZ43%R HhˡM`* 3fXTlzUױ?=3m5|9:2_s}9$gfOMOMW<ϡEiK,}U>0NI{ Y*=<[:q;#v?; /k:+Ԗ1qVz:ɼĢqhI[wh3MJ"fbѭ{6o;SΣ?u"3m]Su8a2Lr]0M>}qmك}GX'p0O0)//36 qٴG䮎RlK zu? DoF ]xoywɭp!BNݸS63'omΑNr^Cmy^{!>)q?w_Hͭ\z^|FDa%> t2_9]ݿ͟VgeBQ+5uڰ~קH@;61* yhFi ,4hC`0s5&`e4,^3ٍsHHHK#BQ_,Ҷ}G•|WuP.*SQl"(l<:y A)POkЀChQGY!ba(A S<4 &Q548ūŐ>lB!uILU5-czk. XTE\Q@)JaMB!uSL@DD R̙_¶46.JykwMDilQ`+[yکn5M!neb+pT*DqЦ'; Ԭ^VOG&Q6TxFu_6!B}O4uUuvKE !"&xhT ÷,!Bvi*oD=p'XCpqpP85M@QEl4aOyY|W|f0 !8{9MV97ı+h"/."Zsٸ蓾נȫk19!ck=uw}j1\ULKsq5py^٪KxⅩϭ,w!WuKnVlqD 2L5ә0%/+HlMsa1 HwP!أI  iVr0(X[Jƴ we aX耉MRf:NӴ0ak(;o 򓰃IU.\t} |z@37-WeM>g&rxWY[#f@|Bnyv4w/pO_8s{طj'o fmq~zV]vt=6],^ZH?:PccoD E7N2oBSC&LxYС&v\qr[j]HcRs2&@U3r8?ݼށkxy]8aӪ ^u oQn}h"kfRW2ZW/ Oljp1eZrE\'_2W֙Ԁ.gqߪ.~NB!ݯP@ЏiMS& #&ak}`5)4&`ò(CqĖtx9 ѣyla>ZO}W>uʳ_W81^#ˍ7wBZb|PZOg(YOg#滺ir4ɭ2lk$қ9?>`ȅ/\pMw &Egͅ'5\|@`K-r=rf3~_"ի$&kSg̖T._[\!Df>O;ht(6U|W6\\\</̳q3ߏOHj'f90J~fFEcx>dEs0/ؓA;쳈o՛s%`\jOlI۶ϿZ ܸc82kJO#O4`"3-Ulk=vMΑJ73}+ϻg^G׏gyШ?4Jlk?UſFAa! n7ZE@(nHP`0OWlge)mL]v?Wwi#6?[/}F Ư Xi3xקķǙWriJq2[YV.e.kJcO5J' H=v ֗+WT]\O+SSkz+¡1Ѽ0lejh?aQb_Fߖ$.>e:7OM~ l|6OA};;)+j m"bϲ} p0 W),ħL5 Z5 :؋(YdgއmWyB+=1UEЕ@J/Ϟ硉atI ȈQȱ4vYN"B׾DbqbCs,z ~sZn Qkw){ ܢo?r VToah;2ئ]TL幛5* 4G3TnxBZl b6q%ȋBc %6m[\!DDL&& > қ%lXR$by&gVu\0-DK ((QLxWyկXq(^x9—xgbMHM `,CۢLbGcϋw\]o,qsl~wÌ /k>y~F΍HMMydq}i1R燦rˀV$^z#ǛlsNҦ&}eKŲϘ~.͏9f -w/NYL`<=!Uoˤ~ `[L}Z,!i=L UxX5aEsٸ㸻kF9kut*.jeK^C,|ftxWN[w*p,zʭ\sl&\q^|1{0MC˙. m&Һǥ~~;vXC^]O:6k0å$u9ͷffv^湷?瀜Pnz8kQ:p-Y4t<ׂ{Ni@3Xn& *!4!g03qH'<ů1[qEw1[/qcrt\ 6ʔBSS'؟H8k! 33cCPj,$B&]E-h9KE8GMGF bUOc9<LvY éqLy!{cmpe}ULa-4`h^MO4U4N q1~nyDK0]Ea<}OB!<| CfzPA<KRxnuȃIse\!BL]=hBiʼn,g6hY41ծL "VxB!?, < ⏹<+8?7 *EAa.Ճ3B!NuPæQ9v6>[=S&SPG6i]km< P di*!Bش(p]e)<\GM4Ǝz9 &5p5uGdn]7yߦqrݍcAllB!Dyxb!Bԉ2-ea}A!um]=y_"JKKh}I!kiĆ"=3 4wx^ğSҥKz1++KXB!˴PX̬וUM:дY 2m lիVg?~gAC'.B\ǎRYRL)ٓY{ضMNf#mUX Kk$id5i[Y* wBR(eKbZ:yW1z3qq$%ls}繬\ /8t\]B! F;iV%%!1زO}Paa!?aTU֤%NYᦰ&B[ZDFFK~X69el}PYi1O3I,Gn}I!ا9 2Yw6gBvY붨mIhmGHB!>MWU^hU6[`ӥ3ϥcX*CO瀤.{nΆpcGsz}[q8&IKv vqy}FgsnK :3aeCů8./ 5ۙWsr7a]U M<<~k$YyJi;|Ķ=w͉ndxG IDAT޺&>:TS>I`1MLD3P} *D 7a$"K%K "sm𪭖s"FY~p#x]/Z>*s$D= zP-c]3}粏3[uS={(w~&c>sdؐ[嚑Doˍp̭,l+1^!k'<~pK‚;t#"~ϥrD^%_:z_؃ [~}>0[aPFքh0<b`3b89K|<82Qw#3Xn};YIp &ɱUav\/Q4w =ֿ#>Uo7ۦ̥J̡qH2S//[I蔰ui,?NhKw(UfcN8hZ&Zx[ KGZ6}>eYqq>|-:'6$SWC˯B#.O45Z+v5CGCZ޲?[ٽVN;%Ğ#;j,K'D<<F l"ј@vf4]|Ĭ9=>~W?[HJqV]w)+-nRV.e)5ߌݓs<4YUtrRx/ԖpJ#؍/&hC\˦D)Y[J1b2miZh>lB4U@{ ZirVv PN's*?L$p.DY`~G.WQ ukDg nZeZ |13\&7:Pm6K ȈQȩ]GHJ7#cHs~{`k[KLBP~pa锷9Dn]<6Z6$>+{9bM@G(Pm}ڙVu]<&D4/5?fdupsr\j%f#3Ƒ-U?N~?sBmyڭnaۅvPPP@AA>~7'~JqQt0Vq ! xuX(r)Ŷ&>-))v4vx2#靵7^յ7bj+"SoڗMu)]ϼ%ynk٢$dޛeҌTaV|Wh?w]:̚yÊ-7MGxl\f[2}6ۦ5oe_2t$N7!*yc~x4>l^%_7nٝrc螗pƼTw=3z++r;Э[ӟm}~OnZ΄FpKeh3=.S`۲v\^xkA`;E6R{pÐ"O/T[pC9MmB-2wt-GmU~rlA7>od=܂<~/NNkwyuO6ߟ5JmTB!Pu;_bDqp.B!j!B!8 lB! 6!BN V-idf5aW  >&#=PNbC]41$Q֮Ym4iVQذtFMVverpI}B)X[O !XڄBEٍs[K\\ʟ*HKO-+D.uqKT̝Q߷P!s~ۼ&5lbܟfSYv..qd$'nLBSB!\(-Vt8n q;[l_MBh;;Xl!UŇZK}E![~Ja lƻv:]5:g\ĿlL.1ll 7v69!8{9* ~ǵwÌ.D nE)1A)?7TVrڽW1Xk^ymfĈoóo+fkyu~?./h*ßWw#Y: )Jm7}_J3.bmH5KY<=6VV^\/n&l귶'1s=/Q.^t ,?r;I>htx gݗss.9?=o∶}V9tп$ ƶߤ{\`e?H?ҨRI=ܮGoQ|L붪ڬ&Cbi߮Kiy\WʾɣcvArS8mf-+Cpism {[NGJ9/;G`Fi|MZP[nAc4M4=o l(V!bĜL;`?JՊ-kOr@A[^r5'7ka`{7E>L7-~j}:fq?Զ[+~ 7_2*o㞚xe <7o:?bӶW'x0~X;y,y4[Wy1ws߸MøwȭrH7ƍᮟCN&<ӯ%j'<9!F߮s={(w~&c>sbc_yp^B)Nbr%*1 Of ޞ1`8{)X+_gQ~Τoj4ʟS[n,je=^͇ljm AJ\DZ.#B]W6HFh7=zב$l[QG dX$V9n2 {#ҥ1t!q i,:'!ZaЙ3ïs<>ܝĬ$TrXͪ2rLge)أ 1&4;|Lk; ݩ+[=m& <ϫ.{EfL{5v M$ 0[Tqwxx_^J4].ޘKq #^3msM) >6^'fm͚'R(\-~n%E[aToĥedĨX,'pI|zoZJC5\m5꫱ĕNGv2y |A|fu2 1U$iOaM$*11-]lXYFLoݒọ7ȝǚp H)NA lB4@m WB8Y⽌~[+0w{1Kg≯lRYŌY(*coZwAA}h[4SShyeTX p]. 38-ֿ-q([:oчjq ! xCѮ}^ 'گ^ͥvaVTy,8Jv.{VbEBlSx{anG7!ݣ_^0htةxP"_{rr&<7_*Cq)ߎLoDnYLf0o~30OMK&VBMrqjs×pƼTw=3z++r[y黹({qD ?voQ\[nd3*Ū*_02 HMQ/dc ['B90K4Z'>l&2tsBae@d#LЪjEg6 6Hɬ !uʲ|$&`k|K`ۇi#QsĚSɝ~_@82-̘qZqQrt}I!J) $8vH`yʤi4}:J)K@!NiZ.v4% gחB!?;+ !B&BI`B!h>heTVTw1Bmwb[>9] !B11Ć6m/?w}$B!ew>lB! 6!BN?HYWw1Υl:* Bl续W]Ү\}Qkos|,N{?RUwu?^Ƥۆ1{!^MS:^.}tzgc@f-7;Cg-;.ǒs3?N.ӟ| ;sϣ_`77f7xzT ?=+;l_Ӟe3_*zUtO\.o_)rn;;(\ʥ z/t(bW "{" tP{!]K;F/%[fg{gH ׹=$=NexC4%o2z-|ʄx97JPHM[_IC Oc&U4$" :+{kCYW߲;(d]Ӣ~1mcf=BdyX?sQ@Hg|m0i\1֡sHٴq*"k>mj`ج=kWGcQ=g2sOuNHM fBϡCWI6A./m9ML3&Ifv,d?8ZWS9u/s'ټZmV1|~rо$Ykқu! [^-K`n(d<+f(OI:t-ҟ+|( H|,u3ayyP0z֓+yH62rL.DϺ(grp|>E׏F;-/ى1i \kHZ= %2oQbj{/>@H ̸X*Ta vC裗 FCl9q77B6Y*V-y7?N%`oP/X%l{T tv2TR7߯bF@vPRx;QH9_OkPw0yRbaڢz敟1iG"*Np؛ONQM^%3b3z7g5 j>^e?pr?Ž.f$ vQOqȽ'3SSfJ,5f#ڊᱱ]<;eT -.qpy{q)|)mIwrʟ?!%Ɏur _a@3z.{@%y X@!ѥىe_%zUz׳pb<O)$ 35HUWpG j۩E;xxx hiXi?oOڋۿqv]W16c=}Ά2+LLlci :=\P *æY98O:s n֭5"I2!(4$-dq$_*DT#CC+3Kgn@-q8(OF 5e缜L 6?߆ax K{>blju,|W"},D@=O8 0$_u ɮ6ţ^2 hJzÎNx.-׻*Ed%5: ^Y6'3o8{u}g.k43׶NwۂJs_'"N9<;< IDATʵ$|4)VKDEoۋENVBx@X0%[U\Kk(L2 ~ɝ0o8\L9  /`h?&z2^>/{аbIP.s=m S~eи uCRbX3m6c\bD;IвH@-W-79- )}e ֝F8ϵFVɲz pqv.ޑ?A."BIW1o6E S tMEC+ 0ǼɒJLoHyiX IN}<\= l/=1h+*jk_dPX90A4.^V Wċd5f/{:D#sSWt&?Ot\!5*+!Ț4{A:rMT/}ccf2ec->_\zx&cUC^Ҙ5( x{ \޶_.+4QJd nى+Y{] "ib(*W1$W xKi꜖Ӥ7]֥a%O)ѻZ87l9Afoe~_0{@5_2JgZELZe.Dfy끔}Kۖ"-%lkXw~]>dd|,!aT A9<,VŌdF%~)2S[sfgLo\BjPmr1irNTqA~̤іClsN}z?փ~xƘ;q\ҫk%\D%jwQ6Fڟ,:d\n srUZ՟d12a:*3` MZ~!%W&}?84/?ODn<$/ŐUN69+ފg^ŷV{aBmƻWbNʩ``%sD ywseϺLT nMZ<;AˈnOugΖ^tZ+NDt,LuGN2ڄG2&{&ׯeT d+}jgsn.R} #d0}voXn4ٗWŧid"d @g,?s*4h_ƦX_@ -yJ>y탾̜-sJt) q7Y& _Rp23,JN$SJ9\$@g㨷ku-<nԉV @pwqԬǓtvSLsV6hf䗫4{k@ =P*OviL?d-:Ap_ A! EdaLqy]a)0(gN"@ (!`+;2 @ 7@ r&@p# 6@ a @ AeMSINN&1!svG $$1 ARos# 2 qs3P12FG $mڕ+\xU]͍ߎ0(q1:UiZ$Ih$I x.u*ժs b  )wDa+$&&^)"XӴBhV qԛ~~>b qׄw)wDx(l ^/khQoԡy\ܰX,BW{f;" 2qQI AazftN+})nJ[Q }V RS3f mB{^R\Q!0@ (LѺ5Lf̢Ʉ0(y{\D#@ )ط̶[G8*[@,|T[@  =^lMd 6en[%vxc)mhJ,-#sˉLzi SPkd>lr}Oe_q|Em۷|w4cCUX_Ź3x,#=%oߦq/NWۂ{׿#`+hv{M!v&·<Τj⫗ZW?~NL5-!~H)$yh\I2{+B㝶xEu k+/- W@pQkIII:|NGHK?J aQ4MsjX_euPqYӹ~#?*W=CCLiHFBrGia .ż lw^ĉTXcǏSfMBBBJ9IIaQn/BW(R(c k$& h[ހDzl@;Ĉv8l9r4 ___? wD@qu.D(^Ƥ7Oj`:9ˮ֮%L'^.Hj:XK VnD&bsY3cYlj\;{/PXW0 u)8cMlb3g0vXN8q67n{!<<UUH'33UUX"wFU;^d2c~塨:ϣx[>$wB񗞥]%w|Jj}/  )ZyU-&eВc,|s8CbL1}fg yӬHY>8<@ѻI^ߑa#S:}^aƷփ_ &  [nH#B~"3g2gF#㥗^Vdd^G;e1/,Eh6[PUIPJXAfF&IIIq1G2qѵAU A2mM7G7Jz6뺣V2.|;_o}RoSU/a )97S>s^ƧaoFL|^uw:w>O8\k zmKc1hre^~I89Zvv6̙3}c.~wnF-عs'kFe$IݝcǎQzu2239vaaa=vVZE  %:o|͐λa4}dfF p?=00|?xo3k9'`B E ^`L}٧'̈{;a㫙5v]4zsߓح*R1?RB.>I<*)G~f5칒Q2g}b~fBϡCWI6A./m9ML3&KO2c!ӗɘL<Тڝ z82iVA]0(^·6p$N#^ۼy̬3ϒ>ЭJO5V ʆ2oU#ק+^s/PZU>dvyqkN]HfصkժUC$9Bxx8YYf:ڕz '>c錼āCs/lwyųQW?!&1 0 44-Zp1=BfMQUUFffڵkJffR lh3Nz&$Lh11͇1sr_?ed|Oڌb֏+;Wc_sDЕQA蜤Qܔ&8JTRVU㐡=c{ډ纮cdߙl:NF7&C))W4RnA>}&>.@^9A:vRJD\WGu?0ڷ$&X* FjbL*Rr _d\eə@SH:&M+$Srȣ i ڽ@/t)Gm g2 $zu@h永p1nxMuXA>HHrѺN`z?i&N\lE\\F$t:H@@-<Ǝ_L}&nv`5GFJ4t-)H;Ck>Xw=T/tOg- vEKIDT臘*}$$(=JZ܂`Oxz6vᾑpS;7Wp(Hgds:6 ɷX@R6Ztt9)#I.\Oζa%-dq$_*DT#C[Ug͞zJZ\;T`}t`LLqQqZ MI]3FkZѰ`IAI\&4T0ㅂ(JUiK -of,ZUʕ7QܼfbX6 EKSaz[S, V\\P۵٣g>(؆-oh,~hX7Z:tI'(R&LyoV%aˠqsiꆤİflt@vm|id_#-{]v'ӨS|}2F[plE@ &IO1l*9v'tuvv6fшb%++ UU`0QmyUCUU fEQ!a(BPPZ1}gݍM6LYNϞ/\w`' ϱq$(޸8 hR ?Y~%Gºӭ5R2HJ-gjh4|;8YJGnSNI !!.DZ">^7t5Lͤ5]wd%nǼ?^ ЗoM̛{rVR׉Z,xzb53o'_x<iޑ?3gRVL73wU*e` sF\e.Hj&- Yqboޕ_,\yҎ,OfZ6 O"Rڡ]쿔^>DŽUs6{qSPbu!6w垳cG|'u cv6oʖ[{N"##Q+񸸸bU$K.ѴiGt$FŒ9IwqnhV~3Acٛmxӧh͑3tT3ggC6BmdD+2ƒο oHḇk㥓@熗vKl2M|rxTcOw2/ĥXBʮ(Sҏ`~˥k͘ğ_e 6͜sW6Qp$ g++aN>%K1dӷos$It2:wa_`78]YԶNn[\zs9FFfM9y11dgeAJHHHzT~deeѱCxdYFаh,m9Ie=NyT6kNwMQTeYFe$4UE0ggwqbvFi~JPXKkam?v #ޚXHq!xy{mI;?G!}m/Uā <9XāoṾTӱg(xl6#ĵRQI?DlPnEçJC"2}SrPL'Y-GC_L}*dΝÔ ~w$xK <w8Q9ɿRTlMJ^ M|.&=,|(qL.~Śz{իOdR^ۗ\]"gsiD; xJvyILL$88Xf35k ыݻy\xZXV')j2*$|qלm1xJk%GVFuGPud}r{Jr'if\s?J9Yy Xr~=I|6,^72Y(R>~Y@ulwK5Z㱣#y駹<O]Q4P9z?Ͽ8>C4g=kň XO3ȱy"{ Ǽ[oi:EŧB5/#4CJX~¨Ffj ly_ɸY+ Z]ƚ&0'1$iۤ u%x:̙yYvߓux@])G/IDATM)3+aM#q]5)a;!S8z"('nzj5WB/#MC?o)t!)1UzʗX[hNJJ*UTFZJ_տ#`+؆giy 28#oDfi344] GCɒ@DKxS#@bK|:VSI>~0y!2xԦqF6Ʀl9׆*/mLf v*87is~.~hif2hĚIN߫: IH^ggDJ&C݇VprvT90^MjO䏣\"V1Z{ޭfgD2^ᖥ >3s+|OW-7$*kZ{]V''!xY5P3Zd~Uţ Dҭlhr y2{YL5LḓW$ٗrt9i=> q;?GVFk$s^~ كJH՚,LjfIvW~A]!orX@ Z¬;8?ƠWQ)e5cw:9|4%{d%/ı埱lq%jw~AO5#@6`Zz81.W), V@ V,5f_ɱpڵ";݅xKePb61u۾˷s2mdG b]V@M?aã|88c;5%/o0e\Ձ$2ujԹnhc.獴g(moW$K&?bּoġ"hr@xAqԂrYR8}+%2ܫѥ|_l4iV06xw%X'N£գ3I5z#BY9_Dc?0ow2*)Ly k&1;-'LOƼe1[r,^%;m3>zöo9QRYn5R.@  }pdz:4lbRډzm]0:tQxנIy&)Z FGjTi370fA(8eG]jD>5XU|xp><̛.C6laQ9.w -WnTA43ƿ³xߛt  {?X ڠ==E0/^PRT؎w>ow/RV*Ii2~W3mF\m!Ih" J6UkRWRCJx)oFd+v͍p"`JM 6+O2*xi̞yť!kxCO :7u]E^SIMEI}728x1==UlَLN≋KcP^<!~%(*yh!4J`Q@vIO$ 5ՕӼ;~i'`zJS w:-IK9 %_W =Cק3nSdt :@ ,#.Hd(D;Krn\@ fPSjJ~ޒz8w v\`!jg _SQz:& L dqa*ujNBy_'.ABjA?TQx:˳Qd#!F48P: u/""=ymoN|&F>ʦk9h׭un[Sv|<Bݐ֎9+Qk)Q iqHށXq%V Aicousxԡӑ\[)Wlt1ػKt j֞J1V+i2koӂ[j۰5ֲ`i,p4mesSkßĹd\ufcI+6>Hĵ,ztk/f/ xqgyv ebV-Gp-k~ eVm}N'Y; :a>(.3Wpٯ1nߨS KF& ɕYsEjQnܱc֋di$bDj>XqY,fŴJ9@ SjJnS}ߡ#Lp|VS"Z~ēmC:3LfA 2OC |'\3>52Ѣr)<;͙ zdn?-)Vr՚ܘT W]~ bM$ ;1T7D@.: nWAR<4K/ǒu֎d'<ƼBf U;$K(UPL|dzt 3juܗRSJqSAzm#[Lm!AI1z6ZQE%,5ث]&`o-n_KTp7`ʪ IDATxw|l $*(Rm4UԋV {^׮׎" J6ed)"1ٝ3NݳOO?UeYz9W.˲B!{F lU(5fwb)0 ~3MIq6iB!8(q; YPʎmŊ,\03fY!@2 !BX40t)l`~vAB!8p)[&ᰅiiH oöizlN0EB!( vABt T!P tlZ[8F vϚ,K0Jf#vڎB!h*̰M)R OQ -*axLlAD7./h[̵[nV<]q ***ciӆ$`¢"֭]˪UI˱B! R ӆ+]ݸKqQhﱡBAMVyxJ4xw28昣 :v~q&fXe uQBeYh: Ϡ.x N0lN A\F8aXiu2 t`i8#r6✴JKʛW rc84R Zn7%#5˕hvfnASf<ͨx.d۴vt7,$?g!.n]ElHLE$-=ma$mB!>dYiWgfY xacmא\w̲۶0lp,0|X;"w6n{g2|[N|z"aloc\QFRՑ^3er%vr [^{rs:V8nz!,7tp-Xͫgݍp`)'-?:s[m`Bwt )ֺē}1P9@|E#SBx,[|>?CZƓe1}sa 0*kvp"_kgGp3_o󓝝  PMtժ%ƚ>}Fq \g} WJHEPרojE.G%n*eڟs7eR@"9)"1Ƃֆa'/픅 }SP)+F lf`@qCQ&n'R8'/IcÎRv<6IrBq!E7p(nU!uSJ՟AHM,-h-ֺ2{s<= 8(NhM]8ifmsVlA ߩ-3ٲukN>ŗfbi.e/[zѕ_$K%(QDksk&vQ-oaJ)*.!.ɍ94Q?cHo30 }C3ASmh}~rm/aW)MS.`"9F0vOM/} JO[L;gƟϒ -7߳U! k0a ôe a̠"NI3|ɘcӦlKd;ME8lVønBNinw*((uu 0a?ǵ7A)"SʪY [J)ltǮfhТ5r*%Z,?m:JgH ?MC3EpxJ{˧E5o}?O{:$^RO/F=s KZa&]uNt}B`¦M?VWdOpsbMu*k:U;27"կέpt4 I.vf0 ~z7n\*QVQkVFZe1^l9UL]~Lg;͡%cg H7v9_pImϖ-s=?`nb+iasjmR,uFUh+f?2*07evjk.BѰhVQSixaUe?/mk<ӤʎznQVG*!CY8oQQ~cAeMZu5l5c,wx%Ws'Z Si +z^h:v̠ }ZV}5ϩR} 쳯h6+y?e[_tTJ5 $'x} XJ ˦P$YLꉙF 2vNH*؄BFװ0D']g7ٸ_[QBj<:g52WQ"axǻ++oQRRڣbf9>o^v4fūӮ]3 l%tztcְU-j eK`AE r<2)V5ZaYR3RĪWV ֨5:cDUn*BXll*qH U1GV]&¥^xy;ZG}l3 vGefٺwΙValݺCs~1pvD0">>U̧Y7hB̞]ݒ]-8r rdb|5p(-o17kU6G֜y [θco} hɦǓ>460UpchIPik]yx5_B!vR UOig>ֆeҶ`mE5[@P+GY&h:k} XKq:;0i#xw Pg:cBQ?sgH$QIrl9SgsY7pl ro<. &#r0 ,U-^NSc?:e*J,OqE2"tyǾ܊V5"]|fݗ?#r3n^RTz!Bc)v찣A(&)X> K([;Ug„&:uth'VWa{4֎(/!#Qgt(!.N6Xj6A[DzU䃢VOzpdrSZKf4!PCD݃+̥U2#YZDȌtP\Z )AQQ .{AYAd],HnO":c&+!+Af*BY6lQ K4 sCj)lȓ {(2\8xA,p:P*&T$i lڴ ]J,!BȲ,CN¡0`274) M's|~ ;m`Ca 8v;P`0르 ӾWc !B45e |%l Mfˌ V4 ]ױ l6[)"iB!%ZHT-T])B!B!$lB!M$lB!M\B!Ry %]B!hvl>!BH&BI&BɽÿWn2$W|׋QQ}z62&?ЅqAq+/s/Fqψ47q#3ht`}2_n8 Vt;ӎI]nw"璄MѨ9mr@*u{Aa-C^$h$^mVu23kϧed9 4dJBYqp-5uJywvJu3iTresؙ=oyjrڷ2<,unG|~WCqJhw\}Tڮ'BaB4*#9K9Mxhge),ZRT4M$l7mu%c;#|e\Z =q^_zm _tUbh YmneXo6d23 X wbËSGcU2I(6n,$|#m4.$l҅\thY; ?ՅrǒaD ShƓZL-!~/JWom,\;\!(g66;fr ы$&7pJ&hْU0o؜؝H[|"\=8/LDmAl5 N qbga-b .ɚi x> %hyܕ\}WLdv InӓӮ9E_sw.gS) Zu;KF['WƇOPz#pe͠F LZ9Soqb0q.i}l%B!Ma?eZ!BN6!B&N6!B&N6!B&N6!B&;3+ez),( B![m iץՙmذ8gmڵ'!!qT!@,@Ϧظqmjݮք-o6lNQJaYY5MC?4JՈ'Bq ͉2/*!8(_1[Ւ:]*ra )61" *Ų,~+K.fҥpѺuMiaj!U-&R1+Z*w&ad| ľFUYW߷k!<"ZΦO(Ҹ6eFG-@IbzJƪ%&ZZhy]zBp8̽K˖k=۸"_ s>gqO0,P aʭc_GԬԪl$xO*&Ѫ5mb6}1lv6;nlW5ymDL17<PV_~`\vk{2t7GQIW5l[)+rhLפiTG @G7¢¡@ph~V^fj8RIi@KkN2y% `\sϑ\~敉1gC)ʝES/3&1n=Cy(, s.umtWZEyZ3`U\ujrD~yq{K࡫^M+9!R}ZbA|mD#DJǪ7j}6q8~7?ʊ,tïl}+r[2pT&6ig‰2/[^á^Lfrǒ^ώ{dgep߃Vq\4G|N1hkaCcx,c*zG_A|\i^ӟ;׽ CoSrLx Ṕ}AeqWu'xЭ㹵4SME.V׿6)>إQ *WEV|_Uޜ9[)((xN#2w"bz+6s%W?yQN3/Mz\hiR[';D:{Oζi߱: ?#Lvrl>Ԏ2Zs]q!,OgoomD qCy_ILvC/YQGYft$e >9bɗT1PJG)0 M*{HZ MB+w_&-Y\}cjժx[ xpiVeӀw~}pB{>J.=%ۋ!L,B'ubf-pEm*'r:PeY_JU_VQ!~ _#l[}v>#x/\4Νs`ٱc/h)˲0nw` pP(@7t44,֌(Y l6Papdf^00l6t-2͊xu]L3b:}dzLp8R޲ @T (hU~ԺA躎?aȰ[-Q#CUE]dEZ6iZe!~K)ꫮaZ_~*,Z6mk[k֡S'~u6gH]lYchB!_GPsGiR\9QʤCNƭ5a3 >fJ7Ϸ/@!BT:.m;оc:'$`*+ àc.teϖT!BKl! hxk!BWl6Jl Iopb}!BѸ fwmfъ -Ikޜ}]F!BR~7aY-[ey REE-B!b4 NbRI"y e& ?RZRr@u'mh#BI:5yX^&3a ,Yd;vM!De()߿s@4 g\͛ >! qpޤUBY2 C7Xl$lB!,[IӶ]{RGȬƅyl޼-!>!RRӰ3R7?}]!NܭdnKBR2pH@ i[lcB"eE*ou]{!M-H8$baR$$&~*딴uT* !hlJ)  P,+DU$cB!D5QJ}9Wp}AιB`j=Ϊ((I 9B!ySIA!DD'@!V".QT?;$ȳ#nbG3ֵ[[?֛fs24e&B#U$lelo=g1Wsټ rz' ^ySvvWpbT!|k^sO-\<=؞L4kB_aޚ;JNoe(ʒr]}vWZ|g?3Tw:[AJ&;T3JQ=V } u)"[us&[ 'n+b„ɦWp-Yu⹍qvXk׏!7^lNza CSs&scyp5\yBZOB|l6wW[fū&nZOmGzBu-`o^\p C~g$Ipƕ wVQ5!Mհ{ILtF&5#Tў8s˙ ל:S|7Oo /No>\D/D(] _}3%[˰ciܯ%qZf m3m&ѧD ?_aXN4,t :9T xe*t {4P%9yfw,-멁e讥g ޟi[>$owx3GPQoӽ[>WḓxΗ@謰݌}5&aJ(fğ8hnB!gU,Z53R8{ +)),_|2Oᅲ;zNje~nf}Dj%oY5 si=Hۈ0Odw:~|2}NW[Qw,I'v!np|6Nl?ߪZ6W7O?WD^A[QZ0rlwғi^fpFH7v !MYIځ8Us2I9r#o1\^xy}뤱arT3ɎUinTʢt<ֻ{sY,<(ν du/~(4 t-z׎~-wjZiQ)ԋW̃ -ӈS#ӝl){yyHؔRS[5IRMJrpT,#bQ ;.w `+^ $^iRwB/ ]<߾/fLqŜ?M;,ʏwy'㨳jָ6Hnu i&lVR6&~KIi~VoLx;7˧DΡ5o--u歲q 얅eEˤ J&NɌN| $antc9酪4o+>iF_Y߾fuOZFs~1e+*O, @X^1حB\{B Aq{<lPq.$vAH;~Mg(oޭ1 5_Yӯ gudzi/̕OL'×wķ1`H)7Q}*7?~z`KΓcmB!DxUVC7Mxiۖ$| q)GsGf(̲"dCϔ?XLcm\wka`)bX育|J+ [>t7Um×ޟ3.*bx/i"w[(ME_wt.)v49W[m-,8`&T7zߵ{ZZs,o }&3:Dvqt~-מO3qG243|]vdi$& B.2ƀ7T7(} 9B!%*\2}CλBm=CιB!vĎO!]L!vw!M4C$TyBѴ,{_6{~4I?2MA!t]㉧u$%'}ŧjIr(Ϸp@s:ůBO{latҭrR{IāL!MnyLlκի꜄_!BCvd|ܰ~ e\B!ҭaYV̈́VY{`B!"ˍxh5KLL3B!UC!lv{LؠqGέXN]7ZZiO|b"P8LqQ!HoaƗQB!L)ŊeQ(zMjZ:NMq87C.m0M)ը5O$קBƒǡ0jO4M#+ ֮O|BITr} !՛DoϥUS-MHJJĻ Re7UF'DcS!|T(-|>\u&$&QTTT1oq]SXhLr} !J^4-.wVXɓ ֭[aCYVhItwkPPj0D"קBQs+V`I$$$0׹+FV(Q T;gDU[g3ޑ\ߔ5B9d7u>.~}eEYds 1?RoN(bI,Y=+>lup!—,€ /0θC$oq1 uwެUץSVB!Lԩ?no>l "4Mw]x@#|{}DBl5 y曼,a&Y}-.k|fҧy ʧ o[G#:$>9Pq ?ᶻ6HA1>r?w[FN~ǎb%LW, ~k(OkNJԓFi&ƏϨQhGw'-uYeUU"(K_gX[SS|܃s\*eWlӒiն52U{Hq^M=xgz Cz*]$U짣iv:iV*7NjY 3 +R|NX`WM6AVV+Vٳ8`@W>9ewK&~W P˵#b/9[7SRZ Ja'^dv-CNTg$=P^;j+28,lJ^!+љN43/Gķʊ&S6Tѓj޸T[~P_Óy6O<=,[dPq.$mK4͛7믿СRR)EI0¥Y4r!75VRfb(Kټy# Il0 :P Fvxn'rI{19b@s=ZY|V$zl`~{|یTDV+ח~`|t~m^;מOLyU3{BfLxz ]_lR 8{5Kg2uG!o rRJJIoahi6ݍ㦤ܭ o`Z]*sء nGsId  ^;=>6}3bRv+U]Ǎi*)NYm?{cit '?Uo$:u)wE$GlRKUO: %*dt  N+l޸6;5ZBZ>>_wiOoH;IO!m6-v4d#hxB4&>B4Q ְ9wuG4v̘os\ meelڣ}C~G_nqaʕӧc|p7g.{N{{<~oNDyyĹ\ytzwy8ƜAδI&X}x>- S9\K qɓsfwfwcﱼscKq{!PS LQUq 016єÆCii_l-Oុ}8>.Pߚ'#Z㰵+๷༉Ip#3m˳=2|/W(#NK(K1'Svu͏{ y;9w|9C ۃ,Mܰ9&x6cC88`n7q;0$k,nr$ίrI!\F˓nSc$5QgrI re|Laz:OiM7摉Ws 97c*5g.Mx㤘'S<;9",#ok{vTkB87U?K ۶ACeQiӢ6!Zk؄B[ˬiסcIs8W4 wgܪ֭evВ}h6 @N`RX>3%իm4B!8T68-\MiX%47ʎP"*j{Z`!BN%lmdжMƞ*B!EBB!$lB!M$lB!M$lB!M$lB!MNe&˗/gtԉlv{N!BF ۬Yi۶-|Y6!B.ְ[-[pYgaBwؑ)SйsgRRRB!]a+**vW$kAIII>ʗ˦bs'BR¦Un`0ۅjPpot .Wy;?گOu|g\ v\&»[~-%,B!D$jY 5w\(w|̖n6@:(UADXEQ U"(Fz"Ei"&R723Z|?e9gΜmO9sA/%aҙЈ&ųQJb H_]!lS]ɨłJI^p:Ag^'LK\ִb Goc/#<>wΚ̵!k ]5wM"70u< 2cl_ؐ^l~ҍRJ6fNHscN$ޞ]Y^OJx{ C IDATHI|Gj#gN_] !l>^0k9׊gj͠m֡da/c'.yXhr`%[LjwDj8 c翃^;*Qmm{Z?c(K*;)xq\)ivh^_G!S9i507g&),X˾7Y>_] !Z:8nBs qf- :9YW?{$b&ywG :03ݱۖp]G?-An˦+~À piz:∪t=B?S"0 M/i`mn 86EaT„^,*W3|eRկFe+D KpyLADT3B!ST b`Rv0jfDۓNr6iRP o1ccN~H'|vR{ sD %)ҝOp`W^6EN9V!w*(?.@)toh"3u;tq|W#0e3{}<1QRz ؿn6ŌUus$=%/P -s3s^ KU?B!R%.0]V<{,X昛|O/ro>J>q}` iPih@+B'>)ӟ`ԧeJ %ӛ~˾0ثӎ]dY}) K>wjB!B?jbkޔw7nÜEf+x< {DAx8A@DEEӓRRRhT& !gVKl޴4EQoZX=?/0[,q'-Z]@m[6ل-5ꂦl`1)؂@ élZB!@U+`3 ۍ Wo F)^͋3X,؊mu;frB!DmU+`S͆&cB!5iB!8I&BqM!<'B!yN6!B\aL4GZZ͚5#..̿&BqVպmӦM޽Fǚ5kرc,B!-ldddпL&M6%))͛~V )Bq!U [~~>"XZXVZN("P;gj\O!{j uF_(;8Gf}Qt_"Κ#zKϣF3C U^)SW0tԉk{ fTJ:Bc t]'((v8fz)yžsLayh\?Q^f˂/4e4K !h g-$mW2C>@Ab夒fNPD<&5G[X:4O&smQ֎ĢrI|_QƴAQRfL 0ұ<+/|\q]0UN;̆)|rJ!q< Bφ:ҟx$iI/ßbkLlS6뽧ǫCEH\ sܔ竷qAM4zI_]ϙ.4ua1V_HI1l@IxzAJM䅬̻gmGM<~ƒ- + !8WjisIh=f(;?(y$'h[gWOk>o531q< c`!InwN.0y ӸD&V #:6Wf|<+㙲tt;% g3u2I3֓B9ixҷEٔՀ/ 9)O'|A|\;G-kbv9yuO_=l'Kb#8E2^ /`k}:\q\^!)V#Z1-)LIP*M!9T.QCM`{.!\yجTG- iޝwőzj5L'w2vxo[­fv!lg(Ĕ#kWo`WŃfk݈2YJ~ǁRٻvAiy> ~k4ti*=[;;yzŖ]g7$FPx6Q>^ cޙAIG M; m;v@ 7r-uT\¤qy eU:,)#u&Q40t6C7TgF"԰XB*JaY/sqEztgf>ZrF[~S2)6AL.Ob75]Cy{ ;q es|V߰%%DP«6U)[QvFp=WRi3|AD`y&*&>E/fi$},ˆmˠ|ALPy:3!9t[űO[/>c=m\Tq38/X8!WT b`Rv03(ʄ3ʉ'4  lӤ:V"cc&N,1 ęJSWNqþ<3A,~}^N|u^GE\{čr0>7?YkVrᄮc3 R~]9?6M:*NκL*S>6-%OaeyɽuPEM)z"I5lBP>2 gI&ώbb2 0NV8s>+Q҈>(|W _7ebƪ9ђs_эt/G}OwtF -cPk6NcFd IE4ܜ#K7=-%͟ށ$=x:!vuj>Z=x/[NBx]%hf'!N+"u,L<ѳ~/;BWV+Rbkދ[>g+n7Y[>dPn\p ✪EPwiJYs͌yi3_ޙ.gø 2x5=D}}EWӟ`TTr,OSTό-b/qP]7qn->.{l|8em_#qH t~a'om=RF|[ti+_ֆpXuz'[BJ9{:F˻z{fPpNUK&掝Sy>ܑ3Ƞ֐gG)qмsjK^ ^}'w^Fp3  !8U]{佻W?PlU&v漵."7[Q $ ›qXDx*ONN&**ꜞՕBvb!+6oZEM(7UxVڞGlF-.U̶-֬l6a hMpp)i`6XL PBp0[N$B!jZan\.%nJ]xK(5Jj^ bVlîq8<6 UB!UMQl66B!8פK!<'B!yN6!BlB!9 ؄B!s52Mطoiii4k֌8,2B!YUM6{n5jD\\k֬aǎglB!ZA1L4mڔ$7oNxxY-B!ąV-l8` jbZ)**:k;$B>B!w*`3 {<2Q==?wp|O;84rd]7ѩS':uϰw֑ 7ikXԩȄPSSW0tԉk{ fTJdB*`uv *Ο|c?/,r绬f˧G7\ܤ\4֮EtR(ScY>ݚfvr_}JB!j4Mt+UUx``XrRU3 N'("LiٚVሣ-xeЧ~Y6D(kG bUcy$/q(xx c.iqB4Nd<1ag\(*:yBORfL 0ұz%jƛiNb}`M&J}Њ 8[1p6 L:JABQ}5 AIU( &l:L8h{)A@P&8M -o!ӊ->\VziY:U\j4JgWuOμtQ;}٫(;NκL*S>6-%Oa%*ɤP@?/9%*H'|vނB`OS'<;S;3"㴲PN5!(wnʺSd$lܐ ؄BB>aq7ЅƙI\|”U̜FĆPGI덿R.`y,O/ 3V͑Lm0/i> SV2kQ-#*%÷l_Xѳk̍{5s]n r׫:qq8(u0UC(Խ+egy]\`vE7Z.fҽx3{#<=W5~EuhW3~<_♞xr";ύi;3?-xsv~^9[v!ӷrӭ!R.Qu +ZӔ h1ϗ0m;Ӆl@c׷Vs]7>yg߱/a>jʘ]S-~ $B!.d Efacp~u18%}cZ߿ B!8HӗB!yN6!BlB!9 ؄B!s !Bj4[eo>h֬qqqXd5!B-l6mb4jԈ8֬YÎ;fلB!laKMM%##c2oڴ)III4oޜZH!B#9|&GȺV+Zl8` jbZ)**M!8Dqq14#N,+EEdg&--<6jt|j%j* 8<Om~YoLُ;{AY${t/3GOWekttk~2ɥ]YB7t]6E5( `a6rN_DuM8k!iQU -'\5t"1O<>wΚ̵!j ux)WofNrJ!G'ЁH!q RimCгg@/i82_F!}7w?gp=ޛٛx{rveD^z=m T[~Հ^GΜcXiBV]#ʦ@@mK~m8?WBqFf-PU7 chW z-4Z,X:, W1`;{'Kqay5/b O3izzQSXĉKp39=X;'2wEZzxĤ72u2y#^N2b&*ۮS\D"oS)`₦:QPxԍGFFiϊ&YH=G.Ar 0@EUx @~Z AI5@5PU50)sd((<Ԋ->a9d7W8\[n: XL&.tѩgh:vjwT~e)plޙ8*`"^0F!.rϯaŹ԰ AposqC$`B5EAQ;t IDAT (mlQvv4< L1QRz ؿn+]%m GaJf-ʡE+X{)fduhQ(e*&vB$GGa*fK#KNBVE꺏Yy "AE|W|oHoN5 -Ll-2}{(7\.8BgKqX6EQPPU#bEPtCxV3ҞOY&wK+BXW)r}*8yMO{t90|G.q2ھFT~d1ϗ0m;Ӆl@c"K掝Sy>ܑ3مcxgڳ5C]obcWM*OobЫS+nFR5!Ttu* W1*?ssjbkޔw7nÜEf+x< {DAx8A@DEEU}yb%a5iRRRh׮_] !cf>`a:>χur]BW {~IVP*fۖokf6@u&8S]40 ,&[(!a8v-Z B!7JdJzT+`3 ۍ Wo F)^͋3X,؊mu;f2 [!r Ϧ+  ѪBT6EQlln|~?ޛO!⬪|AْTeB!"ʮ rl5E8}B!3T W>P9 !BO۹c{-ZdSM!x}pJ&Bg**Fk]?:`4}@f͈" !B`*7oѺFikmڴ,ڶmiY.Y !B:]dddпL&jM6%))͛^lB!gUZl8` jbZ)**M!s%j* 8<Omړ?mg?_^ԇB9u{l^  `킧},tP=+?t#a1oH:VJ2n;suƹPBQSe\h˺&_/5 tM8k!iQU_Tb夒fNPD<&Ч~Y6D(kG bQrfF H$yt";0_)6t=:N8y_|ggШ5{QaPeO?˂, >è_ͻ3Ź|%dd. )"ٹl=I_w&zs?/|ExzYFc hITcTlaDE3u~~/q҃4m{cu绔zV#M<66v<2S:}̄Ib<c?h:s>C#l BdT1W׭:& !jSQ(՞ףFϧ%ZidYZa3h!u(YA؃:cv&FOi,Ü'jD#^m 9.*?fҌ\j7L'agd^KlL"S?C b6nz{_oh~}^j>Ÿ=sꃵk:nWuz?4@/,5d]'+WKklM;qc׹-e q Bʋ!py[.n^1TxW+B`ALoú&|A'Op-{mS:V^Gng̪񇁡tqC@l 6zhͳ<ڜ}Vòe[}ȉ)G֮ހ\t0B'^z? wϜ˶T8esb#5|7]č#'rK'Ho]δyV`U=ﱇrϑZ46Z 04Ctljss^Uu;keB31jO{25B04즁7?ooUǧSlD˿.Ua(b~Ƨ˓0M|AM|Pɾ]MvB7EQQU vK Jl $yf;qPCP~r@dρDTbr%H?<Z3q^F>>ݿb<{y L&̊NԇG|,(R,\6_Bp'owt.|Ov )^Gt,WW "ny<;ZaWjT񺝵2 !D5T| dѨz,oU1Pjj(:j`RJա:^Z1ZųziJ;|M&h: XL&.[;ǎT{u}Sn{ Jb宭,]}x.kd4hb∋!<*Up%P}w; B+(;>"*kGrS.ߨ݆F]unQTE5aRX>V;v6$'Q6?\M9o:4j~bbJyN͂Sp uT+JA'yIH/QYrhѽg3~4^ aD0YZT0Joپԇfj+ύo媰*[k> zq&˷en] O3 ]>MVV\OX8?[KznfIt]L +NnoboxOK%?_2Is cMuSAu;eB(- Rʟ+[c:S-DׅǺŎkSB3x5=D}}Eȱ%(ZjyyK4!S LrQ醫ERX,l6Á[p`PUY1@!EQ*VRƲ(b(fb Efaj\wΎ'Bq(bEU5ϔf6]rLB!2EU9|8EU+ͻVt_1T9B=4I&Bq֙M&~%MAyhZ{( p6? ؄B!2UUq8L-lIdϻ p>sPf!B Ntt=6mCvc25ÇvhаͅB!]/Ғ235%Ol6tqQ8Aʫi۷45kF\\M!{EAS-i&vMFc͚5ر !BSU [jj*ɿZgӦMIJJy愇B !B\j–V+VV8!BQˀ0 Up8x~ܩ+`:uĵ3yE*B uje ?A1qUfV;o xۂs8s VtanCyV<F>hx_'ma΄fkv7/=xf6/e_qwFf^}{/aq ^Vaߖ o{7oo$sPҽ=^ k;ٍhsBjNqBv%*?ÿμbAI%W$/8NwpC;gMj5j:Ŕ73bFZ\e'9ͣqO @$ِ8BN)4綡C_|ggШ5{Qay=aN/i82_FG$ޞ]Y^O ̘9`6cGyV7]-E<ޓn&5঒Oxp:.;ݭS<3Kkߞ{*QkvA(S>_1ޑ 'MaeɸNbn=3ћS+i;B3mڌx/Zcs/A۷c3ov$f9bc{AQ 07` Cmn5w<ޑyW툲)?Gۯb_xe$dBv|z\ZO%O(J; ֙ĕSڄ{3J'N^6oɎxuy;% g3u2I3֓<p;⟉2kZ*'0v>zV+gw/eLOX,XH҄`D&,eLz};2oG_Ȏ'zMU=!O{x?99 }i%4 cNm#F[ˆu v3L LHF|5KQLX}J"s_}Janڐʻ~gиM\Ԩ wJE).N_b~^}=!p^绐CtܙnLuUAhY)W!=x˩cҲ [8r)9ªfKpwbѝ9sW(LjHʹPpي7(3 Oܥe,c܋k;=|ӆP8-ˀwKys`'ՏCy}B8V|XϏB5UPfP$Ñʏ-{_*0ei9 C?IL&&tk(todsЙ8ќ|G0Qx5,Z18Å(u .DLDSzjZօ8/(&ڌW^MIT[u#< 3^oF?}̂BUt>]Yn7gG.W[O-l' =#ۖcXfoCh۟'\ 6rmԷU,D5B]?83`uT VT b`Rv0;sbx˻2brk9d`WGSs1ƖN^þ<3A,~}^N|u^)\"3('ڞt |h(<711(̀"'F:$滷gה0GP‹W.IUa.$"*ȁ#}7Q%i4J)Ge(" ("8#T("8q Kā (.""*-mJW=i6-mO{\MXZ?4m>COes<`O'Mb"N.%xkҷ'1ƨEeț\ΟDy8}z}%.Vв0m2bl.^t .L(VKA5}01q]kJ%*tX\2$lB4IT1@1|y?}u_dLMhW{q طf)%8\ŹcMg}!=:5Bh4B[T0J퇯ټYYge2M׋s'_z}zұŴ~ER-%Ĝq9˙r'^wf;c[OqfY'+Vᕗ?`_VGxX:Bcbq`5Ѩet~m#ǣo7w.]{s#{Y̋r0ݢoqtRaHfŕ$qei~d9K*p퇟Vw 3s$>)YJ̙阷wps, a 2`=̛ʇ<ͼ[[0&0a| ?Q:p4jnxaC\3MTVח-dˏ3lE#xS²գ/RY:u\S䅥S7 8nSn[ 8>1*&.fNf|/壛bH?wփHBWg4ݺ}U!s> 8gB0PO[<7/nf~>Gjs״40S6>Pf}ՓLՔcS1uh-ʅw䞳PHO'&1diFD.5eJ!(|rŃ(-)`$&5%"" kq.%Ĝ9Yd) PPՇ0ЀwE\\\ =yO'>vBߞ={ҥsp 7޸kߙE IDAT1'T\ kiѪuB?U?ˣi-vv;PR\Ħ _ׯl6aցRLi`6XL V(.-uzB!Sf.bJQ\ZLRX,EV0l6.=͆jEUVA!ꔰ)jj)1' eCobiv=}q] !cR%B' B!_$lB!["U񷓄M!PRR\E AӉX a[~=۷oy$''駟74B!?Jm&33"^/a:%%%b QjP [ZZ\qL:[n͒%Kh۶-111 +B񏡪*-Ẓ÷؀IRR2p{b5(af'k!!!PXX( B!D##whPaUYfvWĉMCG;=RnkX/Yg3~ٓf_80?7u/J[S7]LϞ=uL]FvB0 auQ0 C>JL]et+8d@p}o}/oVȉLi{)ސN•2f(Kw2I}3bH-&⟣^ ePUv -;58bd=RF^0^ |~p?9-G}EnaDs4>?hQ{WJv)D<+G``kU`x/㞚uìyxÖLˆseѬg4?^1}cQKMsFMgxljk-D1U6t \QC 5j27w3rPcJyg]*pR;#)BWjoз:3BHج$i!Et;nvN&4m[%Qئ}9 L8 *G/$k`㦅6qk w/93b=b HBLڷoύÆ1bD5gfKT@UtLWE1PU0)ef FA1t< Z!4"TKnZFDw9Kƒ3nB-^y/t.RyrU<^ZD?>×a8Z$фFJ_~}kf<.YR/=l 8 yYBimb'ܢQo?|}ΊqѮG?Zf,cު{8|iXh}^[\认FT<߾ag- Ĝq9˙r'^wf;c؋ +[+CY5-u S\fiAыI[ihno*1gcrf/IWGyEԮY˶qiOzRηo`d\dnxٛpp[p 'prss=l "BBBj׀&Q߸P5FE3R^x%+ڃg_˵ L$=AgDƿ)T#jat<{%=eѽW[!,TsyS𔧙7E*h8BK0Y(ft8C|4۝Gi#֙XE9Ե;ࣅ~q-rbh{o@X')[ LMj)Muug"m\eO^9&G#w}:0% d<͸/g_$S&c5%ؔcL1s1Er3(T%SI YZцFMfC!N M8F:Surs]k</DiI vn'1)QXLvy(9p%*$'KVBdĴN>фk.|˸ 4}w={ХK?B!ؽs;СA< P~f3ŽЮ}'Jشհ&1:Q)4 fI%2s*?!B(lӎӏ49#АIα,ֲkTSf.bJQ\ZLR2Y ðlnB|?bÉur0#%p{4P9B t^=`o!gGyT`=?R˷khI4ȸ4;5<@撑[+;唰'IfF]Ԃ^W!9&UOYx/Q)W fc>h:Fx.[(a;ORcΓ稧ǽnp^'g^UH)J7Vi |.c!{sIidX:6sυ-Q'W&!"3b`Y ػ=E1sswz8t|k Jyp@f_~3o#BNBְUm&рuפiTa'"qz-r1("7EZŭAt%hc #RVf$e >Ӷf43EbX#g  _?G:tው<|*~i;Z&_/|k%"[`[2MqhvB>(ɪDA|A|MRo#T[qR:˫QkYPZiHSC*.x^#| ,_1s^:S:`9٘0qľ 5 hΝlKE?9%3z+ d8sr?a79yQaƸ΍6*Lq(jʇ*j،L͠l4J@e߀+?Ԫ !UgEQ1 sKik_)fЩ}oV ^£mī2z[ d 'ܢBր#K&ɮ^S?Y37 K1P˒z7n܈t|*1.p*~7l„_F -GYQUWT K͘kζw:[\}C`qG$2o4X0E[w];B`}G|MDմo{`侗xu (%twծ ˾*JE&MBb9O` Ͻ=O>\nx%%Ox%.uFWUTPN)S>>+f|oh aBvZv l6cX0tU鵐PT \(lFUU tM*K& Nj&SUS} b A5((膎iZy'$4TqQ* wMAUMªKʷ.).bӆkj 5*ײoEQB MCy6|s.?k` QiFtN7TxxoS%Y=Ga nVKE9!B?/ҩ/8PcsP+Y8YY[kY?e(oB!8TP*-{M1|ɚ7Yvv6֠q&lI)߳<(oTa*VC6!BΜϓ*?_VTlcXVR 7hֶ]*~o֯uv$$6Mm}NZF!BSG|\H4 `Ц]jиA6Y=eﯻM2I!*pZlCj.hmjڦvC (B!FUU‚?B!jAα,=B?RZYkcܼ|=ؚXI,0\SxwcL^Y]` UՌWt n`-+B.?_3pAT:+=˹;IM;y&M`)Ȇ838-x 3nDKee!D*O،­G]=&K;s,޻sk) ^]wcؚpEAg~GP~rB a$宬+Y+V')]ŮWbs֔Cn6>3uE0mclFKw؞Өӹ/ԫ_-5RT9GU`UjBWJHD ae|\gxv_9ti @\ FX(Z*afi?8ǨkYz .B!D}\wp M/ΣA2 _r RoC h՗c'ߒqLMӧhMf8񶡆>e/@hٛ_!m}Կ- 2x&Utg r(b>)a&hv5\8!RDuy 0A=IDATl6k m97MMoGH/ % f=ZQPrh,B1zj"PJ -4m3-ė$unKlJZ૱mEr*2:Df\~]/Rl&H9k|ʃk8ǨSYkyssuB!Y$l&{#`fum)*DJ$<3a\Mj(P*& Ct 3 r??\ x)!Ķh{ XYK"pU1Iåj?ڪhP1^JbH3o-VPVё6k:o]2@@4{߼79?sw;{Z(bx;VhLXQѯO择(&Tł/ e+!1$3$8bڎQײ4]B7: 'l!5ݜE x8SG4s8p ^¡ף?/Pjshׯ3au9qbrMpJ|B!D9 ˛B:3'lELz/ 1+z6N1KXTn_Rޔb%MdР˽F!) cYrט\/m8w+H]8G3&3ښ[r|^^8_qٮ7ݛ[@qk9ZB.w|/BL\;:}dbčF{,3r܀9eԄAWa:爫^7p91 =3/^Yz0zf;5Ë?:VsrXM>yS{B!Dm5>V O,=GLm!Bԕ#"ը{tV.!( 9G$kB!D}@kz_KTx8a@ټB!Ŋw.A;ciB!4$lB!qiS`pIENDB`nut-2.8.1/scripts/python/app/screenshots/nut-monitor-3.png0000644000175000017500000015032014501607135020545 00000000000000PNG  IHDRl]19bKGD pHYs  tIME 221 IDATxg\ɖwNueW; `>F"VDJ *D}>,wE%(J PH 78w thuGnUuuUu : U{+oߓ$= GD ̀ǰ#""c 9c"""k@0GB D9 3n,du=ΘnR ;k|)$ Ը{Λ1ƹ뺦iqM4L|J$%sM835MC [aDZ3٬D aC1L':n:f3!܇(,ܹXtJ[t2Tka<:㹮O5!ɈIڮפ 9͓d٬6CQ'eZ2OF|_{78afptK2G}:PTBw%GixwWȊV4wW j: HD +_Bٸ5DCspmGp:i)% ifZ}{F4!|"4 Ht"0Cg@.3Oɘ2΅SbBx2U,cRs''Me9=95hNxx,NVbXU ,PUx+MTAL@'fu[Oȝ;ޓ5{qb2 1bMOhiয়y4+[LD"j̞~{c- 8apq1ߨi+1p̙gBP@ . G4S Sy  y&>&dFܜ8ڝqZr$HT j@ɞ&,GFyZ|G䗗F艮0^_~zga|f3r]ژ Шm'ߪP(/">cfMmLCCC]7L|"%C^*-TRlXM?sΨ=vNܑg.Wړֹ𑜙ZCÃ6io.fX[ -;jC=^Ztz=-) zd&DGt]~ 4< !ڠP(/ *N-]ojjuͲB=ߕU(1\ Lݾ1#L$I0@d@!$(OdZoqx4huYhI f bHWit̳@^#b BBU"DvȲqəDiY 5Bڶe L B'gտqt/sX%H/bM8\88îe %TVrMsoّ)>3PrI٨ieE\~FFm0,2FlSRhf^&9!=l")x"vf/l.oG4t9ev)iT E"3oҴN!]ݝƃzo1e* BEwv42! !fgnha$pwzjfl8nCBP(3Dg8U=$I([A* B<=rkbu  BxEBP(6F+ BNhE BP(VQ՜P( Ņy BPl* BDTP( % BPl TsbC><8yVx3u71to~zE [M?yP[ɯlYfHAf'?Zp$0c % P҉nM<1%#֑'>|X7Nu4(X;Ʃ .{eRBDT0-:wHù_93L K{lFO )#GO>6xC/[v/g @xõL s}.efOlzdWH _]XbՀb`dw2Yޕ(pBy/5ium|oOg<ZWts/;?OȁoL `HLƹ;pѢ 'DsWᧆZw#)Ddrqqa~\# JS*j9?L'Ll<֙'=-޵o"Dд}zWth{c]MzCw 4<Ջ hyN`u+_ʠs?P[|k"jD(gV A JdP(\FӁc.^o:W_t1$oYߥ95&>Z;Q:c}Wn~m瘑qKF>1@QJѦ]42[_cV*} EE"(Imkgg0-TBNXc=^)| -3-,d9P#]̂1b*&/vS?HΞs,F ݴ#-{<#wM>MnjDB= iZWs,83 S)BA%^՝p2,_?o^hs#4sΔ fb V b NkێŅy}9S P|S/99YbĻyHnյHG *Z[w?-o9ƾ&|)o5GOhen߿E1Z oBBݥFX/a9Qa0_Dc _6D44){g[KMHd&ef9EG\JPP8r55OT ƷK)eT)(SdU?)ejP(օjU( BBP(JD BP"P( v""rd EP(Ddi#$Dta~N׵F S( K$e9Hx\M]*"Iw@ $f^ Rkq(Jʄr,Ty%}SL:Tl6& D e )VzP(tu+k%dB! ToR7L"{  b PHDWjŋԓB,AR"%"('Zy@[ "\?s JJCv ߼8fTn(r2)\K.X1Q|/by 2b}MD@As./ݢKxIFB"K.K?ƈda̹]rE|h`Ո"%/'T*N{k.˲J.2$ Rwb{B/R 7cNUiuIx %QDJ>_fCCCpM@K.[t1CEK$95e39A,B֪Vdޯ/~VזSPU'n,LjJ$5;55uՠfolmk$IIR&Wѥ=}+qD~7tw=2:DWQlF%n; "b…A_(Jܘnkl 3AIJD ^s%(V<éd`fv4fD,_/%Cv|16~( ?|$^vɝ+?~t~wXrę (7c '$jނ}?n ~s//y,?#5hKާз|)t}=$y M$$ $@:R񖃧߂~yT&ؾ}On\x&Uyī;@ԃ9dv<3wÑר/g-؜P׏o3ߝqCFmv(Kԫ~#ۅO>M=x$k9Ԩ@!QDDD s߭IDFF$!H0J-RO\p1K3-}J/A+R) 3vxj܉Wk6׆wk.};4O>pgh_}>Uv=Xn >5̧b5uW1Os-hqf$ elwGρ֖B]]A]mTss"Ks \.FdϥK{;.sU.m+nF]*(5@HߖjݥP8[t+F""tYs#H.bS?VB[nImٮuB<\$y`^ʚ#IZAiU7Tp+4,ӨT)6yz!2YQ2rE F $\\Mҩ$׵M~P.||{l}⋪G y(,:w~GsCGQBBt*i*"LOutsfk^~EubO b+iƽʲZ](B>dnsy(<[ED =~׮ajA|6>hŕKTPP`hůAqoH˨xkR:GDд2::fG UQSd]D [ E64&=7\/nUªPrU>WuLVA5u<Ѕm,Ϥ5CPl=pmP~Q|s] cBTO&lc4-LꚦEc5s;:s}WE9UѕtK,Pu*/YlZ~#N-al^lKk1x(VS OGXc"תB<* {+lg IDATQb;(>+m%m?%}:6*lkŅy"0'U6Vx]xP".BuE٩oe-ĥUttUf4M..̫fg<J+A[;cp^b kQX]eh̭ٙ}?UиjYXВui @J95^w. fomXCZ.-?ZxGADSɉmW\zLJ$8 ?y|FZ4}~Pk{jmSkTBIΕFjaai/Sۈn[O4\~C,!h[Dct:U(܀,mLAKU4Qj곙3GP>+R2ƈ 4EAI)(_?o*_qb7JA :ZHg^eN,='X㡢j_6(ITz.lʏBו)*:Zޮ[^Ϭq"vQ"✻ _ Ra.S hR D>blttD_2Pl,jlj:wοc򑷥hKoIDHT]IKpުqs :33?~94i 9}O_A"`jn3@(,kIU]eQt>?`ttk\uQ(@dMMN?-Hi8-T}/>bRY5-O""㏆9gG)TII]/~A%Ղny[%u WϲWͪ͹W+pcǮC[ WA"}Bx9…'`%m_ObK?}թ%= =6Yr]CW.NtVgrq54Q;\u (UpKJ"d =0H ߞovdZAA@*P(6Ki~$\]V+ϫi' |,`n2o/N ܼ޳[uwG0ёj:/yD i%p(˳cհD@ &4͖]zpX#7ޭc Wtg~|[ܡ:$"VAB2q_,>CB tȶB^PAi6D+ykט}#R)@lZ0o%6{XǓɮWt"Z+&wmFС33uƨOoie{Cc@ٿ)S+5zzo֊43}ǭO޿,YKV~ nC*$H5G?Mƨ3rۻ3|}xHW>7?Qr)Bp8n(9Ig9mCBmTLD1xJCs_>Q+.%) AojL:`}7>C7/^9D7S^'#2qAi 9o ϟ/]}VHaIl_tgto7v߉cҠ;}Od¢=yS ]v O /d5ϭꋮQBs2L `O>ҺOlȓ]Nu%إYޛ2YRZZZ,(,ebQq&'}_h A\'W2RKAU( @gK4jtВ_H@nxwi$]].=ǻȂcӐ8Qå/r3^몓NVZ;*#L#m,gLљ}<~=ݔR:Yul4ێCfvqzi<PQ/rBe|L* OPz쁯r@W2򰵽_vrd4F rțeYmmcO pE5Me&ON͌xv3 H>5͚d6K|65sɈZ˜B=+p씐fPTdf"8/k}ny*^f_4pAK<Ͷ4nyRVJ@-Etfqn%gGK.okkծ= o>^C+IH!DRٴSLϟFw?42kZvi ґR /;lHy'Bwr<' aU*^bXDˇ4$ΨDRVӑd֨o4AȞ #L1/j\{<3sz8l:xiXWSHgtΝI'1;^svMن&I8? xG-aF"5I@AI)$I @zddSey 4c-k$mM ߷&n{͇q 3U{GM:c~剆7P]a'*" %%ykHFeYh8r PphqIwwW.qOWl%/dX;u_`5N~݄C$"s/!lMd`#R8ܴÆ4t3-=iZ-Y(l"kD :/tyJDvq.7` 4!|05iWjD,dTZDUЊ-.9Ks+{II.$MϏM{m5{:Nܹ7xq_o?V~SxUou6j8h"~by<&:R.2`Lӑ̤2~Xg$5]=8Iї;LYdll>ք4ivQ,Qٔbk4(.̌6vrvk Iޝo>W^HHn޿%[*:Rxy%~:wѬbo35.3{r ~~3|hɳKW|Ĝ5o;3gv6w/K =l[욛5:p>`ϯNVM֑|77fՌ&ќ#Z-uF%Ԝ+ @\MfDڝ0d6k8p\񶃯ݬ$-["~̞YW]QӲ8ӵTH'>nρȑ ;id1{eϜ={Ưu+ӞOf$v8ݴ{G|ۇO XÁ-wʒ62Uk>8R)dVʹGr|);xo8 G4X<\lnNQ62 g]bXgbꍘ3b:zoٚgq$ r1 @2VޓoO̷uG|`w5ˑ{D<~Տ')ɣ'ķ_O >o9ǐ[2,P9ԥk_;ŧ^p$oSϽÊ(vF(`gn9M..NN?컻k~mUyP<^hB_'TЈ2|1Yd#KAT6)m34M $srݖ"zUcMT#7ViDda  6J"ɬw$v3z62~2XHXVl0,jKL-4C2X+G=Bx81 nYMC[ݻPpRe"I[w-[O zJ)r BI=hL4s4Mc#`q(Fa]|Q@P( \sZWsZUhR%r1r hND"BxQ5_4㜗.u2Jl@K]W ccd۵hy\OxDTP(6a-h\\a&Qwy"z:>:><`s2DssK[, |c}lV]&WkϕXݮ b1<<DYjM #ƈ1D2"/\DKwmutFcQ]7|K.&&...t*^qrupƚe{n] 7U^W ߢUB $j*"lln׿<'n74׏  SQൕł6~nxlLO+ kaٳ#)\`PJobs-:'Og#^-(hgڶcdcS=Q O>[ 9r$":$$% bsz)x% '(*`3a4X!7%ʯPs܉Ѷ ZXfnvf" jZ?tj΅\*X3Uk(ZAbJ."@>("WBO|״%}ŅIi+gVʔJm?ܜ[$Kʝ BI=+]@HD[`4" $BPxiqw|(uOqH,Ut~~#rgo.?}'V|qmrs#s+5*g|t8VP(υ]{7JV}_'vYjwg ~4e٣m!$w{Ok:zbO 447y֜ ݮP(~4t]*C|JXL*Uque>QYzp]+zĥznT( y3+;BH"cMg>x%D'?|ud $ȹ, <$ݙqw~dc~w#mo5T*554IiH!n""Htٺwf;kFw IDATq"<|i:O;R'Apq<ٕSB5B:}q tF t8*p*BhQU&%0փr .c5u wX<֘h^RL-wvoܛIk_ItCg@“} "zU_9労`4ܾ}cz~zKMg?<֠` }Hh`ԭP(6fQnP~7tN` L iV(Igf&m(+زxOl̷Ȇ;Pmk )#UBTNxB)Jp߸\BșC|mmo΅$NU(RB;q!UlʧֹVdd/DDT7nL+ٲw~grSo g SXSo;{x? O}$?ט>؎ bUǠP(9RT[ݢ|6M4ce ZQ0+x~g mQUB،H)ʪ-ܖ&[eU0(}H'ZpBPiyQBؔz<=`ՁE9+e*UЮ?v&'Zk*ME.X۬JKKgcJRŏ+XkgXrSO(WYS"E4WUlR-X n ٙ n7O܆ J\Bʭ4 q!6'dfw]88RK~p[U߻s&Pd"ON[aQ~ofo|}Sx&7ϔP(9\1x_nQ_˝"_ņS}v~[ŵ_Ba ^e.^J~o|uĿ~wW{[ۣkyڬOCƌ++ŴPUXL\a_?y9^aNOKKEOcq2&2d{B^H+Jf-/DDG?JD|ݒ-L&k -O'&K:c^-DWD IQ"Bȭ޼pm}ۻs׮]m9籒;՗}YSX;lMQz{zbAv TiR R7پgi3ΦSf3gf̜NրJ ruip}KgMlgߺ'|s{'~Ai3*H_]19Mjo}gcҎS&?̢J>/<5-\%^#oҮdŢz~z<'t }$}}XqݣaM#tYSؕ;]><;c5%ʟB>X8aY15(m@bP4%z:eحWw繹?ۮu凴F!4hLMMl#lS\;&°LUgj"=yӲaUa|nWVTu_sQ{zߤyk3O[5Oϼ~0OZtI%m=Y3hEllJ$v۱[Jvvi˭-;=Pr>~O6 k<'sqr}njaYh6sb͛q(2f11\C[^)p҄`LAN,e罺on/r_#F_`Y-"%1*ˢ,˲$cB0,^qfn%.jwi%jSos.SpBPGtFqIyIKsxUx6ڄW]dRفWEA%zIapYIdIGtkÖ/EP#KVP|XHㅀ"bjk[6&qRPL0VU ٳtl(>C,7nϞ=VҥÇápww5y7lӣ}(#zqv']RgK%. ]eK\NјdN|XyQP(,wn/Щ+ĢֶVgOE(DbuzSQIXkBX{ݕ31 ^_\2uOVĸh'n ޭ4 B9q[,qC : z} Z^^(ҥKR(Qb2j11  A,h4AcBQ% DYG<%GJ B@[q(T|(1y.W5^XDJu#%E6gʳkYayDis9ՠx0WA ㎁ʎiz&>PNQi .XGkf4 B\oiB}(F6FV s"~Hk!Z~h6]1YӴD ê!5+J~Q) ?uUr_۲ronA*,K~MAP(Mrw.0,ba0 0͏U*==͌(֙45j::$ńƠpP9h +FȘӲZYbDgdch(j2@ ^/IJ1jj xTq 7j\˕AHXP8UJ" !HJx>[^zI`aXajxC:wjݳ.)"I(X,p8 Bp8D"x\$EUUQmSԕ ?}bʗGdPJqi6d졯륭_ƁUO?{Ul {mͿ:7V*,Ao{uۉ7N^8y5wٻM^;nW>-D.z?qp;+xAcO3~q+]=k7E2P:K4\OYՁr 3^M6.d])"N&*+ opfcG=RŐ?#E!'[q8.Q Vkte9͑driMiYF,x#ڌ =iNK.Nov@,䮈+XVg?f q,kETvEQ{XXU6a".\X8eY?N;GCtg^v:}Bu;;}}]/=5u +x ['ɵ@ƯyuZ䉙7uO0׷u]2]k|#;nzn4/zǟ ϫn|3rµKe{vL-k%#sZk5"ZE2J^oNwa9.! #Y\YZ31L,G*Mɰ۬ZW= 3iF!D" bHJqFWfɁ՚\gU a19\^gIs$O*BJ$.F0[tHMŪUArY8V4tHysJzՠ5:i%PyF((Qc,wڥÆ>ޭ[(+5%0Iep&Fy[8-\%^#oҮL~ūO U^[ NP{OK>xab{ͷ\ҬDP IDAT<{rQW-L*W6>"wڷ]mHwϊ S%_/Z,`]FKo_/߳w =Q`y~#3>vh[:h@~ev=rIfl׏my.N\ͥ 0u_RR]uoYYM_F-/}Fpׯ!-$YjwWꣳH;fiozՕKP*Z֛sW>|hާ։װE_O{uw_SvEuՌڔeaAːȮEKޑ͔/k?:v|P90]IrU|9m$?WD'dU% 0 `1QXň$gAzZ7+I"t Zrۧ{^رryVeL-?Pdֵc pؚ_كntزڌn_xcNgDޮ}1jds5dhg3ټrUN1_c`3G^yn C|QI?Œ4k7@ CMWS\3{L[{.)o?9aE,(Q, W-5?/oSBBw X3 oz%T ȖQ=Ě\4\R˞iYwiq9V%ݮP&![|z[1tŭ7]9rqkg΄Vꄮ˽{5t[;!Ng[`IIJܕjKAy,R`02UE^ ~{KwwFoZ̰ #9A}TAPiFFDY]1N^)色ؑ-ENc\3Fr&h_)d Htd"uQ*\ƴ Ⱦ՟EI>O܇*28w rGb9e l:* I=f wڤ:v}} (o!SZf<{c\P e˞csh%  QC٘(o$EQLyvێOlWY5{Ǵ05™Y=Y43񞲰 T+ZYV*Gz Xw1:\_%>⏜XfifQLdG! M,==geDޟ4vgO4CF0⇗|3{.5S^;Wc5[ΑoQYrvXR~^^VV755C=`/3`t)_~Ѳ5I`oAZO}E\l#5RB{nË?.X=& jwBP_QjRuvr99 Nvoq3DoMር{bqTi;K/9(!Y=Ƕ+a[vv2 sl\/`nmd5S Bi?zp~$ۙqÔP=?]pP4e`DPwvX(-[{9C%gʲu;*$I{̏翲c&gՃݡglZ,l6L&ѨZmb6M3$׽h޲!E$~t'*ZP…k,-Sa$_yE ^c1./d_@!~U( I7V(4궪 :{_[ˆ/[ +$qط3)AcuZ,o4됎ᕟ.?V}G9ŕZWO5H^V.oP;{m=ۙ5g7-ܪ5Z>urdt@ݖg[^pu_Q{ϞI9S9#+ZwE"׵M˵7 33>] lz~v|RDFpζh0¾%,XM,*VUY h:H>ug>{+y/+%,VlW?rž >;ȕLf;'xU(, sq۳YcF#ڿE%֡暙94$  *l:D)͋(|qu̷93|-quLt8_EӇO{oތ;G1q?b3òV}|rϟ_}yy>"`= k;hMșWk7{uI)/NH|aHֺɓygmҺ\xmAM;wE=|M{)/+vҮ,p9}rkKzN/ZI3uiG_/|uOଭϺ`ׁTٳ59s{|ώVΩ"i#qs_Gg *cH=b #{xIk:8R`g?2>Z枋7ѕi]^40"9ut jpg`,g_7t3&W)ϽQ]eER Gҵ,ڼ꣧P&{^ 29zœζ2Uݏl;R2^!{o)d JuCm*|]:}|Џ-1x,{wʶXl!|b4 E"$2ѩJӯ>{ҙ}8m oJ詢)K4(IZ )BY*g]ZY"KԙzWUo1BP(#bAYQf_į'(ԓBP(LD&J(HbDQQ!h%pc@)Ϋ_$͆L=0nh:_TMBP('JfjfJX5}m pp7ohCas^}] ]͉;| /P(L5Mr3?ID 7Y"@T6\aXcH)g5];QmQצMyi 0 l|N)V`/~"\;Goʳ/_yvUlp/=5)w%Q/JwT|7UK#IL0֦ oNi o})/=\{3ڡ}?9mܑtY|w8g/I1Bi!X{wtW%H %Q3 iVh"q,P'絉3bPUbCW~q ӝRzVKϽ@7tvjL))WVf\ j%vX .B۲ݖ3Fu|jz?1jZU#GuqvnS(p̦۷AE/r۶.k!TvG"Դ?f"b0{8fx@EJ-0,kYNN.R)usĤ$5&^Cw!5t'%R}UC &!ve=_|'Ob;;J%͜(0Ik l g%1‚ڠ HOܸ~-Pwn5~_?!VUUUmFfVZz*n^w"*r՚ -VG(BW& ΔjRwFpG61 "(5>ϝb;@⇾j{tUob*snE r,XPTT{^!  ܭ{oY6˾y eE cj;*+*83lvشAE \ECf;2RѕkСÏ:G3#:BsOuCXqM8&?x/|~Pn$NOq\v-1yΡejp7?kIr R &m{2B 1Qq⠐Դh4z(!DUTEUIonLgJ8N2G=xw]^r+r4l 'd ץ=?&sР?\«Tkޚ kkSnDjBynݻ36;;6k#_{ɱs$[ %OK6w^}uIH}{'N>ޏ"Koz|\]h B,QMMMڟ qVzZzYYIk= M6"\+AјH:Qhhd/1bu6Kl3{CRw./>uɿdv.?(/1E TUUQEQTUŪh7aO(X,V#X!1VEeQhkn'7nAYg[dgæ>4ïځZ~]3'ѫ߿?UK̚2 u r5ֵwS7,r[rG3ZQ!b>z?65 ""j DAM#mk6‚Tt(j]BϳF=}0YH=Q]߾b7)Mh svʎQ=gܦn}γr+>~[ }k̤xH/Z5>Q(g2% ^  !@&QNGM̿l).W+vEfHkWD1gw>xc]lܗG8=ew*_{ߺ3s=^!bj}{O[׮%낝Fٖ(՛Pb!@:Ll BVt^)ɧF,ķ{Rl/(WȽ wN0"TJy>>oWouok=s[n7~Սp{^<&źŸ6 m kUw5d۲=±E:y|s_[[ŎHVE2JLć{DELK&]qሑ9d{2Nvv[a-x`͡R[ 㮀ܱ8kHO;x7}~]Wpj8K.nfFfOK3;LƝ=KS`nz@ 7;&*3jK5g:yB~6;s]aEކ`u)]f_éd#AŻKFYTRL Ik}=8G/8gyўUp,#ks^9m["$t*B%,Ő!V4(C (kM10Bde6P6m> ؠ/R+虯Wfvv]9̈́/*ljg6U~s՚eYvhߖcvz{lnbR: j: yI>y0]wٷ+QzǶ7\ǿl}uULMbzIJZ1QPW =0DspQi%tn~FP #YXԝ{fåmo.To}t4x}a ?ɢI^F99gto-Su<4Xz\1L~m[X\tpO^萣_Mj08ZbER)֝ɃLgv ?ߋ_ٞM7wScJAKW?XE8-#zJ}uJP F͔,@f' "b\mEI7x) r&S{emSE !@HV* B$N'zZ-Q BP7FA JIٹTD) BF P@5+:\DEBP(YiT(B)D) Bi1OL-B "AQ+N<%@0%IR( \^^zmhFz=F>9m‚ I` x^b2 } {M^B@UA|]Bp( $mcYɜJAH+xI8U{ТڗjݟǾ6_9Q{3Bc~'!e]KET$INGz]Y(*:r͖3(Krrri%J^ Xlݲg1 ˰߶u`AKTUjmgVՓ)DU 2'5Ieq/'cvq] $>4vnǹC"Z>]=^әB+V"j5jݦ$ˋ WjZ(HzqQXM<3'I䰧RP(aO'߽nxRVEW$D|noA"*OR>}ޜܶubu_ ^j{OԞJ[ymxh%Jv)nJlZK7<55JmB͋"z0hC0,cY9!(B 2iPP0Q`YPHO.3;L6M Vhj"AImV+/[V+J^?^9Ѹ t=T_PwzvLJL+V"Djcu(!DQ$A U:!$KR  HP("*5Y-&-R^hJM1<Q cޛI_D-ګz^{gه`dQ]A"WqrUT{āa{z{-r;kD|?NfVVVVU]Sy2Ns"_|!% L4+b $P͊1rI.`t⩄]x#Un1_v|V,j<=ǻ3Qf}3e̴R΅IJ\*@"aV#@8#\)EdT#ȝbTĎ&R1(\af<3f{ {oVOӤowr9.Kv L\+5aD#t@ogTfrhZ:bdz:hƘWAӠM#5DǮFynM6C)Tcme|ϹNv-n>|i>|2:ǎ_ApLUePUW#C%h1Ce˰ u֦:B(|`a,J/EDHvd=<3pz$1 %3DL#Q7)RY)$)] $JЯPQڮ.aKg'H Tz%O Jv* iդ:i%:cؑu9(`oLS*BßRf%ܼg'sLigs'2df C+Dk. u(z>TV9U B7e#eMz8w~|Kb%{:{ GK2խq Y.ؚb1˴InZ[6 edQԠRx|RQ-45-7pfOχύB(ŁrI,C)PJ!ycrRdYMlϿG?@t+Sok\B,ak?>s81w? M^ړ:;=W/v;'"j܋_+ [G.͐S~W}>{*…(GfET7FPrTZ*e PTrds`.n @WVL/NN *t˳9N#ΧD]z>s%.GBh\/ Kinvt( gl=.~i@xQ Ԉ"?=IP~Tr =Hh´]XM?W2@z-TB-` l2(h۷FD[RԌܭjj?k-&;]!~o{$N_?߭( 62Rs28FcP7ޭE>~B`>umI]q|"ڿn?>3N#;s희x.vio~MTb[htZ<칉IOx@oLz^<+ϜYx,K?6͚u)Olߺ޸?6J[ztd493c] jDtD~Y:e*oo/&Ԟ-D-WrcG"̌%bAe1LozY%CZC \hWlov$О[#G٬a?4oc=o~Q%3J__D|+>OW3@0޽1W>ݓEͿKo'D|* Ui]'|Ou?a aO٧䏤ؤ3l P\O~;2ozᣟ:v|Y\q|n.|={ftc7ZXzw_xTQ47/~[mMTDkF\I/QJdzc"peGjT6=E9сS#ߛNDta$4pfŻ:zbQ]#%%[ )k]6as=5Qb Ќg=N rɗ4K':!}t$h@WJ'.To/nQJdzcJW.2=P3ߗc}uqS#(Z:l_:0OR wJeebj5ؼ9 lXog۶cXloH7>}뢖}~| +/X}M'~7;ҥ _X)$)"0ќB%pS@AɘwTi)D T@TWKuEL@?8l^#"vXaRv[ ^kY_]e豰v*Qv/!J)R(%8R(%rƘ$Vs\I }R^M % IԉDhTӴH$r%o湣OhoFq!DT;@)GMf384GlD\{K-޻dA[?/Coѽ4=HT2tK(\%3vp @;oЇo!!Qi:w噙FC~a֏e'q RTfJ艁RJVYFxR⚪DţD)TӢRYÕRn"buSAuCܹ94xǗE{G-ms'IO_%&^#{/}/??D(]RڳЃ~oRƲq~-4@^4w<|0<"U[wwtMT;Wzc|^>w332+uPw7zlmL7^^]"J D fP/2${k_<8ZfG5k\SxBR5+i DPAFhJ(ݷoq=]?|m:4::nدFw^}ؙ_t[w\1o HzzUK=G9"Iyܗ/OU\{xϯO[~I ;wJz#Կ|6G_ٷs%?_|gߞS@[h%>~|?~/\ns_~f6(IXLzuůEKG<>m2-k*QubP*\aMg%P6TjPx6\.u]aem>Z5܇~?>Hӛnz71=oy?NٍG~ (J9e3DƷ>BLcА8BpW\Ep0Mp8ڔ@toҲ&*:x14QF)a}RJH8G)%0Q+͆ʗSհ> Ȓban=zqvcW~ DUذjxУr*Jξ ^BH)=sǶmyTdҍZ#m]>y04`@%띻B%RC{Ň޵grODRɡ_ݲZ/c IDATYG/: 50Uwb#5܆AhS;; r,A6n,)!ao׉_[7>{xqjJUѵFyڎ#z.B]e0 sff gBN! +EV7I V/%̘kT*QʖSΑlGR0˜B݊t y֝:vn 0D H(i/?=QC/ܰQUDţkD`pppvfRaZQM7!约UCP~H!1zQS^+ d y7o̓mٶa [U[ o/tBRSClU*QZ!QvLVͰa8\HimD"Y˘ȃ )D83SՕkBs9Om]N٧YOJ)D7nڲEU*B$ F$wJ2] Dc"ẾQ]@{/KEP F)\h}>e9X|NF#fƝuc[n߲uzU%*\{se]DۮP3ڕr!K "HnKJbfSɸIx %c&)aXGga+b $P͊1rIQpKb̈.(b խX* H\*k);1\p[ ׬UPPXzV]eּb'0\@ hcL,+s 7nߵu[sE/,rM Zٞcɍ;6u&Z +HoԭUrG3$+9nCBۋrٸcRF@؅\Y6n~ .0r(((\<چB]KhD5]uM״Lb0t0tu]'AUߡŲ ᗅiL] %-{435rA+Ɯ2Z&̧dõlu$[7!ȝR([ɹFw@g"jo4ӟтreɞގT2r^dRJM0(((\[t@}׏jmH $b07HfYڱTr Z̐v2,hޮ“B(|`a,Eu=@ !(A-rlPp3GGӄtm7@(AR"/Qsl2BYWAAT%%Q.4^FTXȗLgW0SF՝@ZF)f(ѳ)P3peo( C]+Fݔ %j%{:{ GK2p wS Rx̤bPE W;k6vG"O%1q㉔rzj(c-KYQ<=U.J+,)X5Tr^6TJgsݝFOs5M2+g}q@2BX$ss"K3*<)\ѸDB~z.(r=ōE3 pm)\]w-(" .lwvvr."-jĤ'jfg7&=/gNpЬD<{h͍If: GSY'\@ho]o\}KˏIvFWV_p2΍MA DМ׹ȗ&G9afk0â,&<Tz3YtijfW\5G֣+Dd3Pז^ jY뺖e-V'[,;RX( t"¤3G #@5+!(W.BoH ]++pNH7^KO -rpЈgz6DM@/VbV_):/b[dŅ TAAᚡ G!Qqk0973 HK9I T[ۡv>_M ZR MP!%s3u U^:W ~enqA筸! jUΣ ̹x MĢr.VcK X$ٹ2hPRTAA*6ObM;,ZJb*U\LJ*((\݊yNsHUaمQ*kR 7R.١E%p!٨Pom $\H(å(DDRb3ꅄ5@m0VxbnGCf|bbm.4- 5 X89OaX0+!RJ(]~\f˪D/o!i?X Y1 / r eR Wh[ChLD{uRlJ%ĵ /sοɶ9ȠMEkHij-)NaebUq6g[sn VLC9ZAb6p~JtdQRBH]=zwD/}&\R嵚`ubqSB%HB#̯-]J\s.%D.nq>JM =HڷаD)%-t>_mRzR\h$-Rdm%5BZ RIRH)R0МXϹqΕ` hwHJUcPPɅzr*b}Z3κؤhBU/:/DKhgfgd<S MünV[$‚XR2T@) MUie<_6Z|q[JT͉*(\e$2R _gBiAϔ^^:љh`gWJŒHO'b)fC-R΅n! T,V|̌rPDb%Z;o#EDTJ'jP5Nm$=( ULTwGqcL2HTA9ӥHtHF` ,Ǥo,uϫ_J1u<.B 0hD(B\BS{:ύ/}i,4bx1ΞSeoP'*f2ӹ0eP+-PĈFB~ffC]1(Q[MM< &AAWO%gO҂ϯ$VT5ωC 3<LRp9H1#4ErKͧ(YAIKUJt0$PhQxulМBمHҨrSJD"/͕j@=Ț^ceB-sn͵ iōC@oޡ== v`[]Pw)jB].&.Yf/lΑPcB¥mΙm$QX,m]A՜¾_=Dp"-fHrPgmDqt c8){BP^VޚGg nKљ!QwSq\/ghέ.^|bJ *UPJXK3Zz|Y+.i9siɂ˃2%UzH4Vݳ\s=i["5疿.( C+/}rϖ(,@mV S 6m\Rd ъ¢9 -ʜpũw)&6SK ]xl¬^*Jn\KLVa ^Jl,#E bzqvrHP)[͹fwwq>%r4u:HL/L-dW_-BAz*Vi($DW]"PRB)U$peJaKDr1RKBivB0mIBR\8# jtV&&=T3=1yT G}z"[Z~H3*b޶"2΍MAz%tK1$Iңf]KVm5q9B bn"Q4YnʜpIt!_B " nsmѪ8Db__(F ("#(Eˎ"lz 55s<F70HhP͊wuĢFJKRB׺l <Jz$ћ /*'|@ߴx]i+15i^!e9%rnڦ[ [9'p޹-]hY] @_,Xi)DsɅ(tB(a'0ӑEvyPxW}]v>_M ZR N ) OrՔ+;0\Zk]JNOiT[gswJ^G}\12 >^[LvvfR)Jt>$*BHB d)R"gIQB^$5Ї)7hbmvH ^Aei J6 m>{d"0LK4D D*:OV82vn;< K_`.ӈ/ٜ(QZkH.4bdЫ n4T.g'YkZ".駦UGWpy7MЪ"Q2/DN ڈx<EWm WaR/F gP$zUV痡նb QE 0.Mm:V$z(-Ŵ4ɞw=oU$p(m>^S$$](q R(ѐFU]+(\sD˄%jU|>RVSJo4."y@4u]EM\x.Q-lAAAa<-ֈؽ{ׁ- w^]CrX43d2b&1 9^F̹ \̘zUݻw:љh`gWJŒHO'b)fn1_v|V,j<=ǻ3Qf}3e̴R΅ ~T,.ڑ顾wfgr%D$SF;R%q PSg* ̈:|"'2ι݉f ">؟5ĜfT=~/\2B=7:ЁcarZVd֥-s<3]sJ 0J CFtZ_+4տ'ޗfUY  V'i~@9{UeoP'*f2ӹ0eP+yՎB;7e"ԙ<>RNݴ#)e/ E5dBOvvŝY F4if}>Y˳0v6WTƞO=sc}tnXeԘ ٽi]&;2Zgr?]/m0\4xBMV}4:".+'/TϨp taViZ7r4-jEzz{+G_Fqɴj[- HG*(((-*74]?Ǯ<J4HjUȣ *mMMߏ~I5+N, rU$DCp((+%֗]u%vc2*kG.%PJ-+O?u 4#5jCW*6UPP*fP^ssբ$Z* !l~XX .*BUPP"Ĺ*4/Vk$##53=Y.r$ZzH2p"KQE(iӄ JkXN"CXnKLvrb|AJ`Utm_cHŵ +@YMXݤ!U4]k[@Dl? C/M;T.%l)K !4YHĥӳՕE.-+\Jz^cp \fc%aork6^BoeD ͹HH'(TժT$"bYhPRONN !bѨrjzfuUuz{j+%P(k*.w-Ik3 ά FT~*VQՏ 0#ш8!DLxUn Ez*Лޜ@꙯vߘ~Y!QޘsG}~|T5.<.C DB"CI~85 kU+(,MBo<0tbHl2#}XֻؑW_߫u7n;ȑ1{ ,xڲҹ3rx\jJhgS(%$ơ!9A+8r0T-*lAsm*ѐC[.$ȁT =u!\xTa2M)\.MӚ53}#ܸޔ+{9ȿO(yXTDZ$G ܝ$+;hEY1bmVM+LǷWO<|vHcj kגd&BĐ('"uَm\X=Q")(@D+(T+.ɢ;-%ZdԔ`-bmUAaͣsxdKcnD)\ BΉ`Hng?ĉWnl~>t{M̿ȈEDnk:rK_HݍPAa'Z9) "PZ|G_Fq_:pݮ<ϭ୩yUUPcXMbX*_(CL+BȄRj&p!xN(#ʀs)iZ eVʼn)c(<@,sQ X=R$''0C'zBa/|qqǮ<(GÍE՘J*(h%uK"a$hj0 5g; ?).N7\ǹQPIMrVMQn%3 jSTPhd"L,zT((\ d޵j$y Ẕ#Iנ5m4`kS}.jdèJAyj^)UϩyUs/~ŷWlkWBKQH(E@\t}M33x9R@" \ CaZܐPH}!4}L&vu:y]==d \eUPPPPF \GjTH9ΙS'wn2;=9rLS*!if]=vuSPPPPPXRZ.UA((((((3t,A|.Hj7{Ц-[YAAAAAay bT|O*4g:'[DFϜ*%7]'@S#ݛ{ иs n˝ZtsO˻he;n)ͷ=ϔEbF$mvP3B)136lmyEGn(C߹;:HǺ[7d4'jm=)(((\;~'~$*׻bpYtЕ|4ݶ=;2ϜsƆwϖF;eT%VٳΚ zѡ]Yv§\;37k~$bɃv:q1ߩcޝ7R[︣{jd|ԙhu uh||>VWh,ي@JDiOV9FbхlmP%^s%̊j:r=}X}-1jcgK$(Ŷںϥgm1>|d2Q'GE@r-[HʼnL-` ")Ay4)((\UKLSGG@^0zI'=%gcE'OWb}i$Fv};ulѮs?gYf}>~ő&<âDDze[ .>KޘN- @wX(f`v,m[i7bxkM::]1Q"ƕ3,Mwp칞f(]WB $S|(,@ύxu[eU}x*[\Qxقd~anJt*((\( !7P7mֽv}/%uזDRq>Ӈ':v$ϏyIi?zgHd=:\Ӧ#~H@Tߎ;o=ѱ{]7g}ГO,=I- ihCn܃M-&}OoN?/zur3vvux 7ܶ5 +^woߔ{i7DϦⱲ#!,'MnmwTmYUoM1l۔W;yp8sm˥CY4YqH3 i(96IBaX1J])1])!iE4MAzA3-RR(=@ LUfB=2[R塠pIIt)"73$S: _φsJ^0LS D=Gu F.eŭDIENDB`nut-2.8.1/scripts/python/app/README0000644000175000017500000000366614501607135013736 00000000000000NUT-Monitor =========== NUT-Monitor is a graphical application to access and manage UPSes connected to a NUT (Network UPS Tools) server. Dependencies ------------ This application (variants written in Python 2 + GTK2, and in Python 3 + Qt5) uses the python-pynut class (available at http://www.lestat.st), delivered as PyNUT in the NUT source tree. Refer to your OS packaging and/or install custom modules with `pip` (or `pip3`) to get required dependencies (GTK + GObject or QT5). Path to PyNUT module -------------------- For quick tests (e.g. during development), you can run the clients like this: ```` :; PYTHONPATH=../module/ python2 ./NUT-Monitor-py2gtk2.in ```` or: ```` :; PYTHONPATH=../module/ python3 ./NUT-Monitor-py3qt5.in ```` Localization ------------ For localized UI, also `export LANG=fr_FR.UTF-8` or `export LANG=ru_RU.UTF-8` (see and feel welcome to improve the choice of languages in `locale` directory). NOTE: Currently localization only works for Python 2 client, PRs are welcome. Desktop menu integration ------------------------ This component ships both implementation-specific `nut-monitor-py2gtk2.desktop` and `nut-monitor-py3qt5.desktop` files which allows a user to have icons for both variants separately, as well as the legacy-named `nut-monitor.desktop` for running the wrapper script `NUT-Monitor` which picks an implementation best suited for current run-time circumstances. Screenshots ----------- image::screenshots/nut-monitor-1.png[Example of device status overview] image::screenshots/nut-monitor-2.png[Example report of device variables] image::screenshots/nut-monitor-3.png[Example modification of a writeable variable] Kudos ----- NUT-Monitor and PyNUT (for Python 2 syntax) were originally authored by David Goncalves NUT-Monitor was converted to Python 3 + QT5 by Luke Dashjr PyNUT was extended, and two variants of NUT-Monitor converged and wrapped for Python 2+3 dual support by Jim Klimov nut-2.8.1/scripts/python/Makefile.am0000644000175000017500000001420414501607135014320 00000000000000# Network UPS Tools: scripts/python # Recognize settings from configure.ac (for make install handling) nut_with_nut_monitor = @nut_with_nut_monitor@ nut_with_nut_monitor_dir = @nut_with_nut_monitor_dir@ nut_with_nut_monitor_py2gtk2 = @nut_with_nut_monitor_py2gtk2@ nut_with_nut_monitor_py3qt5 = @nut_with_nut_monitor_py3qt5@ # Note: this may be "desktop-file-install" to use in e.g. # packaging postinstall scripts for tighter OS integration; # note also the icon files, etc. that may want symlinks to # system-defined locations. For examples please see e.g. # https://aur.archlinux.org/cgit/aur.git/tree/PKGBUILD?h=nut-monitor #nut_with_nut_monitor_desktop = @nut_with_nut_monitor_desktop@ nut_with_pynut = @nut_with_pynut@ nut_with_pynut_py = @nut_with_pynut_py@ nut_with_pynut_py2 = @nut_with_pynut_py2@ nut_with_pynut_py3 = @nut_with_pynut_py3@ PYTHON_SITE_PACKAGES = @PYTHON_SITE_PACKAGES@ PYTHON2_SITE_PACKAGES = @PYTHON2_SITE_PACKAGES@ PYTHON3_SITE_PACKAGES = @PYTHON3_SITE_PACKAGES@ BINDIR = @BINDIR@ NUT_MONITOR_PY2GTK2 = \ app/ui/gui-1.3.glade \ app/nut-monitor-py2gtk2.desktop NUT_MONITOR_PY2GTK2_TEMPLATE = \ app/NUT-Monitor-py2gtk2.in NUT_MONITOR_PY2GTK2_GENERATED_SCRIPT = \ app/NUT-Monitor-py2gtk2 NUT_MONITOR_PY3QT5 = \ app/ui/aboutdialog1.ui \ app/ui/dialog1.ui \ app/ui/dialog2.ui \ app/ui/window1.ui \ app/nut-monitor-py3qt5.desktop NUT_MONITOR_PY3QT5_TEMPLATE = \ app/NUT-Monitor-py3qt5.in NUT_MONITOR_PY3QT5_GENERATED_SCRIPT = \ app/NUT-Monitor-py3qt5 NUT_MONITOR_COMMON = \ README \ app/nut-monitor.appdata.xml \ app/icons/48x48/nut-monitor.png \ app/icons/64x64/nut-monitor.png \ app/icons/256x256/nut-monitor.png \ app/icons/scalable/nut-monitor.svg \ app/README \ app/screenshots/nut-monitor-1.png \ app/screenshots/nut-monitor-2.png \ app/screenshots/nut-monitor-3.png \ app/pixmaps/on_battery.png \ app/pixmaps/on_line.png \ app/pixmaps/var-ro.png \ app/pixmaps/var-rw.png \ app/pixmaps/warning.png \ app/locale/fr/LC_MESSAGES/NUT-Monitor.mo \ app/locale/it/LC_MESSAGES/NUT-Monitor.mo \ app/locale/ru/LC_MESSAGES/NUT-Monitor.mo PYNUT_COMMON = \ module/README # Note: we both distribute and install the generated *.mo translation files # so they are listed above and not in NUT_MONITOR_COMMON_TEMPLATE NUT_MONITOR_COMMON_TEMPLATE = \ app/locale/NUT-Monitor.pot \ app/locale/fr/fr.po \ app/locale/it/it.po \ app/locale/ru/ru.po PYNUT_TEMPLATE = \ module/PyNUT.py.in \ module/test_nutclient.py.in PYNUT_GENERATED_NOEXEC = \ module/PyNUT.py PYNUT_GENERATED_SCRIPT = \ module/test_nutclient.py # For now, we have a "dispatcher" script and applet manifest, # to select a functional choice of the GUI client, if possible: NUT_MONITOR_DISPATCHER_NOEXEC = \ app/nut-monitor.desktop NUT_MONITOR_DISPATCHER_SCRIPT = \ app/NUT-Monitor ################################################################# # `make dist` tarball contents: EXTRA_DIST = \ $(NUT_MONITOR_DISPATCHER_NOEXEC) $(NUT_MONITOR_DISPATCHER_SCRIPT) \ $(NUT_MONITOR_COMMON) $(NUT_MONITOR_COMMON_TEMPLATE) \ $(PYNUT_COMMON) $(PYNUT_TEMPLATE) EXTRA_DIST += $(NUT_MONITOR_PY2GTK2) $(NUT_MONITOR_PY2GTK2_TEMPLATE) EXTRA_DIST += $(NUT_MONITOR_PY3QT5) $(NUT_MONITOR_PY3QT5_TEMPLATE) ################################################################# # `make install` handling (nobase_ to keep tree structure): # Make py2/py3-only builds, delivered preferred symlinks, etc. optional if WITH_NUT_MONITOR nutmonitordir = $(nut_with_nut_monitor_dir) nobase_nutmonitor_DATA = $(NUT_MONITOR_DISPATCHER_NOEXEC) $(NUT_MONITOR_COMMON) nobase_nutmonitor_SCRIPTS = $(NUT_MONITOR_DISPATCHER_SCRIPT) if HAVE_MSGFMT # Note lack of "$<" below - it is a non-portable GNU Make extension # The POT-Creation-Date: is removed by current python gettext builder to avoid # "spurious" changes that do not benefit (otherwise unmodified) contents; see: # https://github.com/sphinx-doc/sphinx/pull/3490 # https://github.com/sphinx-doc/sphinx/issues/3443 # Note that OUTFILE may be in builddir (not necessarily same as srcdir) ACT_MSGFMT = { \ $(GREP) -v -E '^.?POT-Creation-Date: ' < "$${SRCFILE}" > "$${OUTFILE}.tmpsrc" && \ $(MSGFMT) -o "$${OUTFILE}" "$${OUTFILE}.tmpsrc" && \ rm -f "$${OUTFILE}.tmpsrc" ; \ } app/locale/fr/LC_MESSAGES/NUT-Monitor.mo: app/locale/fr/fr.po @$(MKDIR_P) "$(builddir)/app/locale/fr/LC_MESSAGES" SRCFILE="$^"; OUTFILE="$@"; $(ACT_MSGFMT) app/locale/it/LC_MESSAGES/NUT-Monitor.mo: app/locale/it/it.po @$(MKDIR_P) "$(builddir)/app/locale/it/LC_MESSAGES" SRCFILE="$^"; OUTFILE="$@"; $(ACT_MSGFMT) app/locale/ru/LC_MESSAGES/NUT-Monitor.mo: app/locale/ru/ru.po @$(MKDIR_P) "$(builddir)/app/locale/ru/LC_MESSAGES" SRCFILE="$^"; OUTFILE="$@"; $(ACT_MSGFMT) endif HAVE_MSGFMT if WITH_NUT_MONITOR_PY2GTK2 nobase_nutmonitor_DATA += $(NUT_MONITOR_PY2GTK2) nobase_nutmonitor_SCRIPTS += $(NUT_MONITOR_PY2GTK2_GENERATED_SCRIPT) endif WITH_NUT_MONITOR_PY2GTK2 if WITH_NUT_MONITOR_PY3QT5 nobase_nutmonitor_DATA += $(NUT_MONITOR_PY3QT5) nobase_nutmonitor_SCRIPTS += $(NUT_MONITOR_PY3QT5_GENERATED_SCRIPT) endif WITH_NUT_MONITOR_PY3QT5 if WITH_PYNUT_APP nobase_nutmonitor_DATA += $(PYNUT_COMMON) $(PYNUT_GENERATED_NOEXEC) nobase_nutmonitor_SCRIPTS += $(PYNUT_GENERATED_SCRIPT) endif WITH_PYNUT_APP sysbindir = $(BINDIR) sysbin_SCRIPTS = NUT-Monitor # Dummy redirector for /usr/bin/... presence NUT-Monitor: Makefile @echo '#!/bin/sh' > "$@" @echo 'exec "$(nutmonitordir)/app/NUT-Monitor" "$$@"' >> "$@" endif WITH_NUT_MONITOR # These are dumped into site-packages directly, right? if WITH_PYNUT_PY pynut_py_sitedir = $(PYTHON_SITE_PACKAGES) pynut_py_site_DATA = $(PYNUT_GENERATED_NOEXEC) pynut_py_site_SCRIPTS = $(PYNUT_GENERATED_SCRIPT) endif if WITH_PYNUT_PY2 pynut_py2_sitedir = $(PYTHON2_SITE_PACKAGES) pynut_py2_site_DATA = $(PYNUT_GENERATED_NOEXEC) pynut_py2_site_SCRIPTS = $(PYNUT_GENERATED_SCRIPT) endif if WITH_PYNUT_PY3 pynut_py3_sitedir = $(PYTHON3_SITE_PACKAGES) pynut_py3_site_DATA = $(PYNUT_GENERATED_NOEXEC) pynut_py3_site_SCRIPTS = $(PYNUT_GENERATED_SCRIPT) endif ################################################################# MAINTAINERCLEANFILES = Makefile.in .dirstamp clean-local: $(AM_V_at)rm -rf *.pyc __pycache__ */*.pyc */__pycache__ */*/*.pyc */*/__pycache__ $(AM_V_at)rm -f NUT-Monitor nut-2.8.1/scripts/python/README0000644000175000017500000000370414501607135013147 00000000000000Python NUT Client files ----------------------- This directory contains various NUT Client related Python scripts, written by David Goncalves, and released under GPL v3. module ~~~~~~ This directory contains PyNUT.py, which is a Python abstraction class to access NUT data server(s). You can use it in Python programs to access NUT's upsd data server in a simple way, without having to know the NUT protocol. The same module should work for Python 2 and Python 3. To import it on Python programs you have to use the following (case sensitive): import PyNUT This module provides a 'PyNUTClient' class that can be used to connect and get data from an upsd data server. To install the PyNUT module on Debian/Ubuntu, copy it to: /usr/share/python-support/python-pynut/ For quick tests, just make sure its directory is exported in `PYTHONPATH` environment variable. This directory also contains test_nutclient.py, which is a PyNUT test program. For this to be fully functional, you will need to adapt the login, password and upsname to fit your configuration. A NUT data server should be running for the test program to verify connection and protocol support. For one practical example, you can research `tests/NIT/nit.sh` in NUT sources. app ~~~ This directory contains the NUT-Monitor application, which uses the PyNUT class, along with its resources. To install it, you will either need to keep the files together, or to install: - Depending on the Python version(s) your system has, put NUT-Monitor-py2gtk2 or NUT-Monitor-py3qt5 to /usr/bin/, /usr/X11R6/bin/ or something like that (optionally making a simple NUT-Monitor symlink to the preferred version), - ui/*.glade (for NUT-Monitor-py2gtk2) or ui/*.ui (for NUT-Monitor-py3qt5) to /usr/share/nut-monitor/, - nut-monitor.png to something like /usr/share/pixmaps/ - finally, nut-monitor-py2gtk2.desktop and/or nut-monitor-py3qt5.desktop (optionally symlinked as nut-monitor.desktop) to /usr/share/applications/ nut-2.8.1/scripts/Makefile.am0000644000175000017500000000133714501607135013002 00000000000000EXTRA_DIST = README \ avahi/nut.service.in \ HP-UX/nut-drvctl \ HP-UX/nut-drvctl.sh \ HP-UX/nut-upsd \ HP-UX/nut-upsd.sh \ HP-UX/nut-upsmon \ HP-UX/nut-upsmon.sh \ logrotate/nutlogd \ misc/nut.bash_completion \ misc/osd-notify \ perl/Nut.pm \ RedHat/halt.patch \ RedHat/README \ RedHat/ups.in \ RedHat/upsd.in \ RedHat/upsmon.in \ Solaris8/S99upsmon \ subdriver/gen-usbhid-subdriver.sh \ subdriver/gen-snmp-subdriver.sh \ upower/95-upower-hid.hwdb \ upower/95-upower-hid.rules \ Windows/halt.c \ Windows/Makefile SUBDIRS = augeas devd hotplug python systemd udev ufw Solaris Windows upsdrvsvcctl MAINTAINERCLEANFILES = Makefile.in .dirstamp nut-2.8.1/scripts/udev/0000755000175000017500000000000014520277777012005 500000000000000nut-2.8.1/scripts/udev/nut-usbups.rules.in0000644000175000017500000003755514520277776015551 00000000000000# This file is generated and installed by the Network UPS Tools package. ACTION=="remove", GOTO="nut-usbups_rules_end" SUBSYSTEM=="usb_device", GOTO="nut-usbups_rules_real" SUBSYSTEM=="usb", GOTO="nut-usbups_rules_real" GOTO="nut-usbups_rules_end" LABEL="nut-usbups_rules_real" # SNR-UPS-LID-XXXX UPSes - nutdrv_qx ATTR{idVendor}=="0001", ATTR{idProduct}=="0000", MODE="664", GROUP="@RUN_AS_GROUP@" # Hewlett Packard # e.g. ? - usbhid-ups ATTR{idVendor}=="03f0", ATTR{idProduct}=="0001", MODE="664", GROUP="@RUN_AS_GROUP@" # T500 - bcmxcp_usb ATTR{idVendor}=="03f0", ATTR{idProduct}=="1f01", MODE="664", GROUP="@RUN_AS_GROUP@" # T750 - bcmxcp_usb ATTR{idVendor}=="03f0", ATTR{idProduct}=="1f02", MODE="664", GROUP="@RUN_AS_GROUP@" # HP T750 INTL - usbhid-ups ATTR{idVendor}=="03f0", ATTR{idProduct}=="1f06", MODE="664", GROUP="@RUN_AS_GROUP@" # HP T1000 INTL - usbhid-ups ATTR{idVendor}=="03f0", ATTR{idProduct}=="1f08", MODE="664", GROUP="@RUN_AS_GROUP@" # HP T1500 INTL - usbhid-ups ATTR{idVendor}=="03f0", ATTR{idProduct}=="1f09", MODE="664", GROUP="@RUN_AS_GROUP@" # HP R/T 2200 INTL (like SMART2200RMXL2U) - usbhid-ups ATTR{idVendor}=="03f0", ATTR{idProduct}=="1f0a", MODE="664", GROUP="@RUN_AS_GROUP@" # HP R1500 G2 and G3 INTL - usbhid-ups ATTR{idVendor}=="03f0", ATTR{idProduct}=="1fe0", MODE="664", GROUP="@RUN_AS_GROUP@" # HP T750 G2 - usbhid-ups ATTR{idVendor}=="03f0", ATTR{idProduct}=="1fe1", MODE="664", GROUP="@RUN_AS_GROUP@" # e.g. ? - usbhid-ups ATTR{idVendor}=="03f0", ATTR{idProduct}=="1fe2", MODE="664", GROUP="@RUN_AS_GROUP@" # HP T1500 G3 - usbhid-ups ATTR{idVendor}=="03f0", ATTR{idProduct}=="1fe3", MODE="664", GROUP="@RUN_AS_GROUP@" # R/T3000 - usbhid-ups ATTR{idVendor}=="03f0", ATTR{idProduct}=="1fe5", MODE="664", GROUP="@RUN_AS_GROUP@" # R/T3000 - usbhid-ups ATTR{idVendor}=="03f0", ATTR{idProduct}=="1fe6", MODE="664", GROUP="@RUN_AS_GROUP@" # various models - usbhid-ups ATTR{idVendor}=="03f0", ATTR{idProduct}=="1fe7", MODE="664", GROUP="@RUN_AS_GROUP@" # various models - usbhid-ups ATTR{idVendor}=="03f0", ATTR{idProduct}=="1fe8", MODE="664", GROUP="@RUN_AS_GROUP@" # Eaton # various models - usbhid-ups ATTR{idVendor}=="0463", ATTR{idProduct}=="0001", MODE="664", GROUP="@RUN_AS_GROUP@" # various models - usbhid-ups ATTR{idVendor}=="0463", ATTR{idProduct}=="ffff", MODE="664", GROUP="@RUN_AS_GROUP@" # Dell # various models - usbhid-ups ATTR{idVendor}=="047c", ATTR{idProduct}=="ffff", MODE="664", GROUP="@RUN_AS_GROUP@" # ST Microelectronics # TS Shara UPSes; vendor ID 0x0483 is from ST Microelectronics - with product IDs delegated to different OEMs - nutdrv_qx ATTR{idVendor}=="0483", ATTR{idProduct}=="0035", MODE="664", GROUP="@RUN_AS_GROUP@" # USB IDs device table - usbhid-ups ATTR{idVendor}=="0483", ATTR{idProduct}=="a113", MODE="664", GROUP="@RUN_AS_GROUP@" # IBM # 6000 VA LCD 4U Rack UPS; 5396-1Kx - usbhid-ups ATTR{idVendor}=="04b3", ATTR{idProduct}=="0001", MODE="664", GROUP="@RUN_AS_GROUP@" # Riello (Cypress Semiconductor Corp.) # various models - riello_usb ATTR{idVendor}=="04b4", ATTR{idProduct}=="5500", MODE="664", GROUP="@RUN_AS_GROUP@" # Minibox # openUPS Intelligent UPS (minimum required firmware 1.4) - usbhid-ups ATTR{idVendor}=="04d8", ATTR{idProduct}=="d004", MODE="664", GROUP="@RUN_AS_GROUP@" # openUPS Intelligent UPS (minimum required firmware 1.4) - usbhid-ups ATTR{idVendor}=="04d8", ATTR{idProduct}=="d005", MODE="664", GROUP="@RUN_AS_GROUP@" # Belkin # F6H375-USB - usbhid-ups ATTR{idVendor}=="050d", ATTR{idProduct}=="0375", MODE="664", GROUP="@RUN_AS_GROUP@" # F6C550-AVR - usbhid-ups ATTR{idVendor}=="050d", ATTR{idProduct}=="0551", MODE="664", GROUP="@RUN_AS_GROUP@" # F6C1250-TW-RK - usbhid-ups ATTR{idVendor}=="050d", ATTR{idProduct}=="0750", MODE="664", GROUP="@RUN_AS_GROUP@" # F6C1500-TW-RK - usbhid-ups ATTR{idVendor}=="050d", ATTR{idProduct}=="0751", MODE="664", GROUP="@RUN_AS_GROUP@" # F6C900-UNV - usbhid-ups ATTR{idVendor}=="050d", ATTR{idProduct}=="0900", MODE="664", GROUP="@RUN_AS_GROUP@" # F6C100-UNV - usbhid-ups ATTR{idVendor}=="050d", ATTR{idProduct}=="0910", MODE="664", GROUP="@RUN_AS_GROUP@" # F6C120-UNV - usbhid-ups ATTR{idVendor}=="050d", ATTR{idProduct}=="0912", MODE="664", GROUP="@RUN_AS_GROUP@" # F6C800-UNV - usbhid-ups ATTR{idVendor}=="050d", ATTR{idProduct}=="0980", MODE="664", GROUP="@RUN_AS_GROUP@" # Regulator PRO-USB - usbhid-ups ATTR{idVendor}=="050d", ATTR{idProduct}=="0f51", MODE="664", GROUP="@RUN_AS_GROUP@" # F6C1100-UNV, F6C1200-UNV - usbhid-ups ATTR{idVendor}=="050d", ATTR{idProduct}=="1100", MODE="664", GROUP="@RUN_AS_GROUP@" # APC # APC AP9584 Serial->USB kit - usbhid-ups ATTR{idVendor}=="051d", ATTR{idProduct}=="0000", MODE="664", GROUP="@RUN_AS_GROUP@" # various models - usbhid-ups ATTR{idVendor}=="051d", ATTR{idProduct}=="0002", MODE="664", GROUP="@RUN_AS_GROUP@" # USB IDs device table - apc_modbus ATTR{idVendor}=="051d", ATTR{idProduct}=="0003", MODE="664", GROUP="@RUN_AS_GROUP@" # various 5G models - usbhid-ups ATTR{idVendor}=="051d", ATTR{idProduct}=="0004", MODE="664", GROUP="@RUN_AS_GROUP@" # Powerware # various models - bcmxcp_usb ATTR{idVendor}=="0592", ATTR{idProduct}=="0002", MODE="664", GROUP="@RUN_AS_GROUP@" # PW 9140 - usbhid-ups ATTR{idVendor}=="0592", ATTR{idProduct}=="0004", MODE="664", GROUP="@RUN_AS_GROUP@" # Agiler UPS - nutdrv_qx ATTR{idVendor}=="05b8", ATTR{idProduct}=="0000", MODE="664", GROUP="@RUN_AS_GROUP@" # Delta UPS # Delta UPS Amplon R Series, Single Phase UPS, 1/2/3 kVA - usbhid-ups ATTR{idVendor}=="05dd", ATTR{idProduct}=="041b", MODE="664", GROUP="@RUN_AS_GROUP@" # Delta/Minuteman Enterprise Plus E1500RM2U - usbhid-ups ATTR{idVendor}=="05dd", ATTR{idProduct}=="a011", MODE="664", GROUP="@RUN_AS_GROUP@" # Delta/Minuteman PRO1500RT2U - usbhid-ups ATTR{idVendor}=="05dd", ATTR{idProduct}=="a0a0", MODE="664", GROUP="@RUN_AS_GROUP@" # Belkin F6C1200-UNV/Voltronic Power UPSes - nutdrv_qx ATTR{idVendor}=="0665", ATTR{idProduct}=="5161", MODE="664", GROUP="@RUN_AS_GROUP@" # Phoenixtec Power Co., Ltd # Online Yunto YQ450 - nutdrv_qx ATTR{idVendor}=="06da", ATTR{idProduct}=="0002", MODE="664", GROUP="@RUN_AS_GROUP@" # Mustek Powermust - nutdrv_qx ATTR{idVendor}=="06da", ATTR{idProduct}=="0003", MODE="664", GROUP="@RUN_AS_GROUP@" # Phoenixtec Innova 3/1 T - nutdrv_qx ATTR{idVendor}=="06da", ATTR{idProduct}=="0004", MODE="664", GROUP="@RUN_AS_GROUP@" # Phoenixtec Innova RT - nutdrv_qx ATTR{idVendor}=="06da", ATTR{idProduct}=="0005", MODE="664", GROUP="@RUN_AS_GROUP@" # Phoenixtec Innova T - nutdrv_qx ATTR{idVendor}=="06da", ATTR{idProduct}=="0201", MODE="664", GROUP="@RUN_AS_GROUP@" # Online Zinto A - nutdrv_qx ATTR{idVendor}=="06da", ATTR{idProduct}=="0601", MODE="664", GROUP="@RUN_AS_GROUP@" # PROTECT B / NAS - usbhid-ups ATTR{idVendor}=="06da", ATTR{idProduct}=="ffff", MODE="664", GROUP="@RUN_AS_GROUP@" # iDowell # iDowell - usbhid-ups ATTR{idVendor}=="075d", ATTR{idProduct}=="0300", MODE="664", GROUP="@RUN_AS_GROUP@" # Cyber Power Systems # 900AVR/BC900D - usbhid-ups ATTR{idVendor}=="0764", ATTR{idProduct}=="0005", MODE="664", GROUP="@RUN_AS_GROUP@" # Dynex DX-800U?, CP1200AVR/BC1200D, CP825AVR-G, CP1000AVRLCD, CP1000PFCLCD, CP1500C, CP550HG, etc. - usbhid-ups ATTR{idVendor}=="0764", ATTR{idProduct}=="0501", MODE="664", GROUP="@RUN_AS_GROUP@" # OR2200LCDRM2U, OR700LCDRM1U, PR6000LCDRTXL5U - usbhid-ups ATTR{idVendor}=="0764", ATTR{idProduct}=="0601", MODE="664", GROUP="@RUN_AS_GROUP@" # Sweex 1000VA - richcomm_usb ATTR{idVendor}=="0925", ATTR{idProduct}=="1234", MODE="664", GROUP="@RUN_AS_GROUP@" # TrippLite # e.g. OMNIVS1000, SMART550USB, ... - tripplite_usb ATTR{idVendor}=="09ae", ATTR{idProduct}=="0001", MODE="664", GROUP="@RUN_AS_GROUP@" # e.g. TrippLite AVR550U - usbhid-ups ATTR{idVendor}=="09ae", ATTR{idProduct}=="1003", MODE="664", GROUP="@RUN_AS_GROUP@" # e.g. TrippLite AVR750U - usbhid-ups ATTR{idVendor}=="09ae", ATTR{idProduct}=="1007", MODE="664", GROUP="@RUN_AS_GROUP@" # e.g. TrippLite ECO550UPS - usbhid-ups ATTR{idVendor}=="09ae", ATTR{idProduct}=="1008", MODE="664", GROUP="@RUN_AS_GROUP@" # e.g. TrippLite ECO550UPS - usbhid-ups ATTR{idVendor}=="09ae", ATTR{idProduct}=="1009", MODE="664", GROUP="@RUN_AS_GROUP@" # e.g. TrippLite ECO550UPS - usbhid-ups ATTR{idVendor}=="09ae", ATTR{idProduct}=="1010", MODE="664", GROUP="@RUN_AS_GROUP@" # e.g. TrippLite SU3000LCD2UHV - usbhid-ups ATTR{idVendor}=="09ae", ATTR{idProduct}=="1330", MODE="664", GROUP="@RUN_AS_GROUP@" # e.g. TrippLite OMNI1000LCD - usbhid-ups ATTR{idVendor}=="09ae", ATTR{idProduct}=="2005", MODE="664", GROUP="@RUN_AS_GROUP@" # e.g. TrippLite OMNI900LCD - usbhid-ups ATTR{idVendor}=="09ae", ATTR{idProduct}=="2007", MODE="664", GROUP="@RUN_AS_GROUP@" # e.g. ? - usbhid-ups ATTR{idVendor}=="09ae", ATTR{idProduct}=="2008", MODE="664", GROUP="@RUN_AS_GROUP@" # e.g. TrippLite Smart1000LCD - usbhid-ups ATTR{idVendor}=="09ae", ATTR{idProduct}=="2009", MODE="664", GROUP="@RUN_AS_GROUP@" # e.g. ? - usbhid-ups ATTR{idVendor}=="09ae", ATTR{idProduct}=="2010", MODE="664", GROUP="@RUN_AS_GROUP@" # e.g. ? - usbhid-ups ATTR{idVendor}=="09ae", ATTR{idProduct}=="2011", MODE="664", GROUP="@RUN_AS_GROUP@" # e.g. ? - usbhid-ups ATTR{idVendor}=="09ae", ATTR{idProduct}=="2012", MODE="664", GROUP="@RUN_AS_GROUP@" # e.g. ? - usbhid-ups ATTR{idVendor}=="09ae", ATTR{idProduct}=="2013", MODE="664", GROUP="@RUN_AS_GROUP@" # e.g. ? - usbhid-ups ATTR{idVendor}=="09ae", ATTR{idProduct}=="2014", MODE="664", GROUP="@RUN_AS_GROUP@" # e.g. ? - usbhid-ups ATTR{idVendor}=="09ae", ATTR{idProduct}=="3008", MODE="664", GROUP="@RUN_AS_GROUP@" # e.g. ? - usbhid-ups ATTR{idVendor}=="09ae", ATTR{idProduct}=="3009", MODE="664", GROUP="@RUN_AS_GROUP@" # e.g. ? - usbhid-ups ATTR{idVendor}=="09ae", ATTR{idProduct}=="3010", MODE="664", GROUP="@RUN_AS_GROUP@" # e.g. ? - usbhid-ups ATTR{idVendor}=="09ae", ATTR{idProduct}=="3011", MODE="664", GROUP="@RUN_AS_GROUP@" # e.g. TrippLite smart2200RMXL2U - usbhid-ups ATTR{idVendor}=="09ae", ATTR{idProduct}=="3012", MODE="664", GROUP="@RUN_AS_GROUP@" # e.g. ? - usbhid-ups ATTR{idVendor}=="09ae", ATTR{idProduct}=="3013", MODE="664", GROUP="@RUN_AS_GROUP@" # e.g. ? - usbhid-ups ATTR{idVendor}=="09ae", ATTR{idProduct}=="3014", MODE="664", GROUP="@RUN_AS_GROUP@" # e.g. ? - usbhid-ups ATTR{idVendor}=="09ae", ATTR{idProduct}=="3015", MODE="664", GROUP="@RUN_AS_GROUP@" # e.g. TrippLite Smart1500LCD (newer unit) - usbhid-ups ATTR{idVendor}=="09ae", ATTR{idProduct}=="3016", MODE="664", GROUP="@RUN_AS_GROUP@" # e.g. TrippLite AVR750U (newer unit) - usbhid-ups ATTR{idVendor}=="09ae", ATTR{idProduct}=="3024", MODE="664", GROUP="@RUN_AS_GROUP@" # e.g. TrippLite SmartOnline SU1500RTXL2UA (older unit?) - usbhid-ups ATTR{idVendor}=="09ae", ATTR{idProduct}=="4001", MODE="664", GROUP="@RUN_AS_GROUP@" # e.g. TrippLite SmartOnline SU6000RT4U? - usbhid-ups ATTR{idVendor}=="09ae", ATTR{idProduct}=="4002", MODE="664", GROUP="@RUN_AS_GROUP@" # e.g. TrippLite SmartOnline SU1500RTXL2ua - usbhid-ups ATTR{idVendor}=="09ae", ATTR{idProduct}=="4003", MODE="664", GROUP="@RUN_AS_GROUP@" # e.g. TrippLite SmartOnline SU1000XLA - usbhid-ups ATTR{idVendor}=="09ae", ATTR{idProduct}=="4004", MODE="664", GROUP="@RUN_AS_GROUP@" # e.g. ? - usbhid-ups ATTR{idVendor}=="09ae", ATTR{idProduct}=="4005", MODE="664", GROUP="@RUN_AS_GROUP@" # e.g. ? - usbhid-ups ATTR{idVendor}=="09ae", ATTR{idProduct}=="4006", MODE="664", GROUP="@RUN_AS_GROUP@" # e.g. ? - usbhid-ups ATTR{idVendor}=="09ae", ATTR{idProduct}=="4007", MODE="664", GROUP="@RUN_AS_GROUP@" # e.g. ? - usbhid-ups ATTR{idVendor}=="09ae", ATTR{idProduct}=="4008", MODE="664", GROUP="@RUN_AS_GROUP@" # PowerCOM # PowerCOM Vanguard and BNT-xxxAP - usbhid-ups ATTR{idVendor}=="0d9f", ATTR{idProduct}=="0001", MODE="664", GROUP="@RUN_AS_GROUP@" # PowerCOM Vanguard and BNT-xxxAP - usbhid-ups ATTR{idVendor}=="0d9f", ATTR{idProduct}=="0004", MODE="664", GROUP="@RUN_AS_GROUP@" # PowerCOM IMP - IMPERIAL Series - usbhid-ups ATTR{idVendor}=="0d9f", ATTR{idProduct}=="00a2", MODE="664", GROUP="@RUN_AS_GROUP@" # PowerCOM SKP - Smart KING Pro (all Smart series) - usbhid-ups ATTR{idVendor}=="0d9f", ATTR{idProduct}=="00a3", MODE="664", GROUP="@RUN_AS_GROUP@" # PowerCOM WOW - usbhid-ups ATTR{idVendor}=="0d9f", ATTR{idProduct}=="00a4", MODE="664", GROUP="@RUN_AS_GROUP@" # PowerCOM VGD - Vanguard - usbhid-ups ATTR{idVendor}=="0d9f", ATTR{idProduct}=="00a5", MODE="664", GROUP="@RUN_AS_GROUP@" # PowerCOM BNT - Black Knight Pro - usbhid-ups ATTR{idVendor}=="0d9f", ATTR{idProduct}=="00a6", MODE="664", GROUP="@RUN_AS_GROUP@" # Unitek Alpha 1200Sx - nutdrv_qx ATTR{idVendor}=="0f03", ATTR{idProduct}=="0001", MODE="664", GROUP="@RUN_AS_GROUP@" # Liebert # Liebert PowerSure PSA UPS - usbhid-ups ATTR{idVendor}=="10af", ATTR{idProduct}=="0001", MODE="664", GROUP="@RUN_AS_GROUP@" # Liebert PowerSure PSI 1440 - usbhid-ups ATTR{idVendor}=="10af", ATTR{idProduct}=="0004", MODE="664", GROUP="@RUN_AS_GROUP@" # Liebert GXT3 - usbhid-ups ATTR{idVendor}=="10af", ATTR{idProduct}=="0008", MODE="664", GROUP="@RUN_AS_GROUP@" # GE EP series - nutdrv_qx ATTR{idVendor}=="14f0", ATTR{idProduct}=="00c9", MODE="664", GROUP="@RUN_AS_GROUP@" # Legrand # Legrand Keor SP - usbhid-ups ATTR{idVendor}=="1cb0", ATTR{idProduct}=="0032", MODE="664", GROUP="@RUN_AS_GROUP@" # Legrand Daker DK / DK Plus - nutdrv_qx ATTR{idVendor}=="1cb0", ATTR{idProduct}=="0035", MODE="664", GROUP="@RUN_AS_GROUP@" # Legrand Keor PDU - usbhid-ups ATTR{idVendor}=="1cb0", ATTR{idProduct}=="0038", MODE="664", GROUP="@RUN_AS_GROUP@" # Arduino # Arduino Leonardo, Leonardo ETH and Pro Micro - usbhid-ups ATTR{idVendor}=="2341", ATTR{idProduct}=="0036", MODE="664", GROUP="@RUN_AS_GROUP@" # Arduino Leonardo, Leonardo ETH and Pro Micro - usbhid-ups ATTR{idVendor}=="2341", ATTR{idProduct}=="8036", MODE="664", GROUP="@RUN_AS_GROUP@" # Arduino # Arduino Leonardo, Leonardo ETH and Pro Micro - usbhid-ups ATTR{idVendor}=="2a03", ATTR{idProduct}=="0036", MODE="664", GROUP="@RUN_AS_GROUP@" # Arduino Leonardo, Leonardo ETH and Pro Micro - usbhid-ups ATTR{idVendor}=="2a03", ATTR{idProduct}=="0040", MODE="664", GROUP="@RUN_AS_GROUP@" # Arduino Leonardo, Leonardo ETH and Pro Micro - usbhid-ups ATTR{idVendor}=="2a03", ATTR{idProduct}=="8036", MODE="664", GROUP="@RUN_AS_GROUP@" # Arduino Leonardo, Leonardo ETH and Pro Micro - usbhid-ups ATTR{idVendor}=="2a03", ATTR{idProduct}=="8040", MODE="664", GROUP="@RUN_AS_GROUP@" # AEG # PROTECT B / NAS - usbhid-ups ATTR{idVendor}=="2b2d", ATTR{idProduct}=="ffff", MODE="664", GROUP="@RUN_AS_GROUP@" # Ever # USB IDs device table - usbhid-ups ATTR{idVendor}=="2e51", ATTR{idProduct}=="0000", MODE="664", GROUP="@RUN_AS_GROUP@" # USB IDs device table - usbhid-ups ATTR{idVendor}=="2e51", ATTR{idProduct}=="ffff", MODE="664", GROUP="@RUN_AS_GROUP@" # Salicru # https://www.salicru.com/sps-3000-adv-rt2.html - usbhid-ups ATTR{idVendor}=="2e66", ATTR{idProduct}=="0101", MODE="664", GROUP="@RUN_AS_GROUP@" # SLC TWIN PRO2<=3KVA per https://github.com/networkupstools/nut/issues/450 - usbhid-ups ATTR{idVendor}=="2e66", ATTR{idProduct}=="0201", MODE="664", GROUP="@RUN_AS_GROUP@" # SLC TWIN PRO2<=3KVA per https://github.com/networkupstools/nut/issues/450 - usbhid-ups ATTR{idVendor}=="2e66", ATTR{idProduct}=="0202", MODE="664", GROUP="@RUN_AS_GROUP@" # SLC TWIN PRO2<=3KVA per https://github.com/networkupstools/nut/issues/450 - usbhid-ups ATTR{idVendor}=="2e66", ATTR{idProduct}=="0203", MODE="664", GROUP="@RUN_AS_GROUP@" # https://www.salicru.com/sps-home.html - usbhid-ups ATTR{idVendor}=="2e66", ATTR{idProduct}=="0300", MODE="664", GROUP="@RUN_AS_GROUP@" # https://www.salicru.com/sps-850-adv-t.html - usbhid-ups ATTR{idVendor}=="2e66", ATTR{idProduct}=="0302", MODE="664", GROUP="@RUN_AS_GROUP@" # Powervar # Powervar - usbhid-ups ATTR{idVendor}=="4234", ATTR{idProduct}=="0002", MODE="664", GROUP="@RUN_AS_GROUP@" # Ablerex 625L USB (Note: earlier best-fit was "krauler_subdriver" before PR #1135) - nutdrv_qx ATTR{idVendor}=="ffff", ATTR{idProduct}=="0000", MODE="664", GROUP="@RUN_AS_GROUP@" LABEL="nut-usbups_rules_end" nut-2.8.1/scripts/udev/Makefile.in0000644000175000017500000005367114520274662013774 00000000000000# Makefile.in generated by automake 1.16.5 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2021 Free Software Foundation, Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. @SET_MAKE@ VPATH = @srcdir@ am__is_gnu_make = { \ if test -z '$(MAKELEVEL)'; then \ false; \ elif test -n '$(MAKE_HOST)'; then \ true; \ elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \ true; \ else \ false; \ fi; \ } am__make_running_with_option = \ case $${target_option-} in \ ?) ;; \ *) echo "am__make_running_with_option: internal error: invalid" \ "target option '$${target_option-}' specified" >&2; \ exit 1;; \ esac; \ has_opt=no; \ sane_makeflags=$$MAKEFLAGS; \ if $(am__is_gnu_make); then \ sane_makeflags=$$MFLAGS; \ else \ case $$MAKEFLAGS in \ *\\[\ \ ]*) \ bs=\\; \ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ esac; \ fi; \ skip_next=no; \ strip_trailopt () \ { \ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ }; \ for flg in $$sane_makeflags; do \ test $$skip_next = yes && { skip_next=no; continue; }; \ case $$flg in \ *=*|--*) continue;; \ -*I) strip_trailopt 'I'; skip_next=yes;; \ -*I?*) strip_trailopt 'I';; \ -*O) strip_trailopt 'O'; skip_next=yes;; \ -*O?*) strip_trailopt 'O';; \ -*l) strip_trailopt 'l'; skip_next=yes;; \ -*l?*) strip_trailopt 'l';; \ -[dEDm]) skip_next=yes;; \ -[JT]) skip_next=yes;; \ esac; \ case $$flg in \ *$$target_option*) has_opt=yes; break;; \ esac; \ done; \ test $$has_opt = yes am__make_dryrun = (target_option=n; $(am__make_running_with_option)) am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkglibexecdir = $(libexecdir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ target_triplet = @target@ @WITH_UDEV_TRUE@@WITH_USB_TRUE@am__append_1 = 62-nut-usbups.rules @WITH_IPMI_TRUE@@WITH_UDEV_TRUE@am__append_2 = 52-nut-ipmipsu.rules subdir = scripts/udev ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/m4/ax_c___attribute__.m4 \ $(top_srcdir)/m4/ax_c_pragmas.m4 \ $(top_srcdir)/m4/ax_check_compile_flag.m4 \ $(top_srcdir)/m4/ax_compare_version.m4 \ $(top_srcdir)/m4/ax_realpath.m4 \ $(top_srcdir)/m4/ax_run_or_link_ifelse.m4 \ $(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \ $(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \ $(top_srcdir)/m4/lt~obsolete.m4 \ $(top_srcdir)/m4/nut_arg_with.m4 \ $(top_srcdir)/m4/nut_check_asciidoc.m4 \ $(top_srcdir)/m4/nut_check_aspell.m4 \ $(top_srcdir)/m4/nut_check_cppcheck.m4 \ $(top_srcdir)/m4/nut_check_headers_windows.m4 \ $(top_srcdir)/m4/nut_check_libavahi.m4 \ $(top_srcdir)/m4/nut_check_libfreeipmi.m4 \ $(top_srcdir)/m4/nut_check_libgd.m4 \ $(top_srcdir)/m4/nut_check_libgpiod.m4 \ $(top_srcdir)/m4/nut_check_libltdl.m4 \ $(top_srcdir)/m4/nut_check_libmodbus.m4 \ $(top_srcdir)/m4/nut_check_libneon.m4 \ $(top_srcdir)/m4/nut_check_libnetsnmp.m4 \ $(top_srcdir)/m4/nut_check_libnss.m4 \ $(top_srcdir)/m4/nut_check_libopenssl.m4 \ $(top_srcdir)/m4/nut_check_libpowerman.m4 \ $(top_srcdir)/m4/nut_check_libregex.m4 \ $(top_srcdir)/m4/nut_check_libsystemd.m4 \ $(top_srcdir)/m4/nut_check_libusb.m4 \ $(top_srcdir)/m4/nut_check_libwrap.m4 \ $(top_srcdir)/m4/nut_check_os.m4 \ $(top_srcdir)/m4/nut_check_pkgconfig.m4 \ $(top_srcdir)/m4/nut_check_python.m4 \ $(top_srcdir)/m4/nut_check_socketlib.m4 \ $(top_srcdir)/m4/nut_compiler_family.m4 \ $(top_srcdir)/m4/nut_func_getnameinfo_argtypes.m4 \ $(top_srcdir)/m4/nut_report_feature.m4 \ $(top_srcdir)/m4/nut_stash_warnings.m4 \ $(top_srcdir)/m4/nut_type_socklen_t.m4 \ $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/include/config.h CONFIG_CLEAN_FILES = nut-ipmipsu.rules nut-usbups.rules CONFIG_CLEAN_VPATH_FILES = AM_V_P = $(am__v_P_@AM_V@) am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) am__v_P_0 = false am__v_P_1 = : AM_V_GEN = $(am__v_GEN_@AM_V@) am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) am__v_GEN_0 = @echo " GEN " $@; am__v_GEN_1 = AM_V_at = $(am__v_at_@AM_V@) am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) am__v_at_0 = @ am__v_at_1 = SOURCES = DIST_SOURCES = am__can_run_installinfo = \ case $$AM_UPDATE_INFO_DIR in \ n|no|NO) false;; \ *) (install-info --version) >/dev/null 2>&1;; \ esac am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; am__vpath_adj = case $$p in \ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ *) f=$$p;; \ esac; am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`; am__install_max = 40 am__nobase_strip_setup = \ srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'` am__nobase_strip = \ for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||" am__nobase_list = $(am__nobase_strip_setup); \ for p in $$list; do echo "$$p $$p"; done | \ sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \ $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \ if (++n[$$2] == $(am__install_max)) \ { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \ END { for (dir in files) print dir, files[dir] }' am__base_list = \ sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' am__uninstall_files_from_dir = { \ test -z "$$files" \ || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \ || { echo " ( cd '$$dir' && rm -f" $$files ")"; \ $(am__cd) "$$dir" && rm -f $$files; }; \ } am__installdirs = "$(DESTDIR)$(udevrulesdir)" DATA = $(udevrules_DATA) am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) am__DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/nut-ipmipsu.rules.in \ $(srcdir)/nut-usbups.rules.in README DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) A2X = @A2X@ ACLOCAL = @ACLOCAL@ ALTPIDPATH = @ALTPIDPATH@ AMTAR = @AMTAR@ AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ AR = @AR@ ASCIIDOC = @ASCIIDOC@ ASPELL = @ASPELL@ ASPELL_FILTER_LIB_PATH = @ASPELL_FILTER_LIB_PATH@ ASPELL_FILTER_SHARE_PATH = @ASPELL_FILTER_SHARE_PATH@ ASPELL_FILTER_TEX_PATH = @ASPELL_FILTER_TEX_PATH@ AUGPARSE = @AUGPARSE@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ BINDIR = @BINDIR@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CONFIG_FLAGS = @CONFIG_FLAGS@ CONFPATH = @CONFPATH@ CPP = @CPP@ CPPCHECK = @CPPCHECK@ CPPFLAGS = @CPPFLAGS@ CPPUNIT_CFLAGS = @CPPUNIT_CFLAGS@ CPPUNIT_LIBS = @CPPUNIT_LIBS@ CSCOPE = @CSCOPE@ CTAGS = @CTAGS@ CXX = @CXX@ CXXCPP = @CXXCPP@ CXXDEPMODE = @CXXDEPMODE@ CXXFLAGS = @CXXFLAGS@ CYGPATH_W = @CYGPATH_W@ DBLATEX = @DBLATEX@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ DEPLOYED_UPSC = @DEPLOYED_UPSC@ DEPLOYED_UPSD = @DEPLOYED_UPSD@ DLLTOOL = @DLLTOOL@ DOC_BUILD_LIST = @DOC_BUILD_LIST@ DOC_CHECK_LIST = @DOC_CHECK_LIST@ DRIVER_BUILD_LIST = @DRIVER_BUILD_LIST@ DRIVER_INSTALL_TARGET = @DRIVER_INSTALL_TARGET@ DRIVER_MAN_LIST = @DRIVER_MAN_LIST@ DRIVER_MAN_LIST_PAGES = @DRIVER_MAN_LIST_PAGES@ DRVPATH = @DRVPATH@ DSYMUTIL = @DSYMUTIL@ DUMPBIN = @DUMPBIN@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ ETAGS = @ETAGS@ EXEEXT = @EXEEXT@ FGREP = @FGREP@ FORCE_NUT_VERSION = @FORCE_NUT_VERSION@ GDLIB_CONFIG = @GDLIB_CONFIG@ GREP = @GREP@ HAVE_SYS_SOCKET_H = @HAVE_SYS_SOCKET_H@ HAVE_WINSOCK2_H = @HAVE_WINSOCK2_H@ HAVE_WS2TCPIP_H = @HAVE_WS2TCPIP_H@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ LD = @LD@ LDFLAGS = @LDFLAGS@ LIBAVAHI_CFLAGS = @LIBAVAHI_CFLAGS@ LIBAVAHI_LIBS = @LIBAVAHI_LIBS@ LIBDIR = @LIBDIR@ LIBGD_CFLAGS = @LIBGD_CFLAGS@ LIBGD_LDFLAGS = @LIBGD_LDFLAGS@ LIBGPIO_CFLAGS = @LIBGPIO_CFLAGS@ LIBGPIO_LIBS = @LIBGPIO_LIBS@ LIBI2C_LIBS = @LIBI2C_LIBS@ LIBIPMI_CFLAGS = @LIBIPMI_CFLAGS@ LIBIPMI_LIBS = @LIBIPMI_LIBS@ LIBLTDL_CFLAGS = @LIBLTDL_CFLAGS@ LIBLTDL_LIBS = @LIBLTDL_LIBS@ LIBMODBUS_CFLAGS = @LIBMODBUS_CFLAGS@ LIBMODBUS_LIBS = @LIBMODBUS_LIBS@ LIBNEON_CFLAGS = @LIBNEON_CFLAGS@ LIBNEON_LIBS = @LIBNEON_LIBS@ LIBNETSNMP_CFLAGS = @LIBNETSNMP_CFLAGS@ LIBNETSNMP_LIBS = @LIBNETSNMP_LIBS@ LIBOBJS = @LIBOBJS@ LIBPOWERMAN_CFLAGS = @LIBPOWERMAN_CFLAGS@ LIBPOWERMAN_LIBS = @LIBPOWERMAN_LIBS@ LIBREGEX_LIBS = @LIBREGEX_LIBS@ LIBS = @LIBS@ LIBSSL_CFLAGS = @LIBSSL_CFLAGS@ LIBSSL_LIBS = @LIBSSL_LIBS@ LIBSSL_REQUIRES = @LIBSSL_REQUIRES@ LIBSYSTEMD_CFLAGS = @LIBSYSTEMD_CFLAGS@ LIBSYSTEMD_LIBS = @LIBSYSTEMD_LIBS@ LIBTOOL = @LIBTOOL@ LIBTOOL_DEPS = @LIBTOOL_DEPS@ LIBUSB_CFLAGS = @LIBUSB_CFLAGS@ LIBUSB_CONFIG = @LIBUSB_CONFIG@ LIBUSB_LIBS = @LIBUSB_LIBS@ LIBWRAP_CFLAGS = @LIBWRAP_CFLAGS@ LIBWRAP_LIBS = @LIBWRAP_LIBS@ LIPO = @LIPO@ LN_S = @LN_S@ LN_S_R = @LN_S_R@ LTLIBOBJS = @LTLIBOBJS@ LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@ MAINT = @MAINT@ MAKEINFO = @MAKEINFO@ MANIFEST_TOOL = @MANIFEST_TOOL@ MKDIR_P = @MKDIR_P@ MSGFMT = @MSGFMT@ NETLIBS = @NETLIBS@ NET_SNMP_CONFIG = @NET_SNMP_CONFIG@ NM = @NM@ NMEDIT = @NMEDIT@ NUT_DATADIR = @NUT_DATADIR@ NUT_LIBEXECDIR = @NUT_LIBEXECDIR@ NUT_NETVERSION = @NUT_NETVERSION@ NUT_SOURCE_GITREV = @NUT_SOURCE_GITREV@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ OS_NAME = @OS_NAME@ OTOOL = @OTOOL@ OTOOL64 = @OTOOL64@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_SEPARATOR = @PATH_SEPARATOR@ PIDPATH = @PIDPATH@ PKGCONFIGDIR = @PKGCONFIGDIR@ PKG_CONFIG = @PKG_CONFIG@ PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@ PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ PORT = @PORT@ POWERDOWNFLAG = @POWERDOWNFLAG@ PREFIX = @PREFIX@ PYTHON = @PYTHON@ PYTHON2 = @PYTHON2@ PYTHON2_SITE_PACKAGES = @PYTHON2_SITE_PACKAGES@ PYTHON3 = @PYTHON3@ PYTHON3_SITE_PACKAGES = @PYTHON3_SITE_PACKAGES@ PYTHON_SITE_PACKAGES = @PYTHON_SITE_PACKAGES@ RANLIB = @RANLIB@ REALPATH = @REALPATH@ RUN_AS_GROUP = @RUN_AS_GROUP@ RUN_AS_USER = @RUN_AS_USER@ SBINDIR = @SBINDIR@ SED = @SED@ SEMLIBS = @SEMLIBS@ SERLIBS = @SERLIBS@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ SOURCE_HIGHLIGHT = @SOURCE_HIGHLIGHT@ STATEPATH = @STATEPATH@ STRIP = @STRIP@ SUN_LIBUSB = @SUN_LIBUSB@ SYSTEMD_ANALYZE_PROGRAM = @SYSTEMD_ANALYZE_PROGRAM@ SYSTEMD_DAEMON_ARGS_DRIVER = @SYSTEMD_DAEMON_ARGS_DRIVER@ SYSTEMD_DAEMON_ARGS_UPSD = @SYSTEMD_DAEMON_ARGS_UPSD@ SYSTEMD_DAEMON_ARGS_UPSMON = @SYSTEMD_DAEMON_ARGS_UPSMON@ SYSTEMD_DAEMON_NOTIFYACCESS_DRIVER = @SYSTEMD_DAEMON_NOTIFYACCESS_DRIVER@ SYSTEMD_DAEMON_NOTIFYACCESS_UPSD = @SYSTEMD_DAEMON_NOTIFYACCESS_UPSD@ SYSTEMD_DAEMON_NOTIFYACCESS_UPSMON = @SYSTEMD_DAEMON_NOTIFYACCESS_UPSMON@ SYSTEMD_DAEMON_TYPE_DRIVER = @SYSTEMD_DAEMON_TYPE_DRIVER@ SYSTEMD_DAEMON_TYPE_UPSD = @SYSTEMD_DAEMON_TYPE_UPSD@ SYSTEMD_DAEMON_TYPE_UPSMON = @SYSTEMD_DAEMON_TYPE_UPSMON@ SYSTEMD_DAEMON_WATCHDOG_DRIVER = @SYSTEMD_DAEMON_WATCHDOG_DRIVER@ SYSTEMD_DAEMON_WATCHDOG_UPSD = @SYSTEMD_DAEMON_WATCHDOG_UPSD@ SYSTEMD_DAEMON_WATCHDOG_UPSMON = @SYSTEMD_DAEMON_WATCHDOG_UPSMON@ SYSTEMD_TMPFILES_PROGRAM = @SYSTEMD_TMPFILES_PROGRAM@ TREE_VERSION = @TREE_VERSION@ VALGRIND = @VALGRIND@ VERSION = @VERSION@ WINDMC = @WINDMC@ WINDRES = @WINDRES@ WORDS_BIGENDIAN = @WORDS_BIGENDIAN@ XMLLINT = @XMLLINT@ XSLTPROC = @XSLTPROC@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_AR = @ac_ct_AR@ ac_ct_CC = @ac_ct_CC@ ac_ct_CXX = @ac_ct_CXX@ ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__tar = @am__tar@ am__untar = @am__untar@ auglensdir = @auglensdir@ bindir = @bindir@ build = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ cgiexecdir = @cgiexecdir@ datadir = @datadir@ datarootdir = @datarootdir@ devddir = @devddir@ docdir = @docdir@ driverexecdir = @driverexecdir@ dummy_PKG_CONFIG = @dummy_PKG_CONFIG@ dummy_PKG_CONFIG_CFLAGS = @dummy_PKG_CONFIG_CFLAGS@ dummy_PKG_CONFIG_LIBS = @dummy_PKG_CONFIG_LIBS@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ hotplugdir = @hotplugdir@ htmldir = @htmldir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libdir = @libdir@ libexecdir = @libexecdir@ localedir = @localedir@ localstatedir = @localstatedir@ mandir = @mandir@ mkdir_p = @mkdir_p@ now = @now@ nut_with_nut_monitor = @nut_with_nut_monitor@ nut_with_nut_monitor_desktop = @nut_with_nut_monitor_desktop@ nut_with_nut_monitor_dir = @nut_with_nut_monitor_dir@ nut_with_nut_monitor_py2gtk2 = @nut_with_nut_monitor_py2gtk2@ nut_with_nut_monitor_py3qt5 = @nut_with_nut_monitor_py3qt5@ nut_with_pynut = @nut_with_pynut@ nut_with_pynut_py = @nut_with_pynut_py@ nut_with_pynut_py2 = @nut_with_pynut_py2@ nut_with_pynut_py3 = @nut_with_pynut_py3@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ pkgconfigdir = @pkgconfigdir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ runstatedir = @runstatedir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ sysconfdir = @sysconfdir@ systemdshutdowndir = @systemdshutdowndir@ systemdsystemunitdir = @systemdsystemunitdir@ systemdtmpfilesdir = @systemdtmpfilesdir@ target = @target@ target_alias = @target_alias@ target_cpu = @target_cpu@ target_os = @target_os@ target_vendor = @target_vendor@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ udevdir = @udevdir@ @WITH_UDEV_TRUE@udevrulesdir = $(udevdir)/rules.d @WITH_UDEV_TRUE@udevrules_DATA = $(am__append_1) $(am__append_2) # Part of dist tarball, regardless of use for current build: EXTRA_DIST = README nut-usbups.rules.in # We should never remove this one, apart from a distclean-check # or stronger... # Generated by autogen.sh and needed to run the configure script # (technically, generated by tools/nut-usbinfo.pl script among # GENERATED_USB_OS_FILES): MAINTAINERCLEANFILES = Makefile.in .dirstamp nut-usbups.rules.in \ nut-usbups.rules.in.AUTOGEN_WITHOUT # Generated by configure script: DISTCLEANFILES = nut-usbups.rules nut-ipmipsu.rules CLEANFILES = 62-nut-usbups.rules 52-nut-ipmipsu.rules all: all-am .SUFFIXES: $(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu scripts/udev/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --gnu scripts/udev/Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): nut-ipmipsu.rules: $(top_builddir)/config.status $(srcdir)/nut-ipmipsu.rules.in cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ nut-usbups.rules: $(top_builddir)/config.status $(srcdir)/nut-usbups.rules.in cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ mostlyclean-libtool: -rm -f *.lo clean-libtool: -rm -rf .libs _libs install-udevrulesDATA: $(udevrules_DATA) @$(NORMAL_INSTALL) @list='$(udevrules_DATA)'; test -n "$(udevrulesdir)" || list=; \ if test -n "$$list"; then \ echo " $(MKDIR_P) '$(DESTDIR)$(udevrulesdir)'"; \ $(MKDIR_P) "$(DESTDIR)$(udevrulesdir)" || exit 1; \ fi; \ for p in $$list; do \ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ echo "$$d$$p"; \ done | $(am__base_list) | \ while read files; do \ echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(udevrulesdir)'"; \ $(INSTALL_DATA) $$files "$(DESTDIR)$(udevrulesdir)" || exit $$?; \ done uninstall-udevrulesDATA: @$(NORMAL_UNINSTALL) @list='$(udevrules_DATA)'; test -n "$(udevrulesdir)" || list=; \ files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ dir='$(DESTDIR)$(udevrulesdir)'; $(am__uninstall_files_from_dir) tags TAGS: ctags CTAGS: cscope cscopelist: distdir: $(BUILT_SOURCES) $(MAKE) $(AM_MAKEFLAGS) distdir-am distdir-am: $(DISTFILES) @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ dist_files=`for file in $$list; do echo $$file; done | \ sed -e "s|^$$srcdirstrip/||;t" \ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ case $$dist_files in \ */*) $(MKDIR_P) `echo "$$dist_files" | \ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ sort -u` ;; \ esac; \ for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d "$(distdir)/$$file"; then \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ else \ test -f "$(distdir)/$$file" \ || cp -p $$d/$$file "$(distdir)/$$file" \ || exit 1; \ fi; \ done check-am: all-am check: check-am all-am: Makefile $(DATA) installdirs: for dir in "$(DESTDIR)$(udevrulesdir)"; do \ test -z "$$dir" || $(MKDIR_P) "$$dir"; \ done install: install-am install-exec: install-exec-am install-data: install-data-am uninstall: uninstall-am install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-am install-strip: if test -z '$(STRIP)'; then \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ install; \ else \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ fi mostlyclean-generic: clean-generic: -test -z "$(CLEANFILES)" || rm -f $(CLEANFILES) distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) -test -z "$(DISTCLEANFILES)" || rm -f $(DISTCLEANFILES) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." -test -z "$(MAINTAINERCLEANFILES)" || rm -f $(MAINTAINERCLEANFILES) clean: clean-am clean-am: clean-generic clean-libtool mostlyclean-am distclean: distclean-am -rm -f Makefile distclean-am: clean-am distclean-generic dvi: dvi-am dvi-am: html: html-am html-am: info: info-am info-am: install-data-am: install-udevrulesDATA install-dvi: install-dvi-am install-dvi-am: install-exec-am: install-html: install-html-am install-html-am: install-info: install-info-am install-info-am: install-man: install-pdf: install-pdf-am install-pdf-am: install-ps: install-ps-am install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-am -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-am mostlyclean-am: mostlyclean-generic mostlyclean-libtool pdf: pdf-am pdf-am: ps: ps-am ps-am: uninstall-am: uninstall-udevrulesDATA .MAKE: install-am install-strip .PHONY: all all-am check check-am clean clean-generic clean-libtool \ cscopelist-am ctags-am distclean distclean-generic \ distclean-libtool distdir dvi dvi-am html html-am info info-am \ install install-am install-data install-data-am install-dvi \ install-dvi-am install-exec install-exec-am install-html \ install-html-am install-info install-info-am install-man \ install-pdf install-pdf-am install-ps install-ps-am \ install-strip install-udevrulesDATA installcheck \ installcheck-am installdirs maintainer-clean \ maintainer-clean-generic mostlyclean mostlyclean-generic \ mostlyclean-libtool pdf pdf-am ps ps-am tags-am uninstall \ uninstall-am uninstall-udevrulesDATA .PRECIOUS: Makefile 62-nut-usbups.rules: nut-usbups.rules cp nut-usbups.rules $@ 52-nut-ipmipsu.rules: nut-ipmipsu.rules cp nut-ipmipsu.rules $@ # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: nut-2.8.1/scripts/udev/Makefile.am0000644000175000017500000000165314501607135013746 00000000000000 if WITH_UDEV udevrulesdir = $(udevdir)/rules.d udevrules_DATA = if WITH_USB udevrules_DATA += 62-nut-usbups.rules endif if WITH_IPMI udevrules_DATA += 52-nut-ipmipsu.rules endif endif EXTRA_DIST = README 62-nut-usbups.rules: nut-usbups.rules cp nut-usbups.rules $@ 52-nut-ipmipsu.rules: nut-ipmipsu.rules cp nut-ipmipsu.rules $@ MAINTAINERCLEANFILES = Makefile.in .dirstamp # Generated by configure script: DISTCLEANFILES = nut-usbups.rules nut-ipmipsu.rules CLEANFILES = 62-nut-usbups.rules 52-nut-ipmipsu.rules # We should never remove this one, apart from a distclean-check # or stronger... # Generated by autogen.sh and needed to run the configure script # (technically, generated by tools/nut-usbinfo.pl script among # GENERATED_USB_OS_FILES): MAINTAINERCLEANFILES += nut-usbups.rules.in nut-usbups.rules.in.AUTOGEN_WITHOUT # Part of dist tarball, regardless of use for current build: EXTRA_DIST += nut-usbups.rules.in nut-2.8.1/scripts/udev/README0000644000175000017500000000313314501607135012565 00000000000000Desc: Udev script for NUT USB and IPMI drivers File: scripts/udev/README Date: 31 July 2014 Auth: Arnaud Quette This document introduces the Linux udev script for NUT USB drivers (usbhid-ups, bcmxcp_usb, tripplite_usb, ...) and IPMI driver (nut-ipmipsu). These are needed on Linux systems running udev (recommended as of kernel 2.6.3, and mandatory as of 2.6.14 and higher). This script ensure that the right privileges are set on the USB and IPMI devices files to allow the NUT driver to operate (ie allowing the nut user to read AND write to the device). Note that the old style hotplug files, available in the scripts/hotplug directory, are not needed if your kernel supports udev. Installation ------------ For most users, these files will be automatically installed in /etc/udev (or /lib/udev) upon "make install", if that directory exists and if the feature (USB and / or IPMI) has been enabled at configure time. You can specify an alternate directory with: ./configure --with-udev-dir=DIR Manual installation ------------------- To install them manually, copy the rules file(s) to /etc/udev/rules.d (or /lib/udev/rules.d on newer systems) using the command(s): :; cp -f nut-usbups.rules /etc/udev/rules.d/62-nut-usbups.rules :; cp -f nut-ipmipsu.rules /etc/udev/rules.d/52-nut-ipmipsu.rules You will need to refresh the bus to avoid a reboot for these rules to be active. You can do so using: :; udevadm trigger --subsystem-match=usb_device For USB devices, you can then plug your UPS USB cord, or unplug / replug it to refresh the device permission, and start NUT. nut-2.8.1/scripts/udev/nut-ipmipsu.rules.in0000644000175000017500000000027714273170601015665 00000000000000# This file is generated and installed by the Network UPS Tools package. # It sets the correct device permissions for nut-ipmipsu driver. KERNEL=="ipmi*", MODE="664", GROUP="@RUN_AS_GROUP@" nut-2.8.1/scripts/logrotate/0000755000175000017500000000000014520277776013041 500000000000000nut-2.8.1/scripts/logrotate/nutlogd0000644000175000017500000000110514273170601014335 00000000000000# Log rotation configuration for NUT: # Rotate NUT log file(s) either monthly or when exceeding 5 Mb # # For more information, refer to logrotate(8) manual page: # http://linuxcommand.org/man_pages/logrotate8.html # # To install this file, use: # $ cp nutlogd /etc/logrotate.d/ # $ chmod 644 /etc/logrotate.d/nutlogd # $ chown root.root /etc/logrotate.d/nutlogd # # Log files must have "nut-" prefix and ".log" suffix /var/log/nut-*.log { missingok notifempty size=5M rotate 12 monthly postrotate /usr/bin/killall -HUP upslog endscript } nut-2.8.1/scripts/avahi/0000755000175000017500000000000014520277775012130 500000000000000nut-2.8.1/scripts/avahi/nut.service.in0000644000175000017500000000207514273170601014632 00000000000000 %h _nut._tcp @PORT@ nut-2.8.1/scripts/HP-UX/0000755000175000017500000000000014520277776011702 500000000000000nut-2.8.1/scripts/HP-UX/nut-upsmon0000644000175000017500000000022714273170601013653 00000000000000# NUT_START: Set to 1 to start NUT # NUT_ARGS: Command line arguments to pass to NUT # # To configure the NUT environment: NUT_START=1 UPSMON_ARGS= nut-2.8.1/scripts/HP-UX/nut-upsd0000644000175000017500000000032114273170601013300 00000000000000# NUT_START: Set to 1 to start NUT # NUT_ARGS: Command line arguments to pass to NUT # # To configure the NUT environment: NUT_START=1 UPSNAME= # Blank == all configured UPSs RUNAS= # Blank == run as root nut-2.8.1/scripts/HP-UX/nut.psf.in0000644000175000017500000001422314273170601013531 00000000000000B/ # PSF file for Network UPS Tools 11/2/2011 # # Useful commands: # # swpackage -p -vv -s /depot/psf_files/xxx.psf -d /depot/s700_opt # swmodify -p -d -vv -s /depot/psf_files/xxx.psf xxx @ /depot/s700_opt # swremove -p -v -d xxx,r=yyy @ /depot/s700_opt # swinstall -p -v -s /depot/s700_opt xxx # # References: # - Creating a Product Specification File (PSF) # http://docs.hp.com/en/B2355-90127/ch09s05.html # - swpackage(8) manual page # http://nixdoc.net/man-pages/hp-ux/man4/swpackage.4.html # # http://www.massconfusion.com/tim/notes/hpux_depot_create_howto.txt # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # This section is optional # This section is optional -- delete it if you don't want it. # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # vendor tag NUT-Team title "NUT - Network UPS Tools - Team" description "UPS monitoring tool" end # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # product # ---------------------------------------- tag NUT title "Network UPS Tools" description "Network UPS Tools (NUT) is a client/server monitoring system that allows computers to share uninterruptible power supply (UPS) and power distribution unit (PDU) hardware. Clients access the hardware through the server, and are notified whenever the power status changes." revision @PACKAGE_VERSION@ # ---------------------------------------- architecture S700/S800_HPUX_10/HP-UX_B.11.23_IA/PA machine_type * os_name HP-UX #os_release ?.11.2* os_release ?.10.*|?.11.* os_version * # ---------------------------------------- #Including "NUT - Server" files. fileset tag Server title "nut-server" revision @PACKAGE_VERSION@ postinstall ./postinstall #Including "conf" files under "/usr/local/ups/etc/". file -u 644 -g bin -o bin ./nut_install@prefix@/etc/ups.conf.sample @prefix@/etc/ups.conf.sample file -u 644 -g bin -o bin ./nut_install@prefix@/etc/upsd.conf.sample @prefix@/etc/upsd.conf.sample file -u 644 -g bin -o bin ./nut_install@prefix@/etc/upsd.users.sample @prefix@/etc/upsd.users.sample #Including "server" files under "/usr/local/ups/sbin". file -u 755 -g bin -o bin ./nut_install@prefix@/sbin/upsd @prefix@/sbin/upsd #Including "share" files under "/usr/local/ups/share". file -u 644 -g bin -o bin ./nut_install@prefix@/share/cmdvartab @prefix@/share/cmdvartab file -u 644 -g bin -o bin ./nut_install@prefix@/share/driver.list @prefix@/share/driver.list #Including required "libupsclient1" under "/usr/local/ups/lib" file -u 755 -g bin -o bin ./nut_install@prefix@/lib/libupsclient.sl.3 @prefix@/lib/libupsclient.sl.3 file -u 555 -g bin -o bin ./nut_install@prefix@/lib/libupsclient.sl.3.1 @prefix@/lib/libupsclient.sl.3.1 #Including nut service script to "usr/local/ups/script" file -u 744 -g bin -o bin @top_srcdir@/scripts/HP-UX/nut-upsd.sh @prefix@/script/nut-upsd.sh file -u 744 -g bin -o bin @top_srcdir@/scripts/HP-UX/nut-drvctl.sh @prefix@/script/nut-drvctl.sh file -u 744 -g bin -o bin @top_srcdir@/scripts/HP-UX/nut-upsmon.sh @prefix@/script/nut-upsmon.sh file -u 444 -g bin -o bin @top_srcdir@/scripts/HP-UX/nut-upsd @prefix@/script/nut-upsd file -u 444 -g bin -o bin @top_srcdir@/scripts/HP-UX/nut-drvctl @prefix@/script/nut-drvctl file -u 444 -g bin -o bin @top_srcdir@/scripts/HP-UX/nut-upsmon @prefix@/script/nut-upsmon #Including required UPS drivers files under "/usr/local/ups/bin/". #such as "nut-snmp", "nut-xml or netxml-ups" directory ./nut_install@prefix@/bin=@prefix@/bin/ #file_permissions -u 755 -g bin -o bin file * #TBD files to be added under "/usr/share/doc/nut-server/*.gz" #TBD files to be added under "/usr/share/man/man5/*.gz" #TBD files to be added under "/usr/share/man/man8/*.gz" end # ---------------------------------------- #Including "NUT - Client" files. fileset tag Client title "nut-client" revision @PACKAGE_VERSION@ file -u 755 -g bin -o bin ./nut_install@prefix@/bin/upsc @prefix@/bin/upsc file -u 755 -g bin -o bin ./nut_install@prefix@/bin/upscmd @prefix@/bin/upscmd file -u 755 -g bin -o bin ./nut_install@prefix@/bin/upslog @prefix@/bin/upslog file -u 755 -g bin -o bin ./nut_install@prefix@/bin/upsrw @prefix@/bin/upsrw file -u 755 -g bin -o bin ./nut_install@prefix@/sbin/upsmon @prefix@/sbin/upsmon file -u 755 -g bin -o bin ./nut_install@prefix@/sbin/upssched @prefix@/sbin/upssched #Including "conf" files under "/usr/local/ups/etc". file -u 644 -g bin -o bin ./nut_install@prefix@/etc/nut.conf.sample @prefix@/etc/nut.conf.sample file -u 644 -g bin -o bin ./nut_install@prefix@/etc/upsmon.conf.sample @prefix@/etc/upsmon.conf.sample file -u 644 -g bin -o bin ./nut_install@prefix@/etc/upssched.conf.sample @prefix@/etc/upssched.conf.sample #Need to check if "libupsclient1" required for Client again. #file -u 755 -g bin -o bin ./nut_install@prefix@/lib/libupsclient.sl.3 @prefix@/lib/libupsclient.sl.3 #file -u 555 -g bin -o bin ./nut_install@prefix@/lib/libupsclient.sl.3.1 @prefix@/lib/libupsclient.sl.3.1 end # ---------------------------------------- #Including "libupsclient1-dev" files. fileset tag Development title "libupsclient1-dev" revision @PACKAGE_VERSION@ file -u 755 -g bin -o bin ./nut_install@prefix@/lib/libupsclient.a @prefix@/lib/libupsclient.a file -u 755 -g bin -o bin ./nut_install@prefix@/lib/libupsclient.la @prefix@/lib/libupsclient.la file -u 755 -g bin -o bin ./nut_install@prefix@/lib/libupsclient.sl @prefix@/lib/libupsclient.sl file -u 644 -g bin -o bin @top_srcdir@/include/parseconf.h @prefix@/include/parseconf.h file -u 644 -g bin -o bin @top_srcdir@/clients/upsclient.h @prefix@/include/upsclient.h file -u 755 -g bin -o bin ./nut_install@prefix@/lib/pkgconfig/libupsclient.pc @prefix@/lib/pkgconfig/libupsclient.pc end # ---------------------------------------- #Including "libups-nut-perl" files. fileset tag libups-nut-perl title "libups-nut-perl" revision @PACKAGE_VERSION@ file -u 644 -g bin -o bin @top_srcdir@/scripts/perl/Nut.pm @prefix@/share/perl5/UPS/Nut.pm end # ---------------------------------------- end #End product nut-2.8.1/scripts/HP-UX/nut-upsd.sh0000755000175000017500000000504514517562211013727 00000000000000#!/sbin/sh # # nut-upsd: NUT upsd start-up and shutdown script # # Allowed exit values: # 0 = success; causes "OK" to show up in checklist. # 1 = failure; causes "FAIL" to show up in checklist. # 2 = skip; causes "N/A" to show up in the checklist. # Use this value if execution of this script is overridden # by the use of a control variable, or if this script is not # appropriate to execute for some other reason. # 3 = reboot; causes the system to be rebooted after execution. # Input and output: # stdin is redirected from /dev/null # # stdout and stderr are redirected to the /etc/rc.log file # during checklist mode, or to the console in raw mode. umask 022 PATH=/usr/sbin:/usr/bin:/sbin export PATH NUT_QUIET_INIT_UPSNOTIFY=true export NUT_QUIET_INIT_UPSNOTIFY WHAT='NUT UPS daemon (Network UPS Tools -- http://www.exploits.org/nut)' WHAT_PATH=/opt/nut/sbin/upsd WHAT_CONFIG=/etc/rc.config.d/nut-upsd # NOTE: If your script executes in run state 0 or state 1, then /usr might # not be available. Do not attempt to access commands or files in # /usr unless your script executes in run state 2 or greater. Other # file systems typically not mounted until run state 2 include /var # and /opt. rval=0 # Check the exit value of a command run by this script. If non-zero, the # exit code is echoed to the log file and the return value of this script # is set to indicate failure. set_return() { x=$? if [ $x -ne 0 ]; then echo "EXIT CODE: $x" rval=1 # script FAILed fi } case $1 in 'start_msg') echo "Starting $WHAT" ;; 'stop_msg') echo "Stopping $WHAT" ;; 'start') if [ -f $WHAT_CONFIG ] ; then . $WHAT_CONFIG else echo "ERROR: $WHAT_CONFIG defaults file MISSING" fi if [ "X$RUNAS" = "X" ] ; then # no user set if [ "$NUT_START" -eq 1 -a -x $WHAT_PATH ]; then $WHAT_PATH && echo $WHAT started set_return else rval=2 fi else # start upsd as a specified user if [ "$NUT_START" -eq 1 -a -x $WHAT_PATH ]; then su $RUNAS -c $WHAT_PATH && echo $WHAT started as user $RUNAS set_return else rval=2 fi fi ;; 'stop') if [ "X$RUNAS" = "X" ] ; then $WHAT_PATH -c stop if [ $? -eq 0 ]; then echo "$WHAT stopped" else rval=1 echo "Unable to stop $WHAT" fi else su $RUNAS -c "$WHAT_PATH -c stop" if [ $? -eq 0 ]; then echo "$WHAT stopped by user $RUNAS" else rval=1 echo "User $RUNAS unable to stop $WHAT" fi fi ;; *) echo "usage: $0 {start|stop|start_msg|stop_msg}" rval=1 ;; esac exit $rval nut-2.8.1/scripts/HP-UX/nut-drvctl0000644000175000017500000000032114273170601013623 00000000000000# NUT_START: Set to 1 to start NUT # NUT_ARGS: Command line arguments to pass to NUT # # To configure the NUT environment: NUT_START=1 UPSNAME= # Blank == all configured UPSs RUNAS= # Blank == run as root nut-2.8.1/scripts/HP-UX/nut-upsmon.sh0000755000175000017500000000420014517562211014265 00000000000000#!/sbin/sh # # nut-upsmon: NUT ups monitor start-up and shutdown script # # Allowed exit values: # 0 = success; causes "OK" to show up in checklist. # 1 = failure; causes "FAIL" to show up in checklist. # 2 = skip; causes "N/A" to show up in the checklist. # Use this value if execution of this script is overridden # by the use of a control variable, or if this script is not # appropriate to execute for some other reason. # 3 = reboot; causes the system to be rebooted after execution. # Input and output: # stdin is redirected from /dev/null # # stdout and stderr are redirected to the /etc/rc.log file # during checklist mode, or to the console in raw mode. umask 022 PATH=/usr/sbin:/usr/bin:/sbin export PATH NUT_QUIET_INIT_UPSNOTIFY=true export NUT_QUIET_INIT_UPSNOTIFY WHAT='NUT UPS monitor (Network UPS Tools -- http://www.exploits.org/nut)' WHAT_PATH=/opt/nut/sbin/upsmon WHAT_CONFIG=/etc/rc.config.d/nut-upsmon # NOTE: If your script executes in run state 0 or state 1, then /usr might # not be available. Do not attempt to access commands or files in # /usr unless your script executes in run state 2 or greater. Other # file systems typically not mounted until run state 2 include /var # and /opt. rval=0 # Check the exit value of a command run by this script. If non-zero, the # exit code is echoed to the log file and the return value of this script # is set to indicate failure. set_return() { x=$? if [ $x -ne 0 ]; then echo "EXIT CODE: $x" rval=1 # script FAILed fi } case $1 in 'start_msg') echo "Starting $WHAT" ;; 'stop_msg') echo "Stopping $WHAT" ;; 'start') if [ -f $WHAT_CONFIG ] ; then . $WHAT_CONFIG else echo "ERROR: $WHAT_CONFIG defaults file MISSING" fi if [ "$NUT_START" -eq 1 -a -x $WHAT_PATH ]; then $WHAT_PATH $UPSMON_ARGS && echo $WHAT $UPSMON_ARGS started set_return else rval=2 fi ;; 'stop') $WHAT_PATH -c stop if [ $? -eq 0 ]; then echo "$WHAT stopped" else rval=1 echo "Unable to stop $WHAT" fi ;; *) echo "usage: $0 {start|stop|start_msg|stop_msg}" rval=1 ;; esac exit $rval nut-2.8.1/scripts/HP-UX/nut-drvctl.sh0000755000175000017500000000524114517562211014250 00000000000000#!/sbin/sh # # nut-drvctl: NUT ups model-specific drivers start-up and shutdown script # # Allowed exit values: # 0 = success; causes "OK" to show up in checklist. # 1 = failure; causes "FAIL" to show up in checklist. # 2 = skip; causes "N/A" to show up in the checklist. # Use this value if execution of this script is overridden # by the use of a control variable, or if this script is not # appropriate to execute for some other reason. # 3 = reboot; causes the system to be rebooted after execution. # Input and output: # stdin is redirected from /dev/null # # stdout and stderr are redirected to the /etc/rc.log file # during checklist mode, or to the console in raw mode. umask 022 PATH=/usr/sbin:/usr/bin:/sbin export PATH NUT_QUIET_INIT_UPSNOTIFY=true export NUT_QUIET_INIT_UPSNOTIFY WHAT='NUT UPS driver (Network UPS Tools -- http://www.exploits.org/nut)' WHAT_PATH=/opt/nut/bin/upsdrvctl WHAT_CONFIG=/etc/rc.config.d/nut-drvctl # NOTE: If your script executes in run state 0 or state 1, then /usr might # not be available. Do not attempt to access commands or files in # /usr unless your script executes in run state 2 or greater. Other # file systems typically not mounted until run state 2 include /var # and /opt. rval=0 # Check the exit value of a command run by this script. If non-zero, the # exit code is echoed to the log file and the return value of this script # is set to indicate failure. set_return() { x=$? if [ $x -ne 0 ]; then echo "EXIT CODE: $x" rval=1 # script FAILed fi } case $1 in 'start_msg') echo "Starting $WHAT" ;; 'stop_msg') echo "Stopping $WHAT" ;; 'start') if [ -f $WHAT_CONFIG ] ; then . $WHAT_CONFIG else echo "ERROR: $WHAT_CONFIG defaults file MISSING" fi if [ "X$RUNAS" = "X" ] ; then # no user set if [ "$NUT_START" -eq 1 -a -x $WHAT_PATH ]; then $WHAT_PATH start $UPSNAME && echo $WHAT started $UPSNAME set_return else rval=2 fi else # start upsd as a specified user if [ "$NUT_START" -eq 1 -a -x $WHAT_PATH ]; then su $RUNAS -c $WHAT_PATH start $UPSNAME && echo $WHAT started $UPSNAME as user $RUNAS set_return else rval=2 fi fi ;; 'stop') if [ "X$RUNAS" = "X" ] ; then $WHAT_PATH stop $UPSNAME if [ $? -eq 0 ]; then echo "$WHAT stopped $UPSNAME" else rval=1 echo "Unable to stop $WHAT $UPSNAME" fi else su $RUNAS -c $WHAT_PATH stop $UPSNAME if [ $? -eq 0 ]; then echo "$WHAT stopped $UPSNAME by user $RUNAS" else rval=1 echo "User $RUNAS unable to stop $WHAT $UPSNAME" fi fi ;; *) echo "usage: $0 {start|stop|start_msg|stop_msg}" rval=1 ;; esac exit $rval nut-2.8.1/scripts/HP-UX/postinstall.in0000644000175000017500000000413314501607135014510 00000000000000#!/bin/sh # directory definitions NUT_DIR="@prefix@" INSTALLPATH="$NUT_DIR/script" CONFIGPATH=/etc/rc.config.d SCRIPTPATH=/sbin/init.d LINKPATH=/sbin/rc3.d LINKPREFIX=991 OWNER=root GROUP=root SCRIPTS="nut-upsd.sh nut-drvctl.sh nut-upsmon.sh" CONFIGS="nut-drvctl nut-upsd nut-upsmon" SCRIPTPERMS=0744 CONFIGPERMS=0444 # make sure the nut user exists and has correct memberships res=`grget -n nut` if [ -z "$res" ]; then groupadd nut fi res=`pwget -n nut` if [ -z "$res" ]; then useradd -g nut -G root -d ${NUT_DIR}/bin nut fi # make sure that conffiles are secured and have the correct ownerships if [ -d @CONFPATH@ ] ; then chown root:nut @CONFPATH@ fi for file in nut.conf ups.conf upsd.conf upsmon.conf upsd.users upssched.conf; do if [ -f @CONFPATH@/$file ] ; then chown root:nut @CONFPATH@/$file chmod 640 @CONFPATH@/$file fi done # make sure that /var/run exists (for privileged processes) if [ ! -d @PIDPATH@ ] ; then mkdir -p @PIDPATH@ fi # make sure that /var/run/nut exists and has the correct ownerships if [ ! -d @ALTPIDPATH@ ] ; then mkdir -p @ALTPIDPATH@ fi if [ -d @ALTPIDPATH@ ] ; then chown root:nut @ALTPIDPATH@ chmod 770 @ALTPIDPATH@ fi # make sure that /var/state/ups exists and has the correct ownerships if [ ! -d @STATEPATH@ ] ; then mkdir -p @STATEPATH@ fi if [ -d /var/state/ups ] ; then chown root:nut @STATEPATH@ chmod 770 @STATEPATH@ fi #Set-up automatic start-up if [ ! -d $CONFIGPATH ]; then echo "NO $CONFIGPATH"; exit 1; fi if [ ! -d $SCRIPTPATH ]; then echo "NO $SCRIPTPATH"; exit 1; fi if [ ! -d $LINKPATH ]; then echo "NO $LINKPATH"; exit 1; fi for script in $SCRIPTS; do name=`basename ${script} .sh` ; cp $INSTALLPATH/$script $SCRIPTPATH/$name chown $OWNER:$GROUP $SCRIPTPATH/$name chmod $SCRIPTPERMS $SCRIPTPATH/$name ln -f -s $SCRIPTPATH/$name $LINKPATH/K$LINKPREFIX$name ln -f -s $SCRIPTPATH/$name $LINKPATH/S$LINKPREFIX$name done for config in $CONFIGS; do cp $INSTALLPATH/$config $CONFIGPATH chown $OWNER:$GROUP $CONFIGPATH chmod $CONFIGPERMS $CONFIGPATH done nut-2.8.1/scripts/README0000644000175000017500000000073614273170601011627 00000000000000These directories hold various scripts: - example startup and shutdown scripts for various operating systems and distributions, - hotplug and udev integration for on the fly privileges settings (Linux only), - UPower (previously DeviceKit-power) rules file, - Python Client module and application, - Perl client module, - Augeas support lenses and modules for NUT, - systemd support files. They have either been contributed by users of the software, or by the NUT Team itself. nut-2.8.1/scripts/misc/0000755000175000017500000000000014520277776011774 500000000000000nut-2.8.1/scripts/misc/nut.bash_completion0000644000175000017500000001223214273170601015572 00000000000000# Bash completion function for Network UPS Tools 'upsc' command. # # Install in /etc/bash_completion.d (and run '. /etc/bash_completion if this # has not been done in your startup files already). # # Charles Lepple _nut_local_upses() { upsc -l 2>/dev/null } _nut_upses() { upsc -l 2>/dev/null # Example syntax: echo UPS@host:port # ... could add others from upsmon.conf, etc. } ### _nut_upsc_completion() { local upses cur COMPREPLY=() cur=${COMP_WORDS[COMP_CWORD]} prev=${COMP_WORDS[COMP_CWORD-1]} # The 'list' options can take a hostname and a port, but we don't complete # the port number: case "$prev" in -l|-L) COMPREPLY=( $(compgen -A hostname ${cur}) ) ; return 0 ;; esac # If the user starts to type an option, then only offer options for that word: if [[ "$cur" == -* ]]; then COMPREPLY=( $(compgen -W "-l -L" -- ${cur}) ) ; return 0 fi upses="$(_nut_upses)" COMPREPLY=( $(compgen -W "-l -L $upses" -- ${cur}) ) return 0 } complete -F _nut_upsc_completion upsc ### _nut_upscmd_completion() { local cur options prev pprev upses COMPREPLY=() cur=${COMP_WORDS[COMP_CWORD]} prev=${COMP_WORDS[COMP_CWORD-1]} (( COMP_CWORD >= 3 )) && pprev=${COMP_WORDS[COMP_CWORD-3]} options="-h -l -u -p" case "$prev" in -u|-p) # TODO: match against upsd.users, if readable. COMPREPLY=( ) ; return 0 ;; -l) upses="$(_nut_upses)" COMPREPLY=( $(compgen -W "$upses" -- ${cur}) ) ; return 0 ;; upscmd) upses="$(_nut_upses)" COMPREPLY=( $(compgen -W "$options $upses" -- ${cur}) ) ; return 0 ;; esac # If the user starts to type an option, then only offer options for that word: if [[ "$cur" == -* ]]; then COMPREPLY=( $(compgen -W "$options" -- ${cur}) ) ; return 0 fi # If we have hit the end of the command line, then don't try and match the command as a host: [[ "$pprev" == -* || "$pprev" == "upscmd" ]] && return 0 # Get the list of commands from the UPS named in the previous word: local cmds cmds=$(upscmd -l $prev 2>/dev/null | tail -n +3 | sed 's/ - .*//' ) COMPREPLY=( $(compgen -W "$cmds" -- ${cur}) ) return 0 } complete -F _nut_upscmd_completion upscmd ### _nut_upsd_completion() { local cur options prev COMPREPLY=() cur=${COMP_WORDS[COMP_CWORD]} prev=${COMP_WORDS[COMP_CWORD-1]} options="-c -D -f -h -r -u -V -4 -6" case "$prev" in -c) # commands: COMPREPLY=( $(compgen -W "reload stop" -- ${cur}) ) ; return 0 ;; -r) # chroot: COMPREPLY=( $(compgen -A directory -- ${cur}) ) ; return 0 ;; -u) # system user, not in upsd.users COMPREPLY=( $(compgen -u -- ${cur}) ) ; return 0 ;; esac # Only options, no other words: COMPREPLY=( $(compgen -W "$options" -- ${cur}) ) ; return 0 return 0 } complete -F _nut_upsd_completion upsd ### _nut_upsdrvctl_completion() { local cur options prev upses COMPREPLY=() cur=${COMP_WORDS[COMP_CWORD]} prev=${COMP_WORDS[COMP_CWORD-1]} options="-h -r -t -u -D" case "$prev" in -r) # chroot: COMPREPLY=( $(compgen -A directory -- ${cur}) ) ; return 0 ;; -u) # system user, not in upsd.users COMPREPLY=( $(compgen -u -- ${cur}) ) ; return 0 ;; start|stop|shutdown) upses="$(_nut_local_upses)" COMPREPLY=( $(compgen -W "$upses" -- ${cur}) ) ; return 0 ;; esac # If the user starts to type an option, then only offer options for that word: if [[ "$cur" == -* ]]; then COMPREPLY=( $(compgen -W "$options" -- ${cur}) ) ; return 0 fi # Don't auto-complete shutdown because it doesn't usually do what you want (upsmon -c fsd): COMPREPLY=( $(compgen -W "$options start stop" -- ${cur}) ) return 0 } complete -F _nut_upsdrvctl_completion upsdrvctl ### _nut_upsmon_completion() { local cur options prev COMPREPLY=() cur=${COMP_WORDS[COMP_CWORD]} prev=${COMP_WORDS[COMP_CWORD-1]} options="-c -D -h -K -u -4 -6" case "$prev" in -c) # commands: COMPREPLY=( $(compgen -W "fsd reload stop" -- ${cur}) ) ; return 0 ;; -u) # system user, not in upsd.users COMPREPLY=( $(compgen -u -- ${cur}) ) ; return 0 ;; esac # Only options, no other words: COMPREPLY=( $(compgen -W "$options" -- ${cur}) ) ; return 0 return 0 } complete -F _nut_upsmon_completion upsmon ### _nut_upsrw_completion() { local cur options prev upses COMPREPLY=() cur=${COMP_WORDS[COMP_CWORD]} prev=${COMP_WORDS[COMP_CWORD-1]} options="-s -u -p -h" upses="$(_nut_upses)" case "$prev" in -u|-p) # TODO: match against upsd.users, if readable. COMPREPLY=( ) ; return 0 ;; -l) COMPREPLY=( $(compgen -W "$upses" -- ${cur}) ) ; return 0 ;; esac # If the user starts to type an option, then only offer options for that word: if [[ "$cur" == -* ]]; then COMPREPLY=( $(compgen -W "$options" -- ${cur}) ) ; return 0 fi COMPREPLY=( $(compgen -W "$options $upses" -- ${cur}) ) return 0 } complete -F _nut_upsrw_completion upsrw nut-2.8.1/scripts/misc/osd-notify0000644000175000017500000000202714273170601013713 00000000000000#!/bin/sh # **********************************************************# # osd-notify: script to make On Screen Display notification # # **********************************************************# # Copyright 2003 - Arnaud Quette # # Distributed under the GNU GPL v2 # # See attached file (osd-notify.txt) for usage information # # **********************************************************# # select your font with xfontsel # ****************************** FONT="-adobe-courier-bold-*-*-*-34-*-100-*-*-*-*-*" # Position # ******** POSITION="-p middle -A center" # Delay in seconds # **************** DELAY="10" # Color # ***** COLOR="red" # You can use a combination of valid message values: # $* => for full text # $UPSNAME => for ups name # $NOTIFYTYPE => depending on event (ONLINE, ONBATT, ...) # ********************************************************************* MESSAGE="$*" # Processing part # *************** echo $MESSAGE | osd_cat - -c $COLOR -f $FONT -d $DELAY $POSITION nut-2.8.1/missing0000755000175000017500000001533614517510735010670 00000000000000#! /bin/sh # Common wrapper for a few potentially missing GNU programs. scriptversion=2018-03-07.03; # UTC # Copyright (C) 1996-2021 Free Software Foundation, Inc. # Originally written by Fran,cois Pinard , 1996. # 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 2, 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 . # As a special exception to the GNU General Public License, if you # distribute this file as part of a program that contains a # configuration script generated by Autoconf, you may include it under # the same distribution terms that you use for the rest of that program. if test $# -eq 0; then echo 1>&2 "Try '$0 --help' for more information" exit 1 fi case $1 in --is-lightweight) # Used by our autoconf macros to check whether the available missing # script is modern enough. exit 0 ;; --run) # Back-compat with the calling convention used by older automake. shift ;; -h|--h|--he|--hel|--help) echo "\ $0 [OPTION]... PROGRAM [ARGUMENT]... Run 'PROGRAM [ARGUMENT]...', returning a proper advice when this fails due to PROGRAM being missing or too old. Options: -h, --help display this help and exit -v, --version output version information and exit Supported PROGRAM values: aclocal autoconf autoheader autom4te automake makeinfo bison yacc flex lex help2man Version suffixes to PROGRAM as well as the prefixes 'gnu-', 'gnu', and 'g' are ignored when checking the name. Send bug reports to ." exit $? ;; -v|--v|--ve|--ver|--vers|--versi|--versio|--version) echo "missing $scriptversion (GNU Automake)" exit $? ;; -*) echo 1>&2 "$0: unknown '$1' option" echo 1>&2 "Try '$0 --help' for more information" exit 1 ;; esac # Run the given program, remember its exit status. "$@"; st=$? # If it succeeded, we are done. test $st -eq 0 && exit 0 # Also exit now if we it failed (or wasn't found), and '--version' was # passed; such an option is passed most likely to detect whether the # program is present and works. case $2 in --version|--help) exit $st;; esac # Exit code 63 means version mismatch. This often happens when the user # tries to use an ancient version of a tool on a file that requires a # minimum version. if test $st -eq 63; then msg="probably too old" elif test $st -eq 127; then # Program was missing. msg="missing on your system" else # Program was found and executed, but failed. Give up. exit $st fi perl_URL=https://www.perl.org/ flex_URL=https://github.com/westes/flex gnu_software_URL=https://www.gnu.org/software program_details () { case $1 in aclocal|automake) echo "The '$1' program is part of the GNU Automake package:" echo "<$gnu_software_URL/automake>" echo "It also requires GNU Autoconf, GNU m4 and Perl in order to run:" echo "<$gnu_software_URL/autoconf>" echo "<$gnu_software_URL/m4/>" echo "<$perl_URL>" ;; autoconf|autom4te|autoheader) echo "The '$1' program is part of the GNU Autoconf package:" echo "<$gnu_software_URL/autoconf/>" echo "It also requires GNU m4 and Perl in order to run:" echo "<$gnu_software_URL/m4/>" echo "<$perl_URL>" ;; esac } give_advice () { # Normalize program name to check for. normalized_program=`echo "$1" | sed ' s/^gnu-//; t s/^gnu//; t s/^g//; t'` printf '%s\n' "'$1' is $msg." configure_deps="'configure.ac' or m4 files included by 'configure.ac'" case $normalized_program in autoconf*) echo "You should only need it if you modified 'configure.ac'," echo "or m4 files included by it." program_details 'autoconf' ;; autoheader*) echo "You should only need it if you modified 'acconfig.h' or" echo "$configure_deps." program_details 'autoheader' ;; automake*) echo "You should only need it if you modified 'Makefile.am' or" echo "$configure_deps." program_details 'automake' ;; aclocal*) echo "You should only need it if you modified 'acinclude.m4' or" echo "$configure_deps." program_details 'aclocal' ;; autom4te*) echo "You might have modified some maintainer files that require" echo "the 'autom4te' program to be rebuilt." program_details 'autom4te' ;; bison*|yacc*) echo "You should only need it if you modified a '.y' file." echo "You may want to install the GNU Bison package:" echo "<$gnu_software_URL/bison/>" ;; lex*|flex*) echo "You should only need it if you modified a '.l' file." echo "You may want to install the Fast Lexical Analyzer package:" echo "<$flex_URL>" ;; help2man*) echo "You should only need it if you modified a dependency" \ "of a man page." echo "You may want to install the GNU Help2man package:" echo "<$gnu_software_URL/help2man/>" ;; makeinfo*) echo "You should only need it if you modified a '.texi' file, or" echo "any other file indirectly affecting the aspect of the manual." echo "You might want to install the Texinfo package:" echo "<$gnu_software_URL/texinfo/>" echo "The spurious makeinfo call might also be the consequence of" echo "using a buggy 'make' (AIX, DU, IRIX), in which case you might" echo "want to install GNU make:" echo "<$gnu_software_URL/make/>" ;; *) echo "You might have modified some files without having the proper" echo "tools for further handling them. Check the 'README' file, it" echo "often tells you about the needed prerequisites for installing" echo "this package. You may also peek at any GNU archive site, in" echo "case some other package contains this missing '$1' program." ;; esac } give_advice "$1" | sed -e '1s/^/WARNING: /' \ -e '2,$s/^/ /' >&2 # Propagate the correct exit status (expected to be 127 for a program # not found, 63 for a program that failed due to version mismatch). exit $st # Local variables: # eval: (add-hook 'before-save-hook 'time-stamp) # time-stamp-start: "scriptversion=" # time-stamp-format: "%:y-%02m-%02d.%02H" # time-stamp-time-zone: "UTC0" # time-stamp-end: "; # UTC" # End: nut-2.8.1/conf/0000755000175000017500000000000014520277775010276 500000000000000nut-2.8.1/conf/nut.conf.sample0000644000175000017500000001007414510262764013144 00000000000000# Network UPS Tools: example nut.conf # # This file tries to standardize the various files being found in the field, # like /etc/default/nut on Debian based systems, /etc/sysconfig/ups on RedHat # based systems, ... Distribution's init script or service unit/method script # should source this file to see which component(s) has to be started. # Some scripts and units provided by NUT project itself may also look into # this file for optional configuration about OS integration. # # IMPORTANT NOTES: # This file is intended to be sourced by standard POSIX shell scripts # (so there is no guaranteed `export VAR=VAL` syntax) and additionally # by systemd on Linux (no guaranteed expansion of variables). # You MUST NOT use spaces around the equal sign! # Practical support for this file and its settings currently varies between # various OS packages and NUT sample scripts, but should converge over time. # # See also: `man nut.conf` (usually in Manual pages Section 5, # for Configuration files) # ############################################################################## # General section ############################################################################## # The MODE determines which part of the NUT is to be started, and which # configuration files must be modified. # # The values of MODE can be: # - none: NUT is not configured, or use the Integrated Power Management, or use # some external system to startup NUT components. So nothing is to be started # by scripts or services bundled with NUT packages. # - standalone: This mode address a local only configuration, with 1 UPS # protecting the local system. This implies to start the 3 NUT layers (driver, # upsd and upsmon) and the matching configuration files. This mode can also # address UPS redundancy. # - netserver: same as for the standalone configuration, but also need # some more network access controls (firewall, tcp-wrappers) and possibly a # specific LISTEN directive in upsd.conf. # Since this MODE is opened to the network, a special care should be applied # to security concerns. # - netclient: this mode only requires upsmon (and tools it may be using, like # upssched or custom scripts) to monitor a remote NUT server and possibly # shut down this system (part of upsmon must run as root then). MODE=none # Uncomment this to allow starting the service even if `ups.conf` has no device # sections configured at the moment. This environment variable overrides the # built-in "false" flag in `upsd`, and an optional same-named default flag that # can be set in `upsd.conf`. If you want a data server always running, even if # it initially has nothing to serve (may be live-reloaded later, when devices # become configured), this option is for you. #ALLOW_NO_DEVICE=true #export ALLOW_NO_DEVICE # The optional 'UPSD_OPTIONS' allow to set upsd specific command-line options. # It is ignored when 'MODE' above indicates that no upsd should be running. # It may be redundant in comparison to options which can be set in `upsd.conf`. #UPSD_OPTIONS= # The optional 'UPSMON_OPTIONS' allow to set upsmon specific command-line options. # It is ignored when 'MODE' above indicates that no upsmon should be running. # It may be redundant in comparison to options which can be set in `upsmon.conf`. #UPSMON_OPTIONS= # If the optional 'POWEROFF_WAIT' is configured (to a value that can be handled # by `/bin/sleep` on the current system - typically an integer with the number # of seconds for a delay, but not always limited to that syntax), and the current # system which manages one or more UPS devices would not only command it to shut # down, but also try to avoid the "Power race". Caveats emptor, see NUT FAQ and # other docs for details. #POWEROFF_WAIT=3600 # The optional 'POWEROFF_QUIET' setting controls if the NUT shutdown integration # scripts or service units would emit messages about their activity (or lack # thereof). By default they may be verbose, to aid post-mortem troubleshooting # via logs or console captures. # Set to `true` to avoid that trove of information, if you consider it noise. #POWEROFF_QUIET=true nut-2.8.1/conf/upsd.conf.sample0000644000175000017500000002006714501607135013307 00000000000000# Network UPS Tools: example upsd configuration file # # This file contains access control data, you should keep it secure. # # It should only be readable by the user that upsd becomes. See the FAQ. # # Each entry below provides usage and default value. # # For more information, refer to upsd.conf manual page. # ======================================================================= # MAXAGE # MAXAGE 15 # # This defaults to 15 seconds. After a UPS driver has stopped updating # the data for this many seconds, upsd marks it stale and stops making # that information available to clients. After all, the only thing worse # than no data is bad data. # # You should only use this if your driver has difficulties keeping # the data fresh within the normal 15 second interval. Watch the syslog # for notifications from upsd about staleness. # ======================================================================= # TRACKINGDELAY # TRACKINGDELAY 3600 # # This defaults to 1 hour. When instant commands and variables setting status # tracking is enabled, status execution information are kept during this # amount of time, and then cleaned up. # ======================================================================= # ALLOW_NO_DEVICE # ALLOW_NO_DEVICE true # # Normally upsd requires that at least one device section is defined in ups.conf # when the daemon starts, to serve its data. For automatically managed services # it may be preferred to have upsd always running, and reload the configuration # when power devices become defined. # # Boolean values 'true', 'yes', 'on' and '1' mean that the server would not # refuse to start with zero device sections found in ups.conf. # # Boolean values 'false', 'no', 'off' and '0' mean that the server should refuse # to start if zero device sections were found in ups.conf. This is the default. # ======================================================================= # STATEPATH # STATEPATH /var/run/nut # # Tell upsd to look for the driver state sockets in 'path' rather # than the default that was compiled into the program. # ======================================================================= # LISTEN [] # LISTEN 127.0.0.1 3493 # LISTEN ::1 3493 # LISTEN myhostname 83493 # LISTEN myhostname.mydomain # # With no LISTEN statement, the default is localhost and port 3493. # In case of IP v4 or v6 disabled kernel, only the available one will # be used. # Note that it is not true for Windows platforms. You shouldn't use IPv6 in # your configuration files unless you have IPv6 installed. # # As a special case, `LISTEN * ` (with an asterisk) will try # to listen on "ANY" IP address for both IPv6 (::0) and IPv4 (0.0.0.0), # subject to `upsd` command-line arguments, or system configuration. # Note that if the system supports IPv4-mapped IPv6 addressing per RFC-3493, # and does not allow to disable this mode, then there may be one listening # socket to handle both address families. # # One or more LISTEN statements give the IP address (or name that # resolves to such an address) for upsd to listen on, optionally with # a port number. # # As an example, a machine with a LAN and a WAN interface that also # functions as a router and firewall might be configured to listen # only on the LAN interface. # # This will only be read at startup of upsd. If you make changes here, # you'll need to restart upsd, as reload will have no effect. # # Please note that older NUT releases could have been using the IPv4-mapped # IPv6 addressing (sometimes also known as "dual-stack") mode, if provided # by the system. Current versions (since NUT v2.8.1 release) explicitly try # to restrict their listening sockets to only support one address family on # each socket, and so avoid IPv4-mapped mode where possible. # ======================================================================= # MAXCONN # MAXCONN 1024 # # This defaults to maximum number allowed on your system. Each UPS, each # LISTEN address and each client count as one connection. If the server # runs out of connections, it will no longer accept new incoming client # connections. Only set this if you know exactly what you're doing. # ======================================================================= # CERTFILE # CERTFILE /usr/local/ups/etc/upsd.pem # # When compiled with SSL support with OpenSSL backend, # you can enter the certificate file here. # The certificates must be in PEM format and must be sorted starting with # the subject's certificate (server certificate), followed by intermediate # CA certificates (if applicable_ and the highest level (root) CA. It should # end with the server key. See 'docs/security.txt' or the Security chapter of # NUT user manual for more information on the SSL support in NUT. # # See 'docs/security.txt' or the Security chapter of NUT user manual # for more information on the SSL support in NUT. # ======================================================================= # CERTPATH # CERTPATH /usr/local/ups/etc/cert/upsd # # When compiled with SSL support with NSS backend, # you can enter the certificate path here. # Certificates are stored in a dedicated database (split into 3 files). # Specify the path of the database directory. # # See 'docs/security.txt' or the Security chapter of NUT user manual # for more information on the SSL support in NUT. # ======================================================================= # CERTIDENT # CERTIDENT "my nut server" "MyPasSw0rD" # # When compiled with SSL support with NSS backend, # you can specify the certificate name to retrieve from database to # authenticate itself and the password # required to access certificate related private key. # # See 'docs/security.txt' or the Security chapter of NUT user manual # for more information on the SSL support in NUT. # ======================================================================= # CERTREQUEST # CERTREQUEST REQUIRE # # When compiled with SSL support with NSS backend and client certificate # validation (disabled by default, see 'docs/security.txt'), # you can specify if upsd requests or requires client's' certificates. # Possible values are : # - 0 to not request to clients to provide any certificate # - 1 to require to all clients a certificate # - 2 to require to all clients a valid certificate # # See 'docs/security.txt' or the Security chapter of NUT user manual # for more information on the SSL support in NUT. # ======================================================================= # DISABLE_WEAK_SSL # DISABLE_WEAK_SSL true # # Tell upsd to disable older/weak SSL/TLS protocols and ciphers. # # With relatively recent versions of OpenSSL or NSS it will be restricted # to TLSv1.2 or better. # # Unless you have really ancient clients, you probably want to enable this. # Currently disabled by default to ensure compatibility with existing setups. # ======================================================================= # DEBUG_MIN # DEBUG_MIN 2 # # Optionally specify a minimum debug level for `upsd` data daemon, e.g. for # troubleshooting a deployment, without impacting foreground or background # running mode directly, and without need to edit init-scripts or service # unit definitions. Note that command-line option `-D` can only increase # this verbosity level. # # NOTE: if the running daemon receives a `reload` command, presence of the # `DEBUG_MIN NUMBER` value in the configuration file can be used to tune # debugging verbosity in the running service daemon (it is recommended to # comment it away or set the minimum to explicit zero when done, to avoid # huge journals and I/O system abuse). Keep in mind that for this run-time # tuning, the `DEBUG_MIN` value *present* in *reloaded* configuration files # is applied instantly and overrides any previously set value, from file # or CLI options, regardless of older logging level being higher or lower # than the newly found number; a missing (or commented away) value however # does not change the previously active logging verbosity. nut-2.8.1/conf/hosts.conf.sample0000644000175000017500000000205714377374134013506 00000000000000# Network UPS Tools: example hosts.conf # # This file is used to control the CGI programs. If you have not # installed them, you may safely ignore or delete this file. # # ----------------------------------------------------------------------- # # upsstats will use the list of MONITOR entries when displaying the # default template (upsstats.html). The "FOREACHUPS" directive in the # template will use this file to find systems running upsd. # # upsstats and upsimage also use this file to determine if a host may be # monitored. This keeps evil people from using your system to annoy # others with unintended queries. # # upsset presents a list of systems that may be viewed and controlled # using this file. # # ----------------------------------------------------------------------- # # Usage: list systems running upsd that you want to monitor # # MONITOR "" # # Examples: # # MONITOR myups@localhost "Local UPS" # MONITOR su2200@10.64.1.1 "Finance department" # MONITOR matrix@shs-server.example.edu "Sierra High School data room #1" nut-2.8.1/conf/upsstats-single.html.sample0000644000175000017500000001531514377374134015533 00000000000000 @TEMPC@ @UPSSTATSPATH upsstats.cgi@ @UPSIMAGEPATH upsimage.cgi@ @REFRESH@ @HOSTDESC@ : @VAR ups.model@ on @HOST@ @IFSUPP ambient.temperature@ @ELSE@ @IFSUPP ambient.humidity@ @ENDIF@ @IFSUPP ambient.temperature@ @IFSUPP ambient.humidity@ @ELSE@ @IFSUPP ambient.temperature@ @ELSE@ @IFSUPP ambient.humidity@ @ENDIF@
Network UPS Tools upsstats @VERSION@ - @HOSTDESC@ - @VAR ups.model@ on @HOST@
@DATE %a %b %d %X %Z %Y@AmbientAmbientBattery Input Output Load
@IFSUPP battery.runtime@ @ENDIF@ @IFSUPP ups.temperature@ @ENDIF@ @IFSUPP battery.voltage@ @ENDIF@ @ELSE@ @IFSUPP input.L2-N.voltage@ @VAR input.L1-N.voltage@ V
@VAR input.L2-N.voltage@ V
@VAR input.L3-N.voltage@ V
@ELSE@ @IFSUPP input.voltage@ @VAR input.voltage@ V
@ENDIF@ @IFSUPP input.L2.current@ @ELSE@ @IFSUPP input.current@ @ENDIF@ @IFSUPP input.frequency@ @ENDIF@ @ELSE@ @IFSUPP output.L2-N.voltage@ @VAR output.L1-N.voltage@ V
@VAR output.L2-N.voltage@ V
@VAR output.L3-N.voltage@ V
@ELSE@ @IFSUPP output.voltage@ @VAR output.voltage@ V @ENDIF@ @IFSUPP output.L2.current@ @ELSE@ @IFSUPP output.current@ @ENDIF@ @IFSUPP output.frequency@ @ENDIF@
UPS Model: @VAR ups.model@
Status: @STATUS@
Runtime: @RUNTIME@
UPS temp: @UPSTEMP@ @DEGREES@
Battery: @VAR battery.voltage@ V@IFSUPP battery.current@, @VAR battery.current@ A
Input: @IFSUPP input.L2-L3.voltage@ @VAR input.L1-L2.voltage@ V
@VAR input.L2-L3.voltage@ V
@VAR input.L3-L1.voltage@ V
@VAR input.L1.current@ A
@VAR input.L2.current@ A
@VAR input.L3.current@ A
@VAR input.current@ A
@VAR input.frequency@ Hz
Output: @IFSUPP output.L2-L3.voltage@ @VAR output.L1-L2.voltage@ V
@VAR output.L2-L3.voltage@ V
@VAR output.L3-L1.voltage@ V
@VAR output.L1.current@ A
@VAR output.L2.current@ A
@VAR output.L3.current@ A
@VAR output.current@ A
@VAR output.frequency@ Hz
Temperature
@IMG ambient.temperature tempmin=0 tempmax=50 width=90@
Humidity
@IMG ambient.humidity width=90@
Temperature
@IMG ambient.temperature tempmin=0 tempmax=50@
Humidity
@IMG ambient.humidity@
@IFSUPP battery.charge@ @IFSUPP battery.voltage@ @ELSE@ @IFSUPP battery.charge@ @ELSE@ @ENDIF@
Charge
@IMG battery.charge width=90@
Voltage
@IMG battery.voltage width=90@
Charge
@IMG battery.charge@
Voltage
@IMG battery.voltage@
@IFSUPP input.L2-L3.voltage@ @ELSE@ @IFSUPP input.L2-N.voltage@ @ELSE@ @ENDIF@
L1-L2
@IMG input.L1-L2.voltage width=68@
L2-L3
@IMG input.L2-L3.voltage width=68@
L3-L1
@IMG input.L3-L1.voltage width=68@
L1-N
@IMG input.L1-N.voltage width=68@
L2-N
@IMG input.L2-N.voltage width=68@
L3-N
@IMG input.L3-N.voltage width=68@

@IMG input.voltage@
@IFSUPP output.L2-L3.voltage@ @ELSE@ @IFSUPP output.L2-N.voltage@ @ELSE@ @ENDIF@
L1-L2
@IMG output.L1-L2.voltage width=68@
L2-L3
@IMG output.L2-L3.voltage width=68@
L3-L1
@IMG output.L3-L1.voltage width=68@
L1-N
@IMG output.L1-N.voltage width=68@
L2-N
@IMG output.L2-N.voltage width=68@
L3-N
@IMG output.L3-N.voltage width=68@

@IMG output.voltage@
@IFSUPP output.L2.power.percent@ @ELSE@ @IFSUPP output.L2.realpower.percent@ @ELSE@ @ENDIF@
L1
@IMG output.L1.power.percent width=68@
L2
@IMG output.L2.power.percent width=68@
L3
@IMG output.L3.power.percent width=68@
L1
@IMG output.L1.realpower.percent width=68@
L2
@IMG output.L2.realpower.percent width=68@
L3
@IMG output.L3.realpower.percent width=68@

@IMG ups.load@
Valid CSS Valid HTML 4.01 Strict
nut-2.8.1/conf/ups.conf.sample0000644000175000017500000002316514517273362013155 00000000000000# Network UPS Tools: example ups.conf # # --- SECURITY NOTE --- # # If you use snmp-ups and set a community string in here, you # will have to secure this file to keep other users from obtaining # that string. It needs to be readable by upsdrvctl and any drivers, # and by upsd. # # --- # # This is where you configure all the UPSes that this system will be # monitoring directly. These are usually attached to serial ports, but # USB devices and SNMP devices are also supported. # # This file is used by upsdrvctl to start and stop your driver(s), and # is also used by upsd to determine which drivers to monitor. The # drivers themselves also read this file for configuration directives. # # The general form is: # # [upsname] # driver = # port = # < any other directives here > # # The section header ([upsname]) can be just about anything as long as # it is a single word inside brackets. upsd uses this to uniquely # identify a UPS on this system. # # If you have a UPS called snoopy, your section header would be "[snoopy]". # On a system called "doghouse", the line in your upsmon.conf to monitor # and manage it would look something like this: # # MONITOR snoopy@doghouse 1 monuser mypassword primary # # It might look like this if monitoring in "secondary" mode (without any # ability to directly manage the UPS) from a different system: # # MONITOR snoopy@doghouse 1 monuser mypassword secondary # # Configuration directives # ------------------------ # # These directives are used by upsdrvctl only and should be specified outside # of a driver definition: # # maxretry: OPTIONAL. Specify the number of attempts to start the driver(s), # in case of failure, before giving up. A delay of 'retrydelay' is # inserted between each attempt. Caution should be taken when using # this option, since it can impact the time taken by your system to # start. # # The built-in default is 1 attempt. # # retrydelay: OPTIONAL. Specify the delay between each restart attempt of the # driver(s), as specified by 'maxretry'. Caution should be taken # when using this option, since it can impact the time taken by your # system to start. # # The default is 5 seconds. # # chroot: OPTIONAL. Used for securing. See man page for details. # # driverpath: OPTIONAL. Used for custom setups. See man page for details. # # nowait: OPTIONAL. Tell upsdrvctl to not wait at all for the driver(s) # to execute the requested command. Fire and forget. # # pollinterval: OPTIONAL. The status of the UPS will be refreshed after a # maximum delay which is controlled by this setting (default # 2 seconds). This may be useful if the driver is creating too # much of a load on your system or network. # Note that some drivers also have an option called *pollfreq* # which controls how frequently some of the less critical # parameters are polled. See respective driver man pages. # # Set maxretry to 3 by default, this should mitigate race with slow devices: maxretry = 3 # These directives can be set outside and inside a driver definition, with # slightly different meanings per context: # # maxstartdelay: OPTIONAL. This can be set as a global variable # above your first UPS definition and it can also be # set in a UPS section. This value controls how long # upsdrvctl will wait for the driver to finish starting. # This keeps your system from getting stuck due to a # broken driver or UPS. # Note that after this time upsdrvctl would just move # along with its business (whether retrying the same # driver if `maxretry>1`, or trying another driver if # starting them all, or just eventually exit); however, # each such most recently started "stuck" driver process # may be further initializing in the background, and # might even succeed eventually. # They would not be actively killed by upsdrvctl after # this timeout expires. # # The default is 45 seconds. # # debug_min: OPTIONAL. Specify a minimum debug level for all driver daemons # (when specified at global level), or for this driver daemon # (when specified in a driver section), e.g. for troubleshooting # a deployment. This does not directly impact the foreground or # background running mode. If both the global and driver level # `debug_min` are set, the driver-level setting takes precedence. # Command-line option `-D` can only increase this verbosity level. # # user, group: OPTIONAL. Overrides the compiled-in (also global-section, # when used in driver section) default unprivileged user/group # name for NUT device driver. Impacts access rights used for # the socket file access (group) and communication ports (user). # # synchronous: OPTIONAL. The driver work by default in asynchronous # mode (like *no*) with fallback to synchronous if sending # fails (i.e *synchronous=auto*). This means that all data # are pushed by the driver on the communication socket to # upsd (Unix socket on Unix, Named pipe on Windows) without # waiting for these data to be actually consumed. With # some HW, such as ePDUs, that can produce a lot of data, # asynchronous mode may cause some congestion, resulting in # the socket to be full, and the driver to appear as not # connected. By enabling the 'synchronous' flag # (value = 'yes'), the driver will wait for data to be # consumed by upsd, prior to publishing more. This can be # enabled either globally or per driver. # # The default is 'no' (i.e. asynchronous mode) for backward # compatibility of the driver behavior. # # These directives are common to all drivers that support ups.conf: # # driver: REQUIRED. Specify the program to run to talk to this UPS. # apcsmart, bestups, and sec are some examples. # # port: REQUIRED. The serial port where your UPS is connected. # For example: # /dev/ttyS0 is usually the first port on Linux boxes. # "\\\\.\\COM1" is the first port on Windows boxes (note that # the backslash characters themselves must be escaped, # for the NUT configuration parser to yield "\\.\COM1"). # # sdorder: OPTIONAL. When you have multiple UPSes on your system, you # usually need to turn them off in a certain order. upsdrvctl # shuts down all the 0s, then the 1s, 2s, and so on. To exclude # a UPS from the shutdown sequence, set this to -1. # # The default value for this parameter is 0. # # desc: optional, to keep a note of the UPS purpose, location, etc. # # nolock: optional, and not recommended for use in this file. # # If you put nolock in here, the driver will not lock the # serial port every time it starts. This may allow other # processes to seize the port if you start more than one by # mistake. # # This is only intended to be used on systems where locking # absolutely must be disabled for the software to work. # # ignorelb: OPTIONAL. Ignore low battery condition reported by device, # and evaluate remaining battery charge or runtime instead. # See man page for details. # # usb_set_altinterface(=num): OPTIONAL. Require that NUT calls this method # to set the interface, even if 0 (default). Some devices require # the call to initialize; others however can get stuck due to it - # so it is not called by default. Yet others can be composite # devices which use a non-zero interface to represent the UPS. # # default.: OPTIONAL. Set a default value for which is # used in case the UPS doesn't provide a value, but which will be # overwritten if a value is available from the UPS, e.g.: # default.input.voltage.nominal = 230 # will report the nominal input voltage to be 230, unless the UPS # eventually tells us differently. # # override.: OPTIONAL. Set a value for that overrides # (for NUT) any value that may be read from the UPS. # Used for overriding values from the UPS that are clearly wrong # (e.g. some devices report wrong values for battery voltage): # override.battery.voltage.nominal = 12 # Use with caution! This will only change the appearance of the # variable to the outside world (and NUT calculations), internally # in the UPS the original value is used. # # Anything else is passed through to the hardware-specific part of # the driver. # # Examples # -------- # # A simple example for a UPS called "powerpal" that uses the blazer_ser # driver on /dev/ttyS0 is: # # [powerpal] # driver = blazer_ser # port = /dev/ttyS0 # desc = "Web server" # # If your UPS driver requires additional settings, you can specify them # here. For example, if it supports a setting of "1234" for the # variable "cable", it would look like this: # # [myups] # driver = mydriver # port = /dev/ttyS1 # cable = 1234 # desc = "Something descriptive" # # To find out if your driver supports any extra settings, start it with # the -h option and/or read the driver's documentation. nut-2.8.1/conf/upsset.conf.sample0000644000175000017500000000351714501607135013660 00000000000000# Network UPS Tools - upsset.conf sample file # # This file is provided to ensure that you do not expose your upsd server # to the world upon installing the CGI programs. Specifically, it keeps # the upsset.cgi program from running until you have assured it that you # have secured your web server's CGI directory. # # By default, your web server will probably let anyone access upsset.cgi # once it is installed. This means that anyone could attempt to crack # upsd logins since they would appear to be coming from your web server, # rather than the outside world, slipping through any ACL/ACCESS definitions. # # For this reason, you *MUST* first secure your CGI programs before # enabling upsset in this configuration file. If you can't do this in # your web server, then you should *not* run this program. # # For Apache, the .htaccess file can be used in the directory with the # programs. You'll need something like this for older versions: # # # deny from all # allow from your.network.addresses # # # You will probably have to set "AllowOverride Limit" for this directory in # your server-level configuration file as well. # # Modern Apache enjoys a more detailed syntax, like this: # # ScriptAlias /upsstats.cgi /usr/share/nut/cgi/upsstats.cgi # ScriptAlias /upsset.cgi /usr/share/nut/cgi/upsset.cgi # # # Options +Includes +ExecCGI # AllowOverride Limit # # Require local # Require ip aa.bb.cc.dd/nn # # # # If this doesn't make sense, then stop reading and leave this program alone. # # Assuming you have all this done (and it works), then you may uncomment # the line below and start using upsset.cgi through your web browser. # ### ### I_HAVE_SECURED_MY_CGI_DIRECTORY ### nut-2.8.1/conf/Makefile.in0000644000175000017500000005757314520274662012274 00000000000000# Makefile.in generated by automake 1.16.5 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2021 Free Software Foundation, Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. @SET_MAKE@ # Network UPS Tools: conf VPATH = @srcdir@ am__is_gnu_make = { \ if test -z '$(MAKELEVEL)'; then \ false; \ elif test -n '$(MAKE_HOST)'; then \ true; \ elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \ true; \ else \ false; \ fi; \ } am__make_running_with_option = \ case $${target_option-} in \ ?) ;; \ *) echo "am__make_running_with_option: internal error: invalid" \ "target option '$${target_option-}' specified" >&2; \ exit 1;; \ esac; \ has_opt=no; \ sane_makeflags=$$MAKEFLAGS; \ if $(am__is_gnu_make); then \ sane_makeflags=$$MFLAGS; \ else \ case $$MAKEFLAGS in \ *\\[\ \ ]*) \ bs=\\; \ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ esac; \ fi; \ skip_next=no; \ strip_trailopt () \ { \ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ }; \ for flg in $$sane_makeflags; do \ test $$skip_next = yes && { skip_next=no; continue; }; \ case $$flg in \ *=*|--*) continue;; \ -*I) strip_trailopt 'I'; skip_next=yes;; \ -*I?*) strip_trailopt 'I';; \ -*O) strip_trailopt 'O'; skip_next=yes;; \ -*O?*) strip_trailopt 'O';; \ -*l) strip_trailopt 'l'; skip_next=yes;; \ -*l?*) strip_trailopt 'l';; \ -[dEDm]) skip_next=yes;; \ -[JT]) skip_next=yes;; \ esac; \ case $$flg in \ *$$target_option*) has_opt=yes; break;; \ esac; \ done; \ test $$has_opt = yes am__make_dryrun = (target_option=n; $(am__make_running_with_option)) am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkglibexecdir = $(libexecdir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ target_triplet = @target@ subdir = conf ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/m4/ax_c___attribute__.m4 \ $(top_srcdir)/m4/ax_c_pragmas.m4 \ $(top_srcdir)/m4/ax_check_compile_flag.m4 \ $(top_srcdir)/m4/ax_compare_version.m4 \ $(top_srcdir)/m4/ax_realpath.m4 \ $(top_srcdir)/m4/ax_run_or_link_ifelse.m4 \ $(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \ $(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \ $(top_srcdir)/m4/lt~obsolete.m4 \ $(top_srcdir)/m4/nut_arg_with.m4 \ $(top_srcdir)/m4/nut_check_asciidoc.m4 \ $(top_srcdir)/m4/nut_check_aspell.m4 \ $(top_srcdir)/m4/nut_check_cppcheck.m4 \ $(top_srcdir)/m4/nut_check_headers_windows.m4 \ $(top_srcdir)/m4/nut_check_libavahi.m4 \ $(top_srcdir)/m4/nut_check_libfreeipmi.m4 \ $(top_srcdir)/m4/nut_check_libgd.m4 \ $(top_srcdir)/m4/nut_check_libgpiod.m4 \ $(top_srcdir)/m4/nut_check_libltdl.m4 \ $(top_srcdir)/m4/nut_check_libmodbus.m4 \ $(top_srcdir)/m4/nut_check_libneon.m4 \ $(top_srcdir)/m4/nut_check_libnetsnmp.m4 \ $(top_srcdir)/m4/nut_check_libnss.m4 \ $(top_srcdir)/m4/nut_check_libopenssl.m4 \ $(top_srcdir)/m4/nut_check_libpowerman.m4 \ $(top_srcdir)/m4/nut_check_libregex.m4 \ $(top_srcdir)/m4/nut_check_libsystemd.m4 \ $(top_srcdir)/m4/nut_check_libusb.m4 \ $(top_srcdir)/m4/nut_check_libwrap.m4 \ $(top_srcdir)/m4/nut_check_os.m4 \ $(top_srcdir)/m4/nut_check_pkgconfig.m4 \ $(top_srcdir)/m4/nut_check_python.m4 \ $(top_srcdir)/m4/nut_check_socketlib.m4 \ $(top_srcdir)/m4/nut_compiler_family.m4 \ $(top_srcdir)/m4/nut_func_getnameinfo_argtypes.m4 \ $(top_srcdir)/m4/nut_report_feature.m4 \ $(top_srcdir)/m4/nut_stash_warnings.m4 \ $(top_srcdir)/m4/nut_type_socklen_t.m4 \ $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) DIST_COMMON = $(srcdir)/Makefile.am $(am__dist_sysconf_DATA_DIST) \ $(am__DIST_COMMON) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/include/config.h CONFIG_CLEAN_FILES = upsmon.conf.sample upssched.conf.sample CONFIG_CLEAN_VPATH_FILES = AM_V_P = $(am__v_P_@AM_V@) am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) am__v_P_0 = false am__v_P_1 = : AM_V_GEN = $(am__v_GEN_@AM_V@) am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) am__v_GEN_0 = @echo " GEN " $@; am__v_GEN_1 = AM_V_at = $(am__v_at_@AM_V@) am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) am__v_at_0 = @ am__v_at_1 = SOURCES = DIST_SOURCES = am__can_run_installinfo = \ case $$AM_UPDATE_INFO_DIR in \ n|no|NO) false;; \ *) (install-info --version) >/dev/null 2>&1;; \ esac am__dist_sysconf_DATA_DIST = upsd.conf.sample upsd.users.sample \ nut.conf.sample ups.conf.sample hosts.conf.sample \ upsset.conf.sample upsstats.html.sample \ upsstats-single.html.sample am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; am__vpath_adj = case $$p in \ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ *) f=$$p;; \ esac; am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`; am__install_max = 40 am__nobase_strip_setup = \ srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'` am__nobase_strip = \ for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||" am__nobase_list = $(am__nobase_strip_setup); \ for p in $$list; do echo "$$p $$p"; done | \ sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \ $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \ if (++n[$$2] == $(am__install_max)) \ { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \ END { for (dir in files) print dir, files[dir] }' am__base_list = \ sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' am__uninstall_files_from_dir = { \ test -z "$$files" \ || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \ || { echo " ( cd '$$dir' && rm -f" $$files ")"; \ $(am__cd) "$$dir" && rm -f $$files; }; \ } am__installdirs = "$(DESTDIR)$(sysconfdir)" "$(DESTDIR)$(sysconfdir)" DATA = $(dist_sysconf_DATA) $(nodist_sysconf_DATA) am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) am__DIST_COMMON = $(srcdir)/Makefile.in \ $(srcdir)/upsmon.conf.sample.in \ $(srcdir)/upssched.conf.sample.in DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) A2X = @A2X@ ACLOCAL = @ACLOCAL@ ALTPIDPATH = @ALTPIDPATH@ AMTAR = @AMTAR@ AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ AR = @AR@ ASCIIDOC = @ASCIIDOC@ ASPELL = @ASPELL@ ASPELL_FILTER_LIB_PATH = @ASPELL_FILTER_LIB_PATH@ ASPELL_FILTER_SHARE_PATH = @ASPELL_FILTER_SHARE_PATH@ ASPELL_FILTER_TEX_PATH = @ASPELL_FILTER_TEX_PATH@ AUGPARSE = @AUGPARSE@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ BINDIR = @BINDIR@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CONFIG_FLAGS = @CONFIG_FLAGS@ CONFPATH = @CONFPATH@ CPP = @CPP@ CPPCHECK = @CPPCHECK@ CPPFLAGS = @CPPFLAGS@ CPPUNIT_CFLAGS = @CPPUNIT_CFLAGS@ CPPUNIT_LIBS = @CPPUNIT_LIBS@ CSCOPE = @CSCOPE@ CTAGS = @CTAGS@ CXX = @CXX@ CXXCPP = @CXXCPP@ CXXDEPMODE = @CXXDEPMODE@ CXXFLAGS = @CXXFLAGS@ CYGPATH_W = @CYGPATH_W@ DBLATEX = @DBLATEX@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ DEPLOYED_UPSC = @DEPLOYED_UPSC@ DEPLOYED_UPSD = @DEPLOYED_UPSD@ DLLTOOL = @DLLTOOL@ DOC_BUILD_LIST = @DOC_BUILD_LIST@ DOC_CHECK_LIST = @DOC_CHECK_LIST@ DRIVER_BUILD_LIST = @DRIVER_BUILD_LIST@ DRIVER_INSTALL_TARGET = @DRIVER_INSTALL_TARGET@ DRIVER_MAN_LIST = @DRIVER_MAN_LIST@ DRIVER_MAN_LIST_PAGES = @DRIVER_MAN_LIST_PAGES@ DRVPATH = @DRVPATH@ DSYMUTIL = @DSYMUTIL@ DUMPBIN = @DUMPBIN@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ ETAGS = @ETAGS@ EXEEXT = @EXEEXT@ FGREP = @FGREP@ FORCE_NUT_VERSION = @FORCE_NUT_VERSION@ GDLIB_CONFIG = @GDLIB_CONFIG@ GREP = @GREP@ HAVE_SYS_SOCKET_H = @HAVE_SYS_SOCKET_H@ HAVE_WINSOCK2_H = @HAVE_WINSOCK2_H@ HAVE_WS2TCPIP_H = @HAVE_WS2TCPIP_H@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ LD = @LD@ LDFLAGS = @LDFLAGS@ LIBAVAHI_CFLAGS = @LIBAVAHI_CFLAGS@ LIBAVAHI_LIBS = @LIBAVAHI_LIBS@ LIBDIR = @LIBDIR@ LIBGD_CFLAGS = @LIBGD_CFLAGS@ LIBGD_LDFLAGS = @LIBGD_LDFLAGS@ LIBGPIO_CFLAGS = @LIBGPIO_CFLAGS@ LIBGPIO_LIBS = @LIBGPIO_LIBS@ LIBI2C_LIBS = @LIBI2C_LIBS@ LIBIPMI_CFLAGS = @LIBIPMI_CFLAGS@ LIBIPMI_LIBS = @LIBIPMI_LIBS@ LIBLTDL_CFLAGS = @LIBLTDL_CFLAGS@ LIBLTDL_LIBS = @LIBLTDL_LIBS@ LIBMODBUS_CFLAGS = @LIBMODBUS_CFLAGS@ LIBMODBUS_LIBS = @LIBMODBUS_LIBS@ LIBNEON_CFLAGS = @LIBNEON_CFLAGS@ LIBNEON_LIBS = @LIBNEON_LIBS@ LIBNETSNMP_CFLAGS = @LIBNETSNMP_CFLAGS@ LIBNETSNMP_LIBS = @LIBNETSNMP_LIBS@ LIBOBJS = @LIBOBJS@ LIBPOWERMAN_CFLAGS = @LIBPOWERMAN_CFLAGS@ LIBPOWERMAN_LIBS = @LIBPOWERMAN_LIBS@ LIBREGEX_LIBS = @LIBREGEX_LIBS@ LIBS = @LIBS@ LIBSSL_CFLAGS = @LIBSSL_CFLAGS@ LIBSSL_LIBS = @LIBSSL_LIBS@ LIBSSL_REQUIRES = @LIBSSL_REQUIRES@ LIBSYSTEMD_CFLAGS = @LIBSYSTEMD_CFLAGS@ LIBSYSTEMD_LIBS = @LIBSYSTEMD_LIBS@ LIBTOOL = @LIBTOOL@ LIBTOOL_DEPS = @LIBTOOL_DEPS@ LIBUSB_CFLAGS = @LIBUSB_CFLAGS@ LIBUSB_CONFIG = @LIBUSB_CONFIG@ LIBUSB_LIBS = @LIBUSB_LIBS@ LIBWRAP_CFLAGS = @LIBWRAP_CFLAGS@ LIBWRAP_LIBS = @LIBWRAP_LIBS@ LIPO = @LIPO@ LN_S = @LN_S@ LN_S_R = @LN_S_R@ LTLIBOBJS = @LTLIBOBJS@ LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@ MAINT = @MAINT@ MAKEINFO = @MAKEINFO@ MANIFEST_TOOL = @MANIFEST_TOOL@ MKDIR_P = @MKDIR_P@ MSGFMT = @MSGFMT@ NETLIBS = @NETLIBS@ NET_SNMP_CONFIG = @NET_SNMP_CONFIG@ NM = @NM@ NMEDIT = @NMEDIT@ NUT_DATADIR = @NUT_DATADIR@ NUT_LIBEXECDIR = @NUT_LIBEXECDIR@ NUT_NETVERSION = @NUT_NETVERSION@ NUT_SOURCE_GITREV = @NUT_SOURCE_GITREV@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ OS_NAME = @OS_NAME@ OTOOL = @OTOOL@ OTOOL64 = @OTOOL64@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_SEPARATOR = @PATH_SEPARATOR@ PIDPATH = @PIDPATH@ PKGCONFIGDIR = @PKGCONFIGDIR@ PKG_CONFIG = @PKG_CONFIG@ PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@ PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ PORT = @PORT@ POWERDOWNFLAG = @POWERDOWNFLAG@ PREFIX = @PREFIX@ PYTHON = @PYTHON@ PYTHON2 = @PYTHON2@ PYTHON2_SITE_PACKAGES = @PYTHON2_SITE_PACKAGES@ PYTHON3 = @PYTHON3@ PYTHON3_SITE_PACKAGES = @PYTHON3_SITE_PACKAGES@ PYTHON_SITE_PACKAGES = @PYTHON_SITE_PACKAGES@ RANLIB = @RANLIB@ REALPATH = @REALPATH@ RUN_AS_GROUP = @RUN_AS_GROUP@ RUN_AS_USER = @RUN_AS_USER@ SBINDIR = @SBINDIR@ SED = @SED@ SEMLIBS = @SEMLIBS@ SERLIBS = @SERLIBS@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ SOURCE_HIGHLIGHT = @SOURCE_HIGHLIGHT@ STATEPATH = @STATEPATH@ STRIP = @STRIP@ SUN_LIBUSB = @SUN_LIBUSB@ SYSTEMD_ANALYZE_PROGRAM = @SYSTEMD_ANALYZE_PROGRAM@ SYSTEMD_DAEMON_ARGS_DRIVER = @SYSTEMD_DAEMON_ARGS_DRIVER@ SYSTEMD_DAEMON_ARGS_UPSD = @SYSTEMD_DAEMON_ARGS_UPSD@ SYSTEMD_DAEMON_ARGS_UPSMON = @SYSTEMD_DAEMON_ARGS_UPSMON@ SYSTEMD_DAEMON_NOTIFYACCESS_DRIVER = @SYSTEMD_DAEMON_NOTIFYACCESS_DRIVER@ SYSTEMD_DAEMON_NOTIFYACCESS_UPSD = @SYSTEMD_DAEMON_NOTIFYACCESS_UPSD@ SYSTEMD_DAEMON_NOTIFYACCESS_UPSMON = @SYSTEMD_DAEMON_NOTIFYACCESS_UPSMON@ SYSTEMD_DAEMON_TYPE_DRIVER = @SYSTEMD_DAEMON_TYPE_DRIVER@ SYSTEMD_DAEMON_TYPE_UPSD = @SYSTEMD_DAEMON_TYPE_UPSD@ SYSTEMD_DAEMON_TYPE_UPSMON = @SYSTEMD_DAEMON_TYPE_UPSMON@ SYSTEMD_DAEMON_WATCHDOG_DRIVER = @SYSTEMD_DAEMON_WATCHDOG_DRIVER@ SYSTEMD_DAEMON_WATCHDOG_UPSD = @SYSTEMD_DAEMON_WATCHDOG_UPSD@ SYSTEMD_DAEMON_WATCHDOG_UPSMON = @SYSTEMD_DAEMON_WATCHDOG_UPSMON@ SYSTEMD_TMPFILES_PROGRAM = @SYSTEMD_TMPFILES_PROGRAM@ TREE_VERSION = @TREE_VERSION@ VALGRIND = @VALGRIND@ VERSION = @VERSION@ WINDMC = @WINDMC@ WINDRES = @WINDRES@ WORDS_BIGENDIAN = @WORDS_BIGENDIAN@ XMLLINT = @XMLLINT@ XSLTPROC = @XSLTPROC@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_AR = @ac_ct_AR@ ac_ct_CC = @ac_ct_CC@ ac_ct_CXX = @ac_ct_CXX@ ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__tar = @am__tar@ am__untar = @am__untar@ auglensdir = @auglensdir@ bindir = @bindir@ build = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ cgiexecdir = @cgiexecdir@ datadir = @datadir@ datarootdir = @datarootdir@ devddir = @devddir@ docdir = @docdir@ driverexecdir = @driverexecdir@ dummy_PKG_CONFIG = @dummy_PKG_CONFIG@ dummy_PKG_CONFIG_CFLAGS = @dummy_PKG_CONFIG_CFLAGS@ dummy_PKG_CONFIG_LIBS = @dummy_PKG_CONFIG_LIBS@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ hotplugdir = @hotplugdir@ htmldir = @htmldir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libdir = @libdir@ libexecdir = @libexecdir@ localedir = @localedir@ localstatedir = @localstatedir@ mandir = @mandir@ mkdir_p = @mkdir_p@ now = @now@ nut_with_nut_monitor = @nut_with_nut_monitor@ nut_with_nut_monitor_desktop = @nut_with_nut_monitor_desktop@ nut_with_nut_monitor_dir = @nut_with_nut_monitor_dir@ nut_with_nut_monitor_py2gtk2 = @nut_with_nut_monitor_py2gtk2@ nut_with_nut_monitor_py3qt5 = @nut_with_nut_monitor_py3qt5@ nut_with_pynut = @nut_with_pynut@ nut_with_pynut_py = @nut_with_pynut_py@ nut_with_pynut_py2 = @nut_with_pynut_py2@ nut_with_pynut_py3 = @nut_with_pynut_py3@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ pkgconfigdir = @pkgconfigdir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ runstatedir = @runstatedir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ sysconfdir = @sysconfdir@ systemdshutdowndir = @systemdshutdowndir@ systemdsystemunitdir = @systemdsystemunitdir@ systemdtmpfilesdir = @systemdtmpfilesdir@ target = @target@ target_alias = @target_alias@ target_cpu = @target_cpu@ target_os = @target_os@ target_vendor = @target_vendor@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ udevdir = @udevdir@ INSTALL_0600 = $(INSTALL) -m 0600 SECFILES = upsd.conf.sample upsd.users.sample PUBFILES = nut.conf.sample ups.conf.sample CGIPUB = hosts.conf.sample upsset.conf.sample upsstats.html.sample \ upsstats-single.html.sample @WITH_CGI_FALSE@CGI_INSTALL = @WITH_CGI_TRUE@CGI_INSTALL = $(CGIPUB) dist_sysconf_DATA = $(SECFILES) $(PUBFILES) $(CGI_INSTALL) nodist_sysconf_DATA = upssched.conf.sample upsmon.conf.sample SPELLCHECK_SRC = $(dist_sysconf_DATA) \ upssched.conf.sample.in upsmon.conf.sample.in MAINTAINERCLEANFILES = Makefile.in .dirstamp CLEANFILES = *.pdf *.html *-spellchecked all: all-am .SUFFIXES: .SUFFIXES: .in .in-spellchecked .sample .sample-spellchecked $(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu conf/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --gnu conf/Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): upsmon.conf.sample: $(top_builddir)/config.status $(srcdir)/upsmon.conf.sample.in cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ upssched.conf.sample: $(top_builddir)/config.status $(srcdir)/upssched.conf.sample.in cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ mostlyclean-libtool: -rm -f *.lo clean-libtool: -rm -rf .libs _libs install-dist_sysconfDATA: $(dist_sysconf_DATA) @$(NORMAL_INSTALL) @list='$(dist_sysconf_DATA)'; test -n "$(sysconfdir)" || list=; \ if test -n "$$list"; then \ echo " $(MKDIR_P) '$(DESTDIR)$(sysconfdir)'"; \ $(MKDIR_P) "$(DESTDIR)$(sysconfdir)" || exit 1; \ fi; \ for p in $$list; do \ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ echo "$$d$$p"; \ done | $(am__base_list) | \ while read files; do \ echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(sysconfdir)'"; \ $(INSTALL_DATA) $$files "$(DESTDIR)$(sysconfdir)" || exit $$?; \ done uninstall-dist_sysconfDATA: @$(NORMAL_UNINSTALL) @list='$(dist_sysconf_DATA)'; test -n "$(sysconfdir)" || list=; \ files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ dir='$(DESTDIR)$(sysconfdir)'; $(am__uninstall_files_from_dir) install-nodist_sysconfDATA: $(nodist_sysconf_DATA) @$(NORMAL_INSTALL) @list='$(nodist_sysconf_DATA)'; test -n "$(sysconfdir)" || list=; \ if test -n "$$list"; then \ echo " $(MKDIR_P) '$(DESTDIR)$(sysconfdir)'"; \ $(MKDIR_P) "$(DESTDIR)$(sysconfdir)" || exit 1; \ fi; \ for p in $$list; do \ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ echo "$$d$$p"; \ done | $(am__base_list) | \ while read files; do \ echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(sysconfdir)'"; \ $(INSTALL_DATA) $$files "$(DESTDIR)$(sysconfdir)" || exit $$?; \ done uninstall-nodist_sysconfDATA: @$(NORMAL_UNINSTALL) @list='$(nodist_sysconf_DATA)'; test -n "$(sysconfdir)" || list=; \ files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ dir='$(DESTDIR)$(sysconfdir)'; $(am__uninstall_files_from_dir) tags TAGS: ctags CTAGS: cscope cscopelist: distdir: $(BUILT_SOURCES) $(MAKE) $(AM_MAKEFLAGS) distdir-am distdir-am: $(DISTFILES) @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ dist_files=`for file in $$list; do echo $$file; done | \ sed -e "s|^$$srcdirstrip/||;t" \ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ case $$dist_files in \ */*) $(MKDIR_P) `echo "$$dist_files" | \ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ sort -u` ;; \ esac; \ for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d "$(distdir)/$$file"; then \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ else \ test -f "$(distdir)/$$file" \ || cp -p $$d/$$file "$(distdir)/$$file" \ || exit 1; \ fi; \ done check-am: all-am check: check-am all-am: Makefile $(DATA) installdirs: for dir in "$(DESTDIR)$(sysconfdir)" "$(DESTDIR)$(sysconfdir)"; do \ test -z "$$dir" || $(MKDIR_P) "$$dir"; \ done install: install-am install-exec: install-exec-am install-data: install-data-am uninstall: uninstall-am install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-am install-strip: if test -z '$(STRIP)'; then \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ install; \ else \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ fi mostlyclean-generic: clean-generic: -test -z "$(CLEANFILES)" || rm -f $(CLEANFILES) distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." -test -z "$(MAINTAINERCLEANFILES)" || rm -f $(MAINTAINERCLEANFILES) clean: clean-am clean-am: clean-generic clean-libtool mostlyclean-am distclean: distclean-am -rm -f Makefile distclean-am: clean-am distclean-generic dvi: dvi-am dvi-am: html: html-am html-am: info: info-am info-am: install-data-am: install-dvi: install-dvi-am install-dvi-am: install-exec-am: install-dist_sysconfDATA install-nodist_sysconfDATA install-html: install-html-am install-html-am: install-info: install-info-am install-info-am: install-man: install-pdf: install-pdf-am install-pdf-am: install-ps: install-ps-am install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-am -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-am mostlyclean-am: mostlyclean-generic mostlyclean-libtool pdf: pdf-am pdf-am: ps: ps-am ps-am: uninstall-am: uninstall-dist_sysconfDATA uninstall-nodist_sysconfDATA .MAKE: install-am install-strip .PHONY: all all-am check check-am clean clean-generic clean-libtool \ cscopelist-am ctags-am distclean distclean-generic \ distclean-libtool distdir dvi dvi-am html html-am info info-am \ install install-am install-data install-data-am \ install-dist_sysconfDATA install-dvi install-dvi-am \ install-exec install-exec-am install-html install-html-am \ install-info install-info-am install-man \ install-nodist_sysconfDATA install-pdf install-pdf-am \ install-ps install-ps-am install-strip installcheck \ installcheck-am installdirs maintainer-clean \ maintainer-clean-generic mostlyclean mostlyclean-generic \ mostlyclean-libtool pdf pdf-am ps ps-am tags-am uninstall \ uninstall-am uninstall-dist_sysconfDATA \ uninstall-nodist_sysconfDATA .PRECIOUS: Makefile # NOTE: Due to portability, we do not use a GNU percent-wildcard extension: #%-spellchecked: % Makefile.am $(top_srcdir)/docs/Makefile.am $(abs_srcdir)/$(NUT_SPELL_DICT) # $(MAKE) -s -f $(top_builddir)/docs/Makefile SPELLCHECK_SRC_ONE="$<" SPELLCHECK_SRCDIR="$(srcdir)" SPELLCHECK_BUILDDIR="$(builddir)" $@ # NOTE: Portable suffix rules do not allow prerequisites, so we shim them here # by a wildcard target in case the make implementation can put the two together. *-spellchecked: Makefile.am $(top_srcdir)/docs/Makefile.am $(abs_srcdir)/$(NUT_SPELL_DICT) .sample.sample-spellchecked: $(MAKE) -s -f $(top_builddir)/docs/Makefile SPELLCHECK_SRC_ONE="$<" SPELLCHECK_SRCDIR="$(srcdir)" SPELLCHECK_BUILDDIR="$(builddir)" $@ .in.in-spellchecked: $(MAKE) -s -f $(top_builddir)/docs/Makefile SPELLCHECK_SRC_ONE="$<" SPELLCHECK_SRCDIR="$(srcdir)" SPELLCHECK_BUILDDIR="$(builddir)" $@ spellcheck spellcheck-interactive spellcheck-sortdict: $(MAKE) -f $(top_builddir)/docs/Makefile SPELLCHECK_SRC="$(SPELLCHECK_SRC)" SPELLCHECK_SRCDIR="$(srcdir)" SPELLCHECK_BUILDDIR="$(builddir)" $@ # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: nut-2.8.1/conf/upsd.users.sample0000644000175000017500000000445514501607135013526 00000000000000# Network UPS Tools: Example upsd.users # # This file sets the permissions for upsd - the UPS network daemon. # Users are defined here, are given passwords, and their privileges are # controlled here too. Since this file will contain passwords, keep it # secure, with only enough permissions for upsd to read it. # -------------------------------------------------------------------------- # Each user gets a section. To start a section, put the username in # brackets on a line by itself. To set something for that user, specify # it under that section heading. The username is case-sensitive, so # admin and AdMiN are two different users. # # Possible settings: # # password: The user's password. This is case-sensitive. # # -------------------------------------------------------------------------- # # actions: Let the user do certain things with upsd. # # Valid actions are: # # SET - change the value of certain variables in the UPS # FSD - set the "forced shutdown" flag in the UPS # # -------------------------------------------------------------------------- # # instcmds: Let the user initiate specific instant commands. Use "ALL" # to grant all commands automatically. There are many possible # commands, so use 'upscmd -l' to see what your hardware supports. Here # are a few examples: # # test.panel.start - Start a front panel test # test.battery.start - Start battery test # test.battery.stop - Stop battery test # calibrate.start - Start calibration # calibrate.stop - Stop calibration # # -------------------------------------------------------------------------- # # Example: # # [admin] # password = mypass # actions = SET # instcmds = ALL # # # --- Configuring for a user who can execute tests only # # [testuser] # password = pass # instcmds = test.battery.start # instcmds = test.battery.stop # # --- Configuring for upsmon # # To add a NUT user for your upsmon, with a particular role, use this example: # # [monuser] # password = pass # upsmon primary # or # upsmon secondary # # The matching MONITOR line in your upsmon.conf would look like this: # # MONITOR myups@localhost 1 monuser pass primary (or secondary) # # See comments in the upsmon.conf(.sample) file for details about this # keyword and the difference of NUT secondary and primary systems. nut-2.8.1/conf/upsstats.html.sample0000644000175000017500000001000014377374134014236 00000000000000 @TEMPC@ @UPSSTATSPATH upsstats.cgi@ @UPSIMAGEPATH upsimage.cgi@ @REFRESH@ Network UPS Tools upsstats @VERSION@ : UPS Status @REFRESH@
@FOREACHUPS@ @IFSUPP input.L2-L3.voltage@ @IFBETWEEN input.transfer.low input.transfer.high input.L1-L2.voltage@ @IFBETWEEN input.transfer.low input.transfer.high input.L2-L3.voltage@ @IFBETWEEN input.transfer.low input.transfer.high input.L3-L1.voltage@ @ENDFOR@
Network UPS Tools upsstats @VERSION@
@DATE %a %b %d %X %Z %Y@
System Model Status Battery Input (VAC) Output (VAC) Load (%) UPS
Temp
Battery
Runtime
Data
Tree
@HOSTLINK@ @VAR ups.model@ @STATUS@ @IFSUPP battery.charge@ @VAR battery.charge@ % @ENDIF@ @ELSE@ @IFSUPP input.L2-N.voltage@ @IFBETWEEN input.transfer.low input.transfer.high input.L1-N.voltage@ @IFBETWEEN input.transfer.low input.transfer.high input.L2-N.voltage@ @IFBETWEEN input.transfer.low input.transfer.high input.L3-N.voltage@ @ELSE@ @IFBETWEEN input.transfer.low input.transfer.high input.voltage@ @ELSE@ @ENDIF@ @IFSUPP input.L2-L3.voltage@ @VAR input.L1-L2.voltage@ @VAR input.L2-L3.voltage@ @VAR input.L3-L1.voltage@ @ELSE@ @IFSUPP input.L2-N.voltage@ @VAR input.L1-N.voltage@ @VAR input.L2-N.voltage@ @VAR input.L3-N.voltage@ @ELSE@ @IFSUPP input.voltage@ @VAR input.voltage@ @ENDIF@ @IFSUPP output.L2-L3.voltage@ @VAR output.L1-L2.voltage@ @VAR output.L2-L3.voltage@ @VAR output.L3-L1.voltage@ @ELSE@ @IFSUPP output.L2-N.voltage@ @VAR output.L1-N.voltage@ @VAR output.L2-N.voltage@ @VAR output.L3-N.voltage@ @ELSE@ @IFSUPP output.voltage@ @VAR output.voltage@ @ENDIF@ @IFSUPP output.L2.power.percent@ @VAR output.L1.power.percent@ @VAR output.L2.power.percent@ @VAR output.L3.power.percent@ @ELSE@ @IFSUPP output.L2.realpower.percent@ @VAR output.L1.realpower.percent@ @VAR output.L2.realpower.percent@ @VAR output.L3.realpower.percent@ @ELSE@ @IFSUPP ups.load@ @VAR ups.load@ % @ENDIF@ @IFSUPP ups.temperature@ @UPSTEMP@ @DEGREES@ @ELSE@ @IFSUPP battery.temperature@ @BATTTEMP@ @DEGREES@ @ENDIF@ @IFSUPP battery.runtime@ @RUNTIME@ @ENDIF@ @TREELINK@

Valid CSS! Valid HTML 4.01 Strict
nut-2.8.1/conf/Makefile.am0000644000175000017500000000324014502413024012224 00000000000000# Network UPS Tools: conf INSTALL_0600 = $(INSTALL) -m 0600 SECFILES = upsd.conf.sample upsd.users.sample PUBFILES = nut.conf.sample ups.conf.sample CGIPUB = hosts.conf.sample upsset.conf.sample upsstats.html.sample \ upsstats-single.html.sample if WITH_CGI CGI_INSTALL = $(CGIPUB) else CGI_INSTALL = endif dist_sysconf_DATA = $(SECFILES) $(PUBFILES) $(CGI_INSTALL) nodist_sysconf_DATA = upssched.conf.sample upsmon.conf.sample SPELLCHECK_SRC = $(dist_sysconf_DATA) \ upssched.conf.sample.in upsmon.conf.sample.in # NOTE: Due to portability, we do not use a GNU percent-wildcard extension: #%-spellchecked: % Makefile.am $(top_srcdir)/docs/Makefile.am $(abs_srcdir)/$(NUT_SPELL_DICT) # $(MAKE) -s -f $(top_builddir)/docs/Makefile SPELLCHECK_SRC_ONE="$<" SPELLCHECK_SRCDIR="$(srcdir)" SPELLCHECK_BUILDDIR="$(builddir)" $@ # NOTE: Portable suffix rules do not allow prerequisites, so we shim them here # by a wildcard target in case the make implementation can put the two together. *-spellchecked: Makefile.am $(top_srcdir)/docs/Makefile.am $(abs_srcdir)/$(NUT_SPELL_DICT) .sample.sample-spellchecked: $(MAKE) -s -f $(top_builddir)/docs/Makefile SPELLCHECK_SRC_ONE="$<" SPELLCHECK_SRCDIR="$(srcdir)" SPELLCHECK_BUILDDIR="$(builddir)" $@ .in.in-spellchecked: $(MAKE) -s -f $(top_builddir)/docs/Makefile SPELLCHECK_SRC_ONE="$<" SPELLCHECK_SRCDIR="$(srcdir)" SPELLCHECK_BUILDDIR="$(builddir)" $@ spellcheck spellcheck-interactive spellcheck-sortdict: $(MAKE) -f $(top_builddir)/docs/Makefile SPELLCHECK_SRC="$(SPELLCHECK_SRC)" SPELLCHECK_SRCDIR="$(srcdir)" SPELLCHECK_BUILDDIR="$(builddir)" $@ MAINTAINERCLEANFILES = Makefile.in .dirstamp CLEANFILES = *.pdf *.html *-spellchecked nut-2.8.1/conf/upssched.conf.sample.in0000644000175000017500000001016314377374134014566 00000000000000# Network UPS Tools - upssched.conf sample file # # ============================================================================ # # CMDSCRIPT # # This script gets called to invoke commands for timers that trigger. # It is given a single argument - the in your # AT ... START-TIMER defines. # # *** This must be defined *before* the first AT line. Otherwise the # program will complain and exit without doing anything. # # A shell script with a big case..esac construct should work nicely for this. # An example has been provided to help you get started. CMDSCRIPT @BINDIR@/upssched-cmd # ============================================================================ # # PIPEFN # # This sets the file name of the FIFO that will pass communications between # processes to start and stop timers. This should be set to some path where # normal users can't create the file, due to the possibility of symlinking # and other evil. # # Note: if you are running Solaris or similar, the permissions that # upssched sets on this file *are not enough* to keep you safe. If # your OS ignores the permissions on a FIFO, then you MUST put this in # a protected directory! # # Note 2: by default, upsmon will run upssched as whatever user you have # defined with RUN_AS_USER in upsmon.conf. Make sure that user can # create files and write to files in the path you use for PIPEFN and # LOCKFN. # # My recommendation: create a special directory for upssched, make it # owned by your upsmon user, then use it for both. # # This is commented out by default to make you visit this file and think # about how your system works before potentially opening a hole. # # PIPEFN @STATEPATH@/upssched/upssched.pipe # ============================================================================ # # LOCKFN # # REQUIRED. This was added after version 1.2.1. # # upssched needs to be able to create this filename in order to avoid # a race condition when two events are dispatched from upsmon at nearly # the same time. This file will only exist briefly. It must not be # created by any other process. # # You should put this in the same directory as PIPEFN. # # LOCKFN @STATEPATH@/upssched/upssched.lock # ============================================================================ # # AT # # Define a handler for a specific event on UPS . # # can be the special value * to apply this handler to every # possible value of . # # Run the command via your CMDSCRIPT when it happens. # # Note that any AT that matches both the and the # for the current event will be used. # ============================================================================ # # Possible AT commands # # - START-TIMER # # Start a timer called that will trigger after # seconds, calling your CMDSCRIPT with as the first # argument. # # Example: # 1) Start a timer that will execute when communication with any UPS (*) has # been gone for 10 seconds # # AT COMMBAD * START-TIMER upsgone 10 # # 2) Start a timer that will execute when any UPS (*) has been running # on battery for 30 seconds # # AT ONBATT * START-TIMER onbattwarn 30 # ----------------------------------------------------------------------- # # - CANCEL-TIMER [cmd] # # Cancel a running timer called , if possible. If the timer # has passed then pass the optional argument to CMDSCRIPT. # # Example: # 1) If a specific UPS (myups@localhost) communication is restored, then stop # the timer before it triggers # # AT COMMOK myups@localhost CANCEL-TIMER upsgone # # 2) If any UPS (*) reverts to utility power, then stop the timer before it # triggers # # AT ONLINE * CANCEL-TIMER onbattwarn # ----------------------------------------------------------------------- # # - EXECUTE # # Immediately pass as an argument to CMDSCRIPT. # # Example: # If any UPS (*) reverts to utility power, then execute # 'ups-back-on-line' via CMDSCRIPT. # # AT ONLINE * EXECUTE ups-back-on-line nut-2.8.1/conf/upsmon.conf.sample.in0000644000175000017500000005745114517277302014277 00000000000000# Network UPS Tools: example upsmon configuration # # This file contains passwords, so keep it secure. # -------------------------------------------------------------------------- # RUN_AS_USER # # By default, upsmon splits into two processes. One stays as root and # waits to run the SHUTDOWNCMD. The other one switches to another userid # and does everything else. # # The default unprivileged user is set at compile-time with the option # 'configure --with-user=...' # # You can override it with '-u ' when starting upsmon, or just # define it here for convenience. # # Note: if you plan to use the reload feature, this file (upsmon.conf) # must be readable by this user! Since it contains passwords, DO NOT # make it world-readable. Also, do not make it writable by the upsmon # user, since it creates an opportunity for an attack by changing the # SHUTDOWNCMD to something malicious. # # For best results, you should create a new normal user like "nutmon", # and make it a member of a "nut" group or similar. Then specify it # here and grant read access to the upsmon.conf for that group. # # This user should not have write access to upsmon.conf. # # (Unprivileged) OS account to run as: # RUN_AS_USER @RUN_AS_USER@ # -------------------------------------------------------------------------- # MONITOR ("primary"|"secondary") # # List systems you want to monitor. Not all of these may supply power # to the system running upsmon, but if you want to watch it, it has to # be in this section. # # You must have at least one of these declared. # # is a UPS identifier in the form @[:] # like ups@localhost, su700@mybox, etc. # # Examples: # # - "su700@mybox" means a UPS called "su700" on a system called "mybox" # # - "fenton@bigbox:5678" is a UPS called "fenton" on a system called # "bigbox" which runs upsd on port "5678". # # The UPS names like "su700" and "fenton" are set in your ups.conf # in [brackets] which identify a section for a particular driver. # # If the ups.conf on host "doghouse" has a section called "snoopy", the # identifier for it would be "snoopy@doghouse". # # is an integer - the number of power supplies that this UPS # feeds on this system. Most personal computers only have one power supply, # so this value is normally set to 1, while most modern servers have at least # two. You need a pretty big or special box to have any other value here. # # You can also set this to 0 for a system that doesn't take any power # from the MONITORed supply, which you still want to monitor (e.g. for an # administrative workstation fed from a different circuit than the datacenter # servers it monitors). Use if 0 when you want to hear about # changes for a given UPS without shutting down when it goes critical. # # and must match an entry in that system's # upsd.users. If your NUT username is "monuser" and your password is # "blah", the upsd.users would look like this: # # [monuser] # password = blah # upsmon primary # (or secondary) # # "primary" means this system will shutdown last, allowing the secondary # systems time to shutdown first. # # "secondary" means this system shuts down immediately when power goes # critical and less than MINSUPPLIES power sources have reliable input feeds. # # The general assumption is that the "primary" system is the one with direct # connection to an UPS (such as serial or USB cable), so the primary system # runs the NUT driver and 'upsd' server locally and can manage the device, # and it would often tell the UPS to completely power itself off as a step # in power-race avoidance (see POWERDOWNFLAG for details). # # Also, since the primary system stays up the longest, it suffers higher risks # of ungraceful shutdown if the estimation of remaining runtime (or of the # time it takes to shut down this system) was guessed wrong. By consequence, # the "secondary" systems typically monitor the power environment state # through the 'upsd' processes running on the remote (often "primary") systems # and do not directly interact with an UPS (no local NUT drivers are running # on the secondary systems). As such, secondaries typically shut down as # soon as there is a sufficiently long power outage, or a low-battery alert # from the UPS, or a loss of connection to the primary while the power was # last known to be missing. # # This assumption and configuration can also make sense for networked UPSes, # where a rack full of servers might overload the communications capacity # of the networked management card on the UPS - in this case you might either # reduce the 'snmp-ups' or 'netxml-ups' driver polling rate, or dedicate a # "primary" server and set up the rest as "secondary" systems. # # In case of such large setups as mentioned above, beware also that shutdown # times of the rack done all at once can substantially differ from smaller # scale experiments with single-server shutdowns, since systems can compete # for shared storage and other limited resources as they go down (and also # not everyone may safely shut down simultaneously - e.g. a NAS or DB server # would better go down after all its clients). You would be well served by # higher-end UPSes with manageable thresholds to declare a critical state. # # Examples: # # MONITOR myups@bigserver 1 upswired blah primary # MONITOR su700@server.example.com 1 monuser secretpass secondary # MONITOR myups@localhost 1 monuser pass primary # (or secondary) # -------------------------------------------------------------------------- # MINSUPPLIES # # Give the number of power supplies that must be receiving power to keep # this system running. Most systems have one power supply, so you would # put "1" in this field. # # Large/expensive server type systems usually have more, and can run with # a few missing. Some of these can run with 2 out of 4, for example, # so you'd set that to 2. The idea is to keep the box running as long # as possible, right? # # Obviously you have to put the redundant supplies on different UPS circuits # for this to make sense! See big-servers.txt in the docs subdirectory # for more information and ideas on how to use this feature. MINSUPPLIES 1 # -------------------------------------------------------------------------- # SHUTDOWNCMD "" # # upsmon runs this command when the system needs to be brought down. # # This should work just about everywhere ... if it doesn't, well, change it, # perhaps to a more complicated custom script. # # Note that while you experiment with the initial setup and want to test how # your configuration reacts to power state changes and ultimately when power # is reported to go critical, but do not want your system to actually turn # off, consider setting the SHUTDOWNCMD temporarily to do something benign - # such as posting a message with 'logger' or 'wall' or 'mailx'. Do be careful # to plug the UPS back into the wall in a timely fashion. # # For Windows setup use something like: # SHUTDOWNCMD "C:\\WINDOWS\\system32\\shutdown.exe -s -t 0" # If you have command line using space character you have to add double quote to them, like this: # SHUTDOWNCMD "\"C:\\Program Files\\some command.bat\" -first_arg -second_arg" # Or use the old DOS 8.3 file name, like this: # SHUTDOWNCMD "C:\\PROGRA~1\\SOMECO~1.bat -first_arg -second_arg" SHUTDOWNCMD "/sbin/shutdown -h +0" # -------------------------------------------------------------------------- # SHUTDOWNEXIT # # After initiating shutdown, should this upsmon daemon itself exit? # By doing so NUT secondary systems can tell the NUT primary that # it can proceed with its own shutdown and eventually tell the UPS # to cut power for the load. ("Yes" by default) # # Some "secondary" systems with workloads that take considerable time # to stop (e.g. virtual machines or large databases) can benefit from # reporting (by virtue of logging off the data server) that they are # ready for the "primary" system to begin its own shutdown and eventually # to tell the UPS to cut the power - not as soon as they have triggered # their own shutdown, but at a later point (e.g. when the upsmon service # is stopped AFTER the heavier workloads). # # Note that the actual ability to complete such shutdown depends on the # remaining battery run-time at the moment when UPS power state becomes # considered critical and the shutdowns begin. You may also have to tune # HOSTSYNC on the NUT primary to be long enough for those secondaries to # stop their services. In practice, it may be worthwhile to investigate # ways to trigger shutdowns earlier on these systems, e.g. by setting up # `upssched` integration, or `dummy-ups` driver with overrides for stricter # `battery.charge` or `battery.runtime` triggers than used by the rest of # your servers. # # This option supports Boolean-style strings (yes/on/true or no/off/false) # or numbers to define a delay (in seconds) between calling SHUTDOWNCMD # and exiting the daemon. Zero means immediate exit (default), negative # values mean never exiting on its own accord. # #SHUTDOWNEXIT yes # -------------------------------------------------------------------------- # NOTIFYCMD # # upsmon calls this to send messages when things happen # # This command is called with the full text of the message (from NOTIFYMSG) # as one argument. # # The environment string NOTIFYTYPE will contain the type string of # whatever caused this event to happen. # # The environment string UPSNAME will contain the name of the system/device # that generated the change. # # Note that this is only called for NOTIFY events that have EXEC set with # NOTIFYFLAG. See NOTIFYFLAG below for more details. # # Making this some sort of shell script might not be a bad idea. # Alternately you can use the upssched program as your NOTIFYCMD for some # more complex setups (e.g. to ease handling of notification storms). # For more information and ideas, see docs/scheduling.txt # # Example: # NOTIFYCMD @BINDIR@/notifyme # -------------------------------------------------------------------------- # POLLFREQ # # Polling frequency for normal activities, measured in seconds. # # Adjust this to keep upsmon from flooding your network, but don't make # it too high or it may miss certain short-lived power events. POLLFREQ 5 # -------------------------------------------------------------------------- # POLLFREQALERT # # Polling frequency in seconds while UPS on battery. # # You can make this number lower than POLLFREQ, which will make updates # faster when any UPS is running on battery. This is a good way to tune # network load if you have a lot of these things running. # # The default is 5 seconds for both this and POLLFREQ. POLLFREQALERT 5 # -------------------------------------------------------------------------- # HOSTSYNC - How long upsmon will wait before giving up on another upsmon # # The primary upsmon process uses this number when waiting for secondary # systems to disconnect once it has set the forced shutdown (FSD) flag. # If they don't disconnect after this many seconds, it goes on without them. # # Similarly, upsmon secondary processes wait up to this interval for the # primary upsmon to set FSD when an UPS they are monitoring goes critical - # that is, on battery and low battery. If the primary doesn't do its job, # the secondaries will shut down anyway to avoid damage to the file systems. # # This "wait for FSD" is done to avoid races where the status changes # to critical and back between polls by the primary. HOSTSYNC 15 # -------------------------------------------------------------------------- # DEADTIME - Interval to wait before declaring a stale ups "dead" # # upsmon requires a UPS to provide status information every few seconds # (see POLLFREQ and POLLFREQALERT) to keep things updated. If the status # fetch fails, the UPS is marked stale. If it stays stale for more than # DEADTIME seconds, the UPS is marked dead. # # A dead UPS that was last known to be on battery is assumed to have gone # to a low battery condition. This may force a shutdown if it is providing # a critical amount of power to your system. # # Note: DEADTIME should be a multiple of POLLFREQ and POLLFREQALERT. # Otherwise you'll have "dead" UPSes simply because upsmon isn't polling # them quickly enough. Rule of thumb: take the larger of the two # POLLFREQ values, and multiply by 3. DEADTIME 15 # -------------------------------------------------------------------------- # POWERDOWNFLAG - Flag file for forcing UPS shutdown on the primary system # # upsmon will create a file with this name in primary mode when it's time # to shut down the load. You should check for this file's existence in # your shutdown scripts and run 'upsdrvctl shutdown' if it exists, to tell # the UPS(es) to power off. # # See the config-notes.txt file in the docs subdirectory for more information. # Refer to the section: # [[UPS_shutdown]] "Configuring automatic shutdowns for low battery events" # or refer to the online version. # # For Windows setup use something like: # POWERDOWNFLAG "C:\\killpower" # # For Unix/Linux systems the legacy default is: # POWERDOWNFLAG /etc/killpower POWERDOWNFLAG "@POWERDOWNFLAG@" # -------------------------------------------------------------------------- # NOTIFYMSG - change messages sent by upsmon when certain events occur # # You can change the default messages to something else if you like. # # NOTIFYMSG "message" # # NOTIFYMSG ONLINE "UPS %s on line power" # NOTIFYMSG ONBATT "UPS %s on battery" # NOTIFYMSG LOWBATT "UPS %s battery is low" # NOTIFYMSG FSD "UPS %s: forced shutdown in progress" # NOTIFYMSG COMMOK "Communications with UPS %s established" # NOTIFYMSG COMMBAD "Communications with UPS %s lost" # NOTIFYMSG SHUTDOWN "Auto logout and shutdown proceeding" # NOTIFYMSG REPLBATT "UPS %s battery needs to be replaced" # NOTIFYMSG NOCOMM "UPS %s is unavailable" # NOTIFYMSG NOPARENT "upsmon parent process died - shutdown impossible" # NOTIFYMSG CAL "UPS %s: calibration in progress" # NOTIFYMSG OFF "UPS %s: administratively OFF or asleep" # NOTIFYMSG NOTOFF "UPS %s: no longer administratively OFF or asleep" # NOTIFYMSG BYPASS "UPS %s: on bypass (powered, not protecting)" # NOTIFYMSG NOTBYPASS "UPS %s: no longer on bypass" # # Note that %s is replaced with the identifier of the UPS in question. # # Possible values for : # # ONLINE : UPS is back online # ONBATT : UPS is on battery # LOWBATT : UPS has a low battery (if also on battery, it's "critical") # FSD : UPS is being shutdown by the primary (FSD = "Forced Shutdown") # COMMOK : Communications established with the UPS # COMMBAD : Communications lost to the UPS # SHUTDOWN : The system is being shutdown # REPLBATT : The UPS battery is bad and needs to be replaced # NOCOMM : A UPS is unavailable (can't be contacted for monitoring) # NOPARENT : The process that shuts down the system has died (shutdown impossible) # -------------------------------------------------------------------------- # NOTIFYFLAG - change behavior of upsmon when NOTIFY events occur # # By default, upsmon sends walls (global messages to all logged in users) # and writes to the syslog when things happen. # Except for Windows where upsmon only writes to the syslog by default. # You can change this. # # NOTIFYFLAG [+][+] ... # # NOTIFYFLAG ONLINE SYSLOG+WALL # NOTIFYFLAG ONBATT SYSLOG+WALL # NOTIFYFLAG LOWBATT SYSLOG+WALL # NOTIFYFLAG FSD SYSLOG+WALL # NOTIFYFLAG COMMOK SYSLOG+WALL # NOTIFYFLAG COMMBAD SYSLOG+WALL # NOTIFYFLAG SHUTDOWN SYSLOG+WALL # NOTIFYFLAG REPLBATT SYSLOG+WALL # NOTIFYFLAG NOCOMM SYSLOG+WALL # NOTIFYFLAG NOPARENT SYSLOG+WALL # # Possible values for the flags: # # SYSLOG - Write the message in the syslog # WALL - Write the message to all users on the system # EXEC - Execute NOTIFYCMD (see above) with the message # IGNORE - Don't do anything # # If you use IGNORE, don't use any other flags on the same line. # -------------------------------------------------------------------------- # OFFDURATION - put "OFF" state into effect if it persists for this many seconds # # NUT supports an "administrative OFF" for power devices which can be managed to # turn off their application workload, while the UPS or ePDU remains accessible # for monitoring and management. This toggle allows to delay propagation of such # state into a known loss of a feed (possibly triggering FSD on `upsmon` clients # which `MONITOR` the device and are in fact still alive -- e.g. with multiple # power sources or because they as the load are not really turned off), because # when some devices begin battery calibration, they report "OFF" for a few seconds # and only then they might report "CAL" after switching all the power relays -- # thus causing false-positives for `upsmon` FSD trigger. # # A negative value means to disable decreasing the counter of working power # supplies in such cases, and a zero makes the effect of detected "OFF" state # immediate. Built-in default value is 30 (seconds). OFFDURATION 30 # -------------------------------------------------------------------------- # RBWARNTIME - replace battery warning time in seconds # # upsmon will normally warn you about a battery that needs to be replaced # every 43200 seconds, which is 12 hours. It does this by triggering a # NOTIFY_REPLBATT which is then handled by the usual notify structure # you've defined above. # # If this number is not to your liking, override it here. RBWARNTIME 43200 # -------------------------------------------------------------------------- # NOCOMMWARNTIME - no communications warning time in seconds # # upsmon will let you know through the usual notify system if it can't # talk to any of the UPS entries that are defined in this file. It will # trigger a NOTIFY_NOCOMM by default every 300 seconds unless you # change the interval with this directive. NOCOMMWARNTIME 300 # -------------------------------------------------------------------------- # POLLFAIL_LOG_THROTTLE_MAX - device poll failure logging throttle # # upsmon normally reports polling failures for each device that are in place # for each POLLFREQ loop (e.g. "Data stale" or "Driver not connected") to # system log as configured. If your devices are expected to be AWOL for an # extended timeframe, you can use this throttle to reduce the stress on # syslog traffic and storage, by posting these messages only once in every # several loop cycles, and when the error condition has changed or cleared. # A negative value means standard behavior, and a zero value means to never # repeat the message (log only on start and end/change of the failure state). # #POLLFAIL_LOG_THROTTLE_MAX 100 # -------------------------------------------------------------------------- # FINALDELAY - last sleep interval before shutting down the system # # On a primary, upsmon will wait this long after sending the NOTIFY_SHUTDOWN # before executing your SHUTDOWNCMD. If you need to do something in between # those events, increase this number. Remember, at this point your UPS is # almost depleted, so don't make this too high. If needed, on high-end UPS # devices you can usually configure when the low-battery state is announced # based on estimated remaining run-time or on charge level of the batteries. # # Alternatively, you can set this very low so you don't wait around when # it's time to shut down. Some UPSes don't give much warning for low # battery and will require a value of 0 here for a safe shutdown. # # Note: If FINALDELAY on the secondary is greater than HOSTSYNC on the # primary, the primary will give up waiting for that secondary system # to disconnect. FINALDELAY 5 # -------------------------------------------------------------------------- # CERTPATH - path to certificates (database directory or directory with CA's) # # When compiled with SSL support, you can enter the certificate path here. # # With NSS: # Certificates are stored in a dedicated database (split into 3 files). # Specify the path of the database directory. # # CERTPATH @CONFPATH@/cert/upsmon # # With OpenSSL: # Directory containing CA certificates in PEM format, used to verify # the server certificate presented by the upsd server. The files each # contain one CA certificate. The files are looked up by the CA subject # name hash value, which must hence be available. # # CERTPATH /usr/ssl/certs # # See 'docs/security.txt' or the Security chapter of NUT user manual # for more information on the SSL support in NUT. # -------------------------------------------------------------------------- # CERTIDENT - self certificate name and database password # CERTIDENT # # When compiled with SSL support with NSS, you can specify the certificate # name to retrieve from database to authenticate itself and the password # required to access certificate related private key. # # CERTIDENT "my nut monitor" "MyPasSw0rD" # # See 'docs/security.txt' or the Security chapter of NUT user manual # for more information on the SSL support in NUT. # -------------------------------------------------------------------------- # CERTHOST - security properties for an host # CERTHOST # # When compiled with SSL support with NSS, you can specify security directive # for each server you can contact. # Each entry maps server name with the expected certificate name and flags # indicating if the server certificate is verified and if the connection # must be secure. # # CERTHOST localhost "My nut server" 1 1 # # See 'docs/security.txt' or the Security chapter of NUT user manual # for more information on the SSL support in NUT. # -------------------------------------------------------------------------- # CERTVERIFY - make upsmon verify all connections with certificates # CERTVERIFY 1 # # When compiled with SSL support, make upsmon verify all connections with # certificates. # Without this, there is no guarantee that the upsd is the right host. # Enabling this greatly reduces the risk of man in the middle attacks. # This effectively forces the use of SSL, so don't use this unless # all of your upsd hosts are ready for SSL and have their certificates # in order. # When compiled with NSS support of SSL, can be overridden for host # specified with a CERTHOST directive. # -------------------------------------------------------------------------- # FORCESSL - force upsmon to use SSL # FORCESSL 1 # # When compiled with SSL, specify that a secured connection must be used # to communicate with upsd. # If you don't use 'CERTVERIFY 1', then this will at least make sure # that nobody can sniff your sessions without a large effort. Setting # this will make upsmon drop connections if the remote upsd doesn't # support SSL, so don't use it unless all of them have it running. # When compiled with NSS support of SSL, can be overridden for host # specified with a CERTHOST directive. # -------------------------------------------------------------------------- # DEBUG_MIN - specify minimal debugging level for upsmon daemon # e.g. DEBUG_MIN 6 # # Optionally specify a minimum debug level for `upsmon` daemon, e.g. for # troubleshooting a deployment, without impacting foreground or background # running mode directly, and without need to edit init-scripts or service # unit definitions. Note that command-line option `-D` can only increase # this verbosity level. # # NOTE: if the running daemon receives a `reload` command, presence of the # `DEBUG_MIN NUMBER` value in the configuration file can be used to tune # debugging verbosity in the running service daemon (it is recommended to # comment it away or set the minimum to explicit zero when done, to avoid # huge journals and I/O system abuse). Keep in mind that for this run-time # tuning, the `DEBUG_MIN` value *present* in *reloaded* configuration files # is applied instantly and overrides any previously set value, from file # or CLI options, regardless of older logging level being higher or lower # than the newly found number; a missing (or commented away) value however # does not change the previously active logging verbosity. nut-2.8.1/configure.ac0000644000175000017500000053651214520274617011563 00000000000000dnl +------------------------------------------------------------------+ dnl | Network UPS Tools: configure.ac | dnl +------------------------------------------------------------------+ dnl NUT version number is defined here, with a Git suffixed macro like dnl NUT_VERSION_MACRO "2.7.4-2838-gdfc3ac08" dnl in include/nut_version.h (generated by make) AC_INIT([nut],[2.8.1],[https://github.com/networkupstools/nut/issues]) dnl See docs/maintainer-guide.txt about releases - updating the version dnl above is a small part of the consistent ritual! dnl Note: this refers to GITREV at the time of configure script running dnl primarily for better messaging in the script itself (also to render dnl the PDF documentation revision history via docs/docinfo.xml.in). dnl If the NUT codebase in this workspace is being developed and rebuilt dnl without reconfiguration, detailed version in the binaries will differ dnl (that one comes from the NUT_VERSION_MACRO from nut_version.h file). (command -v git >/dev/null 2>/dev/null) \ && NUT_SOURCE_GITREV="`(git describe --tags --match 'v[0-9]*.[0-9]*.[0-9]' --exclude '*-signed' --exclude '*rc*' --exclude '*alpha*' --exclude '*beta*' 2>/dev/null || git describe --tags --exclude '*rc*' --exclude '*alpha*' --exclude '*beta*' --exclude '*Windows*' --exclude '*IPM*' 2>/dev/null ) | sed -e 's/^v\([0-9]\)/\1/' -e 's,^.*/,,'`" \ || NUT_SOURCE_GITREV="" dnl Note: except for experiments, do not pass this into config.h - use dnl the NUT_VERSION_MACRO from nut_version.h instead. Developers may dnl want to disable their "force-nut-version-header" configure option dnl to reduce rebuild scope and so speed up the iterations with ccache. dnl New "config.h" contents for every reconfig would defeat that purpose! dnl ### AS_IF([test -n "${NUT_SOURCE_GITREV-}"], dnl ### [AC_DEFINE_UNQUOTED([NUT_SOURCE_GITREV], ["${NUT_SOURCE_GITREV}"], [NUT source revision when the build was configured])], dnl ### [AC_DEFINE([NUT_SOURCE_GITREV], [NULL], [NUT source revision when the build was configured: not detected])]) dnl Keep track of command-line options passed to this script: AC_MSG_CHECKING([for CONFIG_FLAGS]) CONFIG_FLAGS="" dnl Keep each token quoted, in case spaces or other special chars crawl in: _flag_enable_inplace_runtime="" for F in "$@" ; do case "$F" in *=*" "*) NF="$(echo "$F" | sed "s,=,=',")""'" && F="$NF" ;; esac case "$F" in --disable-inplace-runtime|--enable-inplace-runtime=no) _flag_enable_inplace_runtime="no" ;; --enable-inplace-runtime*) _flag_enable_inplace_runtime="$F" ;; *) test -z "${CONFIG_FLAGS}" \ && CONFIG_FLAGS="$F" \ || CONFIG_FLAGS="${CONFIG_FLAGS} $F" ;; esac done dnl Keep it "known" that we tried to re-use at least some local configuration dnl so unspecified options are not necessarily at default values for this script AS_IF([test x"${NUT_VERSION_DEPLOYED-}" = x""], [_flag_enable_inplace_runtime="reenter"]) F="" AS_IF([test x"${NUT_VERSION_DEPLOYED-}" != x && test x"${NUT_VERSION_DEPLOYED-}" != x""], [ dnl Even if explicitly disabled... did we re-enter? Save the value to be seen: F="--enable-inplace-runtime='${NUT_VERSION_DEPLOYED}'" ],[ AS_CASE(["${_flag_enable_inplace_runtime}"], [no|""|reenter], [], [F="${_flag_enable_inplace_runtime}"]) ]) AS_IF([test x"$F" != x], [ test -z "${CONFIG_FLAGS}" \ && CONFIG_FLAGS="$F" \ || CONFIG_FLAGS="${CONFIG_FLAGS} $F" ]) unset _flag_enable_inplace_runtime unset F unset NF AC_MSG_RESULT([${CONFIG_FLAGS}]) AC_DEFINE_UNQUOTED([CONFIG_FLAGS],["${CONFIG_FLAGS}"],[Flags passed to configure script]) AC_SUBST(CONFIG_FLAGS) AC_CONFIG_AUX_DIR([.]) AC_CONFIG_SRCDIR(server/upsd.c) AC_CONFIG_MACRO_DIR([m4]) AS_IF([test x"${NUT_SOURCE_GITREV}" = x], [echo "Network UPS Tools version ${PACKAGE_VERSION}"], [echo "Network UPS Tools version ${PACKAGE_VERSION} (${NUT_SOURCE_GITREV})"]) AC_CANONICAL_TARGET NUT_CHECK_OS NUT_STASH_WARNINGS AC_CONFIG_HEADERS([include/config.h]) AC_PREFIX_DEFAULT(/usr/local/ups) AM_INIT_AUTOMAKE([subdir-objects]) dnl Default to `configure --enable-silent-rules` or `make V=1` for details? dnl This feature seems to require automake-1.13 or newer (1.11+ by other info) dnl On very old systems can comment it away with little loss (then automake-1.10 dnl is known to suffice): m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES([yes])], [AC_MSG_NOTICE([Silent Rules feature not defined in this automake version, skipped])]) dnl we need Autoconf 2.61 or better to enable features of Posix that are extensions to C dnl (and actually 2.64 or better for m4/ax_check_compile_flag.m4 when it is sourced) dnl UPDATE: As tested on CentOS 6, its "autoconf-2.63-5.1.el6.noarch" also suffices. dnl But OpenBSD 6.5 requires autoconf-2.65 and automake-1.13 or newer... AC_MSG_CHECKING(for autoconf macro to enable system extensions) m4_version_prereq(2.61, [ AC_MSG_RESULT(yes) AC_USE_SYSTEM_EXTENSIONS ], [ AC_MSG_RESULT(no) ]) AC_PREREQ([2.63]) dnl #AC_PREREQ([2.64]) dnl Use "./configure --enable-maintainer-mode" to keep Makefile.in and Makefile dnl in sync after Git updates. AM_MAINTAINER_MODE dnl Some systems have older autotools without direct macro support for PKG_CONF* NUT_CHECK_PKGCONFIG dnl Various version related processing dnl ---------------------------------- dnl # the following is commented out, because the UPS_VERSION macro now dnl # resides in include/nut_version.h, which is generated by Makefile.am, dnl # rather than in include/config.h, which is generated by configure. The dnl # reason is that the SVN revision should be computed at compile time, dnl # not configure time. dnl AC_DEFINE_UNQUOTED(UPS_VERSION, "${PACKAGE_VERSION}", [NUT version]) dnl However, automatically define the tree version (mostly for AC_SUBST) TREE_VERSION="`echo ${PACKAGE_VERSION} | awk '{ print substr($0,1,3) }'`" AC_DEFINE_UNQUOTED(TREE_VERSION, "${TREE_VERSION}", [NUT tree version]) dnl Should not be necessary, since old servers have well-defined errors for dnl unsupported commands: NUT_NETVERSION="1.3" AC_DEFINE_UNQUOTED(NUT_NETVERSION, "${NUT_NETVERSION}", [NUT network protocol version]) dnl Fix this early so we can expand with eval later test "${prefix}" = "NONE" && prefix="${ac_default_prefix}" test "${exec_prefix}" = "NONE" && exec_prefix='${prefix}' CFLAGS=${CFLAGS-"-O"} dnl Note: for practical and platform-independent use, see AX_REALPATH macro AC_CHECK_PROGS([REALPATH], [realpath], []) dnl FIXME: remove after dev-testing dnl UNITTEST_AX_REALPATH dnl exit dnl NOTE: for definition of NUT_* autoconf macros, see m4/ directory dnl and docs/macros.txt dnl +------------------------------------------------------------------+ dnl | default values for things later on (can be overridden) | STATEPATH="/var/state/ups" dnl Historically this refers to *system location* for PID files, dnl and more specifically that for `upsmon` (running as `root`). dnl See also ALTPIDPATH (defaulted to STATEPATH) setting below dnl for the unprivileged daemons (`upsd`, drivers). PIDPATH="/var/run" dnl Honour new LFS recommendations if applied on the build system: AS_IF([test -d "/run"], [PIDPATH="/run"]) dnl Defaults for respective configure options below dnl Note these defaults may change further below depending on OS and dnl certain other configure options (e.g. "in-place replacement") RUN_AS_USER="nobody" RUN_AS_GROUP="nobody" AS_IF([test -n "`getent group nogroup`" && ! test -n "`getent group "${RUN_AS_GROUP}"`"], [RUN_AS_GROUP="nogroup"] ) dnl NOTE: NUT legacy default, keep as is for least surprise dnl Distributions are however welcome to specify the option to use tmpfs AS_CASE([${target_os}], [*mingw*], [POWERDOWNFLAG="C:\\\\killpower"], dnl NOTE: Double backslashes (times escaping) are correct! [POWERDOWNFLAG="/etc/killpower"] dnl POSIX systems default ) cgiexecdir='${exec_prefix}/cgi-bin' driverexecdir='${exec_prefix}/bin' htmldir='${prefix}/html' pkgconfigdir='${libdir}/pkgconfig' auglensdir='/usr/share/augeas/lenses/dist' if test ! -d "${auglensdir}"; then auglensdir='/usr/share/augeas/lenses' if test ! -d "${auglensdir}"; then auglensdir='' fi fi dnl ### NUT_CHECK_LIBREGEX ### Detect below as part of libusb etc. dnl ### LIBREGEX_LIBS='' dnl Disable Hotplug, DevD and udev support on Windows dnl (useful when cross-compiling) case "${target_os}" in *mingw* ) dnl TODO: Actually detect it? See also nut_check_libregex.m4 for same. dnl Here we assumed from practice that it is available... dnl ### if test x"${LIBREGEX_LIBS}" = x ; then dnl ### LIBREGEX_LIBS='-lregex' dnl ### fi hotplugdir='' udevdir='' devddir='' ;; * ) hotplugdir='/etc/hotplug' if test ! -d "${hotplugdir}"; then hotplugdir='' fi udevdir='/lib/udev' if test ! -d "${udevdir}"; then udevdir='/etc/udev' if test ! -d "${udevdir}"; then udevdir='' fi fi devddir='/usr/local/etc/devd' if test ! -d "${devddir}"; then devddir='/etc/devd' if test ! -d "${devddir}"; then devddir='' fi fi ;; esac dnl Note: this deals with run-time settings so that the newly built dnl programs can be "just executed" to use same configuration files dnl and filesystem object permissions as an older deployment of NUT dnl on this system; this specifically does not deal with trying to dnl use same prefix and other paths to fully replace an older setup dnl (a different option might be crafted to do that, but really the dnl arcane distro-dependent packaging recipes are a better way here). dnl This feature is intended for users who want to see if a custom dnl build of NUT supports their hardware or other use-cases better. NUT_ARG_ENABLE([inplace-runtime], [Request configure option defaults for runtime user/group/confpath based on currently installed NUT (to extent these can be detected)], [no]) dnl Check for not re-entering in this run - whether NUT_VERSION_DEPLOYED is set AS_IF([test x"$nut_enable_inplace_runtime" = xyes -a x"${NUT_VERSION_DEPLOYED-}" = x], [ AC_MSG_NOTICE([checking for location, CONFIG_FLAGS and version of an already deployed NUT build (if it reports those)]) dnl If existing NUT installation reports its build options, re-run this dnl script with those flags (overridden by any options passed currently): conftemp="${sbindir}" eval conftemp=\"${conftemp}\" eval conftemp=\"${conftemp}\" PREFIX_SBINDIR="${conftemp}" conftemp="${bindir}" eval conftemp=\"${conftemp}\" eval conftemp=\"${conftemp}\" PREFIX_BINDIR="${conftemp}" DEPLOYED_SBINDIR="${PREFIX_SBINDIR}" DEPLOYED_BINDIR="${PREFIX_BINDIR}" dnl Note use of AC_PATH_PROG for specific pathname (not AC_CHECK_PROGS which picks filename variants)! dnl Note: "ordinary" users might not have "sbin" in their default PATH, so appending it: dnl Note: in some systems, the file in PATH is a shell dnl wrapper for /etc/nut/nut.conf MODE support AC_PATH_PROG([DEPLOYED_UPSD], [upsd], [], [${PREFIX_SBINDIR}:${PATH}:/sbin:/usr/sbin:/usr/local/sbin]) dnl ...however "upsc" is a userland tool so should be there: AC_PATH_PROG([DEPLOYED_UPSC], [upsc], [], [${PREFIX_BINDIR}:${PATH}]) AS_IF([test -x "${DEPLOYED_UPSD}"], [ AX_REALPATH([$DEPLOYED_UPSD], [DEPLOYED_UPSD]) DEPLOYED_SBINDIR="`dirname "${DEPLOYED_UPSD}"`" ]) AS_IF([test -x "${DEPLOYED_UPSC}"], [ AX_REALPATH([$DEPLOYED_UPSC], [DEPLOYED_UPSC]) DEPLOYED_BINDIR="`dirname "${DEPLOYED_UPSC}"`" ]) DEPLOYED_PREFIX="" AS_IF([test -d "${DEPLOYED_SBINDIR}"], [DEPLOYED_PREFIX="`dirname "${DEPLOYED_SBINDIR}"`"], [AS_IF([test -d "${DEPLOYED_BINDIR}"], [DEPLOYED_PREFIX="`dirname "${DEPLOYED_BINDIR}"`"])] ) AC_MSG_CHECKING([for CONFIG_FLAGS of an already deployed NUT build (if it reports those)]) CONFIG_FLAGS_DEPLOYED="" NUT_VERSION_DEPLOYED="" dnl TODO: Similar query can be done for BINDIR tools dnl and for libupsclient-config if deployed locally for DEPLOYED_TOOL in \ "${DEPLOYED_UPSD}" \ "${DEPLOYED_UPSC}" \ ; do AS_IF([test x"${DEPLOYED_TOOL}" = x], [continue]) AS_IF([test -x "${DEPLOYED_TOOL}"], [], [continue]) AC_MSG_CHECKING([for CONFIG_FLAGS from ${DEPLOYED_TOOL}]) CONFIG_FLAGS_DEPLOYED="`"${DEPLOYED_TOOL}" -DV 2>&1 | grep 'configured with flags:' | head -1 | sed 's,^.*configured with flags: *,,'`" \ && test x"${CONFIG_FLAGS_DEPLOYED}" != x \ || CONFIG_FLAGS_DEPLOYED="" NUT_VERSION_DEPLOYED="`"${DEPLOYED_TOOL}" -DV 2>&1 | grep 'configured with flags:' | head -1 | sed 's,^.*Network UPS Tools version \(.*\) configured with flags:.*$,\1,'`" \ && test x"${NUT_VERSION_DEPLOYED}" != x \ || NUT_VERSION_DEPLOYED="" AS_IF([test x"${CONFIG_FLAGS_DEPLOYED}${NUT_VERSION_DEPLOYED}" = x], [], [break]) done AS_IF([test x"${CONFIG_FLAGS_DEPLOYED}" != x], [ AC_MSG_RESULT([CONFIG_FLAGS_DEPLOYED: ${CONFIG_FLAGS_DEPLOYED}]) ],[ AC_MSG_RESULT([CONFIG_FLAGS_DEPLOYED: not reported]) ]) dnl Account for custom paths if known/found: AS_IF([test x"${DEPLOYED_PREFIX}" != x && test x"${DEPLOYED_PREFIX}" != x"${prefix}"], AC_MSG_WARN([Deployed NUT installation uses a PREFIX different from one specified (wins) or derived (loses) for this build: '${DEPLOYED_PREFIX}' vs. '${prefix}']) [AS_CASE(["${CONFIG_FLAGS_DEPLOYED} ${CONFIG_FLAGS}"], [*--prefix=*], [], [CONFIG_FLAGS_DEPLOYED="${CONFIG_FLAGS_DEPLOYED} --prefix='${DEPLOYED_PREFIX}'"]) ]) AS_IF([test x"${DEPLOYED_SBINDIR}" != x && test x"${DEPLOYED_SBINDIR}" != x"${PREFIX_SBINDIR}"], AC_MSG_WARN([Deployed NUT installation uses a SBINDIR different from one specified (wins) or derived (loses) for this build: '${DEPLOYED_SBINDIR}' vs. '${sbindir}']) [AS_CASE(["${CONFIG_FLAGS_DEPLOYED} ${CONFIG_FLAGS}"], [*--sbindir=*], [], [CONFIG_FLAGS_DEPLOYED="${CONFIG_FLAGS_DEPLOYED} --sbindir='${DEPLOYED_SBINDIR}'"]) ]) AS_IF([test x"${DEPLOYED_BINDIR}" != x && test x"${DEPLOYED_BINDIR}" != x"${PREFIX_BINDIR}"], AC_MSG_WARN([Deployed NUT installation uses a BINDIR different from one specified (wins) or derived (loses) for this build: '${DEPLOYED_BINDIR}' vs. '${bindir}']) [AS_CASE(["${CONFIG_FLAGS_DEPLOYED} ${CONFIG_FLAGS}"], [*--bindir=*], [], [CONFIG_FLAGS_DEPLOYED="${CONFIG_FLAGS_DEPLOYED} --bindir='${DEPLOYED_BINDIR}'"]) ]) AS_CASE(["${CONFIG_FLAGS_DEPLOYED} ${CONFIG_FLAGS}"], [*--sysconfdir=*], [ for F in ${CONFIG_FLAGS_DEPLOYED} ${CONFIG_FLAGS} ; do case "$F" in "--sysconfdir="*) sysconfdir="`echo "$F" | ( IFS='=' read K V ; echo "$V" )`" ;; esac done ], [ dnl If there was no custom --sysconfdir=/etc/myNUT passed, dnl try to default it to something from existing deployment. dnl NOTE: Single-quotes are correct for autotools default, dnl expanded at runtime (see conftemp tricks below) AC_MSG_CHECKING([for in-place replacement default sysconfdir (better than '${sysconfdir}')]) DEPLOYED_SYSCONFDIR="" dnl TODO: Any more reasonable defaults? Pile them on here :) for D in \ /etc/nut /etc/ups \ /usr/etc/nut /usr/etc/ups \ /usr/local/etc/nut /usr/local/etc/ups \ /usr/local/nut/etc /usr/local/ups/etc \ ; do if test -e "$D/ups.conf" || test -e "$D/upsmon.conf" \ || ( test -e "$D/upsd.conf" && test -e "$D/upsd.users" ) \ ; then DEPLOYED_SYSCONFDIR="$D" break else if test -d "$D/" && test ! -r "$D/" ; then dnl Keeping order of preference defined by "for" loop: AC_MSG_WARN([Picking directory '${D}' which exists but current build user may not read]) DEPLOYED_SYSCONFDIR="$D" break fi fi done AS_IF([test -n "${DEPLOYED_SYSCONFDIR}"], [ AC_MSG_RESULT([${DEPLOYED_SYSCONFDIR}]) dnl May be used in searches below: sysconfdir="${DEPLOYED_SYSCONFDIR}" CONFIG_FLAGS_DEPLOYED="${CONFIG_FLAGS_DEPLOYED} --sysconfdir='${DEPLOYED_SYSCONFDIR}'" ], [ AC_MSG_RESULT([not detected]) ]) ]) dnl Prepare paths that may be used in user/group searches below: conftemp="${sysconfdir}" eval conftemp=\"${conftemp}\" eval conftemp=\"${conftemp}\" CONFPATH="${conftemp}" AS_CASE(["${CONFIG_FLAGS_DEPLOYED} ${CONFIG_FLAGS}"], [*--libdir=*], [ for F in ${CONFIG_FLAGS_DEPLOYED} ${CONFIG_FLAGS} ; do case "$F" in "--libdir="*) libdir="`echo "$F" | ( IFS='=' read K V ; echo "$V" )`" ;; esac done ] ) conftemp="${libdir}" eval conftemp=\"${conftemp}\" eval conftemp=\"${conftemp}\" LIBDIR="${conftemp}" AS_CASE(["${CONFIG_FLAGS_DEPLOYED} ${CONFIG_FLAGS}"], [*--with-pkgconfig-dir=*], [ for F in ${CONFIG_FLAGS_DEPLOYED} ${CONFIG_FLAGS} ; do case "$F" in "--with-pkgconfig-dir="*) pkgconfigdir="`echo "$F" | ( IFS='=' read K V ; echo "$V" )`" ;; esac done ] ) dnl pkgconfigdir may have more indirections: conftemp="${pkgconfigdir}" eval conftemp=\"${conftemp}\" eval conftemp=\"${conftemp}\" eval conftemp=\"${conftemp}\" PKGCONFIGDIR="${conftemp}" AS_CASE(["${CONFIG_FLAGS_DEPLOYED} ${CONFIG_FLAGS}"], [*--with-group=*], [], [ AC_MSG_CHECKING([for in-place replacement default group (better than '${RUN_AS_GROUP}')]) nut_inplace_group="" AS_IF([test -d "${udevdir}/rules.d"], [for F in "${udevdir}/rules.d"/*-nut-*.rules ; do if test -s "$F" ; then nut_inplace_group="`grep GROUP= "$F" | head -1 | sed 's,^.* GROUP="*\(.*\)"*.*$,\1,'`" \ && test -n "`getent group "${nut_inplace_group}"`" \ && AC_MSG_RESULT([Got from ${F}]) \ && break \ || nut_inplace_group="" fi done ]) AS_IF([test -z "${nut_inplace_group}"], [AS_IF([test -n "`getent group nut`"], [nut_inplace_group="nut"], [AS_IF([test -n "`getent group ups`"], [nut_inplace_group="ups"])])]) AS_IF([test -n "${nut_inplace_group}"], [ AC_MSG_RESULT([${nut_inplace_group}]) CONFIG_FLAGS_DEPLOYED="${CONFIG_FLAGS_DEPLOYED} --with-group='${nut_inplace_group}'" ], [ AC_MSG_RESULT([not detected]) ]) ]) AS_CASE(["${CONFIG_FLAGS_DEPLOYED} ${CONFIG_FLAGS}"], [*--with-user=*], [], [ AC_MSG_CHECKING([for in-place replacement default user (better than '${RUN_AS_USER}')]) nut_inplace_user="" dnl Beside currently active setting, check the built-in default sugestion AS_IF([test -s "${CONFPATH}/upsmon.conf"], [for nut_inplace_user in \ `grep -E '^ *RUN_AS_USER' "${CONFPATH}/upsmon.conf" | awk '{print $2}'`\ `grep -E '^ *##*RUN_AS_USER' "${CONFPATH}/upsmon.conf" | awk '{print $2}'`\ `grep -E '^ *##* *RUN_AS_USER' "${CONFPATH}/upsmon.conf" | awk '{print $3}'`\ ; do \ AS_IF([test -z "${nut_inplace_user}"], [ test -n "`getent passwd "${nut_inplace_user}"`" \ && AC_MSG_RESULT([Got from ${CONFPATH}/upsmon.conf]) \ || nut_inplace_user=""]) done ]) AS_IF([test -s "${CONFPATH}/upsmon.conf.sample" && test -z "${nut_inplace_user}"], [for nut_inplace_user in \ `grep -E '^ *RUN_AS_USER' "${CONFPATH}/upsmon.conf.sample" | awk '{print $2}'`\ `grep -E '^ *##*RUN_AS_USER' "${CONFPATH}/upsmon.conf.sample" | awk '{print $2}'`\ `grep -E '^ *##* *RUN_AS_USER' "${CONFPATH}/upsmon.conf.sample" | awk '{print $3}'`\ ; do \ AS_IF([test -z "${nut_inplace_user}"], [ test -n "`getent passwd "${nut_inplace_user}"`" \ && AC_MSG_RESULT([Got from ${CONFPATH}/upsmon.conf]) \ || nut_inplace_user=""]) done ]) dnl Note: with default short inplace and no prefix, this would look under dnl /usr/local/ups/lib/pkgconfig which may be irrelevant for packaged setups dnl TODO: Any more reasonable defaults? Pile them on here :) for F in \ "${PKGCONFDIR}/libupsclient.pc" \ "${PKGCONFDIR}/libnutclient.pc" \ "${LIBDIR}/pkgconfig/libupsclient.pc" \ "${LIBDIR}/pkgconfig/libnutclient.pc" \ ; do AS_IF([test -z "${nut_inplace_user}" && test -s "$F"], [nut_inplace_user="`grep -E '^ *nutuser=' "$F" | sed 's,^ *nutuser=,,'`" \ && test -n "`getent passwd "${nut_inplace_user}"`" \ && AC_MSG_RESULT([Got from $F]) \ || nut_inplace_user="" ]) done AS_IF([test -z "${nut_inplace_user}"], [AS_IF([test -n "`getent passwd nut`"], [nut_inplace_user="nut"], [AS_IF([test -n "`getent passwd ups`"], [nut_inplace_user="ups"])])]) AS_IF([test -n "${nut_inplace_user}"], [ AC_MSG_RESULT([${nut_inplace_user}]) CONFIG_FLAGS_DEPLOYED="${CONFIG_FLAGS_DEPLOYED} --with-user='${nut_inplace_user}'" ], [ AC_MSG_RESULT([not detected]) ]) ]) AS_IF([test x"${CONFIG_FLAGS_DEPLOYED}" != x], [ AC_MSG_NOTICE([Detected CONFIG_FLAGS of an already deployed NUT installation, using them for --inplace-runtime configuration (restarting script)]) dnl For multiply-specified flags with conflicting values, last mention wins: AC_MSG_NOTICE([exec "$0" $CONFIG_FLAGS_DEPLOYED $CONFIG_FLAGS --disable-inplace-runtime]) AS_IF([test x"${NUT_VERSION_DEPLOYED}" != x], [ AC_MSG_NOTICE([NUT_VERSION_DEPLOYED: ${NUT_VERSION_DEPLOYED}]) ],[ NUT_VERSION_DEPLOYED="" ]) export NUT_VERSION_DEPLOYED eval exec "$0" $CONFIG_FLAGS_DEPLOYED $CONFIG_FLAGS --disable-inplace-runtime ],[ AC_MSG_NOTICE([No CONFIG_FLAGS were reported or discovered from existing NUT deployment (if any); restarting script for a clean run]) NUT_VERSION_DEPLOYED="" export NUT_VERSION_DEPLOYED AC_MSG_NOTICE([exec "$0" $CONFIG_FLAGS --disable-inplace-runtime]) eval exec "$0" $CONFIG_FLAGS --disable-inplace-runtime ]) ]) dnl Define directory where LIBOBJS replacement functions are AC_CONFIG_LIBOBJ_DIR([common]) dnl +------------------------------------------------------------------- dnl AC_PROG_CC dnl Macro AC_PROG_CC_C99 is obsolete; use AC_PROG_CC dnl Note that NUT does not support building with C89 anyway dnl AC_PROG_CC_C99 dnl Needed for per-target flags AM_PROG_CC_C_O AC_PROG_CPP AC_PROG_CXX AC_PROG_CXX_C_O AC_PROG_INSTALL AC_PROG_MKDIR_P AC_PROG_LN_S AC_PROG_EGREP AC_PATH_PROG(AR, ar) AC_CHECK_TOOL(RANLIB, ranlib, :) dnl Postpone call to LT_INIT/AC_CONFIG_FILES to allow disabling static lib AC_C_BIGENDIAN AC_C_INLINE AC_C_FLEXIBLE_ARRAY_MEMBER AC_C_VARARRAYS NUT_ARG_ENABLE([keep_nut_report_feature], [Request that we keep config.nut_report_feature.log (normally deleted by configure script after displaying)], [no]) AS_IF([test x"${NUT_SOURCE_GITREV}" = x], [NUT_REPORT([configured version], [${PACKAGE_VERSION}])], [NUT_REPORT([configured version], [${PACKAGE_VERSION} (${NUT_SOURCE_GITREV})])]) dnl Note: the compiler/pragma/attr methods below are custom for NUT codebase: NUT_COMPILER_FAMILY dnl Note: DO NOT AC_DEFINE the "FULL" items: they are generally multi-line. dnl NUT_REPORT_TARGET([CC_VERSION_FULL], ["${CC_VERSION_FULL}"], [Version and other details of C compiler]) dnl NUT_REPORT_TARGET([CXX_VERSION_FULL], ["${CXX_VERSION_FULL}"], [Version and other details of C++ compiler]) dnl NUT_REPORT_TARGET([CPP_VERSION_FULL], ["${CPP_VERSION_FULL}"], [Version and other details of C preprocessor]) NUT_REPORT_TARGET([CC_VERSION], ["${CC_VERSION}"], [Compact version of C compiler]) NUT_REPORT_TARGET([CXX_VERSION], ["${CXX_VERSION}"], [Compact version of C++ compiler]) NUT_REPORT_TARGET([CPP_VERSION], ["${CPP_VERSION}"], [Compact version of C preprocessor]) dnl Help find warning/error details in a wall of text (must be processed before NUT_COMPILER_FAMILY_FLAGS): NUT_ARG_ENABLE([Wcolor], [Request that compiler output is colorized (no = leave it up to compiler defaults)], [no]) NUT_COMPILER_FAMILY_FLAGS AX_C_PRAGMAS AX_C___ATTRIBUTE__ AX_C_PRINTF_STRING_NULL dnl All current systems provide time.h; it need not be checked for. dnl Not all systems provide sys/time.h, but those that do, all allow dnl you to include it and time.h simultaneously. dnl NUT codebase provides the include/timehead.h to wrap these nuances. AC_CHECK_HEADERS_ONCE([sys/time.h time.h sys/types.h sys/socket.h netdb.h]) dnl ###obsolete### AC_HEADER_TIME AS_IF([test "$ac_cv_header_sys_time_h" = yes], [AC_DEFINE([TIME_WITH_SYS_TIME],[1],[Define to 1 if you can safely include both and . This macro is deemed obsolete by autotools.]) ], []) AC_CHECK_FUNCS(flock lockf fcvt fcvtl dup dup2 abs_val abs) AC_CHECK_HEADER([float.h], [AC_DEFINE([HAVE_FLOAT_H], [1], [Define to 1 if you have .])]) AC_CHECK_HEADER([math.h], [AC_DEFINE([HAVE_MATH_H], [1], [Define to 1 if you have .])]) AC_CHECK_DECLS([fabs, fabsf, fabsl, pow10, round], [], [], [#ifdef HAVE_MATH_H # include #endif #ifdef HAVE_FLOAT_H # include #endif ]) AC_CHECK_HEADER([limits.h], [AC_DEFINE([HAVE_LIMITS_H], [1], [Define to 1 if you have .])]) AC_CHECK_HEADER([stdlib.h], [AC_DEFINE([HAVE_STDLIB_H], [1], [Define to 1 if you have .])]) AC_CHECK_DECLS(realpath, [], [], [#ifdef HAVE_LIMITS_H # include #endif #ifdef HAVE_STDLIB_H # include #endif ]) AC_CHECK_HEADER([signal.h], [AC_DEFINE([HAVE_SIGNAL_H], [1], [Define to 1 if you have .])]) AC_CHECK_HEADER([sys/signal.h], [AC_DEFINE([HAVE_SYS_SIGNAL_H], [1], [Define to 1 if you have .])]) AC_CHECK_HEADER([sys/resource.h], [AC_MSG_CHECKING([for struct rlimit and getrlimit()]) AC_LANG_PUSH([C]) AC_COMPILE_IFELSE([AC_LANG_PROGRAM([ #include ], [struct rlimit limit; getrlimit(RLIMIT_NOFILE, &limit); /* Do not care about actual return value in this test, * normally check for non-zero meaning to look in errno */ ] )], [AC_DEFINE([HAVE_SYS_RESOURCE_H], [1], [Define to 1 if you have with usable struct rlimit and getrlimit().]) AC_MSG_RESULT([ok]) ], [AC_MSG_RESULT([no])] ) AC_LANG_POP([C]) ] ) AC_CHECK_HEADER([poll.h], [AC_DEFINE([HAVE_POLL_H], [1], [Define to 1 if you have .])]) SEMLIBS="" AC_CHECK_HEADER([semaphore.h], [AC_DEFINE([HAVE_SEMAPHORE_H], [1], [Define to 1 if you have .]) AC_MSG_CHECKING([for sem_t, sem_init() and sem_destroy()]) AC_LANG_PUSH([C]) AC_COMPILE_IFELSE([AC_LANG_PROGRAM([ #include ], [sem_t semaphore; sem_init(&semaphore, 0, 4); sem_destroy(&semaphore); /* Do not care about actual return value in this test, * normally check for non-zero meaning to look in errno */ ] )], [AC_DEFINE([HAVE_SEMAPHORE], [1], [Define to 1 if you have with usable sem_t sem_init() and sem_destroy().]) AC_MSG_RESULT([ok]) dnl Solaris 8 builds complain about indirect dependency involved: dnl sem_init nut_scanner-nut-scanner.o dnl (symbol belongs to implicit dependency /usr/lib/librt.so.1) AC_CHECK_LIB(rt, sem_init, SEMLIBS="-lrt") ], [AC_MSG_RESULT([no])] ) AC_LANG_POP([C]) ] ) AM_CONDITIONAL(HAVE_SEMAPHORE_LIBS, test -n "${SEMLIBS}") AC_CHECK_FUNCS(cfsetispeed tcsendbreak) AC_CHECK_FUNCS(seteuid setsid getpassphrase) AC_CHECK_FUNCS(on_exit setlogmask) AC_CHECK_DECLS(LOG_UPTO, [], [], [#include ]) dnl These common routines are not available in strict C standard library dnl compilation modes (not part of ANSI or later standard), only in GNU, dnl POSIX or other extension modes. Note that on modern systems they are dnl available, just hidden in headers - so AC_CHECK_FUNCS() finds them dnl by adding a declaration, while the "real" codebase can't use them. AC_MSG_NOTICE( [----------------------------------------------------------------------- The next few tests look for required C library routines; if something is not found, you may need to enable a different C standard or extension macro version. You may also have to configure without extreme warning levels since autotools tests fail those on their own and assume system lacks stuff (although note we try to not involve standard -W* flags here). -----------------------------------------------------------------------]) dnl# AC_CHECK_FUNCS(strcasecmp strncasecmp, dnl# [], [AC_MSG_WARN([Required C library routine not found; try adding __EXTENSIONS__])]) dnl These appear with CFLAGS="-std=c99 -D_POSIX_C_SOURCE=200112L": dnl# Methods below currently do not cause build errors for C99+ modes so are dnl# not tested as thoroughly as those further below: AC_CHECK_FUNCS(strtok_r fileno sigemptyset sigaction, [], [AC_MSG_WARN([Required C library routine not found; try adding -D_POSIX_C_SOURCE=200112L])]) dnl For these we have a fallback implementation via the other, dnl if at least one is available, so initial check is quiet. dnl This typically pops up in POSIX vs. Windows builds: AC_CHECK_FUNCS(localtime_r localtime_s gmtime_r gmtime_s, [], []) AC_MSG_CHECKING([for at least one gmtime implementation]) AS_IF([test x"${ac_cv_func_gmtime_s}-${ac_cv_func_gmtime_r}" = "xno-no"], [ AC_MSG_RESULT([no]) AC_MSG_WARN([Required C library routine gmtime_s nor gmtime_r was not found; try adding -D_POSIX_C_SOURCE=200112L]) ],[ AC_MSG_RESULT([yes]) ]) AC_MSG_CHECKING([for at least one localtime implementation]) AS_IF([test x"${ac_cv_func_localtime_s}-${ac_cv_func_localtime_r}" = "xno-no"], [ AC_MSG_RESULT([no]) AC_MSG_WARN([Required C library routine localtime_s nor localtime_r was not found; try adding -D_POSIX_C_SOURCE=200112L]) ],[ AC_MSG_RESULT([yes]) ]) AC_LANG_PUSH([C]) AC_CHECK_HEADER([string.h], [AC_DEFINE([HAVE_STRING_H], [1], [Define to 1 if you have .])]) AC_CHECK_HEADER([strings.h], [AC_DEFINE([HAVE_STRINGS_H], [1], [Define to 1 if you have .])]) CODE_STRINGINCL='#ifdef HAVE_STRING_H #include #endif #ifdef HAVE_STRINGS_H #include #endif' AC_CACHE_CHECK([for strcasecmp(s1,s2)], [ac_cv_func_strcasecmp], [AX_RUN_OR_LINK_IFELSE( [AC_LANG_PROGRAM([$CODE_STRINGINCL], [if (strcasecmp("STR1", "str1") != 0) return 1])], [ac_cv_func_strcasecmp=yes], [ac_cv_func_strcasecmp=no] )]) AS_IF([test x"${ac_cv_func_strcasecmp}" = xyes], [AC_DEFINE([HAVE_STRCASECMP], 1, [defined if standard library has, and C standard allows, the strcasecmp(s1,s2) method])], [AC_MSG_WARN([Required C library routine strcasecmp not found; try adding __EXTENSIONS__])] ) AC_CACHE_CHECK([for strncasecmp(s1,s2,n)], [ac_cv_func_strncasecmp], [AX_RUN_OR_LINK_IFELSE( [AC_LANG_PROGRAM([$CODE_STRINGINCL], [if (strncasecmp("STR1", "strX", 2) != 0) return 1])], [ac_cv_func_strncasecmp=yes], [ac_cv_func_strncasecmp=no] )]) AS_IF([test x"${ac_cv_func_strncasecmp}" = xyes], [AC_DEFINE([HAVE_STRNCASECMP], 1, [defined if standard library has, and C standard allows, the strncasecmp(s1,s2,n) method])], [AC_MSG_WARN([Required C library routine strncasecmp not found; try adding __EXTENSIONS__])] ) dnl Note: this changes the original string in argument! dnl Do not pass it constants (strdup them if needed)! AC_CACHE_CHECK([for strlwr(s)], [ac_cv_func_strlwr], [AX_RUN_OR_LINK_IFELSE( [AC_LANG_PROGRAM([$CODE_STRINGINCL], [char s@<:@64@:>@ = {"Some STR1 text"} ; if (strlwr(s) == NULL) return 1])], [ac_cv_func_strlwr=yes], [ac_cv_func_strlwr=no] )]) AS_IF([test x"${ac_cv_func_strlwr}" = xyes], [AC_DEFINE([HAVE_STRLWR], 1, [defined if standard library has, and C standard allows, the strlwr(s1,s2) method])], [AC_MSG_WARN([Optional C library routine strlwr not found])] ) AC_CACHE_CHECK([for strsep(s1,s2)], [ac_cv_func_strsep], [AX_RUN_OR_LINK_IFELSE( [AC_LANG_PROGRAM([$CODE_STRINGINCL], [char arr@<:@64@:>@ = {"Some,tuple,text"} ; char *s = arr; if (strsep(&s, ",") == NULL) return 1])], [ac_cv_func_strsep=yes], [ac_cv_func_strsep=no] )]) AS_IF([test x"${ac_cv_func_strsep}" = xyes], [AC_DEFINE([HAVE_STRSEP], 1, [defined if standard library has, and C standard allows, the strsep(s1,s2) method])], [AC_MSG_WARN([Optional C library routine strsep not found])] ) AM_CONDITIONAL([HAVE_STRSEP], [test x"${ac_cv_func_strsep}" = "xyes"]) AC_CACHE_CHECK([for strstr(s1,s2)], [ac_cv_func_strstr], [AX_RUN_OR_LINK_IFELSE( [AC_LANG_PROGRAM([$CODE_STRINGINCL], [if (strstr("Some str1 text", "str1") == NULL) return 1])], [ac_cv_func_strstr=yes], [ac_cv_func_strstr=no] )]) AS_IF([test x"${ac_cv_func_strstr}" = xyes], [AC_DEFINE([HAVE_STRSTR], 1, [defined if standard library has, and C standard allows, the strstr(s1,s2) method])], [AC_MSG_ERROR([Required C library routine strstr not found])] ) AC_CACHE_CHECK([for strcasestr(s1,s2)], [ac_cv_func_strcasestr], [AX_RUN_OR_LINK_IFELSE( [AC_LANG_PROGRAM([$CODE_STRINGINCL], [if (strcasestr("Some STR1 text", "str1") == NULL) return 1])], [ac_cv_func_strcasestr=yes], [ac_cv_func_strcasestr=no] )]) AS_IF([test x"${ac_cv_func_strcasestr}" = xyes], [AC_DEFINE([HAVE_STRCASESTR], 1, [defined if standard library has, and C standard allows, the strcasestr(s1,s2) method])], [AS_IF([test x"${ac_cv_func_strlwr}" = xyes && test x"${ac_cv_func_strstr}" = xyes], [AC_MSG_WARN([Optional C library routine strcasestr not found; a simple wrapper will be built in])] [AC_MSG_WARN([Required C library routine strcasestr not found; try adding _GNU_SOURCE])] )]) AC_CACHE_CHECK([for strptime(s1,s2,tm)], [ac_cv_func_strptime], [AX_RUN_OR_LINK_IFELSE( [AC_LANG_PROGRAM([$CODE_STRINGINCL #ifdef TIME_WITH_SYS_TIME # include # include #else # ifdef HAVE_SYS_TIME_H # include # else # include # endif #endif ], [struct tm tm; char *date = "12/30/1999"; char *p = strptime(date, "%m/%d/%Y", &tm); if (p == NULL || *p != '\0') return 1])], [ac_cv_func_strptime=yes], [ac_cv_func_strptime=no] )]) AS_IF([test x"${ac_cv_func_strptime}" = xyes], [AC_DEFINE([HAVE_STRPTIME], 1, [defined if standard library has, and C standard allows, the strptime(s1,s2,tm) method])], [AC_MSG_WARN([Optional C library routine strptime not found; try adding _GNU_SOURCE; a fallback implementation will be built in])] ) dnl Note: per Linux headers, this may need __USE_XOPEN (features.h) dnl which is enabled by _XOPEN_SOURCE via _GNU_SOURCE on the platform. AM_CONDITIONAL([HAVE_STRPTIME], [test x"${ac_cv_func_strptime}" = "xyes"]) AC_CACHE_CHECK([for clock_gettime(CLOCK_MONOTONIC,ts)], [ac_cv_func_clock_gettime], [AX_RUN_OR_LINK_IFELSE( [AC_LANG_PROGRAM([$CODE_STRINGINCL #ifdef TIME_WITH_SYS_TIME # include # include #else # ifdef HAVE_SYS_TIME_H # include # else # include # endif #endif ], [struct timespec monoclock_ts; int got_monoclock = clock_gettime(CLOCK_MONOTONIC, &monoclock_ts); if (monoclock_ts.tv_sec < 0 || monoclock_ts.tv_nsec < 0) return 1])], [ac_cv_func_clock_gettime=yes], [ac_cv_func_clock_gettime=no] )]) AS_IF([test x"${ac_cv_func_clock_gettime}" = xyes], [AC_DEFINE([HAVE_CLOCK_GETTIME], 1, [defined if standard library has, and C standard allows, the clock_gettime(clkid,ts) method]) AC_DEFINE([HAVE_CLOCK_MONOTONIC], 1, [defined if standard library has, and C standard allows, the CLOCK_MONOTONIC macro or token])], [AC_MSG_WARN([Optional C library routine clock_gettime not found; will not be used in notifications])] ) dnl Currently these two are the same for us; note also fallback support for dnl older autoconf in SYSTEMD_SUPPORTS_DAEMON_TYPE_NOTIFY_RELOAD way below: AM_CONDITIONAL([HAVE_CLOCK_GETTIME], [test x"${ac_cv_func_clock_gettime}" = "xyes"]) AM_CONDITIONAL([HAVE_CLOCK_MONOTONIC], [test x"${ac_cv_func_clock_gettime}" = "xyes"]) AC_CACHE_CHECK([for strnlen(s1,s2,tm)], [ac_cv_func_strnlen], [AX_RUN_OR_LINK_IFELSE( [AC_LANG_PROGRAM([$CODE_STRINGINCL #include ], [size_t len = strnlen("LongString", 5); if (len != 5) return 5; len = strnlen("LongString", 50); if (len != 10) return 10 ])], [ac_cv_func_strnlen=yes], [ac_cv_func_strnlen=no] )]) AS_IF([test x"${ac_cv_func_strnlen}" = xyes], [AC_DEFINE([HAVE_STRNLEN], 1, [defined if standard library has, and C standard allows, the strnlen(s1,s2) method])], [AC_MSG_WARN([Optional C library routine strnlen not found; a fallback implementation will be built in])] ) AM_CONDITIONAL([HAVE_STRNLEN], [test x"${ac_cv_func_strnlen}" = "xyes"]) AC_CACHE_CHECK([for strdup(s)], [ac_cv_func_strdup], [AX_RUN_OR_LINK_IFELSE( [AC_LANG_PROGRAM([$CODE_STRINGINCL #include ], [[int res = 0; char *t = "Test"; char *s = strdup(t); if (!s || !(s[0]=='T'&&s[1]=='e'&&s[2]=='s'&&s[3]=='t'&&s[4]=='\0') || s == t) res = 1; if (s) free (s); if (res != 0) return res /* autoconf adds ";return 0;" */ ]])], [ac_cv_func_strdup=yes], [ac_cv_func_strdup=no] )]) AS_IF([test x"${ac_cv_func_strdup}" = xyes], [AC_DEFINE([HAVE_STRDUP], 1, [defined if standard library has, and C standard allows, the strdup(s) method])], [AC_MSG_WARN([Required C library routine strdup not found; try adding -D_POSIX_C_SOURCE=200112L])] ) AC_CHECK_HEADER([sys/select.h], [AC_DEFINE([HAVE_SYS_SELECT_H], [1], [Define to 1 if you have .])]) AC_CACHE_CHECK([for suseconds_t], [ac_cv_type_suseconds_t], [AC_COMPILE_IFELSE( [AC_LANG_PROGRAM([[#include #if HAVE_SYS_SELECT_H # include #endif ]], [[suseconds_t us = 1000000; signed long int l = 1000000; if (l != (signed long int)us) return 1; l = -1; us = -1; if (l != (signed long int)us) return 1 /* autoconf adds ";return 0;" */ /* we hope the code above fails if type is not defined or range is not sufficient */ ]])], [ac_cv_type_suseconds_t=yes], [ac_cv_type_suseconds_t=no] )]) AS_IF([test x"${ac_cv_type_suseconds_t}" = xyes], [AC_DEFINE([HAVE_SUSECONDS_T], 1, [defined if standard library has, and C standard allows, the suseconds_t type])], [AC_MSG_WARN([Required C library type suseconds_t not found; try adding -D_POSIX_C_SOURCE=200112L])] ) AC_CACHE_CHECK([for useconds_t], [ac_cv_type_useconds_t], [AC_COMPILE_IFELSE( [AC_LANG_PROGRAM([[#include ]], [[useconds_t us = 1000000; unsigned long int l = 1000000; if (l != (unsigned long int)us) return 1 /* autoconf adds ";return 0;" */ /* we hope the code above fails if type is not defined or range is not sufficient */ ]])], [ac_cv_type_useconds_t=yes], [ac_cv_type_useconds_t=no] )]) AS_IF([test x"${ac_cv_type_useconds_t}" = xyes], [AC_DEFINE([HAVE_USECONDS_T], 1, [defined if standard library has, and C standard allows, the useconds_t type])], [AC_MSG_WARN([Required C library type useconds_t not found; try adding -D_POSIX_C_SOURCE=200112L])] ) AC_CACHE_CHECK([for usleep(us)], [ac_cv_func_usleep], [AC_COMPILE_IFELSE( [AC_LANG_PROGRAM([[#include ]], [[useconds_t us = 1000; if (usleep(us) != 0) return 1 /* per doc, no errors are returned actually */ /* autoconf adds ";return 0;" */ ]])], [ac_cv_func_usleep=yes], [ac_cv_func_usleep=no] )]) AS_IF([test x"${ac_cv_func_usleep}" = xyes], [AC_DEFINE([HAVE_USLEEP], 1, [defined if standard library has, and C standard allows, the usleep(us) method])], [AC_MSG_WARN([Required C library routine usleep not found; try adding -D_POSIX_C_SOURCE=200112L])] ) AC_LANG_POP([C]) dnl These routines' arg types differ in strict C standard mode dnl from what they use in the modes expected by NUT codebase: dnl bind() : /usr/include/x86_64-linux-gnu/sys/socket.h:123:12: note: expected '__CONST_SOCKADDR_ARG {aka union }' but argument is of type 'struct sockaddr *' dnl accept() : /usr/include/x86_64-linux-gnu/sys/socket.h:243:12: note: expected '__SOCKADDR_ARG {aka union }' but argument is of type 'struct sockaddr *' dnl connect() : /usr/include/x86_64-linux-gnu/sys/socket.h:137:12: note: expected '__CONST_SOCKADDR_ARG {aka union }' but argument is of type 'const struct sockaddr *' dnl sendto() : /usr/include/x86_64-linux-gnu/sys/socket.h:163:16: note: expected '__CONST_SOCKADDR_ARG {aka union }' but argument is of type 'struct sockaddr *' dnl recvfrom() : /usr/include/x86_64-linux-gnu/bits/socket2.h:64:1: note: expected '__SOCKADDR_ARG {aka union }' but argument is of type 'struct sockaddr *' AC_MSG_CHECKING([whether ln -sr works]) dnl We need to relative-symlink some files. Or hardlink. Or copy... LN_S_R="cp -pR" if test "$as_ln_s" = "ln -s" ; then LN_S_R="ln" DIR1="$(mktemp -d "dir1.XXXXXXX")" && \ DIR2="$(mktemp -d "dir2.XXXXXXX")" && \ touch "${DIR1}/a" && \ $as_ln_s -r "${DIR1}/a" "${DIR2}/b" && \ ls -la "${DIR2}/b" | grep '\.\./' > /dev/null && \ LN_S_R="$as_ln_s -r" rm -rf "${DIR1}" "${DIR2}" fi AC_SUBST([LN_S_R], [${LN_S_R}]) if test "$LN_S_R" = "ln -s -r" ; then AC_MSG_RESULT([yes]) else AC_MSG_RESULT([no, using $LN_S_R]) fi dnl the following may add stuff to LIBOBJS (is this still needed?) AC_CHECK_FUNCS(vsnprintf snprintf, [], [ AC_LIBOBJ(snprintf) AC_TYPE_LONG_DOUBLE AC_TYPE_LONG_LONG_INT ]) AC_REPLACE_FUNCS(setenv strerror atexit) case ${target_os} in solaris2* ) dnl On Solaris, this allows errno to use thread local storage CFLAGS="${CFLAGS} -D_REENTRANT" ;; aix* ) dnl On AIX, this allows errno to use thread local storage CFLAGS="${CFLAGS} -D_REENTRANT" ;; hpux11* ) dnl It seems like the thread safe string functions will not be included dnl on 64 bit HP-UX unless we define _REENTRANT CFLAGS="${CFLAGS} -D_REENTRANT" ;; esac dnl optind handling: dnl need to check if unistd.h is enough, else try getopt.h, else need decls AC_CHECK_DECLS(optind, [], [ AC_CHECK_HEADERS(getopt.h, [ AC_DEFINE(NEED_GETOPT_H, 1, [Define if getopt.h is needed]) ], [ AC_DEFINE(NEED_GETOPT_DECLS, 1, [Define to use explicit getopt declarations]) ], [AC_INCLUDES_DEFAULT]) ], [AC_INCLUDES_DEFAULT]) dnl do a 2nd check to ensure inclusion of getopt.h, in case optind is known AC_CHECK_HEADERS(getopt.h, [ AC_DEFINE(NEED_GETOPT_H, 1, [Define if getopt.h is needed]) ], [ AC_DEFINE(NEED_GETOPT_DECLS, 1, [Define to use explicit getopt declarations]) ], [AC_INCLUDES_DEFAULT]) dnl also check for getopt_long AC_CHECK_FUNCS(getopt_long) dnl FreeBSD serial locking compatibility - look for uu_lock in libutil.h AC_CHECK_DECLS(uu_lock, [ AC_DEFINE(HAVE_UU_LOCK, 1, [Use uu_lock for locking (FreeBSD)]) SERLIBS="-lutil" dnl put in some better defaults for FreeBSD RUN_AS_USER="uucp" ], [ SERLIBS="" ], [ #include #include ]) AC_CHECK_DECLS(__func__, [], [ AC_CHECK_DECLS(__FUNCTION__, [ AC_DEFINE(__func__, __FUNCTION__, [Replace missing __func__ declaration]) ], [ AC_DEFINE(__func__, __LINE__, [Replace missing __func__ declaration]) ], [AC_INCLUDES_DEFAULT]) ], [AC_INCLUDES_DEFAULT]) dnl Solaris compatibility - check for -lnsl and -lsocket AC_SEARCH_LIBS(gethostbyname, nsl) AC_SEARCH_LIBS(connect, socket) AC_CHECK_HEADERS(sys/modem.h stdarg.h varargs.h, [], [], [AC_INCLUDES_DEFAULT]) dnl pthread related checks dnl Note: pthread_tryjoin_np() should be available since glibc 2.3.3, according dnl to https://man7.org/linux/man-pages/man3/pthread_tryjoin_np.3.html AC_SEARCH_LIBS([pthread_create], [pthread], [AC_DEFINE(HAVE_PTHREAD, 1, [Define to enable pthread support code]) AC_SEARCH_LIBS([pthread_tryjoin_np], [pthread], [AC_DEFINE(HAVE_PTHREAD_TRYJOIN, 1, [Define to enable pthread_tryjoin support code])], []) ], []) dnl ---------------------------------------------------------------------- dnl Check for types and define possible replacements NUT_TYPE_SOCKLEN_T NUT_CHECK_SOCKETLIB NUT_FUNC_GETNAMEINFO_ARGTYPES AC_CACHE_CHECK([for inet_ntop() with IPv4 and IPv6 support], [ac_cv_func_inet_ntop], [AC_LANG_PUSH([C]) dnl e.g. add "-lws2_32" for mingw builds dnl the NETLIBS are set by NUT_CHECK_SOCKETLIB above SAVED_LIBS="$LIBS" LIBS="$LIBS $NETLIBS" AX_RUN_OR_LINK_IFELSE( [AC_LANG_PROGRAM([[ #if HAVE_WINDOWS_H # undef inline # ifndef WIN32_LEAN_AND_MEAN # define WIN32_LEAN_AND_MEAN # endif # include # if HAVE_WINSOCK2_H # include # endif # if HAVE_WS2TCPIP_H # include # endif #else # include #endif #include ]], [[/* const char* inet_ntop(int af, const void* src, char* dst, size_t cnt); */ char buf[128]; printf("%s", inet_ntop(AF_INET, "1.2.3.4", buf, 10)); printf("%s", inet_ntop(AF_INET6, "::1", buf, 10)) /* autoconf adds ";return 0;" */ ]])], [ac_cv_func_inet_ntop=yes], [ac_cv_func_inet_ntop=no] ) AC_LANG_POP([C]) LIBS="$SAVED_LIBS" ]) AS_IF([test x"${ac_cv_func_inet_ntop}" = xyes], [AC_DEFINE([HAVE_INET_NTOP], 1, [defined if system has the inet_ntop() method])], [AC_MSG_WARN([Required C library routine inet_ntop() not found]) AS_CASE([${target_os}], [*mingw*], [AC_MSG_WARN([Windows antivirus might block this test])] ) ] ) AC_CACHE_CHECK([for inet_pton() with IPv4 and IPv6 support], [ac_cv_func_inet_pton], [AC_LANG_PUSH([C]) dnl e.g. add "-lws2_32" for mingw builds dnl the NETLIBS are set by NUT_CHECK_SOCKETLIB above SAVED_LIBS="$LIBS" LIBS="$LIBS $NETLIBS" AX_RUN_OR_LINK_IFELSE( [AC_LANG_PROGRAM([[ #if HAVE_WINDOWS_H # undef inline # ifndef WIN32_LEAN_AND_MEAN # define WIN32_LEAN_AND_MEAN # endif # include # if HAVE_WINSOCK2_H # include # endif # if HAVE_WS2TCPIP_H # include # endif #else # include #endif #include ]], [[/* int inet_pton(int af, const char *src, char *dst); */ struct in_addr ipv4; struct in6_addr ipv6; printf("%i ", inet_pton(AF_INET, "1.2.3.4", &ipv4)); printf("%i ", inet_pton(AF_INET6, "::1", &ipv6)) /* autoconf adds ";return 0;" */ ]])], [ac_cv_func_inet_pton=yes], [ac_cv_func_inet_pton=no] ) AC_LANG_POP([C]) LIBS="$SAVED_LIBS" ]) AS_IF([test x"${ac_cv_func_inet_pton}" = xyes], [AC_DEFINE([HAVE_INET_PTON], 1, [defined if system has the inet_pton() method])], [AC_MSG_WARN([Required C library routine inet_pton() not found]) AS_CASE([${target_os}], [*mingw*], [AC_MSG_WARN([Windows antivirus might block this test])] ) ] ) AC_CACHE_CHECK([for struct pollfd], [ac_cv_struct_pollfd], [AC_LANG_PUSH([C]) dnl e.g. add "-lws2_32" for mingw builds dnl the NETLIBS are set by NUT_CHECK_SOCKETLIB above SAVED_LIBS="$LIBS" LIBS="$LIBS $NETLIBS" AX_RUN_OR_LINK_IFELSE( [AC_LANG_PROGRAM([[ #if HAVE_WINDOWS_H # undef inline # ifndef WIN32_LEAN_AND_MEAN # define WIN32_LEAN_AND_MEAN # endif # include # if HAVE_WINSOCK2_H # include # endif # if HAVE_WS2TCPIP_H # include # endif #else # include #endif #include ]], [[ struct pollfd pfd; pfd.fd = 0; /* autoconf adds ";return 0;" */ ]])], [ac_cv_struct_pollfd=yes], [ac_cv_struct_pollfd=no] ) AC_LANG_POP([C]) LIBS="$SAVED_LIBS" ]) AS_IF([test x"${ac_cv_struct_pollfd}" = xyes], [AC_DEFINE([HAVE_STRUCT_POLLFD], 1, [defined if system has the struct pollfd type])], [AC_MSG_WARN([Required C library type struct pollfd not found]) AS_CASE([${target_os}], [*mingw*], [AC_MSG_WARN([Windows antivirus might block this test])] ) ] ) dnl ---------------------------------------------------------------------- dnl Check for python binary program names per language version dnl to embed into scripts and Make rules NUT_CHECK_PYTHON_DEFAULT dnl ---------------------------------------------------------------------- dnl check for --with-drivers=all (or --with-drivers=name[,name...]) flag dnl Note: a few drivers are NUT software constructs (NUTSW_DRIVERLIST) dnl e.g. dummy-ups, clone and clone-outlet; they do not have a separate dnl toggle or dependency at the moment. Earlier NUT releases before 2.8.0 dnl grouped them with serial drivers, which were enabled by default. dnl Autoconf versions before 2.62 do not allow consecutive quadrigraphs dnl (square brackets), so the help string depends on the version used AC_MSG_CHECKING(which drivers to build) AC_ARG_WITH(drivers, AS_HELP_STRING([m4_version_prereq(2.62, [@<:@--with-drivers=driver@<:@,driver@:>@@:>@], [[[[--with-drivers=driver@<:@,driver@:>@]]]])], [Only build specific drivers (all)]), [ case "${withval}" in yes|no|'') AC_MSG_ERROR(invalid option --with(out)-drivers - see docs/configure.txt) ;; all) dnl Explicit request to build all drivers (unless specified), or fail DRIVER_BUILD_LIST="all" if test -z "${with_serial}"; then with_serial="yes"; fi if test -z "${with_usb}"; then with_usb="yes"; fi if test -z "${with_snmp}"; then with_snmp="yes"; fi if test -z "${with_neon}"; then with_neon="yes"; fi if test -z "${with_powerman}"; then with_powerman="yes"; fi if test -z "${with_modbus}"; then with_modbus="yes"; fi if test -z "${with_ipmi}"; then with_ipmi="yes"; fi dnl Platform-dependent snowflakes that are required or auto: if test -z "${with_gpio}"; then dnl NOTE: Currently we only support a Linux libgpiod dnl backend for GPIO; eventually there could be more. case ${target_os} in linux*) with_gpio="auto";; dnl # TODO: Detect 2018+ distros? *) with_gpio="auto";; esac fi if test -z "${with_linux_i2c}"; then case ${target_os} in linux*) with_linux_i2c="yes";; *) with_linux_i2c="auto";; esac fi if test -z "${with_macosx_ups}"; then if test -d /System/Library/Frameworks/IOKit.framework/ ; then with_macosx_ups="yes" else with_macosx_ups="auto" fi fi AC_MSG_RESULT(${DRIVER_BUILD_LIST}) ;; auto) dnl Explicit request to build all drivers that we can DRIVER_BUILD_LIST="all" if test -z "${with_serial}"; then with_serial="${withval}"; fi if test -z "${with_usb}"; then with_usb="${withval}"; fi if test -z "${with_snmp}"; then with_snmp="${withval}"; fi if test -z "${with_neon}"; then with_neon="${withval}"; fi if test -z "${with_powerman}"; then with_powerman="${withval}"; fi if test -z "${with_modbus}"; then with_modbus="${withval}"; fi if test -z "${with_ipmi}"; then with_ipmi="${withval}"; fi if test -z "${with_gpio}"; then with_gpio="${withval}"; fi if test -z "${with_linux_i2c}"; then with_linux_i2c="${withval}"; fi if test -z "${with_macosx_ups}"; then with_macosx_ups="${withval}"; fi AC_MSG_RESULT(${DRIVER_BUILD_LIST}) ;; *) DRIVER_BUILD_LIST="`echo ${withval} | sed 's/,/ /g'`" AC_MSG_RESULT(${DRIVER_BUILD_LIST}) AS_IF([test -n "$DRIVER_BUILD_LIST"], [dnl DRVLIST is occasionally synced with drivers/Makefile.am dnl NOTE: Currently "USB_DRIVERLIST" is not used standalone: DRVLIST_NAMES="NUTSW_DRIVERLIST SERIAL_DRIVERLIST USB_LIBUSB_DRIVERLIST SERIAL_USB_DRIVERLIST SNMP_DRIVERLIST NEONXML_DRIVERLIST MACOSX_DRIVERLIST MODBUS_DRIVERLIST LINUX_I2C_DRIVERLIST POWERMAN_DRIVERLIST IPMI_DRIVERLIST GPIO_DRIVERLIST" get_drvlist() ( dnl Note escaped brackets - "against" m4 parser m4_version_prereq(2.62, [LB="@<:@"; RB="@:>@"], [LB="[["; RB="]]"] ) SPACE="`printf "$LB"' \t'"$RB"`" SPACES="${SPACE}*" sed -e "s/${SPACES}""$LB"'+'"$RB"'*='"${SPACES}/=/" \ -e "s/^${SPACES}//" < "$srcdir/drivers/Makefile.am" \ | { C=false; V=false while read LINE ; do case "$LINE" in *'\') C=true; if $V ; then echo "$LINE" ; fi ;; *) C=false; V=false ;; esac case "$LINE" in "$1"=*) echo "$LINE" | sed -e 's,^'"$LB"'^='"$RB"'*=,,' -e 's,\$,,' V=$C ;; esac done } | tr '\n' ' ' | sed -e "s,${SPACE}${SPACES}, ," -e "s,${SPACES}\$,," ) for DRVLIST_NAME in $DRVLIST_NAMES; do OUT="`get_drvlist "$DRVLIST_NAME"`" \ && test -n "$OUT" || OUT="" eval $DRVLIST_NAME="\$OUT" AC_MSG_NOTICE([Will check custom driver selection against $DRVLIST_NAME="$OUT"]) done dnl Note: do not quote the expansion below to keep it multi-token: for DRV in $DRIVER_BUILD_LIST ; do DRV_HITS="" dnl #DEVEL-DEBUG# AC_MSG_NOTICE([= Checking DRV="$DRV"]) for DRVLIST_NAME in $DRVLIST_NAMES; do dnl #DEVEL-DEBUG# AC_MSG_NOTICE([== Checking DRVLIST_NAME="$DRVLIST_NAME"]) eval DRVLIST="\${$DRVLIST_NAME}" dnl #DEVEL-DEBUG# AC_MSG_NOTICE([== Contents DRVLIST="$DRVLIST"]) for DN in $DRVLIST ; do dnl #DEVEL-DEBUG# AC_MSG_NOTICE([=== Checking DN="$DN"]) AS_IF([test x"$DN" = x"$DRV"], [ DRV_HITS="$DRV_HITS $DRVLIST_NAME" AS_CASE(["$DRVLIST_NAME"], [NUTSW_DRIVERLIST], [ AC_MSG_NOTICE([Building NUT-Software-only driver "$DRV"]) ], [SERIAL_DRIVERLIST], [ AS_IF([test -z "${with_serial}"], [AC_MSG_NOTICE([Requiring --with-serial=yes for driver "$DRV"]) with_serial=yes] )], [USB_LIBUSB_DRIVERLIST], [ AS_IF([test -z "${with_usb}"], [AC_MSG_NOTICE([Requiring --with-usb=yes for driver "$DRV"]) with_usb=yes] )], [SERIAL_USB_DRIVERLIST], [ dnl e.g. nutdrv_qx that can do both AS_IF([test -z "${with_usb}"], [AC_MSG_NOTICE([Requiring --with-usb=yes for driver "$DRV"]) with_usb=yes] ) AS_IF([test -z "${with_serial}"], [AC_MSG_NOTICE([Requiring --with-serial=yes for driver "$DRV"]) with_serial=yes] )], [SNMP_DRIVERLIST], [ AS_IF([test -z "${with_snmp}"], [AC_MSG_NOTICE([Requiring --with-snmp=yes for driver "$DRV"]) with_snmp=yes] )], [NEONXML_DRIVERLIST], [ AS_IF([test -z "${with_neon}"], [AC_MSG_NOTICE([Requiring --with-neon=yes for driver "$DRV"]) with_neon=yes] )], [MACOSX_DRIVERLIST], [ dnl NOTE: This one is a bit special, dnl just one certain driver so far AS_IF([test -z "${with_macosx_ups}"], [AC_MSG_NOTICE([Requiring --with-macosx-ups=yes for driver "$DRV"]) with_macosx_ups=yes] )], [MODBUS_DRIVERLIST], [ AS_IF([test -z "${with_modbus}"], [AC_MSG_NOTICE([Requiring --with-modbus=yes for driver "$DRV"]) with_modbus=yes] )], [LINUX_I2C_DRIVERLIST], [ AS_IF([test -z "${with_linux_i2c}"], [AC_MSG_NOTICE([Requiring --with-linux-i2c=yes for driver "$DRV"]) with_linux_i2c=yes] )], [POWERMAN_DRIVERLIST], [ AS_IF([test -z "${with_powerman}"], [AC_MSG_NOTICE([Requiring --with-powerman=yes for driver "$DRV"]) with_powerman=yes] )], [IPMI_DRIVERLIST], [ AS_IF([test -z "${with_ipmi}"], [AC_MSG_NOTICE([Requiring --with-ipmi=yes for driver "$DRV"]) with_ipmi=yes] )], [GPIO_DRIVERLIST], [ AS_IF([test -z "${with_gpio}"], [AC_MSG_NOTICE([Requiring --with-gpio=yes for driver "$DRV"]) with_gpio=yes] )], [AC_MSG_WARN([Unhandled DRVLIST_NAME=$DRVLIST_NAME])] ) break dnl Break once, maybe a driver hits several categories ]) done done AS_IF([test -z "${DRV_HITS}"], [AC_MSG_ERROR([Requested driver '$DRV' is not defined in drivers/Makefile.am (or configure.ac has a bug/lag detecting driver lists)])]) done ]) ;; esac ], [ dnl Implicit request to build whatever is enabled; dnl do not force --with-all here: DRIVER_BUILD_LIST="all" AC_MSG_RESULT(all available) ]) AM_CONDITIONAL(SOME_DRIVERS, test "${DRIVER_BUILD_LIST}" != "all") if test "${DRIVER_BUILD_LIST}" != "all"; then NUT_REPORT([only build specific drivers], [${DRIVER_BUILD_LIST}]) fi dnl ---------------------------------------------------------------------- dnl check for --with-all (or --without-all, or --with-all=auto) flag AC_MSG_CHECKING(for --with-all) AC_ARG_WITH(all, AS_HELP_STRING([--with-all], [enable serial, usb, snmp, neon, ipmi, powerman, modbus, gpio (currently on Linux released after ~2018), linux_i2c (on Linux), macosx-ups (on MacOS), cgi, dev, avahi, nut-scanner, pynut]), [ if test -n "${withval}"; then dnl Note: we allow "no" as a positive value, because dnl this is what the user expects from --without-all dnl Note: these settings do not touch generation of dnl "--with-docs=...", that is handled separately if test -z "${with_serial}"; then with_serial="${withval}"; fi if test -z "${with_usb}"; then with_usb="${withval}"; fi if test -z "${with_snmp}"; then with_snmp="${withval}"; fi if test -z "${with_neon}"; then with_neon="${withval}"; fi if test -z "${with_powerman}"; then with_powerman="${withval}"; fi if test -z "${with_modbus}"; then with_modbus="${withval}"; fi if test -z "${with_ipmi}"; then with_ipmi="${withval}"; fi dnl Platform-dependent snowflakes that are required or auto: if test -z "${with_gpio}"; then dnl NOTE: Currently we only support a Linux libgpiod dnl backend for GPIO; eventually there could be more. with_gpio="${withval}" case ${target_os} in linux*) ;; *) test x"${withval}" = xno || with_gpio="auto" ;; esac fi if test -z "${with_linux_i2c}"; then with_linux_i2c="${withval}" case ${target_os} in linux*) ;; *) test x"${withval}" = xno || with_linux_i2c="auto" ;; esac fi if test -z "${with_macosx_ups}"; then with_macosx_ups="${withval}" if ! test -d /System/Library/Frameworks/IOKit.framework/ ; then test x"${withval}" = xno || with_macosx_ups="auto" fi fi dnl These are not driver families, but other features: if test -z "${with_cgi}"; then with_cgi="${withval}"; fi if test -z "${with_dev}"; then with_dev="${withval}"; fi if test -z "${with_avahi}"; then with_avahi="${withval}"; fi if test -z "${with_nut_scanner}"; then with_nut_scanner="${withval}"; fi if test -n "${PYTHON}${PYTHON2}${PYTHON3}" -a x"${withval}" = xyes \ || test x"${withval}" != xyes \ ; then dnl We expect Python to be available (augeas etc), dnl so if it is present - try to provide the PyNUT dnl binding module: if test -z "${with_pynut}"; then with_pynut="${withval}"; fi dnl However, do not let "--with-all" break builds dnl on servers that lack some GUI modules in their dnl Python installations; "auto" is defaulted below. dnl # if test -z "${with_nut_monitor}"; then with_nut_monitor="${withval}"; fi fi AC_MSG_RESULT("${withval}") else AC_MSG_RESULT(not given) fi ], [ AC_MSG_RESULT(not given) ]) dnl ---------------------------------------------------------------------- dnl declare a number of --with-FEATURE options. Do this early, so that dnl they are listed near the top by "./configure --help"; however, dnl note that options with further investigation methods are listed dnl a bit below to be grouped with their additional with/enable help. NUT_ARG_WITH([dev], [build and install the development files], [no]) dnl Activate WITH_UNMAPPED_DATA_POINTS for troubleshooting and evolution? dnl Note that production drivers must conform to docs/nut-names.txt NUT_ARG_WITH([unmapped-data-points], [represent USB-HID and SNMP data points discovered during subdriver generation but not mapped to nut-names yet], [no]) AS_IF([test x"${nut_with_unmapped_data_points}" = xyes], [AC_DEFINE(WITH_UNMAPPED_DATA_POINTS, 1, [Define to enable data points discovered during subdriver generation but not mapped to nut-names yet])], [AC_DEFINE(WITH_UNMAPPED_DATA_POINTS, 0, [Define to enable data points discovered during subdriver generation but not mapped to nut-names yet])] ) dnl The NUT legacy option was --with-doc; however to simplify configuration dnl in some common packaging frameworks, we also allow --with-docs as dnl a second-class citizen (if both are set, the old option name wins). dnl Also note that the legacy default was "man=yes" due to requirements dnl of the "make distcheck", but it was reduced to "man=auto" so that dnl the usual builds can pass by default on systems without asciidoc. NUT_ARG_WITH([docs], [build and install documentation (alias to --with-doc)], [man=auto]) NUT_ARG_WITH([doc], [build and install documentation (see docs/configure.txt for many variants of the option)], [${nut_with_docs}]) dnl NOTE: Until X-Mas 2021, the default was "legacy" (now "medium") NUT_ARG_ENABLE([warnings], [enable warning presets that were picked as useful in maintainership and CI practice (variants include gcc-minimal, gcc-medium, gcc-hard, clang-minimal, clang-medium, clang-hard, all; auto-choosers: hard, medium, minimal, yes=auto='gcc or clang or all at hardcoded default difficulty')], [auto]) NUT_ARG_ENABLE([Werror], [fail the build if compiler emits any warnings (treat them as errors)], [no]) dnl To help find warning/error details in a wall of text, see --enable-Wcolor handled above dnl ---------------------------------------------------------------------- dnl Check for presence and compiler flags of various libraries NUT_ARG_WITH([serial], [build and install serial drivers], [yes]) dnl These checks are performed unconditionally, even if the corresponding dnl --with-* options are not given. This is because we cannot predict dnl what will be in the --with-drivers argument. NUT_CHECK_LIBREGEX NUT_ARG_WITH([usb], [build and install USB drivers, optionally require build with specified version of libusb library and API: (auto|libusb-0.1|libusb-1.0)], [auto]) nut_usb_lib="" NUT_CHECK_LIBUSB NUT_ARG_WITH([snmp], [build and install SNMP drivers], [auto]) NUT_CHECK_LIBNETSNMP NUT_ARG_WITH([neon], [build and install neon based XML/HTTP driver], [auto]) NUT_CHECK_LIBNEON NUT_ARG_WITH([powerman], [build and install Powerman PDU client driver], [auto]) NUT_CHECK_LIBPOWERMAN NUT_ARG_WITH([modbus], [build and install modbus drivers], [auto]) NUT_CHECK_LIBMODBUS NUT_ARG_WITH([gpio], [build and install GPIO driver], [auto]) NUT_CHECK_LIBGPIO NUT_ARG_WITH([avahi], [build and install Avahi support], [auto]) NUT_CHECK_LIBAVAHI NUT_ARG_WITH([ipmi], [build and install IPMI PSU driver], [auto]) NUT_ARG_WITH([freeipmi], [enable IPMI support using FreeIPMI], [auto]) dnl NUT_ARG_WITH([openipmi], [enable IPMI support using OpenIPMI], [auto]) dnl Platform-dependent drivers, currently their detection code is directly dnl spelled out in configure.ac NUT_ARG_WITH([macosx_ups], [build and install Mac OS X Power Sources meta-driver], [auto]) NUT_ARG_WITH([linux_i2c], [build and install i2c drivers], [auto]) dnl A Python GUI client application for the sysadmin desktop dnl (not necessarily on the NUT server itself): NUT_ARG_WITH([nut_monitor], [install the NUT-Monitor GUI files], [auto]) NUT_ARG_WITH([pynut], [install the PyNUT module files (yes, no, app, auto)], [auto]) dnl Note: we did NUT_CHECK_PYTHON2 NUT_CHECK_PYTHON3 etc above, dnl and if at all possible, we generate the files from .in templates dnl anyway by running this configure script. The question is about dnl installing these features or not. dnl Note: more for tests than other reasons, there is also an option dnl value to "force" the installation. dnl The gettext "msgfmt" tool (or equivalent) can be used to maintain dnl human-language text translations. Currently this is used specifically dnl in the Python NUT-Monitor app sources (*.po => *.mo conversions). AC_PATH_PROGS([MSGFMT], [msgfmt], [none]) AM_CONDITIONAL([HAVE_MSGFMT], [test "x${MSGFMT}" != "xnone"]) dnl ---------------------------------------------------------------------- dnl checks related to --with-serial dnl ${nut_with_serial}: any value except "yes" or "no" is treated as "auto". dnl Below we try to detect if we can build serial drivers, and if we must? AS_IF([test "${nut_with_serial}" != "no"], [AS_IF([test "${nut_with_serial}" != "yes"],[nut_with_serial="auto"]) CFLAGS_SAVED_SERIAL="${CFLAGS}" AS_IF([test "${GCC}" = yes], [CFLAGS_SAVED_WERROR="${CFLAGS} -Wall -Werror" CFLAGS_SAVED_WNOERROR="${CFLAGS} -Wno-error" ], [CFLAGS_SAVED_WERROR="${CFLAGS}" CFLAGS_SAVED_WNOERROR="${CFLAGS}" ]) dnl At least recent *BSD distros have deprecated sys/termios.h and spew dnl warnings that termios.h should be used instead. This is redundantly dnl fatal for pedantic builds where we aim to have no warnings in code. dnl So there AC_CHECK_HEADERS does find the header, but we don't really dnl want to use it unless we have no choice: if there is a warning while dnl trying sys/ version, try the plain header path (without fatal warnings), dnl and only if that is missing - retry with the sys/ version again (and dnl no warnings still). CFLAGS="${CFLAGS_SAVED_WERROR}" AC_CHECK_HEADERS(sys/termios.h, [], [ CFLAGS="${CFLAGS_SAVED_WNOERROR}" AC_CHECK_HEADERS(termios.h, [], [ AC_CHECK_HEADERS(sys/termios.h, [], [], [AC_INCLUDES_DEFAULT]) ], [AC_INCLUDES_DEFAULT]) ], [AC_INCLUDES_DEFAULT]) dnl CFLAGS at this point suffice for surviving a compilation with termios.h dnl Don't mind the stupid code below, it just probes the tokens and dnl sails around compiler warnings AC_MSG_CHECKING([for struct termios and speed_t]) AC_LANG_PUSH([C]) AC_COMPILE_IFELSE([AC_LANG_PROGRAM([ #if defined(HAVE_SYS_TERMIOS_H) # include /* for speed_t */ #else # if defined(HAVE_TERMIOS_H) # include # endif /* HAVE_TERMIOS_H */ #endif /* HAVE_SYS_TERMIOS_H */ void getspeed(speed_t* b) { *b = B19200; } ], [struct termios tio; if (!tcgetattr(0, &tio)) { return 1; } speed_t baudrate; getspeed(&baudrate); ] )], [AC_MSG_RESULT([ok]) nut_have_serial_types=yes ], [AC_MSG_RESULT([no, struct termios and/or speed_t not found in discovered headers]) nut_have_serial_types=no ] ) AC_LANG_POP([C]) dnl Restore common set-or-discovered CFLAGS CFLAGS="${CFLAGS_SAVED_SERIAL}" AC_MSG_CHECKING([whether we can build serial drivers]) AS_CASE(["${target_os}"], [*mingw*], [ AS_IF([test "${nut_have_serial_types}" != yes], [AC_MSG_WARN([not with system includes, but can try with our fallback for the target platform]) nut_have_serial_types=yes] ) ]) AS_IF([test "${nut_have_serial_types}" = yes], [AS_IF([test "${nut_with_serial}" = "auto"],[nut_with_serial="yes"])], [AS_IF([test "${nut_with_serial}" = "auto"],[nut_with_serial="no"]) AS_IF([test "${nut_with_serial}" = "yes"],[AC_MSG_ERROR([no, and were required to])]) ]) AS_IF([test "${nut_with_serial}" = "yes"], [AC_MSG_RESULT([yes])], [AC_MSG_RESULT([no])]) ]) NUT_REPORT_FEATURE([build serial drivers], [${nut_with_serial}], [], [WITH_SERIAL], [Define to enable serial support]) dnl ---------------------------------------------------------------------- dnl checks related to --with-usb are in its m4 file and NUT_CHECK_LIBUSB() called above dnl Note: there is no libusb-config script (and variable) for libusb-1.0 AM_CONDITIONAL(WITH_LIBUSB_1_0, test "${nut_usb_lib}" = "(libusb-1.0)") AM_CONDITIONAL(WITH_LIBUSB_0_1, test "${nut_usb_lib}" = "(libusb-0.1)" -o "${nut_usb_lib}" = "(libusb-0.1-config)") NUT_REPORT_FEATURE([build USB drivers], [${nut_with_usb}], [${nut_usb_lib}], [WITH_USB], [Define to enable USB support]) dnl ---------------------------------------------------------------------- dnl checks related to --with-neon dnl ${nut_with_neon}: any value except "yes" or "no" is treated as "auto". if test "${nut_with_neon}" = "yes" -a "${nut_have_neon}" != "yes"; then AC_MSG_ERROR([neon libraries not found, required for neon based XML/HTTP driver]) fi if test "${nut_with_neon}" != "no"; then nut_with_neon="${nut_have_neon}" fi NUT_REPORT_FEATURE([build neon based XML driver], [${nut_with_neon}], [], [WITH_NEON], [Define to enable Neon HTTP support]) AM_CONDITIONAL([HAVE_NEON], [test "${nut_have_neon}" = "yes"]) dnl ---------------------------------------------------------------------- dnl checks related to --with-avahi dnl ${nut_with_avahi}: any value except "yes" or "no" is treated as "auto". if test "${nut_with_avahi}" = "yes" -a "${nut_have_avahi}" != "yes"; then AC_MSG_ERROR([avahi libraries not found]) fi if test "${nut_with_avahi}" != "no"; then nut_with_avahi="${nut_have_avahi}" fi NUT_REPORT_FEATURE([enable Avahi support], [${nut_with_avahi}], [], [WITH_AVAHI], [Define to enable Avahi support]) dnl ---------------------------------------------------------------------- dnl checks related to --with-powerman dnl ${nut_with_powerman}: any value except "yes" or "no" is treated as "auto". if test "${nut_with_powerman}" = "yes" -a "${nut_have_libpowerman}" != "yes"; then AC_MSG_ERROR([Powerman client libraries not found, required for Powerman PDU client driver]) fi if test "${nut_with_powerman}" != "no"; then nut_with_powerman="${nut_have_libpowerman}" fi NUT_REPORT_FEATURE([build Powerman PDU client driver], [${nut_with_powerman}], [], [WITH_LIBPOWERMAN], [Define to enable Powerman PDU support]) dnl ---------------------------------------------------------------------- dnl checks related to --with-modbus dnl ${nut_with_modbus}: any value except "yes" or "no" is treated as "auto". if test "${nut_with_modbus}" = "yes" -a "${nut_have_libmodbus}" != "yes"; then AC_MSG_ERROR([modbus library not found, required for Modbus driver]) fi if test "${nut_with_modbus}" != "no"; then nut_with_modbus="${nut_have_libmodbus}" fi NUT_REPORT_FEATURE([build Modbus driver], [${nut_with_modbus}], [], [WITH_MODBUS], [Define to enable Modbus support]) dnl ---------------------------------------------------------------------- dnl Check for with-ipmi, and --with-freeipmi (or --with-openipmi) dnl Only one can be enabled at a time, with a preference for FreeIPMI dnl if both are available (since it is the only one supported ATM!!) nut_ipmi_lib="" dnl ${nut_with_ipmi}: any value except "yes" or "no" is treated as "auto". if test "${nut_with_ipmi}" != "no"; then dnl check if FreeIPMI (and maybe later OpenIPMI) was explicitly requested if test "${nut_with_freeipmi}" = "yes"; then NUT_CHECK_LIBFREEIPMI if test "${nut_have_freeipmi}" != "yes"; then AC_MSG_ERROR([FreeIPMI not found, required for IPMI support]) fi dnl Implies --with-ipmi nut_with_ipmi="yes" dnl elif test "${nut_with_openipmi}" = "yes"; then dnl AC_MSG_ERROR([OpenIPMI is not yet supported]) dnl NUT_CHECK_LIBOPENIPMI dnl if test "${nut_have_openipmi}" != "yes"; then dnl AC_MSG_ERROR([OpenIPMI not found, required for IPMI support]) dnl fi dnl Implies --with-ipmi dnl nut_with_ipmi="yes" dnl AC_DEFINE(WITH_OPENIPMI, 1, [Define to enable IPMI support using OpenIPMI]) else dnl Prefer FreeIPMI over OpenIPMI otherwise NUT_CHECK_LIBFREEIPMI if test "${nut_have_freeipmi}" != "yes"; then if test "${nut_with_ipmi}" = "yes"; then AC_MSG_ERROR([FreeIPMI not found, required for IPMI support]) fi nut_with_ipmi="no" dnl NUT_CHECK_OPENIPMI dnl if test "${nut_have_openipmi}" != "yes"; then dnl if test "${nut_with_ipmi}" = "yes"; then dnl AC_MSG_ERROR([Neither GNU FreeIPMI nor OpenIPMI was found (required for IPMI support)]) dnl fi dnl nut_with_ipmi="no" dnl else dnl Implies --with-ipmi dnl nut_with_ipmi="yes" dnl nut_with_openipmi="yes" dnl fi else dnl Implies --with-ipmi nut_with_ipmi="yes" nut_with_freeipmi="yes" AC_DEFINE(WITH_FREEIPMI, 1, [Define to enable IPMI support using FreeIPMI]) fi fi fi NUT_REPORT_FEATURE([build IPMI driver], [${nut_with_ipmi}], [${nut_ipmi_lib}], [WITH_IPMI], [Define to enable IPMI support]) dnl Note: we still have to manually enable complementary AC_DEFINEs (see above) dnl and AM_CONDITIONALs (see below)... AM_CONDITIONAL(WITH_FREEIPMI, test "${nut_with_freeipmi}" = "yes") dnl AM_CONDITIONAL(WITH_OPENIPMI, test "${nut_with_openipmi}" = "yes") dnl ---------------------------------------------------------------------- dnl Check for with-gpio if test "${nut_with_gpio}" = "yes" -a "${nut_have_gpio}" != "yes"; then AC_MSG_ERROR([No supported GPIO library was found, required for GPIO driver]) fi dnl ${nut_with_gpio}: any value except "yes" or "no" is treated as "auto". if test "${nut_with_gpio}" != "no"; then nut_with_gpio="${nut_have_gpio}" fi NUT_REPORT_FEATURE([build GPIO driver], [${nut_with_gpio}], [${nut_gpio_lib}], [WITH_GPIO], [Define to enable GPIO support]) dnl ---------------------------------------------------------------------- dnl The Mac OS X meta-driver looks at IOKit Power Sources keys managed by dnl the internal USB UPS driver. dnl dnl FIXME: be slightly more clever here: if test "${nut_with_macosx_ups}" != no; then if test -d /System/Library/Frameworks/IOKit.framework/ ; then nut_with_macosx_ups="yes" else if test "${nut_with_macosx_ups}" = yes; then AC_MSG_ERROR([macosx-ups was required but can not be fulfilled for this build: not MacOS]) fi nut_with_macosx_ups="no" fi fi NUT_REPORT_FEATURE([build Mac OS X meta-driver], [${nut_with_macosx_ups}], [${nut_macosx_ups_lib}], [WITH_MACOSX], [Define to enable Mac OS X meta-driver]) dnl ---------------------------------------------------------------------- dnl checks related to --with_linux_i2c dnl Check for i2c header on Linux, used for ASEM UPS driver LIBI2C_LIBS="" if test "${nut_with_linux_i2c}" != no; then case ${target_os} in linux* ) AC_CHECK_HEADER( [linux/i2c-dev.h], [AC_DEFINE([HAVE_LINUX_I2C_DEV_H], [1], [Define to 1 if you have .])] ) AC_CHECK_HEADER( [i2c/smbus.h], [AC_DEFINE([HAVE_LINUX_SMBUS_H], [1], [Define to 1 if you have .])] ) AC_CHECK_DECLS( [i2c_smbus_access, i2c_smbus_read_byte_data, i2c_smbus_write_byte_data, i2c_smbus_read_word_data, i2c_smbus_write_word_data, i2c_smbus_read_block_data], [], dnl # nut_with_linux_i2c="yes" [AS_IF([test "${nut_with_linux_i2c}" = "yes"], [AC_MSG_ERROR(i2c was required but can not be fulfilled for this build)], [nut_with_linux_i2c="no"])], [#include #ifdef HAVE_LINUX_I2C_DEV_H #include #endif #ifdef HAVE_LINUX_SMBUS_H #include #endif ] ) dnl Builds for bitness/arch other than system default can be dnl "compromised" by lack of respective binary library, so dnl even if we have the right headers, ultimate link fails. dnl Note: here we keep the verdict from above, or make it worse. LIBS_SAVED="$LIBS" LIBS="" AC_SEARCH_LIBS([i2c_smbus_read_byte, i2c_smbus_access, i2c_smbus_read_byte_data, i2c_smbus_write_byte_datai2c_smbus_write_byte_data, i2c_smbus_read_word_data, i2c_smbus_write_word_data, i2c_smbus_read_block_data], [i2c], [nut_with_linux_i2c="yes"], [AS_IF([test "${nut_with_linux_i2c}" = "yes"], [AC_MSG_ERROR(i2c was required but can not be fulfilled for this build)], [nut_with_linux_i2c="no"]) ]) LIBI2C_LIBS="$LIBS" LIBS="$LIBS_SAVED" ;; * ) if test "${nut_with_linux_i2c}" = yes; then AC_MSG_ERROR([i2c was required but can not be fulfilled for this build: not linux]) fi nut_with_linux_i2c="no" ;; esac fi NUT_REPORT_FEATURE( [build i2c based drivers], [${nut_with_linux_i2c}], [], [WITH_LINUX_I2C], [Define to enable I2C support] ) dnl ---------------------------------------------------------------------- dnl Check for with-ssl, and --with-nss or --with-openssl dnl Only one can be enabled at a time, with a preference for OpenSSL dnl if both are available nut_ssl_lib="" NUT_ARG_WITH([ssl], [enable SSL support (either NSS or OpenSSL)], [auto]) NUT_ARG_WITH([nss], [enable SSL support using Mozilla NSS], [auto]) NUT_ARG_WITH([openssl], [enable SSL support using OpenSSL], [auto]) dnl ${nut_with_ssl}: any value except "yes" or "no" is treated as "auto". if test "${nut_with_ssl}" != "no"; then dnl check if either NSS or OpenSSL was explicitly requested if test "${nut_with_nss}" = "yes"; then NUT_CHECK_LIBNSS if test "${nut_have_libnss}" != "yes"; then AC_MSG_ERROR([Mozilla NSS not found (required for SSL support)]) fi elif test "${nut_with_openssl}" = "yes"; then NUT_CHECK_LIBOPENSSL if test "${nut_have_openssl}" != "yes"; then AC_MSG_ERROR([OpenSSL not found (required for SSL support)]) fi else dnl Prefer OpenSSL over NSS otherwise NUT_CHECK_LIBOPENSSL if test "${nut_have_openssl}" != "yes"; then NUT_CHECK_LIBNSS if test "${nut_have_libnss}" != "yes"; then dnl Only abort if SSL has been explicitly requested by the user if test "${nut_with_ssl}" = "yes"; then AC_MSG_ERROR([Neither Mozilla NSS nor OpenSSL was found, but one is needed for the requested SSL support.]) else AC_MSG_WARN([Neither Mozilla NSS nor OpenSSL was found (required for SSL support)]) fi nut_with_ssl="no" else nut_with_nss="${nut_have_libnss}" fi else nut_with_openssl="${nut_have_openssl}" fi fi fi AM_CONDITIONAL(WITH_NSS, test "${nut_with_nss}" = "yes") AM_CONDITIONAL(WITH_OPENSSL, test "${nut_with_openssl}" = "yes") NUT_REPORT_FEATURE([enable SSL support], [${nut_with_ssl}], [${nut_ssl_lib}], [WITH_SSL], [Define to enable SSL]) dnl ---------------------------------------------------------------------- dnl Check for --with-wrap NUT_ARG_WITH([wrap], [enable libwrap (tcp-wrappers) support], [auto]) dnl ${nut_with_wrap}: any value except "yes" or "no" is treated as "auto". if test "${nut_with_wrap}" != "no"; then dnl check for libwrap compiler flags NUT_CHECK_LIBWRAP fi if test "${nut_with_wrap}" = "yes" -a "${nut_have_libwrap}" != "yes"; then AC_MSG_ERROR([libwrap not found]) fi if test "${nut_with_wrap}" != "no"; then nut_with_wrap="${nut_have_libwrap}" fi NUT_REPORT_FEATURE([enable libwrap (tcp-wrappers) support], [${nut_with_wrap}], [], [WITH_WRAP], [Define to enable libwrap (tcp-wrappers) support]) dnl ---------------------------------------------------------------------- dnl Check for --with-libltdl and --with-nut-scanner dnl Note: libltdl is primarily used by nut-scanner now; however some dnl side projects and forks of NUT have more creative uses for it dnl and might eventually land in NUT codebase proper. NUT_ARG_WITH([libltdl], [enable libltdl (Libtool dlopen abstraction) support], [auto]) dnl Note: default could be overridden above by --with-all handling. dnl While nut-scanner decides at run-time if it would use third-party shared dnl library files (bundled along or not, if available for the platform), its dnl binary must be configured now and built against their headers at least. NUT_ARG_WITH([nut-scanner], [build and install nut-scanner tool (requires libltdl; optionally libusb, libneon, libsnmp)], [auto]) dnl ${nut_with_libltdl}: any value except "yes" or "no" is treated as "auto". if test x"${nut_with_libltdl}" != x"no"; then if test x"${nut_with_nut_scanner}" = x"yes"; then dnl Require libltdl to be present (or fail the configure script) nut_with_libltdl="yes" fi dnl check for libltdl compiler flags NUT_CHECK_LIBLTDL fi if test x"${nut_with_libltdl}" = x"yes" -a x"${nut_have_libltdl}" != x"yes"; then AC_MSG_ERROR([libltdl not found]) fi if test x"${nut_with_libltdl}" != x"no"; then nut_with_libltdl="${nut_have_libltdl}" fi NUT_REPORT_FEATURE([enable libltdl (Libtool dlopen abstraction) support], [${nut_with_libltdl}], [], [WITH_LIBLTDL], [Define to enable libltdl (Libtool dlopen abstraction) support]) if test x"${nut_with_libltdl}" = x"no" && test x"${nut_with_nut_scanner}" = x"yes"; then AC_MSG_ERROR([libltdl support was disabled or not found, but --with-nut-scanner was requested and requires it]) fi if test x"${nut_with_nut_scanner}" = x"auto"; then nut_with_nut_scanner="${nut_with_libltdl}" fi NUT_REPORT_FEATURE([build nut-scanner], [${nut_with_nut_scanner}], [], [WITH_NUT_SCANNER], [Define to enable nut-scanner tool support]) dnl ---------------------------------------------------------------------- dnl checks related to --with-cgi NUT_ARG_WITH([cgi], [build and install the CGI programs], [no]) dnl ${nut_with_cgi}: any value except "yes" or "no" is treated as "auto". if test "${nut_with_cgi}" != "no"; then dnl check for libgd compiler flags NUT_CHECK_LIBGD fi if test "${nut_with_cgi}" = "yes" -a "${nut_have_libgd}" != "yes"; then AC_MSG_ERROR([libgd not found, required for CGI build]) fi if test "${nut_with_cgi}" != "no"; then nut_with_cgi="${nut_have_libgd}" fi NUT_REPORT_FEATURE([build CGI programs], [${nut_with_cgi}], [], [WITH_CGI], [Define to enable CGI (HTTP) support]) dnl ---------------------------------------------------------------------- dnl checks related to --with-pynut and --with-nut_monitor dnl ${nut_with_nut_monitor}: TODO: arg values to request python 2 gtk2, dnl python 3 qt5, or both AC_MSG_CHECKING([if we can and should install NUT-Monitor desktop application]) nut_with_nut_monitor_py2gtk2="" nut_with_nut_monitor_py3qt5="" nut_with_nut_monitor_desktop="" dnl TODO: Add a way to define this path? will have app/ maybe module/ inside... nut_with_nut_monitor_dir="${datarootdir}/nut-monitor" PYTHON_FAILED_TEST_DETAILS="" if test x"${nut_with_nut_monitor}" != xno ; then dnl While we might just install for "yes" request, in hopes user would dnl get their python ecosystem in place later, we need some criteria to dnl avoid installing it always :) Also, need to substitute the shebang. if test -z "${PYTHON}${PYTHON2}${PYTHON3}" ; then case "${nut_with_nut_monitor}" in "auto") nut_with_nut_monitor="no" PYTHON_FAILED_TEST_DETAILS="No python 2/3 interpreter was found" ;; "yes") AC_MSG_ERROR([No python 2/3 interpreter was found, required for NUT-Monitor desktop application]) ;; esac fi fi if test x"${nut_with_nut_monitor}" != xno ; then dnl Note: no double-quoting for use, the command string may be multi-token dnl HACK NOTE: Here we redirect outputs to "&5" which is autoconf stream dnl for "config.log" details since... forever? Still, hardcoded numbers... PYTHON2_TEST_MODULES="re,glob,codecs,gtk,gtk.glade,gobject,ConfigParser" PYTHON3_TEST_MODULES="re,glob,codecs,PyQt5.uic,configparser" if test -n "${PYTHON2}" \ && (command -v ${PYTHON2} || which ${PYTHON2}) >/dev/null 2>/dev/null \ ; then if ${PYTHON2} -c "import ${PYTHON2_TEST_MODULES}" 1>&5 2>&5 \ ; then nut_with_nut_monitor_py2gtk2="yes" else PYTHON_FAILED_TEST_DETAILS="Missing some or all of these Python2 modules: '${PYTHON2_TEST_MODULES}'" fi fi if test -n "${PYTHON3}" \ && (command -v ${PYTHON3} || which ${PYTHON3}) >/dev/null 2>/dev/null \ ; then if ${PYTHON3} -c "import ${PYTHON3_TEST_MODULES}" 1>&5 2>&5 \ ; then nut_with_nut_monitor_py3qt5="yes" else PYTHON_FAILED_TEST_DETAILS="Missing some or all of these Python3 modules: '${PYTHON3_TEST_MODULES}'" fi fi dnl Fall back to default interpreter if test -z "${nut_with_nut_monitor_py2gtk2}${nut_with_nut_monitor_py3qt5}" \ && test -n "${PYTHON}" \ && (command -v ${PYTHON} || which ${PYTHON2}) >/dev/null 2>/dev/null \ ; then if ${PYTHON} -c "import ${PYTHON3_TEST_MODULES}" 1>&5 2>&5 \ ; then nut_with_nut_monitor_py3qt5="yes" else PYTHON_FAILED_TEST_DETAILS="Missing some or all of these Python3 modules: '${PYTHON3_TEST_MODULES}'" fi if ${PYTHON} -c "import ${PYTHON2_TEST_MODULES}" 1>&5 2>&5 \ ; then nut_with_nut_monitor_py2gtk2="yes" PYTHON_FAILED_TEST_DETAILS="" else if test -n "${PYTHON_FAILED_TEST_DETAILS}" ; then PYTHON_FAILED_TEST_DETAILS="${PYTHON_FAILED_TEST_DETAILS} and some or all of these Python2 modules: '${PYTHON2_TEST_MODULES}'" else PYTHON_FAILED_TEST_DETAILS="Missing some or all of these Python2 modules: '${PYTHON2_TEST_MODULES}'" fi fi fi dnl Can we satisfy any NUT-Monitor installation request? if test -n "${nut_with_nut_monitor_py2gtk2}${nut_with_nut_monitor_py3qt5}" ; then case "${nut_with_nut_monitor}" in "auto") nut_with_nut_monitor="yes" ;; esac else case "${nut_with_nut_monitor}" in "auto") nut_with_nut_monitor="no" ;; "yes") AC_MSG_ERROR([No python 2/3 interpreter with needed modules was found, as required for NUT-Monitor desktop application: ${PYTHON_FAILED_TEST_DETAILS}]) ;; esac fi fi case "${nut_with_nut_monitor}" in "no") if test -n "${PYTHON_FAILED_TEST_DETAILS}" ; then AC_MSG_RESULT([${nut_with_nut_monitor}: ${PYTHON_FAILED_TEST_DETAILS}]) else AC_MSG_RESULT([${nut_with_nut_monitor}]) fi ;; *) AC_MSG_RESULT([${nut_with_nut_monitor}]) ;; esac if test x"${nut_with_nut_monitor}" != xno ; then if (command -v desktop-file-install || which desktop-file-install) >/dev/null 2>/dev/null ; then case "${nut_with_nut_monitor}" in "auto"|"yes") nut_with_nut_monitor_desktop="desktop-file-install" ;; esac else case "${nut_with_nut_monitor}" in "yes") AC_MSG_WARN([Current OS does not seem to provide desktop-file-install]) nut_with_nut_monitor_desktop="install" ;; "auto") nut_with_nut_monitor_desktop="install" ;; esac fi fi dnl ${nut_with_pynut}: TODO: arg values to request python 2, 3 or both AC_MSG_CHECKING([if we can and should install PyNUT module]) nut_with_pynut_py="" nut_with_pynut_py2="" nut_with_pynut_py3="" if test x"${nut_with_pynut}" != xno \ -a -n "${PYTHON}${PYTHON2}${PYTHON3}" \ ; then if test -n "${PYTHON2}" \ && (command -v ${PYTHON2} || which ${PYTHON2}) >/dev/null 2>/dev/null \ ; then if ${PYTHON2} -c "import telnetlib" \ ; then nut_with_pynut_py2="yes" fi fi if test -n "${PYTHON3}" \ && (command -v ${PYTHON3} || which ${PYTHON3}) >/dev/null 2>/dev/null \ ; then if ${PYTHON3} -c "import telnetlib" \ ; then nut_with_pynut_py3="yes" fi fi dnl Test same-ness of pythons with sys.version also? if test -n "${PYTHON}" \ && (command -v ${PYTHON} || which ${PYTHON}) >/dev/null 2>/dev/null \ && test "${PYTHON}" != "${PYTHON2}" -a "${PYTHON}" != "${PYTHON3}" \ ; then if ${PYTHON} -c "import telnetlib" \ ; then nut_with_pynut_py="yes" fi fi fi if test -z "${nut_with_pynut_py}${nut_with_pynut_py2}${nut_with_pynut_py3}" ; then dnl Not all prereqs are available... case "${nut_with_pynut}" in "auto"|"app") if test "${nut_with_nut_monitor}" = yes ; then AC_MSG_ERROR([Prerequisites for PyNUT not found, can't install as required for NUT-Monitor desktop application]) else nut_with_pynut="no" fi ;; "yes") AC_MSG_ERROR([Prerequisites for PyNUT not found, can't install as required]) ;; esac fi if test x"${nut_with_pynut}" != xno ; then if test -n "${PYTHON_SITE_PACKAGES}${PYTHON2_SITE_PACKAGES}${PYTHON3_SITE_PACKAGES}" \ ; then dnl retain "app" if requested by caller case "${nut_with_pynut}" in "auto") nut_with_pynut="yes" ;; esac else case "${nut_with_pynut}" in "auto") if test "${nut_with_nut_monitor}" = yes -o "${nut_with_nut_monitor}" = force ; then nut_with_pynut="app" else nut_with_pynut="no" fi ;; "yes") dnl Note: this would die for --with-nut_monitor=yes but no site location if test "${nut_with_nut_monitor}" = yes -o "${nut_with_nut_monitor}" = force ; then nut_with_pynut="app" else AC_MSG_ERROR([python interpreter and/or its site-packages location not found, but required for PyNUT]) fi ;; esac fi fi AC_MSG_RESULT([${nut_with_pynut}]) dnl Note: do not move up to before pynut processing if test "${nut_with_nut_monitor}" = force ; then AC_MSG_NOTICE([overriding nut_with_nut_monitor=yes because caller forced it]) nut_with_nut_monitor=yes nut_with_nut_monitor_py2gtk2=yes nut_with_nut_monitor_py3qt5=yes fi if test "${nut_with_pynut}" = force ; then AC_MSG_NOTICE([overriding nut_with_pynut=yes because caller forced it]) if test "${nut_with_nut_monitor}" = yes ; then nut_with_pynut=app else nut_with_pynut=yes fi fi NUT_REPORT_FEATURE([install NUT-Monitor desktop application], [${nut_with_nut_monitor}], [], [WITH_NUT_MONITOR], [Define to enable NUT-Monitor desktop application installation]) NUT_REPORT_FEATURE([install PyNUT binding module], [${nut_with_pynut}], [], [WITH_PYNUT], [Define to enable PyNUT module installation]) dnl One or both of these may be installed: AM_CONDITIONAL(WITH_NUT_MONITOR, test "${nut_with_nut_monitor}" = "yes" && test "${nut_with_nut_monitor_py2gtk2}" = "yes" -o "${nut_with_nut_monitor_py3qt5}" = "yes") AM_CONDITIONAL(WITH_NUT_MONITOR_PY2GTK2, test "${nut_with_nut_monitor_py2gtk2}" = "yes") AM_CONDITIONAL(WITH_NUT_MONITOR_PY3QT5, test "${nut_with_nut_monitor_py3qt5}" = "yes") dnl Install PyNUT as a globally usable module, or just as app internals? AM_CONDITIONAL(WITH_PYNUT_PY, test "${nut_with_pynut_py}" = "yes" -a "${nut_with_pynut}" = yes) AM_CONDITIONAL(WITH_PYNUT_PY2, test "${nut_with_pynut_py2}" = "yes" -a "${nut_with_pynut}" = yes) AM_CONDITIONAL(WITH_PYNUT_PY3, test "${nut_with_pynut_py3}" = "yes" -a "${nut_with_pynut}" = yes) AM_CONDITIONAL(WITH_PYNUT_APP, test "${nut_with_pynut}" = "app") AC_SUBST([nut_with_nut_monitor_dir], [${nut_with_nut_monitor_dir}]) AC_SUBST([nut_with_nut_monitor_py2gtk2], [${nut_with_nut_monitor_py2gtk2}]) AC_SUBST([nut_with_nut_monitor_py3qt5], [${nut_with_nut_monitor_py3qt5}]) AC_SUBST([nut_with_nut_monitor_desktop], [${nut_with_nut_monitor_desktop}]) AC_SUBST([nut_with_nut_monitor], [${nut_with_nut_monitor}]) AC_SUBST([nut_with_pynut], [${nut_with_pynut}]) AC_SUBST([nut_with_pynut_py], [${nut_with_pynut_py}]) AC_SUBST([nut_with_pynut_py2], [${nut_with_pynut_py2}]) AC_SUBST([nut_with_pynut_py3], [${nut_with_pynut_py3}]) AS_IF([test "${nut_with_nut_monitor}" != no -o "${nut_with_pynut}" != no], [ NUT_REPORT([use default Python interpreter], [${PYTHON}]) NUT_REPORT([use specific Python2 interpreter], [${PYTHON2}]) NUT_REPORT([use specific Python3 interpreter], [${PYTHON3}]) NUT_REPORT_PATH_INTEGRATIONS([Default Python interpreter site-packages], [${PYTHON_SITE_PACKAGES}]) NUT_REPORT_PATH_INTEGRATIONS([Specific Python2 interpreter site-packages], [${PYTHON2_SITE_PACKAGES}]) NUT_REPORT_PATH_INTEGRATIONS([Specific Python3 interpreter site-packages], [${PYTHON3_SITE_PACKAGES}]) dnl # Python site-packages installation path for specific Python3 interpreter ]) dnl ---------------------------------------------------------------------- dnl checks related to --enable-cppcheck dnl Currently this is experimental; maybe change default to auto in the future dnl At that point, see also defaults in ci_build.sh then (to avoid the workload dnl unless desired). NUT_ARG_ENABLE([cppcheck], [Run a cppcheck on the codebase among checks], [no]) NUT_CHECK_CPPCHECK AC_MSG_CHECKING(whether to run cppcheck among default make check target) case "${nut_enable_cppcheck}" in yes) if test "${nut_have_cppcheck}" = "no" ; then AC_MSG_ERROR([Requested to --enable-cppcheck but did not find a good one]) fi WITH_CPPCHECK=yes ;; no) WITH_CPPCHECK=no ;; auto) if test "${nut_have_cppcheck}" = "yes" ; then WITH_CPPCHECK=yes else WITH_CPPCHECK=no fi ;; esac AC_MSG_RESULT([${WITH_CPPCHECK}]) AM_CONDITIONAL(WITH_CPPCHECK, test "${WITH_CPPCHECK}" = "yes") dnl ---------------------------------------------------------------------- dnl checks related to --enable-check-NIT AC_MSG_CHECKING(whether to run NIT among default make check target) nut_enable_check_NIT="no" AC_ARG_ENABLE([check-NIT], AS_HELP_STRING([--enable-check-NIT], [Run check-NIT among default checks (no)]), [ case "${enableval}" in no) AC_MSG_RESULT(no) ;; *) AC_MSG_RESULT(yes) nut_enable_check_NIT="yes" ;; esac ], [ AC_MSG_RESULT(no) ]) AM_CONDITIONAL(WITH_CHECK_NIT, test "${nut_enable_check_NIT}" = "yes") dnl ---------------------------------------------------------------------- dnl checks related to --enable-spellcheck NUT_CHECK_ASPELL NUT_ARG_ENABLE([spellcheck], [Run spellcheck among default checks], [auto]) AC_MSG_CHECKING(whether to run spellcheck among default make check target) case "${nut_enable_spellcheck}" in yes) if test "${nut_have_aspell}" = "no" ; then AC_MSG_ERROR([Requested to --enable-spellcheck but did not find a good one]) fi WITH_SPELLCHECK=yes ;; no) WITH_SPELLCHECK=no ;; auto) if test "${nut_have_aspell}" = "yes" ; then WITH_SPELLCHECK=yes else WITH_SPELLCHECK=no fi ;; esac AC_MSG_RESULT([${WITH_SPELLCHECK}]) AM_CONDITIONAL(WITH_SPELLCHECK, test "${WITH_SPELLCHECK}" = "yes") dnl ---------------------------------------------------------------------- dnl checks related to --with-doc dnl Always check for AsciiDoc prerequisites, since even if --with-doc dnl is set to 'no', we may still want to build some doc targets manually dnl (so enable the Makefile recipes for those targets if tools are available) NUT_CHECK_ASCIIDOC NUT_REPORT_FEATURE([build and install documentation], [${nut_with_doc}], [], [WITH_ASCIIDOC], [Define to enable Asciidoc support]) DOC_INSTALL_DISTED_MANS=no case "${nut_with_doc}" in yes|all|all=yes) nut_doc_build_list="man html-single html-chunked pdf" ;; auto|all=auto) nut_doc_build_list="man=auto html-single=auto html-chunked=auto pdf=auto" ;; skip|all=skip) nut_doc_build_list="man=skip html-single=skip html-chunked=skip pdf=skip" ;; no|all=no) nut_doc_build_list="" ;; dnl If user passed --with-doc='' they they want nothing, right? "") nut_doc_build_list="" AC_MSG_NOTICE([Got explicit empty list of document formats to build; nothing will be generated]) ;; *) nut_doc_build_list="`echo ${nut_with_doc} | sed 's/,/ /g'`" AC_MSG_NOTICE([Got explicit list of document formats to build or not: ${nut_doc_build_list}; formats not listed will be silently skipped]) ;; esac if test -z "${abs_srcdir}" ; then case "${srcdir}" in /*) abs_srcdir="${srcdir}";; "") AC_MSG_ERROR([Can not detect 'srcdir']) ;; *) abs_srcdir="$(cd "${srcdir}" && pwd)" || AC_MSG_ERROR([Can not detect 'srcdir']) ;; esac fi DOCTESTDIR="$(mktemp -d configure-test.docbuild.$$.XXXXXXX)" && \ DOCTESTDIR="$(cd "$DOCTESTDIR" && pwd)" dnl Note: Do not cover ${nut_doc_build_list} in braces or quotes here, dnl to ensure that it is processed as several space-separated tokens for nut_doc_build_target in $nut_doc_build_list; do case "${nut_doc_build_target}" in *=*=*) rm -rf "${DOCTESTDIR}" AC_MSG_ERROR([Invalid documentation format option: ${nut_doc_build_target}]) ;; *=*) nut_doc_build_target_base="`echo "${nut_doc_build_target}" | sed 's,=.*$,,'`" nut_doc_build_target_flag="`echo "${nut_doc_build_target}" | sed 's,^.*=,,'`" ;; *) nut_doc_build_target_base="${nut_doc_build_target}" nut_doc_build_target_flag="yes" ;; esac case "${nut_doc_build_target_flag}" in yes|no|auto|skip) ;; "") nut_doc_build_target_flag="yes" ;; *) rm -rf "${DOCTESTDIR}" AC_MSG_ERROR([Invalid documentation format option: ${nut_doc_build_target}]) ;; esac AC_MSG_CHECKING([desire and ability to build ${nut_doc_build_target_base} documentation]) AC_MSG_RESULT([${nut_doc_build_target_flag}]) case "${nut_doc_build_target}" in *=no|*=skip) DOC_SKIPBUILD_LIST="${DOC_SKIPBUILD_LIST} ${nut_doc_build_target_base}" ;; dnl Notes: Document options below assume either no flag value (which dnl by default means "yes"), "yes" which is a requirement, or "auto" dnl to detect if we can build the wanted documentation format and yet dnl not fail if we have no tools to generate it (so add to SKIP list). html-single*) AC_MSG_CHECKING([if asciidoc version can build ${nut_doc_build_target_base} (minimum required ${ASCIIDOC_MIN_VERSION})]) can_build_doc_html_single=no AX_COMPARE_VERSION([${ASCIIDOC_VERSION}], [ge], [${ASCIIDOC_MIN_VERSION}], [ ( cd "$DOCTESTDIR" && ${A2X} --attribute=xhtml11_format --format=xhtml --xsl-file="${abs_srcdir}"/docs/xhtml.xsl --destination-dir=. "${abs_srcdir}"/docs/asciidoc.txt && test -s asciidoc.html ) && can_build_doc_html_single=yes rm -f "$DOCTESTDIR"/asciidoc*.htm* ], []) if test "${can_build_doc_html_single}" = yes ; then AC_MSG_RESULT(yes) DOC_BUILD_LIST="${DOC_BUILD_LIST} ${nut_doc_build_target_base}" else AC_MSG_RESULT(no) if test "${nut_doc_build_target_flag}" = "yes" ; then DOC_CANNOTBUILD_LIST="${DOC_CANNOTBUILD_LIST} ${nut_doc_build_target_base}" AC_MSG_WARN([Unable to build ${nut_doc_build_target_base} documentation which you requested]) else DOC_SKIPBUILD_LIST="${DOC_SKIPBUILD_LIST} ${nut_doc_build_target_base}" fi fi ;; html-chunked*) AC_MSG_CHECKING([if a2x version can build ${nut_doc_build_target_base} (minimum required ${ASCIIDOC_MIN_VERSION})]) can_build_doc_html_chunked=no AX_COMPARE_VERSION([${A2X_VERSION}], [ge], [${ASCIIDOC_MIN_VERSION}], [ ( cd "$DOCTESTDIR" && ${A2X} --attribute=chunked_format --format=chunked --xsl-file="${abs_srcdir}"/docs/chunked.xsl --destination-dir=. "${abs_srcdir}"/docs/FAQ.txt && test -s FAQ.chunked/index.html ) && can_build_doc_html_chunked=yes rm -rf "${DOCTESTDIR}"/FAQ*.chunked* ], []) if test "${can_build_doc_html_chunked}" = yes ; then AC_MSG_RESULT(yes) DOC_BUILD_LIST="${DOC_BUILD_LIST} ${nut_doc_build_target_base}" else AC_MSG_RESULT(no) if test "${nut_doc_build_target_flag}" = "yes" ; then DOC_CANNOTBUILD_LIST="${DOC_CANNOTBUILD_LIST} ${nut_doc_build_target_base}" AC_MSG_WARN([Unable to build ${nut_doc_build_target_base} documentation which you requested]) else DOC_SKIPBUILD_LIST="${DOC_SKIPBUILD_LIST} ${nut_doc_build_target_base}" fi fi ;; pdf*) AC_MSG_CHECKING([if dblatex version can build ${nut_doc_build_target_base} (minimum required ${DBLATEX_MIN_VERSION})]) can_build_doc_pdf=no AX_COMPARE_VERSION([${DBLATEX_VERSION}], [ge], [${DBLATEX_MIN_VERSION}], [ ( cd "$DOCTESTDIR" && ${A2X} --format=pdf --destination-dir=. "${abs_srcdir}"/docs/asciidoc.txt && test -s asciidoc.pdf ) && can_build_doc_pdf=yes rm -f "${DOCTESTDIR}"/asciidoc.pdf ], []) if test "${can_build_doc_pdf}" = yes ; then AC_MSG_RESULT(yes) DOC_BUILD_LIST="${DOC_BUILD_LIST} ${nut_doc_build_target_base}" else AC_MSG_RESULT(no) if test "${nut_doc_build_target_flag}" = "yes" ; then DOC_CANNOTBUILD_LIST="${DOC_CANNOTBUILD_LIST} ${nut_doc_build_target_base}" AC_MSG_WARN([Unable to build ${nut_doc_build_target_base} documentation which you requested]) else DOC_SKIPBUILD_LIST="${DOC_SKIPBUILD_LIST} ${nut_doc_build_target_base}" fi fi ;; man*) AC_MSG_CHECKING([if we can build ${nut_doc_build_target_base}]) can_build_doc_man=no if test "${nut_have_asciidoc}" = yes ; then ( cd "$DOCTESTDIR" && ${A2X} --format manpage --destination-dir=. --xsltproc-opts="--nonet" "${abs_srcdir}"/docs/man/snmp-ups.txt && test -s snmp-ups.8 ) && can_build_doc_man=yes rm -f "${DOCTESTDIR}"/snmp-ups.8 fi if test "${can_build_doc_man}" = yes ; then AC_MSG_RESULT(yes) DOC_BUILD_LIST="${DOC_BUILD_LIST} ${nut_doc_build_target_base}" else AC_MSG_RESULT(no) if test "${nut_doc_build_target_flag}" = "yes" ; then DOC_CANNOTBUILD_LIST="${DOC_CANNOTBUILD_LIST} ${nut_doc_build_target_base}" AC_MSG_WARN([Unable to build ${nut_doc_build_target_base} documentation which you requested]) else DOC_SKIPBUILD_LIST="${DOC_SKIPBUILD_LIST} ${nut_doc_build_target_base}" if test "${nut_doc_build_target_flag}" = "auto" ; then dnl Test that groff files exist (building from distributed tarball, not git repo) if test -s "${abs_srcdir}"/docs/man/snmp-ups.8 ; then AC_MSG_WARN([Unable to build ${nut_doc_build_target_base} documentation, but can install pre-built distributed copies]) DOC_INSTALL_DISTED_MANS="yes" else AC_MSG_WARN([Unable to build ${nut_doc_build_target_base} documentation, and unable to install pre-built distributed copies because they are absent]) fi fi # Other variants include "no", "skip"... fi fi ;; *) rm -rf "${DOCTESTDIR}" AC_MSG_ERROR([--with-doc option refers to unknown documentation format: $nut_doc_build_target]) ;; esac done rm -rf "${DOCTESTDIR}" case "${nut_with_doc}" in auto) if test -n "${DOC_BUILD_LIST}"; then nut_with_doc="yes" else nut_with_doc="no" fi ;; no) ;; *) if test -n "${DOC_CANNOTBUILD_LIST}"; then AC_MSG_ERROR([Unable to build${DOC_CANNOTBUILD_LIST} documentation (check for 'no' results above)]) fi if test -n "${DOC_SKIPBUILD_LIST}"; then AC_MSG_NOTICE([Skipping build of${DOC_SKIPBUILD_LIST} documentation (check for 'skip' results above)]) fi if test -n "${DOC_BUILD_LIST}"; then nut_with_doc="yes" else nut_with_doc="no" fi ;; esac NUT_REPORT_FEATURE([build specific documentation format(s)], [${nut_with_doc}], [${DOC_BUILD_LIST}], [WITH_DOCS], [Define to enable overall documentation generation]) # To cater for less portable make's, precalculate the target list # for "make check" in "docs/" here... DOC_CHECK_LIST="" if test "${nut_with_doc}" = yes ; then for V in $DOC_BUILD_LIST ; do DOC_CHECK_LIST="$DOC_CHECK_LIST check-$V" done fi WITH_MANS=no SKIP_MANS=no if echo "${DOC_BUILD_LIST}" | grep -w "man" >/dev/null || test "${DOC_INSTALL_DISTED_MANS}" = "yes" ; then WITH_MANS=yes fi if echo "${DOC_SKIPBUILD_LIST}" | grep -w "man" >/dev/null ; then SKIP_MANS=yes fi dnl Generally WITH_MANS=no is intentionally fatal for "make distcheck" dnl But some larger distcheck suites check mans once and then focus on dnl other aspects of the project, so they can explicitly skip docs (or dnl just mans) instead. Note that for WITH_MANS=yes the SKIP_MANS value dnl is effectively ignored by docs/man/Makefile.am at this time. AM_CONDITIONAL(WITH_MANS, test "${WITH_MANS}" = "yes") AM_CONDITIONAL(SKIP_MANS, test "${SKIP_MANS}" = "yes") AM_CONDITIONAL(DOC_INSTALL_DISTED_MANS, test "${DOC_INSTALL_DISTED_MANS}" = "yes") dnl ---------------------------------------------------------------------- dnl checks related to --with-dev dnl We only init libtool there to allow AC_DISABLE_STATIC if ( test "${GCC}" = "yes" ) then dnl # Avoid new compilers' warnings/errors about libtool distro flaws in this test like: dnl # error: ISO C forbids conversion of function pointer to object pointer type [-Werror=pedantic] dnl # {"nm_test_func", (void *) &nm_test_func}, dnl # or ones about LTO (-flto -fno-common) as discussed and suggested dnl # in https://www.mail-archive.com/libtool@gnu.org/msg14037.html - dnl # all leading to undefined "global_symbol_pipe" in the generated dnl # libtool script, and resulting in errors like `... | | ...` below : dnl # libtool: link: /usr/bin/nm -B .libs/upsclient.o \ dnl # ../common/.libs/libcommonclient.a | | /usr/bin/sed 's/.* //' \ dnl # | sort | uniq > .libs/libupsclient.exp dnl # ../libtool: syntax error: `|' unexpected CFLAGS_SAVED_NOPEDANTIC="$CFLAGS" AS_CASE(["${CFLAGS}"],[*"-pedantic"*],[CFLAGS="${CFLAGS} -Wno-pedantic"]) AS_CASE(["${CFLAGS}"],[*"-Werror"*],[CFLAGS="${CFLAGS} -Wno-error"]) AS_CASE(["${CFLAGS}"],[*"-flto"*],[CFLAGS="${CFLAGS} -ffat-lto-objects"]) fi dnl See https://www.gnu.org/software/libtool/manual/html_node/LT_005fINIT.html dnl #OBSOLETED:# LT_INIT and AC_PROG_LIBTOOL dnl # Hack around the libtool script: as of version 58 (current in 2021), dnl # they use code like below to detect library paths: dnl # if test yes = "$GCC"; then ... lt_search_path_spec=`$CC -print-search-dirs | ... dnl # which explodes when non-default architecture is used for the build, dnl # where e.g. "CC=gcc" and "CFLAGS=-m32" on a 64-bit capable system. dnl # And similarly for compilation-checks to link third-party libraries. SAVED_GCC="$GCC" SAVED_CC="$CC" if ( test "${GCC}" = "yes" ) then case "$CFLAGS$LDFLAGS" in *-m32*) CC="$CC -m32" ;; *-m64*) CC="$CC -m64" ;; esac fi m4_ifdef([AM_PROG_AR], [AM_PROG_AR]) LT_INIT AC_SUBST([LIBTOOL_DEPS]) GCC="$SAVED_GCC" CC="$SAVED_CC" if ( test "${GCC}" = "yes" ) then CFLAGS="$CFLAGS_SAVED_NOPEDANTIC" fi dnl ${nut_with_dev}: any value except "yes" or "no" is treated as "auto". if test "${nut_with_dev}" != "no"; then nut_with_dev="yes" else AC_DISABLE_STATIC fi AM_CONDITIONAL(WITH_DEV, test "${nut_with_dev}" = "yes") NUT_REPORT_FEATURE([build and install the development files], [${nut_with_dev}], [], [WITH_DEV], [Define to enable development files support]) dnl ---------------------------------------------------------------------- dnl checks related to MS Windows support (MingW) AC_CHECK_TOOL([WINDMC], [windmc], [none]) AC_CHECK_TOOL([WINDRES], [windres], [none]) if test "x$WINDMC" != "xnone" -a "x$WINDRES" != "xnone" ; then nut_have_mingw_resgen="yes" fi AM_CONDITIONAL([HAVE_MINGW_RESGEN], [test "${nut_have_mingw_resgen}" = "yes"]) dnl Also define a generic AM_CONDITIONAL for general Windows compilation AM_CONDITIONAL([HAVE_WINDOWS], [test "${nut_have_mingw_resgen}" = "yes"]) dnl ---------------------------------------------------------------------- PREFIX="${prefix}" NUT_REPORT_SETTING_PATH([Default installation prefix path], PREFIX, "${prefix}", [Default installation prefix path]) AC_MSG_CHECKING(if requested state path) AC_ARG_WITH(statepath, AS_HELP_STRING([--with-statepath=PATH], [path for ups state files (${STATEPATH}, typically /var/state/ups)]), [ case "${withval}" in yes|no) AC_MSG_ERROR(invalid option --with(out)-statepath - see docs/configure.txt) ;; *) STATEPATH="${withval}" AC_MSG_RESULT([specified]) ;; esac ], [AC_MSG_RESULT([default])]) NUT_REPORT_SETTING_PATH([State file path], STATEPATH, "${STATEPATH}", [Path for UPS driver state files]) dnl --------------------------------------------------------------------- dnl The 'alt pid path' is used by the drivers (via main.c) and upsd, since dnl ideally they do not run as root and will not be able to write to the usual dnl /var/run path. This defaults to the STATEPATH since they should be dnl able to write there. dnl AC_MSG_CHECKING(if requested alt pid path) AC_ARG_WITH(altpidpath, AS_HELP_STRING([--with-altpidpath=PATH], [path for NUT driver/upsd .pid files not running as root ()]), [ case "${withval}" in yes|no) AC_MSG_ERROR(invalid option --with(out)-altpidpath - see docs/configure.txt) ;; *) ALTPIDPATH="${withval}" AC_MSG_RESULT([specified]) ;; esac ], [ ALTPIDPATH="${STATEPATH}" AC_MSG_RESULT([default]) ]) NUT_REPORT_SETTING_PATH([Unprivileged PID file path], ALTPIDPATH, "${ALTPIDPATH}", [Path for pid files of processes not running as root, such as drivers and upsd (usually STATEPATH)]) AC_MSG_CHECKING(if requested pidpath) AC_ARG_WITH(pidpath, AS_HELP_STRING([--with-pidpath=PATH], [Path for root-owned .pid files (${PIDPATH}, typically /var/run)]), [ case "${withval}" in yes|no) AC_MSG_ERROR(invalid option --with(out)-pidpath - see docs/configure.txt) ;; *) PIDPATH="${withval}" AC_MSG_RESULT([specified]) ;; esac ], [AC_MSG_RESULT([default])]) NUT_REPORT_SETTING_PATH([Privileged PID file path], PIDPATH, "${PIDPATH}", [Path for pid files of processes running as root, such as upsmon]) dnl -------------------------------------------------------------------- dnl Legacy default was /etc/killpower, but modern distros may prefer some dnl temporary filesystem (no I/O storage device impact) as long as it is dnl mounted at least read-only late in shutdown routine. The upsmon program dnl writes it as root, so this may well be in /var/run or in NUT PID/state dnl path (if that location remains mounted in run-time OS distribution). dnl Ideally the filesystems with `upsmon` program and libraries it needs dnl also remain mounted, so `upsmon -K` may be queried late in shutdown - dnl and we can avoid hardcoding such paths into those shutdown hooks. dnl Note that upsmon removes this file early in any daemonized start-up. AC_MSG_CHECKING(if requested default upsmon POWERDOWNFLAG path) AC_ARG_WITH(powerdownflag, AS_HELP_STRING([--with-powerdownflag=PATH], [default path for upsmon POWERDOWNFLAG file (${POWERDOWNFLAG}, typically /etc/killpower)]), [ case "${withval}" in yes|no) AC_MSG_ERROR(invalid option --with(out)-powerdownflag - see docs/configure.txt) ;; *) POWERDOWNFLAG="${withval}" AC_MSG_RESULT([specified]) ;; esac ], [AC_MSG_RESULT([default])]) dnl # This should be internal detail for "upsmon -K" implementation, dnl # so not necessarily reported (reduce noise): dnl NUT_REPORT_SETTING_PATH([Default upsmon POWERDOWNFLAG path], dnl POWERDOWNFLAG, "${POWERDOWNFLAG}", [Default path for upsmon POWERDOWNFLAG file]) dnl --------------------------------------------------------------------- AC_MSG_CHECKING(if requested driver path) AC_ARG_WITH(drvpath, AS_HELP_STRING([--with-drvpath=PATH], [where to install UPS drivers (EPREFIX/bin)]), [ case "${withval}" in yes|no) AC_MSG_ERROR(invalid option --with(out)-drvpath - see docs/configure.txt) ;; *) driverexecdir="${withval}" AC_MSG_RESULT([specified]) ;; esac ], [AC_MSG_RESULT([default])]) conftemp="${driverexecdir}" eval conftemp=\"${conftemp}\" eval conftemp=\"${conftemp}\" DRVPATH="${conftemp}" NUT_REPORT_SETTING_PATH([Driver program path], DRVPATH, "${conftemp}", [Default path for UPS drivers]) AC_MSG_CHECKING(if requested cgi path) AC_ARG_WITH(cgipath, AS_HELP_STRING([--with-cgipath=PATH], [where to install CGI programs (EPREFIX/cgi-bin)]), [ case "${withval}" in yes|no) AC_MSG_ERROR(invalid option --with(out)-cgipath - see docs/configure.txt) ;; *) cgiexecdir="${withval}" AC_MSG_RESULT([specified]) ;; esac ], [AC_MSG_RESULT([default])]) conftemp="${cgiexecdir}" eval conftemp=\"${conftemp}\" eval conftemp=\"${conftemp}\" CGIPATH="${conftemp}" NUT_REPORT_SETTING_PATH([CGI program path], CGIPATH, "${conftemp}", [Default path for CGI programs]) AC_MSG_CHECKING(if requested html path) AC_ARG_WITH(htmlpath, AS_HELP_STRING([--with-htmlpath=PATH], [where to install HTML files (PREFIX/html)]), [ case "${withval}" in yes|no) AC_MSG_ERROR(invalid option --with(out)-htmlpath - see docs/configure.txt) ;; *) htmldir="${withval}" AC_MSG_RESULT([specified]) ;; esac ], [AC_MSG_RESULT([default])]) conftemp="${htmldir}" eval conftemp=\"${conftemp}\" eval conftemp=\"${conftemp}\" HTMLPATH="${conftemp}" NUT_REPORT_SETTING_PATH([HTML file path], HTMLPATH, "${conftemp}", [Default path for HTML files (CGI templates)]) AC_MSG_CHECKING(network port number) AC_ARG_WITH(port, AS_HELP_STRING([--with-port=PORT], [port for network communications (3493)]), [ case "${withval}" in yes|no) AC_MSG_ERROR(invalid option --with(out)-port - see docs/configure.txt) ;; *) PORT="${withval}" ;; esac ], [ PORT="3493" ]) AC_DEFINE_UNQUOTED(PORT, ${PORT}, [Port for network communications]) AC_MSG_RESULT(${PORT}) AC_MSG_CHECKING(facility for syslog) AC_ARG_WITH(logfacility, AS_HELP_STRING([--with-logfacility=FACILITY], [facility for log messages (LOG_DAEMON)]), [ case "${withval}" in yes|no) AC_MSG_ERROR(invalid option --with(out)-logfacility - see docs/configure.txt) ;; *) LOGFACILITY="${withval}" ;; esac ], [ LOGFACILITY="LOG_DAEMON" ]) AC_DEFINE_UNQUOTED(LOG_FACILITY, ${LOGFACILITY}, [Desired syslog facility - see syslog(3)]) AC_MSG_RESULT(${LOGFACILITY}) AC_MSG_CHECKING(which driver man pages to install) DRIVER_MAN_LIST_PAGES="" if test "${WITH_MANS}" = "yes"; then if test "${DRIVER_BUILD_LIST}" = "all"; then DRIVER_MAN_LIST=all AC_MSG_RESULT(all available) else DRIVER_MAN_LIST="" for i in ${DRIVER_BUILD_LIST}; do dnl See if source or pre-generated (tarball) doc file exists: if test -f ${srcdir}/docs/man/$i.txt -o -f ${srcdir}/docs/man/$i.8; then DRIVER_MAN_LIST="${DRIVER_MAN_LIST} $i.8" DRIVER_MAN_LIST_PAGES="${DRIVER_MAN_LIST_PAGES} $i.txt" fi done AC_MSG_RESULT(${DRIVER_MAN_LIST}) fi else DRIVER_MAN_LIST="" AC_MSG_RESULT([none (manpages disabled)]) fi dnl By default as we iterate (and git commit) the codebase during development, dnl prerequisites for that header file change and cause much of the C code dnl to be rebuilt and re-linked. For developers fixing one small part of the dnl project after another (*and* committing fixes as they go on), the version dnl string reported by their new binaries may be of lesser consequence than dnl iterating *quickly* and rebuiding just what "really" changed! dnl Still, this speed-up is not default to avoid surprises for core team. AC_MSG_CHECKING(whether to force nut_version.h generation for every make run) dnl Value is "FORCE" or empty, substituted into Makefile.am rule: FORCE_NUT_VERSION="FORCE" AC_ARG_ENABLE(force-nut-version-header, AS_HELP_STRING([--enable-force-nut-version-header], [Force nut_version.h generation for every make run (yes)]), [ case "${enableval}" in no) AC_MSG_RESULT(no) FORCE_NUT_VERSION="" ;; *) AC_MSG_RESULT(yes) ;; esac ], [ AC_MSG_RESULT(no) ]) AC_MSG_CHECKING(whether to strip debug symbols) AC_ARG_ENABLE(strip, AS_HELP_STRING([--enable-strip], [Strip debugging symbols from binaries (no)]), [ case "${enableval}" in no) AC_MSG_RESULT(no) ;; *) AC_MSG_RESULT(yes) CFLAGS="${CFLAGS} -s" ;; esac ], [ AC_MSG_RESULT(no) ]) AC_MSG_CHECKING(whether to install pkg-config *.pc files) AC_ARG_WITH(pkgconfig-dir, AS_HELP_STRING([--with-pkgconfig-dir=PATH], [where to install pkg-config *.pc files (EPREFIX/lib/pkgconfig)]), [ case "${withval}" in yes|auto) ;; no) pkgconfigdir="" ;; *) pkgconfigdir="${withval}" ;; esac ], []) dnl Note: currently pkgconfigdir='${libdir}/pkgconfig' literally dnl goes into lib/Makefile.am substitution for pkgconfig_DATA. dnl By default we get ${libdir}/pkgconfig and below expand it to dnl => ${exec_prefix}/lib/pkgconfig => ${prefix}/lib/pkgconfig => real path conftemp="${pkgconfigdir}" eval conftemp=\"${conftemp}\" eval conftemp=\"${conftemp}\" eval conftemp=\"${conftemp}\" PKGCONFIGDIR="${conftemp}" if test -n "${pkgconfigdir}"; then AC_MSG_RESULT(using ${pkgconfigdir} => ${conftemp}) NUT_REPORT_PATH_INTEGRATIONS([pkg-config *.pc directory], [${pkgconfigdir} => ${conftemp}]) else AC_MSG_RESULT(no) fi AM_CONDITIONAL(WITH_PKG_CONFIG, test -n "${pkgconfigdir}") dnl Options for Solaris/illumos `make install` and `make package` AC_MSG_CHECKING(whether to make Solaris SVR4 packages) solarispkg_svr4="auto" AC_ARG_WITH([solaris-pkg-svr4], AS_HELP_STRING([--with-solaris-pkg-svr4=(yes|auto|no)], [Enable construction of Solaris SVR4 packages (auto)]), [ case "${withval}" in auto|"") solarispkg_svr4="auto" ;; yes|no) solarispkg_svr4="${withval}" ;; *) AC_MSG_ERROR([Unexpected argument for --with-solaris-pkg-svr4=${withval}]) ;; esac ], []) if test x"$solarispkg_svr4" = xauto ; then if test -x /usr/bin/pkgtrans && test -x /usr/bin/pkgmk && test -x /usr/bin/pkgproto ; then solarispkg_svr4="yes" else solarispkg_svr4="no" fi fi AC_MSG_RESULT([${solarispkg_svr4}]) AM_CONDITIONAL(WITH_SOLARIS_PKG_SVR4, test x"$solarispkg_svr4" = x"yes") AC_MSG_CHECKING(whether to make Solaris IPS packages) solarispkg_ips="auto" AC_ARG_WITH([solaris-pkg-ips], AS_HELP_STRING([--with-solaris-pkg-ips=(yes|auto|no)], [Enable construction of Solaris IPS packages (auto)]), [ case "${withval}" in auto|"") solarispkg_ips="auto" ;; yes|no) solarispkg_ips="${withval}" ;; *) AC_MSG_ERROR([Unexpected argument for --with-solaris-pkg-ips=${withval}]) ;; esac ], []) if test x"$solarispkg_ips" = xauto ; then if test -x /usr/bin/pkg && test -x /usr/bin/pkgmogrify && test -x /usr/bin/pkgdepend ; then solarispkg_ips="yes" else solarispkg_ips="no" fi fi AC_MSG_RESULT([${solarispkg_ips}]) AM_CONDITIONAL(WITH_SOLARIS_PKG_IPS, test x"$solarispkg_ips" = x"yes") dnl NOTE: Be sure to customize e.g. --datarootdir=/usr/share/nut to install dnl these scripts not into default location as e.g. /usr/share/solaris-smf AC_MSG_CHECKING(whether to install Solaris SMF files) solarissmf="auto" AC_ARG_WITH([solaris-smf], AS_HELP_STRING([--with-solaris-smf=(yes|auto|no)], [Enable installation of NUT scripts and manifests for Solaris Service Management Framework (auto)]), [ case "${withval}" in auto|"") solarissmf="auto" ;; yes|no) solarissmf="${withval}" ;; *) AC_MSG_ERROR([Unexpected argument for --with-solaris-smf=${withval}]) ;; esac ], []) if test x"$solarissmf" = xauto ; then if test -x /usr/sbin/svcadm && test -x /usr/sbin/svccfg && test -x /usr/bin/svcs ; then solarissmf="yes" else case "${solarispkg_ips}${solarispkg_svr4}" in *yes*) solarisinit="yes" ;; dnl Want to install so we can generally package *) solarissmf="no" ;; dnl Target not solarish esac fi fi AC_MSG_RESULT([${solarissmf}]) AM_CONDITIONAL(WITH_SOLARIS_SMF, test x"$solarissmf" = x"yes") NUT_REPORT([consider basic SMF support], [${solarissmf}]) AC_MSG_CHECKING(whether to install Solaris SVR4 (legacy) init-script files) solarisinit="auto" AC_ARG_WITH([solaris-init], AS_HELP_STRING([--with-solaris-init=(yes|auto|no)], [Enable installation of NUT legacy init-scripts for Solaris/illumos (auto)]), [ case "${withval}" in auto|"") solarisinit="auto" ;; yes|no) solarisinit="${withval}" ;; *) AC_MSG_ERROR([Unexpected argument for --with-solaris-init=${withval}]) ;; esac ], []) if test x"$solarisinit" = xauto ; then dnl Depends on usability of SMF or making for packaging case "${solarispkg_ips}${solarispkg_svr4}" in *yes*) solarisinit="yes" ;; dnl Want to install so we can generally package *) case ${target_os} in solaris*|sunos*|SunOS*|illumos*) if test "$solarissmf" = x"yes" ; then dnl no need on modern OSes solarisinit="no" else solarisinit="yes" fi ;; *) solarisinit="no" ;; dnl Some other OS esac ;; esac fi AC_MSG_RESULT([${solarisinit}]) AM_CONDITIONAL(WITH_SOLARIS_INIT, test x"$solarisinit" = x"yes") dnl Note: Currently there is no reliable automatic detection - dnl users have to ask they want systemd units installed, or dnl risk auto-detection like seen below. AC_MSG_CHECKING(whether to install systemd unit files) AC_ARG_WITH([systemdsystemunitdir], AS_HELP_STRING([--with-systemdsystemunitdir=DIR], [Directory for systemd service files (auto)]), [systemdsystemunitdir="${withval}"], [systemdsystemunitdir="auto"]) case "${systemdsystemunitdir}" in yes|auto|"") AS_IF([test x"$have_PKG_CONFIG" = xyes], [systemdsystemunitdir="`$PKG_CONFIG --variable=systemdsystemunitdir systemd 2>/dev/null`" && test -n "$systemdsystemunitdir" || systemdsystemunitdir="`$PKG_CONFIG --variable=systemdsystemunitdir libsystemd 2>/dev/null`"], [AS_IF([test "${systemdsystemunitdir}" = yes], [AC_MSG_ERROR([--with-systemdsystemunitdir=${systemdsystemunitdir} was requested, but PKG_CONFIG could not be queried for the system settings])]) systemdsystemunitdir="" ]) ;; no) systemdsystemunitdir="" ;; *) AS_IF([test -d "${systemdsystemunitdir}"], [], [AC_MSG_WARN([--with-systemdsystemunitdir='${systemdsystemunitdir}' was requested, but that location does not currently exist in build environment - just so you know...])]) ;; esac if test "${systemdsystemunitdir}" = "auto" ; then systemdsystemunitdir=""; fi if test -n "${systemdsystemunitdir}"; then have_systemd="yes" AC_MSG_RESULT(using ${systemdsystemunitdir}) NUT_REPORT_PATH_INTEGRATIONS([Service units for systemd], [${systemdsystemunitdir}]) else have_systemd="no" AC_MSG_RESULT(no) fi dnl Note: we may want tighter integration, e.g. systemd-notify support dnl configured as a further option/flag (see --with-systemd below). dnl This one is a very basic yes/no toggle for unit file delivery. NUT_REPORT_FEATURE([consider basic systemd support], [${have_systemd}], [], [HAVE_SYSTEMD], [Define to consider basic systemd support (provide units and configuration files)]) dnl This option is only provided so that make distcheck can override it, dnl otherwise we ask pkg-config whenever --with-systemdsystemunitdir is dnl given AC_MSG_CHECKING(whether to install systemd shutdown files) AC_ARG_WITH([systemdshutdowndir], AS_HELP_STRING([--with-systemdshutdowndir=DIR], [Directory for systemd shutdown scripts (auto)]), [systemdshutdowndir="${withval}"], [systemdshutdowndir="auto"]) dnl Note: this option is enabled only if systemdsystemunitdir is not trivial if test -n "${systemdsystemunitdir}"; then case "${systemdshutdowndir}" in yes|auto|"") AS_IF([test x"$have_PKG_CONFIG" = xyes], [systemdshutdowndir="`$PKG_CONFIG --variable=systemdshutdowndir systemd 2>/dev/null`" && test -n "$systemdshutdowndir" || systemdshutdowndir="`$PKG_CONFIG --variable=systemdshutdowndir libsystemd 2>/dev/null`"], [AS_IF([test "${systemdshutdowndir}" = yes], [AC_MSG_ERROR([--with-systemdshutdowndir=${systemdshutdowndir} was requested, but PKG_CONFIG could not be queried for the system settings])]) systemdshutdowndir="" ]) ;; no) systemdshutdowndir="" ;; *) AS_IF([test -d "${systemdshutdowndir}"], [], [AC_MSG_WARN([--with-systemdshutdowndir='${systemdshutdowndir}' was requested, but that location does not currently exist in build environment - just so you know...])]) ;; esac fi if test "${systemdshutdowndir}" = "auto" ; then systemdshutdowndir=""; fi if test -n "${systemdshutdowndir}"; then AC_MSG_RESULT(using ${systemdshutdowndir}) NUT_REPORT_PATH_INTEGRATIONS([Shutdown hooks for systemd], [${systemdshutdowndir}]) else AC_MSG_RESULT(no) fi dnl Note: if (systemd-)tmpfiles tech is present, it can be useful even for dnl daemons starting not as systemd units, to pre-create /var/run/nut etc. AC_MSG_CHECKING([whether to install systemd tmpfiles files]) AC_ARG_WITH([systemdtmpfilesdir], AS_HELP_STRING([--with-systemdtmpfilesdir=DIR], [Directory for systemd tmpfiles scripts (auto)]), [systemdtmpfilesdir="${withval}"], [systemdtmpfilesdir="auto"]) case "${systemdtmpfilesdir}" in yes|auto|"") AS_IF([test x"$have_PKG_CONFIG" = xyes], [systemdtmpfilesdir="`$PKG_CONFIG --variable=tmpfilesdir systemd 2>/dev/null`" && test -n "$systemdtmpfilesdir" || systemdtmpfilesdir="`$PKG_CONFIG --variable=tmpfilesdir libsystemd 2>/dev/null`"], [AS_IF([test "${systemdtmpfilesdir}" = yes], [AC_MSG_ERROR([--with-systemdtmpfilesdir=${systemdtmpfilesdir} was requested, but PKG_CONFIG could not be queried for the system settings])]) systemdtmpfilesdir="" ]) ;; no) systemdtmpfilesdir="" ;; *) AS_IF([test -d "${systemdtmpfilesdir}"], [], [AC_MSG_WARN([--with-systemdtmpfilesdir='${systemdtmpfilesdir}' was requested, but that location does not currently exist in build environment - just so you know...])]) ;; esac if test "${systemdtmpfilesdir}" = "auto" ; then systemdtmpfilesdir=""; fi if test -n "${systemdtmpfilesdir}"; then AC_MSG_RESULT(using ${systemdtmpfilesdir}) NUT_REPORT_PATH_INTEGRATIONS([Systemd-tmpfiles configs], [${systemdtmpfilesdir}]) else AC_MSG_RESULT(no) fi dnl What pathname would we embed into unit files ExecStartPre? dnl TODO? Any need to make it a --with-... argument? AC_PATH_PROG([SYSTEMD_TMPFILES_PROGRAM], [systemd-tmpfiles], [/usr/bin/systemd-tmpfiles]) dnl Note: we may want binaries with sd_notify and similar features regardless dnl of building and delivering unit files (which may be crafted separately). dnl TODO: although end-user deployments (for custom builds) may be lacking dnl libsystemd development files, they might have a `systemd-notify` program dnl intended to help scripted service units. Consider making use of that then. NUT_ARG_WITH([libsystemd], [build binaries with tighter systemd integration (notifications etc)], [auto]) NUT_CHECK_LIBSYSTEMD AC_MSG_CHECKING(whether requested and can build binaries with tighter systemd integration support) AS_IF([test x"${nut_with_libsystemd}" = xyes && test x"${nut_have_libsystemd}" != xyes], [AC_MSG_ERROR([--with-libsystemd was requested, but the library was not found or usable])]) AS_CASE(["${nut_with_libsystemd}"], [yes|no], [have_libsystemd="${nut_with_libsystemd}"], [AS_IF([test x"${nut_have_libsystemd}" = xyes], [with_libsystemd="yes"], [with_libsystemd="no"]) ]) AC_MSG_RESULT(${with_libsystemd}) AC_PATH_PROG([SYSTEMD_ANALYZE_PROGRAM], [systemd-analyze], [/usr/bin/systemd-analyze]) dnl Relevant since 2023: https://github.com/systemd/systemd/pull/25916 SYSTEMD_SUPPORTS_DAEMON_TYPE_NOTIFY=no AS_IF([test -x "$SYSTEMD_ANALYZE_PROGRAM"], [ AC_MSG_CHECKING([if your systemd version supports Type=notify]) myFILE="`mktemp systemd-analyze-XXXXXX.service`" cat > "$myFILE" << EOF @<:@Unit@:>@ Description=temp @<:@Service@:>@ ExecStart=/bin/true Type=notify EOF if myOUT="`"$SYSTEMD_ANALYZE_PROGRAM" verify "$myFILE" 2>&1`" \ && ! (echo "$myOUT" | grep "Failed to parse service type, ignoring") \ ; then SYSTEMD_SUPPORTS_DAEMON_TYPE_NOTIFY=yes fi rm -f "$myFILE" AC_MSG_RESULT([${SYSTEMD_SUPPORTS_DAEMON_TYPE_NOTIFY}]) ]) SYSTEMD_SUPPORTS_DAEMON_TYPE_NOTIFY_RELOAD=no AS_IF([test -x "$SYSTEMD_ANALYZE_PROGRAM"], [ AC_MSG_CHECKING([if your systemd version supports Type=notify-reload]) myFILE="`mktemp systemd-analyze-XXXXXX.service`" cat > "$myFILE" << EOF @<:@Unit@:>@ Description=temp @<:@Service@:>@ ExecStart=/bin/true Type=notify-reload EOF if myOUT="`"$SYSTEMD_ANALYZE_PROGRAM" verify "$myFILE" 2>&1`" \ && ! (echo "$myOUT" | grep "Failed to parse service type, ignoring") \ ; then SYSTEMD_SUPPORTS_DAEMON_TYPE_NOTIFY_RELOAD=yes fi rm -f "$myFILE" AC_MSG_RESULT([${SYSTEMD_SUPPORTS_DAEMON_TYPE_NOTIFY_RELOAD}]) ]) AS_IF([test x"${with_libsystemd}" = xyes && test x"${SYSTEMD_SUPPORTS_DAEMON_TYPE_NOTIFY}" = xyes], [ dnl Built with sd_notify support dnl Note: `upsd -FF` both runs without forking and leaves a PID file, as dnl needed for `upsd -c reload` in legacy scripts and old habits to work: SYSTEMD_DAEMON_ARGS_UPSD="-FF" SYSTEMD_DAEMON_TYPE_UPSD="notify" SYSTEMD_DAEMON_ARGS_UPSMON="-F" SYSTEMD_DAEMON_TYPE_UPSMON="notify" SYSTEMD_DAEMON_ARGS_DRIVER="-FF" SYSTEMD_DAEMON_TYPE_DRIVER="notify" AS_IF([test x"${SYSTEMD_SUPPORTS_DAEMON_TYPE_NOTIFY_RELOAD}" = xyes], [ dnl Macro supported since aclocal-1.11: m4_ifdef([AM_COND_IF], [AM_COND_IF([HAVE_CLOCK_GETTIME], [AM_COND_IF([HAVE_CLOCK_MONOTONIC], [SYSTEMD_DAEMON_TYPE_DRIVER="notify-reload"])])], [AS_IF([test x"${ac_cv_func_clock_gettime}" = "xyes"], [SYSTEMD_DAEMON_TYPE_DRIVER="notify-reload"])]) ]) dnl Calling shell, upsdrvctl, driver, and then it forks... ugh! dnl https://github.com/systemd/systemd/issues/25961 dnl FIXME: if NotifyAccess=cgroup appears, use it (consult SYSTEMD_VERSION) SYSTEMD_DAEMON_NOTIFYACCESS_DRIVER="NotifyAccess=all" dnl Similar for UPSMON with its two processes: SYSTEMD_DAEMON_NOTIFYACCESS_UPSMON="NotifyAccess=all" dnl UPSD is started directly by systemd and do not fork: SYSTEMD_DAEMON_NOTIFYACCESS_UPSD="NotifyAccess=main" dnl Note: at this time we do not pre-define watchdog settings, dnl to avoid breaking something by a poorly hardcoded guess. dnl This is something end-users should do for their deployment, dnl especially for drivers SYSTEMD_DAEMON_WATCHDOG_DRIVER="#WatchdogSec=240s" SYSTEMD_DAEMON_WATCHDOG_UPSD="#WatchdogSec=240s" SYSTEMD_DAEMON_WATCHDOG_UPSMON="#WatchdogSec=240s" ], [ dnl "Usual" daemons that happen to be spawned by systemd SYSTEMD_DAEMON_ARGS_UPSD="-F" SYSTEMD_DAEMON_TYPE_UPSD="simple" SYSTEMD_DAEMON_ARGS_UPSMON="-F" SYSTEMD_DAEMON_TYPE_UPSMON="simple" SYSTEMD_DAEMON_ARGS_DRIVER="" SYSTEMD_DAEMON_TYPE_DRIVER="forking" SYSTEMD_DAEMON_NOTIFYACCESS_DRIVER="" SYSTEMD_DAEMON_NOTIFYACCESS_UPSD="" SYSTEMD_DAEMON_NOTIFYACCESS_UPSMON="" dnl Watchdog should not be configured for not-notifying units, right? SYSTEMD_DAEMON_WATCHDOG_DRIVER="#WatchdogSec=240s" SYSTEMD_DAEMON_WATCHDOG_UPSD="#WatchdogSec=240s" SYSTEMD_DAEMON_WATCHDOG_UPSMON="#WatchdogSec=240s" ]) NUT_REPORT_FEATURE([build with tighter systemd support], [${with_libsystemd}], [], [WITH_LIBSYSTEMD], [Define to build with tighter systemd support (sd_notify etc)]) dnl dnl Tests for CppUnit availability and usability (will be built if we can, dnl and if valgrind is enabled for this configuration - reported below). dnl Using CppUnit implies C++ support! dnl Theoretically, libcppunit-dev will pull up to g++, through libstdc++... dnl AM_PATH_CPPUNIT(1.9.6) dnl # Tests with gcc-4.8 require this C++11 option to be provided explicitly dnl # gcc-4.6 does not support this yet; newer gcc's should be ok by default. dnl # Could use `AX_CXX_COMPILE_STDCXX_11([noext], [optional])` if it were dnl # available everywhere. Or AX_CHECK_COMPILE_FLAG if it was ubiquitous: dnl ###AX_CHECK_COMPILE_FLAG([-std=c++11], dnl ### [CXXFLAGS="$CXXFLAGS -std=c++11" dnl ### have_cxx11=yes], dnl ### [have_cxx11=no]) AC_MSG_CHECKING(for C++11 support in current compiler) have_cxx11=unknown my_CXXFLAGS="$CXXFLAGS" AC_LANG_PUSH([C++]) CPLUSPLUS_DECL=' #include #if __cplusplus < 201103L #error This library needs at least a C++11 compliant compiler #endif /* Make sure it supports modern syntax */ #include #include ' CPLUSPLUS_MAIN=' printf("%ld\n", __cplusplus); /* Make sure it supports modern syntax */ std::map map; map.emplace("key", "value"); ' AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[${CPLUSPLUS_DECL}]], [[${CPLUSPLUS_MAIN}]])], [AC_MSG_RESULT([yes, out of the box]) have_cxx11=yes], [AS_CASE(["${CXXFLAGS}"], [*"-std="*], [ AC_MSG_RESULT([no, not with the standard already set in CXXFLAGS='${CXXFLAGS}']) have_cxx11=no ],[ CXXFLAGS="$CXXFLAGS -std=c++11" AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[${CPLUSPLUS_DECL}]], [[${CPLUSPLUS_MAIN}]])], [AC_MSG_RESULT([yes, GCC-style (as C++11)]) have_cxx11=yes], [CXXFLAGS="$CXXFLAGS -std=c++0x" AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[${CPLUSPLUS_DECL}]], [[${CPLUSPLUS_MAIN}]])], [AC_MSG_RESULT([yes, GCC-style (as C++0X)]) have_cxx11=yes], [AC_MSG_RESULT([no]) CXXFLAGS="$my_CXXFLAGS" have_cxx11=no])])])]) NUT_REPORT_FEATURE([build C++11 codebase (client library, etc.)], [${have_cxx11}], [], [HAVE_CXX11], [Define to enable C++11 support]) AC_LANG_POP([C++]) unset CPLUSPLUS_MAIN unset CPLUSPLUS_DECL AC_MSG_CHECKING(for have_cppunit) have_cppunit="no" CPPUNIT_NUT_CXXFLAGS="" AS_IF([test x"$have_PKG_CONFIG" = xyes], [AS_IF([test x"${have_cxx11}" = xyes], [ifdef([PKG_CHECK_MODULES], [PKG_CHECK_MODULES(CPPUNIT, cppunit, have_cppunit=yes, have_cppunit=no)], [have_cppunit=no]) AS_IF([test "${have_cppunit}" != "yes"], [AC_MSG_WARN([libcppunit not found - those C++ tests will not be built.]) have_cppunit=no], [AS_IF([test "x$GXX" = xyes], [CPPUNIT_NUT_CXXFLAGS="-g -O0"]) ]) ]) ], [AC_MSG_WARN([pkg-config not found, can not look properly for libcppunit - those C++ tests will not be built.]) have_cppunit=no] ) AC_MSG_RESULT(${have_cppunit}) dnl On some systems, CppUnit inexplicably fails with trivial assertions dnl so it should not be enabled with those environments, corrupting the dnl test results with misleading errors. dnl Tracked in https://github.com/networkupstools/nut/issues/1126 dnl One such situation was e.g. "clang++ + arm64(QEMU) + -m64" while dnl this was not seen with other compilers or bitness on same system. AS_IF([test "${have_cppunit}" = "yes"], [AC_MSG_CHECKING([if current toolkit can build and run cppunit tests (e.g. no ABI issues, related segfaults, etc.)]) dnl Code below is largely a stripped variant of our tests/example.cpp and cpputest.cpp CPLUSPLUS_DECL=' #include #include #include #include #include class ExampleTest : public CppUnit::TestFixture { CPPUNIT_TEST_SUITE( ExampleTest ); CPPUNIT_TEST( testOne ); CPPUNIT_TEST_SUITE_END(); public: void setUp() {}; void tearDown() {}; void testOne(); }; CPPUNIT_TEST_SUITE_REGISTRATION( ExampleTest ); void ExampleTest::testOne() { int i = 1; float f = 1.0; int cast = static_cast(f); CPPUNIT_ASSERT_EQUAL_MESSAGE("Casted float is not the expected int (assert_eq)", i, cast ); CPPUNIT_ASSERT_MESSAGE("Casted float is not the expected int (assert)", (i == cast) ); } ' CPLUSPLUS_MAIN=' CppUnit::Test *suite = CppUnit::TestFactoryRegistry::getRegistry().makeTest(); CppUnit::TextUi::TestRunner runner; runner.addTest( suite ); runner.setOutputter( new CppUnit::CompilerOutputter( &runner.result(), std::cerr ) ); bool res = runner.run(); return res ? 0 : 1; ' my_CXXFLAGS="$CXXFLAGS" my_LDFLAGS="$LDFLAGS" my_LIBS="$LIBS" CXXFLAGS="$myCXXFLAGS $pkg_cv_CPPUNIT_CFLAGS $pkg_cv_CPPUNIT_CXXFLAGS" LDFLAGS="$my_LDFLAGS $pkg_cv_CPPUNIT_LDFLAGS" LIBS="$my_LIBS $pkg_cv_CPPUNIT_LIBS" AC_LANG_PUSH([C++]) AX_RUN_OR_LINK_IFELSE([AC_LANG_PROGRAM([[${CPLUSPLUS_DECL}]], [[${CPLUSPLUS_MAIN}]])], [have_cppunit=yes], [have_cppunit=no]) CXXFLAGS="$my_CXXFLAGS" LDFLAGS="$my_LDFLAGS" LIBS="$my_LIBS" AC_LANG_POP([C++]) unset CPLUSPLUS_MAIN unset CPLUSPLUS_DECL AC_MSG_RESULT(${have_cppunit}) ]) dnl # By default keep the originally detected have_cppunit value AC_MSG_CHECKING(for impact from --enable-cppunit option - should we build cppunit tests?) AC_ARG_ENABLE(cppunit, [AS_HELP_STRING([--enable-cppunit], [enable CPPUNIT tests for C++ bindings])], [AS_CASE(["${enableval}"], ["yes"], [AS_IF([test x"${have_cppunit}" = xyes], [], [AC_MSG_ERROR([--with-cppunit=yes can not be satisfied])])], ["no"], [have_cppunit=no] )]) AC_MSG_RESULT(${have_cppunit}) NUT_REPORT_FEATURE([build C++ tests with CPPUNIT], [${have_cppunit}], [], [HAVE_CPPUNIT], [Define to enable CPPUNIT tests]) AC_DEFINE_UNQUOTED(CPPUNIT_NUT_CXXFLAGS, $CPPUNIT_NUT_CXXFLAGS, [Compiler flags for cppunit tests]) AC_MSG_CHECKING(whether to install Augeas configuration-management lenses) AC_ARG_WITH(augeas-lenses-dir, AS_HELP_STRING([--with-augeas-lenses-dir=PATH], [where to install Augeas configuration-management lenses (/usr/share/augeas/lenses{/dist,/})]), [ case "${withval}" in yes) if test -z "${auglensdir}"; then AC_MSG_RESULT(no) AC_MSG_ERROR([augeas lenses directory requested but not found in default location]) fi if ! test -s scripts/augeas/nutupsconf.aug.in ; then AC_MSG_RESULT(no) AC_MSG_ERROR([augeas lenses directory requested but a non-trivial scripts/augeas/nutupsconf.aug.in was not provided by autogen.sh or dist archive]) fi ;; auto) if ! test -s scripts/augeas/nutupsconf.aug.in ; then AC_MSG_WARN([augeas lenses directory skipped because a non-trivial scripts/augeas/nutupsconf.aug.in was not provided by autogen.sh or dist archive]) auglensdir="" fi ;; no) auglensdir="" ;; *) auglensdir="${withval}" ;; esac ], []) if test -n "${auglensdir}"; then AC_MSG_RESULT(using ${auglensdir}) NUT_REPORT_PATH_INTEGRATIONS([Augeas lenses directory], [${auglensdir}]) else AC_MSG_RESULT(no) fi AM_CONDITIONAL(WITH_AUGLENS, test -n "${auglensdir}") AC_PATH_PROGS([AUGPARSE], [augparse], [none]) AM_CONDITIONAL([HAVE_AUGPARSE], [test "x${AUGPARSE}" != "xnone"]) AC_MSG_CHECKING([whether to enable Augeas configuration-management lenses tests]) if test "x${AUGPARSE}" != xnone ; then AC_MSG_RESULT(yes) else AC_MSG_RESULT(no) fi AC_MSG_CHECKING(whether to install hotplug rules) AC_ARG_WITH(hotplug-dir, AS_HELP_STRING([--with-hotplug-dir=PATH], [where to install hotplug rules (${hotplugdir}); typically /etc/hotplug]), [ case "${withval}" in yes) if test -z "${hotplugdir}"; then AC_MSG_RESULT(no) AC_MSG_ERROR([hotplug directory requested but not found]) fi ;; auto) ;; no) hotplugdir="" ;; *) hotplugdir="${withval}" ;; esac ], []) if test -n "${hotplugdir}"; then AC_MSG_RESULT(using ${hotplugdir}) NUT_REPORT_PATH_INTEGRATIONS([Hotplug rules directory], [${hotplugdir}]) else AC_MSG_RESULT(no) fi AM_CONDITIONAL(WITH_HOTPLUG, test -n "${hotplugdir}") AC_MSG_CHECKING(whether to install udev rules) AC_ARG_WITH(udev-dir, AS_HELP_STRING([--with-udev-dir=PATH], [where to install udev rules (${udevdir}; typically /lib/udev or /etc/udev)]), [ case "${withval}" in yes) dnl Typically /lib/udev or /etc/udev if test -z "${udevdir}"; then AC_MSG_RESULT(no) AC_MSG_ERROR([udev directory requested but not found]) fi if test "${nut_with_usb}" = yes && ! test -s scripts/udev/nut-usbups.rules.in ; then AC_MSG_RESULT(no) AC_MSG_ERROR([udev directory and USB driver support requested but a non-trivial scripts/udev/nut-usbups.rules.in was not provided by autogen.sh or dist archive]) fi ;; auto) if test "${nut_with_usb}" = yes && ! test -s scripts/udev/nut-usbups.rules.in ; then AC_MSG_WARN([udev directory skipped because a non-trivial scripts/udev/nut-usbups.rules.in was not provided by autogen.sh or dist archive]) udevdir="" fi ;; no) udevdir="" ;; *) udevdir="${withval}" ;; esac ], []) if test -n "${udevdir}"; then AC_MSG_RESULT(using ${udevdir}) NUT_REPORT_PATH_INTEGRATIONS([Udev rules directory], [${udevdir}]) else AC_MSG_RESULT(no) fi AM_CONDITIONAL(WITH_UDEV, test -n "${udevdir}") dnl FreeBSD devd support: AC_MSG_CHECKING(whether to install FreeBSD devd.conf file) AC_ARG_WITH(devd-dir, AS_HELP_STRING([--with-devd-dir=PATH], [where to install devd.conf file (${devddir}; typically /usr/local/etc/devd or /etc/devd)]), [ case "${withval}" in yes) dnl Typically /usr/local/etc/devd or /etc/devd if test -z "${devddir}"; then AC_MSG_RESULT(no) AC_MSG_ERROR([devd directory requested but not found]) fi if test "${nut_with_usb}" = yes && ! test -s scripts/devd/nut-usbups.rules.in -a -s scripts/devd/nut-usb.conf.in ; then AC_MSG_RESULT(no) AC_MSG_ERROR([devd directory and USB driver support requested but non-trivial scripts/devd/nut-usbups.rules.in and scripts/devd/nut-usb.conf.in were not provided by autogen.sh or dist archive]) fi ;; auto) if test "${nut_with_usb}" = yes && ! test -s scripts/devd/nut-usbups.rules.in -a -s scripts/devd/nut-usb.conf.in ; then AC_MSG_WARN([devd directory skipped because non-trivial scripts/devd/nut-usbups.rules.in and scripts/devd/nut-usb.conf.in were not provided by autogen.sh or dist archive]) devddir="" fi ;; no) devddir="" ;; *) devddir="${withval}" ;; esac ], []) if test -n "${devddir}"; then AC_MSG_RESULT(using ${devddir}) NUT_REPORT_PATH_INTEGRATIONS([FreeBSD devd rules directory], [${devddir}]) else AC_MSG_RESULT(no) fi AM_CONDITIONAL(WITH_DEVD, test -n "${devddir}") dnl dnl AIX system AM_CONDITIONAL([SYSTEM_AIX], [test "xAIX" = "x`uname -s 2>/dev/null`"]) dnl processor type AC_DEFINE_UNQUOTED(CPU_TYPE, ["$target_cpu"], [Define processor type]) dnl Can use valgrind for memory-leak testing, if present AC_PATH_PROGS([VALGRIND], [valgrind], [none]) dnl Even if the tool is installed, it may be not usable on build platform. dnl QEMU may further complicate things, providing CPUs that formally match dnl a supported family but crash in practice, or hopefully rejected early: dnl valgrind: fatal error: unsupported CPU. dnl Supported CPUs are: dnl * x86 (practically any; Pentium-I or above), AMD Athlon or above) dnl * AMD Athlon64/Opteron dnl * ARM (armv7) dnl * MIPS (mips32 and above; mips64 and above) dnl * PowerPC (most; ppc405 and above) dnl * System z (64bit only - s390x; z990 and above) dnl Even if the tool does basically start, on some QEMU systems it crashes dnl later (e.g. claims Signal 11 in tear-down after a successful test), so dnl we support an explicit --without-valgrind (aka --with-valgrind=no) too. AS_IF([test -n "${VALGRIND}"], [ AC_MSG_CHECKING([whether valgrind is usable on current platform]) AS_IF([( ${VALGRIND} --help >/dev/null 2>/dev/null )], [AS_IF([( ${VALGRIND} /bin/sh -c true >/dev/null 2>/dev/null )], [AC_MSG_RESULT([yes])], [AC_MSG_RESULT([no]) VALGRIND="none" ])], [AC_MSG_RESULT([no]) VALGRIND="none" ]) ]) AC_MSG_CHECKING(whether to use valgrind for memory-leak testing) AC_ARG_WITH(valgrind, AS_HELP_STRING([--with-valgrind=PATH], [whether to use valgrind for memory-leak testing]), [ dnl ### echo "Caller said: '${withval}'... Discovered tool: '${VALGRIND}'... " case "${withval}" in yes) if test "x$VALGRIND" = "xnone"; then AC_MSG_RESULT(no) AC_MSG_ERROR([valgrind requested but not found]) fi with_valgrind="yes" ;; auto) with_valgrind="auto" ;; no) with_valgrind="no" ;; *) AC_PATH_PROGS([VALGRIND], ["${withval}"], [none]) if test "x$VALGRIND" = "xnone"; then AC_MSG_RESULT(no) AC_MSG_ERROR([valgrind requested but not found]) fi with_valgrind="yes" ;; esac ], []) if test "x${with_valgrind}" = xauto; then if test "x$VALGRIND" = "xnone"; then with_valgrind="no" else with_valgrind="yes" fi fi if test "x${with_valgrind}" = xyes; then AC_MSG_RESULT(using ${VALGRIND}) AC_MSG_NOTICE([Do not forget to build with debug (e.g. pass '-g' in CFLAGS for GCC) for best results with valgrind tests]) else AC_MSG_RESULT(no) fi AM_CONDITIONAL([HAVE_VALGRIND], [test "x${VALGRIND}" != "xnone"]) AM_CONDITIONAL([WITH_VALGRIND], [test "x${with_valgrind}" = "xyes"]) AC_MSG_CHECKING([whether to build cppunit tests using valgrind support]) if test "x${with_valgrind}" = xyes && test "x${have_cppunit}" = xyes ; then AC_MSG_RESULT(yes) else AC_MSG_RESULT(no) fi dnl expand ${sysconfdir} and write it out - note that most packages dnl override it to be /etc/nut, /etc/ups or similar, while the dnl autotools default would be $prefix/etc conftemp="${sysconfdir}" eval conftemp=\"${conftemp}\" eval conftemp=\"${conftemp}\" CONFPATH="${conftemp}" NUT_REPORT_SETTING_PATH([Config file path], CONFPATH, "${conftemp}", [Default path for configuration files]) dnl same for datadir conftemp="${datadir}" eval conftemp=\"${conftemp}\" eval conftemp=\"${conftemp}\" NUT_DATADIR="${conftemp}" NUT_REPORT_SETTING_PATH([Data file path], NUT_DATADIR, "${conftemp}", [Default path for data files]) dnl same for bindir conftemp="${bindir}" eval conftemp=\"${conftemp}\" eval conftemp=\"${conftemp}\" BINDIR="${conftemp}" NUT_REPORT_SETTING_PATH([Tool program path], BINDIR, "${conftemp}", [Default path for user executables]) dnl same for sbindir conftemp="${sbindir}" eval conftemp=\"${conftemp}\" eval conftemp=\"${conftemp}\" SBINDIR="${conftemp}" NUT_REPORT_SETTING_PATH([System program path], SBINDIR, "${conftemp}", [Default path for system executables]) dnl same for libdir conftemp="${libdir}" eval conftemp=\"${conftemp}\" eval conftemp=\"${conftemp}\" LIBDIR="${conftemp}" NUT_REPORT_SETTING_PATH([System library path], LIBDIR, "${conftemp}", [Default path for system libraries]) dnl same for libexecdir conftemp="${libexecdir}" eval conftemp=\"${conftemp}\" eval conftemp=\"${conftemp}\" LIBEXECDIR="${conftemp}" NUT_REPORT_SETTING_PATH([System exec-library path], LIBEXECDIR, "${conftemp}", [Default path for system exec-libraries]) dnl checks related to --with-snmp enabled on command-line dnl ${nut_with_snmp}: any value except "yes" or "no" is treated as "auto". if test "${nut_with_snmp}" = "yes" -a "${nut_have_libnetsnmp}" != "yes"; then AC_MSG_ERROR([Net-SNMP libraries not found, required for SNMP drivers]) fi if test "${nut_with_snmp}" != "no"; then nut_with_snmp="${nut_have_libnetsnmp}" else nut_have_libnetsnmp_static="no" fi NUT_REPORT_FEATURE([build SNMP drivers], [${nut_with_snmp}], [], [WITH_SNMP], [Define to enable SNMP support]) NUT_REPORT_FEATURE([build SNMP drivers with statically linked lib(net)snmp], [${nut_have_libnetsnmp_static}], [], [WITH_SNMP_STATIC], [Define to use SNMP support with a statically linked libnetsnmp]) if test -n "${host_alias}" ; then NUT_REPORT_TARGET(AUTOTOOLS_HOST_ALIAS, "${host_alias}", [host env spec we run on]) else if test -n "${host}" ; then NUT_REPORT_TARGET(AUTOTOOLS_HOST_ALIAS, "${host}", [host env spec we run on]) fi fi if test -n "${build_alias}" ; then NUT_REPORT_TARGET(AUTOTOOLS_BUILD_ALIAS, "${build_alias}", [host env spec we built on]) else if test -n "${build}" ; then NUT_REPORT_TARGET(AUTOTOOLS_BUILD_ALIAS, "${build}", [host env spec we built on]) fi fi if test -n "${target_alias}" ; then NUT_REPORT_TARGET(AUTOTOOLS_TARGET_ALIAS, "${target_alias}", [host env spec we built for]) else if test -n "${target}" ; then NUT_REPORT_TARGET(AUTOTOOLS_TARGET_ALIAS, "${target}", [host env spec we built for]) fi fi if test -n "${host_cpu}" -a -n "${host_os}" ; then NUT_REPORT_TARGET(AUTOTOOLS_HOST_SHORT_ALIAS, "${host_cpu}-${host_os}", [host OS short spec we run on]) fi if test -n "${build_cpu}" -a -n "${build_os}" ; then NUT_REPORT_TARGET(AUTOTOOLS_BUILD_SHORT_ALIAS, "${build_cpu}-${build_os}", [host OS short spec we built on]) fi if test -n "${target_cpu}" -a -n "${target_os}" ; then NUT_REPORT_TARGET(AUTOTOOLS_TARGET_SHORT_ALIAS, "${target_cpu}-${target_os}", [host OS short spec we built for]) fi AC_MSG_CHECKING([whether compiler suggests a MULTIARCH value]) dnl Recent GCC generally supports this call, although it often returns empty dnl Some versions of CLANG also have it, others reject the unknown CLI switch compiler_multiarch="`${CC} -print-multiarch 2>/dev/null`" || compiler_multiarch="" if test -n "${compiler_multiarch}" ; then NUT_REPORT_TARGET(MULTIARCH_TARGET_ALIAS, "${compiler_multiarch}", [host multiarch spec we build for (as suggested by compiler being used)]) fi dnl ---------------------------------------------------------------------- dnl Check the user and group to run as last, so we can use the paths configured dnl above as data sources for default values if building an in-place replacement AC_MSG_CHECKING(if requested user to run as) AC_ARG_WITH(user, AS_HELP_STRING([--with-user=username], [user for programs started as root (${RUN_AS_USER})]), [ case "${withval}" in yes|no) AC_MSG_ERROR(invalid option --with(out)-user - see docs/configure.txt) ;; *) RUN_AS_USER="${withval}" nut_user_given=yes AC_MSG_RESULT([specified]) ;; esac ], [ nut_user_given=no AC_MSG_RESULT([default]) ]) NUT_REPORT_SETTING([User to run as], RUN_AS_USER, "${RUN_AS_USER}", [User to switch to if started as root]) AC_MSG_CHECKING(if requested group membership of user to run as) AC_ARG_WITH(group, AS_HELP_STRING([--with-group=groupname], [group membership of user for programs started as root (${RUN_AS_GROUP})]), [ case "${withval}" in yes|no) AC_MSG_ERROR(invalid option --with(out)-group - see docs/configure.txt) ;; *) RUN_AS_GROUP="${withval}" nut_group_given=yes AC_MSG_RESULT([specified]) ;; esac ], [ nut_group_given=no AC_MSG_RESULT([default]) ]) NUT_REPORT_SETTING([Group of user to run as], RUN_AS_GROUP, "${RUN_AS_GROUP}", [Group membership of user to switch to if started as root]) dnl check that --with-user is given if --with-group is given. if test "${nut_user_given}" = "yes" -a "${nut_group_given}" = "no"; then AC_MSG_ERROR([If you specify --with-user, you also must specify --with-group]) elif test "${nut_user_given}" = "no" -a "${nut_group_given}" = "yes"; then AC_MSG_ERROR([If you specify --with-group, you also must specify --with-user]) fi dnl ---------------------------------------------------------------------- dnl Current date now=`TZ=UTC date +%Y-%m-%d` AC_SUBST(now) AC_SUBST(OS_NAME) AC_SUBST(TREE_VERSION) AC_SUBST(NUT_NETVERSION) AC_SUBST(FORCE_NUT_VERSION) AC_SUBST(NUT_SOURCE_GITREV) AC_SUBST(LIBSSL_CFLAGS) AC_SUBST(LIBSSL_LIBS) AC_SUBST(LIBSSL_REQUIRES) AC_SUBST(LIBGD_CFLAGS) AC_SUBST(LIBGD_LDFLAGS) AC_SUBST(LIBNETSNMP_CFLAGS) AC_SUBST(LIBNETSNMP_LIBS) AC_SUBST(LIBREGEX_LIBS) AC_SUBST(LIBUSB_CFLAGS) AC_SUBST(LIBUSB_LIBS) AC_SUBST(LIBNEON_CFLAGS) AC_SUBST(LIBNEON_LIBS) AC_SUBST(LIBAVAHI_CFLAGS) AC_SUBST(LIBAVAHI_LIBS) AC_SUBST(LIBPOWERMAN_CFLAGS) AC_SUBST(LIBPOWERMAN_LIBS) AC_SUBST(LIBMODBUS_CFLAGS) AC_SUBST(LIBMODBUS_LIBS) AC_SUBST(LIBIPMI_CFLAGS) AC_SUBST(LIBIPMI_LIBS) AC_SUBST(LIBGPIO_CFLAGS) AC_SUBST(LIBGPIO_LIBS) AC_SUBST(LIBI2C_LIBS) AC_SUBST(DOC_BUILD_LIST) AC_SUBST(DOC_CHECK_LIST) AC_SUBST(LIBWRAP_CFLAGS) AC_SUBST(LIBWRAP_LIBS) AC_SUBST(LIBLTDL_CFLAGS) AC_SUBST(LIBLTDL_LIBS) AC_SUBST(LIBSYSTEMD_CFLAGS) AC_SUBST(LIBSYSTEMD_LIBS) AC_SUBST(SYSTEMD_DAEMON_ARGS_UPSD) AC_SUBST(SYSTEMD_DAEMON_TYPE_UPSD) AC_SUBST(SYSTEMD_DAEMON_ARGS_UPSMON) AC_SUBST(SYSTEMD_DAEMON_TYPE_UPSMON) AC_SUBST(SYSTEMD_DAEMON_ARGS_DRIVER) AC_SUBST(SYSTEMD_DAEMON_TYPE_DRIVER) AC_SUBST(SYSTEMD_DAEMON_NOTIFYACCESS_DRIVER) AC_SUBST(SYSTEMD_DAEMON_NOTIFYACCESS_UPSD) AC_SUBST(SYSTEMD_DAEMON_NOTIFYACCESS_UPSMON) AC_SUBST(SYSTEMD_DAEMON_WATCHDOG_UPSD) AC_SUBST(SYSTEMD_DAEMON_WATCHDOG_UPSMON) AC_SUBST(SYSTEMD_DAEMON_WATCHDOG_DRIVER) AC_SUBST(SYSTEMD_TMPFILES_PROGRAM) AC_SUBST(DRIVER_BUILD_LIST) AC_SUBST(DRIVER_MAN_LIST) AC_SUBST(DRIVER_MAN_LIST_PAGES) AC_SUBST(DRIVER_INSTALL_TARGET) AC_SUBST(NETLIBS) AC_SUBST(SERLIBS) AC_SUBST(SEMLIBS) AC_SUBST(PREFIX) AC_SUBST(PIDPATH) AC_SUBST(STATEPATH) AC_SUBST(ALTPIDPATH) dnl #Not in main codebase yet# AC_SUBST(ALTSTATEPATH) AC_SUBST(CONFPATH) AC_SUBST(POWERDOWNFLAG) AC_SUBST(BINDIR) AC_SUBST(LIBDIR) AC_SUBST(PKGCONFIGDIR) AC_SUBST(NUT_DATADIR, [`eval echo "${NUT_DATADIR}"`]) AC_SUBST(NUT_LIBEXECDIR, [`eval echo "${LIBEXECDIR}"`]) AC_SUBST(DRVPATH) AC_SUBST(SBINDIR) AC_SUBST(PORT) AC_SUBST(RUN_AS_USER) AC_SUBST(RUN_AS_GROUP) AC_SUBST(SUN_LIBUSB) AC_SUBST(WORDS_BIGENDIAN) AC_SUBST(cgiexecdir) AC_SUBST(devddir) AC_SUBST(driverexecdir) AC_SUBST(htmldir) AC_SUBST(pkgconfigdir) AC_SUBST(systemdsystemunitdir) AC_SUBST(systemdshutdowndir) AC_SUBST(systemdtmpfilesdir) AC_SUBST(auglensdir) AC_SUBST(hotplugdir) AC_SUBST(udevdir) dnl On a related note to warning setup below, we limit the minimum C and C++ dnl standard versions to ones we actively strive to support (C99 and C++11, dnl GNU dialects tend to work on more systems if supported by compiler there). dnl It is assumed that on very old systems whose compilers do not know these dnl standards (only support ANSI/C89/C90 or older), as well as for builds dnl that explicitly specify a CFLAGS="-std=..." (for GCC/CLANG toolkits), dnl nothing should get added to CFLAGS/CXXFLAGS by this method: NUT_COMPILER_FAMILY_FLAGS_DEFAULT_STANDARD dnl Filter through known variants first, so automatic choices can be made. dnl Note that clang identifies as gcc-compatible so should be probed first. dnl TODO: Flip this default to "hard" when we clear existing codebase. dnl Note: the "gcc-legacy" option is intentionally undocumented, it acts as dnl least-surprise default if caller did not specify any --enable-warnings. dnl Note: Currently the "gcc-minimal" mode below adapts to builds with dnl C89/C90/ANSI mode to be less noisy. Keep this in mind if changing the dnl default "nut_warning_difficulty" and/or the case handling below. dnl NOTE: Until X-Mas 2021, the default was "minimal" (now "medium") nut_warning_difficulty="medium" AC_MSG_CHECKING([whether to pre-set warnings (from '${nut_enable_warnings}')]) AS_CASE(["${nut_enable_warnings}"], [no|all|gcc-legacy|gcc-minimal|clang-minimal|gcc-medium|clang-medium|gcc-hard|clang-hard], [], [clang], [nut_enable_warnings="${nut_enable_warnings}-${nut_warning_difficulty}"], [gcc], [ AS_CASE(["${CFLAGS}"], [*89*|*90*|*ansi*], [nut_enable_warnings="${nut_enable_warnings}-minimal"], [nut_enable_warnings="${nut_enable_warnings}-${nut_warning_difficulty}"] )], [yes|auto|""], [ AS_IF([test "${CLANGCC}" = "yes"], [nut_enable_warnings="clang-${nut_warning_difficulty}"], [AS_IF([test "${GCC}" = "yes"], [ AS_CASE(["${CFLAGS}"], [*89*|*90*|*ansi*], [nut_enable_warnings="gcc-minimal"], [AS_CASE(["$CC_VERSION"], [*" "1.*|*" "2.*|3.*|*" "4.0*|*" "4.1*|*" "4.2*|*" "4.3*], [ AC_MSG_WARN([Very old GCC in use, disabling warnings]) dnl #AS_IF([test x"${nut_enable_Werror}" = xauto], [nut_enable_Werror="no"]) nut_enable_Werror="no" nut_enable_warnings="no"], [*" "4.4*|*" "4.5*|*" "4.6*|*" "4.7*|*" "4.8*], [nut_enable_warnings="gcc-legacy"], [nut_enable_warnings="gcc-${nut_warning_difficulty}"] )] )], [nut_enable_warnings="all"]) ]) ], [hard|auto-hard|auto=hard], [ AS_IF([test "${CLANGCC}" = "yes"], [nut_enable_warnings="clang-hard"], [AS_IF([test "${GCC}" = "yes"], [nut_enable_warnings="gcc-hard"], [nut_enable_warnings="all"]) ]) ], [medium|auto-medium|auto=medium], [ AS_IF([test "${CLANGCC}" = "yes"], [nut_enable_warnings="clang-medium"], [AS_IF([test "${GCC}" = "yes"], [nut_enable_warnings="gcc-medium"], [nut_enable_warnings="all"]) ]) ], [minimal|auto-minimal|auto=minimal], [ AS_IF([test "${CLANGCC}" = "yes"], [nut_enable_warnings="clang-minimal"], [AS_IF([test "${GCC}" = "yes"], [nut_enable_warnings="gcc-minimal"], [nut_enable_warnings="all"]) ]) ], [legacy], [AS_IF([test "${GCC}" = "yes"], [nut_enable_warnings="gcc-legacy"], [nut_enable_warnings="no"])], [AC_MSG_WARN([Unsupported variant for --enable-warnings=${nut_enable_warnings}, ignored]) nut_enable_warnings="no" ] ) AC_MSG_RESULT(["${nut_enable_warnings}"]) dnl # Nothing special for gcc - we tend to survive it with GNU standard >= 99 dnl # and fail with strict C standard. Suggestions welcome for "gcc-hard" to dnl # make a difference. dnl # Note that "medium" and "hard" settings tend to trigger warnings also dnl # from system headers, so we try to avoid them, using "-isystem path" dnl # pre-set in our `m4/nut_compiler_family.m4` script: dnl # https://stackoverflow.com/questions/36355232/disable-certain-warnings-for-system-headers dnl # and "-Wno-system-headers" below. dnl # Some of the compiler flags (including those added by pkg-config of some dnl # third-party dependency packages) can upset older compiler releases which dnl # did not yet support those. Flags like "-Wno-unknown-warning" for GCC or dnl # "-Wno-unknown-warning-option" for CLANG should take care of that at least dnl # for toolkit versions that support these - set in NUT_COMPILER_FAMILY_FLAGS dnl # Majority of sanity checks are enabled by "-Wextra" on both GCC and CLANG dnl # and "-Weverything" additionally on CLANG. They are impractically picky, dnl # especially with fallout from system headers that we can not impact anyway dnl # so the "difficulty level" pre-sets exclude certain warning classes from dnl # that report. dnl ### Special exclusion picks for clang-hard: dnl # -Wno-unused-macros -- system headers define a lot of stuff we do not use, dnl # gotta be fatal right? dnl # -Wno-reserved-id-macro -- configure script tends to define _GNU_SOURCE_, dnl # __EXTENSIONS__ etc. which are underscored and reserved for compilers dnl # -Wno-padded -- NSPR and NSS headers get to issue lots of that dnl # -Wno-c++98-compat-pedantic -Wno-c++98-compat -- our C++ code uses nullptr dnl # as requested by newer linters, and C++98 does not. We require C++11 dnl # or newer anyway, and skip building C++ library and test otherwise. dnl # -Wno-fuse-ld-path -- not much in our control what recipes the autotools dnl # on the build host generate... this tries to avoid failures due to: dnl # clang-13: error: '-fuse-ld=' taking a path is deprecated. dnl # Use '--ld-path=' instead [-Werror,-Wfuse-ld-path] dnl # -Wno-unsafe-buffer-usage -- clang-16 introduced a check too smart for dnl # its own good. It detects use of pointer aritmetics as arrays are dnl # walked, which is indeed potentially dangerous. And also is nearly dnl # unavoidable in C (at least not without major rewrites of the world). dnl ### Special exclusion picks for clang-medium (same as hard, plus...): dnl # -Wno-float-conversion -Wno-double-promotion -Wno-implicit-float-conversion dnl # -- reduce noise due to floating-point literals like "3.14" being a C dnl # double type (a "3.14f" literal is a C float) cast implicitly into dnl # float variables. Also variadic functions like printf() cast their dnl # floating-point arguments into double (and small integer types into dnl # "int") which then confuses pedantic checks of printf("%f", floatval). dnl # -Wno-conversion -- similarly for error: implicit conversion loses dnl # floating-point precision: 'double' to 'float' [-Werror,-Wconversion] dnl # max_output = atof(sValue); dnl # -Wno-cast-qual -- our code calls some library methods in ways which use dnl # a "const char *" as a "char *" or vice-versa. Sometimes these method dnl # signatures differ between dependency releases; sometimes they just dnl # happened too hard to unravel cleanly and add more warnings. dnl # This exclusion may be removed after common warnings are solved, dnl # to allow progress on rectifying these cases next. dnl # -Wno-incompatible-pointer-types-discards-qualifiers -- our code often dnl # defines (char*) as the type for struct fields and method arguments, dnl # but initializes/passes (char[]) variables or fixed strings. dnl # This makes at least clang-3.4 quite upset and noisy (seems newer dnl # versions care less about this situation). dnl # -Wno-disabled-macro-expansion -- some system definitions of strncmp() dnl # and other routines are in fact recursive macros. The -Weverything dnl # mode of clang(-3.4) disables their handling, unless told otherwise. AS_CASE(["${nut_enable_warnings}"], [all], [ CFLAGS="${CFLAGS} -Wall" CXXFLAGS="${CXXFLAGS} -Wall" ], [clang-hard], [ CFLAGS="${CFLAGS} -ferror-limit=0 -Wno-system-headers -Wall -Wextra -Weverything -Wno-disabled-macro-expansion -Wno-unused-macros -Wno-reserved-id-macro -Wno-padded -Wno-documentation -Wno-cast-qual -pedantic -Wno-fuse-ld-path -Wno-unsafe-buffer-usage" CXXFLAGS="${CXXFLAGS} -ferror-limit=0 -Wno-system-headers -Wall -Wextra -Weverything -Wno-disabled-macro-expansion -Wno-unused-macros -Wno-reserved-id-macro -Wno-padded -Wno-documentation -Wno-cast-qual -Wno-c++98-compat-pedantic -Wno-c++98-compat -Wno-fuse-ld-path -Wno-unsafe-buffer-usage" ], [clang-medium], [ CFLAGS="${CFLAGS} -ferror-limit=0 -Wno-system-headers -Wall -Wextra -Weverything -Wno-disabled-macro-expansion -Wno-unused-macros -Wno-reserved-id-macro -Wno-padded -Wno-documentation -Wno-cast-qual -pedantic -Wno-fuse-ld-path -Wno-unsafe-buffer-usage -Wno-float-conversion -Wno-double-promotion -Wno-implicit-float-conversion -Wno-conversion -Wno-incompatible-pointer-types-discards-qualifiers" CXXFLAGS="${CXXFLAGS} -ferror-limit=0 -Wno-system-headers -Wall -Wextra -Weverything -Wno-disabled-macro-expansion -Wno-unused-macros -Wno-reserved-id-macro -Wno-padded -Wno-documentation -Wno-cast-qual -Wno-c++98-compat-pedantic -Wno-c++98-compat -Wno-fuse-ld-path -Wno-unsafe-buffer-usage" ], [clang-minimal], [ CFLAGS="${CFLAGS} -ferror-limit=0 -Wall -Wextra -Wno-documentation" CXXFLAGS="${CXXFLAGS} -ferror-limit=0 -Wall -Wextra -Wno-documentation" ], [gcc-legacy], [CFLAGS="${CFLAGS} -Wall -Wsign-compare"], [gcc-minimal], [ dnl Builds with C89 (and aliases) are quite noisy for C99+ syntax used dnl in NUT. The minimal-warnings should not complain in these builds. dnl To make matters worse, many modern OS and third-party library dnl headers can not be used with "C90 + pedantic" mode of GCC, either. CFLAGS="${CFLAGS} -Wall -Wsign-compare" CXXFLAGS="${CXXFLAGS} -Wall -Wextra" AS_CASE(["${CFLAGS}"], [*89*|*90*|*ansi*], [], [CFLAGS="${CFLAGS} -Wextra -pedantic"] ) ], [gcc-medium|gcc-hard], [ CFLAGS="${CFLAGS} -Wno-system-headers -Wall -Wextra -Wsign-compare" CXXFLAGS="${CXXFLAGS} -Wno-system-headers -Wall -Wextra" AS_CASE(["${CFLAGS}"], [*89*|*90*|*ansi*], [], [CFLAGS="${CFLAGS} -pedantic"] ) ] ) AS_IF([test x"${nut_enable_warnings}" != xno || test x"${nut_enable_Werror}" != xno], [AS_IF([test "x${CLANGCC}" = "xyes" || test "x${GCC}" = "xyes"], [AS_CASE(["${target_os}"], [*mingw*], [ AC_MSG_NOTICE( [GCC on WIN32 builds warns about '%lld' etc. via PRId64 etc. even though modern libraries support long-long printing in practice (older ones did not - hence the warning). Forcing "-Wno-format" into warnings options. ]) CFLAGS="${CFLAGS} -Wno-format" CXXFLAGS="${CXXFLAGS} -Wno-format" ] ) ]) ]) AC_MSG_CHECKING([whether to make warnings fatal]) AS_CASE(["${nut_enable_Werror}"], [yes|auto], [ CFLAGS="${CFLAGS} -Werror" CXXFLAGS="${CXXFLAGS} -Werror" ], [no], [ CFLAGS="${CFLAGS} -Wno-error" CXXFLAGS="${CXXFLAGS} -Wno-error" ] ) AC_MSG_RESULT(["${nut_enable_Werror}"]) dnl Some compilers (e.g. older clang-3.4) have issues with built-in methods dnl that are implemented as macros in system headers -- but only for some dnl sources like snmp-ups.c, nutscan-serial.c, scan_eaton_serial.c, serial.c, dnl scan_avahi.c, scan_xml_http.c, scan_snmp.c... (Seems they all refer to dnl -DNETSNMP_USE_INLINE among other options, and tends to happen more with dnl OpenSSL-enabled builds). Check if we like them? AC_CHECK_HEADER([string.h], [AC_LANG_PUSH([C]) CFLAGS_SAVED="${CFLAGS}" CFLAGS_BUILTIN_STR="-fno-builtin-strchr -fno-builtin-strcmp -fno-builtin-strncmp" CFLAGS="${CFLAGS} -Werror -Wunreachable-code ${LIBNETSNMP_CFLAGS} ${LIBLTDL_CFLAGS} ${LIBNEON_CFLAGS} ${LIBSSL_CFLAGS}" AC_MSG_CHECKING([whether we should disable string built-ins]) dnl AC_DEFINE([HAVE_STRING_H], [1], [Define to 1 if you have .]) AC_COMPILE_IFELSE( [AC_LANG_PROGRAM( [[#include ]], [char *s = "v1", c = '%'; if (strcmp(s, "v1") != 0) return 1; if (strchr(s, '1') == NULL) return 1; if (strchr(s, c) != NULL) return 1 /* no ";return 0;" here - autoconf adds one */ ])], [CFLAGS="${CFLAGS_SAVED}" AC_MSG_RESULT([no, they are not a problem])], [CFLAGS="${CFLAGS_BUILTIN_STR} ${CFLAGS}" AC_COMPILE_IFELSE( [AC_LANG_PROGRAM( [[#include ]], [char *s = "v1", c = '%'; if (strcmp(s, "v1") != 0) return 1; if (strchr(s, '1') == NULL) return 1; if (strchr(s, c) != NULL) return 1 /* no ";return 0;" here - autoconf adds one */ ])], [CFLAGS="${CFLAGS_BUILTIN_STR} ${CFLAGS_SAVED}" AC_MSG_RESULT([yes, this solves a problem])], [CFLAGS="${CFLAGS_SAVED} -Werror -Wno-unreachable-code ${LIBNETSNMP_CFLAGS} ${LIBLTDL_CFLAGS} ${LIBNEON_CFLAGS} ${LIBSSL_CFLAGS}" AC_COMPILE_IFELSE( [AC_LANG_PROGRAM( [[#include ]], [char *s = "mibs", c = '%'; /* Macro version of strcmp() has problems with strings shorter than * 3 or 4 bytes, so to avoid nailing "-Warray-bounds" as well, * here we just test for longer strings - existing NUT sources were * fixed for this situation already */ if (strcmp(s, "mibs") != 0) return 1; if (strchr(s, 'b') == NULL) return 1; if (strchr(s, c) != NULL) return 1 /* no ";return 0;" here - autoconf adds one */ ])], [dnl CFLAGS="${CFLAGS_SAVED} -Wno-unreachable-code" dnl NOTE: Empirically, constrain to just LIBNETSNMP_CFLAGS CFLAGS="${CFLAGS_SAVED}" LIBLTDL_CFLAGS="${LIBLTDL_CFLAGS} -Wno-unreachable-code" LIBNETSNMP_CFLAGS="${LIBNETSNMP_CFLAGS} -Wno-unreachable-code" AC_MSG_RESULT([no, but -Wno-unreachable-code solves the problem for this compiler])], [CFLAGS="${CFLAGS_SAVED}" AC_MSG_RESULT([no, this does not solve the problem or is not supported]) ]) ]) ] ) AC_LANG_POP([C])] ) dnl Similar to above, for s_addr = htonl((ntohl(ip->start.s_addr) + 1)); dnl which causes "shadowed local variable" as (re-)defined in nested macros. dnl Technically also needs to `#include ` for struct in_addr dnl but that should be pulled by inet.h anyway AC_CHECK_HEADER([arpa/inet.h], [AC_LANG_PUSH([C]) CFLAGS_SAVED="${CFLAGS}" CFLAGS_BUILTIN_NTOHL="-fno-builtin-htonl -fno-builtin-ntohl" CFLAGS="${CFLAGS} -Werror -Wunreachable-code -Wshadow ${LIBNETSNMP_CFLAGS} ${LIBLTDL_CFLAGS} ${LIBNEON_CFLAGS} ${LIBSSL_CFLAGS}" AC_MSG_CHECKING([whether we should disable htonl/ntohl built-ins]) dnl AC_DEFINE([HAVE_ARPA_INET_H], [1], [Define to 1 if you have .]) AC_COMPILE_IFELSE( [AC_LANG_PROGRAM( [[#include ]], [struct in_addr sin = {0}; sin.s_addr = htonl((ntohl(sin.s_addr) + 1)) /* no ";return 0;" here - autoconf adds one */ ])], [CFLAGS="${CFLAGS_SAVED}" AC_MSG_RESULT([no, they are not a problem])], [CFLAGS="${CFLAGS_BUILTIN_NTOHL} ${CFLAGS}" AC_COMPILE_IFELSE( [AC_LANG_PROGRAM( [[#include ]], [struct in_addr sin = {0}; sin.s_addr = htonl((ntohl(sin.s_addr) + 1)) /* no ";return 0;" here - autoconf adds one */ ])], [CFLAGS="${CFLAGS_BUILTIN_NTOHL} ${CFLAGS_SAVED}" AC_MSG_RESULT([yes, this solves a problem])], [CFLAGS="${CFLAGS_SAVED} -Werror -Wno-shadow ${LIBNETSNMP_CFLAGS} ${LIBLTDL_CFLAGS} ${LIBNEON_CFLAGS} ${LIBSSL_CFLAGS}" AC_COMPILE_IFELSE( [AC_LANG_PROGRAM( [[#include ]], [struct in_addr sin = {0}; sin.s_addr = htonl((ntohl(sin.s_addr) + 1)) ])], [CFLAGS="${CFLAGS_SAVED}" LIBLTDL_CFLAGS="${LIBLTDL_CFLAGS} -Wno-shadow" LIBNETSNMP_CFLAGS="${LIBNETSNMP_CFLAGS} -Wno-shadow" AC_MSG_RESULT([no, but -Wno-shadow solves the problem for this compiler])], [CFLAGS="${CFLAGS_SAVED}" AC_MSG_RESULT([no, this does not solve the problem or is not supported]) ]) ]) ] ) AC_LANG_POP([C])] ) dnl Finally restore warnings settings that the caller might have provided in CFLAGS etc NUT_POP_WARNINGS dnl Due to possibly repetitive content, generate unique settings dnl relative to the top_builddir (distcheck and all): AC_MSG_CHECKING([for top build dir for this configure run]) TOP_BUILDDIR="" AS_IF([test -n "${ac_abs_top_builddir}" && test -d "${ac_abs_top_builddir}"], [TOP_BUILDDIR="${ac_abs_top_builddir}"], [AS_IF([test -n "${ac_pwd}" && test -d "${ac_pwd}"], [TOP_BUILDDIR="${ac_pwd}"], [TOP_BUILDDIR="`dirname "$0"`" TOP_BUILDDIR="`cd "$TOP_BUILDDIR" && pwd`" || AC_MSG_ERROR([Can not detect TOP_BUILDDIR])] )] ) AC_MSG_RESULT(["${TOP_BUILDDIR}"]) ABS_TOP_BUILDDIR="`cd "${TOP_BUILDDIR}" && pwd`" || AC_MSG_ERROR([Can not detect ABS_TOP_BUILDDIR]) ABS_TOP_SRCDIR="`cd "${abs_srcdir}" && pwd`" || AC_MSG_ERROR([Can not detect ABS_TOP_SRCDIR]) AM_CONDITIONAL([BUILDING_IN_TREE], [test "${ABS_TOP_BUILDDIR}" = "${ABS_TOP_SRCDIR}"]) AC_MSG_CHECKING([whether to customize ${TOP_BUILDDIR}/scripts/systemd/nut-common-tmpfiles.conf.in for this system]) dnl TOTHINK: Some distributions make the directories below owned dnl by "root:${RUN_AS_GROUP}" with 77x permissions. Is it safer?.. AS_IF([test -n "$systemdtmpfilesdir"], [mkdir -p "${TOP_BUILDDIR}"/scripts/systemd cat > "${TOP_BUILDDIR}"/scripts/systemd/nut-common-tmpfiles.conf.in << EOF # Network UPS Tools (NUT) systemd integration # Distributed under the terms of GPLv2+ # See https://networkupstools.org/ # and https://github.com/networkupstools/nut/ # See also: https://github.com/networkupstools/nut/wiki/Technicalities:-Work-with-PID-and-state-file-paths#pidpath-altpidpath-statepath # State file (e.g. upsd to driver pipes) and PID file location for NUT: d @STATEPATH@ 0770 @RUN_AS_USER@ @RUN_AS_GROUP@ - - # Default PIPEFN and LOCKFN locations per upssched.conf: d @STATEPATH@/upssched 0770 @RUN_AS_USER@ @RUN_AS_GROUP@ - - X @STATEPATH@ EOF AS_IF([test "$STATEPATH" != "$PIDPATH"], [AS_CASE(["${PIDPATH}"], [*/run|*/tmp|*/shm], [], dnl Do not intrude into system paths; TODO: add more if appropriate for some Linux distro [cat >> "${TOP_BUILDDIR}"/scripts/systemd/nut-common-tmpfiles.conf.in << EOF # Primarily used by upsmon and upslog, possibly running as root: d @PIDPATH@ 0770 @RUN_AS_USER@ @RUN_AS_GROUP@ - - X @PIDPATH@ EOF ])]) AS_IF([test -n "$ALTPIDPATH" && test "$STATEPATH" != "$ALTPIDPATH" && test "$PIDPATH" != "$ALTPIDPATH"], [cat >> "${TOP_BUILDDIR}"/scripts/systemd/nut-common-tmpfiles.conf.in << EOF # Should be used as upsd and driver PID file location for NUT # (if ALTPIDPATH differs from STATEPATH): d @ALTPIDPATH@ 0770 @RUN_AS_USER@ @RUN_AS_GROUP@ - - X @ALTPIDPATH@ EOF]) dnl Generally added to support some forks AS_IF([test -n "$ALTSTATEPATH" && test "$STATEPATH" != "$ALTSTATEPATH" && test "$ALTSTATEPATH" != "$ALTPIDPATH" && test "$PIDPATH" != "$ALTSTATEPATH"], [cat >> "${TOP_BUILDDIR}"/scripts/systemd/nut-common-tmpfiles.conf.in << EOF # Some NUT variants also maintain an ALTSTATEPATH: d @ALTSTATEPATH@ 0770 @RUN_AS_USER@ @RUN_AS_GROUP@ - - X @ALTSTATEPATH@ EOF]) ]) AC_MSG_RESULT([done]) AC_MSG_NOTICE([Generating "data" files from templates, see below for executable scripts]) AC_CONFIG_FILES([ clients/Makefile common/Makefile conf/Makefile conf/upsmon.conf.sample conf/upssched.conf.sample data/html/header.html data/html/Makefile data/Makefile data/driver.list docs/Makefile docs/cables/Makefile docs/docinfo.xml docs/man/Makefile drivers/Makefile include/Makefile lib/libupsclient.pc lib/libnutclient.pc lib/libnutclientstub.pc lib/libnutscan.pc lib/Makefile scripts/Aix/nut-aix.spec scripts/RedHat/ups scripts/augeas/Makefile scripts/augeas/nutnutconf.aug scripts/augeas/nutupsdconf.aug scripts/augeas/nutupsdusers.aug scripts/augeas/nutupsmonconf.aug scripts/augeas/nutupsschedconf.aug scripts/augeas/nuthostsconf.aug scripts/augeas/nutupssetconf.aug scripts/avahi/nut.service scripts/devd/Makefile scripts/hotplug/Makefile scripts/hotplug/libhidups scripts/HP-UX/nut.psf scripts/python/Makefile scripts/python/module/PyNUT.py scripts/upsdrvsvcctl/Makefile scripts/systemd/Makefile scripts/systemd/nut-common-tmpfiles.conf scripts/systemd/nut-driver@.service scripts/systemd/nut-monitor.service scripts/systemd/nut-server.service scripts/systemd/nut-driver-enumerator.service scripts/systemd/nut-driver-enumerator.path scripts/Solaris/nut-driver-enumerator.xml scripts/Solaris/nut-driver.xml scripts/Solaris/nut-monitor.xml scripts/Solaris/nut-server.xml scripts/Solaris/nut.xml scripts/Solaris/Makefile scripts/Solaris/pkginfo scripts/udev/Makefile scripts/udev/nut-ipmipsu.rules scripts/ufw/Makefile scripts/ufw/nut.ufw.profile scripts/Windows/Makefile scripts/Windows/Installer/NUT-Installer.xml scripts/Makefile server/Makefile tools/Makefile tools/nut-scanner/Makefile tests/Makefile tests/NIT/Makefile Makefile ]) AC_MSG_NOTICE([Generating templated script files that should be marked executable]) m4_foreach_w([SCRIPTFILE], [ lib/libupsclient-config scripts/Aix/nut.init scripts/HP-UX/postinstall scripts/RedHat/upsd scripts/RedHat/upsmon scripts/python/app/NUT-Monitor-py2gtk2 scripts/python/app/NUT-Monitor-py3qt5 scripts/augeas/gen-nutupsconf-aug.py scripts/python/module/test_nutclient.py scripts/upsdrvsvcctl/nut-driver-enumerator.sh scripts/upsdrvsvcctl/upsdrvsvcctl scripts/systemd/nutshutdown scripts/Solaris/svc-nut-server scripts/Solaris/svc-nut-monitor scripts/Solaris/precheck.py scripts/Solaris/preinstall scripts/Solaris/postinstall scripts/Solaris/preremove scripts/Solaris/postremove scripts/Solaris/preproto.pl scripts/Solaris/nut tools/gitlog2changelog.py tools/nut-snmpinfo.py ], [ dnl Autoconf substitutes the token above specified in plain text, dnl e.g. the brace below is empty and bracket gives verbatim varname dnl AC_MSG_NOTICE([Script: SCRIPTFILE brace:(${SCRIPTFILE}) bracket:([SCRIPTFILE])]) AC_CONFIG_FILES(SCRIPTFILE, chmod +x "SCRIPTFILE") ]) AC_MSG_NOTICE([Generating templated script files whose templates might have been generated (or not) by autogen.sh calling our helper scripts]) m4_foreach_w([SCRIPTFILE], [ scripts/augeas/nutupsconf.aug scripts/udev/nut-usbups.rules scripts/devd/nut-usb.conf ], [ AC_MSG_CHECKING([whether to generate SCRIPTFILE]) AS_IF([test -s SCRIPTFILE.in && ! test -f SCRIPTFILE.in.AUTOGEN_WITHOUT], [AC_MSG_RESULT(yes) AC_CONFIG_FILES(SCRIPTFILE)], [AC_MSG_RESULT(no)] ) ]) dnl Define this before AC_OUTPUT(), so not inside the report routine below: AM_CONDITIONAL(KEEP_NUT_REPORT, test x"${nut_enable_keep_nut_report_feature-}" = xyes) dnl Prints a long list of files generated from templates... AC_OUTPUT dnl Normally the latest action, for the summary to be visible: NUT_REPORT_COMPILERS NUT_PRINT_FEATURE_REPORT dnl Stopping short of patching the unknown script, we can warn about the issue dnl (visibly as it impacts next activities of the caller): AS_IF([test -s "${ABS_TOP_SRCDIR}/install-sh" && grep -w MKDIRPROG "${ABS_TOP_SRCDIR}/install-sh" >/dev/null], [AS_IF([grep -v '#' "${ABS_TOP_SRCDIR}/install-sh" | grep -E '\$mkdirprog.*-p' >/dev/null], [], [AC_MSG_WARN([=====================================================]) AC_MSG_WARN([Your system provided (or NUT tarball included) an]) AC_MSG_WARN(['install-sh' implementation which is not safe for]) AC_MSG_WARN([parallel installs; export MKDIRPROG='mkdir -p']) AC_MSG_WARN([may help, otherwise run 'make install' sequentially.]) AC_MSG_WARN([This should not impact parallel builds.]) AC_MSG_WARN([=====================================================]) ]) ]) nut-2.8.1/docs/0000755000175000017500000000000014520277775010301 500000000000000nut-2.8.1/docs/nut-qa.txt0000644000175000017500000001643714500336654012170 00000000000000NUT Quality Assurance ===================== Recognizing the critical nature of NUT, the NUT Quality Assurance (NQA) effort has been established to improve NUT where necessary, and to maintain software quality as high as it should be. NQA is present in many aspects and areas of NUT. Documentation ------------- The documentation toolchain uses link:https://asciidoc.org/[AsciiDoc] to output both HTML pages and manual pages (troff). This single point of control fills many gaps, suppresses many redundancies, and optimizes documentation management in general. - The NUT website and HTML documentation are tested for W3C XHTML 1.1 and CSS compliance. This can be counter verified by clicking the W3C XHTML 1.1 and CSS icons, at the bottom of each page. //////////////////////////////////////////////////////////////////////////////// - the manual pages conformance is tested with link:http://catb.org/~esr/doclifter/index.html[doclifter] (outdated) //////////////////////////////////////////////////////////////////////////////// - Documentation source files are spell checked, using link:http://aspell.net[Aspell], both interactively (using 'make spellcheck-interactive') and automatically in Buildbot (using 'make spellcheck'). NOTE: A NUT dictionary is also available (docs/nut.dict), providing a glossary of terms related to power devices and management, as well as partial terms, technical jargon and author names. Source code ----------- Use of standards ~~~~~~~~~~~~~~~~ NUT promotes and uses many standards, such as: - the variable names standard used in NUT, - the coding rules and best practices for developers, - the use of a software architecture limiting developments to the very minimum, - the use of standard Free and OpenSource Software components, like: * the USB library, * the Net SNMP project, * the Neon library, * the OpenSSL library (to be replaced by NSS, which is more license compliant with NUT and can be FIPS 140 certified), * the TCP Wrappers library. QA tools and metrics ~~~~~~~~~~~~~~~~~~~~ NUT's quality is constantly monitored using many tools, like: - a Revision Control System (link:https://github.com/networkupstools/nut[Git]) to track development and ease regression fixes. //////////////////////////////////////////////////////////////////////////////// Any modification on the NUT source trees are reported on the link:http://lists.alioth.debian.org/mailman/listinfo/nut-commits[NUT Commits] mailing list. //////////////////////////////////////////////////////////////////////////////// - link:http://buildbot.networkupstools.org/public/nut/[Buildbot] for older take on multi-platform builds, and the - new dedicated Jenkins incarnation of the NUT CI Farm with "legacy UI" for link:https://ci.networkupstools.org/job/nut/job/nut/job/master/[main branch] and link:https://ci.networkupstools.org/job/nut/job/nut/view/change-requests/[PRs], also accessible at the slower but slicker-looking Blue Ocean user interface for link:https://ci.networkupstools.org/blue/organizations/jenkins/nut%2Fnut/activity/[activity], link:https://ci.networkupstools.org/blue/organizations/jenkins/nut%2Fnut/branches/[branches] and link:https://ci.networkupstools.org/blue/organizations/jenkins/nut%2Fnut/pr/[PRs], are all used to automate the compile/test cycle, using numerous platforms, target distributions, C/C++ revisions, compiler toolkits and make program implementations. Any build failure is caught early, and fixed quickly. Also we get to see if incoming pull requests (as well as Git branch HEADs) do not have code (or recipe) that is instantly faulty and can not build on one of the platforms we track even with relaxed warnings. //////////////////////////////////////////////////////////////////////////////// reported through the link:http://lists.alioth.debian.org/mailman/listinfo/nut-commits[NUT Commits] mailing list, and fixed quickly. //////////////////////////////////////////////////////////////////////////////// - a project portal with trackers for bugs, feature request, patches and tasks - LGTM.COM automatically checking C/C++ and Python code - Static code analysis: * link:https://scan.coverity.com/projects/networkupstools-nut[Coverity Scan overview of NUT] * status: image:https://scan.coverity.com/projects/8829/badge.svg[Coverity Scan Build Status] * cppcheck as part of NUT CI farm builds and reports NUT QA also relies on external tools and trackers, like: //////////////////////////////////////////////////////////////////////////////// FIXME (POST): - integrate static code analysis - consider splint, Frama-C, BLAST and Clang, and choose one. - only use coverity?! - point other distro BTS (use Launchpad as an aggregator?!) //////////////////////////////////////////////////////////////////////////////// - Clang - the Debian QA tools, available through the link:https://tracker.debian.org/pkg/nut[NUT Package Tracking System]: * Lintian general QA checks, * link:http://piuparts.debian.org/sid/source/n/nut.html[piuparts] automates the installation, upgrade and removal testing processes. - a runtime testing suite, which automates the inter-layer communication testing (driver -- upsd -- upsmon / clients), that is part of Ubuntu. link:https://git.launchpad.net/ubuntu/+source/nut/tree/debian/tests/test-nut.py[The NUT testing script] is available in the link:https://code.edge.launchpad.net/qa-regression-testing[Ubuntu QA Regression Testing suite]. + It installs NUT packages, configures it with the dummy-ups driver, changes a few data points and checks that these are well propagated with upsc. - similar approach is explored in NIT (NUT Integration Testing) suite, which is part of the codebase and automated with `make check-NIT`; it can also be added to default `make check` activities by running `configure --enable-check-NIT` * Note that developers updating components which directly impact NIT runs may benefit from `make check-NIT-devel` target, to rebuild the `upsd`, `dummy-ups`, `cppnit` and other programs used in the test as they iterate. - link:https://bugzilla.redhat.com/buglist.cgi?component=nut[Redhat / Fedora Bug tracker] - link:https://www.openhub.net/p/nut[Black Duck Open Hub] (formerly Ohloh.net) provides metrics on NUT source code base and activity. Runtime quality ~~~~~~~~~~~~~~~ - NUT provides many link:user-manual.html#NUT_Security[security features] to ensure a maximum runtime security level. - Packages use several link:http://wiki.debian.org/Hardening[Hardening methods] to protect NUT binaries. //////////////////////////////////////////////////////////////////////////////// FIXME (POST): - write a code conformance checker (nut-lint) - write a § on driver maintenance status - consider using [http://forge.novell.com/modules/xfmod/project/?opensuse OpenSUSE Build Service tools] - provide software metrics and evolution over the time * [http://www.flossmetrics.org/ FlossMetrics] * [http://en.wikipedia.org/wiki/Software_metric Wikipedia] * [http://cccc.sourceforge.net/ CCCC - C and C++ Code Counter] * [http://open.ncsu.edu/se/tutorials/metrics/ Metrics with Eclipse] - Code documentation, for the core architecture (client and drivers are already documented) * [http://doxygen.org/ Doxygen] * [http://naturaldocs.org/ NaturalDocs] //////////////////////////////////////////////////////////////////////////////// nut-2.8.1/docs/sock-protocol.txt0000644000175000017500000002160614501607135013547 00000000000000Driver/server socket protocol ============================= Here's a brief explanation of the text-based protocol which is used between the drivers and server. The drivers may send things on the socket at any time. They will send out changes to their local storage immediately, without any sort of prompting from the server. As a result, the server must always check on any driver sockets for activity. In terms of communications, each driver is a server on the Unix socket (or Windows named pipe) which it creates, and the data server `upsd` is a client which knows where to find such sockets, how they are named, and connects to all of them to send commands and receive data updates. During development, it is possible to use tools like `socat` to connect to the socket (you may want to enable `NOBROADCAST` mode soon), e.g. socat - UNIX-CONNECT:/var/state/ups/dummy-ups-UPS1 For more insight, NUT provides an optional tool of its own (not built by default): the `sockdebug` which is built when `configure --with-dev` is in effect, or can be requested from the root directory of the build workspace: make sockdebug && \ ./server/sockdebug dummy-ups-UPS1 Formatting ---------- All parsing on either side of the socket is done by parseconf, so the same rules about escaping characters and "quoting multi-word elements" apply here. Values which may contain odd characters are typically sent through pconf_encode to apply \ characters where necessary. The "" construct is used throughout to force a multi-word value to stay together on its way to the other end. Commands used by the drivers ---------------------------- These commands (or semantically responses to server commands in some cases) can be sent by drivers to the data server over the socket protocol. SETINFO ~~~~~~~ SETINFO "" SETINFO ups.status "OB LB" There is no "ADDINFO" -- if a given variable does not exist, it is created upon receiving the first SETINFO command. DELINFO ~~~~~~~ DELINFO DELINFO ups.temperature ADDENUM ~~~~~~~ ADDENUM "" ADDENUM input.transfer.low "95" DELENUM ~~~~~~~ DELENUM "" DELENUM input.transfer.low "98" ADDRANGE ~~~~~~~~ ADDRANGE ADDRANGE input.transfer.low 95 100 DELRANGE ~~~~~~~~ DELRANGE DELRANGE input.transfer.low 95 100 SETAUX ~~~~~~ SETAUX SETAUX ups.id 8 This overrides any previous value. The auxiliary value is presently used as a length byte for read-write variables that are strings. SETFLAGS ~~~~~~~~ SETFLAGS ... SETFLAGS ups.id RW STRING Note that this command takes a variable number of arguments, as multiple flags are supported. Also note that they are not crammed together in "", since "RW STRING" would mean something completely different. This also replaces any previous flags for a given variable. ADDCMD ~~~~~~ ADDCMD ADDCMD load.off DELCMD ~~~~~~ DELCMD DELCMD load.on DUMPDONE ~~~~~~~~ DUMPDONE This is only used to tell the server that every possible item has been transmitted in response to its DUMPALL request. Once this has been received by the server, it can be sure that it knows everything that the driver does. PONG ~~~~ PONG This is sent in response to a PING from the server. It is only used as a sanity check to make sure that the driver has not gotten stuck somewhere. DATAOK ~~~~~~ DATAOK This means that the driver is able to communicate with the UPS, and the data should be treated as usable. It is always sent at the end of the dump if the data is not stale. It may also be sent at other times. DATASTALE ~~~~~~~~~ DATASTALE This is sent by the driver to inform any listeners that the data is no longer usable. This usually means that the driver is unable to get any sort of meaningful response from the UPS. You must not rely on any status information once this has been sent. This will be sent in the beginning of a dump if the data is stale, and may be repeated. It is cleared by DATAOK. TRACKING ~~~~~~~~ TRACKING This is sent in response to an INSTCMD or SET VAR that includes a TRACKING, upon completion of request execution by the driver. is the integer return value from the driver handlers instcmd and setvar (see drivers/upshandler.h). The server is in charge of translating these codes into strings, as per docs/net-protocol.txt GET TRACKING. Commands sent by the server --------------------------- The data server `upsd` (or technically any client that connects to a Unix socket or Windows named pipe provided by each NUT driver) can send the following commands to the driver: PING ~~~~ PING This is sent to check on the health of a driver. The server should only send this when it hasn't heard anything valid from a driver recently. Some drivers have very little to say in terms of updates, and this may be the only communications they have with the server on a normal basis. If a driver does not respond with the PONG within a few seconds at the most, it should be treated as dead/unavailable. Data stored in the server must not be passed on to the clients when this happens. NOTE: For the `upsd` data server, the MAXAGE setting in upsd.conf controls how long since the last message from the driver it is considered stale. At 1/3 of this time the server sends a `PING` command to the driver, so there is some time for a `PONG` to arrive and reset the timer (any other message would serve that goal as well). INSTCMD ~~~~~~~ INSTCMD [] [TRACKING ] INSTCMD panel.test.start INSTCMD load.off 10 INSTCMD load.on 10 TRACKING 1bd31808-cb49-4aec-9d75-d056e6f018d2 NOTE: * is an additional and optional parameter for the command, * "TRACKING " can be provided to track commands execution status, if TRACKING was set to ON on upsd. In this case, driver will later return the execution status, using TRACKING. SET ~~~ SET "" [TRACKING ] SET ups.id "Data room" SET ups.id "Data room" TRACKING 2dedb58a-3b91-4fab-831f-c8af4b90760a NOTE: * "TRACKING " can be provided to track commands execution status, if TRACKING was set to ON on upsd. In this case, driver will later return the execution status, using TRACKING. DUMPALL ~~~~~~~ DUMPALL The server uses this to request a complete copy of everything the driver knows. This is returned in the form of the same commands (SETINFO, etc.) that would be used if they were being updated normally. As a result, the same parsing happens either way. The server can tell when it has a full copy of the data by waiting for DUMPDONE. That special response from the driver is sent once the entire set has been transmitted. NOBROADCAST ~~~~~~~~~~~ This connection does not want to receive broadcast messages (implemented by `send_to_all()` method in `dstate.c`). Default is to receive everything. BROADCAST (NUM) ~~~~~~~~~~~~~~~ This connection specified whether it wants to receive broadcast messages (implemented by `send_to_all()` method in `dstate.c`), and by default enables that -- unless disabled by providing an optional zero or negative numeric argument. Note that initial default is to receive everything, so this command may be useful for connections that disabled broadcasts at some point. Design notes ------------ Requests ~~~~~~~~ There is no way to request just one variable. This was done on purpose to limit the complexity of the drivers. Their job is to send out updates and handle a few simple requests. DUMPALL is provided to give the server a known foundation. To track a limited set of variables, a server just needs to do DUMPALL, then only have handlers that remember values for the variables that matter. Anything else should be ignored. Access/Security ~~~~~~~~~~~~~~~ There are no access controls in the drivers. Anything that can connect to their sockets can make requests, including SET and INSTCMD if supported by the driver and hardware. These sockets must be kept secure. If your operating system does not honor permissions or modes on sockets, then you must store them in a directory with suitable permissions to limit access. Command limitations ~~~~~~~~~~~~~~~~~~~ As parseconf is used to handle decoding and chunking of the data, there are some limits on what may be used. These default to 32 arguments of 512 characters each, which should be more than enough for everything which is currently needed by the software. These limits are strictly for sanity purposes, and may be raised if necessary. parseconf itself can handle vast numbers of arguments and characters, with some speed penalty as things get really big. Re-establishing communications ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ If the server loses its connection to the driver and later reconnects, it must flush any local storage and start again with DUMPALL. The driver may have changed the internal state considerably during that time, and any other approach could leave old elements behind. nut-2.8.1/docs/support.txt0000644000175000017500000001204514501607135012462 00000000000000ifdef::website[] Support instructions ==================== endif::website[] There are various ways to obtain support for NUT. Documentation ------------- - First, be sure to read the link:docs/FAQ.html[FAQ]. The most common problems are already addressed there. ifdef::website[] - Else, you can read the link:docs/user-manual.chunked/index.html[NUT User Manual]. endif::website[] ifndef::website[] - Else, you can read the linkdoc:user-manual[NUT user manual]. endif::website[] It also covers many areas about installing, configuring and using NUT. The specific steps on system integration are also discussed. - Finally, link:docs/man/index.html#User_man[User manual pages] will also complete the User Manual provided information. At least, read the manual page related to your driver(s). Mailing lists ------------- If you have still not found a solution, you should search the lists before posting a question. Someone may have already solved the problem: ifdef::backend-xhtml11[] ++++++++++++++++++++++++++++++++++++++
++++++++++++++++++++++++++++++++++++++ endif::backend-xhtml11[] ifndef::backend-xhtml11[] link:http://www.google.com/search?as_q=&as_oq=nut-upsuser+nut-upsdev&domains=lists.alioth.debian.org&sitesearch=lists.alioth.debian.org&btnG=Search+NUT+lists[search on the NUT lists using Google] endif::backend-xhtml11[] Finally, you can *subscribe* to a NUT mailing list to: Request help ~~~~~~~~~~~~ Use the link:http://lists.alioth.debian.org/mailman/listinfo/nut-upsuser[NUT Users] mailing list. In this case, be sure to include the following information: - OS name and version, - exact NUT version, - NUT installation method: package, or a custom build from source tarball or GitHub (which fork, branch, PR), - exact device name and related information (manufacturing date, web pointers, ...), - complete problem description, with any relevant traces, like system log excerpts, and driver debug output. You can obtain the latter using the following command, running as root and after having stopped NUT: /path/to/driver -DD -a If you don't include the above information in your help request, we will not be able to help you! Post a patch, ask a development question, ... ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Use the link:http://lists.alioth.debian.org/mailman/listinfo/nut-upsdev[NUT Developers] mailing list. Refer to the ifdef::website[] link:docs/developer-guide.chunked/index.html[NUT Developer Guide] for more information, and the chapter on how to link:docs/developer-guide.chunked/developers.html#_submitting_patches[submit patches]. endif::website[] ifndef::website[] linkdoc:developer-guide[NUT Developer Guide] for more information, and the chapter on how to link:../developer-guide.chunked/developers.html#_submitting_patches[submit patches]. endif::website[] Note that the currently preferable way for ultimate submission of improvements is to link:https://github.com/networkupstools/nut/pulls[post a pull request] from your GitHub fork of NUT. Benefits of PRs include automated testing and merge-conflict detection and resolution, as well as tracking discussion that is often needed to better understand, integrate or document the patch. Discuss packaging and related topics ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Use the link:http://lists.alioth.debian.org/mailman/listinfo/nut-packaging[NUT Packagers] mailing list. Refer to the ifdef::website[] link:docs/packager-guide.chunked/index.html[NUT Packager Guide] endif::website[] ifndef::website[] linkdoc:packager-guide[NUT Packager Guide] endif::website[] for more information. IRC (Internet Relay Chat) ------------------------- Yes, we're open! There is an official `#nut` channel on https://libera.chat/ network. Feel free to hang out with whoever is on-line at the moment, or watch reports from the NUT CI farm as they come. Please don't forget the basics of netiquette, such as that any help is done on a best-effort basis, people have other obligations, and are not always there even if their chat client is, and that respect and politeness are the norm (this includes doing some research before asking, and explaining the context where it is not trivial). GitHub Issues ------------- See https://github.com/networkupstools/nut/issues for another venue of asking (and answering) questions, as well as proposing improvements. To report new Devices Dumps Library entries, posting an issue is okay, but posting a link:https://github.com/networkupstools/nut-ddl/pulls[pull request] is a lot better -- easier for maintainers to review and merge any time. For some more detailed instructions about useful DDL reports, please see link:https://www.networkupstools.org/ddl/#_file_naming_convention[NUT DDL page]. nut-2.8.1/docs/features.txt0000644000175000017500000002342314501607135012566 00000000000000Features ======== NUT provides many features, and is always improving. Thus this list may lag behind the current code. Features frequently appear during the development cycles, so be sure to look at the link:https://www.networkupstools.org/download.html[release notes and change logs] to see the latest additions. //////////////////////////////////////////////////////////////////////////////// *FIXME* statement that NUT is *the* de facto standard on Opensource system. all Linux distributors have standardized the Power Devices support using NUT. More and more appliances manufacturers are bundling NUT... => add an Appendix NUT Device Integration in the User Manual //////////////////////////////////////////////////////////////////////////////// Multiple manufacturer and device support ---------------------------------------- - Monitors many UPS, PDU, ATS, PSU and SCD models from more than 170 manufacturers with a unified interface (link:stable-hcl.html[Hardware Compatibility List]). - Various communication types and many protocols are supported with the same common interface: * serial, * USB, * network (SNMP, Eaton / MGE XML/HTTP, IPMI). Multiple architecture support ----------------------------- - Cross-platform -- different flavors of Unix can be managed together with a common set of tools, even crossing architectures. - This software has been reported to run on Linux distributions, the BSDs, Apple's OS X, commercial Solaris and open-source illumos distros, IRIX, HP/UX, Tru64 Unix, and AIX. - Windows users may be able to build it directly with MSYS2, MinGW or Cygwin. There is also a port of the client-side monitoring to Windows called WinNUT. - Your system will probably run it too. You just need a good C compiler and possibly some more packages to gain access to the serial ports. Other features, such as USB / SNMP / whatever, will also need extra software installed. Layered and modular design with multiple processes -------------------------------------------------- - Three layers: drivers, server, clients. - Drivers run on the same host as the server, and clients communicate with the server over the network. - This means clients can monitor any UPS anywhere as long as there is a network path between them. WARNING: Be sure to plug your network's physical hardware (switches, hubs, routers, bridges, ...) into the UPS! Redundancy support -- Hot swap/high availability power supplies --------------------------------------------------------------- - upsmon can handle high-end servers which receive power from multiple UPSes simultaneously. - upsmon won't initiate a shutdown until the total power situation across all source UPSes becomes critical (on battery and low battery). - You can lose a UPS completely as long as you still have at least the minimum number of sources available. The minimum value is configurable. Security and access control --------------------------- - Manager functions are granted with per-user granularity. The admin can have full powers, while the admin's helper can only do specific non-destructive tasks such as a battery test (beware that with a worn-out battery whose replacement is a few years overdue, a "capacity/remaining runtime" test can still be destructive by powering off the load abruptly -- and also such a test can cause hosts to hide into graceful shutdowns when the battery state does get critical as part of the test). - The drivers, server, and monitoring client (upsmon) can all run as separate user IDs if this is desired for privilege separation. - Only one tiny part of one program has root powers. upsmon starts as root and forks an unprivileged process which does the actual monitoring over the network. They remain connected over a pipe. When a shutdown is necessary, a single character is sent to the privileged process. It then calls the predefined shutdown command. In any other case, the privileged process exits. This was inspired by the auth mechanism in Solar Designer's excellent popa3d. - The drivers and network server may be run in a chroot jail for further security benefits. This is supported directly since version 1.4 and beyond with the 'chroot=' configuration directive. - IP-based access control relies on the local firewall and link:http://en.wikipedia.org/wiki/TCP_Wrapper[TCP Wrapper]. - SSL is available as a build option ("--with-ssl"). It encrypts sessions with upsd and can also be used to authenticate servers. Web-based monitoring -------------------- - Comes stock with CGI-based web interface tools for UPS monitoring and management, including graphical status displays. - Custom status web pages may be generated with the CGI programs, since they use templates to create the pages. This allows you to have status pages which fit the look and feel of the rest of your site. Free software ------------- - That's free beer and free speech. Licensed under the GNU General Public License version 2 or later. - Know your systems -- all source code is available for inspection, so there are no mysteries or secrets in your critical monitoring tools. UPS management and control -------------------------- - Writable variables may be edited on higher end equipment for local customization - Status monitoring can generate notifications (email/pager/SMS/...) on alert conditions - Alert notices may be dampened to only trigger after a condition persists. This avoids the usual pager meltdown when something happens and no delay is used. - Maintenance actions such as battery runtime calibration are available where supported by the UPS hardware. - Power statistics can be logged in custom formats for later retrieval and analysis - All drivers are started and stopped with one common program. Starting one is as easy as starting ten: `upsdrvctl start`. - For operating systems with a supported service management framework, you can manage the NUT drivers wrapped into independent service instances using the 'upsdrvsvcctl' instead, and gain the benefits of automated restart as well as possibility to define further dependencies between your OS components. - Shutdowns and other procedures may be tested without stressing actual UPS hardware by simulating status values with the dummy-ups pseudo-driver. Anything that can happen in a driver can be replicated with dummy-ups. Monitoring diagrams ------------------- These are the most common situations for monitoring UPS hardware. Other ways are possible, but they are mostly variations of these four. NOTE: these examples show serial communications for simplicity, but USB or SNMP or any other monitoring is also possible. "Simple" configuration ~~~~~~~~~~~~~~~~~~~~~~ image:images/simple.png[] One UPS, one computer. This is also known as "Standalone" configuration. This is the configuration that most users will use. You need at least a driver, `upsd`, and `upsmon` running. "Advanced" configuration ~~~~~~~~~~~~~~~~~~~~~~~~ image:images/advanced.png[] One UPS, multiple computers. Only one of them can actually talk to the UPS directly. That's where the network comes in: - The Primary system runs the relevant driver, `upsd`, and `upsmon` in "primary" mode. - The Secondary systems only run `upsmon` in "secondary" mode which all connect to `upsd` on Primary. This is useful when you have a very large UPS that's capable of running multiple systems simultaneously. There is no longer the need to buy a bunch of individual UPSes or "sharing" hardware, since this software will handle the sharing for you. ////////////////////////////////////////////////////////////////////////////// *FIXME* remainder === One UPS, many clients === - Multiple systems may monitor a single UPS using only their network connections -- no special "UPS sharing" hardware is required. - "Secondaries and a primary" monitoring design synchronizes shutdowns so that secondary systems can bring down their operating systems cleanly before the primary tells the UPS to switch off the power. === Many UPSes, many clients === - Each `upsd` process can serve status data for multiple UPSes to many clients. Multiple NUT drivers need to be configured and running locally on the system with `upsd` then, and have appropriate media connections to the power devices. - Each `upsmon` process can monitor multiple UPSes, possibly from multiple `upsd` hosts, for status data. ////////////////////////////////////////////////////////////////////////////// "Big Box" configuration ~~~~~~~~~~~~~~~~~~~~~~~ image:images/bigbox.png[] Some systems have multiple power supplies and cords. You typically find this on high-end servers that allow hot-swap and other fun features. In this case, you run multiple drivers (one per UPS), a single `upsd`, and a single `upsmon` (as a primary for both UPS 1 and UPS 2) This software understands that some of these servers can also run with some of the supplies gone. For this reason, every UPS is assigned a "power value" -- the quantity of power supplies that it feeds on this system. The total available "power value" is compared to the minimum that is required for that hardware. For example, if you have 3 power supplies and 3 UPSes, but only 2 supplies must be running at any given moment, the minimum would be 2. This means that you can safely lose any one UPS and the software will handle it properly by remaining online and not causing a shut down. "Bizarre" configuration ~~~~~~~~~~~~~~~~~~~~~~~ image:images/bizarre.png[] You can even have a UPS that has the serial port connected to a system that it's not feeding. Sometimes a PC will be close to a UPS that needs to be monitored, so it's drafted to supply a serial port for the purpose. This PC may in fact be getting its own power from some other UPS. This is not a problem for the set-up. The first system ("mixed") is a Primary for UPS 1, but is only monitoring UPS 2. The other systems are Secondaries of UPS 2. Image credits ------------- Thanks to Eaton for providing shiny modern graphics. nut-2.8.1/docs/nut-names.txt0000644000175000017500000012225614504306366012670 00000000000000ifndef::external_title[] NUT variable names and instant commands ======================================= endif::external_title[] [NOTE] .RFC 9271 Recording Document ==== This document is defined by RFC 9271 published by IETF at https://www.rfc-editor.org/info/rfc9271 and is referenced as the document of record for the variable names and the instant commands used in the protocol described by the RFC. On behalf of the RFC, this document records the names of variables describing the abstracted state of an UPS or similar power distribution device, and the instant commands sent to the UPS using command `INSTCMD`, as used in commands and messages between the Attachment Daemon (the `upsd` in case of NUT implementation of the standard) and the clients. ==== This document defines the standard names of NUT commands and variables (not to be confused with <<_status_data,device status data>> described in ifdef::website[] another chapter). endif::website[] ifndef::website[] the `docs/new-drivers.txt` in NUT source codebase). endif::website[] Developers should use the names recorded here, with dstate functions and data mappings provided in NUT drivers for interactions with power devices. If you need to express a state which cannot be described by any existing name, please make a request to the NUT developers' mailing list for definition and assignment of a new name. Clients using unrecorded names risk breaking at a future update. If you wish to experiment with new concepts before obtaining your requested variable name, you should use a name of the form `experimental.x.y` for those states. Put another way: if you make up a name that is not in this list and it gets into the source code tree, and then the NUT community comes up with a better name later, clients that already use the undocumented variable will break when it is eventually changed. An explicitly "experimental" data point is less surprising in this regard. Similarly, some source files (`drivers/*-mib.c` and `drivers/*-hid.c`) may mention data point names following the pattern of `unmapped.x.y`. These are generated by helper scripts which walk the reports from SNMP and USB HID devices, respectively `scripts/subdriver/gen-snmp-subdriver.sh` and `scripts/subdriver/gen-usbhid-subdriver.sh`, and assign names based on strings in those reports. The `unmapped` entries should not be exposed in "production" builds of the NUT drivers. They are an aid for developers to know that such entries are served by their device, so an existing standard NUT name can be assigned for the concept (or new name negotiated with the community), but are normally hidden with `#if WITH_UNMAPPED_DATA_POINTS` clauses which can be enabled in custom NUT builds by use of `./configure --with-unmapped-data-points` option. NOTE: In the descriptions, "opaque" means programs should not attempt to parse the value for that variable as it may vary greatly from one UPS (or similar device) to the next. These strings are best handled directly by the user. Structured naming ----------------- All standard NUT names of variables and commands are structured, with a certain domain-specific prefix and purpose-specific suffix parts. NUT tools provide and interpret them as dot-separated strings (although third-party tools might restructure them by cutting and pasting at the dot separation location, e.g. to represent as a JSON data tree or as data model classes for specific programming languages). If you would be making a parser of this information, please do also note that in some *but not all* cases there is a defined data point for some reading or command at the "root level" of what evolved to be a collection of further structured related information (and there are no guarantees for future evolution in this regard), for example: * an `input.voltage` reports the momentary voltage level value and there is a `input.voltage.maximum` for a certain related detail; * conversely, there are several items like `input.transfer.reason` but there is no actual `input.transfer` report. There may be more layers than two (e.g. `input.voltage.low.warning`), and in certain cases detailed below there may be a variable component in the practical values (e.g. the `n` in `ambient.n.temperature.alarm` variable or `outlet.n.load.off` command names). Time and Date format -------------------- When possible, dates should be expressed in ISO 8601 and RFC 3339 compatible Calendar format, that is to say "YYYY-MM-DD", or otherwise a Combined Date and Time representation (`T