commit cbf3c258e05f4267d29a848523f8460254b4b77f Author: Xavier Date: Mon Oct 20 20:11:21 2025 +0200 first commit diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..f288702 --- /dev/null +++ b/LICENSE @@ -0,0 +1,674 @@ + GNU GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU General Public License is a free, copyleft license for +software and other kinds of works. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +the GNU General Public License is intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. We, the Free Software Foundation, use the +GNU General Public License for most of our software; it applies also to +any other work released this way by its authors. You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + + To protect your rights, we need to prevent others from denying you +these rights or asking you to surrender the rights. Therefore, you have +certain responsibilities if you distribute copies of the software, or if +you modify it: responsibilities to respect the freedom of others. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must pass on to the recipients the same +freedoms that you received. You must make sure that they, too, receive +or can get the source code. And you must show them these terms so they +know their rights. + + Developers that use the GNU GPL protect your rights with two steps: +(1) assert copyright on the software, and (2) offer you this License +giving you legal permission to copy, distribute and/or modify it. + + For the developers' and authors' protection, the GPL clearly explains +that there is no warranty for this free software. For both users' and +authors' sake, the GPL requires that modified versions be marked as +changed, so that their problems will not be attributed erroneously to +authors of previous versions. + + Some devices are designed to deny users access to install or run +modified versions of the software inside them, although the manufacturer +can do so. This is fundamentally incompatible with the aim of +protecting users' freedom to change the software. The systematic +pattern of such abuse occurs in the area of products for individuals to +use, which is precisely where it is most unacceptable. Therefore, we +have designed this version of the GPL to prohibit the practice for those +products. If such problems arise substantially in other domains, we +stand ready to extend this provision to those domains in future versions +of the GPL, as needed to protect the freedom of users. + + Finally, every program is threatened constantly by software patents. +States should not allow patents to restrict development and use of +software on general-purpose computers, but in those that do, we wish to +avoid the special danger that patents applied to a free program could +make it effectively proprietary. To prevent this, the GPL assures that +patents cannot be used to render the program non-free. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Use with the GNU Affero General Public License. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU Affero General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the special requirements of the GNU Affero General Public License, +section 13, concerning interaction through a network will apply to the +combination as such. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +state the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +Also add information on how to contact you by electronic and paper mail. + + If the program does terminal interaction, make it output a short +notice like this when it starts in an interactive mode: + + Copyright (C) + This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, your program's commands +might be different; for a GUI interface, you would use an "about box". + + You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU GPL, see +. + + The GNU General Public License does not permit incorporating your program +into proprietary programs. If your program is a subroutine library, you +may consider it more useful to permit linking proprietary applications with +the library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. But first, please read +. diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..ff4b526 --- /dev/null +++ b/Makefile @@ -0,0 +1,27 @@ +VERSION := 173 +CXXFLAGS = -Wall -O3 -std=c++0x -Wno-write-strings -Wno-narrowing -DDRIVER_SERIAL=$(VERSION) $(RASPI) +LDFLAGS = -lpthread -lrt -lm -liio -lliquid -lad9361 -lfftw3 -lfftw3_threads -lsndfile -lasound -lsoundio -lgpiod +OBJ = qo100trx.o rx.o tx.o fft.o\ +kmlib/kmtimer.o kmlib/km_helper.o kmlib/kmfifo.o kmlib/rotary.o\ +udp/udp.o\ +liquid/liquiddrv.o liquid/liquiddrv_modulator.o\ +pluto/pluto_finder.o pluto/pluto_driver.o pluto/pluto_setup.o pluto/pluto_run.o\ +libkmaudio/libkmaudio_fifo.o libkmaudio/libkmaudio_getDevices.o libkmaudio/libkmaudio_getDevices_Linux.o\ +libkmaudio/libkmaudio_init.o libkmaudio/libkmaudio_init_linux.o libkmaudio/libkmaudio_interface.o libkmaudio/libkmaudio_capture_linux.o\ +libkmaudio/libkmaudio_playback_linux.o libkmaudio/libkmaudio_resampler.o + +default: $(OBJ) + g++ $(CXXFLAGS) -o Release/trxdriver $(OBJ) $(LDFLAGS) + echo $(VERSION) > version.txt + rm -rf Release/*.config Release/*.pdb + chmod 755 Release/startQO100trx + +clean: + rm -rf *.o + rm -rf kmlib/*.o + rm -rf pluto/*.o + rm -rf udp/*.o + rm -rf liquid/*.o + rm -rf libkmaudio/*.o + rm -rf Release/trxdriver + \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..3208dc8 --- /dev/null +++ b/README.md @@ -0,0 +1,103 @@ +# QO100_Transceiver +QO-100 Software Transceiver using an Adalm-Pluto and an SBC (Raspberry, Odroid ...), also works on Linux-Desktop PCs + + +This project is a fully functional software based transceiver for QO-100 + +Version Status:\ +V1.0 ... May, 28 2021 ... Now fully working, Setup via Setup Menu.\ +V1.1 ... May, 31 2021 ... Pluto USB/ETH setup, speech compressor\ +V1.2 ... June, 2 2021 ... Audio Filter, Muting, new user interface\ +V1.4 ... June, 6 2021 ... calibration for Pluto and LNB\ +V1.5 ... June,11 2021 ... Major Upgrade (!) PLEASE CHECK YOUR SETUP (frequencies have been changed)\ +V1.6 ... June,12 2021 ... various bug fixes (Sound card name, now working on 64bit Raspi)\ +V1.63 .. June,16 2021 ... new settings: Pluto TX power, Screen Size\ +V1.64 .. June,17 2021 ... many more Screen Sizes, new languages\ +V1.66 .. June,25 2021 ... cleanup in the GUI, new RX/TX QRG settings, now usable also by touch screens. Stores RX-to-TX offset.\ +V1.67 .. June,28 2021 ... first version which officially runs on Rapberry PI-3B+ (choose smaller screen size i.e. 1024x768, and disable beacon lock (important !) the lock symbol must show "FREE"). Also works on Orange PC+. \ +V1.67 .. July,19 2021 ... Install files updated\ +V1.68 .. July,26 2021 ... PTT control implemented, needs F5OEO firmware 2021 or later (version from 2019 does not work ! Pluto Rev.C needs also a patch)\ +V1.69 ...August, 9 2021 ... rotary enocder for raspberry (frequency and RX volume), details see documentation\ +V1.70 ...August, 23 2021 ... new screen size 1600x1050, 800Hz Test Tone (see left buttons), PTT output (and input), Mute input on Raspi GPIO, changes in installation scripts\ +V1.71 ...September, 14 2021 ... HF-Loop corrected, Level (dB) display, Auto-QSO-Sync (see Setup), Microphone TX levels modified to avoid splatter\ +V1.72 ...September, 18 2021 ... new AUDIO menu, new AGC, allows full output even with weak microphones\ + January 13, 2022 ... modified installation procedure to get it running on raspberry OS "bullseye"\ +V1.73 ...April, 2 2022 ... when restarting: uses last RX/TX qrg. This makes it easier to continue a QSO if the software was stopped or crashed.\ +V1.73a...November, 16 2022 ... extended the install script for the ubuntu version vanessa. The TRX is the same as 1.73, just the installation has been extended.\ + + +![alt text](https://github.com/dj0abr/QO100_Transceiver/blob/main/trxGui/Properties/sampleGUI.png) + +## Hardware requirements + +* Pluto SDR (connected via USB or Eth/USB Adapter) +* SBC like Raspberry PI-4, Odroid C4, Odroid N2 or Desktop-PC (Debuian based, Ubuntu, Mint...) and many others +* USB sound stick (if the SBC does not have a microphone connector) +* Satellite-Dish, QO-100 Feed and 2,4 GHz Amplifier (i.e. Amsat-DL 46dB Amp) + +## Documentation + +this software was developed for Amsat-DL. You can find the detailed documentation in the Amsat-Wiki: +http://wiki.amsat-dl.org/doku.php?id=en:plutotrx:overview + +## Installation + +The complete installation (and upgrading) is done by one single install file: +https://raw.githubusercontent.com/dj0abr/QO100_Transceiver/main/install + +(no need to clone this github project, all is done automatically by this install file) + +open a terminal and run these commands: + +``` +wget https://raw.githubusercontent.com/dj0abr/QO100_Transceiver/main/install +chmod 755 install +./install +``` + +that's all. There is nothing more to do than to run this install file. + +The install script was made for debian/ubuntu based Linux systems. If you are using another system then please do these steps manually: + +* clone this project +* in the script QO100_Transceiver/sctipts/prepare_ubuntu_pluto look for the installation of several libraries and install them for your OS. +* Install the latest version of the mono project (see prepare_mono as an example) +* make clean and make the transceiver software + +## run the software + +the software has two parts: + +trxdriver .... this is the part doing all the work, without the GUI\ +trxGui.exe ... the user interface + +After installation both files are located in the folder\ +.../QO100_Transceiver/Release + +Additionally a start script was created + +* start the software by entering: ./startQO100trx + +this opens the user interface and automatically starts the background jobs + +## configuration + +click the SETUP button + +* enter how the pluto is connected +* choose the sound device where microphone and loud speaker are connected +* enter the correct RX and TX frequencies. See the examples on the screen. + +#### Audio on Raspberry PI OS: + +Raspi OS shows many many audio devices nobody really needs.\ +It is highly recommended to choose Pulseaudio for loudspeaker and microphone and then use the sound mixer pavucontrol (is installed) to select devices and control volume. + +## Linux OS issues + +In general this software runs on all linux distributions. +The script prepare_ubuntu_pluto contains the installation for all required libraries. + +But different distributions may use different names for their libraries. The script was developed for Ubuntu based systems, like Ubuntu, Mint, Raspbery-OS and many others. + +If you try to run prepare_ubuntu_pluto on different platforms like Suse, Fedora... you maybe need to change the name of some libraries. diff --git a/Release/ColorSlider.dll b/Release/ColorSlider.dll new file mode 100755 index 0000000..2effcf8 Binary files /dev/null and b/Release/ColorSlider.dll differ diff --git a/Release/SOInstLin.sh b/Release/SOInstLin.sh new file mode 100644 index 0000000..aecb505 Binary files /dev/null and b/Release/SOInstLin.sh differ diff --git a/Release/bcn_fftcfg b/Release/bcn_fftcfg new file mode 100644 index 0000000..ad9536b --- /dev/null +++ b/Release/bcn_fftcfg @@ -0,0 +1,13 @@ +(fftw-3.3.10 fftw_wisdom #x3c273403 #x192df114 #x4d08727c #xe98e9b9d + (fftw_codelet_t1fv_4_avx 1 #x11bdd #x11bdd #x0 #x3faffd6c #x36c48939 #x2b89344c #x07d800dd) + (fftw_codelet_t2fv_20_avx 0 #x11bdd #x11bdd #x0 #x587c66c4 #x4f76fdef #xceb21d82 #xa0de1395) + (fftw_codelet_t2fv_25_sse2 1 #x11bdd #x11bdd #x0 #x5ecdb41b #x076a3fa6 #x4b08f138 #x4d35e39a) + (fftw_dft_thr_vrank_geq1_register 0 #x11bdd #x11bdd #x0 #x437baa88 #x22931f52 #xd4baa3df #x89d10f69) + (fftw_dft_thr_vrank_geq1_register 0 #x11bdd #x11bdd #x0 #x4cd32709 #xcef8290a #x90af32c9 #xefa6f35c) + (fftw_dft_vrank_geq1_register 0 #x11bdd #x11bdd #x0 #xfd422625 #x3b710790 #xb20b63af #x07bc3484) + (fftw_codelet_t1fv_5_avx 0 #x11bdd #x11bdd #x0 #xd9f832de #xb911c57e #xb0878a3f #x59d43138) + (fftw_codelet_n1fv_20_avx 0 #x11bdd #x11bdd #x0 #xdc55ecc0 #x01886d93 #x75a23ccf #x95afb0b0) + (fftw_codelet_n1fv_14_avx 0 #x11bdd #x11bdd #x0 #xc521610b #x38693a8a #x5257754a #xcc97d2ef) + (fftw_dft_thr_vrank_geq1_register 0 #x11bdd #x11bdd #x0 #x6c8cc274 #xb6b23efe #x536976d9 #xba7dfb58) + (fftw_codelet_t1fv_16_sse2 1 #x11bdd #x11bdd #x0 #x0356ef58 #xd4323bdf #xbb447b08 #x9e812fce) +) diff --git a/Release/fftcfg b/Release/fftcfg new file mode 100644 index 0000000..df79cad --- /dev/null +++ b/Release/fftcfg @@ -0,0 +1,9 @@ +(fftw-3.3.10 fftw_wisdom #x3c273403 #x192df114 #x4d08727c #xe98e9b9d + (fftw_codelet_n1fv_14_avx 0 #x11bdd #x11bdd #x0 #xc521610b #x38693a8a #x5257754a #xcc97d2ef) + (fftw_codelet_t2fv_20_avx 0 #x11bdd #x11bdd #x0 #x587c66c4 #x4f76fdef #xceb21d82 #xa0de1395) + (fftw_codelet_t1fv_5_avx 0 #x11bdd #x11bdd #x0 #xd9f832de #xb911c57e #xb0878a3f #x59d43138) + (fftw_dft_thr_vrank_geq1_register 0 #x11bdd #x11bdd #x0 #x6c8cc274 #xb6b23efe #x536976d9 #xba7dfb58) + (fftw_dft_vrank_geq1_register 0 #x11bdd #x11bdd #x0 #xfd422625 #x3b710790 #xb20b63af #x07bc3484) + (fftw_dft_thr_vrank_geq1_register 0 #x11bdd #x11bdd #x0 #x437baa88 #x22931f52 #xd4baa3df #x89d10f69) + (fftw_codelet_t1fv_16_sse2 1 #x11bdd #x11bdd #x0 #x0356ef58 #xd4323bdf #xbb447b08 #x9e812fce) +) diff --git a/Release/qo100trx.exe b/Release/qo100trx.exe new file mode 100755 index 0000000..ddbfacf Binary files /dev/null and b/Release/qo100trx.exe differ diff --git a/Release/startQO100trx b/Release/startQO100trx new file mode 100755 index 0000000..ccd8bac --- /dev/null +++ b/Release/startQO100trx @@ -0,0 +1,2 @@ +export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/usr/local/lib:/usr/local/lib/arm-linux-gnueabihf +mono qo100trx.exe diff --git a/Release/trxdriver b/Release/trxdriver new file mode 100755 index 0000000..4480664 Binary files /dev/null and b/Release/trxdriver differ diff --git a/ai.ico b/ai.ico new file mode 100644 index 0000000..64581ff Binary files /dev/null and b/ai.ico differ diff --git a/fft.cpp b/fft.cpp new file mode 100644 index 0000000..5b08134 --- /dev/null +++ b/fft.cpp @@ -0,0 +1,484 @@ +/* +* Adalm Pluto Driver +* ================== +* Author: DJ0ABR +* +* (c) DJ0ABR +* www.dj0abr.de +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 2 of the License, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You 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. +* +* ========================= +* FFT for Spectrum/Waterfall +* ========================= +* +*/ + +#include "qo100trx.h" +#include + +void fftinit(); +void calc_fft(uint8_t *data, int len); +void findSignal(uint16_t *p16, int anz); + +void* fft_threadfunction(void* param); + +void init_fft() +{ + fftinit(); + + pthread_t fftthread; + pthread_create(&fftthread, NULL, fft_threadfunction, NULL); +} + +void* fft_threadfunction(void* param) +{ +int ph = 0; + + pthread_detach(pthread_self()); + + printf("entering FFT loop, *** PID:%ld ***\n",syscall(SYS_gettid)); + while(keeprunning) + { + uint8_t data[PLUTOBUFSIZE*4]; + if(read_fifo(FFTfifo, data, PLUTOBUFSIZE*4)) + { + if(++ph >= 2) // uncomment to reduce cpu load + { + ph=0; + calc_fft(data, PLUTOBUFSIZE*4); + } + } + + usleep(1000); + } + printf("exit FFT loop\n"); + pthread_exit(NULL); // self terminate this thread + return NULL; +} + +fftw_complex *din = NULL; +fftw_complex *cpout = NULL; +fftw_plan plan = NULL; + +#define FFT_RESOLUTION 25 // Hz per bin +#define FFT_LENGTH (SAMPRATE / FFT_RESOLUTION) // 560kS/s / 25 = 22400 + +void fftinit() +{ + + int numofcpus = sysconf(_SC_NPROCESSORS_ONLN); // Get the number of logical CPUs. + if(numofcpus > 1) + { + printf("found %d cores, running FFT in multithreading mode\n",numofcpus); + fftw_init_threads(); + fftw_plan_with_nthreads(numofcpus); + } + + fftw_import_wisdom_from_filename("fftcfg"); + + din = (fftw_complex *)fftw_malloc(sizeof(fftw_complex) * FFT_LENGTH); + cpout = (fftw_complex *)fftw_malloc(sizeof(fftw_complex) * FFT_LENGTH); + plan = fftw_plan_dft_1d(FFT_LENGTH, din, cpout, FFTW_FORWARD, FFTW_MEASURE); + + fftw_export_wisdom_to_filename("fftcfg"); + printf("fft init ok\n"); +} + +void close_fft() +{ + if(din) fftw_free(din); + din = NULL; + + if(cpout) fftw_free(cpout); + cpout = NULL; +} + +// convert a frequency offset (starting at ,470 and the kHz part only) to the bin index +int FreqToBinIdx(int freq) +{ + // bins: 0.. 22400 + // freq: 0..560000 + return freq * 224 / 5600; +} + +void calc_fft(uint8_t *data, int len) +{ +static int din_idx = 0; +double real, imag; + + // values for small WF, calculate only once per loop + int span = FFT_RESOLUTION*1120; // size of small waterfall in Hz (28000Hz, +/-14kHz) + int start = FreqToBinIdx(RXoffsetfreq - span/2); + int end = FreqToBinIdx(RXoffsetfreq + span/2); + + // bin position of RX signal at 0.2-2.8kHz above RXoffsetfreq + int qsostart = FreqToBinIdx(RXoffsetfreq + 200); + int qsoend = FreqToBinIdx(RXoffsetfreq + 2800); + + for(int i=0; i= FFT_LENGTH) + { + + din_idx = 0; + // if fftspeed > 0 then ignore every n fft line + // this helps to run this software on slow SBCs + static int fdel = 0; + if(fdel++ < fftspeed) continue; + fdel = 0; + + // the fft input buffer is full, now lets execute the fft + fftw_execute(plan); + // the FFT delivers FFT_LENGTH values (44800 bins) + // but we only use the first half of them, which is the full range with the + // requested resolution of 25 Hz per bin (22400 bins) + int numbins = FFT_LENGTH; // 22400 (22400*25=560k) + // the FFT generates the upper half folloed by the lower half + // the tuned freq is in the center + + // range centerfreq(,750) - 560k/2 to +560k/2 + // is ,470 ... 1,030 + + float bin[numbins]; + int binidx = 0; + // lower half + for(int i=numbins/2; i 32768) printf("reduce multiplicator %f\n",bin[binidx]); + binidx++; + } + // upper half + for(int i=0; i 32768) printf("reduce multiplicator %f\n",bin[binidx]); + binidx++; + } + // bins are in the range 0..32767 (16 bit) + + // ======== noise level ========== + // measure the noise level on freq: ,475 to ,490 MHz, just below the lower beacon + // ,470 is index 0, steps 25 Hz + // ,475 is index 200 and ,490 is index 800 + // so we calc the mid value if this range + float gval = 0; + float maxgval = 0; + int gstart = FreqToBinIdx(485000 - 470000); + int gend = FreqToBinIdx(495000 - 470000); + + // mean noise level + for(int g=gstart; g maxgval) maxgval = bin[g]; + + // bring down a little, looks nicer + gval = gval * 100 / 99; + + // and make the mid value over 10 values + #define GMIDLEN 10 + static float gmid[GMIDLEN]; + static int gmididx = 0; + gmid[gmididx] = gval; + if(++gmididx >= GMIDLEN) gmididx = 0; + float gvalmid = 0; + for(int g=0; g mval) mval = bin[m]; + + // and make the mid value over 10 values + #define MMIDLEN 10 + static float mmid[MMIDLEN]; + static int mmididx = 0; + mmid[mmididx] = mval; + if(++mmididx >= MMIDLEN) mmididx = 0; + float mvalmid = 0; + for(int m=0; m qmval) qmval = bin[m]; + + uint32_t qmvalmid_u = (uint32_t)qmval; //qmvalmid; + + // ======= QSO level above noise max level ======= + float qdlev = qmval - (maxgval + gvalmid)/2; + // and make the mean value + #define DIFFMIDLEN 50 + static float diffmid[DIFFMIDLEN]; + static int diffmididx = 0; + diffmid[diffmididx] = qdlev; + if(++diffmididx >= DIFFMIDLEN) diffmididx = 0; + float diffvalmid = 0; + for(int m=0; m> 24; + levels[2] = gvalmid_u >> 16; + levels[3] = gvalmid_u >> 8; + levels[4] = gvalmid_u & 0xff; + levels[5] = mvalmid_u >> 24; + levels[6] = mvalmid_u >> 16; + levels[7] = mvalmid_u >> 8; + levels[8] = mvalmid_u & 0xff; + levels[9] = qmvalmid_u >> 24; + levels[10] = qmvalmid_u >> 16; + levels[11] = qmvalmid_u >> 8; + levels[12] = qmvalmid_u & 0xff; + levels[13] = gvalmax_u >> 24; + levels[14] = gvalmax_u >> 16; + levels[15] = gvalmax_u >> 8; + levels[16] = gvalmax_u & 0xff; + levels[17] = diffvalmid_u >> 24; + levels[18] = diffvalmid_u >> 16; + levels[19] = diffvalmid_u >> 8; + levels[20] = diffvalmid_u & 0xff; + levels[21] = ptt; + + sendUDP(gui_ip, GUI_UDPPORT, levels, 22); + + // ======== BIG Waterfall ======== + // the big waterfall has a screen resulution of 1120 pixel + // FFT_RESOLUTION=25 Hz/bin + // the FFT delivers 1,12MS/s / 25 / 2 = 22400 values + // so the BIG WF resolution is 22400 / 1120 = 20 + static const int bigres = numbins / 1120; + static const int midlen = 15; + static uint32_t bigmid[midlen][FFT_LENGTH]; + static int bmididx = 0; + + int didx = 0; + for(int i=0; i max) max = fbin; + } + bigmid[bmididx][didx++] = (uint32_t)max; + if(max > 32768) printf("16bit overflow %f\n",max); + } + + uint8_t bigline[1 + 2 * (numbins/bigres)]; + uint8_t biglineraw[1 + 2 * (numbins/bigres)]; + int bigidx = 0; + bigline[bigidx] = 0; // ID for big spectrum + biglineraw[bigidx] = 2; // ID for big waterfall + bigidx++; + for(int i=0; i<(numbins/bigres); i++) + { + uint32_t uv = 0; + for(int j=0; j= (int)sizeof(biglineraw)) + printf("+++++++++++++++++++++++ %d %d\n",bmididx, numbins/bigres); + + biglineraw[bigidx] = bigmid[bmididx][i] >> 8; + biglineraw[bigidx+1] = bigmid[bmididx][i] & 0xff; + + bigline[bigidx] = uv >> 8; + bigline[bigidx+1] = uv & 0xff; + + bigidx+=2; + } + + if(++bmididx >= midlen) bmididx = 0; + + // send the big fft bins to the GUI + // raw values, no mid val, for waterfall + sendUDP(gui_ip, GUI_UDPPORT, biglineraw, bigidx); + + // send the big fft bins to the GUI + // mid vals for spectrum + sendUDP(gui_ip, GUI_UDPPORT, bigline, bigidx); + + // ======== SMALL Waterfall ======== + // the small waterfall is a piece of some kHz around the mid RX frequency "RXoffsetfreq" + // RXoffsetfreq is in kHz above the left margin which is 750-280= 470k + // the bin-index of RXoffsetfreq is: RXoffsetfreq/10 + + static const int small_midlen = 15; + static uint32_t smallmid[small_midlen][FFT_LENGTH]; + static int smididx = 0; + for(int i=start; i=0 && i=0 && i= (int)sizeof(smalllineraw)) printf("*********************** %d %d %d\n",smallidx, start,end); + + smalllineraw[smallidx] = smallmid[smididx][i] >> 8; + smalllineraw[smallidx+1] = smallmid[smididx][i] & 0xff; + + smallline[smallidx] = uv >> 8; + smallline[smallidx+1] = uv & 0xff; + } + else + { + smalllineraw[smallidx] = 0; + smalllineraw[smallidx+1] = 0; + + smallline[smallidx] = 0; + smallline[smallidx+1] = 0; + } + + smallidx += 2; + } + + if(++smididx >= small_midlen) smididx = 0; + + findSignal((uint16_t *)smallline,smallidx/2); + + + // send the small fft bins to the GUI + sendUDP(gui_ip, GUI_UDPPORT, smalllineraw, smallidx); + + // send the small fft bins to the GUI + sendUDP(gui_ip, GUI_UDPPORT, smallline, smallidx); + } + } +} + +#define SRCHANZ 20 +int srch[SRCHANZ]; +int srchpos = 0; + +void findSignal(uint16_t *p16, int anz) +{ + // measure frequency of a signal within +/-4kHz of the RXfrequency + int st12 = (14000-6000)*1120/28000; // -4kHz + int en12 = (14000+6000)*1120/28000; // +4kHz + uint32_t mv16=0; + + // measure mean value over 28 kHz + for(int i=0; i (mv16*vt/vb) && + p16[i] > (mv16*vt/vb) && + p16[i+1] > (mv16*vt/vb)) + { + filtval += i; + filtanz++; + } + } + + // calculate the mid frequency of the signal + if(filtanz > 0) + { + filtval /= filtanz; + int freq = filtval * 25 - 14000; + srch[srchpos] = freq; + if(++srchpos >= SRCHANZ) srchpos = 0; + + // calculate a mean value of the found frequency + int srchmid = 0; + for(int i=0; i> 24; + cf[2] = korrfact >> 16; + cf[3] = korrfact >> 8; + cf[4] = korrfact & 0xff; + + sendUDP(gui_ip, GUI_UDPPORT, cf, 5); + } + } +} diff --git a/fft.o b/fft.o new file mode 100644 index 0000000..ef8c63d Binary files /dev/null and b/fft.o differ diff --git a/fftcfg b/fftcfg new file mode 100644 index 0000000..a49d8a7 --- /dev/null +++ b/fftcfg @@ -0,0 +1,35 @@ +(fftw-3.3.8 fftw_wisdom #x3c273403 #x192df114 #x4d08727c #xe98e9b9d + (fftw_dft_vrank_geq1_register 0 #x11bdd #x11bdd #x0 #x35500318 #xa2053218 #x9432ec0f #x87073922) + (fftw_dft_thr_vrank_geq1_register 0 #x11bdd #x11bdd #x0 #x7f68e9fa #x7bad3d01 #x98dafd20 #xcdb6b7ce) + (fftw_dft_vrank_geq1_register 0 #x11bdd #x11bdd #x0 #x3c7290dd #x1d739c0c #xa05436a1 #xf127d781) + (fftw_codelet_t1fv_7_avx 0 #x11bdd #x11bdd #x0 #x8730deaa #xb4423bfd #xf2c34131 #x945d59f7) + (fftw_codelet_n1fv_25_avx 0 #x11bdd #x11bdd #x0 #x10c82991 #xd13397bb #x911f3bcd #x9a0aac9d) + (fftw_dft_vrank_geq1_register 0 #x11bdd #x11bdd #x0 #x73f2196a #xb7039b28 #x543344bd #xc5d57c2e) + (fftw_codelet_t1fuv_7_avx 0 #x11bdd #x11bdd #x0 #x91a3d5b1 #x71a7404e #x48b7e1ae #x9d253d8e) + (fftw_codelet_n1fv_14_avx 0 #x11bdd #x11bdd #x0 #xe6cf6c3f #xd07b6475 #x8d35d10b #xa15f720d) + (fftw_dft_thr_vrank_geq1_register 0 #x11bdd #x11bdd #x0 #x00e91bf9 #x18dbc270 #x1de439e6 #x1a48325e) + (fftw_codelet_t1fv_7_avx 0 #x11bdd #x11bdd #x0 #x94b1535d #x464eb909 #xbb1d6ae9 #xc97b824a) + (fftw_codelet_n1fv_25_avx 0 #x11bdd #x11bdd #x0 #x2aa7ed75 #xa9e5dff5 #x81285df6 #xe9ac14fa) + (fftw_codelet_t2fv_10_avx 0 #x11bdd #x11bdd #x0 #xb76f3788 #x7be6dae5 #xc3f94ec6 #x648cbd8e) + (fftw_codelet_t1fuv_10_avx 0 #x11bdd #x11bdd #x0 #x03171678 #xebaa405d #x03f48716 #x4140fb61) + (fftw_codelet_t2fv_10_avx 0 #x11bdd #x11bdd #x0 #x766ce6ab #x100d658e #xc75adcb3 #xfefbee0c) + (fftw_codelet_t3fv_16_avx 1 #x11bdd #x11bdd #x0 #x9dc31525 #xa7b2f94b #xac1cc9df #xaaa77f45) + (fftw_codelet_t1fv_64_avx 1 #x11bdd #x11bdd #x0 #x3550de6a #x2d8f363f #x24a26c56 #x1e578d59) + (fftw_dft_thr_vrank_geq1_register 0 #x11bdd #x11bdd #x0 #x9a6f97a3 #xd526ccb4 #xf3f9e9a6 #x810686ae) + (fftw_codelet_t1fv_32_avx 1 #x11bdd #x11bdd #x0 #x8048e739 #x6d9eef36 #x57776ea1 #x73b49435) + (fftw_codelet_t1fv_32_avx 1 #x11bdd #x11bdd #x0 #x27f49072 #x8acb2efd #xd50279ca #x457292fa) + (fftw_codelet_t1fv_7_avx 0 #x11bdd #x11bdd #x0 #xd9f832de #xb911c57e #xb0878a3f #x59d43138) + (fftw_codelet_t2fv_16_avx 1 #x11bdd #x11bdd #x0 #xd4d39737 #x36e690cf #x36d4c10c #x64f4ef7c) + (fftw_codelet_t2fv_10_avx 0 #x11bdd #x11bdd #x0 #x2c0ddf29 #x02d7f1b0 #x1f788f28 #x1c6eca0e) + (fftw_dft_vrank_geq1_register 0 #x11bdd #x11bdd #x0 #x2ffc6c7e #x04642ea9 #xd059ca7e #xc3bf3501) + (fftw_dft_thr_vrank_geq1_register 0 #x11bdd #x11bdd #x0 #xcd395e7b #x704347eb #x93fba7b1 #x1f8e8683) + (fftw_dft_thr_vrank_geq1_register 0 #x11bdd #x11bdd #x0 #x6f619c66 #xb9dcd1c8 #xc74e9a5c #x82ce38a4) + (fftw_codelet_n1fv_20_avx 0 #x11bdd #x11bdd #x0 #x3db87a70 #x7c5108ec #x2580e3b5 #xbf99f2dd) + (fftw_dft_vrank_geq1_register 0 #x11bdd #x11bdd #x0 #x7f000442 #x58e4dd05 #xa3b6bd4b #x8e39c722) + (fftw_codelet_t1fuv_10_avx 0 #x11bdd #x11bdd #x0 #xccaa18a4 #x0ad043df #x96b3e0fb #xa29ecc39) + (fftw_dft_vrank_geq1_register 0 #x11bdd #x11bdd #x0 #xf66ff4c6 #x77e7b389 #x4a1777f4 #xa9d87b9f) + (fftw_dft_vrank_geq1_register 0 #x11bdd #x11bdd #x0 #xad5917a6 #xc3718057 #x519be636 #x6e895acb) + (fftw_codelet_t1fv_5_avx 0 #x11bdd #x11bdd #x0 #x28df877c #xf3587663 #x562a5896 #x1c47bd8e) + (fftw_dft_vrank_geq1_register 0 #x11bdd #x11bdd #x0 #x12559e03 #x58c96dec #x2a4ced70 #xb7d49335) + (fftw_codelet_n1fv_20_avx 0 #x11bdd #x11bdd #x0 #x936acb7d #xd96def60 #x5c99c8f9 #xa8f5af47) +) diff --git a/install b/install new file mode 100755 index 0000000..8a468a9 --- /dev/null +++ b/install @@ -0,0 +1,17 @@ +#!/bin/bash +echo "==== complete install QO100 Transceiver ====" +echo "full update, upgrade and installation" +set -e +cd ~ +echo "update system by running apt-get update" +sudo apt-get update +echo "install git" +sudo apt-get install git -y +cd ~/QO100_Transceiver/scripts +./prepare_ubuntu_pluto +cd ~/QO100_Transceiver/scripts +./makeall +echo "==== Installation: OK ====" +cd ~/QO100_Transceiver/Release +echo "==== Start the Transceiver in the folder QO100_Transceiver/Release ====" +echo "==== by entering ./startQO100trx ====" diff --git a/kmlib/km_helper.cpp b/kmlib/km_helper.cpp new file mode 100644 index 0000000..cd1c87b --- /dev/null +++ b/kmlib/km_helper.cpp @@ -0,0 +1,428 @@ +/* +* Raspberry PI / Zero AddOn Board specially for Ham Radio Applications +* ==================================================================== +* Author: DJ0ABR +* +* (c) DJ0ABR +* www.dj0abr.de +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 2 of the License, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You 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. +* +kmhelper.cpp +=========== + +useful functions + +* +*/ + +#include "../qo100trx.h" +#include + +int keeprunning = 1; // set to 0 at program end to exit all processes +char configfile[512] = {0}; + +// check if it is already running +int isRunning(char *prgname) +{ + int num = 0; + char s[256]; + sprintf(s,"ps -e | grep %s",prgname); + + FILE *fp = popen(s,"r"); + if(fp) + { + // gets the output of the system command + while (fgets(s, sizeof(s)-1, fp) != NULL) + { + if(strstr(s,prgname) && !strstr(s,"grep")) + { + if(++num == 2) + { + printf("%s is already running, do not start twice !\n",prgname); + pclose(fp); + return 1; + } + } + } + pclose(fp); + } + return 0; +} + +void (*sigfunc)(); + +// signal handler +void sighandler(int signum) +{ + //printf("\n\nprogram stopped by signal\n"); + + (*sigfunc)(); +} + +void install_signal_handler(void (*signalfunction)()) +{ + sigfunc = signalfunction; + // signal handler, mainly used if the user presses Ctrl-C + struct sigaction sigact; + sigact.sa_handler = sighandler; + sigemptyset(&sigact.sa_mask); + sigact.sa_flags = 0; + sigaction(SIGINT, &sigact, NULL); + sigaction(SIGTERM, &sigact, NULL); + sigaction(SIGQUIT, &sigact, NULL); + sigaction(SIGABRT, &sigact, NULL); // assert() error + + //sigaction(SIGSEGV, &sigact, NULL); + + // switch off signal 13 (broken pipe) + // instead handle the return value of the write or send function + signal(SIGPIPE, SIG_IGN); +} + +void getParameters(int argc, char *argv[]) +{ + int opt; + while ((opt = getopt(argc, argv, "c:")) != -1) + { + switch (opt) + { + case 'c': + // specify config file name + if(optarg && strlen(optarg) > 2 && strlen(optarg) < (sizeof(configfile)-1)) + { + strcpy(configfile,optarg); + } + else + { + printf("invalid Config File Parameter [-c Configfilename]: %s\n", optarg); + exit(0); + } + break; + } + } +} + +// run external program and return it's output +char *runProgram(char *parameter, int maxlen) +{ + //printf("run:<%s>\n",parameter); + FILE *fp = popen(parameter,"r"); + if(fp) + { + *parameter = 0; + while (fgets(parameter+strlen(parameter), maxlen-1-strlen(parameter), fp) != NULL) + { + //printf("returns:<%s>\n", parameter); + } + pclose(fp); + return parameter; + } + else + printf("ERROR: cannot run: %s\n",parameter); + return NULL; +} + +void showbitstring(char* title, uint8_t* data, int totallen, int anz) +{ + printf("%s. len %d: ", title, totallen); + for (int i = 0; i < anz; i++) + printf("%01X ", data[i]); + printf("\n"); +} + +void showbytestring(char *title, uint8_t *data, int totallen, int anz) +{ + printf("%s. len % 4d: ",title, totallen); + for(int i=0; iifa_next) + { + if (ifa->ifa_addr == NULL) + continue; + + s = getnameinfo(ifa->ifa_addr, sizeof(struct sockaddr_in), host, NI_MAXHOST, NULL, 0, NI_NUMERICHOST); + + if (ifa->ifa_addr->sa_family == AF_INET) + { + if (s != 0) + { + printf("getnameinfo() failed: %s\n", gai_strerror(s)); + printf("cannot read own IP address, getnameinfo failed: %s. Check Networking\n", gai_strerror(s)); + break; + } + if (strncmp(host, "127", 3) != 0) + { + strcpy(ip, host); + break; + } + } + } + + freeifaddrs(ifaddr); + return ip; +} + +char* cleanStr(char *s) +{ + if(s[0] > ' ') + { + // remove trailing crlf + for(size_t j=0; j= '0') + { + // i is on first character + memmove(s,s+i,strlen(s)-i); + s[strlen(s)-i] = 0; + // remove trailing crlf + for(size_t j=0; j ' ') + { + char *start = s+j; + for(size_t k=0; k 512) + { + printf("config file path+name too long: %s\n",configfile); + exit(0); + } + strcpy(fn,configfile); + + if(fn[0] == '~') + { + struct passwd *pw = getpwuid(getuid()); + const char *homedir = pw->pw_dir; + sprintf(fn,"%s%s",homedir,configfile+1); + } + + //printf("read Configuration file %s\n",fn); + FILE *fr = fopen(fn,"rb"); + if(!fr) + { + printf("!!! Configuration file %s not found !!!\n",fn); + exit(0); + } + + while(1) + { + if(fgets(s,500,fr) == NULL) break; + // remove leading SPC or TAB + if(cleanStr(s) == 0) continue; + // check if its a comment + if(s[0] == '#') continue; + // get word on index + char *p = getword(s,0); + if(!p) break; + if(strcmp(p, elemname) == 0) + { + char val[500]; + if(*(s+strlen(p)+1) == 0) continue; + p = getword(s+strlen(p)+1,1); + if(!p) break; + // replace , with . + char *pkomma = strchr(p,','); + if(pkomma) *pkomma = '.'; + strcpy(val,p); + strcpy(s,val); + found = 1; + break; + } + + } + + fclose(fr); + if(found == 0) return NULL; + return s; +} + +void getConfigElement_double(char *elemname, double *pv, double multiplier) +{ + char *p = getConfigElement(elemname); + if(p) *pv = atof(p) * multiplier; +} + +void getConfigElement_longlong(char *elemname, long long *pv, double multiplier) +{ + char *p = getConfigElement(elemname); + if(p) *pv = (long long)(atof(p) * multiplier); +} + +void getConfigElement_int(char *elemname, int *pv, double multiplier) +{ + char *p = getConfigElement(elemname); + if(p) *pv = (int)(atof(p) * multiplier); +} + +float measure_samplerate(int id, int samp, int prt) +{ +static unsigned long lastus[10]; +static unsigned long samples[10]; +static int f[10]; +static int cnt[10]; +static int first=1; + + if(first) + { + first = 0; + for(int i=0; i<10; i++) + { + f[i] = 1; + cnt[i] = 0; + } + } + + // measure sample rate + struct timeval tv; + gettimeofday(&tv, NULL); + if(f[id]) + { + f[id] = 0; + lastus[id] = tv.tv_sec * 1000000 + tv.tv_usec; + samples[id] = samp; + } + samples[id] += samp; + unsigned long tnow = tv.tv_sec * 1000000 + tv.tv_usec; + + float sr = 0; + if(++(cnt[id]) >= prt) + { + cnt[id] = 0; + sr = (samples[id]*1e6)/(tnow - lastus[id]); + printf("%d: %.6f\n",id,sr/1e6); + } + return sr; +} + +int measure_maxval(double v, int anz) +{ +static double max = - 99999999; +static int cnt = 0; + + v = fabs(v); + if(v > max) + { + max = v; + //printf("maxval: %f\n",max); + } + + if(++cnt >= anz) + { + printf("maxval: %f\n",max); + max = - 99999999; + cnt = 0; + return 1; + } + return 0; +} diff --git a/kmlib/km_helper.h b/kmlib/km_helper.h new file mode 100644 index 0000000..e2e1b87 --- /dev/null +++ b/kmlib/km_helper.h @@ -0,0 +1,27 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +int isRunning(char *prgname); +void install_signal_handler(void (*signalfunction)()); +void showbitstring(char* title, uint8_t* data, int totallen, int anz); +void showbytestring(char *title, uint8_t *data, int totallen, int anz); +void showbytestring16(char *title, uint16_t *data, int anz); +void showbytestring32(char* title, uint32_t* data, int anz); +void showbytestringf(char* title, float* data, int totallen, int anz); +char* ownIP(); +char *getConfigElement(char *elemname); +void getConfigElement_double(char *elemname, double *pv, double multiplier); +void getConfigElement_longlong(char *elemname, long long *pv, double multiplier); +void getConfigElement_int(char *elemname, int *pv, double multiplier); +float measure_samplerate(int id, int samp, int prt); +int measure_maxval(double v, int anz); +char *runProgram(char *parameter, int maxlen); + +extern int keeprunning; diff --git a/kmlib/km_helper.o b/kmlib/km_helper.o new file mode 100644 index 0000000..b53cc71 Binary files /dev/null and b/kmlib/km_helper.o differ diff --git a/kmlib/kmfifo.cpp b/kmlib/kmfifo.cpp new file mode 100644 index 0000000..a294f4b --- /dev/null +++ b/kmlib/kmfifo.cpp @@ -0,0 +1,173 @@ +/* +* Raspberry PI / Zero AddOn Board specially for Ham Radio Applications +* ==================================================================== +* Author: DJ0ABR +* +* (c) DJ0ABR +* www.dj0abr.de +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 2 of the License, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You 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. +* +* universal thread safe fifo, used by many drivers and applications +* +*/ + +#include +#include +#include +#include +#include +#include "kmfifo.h" + + +FIFOOBJ fifo[MAXFIFOS]; +int fifonum = 0; + +#define LOCK(id) pthread_mutex_lock(&fifo[id].crit_sec) +#define UNLOCK(id) pthread_mutex_unlock(&fifo[id].crit_sec) + +// creates a new fifo +// maxelem_num ... max. number of elements in fifo +// maxelem_len ... max. length of one element (shorter elements are allowed) +// returns: ID of a fifo object, to be used for fifo functions +int create_fifo(int maxelem_num, int maxelem_len) +{ + // create the fifo memory and init variables + fifo[fifonum].fifomem = malloc(maxelem_num * maxelem_len); + fifo[fifonum].plen = (int *)malloc(maxelem_num * sizeof(int)); + fifo[fifonum].maxelemlen =maxelem_len; + fifo[fifonum].maxelem = maxelem_num; + fifo[fifonum].rdidx = 0; + fifo[fifonum].wridx = 0; + + pthread_mutex_init(&fifo[fifonum].crit_sec, NULL); + + int id = fifonum; + fifonum++; + return id; +} + +void destroy_fifos() +{ + for(int i=0; i pfo->maxelemlen) + { + printf("element too long\n"); + return; + } + + LOCK(id); + + if (((pfo->wridx + 1) % pfo->maxelem) == pfo->rdidx) + { + printf("cannot WRITE fifo %d full\n",id); + UNLOCK(id); + return; + } + + // insert length of new data + *(pfo->plen) = len; // real length of the element + + // insert new data + void *dst = (void *)((uint8_t *)pfo->fifomem + pfo->wridx * pfo->maxelemlen); + memcpy(dst, pdata, len); + if(++pfo->wridx >= pfo->maxelem) pfo->wridx = 0; + + UNLOCK(id); +} + +// read from the fifo +// return: number of bytes read +int read_fifo(int id, uint8_t* pdata, int maxlen) +{ + FIFOOBJ *pfo = &fifo[id]; + LOCK(id); + + if(pfo->rdidx == pfo->wridx) + { + // Fifo empty, no data available + //printf("read: no data\n"); + UNLOCK(id); + return 0; + } + + // read length + int len = *pfo->plen; // length of an element + + if (len > maxlen) + { + printf("read_fifo: %d, pdata too small. Need:%d has:%d\n", id, len, maxlen); + return 0; // pdata too small + } + + // read data + void *src = (void *)((uint8_t *)pfo->fifomem + pfo->rdidx * pfo->maxelemlen); + memcpy(pdata, src, len); + if (++pfo->rdidx >= pfo->maxelem) pfo->rdidx = 0; + + UNLOCK(id); + return len; +} + +void fifo_clear(int id) +{ + fifo[id].wridx = fifo[id].rdidx = 0; +} + +int fifo_freespace(int id) +{ + int freebuf = 0; + + LOCK(id); + + int elemInFifo = (fifo[id].wridx + fifo[id].maxelem - fifo[id].rdidx) % fifo[id].maxelem; + freebuf = fifo[id].maxelem - elemInFifo; + + UNLOCK(id); + return freebuf; +} + +int fifo_dataavail(int id) +{ + LOCK(id); + + if (fifo[id].rdidx == fifo[id].wridx) + { + // Fifo empty, no data available + UNLOCK(id); + return 0; + } + UNLOCK(id); + return 1; +} + +int fifo_usedspace(int id) +{ + int us = fifo[id].maxelem - fifo_freespace(id); + return us; +} diff --git a/kmlib/kmfifo.h b/kmlib/kmfifo.h new file mode 100644 index 0000000..fb1f691 --- /dev/null +++ b/kmlib/kmfifo.h @@ -0,0 +1,21 @@ +// max number of fifo, just a high number, never really used +#define MAXFIFOS 200 + +typedef struct _FIFOOBJ_ { + int maxelem; + int maxelemlen; + int rdidx; + int wridx; + void *fifomem; + int *plen; // real length of an element + pthread_mutex_t crit_sec; +} FIFOOBJ; + +int create_fifo(int elem_num, int elem_len); +void destroy_fifos(); +void write_fifo(int id, uint8_t *pdata, int len); +int read_fifo(int id, uint8_t* pdata, int maxlen); +void fifo_clear(int id); +int fifo_freespace(int id); +int fifo_dataavail(int id); +int fifo_usedspace(int id); diff --git a/kmlib/kmfifo.o b/kmlib/kmfifo.o new file mode 100644 index 0000000..5d6577e Binary files /dev/null and b/kmlib/kmfifo.o differ diff --git a/kmlib/kmtimer.cpp b/kmlib/kmtimer.cpp new file mode 100644 index 0000000..147a39b --- /dev/null +++ b/kmlib/kmtimer.cpp @@ -0,0 +1,114 @@ +/* +* Linux multithreaded timer +* ========================= +* Author: DJ0ABR +* +* (c) DJ0ABR +* www.dj0abr.de + +This program is free software: you can 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 +* +* Repeatable Timer for various needs +* ================================== +* +*/ + +#include "kmtimer.h" + +/* +usage: + +// this function is called every time_in_ms milliseconds +void timerhandler_function(void) +{ + // called every time_in_ms +} + +// start a new timer +int timernum = start_timer(time_in_ms, &timerhandler_function); + +stop_timer(timernum); + +*/ + + +typedef struct _TIMERDEF_ { + int to_ms; // timeout value in ms + timer_t timerid; + void(*timer_func_handler_pntr)(void); // this user supplied function is called on timeout + struct itimerspec in, out; +} TIMERDEF; + +#define MAXTIMERS 20 +TIMERDEF timers[MAXTIMERS]; +int timernum = 0; + +// callback function. The timer number is in val.sival_int +void sighler (union sigval val) +{ + int tnum = val.sival_int; + timers[tnum].timer_func_handler_pntr(); +} + +int start_timer(int mSec, void(*timer_func_handler)(void)) +{ + timers[timernum].timer_func_handler_pntr = timer_func_handler; + timers[timernum].to_ms = mSec; + + pthread_attr_t attr; + pthread_attr_init( &attr ); + + struct sched_param parm; + parm.sched_priority = 255; + pthread_attr_setschedparam(&attr, &parm); + + struct sigevent sig; + sig.sigev_notify = SIGEV_THREAD; + sig.sigev_notify_function = sighler; + sig.sigev_value.sival_int = timernum; + sig.sigev_notify_attributes = &attr; + + + int ret = timer_create(CLOCK_REALTIME, &sig, &(timers[timernum].timerid)); + if (ret == 0) + { + timers[timernum].in.it_value.tv_sec = mSec / 1000; + timers[timernum].in.it_value.tv_nsec = (mSec % 1000) * 1000000; + timers[timernum].in.it_interval.tv_sec = mSec / 1000; + timers[timernum].in.it_interval.tv_nsec = (mSec % 1000) * 1000000; + + ret = timer_settime(timers[timernum].timerid, 0, &timers[timernum].in, &timers[timernum].out); + if(ret == -1) + { + printf("timer_settime() failed with %d\n", errno); + return -1; + } + } + else + { + printf("timer_create() failed with %d\n", errno); + return -1; + } + + int r = timernum; + timernum++; + + return r; +} + + +void stop_timer(int timer) +{ + timer_delete(timers[timer].timerid); +} diff --git a/kmlib/kmtimer.h b/kmlib/kmtimer.h new file mode 100644 index 0000000..a405b88 --- /dev/null +++ b/kmlib/kmtimer.h @@ -0,0 +1,13 @@ +#include +#include +#include +#include +#include +#include +#include + +int start_timer(int mSec, void(*timer_func_handler)(void)); +void stop_timer(int timer); +void sleep_ms(int ms); + + diff --git a/kmlib/kmtimer.o b/kmlib/kmtimer.o new file mode 100644 index 0000000..8f261ab Binary files /dev/null and b/kmlib/kmtimer.o differ diff --git a/kmlib/rotary.cpp b/kmlib/rotary.cpp new file mode 100644 index 0000000..65a919c --- /dev/null +++ b/kmlib/rotary.cpp @@ -0,0 +1,393 @@ +/* + this is an extract from kmclib (see github, dj0abr repos) + it works on raspberry pi only + +* Raspberry PI / Zero AddOn Board specially for Ham Radio Applications +* ==================================================================== +* Author: DJ0ABR +* +* (c) DJ0ABR +* www.dj0abr.de +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 2 of the License, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You 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. +* +encoder.cpp +=========== + +function to handle rotary encoder + +Usage: +====== +initialize and assign ports to the encoders +------------------------------------------- +up to 3 encoders are supported, If not used, then assign port nunmber -1 +init_rotencoder(int portA1, int portB1, int portA2, int portB2, int portA3, int portB3) +see gpio.h _INPUTS_ for valid port numbers + +read encoder: +------------- +int getEncSteps(int idx) +idx ... encoder number 0,1 or 2 +returns the number of steps since last read + +* +*/ + +#include "../qo100trx.h" + + +int init_gpio(); +int getPort(char *port); + +#define NUM_OF_ENCODERS 2 + +pthread_mutex_t rotenc_crit_sec; +#define LOCK pthread_mutex_lock(&(rotenc_crit_sec)) +#define UNLOCK pthread_mutex_unlock(&(rotenc_crit_sec)) + +void *rotencproc(void *); + +char portA[NUM_OF_ENCODERS][3] = {"fa","va"}; +char portB[NUM_OF_ENCODERS][3] = {"fb","vb"}; + +int encsteps[NUM_OF_ENCODERS]; + +pthread_t rotenc_tid; + +// port numbers see gpio.h _INPORTS_ +// -1 if not used +void init_rotencoder() +{ + // use the rotary encoder on a raspberry board only + // RASPI is passed to the Makefile as: make RASPI='-DRASPI' + #ifndef RASPI + return; + #endif + + if(init_gpio() == -1) return; + + memset(&encsteps, 0, sizeof(int)*NUM_OF_ENCODERS); + + int pret = pthread_create(&rotenc_tid,NULL,rotencproc, NULL); + if(pret) + { + printf("rotenc process NOT started\n"); + exit(0); + } +} + +int getEncSteps(int idx) +{ + int v; + LOCK; + v = encsteps[idx]; + encsteps[idx] = 0; + UNLOCK; + return v; +} + +void *rotencproc(void *pdata) +{ + pthread_detach(pthread_self()); + + printf("rotenc process started\n"); + + int aval[NUM_OF_ENCODERS]; + int bval[NUM_OF_ENCODERS]; + int oldaval[NUM_OF_ENCODERS]={0,0}; + while(keeprunning) + { + for(int i=0; i + +struct gpiod_chip *chip = NULL; +struct gpiod_line *fa = NULL; +struct gpiod_line *fb = NULL, *va = NULL, *vb = NULL, *gptt = NULL, *gmute = NULL, *pttout = NULL; + +int init_gpio() +{ + int ret; + + chip= gpiod_chip_open("/dev/gpiochip0"); + if(!chip) + { + printf("cannot open GPIO chip\n"); + return -1; + } + + //fa= gpiod_chip_get_info(chip,17); + if (!fa) { + printf("cannot access GPIO17\n"); + gpiod_chip_close(chip); + return -1; + } + + //fb= gpiod_chip_get_line(chip,27); + if (!fb) { + printf("cannot access GPIO27\n"); + gpiod_chip_close(chip); + return -1; + } + + //va= gpiod_chip_get_line(chip,4); + if (!va) { + printf("cannot access GPIO4\n"); + gpiod_chip_close(chip); + return -1; + } + + //vb= gpiod_chip_get_line(chip,22); + if (!vb) { + printf("cannot access GPIO22\n"); + gpiod_chip_close(chip); + return -1; + } + + //gptt = gpiod_chip_get_line(chip,18); + if (!gptt) { + printf("cannot access GPIO18\n"); + gpiod_chip_close(chip); + return -1; + } + + //gmute = gpiod_chip_get_line(chip,23); + if (!gmute) { + printf("cannot access GPIO23\n"); + gpiod_chip_close(chip); + return -1; + } + + //pttout = gpiod_chip_get_line(chip,24); + if (!pttout) { + printf("cannot access GPIO24\n"); + gpiod_chip_close(chip); + return -1; + } + + //ret = gpiod_line_request_get_fd(fa, "huhu"); + if (ret) { + printf("cannot init GPIO17 for input\n"); + gpiod_chip_close(chip); + return -1; + } + + //ret = gpiod_line_request_input(fb, "huhu"); + if (ret) { + printf("cannot init GPIO27 for input\n"); + gpiod_chip_close(chip); + return -1; + } + + //ret = gpiod_line_request_input(va, "huhu"); + if (ret) { + printf("cannot init GPIO4 for input\n"); + gpiod_chip_close(chip); + return -1; + } + + //ret = gpiod_line_request_input(vb, "huhu"); + if (ret) { + printf("cannot init GPIO22 for input\n"); + gpiod_chip_close(chip); + return -1; + } + + //ret = gpiod_line_request_input(gptt, "huhu"); + if (ret) { + printf("cannot init GPIO18 for input\n"); + gpiod_chip_close(chip); + return -1; + } + + //ret = gpiod_line_request_input(gmute, "huhu"); + if (ret) { + printf("cannot init GPIO23 for input\n"); + gpiod_chip_close(chip); + return -1; + } + + //ret = gpiod_line_request_get_fd(pttout, "huhu", 0); + if (ret) { + printf("cannot init GPIO24 for output\n"); + gpiod_chip_close(chip); + return -1; + } + + printf("GPIOs initialized\n"); + + return 0; +} +void close_gpio() +{ + /* if(fa) gpiod_line_request(fa); + if(fb) gpiod_line_request(fb); + if(va) gpiod_line_request(va); + if(vb) gpiod_line_request(vb); + if(gptt) gpiod_line_request(gptt); + if(gmute) gpiod_line_request(gmute); +*/ + if(chip) gpiod_chip_close(chip); +} + +// get status of physical port +int getPort(char *port) +{ + #ifndef RASPI + return 0; + #endif + + if(port[0] == 'f') + { + //if(port[1] == 'a') return gpiod_line_value(fa); + //return gpiod_line_value(fb); + } + + if(port[0] == 'v') + { + //if(port[1] == 'a') return gpiod_line_value(va); + //return gpiod_line_value(vb); + } + + //if(port[0] == 'p') + //return gpiod_line_value(gptt); + + //if(port[0] == 'm') + //return gpiod_line_value(gmute); + + return 0; +} + +void setPort(char *port, int value) +{ + #ifndef RASPI + return; + #endif + + if(port[0] == 'p') + { + //gpiod_line_value(pttout,value); + } +} + diff --git a/kmlib/rotary.h b/kmlib/rotary.h new file mode 100644 index 0000000..c29c16e --- /dev/null +++ b/kmlib/rotary.h @@ -0,0 +1,7 @@ +void init_rotencoder(); +void close_gpio(); +int getEncSteps(int idx); +int test_ptt_gpio(); +int test_mute_gpio(); +void setPort(char *port, int value); +int getPort(char *port); diff --git a/kmlib/rotary.o b/kmlib/rotary.o new file mode 100644 index 0000000..a3e573c Binary files /dev/null and b/kmlib/rotary.o differ diff --git a/libkmaudio/LICENSE b/libkmaudio/LICENSE new file mode 100644 index 0000000..0ad25db --- /dev/null +++ b/libkmaudio/LICENSE @@ -0,0 +1,661 @@ + GNU AFFERO GENERAL PUBLIC LICENSE + Version 3, 19 November 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 Affero General Public License is a free, copyleft license for +software and other kinds of works, specifically designed to ensure +cooperation with the community in the case of network server software. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +our General Public Licenses are 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. + + 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. + + Developers that use our General Public Licenses protect your rights +with two steps: (1) assert copyright on the software, and (2) offer +you this License which gives you legal permission to copy, distribute +and/or modify the software. + + A secondary benefit of defending all users' freedom is that +improvements made in alternate versions of the program, if they +receive widespread use, become available for other developers to +incorporate. Many developers of free software are heartened and +encouraged by the resulting cooperation. However, in the case of +software used on network servers, this result may fail to come about. +The GNU General Public License permits making a modified version and +letting the public access it on a server without ever releasing its +source code to the public. + + The GNU Affero General Public License is designed specifically to +ensure that, in such cases, the modified source code becomes available +to the community. It requires the operator of a network server to +provide the source code of the modified version running there to the +users of that server. Therefore, public use of a modified version, on +a publicly accessible server, gives the public access to the source +code of the modified version. + + An older license, called the Affero General Public License and +published by Affero, was designed to accomplish similar goals. This is +a different license, not a version of the Affero GPL, but Affero has +released a new version of the Affero GPL which permits relicensing under +this license. + + 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 Affero 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. Remote Network Interaction; Use with the GNU General Public License. + + Notwithstanding any other provision of this License, if you modify the +Program, your modified version must prominently offer all users +interacting with it remotely through a computer network (if your version +supports such interaction) an opportunity to receive the Corresponding +Source of your version by providing access to the Corresponding Source +from a network server at no charge, through some standard or customary +means of facilitating copying of software. This Corresponding Source +shall include the Corresponding Source for any work covered by version 3 +of the GNU General Public License that is incorporated pursuant to the +following paragraph. + + 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 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 work with which it is combined will remain governed by version +3 of the GNU General Public License. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU Affero 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 Affero 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 Affero 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 Affero 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 Affero 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 Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see . + +Also add information on how to contact you by electronic and paper mail. + + If your software can interact with users remotely through a computer +network, you should also make sure that it provides a way for users to +get its source. For example, if your program is a web application, its +interface could display a "Source" link that leads users to an archive +of the code. There are many ways you could offer source, and different +solutions will be better for different programs; see section 13 for the +specific requirements. + + 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 AGPL, see +. diff --git a/libkmaudio/Makefile b/libkmaudio/Makefile new file mode 100644 index 0000000..2aba7b6 --- /dev/null +++ b/libkmaudio/Makefile @@ -0,0 +1,22 @@ +# Make file for libkmaudio +# make clean ... clean up intermediate files +# make ... generate libkmaudio as executable for testing purposes +# and also creates the static library libkmaudio.a to be linked with another program +# when linking to another program also include "-lliquid -lsoundio" to your linker + +CXXFLAGS = -Wall -O3 -std=c++0x -Wno-write-strings -Wno-narrowing +LDFLAGS = -lliquid -lsoundio +OBJM = libkmaudio.o +OBJ = libkmaudio_fifo.o libkmaudio_getDevices.o libkmaudio_getDevices_Linux.o libkmaudio_init.o libkmaudio_init_linux.o libkmaudio_interface.o libkmaudio_capture_linux.o libkmaudio_playback_linux.o libkmaudio_resampler.o + +default: $(OBJ) $(OBJM) + g++ $(CXXFLAGS) -o libkmaudio $(OBJ) $(OBJM) $(LDFLAGS) + ar rcs libkmaudio.a $(OBJ) + +clean: + rm -f *.o libkmaudio.a + -rm -rf ./Release/* + -rmdir Release + -rm -rf ./Debug/* + -rmdir Debug + diff --git a/libkmaudio/README.md b/libkmaudio/README.md new file mode 100644 index 0000000..a0e86c4 --- /dev/null +++ b/libkmaudio/README.md @@ -0,0 +1,48 @@ +# libkmaudio +## very simple to use audio library for Linux and Windows + +I was looking for an audio soultion working on both, Linux and Windows. +It was impossible to find a reliable open source solution. +If you have no problem using a commercial closed source library, then I recommend "bass" +which worked nicely for me, but I need open source to fulfil the requirements of GPL V3. + +## My solution: + +**portaudio:** works fine under Windows. Does not work under Linux because it does not support +pulseaudio and takes all these cryptical Alsa device names. + +**libsoundio:** works well under Linux and supports pulseaudio, uses excellent device names. +But has problems under Windows, distortions and stuttering, so not usable on Windows. + +So I wrote this library which uses portaudio for windows and libsoundio for Linux putting +all in a very simple to use library. + +## highlights + +* a capture or playback stream can be opened for every soundcard available in the computer simultaneously +* each stream gets its own fifo. So we do not have to work with streams, we just put our samples into a fifo or read samples from a fifo. +* Except the soundcard name we do not need to know anything about sound, all is done by this library. +* the library is thread safe and can be used in multithreading environments + +## Restrictions + +this library was written to be used with SDR receivers/transmitters or for signal analysis purposes. Therefore it supports 1 channel and two sample rates (44100 and 48000). +However, the 1-channel limit is just the fifo. So if someone needs stereo, adjust the routines to write both channels to the fifo. + +## Windows + +compatible with Visual Studio. All required Windows-Shared Libraries are included and must be copied to the path of the executable file. + +## Linux + +run "make" to compile the library. The shared libraries (supplied for PC 64bit or ARM 64 bit) must be copied to the folder where Linux searches for shared libraries on your computer. To find this folder you can use this command: + +*find /usr -name libc.so | head -1* + +## Documentation + +There are only very few functions needed. They are described in libkmaudio.h + +## Example + +An example how to init the sound system, record from microphone and play back to loadspeaker can be found in libkmaudio.cpp. For use in another project simply remove main(). diff --git a/libkmaudio/SharedLibs/aarch64/libliquid.so b/libkmaudio/SharedLibs/aarch64/libliquid.so new file mode 100644 index 0000000..e4da177 Binary files /dev/null and b/libkmaudio/SharedLibs/aarch64/libliquid.so differ diff --git a/libkmaudio/SharedLibs/aarch64/libsoundio.so b/libkmaudio/SharedLibs/aarch64/libsoundio.so new file mode 100644 index 0000000..9e2fff9 Binary files /dev/null and b/libkmaudio/SharedLibs/aarch64/libsoundio.so differ diff --git a/libkmaudio/SharedLibs/aarch64/libsoundio.so.2 b/libkmaudio/SharedLibs/aarch64/libsoundio.so.2 new file mode 100644 index 0000000..9e2fff9 Binary files /dev/null and b/libkmaudio/SharedLibs/aarch64/libsoundio.so.2 differ diff --git a/libkmaudio/SharedLibs/aarch64/libsoundio.so.2.0.0 b/libkmaudio/SharedLibs/aarch64/libsoundio.so.2.0.0 new file mode 100644 index 0000000..9e2fff9 Binary files /dev/null and b/libkmaudio/SharedLibs/aarch64/libsoundio.so.2.0.0 differ diff --git a/libkmaudio/SharedLibs/windows/libgcc_s_dw2-1.dll b/libkmaudio/SharedLibs/windows/libgcc_s_dw2-1.dll new file mode 100644 index 0000000..9e32dc2 Binary files /dev/null and b/libkmaudio/SharedLibs/windows/libgcc_s_dw2-1.dll differ diff --git a/libkmaudio/SharedLibs/windows/libgcc_s_sjlj-1.dll b/libkmaudio/SharedLibs/windows/libgcc_s_sjlj-1.dll new file mode 100644 index 0000000..24fa2dc Binary files /dev/null and b/libkmaudio/SharedLibs/windows/libgcc_s_sjlj-1.dll differ diff --git a/libkmaudio/SharedLibs/windows/libliquid.dll b/libkmaudio/SharedLibs/windows/libliquid.dll new file mode 100644 index 0000000..f7eb831 Binary files /dev/null and b/libkmaudio/SharedLibs/windows/libliquid.dll differ diff --git a/libkmaudio/SharedLibs/windows/portaudio_x86.dll b/libkmaudio/SharedLibs/windows/portaudio_x86.dll new file mode 100644 index 0000000..e4f98d4 Binary files /dev/null and b/libkmaudio/SharedLibs/windows/portaudio_x86.dll differ diff --git a/libkmaudio/SharedLibs/x86_64/libliquid.so b/libkmaudio/SharedLibs/x86_64/libliquid.so new file mode 100644 index 0000000..723192d Binary files /dev/null and b/libkmaudio/SharedLibs/x86_64/libliquid.so differ diff --git a/libkmaudio/SharedLibs/x86_64/libsoundio.so b/libkmaudio/SharedLibs/x86_64/libsoundio.so new file mode 100644 index 0000000..0bc1be2 Binary files /dev/null and b/libkmaudio/SharedLibs/x86_64/libsoundio.so differ diff --git a/libkmaudio/SharedLibs/x86_64/libsoundio.so.2 b/libkmaudio/SharedLibs/x86_64/libsoundio.so.2 new file mode 100644 index 0000000..0bc1be2 Binary files /dev/null and b/libkmaudio/SharedLibs/x86_64/libsoundio.so.2 differ diff --git a/libkmaudio/SharedLibs/x86_64/libsoundio.so.2.0.0 b/libkmaudio/SharedLibs/x86_64/libsoundio.so.2.0.0 new file mode 100644 index 0000000..0bc1be2 Binary files /dev/null and b/libkmaudio/SharedLibs/x86_64/libsoundio.so.2.0.0 differ diff --git a/libkmaudio/endian.h b/libkmaudio/endian.h new file mode 100644 index 0000000..f69072f --- /dev/null +++ b/libkmaudio/endian.h @@ -0,0 +1,97 @@ +/* + * Copyright (c) 2015 Andrew Kelley + * + * This file is part of libsoundio, which is MIT licensed. + * See http://opensource.org/licenses/MIT + */ + +#ifndef SOUNDIO_ENDIAN_H +#define SOUNDIO_ENDIAN_H + +#if defined(__BIG_ENDIAN__) +#define SOUNDIO_OS_BIG_ENDIAN +#elif defined(__ARMEB__) +#define SOUNDIO_OS_BIG_ENDIAN +#elif defined(__THUMBEB__) +#define SOUNDIO_OS_BIG_ENDIAN +#elif defined(__AARCH64EB__) +#define SOUNDIO_OS_BIG_ENDIAN +#elif defined(_MIPSEB) +#define SOUNDIO_OS_BIG_ENDIAN +#elif defined(__MIPSEB) +#define SOUNDIO_OS_BIG_ENDIAN +#elif defined(__MIPSEB__) +#define SOUNDIO_OS_BIG_ENDIAN +#elif defined(__BYTE_ORDER__) && __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ +#define SOUNDIO_OS_BIG_ENDIAN +#elif defined(_BIG_ENDIAN) +#define SOUNDIO_OS_BIG_ENDIAN +#elif defined(__sparc) +#define SOUNDIO_OS_BIG_ENDIAN +#elif defined(__sparc__) +#define SOUNDIO_OS_BIG_ENDIAN +#elif defined(_POWER) +#define SOUNDIO_OS_BIG_ENDIAN +#elif defined(__powerpc__) +#define SOUNDIO_OS_BIG_ENDIAN +#elif defined(__ppc__) +#define SOUNDIO_OS_BIG_ENDIAN +#elif defined(__hpux) +#define SOUNDIO_OS_BIG_ENDIAN +#elif defined(__hppa) +#define SOUNDIO_OS_BIG_ENDIAN +#elif defined(_POWER) +#define SOUNDIO_OS_BIG_ENDIAN +#elif defined(__s390__) +#define SOUNDIO_OS_BIG_ENDIAN +#elif defined(__LITTLE_ENDIAN__) +#define SOUNDIO_OS_LITTLE_ENDIAN +#elif defined(__ARMEL__) +#define SOUNDIO_OS_LITTLE_ENDIAN +#elif defined(__THUMBEL__) +#define SOUNDIO_OS_LITTLE_ENDIAN +#elif defined(__AARCH64EL__) +#define SOUNDIO_OS_LITTLE_ENDIAN +#elif defined(_MIPSEL) +#define SOUNDIO_OS_LITTLE_ENDIAN +#elif defined(__MIPSEL) +#define SOUNDIO_OS_LITTLE_ENDIAN +#elif defined(__MIPSEL__) +#define SOUNDIO_OS_LITTLE_ENDIAN +#elif defined(__BYTE_ORDER__) && __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ +#define SOUNDIO_OS_LITTLE_ENDIAN +#elif defined(_LITTLE_ENDIAN) +#define SOUNDIO_OS_LITTLE_ENDIAN +#elif defined(__i386__) +#define SOUNDIO_OS_LITTLE_ENDIAN +#elif defined(__alpha__) +#define SOUNDIO_OS_LITTLE_ENDIAN +#elif defined(__ia64) +#define SOUNDIO_OS_LITTLE_ENDIAN +#elif defined(__ia64__) +#define SOUNDIO_OS_LITTLE_ENDIAN +#elif defined(_M_IX86) +#define SOUNDIO_OS_LITTLE_ENDIAN +#elif defined(_M_IA64) +#define SOUNDIO_OS_LITTLE_ENDIAN +#elif defined(_M_ALPHA) +#define SOUNDIO_OS_LITTLE_ENDIAN +#elif defined(__amd64) +#define SOUNDIO_OS_LITTLE_ENDIAN +#elif defined(__amd64__) +#define SOUNDIO_OS_LITTLE_ENDIAN +#elif defined(_M_AMD64) +#define SOUNDIO_OS_LITTLE_ENDIAN +#elif defined(__x86_64) +#define SOUNDIO_OS_LITTLE_ENDIAN +#elif defined(__x86_64__) +#define SOUNDIO_OS_LITTLE_ENDIAN +#elif defined(_M_X64) +#define SOUNDIO_OS_LITTLE_ENDIAN +#elif defined(__bfin__) +#define SOUNDIO_OS_LITTLE_ENDIAN +#else +#error unable to detect endianness +#endif + +#endif diff --git a/libkmaudio/libkmaudio b/libkmaudio/libkmaudio new file mode 100644 index 0000000..1c3988f Binary files /dev/null and b/libkmaudio/libkmaudio differ diff --git a/libkmaudio/libkmaudio.cpp b/libkmaudio/libkmaudio.cpp new file mode 100644 index 0000000..0326b21 --- /dev/null +++ b/libkmaudio/libkmaudio.cpp @@ -0,0 +1,96 @@ +/* +* Audio Library for Linux and Windows +* =================================== +* Author: DJ0ABR +* +* Author: Kurt Moraw, Ham radio: DJ0ABR, github: dj0abr +* License: GPL-3 +* +* compilation: +* Windows ... Visual Studio +* Linux ... make +* +* Documentation see: libkmaudio.h +* Usage Example: see main() in this file +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 2 of the License, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You 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. +* +* libkmaudio.cpp ... main() for test purposes only +* usually this library is linked to another program, in this case +* comment-out #define LIBTEST +* +*/ + +#include "libkmaudio.h" + +int kmaudio_getDeviceList_test(); + +int keeprunning = 1; + +/* +* main() +* for testing purposes only +* for library generation comment out: LIBTEST +*/ + + +#define LIBTEST + +#ifdef LIBTEST +int main() +{ + // initialize sound system + // must be called once after program start + // if called during program run, this will reset the sound system, so better don't do it + kmaudio_init(); + + // read list of devices + // call as often as needed + // if a user pluggs-in an USB device on the fly then the running stream may + // be redirected by the OS. In this case closing/opening the stream + // may be required. + kmaudio_getDeviceList(); + + // start capture and/or playback streams + // Parameter: the device name and the sample rate (44100 or 48000 are supported) + // these function return the fifo-index, which is used to access the data in the + // coresponding fifo + + int capidx = kmaudio_startCapture((char *)"Line 2 (Virtual Audio Cable)", 48000); + int pbidx = kmaudio_startPlayback((char *)"Line 2 (Virtual Audio Cable)", 48000); + + float f[1100]; + while (1) + { + // make a loop: record from Mic and play to Speaker + + int done = 0; + // read samples from the capture fifo + int anz = kmaudio_readsamples(capidx, f, 1000, 1.0f, 0); + if (anz > 0) + { + // if samples are available, send them to playback fifo + //printf("write %d samples from %d to %d\n", anz, capidx, pbidx); + kmaudio_playsamples(pbidx, f, anz,1.0f); + done = 1; + } + } + + // free resources. This will never happen in this example + // but should be done in the final program + kmaudio_close(); + return 0; +} +#endif // LIBTEST diff --git a/libkmaudio/libkmaudio.h b/libkmaudio/libkmaudio.h new file mode 100644 index 0000000..dcc5ad3 --- /dev/null +++ b/libkmaudio/libkmaudio.h @@ -0,0 +1,275 @@ +/* +* Audio Library for Linux and Windows +* =================================== +* Author: DJ0ABR +* +* Author: Kurt Moraw, Ham radio: DJ0ABR, github: dj0abr +* License: GPL-3 +* +* compilation: +* Windows ... Visual Studio +* Linux ... make +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 2 of the License, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You 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. +*/ + +#pragma once + + +#ifdef WIN32 +// ignore senseless warnings invented by M$ to confuse developers +#pragma warning( disable : 4091 ) +#pragma warning( disable : 4003 ) +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef WIN32 +#include "Winsock2.h" +#include "io.h" +#include +#include +#include +#include +#include +#include +#define _USE_MATH_DEFINES +#include +#include "portaudio.h" +#include "pa_win_wasapi.h" + +#pragma comment(lib, "portaudio_x86.lib") +#pragma comment(lib, "libliquid.lib") +#else +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "soundio.h" +#endif + +#include "liquid.h" + +/* +* Sample usage: +* init sound system +* 1. kmaudio_init(); +* 2. kmaudio_getDeviceList(); +* +* start a capture and a playback stream +* 3. kmaudio_startCapture() using a device name returned by io_getAudioDevicelist() +* 4. kmaudio_startPlayback() using a device name returned by io_getAudioDevicelist() +* +* now everything runs in the background, no more need for the user program +* to handle sound specific data +* now we can read/write sound samples as needed by our application +* as an example: get sound from microphone and send to speaker +* process in a loop: +* 5. kmaudio_readsamples() +* 6. kmaudio_playsamples() +* +* for a working example see main(), you will need to +* replace the device names with the names in your computer +*/ + +/* +* initialize the audio library, create required processes +* call only once when your application starts +* returns: 0 = OK, -1 = error +*/ +int kmaudio_init(); + +/* +* closes and frees all resources +* call only when the application exits +*/ +void kmaudio_close(); + +/* +* read a list of all available audio devices into devlist +* the list can then be read by calling io_getAudioDevicelist() +* call any time to find new plugged in/out devices +* returns: 0=OK, -1 if error +*/ +int kmaudio_getDeviceList(); + +/* +* starts a capturing stream from devname with samprate +* returns: id of the capture stream or -1 = error +*/ +int kmaudio_startCapture(char* devname, int samprate); + +/* +* starts a playback stream to devname with samprate +* returns: id of the playback stream or -1 = error +*/ + +int kmaudio_startPlayback(char* devname, int samprate); + +/* +* plays len samples from psamp to device id +* returns: 0=ok, -1=error +* id ... device id returned by kmaudio_startPlayback +* psamp ... float array of length len with the audio data (mono) +* len ... number of float values in psamp +* volume ... 0.0f..2.0f will be multiplied with the output sample +*/ +int kmaudio_playsamples(int id, float* psamp, int len, float volume); + +/* +* reads len samples from device id into psamp +* returns: 0=ok, -1=error +* id ... device id returned by kmaudio_startCapture +* psamp ... float array of length len getting the audio data (mono) +* len ... number of float values to write into psamp +* volume ... 0.0f..2.0f will be multiplied with the input sample +* wait ... 1=wait for data, 0=return if not enough data available (in this case psamp will return 0,0,0...) +*/ +int kmaudio_readsamples(int id, float* psamp, int len, float volume, int wait); + +/* +* reads the names of detected sound devices +* *len...length of the returned string +* returns: pointer to device string +* Format of the device string: +* first byte = 3 ... ID of this string, followed by pure text: +* Active status of the following device "0" or "1" +* Name of playback devices, followed by ~ +* separator ^ +* Active status of the following device "0" or "1" +* Name of capture devices, followed by ~ +* these names are used for calls to kmaudio_startCapture and kmaudio_startPlayback +* to select the device +*/ +uint8_t* io_getAudioDevicelist(int* len); + +/* +* returns the max level (within 1 second) of this stream in % (0..100) +* if the level >= 100 the signal will get clipped and distorted +*/ +uint8_t kmaudio_maxlevel(int id); + +/* +* closes a stream which was started by +* kmaudio_startCapture or kmaudio_startPlayback +* id ... stream ID which was returned by kmaudio_startCapture or kmaudio_startPlayback +*/ +void close_stream(int id); + +/* +* handle the FIFO which is used to buffer audio data +* pipenum ... stream ID which was returned by kmaudio_startCapture or kmaudio_startPlayback +* IMPORTANT: this information MUST be used to synchonize the data flow into +* the fifo. The speed is always defined by the audio sample rate +* by checking the fifo an application knows when it has to put more audio samples +* into the fifo +*/ +// returns number of remaining elements (audio 16 bit short values) +int io_fifo_freespace(int pipenum); + +// returns number of used elements (audio 16 bit short values) +int io_fifo_usedspace(int pipenum); + +// like before, but returns a number between 0 and 100 % +int io_fifo_usedpercent(int pipenum); + +// clear the fifo +void io_fifo_clear(int pipenum); + + +// -------- functions for internal use only -------- + +#define MAXDEVICES 200 +#define MAXDEVNAMELENGTH 150 + +typedef struct _DEVLIST_ { + int index = 0; // index to this list + int active = 0; // 1=device valid, 0=possibly disconencted + char name[MAXDEVNAMELENGTH] = { 0 };// real name + int in_out = 0; // 0=capture device, 1=playback device, 2=both + int supports_44100 = 0; // 1 if supported + int supports_48000 = 0; // 1 if supported + int requested_samprate = 0; // sample rate requested by caller + int real_samprate = 0; // real sample rate of the device + int working = 0; // 0=not running, 1=initialized and working +#ifdef WIN32 // Windows using portaudio + int devnum = -1; // port audio device number + PaStreamParameters inputParameters; + PaStreamParameters outputParameters; + PaStream* capStream = NULL; + PaStream* pbStream = NULL; +#else // Linux using libsoundio + struct SoundIoDevice* io_pb_device = NULL; + struct SoundIoDevice* io_cap_device = NULL; + struct SoundIoInStream* instream = NULL; + struct SoundIoOutStream* outstream = NULL; + int stereo_mono = 2; // 1=mono, 2=stereo + char id[1000] = { 0 }; +#endif +} DEVLIST; + +int searchDevice(char* devname, int io); +void measure_speed_bps(int len); +void sleep_ms(int ms); +void io_write_fifo(int pipenum, float sample); +void io_write_fifo_short(int pipenum, int16_t sample); +void io_fifo_clear(int pipenum); +void init_pipes(); +int io_read_fifo_num(int pipenum, float* data, int num); +int io_read_fifo(int pipenum, float* data); +int getRealSamprate(int idx); +int io_fifo_elems_avail(int pipenum); +void sleep_ms(int ms); +void io_buildAudioDevString(); +void resampler_create(int devidx); +float* resample(int id, float* psamp, int len, int* pnewlen); +uint64_t getms(); +void init_maxarray(); +void kmaudio_detectDropouts(int id); +int io_read_fifo_num_short(int pipenum, int16_t* data, int num); +void close_capture_stream(int idx); +void close_playback_stream(int idx); + +extern DEVLIST devlist[MAXDEVICES]; +extern int devanz; +extern int keeprunning; + +#ifndef WIN32 // Linux +int kmaudio_init_linux(); +void kmaudio_close_linux(); +char* getDevID(char* devname, int io, int* pidx); + +extern struct SoundIo* soundio; +#endif // ndef WIN32 + diff --git a/libkmaudio/libkmaudio.sln b/libkmaudio/libkmaudio.sln new file mode 100644 index 0000000..4fbf55a --- /dev/null +++ b/libkmaudio/libkmaudio.sln @@ -0,0 +1,77 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 16 +VisualStudioVersion = 16.0.30717.126 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libkmaudio", "libkmaudio.vcxproj", "{47EECFB7-1F9E-409C-B8AD-0A2BCCA9CB34}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + 64bit|Any CPU = 64bit|Any CPU + 64bit|Mixed Platforms = 64bit|Mixed Platforms + 64bit|Win32 = 64bit|Win32 + 64bit|x64 = 64bit|x64 + 64bit|x86 = 64bit|x86 + Debug|Any CPU = Debug|Any CPU + Debug|Mixed Platforms = Debug|Mixed Platforms + Debug|Win32 = Debug|Win32 + Debug|x64 = Debug|x64 + Debug|x86 = Debug|x86 + Release|Any CPU = Release|Any CPU + Release|Mixed Platforms = Release|Mixed Platforms + Release|Win32 = Release|Win32 + Release|x64 = Release|x64 + Release|x86 = Release|x86 + ReleaseMinDependency|Any CPU = ReleaseMinDependency|Any CPU + ReleaseMinDependency|Mixed Platforms = ReleaseMinDependency|Mixed Platforms + ReleaseMinDependency|Win32 = ReleaseMinDependency|Win32 + ReleaseMinDependency|x64 = ReleaseMinDependency|x64 + ReleaseMinDependency|x86 = ReleaseMinDependency|x86 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {47EECFB7-1F9E-409C-B8AD-0A2BCCA9CB34}.64bit|Any CPU.ActiveCfg = Release|x64 + {47EECFB7-1F9E-409C-B8AD-0A2BCCA9CB34}.64bit|Any CPU.Build.0 = Release|x64 + {47EECFB7-1F9E-409C-B8AD-0A2BCCA9CB34}.64bit|Mixed Platforms.ActiveCfg = Release|Win32 + {47EECFB7-1F9E-409C-B8AD-0A2BCCA9CB34}.64bit|Mixed Platforms.Build.0 = Release|Win32 + {47EECFB7-1F9E-409C-B8AD-0A2BCCA9CB34}.64bit|Win32.ActiveCfg = Release|Win32 + {47EECFB7-1F9E-409C-B8AD-0A2BCCA9CB34}.64bit|Win32.Build.0 = Release|Win32 + {47EECFB7-1F9E-409C-B8AD-0A2BCCA9CB34}.64bit|x64.ActiveCfg = Release|x64 + {47EECFB7-1F9E-409C-B8AD-0A2BCCA9CB34}.64bit|x64.Build.0 = Release|x64 + {47EECFB7-1F9E-409C-B8AD-0A2BCCA9CB34}.64bit|x86.ActiveCfg = Release|Win32 + {47EECFB7-1F9E-409C-B8AD-0A2BCCA9CB34}.64bit|x86.Build.0 = Release|Win32 + {47EECFB7-1F9E-409C-B8AD-0A2BCCA9CB34}.Debug|Any CPU.ActiveCfg = Debug|Win32 + {47EECFB7-1F9E-409C-B8AD-0A2BCCA9CB34}.Debug|Mixed Platforms.ActiveCfg = Debug|Win32 + {47EECFB7-1F9E-409C-B8AD-0A2BCCA9CB34}.Debug|Mixed Platforms.Build.0 = Debug|Win32 + {47EECFB7-1F9E-409C-B8AD-0A2BCCA9CB34}.Debug|Win32.ActiveCfg = Debug|Win32 + {47EECFB7-1F9E-409C-B8AD-0A2BCCA9CB34}.Debug|Win32.Build.0 = Debug|Win32 + {47EECFB7-1F9E-409C-B8AD-0A2BCCA9CB34}.Debug|x64.ActiveCfg = Debug|x64 + {47EECFB7-1F9E-409C-B8AD-0A2BCCA9CB34}.Debug|x64.Build.0 = Debug|x64 + {47EECFB7-1F9E-409C-B8AD-0A2BCCA9CB34}.Debug|x86.ActiveCfg = Debug|Win32 + {47EECFB7-1F9E-409C-B8AD-0A2BCCA9CB34}.Debug|x86.Build.0 = Debug|Win32 + {47EECFB7-1F9E-409C-B8AD-0A2BCCA9CB34}.Release|Any CPU.ActiveCfg = Release|Win32 + {47EECFB7-1F9E-409C-B8AD-0A2BCCA9CB34}.Release|Mixed Platforms.ActiveCfg = Release|Win32 + {47EECFB7-1F9E-409C-B8AD-0A2BCCA9CB34}.Release|Mixed Platforms.Build.0 = Release|Win32 + {47EECFB7-1F9E-409C-B8AD-0A2BCCA9CB34}.Release|Win32.ActiveCfg = Release|Win32 + {47EECFB7-1F9E-409C-B8AD-0A2BCCA9CB34}.Release|Win32.Build.0 = Release|Win32 + {47EECFB7-1F9E-409C-B8AD-0A2BCCA9CB34}.Release|x64.ActiveCfg = Release|x64 + {47EECFB7-1F9E-409C-B8AD-0A2BCCA9CB34}.Release|x64.Build.0 = Release|x64 + {47EECFB7-1F9E-409C-B8AD-0A2BCCA9CB34}.Release|x86.ActiveCfg = Release|Win32 + {47EECFB7-1F9E-409C-B8AD-0A2BCCA9CB34}.Release|x86.Build.0 = Release|Win32 + {47EECFB7-1F9E-409C-B8AD-0A2BCCA9CB34}.ReleaseMinDependency|Any CPU.ActiveCfg = Release|x64 + {47EECFB7-1F9E-409C-B8AD-0A2BCCA9CB34}.ReleaseMinDependency|Any CPU.Build.0 = Release|x64 + {47EECFB7-1F9E-409C-B8AD-0A2BCCA9CB34}.ReleaseMinDependency|Mixed Platforms.ActiveCfg = Release|Win32 + {47EECFB7-1F9E-409C-B8AD-0A2BCCA9CB34}.ReleaseMinDependency|Mixed Platforms.Build.0 = Release|Win32 + {47EECFB7-1F9E-409C-B8AD-0A2BCCA9CB34}.ReleaseMinDependency|Win32.ActiveCfg = Release|Win32 + {47EECFB7-1F9E-409C-B8AD-0A2BCCA9CB34}.ReleaseMinDependency|Win32.Build.0 = Release|Win32 + {47EECFB7-1F9E-409C-B8AD-0A2BCCA9CB34}.ReleaseMinDependency|x64.ActiveCfg = Release|x64 + {47EECFB7-1F9E-409C-B8AD-0A2BCCA9CB34}.ReleaseMinDependency|x64.Build.0 = Release|x64 + {47EECFB7-1F9E-409C-B8AD-0A2BCCA9CB34}.ReleaseMinDependency|x86.ActiveCfg = Release|Win32 + {47EECFB7-1F9E-409C-B8AD-0A2BCCA9CB34}.ReleaseMinDependency|x86.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {D885561A-FFA2-42EF-A790-D54EB24B2E82} + EndGlobalSection +EndGlobal diff --git a/libkmaudio/libkmaudio.vcxproj b/libkmaudio/libkmaudio.vcxproj new file mode 100644 index 0000000..f5e8bf0 --- /dev/null +++ b/libkmaudio/libkmaudio.vcxproj @@ -0,0 +1,164 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + Debug + x64 + + + Release + x64 + + + + 16.0 + Win32Proj + {47eecfb7-1f9e-409c-b8ad-0a2bcca9cb34} + libkmaudio + 10.0 + + + + Application + true + v142 + Unicode + + + Application + false + v142 + true + Unicode + + + Application + true + v142 + Unicode + + + Application + false + v142 + true + Unicode + + + + + + + + + + + + + + + + + + + + + true + + + false + + + true + + + false + + + + Level3 + true + WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + + + Console + true + + + + + Level3 + true + true + true + WIN32;NDEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + true + + + Console + true + true + true + + + + + Level3 + true + _DEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + + + Console + true + + + + + Level3 + true + true + true + NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + + + Console + true + true + true + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/libkmaudio/libkmaudio.vcxproj.filters b/libkmaudio/libkmaudio.vcxproj.filters new file mode 100644 index 0000000..551c087 --- /dev/null +++ b/libkmaudio/libkmaudio.vcxproj.filters @@ -0,0 +1,69 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms + + + + + Quelldateien + + + Quelldateien + + + Quelldateien + + + Quelldateien + + + Quelldateien + + + Quelldateien + + + Quelldateien + + + Quelldateien + + + Quelldateien + + + Quelldateien + + + Quelldateien + + + Quelldateien + + + + + Headerdateien + + + Headerdateien + + + Headerdateien + + + Headerdateien + + + \ No newline at end of file diff --git a/libkmaudio/libkmaudio.vcxproj.user b/libkmaudio/libkmaudio.vcxproj.user new file mode 100644 index 0000000..0f14913 --- /dev/null +++ b/libkmaudio/libkmaudio.vcxproj.user @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/libkmaudio/libkmaudio_capture.cpp b/libkmaudio/libkmaudio_capture.cpp new file mode 100644 index 0000000..be26da7 --- /dev/null +++ b/libkmaudio/libkmaudio_capture.cpp @@ -0,0 +1,157 @@ +/* +* Audio Library for Linux and Windows +* =================================== +* Author: DJ0ABR +* +* Author: Kurt Moraw, Ham radio: DJ0ABR, github: dj0abr +* License: GPL-3 +* +* compilation: +* Windows ... Visual Studio +* Linux ... make +* +* Documentation see: libkmaudio.h +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 2 of the License, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You 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. +* +* libkmaudio_capture.cpp ... +* starts a portaudio capture stream and a callback routine. Writes the +* received audio samples into the fifo (Windows only) +*/ +#include "libkmaudio.h" + +#define FRAMES_PER_BUFFER 512 + +int recordCallback(const void* inputBuffer, void* outputBuffer, + unsigned long framesPerBuffer, + const PaStreamCallbackTimeInfo* timeInfo, + PaStreamCallbackFlags statusFlags, + void* userData); + +void close_capture_stream(int idx) +{ + if (devlist[idx].capStream != NULL) + { + Pa_CloseStream(devlist[idx].capStream); + devlist[idx].capStream = NULL; + } +} + +int kmaudio_startCapture(char* devname, int samprate) +{ + printf("Start request for CAP stream:%s\n", devname); + + if (devname == NULL || strlen(devname) < 3) // no devices defined yet + { + printf("no capture devices specified\n"); + return -1; + } + + int idx = searchDevice(devname, 0); + if (idx == -1) + { + printf("Device:<%s> not found\n", devname); + return -1; + } + + devlist[idx].working = 0; + + close_capture_stream(idx); + + printf("Starting CAP stream:%s [%d]\n", devname, idx); + + io_fifo_clear(idx); + + devlist[idx].requested_samprate = samprate; + if(getRealSamprate(idx) == -1) + { + printf("Samplerate %d not supported by device:<%s>\n", samprate, devname); + return -1; + } + + if (devlist[idx].requested_samprate != devlist[idx].real_samprate) + resampler_create(idx); + + struct PaWasapiStreamInfo wasapiInfo; + memset(&wasapiInfo, 0, sizeof(PaWasapiStreamInfo)); + wasapiInfo.size = sizeof(PaWasapiStreamInfo); + wasapiInfo.hostApiType = paWASAPI; + wasapiInfo.version = 1; + wasapiInfo.flags = (paWinWasapiExclusive | paWinWasapiThreadPriority); + wasapiInfo.threadPriority = eThreadPriorityProAudio; + + devlist[idx].inputParameters.hostApiSpecificStreamInfo = (&wasapiInfo); + + int e = Pa_IsFormatSupported(&devlist[idx].inputParameters, NULL, (double)devlist[idx].real_samprate); + printf("err:%d device:%d PAdev:%d samprate: %f\n", e,idx, devlist[idx].devnum,(double)devlist[idx].real_samprate); + + devlist[idx].index = idx; + + int err = Pa_OpenStream( + &devlist[idx].capStream, + &devlist[idx].inputParameters, + NULL, + (double)devlist[idx].real_samprate, + FRAMES_PER_BUFFER, + paClipOff, + recordCallback, + &(devlist[idx].index)); + + if (err != paNoError) + { + printf("cannot open capture stream for device:<%s> %d\n", devname,err); + return -1; + } + + err = Pa_StartStream(devlist[idx].capStream); + if (err != paNoError) + { + printf("cannot start capture stream for device:<%s>\n", devname); + return -1; + } + + printf("Capture started sucessfully\n"); + devlist[idx].working = 1; + return idx; +} + +int recordCallback( const void* inputBuffer, + void* outputBuffer, + unsigned long framesPerBuffer, + const PaStreamCallbackTimeInfo* timeInfo, + PaStreamCallbackFlags statusFlags, + void* userData) +{ + const int16_t* rptr = (const int16_t*)inputBuffer; + int devidx = *((int *)userData); + int chans = devlist[devidx].inputParameters.channelCount; + + //printf("%ld captured %d frames. Flag: %X\n", (long)rptr,framesPerBuffer, statusFlags); + //measure_speed_bps(framesPerBuffer); + + //printf("%d %d\n", chans, rptr[0]); + for (unsigned int i = 0; i < framesPerBuffer; i++) + io_write_fifo_short(devidx, rptr[i * chans]); + + // Prevent unused variable warnings + (void)outputBuffer; + (void)timeInfo; + (void)statusFlags; + + if(keeprunning == 1) + return paContinue; + + return paComplete; +} diff --git a/libkmaudio/libkmaudio_capture_linux.cpp b/libkmaudio/libkmaudio_capture_linux.cpp new file mode 100644 index 0000000..b74cc3e --- /dev/null +++ b/libkmaudio/libkmaudio_capture_linux.cpp @@ -0,0 +1,222 @@ +/* +* Audio Library for Linux and Windows +* =================================== +* Author: DJ0ABR +* +* Author: Kurt Moraw, Ham radio: DJ0ABR, github: dj0abr +* License: GPL-3 +* +* compilation: +* Windows ... Visual Studio +* Linux ... make +* +* Documentation see: libkmaudio.h +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 2 of the License, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You 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. +* +* libkmaudio_capture.cpp ... +* starts a libsoundio capture stream and a callback routine. Writes the +* received audio samples into the fifo (Linux only) +*/ + +#ifndef WIN32 + +#include "libkmaudio.h" + +char* getDevID(char* devname, int io, int *pidx) +{ + for (int i = 0; i < devanz; i++) + { + //printf("%s: %d %d\n", devlist[i].name, io, devlist[i].in_out); + if (!strcmp(devname, devlist[i].name) && io == devlist[i].in_out) + { + *pidx = i; + return devlist[i].id; + } + } + return NULL; +} + +int min_int(int a, int b) +{ + return (a < b) ? a : b; +} + +void read_callback(struct SoundIoInStream* instream, int frame_count_min, int frame_count_max) +{ + int err; + if (instream == NULL || soundio == NULL) return; + //printf("cap: %d %d\n", frame_count_min, frame_count_max); + //int chans = instream->layout.channel_count; + //printf("cap:%d\n", instream->sample_rate); + int idx = *((int *)(instream->userdata)); + + struct SoundIoChannelArea* areas; + // samples are in areas.ptr + int frames_left = frame_count_max; // take all + while (keeprunning) + { + int frame_count = frames_left; + if ((err = soundio_instream_begin_read(instream, &areas, &frame_count))) + { + fprintf(stderr, "begin read error: %s", soundio_strerror(err)); + return; + } + if (!frame_count) + break; + + //printf("write %d samples to fifo %d. Channels:%d\n", frame_count, idx, instream->layout.channel_count); + for (int frame = 0; frame < frame_count; frame += 1) + { + for (int ch = 0; ch < instream->layout.channel_count; ch += 1) + { + float frxdata; + memcpy(&frxdata, areas[ch].ptr, instream->bytes_per_sample); + areas[ch].ptr += areas[ch].step; + if (ch == 0) + { + io_write_fifo(idx, frxdata); + } + } + } + + //measure_speed_bps(frame_count); + + if ((err = soundio_instream_end_read(instream))) + { + printf("end read error: %s", soundio_strerror(err)); + return; + } + + frames_left -= frame_count; + if (frames_left <= 0) + break; + } +} + +void overflow_callback(struct SoundIoInStream* instream) +{ + static int count = 0; + printf("overflow %d\n", ++count); +} + +void close_capture_stream(int idx) +{ + if (devlist[idx].instream != NULL) + { + soundio_instream_destroy(devlist[idx].instream); + devlist[idx].instream = NULL; + } +} + +int kmaudio_startCapture(char* devname, int samprate) +{ + printf("Start request for CAP stream:%s\n", devname); + + if (devname == NULL || strlen(devname) < 3) // no devices defined yet + { + printf("no capture devices specified\n"); + return -1; + } + + int idx = 0; // index into devlist + char* capdevid = getDevID(devname, 0, &idx); + if (capdevid == NULL) + { + printf("CAP: Device ID not found\n"); + return -1; + } + + + // if an old stream is open, close it + close_capture_stream(idx); + + printf("Starting CAP stream:%s [%d]\n", devname, idx); + + io_fifo_clear(idx); + + devlist[idx].working = 0; + + // define the capture device + soundio_flush_events(soundio); + + for (int i = 0; i < soundio_input_device_count(soundio); i++) + { + devlist[idx].io_cap_device = NULL; + struct SoundIoDevice* device = soundio_get_input_device(soundio, i); + if (strcmp(device->id, capdevid) == 0) + { + devlist[idx].io_cap_device = device; + break; + } + soundio_device_unref(device); + } + if (!devlist[idx].io_cap_device) + { + printf("Invalid device id: %s\n", capdevid); + return -1; + } + + if (devlist[idx].io_cap_device->probe_error) + { + printf("Unable to probe device: %s\n", soundio_strerror(devlist[idx].io_cap_device->probe_error)); + return -1; + } + + // create capture callback + devlist[idx].instream = soundio_instream_create(devlist[idx].io_cap_device); + if (!devlist[idx].instream) { + printf("capture: out of memory\n"); + return -1; + } + + devlist[idx].requested_samprate = samprate; + if (getRealSamprate(idx) == -1) + { + printf("Samplerate %d not supported by device:<%s>\n", samprate, devname); + return -1; + } + + if (devlist[idx].requested_samprate != devlist[idx].real_samprate) + resampler_create(idx); + + devlist[idx].instream->format = SoundIoFormatFloat32NE; + devlist[idx].instream->sample_rate = devlist[idx].real_samprate; + devlist[idx].instream->software_latency = 0.1f; + devlist[idx].instream->read_callback = read_callback; + devlist[idx].instream->overflow_callback = overflow_callback; + devlist[idx].instream->userdata = &(devlist[idx].index); + + int err = 0; + if ((err = soundio_instream_open(devlist[idx].instream))) { + printf("unable to open input stream: %d: %s", err, soundio_strerror(err)); + return -1; + } + + if ((err = soundio_instream_start(devlist[idx].instream))) { + printf("unable to start input device: %s", soundio_strerror(err)); + return -1; + } + + printf("selected CAPTURE device:\nname:%s\nid :%s\n", devlist[idx].name, capdevid); + printf("physical capture rate:%d, requested capture rate:%d\n", devlist[idx].real_samprate, devlist[idx].requested_samprate); + printf("format: %s\n\n", soundio_format_string(devlist[idx].instream->format)); + + devlist[idx].working = 1; + + return idx; +} + +#endif // #ifndef WIN32 diff --git a/libkmaudio/libkmaudio_capture_linux.o b/libkmaudio/libkmaudio_capture_linux.o new file mode 100644 index 0000000..8ac67c3 Binary files /dev/null and b/libkmaudio/libkmaudio_capture_linux.o differ diff --git a/libkmaudio/libkmaudio_fifo.cpp b/libkmaudio/libkmaudio_fifo.cpp new file mode 100644 index 0000000..55afd60 --- /dev/null +++ b/libkmaudio/libkmaudio_fifo.cpp @@ -0,0 +1,252 @@ +/* +* Audio Library for Linux and Windows +* =================================== +* Author: DJ0ABR +* +* Author: Kurt Moraw, Ham radio: DJ0ABR, github: dj0abr +* License: GPL-3 +* +* compilation: +* Windows ... Visual Studio +* Linux ... make +* +* Documentation see: libkmaudio.h +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 2 of the License, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You 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. +* +* libkmaudio_fifo.cpp ... thread safe FIFOs, used to interface the +* audio callback routines to the other program +* +*/ + +#include "libkmaudio.h" + +#define NUM_OF_PIPES 20 + +#ifdef WIN32 +CRITICAL_SECTION audio_crit_sec[NUM_OF_PIPES]; +#define LOCK(pn) EnterCriticalSection(&(audio_crit_sec[pn])) +void UNLOCK(int pn) +{ + if (&(audio_crit_sec[pn]) != NULL) + LeaveCriticalSection(&(audio_crit_sec[pn])); +} +#else +pthread_mutex_t audio_crit_sec[NUM_OF_PIPES]; +#define LOCK(pn) pthread_mutex_lock(&(audio_crit_sec[pn])) +#define UNLOCK(pn) pthread_mutex_unlock(&(audio_crit_sec[pn])) +#endif + +#define AUDIO_FIFOFLEN 48000 + +int io_wridx[NUM_OF_PIPES]; +int io_rdidx[NUM_OF_PIPES]; +int16_t io_buffer[NUM_OF_PIPES][AUDIO_FIFOFLEN]; + +void init_pipes() +{ + // init pipes only once + static int f = 1; + if (f) + { + f = 0; + for (int i = 0; i < NUM_OF_PIPES; i++) + { +#ifdef WIN32 + if (&(audio_crit_sec[i]) != NULL) DeleteCriticalSection(&(audio_crit_sec[i])); + InitializeCriticalSection(&(audio_crit_sec[i])); +#else + if (&(audio_crit_sec[i]) != NULL) pthread_mutex_destroy(&(audio_crit_sec[i])); + pthread_mutex_init(&(audio_crit_sec[i]), NULL); +#endif + } + } + + for (int i = 0; i < NUM_OF_PIPES; i++) + io_fifo_clear(i); +} + +// write one sample into the fifo +// ignore data if the fifo is full +void io_write_fifo(int pipenum, float sample) +{ + if (pipenum < 0 || pipenum >= NUM_OF_PIPES) return; + + LOCK(pipenum); + if (((io_wridx[pipenum] + 1) % AUDIO_FIFOFLEN) == io_rdidx[pipenum]) + { + //printf("cannot float WRITE fifo %d full\n",pipenum); + UNLOCK(pipenum); + return; + } + + io_buffer[pipenum][io_wridx[pipenum]] = (int16_t)(sample * 32768.0f); + if (++io_wridx[pipenum] >= AUDIO_FIFOFLEN) io_wridx[pipenum] = 0; + + UNLOCK(pipenum); +} + +void io_write_fifo_short(int pipenum, int16_t sample) +{ + if (pipenum < 0 || pipenum >= NUM_OF_PIPES) return; + + LOCK(pipenum); + if (((io_wridx[pipenum] + 1) % AUDIO_FIFOFLEN) == io_rdidx[pipenum]) + { + //printf("cannot short WRITE fifo %d full\n", pipenum); + UNLOCK(pipenum); + return; + } + + io_buffer[pipenum][io_wridx[pipenum]] = sample; + if (++io_wridx[pipenum] >= AUDIO_FIFOFLEN) io_wridx[pipenum] = 0; + + UNLOCK(pipenum); +} + +int io_read_fifo(int pipenum, float* data) +{ + if (pipenum < 0 || pipenum >= NUM_OF_PIPES) return 0; + + LOCK(pipenum); + + if (io_rdidx[pipenum] == io_wridx[pipenum]) + { + // Fifo empty, no data available + UNLOCK(pipenum); + return 0; + } + + int16_t id = io_buffer[pipenum][io_rdidx[pipenum]]; + if (++io_rdidx[pipenum] >= AUDIO_FIFOFLEN) io_rdidx[pipenum] = 0; + UNLOCK(pipenum); + + *data = (float)id / 32768; + + return 1; +} + +// read num elements +// if num elems not avail, return all what fifo has stored +int io_read_fifo_num(int pipenum, float* data, int num) +{ + if (pipenum < 0 || pipenum >= NUM_OF_PIPES) return 0; + + LOCK(pipenum); + + int elemInFifo = (io_wridx[pipenum] + AUDIO_FIFOFLEN - io_rdidx[pipenum]) % AUDIO_FIFOFLEN; + elemInFifo -= 1; + + /*if (num > elemInFifo) + { + // Fifo not enough data available + //printf("only %d elements available\n", elemInFifo); + UNLOCK(pipenum); + return 0; + }*/ + + if (num > elemInFifo) num = elemInFifo; + + int16_t id; + + for (int i = 0; i < num; i++) + { + id = io_buffer[pipenum][io_rdidx[pipenum]]; + *data++ = (float)id / 32768; + if (++io_rdidx[pipenum] >= AUDIO_FIFOFLEN) io_rdidx[pipenum] = 0; + } + UNLOCK(pipenum); + + return num; +} + +int io_read_fifo_num_short(int pipenum, int16_t* data, int num) +{ + if (pipenum < 0 || pipenum >= NUM_OF_PIPES) return 0; + + LOCK(pipenum); + + int elemInFifo = (io_wridx[pipenum] + AUDIO_FIFOFLEN - io_rdidx[pipenum]) % AUDIO_FIFOFLEN; + elemInFifo -= 1; + + /*if (num > elemInFifo) + { + // Fifo not enough data available + //printf("only %d elements available\n", elemInFifo); + UNLOCK(pipenum); + return 0; + }*/ + + if (num > elemInFifo) num = elemInFifo; + + for (int i = 0; i < num; i++) + { + *data++ = io_buffer[pipenum][io_rdidx[pipenum]]; + if (++io_rdidx[pipenum] >= AUDIO_FIFOFLEN) io_rdidx[pipenum] = 0; + } + UNLOCK(pipenum); + + return num; +} + +void io_fifo_clear(int pipenum) +{ + if (pipenum < 0 || pipenum >= NUM_OF_PIPES) return; + + io_wridx[pipenum] = io_rdidx[pipenum] = 0; +} + +int io_fifo_freespace(int pipenum) +{ + if (pipenum < 0 || pipenum >= NUM_OF_PIPES) return 0; + + int freebuf = 0; + + LOCK(pipenum); + + int elemInFifo = (io_wridx[pipenum] + AUDIO_FIFOFLEN - io_rdidx[pipenum]) % AUDIO_FIFOFLEN; + freebuf = AUDIO_FIFOFLEN - elemInFifo -1; + + UNLOCK(pipenum); + return freebuf; +} + +int io_fifo_elems_avail(int pipenum) +{ + if (pipenum < 0 || pipenum >= NUM_OF_PIPES) return 0; + + int elems = 0; + + LOCK(pipenum); + elems = (io_wridx[pipenum] + AUDIO_FIFOFLEN - io_rdidx[pipenum]) % AUDIO_FIFOFLEN; + UNLOCK(pipenum); + + elems -= 10; + return elems; +} + +int io_fifo_usedspace(int pipenum) +{ + return AUDIO_FIFOFLEN - io_fifo_freespace(pipenum); +} + +int io_fifo_usedpercent(int pipenum) +{ + int used = AUDIO_FIFOFLEN - io_fifo_freespace(pipenum); + int percent = (used * 100) / AUDIO_FIFOFLEN; + //printf("idx:%d used:%d size:%d percent:%d\n", pipenum, used, AUDIO_FIFOFLEN, percent); + return percent; +} + diff --git a/libkmaudio/libkmaudio_fifo.o b/libkmaudio/libkmaudio_fifo.o new file mode 100644 index 0000000..413bbf5 Binary files /dev/null and b/libkmaudio/libkmaudio_fifo.o differ diff --git a/libkmaudio/libkmaudio_getDevices.cpp b/libkmaudio/libkmaudio_getDevices.cpp new file mode 100644 index 0000000..e4f7f62 --- /dev/null +++ b/libkmaudio/libkmaudio_getDevices.cpp @@ -0,0 +1,298 @@ +/* +* Audio Library for Linux and Windows +* =================================== +* Author: DJ0ABR +* +* Author: Kurt Moraw, Ham radio: DJ0ABR, github: dj0abr +* License: GPL-3 +* +* compilation: +* Windows ... Visual Studio +* Linux ... make +* +* Documentation see: libkmaudio.h +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 2 of the License, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You 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. +* +* libkmaudio_getDevices.cpp +* read audio device list via portaudio (which is only used for Windows) +* prepare a device name string which can be read by another program +* in order to present the devices to use user for selection +* +*/ + +#include "libkmaudio.h" + +void io_buildAudioDevString(); + +// number of detected devices, updated after a call to kmaudio_getDeviceList() +int devanz = 0; + +// devlist contains all information for all detected devices +// the list is filled by a call to kmaudio_getDeviceList() +DEVLIST devlist[MAXDEVICES]; + +double latency = 0.2; // WASAPI latency in seconds + +#ifdef WIN32 + +/*static double standardSampleRates[] = { +8000.0, 9600.0, 11025.0, 12000.0, 16000.0, +22050.0, 24000.0, 32000.0, 44100.0, 48000.0, +88200.0, 96000.0, 192000.0, -1 };*/ + +static double standardSampleRates[] = {44100.0, 48000.0, -1}; + +int getDevlistIndex(const char* name, int ichans, int ochans) +{ + for (int i = 0; i < devanz; i++) + { + // check if already exists + if (!strcmp(devlist[i].name, name) && + devlist[i].inputParameters.channelCount == ichans && + devlist[i].outputParameters.channelCount == ochans) + return i; + } + + int newidx = devanz; + devanz++; + //printf("New Dev:%s Idx:%d\n", name, newidx); + return newidx; +} + +int kmaudio_getDeviceList() +{ + int numDevices = Pa_GetDeviceCount(); + if (numDevices < 0) + { + printf("ERROR: Pa_GetDeviceCount returned 0x%x\n", numDevices); + return -1; + } + + //printf("%d Devices found\n", numDevices); + + for (int i = 0; i < devanz; i++) + devlist[i].active = 0; + + int didx; + for (int i = 0; i < numDevices; i++) + { + const PaDeviceInfo* deviceInfo = Pa_GetDeviceInfo(i); + const PaHostApiInfo *ai = Pa_GetHostApiInfo(deviceInfo->hostApi); + + // Windows: use WASAPI devices only + if (strstr(ai->name, "WASAPI") != NULL) + { + didx = getDevlistIndex(deviceInfo->name, deviceInfo->maxInputChannels, deviceInfo->maxOutputChannels); + + devlist[didx].devnum = i; + snprintf(devlist[didx].name, MAXDEVNAMELENGTH - 1, "%s", deviceInfo->name); + //printf("------%s-------\n", deviceInfo->name); + + devlist[didx].inputParameters.device = i; + devlist[didx].inputParameters.channelCount = deviceInfo->maxInputChannels; + devlist[didx].inputParameters.sampleFormat = paInt16; + devlist[didx].inputParameters.suggestedLatency = latency; + devlist[didx].inputParameters.hostApiSpecificStreamInfo = NULL; + + devlist[didx].outputParameters.device = i; + devlist[didx].outputParameters.channelCount = deviceInfo->maxOutputChannels; + devlist[didx].outputParameters.sampleFormat = paInt16; + devlist[didx].outputParameters.suggestedLatency = latency; + devlist[didx].outputParameters.hostApiSpecificStreamInfo = NULL; + + if (devlist[didx].inputParameters.channelCount > 0 && devlist[devanz].outputParameters.channelCount > 0) + devlist[didx].in_out = 2; + else if (devlist[didx].inputParameters.channelCount > 0) + devlist[didx].in_out = 0; + else if (devlist[didx].outputParameters.channelCount > 0) + devlist[didx].in_out = 1; + + devlist[didx].index = didx; + devlist[didx].active = 1; + + for (int j = 0; standardSampleRates[j] > 0; j++) + { + PaError err = 0; + //if (devlist[didx].inputParameters.channelCount > 0 && devlist[didx].outputParameters.channelCount > 0) + // err = Pa_IsFormatSupported(&devlist[didx].inputParameters, &devlist[didx].outputParameters, standardSampleRates[j]); + if (devlist[didx].inputParameters.channelCount > 0) + err = Pa_IsFormatSupported(&devlist[didx].inputParameters, NULL, standardSampleRates[j]); + if (devlist[didx].outputParameters.channelCount > 0) + err = Pa_IsFormatSupported(NULL, &devlist[didx].outputParameters, standardSampleRates[j]); + + // portaudio cannot detect if a device was removed, instead it delivers errors + if (err == paInvalidDevice) + devlist[didx].active = 0; + else if (err == paFormatIsSupported) + { + if (j == 0) devlist[didx].supports_44100 = 1; + if (j == 1) devlist[didx].supports_48000 = 1; + } + } + } + } + + io_buildAudioDevString(); + + // close stream if a device does not exist any more + for (int i = 0; i < devanz; i++) + { + if (devlist[i].active == 0) + { + if (devlist[i].capStream != NULL) + { + printf("capture device %s disconnected, stop stream\n", devlist[i].name); + Pa_CloseStream(devlist[i].capStream); + devlist[i].capStream = NULL; + devlist[i].working = 0; + } + + if (devlist[i].pbStream != NULL) + { + printf("playback device %s disconnected, stop stream\n", devlist[i].name); + Pa_CloseStream(devlist[i].pbStream); + devlist[i].pbStream = NULL; + devlist[i].working = 0; + } + } + } + + static int csum = 0; + int sum = 0; + uint8_t* p = (uint8_t*)&(devlist[0].index); + for (int i = 0; i < (int)sizeof(devlist); i++) + sum += *p++; + + if (csum != sum) + { + csum = sum; + + printf("Windows Devices found:\n"); + for (int i = 0; i < devanz; i++) + { + printf("Portaudio ID: %d\n", devlist[i].index); + printf("Name: %s\n", devlist[i].name); + printf("Cap/PB: %d\n", devlist[i].in_out); + printf("Channels: i:%d o:%d\n", devlist[i].inputParameters.channelCount, devlist[i].outputParameters.channelCount); + printf("SR 44100: %d\n", devlist[i].supports_44100); + printf("SR 48000: %d\n", devlist[i].supports_48000); + printf("is active: %s\n", devlist[i].active ? "yes" : "no"); + } + } + + return 0; +} + +#endif //WIN32 + + +// find a device in devlist +// returns: list index or -1 if error +int searchDevice(char* devname, int io) +{ + for (int i = 0; i < devanz; i++) + { + if (strcmp(devname, devlist[i].name) == 0 && (devlist[i].in_out == io || devlist[i].in_out == 2)) + return i; + } + return -1; +} + +// choose physical, real sample rate for a device +// returns: 0=ok, -1=error: no sample rate supported +int getRealSamprate(int idx) +{ + if (devlist[idx].requested_samprate == 44100) + { + if (devlist[idx].supports_44100) devlist[idx].real_samprate = 44100; + else if (devlist[idx].supports_48000) devlist[idx].real_samprate = 48000; + else return -1; + } + + else if (devlist[idx].requested_samprate == 48000) + { + if (devlist[idx].supports_48000) devlist[idx].real_samprate = 48000; + else if (devlist[idx].supports_44100) devlist[idx].real_samprate = 44100; + else return -1; + } + + else + { + if (devlist[idx].supports_48000) devlist[idx].real_samprate = 48000; + else if (devlist[idx].supports_44100) devlist[idx].real_samprate = 44100; + else return -1; + } + + return 0; +} + +// build string of audio device name, to be sent to application as response to Broadcast search +// starting with PB devices, sperarator ^, capture devices +// separator between devices: ~ +#define MAXDEVSTRLEN (MAXDEVICES * (MAXDEVNAMELENGTH + 2) + 10) +uint8_t io_devstring[MAXDEVSTRLEN]; + +void io_buildAudioDevString() +{ + memset(io_devstring, 0, sizeof(io_devstring)); + io_devstring[0] = ' '; // placeholder for other data + io_devstring[1] = ' '; + io_devstring[2] = ' '; + io_devstring[3] = ' '; + io_devstring[4] = ' '; + + // playback devices + for (int i = 0; i < devanz; i++) + { + if (devlist[i].active == 0) continue; + if (strlen((char *)io_devstring) > MAXDEVSTRLEN) + { + printf("io_devstring too small:%d / %d. Serious error, abort program\n", MAXDEVSTRLEN, (int)strlen((char*)io_devstring)); + exit(0); + } + if (devlist[i].in_out == 1) + { + strcat((char*)io_devstring, devlist[i].name); + strcat((char*)io_devstring, "~"); // audio device separator + } + } + + strcat((char*)(io_devstring + 1), "^"); // PB, CAP separator + + // capture devices + for (int i = 0; i < devanz; i++) + { + if (devlist[i].active == 0) continue; + if (strlen((char*)io_devstring) > MAXDEVSTRLEN) + { + printf("io_devstring too small:%d / %d. Serious error, abort program\n", MAXDEVSTRLEN, (int)strlen((char*)io_devstring)); + exit(0); + } + if (devlist[i].in_out == 0) + { + strcat((char*)io_devstring, devlist[i].name); + strcat((char*)io_devstring, "~"); // audio device separator + } + } + + //printf("<%s>\n", (char *)io_devstring); +} + +uint8_t* io_getAudioDevicelist(int* len) +{ + *len = strlen((char*)(io_devstring + 1)) + 1; + return io_devstring; +} diff --git a/libkmaudio/libkmaudio_getDevices.o b/libkmaudio/libkmaudio_getDevices.o new file mode 100644 index 0000000..f44c9f5 Binary files /dev/null and b/libkmaudio/libkmaudio_getDevices.o differ diff --git a/libkmaudio/libkmaudio_getDevices_Linux.cpp b/libkmaudio/libkmaudio_getDevices_Linux.cpp new file mode 100644 index 0000000..591c611 --- /dev/null +++ b/libkmaudio/libkmaudio_getDevices_Linux.cpp @@ -0,0 +1,228 @@ +/* +* Audio Library for Linux and Windows +* =================================== +* Author: DJ0ABR +* +* Author: Kurt Moraw, Ham radio: DJ0ABR, github: dj0abr +* License: GPL-3 +* +* compilation: +* Windows ... Visual Studio +* Linux ... make +* +* Documentation see: libkmaudio.h +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 2 of the License, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You 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. +* +* libkmaudio_getDevices_linux.cpp +* like libkmaudio_getDevices.cpp, but uses libsoundio under Linux +* to get the device list. Portaudio does not work under Linux because +* it does not support pulseaudio. Therefore the linux functions +* use libsoundio +* +*/ + +#ifndef WIN32 // Linux + +#include "libkmaudio.h" + +int scan_devices(); + +int kmaudio_getDeviceList() +{ + if (soundio == NULL) + { + printf("kmaudio_getDeviceList: soundio not initialized\n"); + return -1; + } + + soundio_flush_events(soundio); // to get actual data + + if (scan_devices() == -1) // read devices + { + printf("cannot read audio devices\n"); + return -1; + } + + io_buildAudioDevString(); + + // close stream if a device does not exist any more + for (int i = 0; i < devanz; i++) + { + if (devlist[i].active == 0) + { + if (devlist[i].instream != NULL) + { + printf("capture device %s disconnected, stop stream\n", devlist[i].name); + soundio_instream_destroy(devlist[i].instream); + devlist[i].instream = NULL; + devlist[i].working = 0; + } + + if (devlist[i].outstream != NULL) + { + printf("playback device %s disconnected, stop stream\n", devlist[i].name); + soundio_outstream_destroy(devlist[i].outstream); + devlist[i].outstream = NULL; + devlist[i].working = 0; + } + } + } + + static int csum = 0; + int sum = 0; + uint8_t *p = (uint8_t *)&(devlist[0].index); + for (int i = 0; i < (int)sizeof(devlist); i++) + sum += *p++; + + if (csum != sum) + { + csum = sum; + + /*printf("====== Linux Devices found: ======\n"); + for (int i = 0; i < devanz; i++) + { + printf("Index: %d\n", devlist[i].index); + printf("Name: %s\n", devlist[i].name); + printf("ID: %s\n", devlist[i].id); + printf("Cap/PB: %d\n", devlist[i].in_out); + printf("Channels: %d\n", devlist[i].stereo_mono); + printf("SR 44100: %d\n", devlist[i].supports_44100); + printf("SR 48000: %d\n", devlist[i].supports_48000); + printf("is active: %s\n", devlist[i].active ? "yes" : "no"); + printf("--------------------------------------\n"); + }*/ + } + return 0; +} + +static void get_channel_layout(const struct SoundIoChannelLayout *layout) +{ + if (layout->name) + { + if (strstr(layout->name, "ereo")) + devlist[devanz].stereo_mono = 2; + if (strstr(layout->name, "ono")) + devlist[devanz].stereo_mono = 1; + } +} + +int getDeviceParameters(int idx, struct SoundIoDevice *device) +{ + strncpy(devlist[idx].id, device->id, sizeof(devlist[0].id) - 1); + devlist[idx].id[sizeof(devlist[0].id) - 1] = 0; + strncpy(devlist[idx].name, device->name, sizeof(devlist[0].name) - 1); + devlist[idx].name[sizeof(devlist[0].name) - 1] = 0; + + for (int i = 0; i < device->layout_count; i++) + get_channel_layout(&device->layouts[i]); + + int min = 999999, max = 0; + for (int i = 0; i < device->sample_rate_count; i++) + { + struct SoundIoSampleRateRange *range = &device->sample_rates[i]; + if (range->min < min) + min = range->min; + + if (range->max > max) + max = range->max; + } + if (min <= 44100) + devlist[idx].supports_44100 = 1; + if (max >= 48000) + devlist[idx].supports_48000 = 1; + if (devlist[idx].supports_44100 == 0 && devlist[idx].supports_48000 == 0) + return 0; + return 1; +} + +int getDevlistIndex(char *name, char *id) +{ + /* !!! Achtung: das hier filtert Devices raus die auf PB und CAP gleiche Daten haben !!! + noch nach PB und CAP unterscheiden + for (int i = 0; i < devanz; i++) + { + // check if already exists + if (!strcmp(devlist[i].id, id) && !strcmp(devlist[i].name, name)) + return i; + }*/ + + int newidx = devanz; + devanz++; + //printf("New Dev:%s Idx:%d\n", name, newidx); + return newidx; +} + +int scan_devices() +{ + for (int i = 0; i < devanz; i++) + devlist[i].active = 0; + + int didx; + for (int i = 0; i < soundio_input_device_count(soundio); i++) + { + struct SoundIoDevice *device = soundio_get_input_device(soundio, i); + if (device == NULL) + continue; + if (strstr(device->name, "onitor")) + continue; + if (device->probe_error) + continue; + + didx = getDevlistIndex(device->name, device->id); + if (getDeviceParameters(didx, device) == 1) + { + printf("%d %d %d ====CAP: name:<%s>\n", i, devanz, didx, device->name); + devlist[didx].in_out = 0; + devlist[didx].index = didx; + devlist[didx].active = 1; + } + else + { + *devlist[didx].name = 0; + *devlist[didx].id = 0; + } + soundio_device_unref(device); + } + + for (int i = 0; i < soundio_output_device_count(soundio); i++) + { + struct SoundIoDevice *device = soundio_get_output_device(soundio, i); + if (device == NULL) + continue; + if (strstr(device->name, "onitor")) + continue; + if (device->probe_error) + continue; + + didx = getDevlistIndex(device->name, device->id); + if (getDeviceParameters(didx, device) == 1) + { + printf("%d %d %d ====PB : name:<%s>\n", i, devanz, didx, device->name); + devlist[didx].in_out = 1; + devlist[didx].index = didx; + devlist[didx].active = 1; + } + else + { + *devlist[didx].name = 0; + *devlist[didx].id = 0; + } + soundio_device_unref(device); + } + return 0; +} + +#endif // ifndef WIN32 \ No newline at end of file diff --git a/libkmaudio/libkmaudio_getDevices_Linux.o b/libkmaudio/libkmaudio_getDevices_Linux.o new file mode 100644 index 0000000..aacf642 Binary files /dev/null and b/libkmaudio/libkmaudio_getDevices_Linux.o differ diff --git a/libkmaudio/libkmaudio_init.cpp b/libkmaudio/libkmaudio_init.cpp new file mode 100644 index 0000000..cf1152b --- /dev/null +++ b/libkmaudio/libkmaudio_init.cpp @@ -0,0 +1,166 @@ +/* +* Audio Library for Linux and Windows +* =================================== +* Author: DJ0ABR +* +* Author: Kurt Moraw, Ham radio: DJ0ABR, github: dj0abr +* License: GPL-3 +* +* compilation: +* Windows ... Visual Studio +* Linux ... make +* +* Documentation see: libkmaudio.h +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 2 of the License, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You 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. +* +* libkmaudio_init.cpp ... initialize portaudio (Windows only) +* +*/ + +#include "libkmaudio.h" + +void kmaudio_close(); + +int kmaudio_init() +{ + + kmaudio_close(); + sleep_ms(100); + + printf("libkmaudio_init\n"); + + init_pipes(); // init fifo + init_maxarray(); // init array for maxlevel measurement + +#ifdef WIN32 + int err = Pa_Initialize(); + if (err != paNoError) + { + printf("ERROR: Pa_Initialize returned 0x%x\n", err); + return -1; + } + + printf("PortAudio version: 0x%08X\n", Pa_GetVersion()); +#else + return kmaudio_init_linux(); +#endif + + return 0; +} + +void kmaudio_close() +{ + printf("libkmaudio_close\n"); + +#ifdef WIN32 + for (int i = 0; i < devanz; i++) + { + if (devlist[i].capStream != NULL) + { + Pa_CloseStream(devlist[i].capStream); + devlist[i].capStream = NULL; + } + if (devlist[i].pbStream != NULL) + { + Pa_CloseStream(devlist[i].pbStream); + devlist[i].pbStream = NULL; + } + } + Pa_Terminate(); + +#else + kmaudio_close_linux(); +#endif +} + +// diagonstic routines for development + +#define MAXSPDARR 10 +int spdarr[MAXSPDARR]; +int spdarrbps[MAXSPDARR]; + +#ifdef _LINUX_ +uint64_t getms() +{ + struct timeval tv; + gettimeofday(&tv, NULL); + uint64_t at = tv.tv_sec * 1000000 + tv.tv_usec; + at = at / 1000; + return at; +} +#endif + +#ifdef WIN32 +uint64_t getms() +{ + // get time in 100ns resolution + FILETIME ft_now; + GetSystemTimeAsFileTime(&ft_now); + + // convert to full 64 bit time + uint64_t ll_now = (uint64_t)ft_now.dwLowDateTime + ((uint64_t)(ft_now.dwHighDateTime) << 32LL); + + // convert to Milliseconds + ll_now /= (10 * 1000); // still needs 64 bit integer + + return ll_now; +} +#else +uint64_t getms() +{ + struct timeval tv; + gettimeofday(&tv, NULL); + uint64_t at = tv.tv_sec * 1000000 + tv.tv_usec; + at = at / 1000; + return at; +} +#endif + +void measure_speed_bps(int len) +{ + static uint64_t lasttim = 0; + static int elems = 0; + + uint64_t tim = getms(); + int timespan = (int)(tim - lasttim); + if (timespan < 0) + { + lasttim = tim; + return; + } + + elems += len; + if (timespan < 1000) return; + + double dspd = elems; + dspd = dspd * 1e3 / timespan; + int speed = (int)dspd; + + // here we have number of elements after 1s + printf(" ======================= %d bit/s\n", speed); + + elems = 0; + lasttim = tim; +} + +void sleep_ms(int ms) +{ +#ifdef WIN32 + Sleep(ms); +#else + usleep(ms * 1000); +#endif +} diff --git a/libkmaudio/libkmaudio_init.o b/libkmaudio/libkmaudio_init.o new file mode 100644 index 0000000..3803a7b Binary files /dev/null and b/libkmaudio/libkmaudio_init.o differ diff --git a/libkmaudio/libkmaudio_init_linux.cpp b/libkmaudio/libkmaudio_init_linux.cpp new file mode 100644 index 0000000..d6da0ec --- /dev/null +++ b/libkmaudio/libkmaudio_init_linux.cpp @@ -0,0 +1,79 @@ +/* +* Audio Library for Linux and Windows +* =================================== +* Author: DJ0ABR +* +* Author: Kurt Moraw, Ham radio: DJ0ABR, github: dj0abr +* License: GPL-3 +* +* compilation: +* Windows ... Visual Studio +* Linux ... make +* +* Documentation see: libkmaudio.h +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 2 of the License, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You 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. +* +* libkmaudio_init_linux.cpp ... initialize libsoundio (Linux only) +* +*/ +#include "libkmaudio.h" + +struct SoundIo* soundio = NULL; + +#ifndef WIN32 // Linux + +int kmaudio_init_linux() +{ + int err; + + // prepare and connect to libsoundio + soundio = soundio_create(); + if (!soundio) { + printf("soundio_create: out of memory\n"); + return -1; + } + + if ((err = soundio_connect(soundio))) { + printf("soundio_connect: %s\n", soundio_strerror(err)); + return -1; + } + printf("linux libkmaudio_init finished\n"); + + return 0; +} + +void kmaudio_close_linux() +{ + for (int i = 0; i < devanz; i++) + { + if (devlist[i].instream) soundio_instream_destroy(devlist[i].instream); + devlist[i].instream = NULL; + + if (devlist[i].outstream) soundio_outstream_destroy(devlist[i].outstream); + devlist[i].outstream = NULL; + + if (devlist[i].io_pb_device) soundio_device_unref(devlist[i].io_pb_device); + devlist[i].io_pb_device = NULL; + + if (devlist[i].io_cap_device) soundio_device_unref(devlist[i].io_cap_device); + devlist[i].io_cap_device = NULL; + } + + if (soundio) soundio_destroy(soundio); + soundio = NULL; +} + +#endif // ndef WIN32 diff --git a/libkmaudio/libkmaudio_init_linux.o b/libkmaudio/libkmaudio_init_linux.o new file mode 100644 index 0000000..a8c5fd5 Binary files /dev/null and b/libkmaudio/libkmaudio_init_linux.o differ diff --git a/libkmaudio/libkmaudio_interface.cpp b/libkmaudio/libkmaudio_interface.cpp new file mode 100644 index 0000000..4ef6f66 --- /dev/null +++ b/libkmaudio/libkmaudio_interface.cpp @@ -0,0 +1,179 @@ + +#include "libkmaudio.h" + +void getMax(int id, float fv); + +void close_stream(int id) +{ +#ifdef WIN32 + if (devlist[id].capStream != NULL) + close_capture_stream(id); + if (devlist[id].pbStream != NULL) + close_playback_stream(id); +#else + if (devlist[id].instream != NULL) + close_capture_stream(id); + if (devlist[id].outstream != NULL) + close_playback_stream(id); +#endif +} + +/* +* reads len samples from device id into psamp +* returns: number of values written to psamp , -1=error +* id ... device id returned by kmaudio_startCapture +* psamp ... float array of length len getting the audio data (mono) +* len ... number of float values to write into psamp +* volume ... 0.0f..2.0f will be multiplied with the input sample +* wait ... 1=wait for data, 0=return if not enough data available (in this case psamp will return 0,0,0...) +* +* if resampling is required the number of returned samples may differ from the number of requested samples +* it can be larger, so the buffer psamp should be larger than "len" by factor 1.1 +*/ + +int kmaudio_readsamples(int id, float* psamp, int len, float volume, int wait) +{ + int e = io_fifo_elems_avail(id); + if (e < len) return 0; + + if (devlist[id].requested_samprate == devlist[id].real_samprate) + { + // data rate is ok, take samples as is + int nl = io_read_fifo_num(id, psamp, len); + for (int i = 0; i < nl; i++) + { + psamp[i] *= volume; + getMax(id, psamp[i]); + //kmaudio_detectDropouts(id); + } + return nl; + } + + // resampling is required + int num = io_read_fifo_num(id, psamp, len); + if (num == 0) return 0; + + int newlen = 0; + float *f = resample(id, psamp, len, &newlen); + for (int i = 0; i < newlen; i++) + { + psamp[i] = f[i] * volume; + getMax(id, psamp[i]); + } + + return newlen; +} + +/* +* plays len samples from psamp to device id +* returns: 0=ok, -1=error +* id ... device id returned by kmaudio_startPlayback +* psamp ... float array of length len with the audio data (mono) +* len ... number of float values in psamp +* volume ... 0.0f..2.0f will be multiplied with the output sample +*/ + +int kmaudio_playsamples(int id, float* psamp, int len, float volume) +{ + // check if resampling is required + //printf("%d %d len:%d\n", devlist[id].requested_samprate , devlist[id].real_samprate,len); + + /* Diagnostic: print buffer usage + static int xxx=0; + if(++xxx >= 10000) + { + xxx = 0; + printf("Pluto->sndcard fifo usage: %d\n",io_fifo_usedspace(id)); + }*/ + + if (devlist[id].requested_samprate == devlist[id].real_samprate) + { + // sampling rate is ok, just play samples + for (int i = 0; i < len; i++) + { + io_write_fifo(id, psamp[i] * volume); + getMax(id, psamp[i] * volume); + } + return 0; + } + + // resampling is required + int newlen = 0; + + float *f = resample(id, psamp, len, &newlen); + for (int i = 0; i < newlen; i++) + { + io_write_fifo(id, f[i] * volume); + getMax(id, f[i] * volume); + } + + return 0; +} + +#define MCHECK 48000 // abt. 1s of samples +float farr[MAXDEVICES][MCHECK]; +int farridx[MAXDEVICES]; + +void init_maxarray() +{ + // initialize arrays + for (int md = 0; md < MAXDEVICES; md++) + { + farridx[md] = 0; + for (int i = 0; i < MCHECK; i++) + farr[md][i] = 0; + } +} + +void getMax(int id, float fv) +{ + // put value into array + farr[id][farridx[id]] = fv; + if (++farridx[id] == MCHECK) + farridx[id] = 0; +} + +/* +* returns the max level (within 1 second) of this stream in % (0..100) +* if the level >= 100 the signal will get clipped and distorted +*/ + +uint8_t kmaudio_maxlevel(int id) +{ + float max = 0; + for (int i = 0; i < MCHECK; i++) + if (farr[id][i] > max) max = farr[id][i]; + + return (uint8_t)(max * 100); +} + +void kmaudio_detectDropouts(int id) +{ + int stat = 0; + int drlen = 0; + + for (int i = 0; i < MCHECK; i++) + { + switch (stat) + { + case 0: // search beginning of dropout + if (farr[id][i] == 0.0f) + stat = 1; + break; + + case 1: // count length of dropout + if (farr[id][i] == 0.0f) drlen++; + else + { + // end of dropout + if (drlen > 0) + { + printf("Dropout len:%d\n", drlen); + } + drlen = 0; + stat = 0; + } + break; + } + } +} \ No newline at end of file diff --git a/libkmaudio/libkmaudio_interface.o b/libkmaudio/libkmaudio_interface.o new file mode 100644 index 0000000..f5dbe5f Binary files /dev/null and b/libkmaudio/libkmaudio_interface.o differ diff --git a/libkmaudio/libkmaudio_playback.cpp b/libkmaudio/libkmaudio_playback.cpp new file mode 100644 index 0000000..3d24d5f --- /dev/null +++ b/libkmaudio/libkmaudio_playback.cpp @@ -0,0 +1,173 @@ +/* +* Audio Library for Linux and Windows +* =================================== +* Author: DJ0ABR +* +* Author: Kurt Moraw, Ham radio: DJ0ABR, github: dj0abr +* License: GPL-3 +* +* compilation: +* Windows ... Visual Studio +* Linux ... make +* +* Documentation see: libkmaudio.h +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 2 of the License, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You 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. +* +* libkmaudio_playback.cpp ... +* starts a portaudio playback stream and a callback routine. Plays the +* audio samples coming via the fifo (Windows only) +*/ + +#include "libkmaudio.h" + +#define FRAMES_PER_BUFFER 512 + +int playCallback(const void* inputBuffer, + void* outputBuffer, + unsigned long framesPerBuffer, + const PaStreamCallbackTimeInfo* timeInfo, + PaStreamCallbackFlags statusFlags, + void* userData); + +void close_playback_stream(int idx) +{ + if (devlist[idx].pbStream != NULL) + { + Pa_CloseStream(devlist[idx].pbStream); + devlist[idx].pbStream = NULL; + } +} + +int kmaudio_startPlayback(char* devname, int samprate) +{ + printf("Start request for PB stream:%s\n", devname); + + if (devname == NULL || strlen(devname) < 3) // no devices defined yet + { + printf("no PB devices specified\n"); + return -1; + } + + int idx = searchDevice(devname, 1); + if (idx == -1) + { + printf("Playback Device:<%s> not found\n", devname); + return -1; + } + + devlist[idx].working = 0; + + close_playback_stream(idx); + + printf("Starting PB stream:%s [%d]\n", devname, idx); + + io_fifo_clear(idx); + + devlist[idx].requested_samprate = samprate; + if (getRealSamprate(idx) == -1) + { + printf("Samplerate %d not supported by device:<%s>\n", samprate, devname); + return -1; + } + + if (devlist[idx].requested_samprate != devlist[idx].real_samprate) + resampler_create(idx); + + struct PaWasapiStreamInfo wasapiInfo; + memset(&wasapiInfo, 0, sizeof(PaWasapiStreamInfo)); + wasapiInfo.size = sizeof(PaWasapiStreamInfo); + wasapiInfo.hostApiType = paWASAPI; + wasapiInfo.version = 1; + wasapiInfo.flags = (paWinWasapiExclusive | paWinWasapiThreadPriority); + wasapiInfo.threadPriority = eThreadPriorityProAudio; + + devlist[idx].outputParameters.hostApiSpecificStreamInfo = (&wasapiInfo); + + PaError e = Pa_IsFormatSupported(&devlist[idx].outputParameters, NULL, (double)devlist[idx].real_samprate); + printf("Playback : err:%d device:%d PAdev:%d samprate: %f chans:%d\n", e, idx, devlist[idx].devnum, (double)devlist[idx].real_samprate, devlist[idx].outputParameters.channelCount); + + devlist[idx].index = idx; + + int err = Pa_OpenStream( + &devlist[idx].pbStream, + NULL, + &devlist[idx].outputParameters, + (double)devlist[idx].real_samprate, + FRAMES_PER_BUFFER, + paClipOff, + playCallback, + &(devlist[idx].index)); + + if (err != paNoError) + { + printf("cannot open playback stream for device:<%s> %d\n", devname, err); + return -1; + } + + err = Pa_StartStream(devlist[idx].pbStream); + if (err != paNoError) + { + printf("cannot start playback stream for device:<%s>\n", devname); + return -1; + } + + printf("Playback started sucessfully\n"); + devlist[idx].working = 1; + return idx; +} + +int playCallback( const void* inputBuffer, + void* outputBuffer, + unsigned long framesPerBuffer, + const PaStreamCallbackTimeInfo* timeInfo, + PaStreamCallbackFlags statusFlags, + void* userData) +{ + int16_t* rptr = (int16_t*)outputBuffer; + int devidx = *((int*)userData); + int chans = devlist[devidx].outputParameters.channelCount; + + //measure_speed_bps(framesPerBuffer); + + int16_t f[FRAMES_PER_BUFFER]; + memset(f, 0, sizeof(int16_t) * FRAMES_PER_BUFFER); + unsigned int num = io_read_fifo_num_short(devidx, f, framesPerBuffer); + if (num < framesPerBuffer) + { + //printf("got %d from fifo, requested %d\n", num, framesPerBuffer); + } + int av = io_fifo_elems_avail(devidx); + + for (unsigned int i = 0; i < framesPerBuffer; i++) + { + if (chans == 1) rptr[i] = f[i]; + else + { + rptr[i * 2] = f[i]; + rptr[i * 2 + 1] = f[i]; + } + } + + // Prevent unused variable warnings + (void)inputBuffer; + (void)timeInfo; + (void)statusFlags; + + if (keeprunning == 1) + return paContinue; + + return paComplete; +} diff --git a/libkmaudio/libkmaudio_playback_linux.cpp b/libkmaudio/libkmaudio_playback_linux.cpp new file mode 100644 index 0000000..c301752 --- /dev/null +++ b/libkmaudio/libkmaudio_playback_linux.cpp @@ -0,0 +1,244 @@ +/* +* Audio Library for Linux and Windows +* =================================== +* Author: DJ0ABR +* +* Author: Kurt Moraw, Ham radio: DJ0ABR, github: dj0abr +* License: GPL-3 +* +* compilation: +* Windows ... Visual Studio +* Linux ... make +* +* Documentation see: libkmaudio.h +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 2 of the License, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You 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. +* +* libkmaudio_playback.cpp ... +* starts a libsoundio playback stream and a callback routine. Plays the +* audio samples coming via the fifo (Linux only) +*/ +#ifndef WIN32 + +#include "libkmaudio.h" + +// #define SINEWAVETEST + +#ifdef SINEWAVETEST +static const double PI = 3.14159265358979323846264338328; +static double seconds_offset = 0.0; +#endif + +void write_sample_float32ne(char* ptr, double sample) +{ + float* buf = (float*)ptr; + *buf = (float)sample; +} + +static void write_callback(struct SoundIoOutStream* outstream, int frame_count_min, int frame_count_max) +{ + if (outstream == NULL || soundio == NULL) return; + //printf("pb: %d %d\n", frame_count_min, frame_count_max); + //printf("pb :%d\n", outstream->sample_rate); + int idx = *((int*)(outstream->userdata)); + +#ifdef SINEWAVETEST + double float_sample_rate = outstream->sample_rate; + double seconds_per_frame = 1.0 / float_sample_rate; + double pitch = 440.0; + double radians_per_second = pitch * 2.0 * PI; +#endif + struct SoundIoChannelArea* areas; + int err; + + int frames_left = 4800; + if (frame_count_max < frames_left) + frames_left = frame_count_max; + + for (;;) { + int frame_count = frames_left; + if ((err = soundio_outstream_begin_write(outstream, &areas, &frame_count))) { + fprintf(stderr, "write_callback unrecoverable soundio_outstream_begin_write error: %s\n", soundio_strerror(err)); + return; + } + + if (!frame_count) + break; + + //printf("ck: %d read from fifo:%d\n", frame_count,idx); + if (frame_count >= 10000) + { + printf("frame count >= 1000: %d\n", frame_count); + exit(0); + } + + float f[10000]; + memset(f, 0, sizeof(float) * frame_count); + if (io_fifo_elems_avail(idx) >= frame_count) + { + // if fifo does not have enough data, don't take any + // this gives the fifo a chance to fill up a bit + io_read_fifo_num(idx, f, frame_count); + } + + //measure_speed_bps(frame_count); + + const struct SoundIoChannelLayout* layout = &outstream->layout; + + for (int frame = 0; frame < frame_count; frame += 1) + { +#ifdef SINEWAVETEST + double sample = sin((seconds_offset + frame * seconds_per_frame) * radians_per_second); +#endif + for (int channel = 0; channel < layout->channel_count; channel += 1) + { + float ftx = f[frame]; + //getTXMax(f[frame]); +#ifdef SINEWAVETEST + write_sample_float32ne(areas[channel].ptr, sample); // sine wave test tone +#endif + write_sample_float32ne(areas[channel].ptr, ftx); + areas[channel].ptr += areas[channel].step; + } + } +#ifdef SINEWAVETEST + seconds_offset = fmod(seconds_offset + seconds_per_frame * frame_count, 1.0); +#endif + + if ((err = soundio_outstream_end_write(outstream))) { + if (err == SoundIoErrorUnderflow) + return; + fprintf(stderr, "unrecoverable stream error: %s\n", soundio_strerror(err)); + return; + } + + frames_left -= frame_count; + if (frames_left <= 0) + break; + } +} + +void underflow_callback(struct SoundIoOutStream* outstream) +{ + static int count = 0; + printf("audio output underflow %d\n", count++); +} + +void close_playback_stream(int idx) +{ + if (devlist[idx].outstream != NULL) + { + soundio_outstream_destroy(devlist[idx].outstream); + devlist[idx].outstream = NULL; + } +} + +int kmaudio_startPlayback(char* devname, int samprate) +{ + printf("Start request for PB stream:%s\n", devname); + + if (devname == NULL || strlen(devname) < 3) // no devices defined yet + { + printf("no PB devices specified\n"); + return -1; + } + + int idx = 0; // index into devlist + char* pbdevid = getDevID(devname, 1, &idx); + if (pbdevid == NULL) + { + printf("PB: Device ID not found\n"); + return -1; + } + + close_playback_stream(idx); + + printf("Starting PB stream:%s [%d]\n", devname, idx); + + io_fifo_clear(idx); + + devlist[idx].working = 0; + + // define the capture device + soundio_flush_events(soundio); + + for (int i = 0; i < soundio_output_device_count(soundio); i++) + { + devlist[idx].io_pb_device = NULL; + struct SoundIoDevice* device = soundio_get_output_device(soundio, i); + if (strcmp(device->id, pbdevid) == 0) + { + devlist[idx].io_pb_device = device; + break; + } + soundio_device_unref(device); + } + if (!devlist[idx].io_pb_device) + { + printf("Invalid device id: %s\n", pbdevid); + return -1; + } + + if (devlist[idx].io_pb_device->probe_error) + { + printf("Unable to probe device: %s\n", soundio_strerror(devlist[idx].io_pb_device->probe_error)); + return -1; + } + + // create playback callback + devlist[idx].outstream = soundio_outstream_create(devlist[idx].io_pb_device); + if (!devlist[idx].outstream) { + printf("soundio_outstream_create: out of memory\n"); + return 0; + } + + devlist[idx].requested_samprate = samprate; + if (getRealSamprate(idx) == -1) + { + printf("Samplerate %d not supported by device:<%s>\n", samprate, devname); + return -1; + } + + //printf("requested SR:%d, real SR:%d\n",devlist[idx].requested_samprate, devlist[idx].real_samprate); + if (devlist[idx].requested_samprate != devlist[idx].real_samprate) + resampler_create(idx); + + devlist[idx].outstream->format = SoundIoFormatFloat32NE; + devlist[idx].outstream->sample_rate = devlist[idx].real_samprate; + devlist[idx].outstream->software_latency = 0.1f; + devlist[idx].outstream->write_callback = write_callback; + devlist[idx].outstream->underflow_callback = underflow_callback; + devlist[idx].outstream->userdata = &(devlist[idx].index); + + int err = 0; + if ((err = soundio_outstream_open(devlist[idx].outstream))) { + printf("unable to open output stream: %s", soundio_strerror(err)); + return -1; + } + + if ((err = soundio_outstream_start(devlist[idx].outstream))) { + printf("unable to start output device: %s", soundio_strerror(err)); + return -1; + } + + printf("selected PLAYBACK device:\nname:%s\nid :%s\n", devname, pbdevid); + printf("physical playback rate:%d, requested capture rate:%d\n", devlist[idx].real_samprate, devlist[idx].requested_samprate); + printf("format: %s\n\n", soundio_format_string(devlist[idx].outstream->format)); + + devlist[idx].working = 1; + return idx; +} + +#endif // ndef WIN32 diff --git a/libkmaudio/libkmaudio_playback_linux.o b/libkmaudio/libkmaudio_playback_linux.o new file mode 100644 index 0000000..97c3a26 Binary files /dev/null and b/libkmaudio/libkmaudio_playback_linux.o differ diff --git a/libkmaudio/libkmaudio_resampler.cpp b/libkmaudio/libkmaudio_resampler.cpp new file mode 100644 index 0000000..a99c1ba --- /dev/null +++ b/libkmaudio/libkmaudio_resampler.cpp @@ -0,0 +1,111 @@ +/* +* Audio Library for Linux and Windows +* =================================== +* Author: DJ0ABR +* +* Author: Kurt Moraw, Ham radio: DJ0ABR, github: dj0abr +* License: GPL-3 +* +* compilation: +* Windows ... Visual Studio +* Linux ... make +* +* Documentation see: libkmaudio.h +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 2 of the License, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You 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. +* +* libkmaudio_resampler.cpp ... converts audio streams +* between 44100 and 48000 samples/s in both directions +* uses the libliquid library +*/ +#include "libkmaudio.h" + +#define MAXRLEN 10000 + +resamp_crcf q[MAXDEVICES]; +float fresamp[MAXDEVICES][MAXRLEN]; + +unsigned int h_len = 13; // filter semi-length (filter delay) +float r = 0.9f; // resampling rate (output/input) +float bw = 0.45f; // resampling filter bandwidth +float slsl = 60.0f; // resampling filter sidelobe suppression level +unsigned int npfb = 32; // number of filters in bank (timing resolution) + +void resampler_create(int devidx) +{ + static int f = 1; + if(f) + { + f = 0; + for (int i = 0; i < MAXDEVICES; i++) + q[i] = NULL; + } + + printf("create resampler %d real %d req %d\n", devidx, devlist[devidx].real_samprate, devlist[devidx].requested_samprate); + + if (q[devidx] != NULL) resamp_crcf_destroy(q[devidx]); + + int src_rate = 0; + int dst_rate = 0; + if (devlist[devidx].in_out == 0) + { + // capture device: + src_rate = devlist[devidx].real_samprate; + dst_rate = devlist[devidx].requested_samprate; + } + else + { + // playback device: + src_rate = devlist[devidx].requested_samprate; + dst_rate = devlist[devidx].real_samprate; + } + + r = (float)dst_rate / (float)src_rate; + + //printf("%f %f %f\n", r, (float)dst_rate, (float)src_rate); + + q[devidx] = resamp_crcf_create(r, h_len, bw, slsl, npfb); +} + + + +float* resample(int id, float*psamp, int len, int *pnewlen) +{ + int didx = 0; + + for (int i = 0; i < len; i++) + { + unsigned int num_written = 0; + liquid_float_complex in; + liquid_float_complex out[10]; + in.real = psamp[i]; + in.imag = 0; + + + resamp_crcf_execute(q[id], in, out, &num_written); + + for (unsigned int r = 0; r < num_written; r++) + { + if (didx < MAXRLEN) + fresamp[id][didx++] = out[r].real; + else + printf("MAXRLEN too small\n"); + } + } + + *pnewlen = didx; + + return fresamp[id]; +} diff --git a/libkmaudio/libkmaudio_resampler.o b/libkmaudio/libkmaudio_resampler.o new file mode 100644 index 0000000..e6ce274 Binary files /dev/null and b/libkmaudio/libkmaudio_resampler.o differ diff --git a/libkmaudio/libliquid.lib b/libkmaudio/libliquid.lib new file mode 100644 index 0000000..ab1122c Binary files /dev/null and b/libkmaudio/libliquid.lib differ diff --git a/libkmaudio/liquid.h b/libkmaudio/liquid.h new file mode 100644 index 0000000..1bb3061 --- /dev/null +++ b/libkmaudio/liquid.h @@ -0,0 +1,8823 @@ +/* + * Copyright (c) 2007 - 2020 Joseph Gaeddert + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#ifndef __LIQUID_H__ +#define __LIQUID_H__ + +#ifdef __cplusplus +extern "C" { +# define LIQUID_USE_COMPLEX_H 0 +#else +# define LIQUID_USE_COMPLEX_H 1 +#endif // __cplusplus + +// common headers +#include + +// +// Make sure the version and version number macros weren't defined by +// some prevoiusly included header file. +// +#ifdef LIQUID_VERSION +# undef LIQUID_VERSION +#endif +#ifdef LIQUID_VERSION_NUMBER +# undef LIQUID_VERSION_NUMBER +#endif + +// +// Compile-time version numbers +// +// LIQUID_VERSION = "X.Y.Z" +// LIQUID_VERSION_NUMBER = (X*1000000 + Y*1000 + Z) +// +#define LIQUID_VERSION "1.3.2" +#define LIQUID_VERSION_NUMBER 1003002 + +// +// Run-time library version numbers +// +extern const char liquid_version[]; +const char * liquid_libversion(void); +int liquid_libversion_number(void); + +// run-time library validation +#define LIQUID_VALIDATE_LIBVERSION \ + if (LIQUID_VERSION_NUMBER != liquid_libversion_number()) { \ + fprintf(stderr,"%s:%u: ", __FILE__,__LINE__); \ + fprintf(stderr,"error: invalid liquid runtime library\n"); \ + exit(1); \ + } \ + +// basic error types +#define LIQUID_NUM_ERRORS 12 +typedef enum { + // everything ok + LIQUID_OK=0, + + // internal logic error; this is a bug with liquid and should be reported immediately + LIQUID_EINT, + + // invalid object, examples: + // - destroy() method called on NULL pointer + LIQUID_EIOBJ, + + // invalid parameter, or configuration; examples: + // - setting bandwidth of a filter to a negative number + // - setting FFT size to zero + // - create a spectral periodogram object with window size greater than nfft + LIQUID_EICONFIG, + + // input out of range; examples: + // - try to take log of -1 + // - try to create an FFT plan of size zero + LIQUID_EIVAL, + + // invalid vector length or dimension; examples + // - trying to refer to the 17th element of a 2 x 2 matrix + // - trying to multiply two matrices of incompatible dimensions + LIQUID_EIRANGE, + + // invalid mode; examples: + // - try to create a modem of type 'LIQUID_MODEM_XXX' which does not exit + LIQUID_EIMODE, + + // unsupported mode (e.g. LIQUID_FEC_CONV_V27 with 'libfec' not installed) + LIQUID_EUMODE, + + // object has not been created or properly initialized + // - try to run firfilt_crcf_execute(NULL, ...) + // - try to modulate using an arbitrary modem without initializing the constellation + LIQUID_ENOINIT, + + // not enough memory allocated for operation; examples: + // - try to factor 100 = 2*2*5*5 but only give 3 spaces for factors + LIQUID_EIMEM, + + // file input/output; examples: + // - could not open a file for writing because of insufficient permissions + // - could not open a file for reading because it does not exist + // - try to read more data than a file has space for + // - could not parse line in file (improper formatting) + LIQUID_EIO, + +} liquid_error_code; + +// error descriptions +extern const char * liquid_error_str[LIQUID_NUM_ERRORS]; +const char * liquid_error_info(liquid_error_code _code); + +#define LIQUID_CONCAT(prefix, name) prefix ## name +#define LIQUID_VALIDATE_INPUT + +/* + * Compile-time complex data type definitions + * + * Default: use the C99 complex data type, otherwise + * define complex type compatible with the C++ complex standard, + * otherwise resort to defining binary compatible array. + */ +#if LIQUID_USE_COMPLEX_H==1 +# include +# define LIQUID_DEFINE_COMPLEX(R,C) typedef R _Complex C +#elif defined _GLIBCXX_COMPLEX || defined _LIBCPP_COMPLEX +# define LIQUID_DEFINE_COMPLEX(R,C) typedef std::complex C +#else +# define LIQUID_DEFINE_COMPLEX(R,C) typedef struct {R real; R imag;} C; +#endif +//# define LIQUID_DEFINE_COMPLEX(R,C) typedef R C[2] + +LIQUID_DEFINE_COMPLEX(float, liquid_float_complex); +LIQUID_DEFINE_COMPLEX(double, liquid_double_complex); + +// +// MODULE : agc (automatic gain control) +// + +// available squelch modes +typedef enum { + LIQUID_AGC_SQUELCH_UNKNOWN=0, // unknown/unavailable squelch mode + LIQUID_AGC_SQUELCH_ENABLED, // squelch enabled but signal not detected + LIQUID_AGC_SQUELCH_RISE, // signal first hit/exceeded threshold + LIQUID_AGC_SQUELCH_SIGNALHI, // signal level high (above threshold) + LIQUID_AGC_SQUELCH_FALL, // signal first dropped below threshold + LIQUID_AGC_SQUELCH_SIGNALLO, // signal level low (below threshold) + LIQUID_AGC_SQUELCH_TIMEOUT, // signal level low (below threshold for a certain time) + LIQUID_AGC_SQUELCH_DISABLED, // squelch not enabled +} agc_squelch_mode; + +#define LIQUID_AGC_MANGLE_CRCF(name) LIQUID_CONCAT(agc_crcf, name) +#define LIQUID_AGC_MANGLE_RRRF(name) LIQUID_CONCAT(agc_rrrf, name) + +// large macro +// AGC : name-mangling macro +// T : primitive data type +// TC : input/output data type +#define LIQUID_AGC_DEFINE_API(AGC,T,TC) \ + \ +/* Automatic gain control (agc) for level correction and signal */ \ +/* detection */ \ +typedef struct AGC(_s) * AGC(); \ + \ +/* Create automatic gain control object. */ \ +AGC() AGC(_create)(void); \ + \ +/* Destroy object, freeing all internally-allocated memory. */ \ +int AGC(_destroy)(AGC() _q); \ + \ +/* Print object properties to stdout, including received signal */ \ +/* strength indication (RSSI), loop bandwidth, lock status, and squelch */ \ +/* status. */ \ +int AGC(_print)(AGC() _q); \ + \ +/* Reset internal state of agc object, including gain estimate, input */ \ +/* signal level estimate, lock status, and squelch mode */ \ +/* If the squelch mode is disabled, it stays disabled, but all enabled */ \ +/* modes (e.g. LIQUID_AGC_SQUELCH_TIMEOUT) resets to just */ \ +/* LIQUID_AGC_SQUELCH_ENABLED. */ \ +int AGC(_reset)(AGC() _q); \ + \ +/* Execute automatic gain control on an single input sample */ \ +/* _q : automatic gain control object */ \ +/* _x : input sample */ \ +/* _y : output sample */ \ +int AGC(_execute)(AGC() _q, \ + TC _x, \ + TC * _y); \ + \ +/* Execute automatic gain control on block of samples pointed to by _x */ \ +/* and store the result in the array of the same length _y. */ \ +/* _q : automatic gain control object */ \ +/* _x : input data array, [size: _n x 1] */ \ +/* _n : number of input, output samples */ \ +/* _y : output data array, [size: _n x 1] */ \ +int AGC(_execute_block)(AGC() _q, \ + TC * _x, \ + unsigned int _n, \ + TC * _y); \ + \ +/* Lock agc object. When locked, the agc object still makes an estimate */ \ +/* of the signal level, but the gain setting is fixed and does not */ \ +/* change. */ \ +/* This is useful for providing coarse input signal level correction */ \ +/* and quickly detecting a packet burst but not distorting signals with */ \ +/* amplitude variation due to modulation. */ \ +int AGC(_lock)(AGC() _q); \ + \ +/* Unlock agc object, and allow amplitude correction to resume. */ \ +int AGC(_unlock)(AGC() _q); \ + \ +/* Set loop filter bandwidth: attack/release time. */ \ +/* _q : automatic gain control object */ \ +/* _bt : bandwidth-time constant, _bt > 0 */ \ +int AGC(_set_bandwidth)(AGC() _q, float _bt); \ + \ +/* Get the agc object's loop filter bandwidth. */ \ +float AGC(_get_bandwidth)(AGC() _q); \ + \ +/* Get the input signal's estimated energy level, relative to unity. */ \ +/* The result is a linear value. */ \ +float AGC(_get_signal_level)(AGC() _q); \ + \ +/* Set the agc object's estimate of the input signal by specifying an */ \ +/* explicit linear value. This is useful for initializing the agc */ \ +/* object with a preliminary estimate of the signal level to help gain */ \ +/* convergence. */ \ +/* _q : automatic gain control object */ \ +/* _x2 : signal level of input, _x2 > 0 */ \ +int AGC(_set_signal_level)(AGC() _q, \ + float _x2); \ + \ +/* Get the agc object's estimated received signal strength indication */ \ +/* (RSSI) on the input signal. */ \ +/* This is similar to getting the signal level (above), but returns the */ \ +/* result in dB rather than on a linear scale. */ \ +float AGC(_get_rssi)(AGC() _q); \ + \ +/* Set the agc object's estimated received signal strength indication */ \ +/* (RSSI) on the input signal by specifying an explicit value in dB. */ \ +/* _q : automatic gain control object */ \ +/* _rssi : signal level of input [dB] */ \ +int AGC(_set_rssi)(AGC() _q, float _rssi); \ + \ +/* Get the gain value currently being applied to the input signal */ \ +/* (linear). */ \ +float AGC(_get_gain)(AGC() _q); \ + \ +/* Set the agc object's internal gain by specifying an explicit linear */ \ +/* value. */ \ +/* _q : automatic gain control object */ \ +/* _gain : gain to apply to input signal, _gain > 0 */ \ +int AGC(_set_gain)(AGC() _q, \ + float _gain); \ + \ +/* Get the ouput scaling applied to each sample (linear). */ \ +float AGC(_get_scale)(AGC() _q); \ + \ +/* Set the agc object's output scaling (linear). Note that this does */ \ +/* affect the response of the AGC. */ \ +/* _q : automatic gain control object */ \ +/* _gain : gain to apply to input signal, _gain > 0 */ \ +int AGC(_set_scale)(AGC() _q, \ + float _scale); \ + \ +/* Estimate signal level and initialize internal gain on an input */ \ +/* array. */ \ +/* _q : automatic gain control object */ \ +/* _x : input data array, [size: _n x 1] */ \ +/* _n : number of input, output samples */ \ +int AGC(_init)(AGC() _q, \ + TC * _x, \ + unsigned int _n); \ + \ +/* Enable squelch mode. */ \ +int AGC(_squelch_enable)(AGC() _q); \ + \ +/* Disable squelch mode. */ \ +int AGC(_squelch_disable)(AGC() _q); \ + \ +/* Return flag indicating if squelch is enabled or not. */ \ +int AGC(_squelch_is_enabled)(AGC() _q); \ + \ +/* Set threshold for enabling/disabling squelch. */ \ +/* _q : automatic gain control object */ \ +/* _thresh : threshold for enabling squelch [dB] */ \ +int AGC(_squelch_set_threshold)(AGC() _q, \ + T _thresh); \ + \ +/* Get squelch threshold (value in dB) */ \ +T AGC(_squelch_get_threshold)(AGC() _q); \ + \ +/* Set timeout before enabling squelch. */ \ +/* _q : automatic gain control object */ \ +/* _timeout : timeout before enabling squelch [samples] */ \ +int AGC(_squelch_set_timeout)(AGC() _q, \ + unsigned int _timeout); \ + \ +/* Get squelch timeout (number of samples) */ \ +unsigned int AGC(_squelch_get_timeout)(AGC() _q); \ + \ +/* Get squelch status (e.g. LIQUID_AGC_SQUELCH_TIMEOUT) */ \ +int AGC(_squelch_get_status)(AGC() _q); \ + +// Define agc APIs +LIQUID_AGC_DEFINE_API(LIQUID_AGC_MANGLE_CRCF, float, liquid_float_complex) +LIQUID_AGC_DEFINE_API(LIQUID_AGC_MANGLE_RRRF, float, float) + + + +// +// MODULE : audio +// + +// CVSD: continuously variable slope delta +typedef struct cvsd_s * cvsd; + +// create cvsd object +// _num_bits : number of adjacent bits to observe (4 recommended) +// _zeta : slope adjustment multiplier (1.5 recommended) +// _alpha : pre-/post-emphasis filter coefficient (0.9 recommended) +// NOTE: _alpha must be in [0,1] +cvsd cvsd_create(unsigned int _num_bits, + float _zeta, + float _alpha); + +// destroy cvsd object +void cvsd_destroy(cvsd _q); + +// print cvsd object parameters +void cvsd_print(cvsd _q); + +// encode/decode single sample +unsigned char cvsd_encode(cvsd _q, float _audio_sample); +float cvsd_decode(cvsd _q, unsigned char _bit); + +// encode/decode 8 samples at a time +void cvsd_encode8(cvsd _q, float * _audio, unsigned char * _data); +void cvsd_decode8(cvsd _q, unsigned char _data, float * _audio); + + +// +// MODULE : buffer +// + +// circular buffer +#define LIQUID_CBUFFER_MANGLE_FLOAT(name) LIQUID_CONCAT(cbufferf, name) +#define LIQUID_CBUFFER_MANGLE_CFLOAT(name) LIQUID_CONCAT(cbuffercf, name) + +// large macro +// CBUFFER : name-mangling macro +// T : data type +#define LIQUID_CBUFFER_DEFINE_API(CBUFFER,T) \ + \ +/* Circular buffer object for storing and retrieving samples in a */ \ +/* first-in/first-out (FIFO) manner using a minimal amount of memory */ \ +typedef struct CBUFFER(_s) * CBUFFER(); \ + \ +/* Create circular buffer object of a particular maximum storage length */ \ +/* _max_size : maximum buffer size, _max_size > 0 */ \ +CBUFFER() CBUFFER(_create)(unsigned int _max_size); \ + \ +/* Create circular buffer object of a particular maximum storage size */ \ +/* and specify the maximum number of elements that can be read at any */ \ +/* any given time */ \ +/* _max_size : maximum buffer size, _max_size > 0 */ \ +/* _max_read : maximum size that will be read from buffer */ \ +CBUFFER() CBUFFER(_create_max)(unsigned int _max_size, \ + unsigned int _max_read); \ + \ +/* Destroy cbuffer object, freeing all internal memory */ \ +void CBUFFER(_destroy)(CBUFFER() _q); \ + \ +/* Print cbuffer object properties to stdout */ \ +void CBUFFER(_print)(CBUFFER() _q); \ + \ +/* Print cbuffer object properties and internal state */ \ +void CBUFFER(_debug_print)(CBUFFER() _q); \ + \ +/* Clear internal buffer */ \ +void CBUFFER(_reset)(CBUFFER() _q); \ + \ +/* Get the number of elements currently in the buffer */ \ +unsigned int CBUFFER(_size)(CBUFFER() _q); \ + \ +/* Get the maximum number of elements the buffer can hold */ \ +unsigned int CBUFFER(_max_size)(CBUFFER() _q); \ + \ +/* Get the maximum number of elements you may read at once */ \ +unsigned int CBUFFER(_max_read)(CBUFFER() _q); \ + \ +/* Get the number of available slots (max_size - size) */ \ +unsigned int CBUFFER(_space_available)(CBUFFER() _q); \ + \ +/* Return flag indicating if the buffer is full or not */ \ +int CBUFFER(_is_full)(CBUFFER() _q); \ + \ +/* Write a single sample into the buffer */ \ +/* _q : circular buffer object */ \ +/* _v : input sample */ \ +void CBUFFER(_push)(CBUFFER() _q, \ + T _v); \ + \ +/* Write a block of samples to the buffer */ \ +/* _q : circular buffer object */ \ +/* _v : array of samples to write to buffer */ \ +/* _n : number of samples to write */ \ +void CBUFFER(_write)(CBUFFER() _q, \ + T * _v, \ + unsigned int _n); \ + \ +/* Remove and return a single element from the buffer by setting the */ \ +/* value of the output sample pointed to by _v */ \ +/* _q : circular buffer object */ \ +/* _v : pointer to sample output */ \ +void CBUFFER(_pop)(CBUFFER() _q, \ + T * _v); \ + \ +/* Read buffer contents by returning a pointer to the linearized array; */ \ +/* note that the returned pointer is only valid until another operation */ \ +/* is performed on the circular buffer object */ \ +/* _q : circular buffer object */ \ +/* _num_requested : number of elements requested */ \ +/* _v : output pointer */ \ +/* _num_read : number of elements referenced by _v */ \ +void CBUFFER(_read)(CBUFFER() _q, \ + unsigned int _num_requested, \ + T ** _v, \ + unsigned int * _num_read); \ + \ +/* Release _n samples from the buffer */ \ +/* _q : circular buffer object */ \ +/* _n : number of elements to release */ \ +void CBUFFER(_release)(CBUFFER() _q, \ + unsigned int _n); \ + +// Define buffer APIs +LIQUID_CBUFFER_DEFINE_API(LIQUID_CBUFFER_MANGLE_FLOAT, float) +LIQUID_CBUFFER_DEFINE_API(LIQUID_CBUFFER_MANGLE_CFLOAT, liquid_float_complex) + + + +// Windowing functions +#define LIQUID_WINDOW_MANGLE_FLOAT(name) LIQUID_CONCAT(windowf, name) +#define LIQUID_WINDOW_MANGLE_CFLOAT(name) LIQUID_CONCAT(windowcf, name) + +// large macro +// WINDOW : name-mangling macro +// T : data type +#define LIQUID_WINDOW_DEFINE_API(WINDOW,T) \ + \ +/* Sliding window first-in/first-out buffer with a fixed size */ \ +typedef struct WINDOW(_s) * WINDOW(); \ + \ +/* Create window buffer object of a fixed length */ \ +WINDOW() WINDOW(_create)(unsigned int _n); \ + \ +/* Recreate window buffer object with new length. */ \ +/* This extends an existing window's size, similar to the standard C */ \ +/* library's realloc() to n samples. */ \ +/* If the size of the new window is larger than the old one, the newest */ \ +/* values are retained at the beginning of the buffer and the oldest */ \ +/* values are truncated. If the size of the new window is smaller than */ \ +/* the old one, the oldest values are truncated. */ \ +/* _q : old window object */ \ +/* _n : new window length */ \ +WINDOW() WINDOW(_recreate)(WINDOW() _q, unsigned int _n); \ + \ +/* Destroy window object, freeing all internally memory */ \ +int WINDOW(_destroy)(WINDOW() _q); \ + \ +/* Print window object to stdout */ \ +int WINDOW(_print)(WINDOW() _q); \ + \ +/* Print window object to stdout (with extra information) */ \ +int WINDOW(_debug_print)(WINDOW() _q); \ + \ +/* Reset window object (initialize to zeros) */ \ +int WINDOW(_reset)(WINDOW() _q); \ + \ +/* Read the contents of the window by returning a pointer to the */ \ +/* aligned internal memory array. This method guarantees that the */ \ +/* elements are linearized. This method should only be used for */ \ +/* reading; writing values to the buffer has unspecified results. */ \ +/* Note that the returned pointer is only valid until another operation */ \ +/* is performed on the window buffer object */ \ +/* _q : window object */ \ +/* _v : output pointer (set to internal array) */ \ +int WINDOW(_read)(WINDOW() _q, \ + T ** _v); \ + \ +/* Index single element in buffer at a particular index */ \ +/* This retrieves the \(i^{th}\) sample in the window, storing the */ \ +/* output value in _v. */ \ +/* This is equivalent to first invoking read() and then indexing on the */ \ +/* resulting pointer; however the result is obtained much faster. */ \ +/* Therefore setting the index to 0 returns the oldest value in the */ \ +/* window. */ \ +/* _q : window object */ \ +/* _i : index of element to read */ \ +/* _v : output value pointer */ \ +int WINDOW(_index)(WINDOW() _q, \ + unsigned int _i, \ + T * _v); \ + \ +/* Shifts a single sample into the right side of the window, pushing */ \ +/* the oldest (left-most) sample out of the end. Unlike stacks, the */ \ +/* window object has no equivalent "pop" method, as values are retained */ \ +/* in memory until they are overwritten. */ \ +/* _q : window object */ \ +/* _v : single input element */ \ +int WINDOW(_push)(WINDOW() _q, \ + T _v); \ + \ +/* Write array of elements onto window buffer */ \ +/* Effectively, this is equivalent to pushing each sample one at a */ \ +/* time, but executes much faster. */ \ +/* _q : window object */ \ +/* _v : input array of values to write */ \ +/* _n : number of input values to write */ \ +int WINDOW(_write)(WINDOW() _q, \ + T * _v, \ + unsigned int _n); \ + +// Define window APIs +LIQUID_WINDOW_DEFINE_API(LIQUID_WINDOW_MANGLE_FLOAT, float) +LIQUID_WINDOW_DEFINE_API(LIQUID_WINDOW_MANGLE_CFLOAT, liquid_float_complex) +//LIQUID_WINDOW_DEFINE_API(LIQUID_WINDOW_MANGLE_UINT, unsigned int) + + +// wdelay functions : windowed-delay +// Implements an efficient z^-k delay with minimal memory +#define LIQUID_WDELAY_MANGLE_FLOAT(name) LIQUID_CONCAT(wdelayf, name) +#define LIQUID_WDELAY_MANGLE_CFLOAT(name) LIQUID_CONCAT(wdelaycf, name) +//#define LIQUID_WDELAY_MANGLE_UINT(name) LIQUID_CONCAT(wdelayui, name) + +// large macro +// WDELAY : name-mangling macro +// T : data type +#define LIQUID_WDELAY_DEFINE_API(WDELAY,T) \ + \ +/* Efficient digital delay line using a minimal amount of memory */ \ +typedef struct WDELAY(_s) * WDELAY(); \ + \ +/* Create delay buffer object with a particular number of samples of */ \ +/* delay */ \ +/* _delay : number of samples of delay in the wdelay object */ \ +WDELAY() WDELAY(_create)(unsigned int _delay); \ + \ +/* Re-create delay buffer object, adjusting the delay size, preserving */ \ +/* the internal state of the object */ \ +/* _q : old delay buffer object */ \ +/* _delay : delay for new object */ \ +WDELAY() WDELAY(_recreate)(WDELAY() _q, \ + unsigned int _delay); \ + \ +/* Destroy delay buffer object, freeing internal memory */ \ +void WDELAY(_destroy)(WDELAY() _q); \ + \ +/* Print delay buffer object's state to stdout */ \ +void WDELAY(_print)(WDELAY() _q); \ + \ +/* Clear/reset state of object */ \ +void WDELAY(_reset)(WDELAY() _q); \ + \ +/* Read delayed sample at the head of the buffer and store it to the */ \ +/* output pointer */ \ +/* _q : delay buffer object */ \ +/* _v : value of delayed element */ \ +void WDELAY(_read)(WDELAY() _q, \ + T * _v); \ + \ +/* Push new sample into delay buffer object */ \ +/* _q : delay buffer object */ \ +/* _v : new value to be added to buffer */ \ +void WDELAY(_push)(WDELAY() _q, \ + T _v); \ + +// Define wdelay APIs +LIQUID_WDELAY_DEFINE_API(LIQUID_WDELAY_MANGLE_FLOAT, float) +LIQUID_WDELAY_DEFINE_API(LIQUID_WDELAY_MANGLE_CFLOAT, liquid_float_complex) +//LIQUID_WDELAY_DEFINE_API(LIQUID_WDELAY_MANGLE_UINT, unsigned int) + + + +// +// MODULE : channel +// + +#define LIQUID_CHANNEL_MANGLE_CCCF(name) LIQUID_CONCAT(channel_cccf,name) + +// large macro +// CHANNEL : name-mangling macro +// TO : output data type +// TC : coefficients data type +// TI : input data type +#define LIQUID_CHANNEL_DEFINE_API(CHANNEL,TO,TC,TI) \ + \ +/* Channel emulation */ \ +typedef struct CHANNEL(_s) * CHANNEL(); \ + \ +/* Create channel object with default parameters */ \ +CHANNEL() CHANNEL(_create)(void); \ + \ +/* Destroy channel object, freeing all internal memory */ \ +int CHANNEL(_destroy)(CHANNEL() _q); \ + \ +/* Print channel object internals to standard output */ \ +int CHANNEL(_print)(CHANNEL() _q); \ + \ +/* Include additive white Gausss noise impairment */ \ +/* _q : channel object */ \ +/* _N0dB : noise floor power spectral density [dB] */ \ +/* _SNRdB : signal-to-noise ratio [dB] */ \ +int CHANNEL(_add_awgn)(CHANNEL() _q, \ + float _N0dB, \ + float _SNRdB); \ + \ +/* Include carrier offset impairment */ \ +/* _q : channel object */ \ +/* _frequency : carrier frequency offset [radians/sample] */ \ +/* _phase : carrier phase offset [radians] */ \ +int CHANNEL(_add_carrier_offset)(CHANNEL() _q, \ + float _frequency, \ + float _phase); \ + \ +/* Include multi-path channel impairment */ \ +/* _q : channel object */ \ +/* _h : channel coefficients (NULL for random) */ \ +/* _h_len : number of channel coefficients */ \ +int CHANNEL(_add_multipath)(CHANNEL() _q, \ + TC * _h, \ + unsigned int _h_len); \ + \ +/* Include slowly-varying shadowing impairment */ \ +/* _q : channel object */ \ +/* _sigma : standard deviation for log-normal shadowing */ \ +/* _fd : Doppler frequency, 0 <= _fd < 0.5 */ \ +int CHANNEL(_add_shadowing)(CHANNEL() _q, \ + float _sigma, \ + float _fd); \ + \ +/* Apply channel impairments on single input sample */ \ +/* _q : channel object */ \ +/* _x : input sample */ \ +/* _y : pointer to output sample */ \ +int CHANNEL(_execute)(CHANNEL() _q, \ + TI _x, \ + TO * _y); \ + \ +/* Apply channel impairments on block of samples */ \ +/* _q : channel object */ \ +/* _x : input array, [size: _n x 1] */ \ +/* _n : input array, length */ \ +/* _y : output array, [size: _n x 1] */ \ +int CHANNEL(_execute_block)(CHANNEL() _q, \ + TI * _x, \ + unsigned int _n, \ + TO * _y); \ + +LIQUID_CHANNEL_DEFINE_API(LIQUID_CHANNEL_MANGLE_CCCF, + liquid_float_complex, + liquid_float_complex, + liquid_float_complex) + + +// +// time-varying multi-path channel +// +#define LIQUID_TVMPCH_MANGLE_CCCF(name) LIQUID_CONCAT(tvmpch_cccf,name) + +// large macro +// TVMPCH : name-mangling macro +// TO : output data type +// TC : coefficients data type +// TI : input data type +#define LIQUID_TVMPCH_DEFINE_API(TVMPCH,TO,TC,TI) \ + \ +/* Time-varying multipath channel emulation */ \ +typedef struct TVMPCH(_s) * TVMPCH(); \ + \ +/* Create time-varying multi-path channel emulator object, specifying */ \ +/* the number of coefficients, the standard deviation of coefficients, */ \ +/* and the coherence time. The larger the standard deviation, the more */ \ +/* dramatic the frequency response of the channel. The shorter the */ \ +/* coeherent time, the faster the channel effects. */ \ +/* _n : number of coefficients, _n > 0 */ \ +/* _std : standard deviation, _std >= 0 */ \ +/* _tau : normalized coherence time, 0 < _tau < 1 */ \ +TVMPCH() TVMPCH(_create)(unsigned int _n, \ + float _std, \ + float _tau); \ + \ +/* Destroy channel object, freeing all internal memory */ \ +int TVMPCH(_destroy)(TVMPCH() _q); \ + \ +/* Reset object */ \ +int TVMPCH(_reset)(TVMPCH() _q); \ + \ +/* Print channel object internals to standard output */ \ +int TVMPCH(_print)(TVMPCH() _q); \ + \ +/* Push sample into emulator */ \ +/* _q : channel object */ \ +/* _x : input sample */ \ +int TVMPCH(_push)(TVMPCH() _q, \ + TI _x); \ + \ +/* Compute output sample */ \ +/* _q : channel object */ \ +/* _y : output sample */ \ +int TVMPCH(_execute)(TVMPCH() _q, \ + TO * _y); \ + \ +/* Apply channel impairments on a block of samples */ \ +/* _q : channel object */ \ +/* _x : input array, [size: _n x 1] */ \ +/* _n : input array length */ \ +/* _y : output array, [size: _n x 1] */ \ +int TVMPCH(_execute_block)(TVMPCH() _q, \ + TI * _x, \ + unsigned int _n, \ + TO * _y); \ + +LIQUID_TVMPCH_DEFINE_API(LIQUID_TVMPCH_MANGLE_CCCF, + liquid_float_complex, + liquid_float_complex, + liquid_float_complex) + + +// +// MODULE : dotprod (vector dot product) +// + +#define LIQUID_DOTPROD_MANGLE_RRRF(name) LIQUID_CONCAT(dotprod_rrrf,name) +#define LIQUID_DOTPROD_MANGLE_CCCF(name) LIQUID_CONCAT(dotprod_cccf,name) +#define LIQUID_DOTPROD_MANGLE_CRCF(name) LIQUID_CONCAT(dotprod_crcf,name) + +// large macro +// DOTPROD : name-mangling macro +// TO : output data type +// TC : coefficients data type +// TI : input data type +#define LIQUID_DOTPROD_DEFINE_API(DOTPROD,TO,TC,TI) \ + \ +/* Vector dot product operation */ \ +typedef struct DOTPROD(_s) * DOTPROD(); \ + \ +/* Run dot product without creating object. This is less efficient than */ \ +/* creating the object as it is an unoptimized portable implementation */ \ +/* that doesn't take advantage of processor extensions. It is meant to */ \ +/* provide a baseline for performance comparison and a convenient way */ \ +/* to invoke a dot product operation when fast operation is not */ \ +/* necessary. */ \ +/* _v : coefficients array [size: _n x 1] */ \ +/* _x : input array [size: _n x 1] */ \ +/* _n : dotprod length, _n > 0 */ \ +/* _y : output sample pointer */ \ +void DOTPROD(_run)( TC * _v, \ + TI * _x, \ + unsigned int _n, \ + TO * _y); \ + \ +/* This provides the same unoptimized operation as the 'run()' method */ \ +/* above, but with the loop unrolled by a factor of 4. It is marginally */ \ +/* faster than 'run()' without unrolling the loop. */ \ +/* _v : coefficients array [size: _n x 1] */ \ +/* _x : input array [size: _n x 1] */ \ +/* _n : dotprod length, _n > 0 */ \ +/* _y : output sample pointer */ \ +void DOTPROD(_run4)( TC * _v, \ + TI * _x, \ + unsigned int _n, \ + TO * _y); \ + \ +/* Create vector dot product object */ \ +/* _v : coefficients array [size: _n x 1] */ \ +/* _n : dotprod length, _n > 0 */ \ +DOTPROD() DOTPROD(_create)(TC * _v, \ + unsigned int _n); \ + \ +/* Re-create dot product object of potentially a different length with */ \ +/* different coefficients. If the length of the dot product object does */ \ +/* not change, not memory reallocation is invoked. */ \ +/* _q : old dotprod object */ \ +/* _v : coefficients array [size: _n x 1] */ \ +/* _n : dotprod length, _n > 0 */ \ +DOTPROD() DOTPROD(_recreate)(DOTPROD() _q, \ + TC * _v, \ + unsigned int _n); \ + \ +/* Destroy dotprod object, freeing all internal memory */ \ +void DOTPROD(_destroy)(DOTPROD() _q); \ + \ +/* Print dotprod object internals to standard output */ \ +void DOTPROD(_print)(DOTPROD() _q); \ + \ +/* Execute dot product on an input array */ \ +/* _q : dotprod object */ \ +/* _x : input array [size: _n x 1] */ \ +/* _y : output sample pointer */ \ +void DOTPROD(_execute)(DOTPROD() _q, \ + TI * _x, \ + TO * _y); \ + +LIQUID_DOTPROD_DEFINE_API(LIQUID_DOTPROD_MANGLE_RRRF, + float, + float, + float) + +LIQUID_DOTPROD_DEFINE_API(LIQUID_DOTPROD_MANGLE_CCCF, + liquid_float_complex, + liquid_float_complex, + liquid_float_complex) + +LIQUID_DOTPROD_DEFINE_API(LIQUID_DOTPROD_MANGLE_CRCF, + liquid_float_complex, + float, + liquid_float_complex) + +// +// sum squared methods +// + +float liquid_sumsqf(float * _v, + unsigned int _n); + +float liquid_sumsqcf(liquid_float_complex * _v, + unsigned int _n); + + +// +// MODULE : equalization +// + +// least mean-squares (LMS) +#define LIQUID_EQLMS_MANGLE_RRRF(name) LIQUID_CONCAT(eqlms_rrrf,name) +#define LIQUID_EQLMS_MANGLE_CCCF(name) LIQUID_CONCAT(eqlms_cccf,name) + +// large macro +// EQLMS : name-mangling macro +// T : data type +#define LIQUID_EQLMS_DEFINE_API(EQLMS,T) \ + \ +/* Least mean-squares equalization object */ \ +typedef struct EQLMS(_s) * EQLMS(); \ + \ +/* Create LMS EQ initialized with external coefficients */ \ +/* _h : filter coefficients; set to NULL for {1,0,0...},[size: _n x 1] */ \ +/* _n : filter length */ \ +EQLMS() EQLMS(_create)(T * _h, \ + unsigned int _n); \ + \ +/* Create LMS EQ initialized with square-root Nyquist prototype filter */ \ +/* as initial set of coefficients. This is useful for applications */ \ +/* where the baseline matched filter is a good starting point, but */ \ +/* where equalization is needed to properly remove inter-symbol */ \ +/* interference. */ \ +/* The filter length is \(2 k m + 1\) */ \ +/* _type : filter type (e.g. LIQUID_FIRFILT_RRC) */ \ +/* _k : samples/symbol */ \ +/* _m : filter delay (symbols) */ \ +/* _beta : rolloff factor (0 < beta <= 1) */ \ +/* _dt : fractional sample delay */ \ +EQLMS() EQLMS(_create_rnyquist)(int _type, \ + unsigned int _k, \ + unsigned int _m, \ + float _beta, \ + float _dt); \ + \ +/* Create LMS EQ initialized with low-pass filter */ \ +/* _n : filter length */ \ +/* _fc : filter cut-off normalized to sample rate, 0 < _fc <= 0.5 */ \ +EQLMS() EQLMS(_create_lowpass)(unsigned int _n, \ + float _fc); \ + \ +/* Re-create EQ initialized with external coefficients */ \ +/* _q : equalizer object */ \ +/* _h : filter coefficients (NULL for {1,0,0...}), [size: _n x 1] */ \ +/* _h_len : filter length */ \ +EQLMS() EQLMS(_recreate)(EQLMS() _q, \ + T * _h, \ + unsigned int _h_len); \ + \ +/* Destroy equalizer object, freeing all internal memory */ \ +int EQLMS(_destroy)(EQLMS() _q); \ + \ +/* Reset equalizer object, clearing internal state */ \ +int EQLMS(_reset)(EQLMS() _q); \ + \ +/* Print equalizer internal state */ \ +int EQLMS(_print)(EQLMS() _q); \ + \ +/* Get equalizer learning rate */ \ +float EQLMS(_get_bw)(EQLMS() _q); \ + \ +/* Set equalizer learning rate */ \ +/* _q : equalizer object */ \ +/* _lambda : learning rate, _lambda > 0 */ \ +int EQLMS(_set_bw)(EQLMS() _q, \ + float _lambda); \ + \ +/* Push sample into equalizer internal buffer */ \ +/* _q : equalizer object */ \ +/* _x : input sample */ \ +int EQLMS(_push)(EQLMS() _q, \ + T _x); \ + \ +/* Push block of samples into internal buffer of equalizer object */ \ +/* _q : equalizer object */ \ +/* _x : input sample array, [size: _n x 1] */ \ +/* _n : input sample array length */ \ +int EQLMS(_push_block)(EQLMS() _q, \ + T * _x, \ + unsigned int _n); \ + \ +/* Execute internal dot product and return result */ \ +/* _q : equalizer object */ \ +/* _y : output sample */ \ +int EQLMS(_execute)(EQLMS() _q, \ + T * _y); \ + \ +/* Execute equalizer with block of samples using constant */ \ +/* modulus algorithm, operating on a decimation rate of _k */ \ +/* samples. */ \ +/* _q : equalizer object */ \ +/* _k : down-sampling rate */ \ +/* _x : input sample array [size: _n x 1] */ \ +/* _n : input sample array length */ \ +/* _y : output sample array [size: _n x 1] */ \ +int EQLMS(_execute_block)(EQLMS() _q, \ + unsigned int _k, \ + T * _x, \ + unsigned int _n, \ + T * _y); \ + \ +/* Step through one cycle of equalizer training */ \ +/* _q : equalizer object */ \ +/* _d : desired output */ \ +/* _d_hat : actual output */ \ +int EQLMS(_step)(EQLMS() _q, \ + T _d, \ + T _d_hat); \ + \ +/* Step through one cycle of equalizer training (blind) */ \ +/* _q : equalizer object */ \ +/* _d_hat : actual output */ \ +int EQLMS(_step_blind)(EQLMS() _q, \ + T _d_hat); \ + \ +/* Get equalizer's internal coefficients */ \ +/* _q : equalizer object */ \ +/* _w : weights, [size: _p x 1] */ \ +int EQLMS(_get_weights)(EQLMS() _q, \ + T * _w); \ + \ +/* Train equalizer object on group of samples */ \ +/* _q : equalizer object */ \ +/* _w : input/output weights, [size: _p x 1] */ \ +/* _x : received sample vector,[size: _n x 1] */ \ +/* _d : desired output vector, [size: _n x 1] */ \ +/* _n : input, output vector length */ \ +int EQLMS(_train)(EQLMS() _q, \ + T * _w, \ + T * _x, \ + T * _d, \ + unsigned int _n); \ + +LIQUID_EQLMS_DEFINE_API(LIQUID_EQLMS_MANGLE_RRRF, float) +LIQUID_EQLMS_DEFINE_API(LIQUID_EQLMS_MANGLE_CCCF, liquid_float_complex) + + +// recursive least-squares (RLS) +#define LIQUID_EQRLS_MANGLE_RRRF(name) LIQUID_CONCAT(eqrls_rrrf,name) +#define LIQUID_EQRLS_MANGLE_CCCF(name) LIQUID_CONCAT(eqrls_cccf,name) + +// large macro +// EQRLS : name-mangling macro +// T : data type +#define LIQUID_EQRLS_DEFINE_API(EQRLS,T) \ + \ +/* Recursive least mean-squares equalization object */ \ +typedef struct EQRLS(_s) * EQRLS(); \ + \ +/* Create RLS EQ initialized with external coefficients */ \ +/* _h : filter coefficients; set to NULL for {1,0,0...},[size: _n x 1] */ \ +/* _n : filter length */ \ +EQRLS() EQRLS(_create)(T * _h, \ + unsigned int _n); \ + \ +/* Re-create EQ initialized with external coefficients */ \ +/* _q : equalizer object */ \ +/* _h : filter coefficients (NULL for {1,0,0...}), [size: _n x 1] */ \ +/* _n : filter length */ \ +EQRLS() EQRLS(_recreate)(EQRLS() _q, \ + T * _h, \ + unsigned int _n); \ + \ +/* Destroy equalizer object, freeing all internal memory */ \ +int EQRLS(_destroy)(EQRLS() _q); \ + \ +/* Reset equalizer object, clearing internal state */ \ +int EQRLS(_reset)(EQRLS() _q); \ + \ +/* Print equalizer internal state */ \ +int EQRLS(_print)(EQRLS() _q); \ + \ +/* Get equalizer learning rate */ \ +float EQRLS(_get_bw)(EQRLS() _q); \ + \ +/* Set equalizer learning rate */ \ +/* _q : equalizer object */ \ +/* _mu : learning rate, _mu > 0 */ \ +int EQRLS(_set_bw)(EQRLS() _q, \ + float _mu); \ + \ +/* Push sample into equalizer internal buffer */ \ +/* _q : equalizer object */ \ +/* _x : input sample */ \ +int EQRLS(_push)(EQRLS() _q, T _x); \ + \ +/* Execute internal dot product and return result */ \ +/* _q : equalizer object */ \ +/* _y : output sample */ \ +int EQRLS(_execute)(EQRLS() _q, T * _y); \ + \ +/* Step through one cycle of equalizer training */ \ +/* _q : equalizer object */ \ +/* _d : desired output */ \ +/* _d_hat : actual output */ \ +int EQRLS(_step)(EQRLS() _q, T _d, T _d_hat); \ + \ +/* Get equalizer's internal coefficients */ \ +/* _q : equalizer object */ \ +/* _w : weights, [size: _p x 1] */ \ +int EQRLS(_get_weights)(EQRLS() _q, \ + T * _w); \ + \ +/* Train equalizer object on group of samples */ \ +/* _q : equalizer object */ \ +/* _w : input/output weights, [size: _p x 1] */ \ +/* _x : received sample vector,[size: _n x 1] */ \ +/* _d : desired output vector, [size: _n x 1] */ \ +/* _n : input, output vector length */ \ +int EQRLS(_train)(EQRLS() _q, \ + T * _w, \ + T * _x, \ + T * _d, \ + unsigned int _n); \ + +LIQUID_EQRLS_DEFINE_API(LIQUID_EQRLS_MANGLE_RRRF, float) +LIQUID_EQRLS_DEFINE_API(LIQUID_EQRLS_MANGLE_CCCF, liquid_float_complex) + + + + +// +// MODULE : fec (forward error-correction) +// + +// soft bit values +#define LIQUID_SOFTBIT_0 (0) +#define LIQUID_SOFTBIT_1 (255) +#define LIQUID_SOFTBIT_ERASURE (127) + +// available CRC schemes +#define LIQUID_CRC_NUM_SCHEMES 7 +typedef enum { + LIQUID_CRC_UNKNOWN=0, // unknown/unavailable CRC scheme + LIQUID_CRC_NONE, // no error-detection + LIQUID_CRC_CHECKSUM, // 8-bit checksum + LIQUID_CRC_8, // 8-bit CRC + LIQUID_CRC_16, // 16-bit CRC + LIQUID_CRC_24, // 24-bit CRC + LIQUID_CRC_32 // 32-bit CRC +} crc_scheme; + +// pretty names for crc schemes +extern const char * crc_scheme_str[LIQUID_CRC_NUM_SCHEMES][2]; + +// Print compact list of existing and available CRC schemes +void liquid_print_crc_schemes(); + +// returns crc_scheme based on input string +crc_scheme liquid_getopt_str2crc(const char * _str); + +// get length of CRC (bytes) +unsigned int crc_get_length(crc_scheme _scheme); + +// generate error-detection key +// _scheme : error-detection scheme +// _msg : input data message, [size: _n x 1] +// _n : input data message size +unsigned int crc_generate_key(crc_scheme _scheme, + unsigned char * _msg, + unsigned int _n); + +// generate error-detection key and append to end of message +// _scheme : error-detection scheme (resulting in 'p' bytes) +// _msg : input data message, [size: _n+p x 1] +// _n : input data message size (excluding key at end) +int crc_append_key(crc_scheme _scheme, + unsigned char * _msg, + unsigned int _n); + +// validate message using error-detection key +// _scheme : error-detection scheme +// _msg : input data message, [size: _n x 1] +// _n : input data message size +// _key : error-detection key +int crc_validate_message(crc_scheme _scheme, + unsigned char * _msg, + unsigned int _n, + unsigned int _key); + +// check message with key appended to end of array +// _scheme : error-detection scheme (resulting in 'p' bytes) +// _msg : input data message, [size: _n+p x 1] +// _n : input data message size (excluding key at end) +int crc_check_key(crc_scheme _scheme, + unsigned char * _msg, + unsigned int _n); + +// get size of key (bytes) +unsigned int crc_sizeof_key(crc_scheme _scheme); + + +// available FEC schemes +#define LIQUID_FEC_NUM_SCHEMES 28 +typedef enum { + LIQUID_FEC_UNKNOWN=0, // unknown/unsupported scheme + LIQUID_FEC_NONE, // no error-correction + LIQUID_FEC_REP3, // simple repeat code, r1/3 + LIQUID_FEC_REP5, // simple repeat code, r1/5 + LIQUID_FEC_HAMMING74, // Hamming (7,4) block code, r1/2 (really 4/7) + LIQUID_FEC_HAMMING84, // Hamming (7,4) with extra parity bit, r1/2 + LIQUID_FEC_HAMMING128, // Hamming (12,8) block code, r2/3 + + LIQUID_FEC_GOLAY2412, // Golay (24,12) block code, r1/2 + LIQUID_FEC_SECDED2216, // SEC-DED (22,16) block code, r8/11 + LIQUID_FEC_SECDED3932, // SEC-DED (39,32) block code + LIQUID_FEC_SECDED7264, // SEC-DED (72,64) block code, r8/9 + + // codecs not defined internally (see http://www.ka9q.net/code/fec/) + LIQUID_FEC_CONV_V27, // r1/2, K=7, dfree=10 + LIQUID_FEC_CONV_V29, // r1/2, K=9, dfree=12 + LIQUID_FEC_CONV_V39, // r1/3, K=9, dfree=18 + LIQUID_FEC_CONV_V615, // r1/6, K=15, dfree<=57 (Heller 1968) + + // punctured (perforated) codes + LIQUID_FEC_CONV_V27P23, // r2/3, K=7, dfree=6 + LIQUID_FEC_CONV_V27P34, // r3/4, K=7, dfree=5 + LIQUID_FEC_CONV_V27P45, // r4/5, K=7, dfree=4 + LIQUID_FEC_CONV_V27P56, // r5/6, K=7, dfree=4 + LIQUID_FEC_CONV_V27P67, // r6/7, K=7, dfree=3 + LIQUID_FEC_CONV_V27P78, // r7/8, K=7, dfree=3 + + LIQUID_FEC_CONV_V29P23, // r2/3, K=9, dfree=7 + LIQUID_FEC_CONV_V29P34, // r3/4, K=9, dfree=6 + LIQUID_FEC_CONV_V29P45, // r4/5, K=9, dfree=5 + LIQUID_FEC_CONV_V29P56, // r5/6, K=9, dfree=5 + LIQUID_FEC_CONV_V29P67, // r6/7, K=9, dfree=4 + LIQUID_FEC_CONV_V29P78, // r7/8, K=9, dfree=4 + + // Reed-Solomon codes + LIQUID_FEC_RS_M8 // m=8, n=255, k=223 +} fec_scheme; + +// pretty names for fec schemes +extern const char * fec_scheme_str[LIQUID_FEC_NUM_SCHEMES][2]; + +// Print compact list of existing and available FEC schemes +void liquid_print_fec_schemes(); + +// returns fec_scheme based on input string +fec_scheme liquid_getopt_str2fec(const char * _str); + +// fec object (pointer to fec structure) +typedef struct fec_s * fec; + +// return the encoded message length using a particular error- +// correction scheme (object-independent method) +// _scheme : forward error-correction scheme +// _msg_len : raw, uncoded message length +unsigned int fec_get_enc_msg_length(fec_scheme _scheme, + unsigned int _msg_len); + +// get the theoretical rate of a particular forward error- +// correction scheme (object-independent method) +float fec_get_rate(fec_scheme _scheme); + +// create a fec object of a particular scheme +// _scheme : error-correction scheme +// _opts : (ignored) +fec fec_create(fec_scheme _scheme, + void *_opts); + +// recreate fec object +// _q : old fec object +// _scheme : new error-correction scheme +// _opts : (ignored) +fec fec_recreate(fec _q, + fec_scheme _scheme, + void *_opts); + +// destroy fec object +int fec_destroy(fec _q); + +// print fec object internals +int fec_print(fec _q); + +// encode a block of data using a fec scheme +// _q : fec object +// _dec_msg_len : decoded message length +// _msg_dec : decoded message +// _msg_enc : encoded message +int fec_encode(fec _q, + unsigned int _dec_msg_len, + unsigned char * _msg_dec, + unsigned char * _msg_enc); + +// decode a block of data using a fec scheme +// _q : fec object +// _dec_msg_len : decoded message length +// _msg_enc : encoded message +// _msg_dec : decoded message +int fec_decode(fec _q, + unsigned int _dec_msg_len, + unsigned char * _msg_enc, + unsigned char * _msg_dec); + +// decode a block of data using a fec scheme (soft decision) +// _q : fec object +// _dec_msg_len : decoded message length +// _msg_enc : encoded message (soft bits) +// _msg_dec : decoded message +int fec_decode_soft(fec _q, + unsigned int _dec_msg_len, + unsigned char * _msg_enc, + unsigned char * _msg_dec); + +// +// Packetizer +// + +// computes the number of encoded bytes after packetizing +// +// _n : number of uncoded input bytes +// _crc : error-detecting scheme +// _fec0 : inner forward error-correction code +// _fec1 : outer forward error-correction code +unsigned int packetizer_compute_enc_msg_len(unsigned int _n, + int _crc, + int _fec0, + int _fec1); + +// computes the number of decoded bytes before packetizing +// +// _k : number of encoded bytes +// _crc : error-detecting scheme +// _fec0 : inner forward error-correction code +// _fec1 : outer forward error-correction code +unsigned int packetizer_compute_dec_msg_len(unsigned int _k, + int _crc, + int _fec0, + int _fec1); + +typedef struct packetizer_s * packetizer; + +// create packetizer object +// +// _n : number of uncoded input bytes +// _crc : error-detecting scheme +// _fec0 : inner forward error-correction code +// _fec1 : outer forward error-correction code +packetizer packetizer_create(unsigned int _dec_msg_len, + int _crc, + int _fec0, + int _fec1); + +// re-create packetizer object +// +// _p : initialz packetizer object +// _n : number of uncoded input bytes +// _crc : error-detecting scheme +// _fec0 : inner forward error-correction code +// _fec1 : outer forward error-correction code +packetizer packetizer_recreate(packetizer _p, + unsigned int _dec_msg_len, + int _crc, + int _fec0, + int _fec1); + +// destroy packetizer object +void packetizer_destroy(packetizer _p); + +// print packetizer object internals +void packetizer_print(packetizer _p); + +// access methods +unsigned int packetizer_get_dec_msg_len(packetizer _p); +unsigned int packetizer_get_enc_msg_len(packetizer _p); +crc_scheme packetizer_get_crc (packetizer _p); +fec_scheme packetizer_get_fec0 (packetizer _p); +fec_scheme packetizer_get_fec1 (packetizer _p); + + +// Execute the packetizer on an input message +// +// _p : packetizer object +// _msg : input message (uncoded bytes) +// _pkt : encoded output message +void packetizer_encode(packetizer _p, + const unsigned char * _msg, + unsigned char * _pkt); + +// Execute the packetizer to decode an input message, return validity +// check of resulting data +// +// _p : packetizer object +// _pkt : input message (coded bytes) +// _msg : decoded output message +int packetizer_decode(packetizer _p, + const unsigned char * _pkt, + unsigned char * _msg); + +// Execute the packetizer to decode an input message, return validity +// check of resulting data +// +// _p : packetizer object +// _pkt : input message (coded soft bits) +// _msg : decoded output message +int packetizer_decode_soft(packetizer _p, + const unsigned char * _pkt, + unsigned char * _msg); + + +// +// interleaver +// +typedef struct interleaver_s * interleaver; + +// create interleaver +// _n : number of bytes +interleaver interleaver_create(unsigned int _n); + +// destroy interleaver object +void interleaver_destroy(interleaver _q); + +// print interleaver object internals +void interleaver_print(interleaver _q); + +// set depth (number of internal iterations) +// _q : interleaver object +// _depth : depth +void interleaver_set_depth(interleaver _q, + unsigned int _depth); + +// execute forward interleaver (encoder) +// _q : interleaver object +// _msg_dec : decoded (un-interleaved) message +// _msg_enc : encoded (interleaved) message +void interleaver_encode(interleaver _q, + unsigned char * _msg_dec, + unsigned char * _msg_enc); + +// execute forward interleaver (encoder) on soft bits +// _q : interleaver object +// _msg_dec : decoded (un-interleaved) message +// _msg_enc : encoded (interleaved) message +void interleaver_encode_soft(interleaver _q, + unsigned char * _msg_dec, + unsigned char * _msg_enc); + +// execute reverse interleaver (decoder) +// _q : interleaver object +// _msg_enc : encoded (interleaved) message +// _msg_dec : decoded (un-interleaved) message +void interleaver_decode(interleaver _q, + unsigned char * _msg_enc, + unsigned char * _msg_dec); + +// execute reverse interleaver (decoder) on soft bits +// _q : interleaver object +// _msg_enc : encoded (interleaved) message +// _msg_dec : decoded (un-interleaved) message +void interleaver_decode_soft(interleaver _q, + unsigned char * _msg_enc, + unsigned char * _msg_dec); + + + +// +// MODULE : fft (fast Fourier transform) +// + +// type of transform +typedef enum { + LIQUID_FFT_UNKNOWN = 0, // unknown transform type + + // regular complex one-dimensional transforms + LIQUID_FFT_FORWARD = +1, // complex one-dimensional FFT + LIQUID_FFT_BACKWARD = -1, // complex one-dimensional inverse FFT + + // discrete cosine transforms + LIQUID_FFT_REDFT00 = 10, // real one-dimensional DCT-I + LIQUID_FFT_REDFT10 = 11, // real one-dimensional DCT-II + LIQUID_FFT_REDFT01 = 12, // real one-dimensional DCT-III + LIQUID_FFT_REDFT11 = 13, // real one-dimensional DCT-IV + + // discrete sine transforms + LIQUID_FFT_RODFT00 = 20, // real one-dimensional DST-I + LIQUID_FFT_RODFT10 = 21, // real one-dimensional DST-II + LIQUID_FFT_RODFT01 = 22, // real one-dimensional DST-III + LIQUID_FFT_RODFT11 = 23, // real one-dimensional DST-IV + + // modified discrete cosine transform + LIQUID_FFT_MDCT = 30, // MDCT + LIQUID_FFT_IMDCT = 31, // IMDCT +} liquid_fft_type; + +#define LIQUID_FFT_MANGLE_FLOAT(name) LIQUID_CONCAT(fft,name) + +// Macro : FFT +// FFT : name-mangling macro +// T : primitive data type +// TC : primitive data type (complex) +#define LIQUID_FFT_DEFINE_API(FFT,T,TC) \ + \ +/* Fast Fourier Transform (FFT) and inverse (plan) object */ \ +typedef struct FFT(plan_s) * FFT(plan); \ + \ +/* Create regular complex one-dimensional transform */ \ +/* _n : transform size */ \ +/* _x : pointer to input array [size: _n x 1] */ \ +/* _y : pointer to output array [size: _n x 1] */ \ +/* _dir : direction (e.g. LIQUID_FFT_FORWARD) */ \ +/* _flags : options, optimization */ \ +FFT(plan) FFT(_create_plan)(unsigned int _n, \ + TC * _x, \ + TC * _y, \ + int _dir, \ + int _flags); \ + \ +/* Create real-to-real one-dimensional transform */ \ +/* _n : transform size */ \ +/* _x : pointer to input array [size: _n x 1] */ \ +/* _y : pointer to output array [size: _n x 1] */ \ +/* _type : transform type (e.g. LIQUID_FFT_REDFT00) */ \ +/* _flags : options, optimization */ \ +FFT(plan) FFT(_create_plan_r2r_1d)(unsigned int _n, \ + T * _x, \ + T * _y, \ + int _type, \ + int _flags); \ + \ +/* Destroy transform and free all internally-allocated memory */ \ +int FFT(_destroy_plan)(FFT(plan) _p); \ + \ +/* Print transform plan and internal strategy to stdout. This includes */ \ +/* information on the strategy for computing large transforms with many */ \ +/* prime factors or with large prime factors. */ \ +int FFT(_print_plan)(FFT(plan) _p); \ + \ +/* Run the transform */ \ +int FFT(_execute)(FFT(plan) _p); \ + \ +/* Perform n-point FFT allocating plan internally */ \ +/* _nfft : fft size */ \ +/* _x : input array [size: _nfft x 1] */ \ +/* _y : output array [size: _nfft x 1] */ \ +/* _dir : fft direction: LIQUID_FFT_{FORWARD,BACKWARD} */ \ +/* _flags : fft flags */ \ +int FFT(_run)(unsigned int _n, \ + TC * _x, \ + TC * _y, \ + int _dir, \ + int _flags); \ + \ +/* Perform n-point real one-dimensional FFT allocating plan internally */ \ +/* _nfft : fft size */ \ +/* _x : input array [size: _nfft x 1] */ \ +/* _y : output array [size: _nfft x 1] */ \ +/* _type : fft type, e.g. LIQUID_FFT_REDFT10 */ \ +/* _flags : fft flags */ \ +int FFT(_r2r_1d_run)(unsigned int _n, \ + T * _x, \ + T * _y, \ + int _type, \ + int _flags); \ + \ +/* Perform _n-point fft shift */ \ +/* _x : input array [size: _n x 1] */ \ +/* _n : input array size */ \ +int FFT(_shift)(TC * _x, \ + unsigned int _n); \ + + +LIQUID_FFT_DEFINE_API(LIQUID_FFT_MANGLE_FLOAT,float,liquid_float_complex) + +// antiquated fft methods +// FFT(plan) FFT(_create_plan_mdct)(unsigned int _n, +// T * _x, +// T * _y, +// int _kind, +// int _flags); + + +// +// spectral periodogram +// + +#define LIQUID_SPGRAM_MANGLE_CFLOAT(name) LIQUID_CONCAT(spgramcf,name) +#define LIQUID_SPGRAM_MANGLE_FLOAT(name) LIQUID_CONCAT(spgramf, name) + +#define LIQUID_SPGRAM_PSD_MIN (1e-12) + +// Macro : SPGRAM +// SPGRAM : name-mangling macro +// T : primitive data type +// TC : primitive data type (complex) +// TI : primitive data type (input) +#define LIQUID_SPGRAM_DEFINE_API(SPGRAM,T,TC,TI) \ + \ +/* Spectral periodogram object for computing power spectral density */ \ +/* estimates of various signals */ \ +typedef struct SPGRAM(_s) * SPGRAM(); \ + \ +/* Create spgram object, fully defined */ \ +/* _nfft : transform (FFT) size, _nfft >= 2 */ \ +/* _wtype : window type, e.g. LIQUID_WINDOW_HAMMING */ \ +/* _window_len : window length, 1 <= _window_len <= _nfft */ \ +/* _delay : delay between transforms, _delay > 0 */ \ +SPGRAM() SPGRAM(_create)(unsigned int _nfft, \ + int _wtype, \ + unsigned int _window_len, \ + unsigned int _delay); \ + \ +/* Create default spgram object of a particular transform size using */ \ +/* the Kaiser-Bessel window (LIQUID_WINDOW_KAISER), a window length */ \ +/* equal to _nfft/2, and a delay of _nfft/4 */ \ +/* _nfft : FFT size, _nfft >= 2 */ \ +SPGRAM() SPGRAM(_create_default)(unsigned int _nfft); \ + \ +/* Destroy spgram object, freeing all internally-allocated memory */ \ +int SPGRAM(_destroy)(SPGRAM() _q); \ + \ +/* Clears the internal state of the object, but not the internal buffer */ \ +int SPGRAM(_clear)(SPGRAM() _q); \ + \ +/* Reset the object to its original state completely. This effectively */ \ +/* executes the clear() method and then resets the internal buffer */ \ +int SPGRAM(_reset)(SPGRAM() _q); \ + \ +/* Print internal state of the object to stdout */ \ +int SPGRAM(_print)(SPGRAM() _q); \ + \ +/* Set the filter bandwidth for accumulating independent transform */ \ +/* squared magnitude outputs. */ \ +/* This is used to compute a running time-average power spectral */ \ +/* density output. */ \ +/* The value of _alpha determines how the power spectral estimate is */ \ +/* accumulated across transforms and can range from 0 to 1 with a */ \ +/* special case of -1 to accumulate infinitely. */ \ +/* Setting _alpha to 0 minimizes the bandwidth and the PSD estimate */ \ +/* will never update. */ \ +/* Setting _alpha to 1 forces the object to always use the most recent */ \ +/* spectral estimate. */ \ +/* Setting _alpha to -1 is a special case to enable infinite spectral */ \ +/* accumulation. */ \ +/* _q : spectral periodogram object */ \ +/* _alpha : forgetting factor, set to -1 for infinite, 0<=_alpha<=1 */ \ +int SPGRAM(_set_alpha)(SPGRAM() _q, \ + float _alpha); \ + \ +/* Get the filter bandwidth for accumulating independent transform */ \ +/* squared magnitude outputs. */ \ +float SPGRAM(_get_alpha)(SPGRAM() _q); \ + \ +/* Set the center frequency of the received signal. */ \ +/* This is for display purposes only when generating the output image. */ \ +/* _q : spectral periodogram object */ \ +/* _freq : center frequency [Hz] */ \ +int SPGRAM(_set_freq)(SPGRAM() _q, \ + float _freq); \ + \ +/* Set the sample rate (frequency) of the received signal. */ \ +/* This is for display purposes only when generating the output image. */ \ +/* _q : spectral periodogram object */ \ +/* _rate : sample rate [Hz] */ \ +int SPGRAM(_set_rate)(SPGRAM() _q, \ + float _rate); \ + \ +/* Get transform (FFT) size */ \ +unsigned int SPGRAM(_get_nfft)(SPGRAM() _q); \ + \ +/* Get window length */ \ +unsigned int SPGRAM(_get_window_len)(SPGRAM() _q); \ + \ +/* Get delay between transforms */ \ +unsigned int SPGRAM(_get_delay)(SPGRAM() _q); \ + \ +/* Get number of samples processed since reset */ \ +unsigned long long int SPGRAM(_get_num_samples)(SPGRAM() _q); \ + \ +/* Get number of samples processed since object was created */ \ +unsigned long long int SPGRAM(_get_num_samples_total)(SPGRAM() _q); \ + \ +/* Get number of transforms processed since reset */ \ +unsigned long long int SPGRAM(_get_num_transforms)(SPGRAM() _q); \ + \ +/* Get number of transforms processed since object was created */ \ +unsigned long long int SPGRAM(_get_num_transforms_total)(SPGRAM() _q); \ + \ +/* Push a single sample into the object, executing internal transform */ \ +/* as necessary. */ \ +/* _q : spgram object */ \ +/* _x : input sample */ \ +int SPGRAM(_push)(SPGRAM() _q, \ + TI _x); \ + \ +/* Write a block of samples to the object, executing internal */ \ +/* transform as necessary. */ \ +/* _q : spgram object */ \ +/* _x : input buffer [size: _n x 1] */ \ +/* _n : input buffer length */ \ +int SPGRAM(_write)(SPGRAM() _q, \ + TI * _x, \ + unsigned int _n); \ + \ +/* Compute spectral periodogram output (fft-shifted values in dB) from */ \ +/* current buffer contents */ \ +/* _q : spgram object */ \ +/* _X : output spectrum (dB), [size: _nfft x 1] */ \ +int SPGRAM(_get_psd)(SPGRAM() _q, \ + T * _X); \ + \ +/* Export stand-alone gnuplot file for plotting output spectrum, */ \ +/* returning 0 on sucess, anything other than 0 for failure */ \ +/* _q : spgram object */ \ +/* _filename : input buffer [size: _n x 1] */ \ +int SPGRAM(_export_gnuplot)(SPGRAM() _q, \ + const char * _filename); \ + \ +/* Estimate spectrum on input signal (create temporary object for */ \ +/* convenience */ \ +/* _nfft : FFT size */ \ +/* _x : input signal [size: _n x 1] */ \ +/* _n : input signal length */ \ +/* _psd : output spectrum, [size: _nfft x 1] */ \ +int SPGRAM(_estimate_psd)(unsigned int _nfft, \ + TI * _x, \ + unsigned int _n, \ + T * _psd); \ + +LIQUID_SPGRAM_DEFINE_API(LIQUID_SPGRAM_MANGLE_CFLOAT, + float, + liquid_float_complex, + liquid_float_complex) + +LIQUID_SPGRAM_DEFINE_API(LIQUID_SPGRAM_MANGLE_FLOAT, + float, + liquid_float_complex, + float) + +// +// asgram : ascii spectral periodogram +// + +#define LIQUID_ASGRAM_MANGLE_CFLOAT(name) LIQUID_CONCAT(asgramcf,name) +#define LIQUID_ASGRAM_MANGLE_FLOAT(name) LIQUID_CONCAT(asgramf, name) + +// Macro : ASGRAM +// ASGRAM : name-mangling macro +// T : primitive data type +// TC : primitive data type (complex) +// TI : primitive data type (input) +#define LIQUID_ASGRAM_DEFINE_API(ASGRAM,T,TC,TI) \ + \ +/* ASCII spectral periodogram for computing and displaying an estimate */ \ +/* of a signal's power spectrum with ASCII characters */ \ +typedef struct ASGRAM(_s) * ASGRAM(); \ + \ +/* Create asgram object with size _nfft */ \ +/* _nfft : size of FFT taken for each transform (character width) */ \ +ASGRAM() ASGRAM(_create)(unsigned int _nfft); \ + \ +/* Destroy asgram object, freeing all internally-allocated memory */ \ +int ASGRAM(_destroy)(ASGRAM() _q); \ + \ +/* Reset the internal state of the asgram object */ \ +int ASGRAM(_reset)(ASGRAM() _q); \ + \ +/* Set the scale and offset for spectrogram in terms of dB for display */ \ +/* purposes */ \ +/* _q : asgram object */ \ +/* _ref : signal reference level [dB] */ \ +/* _div : signal division [dB] */ \ +int ASGRAM(_set_scale)(ASGRAM() _q, \ + float _ref, \ + float _div); \ + \ +/* Set the display's 10 characters for output string starting from the */ \ +/* weakest and ending with the strongest */ \ +/* _q : asgram object */ \ +/* _ascii : 10-character display, default: " .,-+*&NM#" */ \ +int ASGRAM(_set_display)(ASGRAM() _q, \ + const char * _ascii); \ + \ +/* Push a single sample into the asgram object, executing internal */ \ +/* transform as necessary. */ \ +/* _q : asgram object */ \ +/* _x : input sample */ \ +int ASGRAM(_push)(ASGRAM() _q, \ + TI _x); \ + \ +/* Write a block of samples to the asgram object, executing internal */ \ +/* transforms as necessary. */ \ +/* _q : asgram object */ \ +/* _x : input buffer [size: _n x 1] */ \ +/* _n : input buffer length */ \ +int ASGRAM(_write)(ASGRAM() _q, \ + TI * _x, \ + unsigned int _n); \ + \ +/* Compute spectral periodogram output from current buffer contents */ \ +/* and return the ascii character string to display along with the peak */ \ +/* value and its frequency location */ \ +/* _q : asgram object */ \ +/* _ascii : output ASCII string [size: _nfft x 1] */ \ +/* _peakval : peak power spectral density value [dB] */ \ +/* _peakfreq : peak power spectral density frequency */ \ +int ASGRAM(_execute)(ASGRAM() _q, \ + char * _ascii, \ + float * _peakval, \ + float * _peakfreq); \ + \ +/* Compute spectral periodogram output from current buffer contents and */ \ +/* print standard format to stdout */ \ +int ASGRAM(_print)(ASGRAM() _q); \ + +LIQUID_ASGRAM_DEFINE_API(LIQUID_ASGRAM_MANGLE_CFLOAT, + float, + liquid_float_complex, + liquid_float_complex) + +LIQUID_ASGRAM_DEFINE_API(LIQUID_ASGRAM_MANGLE_FLOAT, + float, + liquid_float_complex, + float) + +// +// spectral periodogram waterfall +// + +#define LIQUID_SPWATERFALL_MANGLE_CFLOAT(name) LIQUID_CONCAT(spwaterfallcf,name) +#define LIQUID_SPWATERFALL_MANGLE_FLOAT(name) LIQUID_CONCAT(spwaterfallf, name) + +// Macro : SPWATERFALL +// SPWATERFALL : name-mangling macro +// T : primitive data type +// TC : primitive data type (complex) +// TI : primitive data type (input) +#define LIQUID_SPWATERFALL_DEFINE_API(SPWATERFALL,T,TC,TI) \ + \ +/* Spectral periodogram waterfall object for computing time-varying */ \ +/* power spectral density estimates */ \ +typedef struct SPWATERFALL(_s) * SPWATERFALL(); \ + \ +/* Create spwaterfall object, fully defined */ \ +/* _nfft : transform (FFT) size, _nfft >= 2 */ \ +/* _wtype : window type, e.g. LIQUID_WINDOW_HAMMING */ \ +/* _window_len : window length, 1 <= _window_len <= _nfft */ \ +/* _delay : delay between transforms, _delay > 0 */ \ +/* _time : number of aggregated transforms, _time > 0 */ \ +SPWATERFALL() SPWATERFALL(_create)(unsigned int _nfft, \ + int _wtype, \ + unsigned int _window_len, \ + unsigned int _delay, \ + unsigned int _time); \ + \ +/* Create default spwatefall object (Kaiser-Bessel window) */ \ +/* _nfft : transform size, _nfft >= 2 */ \ +/* _time : delay between transforms, _delay > 0 */ \ +SPWATERFALL() SPWATERFALL(_create_default)(unsigned int _nfft, \ + unsigned int _time); \ + \ +/* Destroy spwaterfall object, freeing all internally-allocated memory */ \ +int SPWATERFALL(_destroy)(SPWATERFALL() _q); \ + \ +/* Clears the internal state of the object, but not the internal buffer */ \ +int SPWATERFALL(_clear)(SPWATERFALL() _q); \ + \ +/* Reset the object to its original state completely. This effectively */ \ +/* executes the clear() method and then resets the internal buffer */ \ +int SPWATERFALL(_reset)(SPWATERFALL() _q); \ + \ +/* Print internal state of the object to stdout */ \ +int SPWATERFALL(_print)(SPWATERFALL() _q); \ + \ +/* Get number of samples processed since object was created */ \ +uint64_t SPWATERFALL(_get_num_samples_total)(SPWATERFALL() _q); \ + \ +/* Get FFT size (columns in PSD output) */ \ +unsigned int SPWATERFALL(_get_num_freq)(SPWATERFALL() _q); \ + \ +/* Get number of accumulated FFTs (rows in PSD output) */ \ +unsigned int SPWATERFALL(_get_num_time)(SPWATERFALL() _q); \ + \ +/* Get power spectral density (PSD), size: nfft x time */ \ +const T * SPWATERFALL(_get_psd)(SPWATERFALL() _q); \ + \ +/* Set the center frequency of the received signal. */ \ +/* This is for display purposes only when generating the output image. */ \ +/* _q : spectral periodogram waterfall object */ \ +/* _freq : center frequency [Hz] */ \ +int SPWATERFALL(_set_freq)(SPWATERFALL() _q, \ + float _freq); \ + \ +/* Set the sample rate (frequency) of the received signal. */ \ +/* This is for display purposes only when generating the output image. */ \ +/* _q : spectral periodogram waterfall object */ \ +/* _rate : sample rate [Hz] */ \ +int SPWATERFALL(_set_rate)(SPWATERFALL() _q, \ + float _rate); \ + \ +/* Set the canvas size. */ \ +/* This is for display purposes only when generating the output image. */ \ +/* _q : spectral periodogram waterfall object */ \ +/* _width : image width [pixels] */ \ +/* _height : image height [pixels] */ \ +int SPWATERFALL(_set_dims)(SPWATERFALL() _q, \ + unsigned int _width, \ + unsigned int _height); \ + \ +/* Set commands for executing directly before 'plot' statement. */ \ +/* _q : spectral periodogram waterfall object */ \ +/* _commands : gnuplot commands separated by semicolons */ \ +int SPWATERFALL(_set_commands)(SPWATERFALL() _q, \ + const char * _commands); \ + \ +/* Push a single sample into the object, executing internal transform */ \ +/* as necessary. */ \ +/* _q : spwaterfall object */ \ +/* _x : input sample */ \ +int SPWATERFALL(_push)(SPWATERFALL() _q, \ + TI _x); \ + \ +/* Write a block of samples to the object, executing internal */ \ +/* transform as necessary. */ \ +/* _q : spwaterfall object */ \ +/* _x : input buffer, [size: _n x 1] */ \ +/* _n : input buffer length */ \ +int SPWATERFALL(_write)(SPWATERFALL() _q, \ + TI * _x, \ + unsigned int _n); \ + \ +/* Export set of files for plotting */ \ +/* _q : spwaterfall object */ \ +/* _base : base filename (will export .gnu, .bin, and .png files) */ \ +int SPWATERFALL(_export)(SPWATERFALL() _q, \ + const char * _base); \ + + +LIQUID_SPWATERFALL_DEFINE_API(LIQUID_SPWATERFALL_MANGLE_CFLOAT, + float, + liquid_float_complex, + liquid_float_complex) + +LIQUID_SPWATERFALL_DEFINE_API(LIQUID_SPWATERFALL_MANGLE_FLOAT, + float, + liquid_float_complex, + float) + + +// +// MODULE : filter +// + +// +// firdes: finite impulse response filter design +// + +// prototypes +#define LIQUID_FIRFILT_NUM_TYPES (16) +typedef enum { + LIQUID_FIRFILT_UNKNOWN=0, // unknown filter type + + // Nyquist filter prototypes + LIQUID_FIRFILT_KAISER, // Nyquist Kaiser filter + LIQUID_FIRFILT_PM, // Parks-McClellan filter + LIQUID_FIRFILT_RCOS, // raised-cosine filter + LIQUID_FIRFILT_FEXP, // flipped exponential + LIQUID_FIRFILT_FSECH, // flipped hyperbolic secant + LIQUID_FIRFILT_FARCSECH, // flipped arc-hyperbolic secant + + // root-Nyquist filter prototypes + LIQUID_FIRFILT_ARKAISER, // root-Nyquist Kaiser (approximate optimum) + LIQUID_FIRFILT_RKAISER, // root-Nyquist Kaiser (true optimum) + LIQUID_FIRFILT_RRC, // root raised-cosine + LIQUID_FIRFILT_hM3, // harris-Moerder-3 filter + LIQUID_FIRFILT_GMSKTX, // GMSK transmit filter + LIQUID_FIRFILT_GMSKRX, // GMSK receive filter + LIQUID_FIRFILT_RFEXP, // flipped exponential + LIQUID_FIRFILT_RFSECH, // flipped hyperbolic secant + LIQUID_FIRFILT_RFARCSECH, // flipped arc-hyperbolic secant +} liquid_firfilt_type; + +// Design (root-)Nyquist filter from prototype +// _type : filter type (e.g. LIQUID_FIRFILT_RRC) +// _k : samples/symbol, _k > 1 +// _m : symbol delay, _m > 0 +// _beta : excess bandwidth factor, _beta in [0,1) +// _dt : fractional sample delay, _dt in [-1,1] +// _h : output coefficient buffer (length: 2*_k*_m+1) +void liquid_firdes_prototype(liquid_firfilt_type _type, + unsigned int _k, + unsigned int _m, + float _beta, + float _dt, + float * _h); + +// pretty names for filter design types +extern const char * liquid_firfilt_type_str[LIQUID_FIRFILT_NUM_TYPES][2]; + +// returns filter type based on input string +int liquid_getopt_str2firfilt(const char * _str); + +// estimate required filter length given +// _df : transition bandwidth (0 < _b < 0.5) +// _As : stop-band attenuation [dB], _As > 0 +unsigned int estimate_req_filter_len(float _df, + float _As); + +// estimate filter stop-band attenuation given +// _df : transition bandwidth (0 < _b < 0.5) +// _N : filter length +float estimate_req_filter_As(float _df, + unsigned int _N); + +// estimate filter transition bandwidth given +// _As : stop-band attenuation [dB], _As > 0 +// _N : filter length +float estimate_req_filter_df(float _As, + unsigned int _N); + + +// returns the Kaiser window beta factor give the filter's target +// stop-band attenuation (As) [Vaidyanathan:1993] +// _As : target filter's stop-band attenuation [dB], _As > 0 +float kaiser_beta_As(float _As); + + +// Design FIR filter using Parks-McClellan algorithm + +// band type specifier +typedef enum { + LIQUID_FIRDESPM_BANDPASS=0, // regular band-pass filter + LIQUID_FIRDESPM_DIFFERENTIATOR, // differentiating filter + LIQUID_FIRDESPM_HILBERT // Hilbert transform +} liquid_firdespm_btype; + +// weighting type specifier +typedef enum { + LIQUID_FIRDESPM_FLATWEIGHT=0, // flat weighting + LIQUID_FIRDESPM_EXPWEIGHT, // exponential weighting + LIQUID_FIRDESPM_LINWEIGHT, // linear weighting +} liquid_firdespm_wtype; + +// run filter design (full life cycle of object) +// _h_len : length of filter (number of taps) +// _num_bands : number of frequency bands +// _bands : band edges, f in [0,0.5], [size: _num_bands x 2] +// _des : desired response [size: _num_bands x 1] +// _weights : response weighting [size: _num_bands x 1] +// _wtype : weight types (e.g. LIQUID_FIRDESPM_FLATWEIGHT) [size: _num_bands x 1] +// _btype : band type (e.g. LIQUID_FIRDESPM_BANDPASS) +// _h : output coefficients array [size: _h_len x 1] +int firdespm_run(unsigned int _h_len, + unsigned int _num_bands, + float * _bands, + float * _des, + float * _weights, + liquid_firdespm_wtype * _wtype, + liquid_firdespm_btype _btype, + float * _h); + +// run filter design for basic low-pass filter +// _n : filter length, _n > 0 +// _fc : cutoff frequency, 0 < _fc < 0.5 +// _As : stop-band attenuation [dB], _As > 0 +// _mu : fractional sample offset, -0.5 < _mu < 0.5 [ignored] +// _h : output coefficient buffer, [size: _n x 1] +int firdespm_lowpass(unsigned int _n, + float _fc, + float _As, + float _mu, + float * _h); + +// firdespm response callback function +// _frequency : normalized frequency +// _userdata : pointer to userdata +// _desired : (return) desired response +// _weight : (return) weight +typedef int (*firdespm_callback)(double _frequency, + void * _userdata, + double * _desired, + double * _weight); + +// structured object +typedef struct firdespm_s * firdespm; + +// create firdespm object +// _h_len : length of filter (number of taps) +// _num_bands : number of frequency bands +// _bands : band edges, f in [0,0.5], [size: _num_bands x 2] +// _des : desired response [size: _num_bands x 1] +// _weights : response weighting [size: _num_bands x 1] +// _wtype : weight types (e.g. LIQUID_FIRDESPM_FLATWEIGHT) [size: _num_bands x 1] +// _btype : band type (e.g. LIQUID_FIRDESPM_BANDPASS) +firdespm firdespm_create(unsigned int _h_len, + unsigned int _num_bands, + float * _bands, + float * _des, + float * _weights, + liquid_firdespm_wtype * _wtype, + liquid_firdespm_btype _btype); + +// create firdespm object with user-defined callback +// _h_len : length of filter (number of taps) +// _num_bands : number of frequency bands +// _bands : band edges, f in [0,0.5], [size: _num_bands x 2] +// _btype : band type (e.g. LIQUID_FIRDESPM_BANDPASS) +// _callback : user-defined callback for specifying desired response & weights +// _userdata : user-defined data structure for callback function +firdespm firdespm_create_callback(unsigned int _h_len, + unsigned int _num_bands, + float * _bands, + liquid_firdespm_btype _btype, + firdespm_callback _callback, + void * _userdata); + +// destroy firdespm object +int firdespm_destroy(firdespm _q); + +// print firdespm object internals +int firdespm_print(firdespm _q); + +// execute filter design, storing result in _h +int firdespm_execute(firdespm _q, float * _h); + + +// Design FIR using kaiser window +// _n : filter length, _n > 0 +// _fc : cutoff frequency, 0 < _fc < 0.5 +// _As : stop-band attenuation [dB], _As > 0 +// _mu : fractional sample offset, -0.5 < _mu < 0.5 +// _h : output coefficient buffer, [size: _n x 1] +void liquid_firdes_kaiser(unsigned int _n, + float _fc, + float _As, + float _mu, + float *_h); + +// Design finite impulse response notch filter +// _m : filter semi-length, m in [1,1000] +// _f0 : filter notch frequency (normalized), -0.5 <= _fc <= 0.5 +// _As : stop-band attenuation [dB], _As > 0 +// _h : output coefficient buffer, [size: 2*_m+1 x 1] +void liquid_firdes_notch(unsigned int _m, + float _f0, + float _As, + float * _h); + +// Design FIR doppler filter +// _n : filter length +// _fd : normalized doppler frequency (0 < _fd < 0.5) +// _K : Rice fading factor (K >= 0) +// _theta : LoS component angle of arrival +// _h : output coefficient buffer +void liquid_firdes_doppler(unsigned int _n, + float _fd, + float _K, + float _theta, + float * _h); + + +// Design Nyquist raised-cosine filter +// _k : samples/symbol +// _m : symbol delay +// _beta : rolloff factor (0 < beta <= 1) +// _dt : fractional sample delay +// _h : output coefficient buffer (length: 2*k*m+1) +void liquid_firdes_rcos(unsigned int _k, + unsigned int _m, + float _beta, + float _dt, + float * _h); + +// Design root-Nyquist raised-cosine filter +void liquid_firdes_rrcos(unsigned int _k, unsigned int _m, float _beta, float _dt, float * _h); + +// Design root-Nyquist Kaiser filter +void liquid_firdes_rkaiser(unsigned int _k, unsigned int _m, float _beta, float _dt, float * _h); + +// Design (approximate) root-Nyquist Kaiser filter +void liquid_firdes_arkaiser(unsigned int _k, unsigned int _m, float _beta, float _dt, float * _h); + +// Design root-Nyquist harris-Moerder filter +void liquid_firdes_hM3(unsigned int _k, unsigned int _m, float _beta, float _dt, float * _h); + +// Design GMSK transmit and receive filters +void liquid_firdes_gmsktx(unsigned int _k, unsigned int _m, float _beta, float _dt, float * _h); +void liquid_firdes_gmskrx(unsigned int _k, unsigned int _m, float _beta, float _dt, float * _h); + +// Design flipped exponential Nyquist/root-Nyquist filters +void liquid_firdes_fexp( unsigned int _k, unsigned int _m, float _beta, float _dt, float * _h); +void liquid_firdes_rfexp(unsigned int _k, unsigned int _m, float _beta, float _dt, float * _h); + +// Design flipped hyperbolic secand Nyquist/root-Nyquist filters +void liquid_firdes_fsech( unsigned int _k, unsigned int _m, float _beta, float _dt, float * _h); +void liquid_firdes_rfsech(unsigned int _k, unsigned int _m, float _beta, float _dt, float * _h); + +// Design flipped arc-hyperbolic secand Nyquist/root-Nyquist filters +void liquid_firdes_farcsech( unsigned int _k, unsigned int _m, float _beta, float _dt, float * _h); +void liquid_firdes_rfarcsech(unsigned int _k, unsigned int _m, float _beta, float _dt, float * _h); + +// Compute group delay for an FIR filter +// _h : filter coefficients array +// _n : filter length +// _fc : frequency at which delay is evaluated (-0.5 < _fc < 0.5) +float fir_group_delay(float * _h, + unsigned int _n, + float _fc); + +// Compute group delay for an IIR filter +// _b : filter numerator coefficients +// _nb : filter numerator length +// _a : filter denominator coefficients +// _na : filter denominator length +// _fc : frequency at which delay is evaluated (-0.5 < _fc < 0.5) +float iir_group_delay(float * _b, + unsigned int _nb, + float * _a, + unsigned int _na, + float _fc); + + +// liquid_filter_autocorr() +// +// Compute auto-correlation of filter at a specific lag. +// +// _h : filter coefficients [size: _h_len x 1] +// _h_len : filter length +// _lag : auto-correlation lag (samples) +float liquid_filter_autocorr(float * _h, + unsigned int _h_len, + int _lag); + +// liquid_filter_crosscorr() +// +// Compute cross-correlation of two filters at a specific lag. +// +// _h : filter coefficients [size: _h_len] +// _h_len : filter length +// _g : filter coefficients [size: _g_len] +// _g_len : filter length +// _lag : cross-correlation lag (samples) +float liquid_filter_crosscorr(float * _h, + unsigned int _h_len, + float * _g, + unsigned int _g_len, + int _lag); + +// liquid_filter_isi() +// +// Compute inter-symbol interference (ISI)--both RMS and +// maximum--for the filter _h. +// +// _h : filter coefficients [size: 2*_k*_m+1 x 1] +// _k : filter over-sampling rate (samples/symbol) +// _m : filter delay (symbols) +// _rms : output root mean-squared ISI +// _max : maximum ISI +void liquid_filter_isi(float * _h, + unsigned int _k, + unsigned int _m, + float * _rms, + float * _max); + +// Compute relative out-of-band energy +// +// _h : filter coefficients [size: _h_len x 1] +// _h_len : filter length +// _fc : analysis cut-off frequency +// _nfft : fft size +float liquid_filter_energy(float * _h, + unsigned int _h_len, + float _fc, + unsigned int _nfft); + + +// +// IIR filter design +// + +// IIR filter design filter type +typedef enum { + LIQUID_IIRDES_BUTTER=0, + LIQUID_IIRDES_CHEBY1, + LIQUID_IIRDES_CHEBY2, + LIQUID_IIRDES_ELLIP, + LIQUID_IIRDES_BESSEL +} liquid_iirdes_filtertype; + +// IIR filter design band type +typedef enum { + LIQUID_IIRDES_LOWPASS=0, + LIQUID_IIRDES_HIGHPASS, + LIQUID_IIRDES_BANDPASS, + LIQUID_IIRDES_BANDSTOP +} liquid_iirdes_bandtype; + +// IIR filter design coefficients format +typedef enum { + LIQUID_IIRDES_SOS=0, + LIQUID_IIRDES_TF +} liquid_iirdes_format; + +// IIR filter design template +// _ftype : filter type (e.g. LIQUID_IIRDES_BUTTER) +// _btype : band type (e.g. LIQUID_IIRDES_BANDPASS) +// _format : coefficients format (e.g. LIQUID_IIRDES_SOS) +// _n : filter order +// _fc : low-pass prototype cut-off frequency +// _f0 : center frequency (band-pass, band-stop) +// _Ap : pass-band ripple in dB +// _As : stop-band ripple in dB +// _B : numerator +// _A : denominator +void liquid_iirdes(liquid_iirdes_filtertype _ftype, + liquid_iirdes_bandtype _btype, + liquid_iirdes_format _format, + unsigned int _n, + float _fc, + float _f0, + float _Ap, + float _As, + float * _B, + float * _A); + +// compute analog zeros, poles, gain for specific filter types +void butter_azpkf(unsigned int _n, + liquid_float_complex * _za, + liquid_float_complex * _pa, + liquid_float_complex * _ka); +void cheby1_azpkf(unsigned int _n, + float _ep, + liquid_float_complex * _z, + liquid_float_complex * _p, + liquid_float_complex * _k); +void cheby2_azpkf(unsigned int _n, + float _es, + liquid_float_complex * _z, + liquid_float_complex * _p, + liquid_float_complex * _k); +void ellip_azpkf(unsigned int _n, + float _ep, + float _es, + liquid_float_complex * _z, + liquid_float_complex * _p, + liquid_float_complex * _k); +void bessel_azpkf(unsigned int _n, + liquid_float_complex * _z, + liquid_float_complex * _p, + liquid_float_complex * _k); + +// compute frequency pre-warping factor +float iirdes_freqprewarp(liquid_iirdes_bandtype _btype, + float _fc, + float _f0); + +// convert analog z/p/k form to discrete z/p/k form (bilinear z-transform) +// _za : analog zeros [length: _nza] +// _nza : number of analog zeros +// _pa : analog poles [length: _npa] +// _npa : number of analog poles +// _m : frequency pre-warping factor +// _zd : output digital zeros [length: _npa] +// _pd : output digital poles [length: _npa] +// _kd : output digital gain (should actually be real-valued) +void bilinear_zpkf(liquid_float_complex * _za, + unsigned int _nza, + liquid_float_complex * _pa, + unsigned int _npa, + liquid_float_complex _ka, + float _m, + liquid_float_complex * _zd, + liquid_float_complex * _pd, + liquid_float_complex * _kd); + +// digital z/p/k low-pass to high-pass +// _zd : digital zeros (low-pass prototype), [length: _n] +// _pd : digital poles (low-pass prototype), [length: _n] +// _n : low-pass filter order +// _zdt : output digital zeros transformed [length: _n] +// _pdt : output digital poles transformed [length: _n] +void iirdes_dzpk_lp2hp(liquid_float_complex * _zd, + liquid_float_complex * _pd, + unsigned int _n, + liquid_float_complex * _zdt, + liquid_float_complex * _pdt); + +// digital z/p/k low-pass to band-pass +// _zd : digital zeros (low-pass prototype), [length: _n] +// _pd : digital poles (low-pass prototype), [length: _n] +// _n : low-pass filter order +// _f0 : center frequency +// _zdt : output digital zeros transformed [length: 2*_n] +// _pdt : output digital poles transformed [length: 2*_n] +void iirdes_dzpk_lp2bp(liquid_float_complex * _zd, + liquid_float_complex * _pd, + unsigned int _n, + float _f0, + liquid_float_complex * _zdt, + liquid_float_complex * _pdt); + +// convert discrete z/p/k form to transfer function +// _zd : digital zeros [length: _n] +// _pd : digital poles [length: _n] +// _n : filter order +// _kd : digital gain +// _b : output numerator [length: _n+1] +// _a : output denominator [length: _n+1] +void iirdes_dzpk2tff(liquid_float_complex * _zd, + liquid_float_complex * _pd, + unsigned int _n, + liquid_float_complex _kd, + float * _b, + float * _a); + +// convert discrete z/p/k form to second-order sections +// _zd : digital zeros [length: _n] +// _pd : digital poles [length: _n] +// _n : filter order +// _kd : digital gain +// _B : output numerator [size: 3 x L+r] +// _A : output denominator [size: 3 x L+r] +// where r = _n%2, L = (_n-r)/2 +void iirdes_dzpk2sosf(liquid_float_complex * _zd, + liquid_float_complex * _pd, + unsigned int _n, + liquid_float_complex _kd, + float * _B, + float * _A); + +// additional IIR filter design templates + +// design 2nd-order IIR filter (active lag) +// 1 + t2 * s +// F(s) = ------------ +// 1 + t1 * s +// +// _w : filter bandwidth +// _zeta : damping factor (1/sqrt(2) suggested) +// _K : loop gain (1000 suggested) +// _b : output feed-forward coefficients [size: 3 x 1] +// _a : output feed-back coefficients [size: 3 x 1] +void iirdes_pll_active_lag(float _w, + float _zeta, + float _K, + float * _b, + float * _a); + +// design 2nd-order IIR filter (active PI) +// 1 + t2 * s +// F(s) = ------------ +// t1 * s +// +// _w : filter bandwidth +// _zeta : damping factor (1/sqrt(2) suggested) +// _K : loop gain (1000 suggested) +// _b : output feed-forward coefficients [size: 3 x 1] +// _a : output feed-back coefficients [size: 3 x 1] +void iirdes_pll_active_PI(float _w, + float _zeta, + float _K, + float * _b, + float * _a); + +// checks stability of iir filter +// _b : feed-forward coefficients [size: _n x 1] +// _a : feed-back coefficients [size: _n x 1] +// _n : number of coefficients +int iirdes_isstable(float * _b, + float * _a, + unsigned int _n); + +// +// linear prediction +// + +// compute the linear prediction coefficients for an input signal _x +// _x : input signal [size: _n x 1] +// _n : input signal length +// _p : prediction filter order +// _a : prediction filter [size: _p+1 x 1] +// _e : prediction error variance [size: _p+1 x 1] +void liquid_lpc(float * _x, + unsigned int _n, + unsigned int _p, + float * _a, + float * _g); + +// solve the Yule-Walker equations using Levinson-Durbin recursion +// for _symmetric_ autocorrelation +// _r : autocorrelation array [size: _p+1 x 1] +// _p : filter order +// _a : output coefficients [size: _p+1 x 1] +// _e : error variance [size: _p+1 x 1] +// +// NOTES: +// By definition _a[0] = 1.0 +void liquid_levinson(float * _r, + unsigned int _p, + float * _a, + float * _e); + +// +// auto-correlator (delay cross-correlation) +// + +#define LIQUID_AUTOCORR_MANGLE_CCCF(name) LIQUID_CONCAT(autocorr_cccf,name) +#define LIQUID_AUTOCORR_MANGLE_RRRF(name) LIQUID_CONCAT(autocorr_rrrf,name) + +// Macro: +// AUTOCORR : name-mangling macro +// TO : output data type +// TC : coefficients data type +// TI : input data type +#define LIQUID_AUTOCORR_DEFINE_API(AUTOCORR,TO,TC,TI) \ + \ +/* Computes auto-correlation with a fixed lag on input signals */ \ +typedef struct AUTOCORR(_s) * AUTOCORR(); \ + \ +/* Create auto-correlator object with a particular window length and */ \ +/* delay */ \ +/* _window_size : size of the correlator window */ \ +/* _delay : correlator delay [samples] */ \ +AUTOCORR() AUTOCORR(_create)(unsigned int _window_size, \ + unsigned int _delay); \ + \ +/* Destroy auto-correlator object, freeing internal memory */ \ +void AUTOCORR(_destroy)(AUTOCORR() _q); \ + \ +/* Reset auto-correlator object's internals */ \ +void AUTOCORR(_reset)(AUTOCORR() _q); \ + \ +/* Print auto-correlator parameters to stdout */ \ +void AUTOCORR(_print)(AUTOCORR() _q); \ + \ +/* Push sample into auto-correlator object */ \ +/* _q : auto-correlator object */ \ +/* _x : single input sample */ \ +void AUTOCORR(_push)(AUTOCORR() _q, \ + TI _x); \ + \ +/* Write block of samples to auto-correlator object */ \ +/* _q : auto-correlation object */ \ +/* _x : input array [size: _n x 1] */ \ +/* _n : number of input samples */ \ +void AUTOCORR(_write)(AUTOCORR() _q, \ + TI * _x, \ + unsigned int _n); \ + \ +/* Compute single auto-correlation output */ \ +/* _q : auto-correlator object */ \ +/* _rxx : auto-correlated output */ \ +void AUTOCORR(_execute)(AUTOCORR() _q, \ + TO * _rxx); \ + \ +/* Compute auto-correlation on block of samples; the input and output */ \ +/* arrays may have the same pointer */ \ +/* _q : auto-correlation object */ \ +/* _x : input array [size: _n x 1] */ \ +/* _n : number of input, output samples */ \ +/* _rxx : input array [size: _n x 1] */ \ +void AUTOCORR(_execute_block)(AUTOCORR() _q, \ + TI * _x, \ + unsigned int _n, \ + TO * _rxx); \ + \ +/* return sum of squares of buffered samples */ \ +float AUTOCORR(_get_energy)(AUTOCORR() _q); \ + +LIQUID_AUTOCORR_DEFINE_API(LIQUID_AUTOCORR_MANGLE_CCCF, + liquid_float_complex, + liquid_float_complex, + liquid_float_complex) + +LIQUID_AUTOCORR_DEFINE_API(LIQUID_AUTOCORR_MANGLE_RRRF, + float, + float, + float) + + +// +// Finite impulse response filter +// + +#define LIQUID_FIRFILT_MANGLE_RRRF(name) LIQUID_CONCAT(firfilt_rrrf,name) +#define LIQUID_FIRFILT_MANGLE_CRCF(name) LIQUID_CONCAT(firfilt_crcf,name) +#define LIQUID_FIRFILT_MANGLE_CCCF(name) LIQUID_CONCAT(firfilt_cccf,name) + +// Macro: +// FIRFILT : name-mangling macro +// TO : output data type +// TC : coefficients data type +// TI : input data type +#define LIQUID_FIRFILT_DEFINE_API(FIRFILT,TO,TC,TI) \ + \ +/* Finite impulse response (FIR) filter */ \ +typedef struct FIRFILT(_s) * FIRFILT(); \ + \ +/* Create a finite impulse response filter (firfilt) object by directly */ \ +/* specifying the filter coefficients in an array */ \ +/* _h : filter coefficients [size: _n x 1] */ \ +/* _n : number of filter coefficients, _n > 0 */ \ +FIRFILT() FIRFILT(_create)(TC * _h, \ + unsigned int _n); \ + \ +/* Create object using Kaiser-Bessel windowed sinc method */ \ +/* _n : filter length, _n > 0 */ \ +/* _fc : filter normalized cut-off frequency, 0 < _fc < 0.5 */ \ +/* _As : filter stop-band attenuation [dB], _As > 0 */ \ +/* _mu : fractional sample offset, -0.5 < _mu < 0.5 */ \ +FIRFILT() FIRFILT(_create_kaiser)(unsigned int _n, \ + float _fc, \ + float _As, \ + float _mu); \ + \ +/* Create object from square-root Nyquist prototype. */ \ +/* The filter length will be \(2 k m + 1 \) samples long with a delay */ \ +/* of \( k m + 1 \) samples. */ \ +/* _type : filter type (e.g. LIQUID_FIRFILT_RRC) */ \ +/* _k : nominal samples per symbol, _k > 1 */ \ +/* _m : filter delay [symbols], _m > 0 */ \ +/* _beta : rolloff factor, 0 < beta <= 1 */ \ +/* _mu : fractional sample offset [samples], -0.5 < _mu < 0.5 */ \ +FIRFILT() FIRFILT(_create_rnyquist)(int _type, \ + unsigned int _k, \ + unsigned int _m, \ + float _beta, \ + float _mu); \ + \ +/* Create object from Parks-McClellan algorithm prototype */ \ +/* _h_len : filter length, _h_len > 0 */ \ +/* _fc : cutoff frequency, 0 < _fc < 0.5 */ \ +/* _As : stop-band attenuation [dB], _As > 0 */ \ +FIRFILT() FIRFILT(_create_firdespm)(unsigned int _h_len, \ + float _fc, \ + float _As); \ + \ +/* Create rectangular filter prototype; that is */ \ +/* \( \vec{h} = \{ 1, 1, 1, \ldots 1 \} \) */ \ +/* _n : length of filter [samples], 0 < _n <= 1024 */ \ +FIRFILT() FIRFILT(_create_rect)(unsigned int _n); \ + \ +/* Create DC blocking filter from prototype */ \ +/* _m : prototype filter semi-length such that filter length is 2*m+1 */ \ +/* _As : prototype filter stop-band attenuation [dB], _As > 0 */ \ +FIRFILT() FIRFILT(_create_dc_blocker)(unsigned int _m, \ + float _As); \ + \ +/* Create notch filter from prototype */ \ +/* _m : prototype filter semi-length such that filter length is 2*m+1 */ \ +/* _As : prototype filter stop-band attenuation [dB], _As > 0 */ \ +/* _f0 : center frequency for notch, _fc in [-0.5, 0.5] */ \ +FIRFILT() FIRFILT(_create_notch)(unsigned int _m, \ + float _As, \ + float _f0); \ + \ +/* Re-create filter object of potentially a different length with */ \ +/* different coefficients. If the length of the filter does not change, */ \ +/* not memory reallocation is invoked. */ \ +/* _q : original filter object */ \ +/* _h : pointer to filter coefficients, [size: _n x 1] */ \ +/* _n : filter length, _n > 0 */ \ +FIRFILT() FIRFILT(_recreate)(FIRFILT() _q, \ + TC * _h, \ + unsigned int _n); \ + \ +/* Destroy filter object and free all internal memory */ \ +void FIRFILT(_destroy)(FIRFILT() _q); \ + \ +/* Reset filter object's internal buffer */ \ +void FIRFILT(_reset)(FIRFILT() _q); \ + \ +/* Print filter object information to stdout */ \ +void FIRFILT(_print)(FIRFILT() _q); \ + \ +/* Set output scaling for filter */ \ +/* _q : filter object */ \ +/* _scale : scaling factor to apply to each output sample */ \ +void FIRFILT(_set_scale)(FIRFILT() _q, \ + TC _scale); \ + \ +/* Get output scaling for filter */ \ +/* _q : filter object */ \ +/* _scale : scaling factor applied to each output sample */ \ +void FIRFILT(_get_scale)(FIRFILT() _q, \ + TC * _scale); \ + \ +/* Push sample into filter object's internal buffer */ \ +/* _q : filter object */ \ +/* _x : single input sample */ \ +void FIRFILT(_push)(FIRFILT() _q, \ + TI _x); \ + \ +/* Write block of samples into filter object's internal buffer */ \ +/* _q : filter object */ \ +/* _x : buffer of input samples, [size: _n x 1] */ \ +/* _n : number of input samples */ \ +void FIRFILT(_write)(FIRFILT() _q, \ + TI * _x, \ + unsigned int _n); \ + \ +/* Execute vector dot product on the filter's internal buffer and */ \ +/* coefficients */ \ +/* _q : filter object */ \ +/* _y : pointer to single output sample */ \ +void FIRFILT(_execute)(FIRFILT() _q, \ + TO * _y); \ + \ +/* Execute the filter on a block of input samples; in-place operation */ \ +/* is permitted (_x and _y may point to the same place in memory) */ \ +/* _q : filter object */ \ +/* _x : pointer to input array, [size: _n x 1] */ \ +/* _n : number of input, output samples */ \ +/* _y : pointer to output array, [size: _n x 1] */ \ +void FIRFILT(_execute_block)(FIRFILT() _q, \ + TI * _x, \ + unsigned int _n, \ + TO * _y); \ + \ +/* Get length of filter object (number of internal coefficients) */ \ +unsigned int FIRFILT(_get_length)(FIRFILT() _q); \ + \ +/* Compute complex frequency response of filter object */ \ +/* _q : filter object */ \ +/* _fc : normalized frequency for evaluation */ \ +/* _H : pointer to output complex frequency response */ \ +void FIRFILT(_freqresponse)(FIRFILT() _q, \ + float _fc, \ + liquid_float_complex * _H); \ + \ +/* Compute and return group delay of filter object */ \ +/* _q : filter object */ \ +/* _fc : frequency to evaluate */ \ +float FIRFILT(_groupdelay)(FIRFILT() _q, \ + float _fc); \ + +LIQUID_FIRFILT_DEFINE_API(LIQUID_FIRFILT_MANGLE_RRRF, + float, + float, + float) + +LIQUID_FIRFILT_DEFINE_API(LIQUID_FIRFILT_MANGLE_CRCF, + liquid_float_complex, + float, + liquid_float_complex) + +LIQUID_FIRFILT_DEFINE_API(LIQUID_FIRFILT_MANGLE_CCCF, + liquid_float_complex, + liquid_float_complex, + liquid_float_complex) + +// +// FIR Hilbert transform +// 2:1 real-to-complex decimator +// 1:2 complex-to-real interpolator +// + +#define LIQUID_FIRHILB_MANGLE_FLOAT(name) LIQUID_CONCAT(firhilbf, name) +//#define LIQUID_FIRHILB_MANGLE_DOUBLE(name) LIQUID_CONCAT(firhilb, name) + +// NOTES: +// Although firhilb is a placeholder for both decimation and +// interpolation, separate objects should be used for each task. +#define LIQUID_FIRHILB_DEFINE_API(FIRHILB,T,TC) \ + \ +/* Finite impulse response (FIR) Hilbert transform */ \ +typedef struct FIRHILB(_s) * FIRHILB(); \ + \ +/* Create a firhilb object with a particular filter semi-length and */ \ +/* desired stop-band attenuation. */ \ +/* Internally the object designs a half-band filter based on applying */ \ +/* a Kaiser-Bessel window to a sinc function to guarantee zeros at all */ \ +/* off-center odd indexed samples. */ \ +/* _m : filter semi-length, delay is \( 2 m + 1 \) */ \ +/* _As : filter stop-band attenuation [dB] */ \ +FIRHILB() FIRHILB(_create)(unsigned int _m, \ + float _As); \ + \ +/* Destroy finite impulse response Hilbert transform, freeing all */ \ +/* internally-allocted memory and objects. */ \ +void FIRHILB(_destroy)(FIRHILB() _q); \ + \ +/* Print firhilb object internals to stdout */ \ +void FIRHILB(_print)(FIRHILB() _q); \ + \ +/* Reset firhilb object internal state */ \ +void FIRHILB(_reset)(FIRHILB() _q); \ + \ +/* Execute Hilbert transform (real to complex) */ \ +/* _q : Hilbert transform object */ \ +/* _x : real-valued input sample */ \ +/* _y : complex-valued output sample */ \ +void FIRHILB(_r2c_execute)(FIRHILB() _q, \ + T _x, \ + TC * _y); \ + \ +/* Execute Hilbert transform (complex to real) */ \ +/* _q : Hilbert transform object */ \ +/* _x : complex-valued input sample */ \ +/* _y0 : real-valued output sample, lower side-band retained */ \ +/* _y1 : real-valued output sample, upper side-band retained */ \ +void FIRHILB(_c2r_execute)(FIRHILB() _q, \ + TC _x, \ + T * _y0, \ + T * _y1); \ + \ +/* Execute Hilbert transform decimator (real to complex) */ \ +/* _q : Hilbert transform object */ \ +/* _x : real-valued input array, [size: 2 x 1] */ \ +/* _y : complex-valued output sample */ \ +void FIRHILB(_decim_execute)(FIRHILB() _q, \ + T * _x, \ + TC * _y); \ + \ +/* Execute Hilbert transform decimator (real to complex) on a block of */ \ +/* samples */ \ +/* _q : Hilbert transform object */ \ +/* _x : real-valued input array, [size: 2*_n x 1] */ \ +/* _n : number of output samples */ \ +/* _y : complex-valued output array, [size: _n x 1] */ \ +void FIRHILB(_decim_execute_block)(FIRHILB() _q, \ + T * _x, \ + unsigned int _n, \ + TC * _y); \ + \ +/* Execute Hilbert transform interpolator (real to complex) */ \ +/* _q : Hilbert transform object */ \ +/* _x : complex-valued input sample */ \ +/* _y : real-valued output array, [size: 2 x 1] */ \ +void FIRHILB(_interp_execute)(FIRHILB() _q, \ + TC _x, \ + T * _y); \ + \ +/* Execute Hilbert transform interpolator (complex to real) on a block */ \ +/* of samples */ \ +/* _q : Hilbert transform object */ \ +/* _x : complex-valued input array, [size: _n x 1] */ \ +/* _n : number of *input* samples */ \ +/* _y : real-valued output array, [size: 2*_n x 1] */ \ +void FIRHILB(_interp_execute_block)(FIRHILB() _q, \ + TC * _x, \ + unsigned int _n, \ + T * _y); \ + +LIQUID_FIRHILB_DEFINE_API(LIQUID_FIRHILB_MANGLE_FLOAT, float, liquid_float_complex) +//LIQUID_FIRHILB_DEFINE_API(LIQUID_FIRHILB_MANGLE_DOUBLE, double, liquid_double_complex) + + +// +// Infinite impulse response (IIR) Hilbert transform +// 2:1 real-to-complex decimator +// 1:2 complex-to-real interpolator +// + +#define LIQUID_IIRHILB_MANGLE_FLOAT(name) LIQUID_CONCAT(iirhilbf, name) +//#define LIQUID_IIRHILB_MANGLE_DOUBLE(name) LIQUID_CONCAT(iirhilb, name) + +// NOTES: +// Although iirhilb is a placeholder for both decimation and +// interpolation, separate objects should be used for each task. +#define LIQUID_IIRHILB_DEFINE_API(IIRHILB,T,TC) \ + \ +/* Infinite impulse response (IIR) Hilbert transform */ \ +typedef struct IIRHILB(_s) * IIRHILB(); \ + \ +/* Create a iirhilb object with a particular filter type, order, and */ \ +/* desired pass- and stop-band attenuation. */ \ +/* _ftype : filter type (e.g. LIQUID_IIRDES_BUTTER) */ \ +/* _n : filter order, _n > 0 */ \ +/* _Ap : pass-band ripple [dB], _Ap > 0 */ \ +/* _As : stop-band ripple [dB], _Ap > 0 */ \ +IIRHILB() IIRHILB(_create)(liquid_iirdes_filtertype _ftype, \ + unsigned int _n, \ + float _Ap, \ + float _As); \ + \ +/* Create a default iirhilb object with a particular filter order. */ \ +/* _n : filter order, _n > 0 */ \ +IIRHILB() IIRHILB(_create_default)(unsigned int _n); \ + \ +/* Destroy finite impulse response Hilbert transform, freeing all */ \ +/* internally-allocted memory and objects. */ \ +void IIRHILB(_destroy)(IIRHILB() _q); \ + \ +/* Print iirhilb object internals to stdout */ \ +void IIRHILB(_print)(IIRHILB() _q); \ + \ +/* Reset iirhilb object internal state */ \ +void IIRHILB(_reset)(IIRHILB() _q); \ + \ +/* Execute Hilbert transform (real to complex) */ \ +/* _q : Hilbert transform object */ \ +/* _x : real-valued input sample */ \ +/* _y : complex-valued output sample */ \ +void IIRHILB(_r2c_execute)(IIRHILB() _q, \ + T _x, \ + TC * _y); \ + \ +/* Execute Hilbert transform (complex to real) */ \ +/* _q : Hilbert transform object */ \ +/* _x : complex-valued input sample */ \ +/* _y : real-valued output sample */ \ +void IIRHILB(_c2r_execute)(IIRHILB() _q, \ + TC _x, \ + T * _y); \ + \ +/* Execute Hilbert transform decimator (real to complex) */ \ +/* _q : Hilbert transform object */ \ +/* _x : real-valued input array, [size: 2 x 1] */ \ +/* _y : complex-valued output sample */ \ +void IIRHILB(_decim_execute)(IIRHILB() _q, \ + T * _x, \ + TC * _y); \ + \ +/* Execute Hilbert transform decimator (real to complex) on a block of */ \ +/* samples */ \ +/* _q : Hilbert transform object */ \ +/* _x : real-valued input array, [size: 2*_n x 1] */ \ +/* _n : number of output samples */ \ +/* _y : complex-valued output array, [size: _n x 1] */ \ +void IIRHILB(_decim_execute_block)(IIRHILB() _q, \ + T * _x, \ + unsigned int _n, \ + TC * _y); \ + \ +/* Execute Hilbert transform interpolator (real to complex) */ \ +/* _q : Hilbert transform object */ \ +/* _x : complex-valued input sample */ \ +/* _y : real-valued output array, [size: 2 x 1] */ \ +void IIRHILB(_interp_execute)(IIRHILB() _q, \ + TC _x, \ + T * _y); \ + \ +/* Execute Hilbert transform interpolator (complex to real) on a block */ \ +/* of samples */ \ +/* _q : Hilbert transform object */ \ +/* _x : complex-valued input array, [size: _n x 1] */ \ +/* _n : number of *input* samples */ \ +/* _y : real-valued output array, [size: 2*_n x 1] */ \ +void IIRHILB(_interp_execute_block)(IIRHILB() _q, \ + TC * _x, \ + unsigned int _n, \ + T * _y); \ + +LIQUID_IIRHILB_DEFINE_API(LIQUID_IIRHILB_MANGLE_FLOAT, float, liquid_float_complex) +//LIQUID_IIRHILB_DEFINE_API(LIQUID_IIRHILB_MANGLE_DOUBLE, double, liquid_double_complex) + + +// +// FFT-based finite impulse response filter +// + +#define LIQUID_FFTFILT_MANGLE_RRRF(name) LIQUID_CONCAT(fftfilt_rrrf,name) +#define LIQUID_FFTFILT_MANGLE_CRCF(name) LIQUID_CONCAT(fftfilt_crcf,name) +#define LIQUID_FFTFILT_MANGLE_CCCF(name) LIQUID_CONCAT(fftfilt_cccf,name) + +// Macro: +// FFTFILT : name-mangling macro +// TO : output data type +// TC : coefficients data type +// TI : input data type +#define LIQUID_FFTFILT_DEFINE_API(FFTFILT,TO,TC,TI) \ + \ +/* Fast Fourier transform (FFT) finite impulse response filter */ \ +typedef struct FFTFILT(_s) * FFTFILT(); \ + \ +/* Create FFT-based FIR filter using external coefficients */ \ +/* _h : filter coefficients, [size: _h_len x 1] */ \ +/* _h_len : filter length, _h_len > 0 */ \ +/* _n : block size = nfft/2, _n >= _h_len-1 */ \ +FFTFILT() FFTFILT(_create)(TC * _h, \ + unsigned int _h_len, \ + unsigned int _n); \ + \ +/* Destroy filter object and free all internal memory */ \ +void FFTFILT(_destroy)(FFTFILT() _q); \ + \ +/* Reset filter object's internal buffer */ \ +void FFTFILT(_reset)(FFTFILT() _q); \ + \ +/* Print filter object information to stdout */ \ +void FFTFILT(_print)(FFTFILT() _q); \ + \ +/* Set output scaling for filter */ \ +void FFTFILT(_set_scale)(FFTFILT() _q, \ + TC _scale); \ + \ +/* Get output scaling for filter */ \ +void FFTFILT(_get_scale)(FFTFILT() _q, \ + TC * _scale); \ + \ +/* Execute the filter on internal buffer and coefficients given a block */ \ +/* of input samples; in-place operation is permitted (_x and _y may */ \ +/* point to the same place in memory) */ \ +/* _q : filter object */ \ +/* _x : pointer to input data array, [size: _n x 1] */ \ +/* _y : pointer to output data array, [size: _n x 1] */ \ +void FFTFILT(_execute)(FFTFILT() _q, \ + TI * _x, \ + TO * _y); \ + \ +/* Get length of filter object's internal coefficients */ \ +unsigned int FFTFILT(_get_length)(FFTFILT() _q); \ + +LIQUID_FFTFILT_DEFINE_API(LIQUID_FFTFILT_MANGLE_RRRF, + float, + float, + float) + +LIQUID_FFTFILT_DEFINE_API(LIQUID_FFTFILT_MANGLE_CRCF, + liquid_float_complex, + float, + liquid_float_complex) + +LIQUID_FFTFILT_DEFINE_API(LIQUID_FFTFILT_MANGLE_CCCF, + liquid_float_complex, + liquid_float_complex, + liquid_float_complex) + + +// +// Infinite impulse response filter +// + +#define LIQUID_IIRFILT_MANGLE_RRRF(name) LIQUID_CONCAT(iirfilt_rrrf,name) +#define LIQUID_IIRFILT_MANGLE_CRCF(name) LIQUID_CONCAT(iirfilt_crcf,name) +#define LIQUID_IIRFILT_MANGLE_CCCF(name) LIQUID_CONCAT(iirfilt_cccf,name) + +// Macro: +// IIRFILT : name-mangling macro +// TO : output data type +// TC : coefficients data type +// TI : input data type +#define LIQUID_IIRFILT_DEFINE_API(IIRFILT,TO,TC,TI) \ + \ +/* Infinite impulse response (IIR) filter */ \ +typedef struct IIRFILT(_s) * IIRFILT(); \ + \ +/* Create infinite impulse response filter from external coefficients. */ \ +/* Note that the number of feed-forward and feed-back coefficients do */ \ +/* not need to be equal, but they do need to be non-zero. */ \ +/* Furthermore, the first feed-back coefficient \(a_0\) cannot be */ \ +/* equal to zero, otherwise the filter will be invalid as this value is */ \ +/* factored out from all coefficients. */ \ +/* For stability reasons the number of coefficients should reasonably */ \ +/* not exceed about 8 for single-precision floating-point. */ \ +/* _b : feed-forward coefficients (numerator), [size: _nb x 1] */ \ +/* _nb : number of feed-forward coefficients, _nb > 0 */ \ +/* _a : feed-back coefficients (denominator), [size: _na x 1] */ \ +/* _na : number of feed-back coefficients, _na > 0 */ \ +IIRFILT() IIRFILT(_create)(TC * _b, \ + unsigned int _nb, \ + TC * _a, \ + unsigned int _na); \ + \ +/* Create IIR filter using 2nd-order secitons from external */ \ +/* coefficients. */ \ +/* _B : feed-forward coefficients [size: _nsos x 3] */ \ +/* _A : feed-back coefficients [size: _nsos x 3] */ \ +/* _nsos : number of second-order sections (sos), _nsos > 0 */ \ +IIRFILT() IIRFILT(_create_sos)(TC * _B, \ + TC * _A, \ + unsigned int _nsos); \ + \ +/* Create IIR filter from design template */ \ +/* _ftype : filter type (e.g. LIQUID_IIRDES_BUTTER) */ \ +/* _btype : band type (e.g. LIQUID_IIRDES_BANDPASS) */ \ +/* _format : coefficients format (e.g. LIQUID_IIRDES_SOS) */ \ +/* _order : filter order, _order > 0 */ \ +/* _fc : low-pass prototype cut-off frequency, 0 <= _fc <= 0.5 */ \ +/* _f0 : center frequency (band-pass, band-stop), 0 <= _f0 <= 0.5 */ \ +/* _Ap : pass-band ripple in dB, _Ap > 0 */ \ +/* _As : stop-band ripple in dB, _As > 0 */ \ +IIRFILT() IIRFILT(_create_prototype)( \ + liquid_iirdes_filtertype _ftype, \ + liquid_iirdes_bandtype _btype, \ + liquid_iirdes_format _format, \ + unsigned int _order, \ + float _fc, \ + float _f0, \ + float _Ap, \ + float _As); \ + \ +/* Create simplified low-pass Butterworth IIR filter */ \ +/* _order : filter order, _order > 0 */ \ +/* _fc : low-pass prototype cut-off frequency */ \ +IIRFILT() IIRFILT(_create_lowpass)(unsigned int _order, \ + float _fc); \ + \ +/* Create 8th-order integrator filter */ \ +IIRFILT() IIRFILT(_create_integrator)(void); \ + \ +/* Create 8th-order differentiator filter */ \ +IIRFILT() IIRFILT(_create_differentiator)(void); \ + \ +/* Create simple first-order DC-blocking filter with transfer function */ \ +/* \( H(z) = \frac{1 - z^{-1}}{1 - (1-\alpha)z^{-1}} \) */ \ +/* _alpha : normalized filter bandwidth, _alpha > 0 */ \ +IIRFILT() IIRFILT(_create_dc_blocker)(float _alpha); \ + \ +/* Create filter to operate as second-order integrating phase-locked */ \ +/* loop (active lag design) */ \ +/* _w : filter bandwidth, 0 < _w < 1 */ \ +/* _zeta : damping factor, \( 1/\sqrt{2} \) suggested, 0 < _zeta < 1 */ \ +/* _K : loop gain, 1000 suggested, _K > 0 */ \ +IIRFILT() IIRFILT(_create_pll)(float _w, \ + float _zeta, \ + float _K); \ + \ +/* Destroy iirfilt object, freeing all internal memory */ \ +void IIRFILT(_destroy)(IIRFILT() _q); \ + \ +/* Print iirfilt object properties to stdout */ \ +void IIRFILT(_print)(IIRFILT() _q); \ + \ +/* Reset iirfilt object internals */ \ +void IIRFILT(_reset)(IIRFILT() _q); \ + \ +/* Compute filter output given a signle input sample */ \ +/* _q : iirfilt object */ \ +/* _x : input sample */ \ +/* _y : output sample pointer */ \ +void IIRFILT(_execute)(IIRFILT() _q, \ + TI _x, \ + TO * _y); \ + \ +/* Execute the filter on a block of input samples; */ \ +/* in-place operation is permitted (the input and output buffers may be */ \ +/* the same) */ \ +/* _q : filter object */ \ +/* _x : pointer to input array, [size: _n x 1] */ \ +/* _n : number of input, output samples, _n > 0 */ \ +/* _y : pointer to output array, [size: _n x 1] */ \ +void IIRFILT(_execute_block)(IIRFILT() _q, \ + TI * _x, \ + unsigned int _n, \ + TO * _y); \ + \ +/* Return number of coefficients for iirfilt object (maximum between */ \ +/* the feed-forward and feed-back coefficients). Note that the filter */ \ +/* length = filter order + 1 */ \ +unsigned int IIRFILT(_get_length)(IIRFILT() _q); \ + \ +/* Compute complex frequency response of filter object */ \ +/* _q : filter object */ \ +/* _fc : normalized frequency for evaluation */ \ +/* _H : pointer to output complex frequency response */ \ +void IIRFILT(_freqresponse)(IIRFILT() _q, \ + float _fc, \ + liquid_float_complex * _H); \ + \ +/* Compute and return group delay of filter object */ \ +/* _q : filter object */ \ +/* _fc : frequency to evaluate */ \ +float IIRFILT(_groupdelay)(IIRFILT() _q, float _fc); \ + +LIQUID_IIRFILT_DEFINE_API(LIQUID_IIRFILT_MANGLE_RRRF, + float, + float, + float) + +LIQUID_IIRFILT_DEFINE_API(LIQUID_IIRFILT_MANGLE_CRCF, + liquid_float_complex, + float, + liquid_float_complex) + +LIQUID_IIRFILT_DEFINE_API(LIQUID_IIRFILT_MANGLE_CCCF, + liquid_float_complex, + liquid_float_complex, + liquid_float_complex) + + +// +// FIR Polyphase filter bank +// +#define LIQUID_FIRPFB_MANGLE_RRRF(name) LIQUID_CONCAT(firpfb_rrrf,name) +#define LIQUID_FIRPFB_MANGLE_CRCF(name) LIQUID_CONCAT(firpfb_crcf,name) +#define LIQUID_FIRPFB_MANGLE_CCCF(name) LIQUID_CONCAT(firpfb_cccf,name) + +// Macro: +// FIRPFB : name-mangling macro +// TO : output data type +// TC : coefficients data type +// TI : input data type +#define LIQUID_FIRPFB_DEFINE_API(FIRPFB,TO,TC,TI) \ + \ +/* Finite impulse response (FIR) polyphase filter bank (PFB) */ \ +typedef struct FIRPFB(_s) * FIRPFB(); \ + \ +/* Create firpfb object with _M sub-filter each of length _h_len/_M */ \ +/* from an external array of coefficients */ \ +/* _M : number of filters in the bank, _M > 1 */ \ +/* _h : coefficients, [size: _h_len x 1] */ \ +/* _h_len : filter length (multiple of _M), _h_len >= _M */ \ +FIRPFB() FIRPFB(_create)(unsigned int _M, \ + TC * _h, \ + unsigned int _h_len); \ + \ +/* Create firpfb object using Kaiser-Bessel windowed sinc filter design */ \ +/* method, using default values for cut-off frequency and stop-band */ \ +/* attenuation. This is equivalent to: */ \ +/* FIRPFB(_create_kaiser)(_M, _m, 0.5, 60.0) */ \ +/* which creates a Nyquist filter at the appropriate cut-off frequency. */ \ +/* _M : number of filters in the bank, _M > 0 */ \ +/* _m : filter semi-length [samples], _m > 0 */ \ +FIRPFB() FIRPFB(_create_default)(unsigned int _M, \ + unsigned int _m); \ + \ +/* Create firpfb object using Kaiser-Bessel windowed sinc filter design */ \ +/* method */ \ +/* _M : number of filters in the bank, _M > 0 */ \ +/* _m : filter semi-length [samples], _m > 0 */ \ +/* _fc : filter normalized cut-off frequency, 0 < _fc < 0.5 */ \ +/* _As : filter stop-band suppression [dB], _As > 0 */ \ +FIRPFB() FIRPFB(_create_kaiser)(unsigned int _M, \ + unsigned int _m, \ + float _fc, \ + float _As); \ + \ +/* Create firpfb from square-root Nyquist prototype */ \ +/* _type : filter type (e.g. LIQUID_FIRFILT_RRC) */ \ +/* _M : number of filters in the bank, _M > 0 */ \ +/* _k : nominal samples/symbol, _k > 1 */ \ +/* _m : filter delay [symbols], _m > 0 */ \ +/* _beta : rolloff factor, 0 < _beta <= 1 */ \ +FIRPFB() FIRPFB(_create_rnyquist)(int _type, \ + unsigned int _M, \ + unsigned int _k, \ + unsigned int _m, \ + float _beta); \ + \ +/* Create from square-root derivative Nyquist prototype */ \ +/* _type : filter type (e.g. LIQUID_FIRFILT_RRC) */ \ +/* _M : number of filters in the bank, _M > 0 */ \ +/* _k : nominal samples/symbol, _k > 1 */ \ +/* _m : filter delay [symbols], _m > 0 */ \ +/* _beta : rolloff factor, 0 < _beta <= 1 */ \ +FIRPFB() FIRPFB(_create_drnyquist)(int _type, \ + unsigned int _M, \ + unsigned int _k, \ + unsigned int _m, \ + float _beta); \ + \ +/* Re-create firpfb object of potentially a different length with */ \ +/* different coefficients. If the length of the filter does not change, */ \ +/* not memory reallocation is invoked. */ \ +/* _q : original firpfb object */ \ +/* _M : number of filters in the bank, _M > 1 */ \ +/* _h : coefficients, [size: _h_len x 1] */ \ +/* _h_len : filter length (multiple of _M), _h_len >= _M */ \ +FIRPFB() FIRPFB(_recreate)(FIRPFB() _q, \ + unsigned int _M, \ + TC * _h, \ + unsigned int _h_len); \ + \ +/* Destroy firpfb object, freeing all internal memory and destroying */ \ +/* all internal objects */ \ +void FIRPFB(_destroy)(FIRPFB() _q); \ + \ +/* Print firpfb object's parameters to stdout */ \ +void FIRPFB(_print)(FIRPFB() _q); \ + \ +/* Set output scaling for filter */ \ +/* _q : filter object */ \ +/* _scale : scaling factor to apply to each output sample */ \ +void FIRPFB(_set_scale)(FIRPFB() _q, \ + TC _scale); \ + \ +/* Get output scaling for filter */ \ +/* _q : filter object */ \ +/* _scale : scaling factor applied to each output sample */ \ +void FIRPFB(_get_scale)(FIRPFB() _q, \ + TC * _scale); \ + \ +/* Reset firpfb object's internal buffer */ \ +void FIRPFB(_reset)(FIRPFB() _q); \ + \ +/* Push sample into filter object's internal buffer */ \ +/* _q : filter object */ \ +/* _x : single input sample */ \ +void FIRPFB(_push)(FIRPFB() _q, \ + TI _x); \ + \ +/* Execute vector dot product on the filter's internal buffer and */ \ +/* coefficients using the coefficients from sub-filter at index _i */ \ +/* _q : firpfb object */ \ +/* _i : index of filter to use */ \ +/* _y : pointer to output sample */ \ +void FIRPFB(_execute)(FIRPFB() _q, \ + unsigned int _i, \ + TO * _y); \ + \ +/* Execute the filter on a block of input samples, all using index _i. */ \ +/* In-place operation is permitted (_x and _y may point to the same */ \ +/* place in memory) */ \ +/* _q : firpfb object */ \ +/* _i : index of filter to use */ \ +/* _x : pointer to input array [size: _n x 1] */ \ +/* _n : number of input, output samples */ \ +/* _y : pointer to output array [size: _n x 1] */ \ +void FIRPFB(_execute_block)(FIRPFB() _q, \ + unsigned int _i, \ + TI * _x, \ + unsigned int _n, \ + TO * _y); \ + +LIQUID_FIRPFB_DEFINE_API(LIQUID_FIRPFB_MANGLE_RRRF, + float, + float, + float) + +LIQUID_FIRPFB_DEFINE_API(LIQUID_FIRPFB_MANGLE_CRCF, + liquid_float_complex, + float, + liquid_float_complex) + +LIQUID_FIRPFB_DEFINE_API(LIQUID_FIRPFB_MANGLE_CCCF, + liquid_float_complex, + liquid_float_complex, + liquid_float_complex) + +// +// Interpolators +// + +// firinterp : finite impulse response interpolator +#define LIQUID_FIRINTERP_MANGLE_RRRF(name) LIQUID_CONCAT(firinterp_rrrf,name) +#define LIQUID_FIRINTERP_MANGLE_CRCF(name) LIQUID_CONCAT(firinterp_crcf,name) +#define LIQUID_FIRINTERP_MANGLE_CCCF(name) LIQUID_CONCAT(firinterp_cccf,name) + +#define LIQUID_FIRINTERP_DEFINE_API(FIRINTERP,TO,TC,TI) \ + \ +/* Finite impulse response (FIR) interpolator */ \ +typedef struct FIRINTERP(_s) * FIRINTERP(); \ + \ +/* Create interpolator from external coefficients. Internally the */ \ +/* interpolator creates a polyphase filter bank to efficiently realize */ \ +/* resampling of the input signal. */ \ +/* If the input filter length is not a multiple of the interpolation */ \ +/* factor, the object internally pads the coefficients with zeros to */ \ +/* compensate. */ \ +/* _M : interpolation factor, _M >= 2 */ \ +/* _h : filter coefficients, [size: _h_len x 1] */ \ +/* _h_len : filter length, _h_len >= _M */ \ +FIRINTERP() FIRINTERP(_create)(unsigned int _M, \ + TC * _h, \ + unsigned int _h_len); \ + \ +/* Create interpolator from filter prototype prototype (Kaiser-Bessel */ \ +/* windowed-sinc function) */ \ +/* _M : interpolation factor, _M >= 2 */ \ +/* _m : filter delay [symbols], _m >= 1 */ \ +/* _As : stop-band attenuation [dB], _As >= 0 */ \ +FIRINTERP() FIRINTERP(_create_kaiser)(unsigned int _M, \ + unsigned int _m, \ + float _As); \ + \ +/* Create interpolator object from filter prototype */ \ +/* _type : filter type (e.g. LIQUID_FIRFILT_RCOS) */ \ +/* _M : interpolation factor, _M > 1 */ \ +/* _m : filter delay (symbols), _m > 0 */ \ +/* _beta : excess bandwidth factor, 0 <= _beta <= 1 */ \ +/* _dt : fractional sample delay, -1 <= _dt <= 1 */ \ +FIRINTERP() FIRINTERP(_create_prototype)(int _type, \ + unsigned int _M, \ + unsigned int _m, \ + float _beta, \ + float _dt); \ + \ +/* Create linear interpolator object */ \ +/* _M : interpolation factor, _M > 1 */ \ +FIRINTERP() FIRINTERP(_create_linear)(unsigned int _M); \ + \ +/* Create window interpolator object */ \ +/* _M : interpolation factor, _M > 1 */ \ +/* _m : filter semi-length, _m > 0 */ \ +FIRINTERP() FIRINTERP(_create_window)(unsigned int _M, \ + unsigned int _m); \ + \ +/* Destroy firinterp object, freeing all internal memory */ \ +void FIRINTERP(_destroy)(FIRINTERP() _q); \ + \ +/* Print firinterp object's internal properties to stdout */ \ +void FIRINTERP(_print)(FIRINTERP() _q); \ + \ +/* Reset internal state */ \ +void FIRINTERP(_reset)(FIRINTERP() _q); \ + \ +/* Get interpolation rate */ \ +unsigned int FIRINTERP(_get_interp_rate)(FIRINTERP() _q); \ + \ +/* Set output scaling for interpolator */ \ +/* _q : interpolator object */ \ +/* _scale : scaling factor to apply to each output sample */ \ +void FIRINTERP(_set_scale)(FIRINTERP() _q, \ + TC _scale); \ + \ +/* Get output scaling for interpolator */ \ +/* _q : interpolator object */ \ +/* _scale : scaling factor to apply to each output sample */ \ +void FIRINTERP(_get_scale)(FIRINTERP() _q, \ + TC * _scale); \ + \ +/* Execute interpolation on single input sample and write \(M\) output */ \ +/* samples (\(M\) is the interpolation factor) */ \ +/* _q : firinterp object */ \ +/* _x : input sample */ \ +/* _y : output sample array, [size: _M x 1] */ \ +void FIRINTERP(_execute)(FIRINTERP() _q, \ + TI _x, \ + TO * _y); \ + \ +/* Execute interpolation on block of input samples */ \ +/* _q : firinterp object */ \ +/* _x : input array, [size: _n x 1] */ \ +/* _n : size of input array */ \ +/* _y : output sample array, [size: _M*_n x 1] */ \ +void FIRINTERP(_execute_block)(FIRINTERP() _q, \ + TI * _x, \ + unsigned int _n, \ + TO * _y); \ + +LIQUID_FIRINTERP_DEFINE_API(LIQUID_FIRINTERP_MANGLE_RRRF, + float, + float, + float) + +LIQUID_FIRINTERP_DEFINE_API(LIQUID_FIRINTERP_MANGLE_CRCF, + liquid_float_complex, + float, + liquid_float_complex) + +LIQUID_FIRINTERP_DEFINE_API(LIQUID_FIRINTERP_MANGLE_CCCF, + liquid_float_complex, + liquid_float_complex, + liquid_float_complex) + +// iirinterp : infinite impulse response interpolator +#define LIQUID_IIRINTERP_MANGLE_RRRF(name) LIQUID_CONCAT(iirinterp_rrrf,name) +#define LIQUID_IIRINTERP_MANGLE_CRCF(name) LIQUID_CONCAT(iirinterp_crcf,name) +#define LIQUID_IIRINTERP_MANGLE_CCCF(name) LIQUID_CONCAT(iirinterp_cccf,name) + +#define LIQUID_IIRINTERP_DEFINE_API(IIRINTERP,TO,TC,TI) \ + \ +/* Infinite impulse response (IIR) interpolator */ \ +typedef struct IIRINTERP(_s) * IIRINTERP(); \ + \ +/* Create infinite impulse response interpolator from external */ \ +/* coefficients. */ \ +/* Note that the number of feed-forward and feed-back coefficients do */ \ +/* not need to be equal, but they do need to be non-zero. */ \ +/* Furthermore, the first feed-back coefficient \(a_0\) cannot be */ \ +/* equal to zero, otherwise the filter will be invalid as this value is */ \ +/* factored out from all coefficients. */ \ +/* For stability reasons the number of coefficients should reasonably */ \ +/* not exceed about 8 for single-precision floating-point. */ \ +/* _M : interpolation factor, _M >= 2 */ \ +/* _b : feed-forward coefficients (numerator), [size: _nb x 1] */ \ +/* _nb : number of feed-forward coefficients, _nb > 0 */ \ +/* _a : feed-back coefficients (denominator), [size: _na x 1] */ \ +/* _na : number of feed-back coefficients, _na > 0 */ \ +IIRINTERP() IIRINTERP(_create)(unsigned int _M, \ + TC * _b, \ + unsigned int _nb, \ + TC * _a, \ + unsigned int _na); \ + \ +/* Create interpolator object with default Butterworth prototype */ \ +/* _M : interpolation factor, _M >= 2 */ \ +/* _order : filter order, _order > 0 */ \ +IIRINTERP() IIRINTERP(_create_default)(unsigned int _M, \ + unsigned int _order); \ + \ +/* Create IIR interpolator from prototype */ \ +/* _M : interpolation factor, _M >= 2 */ \ +/* _ftype : filter type (e.g. LIQUID_IIRDES_BUTTER) */ \ +/* _btype : band type (e.g. LIQUID_IIRDES_BANDPASS) */ \ +/* _format : coefficients format (e.g. LIQUID_IIRDES_SOS) */ \ +/* _order : filter order, _order > 0 */ \ +/* _fc : low-pass prototype cut-off frequency, 0 <= _fc <= 0.5 */ \ +/* _f0 : center frequency (band-pass, band-stop), 0 <= _f0 <= 0.5 */ \ +/* _Ap : pass-band ripple in dB, _Ap > 0 */ \ +/* _As : stop-band ripple in dB, _As > 0 */ \ +IIRINTERP() IIRINTERP(_create_prototype)( \ + unsigned int _M, \ + liquid_iirdes_filtertype _ftype, \ + liquid_iirdes_bandtype _btype, \ + liquid_iirdes_format _format, \ + unsigned int _order, \ + float _fc, \ + float _f0, \ + float _Ap, \ + float _As); \ + \ +/* Destroy interpolator object and free internal memory */ \ +void IIRINTERP(_destroy)(IIRINTERP() _q); \ + \ +/* Print interpolator object internals to stdout */ \ +void IIRINTERP(_print)(IIRINTERP() _q); \ + \ +/* Reset interpolator object */ \ +void IIRINTERP(_reset)(IIRINTERP() _q); \ + \ +/* Execute interpolation on single input sample and write \(M\) output */ \ +/* samples (\(M\) is the interpolation factor) */ \ +/* _q : iirinterp object */ \ +/* _x : input sample */ \ +/* _y : output sample array, [size: _M x 1] */ \ +void IIRINTERP(_execute)(IIRINTERP() _q, \ + TI _x, \ + TO * _y); \ + \ +/* Execute interpolation on block of input samples */ \ +/* _q : iirinterp object */ \ +/* _x : input array, [size: _n x 1] */ \ +/* _n : size of input array */ \ +/* _y : output sample array, [size: _M*_n x 1] */ \ +void IIRINTERP(_execute_block)(IIRINTERP() _q, \ + TI * _x, \ + unsigned int _n, \ + TO * _y); \ + \ +/* Compute and return group delay of object */ \ +/* _q : filter object */ \ +/* _fc : frequency to evaluate */ \ +float IIRINTERP(_groupdelay)(IIRINTERP() _q, \ + float _fc); \ + +LIQUID_IIRINTERP_DEFINE_API(LIQUID_IIRINTERP_MANGLE_RRRF, + float, + float, + float) + +LIQUID_IIRINTERP_DEFINE_API(LIQUID_IIRINTERP_MANGLE_CRCF, + liquid_float_complex, + float, + liquid_float_complex) + +LIQUID_IIRINTERP_DEFINE_API(LIQUID_IIRINTERP_MANGLE_CCCF, + liquid_float_complex, + liquid_float_complex, + liquid_float_complex) + +// +// Decimators +// + +// firdecim : finite impulse response decimator +#define LIQUID_FIRDECIM_MANGLE_RRRF(name) LIQUID_CONCAT(firdecim_rrrf,name) +#define LIQUID_FIRDECIM_MANGLE_CRCF(name) LIQUID_CONCAT(firdecim_crcf,name) +#define LIQUID_FIRDECIM_MANGLE_CCCF(name) LIQUID_CONCAT(firdecim_cccf,name) + +#define LIQUID_FIRDECIM_DEFINE_API(FIRDECIM,TO,TC,TI) \ + \ +/* Finite impulse response (FIR) decimator */ \ +typedef struct FIRDECIM(_s) * FIRDECIM(); \ + \ +/* Create decimator from external coefficients */ \ +/* _M : decimation factor, _M >= 2 */ \ +/* _h : filter coefficients, [size: _h_len x 1] */ \ +/* _h_len : filter length, _h_len >= _M */ \ +FIRDECIM() FIRDECIM(_create)(unsigned int _M, \ + TC * _h, \ + unsigned int _h_len); \ + \ +/* Create decimator from filter prototype prototype (Kaiser-Bessel */ \ +/* windowed-sinc function) */ \ +/* _M : decimation factor, _M >= 2 */ \ +/* _m : filter delay [symbols], _m >= 1 */ \ +/* _As : stop-band attenuation [dB], _As >= 0 */ \ +FIRDECIM() FIRDECIM(_create_kaiser)(unsigned int _M, \ + unsigned int _m, \ + float _As); \ + \ +/* Create decimator object from filter prototype */ \ +/* _type : filter type (e.g. LIQUID_FIRFILT_RCOS) */ \ +/* _M : interpolation factor, _M > 1 */ \ +/* _m : filter delay (symbols), _m > 0 */ \ +/* _beta : excess bandwidth factor, 0 <= _beta <= 1 */ \ +/* _dt : fractional sample delay, -1 <= _dt <= 1 */ \ +FIRDECIM() FIRDECIM(_create_prototype)(int _type, \ + unsigned int _M, \ + unsigned int _m, \ + float _beta, \ + float _dt); \ + \ +/* Destroy decimator object, freeing all internal memory */ \ +void FIRDECIM(_destroy)(FIRDECIM() _q); \ + \ +/* Print decimator object propreties to stdout */ \ +void FIRDECIM(_print)(FIRDECIM() _q); \ + \ +/* Reset decimator object internal state */ \ +void FIRDECIM(_reset)(FIRDECIM() _q); \ + \ +/* Get decimation rate */ \ +unsigned int FIRDECIM(_get_decim_rate)(FIRDECIM() _q); \ + \ +/* Set output scaling for decimator */ \ +/* _q : decimator object */ \ +/* _scale : scaling factor to apply to each output sample */ \ +void FIRDECIM(_set_scale)(FIRDECIM() _q, \ + TC _scale); \ + \ +/* Get output scaling for decimator */ \ +/* _q : decimator object */ \ +/* _scale : scaling factor to apply to each output sample */ \ +void FIRDECIM(_get_scale)(FIRDECIM() _q, \ + TC * _scale); \ + \ +/* Execute decimator on _M input samples */ \ +/* _q : decimator object */ \ +/* _x : input samples, [size: _M x 1] */ \ +/* _y : output sample pointer */ \ +void FIRDECIM(_execute)(FIRDECIM() _q, \ + TI * _x, \ + TO * _y); \ + \ +/* Execute decimator on block of _n*_M input samples */ \ +/* _q : decimator object */ \ +/* _x : input array, [size: _n*_M x 1] */ \ +/* _n : number of _output_ samples */ \ +/* _y : output array, [_size: _n x 1] */ \ +void FIRDECIM(_execute_block)(FIRDECIM() _q, \ + TI * _x, \ + unsigned int _n, \ + TO * _y); \ + +LIQUID_FIRDECIM_DEFINE_API(LIQUID_FIRDECIM_MANGLE_RRRF, + float, + float, + float) + +LIQUID_FIRDECIM_DEFINE_API(LIQUID_FIRDECIM_MANGLE_CRCF, + liquid_float_complex, + float, + liquid_float_complex) + +LIQUID_FIRDECIM_DEFINE_API(LIQUID_FIRDECIM_MANGLE_CCCF, + liquid_float_complex, + liquid_float_complex, + liquid_float_complex) + + +// iirdecim : infinite impulse response decimator +#define LIQUID_IIRDECIM_MANGLE_RRRF(name) LIQUID_CONCAT(iirdecim_rrrf,name) +#define LIQUID_IIRDECIM_MANGLE_CRCF(name) LIQUID_CONCAT(iirdecim_crcf,name) +#define LIQUID_IIRDECIM_MANGLE_CCCF(name) LIQUID_CONCAT(iirdecim_cccf,name) + +#define LIQUID_IIRDECIM_DEFINE_API(IIRDECIM,TO,TC,TI) \ + \ +/* Infinite impulse response (IIR) decimator */ \ +typedef struct IIRDECIM(_s) * IIRDECIM(); \ + \ +/* Create infinite impulse response decimator from external */ \ +/* coefficients. */ \ +/* Note that the number of feed-forward and feed-back coefficients do */ \ +/* not need to be equal, but they do need to be non-zero. */ \ +/* Furthermore, the first feed-back coefficient \(a_0\) cannot be */ \ +/* equal to zero, otherwise the filter will be invalid as this value is */ \ +/* factored out from all coefficients. */ \ +/* For stability reasons the number of coefficients should reasonably */ \ +/* not exceed about 8 for single-precision floating-point. */ \ +/* _M : decimation factor, _M >= 2 */ \ +/* _b : feed-forward coefficients (numerator), [size: _nb x 1] */ \ +/* _nb : number of feed-forward coefficients, _nb > 0 */ \ +/* _a : feed-back coefficients (denominator), [size: _na x 1] */ \ +/* _na : number of feed-back coefficients, _na > 0 */ \ +IIRDECIM() IIRDECIM(_create)(unsigned int _M, \ + TC * _b, \ + unsigned int _nb, \ + TC * _a, \ + unsigned int _na); \ + \ +/* Create decimator object with default Butterworth prototype */ \ +/* _M : decimation factor, _M >= 2 */ \ +/* _order : filter order, _order > 0 */ \ +IIRDECIM() IIRDECIM(_create_default)(unsigned int _M, \ + unsigned int _order); \ + \ +/* Create IIR decimator from prototype */ \ +/* _M : decimation factor, _M >= 2 */ \ +/* _ftype : filter type (e.g. LIQUID_IIRDES_BUTTER) */ \ +/* _btype : band type (e.g. LIQUID_IIRDES_BANDPASS) */ \ +/* _format : coefficients format (e.g. LIQUID_IIRDES_SOS) */ \ +/* _order : filter order, _order > 0 */ \ +/* _fc : low-pass prototype cut-off frequency, 0 <= _fc <= 0.5 */ \ +/* _f0 : center frequency (band-pass, band-stop), 0 <= _f0 <= 0.5 */ \ +/* _Ap : pass-band ripple in dB, _Ap > 0 */ \ +/* _As : stop-band ripple in dB, _As > 0 */ \ +IIRDECIM() IIRDECIM(_create_prototype)( \ + unsigned int _M, \ + liquid_iirdes_filtertype _ftype, \ + liquid_iirdes_bandtype _btype, \ + liquid_iirdes_format _format, \ + unsigned int _order, \ + float _fc, \ + float _f0, \ + float _Ap, \ + float _As); \ + \ +/* Destroy decimator object and free internal memory */ \ +void IIRDECIM(_destroy)(IIRDECIM() _q); \ + \ +/* Print decimator object internals */ \ +void IIRDECIM(_print)(IIRDECIM() _q); \ + \ +/* Reset decimator object */ \ +void IIRDECIM(_reset)(IIRDECIM() _q); \ + \ +/* Execute decimator on _M input samples */ \ +/* _q : decimator object */ \ +/* _x : input samples, [size: _M x 1] */ \ +/* _y : output sample pointer */ \ +void IIRDECIM(_execute)(IIRDECIM() _q, \ + TI * _x, \ + TO * _y); \ + \ +/* Execute decimator on block of _n*_M input samples */ \ +/* _q : decimator object */ \ +/* _x : input array, [size: _n*_M x 1] */ \ +/* _n : number of _output_ samples */ \ +/* _y : output array, [_sze: _n x 1] */ \ +void IIRDECIM(_execute_block)(IIRDECIM() _q, \ + TI * _x, \ + unsigned int _n, \ + TO * _y); \ + \ +/* Compute and return group delay of object */ \ +/* _q : filter object */ \ +/* _fc : frequency to evaluate */ \ +float IIRDECIM(_groupdelay)(IIRDECIM() _q, \ + float _fc); \ + +LIQUID_IIRDECIM_DEFINE_API(LIQUID_IIRDECIM_MANGLE_RRRF, + float, + float, + float) + +LIQUID_IIRDECIM_DEFINE_API(LIQUID_IIRDECIM_MANGLE_CRCF, + liquid_float_complex, + float, + liquid_float_complex) + +LIQUID_IIRDECIM_DEFINE_API(LIQUID_IIRDECIM_MANGLE_CCCF, + liquid_float_complex, + liquid_float_complex, + liquid_float_complex) + + + +// +// Half-band resampler +// +#define LIQUID_RESAMP2_MANGLE_RRRF(name) LIQUID_CONCAT(resamp2_rrrf,name) +#define LIQUID_RESAMP2_MANGLE_CRCF(name) LIQUID_CONCAT(resamp2_crcf,name) +#define LIQUID_RESAMP2_MANGLE_CCCF(name) LIQUID_CONCAT(resamp2_cccf,name) + +#define LIQUID_RESAMP2_DEFINE_API(RESAMP2,TO,TC,TI) \ + \ +/* Half-band resampler, implemented as a dyadic (half-band) polyphase */ \ +/* filter bank for interpolation, decimation, synthesis, and analysis. */ \ +typedef struct RESAMP2(_s) * RESAMP2(); \ + \ +/* Create half-band resampler from design prototype. */ \ +/* _m : filter semi-length (h_len = 4*m+1), _m >= 2 */ \ +/* _f0 : filter center frequency, -0.5 <= _f0 <= 0.5 */ \ +/* _As : stop-band attenuation [dB], _As > 0 */ \ +RESAMP2() RESAMP2(_create)(unsigned int _m, \ + float _f0, \ + float _As); \ + \ +/* Re-create half-band resampler with new properties */ \ +/* _q : original half-band resampler object */ \ +/* _m : filter semi-length (h_len = 4*m+1), _m >= 2 */ \ +/* _f0 : filter center frequency, -0.5 <= _f0 <= 0.5 */ \ +/* _As : stop-band attenuation [dB], _As > 0 */ \ +RESAMP2() RESAMP2(_recreate)(RESAMP2() _q, \ + unsigned int _m, \ + float _f0, \ + float _As); \ + \ +/* Destroy resampler, freeing all internally-allocated memory */ \ +void RESAMP2(_destroy)(RESAMP2() _q); \ + \ +/* print resampler object's internals to stdout */ \ +void RESAMP2(_print)(RESAMP2() _q); \ + \ +/* Reset internal buffer */ \ +void RESAMP2(_reset)(RESAMP2() _q); \ + \ +/* Get resampler filter delay (semi-length m) */ \ +unsigned int RESAMP2(_get_delay)(RESAMP2() _q); \ + \ +/* Execute resampler as half-band filter for a single input sample */ \ +/* \(x\) where \(y_0\) is the output of the effective low-pass filter, */ \ +/* and \(y_1\) is the output of the effective high-pass filter. */ \ +/* _q : resampler object */ \ +/* _x : input sample */ \ +/* _y0 : output sample pointer (low frequency) */ \ +/* _y1 : output sample pointer (high frequency) */ \ +void RESAMP2(_filter_execute)(RESAMP2() _q, \ + TI _x, \ + TO * _y0, \ + TO * _y1); \ + \ +/* Execute resampler as half-band analysis filterbank on a pair of */ \ +/* sequential time-domain input samples. */ \ +/* The decimated outputs of the low- and high-pass equivalent filters */ \ +/* are stored in \(y_0\) and \(y_1\), respectively. */ \ +/* _q : resampler object */ \ +/* _x : input array, [size: 2 x 1] */ \ +/* _y : output array, [size: 2 x 1] */ \ +void RESAMP2(_analyzer_execute)(RESAMP2() _q, \ + TI * _x, \ + TO * _y); \ + \ +/* Execute resampler as half-band synthesis filterbank on a pair of */ \ +/* input samples. The low- and high-pass input samples are provided by */ \ +/* \(x_0\) and \(x_1\), respectively. The sequential time-domain output */ \ +/* samples are stored in \(y_0\) and \(y_1\). */ \ +/* _q : resampler object */ \ +/* _x : input array [size: 2 x 1] */ \ +/* _y : output array [size: 2 x 1] */ \ +void RESAMP2(_synthesizer_execute)(RESAMP2() _q, \ + TI * _x, \ + TO * _y); \ + \ +/* Execute resampler as half-band decimator on a pair of sequential */ \ +/* time-domain input samples. */ \ +/* _q : resampler object */ \ +/* _x : input array [size: 2 x 1] */ \ +/* _y : output sample pointer */ \ +void RESAMP2(_decim_execute)(RESAMP2() _q, \ + TI * _x, \ + TO * _y); \ + \ +/* Execute resampler as half-band interpolator on a single input sample */ \ +/* _q : resampler object */ \ +/* _x : input sample */ \ +/* _y : output array [size: 2 x 1] */ \ +void RESAMP2(_interp_execute)(RESAMP2() _q, \ + TI _x, \ + TO * _y); \ + +LIQUID_RESAMP2_DEFINE_API(LIQUID_RESAMP2_MANGLE_RRRF, + float, + float, + float) + +LIQUID_RESAMP2_DEFINE_API(LIQUID_RESAMP2_MANGLE_CRCF, + liquid_float_complex, + float, + liquid_float_complex) + +LIQUID_RESAMP2_DEFINE_API(LIQUID_RESAMP2_MANGLE_CCCF, + liquid_float_complex, + liquid_float_complex, + liquid_float_complex) + + +// +// Rational resampler +// +#define LIQUID_RRESAMP_MANGLE_RRRF(name) LIQUID_CONCAT(rresamp_rrrf,name) +#define LIQUID_RRESAMP_MANGLE_CRCF(name) LIQUID_CONCAT(rresamp_crcf,name) +#define LIQUID_RRESAMP_MANGLE_CCCF(name) LIQUID_CONCAT(rresamp_cccf,name) + +#define LIQUID_RRESAMP_DEFINE_API(RRESAMP,TO,TC,TI) \ + \ +/* Rational rate resampler, implemented as a polyphase filterbank */ \ +typedef struct RRESAMP(_s) * RRESAMP(); \ + \ +/* Create rational-rate resampler object from external coeffcients to */ \ +/* resample at an exact rate P/Q. */ \ +/* Note that to preserve the input filter coefficients, the greatest */ \ +/* common divisor (gcd) is not removed internally from _P and _Q when */ \ +/* this method is called. */ \ +/* _P : interpolation factor, P > 0 */ \ +/* _Q : decimation factor, Q > 0 */ \ +/* _m : filter semi-length (delay), 0 < _m */ \ +/* _h : filter coefficients, [size: 2*_P*_m x 1] */ \ +RRESAMP() RRESAMP(_create)(unsigned int _P, \ + unsigned int _Q, \ + unsigned int _m, \ + TC * _h); \ + \ +/* Create rational-rate resampler object from filter prototype to */ \ +/* resample at an exact rate P/Q. */ \ +/* Note that because the filter coefficients are computed internally */ \ +/* here, the greatest common divisor (gcd) from _P and _Q is internally */ \ +/* removed to improve speed. */ \ +/* _P : interpolation factor, P > 0 */ \ +/* _Q : decimation factor, Q > 0 */ \ +/* _m : filter semi-length (delay), 0 < _m */ \ +/* _bw : filter bandwidth relative to sample rate, 0 < _bw <= 0.5 */ \ +/* _As : filter stop-band attenuation [dB], 0 < _As */ \ +RRESAMP() RRESAMP(_create_kaiser)(unsigned int _P, \ + unsigned int _Q, \ + unsigned int _m, \ + float _bw, \ + float _As); \ + \ +/* Create rational-rate resampler object from filter prototype to */ \ +/* resample at an exact rate P/Q. */ \ +/* Note that because the filter coefficients are computed internally */ \ +/* here, the greatest common divisor (gcd) from _P and _Q is internally */ \ +/* removed to improve speed. */ \ +RRESAMP() RRESAMP(_create_prototype)(int _type, \ + unsigned int _P, \ + unsigned int _Q, \ + unsigned int _m, \ + float _beta); \ + \ +/* Create rational resampler object with a specified resampling rate of */ \ +/* exactly P/Q with default parameters. This is a simplified method to */ \ +/* provide a basic resampler with a baseline set of parameters, */ \ +/* abstracting away some of the complexities with the filterbank */ \ +/* design. */ \ +/* The default parameters are */ \ +/* m = 12 (filter semi-length), */ \ +/* bw = 0.5 (filter bandwidth), and */ \ +/* As = 60 dB (filter stop-band attenuation) */ \ +/* _P : interpolation factor, P > 0 */ \ +/* _Q : decimation factor, Q > 0 */ \ +RRESAMP() RRESAMP(_create_default)(unsigned int _P, \ + unsigned int _Q); \ + \ +/* Destroy resampler object, freeing all internal memory */ \ +void RRESAMP(_destroy)(RRESAMP() _q); \ + \ +/* Print resampler object internals to stdout */ \ +void RRESAMP(_print)(RRESAMP() _q); \ + \ +/* Reset resampler object internals */ \ +void RRESAMP(_reset)(RRESAMP() _q); \ + \ +/* Set output scaling for filter, default: \( 2 w \sqrt{P/Q} \) */ \ +/* _q : resampler object */ \ +/* _scale : scaling factor to apply to each output sample */ \ +void RRESAMP(_set_scale)(RRESAMP() _q, \ + TC _scale); \ + \ +/* Get output scaling for filter */ \ +/* _q : resampler object */ \ +/* _scale : scaling factor to apply to each output sample */ \ +void RRESAMP(_get_scale)(RRESAMP() _q, \ + TC * _scale); \ + \ +/* Get resampler delay (filter semi-length \(m\)) */ \ +unsigned int RRESAMP(_get_delay)(RRESAMP() _q); \ + \ +/* Get original interpolation factor \(P\) when object was created */ \ +/* before removing greatest common divisor */ \ +unsigned int RRESAMP(_get_P)(RRESAMP() _q); \ + \ +/* Get internal interpolation factor of resampler, \(P\), after */ \ +/* removing greatest common divisor */ \ +unsigned int RRESAMP(_get_interp)(RRESAMP() _q); \ + \ +/* Get original decimation factor \(Q\) when object was created */ \ +/* before removing greatest common divisor */ \ +unsigned int RRESAMP(_get_Q)(RRESAMP() _q); \ + \ +/* Get internal decimation factor of resampler, \(Q\), after removing */ \ +/* greatest common divisor */ \ +unsigned int RRESAMP(_get_decim)(RRESAMP() _q); \ + \ +/* Get block length (e.g. greatest common divisor) between original P */ \ +/* and Q values */ \ +unsigned int RRESAMP(_get_block_len)(RRESAMP() _q); \ + \ +/* Get rate of resampler, \(r = P/Q\) */ \ +float RRESAMP(_get_rate)(RRESAMP() _q); \ + \ +/* Execute rational-rate resampler on a block of input samples and */ \ +/* store the resulting samples in the output array. */ \ +/* Note that the size of the input and output buffers correspond to the */ \ +/* values of P and Q passed when the object was created, even if they */ \ +/* share a common divisor. Internally the rational resampler reduces P */ \ +/* and Q by their greatest commmon denominator to reduce processing; */ \ +/* however sometimes it is convenienct to create the object based on */ \ +/* expected output/input block sizes. This expectation is preserved. So */ \ +/* if an object is created with P=80 and Q=72, the object will */ \ +/* internally set P=10 and Q=9 (with a g.c.d of 8); however when */ \ +/* "execute" is called the resampler will still expect an input buffer */ \ +/* of 72 and an output buffer of 80. */ \ +/* _q : resamp object */ \ +/* _x : input sample array, [size: Q x 1] */ \ +/* _y : output sample array [size: P x 1] */ \ +void RRESAMP(_execute)(RRESAMP() _q, \ + TI * _x, \ + TO * _y); \ + +LIQUID_RRESAMP_DEFINE_API(LIQUID_RRESAMP_MANGLE_RRRF, + float, + float, + float) + +LIQUID_RRESAMP_DEFINE_API(LIQUID_RRESAMP_MANGLE_CRCF, + liquid_float_complex, + float, + liquid_float_complex) + +LIQUID_RRESAMP_DEFINE_API(LIQUID_RRESAMP_MANGLE_CCCF, + liquid_float_complex, + liquid_float_complex, + liquid_float_complex) + + +// +// Arbitrary resampler +// +#define LIQUID_RESAMP_MANGLE_RRRF(name) LIQUID_CONCAT(resamp_rrrf,name) +#define LIQUID_RESAMP_MANGLE_CRCF(name) LIQUID_CONCAT(resamp_crcf,name) +#define LIQUID_RESAMP_MANGLE_CCCF(name) LIQUID_CONCAT(resamp_cccf,name) + +#define LIQUID_RESAMP_DEFINE_API(RESAMP,TO,TC,TI) \ + \ +/* Arbitrary rate resampler, implemented as a polyphase filterbank */ \ +typedef struct RESAMP(_s) * RESAMP(); \ + \ +/* Create arbitrary resampler object from filter prototype */ \ +/* _rate : arbitrary resampling rate, 0 < _rate */ \ +/* _m : filter semi-length (delay), 0 < _m */ \ +/* _fc : filter cutoff frequency, 0 < _fc < 0.5 */ \ +/* _As : filter stop-band attenuation [dB], 0 < _As */ \ +/* _npfb : number of filters in the bank, 0 < _npfb */ \ +RESAMP() RESAMP(_create)(float _rate, \ + unsigned int _m, \ + float _fc, \ + float _As, \ + unsigned int _npfb); \ + \ +/* Create arbitrary resampler object with a specified input resampling */ \ +/* rate and default parameters. This is a simplified method to provide */ \ +/* a basic resampler with a baseline set of parameters, abstracting */ \ +/* away some of the complexities with the filterbank design. */ \ +/* The default parameters are */ \ +/* m = 7 (filter semi-length), */ \ +/* fc = min(0.49,_rate/2) (filter cutoff frequency), */ \ +/* As = 60 dB (filter stop-band attenuation), and */ \ +/* npfb = 64 (number of filters in the bank). */ \ +/* _rate : arbitrary resampling rate, 0 < _rate */ \ +RESAMP() RESAMP(_create_default)(float _rate); \ + \ +/* Destroy arbitrary resampler object, freeing all internal memory */ \ +void RESAMP(_destroy)(RESAMP() _q); \ + \ +/* Print resamp object internals to stdout */ \ +void RESAMP(_print)(RESAMP() _q); \ + \ +/* Reset resamp object internals */ \ +void RESAMP(_reset)(RESAMP() _q); \ + \ +/* Get resampler delay (filter semi-length \(m\)) */ \ +unsigned int RESAMP(_get_delay)(RESAMP() _q); \ + \ +/* Set rate of arbitrary resampler */ \ +/* _q : resampling object */ \ +/* _rate : new sampling rate, _rate > 0 */ \ +void RESAMP(_set_rate)(RESAMP() _q, \ + float _rate); \ + \ +/* Get rate of arbitrary resampler */ \ +float RESAMP(_get_rate)(RESAMP() _q); \ + \ +/* adjust rate of arbitrary resampler */ \ +/* _q : resampling object */ \ +/* _gamma : rate adjustment factor: rate <- rate * gamma, _gamma > 0 */ \ +void RESAMP(_adjust_rate)(RESAMP() _q, \ + float _gamma); \ + \ +/* Set resampling timing phase */ \ +/* _q : resampling object */ \ +/* _tau : sample timing phase, -1 <= _tau <= 1 */ \ +void RESAMP(_set_timing_phase)(RESAMP() _q, \ + float _tau); \ + \ +/* Adjust resampling timing phase */ \ +/* _q : resampling object */ \ +/* _delta : sample timing adjustment, -1 <= _delta <= 1 */ \ +void RESAMP(_adjust_timing_phase)(RESAMP() _q, \ + float _delta); \ + \ +/* Execute arbitrary resampler on a single input sample and store the */ \ +/* resulting samples in the output array. The number of output samples */ \ +/* is depenent upon the resampling rate but will be at most */ \ +/* \( \lceil{ r \rceil} \) samples. */ \ +/* _q : resamp object */ \ +/* _x : single input sample */ \ +/* _y : output sample array (pointer) */ \ +/* _num_written : number of samples written to _y */ \ +void RESAMP(_execute)(RESAMP() _q, \ + TI _x, \ + TO * _y, \ + unsigned int * _num_written); \ + \ +/* Execute arbitrary resampler on a block of input samples and store */ \ +/* the resulting samples in the output array. The number of output */ \ +/* samples is depenent upon the resampling rate and the number of input */ \ +/* samples but will be at most \( \lceil{ r n_x \rceil} \) samples. */ \ +/* _q : resamp object */ \ +/* _x : input buffer, [size: _nx x 1] */ \ +/* _nx : input buffer */ \ +/* _y : output sample array (pointer) */ \ +/* _ny : number of samples written to _y */ \ +void RESAMP(_execute_block)(RESAMP() _q, \ + TI * _x, \ + unsigned int _nx, \ + TO * _y, \ + unsigned int * _ny); \ + +LIQUID_RESAMP_DEFINE_API(LIQUID_RESAMP_MANGLE_RRRF, + float, + float, + float) + +LIQUID_RESAMP_DEFINE_API(LIQUID_RESAMP_MANGLE_CRCF, + liquid_float_complex, + float, + liquid_float_complex) + +LIQUID_RESAMP_DEFINE_API(LIQUID_RESAMP_MANGLE_CCCF, + liquid_float_complex, + liquid_float_complex, + liquid_float_complex) + + +// +// Multi-stage half-band resampler +// + +// resampling type (interpolator/decimator) +typedef enum { + LIQUID_RESAMP_INTERP=0, // interpolator + LIQUID_RESAMP_DECIM, // decimator +} liquid_resamp_type; + +#define LIQUID_MSRESAMP2_MANGLE_RRRF(name) LIQUID_CONCAT(msresamp2_rrrf,name) +#define LIQUID_MSRESAMP2_MANGLE_CRCF(name) LIQUID_CONCAT(msresamp2_crcf,name) +#define LIQUID_MSRESAMP2_MANGLE_CCCF(name) LIQUID_CONCAT(msresamp2_cccf,name) + +#define LIQUID_MSRESAMP2_DEFINE_API(MSRESAMP2,TO,TC,TI) \ + \ +/* Multi-stage half-band resampler, implemented as cascaded dyadic */ \ +/* (half-band) polyphase filter banks for interpolation and decimation. */ \ +typedef struct MSRESAMP2(_s) * MSRESAMP2(); \ + \ +/* Create multi-stage half-band resampler as either decimator or */ \ +/* interpolator. */ \ +/* _type : resampler type (e.g. LIQUID_RESAMP_DECIM) */ \ +/* _num_stages : number of resampling stages, _num_stages <= 16 */ \ +/* _fc : filter cut-off frequency, 0 < _fc < 0.5 */ \ +/* _f0 : filter center frequency (set to zero) */ \ +/* _As : stop-band attenuation [dB], _As > 0 */ \ +MSRESAMP2() MSRESAMP2(_create)(int _type, \ + unsigned int _num_stages, \ + float _fc, \ + float _f0, \ + float _As); \ + \ +/* Destroy multi-stage half-band resampler, freeing all internal memory */ \ +void MSRESAMP2(_destroy)(MSRESAMP2() _q); \ + \ +/* Print msresamp object internals to stdout */ \ +void MSRESAMP2(_print)(MSRESAMP2() _q); \ + \ +/* Reset msresamp object internal state */ \ +void MSRESAMP2(_reset)(MSRESAMP2() _q); \ + \ +/* Get multi-stage half-band resampling rate */ \ +float MSRESAMP2(_get_rate)(MSRESAMP2() _q); \ + \ +/* Get number of half-band resampling stages in object */ \ +unsigned int MSRESAMP2(_get_num_stages)(MSRESAMP2() _q); \ + \ +/* Get resampling type (LIQUID_RESAMP_DECIM, LIQUID_RESAMP_INTERP) */ \ +int MSRESAMP2(_get_type)(MSRESAMP2() _q); \ + \ +/* Get group delay (number of output samples) */ \ +float MSRESAMP2(_get_delay)(MSRESAMP2() _q); \ + \ +/* Execute multi-stage resampler, M = 2^num_stages */ \ +/* LIQUID_RESAMP_INTERP: input: 1, output: M */ \ +/* LIQUID_RESAMP_DECIM: input: M, output: 1 */ \ +/* _q : msresamp object */ \ +/* _x : input sample array */ \ +/* _y : output sample array */ \ +void MSRESAMP2(_execute)(MSRESAMP2() _q, \ + TI * _x, \ + TO * _y); \ + +LIQUID_MSRESAMP2_DEFINE_API(LIQUID_MSRESAMP2_MANGLE_RRRF, + float, + float, + float) + +LIQUID_MSRESAMP2_DEFINE_API(LIQUID_MSRESAMP2_MANGLE_CRCF, + liquid_float_complex, + float, + liquid_float_complex) + +LIQUID_MSRESAMP2_DEFINE_API(LIQUID_MSRESAMP2_MANGLE_CCCF, + liquid_float_complex, + liquid_float_complex, + liquid_float_complex) + + +// +// Multi-stage arbitrary resampler +// +#define LIQUID_MSRESAMP_MANGLE_RRRF(name) LIQUID_CONCAT(msresamp_rrrf,name) +#define LIQUID_MSRESAMP_MANGLE_CRCF(name) LIQUID_CONCAT(msresamp_crcf,name) +#define LIQUID_MSRESAMP_MANGLE_CCCF(name) LIQUID_CONCAT(msresamp_cccf,name) + +#define LIQUID_MSRESAMP_DEFINE_API(MSRESAMP,TO,TC,TI) \ + \ +/* Multi-stage half-band resampler, implemented as cascaded dyadic */ \ +/* (half-band) polyphase filter banks followed by an arbitrary rate */ \ +/* resampler for interpolation and decimation. */ \ +typedef struct MSRESAMP(_s) * MSRESAMP(); \ + \ +/* Create multi-stage arbitrary resampler */ \ +/* _r : resampling rate (output/input), _r > 0 */ \ +/* _As : stop-band attenuation [dB], _As > 0 */ \ +MSRESAMP() MSRESAMP(_create)(float _r, \ + float _As); \ + \ +/* Destroy multi-stage arbitrary resampler */ \ +void MSRESAMP(_destroy)(MSRESAMP() _q); \ + \ +/* Print msresamp object internals to stdout */ \ +void MSRESAMP(_print)(MSRESAMP() _q); \ + \ +/* Reset msresamp object internal state */ \ +void MSRESAMP(_reset)(MSRESAMP() _q); \ + \ +/* Get filter delay (output samples) */ \ +float MSRESAMP(_get_delay)(MSRESAMP() _q); \ + \ +/* get overall resampling rate */ \ +float MSRESAMP(_get_rate)(MSRESAMP() _q); \ + \ +/* Execute multi-stage resampler on one or more input samples. */ \ +/* The number of output samples is dependent upon the resampling rate */ \ +/* and the number of input samples. In general it is good practice to */ \ +/* allocate at least \( \lceil{ 1 + 2 r n_x \rceil} \) samples in the */ \ +/* output array to avoid overflows. */ \ +/* _q : msresamp object */ \ +/* _x : input sample array, [size: _nx x 1] */ \ +/* _nx : input sample array size */ \ +/* _y : pointer to output array for storing result */ \ +/* _ny : number of samples written to _y */ \ +void MSRESAMP(_execute)(MSRESAMP() _q, \ + TI * _x, \ + unsigned int _nx, \ + TO * _y, \ + unsigned int * _ny); \ + +LIQUID_MSRESAMP_DEFINE_API(LIQUID_MSRESAMP_MANGLE_RRRF, + float, + float, + float) + +LIQUID_MSRESAMP_DEFINE_API(LIQUID_MSRESAMP_MANGLE_CRCF, + liquid_float_complex, + float, + liquid_float_complex) + +LIQUID_MSRESAMP_DEFINE_API(LIQUID_MSRESAMP_MANGLE_CCCF, + liquid_float_complex, + liquid_float_complex, + liquid_float_complex) + +// +// Direct digital [up/down] synthesizer +// + +#define DDS_MANGLE_CCCF(name) LIQUID_CONCAT(dds_cccf,name) + +#define LIQUID_DDS_DEFINE_API(DDS,TO,TC,TI) \ +typedef struct DDS(_s) * DDS(); \ + \ +/* create digital synthesizer object */ \ +DDS() DDS(_create)(unsigned int _num_stages, \ + float _fc, \ + float _bw, \ + float _As); \ + \ +/* destroy digital synthesizer object */ \ +void DDS(_destroy)(DDS() _q); \ + \ +/* print synthesizer object internals to stdout */ \ +void DDS(_print)(DDS() _q); \ + \ +/* reset synthesizer object internals */ \ +void DDS(_reset)(DDS() _q); \ + \ +void DDS(_decim_execute)(DDS() _q, \ + TI * _x, \ + TO * _y); \ +void DDS(_interp_execute)(DDS() _q, \ + TI _x, \ + TO * _y); \ + +LIQUID_DDS_DEFINE_API(DDS_MANGLE_CCCF, + liquid_float_complex, + liquid_float_complex, + liquid_float_complex) + + +// +// Symbol timing recovery (symbol synchronizer) +// +#define LIQUID_SYMSYNC_MANGLE_RRRF(name) LIQUID_CONCAT(symsync_rrrf,name) +#define LIQUID_SYMSYNC_MANGLE_CRCF(name) LIQUID_CONCAT(symsync_crcf,name) + +#define LIQUID_SYMSYNC_DEFINE_API(SYMSYNC,TO,TC,TI) \ + \ +/* Multi-rate symbol synchronizer for symbol timing recovery. */ \ +typedef struct SYMSYNC(_s) * SYMSYNC(); \ + \ +/* Create synchronizer object from external coefficients */ \ +/* _k : samples per symbol, _k >= 2 */ \ +/* _M : number of filters in the bank, _M > 0 */ \ +/* _h : matched filter coefficients, [size: _h_len x 1] */ \ +/* _h_len : length of matched filter; \( h_{len} = 2 k m + 1 \) */ \ +SYMSYNC() SYMSYNC(_create)(unsigned int _k, \ + unsigned int _M, \ + TC * _h, \ + unsigned int _h_len); \ + \ +/* Create square-root Nyquist symbol synchronizer from prototype */ \ +/* _type : filter type (e.g. LIQUID_FIRFILT_RRC) */ \ +/* _k : samples/symbol, _k >= 2 */ \ +/* _m : symbol delay, _m > 0 */ \ +/* _beta : rolloff factor, 0 <= _beta <= 1 */ \ +/* _M : number of filters in the bank, _M > 0 */ \ +SYMSYNC() SYMSYNC(_create_rnyquist)(int _type, \ + unsigned int _k, \ + unsigned int _m, \ + float _beta, \ + unsigned int _M); \ + \ +/* Create symsync using Kaiser filter interpolator. This is useful when */ \ +/* the input signal has its matched filter applied already. */ \ +/* _k : input samples/symbol, _k >= 2 */ \ +/* _m : symbol delay, _m > 0 */ \ +/* _beta : rolloff factor, 0<= _beta <= 1 */ \ +/* _M : number of filters in the bank, _M > 0 */ \ +SYMSYNC() SYMSYNC(_create_kaiser)(unsigned int _k, \ + unsigned int _m, \ + float _beta, \ + unsigned int _M); \ + \ +/* Destroy symsync object, freeing all internal memory */ \ +void SYMSYNC(_destroy)(SYMSYNC() _q); \ + \ +/* Print symsync object's parameters to stdout */ \ +void SYMSYNC(_print)(SYMSYNC() _q); \ + \ +/* Reset symsync internal state */ \ +void SYMSYNC(_reset)(SYMSYNC() _q); \ + \ +/* Lock the symbol synchronizer's loop control */ \ +void SYMSYNC(_lock)(SYMSYNC() _q); \ + \ +/* Unlock the symbol synchronizer's loop control */ \ +void SYMSYNC(_unlock)(SYMSYNC() _q); \ + \ +/* Set synchronizer output rate (samples/symbol) */ \ +/* _q : synchronizer object */ \ +/* _k_out : output samples/symbol, _k_out > 0 */ \ +void SYMSYNC(_set_output_rate)(SYMSYNC() _q, \ + unsigned int _k_out); \ + \ +/* Set loop-filter bandwidth */ \ +/* _q : synchronizer object */ \ +/* _bt : loop bandwidth, 0 <= _bt <= 1 */ \ +void SYMSYNC(_set_lf_bw)(SYMSYNC() _q, \ + float _bt); \ + \ +/* Return instantaneous fractional timing offset estimate */ \ +float SYMSYNC(_get_tau)(SYMSYNC() _q); \ + \ +/* Execute synchronizer on input data array */ \ +/* _q : synchronizer object */ \ +/* _x : input data array, [size: _nx x 1] */ \ +/* _nx : number of input samples */ \ +/* _y : output data array */ \ +/* _ny : number of samples written to output buffer */ \ +void SYMSYNC(_execute)(SYMSYNC() _q, \ + TI * _x, \ + unsigned int _nx, \ + TO * _y, \ + unsigned int * _ny); \ + +LIQUID_SYMSYNC_DEFINE_API(LIQUID_SYMSYNC_MANGLE_RRRF, + float, + float, + float) + +LIQUID_SYMSYNC_DEFINE_API(LIQUID_SYMSYNC_MANGLE_CRCF, + liquid_float_complex, + float, + liquid_float_complex) + + +// +// Finite impulse response Farrow filter +// + +#define LIQUID_FIRFARROW_MANGLE_RRRF(name) LIQUID_CONCAT(firfarrow_rrrf,name) +#define LIQUID_FIRFARROW_MANGLE_CRCF(name) LIQUID_CONCAT(firfarrow_crcf,name) +//#define LIQUID_FIRFARROW_MANGLE_CCCF(name) LIQUID_CONCAT(firfarrow_cccf,name) + +// Macro: +// FIRFARROW : name-mangling macro +// TO : output data type +// TC : coefficients data type +// TI : input data type +#define LIQUID_FIRFARROW_DEFINE_API(FIRFARROW,TO,TC,TI) \ + \ +/* Finite impulse response (FIR) Farrow filter for timing delay */ \ +typedef struct FIRFARROW(_s) * FIRFARROW(); \ + \ +/* Create firfarrow object */ \ +/* _h_len : filter length, _h_len >= 2 */ \ +/* _p : polynomial order, _p >= 1 */ \ +/* _fc : filter cutoff frequency, 0 <= _fc <= 0.5 */ \ +/* _As : stopband attenuation [dB], _As > 0 */ \ +FIRFARROW() FIRFARROW(_create)(unsigned int _h_len, \ + unsigned int _p, \ + float _fc, \ + float _As); \ + \ +/* Destroy firfarrow object, freeing all internal memory */ \ +void FIRFARROW(_destroy)(FIRFARROW() _q); \ + \ +/* Print firfarrow object's internal properties */ \ +void FIRFARROW(_print)(FIRFARROW() _q); \ + \ +/* Reset firfarrow object's internal state */ \ +void FIRFARROW(_reset)(FIRFARROW() _q); \ + \ +/* Push sample into firfarrow object */ \ +/* _q : firfarrow object */ \ +/* _x : input sample */ \ +void FIRFARROW(_push)(FIRFARROW() _q, \ + TI _x); \ + \ +/* Set fractional delay of firfarrow object */ \ +/* _q : firfarrow object */ \ +/* _mu : fractional sample delay, -1 <= _mu <= 1 */ \ +void FIRFARROW(_set_delay)(FIRFARROW() _q, \ + float _mu); \ + \ +/* Execute firfarrow internal dot product */ \ +/* _q : firfarrow object */ \ +/* _y : output sample pointer */ \ +void FIRFARROW(_execute)(FIRFARROW() _q, \ + TO * _y); \ + \ +/* Execute firfarrow filter on block of samples. */ \ +/* In-place operation is permitted (the input and output arrays may */ \ +/* share the same pointer) */ \ +/* _q : firfarrow object */ \ +/* _x : input array, [size: _n x 1] */ \ +/* _n : input, output array size */ \ +/* _y : output array, [size: _n x 1] */ \ +void FIRFARROW(_execute_block)(FIRFARROW() _q, \ + TI * _x, \ + unsigned int _n, \ + TO * _y); \ + \ +/* Get length of firfarrow object (number of filter taps) */ \ +unsigned int FIRFARROW(_get_length)(FIRFARROW() _q); \ + \ +/* Get coefficients of firfarrow object */ \ +/* _q : firfarrow object */ \ +/* _h : output coefficients pointer, [size: _h_len x 1] */ \ +void FIRFARROW(_get_coefficients)(FIRFARROW() _q, \ + float * _h); \ + \ +/* Compute complex frequency response */ \ +/* _q : filter object */ \ +/* _fc : frequency */ \ +/* _H : output frequency response */ \ +void FIRFARROW(_freqresponse)(FIRFARROW() _q, \ + float _fc, \ + liquid_float_complex * _H); \ + \ +/* Compute group delay [samples] */ \ +/* _q : filter object */ \ +/* _fc : frequency */ \ +float FIRFARROW(_groupdelay)(FIRFARROW() _q, \ + float _fc); \ + +LIQUID_FIRFARROW_DEFINE_API(LIQUID_FIRFARROW_MANGLE_RRRF, + float, + float, + float) + +LIQUID_FIRFARROW_DEFINE_API(LIQUID_FIRFARROW_MANGLE_CRCF, + liquid_float_complex, + float, + liquid_float_complex) + + +// +// Order-statistic filter +// + +#define LIQUID_ORDFILT_MANGLE_RRRF(name) LIQUID_CONCAT(ordfilt_rrrf,name) + +// Macro: +// ORDFILT : name-mangling macro +// TO : output data type +// TC : coefficients data type +// TI : input data type +#define LIQUID_ORDFILT_DEFINE_API(ORDFILT,TO,TC,TI) \ + \ +/* Finite impulse response (FIR) filter */ \ +typedef struct ORDFILT(_s) * ORDFILT(); \ + \ +/* Create a order-statistic filter (ordfilt) object by specifying */ \ +/* the buffer size and appropriate sample index of order statistic. */ \ +/* _n : buffer size, _n > 0 */ \ +/* _k : sample index for order statistic, 0 <= _k < _n */ \ +ORDFILT() ORDFILT(_create)(unsigned int _n, \ + unsigned int _k); \ + \ +/* Create a median filter by specifying buffer semi-length. */ \ +/* _m : buffer semi-length */ \ +ORDFILT() ORDFILT(_create_medfilt)(unsigned int _m); \ + \ +/* Destroy filter object and free all internal memory */ \ +void ORDFILT(_destroy)(ORDFILT() _q); \ + \ +/* Reset filter object's internal buffer */ \ +void ORDFILT(_reset)(ORDFILT() _q); \ + \ +/* Print filter object information to stdout */ \ +void ORDFILT(_print)(ORDFILT() _q); \ + \ +/* Push sample into filter object's internal buffer */ \ +/* _q : filter object */ \ +/* _x : single input sample */ \ +void ORDFILT(_push)(ORDFILT() _q, \ + TI _x); \ + \ +/* Write block of samples into object's internal buffer */ \ +/* _q : filter object */ \ +/* _x : array of input samples, [size: _n x 1] */ \ +/* _n : number of input elements */ \ +void ORDFILT(_write)(ORDFILT() _q, \ + TI * _x, \ + unsigned int _n); \ + \ +/* Execute vector dot product on the filter's internal buffer and */ \ +/* coefficients */ \ +/* _q : filter object */ \ +/* _y : pointer to single output sample */ \ +void ORDFILT(_execute)(ORDFILT() _q, \ + TO * _y); \ + \ +/* Execute the filter on a block of input samples; in-place operation */ \ +/* is permitted (_x and _y may point to the same place in memory) */ \ +/* _q : filter object */ \ +/* _x : pointer to input array, [size: _n x 1] */ \ +/* _n : number of input, output samples */ \ +/* _y : pointer to output array, [size: _n x 1] */ \ +void ORDFILT(_execute_block)(ORDFILT() _q, \ + TI * _x, \ + unsigned int _n, \ + TO * _y); \ + +LIQUID_ORDFILT_DEFINE_API(LIQUID_ORDFILT_MANGLE_RRRF, + float, + float, + float) + + +// +// MODULE : framing +// + +// framesyncstats : generic frame synchronizer statistic structure + +typedef struct { + // signal quality + float evm; // error vector magnitude [dB] + float rssi; // received signal strength indicator [dB] + float cfo; // carrier frequency offset (f/Fs) + + // demodulated frame symbols + liquid_float_complex * framesyms; // pointer to array [size: framesyms x 1] + unsigned int num_framesyms; // length of framesyms + + // modulation/coding scheme etc. + unsigned int mod_scheme; // modulation scheme + unsigned int mod_bps; // modulation depth (bits/symbol) + unsigned int check; // data validity check (crc, checksum) + unsigned int fec0; // forward error-correction (inner) + unsigned int fec1; // forward error-correction (outer) +} framesyncstats_s; + +// external framesyncstats default object +extern framesyncstats_s framesyncstats_default; + +// initialize framesyncstats object on default +int framesyncstats_init_default(framesyncstats_s * _stats); + +// print framesyncstats object +int framesyncstats_print(framesyncstats_s * _stats); + + +// framedatastats : gather frame data +typedef struct { + unsigned int num_frames_detected; + unsigned int num_headers_valid; + unsigned int num_payloads_valid; + unsigned long int num_bytes_received; +} framedatastats_s; + +// reset framedatastats object +int framedatastats_reset(framedatastats_s * _stats); + +// print framedatastats object +int framedatastats_print(framedatastats_s * _stats); + + +// Generic frame synchronizer callback function type +// _header : header data [size: 8 bytes] +// _header_valid : is header valid? (0:no, 1:yes) +// _payload : payload data [size: _payload_len] +// _payload_len : length of payload (bytes) +// _payload_valid : is payload valid? (0:no, 1:yes) +// _stats : frame statistics object +// _userdata : pointer to userdata +typedef int (*framesync_callback)(unsigned char * _header, + int _header_valid, + unsigned char * _payload, + unsigned int _payload_len, + int _payload_valid, + framesyncstats_s _stats, + void * _userdata); + +// framesync csma callback functions invoked when signal levels is high or low +// _userdata : user-defined data pointer +typedef void (*framesync_csma_callback)(void * _userdata); + +// +// packet encoder/decoder +// + +typedef struct qpacketmodem_s * qpacketmodem; + +// create packet encoder +qpacketmodem qpacketmodem_create (); +int qpacketmodem_destroy(qpacketmodem _q); +int qpacketmodem_reset (qpacketmodem _q); +int qpacketmodem_print (qpacketmodem _q); + +int qpacketmodem_configure(qpacketmodem _q, + unsigned int _payload_len, + crc_scheme _check, + fec_scheme _fec0, + fec_scheme _fec1, + int _ms); + +// get length of encoded frame in symbols +unsigned int qpacketmodem_get_frame_len(qpacketmodem _q); + +// get unencoded/decoded payload length (bytes) +unsigned int qpacketmodem_get_payload_len(qpacketmodem _q); + +// regular access methods +unsigned int qpacketmodem_get_crc (qpacketmodem _q); +unsigned int qpacketmodem_get_fec0 (qpacketmodem _q); +unsigned int qpacketmodem_get_fec1 (qpacketmodem _q); +unsigned int qpacketmodem_get_modscheme(qpacketmodem _q); + +float qpacketmodem_get_demodulator_phase_error(qpacketmodem _q); +float qpacketmodem_get_demodulator_evm(qpacketmodem _q); + +// encode packet into un-modulated frame symbol indices +// _q : qpacketmodem object +// _payload : unencoded payload bytes +// _syms : encoded but un-modulated payload symbol indices +int qpacketmodem_encode_syms(qpacketmodem _q, + const unsigned char * _payload, + unsigned char * _syms); + +// decode packet from demodulated frame symbol indices (hard-decision decoding) +// _q : qpacketmodem object +// _syms : received hard-decision symbol indices [size: frame_len x 1] +// _payload : recovered decoded payload bytes +int qpacketmodem_decode_syms(qpacketmodem _q, + unsigned char * _syms, + unsigned char * _payload); + +// decode packet from demodulated frame bits (soft-decision decoding) +// _q : qpacketmodem object +// _bits : received soft-decision bits, [size: bps*frame_len x 1] +// _payload : recovered decoded payload bytes +int qpacketmodem_decode_bits(qpacketmodem _q, + unsigned char * _bits, + unsigned char * _payload); + +// encode and modulate packet into modulated frame samples +// _q : qpacketmodem object +// _payload : unencoded payload bytes +// _frame : encoded/modulated payload symbols +int qpacketmodem_encode(qpacketmodem _q, + const unsigned char * _payload, + liquid_float_complex * _frame); + +// decode packet from modulated frame samples, returning flag if CRC passed +// NOTE: hard-decision decoding +// _q : qpacketmodem object +// _frame : encoded/modulated payload symbols +// _payload : recovered decoded payload bytes +int qpacketmodem_decode(qpacketmodem _q, + liquid_float_complex * _frame, + unsigned char * _payload); + +// decode packet from modulated frame samples, returning flag if CRC passed +// NOTE: soft-decision decoding +// _q : qpacketmodem object +// _frame : encoded/modulated payload symbols +// _payload : recovered decoded payload bytes +int qpacketmodem_decode_soft(qpacketmodem _q, + liquid_float_complex * _frame, + unsigned char * _payload); + +int qpacketmodem_decode_soft_sym(qpacketmodem _q, + liquid_float_complex _symbol); + +int qpacketmodem_decode_soft_payload(qpacketmodem _q, + unsigned char * _payload); + +// +// pilot generator/synchronizer for packet burst recovery +// + +// get number of pilots in frame +unsigned int qpilot_num_pilots(unsigned int _payload_len, + unsigned int _pilot_spacing); + +// get length of frame with a particular payload length and pilot spacing +unsigned int qpilot_frame_len(unsigned int _payload_len, + unsigned int _pilot_spacing); + +// +// pilot generator for packet burst recovery +// + +typedef struct qpilotgen_s * qpilotgen; + +// create packet encoder +qpilotgen qpilotgen_create(unsigned int _payload_len, + unsigned int _pilot_spacing); + +qpilotgen qpilotgen_recreate(qpilotgen _q, + unsigned int _payload_len, + unsigned int _pilot_spacing); + +int qpilotgen_destroy(qpilotgen _q); +int qpilotgen_reset( qpilotgen _q); +int qpilotgen_print( qpilotgen _q); + +unsigned int qpilotgen_get_frame_len(qpilotgen _q); + +// insert pilot symbols +int qpilotgen_execute(qpilotgen _q, + liquid_float_complex * _payload, + liquid_float_complex * _frame); + +// +// pilot synchronizer for packet burst recovery +// +typedef struct qpilotsync_s * qpilotsync; + +// create packet encoder +qpilotsync qpilotsync_create(unsigned int _payload_len, + unsigned int _pilot_spacing); + +qpilotsync qpilotsync_recreate(qpilotsync _q, + unsigned int _payload_len, + unsigned int _pilot_spacing); + +int qpilotsync_destroy(qpilotsync _q); +int qpilotsync_reset( qpilotsync _q); +int qpilotsync_print( qpilotsync _q); + +unsigned int qpilotsync_get_frame_len(qpilotsync _q); + +// recover frame symbols from received frame +int qpilotsync_execute(qpilotsync _q, + liquid_float_complex * _frame, + liquid_float_complex * _payload); + +// get estimates +float qpilotsync_get_dphi(qpilotsync _q); +float qpilotsync_get_phi (qpilotsync _q); +float qpilotsync_get_gain(qpilotsync _q); +float qpilotsync_get_evm (qpilotsync _q); + + +// +// Basic frame generator (64 bytes data payload) +// + +// frame length in samples +#define LIQUID_FRAME64_LEN (1440) + +typedef struct framegen64_s * framegen64; + +// create frame generator +framegen64 framegen64_create(); + +// destroy frame generator +int framegen64_destroy(framegen64 _q); + +// print frame generator internal properties +int framegen64_print(framegen64 _q); + +// generate frame +// _q : frame generator object +// _header : 8-byte header data, NULL for random +// _payload : 64-byte payload data, NULL for random +// _frame : output frame samples [size: LIQUID_FRAME64_LEN x 1] +int framegen64_execute(framegen64 _q, + unsigned char * _header, + unsigned char * _payload, + liquid_float_complex * _frame); + +typedef struct framesync64_s * framesync64; + +// create framesync64 object +// _callback : callback function +// _userdata : user data pointer passed to callback function +framesync64 framesync64_create(framesync_callback _callback, + void * _userdata); + +// destroy frame synchronizer +int framesync64_destroy(framesync64 _q); + +// print frame synchronizer internal properties +int framesync64_print(framesync64 _q); + +// reset frame synchronizer internal state +int framesync64_reset(framesync64 _q); + +// push samples through frame synchronizer +// _q : frame synchronizer object +// _x : input samples [size: _n x 1] +// _n : number of input samples +int framesync64_execute(framesync64 _q, + liquid_float_complex * _x, + unsigned int _n); + +// enable/disable debugging +int framesync64_debug_enable(framesync64 _q); +int framesync64_debug_disable(framesync64 _q); +int framesync64_debug_print(framesync64 _q, const char * _filename); + +// frame data statistics +int framesync64_reset_framedatastats(framesync64 _q); +framedatastats_s framesync64_get_framedatastats (framesync64 _q); + +#if 0 +// advanced modes +int framesync64_set_csma_callbacks(framesync64 _q, + framesync_csma_callback _csma_lock, + framesync_csma_callback _csma_unlock, + void * _csma_userdata); +#endif + +// +// Flexible frame : adjustable payload, mod scheme, etc., but bring +// your own error correction, redundancy check +// + +// frame generator +typedef struct { + unsigned int check; // data validity check + unsigned int fec0; // forward error-correction scheme (inner) + unsigned int fec1; // forward error-correction scheme (outer) + unsigned int mod_scheme; // modulation scheme +} flexframegenprops_s; + +int flexframegenprops_init_default(flexframegenprops_s * _fgprops); + +typedef struct flexframegen_s * flexframegen; + +// create flexframegen object +// _props : frame properties (modulation scheme, etc.) +flexframegen flexframegen_create(flexframegenprops_s * _props); + +// destroy flexframegen object +int flexframegen_destroy(flexframegen _q); + +// print flexframegen object internals +int flexframegen_print(flexframegen _q); + +// reset flexframegen object internals +int flexframegen_reset(flexframegen _q); + +// is frame assembled? +int flexframegen_is_assembled(flexframegen _q); + +// get frame properties +int flexframegen_getprops(flexframegen _q, flexframegenprops_s * _props); + +// set frame properties +int flexframegen_setprops(flexframegen _q, flexframegenprops_s * _props); + +// set length of user-defined portion of header +int flexframegen_set_header_len(flexframegen _q, unsigned int _len); + +// set properties for header section +int flexframegen_set_header_props(flexframegen _q, + flexframegenprops_s * _props); + +// get length of assembled frame (samples) +unsigned int flexframegen_getframelen(flexframegen _q); + +// assemble a frame from an array of data +// _q : frame generator object +// _header : frame header +// _payload : payload data [size: _payload_len x 1] +// _payload_len : payload data length +int flexframegen_assemble(flexframegen _q, + const unsigned char * _header, + const unsigned char * _payload, + unsigned int _payload_len); + +// write samples of assembled frame, two samples at a time, returning +// '1' when frame is complete, '0' otherwise. Zeros will be written +// to the buffer if the frame is not assembled +// _q : frame generator object +// _buffer : output buffer [size: _buffer_len x 1] +// _buffer_len : output buffer length +int flexframegen_write_samples(flexframegen _q, + liquid_float_complex * _buffer, + unsigned int _buffer_len); + +// frame synchronizer + +typedef struct flexframesync_s * flexframesync; + +// create flexframesync object +// _callback : callback function +// _userdata : user data pointer passed to callback function +flexframesync flexframesync_create(framesync_callback _callback, + void * _userdata); + +// destroy frame synchronizer +int flexframesync_destroy(flexframesync _q); + +// print frame synchronizer internal properties +int flexframesync_print(flexframesync _q); + +// reset frame synchronizer internal state +int flexframesync_reset(flexframesync _q); + +// has frame been detected? +int flexframesync_is_frame_open(flexframesync _q); + +// change length of user-defined region in header +int flexframesync_set_header_len(flexframesync _q, + unsigned int _len); + +// enable or disable soft decoding of header +int flexframesync_decode_header_soft(flexframesync _q, + int _soft); + +// enable or disable soft decoding of payload +int flexframesync_decode_payload_soft(flexframesync _q, + int _soft); + +// set properties for header section +int flexframesync_set_header_props(flexframesync _q, + flexframegenprops_s * _props); + +// push samples through frame synchronizer +// _q : frame synchronizer object +// _x : input samples [size: _n x 1] +// _n : number of input samples +int flexframesync_execute(flexframesync _q, + liquid_float_complex * _x, + unsigned int _n); + +// frame data statistics +int flexframesync_reset_framedatastats(flexframesync _q); +framedatastats_s flexframesync_get_framedatastats (flexframesync _q); + +// enable/disable debugging +int flexframesync_debug_enable(flexframesync _q); +int flexframesync_debug_disable(flexframesync _q); +int flexframesync_debug_print(flexframesync _q, + const char * _filename); + +// +// bpacket : binary packet suitable for data streaming +// + +// +// bpacket generator/encoder +// +typedef struct bpacketgen_s * bpacketgen; + +// create bpacketgen object +// _m : p/n sequence length (ignored) +// _dec_msg_len : decoded message length (original uncoded data) +// _crc : data validity check (e.g. cyclic redundancy check) +// _fec0 : inner forward error-correction code scheme +// _fec1 : outer forward error-correction code scheme +bpacketgen bpacketgen_create(unsigned int _m, + unsigned int _dec_msg_len, + int _crc, + int _fec0, + int _fec1); + +// re-create bpacketgen object from old object +// _q : old bpacketgen object +// _m : p/n sequence length (ignored) +// _dec_msg_len : decoded message length (original uncoded data) +// _crc : data validity check (e.g. cyclic redundancy check) +// _fec0 : inner forward error-correction code scheme +// _fec1 : outer forward error-correction code scheme +bpacketgen bpacketgen_recreate(bpacketgen _q, + unsigned int _m, + unsigned int _dec_msg_len, + int _crc, + int _fec0, + int _fec1); + +// destroy bpacketgen object, freeing all internally-allocated memory +void bpacketgen_destroy(bpacketgen _q); + +// print bpacketgen internals +void bpacketgen_print(bpacketgen _q); + +// return length of full packet +unsigned int bpacketgen_get_packet_len(bpacketgen _q); + +// encode packet +void bpacketgen_encode(bpacketgen _q, + unsigned char * _msg_dec, + unsigned char * _packet); + +// +// bpacket synchronizer/decoder +// +typedef struct bpacketsync_s * bpacketsync; +typedef int (*bpacketsync_callback)(unsigned char * _payload, + int _payload_valid, + unsigned int _payload_len, + framesyncstats_s _stats, + void * _userdata); +bpacketsync bpacketsync_create(unsigned int _m, + bpacketsync_callback _callback, + void * _userdata); +int bpacketsync_destroy(bpacketsync _q); +int bpacketsync_print(bpacketsync _q); +int bpacketsync_reset(bpacketsync _q); + +// run synchronizer on array of input bytes +// _q : bpacketsync object +// _bytes : input data array [size: _n x 1] +// _n : input array size +int bpacketsync_execute(bpacketsync _q, + unsigned char * _bytes, + unsigned int _n); + +// run synchronizer on input byte +// _q : bpacketsync object +// _byte : input byte +int bpacketsync_execute_byte(bpacketsync _q, + unsigned char _byte); + +// run synchronizer on input symbol +// _q : bpacketsync object +// _sym : input symbol with _bps significant bits +// _bps : number of bits in input symbol +int bpacketsync_execute_sym(bpacketsync _q, + unsigned char _sym, + unsigned int _bps); + +// execute one bit at a time +int bpacketsync_execute_bit(bpacketsync _q, + unsigned char _bit); + +// +// M-FSK frame generator +// + +typedef struct fskframegen_s * fskframegen; + +// create M-FSK frame generator +fskframegen fskframegen_create(); +int fskframegen_destroy (fskframegen _fg); +int fskframegen_print (fskframegen _fg); +int fskframegen_reset (fskframegen _fg); +int fskframegen_assemble(fskframegen _fg, + unsigned char * _header, + unsigned char * _payload, + unsigned int _payload_len, + crc_scheme _check, + fec_scheme _fec0, + fec_scheme _fec1); +unsigned int fskframegen_getframelen(fskframegen _q); +int fskframegen_write_samples(fskframegen _fg, + liquid_float_complex * _buf, + unsigned int _buf_len); + + +// +// M-FSK frame synchronizer +// + +typedef struct fskframesync_s * fskframesync; + +// create M-FSK frame synchronizer +// _callback : callback function +// _userdata : user data pointer passed to callback function +fskframesync fskframesync_create(framesync_callback _callback, + void * _userdata); +int fskframesync_destroy(fskframesync _q); +int fskframesync_print (fskframesync _q); +int fskframesync_reset (fskframesync _q); +int fskframesync_execute(fskframesync _q, + liquid_float_complex _x); +int fskframesync_execute_block(fskframesync _q, + liquid_float_complex * _x, + unsigned int _n); + +// debugging +int fskframesync_debug_enable (fskframesync _q); +int fskframesync_debug_disable(fskframesync _q); +int fskframesync_debug_export (fskframesync _q, const char * _filename); + + +// +// GMSK frame generator +// + +typedef struct gmskframegen_s * gmskframegen; + +// create GMSK frame generator +gmskframegen gmskframegen_create(); +int gmskframegen_destroy (gmskframegen _q); +int gmskframegen_is_assembled (gmskframegen _q); +int gmskframegen_print (gmskframegen _q); +int gmskframegen_set_header_len(gmskframegen _q, unsigned int _len); +int gmskframegen_reset (gmskframegen _q); +int gmskframegen_assemble (gmskframegen _q, + const unsigned char * _header, + const unsigned char * _payload, + unsigned int _payload_len, + crc_scheme _check, + fec_scheme _fec0, + fec_scheme _fec1); +unsigned int gmskframegen_getframelen(gmskframegen _q); +int gmskframegen_write_samples(gmskframegen _q, + liquid_float_complex * _y); + +// write samples of assembled frame +// _q : frame generator object +// _buf : output buffer [size: _buf_len x 1] +// _buf_len : output buffer length +int gmskframegen_write(gmskframegen _q, + liquid_float_complex * _buf, + unsigned int _buf_len); + + +// +// GMSK frame synchronizer +// + +typedef struct gmskframesync_s * gmskframesync; + +// create GMSK frame synchronizer +// _callback : callback function +// _userdata : user data pointer passed to callback function +gmskframesync gmskframesync_create(framesync_callback _callback, + void * _userdata); +int gmskframesync_destroy(gmskframesync _q); +int gmskframesync_print(gmskframesync _q); +int gmskframesync_set_header_len(gmskframesync _q, unsigned int _len); +int gmskframesync_reset(gmskframesync _q); +int gmskframesync_is_frame_open(gmskframesync _q); +int gmskframesync_execute(gmskframesync _q, + liquid_float_complex * _x, + unsigned int _n); + +// debugging +int gmskframesync_debug_enable(gmskframesync _q); +int gmskframesync_debug_disable(gmskframesync _q); +int gmskframesync_debug_print(gmskframesync _q, const char * _filename); + + +// +// DSSS frame generator +// + +typedef struct { + unsigned int check; + unsigned int fec0; + unsigned int fec1; +} dsssframegenprops_s; + +typedef struct dsssframegen_s * dsssframegen; + +dsssframegen dsssframegen_create(dsssframegenprops_s * _props); +int dsssframegen_destroy(dsssframegen _q); +int dsssframegen_reset(dsssframegen _q); +int dsssframegen_is_assembled(dsssframegen _q); +int dsssframegen_getprops(dsssframegen _q, dsssframegenprops_s * _props); +int dsssframegen_setprops(dsssframegen _q, dsssframegenprops_s * _props); +int dsssframegen_set_header_len(dsssframegen _q, unsigned int _len); +int dsssframegen_set_header_props(dsssframegen _q, + dsssframegenprops_s * _props); +unsigned int dsssframegen_getframelen(dsssframegen _q); + +// assemble a frame from an array of data +// _q : frame generator object +// _header : frame header +// _payload : payload data [size: _payload_len x 1] +// _payload_len : payload data length +int dsssframegen_assemble(dsssframegen _q, + const unsigned char * _header, + const unsigned char * _payload, + unsigned int _payload_len); + +int dsssframegen_write_samples(dsssframegen _q, + liquid_float_complex * _buffer, + unsigned int _buffer_len); + + +// +// DSSS frame synchronizer +// + +typedef struct dsssframesync_s * dsssframesync; + +dsssframesync dsssframesync_create(framesync_callback _callback, void * _userdata); +int dsssframesync_destroy (dsssframesync _q); +int dsssframesync_print (dsssframesync _q); +int dsssframesync_reset (dsssframesync _q); +int dsssframesync_is_frame_open (dsssframesync _q); +int dsssframesync_set_header_len (dsssframesync _q, unsigned int _len); +int dsssframesync_decode_header_soft (dsssframesync _q, int _soft); +int dsssframesync_decode_payload_soft (dsssframesync _q, int _soft); +int dsssframesync_set_header_props (dsssframesync _q, dsssframegenprops_s * _props); +int dsssframesync_execute (dsssframesync _q, liquid_float_complex * _x, unsigned int _n); +int dsssframesync_reset_framedatastats(dsssframesync _q); +int dsssframesync_debug_enable (dsssframesync _q); +int dsssframesync_debug_disable (dsssframesync _q); +int dsssframesync_debug_print (dsssframesync _q, const char * _filename); +framedatastats_s dsssframesync_get_framedatastats (dsssframesync _q); + +// +// OFDM flexframe generator +// + +// ofdm frame generator properties +typedef struct { + unsigned int check; // data validity check + unsigned int fec0; // forward error-correction scheme (inner) + unsigned int fec1; // forward error-correction scheme (outer) + unsigned int mod_scheme; // modulation scheme + //unsigned int block_size; // framing block size +} ofdmflexframegenprops_s; +int ofdmflexframegenprops_init_default(ofdmflexframegenprops_s * _props); + +typedef struct ofdmflexframegen_s * ofdmflexframegen; + +// create OFDM flexible framing generator object +// _M : number of subcarriers, >10 typical +// _cp_len : cyclic prefix length +// _taper_len : taper length (OFDM symbol overlap) +// _p : subcarrier allocation (null, pilot, data), [size: _M x 1] +// _fgprops : frame properties (modulation scheme, etc.) +ofdmflexframegen ofdmflexframegen_create(unsigned int _M, + unsigned int _cp_len, + unsigned int _taper_len, + unsigned char * _p, + ofdmflexframegenprops_s * _fgprops); + +// destroy ofdmflexframegen object +int ofdmflexframegen_destroy(ofdmflexframegen _q); + +// print parameters, properties, etc. +int ofdmflexframegen_print(ofdmflexframegen _q); + +// reset ofdmflexframegen object internals +int ofdmflexframegen_reset(ofdmflexframegen _q); + +// is frame assembled? +int ofdmflexframegen_is_assembled(ofdmflexframegen _q); + +// get properties +int ofdmflexframegen_getprops(ofdmflexframegen _q, + ofdmflexframegenprops_s * _props); + +// set properties +int ofdmflexframegen_setprops(ofdmflexframegen _q, + ofdmflexframegenprops_s * _props); + +// set user-defined header length +int ofdmflexframegen_set_header_len(ofdmflexframegen _q, + unsigned int _len); + +int ofdmflexframegen_set_header_props(ofdmflexframegen _q, + ofdmflexframegenprops_s * _props); + +// get length of frame (symbols) +// _q : OFDM frame generator object +unsigned int ofdmflexframegen_getframelen(ofdmflexframegen _q); + +// assemble a frame from an array of data (NULL pointers will use random data) +// _q : OFDM frame generator object +// _header : frame header [8 bytes] +// _payload : payload data [size: _payload_len x 1] +// _payload_len : payload data length +int ofdmflexframegen_assemble(ofdmflexframegen _q, + const unsigned char * _header, + const unsigned char * _payload, + unsigned int _payload_len); + +// write samples of assembled frame +// _q : OFDM frame generator object +// _buf : output buffer [size: _buf_len x 1] +// _buf_len : output buffer length +int ofdmflexframegen_write(ofdmflexframegen _q, + liquid_float_complex * _buf, + unsigned int _buf_len); + +// +// OFDM flex frame synchronizer +// + +typedef struct ofdmflexframesync_s * ofdmflexframesync; + +// create OFDM flexible framing synchronizer object +// _M : number of subcarriers +// _cp_len : cyclic prefix length +// _taper_len : taper length (OFDM symbol overlap) +// _p : subcarrier allocation (null, pilot, data), [size: _M x 1] +// _callback : user-defined callback function +// _userdata : user-defined data pointer +ofdmflexframesync ofdmflexframesync_create(unsigned int _M, + unsigned int _cp_len, + unsigned int _taper_len, + unsigned char * _p, + framesync_callback _callback, + void * _userdata); + +int ofdmflexframesync_destroy(ofdmflexframesync _q); +int ofdmflexframesync_print(ofdmflexframesync _q); +// set user-defined header length +int ofdmflexframesync_set_header_len(ofdmflexframesync _q, + unsigned int _len); + +int ofdmflexframesync_decode_header_soft(ofdmflexframesync _q, + int _soft); + +int ofdmflexframesync_decode_payload_soft(ofdmflexframesync _q, + int _soft); + +int ofdmflexframesync_set_header_props(ofdmflexframesync _q, + ofdmflexframegenprops_s * _props); + +int ofdmflexframesync_reset(ofdmflexframesync _q); +int ofdmflexframesync_is_frame_open(ofdmflexframesync _q); +int ofdmflexframesync_execute(ofdmflexframesync _q, + liquid_float_complex * _x, + unsigned int _n); + +// query the received signal strength indication +float ofdmflexframesync_get_rssi(ofdmflexframesync _q); + +// query the received carrier offset estimate +float ofdmflexframesync_get_cfo(ofdmflexframesync _q); + +// frame data statistics +int ofdmflexframesync_reset_framedatastats(ofdmflexframesync _q); +framedatastats_s ofdmflexframesync_get_framedatastats (ofdmflexframesync _q); + +// set the received carrier offset estimate +int ofdmflexframesync_set_cfo(ofdmflexframesync _q, float _cfo); + +// enable/disable debugging +int ofdmflexframesync_debug_enable(ofdmflexframesync _q); +int ofdmflexframesync_debug_disable(ofdmflexframesync _q); +int ofdmflexframesync_debug_print(ofdmflexframesync _q, + const char * _filename); + + + +// +// Binary P/N synchronizer +// +#define LIQUID_BSYNC_MANGLE_RRRF(name) LIQUID_CONCAT(bsync_rrrf,name) +#define LIQUID_BSYNC_MANGLE_CRCF(name) LIQUID_CONCAT(bsync_crcf,name) +#define LIQUID_BSYNC_MANGLE_CCCF(name) LIQUID_CONCAT(bsync_cccf,name) + +// Macro: +// BSYNC : name-mangling macro +// TO : output data type +// TC : coefficients data type +// TI : input data type +#define LIQUID_BSYNC_DEFINE_API(BSYNC,TO,TC,TI) \ + \ +/* Binary P/N synchronizer */ \ +typedef struct BSYNC(_s) * BSYNC(); \ + \ +/* Create bsync object */ \ +/* _n : sequence length */ \ +/* _v : correlation sequence [size: _n x 1] */ \ +BSYNC() BSYNC(_create)(unsigned int _n, \ + TC * _v); \ + \ +/* Create binary synchronizer from m-sequence */ \ +/* _g : m-sequence generator polynomial */ \ +/* _k : samples/symbol (over-sampling factor) */ \ +BSYNC() BSYNC(_create_msequence)(unsigned int _g, \ + unsigned int _k); \ + \ +/* Destroy binary synchronizer object, freeing all internal memory */ \ +/* _q : bsync object */ \ +void BSYNC(_destroy)(BSYNC() _q); \ + \ +/* Print object internals to stdout */ \ +/* _q : bsync object */ \ +void BSYNC(_print)(BSYNC() _q); \ + \ +/* Correlate input signal against internal sequence */ \ +/* _q : bsync object */ \ +/* _x : input sample */ \ +/* _y : pointer to output sample */ \ +void BSYNC(_correlate)(BSYNC() _q, \ + TI _x, \ + TO * _y); \ + +LIQUID_BSYNC_DEFINE_API(LIQUID_BSYNC_MANGLE_RRRF, + float, + float, + float) + +LIQUID_BSYNC_DEFINE_API(LIQUID_BSYNC_MANGLE_CRCF, + liquid_float_complex, + float, + liquid_float_complex) + +LIQUID_BSYNC_DEFINE_API(LIQUID_BSYNC_MANGLE_CCCF, + liquid_float_complex, + liquid_float_complex, + liquid_float_complex) + + +// +// Pre-demodulation synchronizers (binary and otherwise) +// +#define LIQUID_PRESYNC_MANGLE_CCCF(name) LIQUID_CONCAT( presync_cccf,name) +#define LIQUID_BPRESYNC_MANGLE_CCCF(name) LIQUID_CONCAT(bpresync_cccf,name) + +// Macro: +// PRESYNC : name-mangling macro +// TO : output data type +// TC : coefficients data type +// TI : input data type +#define LIQUID_PRESYNC_DEFINE_API(PRESYNC,TO,TC,TI) \ + \ +/* Pre-demodulation signal synchronizer */ \ +typedef struct PRESYNC(_s) * PRESYNC(); \ + \ +/* Create pre-demod synchronizer from external sequence */ \ +/* _v : baseband sequence, [size: _n x 1] */ \ +/* _n : baseband sequence length, _n > 0 */ \ +/* _dphi_max : maximum absolute frequency deviation for detection */ \ +/* _m : number of correlators, _m > 0 */ \ +PRESYNC() PRESYNC(_create)(TC * _v, \ + unsigned int _n, \ + float _dphi_max, \ + unsigned int _m); \ + \ +/* Destroy pre-demod synchronizer, freeing all internal memory */ \ +int PRESYNC(_destroy)(PRESYNC() _q); \ + \ +/* Print pre-demod synchronizer internal state */ \ +int PRESYNC(_print)(PRESYNC() _q); \ + \ +/* Reset pre-demod synchronizer internal state */ \ +int PRESYNC(_reset)(PRESYNC() _q); \ + \ +/* Push input sample into pre-demod synchronizer */ \ +/* _q : pre-demod synchronizer object */ \ +/* _x : input sample */ \ +int PRESYNC(_push)(PRESYNC() _q, \ + TI _x); \ + \ +/* Correlate original sequence with internal input buffer */ \ +/* _q : pre-demod synchronizer object */ \ +/* _rxy : output cross correlation */ \ +/* _dphi_hat : output frequency offset estimate */ \ +int PRESYNC(_execute)(PRESYNC() _q, \ + TO * _rxy, \ + float * _dphi_hat); \ + +// non-binary pre-demodulation synchronizer +LIQUID_PRESYNC_DEFINE_API(LIQUID_PRESYNC_MANGLE_CCCF, + liquid_float_complex, + liquid_float_complex, + liquid_float_complex) + +// binary pre-demodulation synchronizer +LIQUID_PRESYNC_DEFINE_API(LIQUID_BPRESYNC_MANGLE_CCCF, + liquid_float_complex, + liquid_float_complex, + liquid_float_complex) + +// +// Frame detector +// + +typedef struct qdetector_cccf_s * qdetector_cccf; + +// create detector with generic sequence +// _s : sample sequence +// _s_len : length of sample sequence +qdetector_cccf qdetector_cccf_create(liquid_float_complex * _s, + unsigned int _s_len); + +// create detector from sequence of symbols using internal linear interpolator +// _sequence : symbol sequence +// _sequence_len : length of symbol sequence +// _ftype : filter prototype (e.g. LIQUID_FIRFILT_RRC) +// _k : samples/symbol +// _m : filter delay +// _beta : excess bandwidth factor +qdetector_cccf qdetector_cccf_create_linear(liquid_float_complex * _sequence, + unsigned int _sequence_len, + int _ftype, + unsigned int _k, + unsigned int _m, + float _beta); + +// create detector from sequence of GMSK symbols +// _sequence : bit sequence +// _sequence_len : length of bit sequence +// _k : samples/symbol +// _m : filter delay +// _beta : excess bandwidth factor +qdetector_cccf qdetector_cccf_create_gmsk(unsigned char * _sequence, + unsigned int _sequence_len, + unsigned int _k, + unsigned int _m, + float _beta); + +// create detector from sequence of CP-FSK symbols (assuming one bit/symbol) +// _sequence : bit sequence +// _sequence_len : length of bit sequence +// _bps : bits per symbol, 0 < _bps <= 8 +// _h : modulation index, _h > 0 +// _k : samples/symbol +// _m : filter delay +// _beta : filter bandwidth parameter, _beta > 0 +// _type : filter type (e.g. LIQUID_CPFSK_SQUARE) +qdetector_cccf qdetector_cccf_create_cpfsk(unsigned char * _sequence, + unsigned int _sequence_len, + unsigned int _bps, + float _h, + unsigned int _k, + unsigned int _m, + float _beta, + int _type); + +int qdetector_cccf_destroy(qdetector_cccf _q); +int qdetector_cccf_print (qdetector_cccf _q); +int qdetector_cccf_reset (qdetector_cccf _q); + +// run detector, looking for sequence; return pointer to aligned, buffered samples +void * qdetector_cccf_execute(qdetector_cccf _q, + liquid_float_complex _x); + +// set detection threshold (should be between 0 and 1, good starting point is 0.5) +int qdetector_cccf_set_threshold(qdetector_cccf _q, + float _threshold); + +// set carrier offset search range +int qdetector_cccf_set_range(qdetector_cccf _q, + float _dphi_max); + +// access methods +unsigned int qdetector_cccf_get_seq_len (qdetector_cccf _q); // sequence length +const void * qdetector_cccf_get_sequence(qdetector_cccf _q); // pointer to sequence +unsigned int qdetector_cccf_get_buf_len (qdetector_cccf _q); // buffer length +float qdetector_cccf_get_rxy (qdetector_cccf _q); // correlator output +float qdetector_cccf_get_tau (qdetector_cccf _q); // fractional timing offset estimate +float qdetector_cccf_get_gamma (qdetector_cccf _q); // channel gain +float qdetector_cccf_get_dphi (qdetector_cccf _q); // carrier frequency offset estimate +float qdetector_cccf_get_phi (qdetector_cccf _q); // carrier phase offset estimate + +// +// Pre-demodulation detector +// + +typedef struct detector_cccf_s * detector_cccf; + +// create pre-demod detector +// _s : sequence +// _n : sequence length +// _threshold : detection threshold (default: 0.7) +// _dphi_max : maximum carrier offset +detector_cccf detector_cccf_create(liquid_float_complex * _s, + unsigned int _n, + float _threshold, + float _dphi_max); + +// destroy pre-demo detector object +void detector_cccf_destroy(detector_cccf _q); + +// print pre-demod detector internal state +void detector_cccf_print(detector_cccf _q); + +// reset pre-demod detector internal state +void detector_cccf_reset(detector_cccf _q); + +// Run sample through pre-demod detector's correlator. +// Returns '1' if signal was detected, '0' otherwise +// _q : pre-demod detector +// _x : input sample +// _tau_hat : fractional sample offset estimate (set when detected) +// _dphi_hat : carrier frequency offset estimate (set when detected) +// _gamma_hat : channel gain estimate (set when detected) +int detector_cccf_correlate(detector_cccf _q, + liquid_float_complex _x, + float * _tau_hat, + float * _dphi_hat, + float * _gamma_hat); + + +// +// symbol streaming for testing (no meaningful data, just symbols) +// +#define LIQUID_SYMSTREAM_MANGLE_CFLOAT(name) LIQUID_CONCAT(symstreamcf,name) + +#define LIQUID_SYMSTREAM_DEFINE_API(SYMSTREAM,TO) \ + \ +/* Symbol streaming generator object */ \ +typedef struct SYMSTREAM(_s) * SYMSTREAM(); \ + \ +/* Create symstream object with default parameters. */ \ +/* This is equivalent to invoking the create_linear() method */ \ +/* with _ftype=LIQUID_FIRFILT_ARKAISER, _k=2, _m=7, _beta=0.3, and */ \ +/* with _ms=LIQUID_MODEM_QPSK */ \ +SYMSTREAM() SYMSTREAM(_create)(void); \ + \ +/* Create symstream object with linear modulation */ \ +/* _ftype : filter type (e.g. LIQUID_FIRFILT_RRC) */ \ +/* _k : samples per symbol, _k >= 2 */ \ +/* _m : filter delay (symbols), _m > 0 */ \ +/* _beta : filter excess bandwidth, 0 < _beta <= 1 */ \ +/* _ms : modulation scheme, e.g. LIQUID_MODEM_QPSK */ \ +SYMSTREAM() SYMSTREAM(_create_linear)(int _ftype, \ + unsigned int _k, \ + unsigned int _m, \ + float _beta, \ + int _ms); \ + \ +/* Destroy symstream object, freeing all internal memory */ \ +int SYMSTREAM(_destroy)(SYMSTREAM() _q); \ + \ +/* Print symstream object's parameters */ \ +int SYMSTREAM(_print)(SYMSTREAM() _q); \ + \ +/* Reset symstream internal state */ \ +int SYMSTREAM(_reset)(SYMSTREAM() _q); \ + \ +/* Set internal linear modulation scheme, leaving the filter parameters */ \ +/* (interpolator) unmodified */ \ +int SYMSTREAM(_set_scheme)(SYMSTREAM() _q, \ + int _ms); \ + \ +/* Get internal linear modulation scheme */ \ +int SYMSTREAM(_get_scheme)(SYMSTREAM() _q); \ + \ +/* Set internal linear gain (before interpolation) */ \ +int SYMSTREAM(_set_gain)(SYMSTREAM() _q, \ + float _gain); \ + \ +/* Get internal linear gain (before interpolation) */ \ +float SYMSTREAM(_get_gain)(SYMSTREAM() _q); \ + \ +/* Write block of samples to output buffer */ \ +/* _q : synchronizer object */ \ +/* _buf : output buffer [size: _buf_len x 1] */ \ +/* _buf_len: output buffer size */ \ +int SYMSTREAM(_write_samples)(SYMSTREAM() _q, \ + TO * _buf, \ + unsigned int _buf_len); \ + +LIQUID_SYMSTREAM_DEFINE_API(LIQUID_SYMSTREAM_MANGLE_CFLOAT, liquid_float_complex) + + + +// +// multi-signal source for testing (no meaningful data, just signals) +// + +#define LIQUID_MSOURCE_MANGLE_CFLOAT(name) LIQUID_CONCAT(msourcecf,name) + +#define LIQUID_MSOURCE_DEFINE_API(MSOURCE,TO) \ + \ +/* Multi-signal source generator object */ \ +typedef struct MSOURCE(_s) * MSOURCE(); \ + \ +/* Create msource object by specifying channelizer parameters */ \ +/* _M : number of channels in analysis channelizer object */ \ +/* _m : prototype channelizer filter semi-length */ \ +/* _As : prototype channelizer filter stop-band suppression (dB) */ \ +MSOURCE() MSOURCE(_create)(unsigned int _M, \ + unsigned int _m, \ + float _As); \ + \ +/* Create default msource object with default parameters: */ \ +/* M = 1200, m = 4, As = 60 */ \ +MSOURCE() MSOURCE(_create_default)(void); \ + \ +/* Destroy msource object */ \ +int MSOURCE(_destroy)(MSOURCE() _q); \ + \ +/* Print msource object */ \ +int MSOURCE(_print)(MSOURCE() _q); \ + \ +/* Reset msource object */ \ +int MSOURCE(_reset)(MSOURCE() _q); \ + \ +/* user-defined callback for generating samples */ \ +typedef int (*MSOURCE(_callback))(void * _userdata, \ + TO * _v, \ + unsigned int _n); \ + \ +/* Add user-defined signal generator */ \ +int MSOURCE(_add_user)(MSOURCE() _q, \ + float _fc, \ + float _bw, \ + float _gain, \ + void * _userdata, \ + MSOURCE(_callback) _callback); \ + \ +/* Add tone to signal generator, returning id of signal */ \ +int MSOURCE(_add_tone)(MSOURCE() _q, \ + float _fc, \ + float _bw, \ + float _gain); \ + \ +/* Add chirp to signal generator, returning id of signal */ \ +/* _q : multi-signal source object */ \ +/* _duration : duration of chirp [samples] */ \ +/* _negate : negate frequency direction */ \ +/* _single : run single chirp? or repeatedly */ \ +int MSOURCE(_add_chirp)(MSOURCE() _q, \ + float _fc, \ + float _bw, \ + float _gain, \ + float _duration, \ + int _negate, \ + int _repeat); \ + \ +/* Add noise source to signal generator, returning id of signal */ \ +/* _q : multi-signal source object */ \ +/* _fc : ... */ \ +/* _bw : ... */ \ +/* _nstd : ... */ \ +int MSOURCE(_add_noise)(MSOURCE() _q, \ + float _fc, \ + float _bw, \ + float _gain); \ + \ +/* Add modem signal source, returning id of signal */ \ +/* _q : multi-signal source object */ \ +/* _ms : modulation scheme, e.g. LIQUID_MODEM_QPSK */ \ +/* _m : filter delay (symbols), _m > 0 */ \ +/* _beta : filter excess bandwidth, 0 < _beta <= 1 */ \ +int MSOURCE(_add_modem)(MSOURCE() _q, \ + float _fc, \ + float _bw, \ + float _gain, \ + int _ms, \ + unsigned int _m, \ + float _beta); \ + \ +/* Add frequency-shift keying modem signal source, returning id of */ \ +/* signal */ \ +/* _q : multi-signal source object */ \ +/* _m : bits per symbol, _bps > 0 */ \ +/* _k : samples/symbol, _k >= 2^_m */ \ +int MSOURCE(_add_fsk)(MSOURCE() _q, \ + float _fc, \ + float _bw, \ + float _gain, \ + unsigned int _m, \ + unsigned int _k); \ + \ +/* Add GMSK modem signal source, returning id of signal */ \ +/* _q : multi-signal source object */ \ +/* _m : filter delay (symbols), _m > 0 */ \ +/* _bt : filter bandwidth-time factor, 0 < _bt <= 1 */ \ +int MSOURCE(_add_gmsk)(MSOURCE() _q, \ + float _fc, \ + float _bw, \ + float _gain, \ + unsigned int _m, \ + float _bt); \ + \ +/* Remove signal with a particular id, returning 0 upon success */ \ +/* _q : multi-signal source object */ \ +/* _id : signal source id */ \ +int MSOURCE(_remove)(MSOURCE() _q, \ + int _id); \ + \ +/* Enable signal source with a particular id */ \ +int MSOURCE(_enable)(MSOURCE() _q, \ + int _id); \ + \ +/* Disable signal source with a particular id */ \ +int MSOURCE(_disable)(MSOURCE() _q, \ + int _id); \ + \ +/* Set gain in decibels on signal */ \ +/* _q : msource object */ \ +/* _id : source id */ \ +/* _gain : signal gain [dB] */ \ +int MSOURCE(_set_gain)(MSOURCE() _q, \ + int _id, \ + float _gain); \ + \ +/* Get gain in decibels on signal */ \ +/* _q : msource object */ \ +/* _id : source id */ \ +/* _gain : signal gain output [dB] */ \ +int MSOURCE(_get_gain)(MSOURCE() _q, \ + int _id, \ + float * _gain); \ + \ +/* Get number of samples generated by the object so far */ \ +/* _q : msource object */ \ +/* _return : number of time-domain samples generated */ \ +unsigned long long int MSOURCE(_get_num_samples)(MSOURCE() _q); \ + \ +/* Set carrier offset to signal */ \ +/* _q : msource object */ \ +/* _id : source id */ \ +/* _fc : normalized carrier frequency offset, -0.5 <= _fc <= 0.5 */ \ +int MSOURCE(_set_frequency)(MSOURCE() _q, \ + int _id, \ + float _dphi); \ + \ +/* Get carrier offset to signal */ \ +/* _q : msource object */ \ +/* _id : source id */ \ +/* _fc : normalized carrier frequency offset */ \ +int MSOURCE(_get_frequency)(MSOURCE() _q, \ + int _id, \ + float * _dphi); \ + \ +/* Write block of samples to output buffer */ \ +/* _q : synchronizer object */ \ +/* _buf : output buffer, [size: _buf_len x 1] */ \ +/* _buf_len: output buffer size */ \ +int MSOURCE(_write_samples)(MSOURCE() _q, \ + TO * _buf, \ + unsigned int _buf_len); \ + +LIQUID_MSOURCE_DEFINE_API(LIQUID_MSOURCE_MANGLE_CFLOAT, liquid_float_complex) + + + + +// +// Symbol tracking: AGC > symsync > EQ > carrier recovery +// +#define LIQUID_SYMTRACK_MANGLE_RRRF(name) LIQUID_CONCAT(symtrack_rrrf,name) +#define LIQUID_SYMTRACK_MANGLE_CCCF(name) LIQUID_CONCAT(symtrack_cccf,name) + +// large macro +// SYMTRACK : name-mangling macro +// T : data type, primitive +// TO : data type, output +// TC : data type, coefficients +// TI : data type, input +#define LIQUID_SYMTRACK_DEFINE_API(SYMTRACK,T,TO,TC,TI) \ + \ +/* Symbol synchronizer and tracking object */ \ +typedef struct SYMTRACK(_s) * SYMTRACK(); \ + \ +/* Create symtrack object, specifying parameters for operation */ \ +/* _ftype : filter type (e.g. LIQUID_FIRFILT_RRC) */ \ +/* _k : samples per symbol, _k >= 2 */ \ +/* _m : filter delay [symbols], _m > 0 */ \ +/* _beta : excess bandwidth factor, 0 <= _beta <= 1 */ \ +/* _ms : modulation scheme, _ms(LIQUID_MODEM_BPSK) */ \ +SYMTRACK() SYMTRACK(_create)(int _ftype, \ + unsigned int _k, \ + unsigned int _m, \ + float _beta, \ + int _ms); \ + \ +/* Create symtrack object using default parameters. */ \ +/* The default parameters are */ \ +/* ftype = LIQUID_FIRFILT_ARKAISER (filter type), */ \ +/* k = 2 (samples per symbol), */ \ +/* m = 7 (filter delay), */ \ +/* beta = 0.3 (excess bandwidth factor), and */ \ +/* ms = LIQUID_MODEM_QPSK (modulation scheme) */ \ +SYMTRACK() SYMTRACK(_create_default)(); \ + \ +/* Destroy symtrack object, freeing all internal memory */ \ +int SYMTRACK(_destroy)(SYMTRACK() _q); \ + \ +/* Print symtrack object's parameters */ \ +int SYMTRACK(_print)(SYMTRACK() _q); \ + \ +/* Reset symtrack internal state */ \ +int SYMTRACK(_reset)(SYMTRACK() _q); \ + \ +/* Set symtrack modulation scheme */ \ +/* _q : symtrack object */ \ +/* _ms : modulation scheme, _ms(LIQUID_MODEM_BPSK) */ \ +int SYMTRACK(_set_modscheme)(SYMTRACK() _q, \ + int _ms); \ + \ +/* Set symtrack internal bandwidth */ \ +/* _q : symtrack object */ \ +/* _bw : tracking bandwidth, _bw > 0 */ \ +int SYMTRACK(_set_bandwidth)(SYMTRACK() _q, \ + float _bw); \ + \ +/* Adjust internal NCO by requested phase */ \ +/* _q : symtrack object */ \ +/* _dphi : NCO phase adjustment [radians] */ \ +int SYMTRACK(_adjust_phase)(SYMTRACK() _q, \ + T _dphi); \ + \ +/* Set symtrack equalization strategy to constant modulus (default) */ \ +int SYMTRACK(_set_eq_cm)(SYMTRACK() _q); \ + \ +/* Set symtrack equalization strategy to decision directed */ \ +int SYMTRACK(_set_eq_dd)(SYMTRACK() _q); \ + \ +/* Disable symtrack equalization */ \ +int SYMTRACK(_set_eq_off)(SYMTRACK() _q); \ + \ +/* Execute synchronizer on single input sample */ \ +/* _q : synchronizer object */ \ +/* _x : input data sample */ \ +/* _y : output data array, [size: 2 x 1] */ \ +/* _ny : number of samples written to output buffer (0, 1, or 2) */ \ +int SYMTRACK(_execute)(SYMTRACK() _q, \ + TI _x, \ + TO * _y, \ + unsigned int * _ny); \ + \ +/* execute synchronizer on input data array */ \ +/* _q : synchronizer object */ \ +/* _x : input data array */ \ +/* _nx : number of input samples */ \ +/* _y : output data array, [size: 2 _nx x 1] */ \ +/* _ny : number of samples written to output buffer */ \ +int SYMTRACK(_execute_block)(SYMTRACK() _q, \ + TI * _x, \ + unsigned int _nx, \ + TO * _y, \ + unsigned int * _ny); \ + +LIQUID_SYMTRACK_DEFINE_API(LIQUID_SYMTRACK_MANGLE_RRRF, + float, + float, + float, + float) + +LIQUID_SYMTRACK_DEFINE_API(LIQUID_SYMTRACK_MANGLE_CCCF, + float, + liquid_float_complex, + liquid_float_complex, + liquid_float_complex) + + + +// +// MODULE : math +// + +// ln( Gamma(z) ) +float liquid_lngammaf(float _z); + +// Gamma(z) +float liquid_gammaf(float _z); + +// ln( gamma(z,alpha) ) : lower incomplete gamma function +float liquid_lnlowergammaf(float _z, float _alpha); + +// ln( Gamma(z,alpha) ) : upper incomplete gamma function +float liquid_lnuppergammaf(float _z, float _alpha); + +// gamma(z,alpha) : lower incomplete gamma function +float liquid_lowergammaf(float _z, float _alpha); + +// Gamma(z,alpha) : upper incomplete gamma function +float liquid_uppergammaf(float _z, float _alpha); + +// n! +float liquid_factorialf(unsigned int _n); + + + +// ln(I_v(z)) : log Modified Bessel function of the first kind +float liquid_lnbesselif(float _nu, float _z); + +// I_v(z) : Modified Bessel function of the first kind +float liquid_besselif(float _nu, float _z); + +// I_0(z) : Modified Bessel function of the first kind (order zero) +float liquid_besseli0f(float _z); + +// J_v(z) : Bessel function of the first kind +float liquid_besseljf(float _nu, float _z); + +// J_0(z) : Bessel function of the first kind (order zero) +float liquid_besselj0f(float _z); + + +// Q function +float liquid_Qf(float _z); + +// Marcum Q-function +float liquid_MarcumQf(int _M, + float _alpha, + float _beta); + +// Marcum Q-function (M=1) +float liquid_MarcumQ1f(float _alpha, + float _beta); + +// sin(pi x) / (pi x) +float sincf(float _x); + +// next power of 2 : y = ceil(log2(_x)) +unsigned int liquid_nextpow2(unsigned int _x); + +// (n choose k) = n! / ( k! (n-k)! ) +float liquid_nchoosek(unsigned int _n, unsigned int _k); + +// +// Windowing functions +// + +// number of window functions available, including "unknown" type +#define LIQUID_WINDOW_NUM_FUNCTIONS (10) + +// prototypes +typedef enum { + LIQUID_WINDOW_UNKNOWN=0, // unknown/unsupported scheme + + LIQUID_WINDOW_HAMMING, // Hamming + LIQUID_WINDOW_HANN, // Hann + LIQUID_WINDOW_BLACKMANHARRIS, // Blackman-harris (4-term) + LIQUID_WINDOW_BLACKMANHARRIS7, // Blackman-harris (7-term) + LIQUID_WINDOW_KAISER, // Kaiser (beta factor unspecified) + LIQUID_WINDOW_FLATTOP, // flat top (includes negative values) + LIQUID_WINDOW_TRIANGULAR, // triangular + LIQUID_WINDOW_RCOSTAPER, // raised-cosine taper (taper size unspecified) + LIQUID_WINDOW_KBD, // Kaiser-Bessel derived window (beta factor unspecified) +} liquid_window_type; + +// pretty names for window +extern const char * liquid_window_str[LIQUID_WINDOW_NUM_FUNCTIONS][2]; + +// Print compact list of existing and available windowing functions +void liquid_print_windows(); + +// returns window type based on input string +liquid_window_type liquid_getopt_str2window(const char * _str); + +// generic window function given type +// _type : window type, e.g. LIQUID_WINDOW_KAISER +// _i : window index, _i in [0,_wlen-1] +// _wlen : length of window +// _arg : window-specific argument, if required +float liquid_windowf(liquid_window_type _type, + unsigned int _i, + unsigned int _wlen, + float _arg); + +// Kaiser window +// _i : window index, _i in [0,_wlen-1] +// _wlen : full window length +// _beta : Kaiser-Bessel window shape parameter +float liquid_kaiser(unsigned int _i, + unsigned int _wlen, + float _beta); + +// Hamming window +// _i : window index, _i in [0,_wlen-1] +// _wlen : full window length +float liquid_hamming(unsigned int _i, + unsigned int _wlen); + +// Hann window +// _i : window index, _i in [0,_wlen-1] +// _wlen : full window length +float liquid_hann(unsigned int _i, + unsigned int _wlen); + +// Blackman-harris window +// _i : window index, _i in [0,_wlen-1] +// _wlen : full window length +float liquid_blackmanharris(unsigned int _i, + unsigned int _wlen); + +// 7th order Blackman-harris window +// _i : window index, _i in [0,_wlen-1] +// _wlen : full window length +float liquid_blackmanharris7(unsigned int _i, + unsigned int _wlen); + +// Flat-top window +// _i : window index, _i in [0,_wlen-1] +// _wlen : full window length +float liquid_flattop(unsigned int _i, + unsigned int _wlen); + +// Triangular window +// _i : window index, _i in [0,_wlen-1] +// _wlen : full window length +// _L : triangle length, _L in {_wlen-1, _wlen, _wlen+1} +float liquid_triangular(unsigned int _i, + unsigned int _wlen, + unsigned int _L); + +// raised-cosine tapering window +// _i : window index +// _wlen : full window length +// _t : taper length, _t in [0,_wlen/2] +float liquid_rcostaper_window(unsigned int _i, + unsigned int _wlen, + unsigned int _t); + +// Kaiser-Bessel derived window (single sample) +// _i : window index, _i in [0,_wlen-1] +// _wlen : length of filter (must be even) +// _beta : Kaiser window parameter (_beta > 0) +float liquid_kbd(unsigned int _i, + unsigned int _wlen, + float _beta); + +// Kaiser-Bessel derived window (full window) +// _wlen : full window length (must be even) +// _beta : Kaiser window parameter (_beta > 0) +// _w : window output buffer, [size: _wlen x 1] +int liquid_kbd_window(unsigned int _wlen, + float _beta, + float * _w); + + +// polynomials + + +#define LIQUID_POLY_MANGLE_DOUBLE(name) LIQUID_CONCAT(poly, name) +#define LIQUID_POLY_MANGLE_FLOAT(name) LIQUID_CONCAT(polyf, name) + +#define LIQUID_POLY_MANGLE_CDOUBLE(name) LIQUID_CONCAT(polyc, name) +#define LIQUID_POLY_MANGLE_CFLOAT(name) LIQUID_CONCAT(polycf, name) + +// large macro +// POLY : name-mangling macro +// T : data type +// TC : data type (complex) +#define LIQUID_POLY_DEFINE_API(POLY,T,TC) \ + \ +/* Evaluate polynomial _p at value _x */ \ +/* _p : polynomial coefficients [size _k x 1] */ \ +/* _k : polynomial coefficients length, order is _k - 1 */ \ +/* _x : input to evaluate polynomial */ \ +T POLY(_val)(T * _p, \ + unsigned int _k, \ + T _x); \ + \ +/* Perform least-squares polynomial fit on data set */ \ +/* _x : x-value sample set [size: _n x 1] */ \ +/* _y : y-value sample set [size: _n x 1] */ \ +/* _n : number of samples in _x and _y */ \ +/* _p : polynomial coefficients output [size _k x 1] */ \ +/* _k : polynomial coefficients length, order is _k - 1 */ \ +int POLY(_fit)(T * _x, \ + T * _y, \ + unsigned int _n, \ + T * _p, \ + unsigned int _k); \ + \ +/* Perform Lagrange polynomial exact fit on data set */ \ +/* _x : x-value sample set, size [_n x 1] */ \ +/* _y : y-value sample set, size [_n x 1] */ \ +/* _n : number of samples in _x and _y */ \ +/* _p : polynomial coefficients output [size _n x 1] */ \ +int POLY(_fit_lagrange)(T * _x, \ + T * _y, \ + unsigned int _n, \ + T * _p); \ + \ +/* Perform Lagrange polynomial interpolation on data set without */ \ +/* computing coefficients as an intermediate step. */ \ +/* _x : x-value sample set [size: _n x 1] */ \ +/* _y : y-value sample set [size: _n x 1] */ \ +/* _n : number of samples in _x and _y */ \ +/* _x0 : x-value to evaluate and compute interpolant */ \ +T POLY(_interp_lagrange)(T * _x, \ + T * _y, \ + unsigned int _n, \ + T _x0); \ + \ +/* Compute Lagrange polynomial fit in the barycentric form. */ \ +/* _x : x-value sample set, size [_n x 1] */ \ +/* _n : number of samples in _x */ \ +/* _w : barycentric weights normalized so _w[0]=1, size [_n x 1] */ \ +int POLY(_fit_lagrange_barycentric)(T * _x, \ + unsigned int _n, \ + T * _w); \ + \ +/* Perform Lagrange polynomial interpolation using the barycentric form */ \ +/* of the weights. */ \ +/* _x : x-value sample set [size: _n x 1] */ \ +/* _y : y-value sample set [size: _n x 1] */ \ +/* _w : barycentric weights [size: _n x 1] */ \ +/* _x0 : x-value to evaluate and compute interpolant */ \ +/* _n : number of samples in _x, _y, and _w */ \ +T POLY(_val_lagrange_barycentric)(T * _x, \ + T * _y, \ + T * _w, \ + T _x0, \ + unsigned int _n); \ + \ +/* Perform binomial expansion on the polynomial */ \ +/* \( P_n(x) = (1+x)^n \) */ \ +/* as */ \ +/* \( P_n(x) = p[0] + p[1]x + p[2]x^2 + ... + p[n]x^n \) */ \ +/* NOTE: _p has order n (coefficients has length n+1) */ \ +/* _n : polynomial order */ \ +/* _p : polynomial coefficients [size: _n+1 x 1] */ \ +int POLY(_expandbinomial)(unsigned int _n, \ + T * _p); \ + \ +/* Perform positive/negative binomial expansion on the polynomial */ \ +/* \( P_n(x) = (1+x)^m (1-x)^k \) */ \ +/* as */ \ +/* \( P_n(x) = p[0] + p[1]x + p[2]x^2 + ... + p[n]x^n \) */ \ +/* NOTE: _p has order n=m+k (array is length n+1) */ \ +/* _m : number of '1+x' terms */ \ +/* _k : number of '1-x' terms */ \ +/* _p : polynomial coefficients [size: _m+_k+1 x 1] */ \ +int POLY(_expandbinomial_pm)(unsigned int _m, \ + unsigned int _k, \ + T * _p); \ + \ +/* Perform root expansion on the polynomial */ \ +/* \( P_n(x) = (x-r[0]) (x-r[1]) ... (x-r[n-1]) \) */ \ +/* as */ \ +/* \( P_n(x) = p[0] + p[1]x + ... + p[n]x^n \) */ \ +/* where \( r[0],r[1],...,r[n-1]\) are the roots of \( P_n(x) \). */ \ +/* NOTE: _p has order _n (array is length _n+1) */ \ +/* _r : roots of polynomial [size: _n x 1] */ \ +/* _n : number of roots in polynomial */ \ +/* _p : polynomial coefficients [size: _n+1 x 1] */ \ +int POLY(_expandroots)(T * _r, \ + unsigned int _n, \ + T * _p); \ + \ +/* Perform root expansion on the polynomial */ \ +/* \( P_n(x) = (xb[0]-a[0]) (xb[1]-a[1])...(xb[n-1]-a[n-1]) \) */ \ +/* as */ \ +/* \( P_n(x) = p[0] + p[1]x + ... + p[n]x^n \) */ \ +/* NOTE: _p has order _n (array is length _n+1) */ \ +/* _a : subtractant of polynomial rotos [size: _n x 1] */ \ +/* _b : multiplicant of polynomial roots [size: _n x 1] */ \ +/* _n : number of roots in polynomial */ \ +/* _p : polynomial coefficients [size: _n+1 x 1] */ \ +int POLY(_expandroots2)(T * _a, \ + T * _b, \ + unsigned int _n, \ + T * _p); \ + \ +/* Find the complex roots of a polynomial. */ \ +/* _p : polynomial coefficients [size: _n x 1] */ \ +/* _k : polynomial length */ \ +/* _roots : resulting complex roots [size: _k-1 x 1] */ \ +int POLY(_findroots)(T * _poly, \ + unsigned int _n, \ + TC * _roots); \ + \ +/* Find the complex roots of the polynomial using the Durand-Kerner */ \ +/* method */ \ +/* _p : polynomial coefficients [size: _n x 1] */ \ +/* _k : polynomial length */ \ +/* _roots : resulting complex roots [size: _k-1 x 1] */ \ +int POLY(_findroots_durandkerner)(T * _p, \ + unsigned int _k, \ + TC * _roots); \ + \ +/* Find the complex roots of the polynomial using Bairstow's method. */ \ +/* _p : polynomial coefficients [size: _n x 1] */ \ +/* _k : polynomial length */ \ +/* _roots : resulting complex roots [size: _k-1 x 1] */ \ +int POLY(_findroots_bairstow)(T * _p, \ + unsigned int _k, \ + TC * _roots); \ + \ +/* Expand the multiplication of two polynomials */ \ +/* \( ( a[0] + a[1]x + a[2]x^2 + ...) (b[0] + b[1]x + b[]x^2 + ...) \) */ \ +/* as */ \ +/* \( c[0] + c[1]x + c[2]x^2 + ... + c[n]x^n \) */ \ +/* where order(c) = order(a) + order(b) + 1 */ \ +/* and therefore length(c) = length(a) + length(b) - 1 */ \ +/* _a : 1st polynomial coefficients (length is _order_a+1) */ \ +/* _order_a : 1st polynomial order */ \ +/* _b : 2nd polynomial coefficients (length is _order_b+1) */ \ +/* _order_b : 2nd polynomial order */ \ +/* _c : output polynomial [size: _order_a+_order_b+1 x 1] */ \ +int POLY(_mul)(T * _a, \ + unsigned int _order_a, \ + T * _b, \ + unsigned int _order_b, \ + T * _c); \ + +LIQUID_POLY_DEFINE_API(LIQUID_POLY_MANGLE_DOUBLE, + double, + liquid_double_complex) + +LIQUID_POLY_DEFINE_API(LIQUID_POLY_MANGLE_FLOAT, + float, + liquid_float_complex) + +LIQUID_POLY_DEFINE_API(LIQUID_POLY_MANGLE_CDOUBLE, + liquid_double_complex, + liquid_double_complex) + +LIQUID_POLY_DEFINE_API(LIQUID_POLY_MANGLE_CFLOAT, + liquid_float_complex, + liquid_float_complex) + +#if 0 +// expands the polynomial: (1+x)^n +void poly_binomial_expand(unsigned int _n, int * _c); + +// expands the polynomial: (1+x)^k * (1-x)^(n-k) +void poly_binomial_expand_pm(unsigned int _n, + unsigned int _k, + int * _c); +#endif + +// +// modular arithmetic, etc. +// + +// maximum number of factors +#define LIQUID_MAX_FACTORS (40) + +// is number prime? +int liquid_is_prime(unsigned int _n); + +// compute number's prime factors +// _n : number to factor +// _factors : pre-allocated array of factors [size: LIQUID_MAX_FACTORS x 1] +// _num_factors: number of factors found, sorted ascending +int liquid_factor(unsigned int _n, + unsigned int * _factors, + unsigned int * _num_factors); + +// compute number's unique prime factors +// _n : number to factor +// _factors : pre-allocated array of factors [size: LIQUID_MAX_FACTORS x 1] +// _num_factors: number of unique factors found, sorted ascending +int liquid_unique_factor(unsigned int _n, + unsigned int * _factors, + unsigned int * _num_factors); + +// compute greatest common divisor between to numbers P and Q +unsigned int liquid_gcd(unsigned int _P, + unsigned int _Q); + +// compute c = base^exp (mod n) +unsigned int liquid_modpow(unsigned int _base, + unsigned int _exp, + unsigned int _n); + +// find smallest primitive root of _n +unsigned int liquid_primitive_root(unsigned int _n); + +// find smallest primitive root of _n, assuming _n is prime +unsigned int liquid_primitive_root_prime(unsigned int _n); + +// Euler's totient function +unsigned int liquid_totient(unsigned int _n); + + +// +// MODULE : matrix +// + +#define LIQUID_MATRIX_MANGLE_DOUBLE(name) LIQUID_CONCAT(matrix, name) +#define LIQUID_MATRIX_MANGLE_FLOAT(name) LIQUID_CONCAT(matrixf, name) + +#define LIQUID_MATRIX_MANGLE_CDOUBLE(name) LIQUID_CONCAT(matrixc, name) +#define LIQUID_MATRIX_MANGLE_CFLOAT(name) LIQUID_CONCAT(matrixcf, name) + +// large macro +// MATRIX : name-mangling macro +// T : data type +#define LIQUID_MATRIX_DEFINE_API(MATRIX,T) \ + \ +/* Print array as matrix to stdout */ \ +/* _x : input matrix, [size: _r x _c] */ \ +/* _r : rows in matrix */ \ +/* _c : columns in matrix */ \ +int MATRIX(_print)(T * _x, \ + unsigned int _r, \ + unsigned int _c); \ + \ +/* Perform point-wise addition between two matrices \(\vec{X}\) */ \ +/* and \(\vec{Y}\), saving the result in the output matrix \(\vec{Z}\). */ \ +/* That is, \(\vec{Z}_{i,j}=\vec{X}_{i,j}+\vec{Y}_{i,j} \), */ \ +/* \( \forall_{i \in r} \) and \( \forall_{j \in c} \) */ \ +/* _x : input matrix, [size: _r x _c] */ \ +/* _y : input matrix, [size: _r x _c] */ \ +/* _z : output matrix, [size: _r x _c] */ \ +/* _r : number of rows in each matrix */ \ +/* _c : number of columns in each matrix */ \ +int MATRIX(_add)(T * _x, \ + T * _y, \ + T * _z, \ + unsigned int _r, \ + unsigned int _c); \ + \ +/* Perform point-wise subtraction between two matrices \(\vec{X}\) */ \ +/* and \(\vec{Y}\), saving the result in the output matrix \(\vec{Z}\) */ \ +/* That is, \(\vec{Z}_{i,j}=\vec{X}_{i,j}-\vec{Y}_{i,j} \), */ \ +/* \( \forall_{i \in r} \) and \( \forall_{j \in c} \) */ \ +/* _x : input matrix, [size: _r x _c] */ \ +/* _y : input matrix, [size: _r x _c] */ \ +/* _z : output matrix, [size: _r x _c] */ \ +/* _r : number of rows in each matrix */ \ +/* _c : number of columns in each matrix */ \ +int MATRIX(_sub)(T * _x, \ + T * _y, \ + T * _z, \ + unsigned int _r, \ + unsigned int _c); \ + \ +/* Perform point-wise multiplication between two matrices \(\vec{X}\) */ \ +/* and \(\vec{Y}\), saving the result in the output matrix \(\vec{Z}\) */ \ +/* That is, \(\vec{Z}_{i,j}=\vec{X}_{i,j} \vec{Y}_{i,j} \), */ \ +/* \( \forall_{i \in r} \) and \( \forall_{j \in c} \) */ \ +/* _x : input matrix, [size: _r x _c] */ \ +/* _y : input matrix, [size: _r x _c] */ \ +/* _z : output matrix, [size: _r x _c] */ \ +/* _r : number of rows in each matrix */ \ +/* _c : number of columns in each matrix */ \ +int MATRIX(_pmul)(T * _x, \ + T * _y, \ + T * _z, \ + unsigned int _r, \ + unsigned int _c); \ + \ +/* Perform point-wise division between two matrices \(\vec{X}\) */ \ +/* and \(\vec{Y}\), saving the result in the output matrix \(\vec{Z}\) */ \ +/* That is, \(\vec{Z}_{i,j}=\vec{X}_{i,j}/\vec{Y}_{i,j} \), */ \ +/* \( \forall_{i \in r} \) and \( \forall_{j \in c} \) */ \ +/* _x : input matrix, [size: _r x _c] */ \ +/* _y : input matrix, [size: _r x _c] */ \ +/* _z : output matrix, [size: _r x _c] */ \ +/* _r : number of rows in each matrix */ \ +/* _c : number of columns in each matrix */ \ +int MATRIX(_pdiv)(T * _x, \ + T * _y, \ + T * _z, \ + unsigned int _r, \ + unsigned int _c); \ + \ +/* Multiply two matrices \(\vec{X}\) and \(\vec{Y}\), storing the */ \ +/* result in \(\vec{Z}\). */ \ +/* NOTE: _rz = _rx, _cz = _cy, and _cx = _ry */ \ +/* _x : input matrix, [size: _rx x _cx] */ \ +/* _rx : number of rows in _x */ \ +/* _cx : number of columns in _x */ \ +/* _y : input matrix, [size: _ry x _cy] */ \ +/* _ry : number of rows in _y */ \ +/* _cy : number of columns in _y */ \ +/* _z : output matrix, [size: _rz x _cz] */ \ +/* _rz : number of rows in _z */ \ +/* _cz : number of columns in _z */ \ +int MATRIX(_mul)(T * _x, unsigned int _rx, unsigned int _cx, \ + T * _y, unsigned int _ry, unsigned int _cy, \ + T * _z, unsigned int _rz, unsigned int _cz); \ + \ +/* Solve \(\vec{X} = \vec{Y} \vec{Z}\) for \(\vec{Z}\) for square */ \ +/* matrices of size \(n\) */ \ +/* _x : input matrix, [size: _n x _n] */ \ +/* _y : input matrix, [size: _n x _n] */ \ +/* _z : output matrix, [size: _n x _n] */ \ +/* _n : number of rows and columns in each matrix */ \ +int MATRIX(_div)(T * _x, \ + T * _y, \ + T * _z, \ + unsigned int _n); \ + \ +/* Compute the determinant of a square matrix \(\vec{X}\) */ \ +/* _x : input matrix, [size: _r x _c] */ \ +/* _r : rows */ \ +/* _c : columns */ \ +T MATRIX(_det)(T * _x, \ + unsigned int _r, \ + unsigned int _c); \ + \ +/* Compute the in-place transpose of the matrix \(\vec{X}\) */ \ +/* _x : input matrix, [size: _r x _c] */ \ +/* _r : rows */ \ +/* _c : columns */ \ +int MATRIX(_trans)(T * _x, \ + unsigned int _r, \ + unsigned int _c); \ + \ +/* Compute the in-place Hermitian transpose of the matrix \(\vec{X}\) */ \ +/* _x : input matrix, [size: _r x _c] */ \ +/* _r : rows */ \ +/* _c : columns */ \ +int MATRIX(_hermitian)(T * _x, \ + unsigned int _r, \ + unsigned int _c); \ + \ +/* Compute \(\vec{X}\vec{X}^T\) on a \(m \times n\) matrix. */ \ +/* The result is a \(m \times m\) matrix. */ \ +/* _x : input matrix, [size: _m x _n] */ \ +/* _m : input rows */ \ +/* _n : input columns */ \ +/* _xxT : output matrix, [size: _m x _m] */ \ +int MATRIX(_mul_transpose)(T * _x, \ + unsigned int _m, \ + unsigned int _n, \ + T * _xxT); \ + \ +/* Compute \(\vec{X}^T\vec{X}\) on a \(m \times n\) matrix. */ \ +/* The result is a \(n \times n\) matrix. */ \ +/* _x : input matrix, [size: _m x _n] */ \ +/* _m : input rows */ \ +/* _n : input columns */ \ +/* _xTx : output matrix, [size: _n x _n] */ \ +int MATRIX(_transpose_mul)(T * _x, \ + unsigned int _m, \ + unsigned int _n, \ + T * _xTx); \ + \ +/* Compute \(\vec{X}\vec{X}^H\) on a \(m \times n\) matrix. */ \ +/* The result is a \(m \times m\) matrix. */ \ +/* _x : input matrix, [size: _m x _n] */ \ +/* _m : input rows */ \ +/* _n : input columns */ \ +/* _xxH : output matrix, [size: _m x _m] */ \ +int MATRIX(_mul_hermitian)(T * _x, \ + unsigned int _m, \ + unsigned int _n, \ + T * _xxH); \ + \ +/* Compute \(\vec{X}^H\vec{X}\) on a \(m \times n\) matrix. */ \ +/* The result is a \(n \times n\) matrix. */ \ +/* _x : input matrix, [size: _m x _n] */ \ +/* _m : input rows */ \ +/* _n : input columns */ \ +/* _xHx : output matrix, [size: _n x _n] */ \ +int MATRIX(_hermitian_mul)(T * _x, \ + unsigned int _m, \ + unsigned int _n, \ + T * _xHx); \ + \ + \ +/* Augment two matrices \(\vec{X}\) and \(\vec{Y}\), storing the result */ \ +/* in \(\vec{Z}\) */ \ +/* NOTE: _rz = _rx = _ry, _rx = _ry, and _cz = _cx + _cy */ \ +/* _x : input matrix, [size: _rx x _cx] */ \ +/* _rx : number of rows in _x */ \ +/* _cx : number of columns in _x */ \ +/* _y : input matrix, [size: _ry x _cy] */ \ +/* _ry : number of rows in _y */ \ +/* _cy : number of columns in _y */ \ +/* _z : output matrix, [size: _rz x _cz] */ \ +/* _rz : number of rows in _z */ \ +/* _cz : number of columns in _z */ \ +int MATRIX(_aug)(T * _x, unsigned int _rx, unsigned int _cx, \ + T * _y, unsigned int _ry, unsigned int _cy, \ + T * _z, unsigned int _rz, unsigned int _cz); \ + \ +/* Compute the inverse of a square matrix \(\vec{X}\) */ \ +/* _x : input/output matrix, [size: _r x _c] */ \ +/* _r : rows */ \ +/* _c : columns */ \ +int MATRIX(_inv)(T * _x, \ + unsigned int _r, \ + unsigned int _c); \ + \ +/* Generate the identity square matrix of size \(n\) */ \ +/* _x : output matrix, [size: _n x _n] */ \ +/* _n : dimensions of _x */ \ +int MATRIX(_eye)(T * _x, \ + unsigned int _n); \ + \ +/* Generate the all-ones matrix of size \(n\) */ \ +/* _x : output matrix, [size: _r x _c] */ \ +/* _r : rows */ \ +/* _c : columns */ \ +int MATRIX(_ones)(T * _x, \ + unsigned int _r, \ + unsigned int _c); \ + \ +/* Generate the all-zeros matrix of size \(n\) */ \ +/* _x : output matrix, [size: _r x _c] */ \ +/* _r : rows */ \ +/* _c : columns */ \ +int MATRIX(_zeros)(T * _x, \ + unsigned int _r, \ + unsigned int _c); \ + \ +/* Perform Gauss-Jordan elimination on matrix \(\vec{X}\) */ \ +/* _x : input/output matrix, [size: _r x _c] */ \ +/* _r : rows */ \ +/* _c : columns */ \ +int MATRIX(_gjelim)(T * _x, \ + unsigned int _r, \ + unsigned int _c); \ + \ +/* Pivot on element \(\vec{X}_{i,j}\) */ \ +/* _x : output matrix, [size: _r x _c] */ \ +/* _r : rows of _x */ \ +/* _c : columns of _x */ \ +/* _i : pivot row */ \ +/* _j : pivot column */ \ +int MATRIX(_pivot)(T * _x, \ + unsigned int _r, \ + unsigned int _c, \ + unsigned int _i, \ + unsigned int _j); \ + \ +/* Swap rows _r1 and _r2 of matrix \(\vec{X}\) */ \ +/* _x : input/output matrix, [size: _r x _c] */ \ +/* _r : rows of _x */ \ +/* _c : columns of _x */ \ +/* _r1 : first row to swap */ \ +/* _r2 : second row to swap */ \ +int MATRIX(_swaprows)(T * _x, \ + unsigned int _r, \ + unsigned int _c, \ + unsigned int _r1, \ + unsigned int _r2); \ + \ +/* Solve linear system of \(n\) equations: \(\vec{A}\vec{x} = \vec{b}\) */ \ +/* _A : system matrix, [size: _n x _n] */ \ +/* _n : system size */ \ +/* _b : equality vector, [size: _n x 1] */ \ +/* _x : solution vector, [size: _n x 1] */ \ +/* _opts : options (ignored for now) */ \ +int MATRIX(_linsolve)(T * _A, \ + unsigned int _n, \ + T * _b, \ + T * _x, \ + void * _opts); \ + \ +/* Solve linear system of equations using conjugate gradient method. */ \ +/* _A : symmetric positive definite square matrix */ \ +/* _n : system dimension */ \ +/* _b : equality, [size: _n x 1] */ \ +/* _x : solution estimate, [size: _n x 1] */ \ +/* _opts : options (ignored for now) */ \ +int MATRIX(_cgsolve)(T * _A, \ + unsigned int _n, \ + T * _b, \ + T * _x, \ + void * _opts); \ + \ +/* Perform L/U/P decomposition using Crout's method */ \ +/* _x : input/output matrix, [size: _rx x _cx] */ \ +/* _rx : rows of _x */ \ +/* _cx : columns of _x */ \ +/* _L : first row to swap */ \ +/* _U : first row to swap */ \ +/* _P : first row to swap */ \ +int MATRIX(_ludecomp_crout)(T * _x, \ + unsigned int _rx, \ + unsigned int _cx, \ + T * _L, \ + T * _U, \ + T * _P); \ + \ +/* Perform L/U/P decomposition, Doolittle's method */ \ +/* _x : input/output matrix, [size: _rx x _cx] */ \ +/* _rx : rows of _x */ \ +/* _cx : columns of _x */ \ +/* _L : first row to swap */ \ +/* _U : first row to swap */ \ +/* _P : first row to swap */ \ +int MATRIX(_ludecomp_doolittle)(T * _x, \ + unsigned int _rx, \ + unsigned int _cx, \ + T * _L, \ + T * _U, \ + T * _P); \ + \ +/* Perform orthnormalization using the Gram-Schmidt algorithm */ \ +/* _A : input matrix, [size: _r x _c] */ \ +/* _r : rows */ \ +/* _c : columns */ \ +/* _v : output matrix */ \ +int MATRIX(_gramschmidt)(T * _A, \ + unsigned int _r, \ + unsigned int _c, \ + T * _v); \ + \ +/* Perform Q/R decomposition using the Gram-Schmidt algorithm such that */ \ +/* \( \vec{A} = \vec{Q} \vec{R} \) */ \ +/* and \( \vec{Q}^T \vec{Q} = \vec{I}_n \) */ \ +/* and \(\vec{R\}\) is a diagonal \(m \times m\) matrix */ \ +/* NOTE: all matrices are square */ \ +/* _A : input matrix, [size: _m x _m] */ \ +/* _m : rows */ \ +/* _n : columns (same as cols) */ \ +/* _Q : output matrix, [size: _m x _m] */ \ +/* _R : output matrix, [size: _m x _m] */ \ +int MATRIX(_qrdecomp_gramschmidt)(T * _A, \ + unsigned int _m, \ + unsigned int _n, \ + T * _Q, \ + T * _R); \ + \ +/* Compute Cholesky decomposition of a symmetric/Hermitian */ \ +/* positive-definite matrix as \( \vec{A} = \vec{L}\vec{L}^T \) */ \ +/* _A : input square matrix, [size: _n x _n] */ \ +/* _n : input matrix dimension */ \ +/* _L : output lower-triangular matrix */ \ +int MATRIX(_chol)(T * _A, \ + unsigned int _n, \ + T * _L); \ + +#define matrix_access(X,R,C,r,c) ((X)[(r)*(C)+(c)]) + +#define matrixc_access(X,R,C,r,c) matrix_access(X,R,C,r,c) +#define matrixf_access(X,R,C,r,c) matrix_access(X,R,C,r,c) +#define matrixcf_access(X,R,C,r,c) matrix_access(X,R,C,r,c) + +LIQUID_MATRIX_DEFINE_API(LIQUID_MATRIX_MANGLE_FLOAT, float) +LIQUID_MATRIX_DEFINE_API(LIQUID_MATRIX_MANGLE_DOUBLE, double) + +LIQUID_MATRIX_DEFINE_API(LIQUID_MATRIX_MANGLE_CFLOAT, liquid_float_complex) +LIQUID_MATRIX_DEFINE_API(LIQUID_MATRIX_MANGLE_CDOUBLE, liquid_double_complex) + + +#define LIQUID_SMATRIX_MANGLE_BOOL(name) LIQUID_CONCAT(smatrixb, name) +#define LIQUID_SMATRIX_MANGLE_FLOAT(name) LIQUID_CONCAT(smatrixf, name) +#define LIQUID_SMATRIX_MANGLE_INT(name) LIQUID_CONCAT(smatrixi, name) + +// sparse 'alist' matrix type (similar to MacKay, Davey Lafferty convention) +// large macro +// SMATRIX : name-mangling macro +// T : primitive data type +#define LIQUID_SMATRIX_DEFINE_API(SMATRIX,T) \ + \ +/* Sparse matrix object (similar to MacKay, Davey, Lafferty convention) */ \ +typedef struct SMATRIX(_s) * SMATRIX(); \ + \ +/* Create _M x _N sparse matrix, initialized with zeros */ \ +SMATRIX() SMATRIX(_create)(unsigned int _M, \ + unsigned int _N); \ + \ +/* Create _M x _N sparse matrix, initialized on array */ \ +/* _x : input matrix, [size: _m x _n] */ \ +/* _m : number of rows in input matrix */ \ +/* _n : number of columns in input matrix */ \ +SMATRIX() SMATRIX(_create_array)(T * _x, \ + unsigned int _m, \ + unsigned int _n); \ + \ +/* Destroy object, freeing all internal memory */ \ +int SMATRIX(_destroy)(SMATRIX() _q); \ + \ +/* Print sparse matrix in compact form to stdout */ \ +int SMATRIX(_print)(SMATRIX() _q); \ + \ +/* Print sparse matrix in expanded form to stdout */ \ +int SMATRIX(_print_expanded)(SMATRIX() _q); \ + \ +/* Get size of sparse matrix (number of rows and columns) */ \ +/* _q : sparse matrix object */ \ +/* _m : number of rows in matrix */ \ +/* _n : number of columns in matrix */ \ +int SMATRIX(_size)(SMATRIX() _q, \ + unsigned int * _m, \ + unsigned int * _n); \ + \ +/* Zero all elements and retain allocated memory */ \ +int SMATRIX(_clear)(SMATRIX() _q); \ + \ +/* Zero all elements and clear memory */ \ +int SMATRIX(_reset)(SMATRIX() _q); \ + \ +/* Determine if value has been set (allocated memory) */ \ +/* _q : sparse matrix object */ \ +/* _m : row index of value to query */ \ +/* _n : column index of value to query */ \ +int SMATRIX(_isset)(SMATRIX() _q, \ + unsigned int _m, \ + unsigned int _n); \ + \ +/* Insert an element at index, allocating memory as necessary */ \ +/* _q : sparse matrix object */ \ +/* _m : row index of value to insert */ \ +/* _n : column index of value to insert */ \ +/* _v : value to insert */ \ +int SMATRIX(_insert)(SMATRIX() _q, \ + unsigned int _m, \ + unsigned int _n, \ + T _v); \ + \ +/* Delete an element at index, freeing memory */ \ +/* _q : sparse matrix object */ \ +/* _m : row index of value to delete */ \ +/* _n : column index of value to delete */ \ +int SMATRIX(_delete)(SMATRIX() _q, \ + unsigned int _m, \ + unsigned int _n); \ + \ +/* Set the value in matrix at specified row and column, allocating */ \ +/* memory if needed */ \ +/* _q : sparse matrix object */ \ +/* _m : row index of value to set */ \ +/* _n : column index of value to set */ \ +/* _v : value to set in matrix */ \ +int SMATRIX(_set)(SMATRIX() _q, \ + unsigned int _m, \ + unsigned int _n, \ + T _v); \ + \ +/* Get the value from matrix at specified row and column */ \ +/* _q : sparse matrix object */ \ +/* _m : row index of value to get */ \ +/* _n : column index of value to get */ \ +T SMATRIX(_get)(SMATRIX() _q, \ + unsigned int _m, \ + unsigned int _n); \ + \ +/* Initialize to identity matrix; set all diagonal elements to 1, all */ \ +/* others to 0. This is done with both square and non-square matrices. */ \ +int SMATRIX(_eye)(SMATRIX() _q); \ + \ +/* Multiply two sparse matrices, \( \vec{Z} = \vec{X} \vec{Y} \) */ \ +/* _x : sparse matrix object (input) */ \ +/* _y : sparse matrix object (input) */ \ +/* _z : sparse matrix object (output) */ \ +int SMATRIX(_mul)(SMATRIX() _x, \ + SMATRIX() _y, \ + SMATRIX() _z); \ + \ +/* Multiply sparse matrix by vector */ \ +/* _q : sparse matrix */ \ +/* _x : input vector, [size: _n x 1] */ \ +/* _y : output vector, [size: _m x 1] */ \ +int SMATRIX(_vmul)(SMATRIX() _q, \ + T * _x, \ + T * _y); \ + +LIQUID_SMATRIX_DEFINE_API(LIQUID_SMATRIX_MANGLE_BOOL, unsigned char) +LIQUID_SMATRIX_DEFINE_API(LIQUID_SMATRIX_MANGLE_FLOAT, float) +LIQUID_SMATRIX_DEFINE_API(LIQUID_SMATRIX_MANGLE_INT, short int) + +// +// smatrix cross methods +// + +// multiply sparse binary matrix by floating-point matrix +// _q : sparse matrix [size: A->M x A->N] +// _x : input vector [size: mx x nx ] +// _y : output vector [size: my x ny ] +int smatrixb_mulf(smatrixb _A, + float * _x, + unsigned int _mx, + unsigned int _nx, + float * _y, + unsigned int _my, + unsigned int _ny); + +// multiply sparse binary matrix by floating-point vector +// _q : sparse matrix +// _x : input vector [size: _N x 1] +// _y : output vector [size: _M x 1] +int smatrixb_vmulf(smatrixb _q, + float * _x, + float * _y); + + +// +// MODULE : modem (modulator/demodulator) +// + +// Maximum number of allowed bits per symbol +#define MAX_MOD_BITS_PER_SYMBOL 8 + +// Modulation schemes available +#define LIQUID_MODEM_NUM_SCHEMES (52) + +typedef enum { + LIQUID_MODEM_UNKNOWN=0, // Unknown modulation scheme + + // Phase-shift keying (PSK) + LIQUID_MODEM_PSK2, LIQUID_MODEM_PSK4, + LIQUID_MODEM_PSK8, LIQUID_MODEM_PSK16, + LIQUID_MODEM_PSK32, LIQUID_MODEM_PSK64, + LIQUID_MODEM_PSK128, LIQUID_MODEM_PSK256, + + // Differential phase-shift keying (DPSK) + LIQUID_MODEM_DPSK2, LIQUID_MODEM_DPSK4, + LIQUID_MODEM_DPSK8, LIQUID_MODEM_DPSK16, + LIQUID_MODEM_DPSK32, LIQUID_MODEM_DPSK64, + LIQUID_MODEM_DPSK128, LIQUID_MODEM_DPSK256, + + // amplitude-shift keying + LIQUID_MODEM_ASK2, LIQUID_MODEM_ASK4, + LIQUID_MODEM_ASK8, LIQUID_MODEM_ASK16, + LIQUID_MODEM_ASK32, LIQUID_MODEM_ASK64, + LIQUID_MODEM_ASK128, LIQUID_MODEM_ASK256, + + // rectangular quadrature amplitude-shift keying (QAM) + LIQUID_MODEM_QAM4, + LIQUID_MODEM_QAM8, LIQUID_MODEM_QAM16, + LIQUID_MODEM_QAM32, LIQUID_MODEM_QAM64, + LIQUID_MODEM_QAM128, LIQUID_MODEM_QAM256, + + // amplitude phase-shift keying (APSK) + LIQUID_MODEM_APSK4, + LIQUID_MODEM_APSK8, LIQUID_MODEM_APSK16, + LIQUID_MODEM_APSK32, LIQUID_MODEM_APSK64, + LIQUID_MODEM_APSK128, LIQUID_MODEM_APSK256, + + // specific modem types + LIQUID_MODEM_BPSK, // Specific: binary PSK + LIQUID_MODEM_QPSK, // specific: quaternary PSK + LIQUID_MODEM_OOK, // Specific: on/off keying + LIQUID_MODEM_SQAM32, // 'square' 32-QAM + LIQUID_MODEM_SQAM128, // 'square' 128-QAM + LIQUID_MODEM_V29, // V.29 star constellation + LIQUID_MODEM_ARB16OPT, // optimal 16-QAM + LIQUID_MODEM_ARB32OPT, // optimal 32-QAM + LIQUID_MODEM_ARB64OPT, // optimal 64-QAM + LIQUID_MODEM_ARB128OPT, // optimal 128-QAM + LIQUID_MODEM_ARB256OPT, // optimal 256-QAM + LIQUID_MODEM_ARB64VT, // Virginia Tech logo + + // arbitrary modem type + LIQUID_MODEM_ARB // arbitrary QAM +} modulation_scheme; + +// structure for holding full modulation type descriptor +struct modulation_type_s { + const char * name; // short name (e.g. 'bpsk') + const char * fullname; // full name (e.g. 'binary phase-shift keying') + modulation_scheme scheme; // modulation scheme (e.g. LIQUID_MODEM_BPSK) + unsigned int bps; // modulation depth (e.g. 1) +}; + +// full modulation type descriptor +extern const struct modulation_type_s modulation_types[LIQUID_MODEM_NUM_SCHEMES]; + +// Print compact list of existing and available modulation schemes +int liquid_print_modulation_schemes(); + +// returns modulation_scheme based on input string +modulation_scheme liquid_getopt_str2mod(const char * _str); + +// query basic modulation types +int liquid_modem_is_psk(modulation_scheme _ms); +int liquid_modem_is_dpsk(modulation_scheme _ms); +int liquid_modem_is_ask(modulation_scheme _ms); +int liquid_modem_is_qam(modulation_scheme _ms); +int liquid_modem_is_apsk(modulation_scheme _ms); + +// useful functions + +// counts the number of different bits between two symbols +unsigned int count_bit_errors(unsigned int _s1, unsigned int _s2); + +// counts the number of different bits between two arrays of symbols +// _msg0 : original message [size: _n x 1] +// _msg1 : copy of original message [size: _n x 1] +// _n : message size +unsigned int count_bit_errors_array(unsigned char * _msg0, + unsigned char * _msg1, + unsigned int _n); + +// converts binary-coded decimal (BCD) to gray, ensuring successive values +// differ by exactly one bit +unsigned int gray_encode(unsigned int symbol_in); + +// converts a gray-encoded symbol to binary-coded decimal (BCD) +unsigned int gray_decode(unsigned int symbol_in); + +// pack soft bits into symbol +// _soft_bits : soft input bits [size: _bps x 1] +// _bps : bits per symbol +// _sym_out : output symbol, value in [0,2^_bps) +int liquid_pack_soft_bits(unsigned char * _soft_bits, + unsigned int _bps, + unsigned int * _sym_out); + +// unpack soft bits into symbol +// _sym_in : input symbol, value in [0,2^_bps) +// _bps : bits per symbol +// _soft_bits : soft output bits [size: _bps x 1] +int liquid_unpack_soft_bits(unsigned int _sym_in, + unsigned int _bps, + unsigned char * _soft_bits); + + +// +// Linear modem +// + +#define LIQUID_MODEM_MANGLE_FLOAT(name) LIQUID_CONCAT(modem,name) + +// Macro : MODEM +// MODEM : name-mangling macro +// T : primitive data type +// TC : primitive data type (complex) +#define LIQUID_MODEM_DEFINE_API(MODEM,T,TC) \ + \ +/* Linear modulator/demodulator (modem) object */ \ +typedef struct MODEM(_s) * MODEM(); \ + \ +/* Create digital modem object with a particular scheme */ \ +/* _scheme : linear modulation scheme (e.g. LIQUID_MODEM_QPSK) */ \ +MODEM() MODEM(_create)(modulation_scheme _scheme); \ + \ +/* Create linear digital modem object with arbitrary constellation */ \ +/* points defined by an external table of symbols. Sample points are */ \ +/* provided as complex float pairs and converted internally if needed. */ \ +/* _table : array of complex constellation points, [size: _M x 1] */ \ +/* _M : modulation order and table size, _M must be power of 2 */ \ +MODEM() MODEM(_create_arbitrary)(liquid_float_complex * _table, \ + unsigned int _M); \ + \ +/* Recreate modulation scheme, re-allocating memory as necessary */ \ +/* _q : modem object */ \ +/* _scheme : linear modulation scheme (e.g. LIQUID_MODEM_QPSK) */ \ +MODEM() MODEM(_recreate)(MODEM() _q, \ + modulation_scheme _scheme); \ + \ +/* Destroy modem object, freeing all allocated memory */ \ +int MODEM(_destroy)(MODEM() _q); \ + \ +/* Print modem status to stdout */ \ +int MODEM(_print)(MODEM() _q); \ + \ +/* Reset internal state of modem object; note that this is only */ \ +/* relevant for modulation types that retain an internal state such as */ \ +/* LIQUID_MODEM_DPSK4 as most linear modulation types are stateless */ \ +int MODEM(_reset)(MODEM() _q); \ + \ +/* Generate random symbol for modulation */ \ +unsigned int MODEM(_gen_rand_sym)(MODEM() _q); \ + \ +/* Get number of bits per symbol (bps) of modem object */ \ +unsigned int MODEM(_get_bps)(MODEM() _q); \ + \ +/* Get modulation scheme of modem object */ \ +modulation_scheme MODEM(_get_scheme)(MODEM() _q); \ + \ +/* Modulate input symbol (bits) and generate output complex sample */ \ +/* _q : modem object */ \ +/* _s : input symbol, 0 <= _s <= M-1 */ \ +/* _y : output complex sample */ \ +int MODEM(_modulate)(MODEM() _q, \ + unsigned int _s, \ + TC * _y); \ + \ +/* Demodulate input sample and provide maximum-likelihood estimate of */ \ +/* symbol that would have generated it. */ \ +/* The output is a hard decision value on the input sample. */ \ +/* This is performed efficiently by taking advantage of symmetry on */ \ +/* most modulation types. */ \ +/* For example, square and rectangular quadrature amplitude modulation */ \ +/* with gray coding can use a bisection search indepdently on its */ \ +/* in-phase and quadrature channels. */ \ +/* Arbitrary modulation schemes are relatively slow, however, for large */ \ +/* modulation types as the demodulator must compute the distance */ \ +/* between the received sample and all possible symbols to derive the */ \ +/* optimal symbol. */ \ +/* _q : modem object */ \ +/* _x : input sample */ \ +/* _s : output hard symbol, 0 <= _s <= M-1 */ \ +int MODEM(_demodulate)(MODEM() _q, \ + TC _x, \ + unsigned int * _s); \ + \ +/* Demodulate input sample and provide (approximate) log-likelihood */ \ +/* ratio (LLR, soft bits) as an output. */ \ +/* Similarly to the hard-decision demodulation method, this is computed */ \ +/* efficiently for most modulation types. */ \ +/* _q : modem object */ \ +/* _x : input sample */ \ +/* _s : output hard symbol, 0 <= _s <= M-1 */ \ +/* _soft_bits : output soft bits, [size: log2(M) x 1] */ \ +int MODEM(_demodulate_soft)(MODEM() _q, \ + TC _x, \ + unsigned int * _s, \ + unsigned char * _soft_bits); \ + \ +/* Get demodulator's estimated transmit sample */ \ +int MODEM(_get_demodulator_sample)(MODEM() _q, \ + TC * _x_hat); \ + \ +/* Get demodulator phase error */ \ +float MODEM(_get_demodulator_phase_error)(MODEM() _q); \ + \ +/* Get demodulator error vector magnitude */ \ +float MODEM(_get_demodulator_evm)(MODEM() _q); \ + +// define modem APIs +LIQUID_MODEM_DEFINE_API(LIQUID_MODEM_MANGLE_FLOAT,float,liquid_float_complex) + + +// +// continuous-phase modulation +// + +// gmskmod : GMSK modulator +typedef struct gmskmod_s * gmskmod; + +// create gmskmod object +// _k : samples/symbol +// _m : filter delay (symbols) +// _BT : excess bandwidth factor +gmskmod gmskmod_create(unsigned int _k, + unsigned int _m, + float _BT); +int gmskmod_destroy(gmskmod _q); +int gmskmod_print(gmskmod _q); +int gmskmod_reset(gmskmod _q); +int gmskmod_modulate(gmskmod _q, + unsigned int _sym, + liquid_float_complex * _y); + + +// gmskdem : GMSK demodulator +typedef struct gmskdem_s * gmskdem; + +// create gmskdem object +// _k : samples/symbol +// _m : filter delay (symbols) +// _BT : excess bandwidth factor +gmskdem gmskdem_create(unsigned int _k, + unsigned int _m, + float _BT); +int gmskdem_destroy(gmskdem _q); +int gmskdem_print(gmskdem _q); +int gmskdem_reset(gmskdem _q); +int gmskdem_set_eq_bw(gmskdem _q, float _bw); +int gmskdem_demodulate(gmskdem _q, + liquid_float_complex * _y, + unsigned int * _sym); + +// +// continuous phase frequency-shift keying (CP-FSK) modems +// + +// CP-FSK filter prototypes +typedef enum { + LIQUID_CPFSK_SQUARE=0, // square pulse + LIQUID_CPFSK_RCOS_FULL, // raised-cosine (full response) + LIQUID_CPFSK_RCOS_PARTIAL, // raised-cosine (partial response) + LIQUID_CPFSK_GMSK, // Gauss minimum-shift keying pulse +} liquid_cpfsk_filter; + +// CP-FSK modulator +typedef struct cpfskmod_s * cpfskmod; + +// create cpfskmod object (frequency modulator) +// _bps : bits per symbol, _bps > 0 +// _h : modulation index, _h > 0 +// _k : samples/symbol, _k > 1, _k even +// _m : filter delay (symbols), _m > 0 +// _beta : filter bandwidth parameter, _beta > 0 +// _type : filter type (e.g. LIQUID_CPFSK_SQUARE) +cpfskmod cpfskmod_create(unsigned int _bps, + float _h, + unsigned int _k, + unsigned int _m, + float _beta, + int _type); +//cpfskmod cpfskmod_create_msk(unsigned int _k); +//cpfskmod cpfskmod_create_gmsk(unsigned int _k, float _BT); + +// destroy cpfskmod object +int cpfskmod_destroy(cpfskmod _q); + +// print cpfskmod object internals +int cpfskmod_print(cpfskmod _q); + +// reset state +int cpfskmod_reset(cpfskmod _q); + +// get transmit delay [symbols] +unsigned int cpfskmod_get_delay(cpfskmod _q); + +// modulate sample +// _q : frequency modulator object +// _s : input symbol +// _y : output sample array [size: _k x 1] +int cpfskmod_modulate(cpfskmod _q, + unsigned int _s, + liquid_float_complex * _y); + + + +// CP-FSK demodulator +typedef struct cpfskdem_s * cpfskdem; + +// create cpfskdem object (frequency modulator) +// _bps : bits per symbol, _bps > 0 +// _h : modulation index, _h > 0 +// _k : samples/symbol, _k > 1, _k even +// _m : filter delay (symbols), _m > 0 +// _beta : filter bandwidth parameter, _beta > 0 +// _type : filter type (e.g. LIQUID_CPFSK_SQUARE) +cpfskdem cpfskdem_create(unsigned int _bps, + float _h, + unsigned int _k, + unsigned int _m, + float _beta, + int _type); +//cpfskdem cpfskdem_create_msk(unsigned int _k); +//cpfskdem cpfskdem_create_gmsk(unsigned int _k, float _BT); + +// destroy cpfskdem object +int cpfskdem_destroy(cpfskdem _q); + +// print cpfskdem object internals +int cpfskdem_print(cpfskdem _q); + +// reset state +int cpfskdem_reset(cpfskdem _q); + +// get receive delay [symbols] +unsigned int cpfskdem_get_delay(cpfskdem _q); + +#if 0 +// demodulate array of samples +// _q : continuous-phase frequency demodulator object +// _y : input sample array [size: _n x 1] +// _n : input sample array length +// _s : output symbol array +// _nw : number of output symbols written +int cpfskdem_demodulate(cpfskdem _q, + liquid_float_complex * _y, + unsigned int _n, + unsigned int * _s, + unsigned int * _nw); +#else +// demodulate array of samples, assuming perfect timing +// _q : continuous-phase frequency demodulator object +// _y : input sample array [size: _k x 1] +unsigned int cpfskdem_demodulate(cpfskdem _q, + liquid_float_complex * _y); +#endif + + + +// +// M-ary frequency-shift keying (MFSK) modems +// + +// FSK modulator +typedef struct fskmod_s * fskmod; + +// create fskmod object (frequency modulator) +// _m : bits per symbol, _bps > 0 +// _k : samples/symbol, _k >= 2^_m +// _bandwidth : total signal bandwidth, (0,0.5) +fskmod fskmod_create(unsigned int _m, + unsigned int _k, + float _bandwidth); + +// destroy fskmod object +int fskmod_destroy(fskmod _q); + +// print fskmod object internals +int fskmod_print(fskmod _q); + +// reset state +int fskmod_reset(fskmod _q); + +// modulate sample +// _q : frequency modulator object +// _s : input symbol +// _y : output sample array [size: _k x 1] +int fskmod_modulate(fskmod _q, + unsigned int _s, + liquid_float_complex * _y); + + + +// FSK demodulator +typedef struct fskdem_s * fskdem; + +// create fskdem object (frequency demodulator) +// _m : bits per symbol, _bps > 0 +// _k : samples/symbol, _k >= 2^_m +// _bandwidth : total signal bandwidth, (0,0.5) +fskdem fskdem_create(unsigned int _m, + unsigned int _k, + float _bandwidth); + +// destroy fskdem object +int fskdem_destroy(fskdem _q); + +// print fskdem object internals +int fskdem_print(fskdem _q); + +// reset state +int fskdem_reset(fskdem _q); + +// demodulate symbol, assuming perfect symbol timing +// _q : fskdem object +// _y : input sample array [size: _k x 1] +unsigned int fskdem_demodulate(fskdem _q, + liquid_float_complex * _y); + +// get demodulator frequency error +float fskdem_get_frequency_error(fskdem _q); + +// get energy for a particular symbol within a certain range +float fskdem_get_symbol_energy(fskdem _q, + unsigned int _s, + unsigned int _range); + + +// +// Analog frequency modulator +// +#define LIQUID_FREQMOD_MANGLE_FLOAT(name) LIQUID_CONCAT(freqmod,name) + +// Macro : FREQMOD (analog frequency modulator) +// FREQMOD : name-mangling macro +// T : primitive data type +// TC : primitive data type (complex) +#define LIQUID_FREQMOD_DEFINE_API(FREQMOD,T,TC) \ + \ +/* Analog frequency modulation object */ \ +typedef struct FREQMOD(_s) * FREQMOD(); \ + \ +/* Create freqmod object with a particular modulation factor */ \ +/* _kf : modulation factor */ \ +FREQMOD() FREQMOD(_create)(float _kf); \ + \ +/* Destroy freqmod object, freeing all internal memory */ \ +int FREQMOD(_destroy)(FREQMOD() _q); \ + \ +/* Print freqmod object internals to stdout */ \ +int FREQMOD(_print)(FREQMOD() _q); \ + \ +/* Reset state */ \ +int FREQMOD(_reset)(FREQMOD() _q); \ + \ +/* Modulate single sample, producing single output sample at complex */ \ +/* baseband. */ \ +/* _q : frequency modulator object */ \ +/* _m : message signal \( m(t) \) */ \ +/* _s : complex baseband signal \( s(t) \) */ \ +int FREQMOD(_modulate)(FREQMOD() _q, \ + T _m, \ + TC * _s); \ + \ +/* Modulate block of samples */ \ +/* _q : frequency modulator object */ \ +/* _m : message signal \( m(t) \), [size: _n x 1] */ \ +/* _n : number of input, output samples */ \ +/* _s : complex baseband signal \( s(t) \), [size: _n x 1] */ \ +int FREQMOD(_modulate_block)(FREQMOD() _q, \ + T * _m, \ + unsigned int _n, \ + TC * _s); \ + +// define freqmod APIs +LIQUID_FREQMOD_DEFINE_API(LIQUID_FREQMOD_MANGLE_FLOAT,float,liquid_float_complex) + +// +// Analog frequency demodulator +// + +#define LIQUID_FREQDEM_MANGLE_FLOAT(name) LIQUID_CONCAT(freqdem,name) + +// Macro : FREQDEM (analog frequency modulator) +// FREQDEM : name-mangling macro +// T : primitive data type +// TC : primitive data type (complex) +#define LIQUID_FREQDEM_DEFINE_API(FREQDEM,T,TC) \ +typedef struct FREQDEM(_s) * FREQDEM(); \ + \ +/* create freqdem object (frequency modulator) */ \ +/* _kf : modulation factor */ \ +FREQDEM() FREQDEM(_create)(float _kf); \ + \ +/* destroy freqdem object */ \ +int FREQDEM(_destroy)(FREQDEM() _q); \ + \ +/* print freqdem object internals */ \ +int FREQDEM(_print)(FREQDEM() _q); \ + \ +/* reset state */ \ +int FREQDEM(_reset)(FREQDEM() _q); \ + \ +/* demodulate sample */ \ +/* _q : frequency modulator object */ \ +/* _r : received signal r(t) */ \ +/* _m : output message signal m(t) */ \ +int FREQDEM(_demodulate)(FREQDEM() _q, \ + TC _r, \ + T * _m); \ + \ +/* demodulate block of samples */ \ +/* _q : frequency demodulator object */ \ +/* _r : received signal r(t) [size: _n x 1] */ \ +/* _n : number of input, output samples */ \ +/* _m : message signal m(t), [size: _n x 1] */ \ +int FREQDEM(_demodulate_block)(FREQDEM() _q, \ + TC * _r, \ + unsigned int _n, \ + T * _m); \ + +// define freqdem APIs +LIQUID_FREQDEM_DEFINE_API(LIQUID_FREQDEM_MANGLE_FLOAT,float,liquid_float_complex) + + + +// amplitude modulation types +typedef enum { + LIQUID_AMPMODEM_DSB=0, // double side-band + LIQUID_AMPMODEM_USB, // single side-band (upper) + LIQUID_AMPMODEM_LSB // single side-band (lower) +} liquid_ampmodem_type; + +typedef struct ampmodem_s * ampmodem; + +// create ampmodem object +// _m : modulation index +// _type : AM type (e.g. LIQUID_AMPMODEM_DSB) +// _suppressed_carrier : carrier suppression flag +ampmodem ampmodem_create(float _mod_index, + liquid_ampmodem_type _type, + int _suppressed_carrier); + +// destroy ampmodem object +int ampmodem_destroy(ampmodem _q); + +// print ampmodem object internals +int ampmodem_print(ampmodem _q); + +// reset ampmodem object state +int ampmodem_reset(ampmodem _q); + +// accessor methods +unsigned int ampmodem_get_delay_mod (ampmodem _q); +unsigned int ampmodem_get_delay_demod(ampmodem _q); + +// modulate sample +int ampmodem_modulate(ampmodem _q, + float _x, + liquid_float_complex * _y); + +int ampmodem_modulate_block(ampmodem _q, + float * _m, + unsigned int _n, + liquid_float_complex * _s); + +// demodulate sample +int ampmodem_demodulate(ampmodem _q, + liquid_float_complex _y, + float * _x); + +int ampmodem_demodulate_block(ampmodem _q, + liquid_float_complex * _r, + unsigned int _n, + float * _m); + +// +// MODULE : multichannel +// + + +#define FIRPFBCH_NYQUIST 0 +#define FIRPFBCH_ROOTNYQUIST 1 + +#define LIQUID_ANALYZER 0 +#define LIQUID_SYNTHESIZER 1 + + +// +// Finite impulse response polyphase filterbank channelizer +// + +#define LIQUID_FIRPFBCH_MANGLE_CRCF(name) LIQUID_CONCAT(firpfbch_crcf,name) +#define LIQUID_FIRPFBCH_MANGLE_CCCF(name) LIQUID_CONCAT(firpfbch_cccf,name) + +// Macro: +// FIRPFBCH : name-mangling macro +// TO : output data type +// TC : coefficients data type +// TI : input data type +#define LIQUID_FIRPFBCH_DEFINE_API(FIRPFBCH,TO,TC,TI) \ +typedef struct FIRPFBCH(_s) * FIRPFBCH(); \ + \ +/* create finite impulse response polyphase filter-bank */ \ +/* channelizer object from external coefficients */ \ +/* _type : channelizer type, e.g. LIQUID_ANALYZER */ \ +/* _M : number of channels */ \ +/* _p : number of coefficients for each channel */ \ +/* _h : coefficients [size: _M*_p x 1] */ \ +FIRPFBCH() FIRPFBCH(_create)(int _type, \ + unsigned int _M, \ + unsigned int _p, \ + TC * _h); \ + \ +/* create FIR polyphase filterbank channelizer object with */ \ +/* prototype filter based on windowed Kaiser design */ \ +/* _type : type (LIQUID_ANALYZER | LIQUID_SYNTHESIZER) */ \ +/* _M : number of channels */ \ +/* _m : filter delay (symbols) */ \ +/* _As : stop-band attentuation [dB] */ \ +FIRPFBCH() FIRPFBCH(_create_kaiser)(int _type, \ + unsigned int _M, \ + unsigned int _m, \ + float _As); \ + \ +/* create FIR polyphase filterbank channelizer object with */ \ +/* prototype root-Nyquist filter */ \ +/* _type : type (LIQUID_ANALYZER | LIQUID_SYNTHESIZER) */ \ +/* _M : number of channels */ \ +/* _m : filter delay (symbols) */ \ +/* _beta : filter excess bandwidth factor, in [0,1] */ \ +/* _ftype : filter prototype (rrcos, rkaiser, etc.) */ \ +FIRPFBCH() FIRPFBCH(_create_rnyquist)(int _type, \ + unsigned int _M, \ + unsigned int _m, \ + float _beta, \ + int _ftype); \ + \ +/* destroy firpfbch object */ \ +int FIRPFBCH(_destroy)(FIRPFBCH() _q); \ + \ +/* clear/reset firpfbch internal state */ \ +int FIRPFBCH(_reset)(FIRPFBCH() _q); \ + \ +/* print firpfbch internal parameters to stdout */ \ +int FIRPFBCH(_print)(FIRPFBCH() _q); \ + \ +/* execute filterbank as synthesizer on block of samples */ \ +/* _q : filterbank channelizer object */ \ +/* _x : channelized input, [size: num_channels x 1] */ \ +/* _y : output time series, [size: num_channels x 1] */ \ +int FIRPFBCH(_synthesizer_execute)(FIRPFBCH() _q, \ + TI * _x, \ + TO * _y); \ + \ +/* execute filterbank as analyzer on block of samples */ \ +/* _q : filterbank channelizer object */ \ +/* _x : input time series, [size: num_channels x 1] */ \ +/* _y : channelized output, [size: num_channels x 1] */ \ +int FIRPFBCH(_analyzer_execute)(FIRPFBCH() _q, \ + TI * _x, \ + TO * _y); \ + + +LIQUID_FIRPFBCH_DEFINE_API(LIQUID_FIRPFBCH_MANGLE_CRCF, + liquid_float_complex, + float, + liquid_float_complex) + +LIQUID_FIRPFBCH_DEFINE_API(LIQUID_FIRPFBCH_MANGLE_CCCF, + liquid_float_complex, + liquid_float_complex, + liquid_float_complex) + + +// +// Finite impulse response polyphase filterbank channelizer +// with output rate 2 Fs / M +// + +#define LIQUID_FIRPFBCH2_MANGLE_CRCF(name) LIQUID_CONCAT(firpfbch2_crcf,name) + +// Macro: +// FIRPFBCH2 : name-mangling macro +// TO : output data type +// TC : coefficients data type +// TI : input data type +#define LIQUID_FIRPFBCH2_DEFINE_API(FIRPFBCH2,TO,TC,TI) \ +typedef struct FIRPFBCH2(_s) * FIRPFBCH2(); \ + \ +/* create firpfbch2 object */ \ +/* _type : channelizer type (e.g. LIQUID_ANALYZER) */ \ +/* _M : number of channels (must be even) */ \ +/* _m : prototype filter semi-length, length=2*M*m */ \ +/* _h : prototype filter coefficient array */ \ +FIRPFBCH2() FIRPFBCH2(_create)(int _type, \ + unsigned int _M, \ + unsigned int _m, \ + TC * _h); \ + \ +/* create firpfbch2 object using Kaiser window prototype */ \ +/* _type : channelizer type (e.g. LIQUID_ANALYZER) */ \ +/* _M : number of channels (must be even) */ \ +/* _m : prototype filter semi-length, length=2*M*m+1 */ \ +/* _As : filter stop-band attenuation [dB] */ \ +FIRPFBCH2() FIRPFBCH2(_create_kaiser)(int _type, \ + unsigned int _M, \ + unsigned int _m, \ + float _As); \ + \ +/* destroy firpfbch2 object, freeing internal memory */ \ +int FIRPFBCH2(_destroy)(FIRPFBCH2() _q); \ + \ +/* reset firpfbch2 object internals */ \ +int FIRPFBCH2(_reset)(FIRPFBCH2() _q); \ + \ +/* print firpfbch2 object internals */ \ +int FIRPFBCH2(_print)(FIRPFBCH2() _q); \ + \ +/* execute filterbank channelizer */ \ +/* LIQUID_ANALYZER: input: M/2, output: M */ \ +/* LIQUID_SYNTHESIZER: input: M, output: M/2 */ \ +/* _x : channelizer input */ \ +/* _y : channelizer output */ \ +int FIRPFBCH2(_execute)(FIRPFBCH2() _q, \ + TI * _x, \ + TO * _y); \ + + +LIQUID_FIRPFBCH2_DEFINE_API(LIQUID_FIRPFBCH2_MANGLE_CRCF, + liquid_float_complex, + float, + liquid_float_complex) + +// +// Finite impulse response polyphase filterbank channelizer +// with output rate Fs * P / M +// + +#define LIQUID_FIRPFBCHR_MANGLE_CRCF(name) LIQUID_CONCAT(firpfbchr_crcf,name) + +#define LIQUID_FIRPFBCHR_DEFINE_API(FIRPFBCHR,TO,TC,TI) \ +typedef struct FIRPFBCHR(_s) * FIRPFBCHR(); \ + \ +/* create rational rate resampling channelizer (firpfbchr) object by */ \ +/* specifying filter coefficients directly */ \ +/* _M : number of output channels in chanelizer */ \ +/* _P : output decimation factor (output rate is 1/P the input) */ \ +/* _m : prototype filter semi-length, length=2*M*m */ \ +/* _h : prototype filter coefficient array, [size: 2*M*m x 1] */ \ +FIRPFBCHR() FIRPFBCHR(_create)(unsigned int _M, \ + unsigned int _P, \ + unsigned int _m, \ + TC * _h); \ + \ +/* create rational rate resampling channelizer (firpfbchr) object by */ \ +/* specifying filter design parameters for Kaiser prototype */ \ +/* _M : number of output channels in chanelizer */ \ +/* _P : output decimation factor (output rate is 1/P the input) */ \ +/* _m : prototype filter semi-length, length=2*M*m */ \ +/* _As : filter stop-band attenuation [dB] */ \ +FIRPFBCHR() FIRPFBCHR(_create_kaiser)(unsigned int _M, \ + unsigned int _P, \ + unsigned int _m, \ + float _As); \ + \ +/* destroy firpfbchr object, freeing internal memory */ \ +int FIRPFBCHR(_destroy)(FIRPFBCHR() _q); \ + \ +/* reset firpfbchr object internal state and buffers */ \ +int FIRPFBCHR(_reset)(FIRPFBCHR() _q); \ + \ +/* print firpfbchr object internals to stdout */ \ +int FIRPFBCHR(_print)(FIRPFBCHR() _q); \ + \ +/* get number of output channels to channelizer */ \ +unsigned int FIRPFBCHR(_get_M)(FIRPFBCHR() _q); \ + \ +/* get decimation factor for channelizer */ \ +unsigned int FIRPFBCHR(_get_P)(FIRPFBCHR() _q); \ + \ +/* get semi-length to channelizer filter prototype */ \ +unsigned int FIRPFBCHR(_get_m)(FIRPFBCHR() _q); \ + \ +/* push buffer of samples into filter bank */ \ +/* _q : channelizer object */ \ +/* _x : channelizer input [size: P x 1] */ \ +int FIRPFBCHR(_push)(FIRPFBCHR() _q, \ + TI * _x); \ + \ +/* execute filterbank channelizer, writing complex baseband samples for */ \ +/* each channel into output array */ \ +/* _q : channelizer object */ \ +/* _y : channelizer output [size: _M x 1] */ \ +int FIRPFBCHR(_execute)(FIRPFBCHR() _q, \ + TO * _y); \ + + +LIQUID_FIRPFBCHR_DEFINE_API(LIQUID_FIRPFBCHR_MANGLE_CRCF, + liquid_float_complex, + float, + liquid_float_complex) + + + +#define OFDMFRAME_SCTYPE_NULL 0 +#define OFDMFRAME_SCTYPE_PILOT 1 +#define OFDMFRAME_SCTYPE_DATA 2 + +// initialize default subcarrier allocation +// _M : number of subcarriers +// _p : output subcarrier allocation array, [size: _M x 1] +int ofdmframe_init_default_sctype(unsigned int _M, + unsigned char * _p); + +// initialize default subcarrier allocation +// _M : number of subcarriers +// _f0 : lower frequency band, _f0 in [-0.5,0.5] +// _f1 : upper frequency band, _f1 in [-0.5,0.5] +// _p : output subcarrier allocation array, [size: _M x 1] +int ofdmframe_init_sctype_range(unsigned int _M, + float _f0, + float _f1, + unsigned char * _p); + +// validate subcarrier type (count number of null, pilot, and data +// subcarriers in the allocation) +// _p : subcarrier allocation array, [size: _M x 1] +// _M : number of subcarriers +// _M_null : output number of null subcarriers +// _M_pilot : output number of pilot subcarriers +// _M_data : output number of data subcarriers +int ofdmframe_validate_sctype(unsigned char * _p, + unsigned int _M, + unsigned int * _M_null, + unsigned int * _M_pilot, + unsigned int * _M_data); + +// print subcarrier allocation to screen +// _p : output subcarrier allocation array, [size: _M x 1] +// _M : number of subcarriers +int ofdmframe_print_sctype(unsigned char * _p, + unsigned int _M); + + +// +// OFDM frame (symbol) generator +// +typedef struct ofdmframegen_s * ofdmframegen; + +// create OFDM framing generator object +// _M : number of subcarriers, >10 typical +// _cp_len : cyclic prefix length +// _taper_len : taper length (OFDM symbol overlap) +// _p : subcarrier allocation (null, pilot, data), [size: _M x 1] +ofdmframegen ofdmframegen_create(unsigned int _M, + unsigned int _cp_len, + unsigned int _taper_len, + unsigned char * _p); + +int ofdmframegen_destroy(ofdmframegen _q); + +int ofdmframegen_print(ofdmframegen _q); + +int ofdmframegen_reset(ofdmframegen _q); + +// write first S0 symbol +int ofdmframegen_write_S0a(ofdmframegen _q, + liquid_float_complex *_y); + +// write second S0 symbol +int ofdmframegen_write_S0b(ofdmframegen _q, + liquid_float_complex *_y); + +// write S1 symbol +int ofdmframegen_write_S1(ofdmframegen _q, + liquid_float_complex *_y); + +// write data symbol +int ofdmframegen_writesymbol(ofdmframegen _q, + liquid_float_complex * _x, + liquid_float_complex *_y); + +// write tail +int ofdmframegen_writetail(ofdmframegen _q, + liquid_float_complex * _x); + +// +// OFDM frame (symbol) synchronizer +// +typedef int (*ofdmframesync_callback)(liquid_float_complex * _y, + unsigned char * _p, + unsigned int _M, + void * _userdata); +typedef struct ofdmframesync_s * ofdmframesync; + +// create OFDM framing synchronizer object +// _M : number of subcarriers, >10 typical +// _cp_len : cyclic prefix length +// _taper_len : taper length (OFDM symbol overlap) +// _p : subcarrier allocation (null, pilot, data), [size: _M x 1] +// _callback : user-defined callback function +// _userdata : user-defined data pointer +ofdmframesync ofdmframesync_create(unsigned int _M, + unsigned int _cp_len, + unsigned int _taper_len, + unsigned char * _p, + ofdmframesync_callback _callback, + void * _userdata); +int ofdmframesync_destroy(ofdmframesync _q); +int ofdmframesync_print(ofdmframesync _q); +int ofdmframesync_reset(ofdmframesync _q); +int ofdmframesync_is_frame_open(ofdmframesync _q); +int ofdmframesync_execute(ofdmframesync _q, + liquid_float_complex * _x, + unsigned int _n); + +// query methods +float ofdmframesync_get_rssi(ofdmframesync _q); // received signal strength indication +float ofdmframesync_get_cfo(ofdmframesync _q); // carrier offset estimate + +// set methods +int ofdmframesync_set_cfo(ofdmframesync _q, float _cfo); // set carrier offset estimate + +// debugging +int ofdmframesync_debug_enable(ofdmframesync _q); +int ofdmframesync_debug_disable(ofdmframesync _q); +int ofdmframesync_debug_print(ofdmframesync _q, const char * _filename); + + +// +// MODULE : nco (numerically-controlled oscillator) +// + +// oscillator type +// LIQUID_NCO : numerically-controlled oscillator (fast) +// LIQUID_VCO : "voltage"-controlled oscillator (precise) +typedef enum { + LIQUID_NCO=0, + LIQUID_VCO +} liquid_ncotype; + +#define LIQUID_NCO_MANGLE_FLOAT(name) LIQUID_CONCAT(nco_crcf, name) + +// large macro +// NCO : name-mangling macro +// T : primitive data type +// TC : input/output data type +#define LIQUID_NCO_DEFINE_API(NCO,T,TC) \ + \ +/* Numerically-controlled oscillator object */ \ +typedef struct NCO(_s) * NCO(); \ + \ +/* Create nco object with either fixed-point or floating-point phase */ \ +/* _type : oscillator type, _type in {LIQUID_NCO, LIQUID_VCO} */ \ +NCO() NCO(_create)(liquid_ncotype _type); \ + \ +/* Destroy nco object, freeing all internally allocated memory */ \ +int NCO(_destroy)(NCO() _q); \ + \ +/* Print nco object internals to stdout */ \ +int NCO(_print)(NCO() _q); \ + \ +/* Set phase/frequency to zero and reset the phase-locked loop filter */ \ +/* state */ \ +int NCO(_reset)(NCO() _q); \ + \ +/* Get frequency of nco object in radians per sample */ \ +T NCO(_get_frequency)(NCO() _q); \ + \ +/* Set frequency of nco object in radians per sample */ \ +/* _q : nco object */ \ +/* _dtheta : input frequency [radians/sample] */ \ +int NCO(_set_frequency)(NCO() _q, \ + T _dtheta); \ + \ +/* Adjust frequency of nco object by a step size in radians per sample */ \ +/* _q : nco object */ \ +/* _step : input frequency step [radians/sample] */ \ +int NCO(_adjust_frequency)(NCO() _q, \ + T _step); \ + \ +/* Get phase of nco object in radians */ \ +T NCO(_get_phase)(NCO() _q); \ + \ +/* Set phase of nco object in radians */ \ +/* _q : nco object */ \ +/* _phi : input phase of nco object [radians] */ \ +int NCO(_set_phase)(NCO() _q, \ + T _phi); \ + \ +/* Adjust phase of nco object by a step of \(\Delta \phi\) radians */ \ +/* _q : nco object */ \ +/* _dphi : input nco object phase adjustment [radians] */ \ +int NCO(_adjust_phase)(NCO() _q, \ + T _dphi); \ + \ +/* Increment phase by internal phase step (frequency) */ \ +int NCO(_step)(NCO() _q); \ + \ +/* Compute sine output given internal phase */ \ +T NCO(_sin)(NCO() _q); \ + \ +/* Compute cosine output given internal phase */ \ +T NCO(_cos)(NCO() _q); \ + \ +/* Compute sine and cosine outputs given internal phase */ \ +/* _q : nco object */ \ +/* _s : output sine component of phase */ \ +/* _c : output cosine component of phase */ \ +int NCO(_sincos)(NCO() _q, \ + T * _s, \ + T * _c); \ + \ +/* Compute complex exponential output given internal phase */ \ +/* _q : nco object */ \ +/* _y : output complex exponential */ \ +int NCO(_cexpf)(NCO() _q, \ + TC * _y); \ + \ +/* Set bandwidth of internal phase-locked loop */ \ +/* _q : nco object */ \ +/* _bw : input phase-locked loop bandwidth, _bw >= 0 */ \ +int NCO(_pll_set_bandwidth)(NCO() _q, \ + T _bw); \ + \ +/* Step internal phase-locked loop given input phase error, adjusting */ \ +/* internal phase and frequency proportional to coefficients defined by */ \ +/* internal PLL bandwidth */ \ +/* _q : nco object */ \ +/* _dphi : input phase-locked loop phase error */ \ +int NCO(_pll_step)(NCO() _q, \ + T _dphi); \ + \ +/* Rotate input sample up by nco angle. */ \ +/* Note that this does not adjust the internal phase or frequency. */ \ +/* _q : nco object */ \ +/* _x : input complex sample */ \ +/* _y : pointer to output sample location */ \ +int NCO(_mix_up)(NCO() _q, \ + TC _x, \ + TC * _y); \ + \ +/* Rotate input sample down by nco angle. */ \ +/* Note that this does not adjust the internal phase or frequency. */ \ +/* _q : nco object */ \ +/* _x : input complex sample */ \ +/* _y : pointer to output sample location */ \ +int NCO(_mix_down)(NCO() _q, \ + TC _x, \ + TC * _y); \ + \ +/* Rotate input vector up by NCO angle (stepping) */ \ +/* Note that this *does* adjust the internal phase as the signal steps */ \ +/* through each input sample. */ \ +/* _q : nco object */ \ +/* _x : array of input samples, [size: _n x 1] */ \ +/* _y : array of output samples, [size: _n x 1] */ \ +/* _n : number of input (and output) samples */ \ +int NCO(_mix_block_up)(NCO() _q, \ + TC * _x, \ + TC * _y, \ + unsigned int _n); \ + \ +/* Rotate input vector down by NCO angle (stepping) */ \ +/* Note that this *does* adjust the internal phase as the signal steps */ \ +/* through each input sample. */ \ +/* _q : nco object */ \ +/* _x : array of input samples, [size: _n x 1] */ \ +/* _y : array of output samples, [size: _n x 1] */ \ +/* _n : number of input (and output) samples */ \ +int NCO(_mix_block_down)(NCO() _q, \ + TC * _x, \ + TC * _y, \ + unsigned int _n); \ + +// Define nco APIs +LIQUID_NCO_DEFINE_API(LIQUID_NCO_MANGLE_FLOAT, float, liquid_float_complex) + + +// nco utilities + +// unwrap phase of array (basic) +void liquid_unwrap_phase(float * _theta, unsigned int _n); + +// unwrap phase of array (advanced) +void liquid_unwrap_phase2(float * _theta, unsigned int _n); + +#define SYNTH_MANGLE_FLOAT(name) LIQUID_CONCAT(synth_crcf, name) + +// large macro +// SYNTH : name-mangling macro +// T : primitive data type +// TC : input/output data type +#define LIQUID_SYNTH_DEFINE_API(SYNTH,T,TC) \ +typedef struct SYNTH(_s) * SYNTH(); \ + \ +SYNTH() SYNTH(_create)(const TC *_table, unsigned int _length); \ +void SYNTH(_destroy)(SYNTH() _q); \ + \ +void SYNTH(_reset)(SYNTH() _q); \ + \ +/* get/set/adjust internal frequency/phase */ \ +T SYNTH(_get_frequency)( SYNTH() _q); \ +void SYNTH(_set_frequency)( SYNTH() _q, T _f); \ +void SYNTH(_adjust_frequency)(SYNTH() _q, T _df); \ +T SYNTH(_get_phase)( SYNTH() _q); \ +void SYNTH(_set_phase)( SYNTH() _q, T _phi); \ +void SYNTH(_adjust_phase)( SYNTH() _q, T _dphi); \ + \ +unsigned int SYNTH(_get_length)(SYNTH() _q); \ +TC SYNTH(_get_current)(SYNTH() _q); \ +TC SYNTH(_get_half_previous)(SYNTH() _q); \ +TC SYNTH(_get_half_next)(SYNTH() _q); \ + \ +void SYNTH(_step)(SYNTH() _q); \ + \ +/* pll : phase-locked loop */ \ +void SYNTH(_pll_set_bandwidth)(SYNTH() _q, T _bandwidth); \ +void SYNTH(_pll_step)(SYNTH() _q, T _dphi); \ + \ +/* Rotate input sample up by SYNTH angle (no stepping) */ \ +void SYNTH(_mix_up)(SYNTH() _q, TC _x, TC *_y); \ + \ +/* Rotate input sample down by SYNTH angle (no stepping) */ \ +void SYNTH(_mix_down)(SYNTH() _q, TC _x, TC *_y); \ + \ +/* Rotate input vector up by SYNTH angle (stepping) */ \ +void SYNTH(_mix_block_up)(SYNTH() _q, \ + TC *_x, \ + TC *_y, \ + unsigned int _N); \ + \ +/* Rotate input vector down by SYNTH angle (stepping) */ \ +void SYNTH(_mix_block_down)(SYNTH() _q, \ + TC *_x, \ + TC *_y, \ + unsigned int _N); \ + \ +void SYNTH(_spread)(SYNTH() _q, \ + TC _x, \ + TC *_y); \ + \ +void SYNTH(_despread)(SYNTH() _q, \ + TC *_x, \ + TC *_y); \ + \ +void SYNTH(_despread_triple)(SYNTH() _q, \ + TC *_x, \ + TC *_early, \ + TC *_punctual, \ + TC *_late); \ + +// Define synth APIs +LIQUID_SYNTH_DEFINE_API(SYNTH_MANGLE_FLOAT, float, liquid_float_complex) + + + +// +// MODULE : optimization +// + +// utility function pointer definition +typedef float (*utility_function)(void * _userdata, + float * _v, + unsigned int _n); + +// n-dimensional Rosenbrock utility function (minimum at _v = {1,1,1...} +// _userdata : user-defined data structure (convenience) +// _v : input vector [size: _n x 1] +// _n : input vector size +float liquid_rosenbrock(void * _userdata, + float * _v, + unsigned int _n); + +// n-dimensional inverse Gauss utility function (minimum at _v = {0,0,0...} +// _userdata : user-defined data structure (convenience) +// _v : input vector [size: _n x 1] +// _n : input vector size +float liquid_invgauss(void * _userdata, + float * _v, + unsigned int _n); + +// n-dimensional multimodal utility function (minimum at _v = {0,0,0...} +// _userdata : user-defined data structure (convenience) +// _v : input vector [size: _n x 1] +// _n : input vector size +float liquid_multimodal(void * _userdata, + float * _v, + unsigned int _n); + +// n-dimensional spiral utility function (minimum at _v = {0,0,0...} +// _userdata : user-defined data structure (convenience) +// _v : input vector [size: _n x 1] +// _n : input vector size +float liquid_spiral(void * _userdata, + float * _v, + unsigned int _n); + + +// +// Gradient search +// + +#define LIQUID_OPTIM_MINIMIZE (0) +#define LIQUID_OPTIM_MAXIMIZE (1) + +typedef struct gradsearch_s * gradsearch; + +// Create a gradient search object +// _userdata : user data object pointer +// _v : array of parameters to optimize +// _num_parameters : array length (number of parameters to optimize) +// _u : utility function pointer +// _direction : search direction (e.g. LIQUID_OPTIM_MAXIMIZE) +gradsearch gradsearch_create(void * _userdata, + float * _v, + unsigned int _num_parameters, + utility_function _utility, + int _direction); + +// Destroy a gradsearch object +void gradsearch_destroy(gradsearch _q); + +// Prints current status of search +void gradsearch_print(gradsearch _q); + +// Iterate once +float gradsearch_step(gradsearch _q); + +// Execute the search +float gradsearch_execute(gradsearch _q, + unsigned int _max_iterations, + float _target_utility); + + +// quasi-Newton search +typedef struct qnsearch_s * qnsearch; + +// Create a simple qnsearch object; parameters are specified internally +// _userdata : userdata +// _v : array of parameters to optimize +// _num_parameters : array length +// _get_utility : utility function pointer +// _direction : search direction (e.g. LIQUID_OPTIM_MAXIMIZE) +qnsearch qnsearch_create(void * _userdata, + float * _v, + unsigned int _num_parameters, + utility_function _u, + int _direction); + +// Destroy a qnsearch object +int qnsearch_destroy(qnsearch _g); + +// Prints current status of search +int qnsearch_print(qnsearch _g); + +// Resets internal state +int qnsearch_reset(qnsearch _g); + +// Iterate once +int qnsearch_step(qnsearch _g); + +// Execute the search +float qnsearch_execute(qnsearch _g, + unsigned int _max_iterations, + float _target_utility); + +// +// chromosome (for genetic algorithm search) +// +typedef struct chromosome_s * chromosome; + +// create a chromosome object, variable bits/trait +chromosome chromosome_create(unsigned int * _bits_per_trait, + unsigned int _num_traits); + +// create a chromosome object, all traits same resolution +chromosome chromosome_create_basic(unsigned int _num_traits, + unsigned int _bits_per_trait); + +// create a chromosome object, cloning a parent +chromosome chromosome_create_clone(chromosome _parent); + +// copy existing chromosomes' internal traits (all other internal +// parameters must be equal) +int chromosome_copy(chromosome _parent, chromosome _child); + +// Destroy a chromosome object +int chromosome_destroy(chromosome _c); + +// get number of traits in chromosome +unsigned int chromosome_get_num_traits(chromosome _c); + +// Print chromosome values to screen (binary representation) +int chromosome_print(chromosome _c); + +// Print chromosome values to screen (floating-point representation) +int chromosome_printf(chromosome _c); + +// clear chromosome (set traits to zero) +int chromosome_reset(chromosome _c); + +// initialize chromosome on integer values +int chromosome_init(chromosome _c, + unsigned int * _v); + +// initialize chromosome on floating-point values +int chromosome_initf(chromosome _c, float * _v); + +// Mutates chromosome _c at _index +int chromosome_mutate(chromosome _c, unsigned int _index); + +// Resulting chromosome _c is a crossover of parents _p1 and _p2 at _threshold +int chromosome_crossover(chromosome _p1, + chromosome _p2, + chromosome _c, + unsigned int _threshold); + +// Initializes chromosome to random value +int chromosome_init_random(chromosome _c); + +// Returns integer representation of chromosome +unsigned int chromosome_value(chromosome _c, + unsigned int _index); + +// Returns floating-point representation of chromosome +float chromosome_valuef(chromosome _c, + unsigned int _index); + +// +// genetic algorithm search +// +typedef struct gasearch_s * gasearch; + +typedef float (*gasearch_utility)(void * _userdata, chromosome _c); + +// Create a simple gasearch object; parameters are specified internally +// _utility : chromosome fitness utility function +// _userdata : user data, void pointer passed to _get_utility() callback +// _parent : initial population parent chromosome, governs precision, etc. +// _minmax : search direction +gasearch gasearch_create(gasearch_utility _u, + void * _userdata, + chromosome _parent, + int _minmax); + +// Create a gasearch object, specifying search parameters +// _utility : chromosome fitness utility function +// _userdata : user data, void pointer passed to _get_utility() callback +// _parent : initial population parent chromosome, governs precision, etc. +// _minmax : search direction +// _population_size : number of chromosomes in population +// _mutation_rate : probability of mutating chromosomes +gasearch gasearch_create_advanced(gasearch_utility _utility, + void * _userdata, + chromosome _parent, + int _minmax, + unsigned int _population_size, + float _mutation_rate); + + +// Destroy a gasearch object +int gasearch_destroy(gasearch _q); + +// print search parameter internals +int gasearch_print(gasearch _q); + +// set mutation rate +int gasearch_set_mutation_rate(gasearch _q, + float _mutation_rate); + +// set population/selection size +// _q : ga search object +// _population_size : new population size (number of chromosomes) +// _selection_size : selection size (number of parents for new generation) +int gasearch_set_population_size(gasearch _q, + unsigned int _population_size, + unsigned int _selection_size); + +// Execute the search +// _q : ga search object +// _max_iterations : maximum number of iterations to run before bailing +// _target_utility : target utility +float gasearch_run(gasearch _q, + unsigned int _max_iterations, + float _target_utility); + +// iterate over one evolution of the search algorithm +int gasearch_evolve(gasearch _q); + +// get optimal chromosome +// _q : ga search object +// _c : output optimal chromosome +// _utility_opt : fitness of _c +int gasearch_getopt(gasearch _q, + chromosome _c, + float * _utility_opt); + +// +// MODULE : quantization +// + +float compress_mulaw(float _x, float _mu); +float expand_mulaw(float _x, float _mu); + +int compress_cf_mulaw(liquid_float_complex _x, float _mu, liquid_float_complex * _y); +int expand_cf_mulaw(liquid_float_complex _y, float _mu, liquid_float_complex * _x); + +//float compress_alaw(float _x, float _a); +//float expand_alaw(float _x, float _a); + +// inline quantizer: 'analog' signal in [-1, 1] +unsigned int quantize_adc(float _x, unsigned int _num_bits); +float quantize_dac(unsigned int _s, unsigned int _num_bits); + +// structured quantizer + +typedef enum { + LIQUID_COMPANDER_NONE=0, + LIQUID_COMPANDER_LINEAR, + LIQUID_COMPANDER_MULAW, + LIQUID_COMPANDER_ALAW +} liquid_compander_type; + +#define LIQUID_QUANTIZER_MANGLE_FLOAT(name) LIQUID_CONCAT(quantizerf, name) +#define LIQUID_QUANTIZER_MANGLE_CFLOAT(name) LIQUID_CONCAT(quantizercf, name) + +// large macro +// QUANTIZER : name-mangling macro +// T : data type +#define LIQUID_QUANTIZER_DEFINE_API(QUANTIZER,T) \ + \ +/* Amplitude quantization object */ \ +typedef struct QUANTIZER(_s) * QUANTIZER(); \ + \ +/* Create quantizer object given compander type, input range, and the */ \ +/* number of bits to represent the output */ \ +/* _ctype : compander type (linear, mulaw, alaw) */ \ +/* _range : maximum abosolute input range (ignored for now) */ \ +/* _num_bits : number of bits per sample */ \ +QUANTIZER() QUANTIZER(_create)(liquid_compander_type _ctype, \ + float _range, \ + unsigned int _num_bits); \ + \ +/* Destroy object, freeing all internally-allocated memory. */ \ +int QUANTIZER(_destroy)(QUANTIZER() _q); \ + \ +/* Print object properties to stdout, including compander type and */ \ +/* number of bits per sample */ \ +int QUANTIZER(_print)(QUANTIZER() _q); \ + \ +/* Execute quantizer as analog-to-digital converter, accepting input */ \ +/* sample and returning digitized output bits */ \ +/* _q : quantizer object */ \ +/* _x : input sample */ \ +/* _s : output bits */ \ +int QUANTIZER(_execute_adc)(QUANTIZER() _q, \ + T _x, \ + unsigned int * _s); \ + \ +/* Execute quantizer as digital-to-analog converter, accepting input */ \ +/* bits and returning representation of original input sample */ \ +/* _q : quantizer object */ \ +/* _s : input bits */ \ +/* _x : output sample */ \ +int QUANTIZER(_execute_dac)(QUANTIZER() _q, \ + unsigned int _s, \ + T * _x); \ + +LIQUID_QUANTIZER_DEFINE_API(LIQUID_QUANTIZER_MANGLE_FLOAT, float) +LIQUID_QUANTIZER_DEFINE_API(LIQUID_QUANTIZER_MANGLE_CFLOAT, liquid_float_complex) + + +// +// MODULE : random (number generators) +// + + +// Uniform random number generator, [0,1) +float randf(); +float randf_pdf(float _x); +float randf_cdf(float _x); + +// Uniform random number generator with arbitrary bounds, [a,b) +float randuf(float _a, float _b); +float randuf_pdf(float _x, float _a, float _b); +float randuf_cdf(float _x, float _a, float _b); + +// Gauss random number generator, N(0,1) +// f(x) = 1/sqrt(2*pi*sigma^2) * exp{-(x-eta)^2/(2*sigma^2)} +// +// where +// eta = mean +// sigma = standard deviation +// +float randnf(); +void awgn(float *_x, float _nstd); +void crandnf(liquid_float_complex *_y); +void cawgn(liquid_float_complex *_x, float _nstd); +float randnf_pdf(float _x, float _eta, float _sig); +float randnf_cdf(float _x, float _eta, float _sig); + +// Exponential +// f(x) = lambda exp{ -lambda x } +// where +// lambda = spread parameter, lambda > 0 +// x >= 0 +float randexpf(float _lambda); +float randexpf_pdf(float _x, float _lambda); +float randexpf_cdf(float _x, float _lambda); + +// Weibull +// f(x) = (a/b) (x/b)^(a-1) exp{ -(x/b)^a } +// where +// a = alpha : shape parameter +// b = beta : scaling parameter +// g = gamma : location (threshold) parameter +// +float randweibf(float _alpha, float _beta, float _gamma); +float randweibf_pdf(float _x, float _a, float _b, float _g); +float randweibf_cdf(float _x, float _a, float _b, float _g); + +// Gamma +// x^(a-1) exp(-x/b) +// f(x) = ------------------- +// Gamma(a) b^a +// where +// a = alpha : shape parameter, a > 0 +// b = beta : scale parameter, b > 0 +// Gamma(z) = regular gamma function +// x >= 0 +float randgammaf(float _alpha, float _beta); +float randgammaf_pdf(float _x, float _alpha, float _beta); +float randgammaf_cdf(float _x, float _alpha, float _beta); + +// Nakagami-m +// f(x) = (2/Gamma(m)) (m/omega)^m x^(2m-1) exp{-(m/omega)x^2} +// where +// m : shape parameter, m >= 0.5 +// omega : spread parameter, omega > 0 +// Gamma(z): regular complete gamma function +// x >= 0 +float randnakmf(float _m, float _omega); +float randnakmf_pdf(float _x, float _m, float _omega); +float randnakmf_cdf(float _x, float _m, float _omega); + +// Rice-K +// f(x) = (x/sigma^2) exp{ -(x^2+s^2)/(2sigma^2) } I0( x s / sigma^2 ) +// where +// s = sqrt( omega*K/(K+1) ) +// sigma = sqrt(0.5 omega/(K+1)) +// and +// K = shape parameter +// omega = spread parameter +// I0 = modified Bessel function of the first kind +// x >= 0 +float randricekf(float _K, float _omega); +float randricekf_cdf(float _x, float _K, float _omega); +float randricekf_pdf(float _x, float _K, float _omega); + + +// Data scrambler : whiten data sequence +void scramble_data(unsigned char * _x, unsigned int _len); +void unscramble_data(unsigned char * _x, unsigned int _len); +void unscramble_data_soft(unsigned char * _x, unsigned int _len); + +// +// MODULE : sequence +// + +// Binary sequence (generic) + +typedef struct bsequence_s * bsequence; + +// Create a binary sequence of a specific length (number of bits) +bsequence bsequence_create(unsigned int num_bits); + +// Free memory in a binary sequence +int bsequence_destroy(bsequence _bs); + +// Clear binary sequence (set to 0's) +int bsequence_reset(bsequence _bs); + +// initialize sequence on external array +int bsequence_init(bsequence _bs, + unsigned char * _v); + +// Print sequence to the screen +int bsequence_print(bsequence _bs); + +// Push bit into to back of a binary sequence +int bsequence_push(bsequence _bs, + unsigned int _bit); + +// circular shift (left) +int bsequence_circshift(bsequence _bs); + +// Correlate two binary sequences together +int bsequence_correlate(bsequence _bs1, bsequence _bs2); + +// compute the binary addition of two bit sequences +int bsequence_add(bsequence _bs1, bsequence _bs2, bsequence _bs3); + +// compute the binary multiplication of two bit sequences +int bsequence_mul(bsequence _bs1, bsequence _bs2, bsequence _bs3); + +// accumulate the 1's in a binary sequence +unsigned int bsequence_accumulate(bsequence _bs); + +// accessor functions +unsigned int bsequence_get_length(bsequence _bs); +unsigned int bsequence_index(bsequence _bs, unsigned int _i); + +// Complementary codes + +// intialize two sequences to complementary codes. sequences must +// be of length at least 8 and a power of 2 (e.g. 8, 16, 32, 64,...) +// _a : sequence 'a' (bsequence object) +// _b : sequence 'b' (bsequence object) +int bsequence_create_ccodes(bsequence _a, bsequence _b); + + +// M-Sequence + +#define LIQUID_MAX_MSEQUENCE_LENGTH 32767 + +// default m-sequence generators: g (hex) m n g (oct) g (binary) +#define LIQUID_MSEQUENCE_GENPOLY_M2 0x0007 // 2 3 7 111 +#define LIQUID_MSEQUENCE_GENPOLY_M3 0x000B // 3 7 13 1011 +#define LIQUID_MSEQUENCE_GENPOLY_M4 0x0013 // 4 15 23 10011 +#define LIQUID_MSEQUENCE_GENPOLY_M5 0x0025 // 5 31 45 100101 +#define LIQUID_MSEQUENCE_GENPOLY_M6 0x0043 // 6 63 103 1000011 +#define LIQUID_MSEQUENCE_GENPOLY_M7 0x0089 // 7 127 211 10001001 +#define LIQUID_MSEQUENCE_GENPOLY_M8 0x011D // 8 255 435 100101101 +#define LIQUID_MSEQUENCE_GENPOLY_M9 0x0211 // 9 511 1021 1000010001 +#define LIQUID_MSEQUENCE_GENPOLY_M10 0x0409 // 10 1023 2011 10000001001 +#define LIQUID_MSEQUENCE_GENPOLY_M11 0x0805 // 11 2047 4005 100000000101 +#define LIQUID_MSEQUENCE_GENPOLY_M12 0x1053 // 12 4095 10123 1000001010011 +#define LIQUID_MSEQUENCE_GENPOLY_M13 0x201b // 13 8191 20033 10000000011011 +#define LIQUID_MSEQUENCE_GENPOLY_M14 0x402b // 14 16383 40053 100000000101011 +#define LIQUID_MSEQUENCE_GENPOLY_M15 0x8003 // 15 32767 100003 1000000000000011 + +typedef struct msequence_s * msequence; + +// create a maximal-length sequence (m-sequence) object with +// an internal shift register length of _m bits. +// _m : generator polynomial length, sequence length is (2^m)-1 +// _g : generator polynomial, starting with most-significant bit +// _a : initial shift register state, default: 000...001 +msequence msequence_create(unsigned int _m, + unsigned int _g, + unsigned int _a); + +// create a maximal-length sequence (m-sequence) object from a generator polynomial +msequence msequence_create_genpoly(unsigned int _g); + +// creates a default maximal-length sequence +msequence msequence_create_default(unsigned int _m); + +// destroy an msequence object, freeing all internal memory +int msequence_destroy(msequence _m); + +// prints the sequence's internal state to the screen +int msequence_print(msequence _m); + +// advance msequence on shift register, returning output bit +unsigned int msequence_advance(msequence _ms); + +// generate pseudo-random symbol from shift register by +// advancing _bps bits and returning compacted symbol +// _ms : m-sequence object +// _bps : bits per symbol of output +unsigned int msequence_generate_symbol(msequence _ms, + unsigned int _bps); + +// reset msequence shift register to original state, typically '1' +int msequence_reset(msequence _ms); + +// initialize a bsequence object on an msequence object +// _bs : bsequence object +// _ms : msequence object +int bsequence_init_msequence(bsequence _bs, + msequence _ms); + +// get the length of the sequence +unsigned int msequence_get_length(msequence _ms); + +// get the internal state of the sequence +unsigned int msequence_get_state(msequence _ms); + +// set the internal state of the sequence +int msequence_set_state(msequence _ms, + unsigned int _a); + + +// +// MODULE : utility +// + +// pack binary array with symbol(s) +// _src : source array [size: _n x 1] +// _n : input source array length +// _k : bit index to write in _src +// _b : number of bits in input symbol +// _sym_in : input symbol +int liquid_pack_array(unsigned char * _src, + unsigned int _n, + unsigned int _k, + unsigned int _b, + unsigned char _sym_in); + +// unpack symbols from binary array +// _src : source array [size: _n x 1] +// _n : input source array length +// _k : bit index to write in _src +// _b : number of bits in output symbol +// _sym_out : output symbol +int liquid_unpack_array(unsigned char * _src, + unsigned int _n, + unsigned int _k, + unsigned int _b, + unsigned char * _sym_out); + +// pack one-bit symbols into bytes (8-bit symbols) +// _sym_in : input symbols array [size: _sym_in_len x 1] +// _sym_in_len : number of input symbols +// _sym_out : output symbols +// _sym_out_len : number of bytes allocated to output symbols array +// _num_written : number of output symbols actually written +int liquid_pack_bytes(unsigned char * _sym_in, + unsigned int _sym_in_len, + unsigned char * _sym_out, + unsigned int _sym_out_len, + unsigned int * _num_written); + +// unpack 8-bit symbols (full bytes) into one-bit symbols +// _sym_in : input symbols array [size: _sym_in_len x 1] +// _sym_in_len : number of input symbols +// _sym_out : output symbols array +// _sym_out_len : number of bytes allocated to output symbols array +// _num_written : number of output symbols actually written +int liquid_unpack_bytes(unsigned char * _sym_in, + unsigned int _sym_in_len, + unsigned char * _sym_out, + unsigned int _sym_out_len, + unsigned int * _num_written); + +// repack bytes with arbitrary symbol sizes +// _sym_in : input symbols array [size: _sym_in_len x 1] +// _sym_in_bps : number of bits per input symbol +// _sym_in_len : number of input symbols +// _sym_out : output symbols array +// _sym_out_bps : number of bits per output symbol +// _sym_out_len : number of bytes allocated to output symbols array +// _num_written : number of output symbols actually written +int liquid_repack_bytes(unsigned char * _sym_in, + unsigned int _sym_in_bps, + unsigned int _sym_in_len, + unsigned char * _sym_out, + unsigned int _sym_out_bps, + unsigned int _sym_out_len, + unsigned int * _num_written); + +// shift array to the left _b bits, filling in zeros +// _src : source address [size: _n x 1] +// _n : input data array size +// _b : number of bits to shift +int liquid_lbshift(unsigned char * _src, + unsigned int _n, + unsigned int _b); + +// shift array to the right _b bits, filling in zeros +// _src : source address [size: _n x 1] +// _n : input data array size +// _b : number of bits to shift +int liquid_rbshift(unsigned char * _src, + unsigned int _n, + unsigned int _b); + +// circularly shift array to the left _b bits +// _src : source address [size: _n x 1] +// _n : input data array size +// _b : number of bits to shift +int liquid_lbcircshift(unsigned char * _src, + unsigned int _n, + unsigned int _b); + +// circularly shift array to the right _b bits +// _src : source address [size: _n x 1] +// _n : input data array size +// _b : number of bits to shift +int liquid_rbcircshift(unsigned char * _src, + unsigned int _n, + unsigned int _b); + +// shift array to the left _b bytes, filling in zeros +// _src : source address [size: _n x 1] +// _n : input data array size +// _b : number of bytes to shift +int liquid_lshift(unsigned char * _src, + unsigned int _n, + unsigned int _b); + +// shift array to the right _b bytes, filling in zeros +// _src : source address [size: _n x 1] +// _n : input data array size +// _b : number of bytes to shift +int liquid_rshift(unsigned char * _src, + unsigned int _n, + unsigned int _b); + +// circular shift array to the left _b bytes +// _src : source address [size: _n x 1] +// _n : input data array size +// _b : number of bytes to shift +int liquid_lcircshift(unsigned char * _src, + unsigned int _n, + unsigned int _b); + +// circular shift array to the right _b bytes +// _src : source address [size: _n x 1] +// _n : input data array size +// _b : number of bytes to shift +int liquid_rcircshift(unsigned char * _src, + unsigned int _n, + unsigned int _b); + +// Count the number of ones in an integer +unsigned int liquid_count_ones(unsigned int _x); + +// count number of ones in an integer, modulo 2 +unsigned int liquid_count_ones_mod2(unsigned int _x); + +// compute bindary dot-product between two integers +unsigned int liquid_bdotprod(unsigned int _x, + unsigned int _y); + +// Count leading zeros in an integer +unsigned int liquid_count_leading_zeros(unsigned int _x); + +// Most-significant bit index +unsigned int liquid_msb_index(unsigned int _x); + +// Print string of bits to stdout +int liquid_print_bitstring(unsigned int _x, unsigned int _n); + +// reverse byte, word, etc. +unsigned char liquid_reverse_byte( unsigned char _x); +unsigned int liquid_reverse_uint16(unsigned int _x); +unsigned int liquid_reverse_uint24(unsigned int _x); +unsigned int liquid_reverse_uint32(unsigned int _x); + +// get scale for constant, particularly for plotting purposes +// _val : input value (e.g. 100e6) +// _unit : output unit character (e.g. 'M') +// _scale : output scale (e.g. 1e-6) +int liquid_get_scale(float _val, + char * _unit, + float * _scale); + +// +// MODULE : vector +// + +#define LIQUID_VECTOR_MANGLE_RF(name) LIQUID_CONCAT(liquid_vectorf, name) +#define LIQUID_VECTOR_MANGLE_CF(name) LIQUID_CONCAT(liquid_vectorcf,name) + +// large macro +// VECTOR : name-mangling macro +// T : data type +// TP : data type (primitive) +#define LIQUID_VECTOR_DEFINE_API(VECTOR,T,TP) \ + \ +/* Initialize vector with scalar: x[i] = c (scalar) */ \ +void VECTOR(_init)(T _c, \ + T * _x, \ + unsigned int _n); \ + \ +/* Add each element pointwise: z[i] = x[i] + y[i] */ \ +void VECTOR(_add)(T * _x, \ + T * _y, \ + unsigned int _n, \ + T * _z); \ + \ +/* Add scalar to each element: y[i] = x[i] + c */ \ +void VECTOR(_addscalar)(T * _x, \ + unsigned int _n, \ + T _c, \ + T * _y); \ + \ +/* Multiply each element pointwise: z[i] = x[i] * y[i] */ \ +void VECTOR(_mul)(T * _x, \ + T * _y, \ + unsigned int _n, \ + T * _z); \ + \ +/* Multiply each element with scalar: y[i] = x[i] * c */ \ +void VECTOR(_mulscalar)(T * _x, \ + unsigned int _n, \ + T _c, \ + T * _y); \ + \ +/* Compute complex phase rotation: x[i] = exp{j theta[i]} */ \ +void VECTOR(_cexpj)(TP * _theta, \ + unsigned int _n, \ + T * _x); \ + \ +/* Compute angle of each element: theta[i] = arg{ x[i] } */ \ +void VECTOR(_carg)(T * _x, \ + unsigned int _n, \ + TP * _theta); \ + \ +/* Compute absolute value of each element: y[i] = |x[i]| */ \ +void VECTOR(_abs)(T * _x, \ + unsigned int _n, \ + TP * _y); \ + \ +/* Compute sum of squares: sum{ |x|^2 } */ \ +TP VECTOR(_sumsq)(T * _x, \ + unsigned int _n); \ + \ +/* Compute l-2 norm: sqrt{ sum{ |x|^2 } } */ \ +TP VECTOR(_norm)(T * _x, \ + unsigned int _n); \ + \ +/* Compute l-p norm: { sum{ |x|^p } }^(1/p) */ \ +TP VECTOR(_pnorm)(T * _x, \ + unsigned int _n, \ + TP _p); \ + \ +/* Scale vector elements by l-2 norm: y[i] = x[i]/norm(x) */ \ +void VECTOR(_normalize)(T * _x, \ + unsigned int _n, \ + T * _y); \ + +LIQUID_VECTOR_DEFINE_API(LIQUID_VECTOR_MANGLE_RF, float, float) +LIQUID_VECTOR_DEFINE_API(LIQUID_VECTOR_MANGLE_CF, liquid_float_complex, float) + +// +// mixed types +// +#if 0 +void liquid_vectorf_add(float * _a, + float * _b, + unsigned int _n, + float * _c); +#endif + +#ifdef __cplusplus +} //extern "C" +#endif // __cplusplus + +#endif // __LIQUID_H__ + diff --git a/libkmaudio/pa_win_wasapi.h b/libkmaudio/pa_win_wasapi.h new file mode 100644 index 0000000..1d86896 --- /dev/null +++ b/libkmaudio/pa_win_wasapi.h @@ -0,0 +1,443 @@ +#ifndef PA_WIN_WASAPI_H +#define PA_WIN_WASAPI_H +/* + * $Id: $ + * PortAudio Portable Real-Time Audio Library + * DirectSound specific extensions + * + * Copyright (c) 1999-2007 Ross Bencina and Phil Burk + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files + * (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, + * publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +/* + * The text above constitutes the entire PortAudio license; however, + * the PortAudio community also makes the following non-binding requests: + * + * Any person wishing to distribute modifications to the Software is + * requested to send the modifications to the original developer so that + * they can be incorporated into the canonical version. It is also + * requested that these non-binding requests be included along with the + * license above. + */ + +/** @file + @ingroup public_header + @brief WASAPI-specific PortAudio API extension header file. +*/ + +#include "portaudio.h" +#include "pa_win_waveformat.h" + +#ifdef __cplusplus +extern "C" +{ +#endif /* __cplusplus */ + + +/* Setup flags */ +typedef enum PaWasapiFlags +{ + /* puts WASAPI into exclusive mode */ + paWinWasapiExclusive = (1 << 0), + + /* allows to skip internal PA processing completely */ + paWinWasapiRedirectHostProcessor = (1 << 1), + + /* assigns custom channel mask */ + paWinWasapiUseChannelMask = (1 << 2), + + /* selects non-Event driven method of data read/write + Note: WASAPI Event driven core is capable of 2ms latency!!!, but Polling + method can only provide 15-20ms latency. */ + paWinWasapiPolling = (1 << 3), + + /* forces custom thread priority setting, must be used if PaWasapiStreamInfo::threadPriority + is set to a custom value */ + paWinWasapiThreadPriority = (1 << 4) +} +PaWasapiFlags; +#define paWinWasapiExclusive (paWinWasapiExclusive) +#define paWinWasapiRedirectHostProcessor (paWinWasapiRedirectHostProcessor) +#define paWinWasapiUseChannelMask (paWinWasapiUseChannelMask) +#define paWinWasapiPolling (paWinWasapiPolling) +#define paWinWasapiThreadPriority (paWinWasapiThreadPriority) + + +/* Host processor. Allows to skip internal PA processing completely. + You must set paWinWasapiRedirectHostProcessor flag to PaWasapiStreamInfo::flags member + in order to have host processor redirected to your callback. + Use with caution! inputFrames and outputFrames depend solely on final device setup. + To query maximal values of inputFrames/outputFrames use PaWasapi_GetFramesPerHostBuffer. +*/ +typedef void (*PaWasapiHostProcessorCallback) (void *inputBuffer, long inputFrames, + void *outputBuffer, long outputFrames, + void *userData); + +/* Device role. */ +typedef enum PaWasapiDeviceRole +{ + eRoleRemoteNetworkDevice = 0, + eRoleSpeakers, + eRoleLineLevel, + eRoleHeadphones, + eRoleMicrophone, + eRoleHeadset, + eRoleHandset, + eRoleUnknownDigitalPassthrough, + eRoleSPDIF, + eRoleHDMI, + eRoleUnknownFormFactor +} +PaWasapiDeviceRole; + + +/* Jack connection type. */ +typedef enum PaWasapiJackConnectionType +{ + eJackConnTypeUnknown, + eJackConnType3Point5mm, + eJackConnTypeQuarter, + eJackConnTypeAtapiInternal, + eJackConnTypeRCA, + eJackConnTypeOptical, + eJackConnTypeOtherDigital, + eJackConnTypeOtherAnalog, + eJackConnTypeMultichannelAnalogDIN, + eJackConnTypeXlrProfessional, + eJackConnTypeRJ11Modem, + eJackConnTypeCombination +} +PaWasapiJackConnectionType; + + +/* Jack geometric location. */ +typedef enum PaWasapiJackGeoLocation +{ + eJackGeoLocUnk = 0, + eJackGeoLocRear = 0x1, /* matches EPcxGeoLocation::eGeoLocRear */ + eJackGeoLocFront, + eJackGeoLocLeft, + eJackGeoLocRight, + eJackGeoLocTop, + eJackGeoLocBottom, + eJackGeoLocRearPanel, + eJackGeoLocRiser, + eJackGeoLocInsideMobileLid, + eJackGeoLocDrivebay, + eJackGeoLocHDMI, + eJackGeoLocOutsideMobileLid, + eJackGeoLocATAPI, + eJackGeoLocReserved5, + eJackGeoLocReserved6, +} +PaWasapiJackGeoLocation; + + +/* Jack general location. */ +typedef enum PaWasapiJackGenLocation +{ + eJackGenLocPrimaryBox = 0, + eJackGenLocInternal, + eJackGenLocSeparate, + eJackGenLocOther +} +PaWasapiJackGenLocation; + + +/* Jack's type of port. */ +typedef enum PaWasapiJackPortConnection +{ + eJackPortConnJack = 0, + eJackPortConnIntegratedDevice, + eJackPortConnBothIntegratedAndJack, + eJackPortConnUnknown +} +PaWasapiJackPortConnection; + + +/* Thread priority. */ +typedef enum PaWasapiThreadPriority +{ + eThreadPriorityNone = 0, + eThreadPriorityAudio, //!< Default for Shared mode. + eThreadPriorityCapture, + eThreadPriorityDistribution, + eThreadPriorityGames, + eThreadPriorityPlayback, + eThreadPriorityProAudio, //!< Default for Exclusive mode. + eThreadPriorityWindowManager +} +PaWasapiThreadPriority; + + +/* Stream descriptor. */ +typedef struct PaWasapiJackDescription +{ + unsigned long channelMapping; + unsigned long color; /* derived from macro: #define RGB(r,g,b) ((COLORREF)(((BYTE)(r)|((WORD)((BYTE)(g))<<8))|(((DWORD)(BYTE)(b))<<16))) */ + PaWasapiJackConnectionType connectionType; + PaWasapiJackGeoLocation geoLocation; + PaWasapiJackGenLocation genLocation; + PaWasapiJackPortConnection portConnection; + unsigned int isConnected; +} +PaWasapiJackDescription; + + +/** Stream category. + Note: + - values are equal to WASAPI AUDIO_STREAM_CATEGORY enum + - supported since Windows 8.0, noop on earler versions + - values 1,2 are deprecated on Windows 10 and not included into enumeration + + @version Available as of 19.6.0 +*/ +typedef enum PaWasapiStreamCategory +{ + eAudioCategoryOther = 0, + eAudioCategoryCommunications = 3, + eAudioCategoryAlerts = 4, + eAudioCategorySoundEffects = 5, + eAudioCategoryGameEffects = 6, + eAudioCategoryGameMedia = 7, + eAudioCategoryGameChat = 8, + eAudioCategorySpeech = 9, + eAudioCategoryMovie = 10, + eAudioCategoryMedia = 11 +} +PaWasapiStreamCategory; + + +/** Stream option. + Note: + - values are equal to WASAPI AUDCLNT_STREAMOPTIONS enum + - supported since Windows 8.1, noop on earler versions + + @version Available as of 19.6.0 +*/ +typedef enum PaWasapiStreamOption +{ + eStreamOptionNone = 0, //!< default + eStreamOptionRaw = 1, //!< bypass WASAPI Audio Engine DSP effects, supported since Windows 8.1 + eStreamOptionMatchFormat = 2 //!< force WASAPI Audio Engine into a stream format, supported since Windows 10 +} +PaWasapiStreamOption; + + +/* Stream descriptor. */ +typedef struct PaWasapiStreamInfo +{ + unsigned long size; /**< sizeof(PaWasapiStreamInfo) */ + PaHostApiTypeId hostApiType; /**< paWASAPI */ + unsigned long version; /**< 1 */ + + unsigned long flags; /**< collection of PaWasapiFlags */ + + /** Support for WAVEFORMATEXTENSIBLE channel masks. If flags contains + paWinWasapiUseChannelMask this allows you to specify which speakers + to address in a multichannel stream. Constants for channelMask + are specified in pa_win_waveformat.h. Will be used only if + paWinWasapiUseChannelMask flag is specified. + */ + PaWinWaveFormatChannelMask channelMask; + + /** Delivers raw data to callback obtained from GetBuffer() methods skipping + internal PortAudio processing inventory completely. userData parameter will + be the same that was passed to Pa_OpenStream method. Will be used only if + paWinWasapiRedirectHostProcessor flag is specified. + */ + PaWasapiHostProcessorCallback hostProcessorOutput; + PaWasapiHostProcessorCallback hostProcessorInput; + + /** Specifies thread priority explicitly. Will be used only if paWinWasapiThreadPriority flag + is specified. + + Please note, if Input/Output streams are opened simultaniously (Full-Duplex mode) + you shall specify same value for threadPriority or othervise one of the values will be used + to setup thread priority. + */ + PaWasapiThreadPriority threadPriority; + + /** Stream category. + @see PaWasapiStreamCategory + @version Available as of 19.6.0 + */ + PaWasapiStreamCategory streamCategory; + + /** Stream option. + @see PaWasapiStreamOption + @version Available as of 19.6.0 + */ + PaWasapiStreamOption streamOption; +} +PaWasapiStreamInfo; + + +/** Returns default sound format for device. Format is represented by PaWinWaveFormat or + WAVEFORMATEXTENSIBLE structure. + + @param pFormat Pointer to PaWinWaveFormat or WAVEFORMATEXTENSIBLE structure. + @param nFormatSize Size of PaWinWaveFormat or WAVEFORMATEXTENSIBLE structure in bytes. + @param nDevice Device index. + + @return Non-negative value indicating the number of bytes copied into format decriptor + or, a PaErrorCode (which are always negative) if PortAudio is not initialized + or an error is encountered. +*/ +int PaWasapi_GetDeviceDefaultFormat( void *pFormat, unsigned int nFormatSize, PaDeviceIndex nDevice ); + + +/** Returns device role (PaWasapiDeviceRole enum). + + @param nDevice device index. + + @return Non-negative value indicating device role or, a PaErrorCode (which are always negative) + if PortAudio is not initialized or an error is encountered. +*/ +int/*PaWasapiDeviceRole*/ PaWasapi_GetDeviceRole( PaDeviceIndex nDevice ); + + +/** Boost thread priority of calling thread (MMCSS). Use it for Blocking Interface only for thread + which makes calls to Pa_WriteStream/Pa_ReadStream. + + @param hTask Handle to pointer to priority task. Must be used with PaWasapi_RevertThreadPriority + method to revert thread priority to initial state. + + @param nPriorityClass Id of thread priority of PaWasapiThreadPriority type. Specifying + eThreadPriorityNone does nothing. + + @return Error code indicating success or failure. + @see PaWasapi_RevertThreadPriority +*/ +PaError PaWasapi_ThreadPriorityBoost( void **hTask, PaWasapiThreadPriority nPriorityClass ); + + +/** Boost thread priority of calling thread (MMCSS). Use it for Blocking Interface only for thread + which makes calls to Pa_WriteStream/Pa_ReadStream. + + @param hTask Task handle obtained by PaWasapi_BoostThreadPriority method. + @return Error code indicating success or failure. + @see PaWasapi_BoostThreadPriority +*/ +PaError PaWasapi_ThreadPriorityRevert( void *hTask ); + + +/** Get number of frames per host buffer. This is maximal value of frames of WASAPI buffer which + can be locked for operations. Use this method as helper to findout maximal values of + inputFrames/outputFrames of PaWasapiHostProcessorCallback. + + @param pStream Pointer to PaStream to query. + @param nInput Pointer to variable to receive number of input frames. Can be NULL. + @param nOutput Pointer to variable to receive number of output frames. Can be NULL. + @return Error code indicating success or failure. + @see PaWasapiHostProcessorCallback +*/ +PaError PaWasapi_GetFramesPerHostBuffer( PaStream *pStream, unsigned int *nInput, unsigned int *nOutput ); + + +/** Get number of jacks associated with a WASAPI device. Use this method to determine if + there are any jacks associated with the provided WASAPI device. Not all audio devices + will support this capability. This is valid for both input and output devices. + @param nDevice device index. + @param jcount Number of jacks is returned in this variable + @return Error code indicating success or failure + @see PaWasapi_GetJackDescription + */ +PaError PaWasapi_GetJackCount(PaDeviceIndex nDevice, int *jcount); + + +/** Get the jack description associated with a WASAPI device and jack number + Before this function is called, use PaWasapi_GetJackCount to determine the + number of jacks associated with device. If jcount is greater than zero, then + each jack from 0 to jcount can be queried with this function to get the jack + description. + @param nDevice device index. + @param jindex Which jack to return information + @param KSJACK_DESCRIPTION This structure filled in on success. + @return Error code indicating success or failure + @see PaWasapi_GetJackCount + */ +PaError PaWasapi_GetJackDescription(PaDeviceIndex nDevice, int jindex, PaWasapiJackDescription *pJackDescription); + + +/* + IMPORTANT: + + WASAPI is implemented for Callback and Blocking interfaces. It supports Shared and Exclusive + share modes. + + Exclusive Mode: + + Exclusive mode allows to deliver audio data directly to hardware bypassing + software mixing. + Exclusive mode is specified by 'paWinWasapiExclusive' flag. + + Callback Interface: + + Provides best audio quality with low latency. Callback interface is implemented in + two versions: + + 1) Event-Driven: + This is the most powerful WASAPI implementation which provides glitch-free + audio at around 3ms latency in Exclusive mode. Lowest possible latency for this mode is + 3 ms for HD Audio class audio chips. For the Shared mode latency can not be + lower than 20 ms. + + 2) Poll-Driven: + Polling is another 2-nd method to operate with WASAPI. It is less efficient than Event-Driven + and provides latency at around 10-13ms. Polling must be used to overcome a system bug + under Windows Vista x64 when application is WOW64(32-bit) and Event-Driven method simply + times out (event handle is never signalled on buffer completion). Please note, such WOW64 bug + does not exist in Vista x86 or Windows 7. + Polling can be setup by speciying 'paWinWasapiPolling' flag. Our WASAPI implementation detects + WOW64 bug and sets 'paWinWasapiPolling' automatically. + + Thread priority: + + Normally thread priority is set automatically and does not require modification. Although + if user wants some tweaking thread priority can be modified by setting 'paWinWasapiThreadPriority' + flag and specifying 'PaWasapiStreamInfo::threadPriority' with value from PaWasapiThreadPriority + enum. + + Blocking Interface: + + Blocking interface is implemented but due to above described Poll-Driven method can not + deliver lowest possible latency. Specifying too low latency in Shared mode will result in + distorted audio although Exclusive mode adds stability. + + Pa_IsFormatSupported: + + To check format with correct Share Mode (Exclusive/Shared) you must supply + PaWasapiStreamInfo with flags paWinWasapiExclusive set through member of + PaStreamParameters::hostApiSpecificStreamInfo structure. + + Pa_OpenStream: + + To set desired Share Mode (Exclusive/Shared) you must supply + PaWasapiStreamInfo with flags paWinWasapiExclusive set through member of + PaStreamParameters::hostApiSpecificStreamInfo structure. +*/ + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* PA_WIN_WASAPI_H */ diff --git a/libkmaudio/pa_win_waveformat.h b/libkmaudio/pa_win_waveformat.h new file mode 100644 index 0000000..2c00267 --- /dev/null +++ b/libkmaudio/pa_win_waveformat.h @@ -0,0 +1,199 @@ +#ifndef PA_WIN_WAVEFORMAT_H +#define PA_WIN_WAVEFORMAT_H + +/* + * PortAudio Portable Real-Time Audio Library + * Windows WAVEFORMAT* data structure utilities + * portaudio.h should be included before this file. + * + * Copyright (c) 2007 Ross Bencina + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files + * (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, + * publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +/* + * The text above constitutes the entire PortAudio license; however, + * the PortAudio community also makes the following non-binding requests: + * + * Any person wishing to distribute modifications to the Software is + * requested to send the modifications to the original developer so that + * they can be incorporated into the canonical version. It is also + * requested that these non-binding requests be included along with the + * license above. + */ + +/** @file + @ingroup public_header + @brief Windows specific PortAudio API extension and utilities header file. +*/ + +#ifdef __cplusplus +extern "C" { +#endif + +/* + The following #defines for speaker channel masks are the same + as those in ksmedia.h, except with PAWIN_ prepended, KSAUDIO_ removed + in some cases, and casts to PaWinWaveFormatChannelMask added. +*/ + +typedef unsigned long PaWinWaveFormatChannelMask; + +/* Speaker Positions: */ +#define PAWIN_SPEAKER_FRONT_LEFT ((PaWinWaveFormatChannelMask)0x1) +#define PAWIN_SPEAKER_FRONT_RIGHT ((PaWinWaveFormatChannelMask)0x2) +#define PAWIN_SPEAKER_FRONT_CENTER ((PaWinWaveFormatChannelMask)0x4) +#define PAWIN_SPEAKER_LOW_FREQUENCY ((PaWinWaveFormatChannelMask)0x8) +#define PAWIN_SPEAKER_BACK_LEFT ((PaWinWaveFormatChannelMask)0x10) +#define PAWIN_SPEAKER_BACK_RIGHT ((PaWinWaveFormatChannelMask)0x20) +#define PAWIN_SPEAKER_FRONT_LEFT_OF_CENTER ((PaWinWaveFormatChannelMask)0x40) +#define PAWIN_SPEAKER_FRONT_RIGHT_OF_CENTER ((PaWinWaveFormatChannelMask)0x80) +#define PAWIN_SPEAKER_BACK_CENTER ((PaWinWaveFormatChannelMask)0x100) +#define PAWIN_SPEAKER_SIDE_LEFT ((PaWinWaveFormatChannelMask)0x200) +#define PAWIN_SPEAKER_SIDE_RIGHT ((PaWinWaveFormatChannelMask)0x400) +#define PAWIN_SPEAKER_TOP_CENTER ((PaWinWaveFormatChannelMask)0x800) +#define PAWIN_SPEAKER_TOP_FRONT_LEFT ((PaWinWaveFormatChannelMask)0x1000) +#define PAWIN_SPEAKER_TOP_FRONT_CENTER ((PaWinWaveFormatChannelMask)0x2000) +#define PAWIN_SPEAKER_TOP_FRONT_RIGHT ((PaWinWaveFormatChannelMask)0x4000) +#define PAWIN_SPEAKER_TOP_BACK_LEFT ((PaWinWaveFormatChannelMask)0x8000) +#define PAWIN_SPEAKER_TOP_BACK_CENTER ((PaWinWaveFormatChannelMask)0x10000) +#define PAWIN_SPEAKER_TOP_BACK_RIGHT ((PaWinWaveFormatChannelMask)0x20000) + +/* Bit mask locations reserved for future use */ +#define PAWIN_SPEAKER_RESERVED ((PaWinWaveFormatChannelMask)0x7FFC0000) + +/* Used to specify that any possible permutation of speaker configurations */ +#define PAWIN_SPEAKER_ALL ((PaWinWaveFormatChannelMask)0x80000000) + +/* DirectSound Speaker Config */ +#define PAWIN_SPEAKER_DIRECTOUT 0 +#define PAWIN_SPEAKER_MONO (PAWIN_SPEAKER_FRONT_CENTER) +#define PAWIN_SPEAKER_STEREO (PAWIN_SPEAKER_FRONT_LEFT | PAWIN_SPEAKER_FRONT_RIGHT) +#define PAWIN_SPEAKER_QUAD (PAWIN_SPEAKER_FRONT_LEFT | PAWIN_SPEAKER_FRONT_RIGHT | \ + PAWIN_SPEAKER_BACK_LEFT | PAWIN_SPEAKER_BACK_RIGHT) +#define PAWIN_SPEAKER_SURROUND (PAWIN_SPEAKER_FRONT_LEFT | PAWIN_SPEAKER_FRONT_RIGHT | \ + PAWIN_SPEAKER_FRONT_CENTER | PAWIN_SPEAKER_BACK_CENTER) +#define PAWIN_SPEAKER_5POINT1 (PAWIN_SPEAKER_FRONT_LEFT | PAWIN_SPEAKER_FRONT_RIGHT | \ + PAWIN_SPEAKER_FRONT_CENTER | PAWIN_SPEAKER_LOW_FREQUENCY | \ + PAWIN_SPEAKER_BACK_LEFT | PAWIN_SPEAKER_BACK_RIGHT) +#define PAWIN_SPEAKER_7POINT1 (PAWIN_SPEAKER_FRONT_LEFT | PAWIN_SPEAKER_FRONT_RIGHT | \ + PAWIN_SPEAKER_FRONT_CENTER | PAWIN_SPEAKER_LOW_FREQUENCY | \ + PAWIN_SPEAKER_BACK_LEFT | PAWIN_SPEAKER_BACK_RIGHT | \ + PAWIN_SPEAKER_FRONT_LEFT_OF_CENTER | PAWIN_SPEAKER_FRONT_RIGHT_OF_CENTER) +#define PAWIN_SPEAKER_5POINT1_SURROUND (PAWIN_SPEAKER_FRONT_LEFT | PAWIN_SPEAKER_FRONT_RIGHT | \ + PAWIN_SPEAKER_FRONT_CENTER | PAWIN_SPEAKER_LOW_FREQUENCY | \ + PAWIN_SPEAKER_SIDE_LEFT | PAWIN_SPEAKER_SIDE_RIGHT) +#define PAWIN_SPEAKER_7POINT1_SURROUND (PAWIN_SPEAKER_FRONT_LEFT | PAWIN_SPEAKER_FRONT_RIGHT | \ + PAWIN_SPEAKER_FRONT_CENTER | PAWIN_SPEAKER_LOW_FREQUENCY | \ + PAWIN_SPEAKER_BACK_LEFT | PAWIN_SPEAKER_BACK_RIGHT | \ + PAWIN_SPEAKER_SIDE_LEFT | PAWIN_SPEAKER_SIDE_RIGHT) +/* + According to the Microsoft documentation: + The following are obsolete 5.1 and 7.1 settings (they lack side speakers). Note this means + that the default 5.1 and 7.1 settings (KSAUDIO_SPEAKER_5POINT1 and KSAUDIO_SPEAKER_7POINT1 are + similarly obsolete but are unchanged for compatibility reasons). +*/ +#define PAWIN_SPEAKER_5POINT1_BACK PAWIN_SPEAKER_5POINT1 +#define PAWIN_SPEAKER_7POINT1_WIDE PAWIN_SPEAKER_7POINT1 + +/* DVD Speaker Positions */ +#define PAWIN_SPEAKER_GROUND_FRONT_LEFT PAWIN_SPEAKER_FRONT_LEFT +#define PAWIN_SPEAKER_GROUND_FRONT_CENTER PAWIN_SPEAKER_FRONT_CENTER +#define PAWIN_SPEAKER_GROUND_FRONT_RIGHT PAWIN_SPEAKER_FRONT_RIGHT +#define PAWIN_SPEAKER_GROUND_REAR_LEFT PAWIN_SPEAKER_BACK_LEFT +#define PAWIN_SPEAKER_GROUND_REAR_RIGHT PAWIN_SPEAKER_BACK_RIGHT +#define PAWIN_SPEAKER_TOP_MIDDLE PAWIN_SPEAKER_TOP_CENTER +#define PAWIN_SPEAKER_SUPER_WOOFER PAWIN_SPEAKER_LOW_FREQUENCY + + +/* + PaWinWaveFormat is defined here to provide compatibility with + compilation environments which don't have headers defining + WAVEFORMATEXTENSIBLE (e.g. older versions of MSVC, Borland C++ etc. + + The fields for WAVEFORMATEX and WAVEFORMATEXTENSIBLE are declared as an + unsigned char array here to avoid clients who include this file having + a dependency on windows.h and mmsystem.h, and also to to avoid having + to write separate packing pragmas for each compiler. +*/ +#define PAWIN_SIZEOF_WAVEFORMATEX 18 +#define PAWIN_SIZEOF_WAVEFORMATEXTENSIBLE (PAWIN_SIZEOF_WAVEFORMATEX + 22) + +typedef struct{ + unsigned char fields[ PAWIN_SIZEOF_WAVEFORMATEXTENSIBLE ]; + unsigned long extraLongForAlignment; /* ensure that compiler aligns struct to DWORD */ +} PaWinWaveFormat; + +/* + WAVEFORMATEXTENSIBLE fields: + + union { + WORD wValidBitsPerSample; + WORD wSamplesPerBlock; + WORD wReserved; + } Samples; + DWORD dwChannelMask; + GUID SubFormat; +*/ + +#define PAWIN_INDEXOF_WVALIDBITSPERSAMPLE (PAWIN_SIZEOF_WAVEFORMATEX+0) +#define PAWIN_INDEXOF_DWCHANNELMASK (PAWIN_SIZEOF_WAVEFORMATEX+2) +#define PAWIN_INDEXOF_SUBFORMAT (PAWIN_SIZEOF_WAVEFORMATEX+6) + + +/* + Valid values to pass for the waveFormatTag PaWin_InitializeWaveFormatEx and + PaWin_InitializeWaveFormatExtensible functions below. These must match + the standard Windows WAVE_FORMAT_* values. +*/ +#define PAWIN_WAVE_FORMAT_PCM (1) +#define PAWIN_WAVE_FORMAT_IEEE_FLOAT (3) +#define PAWIN_WAVE_FORMAT_DOLBY_AC3_SPDIF (0x0092) +#define PAWIN_WAVE_FORMAT_WMA_SPDIF (0x0164) + + +/* + returns PAWIN_WAVE_FORMAT_PCM or PAWIN_WAVE_FORMAT_IEEE_FLOAT + depending on the sampleFormat parameter. +*/ +int PaWin_SampleFormatToLinearWaveFormatTag( PaSampleFormat sampleFormat ); + +/* + Use the following two functions to initialize the waveformat structure. +*/ + +void PaWin_InitializeWaveFormatEx( PaWinWaveFormat *waveFormat, + int numChannels, PaSampleFormat sampleFormat, int waveFormatTag, double sampleRate ); + + +void PaWin_InitializeWaveFormatExtensible( PaWinWaveFormat *waveFormat, + int numChannels, PaSampleFormat sampleFormat, int waveFormatTag, double sampleRate, + PaWinWaveFormatChannelMask channelMask ); + + +/* Map a channel count to a speaker channel mask */ +PaWinWaveFormatChannelMask PaWin_DefaultChannelMask( int numChannels ); + + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* PA_WIN_WAVEFORMAT_H */ \ No newline at end of file diff --git a/libkmaudio/portaudio.h b/libkmaudio/portaudio.h new file mode 100644 index 0000000..8a94aaf --- /dev/null +++ b/libkmaudio/portaudio.h @@ -0,0 +1,1225 @@ +#ifndef PORTAUDIO_H +#define PORTAUDIO_H +/* + * $Id$ + * PortAudio Portable Real-Time Audio Library + * PortAudio API Header File + * Latest version available at: http://www.portaudio.com/ + * + * Copyright (c) 1999-2002 Ross Bencina and Phil Burk + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files + * (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, + * publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +/* + * The text above constitutes the entire PortAudio license; however, + * the PortAudio community also makes the following non-binding requests: + * + * Any person wishing to distribute modifications to the Software is + * requested to send the modifications to the original developer so that + * they can be incorporated into the canonical version. It is also + * requested that these non-binding requests be included along with the + * license above. + */ + +/** @file + @ingroup public_header + @brief The portable PortAudio API. +*/ + + +#ifdef __cplusplus +extern "C" +{ +#endif /* __cplusplus */ + +/** Retrieve the release number of the currently running PortAudio build. + For example, for version "19.5.1" this will return 0x00130501. + + @see paMakeVersionNumber +*/ +int Pa_GetVersion( void ); + +/** Retrieve a textual description of the current PortAudio build, + e.g. "PortAudio V19.5.0-devel, revision 1952M". + The format of the text may change in the future. Do not try to parse the + returned string. + + @deprecated As of 19.5.0, use Pa_GetVersionInfo()->versionText instead. +*/ +const char* Pa_GetVersionText( void ); + +/** + Generate a packed integer version number in the same format used + by Pa_GetVersion(). Use this to compare a specified version number with + the currently running version. For example: + + @code + if( Pa_GetVersion() < paMakeVersionNumber(19,5,1) ) {} + @endcode + + @see Pa_GetVersion, Pa_GetVersionInfo + @version Available as of 19.5.0. +*/ +#define paMakeVersionNumber(major, minor, subminor) \ + (((major)&0xFF)<<16 | ((minor)&0xFF)<<8 | ((subminor)&0xFF)) + + +/** + A structure containing PortAudio API version information. + @see Pa_GetVersionInfo, paMakeVersionNumber + @version Available as of 19.5.0. +*/ +typedef struct PaVersionInfo { + int versionMajor; + int versionMinor; + int versionSubMinor; + /** + This is currently the Git revision hash but may change in the future. + The versionControlRevision is updated by running a script before compiling the library. + If the update does not occur, this value may refer to an earlier revision. + */ + const char *versionControlRevision; + /** Version as a string, for example "PortAudio V19.5.0-devel, revision 1952M" */ + const char *versionText; +} PaVersionInfo; + +/** Retrieve version information for the currently running PortAudio build. + @return A pointer to an immutable PaVersionInfo structure. + + @note This function can be called at any time. It does not require PortAudio + to be initialized. The structure pointed to is statically allocated. Do not + attempt to free it or modify it. + + @see PaVersionInfo, paMakeVersionNumber + @version Available as of 19.5.0. +*/ +const PaVersionInfo* Pa_GetVersionInfo(); + + +/** Error codes returned by PortAudio functions. + Note that with the exception of paNoError, all PaErrorCodes are negative. +*/ + +typedef int PaError; +typedef enum PaErrorCode +{ + paNoError = 0, + + paNotInitialized = -10000, + paUnanticipatedHostError, + paInvalidChannelCount, + paInvalidSampleRate, + paInvalidDevice, + paInvalidFlag, + paSampleFormatNotSupported, + paBadIODeviceCombination, + paInsufficientMemory, + paBufferTooBig, + paBufferTooSmall, + paNullCallback, + paBadStreamPtr, + paTimedOut, + paInternalError, + paDeviceUnavailable, + paIncompatibleHostApiSpecificStreamInfo, + paStreamIsStopped, + paStreamIsNotStopped, + paInputOverflowed, + paOutputUnderflowed, + paHostApiNotFound, + paInvalidHostApi, + paCanNotReadFromACallbackStream, + paCanNotWriteToACallbackStream, + paCanNotReadFromAnOutputOnlyStream, + paCanNotWriteToAnInputOnlyStream, + paIncompatibleStreamHostApi, + paBadBufferPtr +} PaErrorCode; + + +/** Translate the supplied PortAudio error code into a human readable + message. +*/ +const char *Pa_GetErrorText( PaError errorCode ); + + +/** Library initialization function - call this before using PortAudio. + This function initializes internal data structures and prepares underlying + host APIs for use. With the exception of Pa_GetVersion(), Pa_GetVersionText(), + and Pa_GetErrorText(), this function MUST be called before using any other + PortAudio API functions. + + If Pa_Initialize() is called multiple times, each successful + call must be matched with a corresponding call to Pa_Terminate(). + Pairs of calls to Pa_Initialize()/Pa_Terminate() may overlap, and are not + required to be fully nested. + + Note that if Pa_Initialize() returns an error code, Pa_Terminate() should + NOT be called. + + @return paNoError if successful, otherwise an error code indicating the cause + of failure. + + @see Pa_Terminate +*/ +PaError Pa_Initialize( void ); + + +/** Library termination function - call this when finished using PortAudio. + This function deallocates all resources allocated by PortAudio since it was + initialized by a call to Pa_Initialize(). In cases where Pa_Initialise() has + been called multiple times, each call must be matched with a corresponding call + to Pa_Terminate(). The final matching call to Pa_Terminate() will automatically + close any PortAudio streams that are still open. + + Pa_Terminate() MUST be called before exiting a program which uses PortAudio. + Failure to do so may result in serious resource leaks, such as audio devices + not being available until the next reboot. + + @return paNoError if successful, otherwise an error code indicating the cause + of failure. + + @see Pa_Initialize +*/ +PaError Pa_Terminate( void ); + + + +/** The type used to refer to audio devices. Values of this type usually + range from 0 to (Pa_GetDeviceCount()-1), and may also take on the PaNoDevice + and paUseHostApiSpecificDeviceSpecification values. + + @see Pa_GetDeviceCount, paNoDevice, paUseHostApiSpecificDeviceSpecification +*/ +typedef int PaDeviceIndex; + + +/** A special PaDeviceIndex value indicating that no device is available, + or should be used. + + @see PaDeviceIndex +*/ +#define paNoDevice ((PaDeviceIndex)-1) + + +/** A special PaDeviceIndex value indicating that the device(s) to be used + are specified in the host api specific stream info structure. + + @see PaDeviceIndex +*/ +#define paUseHostApiSpecificDeviceSpecification ((PaDeviceIndex)-2) + + +/* Host API enumeration mechanism */ + +/** The type used to enumerate to host APIs at runtime. Values of this type + range from 0 to (Pa_GetHostApiCount()-1). + + @see Pa_GetHostApiCount +*/ +typedef int PaHostApiIndex; + + +/** Retrieve the number of available host APIs. Even if a host API is + available it may have no devices available. + + @return A non-negative value indicating the number of available host APIs + or, a PaErrorCode (which are always negative) if PortAudio is not initialized + or an error is encountered. + + @see PaHostApiIndex +*/ +PaHostApiIndex Pa_GetHostApiCount( void ); + + +/** Retrieve the index of the default host API. The default host API will be + the lowest common denominator host API on the current platform and is + unlikely to provide the best performance. + + @return A non-negative value ranging from 0 to (Pa_GetHostApiCount()-1) + indicating the default host API index or, a PaErrorCode (which are always + negative) if PortAudio is not initialized or an error is encountered. +*/ +PaHostApiIndex Pa_GetDefaultHostApi( void ); + + +/** Unchanging unique identifiers for each supported host API. This type + is used in the PaHostApiInfo structure. The values are guaranteed to be + unique and to never change, thus allowing code to be written that + conditionally uses host API specific extensions. + + New type ids will be allocated when support for a host API reaches + "public alpha" status, prior to that developers should use the + paInDevelopment type id. + + @see PaHostApiInfo +*/ +typedef enum PaHostApiTypeId +{ + paInDevelopment=0, /* use while developing support for a new host API */ + paDirectSound=1, + paMME=2, + paASIO=3, + paSoundManager=4, + paCoreAudio=5, + paOSS=7, + paALSA=8, + paAL=9, + paBeOS=10, + paWDMKS=11, + paJACK=12, + paWASAPI=13, + paAudioScienceHPI=14 +} PaHostApiTypeId; + + +/** A structure containing information about a particular host API. */ + +typedef struct PaHostApiInfo +{ + /** this is struct version 1 */ + int structVersion; + /** The well known unique identifier of this host API @see PaHostApiTypeId */ + PaHostApiTypeId type; + /** A textual description of the host API for display on user interfaces. */ + const char *name; + + /** The number of devices belonging to this host API. This field may be + used in conjunction with Pa_HostApiDeviceIndexToDeviceIndex() to enumerate + all devices for this host API. + @see Pa_HostApiDeviceIndexToDeviceIndex + */ + int deviceCount; + + /** The default input device for this host API. The value will be a + device index ranging from 0 to (Pa_GetDeviceCount()-1), or paNoDevice + if no default input device is available. + */ + PaDeviceIndex defaultInputDevice; + + /** The default output device for this host API. The value will be a + device index ranging from 0 to (Pa_GetDeviceCount()-1), or paNoDevice + if no default output device is available. + */ + PaDeviceIndex defaultOutputDevice; + +} PaHostApiInfo; + + +/** Retrieve a pointer to a structure containing information about a specific + host Api. + + @param hostApi A valid host API index ranging from 0 to (Pa_GetHostApiCount()-1) + + @return A pointer to an immutable PaHostApiInfo structure describing + a specific host API. If the hostApi parameter is out of range or an error + is encountered, the function returns NULL. + + The returned structure is owned by the PortAudio implementation and must not + be manipulated or freed. The pointer is only guaranteed to be valid between + calls to Pa_Initialize() and Pa_Terminate(). +*/ +const PaHostApiInfo * Pa_GetHostApiInfo( PaHostApiIndex hostApi ); + + +/** Convert a static host API unique identifier, into a runtime + host API index. + + @param type A unique host API identifier belonging to the PaHostApiTypeId + enumeration. + + @return A valid PaHostApiIndex ranging from 0 to (Pa_GetHostApiCount()-1) or, + a PaErrorCode (which are always negative) if PortAudio is not initialized + or an error is encountered. + + The paHostApiNotFound error code indicates that the host API specified by the + type parameter is not available. + + @see PaHostApiTypeId +*/ +PaHostApiIndex Pa_HostApiTypeIdToHostApiIndex( PaHostApiTypeId type ); + + +/** Convert a host-API-specific device index to standard PortAudio device index. + This function may be used in conjunction with the deviceCount field of + PaHostApiInfo to enumerate all devices for the specified host API. + + @param hostApi A valid host API index ranging from 0 to (Pa_GetHostApiCount()-1) + + @param hostApiDeviceIndex A valid per-host device index in the range + 0 to (Pa_GetHostApiInfo(hostApi)->deviceCount-1) + + @return A non-negative PaDeviceIndex ranging from 0 to (Pa_GetDeviceCount()-1) + or, a PaErrorCode (which are always negative) if PortAudio is not initialized + or an error is encountered. + + A paInvalidHostApi error code indicates that the host API index specified by + the hostApi parameter is out of range. + + A paInvalidDevice error code indicates that the hostApiDeviceIndex parameter + is out of range. + + @see PaHostApiInfo +*/ +PaDeviceIndex Pa_HostApiDeviceIndexToDeviceIndex( PaHostApiIndex hostApi, + int hostApiDeviceIndex ); + + + +/** Structure used to return information about a host error condition. +*/ +typedef struct PaHostErrorInfo{ + PaHostApiTypeId hostApiType; /**< the host API which returned the error code */ + long errorCode; /**< the error code returned */ + const char *errorText; /**< a textual description of the error if available, otherwise a zero-length string */ +}PaHostErrorInfo; + + +/** Return information about the last host error encountered. The error + information returned by Pa_GetLastHostErrorInfo() will never be modified + asynchronously by errors occurring in other PortAudio owned threads + (such as the thread that manages the stream callback.) + + This function is provided as a last resort, primarily to enhance debugging + by providing clients with access to all available error information. + + @return A pointer to an immutable structure constraining information about + the host error. The values in this structure will only be valid if a + PortAudio function has previously returned the paUnanticipatedHostError + error code. +*/ +const PaHostErrorInfo* Pa_GetLastHostErrorInfo( void ); + + + +/* Device enumeration and capabilities */ + +/** Retrieve the number of available devices. The number of available devices + may be zero. + + @return A non-negative value indicating the number of available devices or, + a PaErrorCode (which are always negative) if PortAudio is not initialized + or an error is encountered. +*/ +PaDeviceIndex Pa_GetDeviceCount( void ); + + +/** Retrieve the index of the default input device. The result can be + used in the inputDevice parameter to Pa_OpenStream(). + + @return The default input device index for the default host API, or paNoDevice + if no default input device is available or an error was encountered. +*/ +PaDeviceIndex Pa_GetDefaultInputDevice( void ); + + +/** Retrieve the index of the default output device. The result can be + used in the outputDevice parameter to Pa_OpenStream(). + + @return The default output device index for the default host API, or paNoDevice + if no default output device is available or an error was encountered. + + @note + On the PC, the user can specify a default device by + setting an environment variable. For example, to use device #1. +
+ set PA_RECOMMENDED_OUTPUT_DEVICE=1
+
+ The user should first determine the available device ids by using + the supplied application "pa_devs". +*/ +PaDeviceIndex Pa_GetDefaultOutputDevice( void ); + + +/** The type used to represent monotonic time in seconds. PaTime is + used for the fields of the PaStreamCallbackTimeInfo argument to the + PaStreamCallback and as the result of Pa_GetStreamTime(). + + PaTime values have unspecified origin. + + @see PaStreamCallback, PaStreamCallbackTimeInfo, Pa_GetStreamTime +*/ +typedef double PaTime; + + +/** A type used to specify one or more sample formats. Each value indicates + a possible format for sound data passed to and from the stream callback, + Pa_ReadStream and Pa_WriteStream. + + The standard formats paFloat32, paInt16, paInt32, paInt24, paInt8 + and aUInt8 are usually implemented by all implementations. + + The floating point representation (paFloat32) uses +1.0 and -1.0 as the + maximum and minimum respectively. + + paUInt8 is an unsigned 8 bit format where 128 is considered "ground" + + The paNonInterleaved flag indicates that audio data is passed as an array + of pointers to separate buffers, one buffer for each channel. Usually, + when this flag is not used, audio data is passed as a single buffer with + all channels interleaved. + + @see Pa_OpenStream, Pa_OpenDefaultStream, PaDeviceInfo + @see paFloat32, paInt16, paInt32, paInt24, paInt8 + @see paUInt8, paCustomFormat, paNonInterleaved +*/ +typedef unsigned long PaSampleFormat; + + +#define paFloat32 ((PaSampleFormat) 0x00000001) /**< @see PaSampleFormat */ +#define paInt32 ((PaSampleFormat) 0x00000002) /**< @see PaSampleFormat */ +#define paInt24 ((PaSampleFormat) 0x00000004) /**< Packed 24 bit format. @see PaSampleFormat */ +#define paInt16 ((PaSampleFormat) 0x00000008) /**< @see PaSampleFormat */ +#define paInt8 ((PaSampleFormat) 0x00000010) /**< @see PaSampleFormat */ +#define paUInt8 ((PaSampleFormat) 0x00000020) /**< @see PaSampleFormat */ +#define paCustomFormat ((PaSampleFormat) 0x00010000) /**< @see PaSampleFormat */ + +#define paNonInterleaved ((PaSampleFormat) 0x80000000) /**< @see PaSampleFormat */ + +/** A structure providing information and capabilities of PortAudio devices. + Devices may support input, output or both input and output. +*/ +typedef struct PaDeviceInfo +{ + int structVersion; /* this is struct version 2 */ + const char *name; + PaHostApiIndex hostApi; /**< note this is a host API index, not a type id*/ + + int maxInputChannels; + int maxOutputChannels; + + /** Default latency values for interactive performance. */ + PaTime defaultLowInputLatency; + PaTime defaultLowOutputLatency; + /** Default latency values for robust non-interactive applications (eg. playing sound files). */ + PaTime defaultHighInputLatency; + PaTime defaultHighOutputLatency; + + double defaultSampleRate; +} PaDeviceInfo; + + +/** Retrieve a pointer to a PaDeviceInfo structure containing information + about the specified device. + @return A pointer to an immutable PaDeviceInfo structure. If the device + parameter is out of range the function returns NULL. + + @param device A valid device index in the range 0 to (Pa_GetDeviceCount()-1) + + @note PortAudio manages the memory referenced by the returned pointer, + the client must not manipulate or free the memory. The pointer is only + guaranteed to be valid between calls to Pa_Initialize() and Pa_Terminate(). + + @see PaDeviceInfo, PaDeviceIndex +*/ +const PaDeviceInfo* Pa_GetDeviceInfo( PaDeviceIndex device ); + + +/** Parameters for one direction (input or output) of a stream. +*/ +typedef struct PaStreamParameters +{ + /** A valid device index in the range 0 to (Pa_GetDeviceCount()-1) + specifying the device to be used or the special constant + paUseHostApiSpecificDeviceSpecification which indicates that the actual + device(s) to use are specified in hostApiSpecificStreamInfo. + This field must not be set to paNoDevice. + */ + PaDeviceIndex device; + + /** The number of channels of sound to be delivered to the + stream callback or accessed by Pa_ReadStream() or Pa_WriteStream(). + It can range from 1 to the value of maxInputChannels in the + PaDeviceInfo record for the device specified by the device parameter. + */ + int channelCount; + + /** The sample format of the buffer provided to the stream callback, + a_ReadStream() or Pa_WriteStream(). It may be any of the formats described + by the PaSampleFormat enumeration. + */ + PaSampleFormat sampleFormat; + + /** The desired latency in seconds. Where practical, implementations should + configure their latency based on these parameters, otherwise they may + choose the closest viable latency instead. Unless the suggested latency + is greater than the absolute upper limit for the device implementations + should round the suggestedLatency up to the next practical value - ie to + provide an equal or higher latency than suggestedLatency wherever possible. + Actual latency values for an open stream may be retrieved using the + inputLatency and outputLatency fields of the PaStreamInfo structure + returned by Pa_GetStreamInfo(). + @see default*Latency in PaDeviceInfo, *Latency in PaStreamInfo + */ + PaTime suggestedLatency; + + /** An optional pointer to a host api specific data structure + containing additional information for device setup and/or stream processing. + hostApiSpecificStreamInfo is never required for correct operation, + if not used it should be set to NULL. + */ + void *hostApiSpecificStreamInfo; + +} PaStreamParameters; + + +/** Return code for Pa_IsFormatSupported indicating success. */ +#define paFormatIsSupported (0) + +/** Determine whether it would be possible to open a stream with the specified + parameters. + + @param inputParameters A structure that describes the input parameters used to + open a stream. The suggestedLatency field is ignored. See PaStreamParameters + for a description of these parameters. inputParameters must be NULL for + output-only streams. + + @param outputParameters A structure that describes the output parameters used + to open a stream. The suggestedLatency field is ignored. See PaStreamParameters + for a description of these parameters. outputParameters must be NULL for + input-only streams. + + @param sampleRate The required sampleRate. For full-duplex streams it is the + sample rate for both input and output + + @return Returns 0 if the format is supported, and an error code indicating why + the format is not supported otherwise. The constant paFormatIsSupported is + provided to compare with the return value for success. + + @see paFormatIsSupported, PaStreamParameters +*/ +PaError Pa_IsFormatSupported( const PaStreamParameters *inputParameters, + const PaStreamParameters *outputParameters, + double sampleRate ); + + + +/* Streaming types and functions */ + + +/** + A single PaStream can provide multiple channels of real-time + streaming audio input and output to a client application. A stream + provides access to audio hardware represented by one or more + PaDevices. Depending on the underlying Host API, it may be possible + to open multiple streams using the same device, however this behavior + is implementation defined. Portable applications should assume that + a PaDevice may be simultaneously used by at most one PaStream. + + Pointers to PaStream objects are passed between PortAudio functions that + operate on streams. + + @see Pa_OpenStream, Pa_OpenDefaultStream, Pa_OpenDefaultStream, Pa_CloseStream, + Pa_StartStream, Pa_StopStream, Pa_AbortStream, Pa_IsStreamActive, + Pa_GetStreamTime, Pa_GetStreamCpuLoad + +*/ +typedef void PaStream; + + +/** Can be passed as the framesPerBuffer parameter to Pa_OpenStream() + or Pa_OpenDefaultStream() to indicate that the stream callback will + accept buffers of any size. +*/ +#define paFramesPerBufferUnspecified (0) + + +/** Flags used to control the behavior of a stream. They are passed as + parameters to Pa_OpenStream or Pa_OpenDefaultStream. Multiple flags may be + ORed together. + + @see Pa_OpenStream, Pa_OpenDefaultStream + @see paNoFlag, paClipOff, paDitherOff, paNeverDropInput, + paPrimeOutputBuffersUsingStreamCallback, paPlatformSpecificFlags +*/ +typedef unsigned long PaStreamFlags; + +/** @see PaStreamFlags */ +#define paNoFlag ((PaStreamFlags) 0) + +/** Disable default clipping of out of range samples. + @see PaStreamFlags +*/ +#define paClipOff ((PaStreamFlags) 0x00000001) + +/** Disable default dithering. + @see PaStreamFlags +*/ +#define paDitherOff ((PaStreamFlags) 0x00000002) + +/** Flag requests that where possible a full duplex stream will not discard + overflowed input samples without calling the stream callback. This flag is + only valid for full duplex callback streams and only when used in combination + with the paFramesPerBufferUnspecified (0) framesPerBuffer parameter. Using + this flag incorrectly results in a paInvalidFlag error being returned from + Pa_OpenStream and Pa_OpenDefaultStream. + + @see PaStreamFlags, paFramesPerBufferUnspecified +*/ +#define paNeverDropInput ((PaStreamFlags) 0x00000004) + +/** Call the stream callback to fill initial output buffers, rather than the + default behavior of priming the buffers with zeros (silence). This flag has + no effect for input-only and blocking read/write streams. + + @see PaStreamFlags +*/ +#define paPrimeOutputBuffersUsingStreamCallback ((PaStreamFlags) 0x00000008) + +/** A mask specifying the platform specific bits. + @see PaStreamFlags +*/ +#define paPlatformSpecificFlags ((PaStreamFlags)0xFFFF0000) + +/** + Timing information for the buffers passed to the stream callback. + + Time values are expressed in seconds and are synchronised with the time base used by Pa_GetStreamTime() for the associated stream. + + @see PaStreamCallback, Pa_GetStreamTime +*/ +typedef struct PaStreamCallbackTimeInfo{ + PaTime inputBufferAdcTime; /**< The time when the first sample of the input buffer was captured at the ADC input */ + PaTime currentTime; /**< The time when the stream callback was invoked */ + PaTime outputBufferDacTime; /**< The time when the first sample of the output buffer will output the DAC */ +} PaStreamCallbackTimeInfo; + + +/** + Flag bit constants for the statusFlags to PaStreamCallback. + + @see paInputUnderflow, paInputOverflow, paOutputUnderflow, paOutputOverflow, + paPrimingOutput +*/ +typedef unsigned long PaStreamCallbackFlags; + +/** In a stream opened with paFramesPerBufferUnspecified, indicates that + input data is all silence (zeros) because no real data is available. In a + stream opened without paFramesPerBufferUnspecified, it indicates that one or + more zero samples have been inserted into the input buffer to compensate + for an input underflow. + @see PaStreamCallbackFlags +*/ +#define paInputUnderflow ((PaStreamCallbackFlags) 0x00000001) + +/** In a stream opened with paFramesPerBufferUnspecified, indicates that data + prior to the first sample of the input buffer was discarded due to an + overflow, possibly because the stream callback is using too much CPU time. + Otherwise indicates that data prior to one or more samples in the + input buffer was discarded. + @see PaStreamCallbackFlags +*/ +#define paInputOverflow ((PaStreamCallbackFlags) 0x00000002) + +/** Indicates that output data (or a gap) was inserted, possibly because the + stream callback is using too much CPU time. + @see PaStreamCallbackFlags +*/ +#define paOutputUnderflow ((PaStreamCallbackFlags) 0x00000004) + +/** Indicates that output data will be discarded because no room is available. + @see PaStreamCallbackFlags +*/ +#define paOutputOverflow ((PaStreamCallbackFlags) 0x00000008) + +/** Some of all of the output data will be used to prime the stream, input + data may be zero. + @see PaStreamCallbackFlags +*/ +#define paPrimingOutput ((PaStreamCallbackFlags) 0x00000010) + +/** + Allowable return values for the PaStreamCallback. + @see PaStreamCallback +*/ +typedef enum PaStreamCallbackResult +{ + paContinue=0, /**< Signal that the stream should continue invoking the callback and processing audio. */ + paComplete=1, /**< Signal that the stream should stop invoking the callback and finish once all output samples have played. */ + paAbort=2 /**< Signal that the stream should stop invoking the callback and finish as soon as possible. */ +} PaStreamCallbackResult; + + +/** + Functions of type PaStreamCallback are implemented by PortAudio clients. + They consume, process or generate audio in response to requests from an + active PortAudio stream. + + When a stream is running, PortAudio calls the stream callback periodically. + The callback function is responsible for processing buffers of audio samples + passed via the input and output parameters. + + The PortAudio stream callback runs at very high or real-time priority. + It is required to consistently meet its time deadlines. Do not allocate + memory, access the file system, call library functions or call other functions + from the stream callback that may block or take an unpredictable amount of + time to complete. + + In order for a stream to maintain glitch-free operation the callback + must consume and return audio data faster than it is recorded and/or + played. PortAudio anticipates that each callback invocation may execute for + a duration approaching the duration of frameCount audio frames at the stream + sample rate. It is reasonable to expect to be able to utilise 70% or more of + the available CPU time in the PortAudio callback. However, due to buffer size + adaption and other factors, not all host APIs are able to guarantee audio + stability under heavy CPU load with arbitrary fixed callback buffer sizes. + When high callback CPU utilisation is required the most robust behavior + can be achieved by using paFramesPerBufferUnspecified as the + Pa_OpenStream() framesPerBuffer parameter. + + @param input and @param output are either arrays of interleaved samples or; + if non-interleaved samples were requested using the paNonInterleaved sample + format flag, an array of buffer pointers, one non-interleaved buffer for + each channel. + + The format, packing and number of channels used by the buffers are + determined by parameters to Pa_OpenStream(). + + @param frameCount The number of sample frames to be processed by + the stream callback. + + @param timeInfo Timestamps indicating the ADC capture time of the first sample + in the input buffer, the DAC output time of the first sample in the output buffer + and the time the callback was invoked. + See PaStreamCallbackTimeInfo and Pa_GetStreamTime() + + @param statusFlags Flags indicating whether input and/or output buffers + have been inserted or will be dropped to overcome underflow or overflow + conditions. + + @param userData The value of a user supplied pointer passed to + Pa_OpenStream() intended for storing synthesis data etc. + + @return + The stream callback should return one of the values in the + ::PaStreamCallbackResult enumeration. To ensure that the callback continues + to be called, it should return paContinue (0). Either paComplete or paAbort + can be returned to finish stream processing, after either of these values is + returned the callback will not be called again. If paAbort is returned the + stream will finish as soon as possible. If paComplete is returned, the stream + will continue until all buffers generated by the callback have been played. + This may be useful in applications such as soundfile players where a specific + duration of output is required. However, it is not necessary to utilize this + mechanism as Pa_StopStream(), Pa_AbortStream() or Pa_CloseStream() can also + be used to stop the stream. The callback must always fill the entire output + buffer irrespective of its return value. + + @see Pa_OpenStream, Pa_OpenDefaultStream + + @note With the exception of Pa_GetStreamCpuLoad() it is not permissible to call + PortAudio API functions from within the stream callback. +*/ +typedef int PaStreamCallback( + const void *input, void *output, + unsigned long frameCount, + const PaStreamCallbackTimeInfo* timeInfo, + PaStreamCallbackFlags statusFlags, + void *userData ); + + +/** Opens a stream for either input, output or both. + + @param stream The address of a PaStream pointer which will receive + a pointer to the newly opened stream. + + @param inputParameters A structure that describes the input parameters used by + the opened stream. See PaStreamParameters for a description of these parameters. + inputParameters must be NULL for output-only streams. + + @param outputParameters A structure that describes the output parameters used by + the opened stream. See PaStreamParameters for a description of these parameters. + outputParameters must be NULL for input-only streams. + + @param sampleRate The desired sampleRate. For full-duplex streams it is the + sample rate for both input and output + + @param framesPerBuffer The number of frames passed to the stream callback + function, or the preferred block granularity for a blocking read/write stream. + The special value paFramesPerBufferUnspecified (0) may be used to request that + the stream callback will receive an optimal (and possibly varying) number of + frames based on host requirements and the requested latency settings. + Note: With some host APIs, the use of non-zero framesPerBuffer for a callback + stream may introduce an additional layer of buffering which could introduce + additional latency. PortAudio guarantees that the additional latency + will be kept to the theoretical minimum however, it is strongly recommended + that a non-zero framesPerBuffer value only be used when your algorithm + requires a fixed number of frames per stream callback. + + @param streamFlags Flags which modify the behavior of the streaming process. + This parameter may contain a combination of flags ORed together. Some flags may + only be relevant to certain buffer formats. + + @param streamCallback A pointer to a client supplied function that is responsible + for processing and filling input and output buffers. If this parameter is NULL + the stream will be opened in 'blocking read/write' mode. In blocking mode, + the client can receive sample data using Pa_ReadStream and write sample data + using Pa_WriteStream, the number of samples that may be read or written + without blocking is returned by Pa_GetStreamReadAvailable and + Pa_GetStreamWriteAvailable respectively. + + @param userData A client supplied pointer which is passed to the stream callback + function. It could for example, contain a pointer to instance data necessary + for processing the audio buffers. This parameter is ignored if streamCallback + is NULL. + + @return + Upon success Pa_OpenStream() returns paNoError and places a pointer to a + valid PaStream in the stream argument. The stream is inactive (stopped). + If a call to Pa_OpenStream() fails, a non-zero error code is returned (see + PaError for possible error codes) and the value of stream is invalid. + + @see PaStreamParameters, PaStreamCallback, Pa_ReadStream, Pa_WriteStream, + Pa_GetStreamReadAvailable, Pa_GetStreamWriteAvailable +*/ +PaError Pa_OpenStream( PaStream** stream, + const PaStreamParameters *inputParameters, + const PaStreamParameters *outputParameters, + double sampleRate, + unsigned long framesPerBuffer, + PaStreamFlags streamFlags, + PaStreamCallback *streamCallback, + void *userData ); + + +/** A simplified version of Pa_OpenStream() that opens the default input + and/or output devices. + + @param stream The address of a PaStream pointer which will receive + a pointer to the newly opened stream. + + @param numInputChannels The number of channels of sound that will be supplied + to the stream callback or returned by Pa_ReadStream. It can range from 1 to + the value of maxInputChannels in the PaDeviceInfo record for the default input + device. If 0 the stream is opened as an output-only stream. + + @param numOutputChannels The number of channels of sound to be delivered to the + stream callback or passed to Pa_WriteStream. It can range from 1 to the value + of maxOutputChannels in the PaDeviceInfo record for the default output device. + If 0 the stream is opened as an output-only stream. + + @param sampleFormat The sample format of both the input and output buffers + provided to the callback or passed to and from Pa_ReadStream and Pa_WriteStream. + sampleFormat may be any of the formats described by the PaSampleFormat + enumeration. + + @param sampleRate Same as Pa_OpenStream parameter of the same name. + @param framesPerBuffer Same as Pa_OpenStream parameter of the same name. + @param streamCallback Same as Pa_OpenStream parameter of the same name. + @param userData Same as Pa_OpenStream parameter of the same name. + + @return As for Pa_OpenStream + + @see Pa_OpenStream, PaStreamCallback +*/ +PaError Pa_OpenDefaultStream( PaStream** stream, + int numInputChannels, + int numOutputChannels, + PaSampleFormat sampleFormat, + double sampleRate, + unsigned long framesPerBuffer, + PaStreamCallback *streamCallback, + void *userData ); + + +/** Closes an audio stream. If the audio stream is active it + discards any pending buffers as if Pa_AbortStream() had been called. +*/ +PaError Pa_CloseStream( PaStream *stream ); + + +/** Functions of type PaStreamFinishedCallback are implemented by PortAudio + clients. They can be registered with a stream using the Pa_SetStreamFinishedCallback + function. Once registered they are called when the stream becomes inactive + (ie once a call to Pa_StopStream() will not block). + A stream will become inactive after the stream callback returns non-zero, + or when Pa_StopStream or Pa_AbortStream is called. For a stream providing audio + output, if the stream callback returns paComplete, or Pa_StopStream() is called, + the stream finished callback will not be called until all generated sample data + has been played. + + @param userData The userData parameter supplied to Pa_OpenStream() + + @see Pa_SetStreamFinishedCallback +*/ +typedef void PaStreamFinishedCallback( void *userData ); + + +/** Register a stream finished callback function which will be called when the + stream becomes inactive. See the description of PaStreamFinishedCallback for + further details about when the callback will be called. + + @param stream a pointer to a PaStream that is in the stopped state - if the + stream is not stopped, the stream's finished callback will remain unchanged + and an error code will be returned. + + @param streamFinishedCallback a pointer to a function with the same signature + as PaStreamFinishedCallback, that will be called when the stream becomes + inactive. Passing NULL for this parameter will un-register a previously + registered stream finished callback function. + + @return on success returns paNoError, otherwise an error code indicating the cause + of the error. + + @see PaStreamFinishedCallback +*/ +PaError Pa_SetStreamFinishedCallback( PaStream *stream, PaStreamFinishedCallback* streamFinishedCallback ); + + +/** Commences audio processing. +*/ +PaError Pa_StartStream( PaStream *stream ); + + +/** Terminates audio processing. It waits until all pending + audio buffers have been played before it returns. +*/ +PaError Pa_StopStream( PaStream *stream ); + + +/** Terminates audio processing immediately without waiting for pending + buffers to complete. +*/ +PaError Pa_AbortStream( PaStream *stream ); + + +/** Determine whether the stream is stopped. + A stream is considered to be stopped prior to a successful call to + Pa_StartStream and after a successful call to Pa_StopStream or Pa_AbortStream. + If a stream callback returns a value other than paContinue the stream is NOT + considered to be stopped. + + @return Returns one (1) when the stream is stopped, zero (0) when + the stream is running or, a PaErrorCode (which are always negative) if + PortAudio is not initialized or an error is encountered. + + @see Pa_StopStream, Pa_AbortStream, Pa_IsStreamActive +*/ +PaError Pa_IsStreamStopped( PaStream *stream ); + + +/** Determine whether the stream is active. + A stream is active after a successful call to Pa_StartStream(), until it + becomes inactive either as a result of a call to Pa_StopStream() or + Pa_AbortStream(), or as a result of a return value other than paContinue from + the stream callback. In the latter case, the stream is considered inactive + after the last buffer has finished playing. + + @return Returns one (1) when the stream is active (ie playing or recording + audio), zero (0) when not playing or, a PaErrorCode (which are always negative) + if PortAudio is not initialized or an error is encountered. + + @see Pa_StopStream, Pa_AbortStream, Pa_IsStreamStopped +*/ +PaError Pa_IsStreamActive( PaStream *stream ); + + + +/** A structure containing unchanging information about an open stream. + @see Pa_GetStreamInfo +*/ + +typedef struct PaStreamInfo +{ + /** this is struct version 1 */ + int structVersion; + + /** The input latency of the stream in seconds. This value provides the most + accurate estimate of input latency available to the implementation. It may + differ significantly from the suggestedLatency value passed to Pa_OpenStream(). + The value of this field will be zero (0.) for output-only streams. + @see PaTime + */ + PaTime inputLatency; + + /** The output latency of the stream in seconds. This value provides the most + accurate estimate of output latency available to the implementation. It may + differ significantly from the suggestedLatency value passed to Pa_OpenStream(). + The value of this field will be zero (0.) for input-only streams. + @see PaTime + */ + PaTime outputLatency; + + /** The sample rate of the stream in Hertz (samples per second). In cases + where the hardware sample rate is inaccurate and PortAudio is aware of it, + the value of this field may be different from the sampleRate parameter + passed to Pa_OpenStream(). If information about the actual hardware sample + rate is not available, this field will have the same value as the sampleRate + parameter passed to Pa_OpenStream(). + */ + double sampleRate; + +} PaStreamInfo; + + +/** Retrieve a pointer to a PaStreamInfo structure containing information + about the specified stream. + @return A pointer to an immutable PaStreamInfo structure. If the stream + parameter is invalid, or an error is encountered, the function returns NULL. + + @param stream A pointer to an open stream previously created with Pa_OpenStream. + + @note PortAudio manages the memory referenced by the returned pointer, + the client must not manipulate or free the memory. The pointer is only + guaranteed to be valid until the specified stream is closed. + + @see PaStreamInfo +*/ +const PaStreamInfo* Pa_GetStreamInfo( PaStream *stream ); + + +/** Returns the current time in seconds for a stream according to the same clock used + to generate callback PaStreamCallbackTimeInfo timestamps. The time values are + monotonically increasing and have unspecified origin. + + Pa_GetStreamTime returns valid time values for the entire life of the stream, + from when the stream is opened until it is closed. Starting and stopping the stream + does not affect the passage of time returned by Pa_GetStreamTime. + + This time may be used for synchronizing other events to the audio stream, for + example synchronizing audio to MIDI. + + @return The stream's current time in seconds, or 0 if an error occurred. + + @see PaTime, PaStreamCallback, PaStreamCallbackTimeInfo +*/ +PaTime Pa_GetStreamTime( PaStream *stream ); + + +/** Retrieve CPU usage information for the specified stream. + The "CPU Load" is a fraction of total CPU time consumed by a callback stream's + audio processing routines including, but not limited to the client supplied + stream callback. This function does not work with blocking read/write streams. + + This function may be called from the stream callback function or the + application. + + @return + A floating point value, typically between 0.0 and 1.0, where 1.0 indicates + that the stream callback is consuming the maximum number of CPU cycles possible + to maintain real-time operation. A value of 0.5 would imply that PortAudio and + the stream callback was consuming roughly 50% of the available CPU time. The + return value may exceed 1.0. A value of 0.0 will always be returned for a + blocking read/write stream, or if an error occurs. +*/ +double Pa_GetStreamCpuLoad( PaStream* stream ); + + +/** Read samples from an input stream. The function doesn't return until + the entire buffer has been filled - this may involve waiting for the operating + system to supply the data. + + @param stream A pointer to an open stream previously created with Pa_OpenStream. + + @param buffer A pointer to a buffer of sample frames. The buffer contains + samples in the format specified by the inputParameters->sampleFormat field + used to open the stream, and the number of channels specified by + inputParameters->numChannels. If non-interleaved samples were requested using + the paNonInterleaved sample format flag, buffer is a pointer to the first element + of an array of buffer pointers, one non-interleaved buffer for each channel. + + @param frames The number of frames to be read into buffer. This parameter + is not constrained to a specific range, however high performance applications + will want to match this parameter to the framesPerBuffer parameter used + when opening the stream. + + @return On success PaNoError will be returned, or PaInputOverflowed if input + data was discarded by PortAudio after the previous call and before this call. +*/ +PaError Pa_ReadStream( PaStream* stream, + void *buffer, + unsigned long frames ); + + +/** Write samples to an output stream. This function doesn't return until the + entire buffer has been written - this may involve waiting for the operating + system to consume the data. + + @param stream A pointer to an open stream previously created with Pa_OpenStream. + + @param buffer A pointer to a buffer of sample frames. The buffer contains + samples in the format specified by the outputParameters->sampleFormat field + used to open the stream, and the number of channels specified by + outputParameters->numChannels. If non-interleaved samples were requested using + the paNonInterleaved sample format flag, buffer is a pointer to the first element + of an array of buffer pointers, one non-interleaved buffer for each channel. + + @param frames The number of frames to be written from buffer. This parameter + is not constrained to a specific range, however high performance applications + will want to match this parameter to the framesPerBuffer parameter used + when opening the stream. + + @return On success PaNoError will be returned, or paOutputUnderflowed if + additional output data was inserted after the previous call and before this + call. +*/ +PaError Pa_WriteStream( PaStream* stream, + const void *buffer, + unsigned long frames ); + + +/** Retrieve the number of frames that can be read from the stream without + waiting. + + @return Returns a non-negative value representing the maximum number of frames + that can be read from the stream without blocking or busy waiting or, a + PaErrorCode (which are always negative) if PortAudio is not initialized or an + error is encountered. +*/ +signed long Pa_GetStreamReadAvailable( PaStream* stream ); + + +/** Retrieve the number of frames that can be written to the stream without + waiting. + + @return Returns a non-negative value representing the maximum number of frames + that can be written to the stream without blocking or busy waiting or, a + PaErrorCode (which are always negative) if PortAudio is not initialized or an + error is encountered. +*/ +signed long Pa_GetStreamWriteAvailable( PaStream* stream ); + + +/* Miscellaneous utilities */ + + +/** Retrieve the size of a given sample format in bytes. + + @return The size in bytes of a single sample in the specified format, + or paSampleFormatNotSupported if the format is not supported. +*/ +PaError Pa_GetSampleSize( PaSampleFormat format ); + + +/** Put the caller to sleep for at least 'msec' milliseconds. This function is + provided only as a convenience for authors of portable code (such as the tests + and examples in the PortAudio distribution.) + + The function may sleep longer than requested so don't rely on this for accurate + musical timing. +*/ +void Pa_Sleep( long msec ); + + + +#ifdef __cplusplus +} +#endif /* __cplusplus */ +#endif /* PORTAUDIO_H */ diff --git a/libkmaudio/portaudio_x86.lib b/libkmaudio/portaudio_x86.lib new file mode 100644 index 0000000..df382b8 Binary files /dev/null and b/libkmaudio/portaudio_x86.lib differ diff --git a/libkmaudio/soundio.h b/libkmaudio/soundio.h new file mode 100644 index 0000000..17a7d06 --- /dev/null +++ b/libkmaudio/soundio.h @@ -0,0 +1,1209 @@ +/* + * Copyright (c) 2015 Andrew Kelley + * + * This file is part of libsoundio, which is MIT licensed. + * See http://opensource.org/licenses/MIT + */ + +#ifndef SOUNDIO_SOUNDIO_H +#define SOUNDIO_SOUNDIO_H + +#include "endian.h" +#include + +/// \cond +#ifdef __cplusplus +#define SOUNDIO_EXTERN_C extern "C" +#else +#define SOUNDIO_EXTERN_C +#endif + +#if defined(SOUNDIO_STATIC_LIBRARY) +# define SOUNDIO_EXPORT SOUNDIO_EXTERN_C +#else +# if defined(_WIN32) +# if defined(SOUNDIO_BUILDING_LIBRARY) +# define SOUNDIO_EXPORT SOUNDIO_EXTERN_C __declspec(dllexport) +# else +# define SOUNDIO_EXPORT SOUNDIO_EXTERN_C __declspec(dllimport) +# endif +# else +# define SOUNDIO_EXPORT SOUNDIO_EXTERN_C __attribute__((visibility ("default"))) +# endif +#endif +/// \endcond + +/** \mainpage + * + * \section intro_sec Overview + * + * libsoundio is a C library for cross-platform audio input and output. It is + * suitable for real-time and consumer software. + * + * Documentation: soundio.h + */ + + +/** \example sio_list_devices.c + * List the available input and output devices on the system and their + * properties. Supports watching for changes and specifying backend to use. + */ + +/** \example sio_sine.c + * Play a sine wave over the default output device. + * Supports specifying device and backend to use. + */ + +/** \example sio_record.c + * Record audio to an output file. + * Supports specifying device and backend to use. + */ + +/** \example sio_microphone.c + * Stream the default input device over the default output device. + * Supports specifying device and backend to use. + */ + +/** \example backend_disconnect_recover.c + * Demonstrates recovering from a backend disconnecting. + */ + +/// See also ::soundio_strerror +enum SoundIoError { + SoundIoErrorNone, + /// Out of memory. + SoundIoErrorNoMem, + /// The backend does not appear to be active or running. + SoundIoErrorInitAudioBackend, + /// A system resource other than memory was not available. + SoundIoErrorSystemResources, + /// Attempted to open a device and failed. + SoundIoErrorOpeningDevice, + SoundIoErrorNoSuchDevice, + /// The programmer did not comply with the API. + SoundIoErrorInvalid, + /// libsoundio was compiled without support for that backend. + SoundIoErrorBackendUnavailable, + /// An open stream had an error that can only be recovered from by + /// destroying the stream and creating it again. + SoundIoErrorStreaming, + /// Attempted to use a device with parameters it cannot support. + SoundIoErrorIncompatibleDevice, + /// When JACK returns `JackNoSuchClient` + SoundIoErrorNoSuchClient, + /// Attempted to use parameters that the backend cannot support. + SoundIoErrorIncompatibleBackend, + /// Backend server shutdown or became inactive. + SoundIoErrorBackendDisconnected, + SoundIoErrorInterrupted, + /// Buffer underrun occurred. + SoundIoErrorUnderflow, + /// Unable to convert to or from UTF-8 to the native string format. + SoundIoErrorEncodingString, +}; + +/// Specifies where a channel is physically located. +enum SoundIoChannelId { + SoundIoChannelIdInvalid, + + SoundIoChannelIdFrontLeft, ///< First of the more commonly supported ids. + SoundIoChannelIdFrontRight, + SoundIoChannelIdFrontCenter, + SoundIoChannelIdLfe, + SoundIoChannelIdBackLeft, + SoundIoChannelIdBackRight, + SoundIoChannelIdFrontLeftCenter, + SoundIoChannelIdFrontRightCenter, + SoundIoChannelIdBackCenter, + SoundIoChannelIdSideLeft, + SoundIoChannelIdSideRight, + SoundIoChannelIdTopCenter, + SoundIoChannelIdTopFrontLeft, + SoundIoChannelIdTopFrontCenter, + SoundIoChannelIdTopFrontRight, + SoundIoChannelIdTopBackLeft, + SoundIoChannelIdTopBackCenter, + SoundIoChannelIdTopBackRight, ///< Last of the more commonly supported ids. + + SoundIoChannelIdBackLeftCenter, ///< First of the less commonly supported ids. + SoundIoChannelIdBackRightCenter, + SoundIoChannelIdFrontLeftWide, + SoundIoChannelIdFrontRightWide, + SoundIoChannelIdFrontLeftHigh, + SoundIoChannelIdFrontCenterHigh, + SoundIoChannelIdFrontRightHigh, + SoundIoChannelIdTopFrontLeftCenter, + SoundIoChannelIdTopFrontRightCenter, + SoundIoChannelIdTopSideLeft, + SoundIoChannelIdTopSideRight, + SoundIoChannelIdLeftLfe, + SoundIoChannelIdRightLfe, + SoundIoChannelIdLfe2, + SoundIoChannelIdBottomCenter, + SoundIoChannelIdBottomLeftCenter, + SoundIoChannelIdBottomRightCenter, + + /// Mid/side recording + SoundIoChannelIdMsMid, + SoundIoChannelIdMsSide, + + /// first order ambisonic channels + SoundIoChannelIdAmbisonicW, + SoundIoChannelIdAmbisonicX, + SoundIoChannelIdAmbisonicY, + SoundIoChannelIdAmbisonicZ, + + /// X-Y Recording + SoundIoChannelIdXyX, + SoundIoChannelIdXyY, + + SoundIoChannelIdHeadphonesLeft, ///< First of the "other" channel ids + SoundIoChannelIdHeadphonesRight, + SoundIoChannelIdClickTrack, + SoundIoChannelIdForeignLanguage, + SoundIoChannelIdHearingImpaired, + SoundIoChannelIdNarration, + SoundIoChannelIdHaptic, + SoundIoChannelIdDialogCentricMix, ///< Last of the "other" channel ids + + SoundIoChannelIdAux, + SoundIoChannelIdAux0, + SoundIoChannelIdAux1, + SoundIoChannelIdAux2, + SoundIoChannelIdAux3, + SoundIoChannelIdAux4, + SoundIoChannelIdAux5, + SoundIoChannelIdAux6, + SoundIoChannelIdAux7, + SoundIoChannelIdAux8, + SoundIoChannelIdAux9, + SoundIoChannelIdAux10, + SoundIoChannelIdAux11, + SoundIoChannelIdAux12, + SoundIoChannelIdAux13, + SoundIoChannelIdAux14, + SoundIoChannelIdAux15, +}; + +/// Built-in channel layouts for convenience. +enum SoundIoChannelLayoutId { + SoundIoChannelLayoutIdMono, + SoundIoChannelLayoutIdStereo, + SoundIoChannelLayoutId2Point1, + SoundIoChannelLayoutId3Point0, + SoundIoChannelLayoutId3Point0Back, + SoundIoChannelLayoutId3Point1, + SoundIoChannelLayoutId4Point0, + SoundIoChannelLayoutIdQuad, + SoundIoChannelLayoutIdQuadSide, + SoundIoChannelLayoutId4Point1, + SoundIoChannelLayoutId5Point0Back, + SoundIoChannelLayoutId5Point0Side, + SoundIoChannelLayoutId5Point1, + SoundIoChannelLayoutId5Point1Back, + SoundIoChannelLayoutId6Point0Side, + SoundIoChannelLayoutId6Point0Front, + SoundIoChannelLayoutIdHexagonal, + SoundIoChannelLayoutId6Point1, + SoundIoChannelLayoutId6Point1Back, + SoundIoChannelLayoutId6Point1Front, + SoundIoChannelLayoutId7Point0, + SoundIoChannelLayoutId7Point0Front, + SoundIoChannelLayoutId7Point1, + SoundIoChannelLayoutId7Point1Wide, + SoundIoChannelLayoutId7Point1WideBack, + SoundIoChannelLayoutIdOctagonal, +}; + +enum SoundIoBackend { + SoundIoBackendNone, + SoundIoBackendJack, + SoundIoBackendPulseAudio, + SoundIoBackendAlsa, + SoundIoBackendCoreAudio, + SoundIoBackendWasapi, + SoundIoBackendDummy, +}; + +enum SoundIoDeviceAim { + SoundIoDeviceAimInput, ///< capture / recording + SoundIoDeviceAimOutput, ///< playback +}; + +/// For your convenience, Native Endian and Foreign Endian constants are defined +/// which point to the respective SoundIoFormat values. +enum SoundIoFormat { + SoundIoFormatInvalid, + SoundIoFormatS8, ///< Signed 8 bit + SoundIoFormatU8, ///< Unsigned 8 bit + SoundIoFormatS16LE, ///< Signed 16 bit Little Endian + SoundIoFormatS16BE, ///< Signed 16 bit Big Endian + SoundIoFormatU16LE, ///< Unsigned 16 bit Little Endian + SoundIoFormatU16BE, ///< Unsigned 16 bit Big Endian + SoundIoFormatS24LE, ///< Signed 24 bit Little Endian using low three bytes in 32-bit word + SoundIoFormatS24BE, ///< Signed 24 bit Big Endian using low three bytes in 32-bit word + SoundIoFormatU24LE, ///< Unsigned 24 bit Little Endian using low three bytes in 32-bit word + SoundIoFormatU24BE, ///< Unsigned 24 bit Big Endian using low three bytes in 32-bit word + SoundIoFormatS32LE, ///< Signed 32 bit Little Endian + SoundIoFormatS32BE, ///< Signed 32 bit Big Endian + SoundIoFormatU32LE, ///< Unsigned 32 bit Little Endian + SoundIoFormatU32BE, ///< Unsigned 32 bit Big Endian + SoundIoFormatFloat32LE, ///< Float 32 bit Little Endian, Range -1.0 to 1.0 + SoundIoFormatFloat32BE, ///< Float 32 bit Big Endian, Range -1.0 to 1.0 + SoundIoFormatFloat64LE, ///< Float 64 bit Little Endian, Range -1.0 to 1.0 + SoundIoFormatFloat64BE, ///< Float 64 bit Big Endian, Range -1.0 to 1.0 +}; + +#if defined(SOUNDIO_OS_BIG_ENDIAN) +#define SoundIoFormatS16NE SoundIoFormatS16BE +#define SoundIoFormatU16NE SoundIoFormatU16BE +#define SoundIoFormatS24NE SoundIoFormatS24BE +#define SoundIoFormatU24NE SoundIoFormatU24BE +#define SoundIoFormatS32NE SoundIoFormatS32BE +#define SoundIoFormatU32NE SoundIoFormatU32BE +#define SoundIoFormatFloat32NE SoundIoFormatFloat32BE +#define SoundIoFormatFloat64NE SoundIoFormatFloat64BE + +#define SoundIoFormatS16FE SoundIoFormatS16LE +#define SoundIoFormatU16FE SoundIoFormatU16LE +#define SoundIoFormatS24FE SoundIoFormatS24LE +#define SoundIoFormatU24FE SoundIoFormatU24LE +#define SoundIoFormatS32FE SoundIoFormatS32LE +#define SoundIoFormatU32FE SoundIoFormatU32LE +#define SoundIoFormatFloat32FE SoundIoFormatFloat32LE +#define SoundIoFormatFloat64FE SoundIoFormatFloat64LE + +#elif defined(SOUNDIO_OS_LITTLE_ENDIAN) + +/// Note that we build the documentation in Little Endian mode, +/// so all the "NE" macros in the docs point to "LE" and +/// "FE" macros point to "BE". On a Big Endian system it is the +/// other way around. +#define SoundIoFormatS16NE SoundIoFormatS16LE +#define SoundIoFormatU16NE SoundIoFormatU16LE +#define SoundIoFormatS24NE SoundIoFormatS24LE +#define SoundIoFormatU24NE SoundIoFormatU24LE +#define SoundIoFormatS32NE SoundIoFormatS32LE +#define SoundIoFormatU32NE SoundIoFormatU32LE +#define SoundIoFormatFloat32NE SoundIoFormatFloat32LE +#define SoundIoFormatFloat64NE SoundIoFormatFloat64LE + +#define SoundIoFormatS16FE SoundIoFormatS16BE +#define SoundIoFormatU16FE SoundIoFormatU16BE +#define SoundIoFormatS24FE SoundIoFormatS24BE +#define SoundIoFormatU24FE SoundIoFormatU24BE +#define SoundIoFormatS32FE SoundIoFormatS32BE +#define SoundIoFormatU32FE SoundIoFormatU32BE +#define SoundIoFormatFloat32FE SoundIoFormatFloat32BE +#define SoundIoFormatFloat64FE SoundIoFormatFloat64BE + +#else +//#error "unknown byte order" +#endif + +#define SOUNDIO_MAX_CHANNELS 24 +/// The size of this struct is OK to use. +struct SoundIoChannelLayout { + const char *name; + int channel_count; + enum SoundIoChannelId channels[SOUNDIO_MAX_CHANNELS]; +}; + +/// The size of this struct is OK to use. +struct SoundIoSampleRateRange { + int min; + int max; +}; + +/// The size of this struct is OK to use. +struct SoundIoChannelArea { + /// Base address of buffer. + char *ptr; + /// How many bytes it takes to get from the beginning of one sample to + /// the beginning of the next sample. + int step; +}; + +/// The size of this struct is not part of the API or ABI. +struct SoundIo { + /// Optional. Put whatever you want here. Defaults to NULL. + void *userdata; + /// Optional callback. Called when the list of devices change. Only called + /// during a call to ::soundio_flush_events or ::soundio_wait_events. + void (*on_devices_change)(struct SoundIo *); + /// Optional callback. Called when the backend disconnects. For example, + /// when the JACK server shuts down. When this happens, listing devices + /// and opening streams will always fail with + /// SoundIoErrorBackendDisconnected. This callback is only called during a + /// call to ::soundio_flush_events or ::soundio_wait_events. + /// If you do not supply a callback, the default will crash your program + /// with an error message. This callback is also called when the thread + /// that retrieves device information runs into an unrecoverable condition + /// such as running out of memory. + /// + /// Possible errors: + /// * #SoundIoErrorBackendDisconnected + /// * #SoundIoErrorNoMem + /// * #SoundIoErrorSystemResources + /// * #SoundIoErrorOpeningDevice - unexpected problem accessing device + /// information + void (*on_backend_disconnect)(struct SoundIo *, int err); + /// Optional callback. Called from an unknown thread that you should not use + /// to call any soundio functions. You may use this to signal a condition + /// variable to wake up. Called when ::soundio_wait_events would be woken up. + void (*on_events_signal)(struct SoundIo *); + + /// Read-only. After calling ::soundio_connect or ::soundio_connect_backend, + /// this field tells which backend is currently connected. + enum SoundIoBackend current_backend; + + /// Optional: Application name. + /// PulseAudio uses this for "application name". + /// JACK uses this for `client_name`. + /// Must not contain a colon (":"). + const char *app_name; + + /// Optional: Real time priority warning. + /// This callback is fired when making thread real-time priority failed. By + /// default, it will print to stderr only the first time it is called + /// a message instructing the user how to configure their system to allow + /// real-time priority threads. This must be set to a function not NULL. + /// To silence the warning, assign this to a function that does nothing. + void (*emit_rtprio_warning)(void); + + /// Optional: JACK info callback. + /// By default, libsoundio sets this to an empty function in order to + /// silence stdio messages from JACK. You may override the behavior by + /// setting this to `NULL` or providing your own function. This is + /// registered with JACK regardless of whether ::soundio_connect_backend + /// succeeds. + void (*jack_info_callback)(const char *msg); + /// Optional: JACK error callback. + /// See SoundIo::jack_info_callback + void (*jack_error_callback)(const char *msg); +}; + +/// The size of this struct is not part of the API or ABI. +struct SoundIoDevice { + /// Read-only. Set automatically. + struct SoundIo *soundio; + + /// A string of bytes that uniquely identifies this device. + /// If the same physical device supports both input and output, that makes + /// one SoundIoDevice for the input and one SoundIoDevice for the output. + /// In this case, the id of each SoundIoDevice will be the same, and + /// SoundIoDevice::aim will be different. Additionally, if the device + /// supports raw mode, there may be up to four devices with the same id: + /// one for each value of SoundIoDevice::is_raw and one for each value of + /// SoundIoDevice::aim. + char *id; + /// User-friendly UTF-8 encoded text to describe the device. + char *name; + + /// Tells whether this device is an input device or an output device. + enum SoundIoDeviceAim aim; + + /// Channel layouts are handled similarly to SoundIoDevice::formats. + /// If this information is missing due to a SoundIoDevice::probe_error, + /// layouts will be NULL. It's OK to modify this data, for example calling + /// ::soundio_sort_channel_layouts on it. + /// Devices are guaranteed to have at least 1 channel layout. + struct SoundIoChannelLayout *layouts; + int layout_count; + /// See SoundIoDevice::current_format + struct SoundIoChannelLayout current_layout; + + /// List of formats this device supports. See also + /// SoundIoDevice::current_format. + enum SoundIoFormat *formats; + /// How many formats are available in SoundIoDevice::formats. + int format_count; + /// A device is either a raw device or it is a virtual device that is + /// provided by a software mixing service such as dmix or PulseAudio (see + /// SoundIoDevice::is_raw). If it is a raw device, + /// current_format is meaningless; + /// the device has no current format until you open it. On the other hand, + /// if it is a virtual device, current_format describes the + /// destination sample format that your audio will be converted to. Or, + /// if you're the lucky first application to open the device, you might + /// cause the current_format to change to your format. + /// Generally, you want to ignore current_format and use + /// whatever format is most convenient + /// for you which is supported by the device, because when you are the only + /// application left, the mixer might decide to switch + /// current_format to yours. You can learn the supported formats via + /// formats and SoundIoDevice::format_count. If this information is missing + /// due to a probe error, formats will be `NULL`. If current_format is + /// unavailable, it will be set to #SoundIoFormatInvalid. + /// Devices are guaranteed to have at least 1 format available. + enum SoundIoFormat current_format; + + /// Sample rate is the number of frames per second. + /// Sample rate is handled very similar to SoundIoDevice::formats. + /// If sample rate information is missing due to a probe error, the field + /// will be set to NULL. + /// Devices which have SoundIoDevice::probe_error set to #SoundIoErrorNone are + /// guaranteed to have at least 1 sample rate available. + struct SoundIoSampleRateRange *sample_rates; + /// How many sample rate ranges are available in + /// SoundIoDevice::sample_rates. 0 if sample rate information is missing + /// due to a probe error. + int sample_rate_count; + /// See SoundIoDevice::current_format + /// 0 if sample rate information is missing due to a probe error. + int sample_rate_current; + + /// Software latency minimum in seconds. If this value is unknown or + /// irrelevant, it is set to 0.0. + /// For PulseAudio and WASAPI this value is unknown until you open a + /// stream. + double software_latency_min; + /// Software latency maximum in seconds. If this value is unknown or + /// irrelevant, it is set to 0.0. + /// For PulseAudio and WASAPI this value is unknown until you open a + /// stream. + double software_latency_max; + /// Software latency in seconds. If this value is unknown or + /// irrelevant, it is set to 0.0. + /// For PulseAudio and WASAPI this value is unknown until you open a + /// stream. + /// See SoundIoDevice::current_format + double software_latency_current; + + /// Raw means that you are directly opening the hardware device and not + /// going through a proxy such as dmix, PulseAudio, or JACK. When you open a + /// raw device, other applications on the computer are not able to + /// simultaneously access the device. Raw devices do not perform automatic + /// resampling and thus tend to have fewer formats available. + bool is_raw; + + /// Devices are reference counted. See ::soundio_device_ref and + /// ::soundio_device_unref. + int ref_count; + + /// This is set to a SoundIoError representing the result of the device + /// probe. Ideally this will be SoundIoErrorNone in which case all the + /// fields of the device will be populated. If there is an error code here + /// then information about formats, sample rates, and channel layouts might + /// be missing. + /// + /// Possible errors: + /// * #SoundIoErrorOpeningDevice + /// * #SoundIoErrorNoMem + int probe_error; +}; + +/// The size of this struct is not part of the API or ABI. +struct SoundIoOutStream { + /// Populated automatically when you call ::soundio_outstream_create. + struct SoundIoDevice *device; + + /// Defaults to #SoundIoFormatFloat32NE, followed by the first one + /// supported. + enum SoundIoFormat format; + + /// Sample rate is the number of frames per second. + /// Defaults to 48000 (and then clamped into range). + int sample_rate; + + /// Defaults to Stereo, if available, followed by the first layout + /// supported. + struct SoundIoChannelLayout layout; + + /// Ignoring hardware latency, this is the number of seconds it takes for + /// the last sample in a full buffer to be played. + /// After you call ::soundio_outstream_open, this value is replaced with the + /// actual software latency, as near to this value as possible. + /// On systems that support clearing the buffer, this defaults to a large + /// latency, potentially upwards of 2 seconds, with the understanding that + /// you will call ::soundio_outstream_clear_buffer when you want to reduce + /// the latency to 0. On systems that do not support clearing the buffer, + /// this defaults to a reasonable lower latency value. + /// + /// On backends with high latencies (such as 2 seconds), `frame_count_min` + /// will be 0, meaning you don't have to fill the entire buffer. In this + /// case, the large buffer is there if you want it; you only have to fill + /// as much as you want. On backends like JACK, `frame_count_min` will be + /// equal to `frame_count_max` and if you don't fill that many frames, you + /// will get glitches. + /// + /// If the device has unknown software latency min and max values, you may + /// still set this, but you might not get the value you requested. + /// For PulseAudio, if you set this value to non-default, it sets + /// `PA_STREAM_ADJUST_LATENCY` and is the value used for `maxlength` and + /// `tlength`. + /// + /// For JACK, this value is always equal to + /// SoundIoDevice::software_latency_current of the device. + double software_latency; + /// Core Audio and WASAPI only: current output Audio Unit volume. Float, 0.0-1.0. + float volume; + /// Defaults to NULL. Put whatever you want here. + void *userdata; + /// In this callback, you call ::soundio_outstream_begin_write and + /// ::soundio_outstream_end_write as many times as necessary to write + /// at minimum `frame_count_min` frames and at maximum `frame_count_max` + /// frames. `frame_count_max` will always be greater than 0. Note that you + /// should write as many frames as you can; `frame_count_min` might be 0 and + /// you can still get a buffer underflow if you always write + /// `frame_count_min` frames. + /// + /// For Dummy, ALSA, and PulseAudio, `frame_count_min` will be 0. For JACK + /// and CoreAudio `frame_count_min` will be equal to `frame_count_max`. + /// + /// The code in the supplied function must be suitable for real-time + /// execution. That means that it cannot call functions that might block + /// for a long time. This includes all I/O functions (disk, TTY, network), + /// malloc, free, printf, pthread_mutex_lock, sleep, wait, poll, select, + /// pthread_join, pthread_cond_wait, etc. + void (*write_callback)(struct SoundIoOutStream *, + int frame_count_min, int frame_count_max); + /// This optional callback happens when the sound device runs out of + /// buffered audio data to play. After this occurs, the outstream waits + /// until the buffer is full to resume playback. + /// This is called from the SoundIoOutStream::write_callback thread context. + void (*underflow_callback)(struct SoundIoOutStream *); + /// Optional callback. `err` is always SoundIoErrorStreaming. + /// SoundIoErrorStreaming is an unrecoverable error. The stream is in an + /// invalid state and must be destroyed. + /// If you do not supply error_callback, the default callback will print + /// a message to stderr and then call `abort`. + /// This is called from the SoundIoOutStream::write_callback thread context. + void (*error_callback)(struct SoundIoOutStream *, int err); + + /// Optional: Name of the stream. Defaults to "SoundIoOutStream" + /// PulseAudio uses this for the stream name. + /// JACK uses this for the client name of the client that connects when you + /// open the stream. + /// WASAPI uses this for the session display name. + /// Must not contain a colon (":"). + const char *name; + + /// Optional: Hint that this output stream is nonterminal. This is used by + /// JACK and it means that the output stream data originates from an input + /// stream. Defaults to `false`. + bool non_terminal_hint; + + + /// computed automatically when you call ::soundio_outstream_open + int bytes_per_frame; + /// computed automatically when you call ::soundio_outstream_open + int bytes_per_sample; + + /// If setting the channel layout fails for some reason, this field is set + /// to an error code. Possible error codes are: + /// * #SoundIoErrorIncompatibleDevice + int layout_error; +}; + +/// The size of this struct is not part of the API or ABI. +struct SoundIoInStream { + /// Populated automatically when you call ::soundio_outstream_create. + struct SoundIoDevice *device; + + /// Defaults to #SoundIoFormatFloat32NE, followed by the first one + /// supported. + enum SoundIoFormat format; + + /// Sample rate is the number of frames per second. + /// Defaults to max(sample_rate_min, min(sample_rate_max, 48000)) + int sample_rate; + + /// Defaults to Stereo, if available, followed by the first layout + /// supported. + struct SoundIoChannelLayout layout; + + /// Ignoring hardware latency, this is the number of seconds it takes for a + /// captured sample to become available for reading. + /// After you call ::soundio_instream_open, this value is replaced with the + /// actual software latency, as near to this value as possible. + /// A higher value means less CPU usage. Defaults to a large value, + /// potentially upwards of 2 seconds. + /// If the device has unknown software latency min and max values, you may + /// still set this, but you might not get the value you requested. + /// For PulseAudio, if you set this value to non-default, it sets + /// `PA_STREAM_ADJUST_LATENCY` and is the value used for `fragsize`. + /// For JACK, this value is always equal to + /// SoundIoDevice::software_latency_current + double software_latency; + + /// Defaults to NULL. Put whatever you want here. + void *userdata; + + + /// In this function call ::soundio_instream_begin_read and + /// ::soundio_instream_end_read as many times as necessary to read at + /// minimum `frame_count_min` frames and at maximum `frame_count_max` + /// frames. If you return from read_callback without having read + /// `frame_count_min`, the frames will be dropped. `frame_count_max` is how + /// many frames are available to read. + /// + /// The code in the supplied function must be suitable for real-time + /// execution. That means that it cannot call functions that might block + /// for a long time. This includes all I/O functions (disk, TTY, network), + /// malloc, free, printf, pthread_mutex_lock, sleep, wait, poll, select, + /// pthread_join, pthread_cond_wait, etc. + void (*read_callback)(struct SoundIoInStream *, int frame_count_min, int frame_count_max); + /// This optional callback happens when the sound device buffer is full, + /// yet there is more captured audio to put in it. + /// This is never fired for PulseAudio. + /// This is called from the SoundIoInStream::read_callback thread context. + void (*overflow_callback)(struct SoundIoInStream *); + /// Optional callback. `err` is always SoundIoErrorStreaming. + /// SoundIoErrorStreaming is an unrecoverable error. The stream is in an + /// invalid state and must be destroyed. + /// If you do not supply `error_callback`, the default callback will print + /// a message to stderr and then abort(). + /// This is called from the SoundIoInStream::read_callback thread context. + void (*error_callback)(struct SoundIoInStream *, int err); + + /// Optional: Name of the stream. Defaults to "SoundIoInStream"; + /// PulseAudio uses this for the stream name. + /// JACK uses this for the client name of the client that connects when you + /// open the stream. + /// WASAPI uses this for the session display name. + /// Must not contain a colon (":"). + const char *name; + + /// Optional: Hint that this input stream is nonterminal. This is used by + /// JACK and it means that the data received by the stream will be + /// passed on or made available to another stream. Defaults to `false`. + bool non_terminal_hint; + + /// computed automatically when you call ::soundio_instream_open + int bytes_per_frame; + /// computed automatically when you call ::soundio_instream_open + int bytes_per_sample; + + /// If setting the channel layout fails for some reason, this field is set + /// to an error code. Possible error codes are: #SoundIoErrorIncompatibleDevice + int layout_error; +}; + +/// See also ::soundio_version_major, ::soundio_version_minor, ::soundio_version_patch +SOUNDIO_EXPORT const char *soundio_version_string(void); +/// See also ::soundio_version_string, ::soundio_version_minor, ::soundio_version_patch +SOUNDIO_EXPORT int soundio_version_major(void); +/// See also ::soundio_version_major, ::soundio_version_string, ::soundio_version_patch +SOUNDIO_EXPORT int soundio_version_minor(void); +/// See also ::soundio_version_major, ::soundio_version_minor, ::soundio_version_string +SOUNDIO_EXPORT int soundio_version_patch(void); + +/// Create a SoundIo context. You may create multiple instances of this to +/// connect to multiple backends. Sets all fields to defaults. +/// Returns `NULL` if and only if memory could not be allocated. +/// See also ::soundio_destroy +SOUNDIO_EXPORT struct SoundIo *soundio_create(void); +SOUNDIO_EXPORT void soundio_destroy(struct SoundIo *soundio); + + +/// Tries ::soundio_connect_backend on all available backends in order. +/// Possible errors: +/// * #SoundIoErrorInvalid - already connected +/// * #SoundIoErrorNoMem +/// * #SoundIoErrorSystemResources +/// * #SoundIoErrorNoSuchClient - when JACK returns `JackNoSuchClient` +/// See also ::soundio_disconnect +SOUNDIO_EXPORT int soundio_connect(struct SoundIo *soundio); +/// Instead of calling ::soundio_connect you may call this function to try a +/// specific backend. +/// Possible errors: +/// * #SoundIoErrorInvalid - already connected or invalid backend parameter +/// * #SoundIoErrorNoMem +/// * #SoundIoErrorBackendUnavailable - backend was not compiled in +/// * #SoundIoErrorSystemResources +/// * #SoundIoErrorNoSuchClient - when JACK returns `JackNoSuchClient` +/// * #SoundIoErrorInitAudioBackend - requested `backend` is not active +/// * #SoundIoErrorBackendDisconnected - backend disconnected while connecting +/// See also ::soundio_disconnect +SOUNDIO_EXPORT int soundio_connect_backend(struct SoundIo *soundio, enum SoundIoBackend backend); +SOUNDIO_EXPORT void soundio_disconnect(struct SoundIo *soundio); + +/// Get a string representation of a #SoundIoError +SOUNDIO_EXPORT const char *soundio_strerror(int error); +/// Get a string representation of a #SoundIoBackend +SOUNDIO_EXPORT const char *soundio_backend_name(enum SoundIoBackend backend); + +/// Returns the number of available backends. +SOUNDIO_EXPORT int soundio_backend_count(struct SoundIo *soundio); +/// get the available backend at the specified index +/// (0 <= index < ::soundio_backend_count) +SOUNDIO_EXPORT enum SoundIoBackend soundio_get_backend(struct SoundIo *soundio, int index); + +/// Returns whether libsoundio was compiled with backend. +SOUNDIO_EXPORT bool soundio_have_backend(enum SoundIoBackend backend); + +/// Atomically update information for all connected devices. Note that calling +/// this function merely flips a pointer; the actual work of collecting device +/// information is done elsewhere. It is performant to call this function many +/// times per second. +/// +/// When you call this, the following callbacks might be called: +/// * SoundIo::on_devices_change +/// * SoundIo::on_backend_disconnect +/// This is the only time those callbacks can be called. +/// +/// This must be called from the same thread as the thread in which you call +/// these functions: +/// * ::soundio_input_device_count +/// * ::soundio_output_device_count +/// * ::soundio_get_input_device +/// * ::soundio_get_output_device +/// * ::soundio_default_input_device_index +/// * ::soundio_default_output_device_index +/// +/// Note that if you do not care about learning about updated devices, you +/// might call this function only once ever and never call +/// ::soundio_wait_events. +SOUNDIO_EXPORT void soundio_flush_events(struct SoundIo *soundio); + +/// This function calls ::soundio_flush_events then blocks until another event +/// is ready or you call ::soundio_wakeup. Be ready for spurious wakeups. +SOUNDIO_EXPORT void soundio_wait_events(struct SoundIo *soundio); + +/// Makes ::soundio_wait_events stop blocking. +SOUNDIO_EXPORT void soundio_wakeup(struct SoundIo *soundio); + + +/// If necessary you can manually trigger a device rescan. Normally you will +/// not ever have to call this function, as libsoundio listens to system events +/// for device changes and responds to them by rescanning devices and preparing +/// the new device information for you to be atomically replaced when you call +/// ::soundio_flush_events. However you might run into cases where you want to +/// force trigger a device rescan, for example if an ALSA device has a +/// SoundIoDevice::probe_error. +/// +/// After you call this you still have to use ::soundio_flush_events or +/// ::soundio_wait_events and then wait for the +/// SoundIo::on_devices_change callback. +/// +/// This can be called from any thread context except for +/// SoundIoOutStream::write_callback and SoundIoInStream::read_callback +SOUNDIO_EXPORT void soundio_force_device_scan(struct SoundIo *soundio); + + +// Channel Layouts + +/// Returns whether the channel count field and each channel id matches in +/// the supplied channel layouts. +SOUNDIO_EXPORT bool soundio_channel_layout_equal( + const struct SoundIoChannelLayout *a, + const struct SoundIoChannelLayout *b); + +SOUNDIO_EXPORT const char *soundio_get_channel_name(enum SoundIoChannelId id); +/// Given UTF-8 encoded text which is the name of a channel such as +/// "Front Left", "FL", or "front-left", return the corresponding +/// SoundIoChannelId. Returns SoundIoChannelIdInvalid for no match. +SOUNDIO_EXPORT enum SoundIoChannelId soundio_parse_channel_id(const char *str, int str_len); + +/// Returns the number of builtin channel layouts. +SOUNDIO_EXPORT int soundio_channel_layout_builtin_count(void); +/// Returns a builtin channel layout. 0 <= `index` < ::soundio_channel_layout_builtin_count +/// +/// Although `index` is of type `int`, it should be a valid +/// #SoundIoChannelLayoutId enum value. +SOUNDIO_EXPORT const struct SoundIoChannelLayout *soundio_channel_layout_get_builtin(int index); + +/// Get the default builtin channel layout for the given number of channels. +SOUNDIO_EXPORT const struct SoundIoChannelLayout *soundio_channel_layout_get_default(int channel_count); + +/// Return the index of `channel` in `layout`, or `-1` if not found. +SOUNDIO_EXPORT int soundio_channel_layout_find_channel( + const struct SoundIoChannelLayout *layout, enum SoundIoChannelId channel); + +/// Populates the name field of layout if it matches a builtin one. +/// returns whether it found a match +SOUNDIO_EXPORT bool soundio_channel_layout_detect_builtin(struct SoundIoChannelLayout *layout); + +/// Iterates over preferred_layouts. Returns the first channel layout in +/// preferred_layouts which matches one of the channel layouts in +/// available_layouts. Returns NULL if none matches. +SOUNDIO_EXPORT const struct SoundIoChannelLayout *soundio_best_matching_channel_layout( + const struct SoundIoChannelLayout *preferred_layouts, int preferred_layout_count, + const struct SoundIoChannelLayout *available_layouts, int available_layout_count); + +/// Sorts by channel count, descending. +SOUNDIO_EXPORT void soundio_sort_channel_layouts(struct SoundIoChannelLayout *layouts, int layout_count); + + +// Sample Formats + +/// Returns -1 on invalid format. +SOUNDIO_EXPORT int soundio_get_bytes_per_sample(enum SoundIoFormat format); + +/// A frame is one sample per channel. +static inline int soundio_get_bytes_per_frame(enum SoundIoFormat format, int channel_count) { + return soundio_get_bytes_per_sample(format) * channel_count; +} + +/// Sample rate is the number of frames per second. +static inline int soundio_get_bytes_per_second(enum SoundIoFormat format, + int channel_count, int sample_rate) +{ + return soundio_get_bytes_per_frame(format, channel_count) * sample_rate; +} + +/// Returns string representation of `format`. +SOUNDIO_EXPORT const char * soundio_format_string(enum SoundIoFormat format); + + + + +// Devices + +/// When you call ::soundio_flush_events, a snapshot of all device state is +/// saved and these functions merely access the snapshot data. When you want +/// to check for new devices, call ::soundio_flush_events. Or you can call +/// ::soundio_wait_events to block until devices change. If an error occurs +/// scanning devices in a background thread, SoundIo::on_backend_disconnect is called +/// with the error code. + +/// Get the number of input devices. +/// Returns -1 if you never called ::soundio_flush_events. +SOUNDIO_EXPORT int soundio_input_device_count(struct SoundIo *soundio); +/// Get the number of output devices. +/// Returns -1 if you never called ::soundio_flush_events. +SOUNDIO_EXPORT int soundio_output_device_count(struct SoundIo *soundio); + +/// Always returns a device. Call ::soundio_device_unref when done. +/// `index` must be 0 <= index < ::soundio_input_device_count +/// Returns NULL if you never called ::soundio_flush_events or if you provide +/// invalid parameter values. +SOUNDIO_EXPORT struct SoundIoDevice *soundio_get_input_device(struct SoundIo *soundio, int index); +/// Always returns a device. Call ::soundio_device_unref when done. +/// `index` must be 0 <= index < ::soundio_output_device_count +/// Returns NULL if you never called ::soundio_flush_events or if you provide +/// invalid parameter values. +SOUNDIO_EXPORT struct SoundIoDevice *soundio_get_output_device(struct SoundIo *soundio, int index); + +/// returns the index of the default input device +/// returns -1 if there are no devices or if you never called +/// ::soundio_flush_events. +SOUNDIO_EXPORT int soundio_default_input_device_index(struct SoundIo *soundio); + +/// returns the index of the default output device +/// returns -1 if there are no devices or if you never called +/// ::soundio_flush_events. +SOUNDIO_EXPORT int soundio_default_output_device_index(struct SoundIo *soundio); + +/// Add 1 to the reference count of `device`. +SOUNDIO_EXPORT void soundio_device_ref(struct SoundIoDevice *device); +/// Remove 1 to the reference count of `device`. Clean up if it was the last +/// reference. +SOUNDIO_EXPORT void soundio_device_unref(struct SoundIoDevice *device); + +/// Return `true` if and only if the devices have the same SoundIoDevice::id, +/// SoundIoDevice::is_raw, and SoundIoDevice::aim are the same. +SOUNDIO_EXPORT bool soundio_device_equal( + const struct SoundIoDevice *a, + const struct SoundIoDevice *b); + +/// Sorts channel layouts by channel count, descending. +SOUNDIO_EXPORT void soundio_device_sort_channel_layouts(struct SoundIoDevice *device); + +/// Convenience function. Returns whether `format` is included in the device's +/// supported formats. +SOUNDIO_EXPORT bool soundio_device_supports_format(struct SoundIoDevice *device, + enum SoundIoFormat format); + +/// Convenience function. Returns whether `layout` is included in the device's +/// supported channel layouts. +SOUNDIO_EXPORT bool soundio_device_supports_layout(struct SoundIoDevice *device, + const struct SoundIoChannelLayout *layout); + +/// Convenience function. Returns whether `sample_rate` is included in the +/// device's supported sample rates. +SOUNDIO_EXPORT bool soundio_device_supports_sample_rate(struct SoundIoDevice *device, + int sample_rate); + +/// Convenience function. Returns the available sample rate nearest to +/// `sample_rate`, rounding up. +SOUNDIO_EXPORT int soundio_device_nearest_sample_rate(struct SoundIoDevice *device, + int sample_rate); + + + +// Output Streams +/// Allocates memory and sets defaults. Next you should fill out the struct fields +/// and then call ::soundio_outstream_open. Sets all fields to defaults. +/// Returns `NULL` if and only if memory could not be allocated. +/// See also ::soundio_outstream_destroy +SOUNDIO_EXPORT struct SoundIoOutStream *soundio_outstream_create(struct SoundIoDevice *device); +/// You may not call this function from the SoundIoOutStream::write_callback thread context. +SOUNDIO_EXPORT void soundio_outstream_destroy(struct SoundIoOutStream *outstream); + +/// After you call this function, SoundIoOutStream::software_latency is set to +/// the correct value. +/// +/// The next thing to do is call ::soundio_outstream_start. +/// If this function returns an error, the outstream is in an invalid state and +/// you must call ::soundio_outstream_destroy on it. +/// +/// Possible errors: +/// * #SoundIoErrorInvalid +/// * SoundIoDevice::aim is not #SoundIoDeviceAimOutput +/// * SoundIoOutStream::format is not valid +/// * SoundIoOutStream::channel_count is greater than #SOUNDIO_MAX_CHANNELS +/// * #SoundIoErrorNoMem +/// * #SoundIoErrorOpeningDevice +/// * #SoundIoErrorBackendDisconnected +/// * #SoundIoErrorSystemResources +/// * #SoundIoErrorNoSuchClient - when JACK returns `JackNoSuchClient` +/// * #SoundIoErrorIncompatibleBackend - SoundIoOutStream::channel_count is +/// greater than the number of channels the backend can handle. +/// * #SoundIoErrorIncompatibleDevice - stream parameters requested are not +/// compatible with the chosen device. +SOUNDIO_EXPORT int soundio_outstream_open(struct SoundIoOutStream *outstream); + +/// After you call this function, SoundIoOutStream::write_callback will be called. +/// +/// This function might directly call SoundIoOutStream::write_callback. +/// +/// Possible errors: +/// * #SoundIoErrorStreaming +/// * #SoundIoErrorNoMem +/// * #SoundIoErrorSystemResources +/// * #SoundIoErrorBackendDisconnected +SOUNDIO_EXPORT int soundio_outstream_start(struct SoundIoOutStream *outstream); + +/// Call this function when you are ready to begin writing to the device buffer. +/// * `outstream` - (in) The output stream you want to write to. +/// * `areas` - (out) The memory addresses you can write data to, one per +/// channel. It is OK to modify the pointers if that helps you iterate. +/// * `frame_count` - (in/out) Provide the number of frames you want to write. +/// Returned will be the number of frames you can actually write, which is +/// also the number of frames that will be written when you call +/// ::soundio_outstream_end_write. The value returned will always be less +/// than or equal to the value provided. +/// It is your responsibility to call this function exactly as many times as +/// necessary to meet the `frame_count_min` and `frame_count_max` criteria from +/// SoundIoOutStream::write_callback. +/// You must call this function only from the SoundIoOutStream::write_callback thread context. +/// After calling this function, write data to `areas` and then call +/// ::soundio_outstream_end_write. +/// If this function returns an error, do not call ::soundio_outstream_end_write. +/// +/// Possible errors: +/// * #SoundIoErrorInvalid +/// * `*frame_count` <= 0 +/// * `*frame_count` < `frame_count_min` or `*frame_count` > `frame_count_max` +/// * function called too many times without respecting `frame_count_max` +/// * #SoundIoErrorStreaming +/// * #SoundIoErrorUnderflow - an underflow caused this call to fail. You might +/// also get a SoundIoOutStream::underflow_callback, and you might not get +/// this error code when an underflow occurs. Unlike #SoundIoErrorStreaming, +/// the outstream is still in a valid state and streaming can continue. +/// * #SoundIoErrorIncompatibleDevice - in rare cases it might just now +/// be discovered that the device uses non-byte-aligned access, in which +/// case this error code is returned. +SOUNDIO_EXPORT int soundio_outstream_begin_write(struct SoundIoOutStream *outstream, + struct SoundIoChannelArea **areas, int *frame_count); + +/// Commits the write that you began with ::soundio_outstream_begin_write. +/// You must call this function only from the SoundIoOutStream::write_callback thread context. +/// +/// Possible errors: +/// * #SoundIoErrorStreaming +/// * #SoundIoErrorUnderflow - an underflow caused this call to fail. You might +/// also get a SoundIoOutStream::underflow_callback, and you might not get +/// this error code when an underflow occurs. Unlike #SoundIoErrorStreaming, +/// the outstream is still in a valid state and streaming can continue. +SOUNDIO_EXPORT int soundio_outstream_end_write(struct SoundIoOutStream *outstream); + +/// Clears the output stream buffer. +/// This function can be called from any thread. +/// This function can be called regardless of whether the outstream is paused +/// or not. +/// Some backends do not support clearing the buffer. On these backends this +/// function will return SoundIoErrorIncompatibleBackend. +/// Some devices do not support clearing the buffer. On these devices this +/// function might return SoundIoErrorIncompatibleDevice. +/// Possible errors: +/// +/// * #SoundIoErrorStreaming +/// * #SoundIoErrorIncompatibleBackend +/// * #SoundIoErrorIncompatibleDevice +SOUNDIO_EXPORT int soundio_outstream_clear_buffer(struct SoundIoOutStream *outstream); + +/// If the underlying backend and device support pausing, this pauses the +/// stream. SoundIoOutStream::write_callback may be called a few more times if +/// the buffer is not full. +/// Pausing might put the hardware into a low power state which is ideal if your +/// software is silent for some time. +/// This function may be called from any thread context, including +/// SoundIoOutStream::write_callback. +/// Pausing when already paused or unpausing when already unpaused has no +/// effect and returns #SoundIoErrorNone. +/// +/// Possible errors: +/// * #SoundIoErrorBackendDisconnected +/// * #SoundIoErrorStreaming +/// * #SoundIoErrorIncompatibleDevice - device does not support +/// pausing/unpausing. This error code might not be returned even if the +/// device does not support pausing/unpausing. +/// * #SoundIoErrorIncompatibleBackend - backend does not support +/// pausing/unpausing. +/// * #SoundIoErrorInvalid - outstream not opened and started +SOUNDIO_EXPORT int soundio_outstream_pause(struct SoundIoOutStream *outstream, bool pause); + +/// Obtain the total number of seconds that the next frame written after the +/// last frame written with ::soundio_outstream_end_write will take to become +/// audible. This includes both software and hardware latency. In other words, +/// if you call this function directly after calling ::soundio_outstream_end_write, +/// this gives you the number of seconds that the next frame written will take +/// to become audible. +/// +/// This function must be called only from within SoundIoOutStream::write_callback. +/// +/// Possible errors: +/// * #SoundIoErrorStreaming +SOUNDIO_EXPORT int soundio_outstream_get_latency(struct SoundIoOutStream *outstream, + double *out_latency); + +SOUNDIO_EXPORT int soundio_outstream_set_volume(struct SoundIoOutStream *outstream, + double volume); + + + +// Input Streams +/// Allocates memory and sets defaults. Next you should fill out the struct fields +/// and then call ::soundio_instream_open. Sets all fields to defaults. +/// Returns `NULL` if and only if memory could not be allocated. +/// See also ::soundio_instream_destroy +SOUNDIO_EXPORT struct SoundIoInStream *soundio_instream_create(struct SoundIoDevice *device); +/// You may not call this function from SoundIoInStream::read_callback. +SOUNDIO_EXPORT void soundio_instream_destroy(struct SoundIoInStream *instream); + +/// After you call this function, SoundIoInStream::software_latency is set to the correct +/// value. +/// The next thing to do is call ::soundio_instream_start. +/// If this function returns an error, the instream is in an invalid state and +/// you must call ::soundio_instream_destroy on it. +/// +/// Possible errors: +/// * #SoundIoErrorInvalid +/// * device aim is not #SoundIoDeviceAimInput +/// * format is not valid +/// * requested layout channel count > #SOUNDIO_MAX_CHANNELS +/// * #SoundIoErrorOpeningDevice +/// * #SoundIoErrorNoMem +/// * #SoundIoErrorBackendDisconnected +/// * #SoundIoErrorSystemResources +/// * #SoundIoErrorNoSuchClient +/// * #SoundIoErrorIncompatibleBackend +/// * #SoundIoErrorIncompatibleDevice +SOUNDIO_EXPORT int soundio_instream_open(struct SoundIoInStream *instream); + +/// After you call this function, SoundIoInStream::read_callback will be called. +/// +/// Possible errors: +/// * #SoundIoErrorBackendDisconnected +/// * #SoundIoErrorStreaming +/// * #SoundIoErrorOpeningDevice +/// * #SoundIoErrorSystemResources +SOUNDIO_EXPORT int soundio_instream_start(struct SoundIoInStream *instream); + +/// Call this function when you are ready to begin reading from the device +/// buffer. +/// * `instream` - (in) The input stream you want to read from. +/// * `areas` - (out) The memory addresses you can read data from. It is OK +/// to modify the pointers if that helps you iterate. There might be a "hole" +/// in the buffer. To indicate this, `areas` will be `NULL` and `frame_count` +/// tells how big the hole is in frames. +/// * `frame_count` - (in/out) - Provide the number of frames you want to read; +/// returns the number of frames you can actually read. The returned value +/// will always be less than or equal to the provided value. If the provided +/// value is less than `frame_count_min` from SoundIoInStream::read_callback this function +/// returns with #SoundIoErrorInvalid. +/// It is your responsibility to call this function no more and no fewer than the +/// correct number of times according to the `frame_count_min` and +/// `frame_count_max` criteria from SoundIoInStream::read_callback. +/// You must call this function only from the SoundIoInStream::read_callback thread context. +/// After calling this function, read data from `areas` and then use +/// ::soundio_instream_end_read` to actually remove the data from the buffer +/// and move the read index forward. ::soundio_instream_end_read should not be +/// called if the buffer is empty (`frame_count` == 0), but it should be called +/// if there is a hole. +/// +/// Possible errors: +/// * #SoundIoErrorInvalid +/// * `*frame_count` < `frame_count_min` or `*frame_count` > `frame_count_max` +/// * #SoundIoErrorStreaming +/// * #SoundIoErrorIncompatibleDevice - in rare cases it might just now +/// be discovered that the device uses non-byte-aligned access, in which +/// case this error code is returned. +SOUNDIO_EXPORT int soundio_instream_begin_read(struct SoundIoInStream *instream, + struct SoundIoChannelArea **areas, int *frame_count); +/// This will drop all of the frames from when you called +/// ::soundio_instream_begin_read. +/// You must call this function only from the SoundIoInStream::read_callback thread context. +/// You must call this function only after a successful call to +/// ::soundio_instream_begin_read. +/// +/// Possible errors: +/// * #SoundIoErrorStreaming +SOUNDIO_EXPORT int soundio_instream_end_read(struct SoundIoInStream *instream); + +/// If the underyling device supports pausing, this pauses the stream and +/// prevents SoundIoInStream::read_callback from being called. Otherwise this returns +/// #SoundIoErrorIncompatibleDevice. +/// This function may be called from any thread. +/// Pausing when already paused or unpausing when already unpaused has no +/// effect and always returns #SoundIoErrorNone. +/// +/// Possible errors: +/// * #SoundIoErrorBackendDisconnected +/// * #SoundIoErrorStreaming +/// * #SoundIoErrorIncompatibleDevice - device does not support pausing/unpausing +SOUNDIO_EXPORT int soundio_instream_pause(struct SoundIoInStream *instream, bool pause); + +/// Obtain the number of seconds that the next frame of sound being +/// captured will take to arrive in the buffer, plus the amount of time that is +/// represented in the buffer. This includes both software and hardware latency. +/// +/// This function must be called only from within SoundIoInStream::read_callback. +/// +/// Possible errors: +/// * #SoundIoErrorStreaming +SOUNDIO_EXPORT int soundio_instream_get_latency(struct SoundIoInStream *instream, + double *out_latency); + + +struct SoundIoRingBuffer; + +/// A ring buffer is a single-reader single-writer lock-free fixed-size queue. +/// libsoundio ring buffers use memory mapping techniques to enable a +/// contiguous buffer when reading or writing across the boundary of the ring +/// buffer's capacity. +/// `requested_capacity` in bytes. +/// Returns `NULL` if and only if memory could not be allocated. +/// Use ::soundio_ring_buffer_capacity to get the actual capacity, which might +/// be greater for alignment purposes. +/// See also ::soundio_ring_buffer_destroy +SOUNDIO_EXPORT struct SoundIoRingBuffer *soundio_ring_buffer_create(struct SoundIo *soundio, int requested_capacity); +SOUNDIO_EXPORT void soundio_ring_buffer_destroy(struct SoundIoRingBuffer *ring_buffer); + +/// When you create a ring buffer, capacity might be more than the requested +/// capacity for alignment purposes. This function returns the actual capacity. +SOUNDIO_EXPORT int soundio_ring_buffer_capacity(struct SoundIoRingBuffer *ring_buffer); + +/// Do not write more than capacity. +SOUNDIO_EXPORT char *soundio_ring_buffer_write_ptr(struct SoundIoRingBuffer *ring_buffer); +/// `count` in bytes. +SOUNDIO_EXPORT void soundio_ring_buffer_advance_write_ptr(struct SoundIoRingBuffer *ring_buffer, int count); + +/// Do not read more than capacity. +SOUNDIO_EXPORT char *soundio_ring_buffer_read_ptr(struct SoundIoRingBuffer *ring_buffer); +/// `count` in bytes. +SOUNDIO_EXPORT void soundio_ring_buffer_advance_read_ptr(struct SoundIoRingBuffer *ring_buffer, int count); + +/// Returns how many bytes of the buffer is used, ready for reading. +SOUNDIO_EXPORT int soundio_ring_buffer_fill_count(struct SoundIoRingBuffer *ring_buffer); + +/// Returns how many bytes of the buffer is free, ready for writing. +SOUNDIO_EXPORT int soundio_ring_buffer_free_count(struct SoundIoRingBuffer *ring_buffer); + +/// Must be called by the writer. +SOUNDIO_EXPORT void soundio_ring_buffer_clear(struct SoundIoRingBuffer *ring_buffer); + +#endif diff --git a/libs/aarch64/libad9361.so b/libs/aarch64/libad9361.so new file mode 120000 index 0000000..1ea2a7d --- /dev/null +++ b/libs/aarch64/libad9361.so @@ -0,0 +1 @@ +libad9361.so.0 \ No newline at end of file diff --git a/libs/aarch64/libad9361.so.0 b/libs/aarch64/libad9361.so.0 new file mode 120000 index 0000000..7beca4d --- /dev/null +++ b/libs/aarch64/libad9361.so.0 @@ -0,0 +1 @@ +libad9361.so.0.1 \ No newline at end of file diff --git a/libs/aarch64/libad9361.so.0.1 b/libs/aarch64/libad9361.so.0.1 new file mode 100644 index 0000000..18d4b61 Binary files /dev/null and b/libs/aarch64/libad9361.so.0.1 differ diff --git a/libs/aarch64/libiio.so b/libs/aarch64/libiio.so new file mode 120000 index 0000000..258226d --- /dev/null +++ b/libs/aarch64/libiio.so @@ -0,0 +1 @@ +libiio.so.0 \ No newline at end of file diff --git a/libs/aarch64/libiio.so.0 b/libs/aarch64/libiio.so.0 new file mode 120000 index 0000000..f6d5980 --- /dev/null +++ b/libs/aarch64/libiio.so.0 @@ -0,0 +1 @@ +libiio.so.0.21 \ No newline at end of file diff --git a/libs/aarch64/libiio.so.0.16 b/libs/aarch64/libiio.so.0.16 new file mode 100644 index 0000000..c4a37ad Binary files /dev/null and b/libs/aarch64/libiio.so.0.16 differ diff --git a/libs/aarch64/libiio.so.0.21 b/libs/aarch64/libiio.so.0.21 new file mode 100644 index 0000000..c2c1d51 Binary files /dev/null and b/libs/aarch64/libiio.so.0.21 differ diff --git a/libs/aarch64/libliquid.a b/libs/aarch64/libliquid.a new file mode 100644 index 0000000..b35ab26 Binary files /dev/null and b/libs/aarch64/libliquid.a differ diff --git a/libs/aarch64/libliquid.so b/libs/aarch64/libliquid.so new file mode 100644 index 0000000..8333b9b Binary files /dev/null and b/libs/aarch64/libliquid.so differ diff --git a/libs/aarch64/libsoundio.a b/libs/aarch64/libsoundio.a new file mode 100644 index 0000000..45961dd Binary files /dev/null and b/libs/aarch64/libsoundio.a differ diff --git a/libs/aarch64/libsoundio.so b/libs/aarch64/libsoundio.so new file mode 120000 index 0000000..3f53e65 --- /dev/null +++ b/libs/aarch64/libsoundio.so @@ -0,0 +1 @@ +libsoundio.so.2 \ No newline at end of file diff --git a/libs/aarch64/libsoundio.so.2 b/libs/aarch64/libsoundio.so.2 new file mode 120000 index 0000000..dc6eecd --- /dev/null +++ b/libs/aarch64/libsoundio.so.2 @@ -0,0 +1 @@ +libsoundio.so.2.0.0 \ No newline at end of file diff --git a/libs/aarch64/libsoundio.so.2.0.0 b/libs/aarch64/libsoundio.so.2.0.0 new file mode 100644 index 0000000..14725d3 Binary files /dev/null and b/libs/aarch64/libsoundio.so.2.0.0 differ diff --git a/libs/armhf/libad9361.so b/libs/armhf/libad9361.so new file mode 120000 index 0000000..1ea2a7d --- /dev/null +++ b/libs/armhf/libad9361.so @@ -0,0 +1 @@ +libad9361.so.0 \ No newline at end of file diff --git a/libs/armhf/libad9361.so.0 b/libs/armhf/libad9361.so.0 new file mode 120000 index 0000000..7beca4d --- /dev/null +++ b/libs/armhf/libad9361.so.0 @@ -0,0 +1 @@ +libad9361.so.0.1 \ No newline at end of file diff --git a/libs/armhf/libad9361.so.0.1 b/libs/armhf/libad9361.so.0.1 new file mode 100644 index 0000000..7fdcf2f Binary files /dev/null and b/libs/armhf/libad9361.so.0.1 differ diff --git a/libs/armhf/libiio.so b/libs/armhf/libiio.so new file mode 120000 index 0000000..258226d --- /dev/null +++ b/libs/armhf/libiio.so @@ -0,0 +1 @@ +libiio.so.0 \ No newline at end of file diff --git a/libs/armhf/libiio.so.0 b/libs/armhf/libiio.so.0 new file mode 120000 index 0000000..f6d5980 --- /dev/null +++ b/libs/armhf/libiio.so.0 @@ -0,0 +1 @@ +libiio.so.0.21 \ No newline at end of file diff --git a/libs/armhf/libiio.so.0.16 b/libs/armhf/libiio.so.0.16 new file mode 100644 index 0000000..a850097 Binary files /dev/null and b/libs/armhf/libiio.so.0.16 differ diff --git a/libs/armhf/libiio.so.0.21 b/libs/armhf/libiio.so.0.21 new file mode 100644 index 0000000..b48ae79 Binary files /dev/null and b/libs/armhf/libiio.so.0.21 differ diff --git a/libs/armhf/libliquid.a b/libs/armhf/libliquid.a new file mode 100644 index 0000000..5344d82 Binary files /dev/null and b/libs/armhf/libliquid.a differ diff --git a/libs/armhf/libliquid.so b/libs/armhf/libliquid.so new file mode 100644 index 0000000..68fb103 Binary files /dev/null and b/libs/armhf/libliquid.so differ diff --git a/libs/armhf/libsoundio.a b/libs/armhf/libsoundio.a new file mode 100644 index 0000000..248564f Binary files /dev/null and b/libs/armhf/libsoundio.a differ diff --git a/libs/armhf/libsoundio.so b/libs/armhf/libsoundio.so new file mode 120000 index 0000000..3f53e65 --- /dev/null +++ b/libs/armhf/libsoundio.so @@ -0,0 +1 @@ +libsoundio.so.2 \ No newline at end of file diff --git a/libs/armhf/libsoundio.so.2 b/libs/armhf/libsoundio.so.2 new file mode 120000 index 0000000..dc6eecd --- /dev/null +++ b/libs/armhf/libsoundio.so.2 @@ -0,0 +1 @@ +libsoundio.so.2.0.0 \ No newline at end of file diff --git a/libs/armhf/libsoundio.so.2.0.0 b/libs/armhf/libsoundio.so.2.0.0 new file mode 100644 index 0000000..348b06f Binary files /dev/null and b/libs/armhf/libsoundio.so.2.0.0 differ diff --git a/libs/include/ad9361.h b/libs/include/ad9361.h new file mode 100644 index 0000000..69f6ff8 --- /dev/null +++ b/libs/include/ad9361.h @@ -0,0 +1,60 @@ +/* + * Copyright (C) 2015 Analog Devices, Inc. + * + * 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. + */ + +#ifndef __AD9361_H__ +#define __AD9361_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +/* FLAGS */ +#define FIXUP_INTERFACE_TIMING 1 +#define CHECK_SAMPLE_RATES 2 + +#ifdef _WIN32 +# ifdef LIBAD9361_EXPORTS +# define __api __declspec(dllexport) +# else +# define __api __declspec(dllimport) +# endif +#elif __GNUC__ >= 4 +# define __api __attribute__((visibility ("default"))) +#else +# define __api +#endif + +struct iio_context; +struct iio_device; + +__api int ad9361_multichip_sync(struct iio_device *master, + struct iio_device **slaves, unsigned int num_slaves, + unsigned int flags); + +__api int ad9361_fmcomms5_multichip_sync( + struct iio_context *ctx, unsigned int flags); + +__api int ad9361_set_bb_rate(struct iio_device *dev, unsigned long rate); + +__api int ad9361_set_trx_fir_enable(struct iio_device *dev, int enable); + +__api int ad9361_get_trx_fir_enable(struct iio_device *dev, int *enable); + +#ifdef __cplusplus +} +#endif + +#undef __api + +#endif /* __AD9361_H__ */ diff --git a/libs/include/iio.h b/libs/include/iio.h new file mode 100644 index 0000000..ccc83be --- /dev/null +++ b/libs/include/iio.h @@ -0,0 +1,1866 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +/* + * libiio - Library for interfacing industrial I/O (IIO) devices + * + * Copyright (C) 2014 Analog Devices, Inc. + * Author: Paul Cercueil + */ + +/** @file iio.h + * @brief Public interface */ + +#ifndef __IIO_H__ +#define __IIO_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include +#include +#include + +#if (defined(_WIN32) || defined(__MBED__)) +#ifndef _SSIZE_T_DEFINED +typedef ptrdiff_t ssize_t; +#define _SSIZE_T_DEFINED +#endif +#else +#include +#endif + +#if defined(_MSC_VER) && (_MSC_VER < 1800) && !defined(__BOOL_DEFINED) +#undef bool +#undef false +#undef true +#define bool char +#define false 0 +#define true 1 +#else +#include +#endif + +#if defined(__GNUC__) && !defined(MATLAB_MEX_FILE) && !defined(MATLAB_LOADLIBRARY) +#ifndef __cnst +#define __cnst __attribute__((const)) +#endif +#ifndef __pure +#define __pure __attribute__((pure)) +#endif +#define __notused __attribute__((unused)) +#ifdef IIO_CHECK_RET +#define __check_ret __attribute__((warn_unused_result)) +#else +#define __check_ret +#endif +#else +#define __cnst +#define __pure +#define __notused +#define __check_ret +#endif + +#ifdef _WIN32 +# ifdef LIBIIO_STATIC +# define __api +# elif defined(LIBIIO_EXPORTS) +# define __api __declspec(dllexport) +# else +# define __api __declspec(dllimport) +# endif +#elif __GNUC__ >= 4 && !defined(MATLAB_MEX_FILE) && !defined(MATLAB_LOADLIBRARY) +# define __api __attribute__((visibility ("default"))) +#else +# define __api +#endif + +struct iio_context; +struct iio_device; +struct iio_channel; +struct iio_buffer; + +struct iio_context_info; +struct iio_scan_context; +struct iio_scan_block; + +/** + * @enum iio_chan_type + * @brief IIO channel type + * + * A IIO channel has a type specifying the type of data associated with the + * channel. + */ +enum iio_chan_type { + IIO_VOLTAGE, + IIO_CURRENT, + IIO_POWER, + IIO_ACCEL, + IIO_ANGL_VEL, + IIO_MAGN, + IIO_LIGHT, + IIO_INTENSITY, + IIO_PROXIMITY, + IIO_TEMP, + IIO_INCLI, + IIO_ROT, + IIO_ANGL, + IIO_TIMESTAMP, + IIO_CAPACITANCE, + IIO_ALTVOLTAGE, + IIO_CCT, + IIO_PRESSURE, + IIO_HUMIDITYRELATIVE, + IIO_ACTIVITY, + IIO_STEPS, + IIO_ENERGY, + IIO_DISTANCE, + IIO_VELOCITY, + IIO_CONCENTRATION, + IIO_RESISTANCE, + IIO_PH, + IIO_UVINDEX, + IIO_ELECTRICALCONDUCTIVITY, + IIO_COUNT, + IIO_INDEX, + IIO_GRAVITY, + IIO_POSITIONRELATIVE, + IIO_PHASE, + IIO_MASSCONCENTRATION, + IIO_CHAN_TYPE_UNKNOWN = INT_MAX +}; + +/** + * @enum iio_modifier + * @brief IIO channel modifier + * + * In a addition to a type a IIO channel can optionally have a channel modifier + * further specifying the data type of of the channel. + */ +enum iio_modifier { + IIO_NO_MOD, + IIO_MOD_X, + IIO_MOD_Y, + IIO_MOD_Z, + IIO_MOD_X_AND_Y, + IIO_MOD_X_AND_Z, + IIO_MOD_Y_AND_Z, + IIO_MOD_X_AND_Y_AND_Z, + IIO_MOD_X_OR_Y, + IIO_MOD_X_OR_Z, + IIO_MOD_Y_OR_Z, + IIO_MOD_X_OR_Y_OR_Z, + IIO_MOD_LIGHT_BOTH, + IIO_MOD_LIGHT_IR, + IIO_MOD_ROOT_SUM_SQUARED_X_Y, + IIO_MOD_SUM_SQUARED_X_Y_Z, + IIO_MOD_LIGHT_CLEAR, + IIO_MOD_LIGHT_RED, + IIO_MOD_LIGHT_GREEN, + IIO_MOD_LIGHT_BLUE, + IIO_MOD_QUATERNION, + IIO_MOD_TEMP_AMBIENT, + IIO_MOD_TEMP_OBJECT, + IIO_MOD_NORTH_MAGN, + IIO_MOD_NORTH_TRUE, + IIO_MOD_NORTH_MAGN_TILT_COMP, + IIO_MOD_NORTH_TRUE_TILT_COMP, + IIO_MOD_RUNNING, + IIO_MOD_JOGGING, + IIO_MOD_WALKING, + IIO_MOD_STILL, + IIO_MOD_ROOT_SUM_SQUARED_X_Y_Z, + IIO_MOD_I, + IIO_MOD_Q, + IIO_MOD_CO2, + IIO_MOD_VOC, + IIO_MOD_LIGHT_UV, + IIO_MOD_LIGHT_DUV, + IIO_MOD_PM1, + IIO_MOD_PM2P5, + IIO_MOD_PM4, + IIO_MOD_PM10, + IIO_MOD_ETHANOL, + IIO_MOD_H2, + IIO_MOD_O2, +}; + +/* ---------------------------------------------------------------------------*/ +/* ------------------------- Scan functions ----------------------------------*/ +/** @defgroup Scan Functions for scanning available contexts + * @{ + * @struct iio_scan_context + * @brief The scanning context + * + * @struct iio_context_info + * @brief The information related to a discovered context + */ + + +/** @brief Create a scan context + * @param backend A NULL-terminated string containing the backend(s) to use for + * scanning (example: pre version 0.20 : "local", "ip", or "usb"; post version + * 0.20 can handle multiple, including "local:usb:", "ip:usb:", "local:usb:ip:"). + * If NULL, all the available backends are used. + * @param flags Unused for now. Set to 0. + * @return on success, a pointer to a iio_scan_context structure + * @return On failure, NULL is returned and errno is set appropriately */ +__api __check_ret struct iio_scan_context * iio_create_scan_context( + const char *backend, unsigned int flags); + + +/** @brief Destroy the given scan context + * @param ctx A pointer to an iio_scan_context structure + * + * NOTE: After that function, the iio_scan_context pointer shall be invalid. */ +__api void iio_scan_context_destroy(struct iio_scan_context *ctx); + + +/** @brief Enumerate available contexts + * @param ctx A pointer to an iio_scan_context structure + * @param info A pointer to a 'const struct iio_context_info **' typed variable. + * The pointed variable will be initialized on success. + * @returns On success, the number of contexts found. + * @returns On failure, a negative error number. + */ +__api __check_ret ssize_t iio_scan_context_get_info_list(struct iio_scan_context *ctx, + struct iio_context_info ***info); + + +/** @brief Free a context info list + * @param info A pointer to a 'const struct iio_context_info *' typed variable + */ +__api void iio_context_info_list_free(struct iio_context_info **info); + + +/** @brief Get a description of a discovered context + * @param info A pointer to an iio_context_info structure + * @return A pointer to a static NULL-terminated string + */ +__api __check_ret __pure const char * iio_context_info_get_description( + const struct iio_context_info *info); + + +/** @brief Get the URI of a discovered context + * @param info A pointer to an iio_context_info structure + * @return A pointer to a static NULL-terminated string + */ +__api __check_ret __pure const char * iio_context_info_get_uri( + const struct iio_context_info *info); + + +/** @brief Create a scan block + * @param backend A NULL-terminated string containing the backend to use for + * scanning. If NULL, all the available backends are used. + * @param flags Unused for now. Set to 0. + * @return on success, a pointer to a iio_scan_block structure + * @return On failure, NULL is returned and errno is set appropriately + * + * Introduced in version 0.20. */ +__api struct iio_scan_block * iio_create_scan_block( + const char *backend, unsigned int flags); + + +/** @brief Destroy the given scan block + * @param blk A pointer to an iio_scan_block structure + * + * NOTE: After that function, the iio_scan_block pointer shall be invalid. + * + * Introduced in version 0.20. */ +__api void iio_scan_block_destroy(struct iio_scan_block *blk); + + +/** @brief Enumerate available contexts via scan block + * @param blk A pointer to a iio_scan_block structure. + * @returns On success, the number of contexts found. + * @returns On failure, a negative error number. + * + * Introduced in version 0.20. */ +__api ssize_t iio_scan_block_scan(struct iio_scan_block *blk); + + +/** @brief Get the iio_context_info for a particular context + * @param blk A pointer to an iio_scan_block structure + * @param index The index corresponding to the context. + * @return A pointer to the iio_context_info for the context + * @returns On success, a pointer to the specified iio_context_info + * @returns On failure, NULL is returned and errno is set appropriately + * + * Introduced in version 0.20. */ +__api struct iio_context_info *iio_scan_block_get_info( + struct iio_scan_block *blk, unsigned int index); + + +/** @} *//* ------------------------------------------------------------------*/ +/* ------------------------- Top-level functions -----------------------------*/ +/** @defgroup TopLevel Top-level functions + * @{ */ + + +/** @brief Get the version of the libiio library + * @param major A pointer to an unsigned integer (NULL accepted) + * @param minor A pointer to an unsigned integer (NULL accepted) + * @param git_tag A pointer to a 8-characters buffer (NULL accepted) */ +__api void iio_library_get_version(unsigned int *major, + unsigned int *minor, char git_tag[8]); + + +/** @brief Get a string description of an error code + * @param err The error code + * @param dst A pointer to the memory area where the NULL-terminated string + * corresponding to the error message will be stored + * @param len The available length of the memory area, in bytes */ +__api void iio_strerror(int err, char *dst, size_t len); + + +/** @brief Check if the specified backend is available + * @param backend The name of the backend to query + * @return True if the backend is available, false otherwise + * + * Introduced in version 0.9. */ +__api __check_ret __cnst bool iio_has_backend(const char *backend); + + +/** @brief Get the number of available backends + * @return The number of available backends + * + * Introduced in version 0.9. */ +__api __check_ret __cnst unsigned int iio_get_backends_count(void); + + +/** @brief Retrieve the name of a given backend + * @param index The index corresponding to the attribute + * @return On success, a pointer to a static NULL-terminated string + * @return If the index is invalid, NULL is returned + * + * Introduced in version 0.9. */ +__api __check_ret __cnst const char * iio_get_backend(unsigned int index); + + +/** @} *//* ------------------------------------------------------------------*/ +/* ------------------------- Context functions -------------------------------*/ +/** @defgroup Context Context + * @{ + * @struct iio_context + * @brief Contains the representation of an IIO context */ + + +/** @brief Create a context from local or remote IIO devices + * @return On success, A pointer to an iio_context structure + * @return On failure, NULL is returned and errno is set appropriately + * + * NOTE: This function will create a context with the URI + * provided in the IIOD_REMOTE environment variable. If not set, a local + * context will be created instead. */ +__api __check_ret struct iio_context * iio_create_default_context(void); + + +/** @brief Create a context from local IIO devices (Linux only) + * @return On success, A pointer to an iio_context structure + * @return On failure, NULL is returned and errno is set appropriately */ +__api __check_ret struct iio_context * iio_create_local_context(void); + + +/** @brief Create a context from a XML file + * @param xml_file Path to the XML file to open + * @return On success, A pointer to an iio_context structure + * @return On failure, NULL is returned and errno is set appropriately + * + * NOTE: The format of the XML must comply to the one returned by + * iio_context_get_xml. */ +__api __check_ret struct iio_context * iio_create_xml_context(const char *xml_file); + + +/** @brief Create a context from XML data in memory + * @param xml Pointer to the XML data in memory + * @param len Length of the XML string in memory (excluding the final \0) + * @return On success, A pointer to an iio_context structure + * @return On failure, NULL is returned and errno is set appropriately + * + * NOTE: The format of the XML must comply to the one returned by + * iio_context_get_xml */ +__api __check_ret struct iio_context * iio_create_xml_context_mem( + const char *xml, size_t len); + + +/** @brief Create a context from the network + * @param host Hostname, IPv4 or IPv6 address where the IIO Daemon is running + * @return On success, a pointer to an iio_context structure + * @return On failure, NULL is returned and errno is set appropriately */ +__api __check_ret struct iio_context * iio_create_network_context(const char *host); + + +/** @brief Create a context from a URI description + * @param uri A URI describing the context location + * @return On success, a pointer to a iio_context structure + * @return On failure, NULL is returned and errno is set appropriately + * + * NOTE: The following URIs are supported based on compile time backend + * support: + * - Local backend, "local:"\n + * Does not have an address part. For example "local:" + * - XML backend, "xml:"\n Requires a path to the XML file for the address part. + * For example "xml:/home/user/file.xml" + * - Network backend, "ip:"\n Requires a hostname, IPv4, or IPv6 to connect to + * a specific running IIO Daemon or no address part for automatic discovery + * when library is compiled with ZeroConf support. For example + * "ip:192.168.2.1", or "ip:localhost", or "ip:" + * or "ip:plutosdr.local" + * - USB backend, "usb:"\n When more than one usb device is attached, requires + * bus, address, and interface parts separated with a dot. For example + * "usb:3.32.5". Where there is only one USB device attached, the shorthand + * "usb:" can be used. + * - Serial backend, "serial:"\n Requires: + * - a port (/dev/ttyUSB0), + * - baud_rate (default 115200) + * - serial port configuration + * - data bits (5 6 7 8 9) + * - parity ('n' none, 'o' odd, 'e' even, 'm' mark, 's' space) + * - stop bits (1 2) + * - flow control ('\0' none, 'x' Xon Xoff, 'r' RTSCTS, 'd' DTRDSR) + * + * For example "serial:/dev/ttyUSB0,115200" or "serial:/dev/ttyUSB0,115200,8n1"*/ +__api __check_ret struct iio_context * iio_create_context_from_uri(const char *uri); + + +/** @brief Duplicate a pre-existing IIO context + * @param ctx A pointer to an iio_context structure + * @return On success, A pointer to an iio_context structure + * @return On failure, NULL is returned and errno is set appropriately + * + * NOTE: This function is not supported on 'usb:' contexts, since libusb + * can only claim the interface once. "Function not implemented" is the expected errno. + * Any context which is cloned, must be destroyed via calling iio_context_destroy() */ +__api __check_ret struct iio_context * iio_context_clone(const struct iio_context *ctx); + + +/** @brief Destroy the given context + * @param ctx A pointer to an iio_context structure + * + * NOTE: After that function, the iio_context pointer shall be invalid. */ +__api void iio_context_destroy(struct iio_context *ctx); + + +/** @brief Get the version of the backend in use + * @param ctx A pointer to an iio_context structure + * @param major A pointer to an unsigned integer (NULL accepted) + * @param minor A pointer to an unsigned integer (NULL accepted) + * @param git_tag A pointer to a 8-characters buffer (NULL accepted) + * @return On success, 0 is returned + * @return On error, a negative errno code is returned */ +__api __check_ret int iio_context_get_version(const struct iio_context *ctx, + unsigned int *major, unsigned int *minor, char git_tag[8]); + + +/** @brief Obtain a XML representation of the given context + * @param ctx A pointer to an iio_context structure + * @return A pointer to a static NULL-terminated string */ +__api __check_ret __pure const char * iio_context_get_xml(const struct iio_context *ctx); + + +/** @brief Get the name of the given context + * @param ctx A pointer to an iio_context structure + * @return A pointer to a static NULL-terminated string + * + * NOTE:The returned string will be local, + * xml or network when the context has been + * created with the local, xml and network backends respectively.*/ +__api __check_ret __pure const char * iio_context_get_name(const struct iio_context *ctx); + + +/** @brief Get a description of the given context + * @param ctx A pointer to an iio_context structure + * @return A pointer to a static NULL-terminated string + * + * NOTE:The returned string will contain human-readable information about + * the current context. */ +__api __check_ret __pure const char * iio_context_get_description( + const struct iio_context *ctx); + + +/** @brief Get the number of context-specific attributes + * @param ctx A pointer to an iio_context structure + * @return The number of context-specific attributes + * + * Introduced in version 0.9. */ +__api __check_ret __pure unsigned int iio_context_get_attrs_count( + const struct iio_context *ctx); + + +/** @brief Retrieve the name and value of a context-specific attribute + * @param ctx A pointer to an iio_context structure + * @param index The index corresponding to the attribute + * @param name A pointer to a const char * pointer (NULL accepted) + * @param value A pointer to a const char * pointer (NULL accepted) + * @return On success, 0 is returned + * @return On error, a negative errno code is returned + * + * Introduced in version 0.9. */ +__api __check_ret int iio_context_get_attr( + const struct iio_context *ctx, unsigned int index, + const char **name, const char **value); + + +/** @brief Retrieve the value of a context-specific attribute + * @param ctx A pointer to an iio_context structure + * @param name The name of the context attribute to read + * @return On success, a pointer to a static NULL-terminated string + * @return If the name does not correspond to any attribute, NULL is + * returned + * + * Introduced in version 0.9. */ +__api __check_ret const char * iio_context_get_attr_value( + const struct iio_context *ctx, const char *name); + + +/** @brief Enumerate the devices found in the given context + * @param ctx A pointer to an iio_context structure + * @return The number of devices found */ +__api __check_ret __pure unsigned int iio_context_get_devices_count( + const struct iio_context *ctx); + + +/** @brief Get the device present at the given index + * @param ctx A pointer to an iio_context structure + * @param index The index corresponding to the device + * @return On success, a pointer to an iio_device structure + * @return If the index is invalid, NULL is returned */ +__api __check_ret __pure struct iio_device * iio_context_get_device( + const struct iio_context *ctx, unsigned int index); + + +/** @brief Try to find a device structure by its ID, label or name + * @param ctx A pointer to an iio_context structure + * @param name A NULL-terminated string corresponding to the ID, label or name + * of the device to search for + * @return On success, a pointer to an iio_device structure + * @return If the parameter does not correspond to the ID, label or name of + * any known device, NULL is returned */ +__api __check_ret __pure struct iio_device * iio_context_find_device( + const struct iio_context *ctx, const char *name); + + +/** @brief Set a timeout for I/O operations + * @param ctx A pointer to an iio_context structure + * @param timeout_ms A positive integer representing the time in milliseconds + * after which a timeout occurs. A value of 0 is used to specify that no + * timeout should occur. + * @return On success, 0 is returned + * @return On error, a negative errno code is returned */ +__api __check_ret int iio_context_set_timeout( + struct iio_context *ctx, unsigned int timeout_ms); + + +/** @} *//* ------------------------------------------------------------------*/ +/* ------------------------- Device functions --------------------------------*/ +/** @defgroup Device Device + * @{ + * @struct iio_device + * @brief Represents a device in the IIO context */ + + +/** @brief Retrieve a pointer to the iio_context structure + * @param dev A pointer to an iio_device structure + * @return A pointer to an iio_context structure */ +__api __check_ret __pure const struct iio_context * iio_device_get_context( + const struct iio_device *dev); + + +/** @brief Retrieve the device ID (e.g. iio:device0) + * @param dev A pointer to an iio_device structure + * @return A pointer to a static NULL-terminated string */ +__api __check_ret __pure const char * iio_device_get_id(const struct iio_device *dev); + + +/** @brief Retrieve the device name (e.g. xadc) + * @param dev A pointer to an iio_device structure + * @return A pointer to a static NULL-terminated string + * + * NOTE: if the device has no name, NULL is returned. */ +__api __check_ret __pure const char * iio_device_get_name(const struct iio_device *dev); + + +/** @brief Retrieve the device label (e.g. lo_pll0_rx_adf4351) + * @param dev A pointer to an iio_device structure + * @return A pointer to a static NULL-terminated string + * + * NOTE: if the device has no label, NULL is returned. */ +__api __check_ret __pure const char * iio_device_get_label(const struct iio_device *dev); + + +/** @brief Enumerate the channels of the given device + * @param dev A pointer to an iio_device structure + * @return The number of channels found */ +__api __check_ret __pure unsigned int iio_device_get_channels_count( + const struct iio_device *dev); + + +/** @brief Enumerate the device-specific attributes of the given device + * @param dev A pointer to an iio_device structure + * @return The number of device-specific attributes found */ +__api __check_ret __pure unsigned int iio_device_get_attrs_count( + const struct iio_device *dev); + +/** @brief Enumerate the buffer-specific attributes of the given device + * @param dev A pointer to an iio_device structure + * @return The number of buffer-specific attributes found */ +__api __check_ret __pure unsigned int iio_device_get_buffer_attrs_count( + const struct iio_device *dev); + +/** @brief Get the channel present at the given index + * @param dev A pointer to an iio_device structure + * @param index The index corresponding to the channel + * @return On success, a pointer to an iio_channel structure + * @return If the index is invalid, NULL is returned */ +__api __check_ret __pure struct iio_channel * iio_device_get_channel( + const struct iio_device *dev, unsigned int index); + + +/** @brief Get the device-specific attribute present at the given index + * @param dev A pointer to an iio_device structure + * @param index The index corresponding to the attribute + * @return On success, a pointer to a static NULL-terminated string + * @return If the index is invalid, NULL is returned */ +__api __check_ret __pure const char * iio_device_get_attr( + const struct iio_device *dev, unsigned int index); + +/** @brief Get the buffer-specific attribute present at the given index + * @param dev A pointer to an iio_device structure + * @param index The index corresponding to the attribute + * @return On success, a pointer to a static NULL-terminated string + * @return If the index is invalid, NULL is returned */ +__api __check_ret __pure const char * iio_device_get_buffer_attr( + const struct iio_device *dev, unsigned int index); + +/** @brief Try to find a channel structure by its name of ID + * @param dev A pointer to an iio_device structure + * @param name A NULL-terminated string corresponding to the name or the ID of + * the channel to search for + * @param output True if the searched channel is output, False otherwise + * @return On success, a pointer to an iio_channel structure + * @return If the name or ID does not correspond to any known channel of the + * given device, NULL is returned */ +__api __check_ret __pure struct iio_channel * iio_device_find_channel( + const struct iio_device *dev, const char *name, bool output); + + +/** @brief Try to find a device-specific attribute by its name + * @param dev A pointer to an iio_device structure + * @param name A NULL-terminated string corresponding to the name of the + * attribute + * @return On success, a pointer to a static NULL-terminated string + * @return If the name does not correspond to any known attribute of the given + * device, NULL is returned + * + * NOTE: This function is useful to detect the presence of an attribute. + * It can also be used to retrieve the name of an attribute as a pointer to a + * static string from a dynamically allocated string. */ +__api __check_ret __pure const char * iio_device_find_attr( + const struct iio_device *dev, const char *name); + +/** @brief Try to find a buffer-specific attribute by its name + * @param dev A pointer to an iio_device structure + * @param name A NULL-terminated string corresponding to the name of the + * attribute + * @return On success, a pointer to a static NULL-terminated string + * @return If the name does not correspond to any known attribute of the given + * device, NULL is returned + * + * NOTE: This function is useful to detect the presence of an attribute. + * It can also be used to retrieve the name of an attribute as a pointer to a + * static string from a dynamically allocated string. */ +__api __check_ret __pure const char * iio_device_find_buffer_attr( + const struct iio_device *dev, const char *name); + +/** @brief Read the content of the given device-specific attribute + * @param dev A pointer to an iio_device structure + * @param attr A NULL-terminated string corresponding to the name of the + * attribute + * @param dst A pointer to the memory area where the NULL-terminated string + * corresponding to the value read will be stored + * @param len The available length of the memory area, in bytes + * @return On success, the number of bytes written to the buffer + * @return On error, a negative errno code is returned + * + * NOTE:By passing NULL as the "attr" argument to iio_device_attr_read, + * it is now possible to read all of the attributes of a device. + * + * The buffer is filled with one block of data per attribute of the device, + * by the order they appear in the iio_device structure. + * + * The first four bytes of one block correspond to a 32-bit signed value in + * network order. If negative, it corresponds to the errno code that were + * returned when reading the attribute; if positive, it corresponds to the + * length of the data read. In that case, the rest of the block contains + * the data. */ +__api __check_ret ssize_t iio_device_attr_read(const struct iio_device *dev, + const char *attr, char *dst, size_t len); + + +/** @brief Read the content of all device-specific attributes + * @param dev A pointer to an iio_device structure + * @param cb A pointer to a callback function + * @param data A pointer that will be passed to the callback function + * @return On success, 0 is returned + * @return On error, a negative errno code is returned + * + * NOTE: This function is especially useful when used with the network + * backend, as all the device-specific attributes are read in one single + * command. */ +__api __check_ret int iio_device_attr_read_all(struct iio_device *dev, + int (*cb)(struct iio_device *dev, const char *attr, + const char *value, size_t len, void *d), + void *data); + + +/** @brief Read the content of the given device-specific attribute + * @param dev A pointer to an iio_device structure + * @param attr A NULL-terminated string corresponding to the name of the + * attribute + * @param val A pointer to a bool variable where the value should be stored + * @return On success, 0 is returned + * @return On error, a negative errno code is returned */ +__api __check_ret int iio_device_attr_read_bool(const struct iio_device *dev, + const char *attr, bool *val); + + +/** @brief Read the content of the given device-specific attribute + * @param dev A pointer to an iio_device structure + * @param attr A NULL-terminated string corresponding to the name of the + * attribute + * @param val A pointer to a long long variable where the value should be stored + * @return On success, 0 is returned + * @return On error, a negative errno code is returned */ +__api __check_ret int iio_device_attr_read_longlong(const struct iio_device *dev, + const char *attr, long long *val); + + +/** @brief Read the content of the given device-specific attribute + * @param dev A pointer to an iio_device structure + * @param attr A NULL-terminated string corresponding to the name of the + * attribute + * @param val A pointer to a double variable where the value should be stored + * @return On success, 0 is returned + * @return On error, a negative errno code is returned */ +__api __check_ret int iio_device_attr_read_double(const struct iio_device *dev, + const char *attr, double *val); + + +/** @brief Set the value of the given device-specific attribute + * @param dev A pointer to an iio_device structure + * @param attr A NULL-terminated string corresponding to the name of the + * attribute + * @param src A NULL-terminated string to set the attribute to + * @return On success, the number of bytes written + * @return On error, a negative errno code is returned + * + * NOTE:By passing NULL as the "attr" argument to iio_device_attr_write, + * it is now possible to write all of the attributes of a device. + * + * The buffer must contain one block of data per attribute of the device, + * by the order they appear in the iio_device structure. + * + * The first four bytes of one block correspond to a 32-bit signed value in + * network order. If negative, the attribute is not written; if positive, + * it corresponds to the length of the data to write. In that case, the rest + * of the block must contain the data. */ +__api __check_ret ssize_t iio_device_attr_write(const struct iio_device *dev, + const char *attr, const char *src); + + +/** @brief Set the value of the given device-specific attribute + * @param dev A pointer to an iio_device structure + * @param attr A NULL-terminated string corresponding to the name of the + * attribute + * @param src A pointer to the data to be written + * @param len The number of bytes that should be written + * @return On success, the number of bytes written + * @return On error, a negative errno code is returned */ +__api __check_ret ssize_t iio_device_attr_write_raw(const struct iio_device *dev, + const char *attr, const void *src, size_t len); + + +/** @brief Set the values of all device-specific attributes + * @param dev A pointer to an iio_device structure + * @param cb A pointer to a callback function + * @param data A pointer that will be passed to the callback function + * @return On success, 0 is returned + * @return On error, a negative errno code is returned + * + * NOTE: This function is especially useful when used with the network + * backend, as all the device-specific attributes are written in one single + * command. */ +__api __check_ret int iio_device_attr_write_all(struct iio_device *dev, + ssize_t (*cb)(struct iio_device *dev, + const char *attr, void *buf, size_t len, void *d), + void *data); + + +/** @brief Set the value of the given device-specific attribute + * @param dev A pointer to an iio_device structure + * @param attr A NULL-terminated string corresponding to the name of the + * attribute + * @param val A bool value to set the attribute to + * @return On success, 0 is returned + * @return On error, a negative errno code is returned */ +__api __check_ret int iio_device_attr_write_bool(const struct iio_device *dev, + const char *attr, bool val); + + +/** @brief Set the value of the given device-specific attribute + * @param dev A pointer to an iio_device structure + * @param attr A NULL-terminated string corresponding to the name of the + * attribute + * @param val A long long value to set the attribute to + * @return On success, 0 is returned + * @return On error, a negative errno code is returned */ +__api __check_ret int iio_device_attr_write_longlong(const struct iio_device *dev, + const char *attr, long long val); + + +/** @brief Set the value of the given device-specific attribute + * @param dev A pointer to an iio_device structure + * @param attr A NULL-terminated string corresponding to the name of the + * attribute + * @param val A double value to set the attribute to + * @return On success, 0 is returned + * @return On error, a negative errno code is returned */ +__api __check_ret int iio_device_attr_write_double(const struct iio_device *dev, + const char *attr, double val); + +/** @brief Read the content of the given buffer-specific attribute + * @param dev A pointer to an iio_device structure + * @param attr A NULL-terminated string corresponding to the name of the + * attribute + * @param dst A pointer to the memory area where the NULL-terminated string + * corresponding to the value read will be stored + * @param len The available length of the memory area, in bytes + * @return On success, the number of bytes written to the buffer + * @return On error, a negative errno code is returned + * + * NOTE:By passing NULL as the "attr" argument to + * iio_device_buffer_attr_read, it is now possible to read all of the attributes + * of a device. + * + * The buffer is filled with one block of data per attribute of the buffer, + * by the order they appear in the iio_device structure. + * + * The first four bytes of one block correspond to a 32-bit signed value in + * network order. If negative, it corresponds to the errno code that were + * returned when reading the attribute; if positive, it corresponds to the + * length of the data read. In that case, the rest of the block contains + * the data. */ +__api __check_ret ssize_t iio_device_buffer_attr_read(const struct iio_device *dev, + const char *attr, char *dst, size_t len); + +/** @brief Read the content of all buffer-specific attributes + * @param dev A pointer to an iio_device structure + * @param cb A pointer to a callback function + * @param data A pointer that will be passed to the callback function + * @return On success, 0 is returned + * @return On error, a negative errno code is returned + * + * NOTE: This function is especially useful when used with the network + * backend, as all the buffer-specific attributes are read in one single + * command. */ +__api __check_ret int iio_device_buffer_attr_read_all(struct iio_device *dev, + int (*cb)(struct iio_device *dev, const char *attr, + const char *value, size_t len, void *d), + void *data); + + +/** @brief Read the content of the given buffer-specific attribute + * @param dev A pointer to an iio_device structure + * @param attr A NULL-terminated string corresponding to the name of the + * attribute + * @param val A pointer to a bool variable where the value should be stored + * @return On success, 0 is returned + * @return On error, a negative errno code is returned */ +__api __check_ret int iio_device_buffer_attr_read_bool(const struct iio_device *dev, + const char *attr, bool *val); + + +/** @brief Read the content of the given buffer-specific attribute + * @param dev A pointer to an iio_device structure + * @param attr A NULL-terminated string corresponding to the name of the + * attribute + * @param val A pointer to a long long variable where the value should be stored + * @return On success, 0 is returned + * @return On error, a negative errno code is returned */ +__api __check_ret int iio_device_buffer_attr_read_longlong(const struct iio_device *dev, + const char *attr, long long *val); + + +/** @brief Read the content of the given buffer-specific attribute + * @param dev A pointer to an iio_device structure + * @param attr A NULL-terminated string corresponding to the name of the + * attribute + * @param val A pointer to a double variable where the value should be stored + * @return On success, 0 is returned + * @return On error, a negative errno code is returned */ +__api __check_ret int iio_device_buffer_attr_read_double(const struct iio_device *dev, + const char *attr, double *val); + + +/** @brief Set the value of the given buffer-specific attribute + * @param dev A pointer to an iio_device structure + * @param attr A NULL-terminated string corresponding to the name of the + * attribute + * @param src A NULL-terminated string to set the attribute to + * @return On success, the number of bytes written + * @return On error, a negative errno code is returned + * + * NOTE:By passing NULL as the "attr" argument to + * iio_device_buffer_attr_write, it is now possible to write all of the + * attributes of a device. + * + * The buffer must contain one block of data per attribute of the buffer, + * by the order they appear in the iio_device structure. + * + * The first four bytes of one block correspond to a 32-bit signed value in + * network order. If negative, the attribute is not written; if positive, + * it corresponds to the length of the data to write. In that case, the rest + * of the block must contain the data. */ +__api __check_ret ssize_t iio_device_buffer_attr_write(const struct iio_device *dev, + const char *attr, const char *src); + + +/** @brief Set the value of the given buffer-specific attribute + * @param dev A pointer to an iio_device structure + * @param attr A NULL-terminated string corresponding to the name of the + * attribute + * @param src A pointer to the data to be written + * @param len The number of bytes that should be written + * @return On success, the number of bytes written + * @return On error, a negative errno code is returned */ +__api __check_ret ssize_t iio_device_buffer_attr_write_raw(const struct iio_device *dev, + const char *attr, const void *src, size_t len); + + +/** @brief Set the values of all buffer-specific attributes + * @param dev A pointer to an iio_device structure + * @param cb A pointer to a callback function + * @param data A pointer that will be passed to the callback function + * @return On success, 0 is returned + * @return On error, a negative errno code is returned + * + * NOTE: This function is especially useful when used with the network + * backend, as all the buffer-specific attributes are written in one single + * command. */ +__api __check_ret int iio_device_buffer_attr_write_all(struct iio_device *dev, + ssize_t (*cb)(struct iio_device *dev, + const char *attr, void *buf, size_t len, void *d), + void *data); + + +/** @brief Set the value of the given buffer-specific attribute + * @param dev A pointer to an iio_device structure + * @param attr A NULL-terminated string corresponding to the name of the + * attribute + * @param val A bool value to set the attribute to + * @return On success, 0 is returned + * @return On error, a negative errno code is returned */ +__api __check_ret int iio_device_buffer_attr_write_bool(const struct iio_device *dev, + const char *attr, bool val); + + +/** @brief Set the value of the given buffer-specific attribute + * @param dev A pointer to an iio_device structure + * @param attr A NULL-terminated string corresponding to the name of the + * attribute + * @param val A long long value to set the attribute to + * @return On success, 0 is returned + * @return On error, a negative errno code is returned */ +__api __check_ret int iio_device_buffer_attr_write_longlong(const struct iio_device *dev, + const char *attr, long long val); + + +/** @brief Set the value of the given buffer-specific attribute + * @param dev A pointer to an iio_device structure + * @param attr A NULL-terminated string corresponding to the name of the + * attribute + * @param val A double value to set the attribute to + * @return On success, 0 is returned + * @return On error, a negative errno code is returned */ +__api __check_ret int iio_device_buffer_attr_write_double(const struct iio_device *dev, + const char *attr, double val); + + +/** @brief Associate a pointer to an iio_device structure + * @param dev A pointer to an iio_device structure + * @param data The pointer to be associated */ +__api void iio_device_set_data(struct iio_device *dev, void *data); + + +/** @brief Retrieve a previously associated pointer of an iio_device structure + * @param dev A pointer to an iio_device structure + * @return The pointer previously associated if present, or NULL */ +__api void * iio_device_get_data(const struct iio_device *dev); + + +/** @brief Retrieve the trigger of a given device + * @param dev A pointer to an iio_device structure + * @param trigger a pointer to a pointer of an iio_device structure. The pointed + * pointer will be set to the address of the iio_device structure corresponding + * to the associated trigger device. + * @return On success, 0 is returned + * @return On error, a negative errno code is returned */ +__api __check_ret int iio_device_get_trigger(const struct iio_device *dev, + const struct iio_device **trigger); + + +/** @brief Associate a trigger to a given device + * @param dev A pointer to an iio_device structure + * @param trigger a pointer to the iio_device structure corresponding to the + * trigger that should be associated. + * @return On success, 0 is returned + * @return On error, a negative errno code is returned */ +__api __check_ret int iio_device_set_trigger(const struct iio_device *dev, + const struct iio_device *trigger); + + +/** @brief Return True if the given device is a trigger + * @param dev A pointer to an iio_device structure + * @return True if the device is a trigger, False otherwise */ +__api __check_ret __pure bool iio_device_is_trigger(const struct iio_device *dev); + +/** @brief Configure the number of kernel buffers for a device + * + * This function allows to change the number of buffers on kernel side. + * @param dev A pointer to an iio_device structure + * @param nb_buffers The number of buffers + * @return On success, 0 is returned + * @return On error, a negative errno code is returned */ +__api __check_ret int iio_device_set_kernel_buffers_count(const struct iio_device *dev, + unsigned int nb_buffers); + +/** @} *//* ------------------------------------------------------------------*/ +/* ------------------------- Channel functions -------------------------------*/ +/** @defgroup Channel Channel + * @{ + * @struct iio_channel + * @brief Represents an input or output channel of a device */ + + +/** @brief Retrieve a pointer to the iio_device structure + * @param chn A pointer to an iio_channel structure + * @return A pointer to an iio_device structure */ +__api __check_ret __pure const struct iio_device * iio_channel_get_device( + const struct iio_channel *chn); + + +/** @brief Retrieve the channel ID (e.g. voltage0) + * @param chn A pointer to an iio_channel structure + * @return A pointer to a static NULL-terminated string */ +__api __check_ret __pure const char * iio_channel_get_id(const struct iio_channel *chn); + + +/** @brief Retrieve the channel name (e.g. vccint) + * @param chn A pointer to an iio_channel structure + * @return A pointer to a static NULL-terminated string + * + * NOTE: if the channel has no name, NULL is returned. */ +__api __check_ret __pure const char * iio_channel_get_name(const struct iio_channel *chn); + + +/** @brief Return True if the given channel is an output channel + * @param chn A pointer to an iio_channel structure + * @return True if the channel is an output channel, False otherwise */ +__api __check_ret __pure bool iio_channel_is_output(const struct iio_channel *chn); + + +/** @brief Return True if the given channel is a scan element + * @param chn A pointer to an iio_channel structure + * @return True if the channel is a scan element, False otherwise + * + * NOTE: a channel that is a scan element is a channel that can + * generate samples (for an input channel) or receive samples (for an output + * channel) after being enabled. */ +__api __check_ret __pure bool iio_channel_is_scan_element(const struct iio_channel *chn); + + +/** @brief Enumerate the channel-specific attributes of the given channel + * @param chn A pointer to an iio_channel structure + * @return The number of channel-specific attributes found */ +__api __check_ret __pure unsigned int iio_channel_get_attrs_count( + const struct iio_channel *chn); + + +/** @brief Get the channel-specific attribute present at the given index + * @param chn A pointer to an iio_channel structure + * @param index The index corresponding to the attribute + * @return On success, a pointer to a static NULL-terminated string + * @return If the index is invalid, NULL is returned */ +__api __check_ret __pure const char * iio_channel_get_attr( + const struct iio_channel *chn, unsigned int index); + + +/** @brief Try to find a channel-specific attribute by its name + * @param chn A pointer to an iio_channel structure + * @param name A NULL-terminated string corresponding to the name of the + * attribute + * @return On success, a pointer to a static NULL-terminated string + * @return If the name does not correspond to any known attribute of the given + * channel, NULL is returned + * + * NOTE: This function is useful to detect the presence of an attribute. + * It can also be used to retrieve the name of an attribute as a pointer to a + * static string from a dynamically allocated string. */ +__api __check_ret __pure const char * iio_channel_find_attr( + const struct iio_channel *chn, const char *name); + + +/** @brief Retrieve the filename of an attribute + * @param chn A pointer to an iio_channel structure + * @param attr a NULL-terminated string corresponding to the name of the + * attribute + * @return On success, a pointer to a static NULL-terminated string + * @return If the attribute name is unknown, NULL is returned */ +__api __check_ret __pure const char * iio_channel_attr_get_filename( + const struct iio_channel *chn, const char *attr); + + +/** @brief Read the content of the given channel-specific attribute + * @param chn A pointer to an iio_channel structure + * @param attr A NULL-terminated string corresponding to the name of the + * attribute + * @param dst A pointer to the memory area where the NULL-terminated string + * corresponding to the value read will be stored + * @param len The available length of the memory area, in bytes + * @return On success, the number of bytes written to the buffer + * @return On error, a negative errno code is returned + * + * NOTE:By passing NULL as the "attr" argument to iio_channel_attr_read, + * it is now possible to read all of the attributes of a channel. + * + * The buffer is filled with one block of data per attribute of the channel, + * by the order they appear in the iio_channel structure. + * + * The first four bytes of one block correspond to a 32-bit signed value in + * network order. If negative, it corresponds to the errno code that were + * returned when reading the attribute; if positive, it corresponds to the + * length of the data read. In that case, the rest of the block contains + * the data. */ +__api __check_ret ssize_t iio_channel_attr_read(const struct iio_channel *chn, + const char *attr, char *dst, size_t len); + + +/** @brief Read the content of all channel-specific attributes + * @param chn A pointer to an iio_channel structure + * @param cb A pointer to a callback function + * @param data A pointer that will be passed to the callback function + * @return On success, 0 is returned + * @return On error, a negative errno code is returned + * + * NOTE: This function is especially useful when used with the network + * backend, as all the channel-specific attributes are read in one single + * command. */ +__api __check_ret int iio_channel_attr_read_all(struct iio_channel *chn, + int (*cb)(struct iio_channel *chn, + const char *attr, const char *val, size_t len, void *d), + void *data); + + +/** @brief Read the content of the given channel-specific attribute + * @param chn A pointer to an iio_channel structure + * @param attr A NULL-terminated string corresponding to the name of the + * attribute + * @param val A pointer to a bool variable where the value should be stored + * @return On success, 0 is returned + * @return On error, a negative errno code is returned */ +__api __check_ret int iio_channel_attr_read_bool(const struct iio_channel *chn, + const char *attr, bool *val); + + +/** @brief Read the content of the given channel-specific attribute + * @param chn A pointer to an iio_channel structure + * @param attr A NULL-terminated string corresponding to the name of the + * attribute + * @param val A pointer to a long long variable where the value should be stored + * @return On success, 0 is returned + * @return On error, a negative errno code is returned */ +__api __check_ret int iio_channel_attr_read_longlong(const struct iio_channel *chn, + const char *attr, long long *val); + + +/** @brief Read the content of the given channel-specific attribute + * @param chn A pointer to an iio_channel structure + * @param attr A NULL-terminated string corresponding to the name of the + * attribute + * @param val A pointer to a double variable where the value should be stored + * @return On success, 0 is returned + * @return On error, a negative errno code is returned */ +__api __check_ret int iio_channel_attr_read_double(const struct iio_channel *chn, + const char *attr, double *val); + + +/** @brief Set the value of the given channel-specific attribute + * @param chn A pointer to an iio_channel structure + * @param attr A NULL-terminated string corresponding to the name of the + * attribute + * @param src A NULL-terminated string to set the attribute to + * @return On success, the number of bytes written + * @return On error, a negative errno code is returned + * + * NOTE:By passing NULL as the "attr" argument to iio_channel_attr_write, + * it is now possible to write all of the attributes of a channel. + * + * The buffer must contain one block of data per attribute of the channel, + * by the order they appear in the iio_channel structure. + * + * The first four bytes of one block correspond to a 32-bit signed value in + * network order. If negative, the attribute is not written; if positive, + * it corresponds to the length of the data to write. In that case, the rest + * of the block must contain the data. */ +__api __check_ret ssize_t iio_channel_attr_write(const struct iio_channel *chn, + const char *attr, const char *src); + + +/** @brief Set the value of the given channel-specific attribute + * @param chn A pointer to an iio_channel structure + * @param attr A NULL-terminated string corresponding to the name of the + * attribute + * @param src A pointer to the data to be written + * @param len The number of bytes that should be written + * @return On success, the number of bytes written + * @return On error, a negative errno code is returned */ +__api __check_ret ssize_t iio_channel_attr_write_raw(const struct iio_channel *chn, + const char *attr, const void *src, size_t len); + + +/** @brief Set the values of all channel-specific attributes + * @param chn A pointer to an iio_channel structure + * @param cb A pointer to a callback function + * @param data A pointer that will be passed to the callback function + * @return On success, 0 is returned + * @return On error, a negative errno code is returned + * + * NOTE: This function is especially useful when used with the network + * backend, as all the channel-specific attributes are written in one single + * command. */ +__api __check_ret int iio_channel_attr_write_all(struct iio_channel *chn, + ssize_t (*cb)(struct iio_channel *chn, + const char *attr, void *buf, size_t len, void *d), + void *data); + + +/** @brief Set the value of the given channel-specific attribute + * @param chn A pointer to an iio_channel structure + * @param attr A NULL-terminated string corresponding to the name of the + * attribute + * @param val A bool value to set the attribute to + * @return On success, 0 is returned + * @return On error, a negative errno code is returned */ +__api __check_ret int iio_channel_attr_write_bool(const struct iio_channel *chn, + const char *attr, bool val); + + +/** @brief Set the value of the given channel-specific attribute + * @param chn A pointer to an iio_channel structure + * @param attr A NULL-terminated string corresponding to the name of the + * attribute + * @param val A long long value to set the attribute to + * @return On success, 0 is returned + * @return On error, a negative errno code is returned */ +__api __check_ret int iio_channel_attr_write_longlong(const struct iio_channel *chn, + const char *attr, long long val); + + +/** @brief Set the value of the given channel-specific attribute + * @param chn A pointer to an iio_channel structure + * @param attr A NULL-terminated string corresponding to the name of the + * attribute + * @param val A double value to set the attribute to + * @return On success, 0 is returned + * @return On error, a negative errno code is returned */ +__api __check_ret int iio_channel_attr_write_double(const struct iio_channel *chn, + const char *attr, double val); + + +/** @brief Enable the given channel + * @param chn A pointer to an iio_channel structure + * + * NOTE:Before creating an iio_buffer structure with + * iio_device_create_buffer, it is required to enable at least one channel of + * the device to read from. */ +__api void iio_channel_enable(struct iio_channel *chn); + + +/** @brief Disable the given channel + * @param chn A pointer to an iio_channel structure */ +__api void iio_channel_disable(struct iio_channel *chn); + + +/** @brief Returns True if the channel is enabled + * @param chn A pointer to an iio_channel structure + * @return True if the channel is enabled, False otherwise */ +__api __check_ret bool iio_channel_is_enabled(const struct iio_channel *chn); + + +/** @brief Demultiplex the samples of a given channel + * @param chn A pointer to an iio_channel structure + * @param buffer A pointer to an iio_buffer structure + * @param dst A pointer to the memory area where the demultiplexed data will be + * stored + * @param len The available length of the memory area, in bytes + * @return The size of the demultiplexed data, in bytes */ +__api __check_ret size_t iio_channel_read_raw(const struct iio_channel *chn, + struct iio_buffer *buffer, void *dst, size_t len); + + +/** @brief Demultiplex and convert the samples of a given channel + * @param chn A pointer to an iio_channel structure + * @param buffer A pointer to an iio_buffer structure + * @param dst A pointer to the memory area where the converted data will be + * stored + * @param len The available length of the memory area, in bytes + * @return The size of the converted data, in bytes */ +__api __check_ret size_t iio_channel_read(const struct iio_channel *chn, + struct iio_buffer *buffer, void *dst, size_t len); + + +/** @brief Multiplex the samples of a given channel + * @param chn A pointer to an iio_channel structure + * @param buffer A pointer to an iio_buffer structure + * @param src A pointer to the memory area where the sequential data will + * be read from + * @param len The length of the memory area, in bytes + * @return The number of bytes actually multiplexed */ +__api __check_ret size_t iio_channel_write_raw(const struct iio_channel *chn, + struct iio_buffer *buffer, const void *src, size_t len); + + +/** @brief Convert and multiplex the samples of a given channel + * @param chn A pointer to an iio_channel structure + * @param buffer A pointer to an iio_buffer structure + * @param src A pointer to the memory area where the sequential data will + * be read from + * @param len The length of the memory area, in bytes + * @return The number of bytes actually converted and multiplexed */ +__api __check_ret size_t iio_channel_write(const struct iio_channel *chn, + struct iio_buffer *buffer, const void *src, size_t len); + + +/** @brief Associate a pointer to an iio_channel structure + * @param chn A pointer to an iio_channel structure + * @param data The pointer to be associated */ +__api void iio_channel_set_data(struct iio_channel *chn, void *data); + + +/** @brief Retrieve a previously associated pointer of an iio_channel structure + * @param chn A pointer to an iio_channel structure + * @return The pointer previously associated if present, or NULL */ +__api void * iio_channel_get_data(const struct iio_channel *chn); + + +/** @brief Get the type of the given channel + * @param chn A pointer to an iio_channel structure + * @return The type of the channel */ +__api __check_ret __pure enum iio_chan_type iio_channel_get_type( + const struct iio_channel *chn); + + +/** @brief Get the modifier type of the given channel + * @param chn A pointer to an iio_channel structure + * @return The modifier type of the channel */ +__api __check_ret __pure enum iio_modifier iio_channel_get_modifier( + const struct iio_channel *chn); + + +/** @} *//* ------------------------------------------------------------------*/ +/* ------------------------- Buffer functions --------------------------------*/ +/** @defgroup Buffer Buffer + * @{ + * @struct iio_buffer + * @brief An input or output buffer, used to read or write samples */ + + +/** @brief Retrieve a pointer to the iio_device structure + * @param buf A pointer to an iio_buffer structure + * @return A pointer to an iio_device structure */ +__api __check_ret __pure const struct iio_device * iio_buffer_get_device( + const struct iio_buffer *buf); + + +/** @brief Create an input or output buffer associated to the given device + * @param dev A pointer to an iio_device structure + * @param samples_count The number of samples that the buffer should contain + * @param cyclic If True, enable cyclic mode + * @return On success, a pointer to an iio_buffer structure + * @return On error, NULL is returned, and errno is set to the error code + * + * NOTE: Channels that have to be written to / read from must be enabled + * before creating the buffer. */ +__api __check_ret struct iio_buffer * iio_device_create_buffer(const struct iio_device *dev, + size_t samples_count, bool cyclic); + + +/** @brief Destroy the given buffer + * @param buf A pointer to an iio_buffer structure + * + * NOTE: After that function, the iio_buffer pointer shall be invalid. */ +__api void iio_buffer_destroy(struct iio_buffer *buf); + +/** @brief Get a pollable file descriptor + * + * Can be used to know when iio_buffer_refill() or iio_buffer_push() can be + * called + * @param buf A pointer to an iio_buffer structure + * @return On success, valid file descriptor + * @return On error, a negative errno code is returned + */ +__api __check_ret int iio_buffer_get_poll_fd(struct iio_buffer *buf); + +/** @brief Make iio_buffer_refill() and iio_buffer_push() blocking or not + * + * After this function has been called with blocking == false, + * iio_buffer_refill() and iio_buffer_push() will return -EAGAIN if no data is + * ready. + * A device is blocking by default. + * @param buf A pointer to an iio_buffer structure + * @param blocking true if the buffer API should be blocking, else false + * @return On success, 0 + * @return On error, a negative errno code is returned + */ +__api __check_ret int iio_buffer_set_blocking_mode(struct iio_buffer *buf, bool blocking); + + +/** @brief Fetch more samples from the hardware + * @param buf A pointer to an iio_buffer structure + * @return On success, the number of bytes read is returned + * @return On error, a negative errno code is returned + * + * NOTE: Only valid for input buffers */ +__api __check_ret ssize_t iio_buffer_refill(struct iio_buffer *buf); + + +/** @brief Send the samples to the hardware + * @param buf A pointer to an iio_buffer structure + * @return On success, the number of bytes written is returned + * @return On error, a negative errno code is returned + * + * NOTE: Only valid for output buffers */ +__api __check_ret ssize_t iio_buffer_push(struct iio_buffer *buf); + + +/** @brief Send a given number of samples to the hardware + * @param buf A pointer to an iio_buffer structure + * @param samples_count The number of samples to submit + * @return On success, the number of bytes written is returned + * @return On error, a negative errno code is returned + * + * NOTE: Only valid for output buffers */ +__api __check_ret ssize_t iio_buffer_push_partial(struct iio_buffer *buf, + size_t samples_count); + +/** @brief Cancel all buffer operations + * @param buf The buffer for which operations should be canceled + * + * This function cancels all outstanding buffer operations previously scheduled. + * This means any pending iio_buffer_push() or iio_buffer_refill() operation + * will abort and return immediately, any further invocations of these functions + * on the same buffer will return immediately with an error. + * + * Usually iio_buffer_push() and iio_buffer_refill() will block until either all + * data has been transferred or a timeout occurs. This can depending on the + * configuration take a significant amount of time. iio_buffer_cancel() is + * useful to bypass these conditions if the buffer operation is supposed to be + * stopped in response to an external event (e.g. user input). + * + * To be able to capture additional data after calling this function the buffer + * should be destroyed and then re-created. + * + * This function can be called multiple times for the same buffer, but all but + * the first invocation will be without additional effect. + * + * This function is thread-safe, but not signal-safe, i.e. it must not be called + * from a signal handler. + */ +__api void iio_buffer_cancel(struct iio_buffer *buf); + + +/** @brief Get the start address of the buffer + * @param buf A pointer to an iio_buffer structure + * @return A pointer corresponding to the start address of the buffer */ +__api void * iio_buffer_start(const struct iio_buffer *buf); + + +/** @brief Find the first sample of a channel in a buffer + * @param buf A pointer to an iio_buffer structure + * @param chn A pointer to an iio_channel structure + * @return A pointer to the first sample found, or to the end of the buffer if + * no sample for the given channel is present in the buffer + * + * NOTE: This function, coupled with iio_buffer_step and iio_buffer_end, + * can be used to iterate on all the samples of a given channel present in the + * buffer, doing the following: + * + * @verbatim + for (void *ptr = iio_buffer_first(buffer, chn); ptr < iio_buffer_end(buffer); ptr += iio_buffer_step(buffer)) { + .... + } + @endverbatim */ +__api void * iio_buffer_first(const struct iio_buffer *buf, + const struct iio_channel *chn); + + +/** @brief Get the step size between two samples of one channel + * @param buf A pointer to an iio_buffer structure + * @return the difference between the addresses of two consecutive samples of + * one same channel */ +__api __check_ret ptrdiff_t iio_buffer_step(const struct iio_buffer *buf); + + +/** @brief Get the address that follows the last sample in a buffer + * @param buf A pointer to an iio_buffer structure + * @return A pointer corresponding to the address that follows the last sample + * present in the buffer */ +__api void * iio_buffer_end(const struct iio_buffer *buf); + + +/** @brief Call the supplied callback for each sample found in a buffer + * @param buf A pointer to an iio_buffer structure + * @param callback A pointer to a function to call for each sample found + * @param data A user-specified pointer that will be passed to the callback + * @return number of bytes processed. + * + * NOTE: The callback receives four arguments: + * * A pointer to the iio_channel structure corresponding to the sample, + * * A pointer to the sample itself, + * * The length of the sample in bytes, + * * The user-specified pointer passed to iio_buffer_foreach_sample. */ +__api __check_ret ssize_t iio_buffer_foreach_sample(struct iio_buffer *buf, + ssize_t (*callback)(const struct iio_channel *chn, + void *src, size_t bytes, void *d), void *data); + + +/** @brief Associate a pointer to an iio_buffer structure + * @param buf A pointer to an iio_buffer structure + * @param data The pointer to be associated */ +__api void iio_buffer_set_data(struct iio_buffer *buf, void *data); + + +/** @brief Retrieve a previously associated pointer of an iio_buffer structure + * @param buf A pointer to an iio_buffer structure + * @return The pointer previously associated if present, or NULL */ +__api void * iio_buffer_get_data(const struct iio_buffer *buf); + + +/** @} *//* ------------------------------------------------------------------*/ +/* ------------------------- Low-level functions -----------------------------*/ +/** @defgroup Debug Debug and low-level functions + * @{ + * @struct iio_data_format + * @brief Contains the format of a data sample. + * + * The different fields inform about the correct way to convert one sample from + * its raw format (as read from / generated by the hardware) to its real-world + * value. + */ +struct iio_data_format { + /** @brief Total length of the sample, in bits */ + unsigned int length; + + /** @brief Length of valuable data in the sample, in bits */ + unsigned int bits; + + /** @brief Right-shift to apply when converting sample */ + unsigned int shift; + + /** @brief Contains True if the sample is signed */ + bool is_signed; + + /** @brief Contains True if the sample is fully defined, sign extended, etc. */ + bool is_fully_defined; + + /** @brief Contains True if the sample is in big-endian format */ + bool is_be; + + /** @brief Contains True if the sample should be scaled when converted */ + bool with_scale; + + /** @brief Contains the scale to apply if with_scale is set */ + double scale; + + /** @brief Number of times length repeats (added in v0.8) */ + unsigned int repeat; +}; + + +/** @brief Get the current sample size + * @param dev A pointer to an iio_device structure + * @return On success, the sample size in bytes + * @return On error, a negative errno code is returned + * + * NOTE: The sample size is not constant and will change when channels + * get enabled or disabled. */ +__api __check_ret ssize_t iio_device_get_sample_size(const struct iio_device *dev); + + +/** @brief Get the index of the given channel + * @param chn A pointer to an iio_channel structure + * @return On success, the index of the specified channel + * @return On error, a negative errno code is returned */ +__api __check_ret __pure long iio_channel_get_index(const struct iio_channel *chn); + + +/** @brief Get a pointer to a channel's data format structure + * @param chn A pointer to an iio_channel structure + * @return A pointer to the channel's iio_data_format structure */ +__api __check_ret __cnst const struct iio_data_format * iio_channel_get_data_format( + const struct iio_channel *chn); + + +/** @brief Convert the sample from hardware format to host format + * @param chn A pointer to an iio_channel structure + * @param dst A pointer to the destination buffer where the converted sample + * should be written + * @param src A pointer to the source buffer containing the sample */ +__api void iio_channel_convert(const struct iio_channel *chn, + void *dst, const void *src); + + +/** @brief Convert the sample from host format to hardware format + * @param chn A pointer to an iio_channel structure + * @param dst A pointer to the destination buffer where the converted sample + * should be written + * @param src A pointer to the source buffer containing the sample */ +__api void iio_channel_convert_inverse(const struct iio_channel *chn, + void *dst, const void *src); + + +/** @brief Enumerate the debug attributes of the given device + * @param dev A pointer to an iio_device structure + * @return The number of debug attributes found */ +__api __check_ret __pure unsigned int iio_device_get_debug_attrs_count( + const struct iio_device *dev); + + +/** @brief Get the debug attribute present at the given index + * @param dev A pointer to an iio_device structure + * @param index The index corresponding to the debug attribute + * @return On success, a pointer to a static NULL-terminated string + * @return If the index is invalid, NULL is returned */ +__api __check_ret __pure const char * iio_device_get_debug_attr( + const struct iio_device *dev, unsigned int index); + + +/** @brief Try to find a debug attribute by its name + * @param dev A pointer to an iio_device structure + * @param name A NULL-terminated string corresponding to the name of the + * debug attribute + * @return On success, a pointer to a static NULL-terminated string + * @return If the name does not correspond to any known debug attribute of the + * given device, NULL is returned + * + * NOTE: This function is useful to detect the presence of a debug + * attribute. + * It can also be used to retrieve the name of a debug attribute as a pointer + * to a static string from a dynamically allocated string. */ +__api __check_ret __pure const char * iio_device_find_debug_attr( + const struct iio_device *dev, const char *name); + + +/** @brief Read the content of the given debug attribute + * @param dev A pointer to an iio_device structure + * @param attr A NULL-terminated string corresponding to the name of the + * debug attribute + * @param dst A pointer to the memory area where the NULL-terminated string + * corresponding to the value read will be stored + * @param len The available length of the memory area, in bytes + * @return On success, the number of bytes written to the buffer + * @return On error, a negative errno code is returned + * + * NOTE:By passing NULL as the "attr" argument to + * iio_device_debug_attr_read, it is now possible to read all of the debug + * attributes of a device. + * + * The buffer is filled with one block of data per debug attribute of the + * device, by the order they appear in the iio_device structure. + * + * The first four bytes of one block correspond to a 32-bit signed value in + * network order. If negative, it corresponds to the errno code that were + * returned when reading the debug attribute; if positive, it corresponds + * to the length of the data read. In that case, the rest of the block contains + * the data. */ +__api __check_ret ssize_t iio_device_debug_attr_read(const struct iio_device *dev, + const char *attr, char *dst, size_t len); + + +/** @brief Read the content of all debug attributes + * @param dev A pointer to an iio_device structure + * @param cb A pointer to a callback function + * @param data A pointer that will be passed to the callback function + * @return On success, 0 is returned + * @return On error, a negative errno code is returned + * + * NOTE: This function is especially useful when used with the network + * backend, as all the debug attributes are read in one single command. */ +__api __check_ret int iio_device_debug_attr_read_all(struct iio_device *dev, + int (*cb)(struct iio_device *dev, const char *attr, + const char *value, size_t len, void *d), + void *data); + + +/** @brief Set the value of the given debug attribute + * @param dev A pointer to an iio_device structure + * @param attr A NULL-terminated string corresponding to the name of the + * debug attribute + * @param src A NULL-terminated string to set the debug attribute to + * @return On success, the number of bytes written + * @return On error, a negative errno code is returned + * + * NOTE:By passing NULL as the "attr" argument to + * iio_device_debug_attr_write, it is now possible to write all of the + * debug attributes of a device. + * + * The buffer must contain one block of data per debug attribute of the device, + * by the order they appear in the iio_device structure. + * + * The first four bytes of one block correspond to a 32-bit signed value in + * network order. If negative, the debug attribute is not written; if positive, + * it corresponds to the length of the data to write. In that case, the rest + * of the block must contain the data. */ +__api __check_ret ssize_t iio_device_debug_attr_write(const struct iio_device *dev, + const char *attr, const char *src); + + +/** @brief Set the value of the given debug attribute + * @param dev A pointer to an iio_device structure + * @param attr A NULL-terminated string corresponding to the name of the + * debug attribute + * @param src A pointer to the data to be written + * @param len The number of bytes that should be written + * @return On success, the number of bytes written + * @return On error, a negative errno code is returned */ +__api __check_ret ssize_t iio_device_debug_attr_write_raw(const struct iio_device *dev, + const char *attr, const void *src, size_t len); + + +/** @brief Set the values of all debug attributes + * @param dev A pointer to an iio_device structure + * @param cb A pointer to a callback function + * @param data A pointer that will be passed to the callback function + * @return On success, 0 is returned + * @return On error, a negative errno code is returned + * + * NOTE: This function is especially useful when used with the network + * backend, as all the debug attributes are written in one single command. */ +__api __check_ret int iio_device_debug_attr_write_all(struct iio_device *dev, + ssize_t (*cb)(struct iio_device *dev, + const char *attr, void *buf, size_t len, void *d), + void *data); + + +/** @brief Read the content of the given debug attribute + * @param dev A pointer to an iio_device structure + * @param attr A NULL-terminated string corresponding to the name of the + * debug attribute + * @param val A pointer to a bool variable where the value should be stored + * @return On success, 0 is returned + * @return On error, a negative errno code is returned */ +__api __check_ret int iio_device_debug_attr_read_bool(const struct iio_device *dev, + const char *attr, bool *val); + + +/** @brief Read the content of the given debug attribute + * @param dev A pointer to an iio_device structure + * @param attr A NULL-terminated string corresponding to the name of the + * debug attribute + * @param val A pointer to a long long variable where the value should be stored + * @return On success, 0 is returned + * @return On error, a negative errno code is returned */ +__api __check_ret int iio_device_debug_attr_read_longlong(const struct iio_device *dev, + const char *attr, long long *val); + + +/** @brief Read the content of the given debug attribute + * @param dev A pointer to an iio_device structure + * @param attr A NULL-terminated string corresponding to the name of the + * debug attribute + * @param val A pointer to a double variable where the value should be stored + * @return On success, 0 is returned + * @return On error, a negative errno code is returned */ +__api __check_ret int iio_device_debug_attr_read_double(const struct iio_device *dev, + const char *attr, double *val); + + +/** @brief Set the value of the given debug attribute + * @param dev A pointer to an iio_device structure + * @param attr A NULL-terminated string corresponding to the name of the + * debug attribute + * @param val A bool value to set the debug attribute to + * @return On success, 0 is returned + * @return On error, a negative errno code is returned */ +__api __check_ret int iio_device_debug_attr_write_bool(const struct iio_device *dev, + const char *attr, bool val); + + +/** @brief Set the value of the given debug attribute + * @param dev A pointer to an iio_device structure + * @param attr A NULL-terminated string corresponding to the name of the + * debug attribute + * @param val A long long value to set the debug attribute to + * @return On success, 0 is returned + * @return On error, a negative errno code is returned */ +__api __check_ret int iio_device_debug_attr_write_longlong(const struct iio_device *dev, + const char *attr, long long val); + + +/** @brief Set the value of the given debug attribute + * @param dev A pointer to an iio_device structure + * @param attr A NULL-terminated string corresponding to the name of the + * debug attribute + * @param val A double value to set the debug attribute to + * @return On success, 0 is returned + * @return On error, a negative errno code is returned */ +__api __check_ret int iio_device_debug_attr_write_double(const struct iio_device *dev, + const char *attr, double val); + + +/** @brief Identify the channel or debug attribute corresponding to a filename + * @param dev A pointer to an iio_device structure + * @param filename A NULL-terminated string corresponding to the filename + * @param chn A pointer to a pointer of an iio_channel structure. The pointed + * pointer will be set to the address of the iio_channel structure if the + * filename correspond to the attribute of a channel, or NULL otherwise. + * @param attr A pointer to a NULL-terminated string. The pointer + * pointer will be set to point to the name of the attribute corresponding to + * the filename. + * @return On success, 0 is returned, and *chn and *attr are modified. + * @return On error, a negative errno code is returned. *chn and *attr are not + * modified. */ +__api __check_ret int iio_device_identify_filename(const struct iio_device *dev, + const char *filename, struct iio_channel **chn, + const char **attr); + + +/** @brief Set the value of a hardware register + * @param dev A pointer to an iio_device structure + * @param address The address of the register + * @param value The value to set the register to + * @return On success, 0 is returned + * @return On error, a negative errno code is returned */ +__api __check_ret int iio_device_reg_write(struct iio_device *dev, + uint32_t address, uint32_t value); + + +/** @brief Get the value of a hardware register + * @param dev A pointer to an iio_device structure + * @param address The address of the register + * @param value A pointer to the variable where the value will be written + * @return On success, 0 is returned + * @return On error, a negative errno code is returned */ +__api __check_ret int iio_device_reg_read(struct iio_device *dev, + uint32_t address, uint32_t *value); + + +/** @} */ + +#ifdef __cplusplus +} +#endif + +#undef __api + +#endif /* __IIO_H__ */ diff --git a/libs/include/liquid.h b/libs/include/liquid.h new file mode 100644 index 0000000..1bb3061 --- /dev/null +++ b/libs/include/liquid.h @@ -0,0 +1,8823 @@ +/* + * Copyright (c) 2007 - 2020 Joseph Gaeddert + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#ifndef __LIQUID_H__ +#define __LIQUID_H__ + +#ifdef __cplusplus +extern "C" { +# define LIQUID_USE_COMPLEX_H 0 +#else +# define LIQUID_USE_COMPLEX_H 1 +#endif // __cplusplus + +// common headers +#include + +// +// Make sure the version and version number macros weren't defined by +// some prevoiusly included header file. +// +#ifdef LIQUID_VERSION +# undef LIQUID_VERSION +#endif +#ifdef LIQUID_VERSION_NUMBER +# undef LIQUID_VERSION_NUMBER +#endif + +// +// Compile-time version numbers +// +// LIQUID_VERSION = "X.Y.Z" +// LIQUID_VERSION_NUMBER = (X*1000000 + Y*1000 + Z) +// +#define LIQUID_VERSION "1.3.2" +#define LIQUID_VERSION_NUMBER 1003002 + +// +// Run-time library version numbers +// +extern const char liquid_version[]; +const char * liquid_libversion(void); +int liquid_libversion_number(void); + +// run-time library validation +#define LIQUID_VALIDATE_LIBVERSION \ + if (LIQUID_VERSION_NUMBER != liquid_libversion_number()) { \ + fprintf(stderr,"%s:%u: ", __FILE__,__LINE__); \ + fprintf(stderr,"error: invalid liquid runtime library\n"); \ + exit(1); \ + } \ + +// basic error types +#define LIQUID_NUM_ERRORS 12 +typedef enum { + // everything ok + LIQUID_OK=0, + + // internal logic error; this is a bug with liquid and should be reported immediately + LIQUID_EINT, + + // invalid object, examples: + // - destroy() method called on NULL pointer + LIQUID_EIOBJ, + + // invalid parameter, or configuration; examples: + // - setting bandwidth of a filter to a negative number + // - setting FFT size to zero + // - create a spectral periodogram object with window size greater than nfft + LIQUID_EICONFIG, + + // input out of range; examples: + // - try to take log of -1 + // - try to create an FFT plan of size zero + LIQUID_EIVAL, + + // invalid vector length or dimension; examples + // - trying to refer to the 17th element of a 2 x 2 matrix + // - trying to multiply two matrices of incompatible dimensions + LIQUID_EIRANGE, + + // invalid mode; examples: + // - try to create a modem of type 'LIQUID_MODEM_XXX' which does not exit + LIQUID_EIMODE, + + // unsupported mode (e.g. LIQUID_FEC_CONV_V27 with 'libfec' not installed) + LIQUID_EUMODE, + + // object has not been created or properly initialized + // - try to run firfilt_crcf_execute(NULL, ...) + // - try to modulate using an arbitrary modem without initializing the constellation + LIQUID_ENOINIT, + + // not enough memory allocated for operation; examples: + // - try to factor 100 = 2*2*5*5 but only give 3 spaces for factors + LIQUID_EIMEM, + + // file input/output; examples: + // - could not open a file for writing because of insufficient permissions + // - could not open a file for reading because it does not exist + // - try to read more data than a file has space for + // - could not parse line in file (improper formatting) + LIQUID_EIO, + +} liquid_error_code; + +// error descriptions +extern const char * liquid_error_str[LIQUID_NUM_ERRORS]; +const char * liquid_error_info(liquid_error_code _code); + +#define LIQUID_CONCAT(prefix, name) prefix ## name +#define LIQUID_VALIDATE_INPUT + +/* + * Compile-time complex data type definitions + * + * Default: use the C99 complex data type, otherwise + * define complex type compatible with the C++ complex standard, + * otherwise resort to defining binary compatible array. + */ +#if LIQUID_USE_COMPLEX_H==1 +# include +# define LIQUID_DEFINE_COMPLEX(R,C) typedef R _Complex C +#elif defined _GLIBCXX_COMPLEX || defined _LIBCPP_COMPLEX +# define LIQUID_DEFINE_COMPLEX(R,C) typedef std::complex C +#else +# define LIQUID_DEFINE_COMPLEX(R,C) typedef struct {R real; R imag;} C; +#endif +//# define LIQUID_DEFINE_COMPLEX(R,C) typedef R C[2] + +LIQUID_DEFINE_COMPLEX(float, liquid_float_complex); +LIQUID_DEFINE_COMPLEX(double, liquid_double_complex); + +// +// MODULE : agc (automatic gain control) +// + +// available squelch modes +typedef enum { + LIQUID_AGC_SQUELCH_UNKNOWN=0, // unknown/unavailable squelch mode + LIQUID_AGC_SQUELCH_ENABLED, // squelch enabled but signal not detected + LIQUID_AGC_SQUELCH_RISE, // signal first hit/exceeded threshold + LIQUID_AGC_SQUELCH_SIGNALHI, // signal level high (above threshold) + LIQUID_AGC_SQUELCH_FALL, // signal first dropped below threshold + LIQUID_AGC_SQUELCH_SIGNALLO, // signal level low (below threshold) + LIQUID_AGC_SQUELCH_TIMEOUT, // signal level low (below threshold for a certain time) + LIQUID_AGC_SQUELCH_DISABLED, // squelch not enabled +} agc_squelch_mode; + +#define LIQUID_AGC_MANGLE_CRCF(name) LIQUID_CONCAT(agc_crcf, name) +#define LIQUID_AGC_MANGLE_RRRF(name) LIQUID_CONCAT(agc_rrrf, name) + +// large macro +// AGC : name-mangling macro +// T : primitive data type +// TC : input/output data type +#define LIQUID_AGC_DEFINE_API(AGC,T,TC) \ + \ +/* Automatic gain control (agc) for level correction and signal */ \ +/* detection */ \ +typedef struct AGC(_s) * AGC(); \ + \ +/* Create automatic gain control object. */ \ +AGC() AGC(_create)(void); \ + \ +/* Destroy object, freeing all internally-allocated memory. */ \ +int AGC(_destroy)(AGC() _q); \ + \ +/* Print object properties to stdout, including received signal */ \ +/* strength indication (RSSI), loop bandwidth, lock status, and squelch */ \ +/* status. */ \ +int AGC(_print)(AGC() _q); \ + \ +/* Reset internal state of agc object, including gain estimate, input */ \ +/* signal level estimate, lock status, and squelch mode */ \ +/* If the squelch mode is disabled, it stays disabled, but all enabled */ \ +/* modes (e.g. LIQUID_AGC_SQUELCH_TIMEOUT) resets to just */ \ +/* LIQUID_AGC_SQUELCH_ENABLED. */ \ +int AGC(_reset)(AGC() _q); \ + \ +/* Execute automatic gain control on an single input sample */ \ +/* _q : automatic gain control object */ \ +/* _x : input sample */ \ +/* _y : output sample */ \ +int AGC(_execute)(AGC() _q, \ + TC _x, \ + TC * _y); \ + \ +/* Execute automatic gain control on block of samples pointed to by _x */ \ +/* and store the result in the array of the same length _y. */ \ +/* _q : automatic gain control object */ \ +/* _x : input data array, [size: _n x 1] */ \ +/* _n : number of input, output samples */ \ +/* _y : output data array, [size: _n x 1] */ \ +int AGC(_execute_block)(AGC() _q, \ + TC * _x, \ + unsigned int _n, \ + TC * _y); \ + \ +/* Lock agc object. When locked, the agc object still makes an estimate */ \ +/* of the signal level, but the gain setting is fixed and does not */ \ +/* change. */ \ +/* This is useful for providing coarse input signal level correction */ \ +/* and quickly detecting a packet burst but not distorting signals with */ \ +/* amplitude variation due to modulation. */ \ +int AGC(_lock)(AGC() _q); \ + \ +/* Unlock agc object, and allow amplitude correction to resume. */ \ +int AGC(_unlock)(AGC() _q); \ + \ +/* Set loop filter bandwidth: attack/release time. */ \ +/* _q : automatic gain control object */ \ +/* _bt : bandwidth-time constant, _bt > 0 */ \ +int AGC(_set_bandwidth)(AGC() _q, float _bt); \ + \ +/* Get the agc object's loop filter bandwidth. */ \ +float AGC(_get_bandwidth)(AGC() _q); \ + \ +/* Get the input signal's estimated energy level, relative to unity. */ \ +/* The result is a linear value. */ \ +float AGC(_get_signal_level)(AGC() _q); \ + \ +/* Set the agc object's estimate of the input signal by specifying an */ \ +/* explicit linear value. This is useful for initializing the agc */ \ +/* object with a preliminary estimate of the signal level to help gain */ \ +/* convergence. */ \ +/* _q : automatic gain control object */ \ +/* _x2 : signal level of input, _x2 > 0 */ \ +int AGC(_set_signal_level)(AGC() _q, \ + float _x2); \ + \ +/* Get the agc object's estimated received signal strength indication */ \ +/* (RSSI) on the input signal. */ \ +/* This is similar to getting the signal level (above), but returns the */ \ +/* result in dB rather than on a linear scale. */ \ +float AGC(_get_rssi)(AGC() _q); \ + \ +/* Set the agc object's estimated received signal strength indication */ \ +/* (RSSI) on the input signal by specifying an explicit value in dB. */ \ +/* _q : automatic gain control object */ \ +/* _rssi : signal level of input [dB] */ \ +int AGC(_set_rssi)(AGC() _q, float _rssi); \ + \ +/* Get the gain value currently being applied to the input signal */ \ +/* (linear). */ \ +float AGC(_get_gain)(AGC() _q); \ + \ +/* Set the agc object's internal gain by specifying an explicit linear */ \ +/* value. */ \ +/* _q : automatic gain control object */ \ +/* _gain : gain to apply to input signal, _gain > 0 */ \ +int AGC(_set_gain)(AGC() _q, \ + float _gain); \ + \ +/* Get the ouput scaling applied to each sample (linear). */ \ +float AGC(_get_scale)(AGC() _q); \ + \ +/* Set the agc object's output scaling (linear). Note that this does */ \ +/* affect the response of the AGC. */ \ +/* _q : automatic gain control object */ \ +/* _gain : gain to apply to input signal, _gain > 0 */ \ +int AGC(_set_scale)(AGC() _q, \ + float _scale); \ + \ +/* Estimate signal level and initialize internal gain on an input */ \ +/* array. */ \ +/* _q : automatic gain control object */ \ +/* _x : input data array, [size: _n x 1] */ \ +/* _n : number of input, output samples */ \ +int AGC(_init)(AGC() _q, \ + TC * _x, \ + unsigned int _n); \ + \ +/* Enable squelch mode. */ \ +int AGC(_squelch_enable)(AGC() _q); \ + \ +/* Disable squelch mode. */ \ +int AGC(_squelch_disable)(AGC() _q); \ + \ +/* Return flag indicating if squelch is enabled or not. */ \ +int AGC(_squelch_is_enabled)(AGC() _q); \ + \ +/* Set threshold for enabling/disabling squelch. */ \ +/* _q : automatic gain control object */ \ +/* _thresh : threshold for enabling squelch [dB] */ \ +int AGC(_squelch_set_threshold)(AGC() _q, \ + T _thresh); \ + \ +/* Get squelch threshold (value in dB) */ \ +T AGC(_squelch_get_threshold)(AGC() _q); \ + \ +/* Set timeout before enabling squelch. */ \ +/* _q : automatic gain control object */ \ +/* _timeout : timeout before enabling squelch [samples] */ \ +int AGC(_squelch_set_timeout)(AGC() _q, \ + unsigned int _timeout); \ + \ +/* Get squelch timeout (number of samples) */ \ +unsigned int AGC(_squelch_get_timeout)(AGC() _q); \ + \ +/* Get squelch status (e.g. LIQUID_AGC_SQUELCH_TIMEOUT) */ \ +int AGC(_squelch_get_status)(AGC() _q); \ + +// Define agc APIs +LIQUID_AGC_DEFINE_API(LIQUID_AGC_MANGLE_CRCF, float, liquid_float_complex) +LIQUID_AGC_DEFINE_API(LIQUID_AGC_MANGLE_RRRF, float, float) + + + +// +// MODULE : audio +// + +// CVSD: continuously variable slope delta +typedef struct cvsd_s * cvsd; + +// create cvsd object +// _num_bits : number of adjacent bits to observe (4 recommended) +// _zeta : slope adjustment multiplier (1.5 recommended) +// _alpha : pre-/post-emphasis filter coefficient (0.9 recommended) +// NOTE: _alpha must be in [0,1] +cvsd cvsd_create(unsigned int _num_bits, + float _zeta, + float _alpha); + +// destroy cvsd object +void cvsd_destroy(cvsd _q); + +// print cvsd object parameters +void cvsd_print(cvsd _q); + +// encode/decode single sample +unsigned char cvsd_encode(cvsd _q, float _audio_sample); +float cvsd_decode(cvsd _q, unsigned char _bit); + +// encode/decode 8 samples at a time +void cvsd_encode8(cvsd _q, float * _audio, unsigned char * _data); +void cvsd_decode8(cvsd _q, unsigned char _data, float * _audio); + + +// +// MODULE : buffer +// + +// circular buffer +#define LIQUID_CBUFFER_MANGLE_FLOAT(name) LIQUID_CONCAT(cbufferf, name) +#define LIQUID_CBUFFER_MANGLE_CFLOAT(name) LIQUID_CONCAT(cbuffercf, name) + +// large macro +// CBUFFER : name-mangling macro +// T : data type +#define LIQUID_CBUFFER_DEFINE_API(CBUFFER,T) \ + \ +/* Circular buffer object for storing and retrieving samples in a */ \ +/* first-in/first-out (FIFO) manner using a minimal amount of memory */ \ +typedef struct CBUFFER(_s) * CBUFFER(); \ + \ +/* Create circular buffer object of a particular maximum storage length */ \ +/* _max_size : maximum buffer size, _max_size > 0 */ \ +CBUFFER() CBUFFER(_create)(unsigned int _max_size); \ + \ +/* Create circular buffer object of a particular maximum storage size */ \ +/* and specify the maximum number of elements that can be read at any */ \ +/* any given time */ \ +/* _max_size : maximum buffer size, _max_size > 0 */ \ +/* _max_read : maximum size that will be read from buffer */ \ +CBUFFER() CBUFFER(_create_max)(unsigned int _max_size, \ + unsigned int _max_read); \ + \ +/* Destroy cbuffer object, freeing all internal memory */ \ +void CBUFFER(_destroy)(CBUFFER() _q); \ + \ +/* Print cbuffer object properties to stdout */ \ +void CBUFFER(_print)(CBUFFER() _q); \ + \ +/* Print cbuffer object properties and internal state */ \ +void CBUFFER(_debug_print)(CBUFFER() _q); \ + \ +/* Clear internal buffer */ \ +void CBUFFER(_reset)(CBUFFER() _q); \ + \ +/* Get the number of elements currently in the buffer */ \ +unsigned int CBUFFER(_size)(CBUFFER() _q); \ + \ +/* Get the maximum number of elements the buffer can hold */ \ +unsigned int CBUFFER(_max_size)(CBUFFER() _q); \ + \ +/* Get the maximum number of elements you may read at once */ \ +unsigned int CBUFFER(_max_read)(CBUFFER() _q); \ + \ +/* Get the number of available slots (max_size - size) */ \ +unsigned int CBUFFER(_space_available)(CBUFFER() _q); \ + \ +/* Return flag indicating if the buffer is full or not */ \ +int CBUFFER(_is_full)(CBUFFER() _q); \ + \ +/* Write a single sample into the buffer */ \ +/* _q : circular buffer object */ \ +/* _v : input sample */ \ +void CBUFFER(_push)(CBUFFER() _q, \ + T _v); \ + \ +/* Write a block of samples to the buffer */ \ +/* _q : circular buffer object */ \ +/* _v : array of samples to write to buffer */ \ +/* _n : number of samples to write */ \ +void CBUFFER(_write)(CBUFFER() _q, \ + T * _v, \ + unsigned int _n); \ + \ +/* Remove and return a single element from the buffer by setting the */ \ +/* value of the output sample pointed to by _v */ \ +/* _q : circular buffer object */ \ +/* _v : pointer to sample output */ \ +void CBUFFER(_pop)(CBUFFER() _q, \ + T * _v); \ + \ +/* Read buffer contents by returning a pointer to the linearized array; */ \ +/* note that the returned pointer is only valid until another operation */ \ +/* is performed on the circular buffer object */ \ +/* _q : circular buffer object */ \ +/* _num_requested : number of elements requested */ \ +/* _v : output pointer */ \ +/* _num_read : number of elements referenced by _v */ \ +void CBUFFER(_read)(CBUFFER() _q, \ + unsigned int _num_requested, \ + T ** _v, \ + unsigned int * _num_read); \ + \ +/* Release _n samples from the buffer */ \ +/* _q : circular buffer object */ \ +/* _n : number of elements to release */ \ +void CBUFFER(_release)(CBUFFER() _q, \ + unsigned int _n); \ + +// Define buffer APIs +LIQUID_CBUFFER_DEFINE_API(LIQUID_CBUFFER_MANGLE_FLOAT, float) +LIQUID_CBUFFER_DEFINE_API(LIQUID_CBUFFER_MANGLE_CFLOAT, liquid_float_complex) + + + +// Windowing functions +#define LIQUID_WINDOW_MANGLE_FLOAT(name) LIQUID_CONCAT(windowf, name) +#define LIQUID_WINDOW_MANGLE_CFLOAT(name) LIQUID_CONCAT(windowcf, name) + +// large macro +// WINDOW : name-mangling macro +// T : data type +#define LIQUID_WINDOW_DEFINE_API(WINDOW,T) \ + \ +/* Sliding window first-in/first-out buffer with a fixed size */ \ +typedef struct WINDOW(_s) * WINDOW(); \ + \ +/* Create window buffer object of a fixed length */ \ +WINDOW() WINDOW(_create)(unsigned int _n); \ + \ +/* Recreate window buffer object with new length. */ \ +/* This extends an existing window's size, similar to the standard C */ \ +/* library's realloc() to n samples. */ \ +/* If the size of the new window is larger than the old one, the newest */ \ +/* values are retained at the beginning of the buffer and the oldest */ \ +/* values are truncated. If the size of the new window is smaller than */ \ +/* the old one, the oldest values are truncated. */ \ +/* _q : old window object */ \ +/* _n : new window length */ \ +WINDOW() WINDOW(_recreate)(WINDOW() _q, unsigned int _n); \ + \ +/* Destroy window object, freeing all internally memory */ \ +int WINDOW(_destroy)(WINDOW() _q); \ + \ +/* Print window object to stdout */ \ +int WINDOW(_print)(WINDOW() _q); \ + \ +/* Print window object to stdout (with extra information) */ \ +int WINDOW(_debug_print)(WINDOW() _q); \ + \ +/* Reset window object (initialize to zeros) */ \ +int WINDOW(_reset)(WINDOW() _q); \ + \ +/* Read the contents of the window by returning a pointer to the */ \ +/* aligned internal memory array. This method guarantees that the */ \ +/* elements are linearized. This method should only be used for */ \ +/* reading; writing values to the buffer has unspecified results. */ \ +/* Note that the returned pointer is only valid until another operation */ \ +/* is performed on the window buffer object */ \ +/* _q : window object */ \ +/* _v : output pointer (set to internal array) */ \ +int WINDOW(_read)(WINDOW() _q, \ + T ** _v); \ + \ +/* Index single element in buffer at a particular index */ \ +/* This retrieves the \(i^{th}\) sample in the window, storing the */ \ +/* output value in _v. */ \ +/* This is equivalent to first invoking read() and then indexing on the */ \ +/* resulting pointer; however the result is obtained much faster. */ \ +/* Therefore setting the index to 0 returns the oldest value in the */ \ +/* window. */ \ +/* _q : window object */ \ +/* _i : index of element to read */ \ +/* _v : output value pointer */ \ +int WINDOW(_index)(WINDOW() _q, \ + unsigned int _i, \ + T * _v); \ + \ +/* Shifts a single sample into the right side of the window, pushing */ \ +/* the oldest (left-most) sample out of the end. Unlike stacks, the */ \ +/* window object has no equivalent "pop" method, as values are retained */ \ +/* in memory until they are overwritten. */ \ +/* _q : window object */ \ +/* _v : single input element */ \ +int WINDOW(_push)(WINDOW() _q, \ + T _v); \ + \ +/* Write array of elements onto window buffer */ \ +/* Effectively, this is equivalent to pushing each sample one at a */ \ +/* time, but executes much faster. */ \ +/* _q : window object */ \ +/* _v : input array of values to write */ \ +/* _n : number of input values to write */ \ +int WINDOW(_write)(WINDOW() _q, \ + T * _v, \ + unsigned int _n); \ + +// Define window APIs +LIQUID_WINDOW_DEFINE_API(LIQUID_WINDOW_MANGLE_FLOAT, float) +LIQUID_WINDOW_DEFINE_API(LIQUID_WINDOW_MANGLE_CFLOAT, liquid_float_complex) +//LIQUID_WINDOW_DEFINE_API(LIQUID_WINDOW_MANGLE_UINT, unsigned int) + + +// wdelay functions : windowed-delay +// Implements an efficient z^-k delay with minimal memory +#define LIQUID_WDELAY_MANGLE_FLOAT(name) LIQUID_CONCAT(wdelayf, name) +#define LIQUID_WDELAY_MANGLE_CFLOAT(name) LIQUID_CONCAT(wdelaycf, name) +//#define LIQUID_WDELAY_MANGLE_UINT(name) LIQUID_CONCAT(wdelayui, name) + +// large macro +// WDELAY : name-mangling macro +// T : data type +#define LIQUID_WDELAY_DEFINE_API(WDELAY,T) \ + \ +/* Efficient digital delay line using a minimal amount of memory */ \ +typedef struct WDELAY(_s) * WDELAY(); \ + \ +/* Create delay buffer object with a particular number of samples of */ \ +/* delay */ \ +/* _delay : number of samples of delay in the wdelay object */ \ +WDELAY() WDELAY(_create)(unsigned int _delay); \ + \ +/* Re-create delay buffer object, adjusting the delay size, preserving */ \ +/* the internal state of the object */ \ +/* _q : old delay buffer object */ \ +/* _delay : delay for new object */ \ +WDELAY() WDELAY(_recreate)(WDELAY() _q, \ + unsigned int _delay); \ + \ +/* Destroy delay buffer object, freeing internal memory */ \ +void WDELAY(_destroy)(WDELAY() _q); \ + \ +/* Print delay buffer object's state to stdout */ \ +void WDELAY(_print)(WDELAY() _q); \ + \ +/* Clear/reset state of object */ \ +void WDELAY(_reset)(WDELAY() _q); \ + \ +/* Read delayed sample at the head of the buffer and store it to the */ \ +/* output pointer */ \ +/* _q : delay buffer object */ \ +/* _v : value of delayed element */ \ +void WDELAY(_read)(WDELAY() _q, \ + T * _v); \ + \ +/* Push new sample into delay buffer object */ \ +/* _q : delay buffer object */ \ +/* _v : new value to be added to buffer */ \ +void WDELAY(_push)(WDELAY() _q, \ + T _v); \ + +// Define wdelay APIs +LIQUID_WDELAY_DEFINE_API(LIQUID_WDELAY_MANGLE_FLOAT, float) +LIQUID_WDELAY_DEFINE_API(LIQUID_WDELAY_MANGLE_CFLOAT, liquid_float_complex) +//LIQUID_WDELAY_DEFINE_API(LIQUID_WDELAY_MANGLE_UINT, unsigned int) + + + +// +// MODULE : channel +// + +#define LIQUID_CHANNEL_MANGLE_CCCF(name) LIQUID_CONCAT(channel_cccf,name) + +// large macro +// CHANNEL : name-mangling macro +// TO : output data type +// TC : coefficients data type +// TI : input data type +#define LIQUID_CHANNEL_DEFINE_API(CHANNEL,TO,TC,TI) \ + \ +/* Channel emulation */ \ +typedef struct CHANNEL(_s) * CHANNEL(); \ + \ +/* Create channel object with default parameters */ \ +CHANNEL() CHANNEL(_create)(void); \ + \ +/* Destroy channel object, freeing all internal memory */ \ +int CHANNEL(_destroy)(CHANNEL() _q); \ + \ +/* Print channel object internals to standard output */ \ +int CHANNEL(_print)(CHANNEL() _q); \ + \ +/* Include additive white Gausss noise impairment */ \ +/* _q : channel object */ \ +/* _N0dB : noise floor power spectral density [dB] */ \ +/* _SNRdB : signal-to-noise ratio [dB] */ \ +int CHANNEL(_add_awgn)(CHANNEL() _q, \ + float _N0dB, \ + float _SNRdB); \ + \ +/* Include carrier offset impairment */ \ +/* _q : channel object */ \ +/* _frequency : carrier frequency offset [radians/sample] */ \ +/* _phase : carrier phase offset [radians] */ \ +int CHANNEL(_add_carrier_offset)(CHANNEL() _q, \ + float _frequency, \ + float _phase); \ + \ +/* Include multi-path channel impairment */ \ +/* _q : channel object */ \ +/* _h : channel coefficients (NULL for random) */ \ +/* _h_len : number of channel coefficients */ \ +int CHANNEL(_add_multipath)(CHANNEL() _q, \ + TC * _h, \ + unsigned int _h_len); \ + \ +/* Include slowly-varying shadowing impairment */ \ +/* _q : channel object */ \ +/* _sigma : standard deviation for log-normal shadowing */ \ +/* _fd : Doppler frequency, 0 <= _fd < 0.5 */ \ +int CHANNEL(_add_shadowing)(CHANNEL() _q, \ + float _sigma, \ + float _fd); \ + \ +/* Apply channel impairments on single input sample */ \ +/* _q : channel object */ \ +/* _x : input sample */ \ +/* _y : pointer to output sample */ \ +int CHANNEL(_execute)(CHANNEL() _q, \ + TI _x, \ + TO * _y); \ + \ +/* Apply channel impairments on block of samples */ \ +/* _q : channel object */ \ +/* _x : input array, [size: _n x 1] */ \ +/* _n : input array, length */ \ +/* _y : output array, [size: _n x 1] */ \ +int CHANNEL(_execute_block)(CHANNEL() _q, \ + TI * _x, \ + unsigned int _n, \ + TO * _y); \ + +LIQUID_CHANNEL_DEFINE_API(LIQUID_CHANNEL_MANGLE_CCCF, + liquid_float_complex, + liquid_float_complex, + liquid_float_complex) + + +// +// time-varying multi-path channel +// +#define LIQUID_TVMPCH_MANGLE_CCCF(name) LIQUID_CONCAT(tvmpch_cccf,name) + +// large macro +// TVMPCH : name-mangling macro +// TO : output data type +// TC : coefficients data type +// TI : input data type +#define LIQUID_TVMPCH_DEFINE_API(TVMPCH,TO,TC,TI) \ + \ +/* Time-varying multipath channel emulation */ \ +typedef struct TVMPCH(_s) * TVMPCH(); \ + \ +/* Create time-varying multi-path channel emulator object, specifying */ \ +/* the number of coefficients, the standard deviation of coefficients, */ \ +/* and the coherence time. The larger the standard deviation, the more */ \ +/* dramatic the frequency response of the channel. The shorter the */ \ +/* coeherent time, the faster the channel effects. */ \ +/* _n : number of coefficients, _n > 0 */ \ +/* _std : standard deviation, _std >= 0 */ \ +/* _tau : normalized coherence time, 0 < _tau < 1 */ \ +TVMPCH() TVMPCH(_create)(unsigned int _n, \ + float _std, \ + float _tau); \ + \ +/* Destroy channel object, freeing all internal memory */ \ +int TVMPCH(_destroy)(TVMPCH() _q); \ + \ +/* Reset object */ \ +int TVMPCH(_reset)(TVMPCH() _q); \ + \ +/* Print channel object internals to standard output */ \ +int TVMPCH(_print)(TVMPCH() _q); \ + \ +/* Push sample into emulator */ \ +/* _q : channel object */ \ +/* _x : input sample */ \ +int TVMPCH(_push)(TVMPCH() _q, \ + TI _x); \ + \ +/* Compute output sample */ \ +/* _q : channel object */ \ +/* _y : output sample */ \ +int TVMPCH(_execute)(TVMPCH() _q, \ + TO * _y); \ + \ +/* Apply channel impairments on a block of samples */ \ +/* _q : channel object */ \ +/* _x : input array, [size: _n x 1] */ \ +/* _n : input array length */ \ +/* _y : output array, [size: _n x 1] */ \ +int TVMPCH(_execute_block)(TVMPCH() _q, \ + TI * _x, \ + unsigned int _n, \ + TO * _y); \ + +LIQUID_TVMPCH_DEFINE_API(LIQUID_TVMPCH_MANGLE_CCCF, + liquid_float_complex, + liquid_float_complex, + liquid_float_complex) + + +// +// MODULE : dotprod (vector dot product) +// + +#define LIQUID_DOTPROD_MANGLE_RRRF(name) LIQUID_CONCAT(dotprod_rrrf,name) +#define LIQUID_DOTPROD_MANGLE_CCCF(name) LIQUID_CONCAT(dotprod_cccf,name) +#define LIQUID_DOTPROD_MANGLE_CRCF(name) LIQUID_CONCAT(dotprod_crcf,name) + +// large macro +// DOTPROD : name-mangling macro +// TO : output data type +// TC : coefficients data type +// TI : input data type +#define LIQUID_DOTPROD_DEFINE_API(DOTPROD,TO,TC,TI) \ + \ +/* Vector dot product operation */ \ +typedef struct DOTPROD(_s) * DOTPROD(); \ + \ +/* Run dot product without creating object. This is less efficient than */ \ +/* creating the object as it is an unoptimized portable implementation */ \ +/* that doesn't take advantage of processor extensions. It is meant to */ \ +/* provide a baseline for performance comparison and a convenient way */ \ +/* to invoke a dot product operation when fast operation is not */ \ +/* necessary. */ \ +/* _v : coefficients array [size: _n x 1] */ \ +/* _x : input array [size: _n x 1] */ \ +/* _n : dotprod length, _n > 0 */ \ +/* _y : output sample pointer */ \ +void DOTPROD(_run)( TC * _v, \ + TI * _x, \ + unsigned int _n, \ + TO * _y); \ + \ +/* This provides the same unoptimized operation as the 'run()' method */ \ +/* above, but with the loop unrolled by a factor of 4. It is marginally */ \ +/* faster than 'run()' without unrolling the loop. */ \ +/* _v : coefficients array [size: _n x 1] */ \ +/* _x : input array [size: _n x 1] */ \ +/* _n : dotprod length, _n > 0 */ \ +/* _y : output sample pointer */ \ +void DOTPROD(_run4)( TC * _v, \ + TI * _x, \ + unsigned int _n, \ + TO * _y); \ + \ +/* Create vector dot product object */ \ +/* _v : coefficients array [size: _n x 1] */ \ +/* _n : dotprod length, _n > 0 */ \ +DOTPROD() DOTPROD(_create)(TC * _v, \ + unsigned int _n); \ + \ +/* Re-create dot product object of potentially a different length with */ \ +/* different coefficients. If the length of the dot product object does */ \ +/* not change, not memory reallocation is invoked. */ \ +/* _q : old dotprod object */ \ +/* _v : coefficients array [size: _n x 1] */ \ +/* _n : dotprod length, _n > 0 */ \ +DOTPROD() DOTPROD(_recreate)(DOTPROD() _q, \ + TC * _v, \ + unsigned int _n); \ + \ +/* Destroy dotprod object, freeing all internal memory */ \ +void DOTPROD(_destroy)(DOTPROD() _q); \ + \ +/* Print dotprod object internals to standard output */ \ +void DOTPROD(_print)(DOTPROD() _q); \ + \ +/* Execute dot product on an input array */ \ +/* _q : dotprod object */ \ +/* _x : input array [size: _n x 1] */ \ +/* _y : output sample pointer */ \ +void DOTPROD(_execute)(DOTPROD() _q, \ + TI * _x, \ + TO * _y); \ + +LIQUID_DOTPROD_DEFINE_API(LIQUID_DOTPROD_MANGLE_RRRF, + float, + float, + float) + +LIQUID_DOTPROD_DEFINE_API(LIQUID_DOTPROD_MANGLE_CCCF, + liquid_float_complex, + liquid_float_complex, + liquid_float_complex) + +LIQUID_DOTPROD_DEFINE_API(LIQUID_DOTPROD_MANGLE_CRCF, + liquid_float_complex, + float, + liquid_float_complex) + +// +// sum squared methods +// + +float liquid_sumsqf(float * _v, + unsigned int _n); + +float liquid_sumsqcf(liquid_float_complex * _v, + unsigned int _n); + + +// +// MODULE : equalization +// + +// least mean-squares (LMS) +#define LIQUID_EQLMS_MANGLE_RRRF(name) LIQUID_CONCAT(eqlms_rrrf,name) +#define LIQUID_EQLMS_MANGLE_CCCF(name) LIQUID_CONCAT(eqlms_cccf,name) + +// large macro +// EQLMS : name-mangling macro +// T : data type +#define LIQUID_EQLMS_DEFINE_API(EQLMS,T) \ + \ +/* Least mean-squares equalization object */ \ +typedef struct EQLMS(_s) * EQLMS(); \ + \ +/* Create LMS EQ initialized with external coefficients */ \ +/* _h : filter coefficients; set to NULL for {1,0,0...},[size: _n x 1] */ \ +/* _n : filter length */ \ +EQLMS() EQLMS(_create)(T * _h, \ + unsigned int _n); \ + \ +/* Create LMS EQ initialized with square-root Nyquist prototype filter */ \ +/* as initial set of coefficients. This is useful for applications */ \ +/* where the baseline matched filter is a good starting point, but */ \ +/* where equalization is needed to properly remove inter-symbol */ \ +/* interference. */ \ +/* The filter length is \(2 k m + 1\) */ \ +/* _type : filter type (e.g. LIQUID_FIRFILT_RRC) */ \ +/* _k : samples/symbol */ \ +/* _m : filter delay (symbols) */ \ +/* _beta : rolloff factor (0 < beta <= 1) */ \ +/* _dt : fractional sample delay */ \ +EQLMS() EQLMS(_create_rnyquist)(int _type, \ + unsigned int _k, \ + unsigned int _m, \ + float _beta, \ + float _dt); \ + \ +/* Create LMS EQ initialized with low-pass filter */ \ +/* _n : filter length */ \ +/* _fc : filter cut-off normalized to sample rate, 0 < _fc <= 0.5 */ \ +EQLMS() EQLMS(_create_lowpass)(unsigned int _n, \ + float _fc); \ + \ +/* Re-create EQ initialized with external coefficients */ \ +/* _q : equalizer object */ \ +/* _h : filter coefficients (NULL for {1,0,0...}), [size: _n x 1] */ \ +/* _h_len : filter length */ \ +EQLMS() EQLMS(_recreate)(EQLMS() _q, \ + T * _h, \ + unsigned int _h_len); \ + \ +/* Destroy equalizer object, freeing all internal memory */ \ +int EQLMS(_destroy)(EQLMS() _q); \ + \ +/* Reset equalizer object, clearing internal state */ \ +int EQLMS(_reset)(EQLMS() _q); \ + \ +/* Print equalizer internal state */ \ +int EQLMS(_print)(EQLMS() _q); \ + \ +/* Get equalizer learning rate */ \ +float EQLMS(_get_bw)(EQLMS() _q); \ + \ +/* Set equalizer learning rate */ \ +/* _q : equalizer object */ \ +/* _lambda : learning rate, _lambda > 0 */ \ +int EQLMS(_set_bw)(EQLMS() _q, \ + float _lambda); \ + \ +/* Push sample into equalizer internal buffer */ \ +/* _q : equalizer object */ \ +/* _x : input sample */ \ +int EQLMS(_push)(EQLMS() _q, \ + T _x); \ + \ +/* Push block of samples into internal buffer of equalizer object */ \ +/* _q : equalizer object */ \ +/* _x : input sample array, [size: _n x 1] */ \ +/* _n : input sample array length */ \ +int EQLMS(_push_block)(EQLMS() _q, \ + T * _x, \ + unsigned int _n); \ + \ +/* Execute internal dot product and return result */ \ +/* _q : equalizer object */ \ +/* _y : output sample */ \ +int EQLMS(_execute)(EQLMS() _q, \ + T * _y); \ + \ +/* Execute equalizer with block of samples using constant */ \ +/* modulus algorithm, operating on a decimation rate of _k */ \ +/* samples. */ \ +/* _q : equalizer object */ \ +/* _k : down-sampling rate */ \ +/* _x : input sample array [size: _n x 1] */ \ +/* _n : input sample array length */ \ +/* _y : output sample array [size: _n x 1] */ \ +int EQLMS(_execute_block)(EQLMS() _q, \ + unsigned int _k, \ + T * _x, \ + unsigned int _n, \ + T * _y); \ + \ +/* Step through one cycle of equalizer training */ \ +/* _q : equalizer object */ \ +/* _d : desired output */ \ +/* _d_hat : actual output */ \ +int EQLMS(_step)(EQLMS() _q, \ + T _d, \ + T _d_hat); \ + \ +/* Step through one cycle of equalizer training (blind) */ \ +/* _q : equalizer object */ \ +/* _d_hat : actual output */ \ +int EQLMS(_step_blind)(EQLMS() _q, \ + T _d_hat); \ + \ +/* Get equalizer's internal coefficients */ \ +/* _q : equalizer object */ \ +/* _w : weights, [size: _p x 1] */ \ +int EQLMS(_get_weights)(EQLMS() _q, \ + T * _w); \ + \ +/* Train equalizer object on group of samples */ \ +/* _q : equalizer object */ \ +/* _w : input/output weights, [size: _p x 1] */ \ +/* _x : received sample vector,[size: _n x 1] */ \ +/* _d : desired output vector, [size: _n x 1] */ \ +/* _n : input, output vector length */ \ +int EQLMS(_train)(EQLMS() _q, \ + T * _w, \ + T * _x, \ + T * _d, \ + unsigned int _n); \ + +LIQUID_EQLMS_DEFINE_API(LIQUID_EQLMS_MANGLE_RRRF, float) +LIQUID_EQLMS_DEFINE_API(LIQUID_EQLMS_MANGLE_CCCF, liquid_float_complex) + + +// recursive least-squares (RLS) +#define LIQUID_EQRLS_MANGLE_RRRF(name) LIQUID_CONCAT(eqrls_rrrf,name) +#define LIQUID_EQRLS_MANGLE_CCCF(name) LIQUID_CONCAT(eqrls_cccf,name) + +// large macro +// EQRLS : name-mangling macro +// T : data type +#define LIQUID_EQRLS_DEFINE_API(EQRLS,T) \ + \ +/* Recursive least mean-squares equalization object */ \ +typedef struct EQRLS(_s) * EQRLS(); \ + \ +/* Create RLS EQ initialized with external coefficients */ \ +/* _h : filter coefficients; set to NULL for {1,0,0...},[size: _n x 1] */ \ +/* _n : filter length */ \ +EQRLS() EQRLS(_create)(T * _h, \ + unsigned int _n); \ + \ +/* Re-create EQ initialized with external coefficients */ \ +/* _q : equalizer object */ \ +/* _h : filter coefficients (NULL for {1,0,0...}), [size: _n x 1] */ \ +/* _n : filter length */ \ +EQRLS() EQRLS(_recreate)(EQRLS() _q, \ + T * _h, \ + unsigned int _n); \ + \ +/* Destroy equalizer object, freeing all internal memory */ \ +int EQRLS(_destroy)(EQRLS() _q); \ + \ +/* Reset equalizer object, clearing internal state */ \ +int EQRLS(_reset)(EQRLS() _q); \ + \ +/* Print equalizer internal state */ \ +int EQRLS(_print)(EQRLS() _q); \ + \ +/* Get equalizer learning rate */ \ +float EQRLS(_get_bw)(EQRLS() _q); \ + \ +/* Set equalizer learning rate */ \ +/* _q : equalizer object */ \ +/* _mu : learning rate, _mu > 0 */ \ +int EQRLS(_set_bw)(EQRLS() _q, \ + float _mu); \ + \ +/* Push sample into equalizer internal buffer */ \ +/* _q : equalizer object */ \ +/* _x : input sample */ \ +int EQRLS(_push)(EQRLS() _q, T _x); \ + \ +/* Execute internal dot product and return result */ \ +/* _q : equalizer object */ \ +/* _y : output sample */ \ +int EQRLS(_execute)(EQRLS() _q, T * _y); \ + \ +/* Step through one cycle of equalizer training */ \ +/* _q : equalizer object */ \ +/* _d : desired output */ \ +/* _d_hat : actual output */ \ +int EQRLS(_step)(EQRLS() _q, T _d, T _d_hat); \ + \ +/* Get equalizer's internal coefficients */ \ +/* _q : equalizer object */ \ +/* _w : weights, [size: _p x 1] */ \ +int EQRLS(_get_weights)(EQRLS() _q, \ + T * _w); \ + \ +/* Train equalizer object on group of samples */ \ +/* _q : equalizer object */ \ +/* _w : input/output weights, [size: _p x 1] */ \ +/* _x : received sample vector,[size: _n x 1] */ \ +/* _d : desired output vector, [size: _n x 1] */ \ +/* _n : input, output vector length */ \ +int EQRLS(_train)(EQRLS() _q, \ + T * _w, \ + T * _x, \ + T * _d, \ + unsigned int _n); \ + +LIQUID_EQRLS_DEFINE_API(LIQUID_EQRLS_MANGLE_RRRF, float) +LIQUID_EQRLS_DEFINE_API(LIQUID_EQRLS_MANGLE_CCCF, liquid_float_complex) + + + + +// +// MODULE : fec (forward error-correction) +// + +// soft bit values +#define LIQUID_SOFTBIT_0 (0) +#define LIQUID_SOFTBIT_1 (255) +#define LIQUID_SOFTBIT_ERASURE (127) + +// available CRC schemes +#define LIQUID_CRC_NUM_SCHEMES 7 +typedef enum { + LIQUID_CRC_UNKNOWN=0, // unknown/unavailable CRC scheme + LIQUID_CRC_NONE, // no error-detection + LIQUID_CRC_CHECKSUM, // 8-bit checksum + LIQUID_CRC_8, // 8-bit CRC + LIQUID_CRC_16, // 16-bit CRC + LIQUID_CRC_24, // 24-bit CRC + LIQUID_CRC_32 // 32-bit CRC +} crc_scheme; + +// pretty names for crc schemes +extern const char * crc_scheme_str[LIQUID_CRC_NUM_SCHEMES][2]; + +// Print compact list of existing and available CRC schemes +void liquid_print_crc_schemes(); + +// returns crc_scheme based on input string +crc_scheme liquid_getopt_str2crc(const char * _str); + +// get length of CRC (bytes) +unsigned int crc_get_length(crc_scheme _scheme); + +// generate error-detection key +// _scheme : error-detection scheme +// _msg : input data message, [size: _n x 1] +// _n : input data message size +unsigned int crc_generate_key(crc_scheme _scheme, + unsigned char * _msg, + unsigned int _n); + +// generate error-detection key and append to end of message +// _scheme : error-detection scheme (resulting in 'p' bytes) +// _msg : input data message, [size: _n+p x 1] +// _n : input data message size (excluding key at end) +int crc_append_key(crc_scheme _scheme, + unsigned char * _msg, + unsigned int _n); + +// validate message using error-detection key +// _scheme : error-detection scheme +// _msg : input data message, [size: _n x 1] +// _n : input data message size +// _key : error-detection key +int crc_validate_message(crc_scheme _scheme, + unsigned char * _msg, + unsigned int _n, + unsigned int _key); + +// check message with key appended to end of array +// _scheme : error-detection scheme (resulting in 'p' bytes) +// _msg : input data message, [size: _n+p x 1] +// _n : input data message size (excluding key at end) +int crc_check_key(crc_scheme _scheme, + unsigned char * _msg, + unsigned int _n); + +// get size of key (bytes) +unsigned int crc_sizeof_key(crc_scheme _scheme); + + +// available FEC schemes +#define LIQUID_FEC_NUM_SCHEMES 28 +typedef enum { + LIQUID_FEC_UNKNOWN=0, // unknown/unsupported scheme + LIQUID_FEC_NONE, // no error-correction + LIQUID_FEC_REP3, // simple repeat code, r1/3 + LIQUID_FEC_REP5, // simple repeat code, r1/5 + LIQUID_FEC_HAMMING74, // Hamming (7,4) block code, r1/2 (really 4/7) + LIQUID_FEC_HAMMING84, // Hamming (7,4) with extra parity bit, r1/2 + LIQUID_FEC_HAMMING128, // Hamming (12,8) block code, r2/3 + + LIQUID_FEC_GOLAY2412, // Golay (24,12) block code, r1/2 + LIQUID_FEC_SECDED2216, // SEC-DED (22,16) block code, r8/11 + LIQUID_FEC_SECDED3932, // SEC-DED (39,32) block code + LIQUID_FEC_SECDED7264, // SEC-DED (72,64) block code, r8/9 + + // codecs not defined internally (see http://www.ka9q.net/code/fec/) + LIQUID_FEC_CONV_V27, // r1/2, K=7, dfree=10 + LIQUID_FEC_CONV_V29, // r1/2, K=9, dfree=12 + LIQUID_FEC_CONV_V39, // r1/3, K=9, dfree=18 + LIQUID_FEC_CONV_V615, // r1/6, K=15, dfree<=57 (Heller 1968) + + // punctured (perforated) codes + LIQUID_FEC_CONV_V27P23, // r2/3, K=7, dfree=6 + LIQUID_FEC_CONV_V27P34, // r3/4, K=7, dfree=5 + LIQUID_FEC_CONV_V27P45, // r4/5, K=7, dfree=4 + LIQUID_FEC_CONV_V27P56, // r5/6, K=7, dfree=4 + LIQUID_FEC_CONV_V27P67, // r6/7, K=7, dfree=3 + LIQUID_FEC_CONV_V27P78, // r7/8, K=7, dfree=3 + + LIQUID_FEC_CONV_V29P23, // r2/3, K=9, dfree=7 + LIQUID_FEC_CONV_V29P34, // r3/4, K=9, dfree=6 + LIQUID_FEC_CONV_V29P45, // r4/5, K=9, dfree=5 + LIQUID_FEC_CONV_V29P56, // r5/6, K=9, dfree=5 + LIQUID_FEC_CONV_V29P67, // r6/7, K=9, dfree=4 + LIQUID_FEC_CONV_V29P78, // r7/8, K=9, dfree=4 + + // Reed-Solomon codes + LIQUID_FEC_RS_M8 // m=8, n=255, k=223 +} fec_scheme; + +// pretty names for fec schemes +extern const char * fec_scheme_str[LIQUID_FEC_NUM_SCHEMES][2]; + +// Print compact list of existing and available FEC schemes +void liquid_print_fec_schemes(); + +// returns fec_scheme based on input string +fec_scheme liquid_getopt_str2fec(const char * _str); + +// fec object (pointer to fec structure) +typedef struct fec_s * fec; + +// return the encoded message length using a particular error- +// correction scheme (object-independent method) +// _scheme : forward error-correction scheme +// _msg_len : raw, uncoded message length +unsigned int fec_get_enc_msg_length(fec_scheme _scheme, + unsigned int _msg_len); + +// get the theoretical rate of a particular forward error- +// correction scheme (object-independent method) +float fec_get_rate(fec_scheme _scheme); + +// create a fec object of a particular scheme +// _scheme : error-correction scheme +// _opts : (ignored) +fec fec_create(fec_scheme _scheme, + void *_opts); + +// recreate fec object +// _q : old fec object +// _scheme : new error-correction scheme +// _opts : (ignored) +fec fec_recreate(fec _q, + fec_scheme _scheme, + void *_opts); + +// destroy fec object +int fec_destroy(fec _q); + +// print fec object internals +int fec_print(fec _q); + +// encode a block of data using a fec scheme +// _q : fec object +// _dec_msg_len : decoded message length +// _msg_dec : decoded message +// _msg_enc : encoded message +int fec_encode(fec _q, + unsigned int _dec_msg_len, + unsigned char * _msg_dec, + unsigned char * _msg_enc); + +// decode a block of data using a fec scheme +// _q : fec object +// _dec_msg_len : decoded message length +// _msg_enc : encoded message +// _msg_dec : decoded message +int fec_decode(fec _q, + unsigned int _dec_msg_len, + unsigned char * _msg_enc, + unsigned char * _msg_dec); + +// decode a block of data using a fec scheme (soft decision) +// _q : fec object +// _dec_msg_len : decoded message length +// _msg_enc : encoded message (soft bits) +// _msg_dec : decoded message +int fec_decode_soft(fec _q, + unsigned int _dec_msg_len, + unsigned char * _msg_enc, + unsigned char * _msg_dec); + +// +// Packetizer +// + +// computes the number of encoded bytes after packetizing +// +// _n : number of uncoded input bytes +// _crc : error-detecting scheme +// _fec0 : inner forward error-correction code +// _fec1 : outer forward error-correction code +unsigned int packetizer_compute_enc_msg_len(unsigned int _n, + int _crc, + int _fec0, + int _fec1); + +// computes the number of decoded bytes before packetizing +// +// _k : number of encoded bytes +// _crc : error-detecting scheme +// _fec0 : inner forward error-correction code +// _fec1 : outer forward error-correction code +unsigned int packetizer_compute_dec_msg_len(unsigned int _k, + int _crc, + int _fec0, + int _fec1); + +typedef struct packetizer_s * packetizer; + +// create packetizer object +// +// _n : number of uncoded input bytes +// _crc : error-detecting scheme +// _fec0 : inner forward error-correction code +// _fec1 : outer forward error-correction code +packetizer packetizer_create(unsigned int _dec_msg_len, + int _crc, + int _fec0, + int _fec1); + +// re-create packetizer object +// +// _p : initialz packetizer object +// _n : number of uncoded input bytes +// _crc : error-detecting scheme +// _fec0 : inner forward error-correction code +// _fec1 : outer forward error-correction code +packetizer packetizer_recreate(packetizer _p, + unsigned int _dec_msg_len, + int _crc, + int _fec0, + int _fec1); + +// destroy packetizer object +void packetizer_destroy(packetizer _p); + +// print packetizer object internals +void packetizer_print(packetizer _p); + +// access methods +unsigned int packetizer_get_dec_msg_len(packetizer _p); +unsigned int packetizer_get_enc_msg_len(packetizer _p); +crc_scheme packetizer_get_crc (packetizer _p); +fec_scheme packetizer_get_fec0 (packetizer _p); +fec_scheme packetizer_get_fec1 (packetizer _p); + + +// Execute the packetizer on an input message +// +// _p : packetizer object +// _msg : input message (uncoded bytes) +// _pkt : encoded output message +void packetizer_encode(packetizer _p, + const unsigned char * _msg, + unsigned char * _pkt); + +// Execute the packetizer to decode an input message, return validity +// check of resulting data +// +// _p : packetizer object +// _pkt : input message (coded bytes) +// _msg : decoded output message +int packetizer_decode(packetizer _p, + const unsigned char * _pkt, + unsigned char * _msg); + +// Execute the packetizer to decode an input message, return validity +// check of resulting data +// +// _p : packetizer object +// _pkt : input message (coded soft bits) +// _msg : decoded output message +int packetizer_decode_soft(packetizer _p, + const unsigned char * _pkt, + unsigned char * _msg); + + +// +// interleaver +// +typedef struct interleaver_s * interleaver; + +// create interleaver +// _n : number of bytes +interleaver interleaver_create(unsigned int _n); + +// destroy interleaver object +void interleaver_destroy(interleaver _q); + +// print interleaver object internals +void interleaver_print(interleaver _q); + +// set depth (number of internal iterations) +// _q : interleaver object +// _depth : depth +void interleaver_set_depth(interleaver _q, + unsigned int _depth); + +// execute forward interleaver (encoder) +// _q : interleaver object +// _msg_dec : decoded (un-interleaved) message +// _msg_enc : encoded (interleaved) message +void interleaver_encode(interleaver _q, + unsigned char * _msg_dec, + unsigned char * _msg_enc); + +// execute forward interleaver (encoder) on soft bits +// _q : interleaver object +// _msg_dec : decoded (un-interleaved) message +// _msg_enc : encoded (interleaved) message +void interleaver_encode_soft(interleaver _q, + unsigned char * _msg_dec, + unsigned char * _msg_enc); + +// execute reverse interleaver (decoder) +// _q : interleaver object +// _msg_enc : encoded (interleaved) message +// _msg_dec : decoded (un-interleaved) message +void interleaver_decode(interleaver _q, + unsigned char * _msg_enc, + unsigned char * _msg_dec); + +// execute reverse interleaver (decoder) on soft bits +// _q : interleaver object +// _msg_enc : encoded (interleaved) message +// _msg_dec : decoded (un-interleaved) message +void interleaver_decode_soft(interleaver _q, + unsigned char * _msg_enc, + unsigned char * _msg_dec); + + + +// +// MODULE : fft (fast Fourier transform) +// + +// type of transform +typedef enum { + LIQUID_FFT_UNKNOWN = 0, // unknown transform type + + // regular complex one-dimensional transforms + LIQUID_FFT_FORWARD = +1, // complex one-dimensional FFT + LIQUID_FFT_BACKWARD = -1, // complex one-dimensional inverse FFT + + // discrete cosine transforms + LIQUID_FFT_REDFT00 = 10, // real one-dimensional DCT-I + LIQUID_FFT_REDFT10 = 11, // real one-dimensional DCT-II + LIQUID_FFT_REDFT01 = 12, // real one-dimensional DCT-III + LIQUID_FFT_REDFT11 = 13, // real one-dimensional DCT-IV + + // discrete sine transforms + LIQUID_FFT_RODFT00 = 20, // real one-dimensional DST-I + LIQUID_FFT_RODFT10 = 21, // real one-dimensional DST-II + LIQUID_FFT_RODFT01 = 22, // real one-dimensional DST-III + LIQUID_FFT_RODFT11 = 23, // real one-dimensional DST-IV + + // modified discrete cosine transform + LIQUID_FFT_MDCT = 30, // MDCT + LIQUID_FFT_IMDCT = 31, // IMDCT +} liquid_fft_type; + +#define LIQUID_FFT_MANGLE_FLOAT(name) LIQUID_CONCAT(fft,name) + +// Macro : FFT +// FFT : name-mangling macro +// T : primitive data type +// TC : primitive data type (complex) +#define LIQUID_FFT_DEFINE_API(FFT,T,TC) \ + \ +/* Fast Fourier Transform (FFT) and inverse (plan) object */ \ +typedef struct FFT(plan_s) * FFT(plan); \ + \ +/* Create regular complex one-dimensional transform */ \ +/* _n : transform size */ \ +/* _x : pointer to input array [size: _n x 1] */ \ +/* _y : pointer to output array [size: _n x 1] */ \ +/* _dir : direction (e.g. LIQUID_FFT_FORWARD) */ \ +/* _flags : options, optimization */ \ +FFT(plan) FFT(_create_plan)(unsigned int _n, \ + TC * _x, \ + TC * _y, \ + int _dir, \ + int _flags); \ + \ +/* Create real-to-real one-dimensional transform */ \ +/* _n : transform size */ \ +/* _x : pointer to input array [size: _n x 1] */ \ +/* _y : pointer to output array [size: _n x 1] */ \ +/* _type : transform type (e.g. LIQUID_FFT_REDFT00) */ \ +/* _flags : options, optimization */ \ +FFT(plan) FFT(_create_plan_r2r_1d)(unsigned int _n, \ + T * _x, \ + T * _y, \ + int _type, \ + int _flags); \ + \ +/* Destroy transform and free all internally-allocated memory */ \ +int FFT(_destroy_plan)(FFT(plan) _p); \ + \ +/* Print transform plan and internal strategy to stdout. This includes */ \ +/* information on the strategy for computing large transforms with many */ \ +/* prime factors or with large prime factors. */ \ +int FFT(_print_plan)(FFT(plan) _p); \ + \ +/* Run the transform */ \ +int FFT(_execute)(FFT(plan) _p); \ + \ +/* Perform n-point FFT allocating plan internally */ \ +/* _nfft : fft size */ \ +/* _x : input array [size: _nfft x 1] */ \ +/* _y : output array [size: _nfft x 1] */ \ +/* _dir : fft direction: LIQUID_FFT_{FORWARD,BACKWARD} */ \ +/* _flags : fft flags */ \ +int FFT(_run)(unsigned int _n, \ + TC * _x, \ + TC * _y, \ + int _dir, \ + int _flags); \ + \ +/* Perform n-point real one-dimensional FFT allocating plan internally */ \ +/* _nfft : fft size */ \ +/* _x : input array [size: _nfft x 1] */ \ +/* _y : output array [size: _nfft x 1] */ \ +/* _type : fft type, e.g. LIQUID_FFT_REDFT10 */ \ +/* _flags : fft flags */ \ +int FFT(_r2r_1d_run)(unsigned int _n, \ + T * _x, \ + T * _y, \ + int _type, \ + int _flags); \ + \ +/* Perform _n-point fft shift */ \ +/* _x : input array [size: _n x 1] */ \ +/* _n : input array size */ \ +int FFT(_shift)(TC * _x, \ + unsigned int _n); \ + + +LIQUID_FFT_DEFINE_API(LIQUID_FFT_MANGLE_FLOAT,float,liquid_float_complex) + +// antiquated fft methods +// FFT(plan) FFT(_create_plan_mdct)(unsigned int _n, +// T * _x, +// T * _y, +// int _kind, +// int _flags); + + +// +// spectral periodogram +// + +#define LIQUID_SPGRAM_MANGLE_CFLOAT(name) LIQUID_CONCAT(spgramcf,name) +#define LIQUID_SPGRAM_MANGLE_FLOAT(name) LIQUID_CONCAT(spgramf, name) + +#define LIQUID_SPGRAM_PSD_MIN (1e-12) + +// Macro : SPGRAM +// SPGRAM : name-mangling macro +// T : primitive data type +// TC : primitive data type (complex) +// TI : primitive data type (input) +#define LIQUID_SPGRAM_DEFINE_API(SPGRAM,T,TC,TI) \ + \ +/* Spectral periodogram object for computing power spectral density */ \ +/* estimates of various signals */ \ +typedef struct SPGRAM(_s) * SPGRAM(); \ + \ +/* Create spgram object, fully defined */ \ +/* _nfft : transform (FFT) size, _nfft >= 2 */ \ +/* _wtype : window type, e.g. LIQUID_WINDOW_HAMMING */ \ +/* _window_len : window length, 1 <= _window_len <= _nfft */ \ +/* _delay : delay between transforms, _delay > 0 */ \ +SPGRAM() SPGRAM(_create)(unsigned int _nfft, \ + int _wtype, \ + unsigned int _window_len, \ + unsigned int _delay); \ + \ +/* Create default spgram object of a particular transform size using */ \ +/* the Kaiser-Bessel window (LIQUID_WINDOW_KAISER), a window length */ \ +/* equal to _nfft/2, and a delay of _nfft/4 */ \ +/* _nfft : FFT size, _nfft >= 2 */ \ +SPGRAM() SPGRAM(_create_default)(unsigned int _nfft); \ + \ +/* Destroy spgram object, freeing all internally-allocated memory */ \ +int SPGRAM(_destroy)(SPGRAM() _q); \ + \ +/* Clears the internal state of the object, but not the internal buffer */ \ +int SPGRAM(_clear)(SPGRAM() _q); \ + \ +/* Reset the object to its original state completely. This effectively */ \ +/* executes the clear() method and then resets the internal buffer */ \ +int SPGRAM(_reset)(SPGRAM() _q); \ + \ +/* Print internal state of the object to stdout */ \ +int SPGRAM(_print)(SPGRAM() _q); \ + \ +/* Set the filter bandwidth for accumulating independent transform */ \ +/* squared magnitude outputs. */ \ +/* This is used to compute a running time-average power spectral */ \ +/* density output. */ \ +/* The value of _alpha determines how the power spectral estimate is */ \ +/* accumulated across transforms and can range from 0 to 1 with a */ \ +/* special case of -1 to accumulate infinitely. */ \ +/* Setting _alpha to 0 minimizes the bandwidth and the PSD estimate */ \ +/* will never update. */ \ +/* Setting _alpha to 1 forces the object to always use the most recent */ \ +/* spectral estimate. */ \ +/* Setting _alpha to -1 is a special case to enable infinite spectral */ \ +/* accumulation. */ \ +/* _q : spectral periodogram object */ \ +/* _alpha : forgetting factor, set to -1 for infinite, 0<=_alpha<=1 */ \ +int SPGRAM(_set_alpha)(SPGRAM() _q, \ + float _alpha); \ + \ +/* Get the filter bandwidth for accumulating independent transform */ \ +/* squared magnitude outputs. */ \ +float SPGRAM(_get_alpha)(SPGRAM() _q); \ + \ +/* Set the center frequency of the received signal. */ \ +/* This is for display purposes only when generating the output image. */ \ +/* _q : spectral periodogram object */ \ +/* _freq : center frequency [Hz] */ \ +int SPGRAM(_set_freq)(SPGRAM() _q, \ + float _freq); \ + \ +/* Set the sample rate (frequency) of the received signal. */ \ +/* This is for display purposes only when generating the output image. */ \ +/* _q : spectral periodogram object */ \ +/* _rate : sample rate [Hz] */ \ +int SPGRAM(_set_rate)(SPGRAM() _q, \ + float _rate); \ + \ +/* Get transform (FFT) size */ \ +unsigned int SPGRAM(_get_nfft)(SPGRAM() _q); \ + \ +/* Get window length */ \ +unsigned int SPGRAM(_get_window_len)(SPGRAM() _q); \ + \ +/* Get delay between transforms */ \ +unsigned int SPGRAM(_get_delay)(SPGRAM() _q); \ + \ +/* Get number of samples processed since reset */ \ +unsigned long long int SPGRAM(_get_num_samples)(SPGRAM() _q); \ + \ +/* Get number of samples processed since object was created */ \ +unsigned long long int SPGRAM(_get_num_samples_total)(SPGRAM() _q); \ + \ +/* Get number of transforms processed since reset */ \ +unsigned long long int SPGRAM(_get_num_transforms)(SPGRAM() _q); \ + \ +/* Get number of transforms processed since object was created */ \ +unsigned long long int SPGRAM(_get_num_transforms_total)(SPGRAM() _q); \ + \ +/* Push a single sample into the object, executing internal transform */ \ +/* as necessary. */ \ +/* _q : spgram object */ \ +/* _x : input sample */ \ +int SPGRAM(_push)(SPGRAM() _q, \ + TI _x); \ + \ +/* Write a block of samples to the object, executing internal */ \ +/* transform as necessary. */ \ +/* _q : spgram object */ \ +/* _x : input buffer [size: _n x 1] */ \ +/* _n : input buffer length */ \ +int SPGRAM(_write)(SPGRAM() _q, \ + TI * _x, \ + unsigned int _n); \ + \ +/* Compute spectral periodogram output (fft-shifted values in dB) from */ \ +/* current buffer contents */ \ +/* _q : spgram object */ \ +/* _X : output spectrum (dB), [size: _nfft x 1] */ \ +int SPGRAM(_get_psd)(SPGRAM() _q, \ + T * _X); \ + \ +/* Export stand-alone gnuplot file for plotting output spectrum, */ \ +/* returning 0 on sucess, anything other than 0 for failure */ \ +/* _q : spgram object */ \ +/* _filename : input buffer [size: _n x 1] */ \ +int SPGRAM(_export_gnuplot)(SPGRAM() _q, \ + const char * _filename); \ + \ +/* Estimate spectrum on input signal (create temporary object for */ \ +/* convenience */ \ +/* _nfft : FFT size */ \ +/* _x : input signal [size: _n x 1] */ \ +/* _n : input signal length */ \ +/* _psd : output spectrum, [size: _nfft x 1] */ \ +int SPGRAM(_estimate_psd)(unsigned int _nfft, \ + TI * _x, \ + unsigned int _n, \ + T * _psd); \ + +LIQUID_SPGRAM_DEFINE_API(LIQUID_SPGRAM_MANGLE_CFLOAT, + float, + liquid_float_complex, + liquid_float_complex) + +LIQUID_SPGRAM_DEFINE_API(LIQUID_SPGRAM_MANGLE_FLOAT, + float, + liquid_float_complex, + float) + +// +// asgram : ascii spectral periodogram +// + +#define LIQUID_ASGRAM_MANGLE_CFLOAT(name) LIQUID_CONCAT(asgramcf,name) +#define LIQUID_ASGRAM_MANGLE_FLOAT(name) LIQUID_CONCAT(asgramf, name) + +// Macro : ASGRAM +// ASGRAM : name-mangling macro +// T : primitive data type +// TC : primitive data type (complex) +// TI : primitive data type (input) +#define LIQUID_ASGRAM_DEFINE_API(ASGRAM,T,TC,TI) \ + \ +/* ASCII spectral periodogram for computing and displaying an estimate */ \ +/* of a signal's power spectrum with ASCII characters */ \ +typedef struct ASGRAM(_s) * ASGRAM(); \ + \ +/* Create asgram object with size _nfft */ \ +/* _nfft : size of FFT taken for each transform (character width) */ \ +ASGRAM() ASGRAM(_create)(unsigned int _nfft); \ + \ +/* Destroy asgram object, freeing all internally-allocated memory */ \ +int ASGRAM(_destroy)(ASGRAM() _q); \ + \ +/* Reset the internal state of the asgram object */ \ +int ASGRAM(_reset)(ASGRAM() _q); \ + \ +/* Set the scale and offset for spectrogram in terms of dB for display */ \ +/* purposes */ \ +/* _q : asgram object */ \ +/* _ref : signal reference level [dB] */ \ +/* _div : signal division [dB] */ \ +int ASGRAM(_set_scale)(ASGRAM() _q, \ + float _ref, \ + float _div); \ + \ +/* Set the display's 10 characters for output string starting from the */ \ +/* weakest and ending with the strongest */ \ +/* _q : asgram object */ \ +/* _ascii : 10-character display, default: " .,-+*&NM#" */ \ +int ASGRAM(_set_display)(ASGRAM() _q, \ + const char * _ascii); \ + \ +/* Push a single sample into the asgram object, executing internal */ \ +/* transform as necessary. */ \ +/* _q : asgram object */ \ +/* _x : input sample */ \ +int ASGRAM(_push)(ASGRAM() _q, \ + TI _x); \ + \ +/* Write a block of samples to the asgram object, executing internal */ \ +/* transforms as necessary. */ \ +/* _q : asgram object */ \ +/* _x : input buffer [size: _n x 1] */ \ +/* _n : input buffer length */ \ +int ASGRAM(_write)(ASGRAM() _q, \ + TI * _x, \ + unsigned int _n); \ + \ +/* Compute spectral periodogram output from current buffer contents */ \ +/* and return the ascii character string to display along with the peak */ \ +/* value and its frequency location */ \ +/* _q : asgram object */ \ +/* _ascii : output ASCII string [size: _nfft x 1] */ \ +/* _peakval : peak power spectral density value [dB] */ \ +/* _peakfreq : peak power spectral density frequency */ \ +int ASGRAM(_execute)(ASGRAM() _q, \ + char * _ascii, \ + float * _peakval, \ + float * _peakfreq); \ + \ +/* Compute spectral periodogram output from current buffer contents and */ \ +/* print standard format to stdout */ \ +int ASGRAM(_print)(ASGRAM() _q); \ + +LIQUID_ASGRAM_DEFINE_API(LIQUID_ASGRAM_MANGLE_CFLOAT, + float, + liquid_float_complex, + liquid_float_complex) + +LIQUID_ASGRAM_DEFINE_API(LIQUID_ASGRAM_MANGLE_FLOAT, + float, + liquid_float_complex, + float) + +// +// spectral periodogram waterfall +// + +#define LIQUID_SPWATERFALL_MANGLE_CFLOAT(name) LIQUID_CONCAT(spwaterfallcf,name) +#define LIQUID_SPWATERFALL_MANGLE_FLOAT(name) LIQUID_CONCAT(spwaterfallf, name) + +// Macro : SPWATERFALL +// SPWATERFALL : name-mangling macro +// T : primitive data type +// TC : primitive data type (complex) +// TI : primitive data type (input) +#define LIQUID_SPWATERFALL_DEFINE_API(SPWATERFALL,T,TC,TI) \ + \ +/* Spectral periodogram waterfall object for computing time-varying */ \ +/* power spectral density estimates */ \ +typedef struct SPWATERFALL(_s) * SPWATERFALL(); \ + \ +/* Create spwaterfall object, fully defined */ \ +/* _nfft : transform (FFT) size, _nfft >= 2 */ \ +/* _wtype : window type, e.g. LIQUID_WINDOW_HAMMING */ \ +/* _window_len : window length, 1 <= _window_len <= _nfft */ \ +/* _delay : delay between transforms, _delay > 0 */ \ +/* _time : number of aggregated transforms, _time > 0 */ \ +SPWATERFALL() SPWATERFALL(_create)(unsigned int _nfft, \ + int _wtype, \ + unsigned int _window_len, \ + unsigned int _delay, \ + unsigned int _time); \ + \ +/* Create default spwatefall object (Kaiser-Bessel window) */ \ +/* _nfft : transform size, _nfft >= 2 */ \ +/* _time : delay between transforms, _delay > 0 */ \ +SPWATERFALL() SPWATERFALL(_create_default)(unsigned int _nfft, \ + unsigned int _time); \ + \ +/* Destroy spwaterfall object, freeing all internally-allocated memory */ \ +int SPWATERFALL(_destroy)(SPWATERFALL() _q); \ + \ +/* Clears the internal state of the object, but not the internal buffer */ \ +int SPWATERFALL(_clear)(SPWATERFALL() _q); \ + \ +/* Reset the object to its original state completely. This effectively */ \ +/* executes the clear() method and then resets the internal buffer */ \ +int SPWATERFALL(_reset)(SPWATERFALL() _q); \ + \ +/* Print internal state of the object to stdout */ \ +int SPWATERFALL(_print)(SPWATERFALL() _q); \ + \ +/* Get number of samples processed since object was created */ \ +uint64_t SPWATERFALL(_get_num_samples_total)(SPWATERFALL() _q); \ + \ +/* Get FFT size (columns in PSD output) */ \ +unsigned int SPWATERFALL(_get_num_freq)(SPWATERFALL() _q); \ + \ +/* Get number of accumulated FFTs (rows in PSD output) */ \ +unsigned int SPWATERFALL(_get_num_time)(SPWATERFALL() _q); \ + \ +/* Get power spectral density (PSD), size: nfft x time */ \ +const T * SPWATERFALL(_get_psd)(SPWATERFALL() _q); \ + \ +/* Set the center frequency of the received signal. */ \ +/* This is for display purposes only when generating the output image. */ \ +/* _q : spectral periodogram waterfall object */ \ +/* _freq : center frequency [Hz] */ \ +int SPWATERFALL(_set_freq)(SPWATERFALL() _q, \ + float _freq); \ + \ +/* Set the sample rate (frequency) of the received signal. */ \ +/* This is for display purposes only when generating the output image. */ \ +/* _q : spectral periodogram waterfall object */ \ +/* _rate : sample rate [Hz] */ \ +int SPWATERFALL(_set_rate)(SPWATERFALL() _q, \ + float _rate); \ + \ +/* Set the canvas size. */ \ +/* This is for display purposes only when generating the output image. */ \ +/* _q : spectral periodogram waterfall object */ \ +/* _width : image width [pixels] */ \ +/* _height : image height [pixels] */ \ +int SPWATERFALL(_set_dims)(SPWATERFALL() _q, \ + unsigned int _width, \ + unsigned int _height); \ + \ +/* Set commands for executing directly before 'plot' statement. */ \ +/* _q : spectral periodogram waterfall object */ \ +/* _commands : gnuplot commands separated by semicolons */ \ +int SPWATERFALL(_set_commands)(SPWATERFALL() _q, \ + const char * _commands); \ + \ +/* Push a single sample into the object, executing internal transform */ \ +/* as necessary. */ \ +/* _q : spwaterfall object */ \ +/* _x : input sample */ \ +int SPWATERFALL(_push)(SPWATERFALL() _q, \ + TI _x); \ + \ +/* Write a block of samples to the object, executing internal */ \ +/* transform as necessary. */ \ +/* _q : spwaterfall object */ \ +/* _x : input buffer, [size: _n x 1] */ \ +/* _n : input buffer length */ \ +int SPWATERFALL(_write)(SPWATERFALL() _q, \ + TI * _x, \ + unsigned int _n); \ + \ +/* Export set of files for plotting */ \ +/* _q : spwaterfall object */ \ +/* _base : base filename (will export .gnu, .bin, and .png files) */ \ +int SPWATERFALL(_export)(SPWATERFALL() _q, \ + const char * _base); \ + + +LIQUID_SPWATERFALL_DEFINE_API(LIQUID_SPWATERFALL_MANGLE_CFLOAT, + float, + liquid_float_complex, + liquid_float_complex) + +LIQUID_SPWATERFALL_DEFINE_API(LIQUID_SPWATERFALL_MANGLE_FLOAT, + float, + liquid_float_complex, + float) + + +// +// MODULE : filter +// + +// +// firdes: finite impulse response filter design +// + +// prototypes +#define LIQUID_FIRFILT_NUM_TYPES (16) +typedef enum { + LIQUID_FIRFILT_UNKNOWN=0, // unknown filter type + + // Nyquist filter prototypes + LIQUID_FIRFILT_KAISER, // Nyquist Kaiser filter + LIQUID_FIRFILT_PM, // Parks-McClellan filter + LIQUID_FIRFILT_RCOS, // raised-cosine filter + LIQUID_FIRFILT_FEXP, // flipped exponential + LIQUID_FIRFILT_FSECH, // flipped hyperbolic secant + LIQUID_FIRFILT_FARCSECH, // flipped arc-hyperbolic secant + + // root-Nyquist filter prototypes + LIQUID_FIRFILT_ARKAISER, // root-Nyquist Kaiser (approximate optimum) + LIQUID_FIRFILT_RKAISER, // root-Nyquist Kaiser (true optimum) + LIQUID_FIRFILT_RRC, // root raised-cosine + LIQUID_FIRFILT_hM3, // harris-Moerder-3 filter + LIQUID_FIRFILT_GMSKTX, // GMSK transmit filter + LIQUID_FIRFILT_GMSKRX, // GMSK receive filter + LIQUID_FIRFILT_RFEXP, // flipped exponential + LIQUID_FIRFILT_RFSECH, // flipped hyperbolic secant + LIQUID_FIRFILT_RFARCSECH, // flipped arc-hyperbolic secant +} liquid_firfilt_type; + +// Design (root-)Nyquist filter from prototype +// _type : filter type (e.g. LIQUID_FIRFILT_RRC) +// _k : samples/symbol, _k > 1 +// _m : symbol delay, _m > 0 +// _beta : excess bandwidth factor, _beta in [0,1) +// _dt : fractional sample delay, _dt in [-1,1] +// _h : output coefficient buffer (length: 2*_k*_m+1) +void liquid_firdes_prototype(liquid_firfilt_type _type, + unsigned int _k, + unsigned int _m, + float _beta, + float _dt, + float * _h); + +// pretty names for filter design types +extern const char * liquid_firfilt_type_str[LIQUID_FIRFILT_NUM_TYPES][2]; + +// returns filter type based on input string +int liquid_getopt_str2firfilt(const char * _str); + +// estimate required filter length given +// _df : transition bandwidth (0 < _b < 0.5) +// _As : stop-band attenuation [dB], _As > 0 +unsigned int estimate_req_filter_len(float _df, + float _As); + +// estimate filter stop-band attenuation given +// _df : transition bandwidth (0 < _b < 0.5) +// _N : filter length +float estimate_req_filter_As(float _df, + unsigned int _N); + +// estimate filter transition bandwidth given +// _As : stop-band attenuation [dB], _As > 0 +// _N : filter length +float estimate_req_filter_df(float _As, + unsigned int _N); + + +// returns the Kaiser window beta factor give the filter's target +// stop-band attenuation (As) [Vaidyanathan:1993] +// _As : target filter's stop-band attenuation [dB], _As > 0 +float kaiser_beta_As(float _As); + + +// Design FIR filter using Parks-McClellan algorithm + +// band type specifier +typedef enum { + LIQUID_FIRDESPM_BANDPASS=0, // regular band-pass filter + LIQUID_FIRDESPM_DIFFERENTIATOR, // differentiating filter + LIQUID_FIRDESPM_HILBERT // Hilbert transform +} liquid_firdespm_btype; + +// weighting type specifier +typedef enum { + LIQUID_FIRDESPM_FLATWEIGHT=0, // flat weighting + LIQUID_FIRDESPM_EXPWEIGHT, // exponential weighting + LIQUID_FIRDESPM_LINWEIGHT, // linear weighting +} liquid_firdespm_wtype; + +// run filter design (full life cycle of object) +// _h_len : length of filter (number of taps) +// _num_bands : number of frequency bands +// _bands : band edges, f in [0,0.5], [size: _num_bands x 2] +// _des : desired response [size: _num_bands x 1] +// _weights : response weighting [size: _num_bands x 1] +// _wtype : weight types (e.g. LIQUID_FIRDESPM_FLATWEIGHT) [size: _num_bands x 1] +// _btype : band type (e.g. LIQUID_FIRDESPM_BANDPASS) +// _h : output coefficients array [size: _h_len x 1] +int firdespm_run(unsigned int _h_len, + unsigned int _num_bands, + float * _bands, + float * _des, + float * _weights, + liquid_firdespm_wtype * _wtype, + liquid_firdespm_btype _btype, + float * _h); + +// run filter design for basic low-pass filter +// _n : filter length, _n > 0 +// _fc : cutoff frequency, 0 < _fc < 0.5 +// _As : stop-band attenuation [dB], _As > 0 +// _mu : fractional sample offset, -0.5 < _mu < 0.5 [ignored] +// _h : output coefficient buffer, [size: _n x 1] +int firdespm_lowpass(unsigned int _n, + float _fc, + float _As, + float _mu, + float * _h); + +// firdespm response callback function +// _frequency : normalized frequency +// _userdata : pointer to userdata +// _desired : (return) desired response +// _weight : (return) weight +typedef int (*firdespm_callback)(double _frequency, + void * _userdata, + double * _desired, + double * _weight); + +// structured object +typedef struct firdespm_s * firdespm; + +// create firdespm object +// _h_len : length of filter (number of taps) +// _num_bands : number of frequency bands +// _bands : band edges, f in [0,0.5], [size: _num_bands x 2] +// _des : desired response [size: _num_bands x 1] +// _weights : response weighting [size: _num_bands x 1] +// _wtype : weight types (e.g. LIQUID_FIRDESPM_FLATWEIGHT) [size: _num_bands x 1] +// _btype : band type (e.g. LIQUID_FIRDESPM_BANDPASS) +firdespm firdespm_create(unsigned int _h_len, + unsigned int _num_bands, + float * _bands, + float * _des, + float * _weights, + liquid_firdespm_wtype * _wtype, + liquid_firdespm_btype _btype); + +// create firdespm object with user-defined callback +// _h_len : length of filter (number of taps) +// _num_bands : number of frequency bands +// _bands : band edges, f in [0,0.5], [size: _num_bands x 2] +// _btype : band type (e.g. LIQUID_FIRDESPM_BANDPASS) +// _callback : user-defined callback for specifying desired response & weights +// _userdata : user-defined data structure for callback function +firdespm firdespm_create_callback(unsigned int _h_len, + unsigned int _num_bands, + float * _bands, + liquid_firdespm_btype _btype, + firdespm_callback _callback, + void * _userdata); + +// destroy firdespm object +int firdespm_destroy(firdespm _q); + +// print firdespm object internals +int firdespm_print(firdespm _q); + +// execute filter design, storing result in _h +int firdespm_execute(firdespm _q, float * _h); + + +// Design FIR using kaiser window +// _n : filter length, _n > 0 +// _fc : cutoff frequency, 0 < _fc < 0.5 +// _As : stop-band attenuation [dB], _As > 0 +// _mu : fractional sample offset, -0.5 < _mu < 0.5 +// _h : output coefficient buffer, [size: _n x 1] +void liquid_firdes_kaiser(unsigned int _n, + float _fc, + float _As, + float _mu, + float *_h); + +// Design finite impulse response notch filter +// _m : filter semi-length, m in [1,1000] +// _f0 : filter notch frequency (normalized), -0.5 <= _fc <= 0.5 +// _As : stop-band attenuation [dB], _As > 0 +// _h : output coefficient buffer, [size: 2*_m+1 x 1] +void liquid_firdes_notch(unsigned int _m, + float _f0, + float _As, + float * _h); + +// Design FIR doppler filter +// _n : filter length +// _fd : normalized doppler frequency (0 < _fd < 0.5) +// _K : Rice fading factor (K >= 0) +// _theta : LoS component angle of arrival +// _h : output coefficient buffer +void liquid_firdes_doppler(unsigned int _n, + float _fd, + float _K, + float _theta, + float * _h); + + +// Design Nyquist raised-cosine filter +// _k : samples/symbol +// _m : symbol delay +// _beta : rolloff factor (0 < beta <= 1) +// _dt : fractional sample delay +// _h : output coefficient buffer (length: 2*k*m+1) +void liquid_firdes_rcos(unsigned int _k, + unsigned int _m, + float _beta, + float _dt, + float * _h); + +// Design root-Nyquist raised-cosine filter +void liquid_firdes_rrcos(unsigned int _k, unsigned int _m, float _beta, float _dt, float * _h); + +// Design root-Nyquist Kaiser filter +void liquid_firdes_rkaiser(unsigned int _k, unsigned int _m, float _beta, float _dt, float * _h); + +// Design (approximate) root-Nyquist Kaiser filter +void liquid_firdes_arkaiser(unsigned int _k, unsigned int _m, float _beta, float _dt, float * _h); + +// Design root-Nyquist harris-Moerder filter +void liquid_firdes_hM3(unsigned int _k, unsigned int _m, float _beta, float _dt, float * _h); + +// Design GMSK transmit and receive filters +void liquid_firdes_gmsktx(unsigned int _k, unsigned int _m, float _beta, float _dt, float * _h); +void liquid_firdes_gmskrx(unsigned int _k, unsigned int _m, float _beta, float _dt, float * _h); + +// Design flipped exponential Nyquist/root-Nyquist filters +void liquid_firdes_fexp( unsigned int _k, unsigned int _m, float _beta, float _dt, float * _h); +void liquid_firdes_rfexp(unsigned int _k, unsigned int _m, float _beta, float _dt, float * _h); + +// Design flipped hyperbolic secand Nyquist/root-Nyquist filters +void liquid_firdes_fsech( unsigned int _k, unsigned int _m, float _beta, float _dt, float * _h); +void liquid_firdes_rfsech(unsigned int _k, unsigned int _m, float _beta, float _dt, float * _h); + +// Design flipped arc-hyperbolic secand Nyquist/root-Nyquist filters +void liquid_firdes_farcsech( unsigned int _k, unsigned int _m, float _beta, float _dt, float * _h); +void liquid_firdes_rfarcsech(unsigned int _k, unsigned int _m, float _beta, float _dt, float * _h); + +// Compute group delay for an FIR filter +// _h : filter coefficients array +// _n : filter length +// _fc : frequency at which delay is evaluated (-0.5 < _fc < 0.5) +float fir_group_delay(float * _h, + unsigned int _n, + float _fc); + +// Compute group delay for an IIR filter +// _b : filter numerator coefficients +// _nb : filter numerator length +// _a : filter denominator coefficients +// _na : filter denominator length +// _fc : frequency at which delay is evaluated (-0.5 < _fc < 0.5) +float iir_group_delay(float * _b, + unsigned int _nb, + float * _a, + unsigned int _na, + float _fc); + + +// liquid_filter_autocorr() +// +// Compute auto-correlation of filter at a specific lag. +// +// _h : filter coefficients [size: _h_len x 1] +// _h_len : filter length +// _lag : auto-correlation lag (samples) +float liquid_filter_autocorr(float * _h, + unsigned int _h_len, + int _lag); + +// liquid_filter_crosscorr() +// +// Compute cross-correlation of two filters at a specific lag. +// +// _h : filter coefficients [size: _h_len] +// _h_len : filter length +// _g : filter coefficients [size: _g_len] +// _g_len : filter length +// _lag : cross-correlation lag (samples) +float liquid_filter_crosscorr(float * _h, + unsigned int _h_len, + float * _g, + unsigned int _g_len, + int _lag); + +// liquid_filter_isi() +// +// Compute inter-symbol interference (ISI)--both RMS and +// maximum--for the filter _h. +// +// _h : filter coefficients [size: 2*_k*_m+1 x 1] +// _k : filter over-sampling rate (samples/symbol) +// _m : filter delay (symbols) +// _rms : output root mean-squared ISI +// _max : maximum ISI +void liquid_filter_isi(float * _h, + unsigned int _k, + unsigned int _m, + float * _rms, + float * _max); + +// Compute relative out-of-band energy +// +// _h : filter coefficients [size: _h_len x 1] +// _h_len : filter length +// _fc : analysis cut-off frequency +// _nfft : fft size +float liquid_filter_energy(float * _h, + unsigned int _h_len, + float _fc, + unsigned int _nfft); + + +// +// IIR filter design +// + +// IIR filter design filter type +typedef enum { + LIQUID_IIRDES_BUTTER=0, + LIQUID_IIRDES_CHEBY1, + LIQUID_IIRDES_CHEBY2, + LIQUID_IIRDES_ELLIP, + LIQUID_IIRDES_BESSEL +} liquid_iirdes_filtertype; + +// IIR filter design band type +typedef enum { + LIQUID_IIRDES_LOWPASS=0, + LIQUID_IIRDES_HIGHPASS, + LIQUID_IIRDES_BANDPASS, + LIQUID_IIRDES_BANDSTOP +} liquid_iirdes_bandtype; + +// IIR filter design coefficients format +typedef enum { + LIQUID_IIRDES_SOS=0, + LIQUID_IIRDES_TF +} liquid_iirdes_format; + +// IIR filter design template +// _ftype : filter type (e.g. LIQUID_IIRDES_BUTTER) +// _btype : band type (e.g. LIQUID_IIRDES_BANDPASS) +// _format : coefficients format (e.g. LIQUID_IIRDES_SOS) +// _n : filter order +// _fc : low-pass prototype cut-off frequency +// _f0 : center frequency (band-pass, band-stop) +// _Ap : pass-band ripple in dB +// _As : stop-band ripple in dB +// _B : numerator +// _A : denominator +void liquid_iirdes(liquid_iirdes_filtertype _ftype, + liquid_iirdes_bandtype _btype, + liquid_iirdes_format _format, + unsigned int _n, + float _fc, + float _f0, + float _Ap, + float _As, + float * _B, + float * _A); + +// compute analog zeros, poles, gain for specific filter types +void butter_azpkf(unsigned int _n, + liquid_float_complex * _za, + liquid_float_complex * _pa, + liquid_float_complex * _ka); +void cheby1_azpkf(unsigned int _n, + float _ep, + liquid_float_complex * _z, + liquid_float_complex * _p, + liquid_float_complex * _k); +void cheby2_azpkf(unsigned int _n, + float _es, + liquid_float_complex * _z, + liquid_float_complex * _p, + liquid_float_complex * _k); +void ellip_azpkf(unsigned int _n, + float _ep, + float _es, + liquid_float_complex * _z, + liquid_float_complex * _p, + liquid_float_complex * _k); +void bessel_azpkf(unsigned int _n, + liquid_float_complex * _z, + liquid_float_complex * _p, + liquid_float_complex * _k); + +// compute frequency pre-warping factor +float iirdes_freqprewarp(liquid_iirdes_bandtype _btype, + float _fc, + float _f0); + +// convert analog z/p/k form to discrete z/p/k form (bilinear z-transform) +// _za : analog zeros [length: _nza] +// _nza : number of analog zeros +// _pa : analog poles [length: _npa] +// _npa : number of analog poles +// _m : frequency pre-warping factor +// _zd : output digital zeros [length: _npa] +// _pd : output digital poles [length: _npa] +// _kd : output digital gain (should actually be real-valued) +void bilinear_zpkf(liquid_float_complex * _za, + unsigned int _nza, + liquid_float_complex * _pa, + unsigned int _npa, + liquid_float_complex _ka, + float _m, + liquid_float_complex * _zd, + liquid_float_complex * _pd, + liquid_float_complex * _kd); + +// digital z/p/k low-pass to high-pass +// _zd : digital zeros (low-pass prototype), [length: _n] +// _pd : digital poles (low-pass prototype), [length: _n] +// _n : low-pass filter order +// _zdt : output digital zeros transformed [length: _n] +// _pdt : output digital poles transformed [length: _n] +void iirdes_dzpk_lp2hp(liquid_float_complex * _zd, + liquid_float_complex * _pd, + unsigned int _n, + liquid_float_complex * _zdt, + liquid_float_complex * _pdt); + +// digital z/p/k low-pass to band-pass +// _zd : digital zeros (low-pass prototype), [length: _n] +// _pd : digital poles (low-pass prototype), [length: _n] +// _n : low-pass filter order +// _f0 : center frequency +// _zdt : output digital zeros transformed [length: 2*_n] +// _pdt : output digital poles transformed [length: 2*_n] +void iirdes_dzpk_lp2bp(liquid_float_complex * _zd, + liquid_float_complex * _pd, + unsigned int _n, + float _f0, + liquid_float_complex * _zdt, + liquid_float_complex * _pdt); + +// convert discrete z/p/k form to transfer function +// _zd : digital zeros [length: _n] +// _pd : digital poles [length: _n] +// _n : filter order +// _kd : digital gain +// _b : output numerator [length: _n+1] +// _a : output denominator [length: _n+1] +void iirdes_dzpk2tff(liquid_float_complex * _zd, + liquid_float_complex * _pd, + unsigned int _n, + liquid_float_complex _kd, + float * _b, + float * _a); + +// convert discrete z/p/k form to second-order sections +// _zd : digital zeros [length: _n] +// _pd : digital poles [length: _n] +// _n : filter order +// _kd : digital gain +// _B : output numerator [size: 3 x L+r] +// _A : output denominator [size: 3 x L+r] +// where r = _n%2, L = (_n-r)/2 +void iirdes_dzpk2sosf(liquid_float_complex * _zd, + liquid_float_complex * _pd, + unsigned int _n, + liquid_float_complex _kd, + float * _B, + float * _A); + +// additional IIR filter design templates + +// design 2nd-order IIR filter (active lag) +// 1 + t2 * s +// F(s) = ------------ +// 1 + t1 * s +// +// _w : filter bandwidth +// _zeta : damping factor (1/sqrt(2) suggested) +// _K : loop gain (1000 suggested) +// _b : output feed-forward coefficients [size: 3 x 1] +// _a : output feed-back coefficients [size: 3 x 1] +void iirdes_pll_active_lag(float _w, + float _zeta, + float _K, + float * _b, + float * _a); + +// design 2nd-order IIR filter (active PI) +// 1 + t2 * s +// F(s) = ------------ +// t1 * s +// +// _w : filter bandwidth +// _zeta : damping factor (1/sqrt(2) suggested) +// _K : loop gain (1000 suggested) +// _b : output feed-forward coefficients [size: 3 x 1] +// _a : output feed-back coefficients [size: 3 x 1] +void iirdes_pll_active_PI(float _w, + float _zeta, + float _K, + float * _b, + float * _a); + +// checks stability of iir filter +// _b : feed-forward coefficients [size: _n x 1] +// _a : feed-back coefficients [size: _n x 1] +// _n : number of coefficients +int iirdes_isstable(float * _b, + float * _a, + unsigned int _n); + +// +// linear prediction +// + +// compute the linear prediction coefficients for an input signal _x +// _x : input signal [size: _n x 1] +// _n : input signal length +// _p : prediction filter order +// _a : prediction filter [size: _p+1 x 1] +// _e : prediction error variance [size: _p+1 x 1] +void liquid_lpc(float * _x, + unsigned int _n, + unsigned int _p, + float * _a, + float * _g); + +// solve the Yule-Walker equations using Levinson-Durbin recursion +// for _symmetric_ autocorrelation +// _r : autocorrelation array [size: _p+1 x 1] +// _p : filter order +// _a : output coefficients [size: _p+1 x 1] +// _e : error variance [size: _p+1 x 1] +// +// NOTES: +// By definition _a[0] = 1.0 +void liquid_levinson(float * _r, + unsigned int _p, + float * _a, + float * _e); + +// +// auto-correlator (delay cross-correlation) +// + +#define LIQUID_AUTOCORR_MANGLE_CCCF(name) LIQUID_CONCAT(autocorr_cccf,name) +#define LIQUID_AUTOCORR_MANGLE_RRRF(name) LIQUID_CONCAT(autocorr_rrrf,name) + +// Macro: +// AUTOCORR : name-mangling macro +// TO : output data type +// TC : coefficients data type +// TI : input data type +#define LIQUID_AUTOCORR_DEFINE_API(AUTOCORR,TO,TC,TI) \ + \ +/* Computes auto-correlation with a fixed lag on input signals */ \ +typedef struct AUTOCORR(_s) * AUTOCORR(); \ + \ +/* Create auto-correlator object with a particular window length and */ \ +/* delay */ \ +/* _window_size : size of the correlator window */ \ +/* _delay : correlator delay [samples] */ \ +AUTOCORR() AUTOCORR(_create)(unsigned int _window_size, \ + unsigned int _delay); \ + \ +/* Destroy auto-correlator object, freeing internal memory */ \ +void AUTOCORR(_destroy)(AUTOCORR() _q); \ + \ +/* Reset auto-correlator object's internals */ \ +void AUTOCORR(_reset)(AUTOCORR() _q); \ + \ +/* Print auto-correlator parameters to stdout */ \ +void AUTOCORR(_print)(AUTOCORR() _q); \ + \ +/* Push sample into auto-correlator object */ \ +/* _q : auto-correlator object */ \ +/* _x : single input sample */ \ +void AUTOCORR(_push)(AUTOCORR() _q, \ + TI _x); \ + \ +/* Write block of samples to auto-correlator object */ \ +/* _q : auto-correlation object */ \ +/* _x : input array [size: _n x 1] */ \ +/* _n : number of input samples */ \ +void AUTOCORR(_write)(AUTOCORR() _q, \ + TI * _x, \ + unsigned int _n); \ + \ +/* Compute single auto-correlation output */ \ +/* _q : auto-correlator object */ \ +/* _rxx : auto-correlated output */ \ +void AUTOCORR(_execute)(AUTOCORR() _q, \ + TO * _rxx); \ + \ +/* Compute auto-correlation on block of samples; the input and output */ \ +/* arrays may have the same pointer */ \ +/* _q : auto-correlation object */ \ +/* _x : input array [size: _n x 1] */ \ +/* _n : number of input, output samples */ \ +/* _rxx : input array [size: _n x 1] */ \ +void AUTOCORR(_execute_block)(AUTOCORR() _q, \ + TI * _x, \ + unsigned int _n, \ + TO * _rxx); \ + \ +/* return sum of squares of buffered samples */ \ +float AUTOCORR(_get_energy)(AUTOCORR() _q); \ + +LIQUID_AUTOCORR_DEFINE_API(LIQUID_AUTOCORR_MANGLE_CCCF, + liquid_float_complex, + liquid_float_complex, + liquid_float_complex) + +LIQUID_AUTOCORR_DEFINE_API(LIQUID_AUTOCORR_MANGLE_RRRF, + float, + float, + float) + + +// +// Finite impulse response filter +// + +#define LIQUID_FIRFILT_MANGLE_RRRF(name) LIQUID_CONCAT(firfilt_rrrf,name) +#define LIQUID_FIRFILT_MANGLE_CRCF(name) LIQUID_CONCAT(firfilt_crcf,name) +#define LIQUID_FIRFILT_MANGLE_CCCF(name) LIQUID_CONCAT(firfilt_cccf,name) + +// Macro: +// FIRFILT : name-mangling macro +// TO : output data type +// TC : coefficients data type +// TI : input data type +#define LIQUID_FIRFILT_DEFINE_API(FIRFILT,TO,TC,TI) \ + \ +/* Finite impulse response (FIR) filter */ \ +typedef struct FIRFILT(_s) * FIRFILT(); \ + \ +/* Create a finite impulse response filter (firfilt) object by directly */ \ +/* specifying the filter coefficients in an array */ \ +/* _h : filter coefficients [size: _n x 1] */ \ +/* _n : number of filter coefficients, _n > 0 */ \ +FIRFILT() FIRFILT(_create)(TC * _h, \ + unsigned int _n); \ + \ +/* Create object using Kaiser-Bessel windowed sinc method */ \ +/* _n : filter length, _n > 0 */ \ +/* _fc : filter normalized cut-off frequency, 0 < _fc < 0.5 */ \ +/* _As : filter stop-band attenuation [dB], _As > 0 */ \ +/* _mu : fractional sample offset, -0.5 < _mu < 0.5 */ \ +FIRFILT() FIRFILT(_create_kaiser)(unsigned int _n, \ + float _fc, \ + float _As, \ + float _mu); \ + \ +/* Create object from square-root Nyquist prototype. */ \ +/* The filter length will be \(2 k m + 1 \) samples long with a delay */ \ +/* of \( k m + 1 \) samples. */ \ +/* _type : filter type (e.g. LIQUID_FIRFILT_RRC) */ \ +/* _k : nominal samples per symbol, _k > 1 */ \ +/* _m : filter delay [symbols], _m > 0 */ \ +/* _beta : rolloff factor, 0 < beta <= 1 */ \ +/* _mu : fractional sample offset [samples], -0.5 < _mu < 0.5 */ \ +FIRFILT() FIRFILT(_create_rnyquist)(int _type, \ + unsigned int _k, \ + unsigned int _m, \ + float _beta, \ + float _mu); \ + \ +/* Create object from Parks-McClellan algorithm prototype */ \ +/* _h_len : filter length, _h_len > 0 */ \ +/* _fc : cutoff frequency, 0 < _fc < 0.5 */ \ +/* _As : stop-band attenuation [dB], _As > 0 */ \ +FIRFILT() FIRFILT(_create_firdespm)(unsigned int _h_len, \ + float _fc, \ + float _As); \ + \ +/* Create rectangular filter prototype; that is */ \ +/* \( \vec{h} = \{ 1, 1, 1, \ldots 1 \} \) */ \ +/* _n : length of filter [samples], 0 < _n <= 1024 */ \ +FIRFILT() FIRFILT(_create_rect)(unsigned int _n); \ + \ +/* Create DC blocking filter from prototype */ \ +/* _m : prototype filter semi-length such that filter length is 2*m+1 */ \ +/* _As : prototype filter stop-band attenuation [dB], _As > 0 */ \ +FIRFILT() FIRFILT(_create_dc_blocker)(unsigned int _m, \ + float _As); \ + \ +/* Create notch filter from prototype */ \ +/* _m : prototype filter semi-length such that filter length is 2*m+1 */ \ +/* _As : prototype filter stop-band attenuation [dB], _As > 0 */ \ +/* _f0 : center frequency for notch, _fc in [-0.5, 0.5] */ \ +FIRFILT() FIRFILT(_create_notch)(unsigned int _m, \ + float _As, \ + float _f0); \ + \ +/* Re-create filter object of potentially a different length with */ \ +/* different coefficients. If the length of the filter does not change, */ \ +/* not memory reallocation is invoked. */ \ +/* _q : original filter object */ \ +/* _h : pointer to filter coefficients, [size: _n x 1] */ \ +/* _n : filter length, _n > 0 */ \ +FIRFILT() FIRFILT(_recreate)(FIRFILT() _q, \ + TC * _h, \ + unsigned int _n); \ + \ +/* Destroy filter object and free all internal memory */ \ +void FIRFILT(_destroy)(FIRFILT() _q); \ + \ +/* Reset filter object's internal buffer */ \ +void FIRFILT(_reset)(FIRFILT() _q); \ + \ +/* Print filter object information to stdout */ \ +void FIRFILT(_print)(FIRFILT() _q); \ + \ +/* Set output scaling for filter */ \ +/* _q : filter object */ \ +/* _scale : scaling factor to apply to each output sample */ \ +void FIRFILT(_set_scale)(FIRFILT() _q, \ + TC _scale); \ + \ +/* Get output scaling for filter */ \ +/* _q : filter object */ \ +/* _scale : scaling factor applied to each output sample */ \ +void FIRFILT(_get_scale)(FIRFILT() _q, \ + TC * _scale); \ + \ +/* Push sample into filter object's internal buffer */ \ +/* _q : filter object */ \ +/* _x : single input sample */ \ +void FIRFILT(_push)(FIRFILT() _q, \ + TI _x); \ + \ +/* Write block of samples into filter object's internal buffer */ \ +/* _q : filter object */ \ +/* _x : buffer of input samples, [size: _n x 1] */ \ +/* _n : number of input samples */ \ +void FIRFILT(_write)(FIRFILT() _q, \ + TI * _x, \ + unsigned int _n); \ + \ +/* Execute vector dot product on the filter's internal buffer and */ \ +/* coefficients */ \ +/* _q : filter object */ \ +/* _y : pointer to single output sample */ \ +void FIRFILT(_execute)(FIRFILT() _q, \ + TO * _y); \ + \ +/* Execute the filter on a block of input samples; in-place operation */ \ +/* is permitted (_x and _y may point to the same place in memory) */ \ +/* _q : filter object */ \ +/* _x : pointer to input array, [size: _n x 1] */ \ +/* _n : number of input, output samples */ \ +/* _y : pointer to output array, [size: _n x 1] */ \ +void FIRFILT(_execute_block)(FIRFILT() _q, \ + TI * _x, \ + unsigned int _n, \ + TO * _y); \ + \ +/* Get length of filter object (number of internal coefficients) */ \ +unsigned int FIRFILT(_get_length)(FIRFILT() _q); \ + \ +/* Compute complex frequency response of filter object */ \ +/* _q : filter object */ \ +/* _fc : normalized frequency for evaluation */ \ +/* _H : pointer to output complex frequency response */ \ +void FIRFILT(_freqresponse)(FIRFILT() _q, \ + float _fc, \ + liquid_float_complex * _H); \ + \ +/* Compute and return group delay of filter object */ \ +/* _q : filter object */ \ +/* _fc : frequency to evaluate */ \ +float FIRFILT(_groupdelay)(FIRFILT() _q, \ + float _fc); \ + +LIQUID_FIRFILT_DEFINE_API(LIQUID_FIRFILT_MANGLE_RRRF, + float, + float, + float) + +LIQUID_FIRFILT_DEFINE_API(LIQUID_FIRFILT_MANGLE_CRCF, + liquid_float_complex, + float, + liquid_float_complex) + +LIQUID_FIRFILT_DEFINE_API(LIQUID_FIRFILT_MANGLE_CCCF, + liquid_float_complex, + liquid_float_complex, + liquid_float_complex) + +// +// FIR Hilbert transform +// 2:1 real-to-complex decimator +// 1:2 complex-to-real interpolator +// + +#define LIQUID_FIRHILB_MANGLE_FLOAT(name) LIQUID_CONCAT(firhilbf, name) +//#define LIQUID_FIRHILB_MANGLE_DOUBLE(name) LIQUID_CONCAT(firhilb, name) + +// NOTES: +// Although firhilb is a placeholder for both decimation and +// interpolation, separate objects should be used for each task. +#define LIQUID_FIRHILB_DEFINE_API(FIRHILB,T,TC) \ + \ +/* Finite impulse response (FIR) Hilbert transform */ \ +typedef struct FIRHILB(_s) * FIRHILB(); \ + \ +/* Create a firhilb object with a particular filter semi-length and */ \ +/* desired stop-band attenuation. */ \ +/* Internally the object designs a half-band filter based on applying */ \ +/* a Kaiser-Bessel window to a sinc function to guarantee zeros at all */ \ +/* off-center odd indexed samples. */ \ +/* _m : filter semi-length, delay is \( 2 m + 1 \) */ \ +/* _As : filter stop-band attenuation [dB] */ \ +FIRHILB() FIRHILB(_create)(unsigned int _m, \ + float _As); \ + \ +/* Destroy finite impulse response Hilbert transform, freeing all */ \ +/* internally-allocted memory and objects. */ \ +void FIRHILB(_destroy)(FIRHILB() _q); \ + \ +/* Print firhilb object internals to stdout */ \ +void FIRHILB(_print)(FIRHILB() _q); \ + \ +/* Reset firhilb object internal state */ \ +void FIRHILB(_reset)(FIRHILB() _q); \ + \ +/* Execute Hilbert transform (real to complex) */ \ +/* _q : Hilbert transform object */ \ +/* _x : real-valued input sample */ \ +/* _y : complex-valued output sample */ \ +void FIRHILB(_r2c_execute)(FIRHILB() _q, \ + T _x, \ + TC * _y); \ + \ +/* Execute Hilbert transform (complex to real) */ \ +/* _q : Hilbert transform object */ \ +/* _x : complex-valued input sample */ \ +/* _y0 : real-valued output sample, lower side-band retained */ \ +/* _y1 : real-valued output sample, upper side-band retained */ \ +void FIRHILB(_c2r_execute)(FIRHILB() _q, \ + TC _x, \ + T * _y0, \ + T * _y1); \ + \ +/* Execute Hilbert transform decimator (real to complex) */ \ +/* _q : Hilbert transform object */ \ +/* _x : real-valued input array, [size: 2 x 1] */ \ +/* _y : complex-valued output sample */ \ +void FIRHILB(_decim_execute)(FIRHILB() _q, \ + T * _x, \ + TC * _y); \ + \ +/* Execute Hilbert transform decimator (real to complex) on a block of */ \ +/* samples */ \ +/* _q : Hilbert transform object */ \ +/* _x : real-valued input array, [size: 2*_n x 1] */ \ +/* _n : number of output samples */ \ +/* _y : complex-valued output array, [size: _n x 1] */ \ +void FIRHILB(_decim_execute_block)(FIRHILB() _q, \ + T * _x, \ + unsigned int _n, \ + TC * _y); \ + \ +/* Execute Hilbert transform interpolator (real to complex) */ \ +/* _q : Hilbert transform object */ \ +/* _x : complex-valued input sample */ \ +/* _y : real-valued output array, [size: 2 x 1] */ \ +void FIRHILB(_interp_execute)(FIRHILB() _q, \ + TC _x, \ + T * _y); \ + \ +/* Execute Hilbert transform interpolator (complex to real) on a block */ \ +/* of samples */ \ +/* _q : Hilbert transform object */ \ +/* _x : complex-valued input array, [size: _n x 1] */ \ +/* _n : number of *input* samples */ \ +/* _y : real-valued output array, [size: 2*_n x 1] */ \ +void FIRHILB(_interp_execute_block)(FIRHILB() _q, \ + TC * _x, \ + unsigned int _n, \ + T * _y); \ + +LIQUID_FIRHILB_DEFINE_API(LIQUID_FIRHILB_MANGLE_FLOAT, float, liquid_float_complex) +//LIQUID_FIRHILB_DEFINE_API(LIQUID_FIRHILB_MANGLE_DOUBLE, double, liquid_double_complex) + + +// +// Infinite impulse response (IIR) Hilbert transform +// 2:1 real-to-complex decimator +// 1:2 complex-to-real interpolator +// + +#define LIQUID_IIRHILB_MANGLE_FLOAT(name) LIQUID_CONCAT(iirhilbf, name) +//#define LIQUID_IIRHILB_MANGLE_DOUBLE(name) LIQUID_CONCAT(iirhilb, name) + +// NOTES: +// Although iirhilb is a placeholder for both decimation and +// interpolation, separate objects should be used for each task. +#define LIQUID_IIRHILB_DEFINE_API(IIRHILB,T,TC) \ + \ +/* Infinite impulse response (IIR) Hilbert transform */ \ +typedef struct IIRHILB(_s) * IIRHILB(); \ + \ +/* Create a iirhilb object with a particular filter type, order, and */ \ +/* desired pass- and stop-band attenuation. */ \ +/* _ftype : filter type (e.g. LIQUID_IIRDES_BUTTER) */ \ +/* _n : filter order, _n > 0 */ \ +/* _Ap : pass-band ripple [dB], _Ap > 0 */ \ +/* _As : stop-band ripple [dB], _Ap > 0 */ \ +IIRHILB() IIRHILB(_create)(liquid_iirdes_filtertype _ftype, \ + unsigned int _n, \ + float _Ap, \ + float _As); \ + \ +/* Create a default iirhilb object with a particular filter order. */ \ +/* _n : filter order, _n > 0 */ \ +IIRHILB() IIRHILB(_create_default)(unsigned int _n); \ + \ +/* Destroy finite impulse response Hilbert transform, freeing all */ \ +/* internally-allocted memory and objects. */ \ +void IIRHILB(_destroy)(IIRHILB() _q); \ + \ +/* Print iirhilb object internals to stdout */ \ +void IIRHILB(_print)(IIRHILB() _q); \ + \ +/* Reset iirhilb object internal state */ \ +void IIRHILB(_reset)(IIRHILB() _q); \ + \ +/* Execute Hilbert transform (real to complex) */ \ +/* _q : Hilbert transform object */ \ +/* _x : real-valued input sample */ \ +/* _y : complex-valued output sample */ \ +void IIRHILB(_r2c_execute)(IIRHILB() _q, \ + T _x, \ + TC * _y); \ + \ +/* Execute Hilbert transform (complex to real) */ \ +/* _q : Hilbert transform object */ \ +/* _x : complex-valued input sample */ \ +/* _y : real-valued output sample */ \ +void IIRHILB(_c2r_execute)(IIRHILB() _q, \ + TC _x, \ + T * _y); \ + \ +/* Execute Hilbert transform decimator (real to complex) */ \ +/* _q : Hilbert transform object */ \ +/* _x : real-valued input array, [size: 2 x 1] */ \ +/* _y : complex-valued output sample */ \ +void IIRHILB(_decim_execute)(IIRHILB() _q, \ + T * _x, \ + TC * _y); \ + \ +/* Execute Hilbert transform decimator (real to complex) on a block of */ \ +/* samples */ \ +/* _q : Hilbert transform object */ \ +/* _x : real-valued input array, [size: 2*_n x 1] */ \ +/* _n : number of output samples */ \ +/* _y : complex-valued output array, [size: _n x 1] */ \ +void IIRHILB(_decim_execute_block)(IIRHILB() _q, \ + T * _x, \ + unsigned int _n, \ + TC * _y); \ + \ +/* Execute Hilbert transform interpolator (real to complex) */ \ +/* _q : Hilbert transform object */ \ +/* _x : complex-valued input sample */ \ +/* _y : real-valued output array, [size: 2 x 1] */ \ +void IIRHILB(_interp_execute)(IIRHILB() _q, \ + TC _x, \ + T * _y); \ + \ +/* Execute Hilbert transform interpolator (complex to real) on a block */ \ +/* of samples */ \ +/* _q : Hilbert transform object */ \ +/* _x : complex-valued input array, [size: _n x 1] */ \ +/* _n : number of *input* samples */ \ +/* _y : real-valued output array, [size: 2*_n x 1] */ \ +void IIRHILB(_interp_execute_block)(IIRHILB() _q, \ + TC * _x, \ + unsigned int _n, \ + T * _y); \ + +LIQUID_IIRHILB_DEFINE_API(LIQUID_IIRHILB_MANGLE_FLOAT, float, liquid_float_complex) +//LIQUID_IIRHILB_DEFINE_API(LIQUID_IIRHILB_MANGLE_DOUBLE, double, liquid_double_complex) + + +// +// FFT-based finite impulse response filter +// + +#define LIQUID_FFTFILT_MANGLE_RRRF(name) LIQUID_CONCAT(fftfilt_rrrf,name) +#define LIQUID_FFTFILT_MANGLE_CRCF(name) LIQUID_CONCAT(fftfilt_crcf,name) +#define LIQUID_FFTFILT_MANGLE_CCCF(name) LIQUID_CONCAT(fftfilt_cccf,name) + +// Macro: +// FFTFILT : name-mangling macro +// TO : output data type +// TC : coefficients data type +// TI : input data type +#define LIQUID_FFTFILT_DEFINE_API(FFTFILT,TO,TC,TI) \ + \ +/* Fast Fourier transform (FFT) finite impulse response filter */ \ +typedef struct FFTFILT(_s) * FFTFILT(); \ + \ +/* Create FFT-based FIR filter using external coefficients */ \ +/* _h : filter coefficients, [size: _h_len x 1] */ \ +/* _h_len : filter length, _h_len > 0 */ \ +/* _n : block size = nfft/2, _n >= _h_len-1 */ \ +FFTFILT() FFTFILT(_create)(TC * _h, \ + unsigned int _h_len, \ + unsigned int _n); \ + \ +/* Destroy filter object and free all internal memory */ \ +void FFTFILT(_destroy)(FFTFILT() _q); \ + \ +/* Reset filter object's internal buffer */ \ +void FFTFILT(_reset)(FFTFILT() _q); \ + \ +/* Print filter object information to stdout */ \ +void FFTFILT(_print)(FFTFILT() _q); \ + \ +/* Set output scaling for filter */ \ +void FFTFILT(_set_scale)(FFTFILT() _q, \ + TC _scale); \ + \ +/* Get output scaling for filter */ \ +void FFTFILT(_get_scale)(FFTFILT() _q, \ + TC * _scale); \ + \ +/* Execute the filter on internal buffer and coefficients given a block */ \ +/* of input samples; in-place operation is permitted (_x and _y may */ \ +/* point to the same place in memory) */ \ +/* _q : filter object */ \ +/* _x : pointer to input data array, [size: _n x 1] */ \ +/* _y : pointer to output data array, [size: _n x 1] */ \ +void FFTFILT(_execute)(FFTFILT() _q, \ + TI * _x, \ + TO * _y); \ + \ +/* Get length of filter object's internal coefficients */ \ +unsigned int FFTFILT(_get_length)(FFTFILT() _q); \ + +LIQUID_FFTFILT_DEFINE_API(LIQUID_FFTFILT_MANGLE_RRRF, + float, + float, + float) + +LIQUID_FFTFILT_DEFINE_API(LIQUID_FFTFILT_MANGLE_CRCF, + liquid_float_complex, + float, + liquid_float_complex) + +LIQUID_FFTFILT_DEFINE_API(LIQUID_FFTFILT_MANGLE_CCCF, + liquid_float_complex, + liquid_float_complex, + liquid_float_complex) + + +// +// Infinite impulse response filter +// + +#define LIQUID_IIRFILT_MANGLE_RRRF(name) LIQUID_CONCAT(iirfilt_rrrf,name) +#define LIQUID_IIRFILT_MANGLE_CRCF(name) LIQUID_CONCAT(iirfilt_crcf,name) +#define LIQUID_IIRFILT_MANGLE_CCCF(name) LIQUID_CONCAT(iirfilt_cccf,name) + +// Macro: +// IIRFILT : name-mangling macro +// TO : output data type +// TC : coefficients data type +// TI : input data type +#define LIQUID_IIRFILT_DEFINE_API(IIRFILT,TO,TC,TI) \ + \ +/* Infinite impulse response (IIR) filter */ \ +typedef struct IIRFILT(_s) * IIRFILT(); \ + \ +/* Create infinite impulse response filter from external coefficients. */ \ +/* Note that the number of feed-forward and feed-back coefficients do */ \ +/* not need to be equal, but they do need to be non-zero. */ \ +/* Furthermore, the first feed-back coefficient \(a_0\) cannot be */ \ +/* equal to zero, otherwise the filter will be invalid as this value is */ \ +/* factored out from all coefficients. */ \ +/* For stability reasons the number of coefficients should reasonably */ \ +/* not exceed about 8 for single-precision floating-point. */ \ +/* _b : feed-forward coefficients (numerator), [size: _nb x 1] */ \ +/* _nb : number of feed-forward coefficients, _nb > 0 */ \ +/* _a : feed-back coefficients (denominator), [size: _na x 1] */ \ +/* _na : number of feed-back coefficients, _na > 0 */ \ +IIRFILT() IIRFILT(_create)(TC * _b, \ + unsigned int _nb, \ + TC * _a, \ + unsigned int _na); \ + \ +/* Create IIR filter using 2nd-order secitons from external */ \ +/* coefficients. */ \ +/* _B : feed-forward coefficients [size: _nsos x 3] */ \ +/* _A : feed-back coefficients [size: _nsos x 3] */ \ +/* _nsos : number of second-order sections (sos), _nsos > 0 */ \ +IIRFILT() IIRFILT(_create_sos)(TC * _B, \ + TC * _A, \ + unsigned int _nsos); \ + \ +/* Create IIR filter from design template */ \ +/* _ftype : filter type (e.g. LIQUID_IIRDES_BUTTER) */ \ +/* _btype : band type (e.g. LIQUID_IIRDES_BANDPASS) */ \ +/* _format : coefficients format (e.g. LIQUID_IIRDES_SOS) */ \ +/* _order : filter order, _order > 0 */ \ +/* _fc : low-pass prototype cut-off frequency, 0 <= _fc <= 0.5 */ \ +/* _f0 : center frequency (band-pass, band-stop), 0 <= _f0 <= 0.5 */ \ +/* _Ap : pass-band ripple in dB, _Ap > 0 */ \ +/* _As : stop-band ripple in dB, _As > 0 */ \ +IIRFILT() IIRFILT(_create_prototype)( \ + liquid_iirdes_filtertype _ftype, \ + liquid_iirdes_bandtype _btype, \ + liquid_iirdes_format _format, \ + unsigned int _order, \ + float _fc, \ + float _f0, \ + float _Ap, \ + float _As); \ + \ +/* Create simplified low-pass Butterworth IIR filter */ \ +/* _order : filter order, _order > 0 */ \ +/* _fc : low-pass prototype cut-off frequency */ \ +IIRFILT() IIRFILT(_create_lowpass)(unsigned int _order, \ + float _fc); \ + \ +/* Create 8th-order integrator filter */ \ +IIRFILT() IIRFILT(_create_integrator)(void); \ + \ +/* Create 8th-order differentiator filter */ \ +IIRFILT() IIRFILT(_create_differentiator)(void); \ + \ +/* Create simple first-order DC-blocking filter with transfer function */ \ +/* \( H(z) = \frac{1 - z^{-1}}{1 - (1-\alpha)z^{-1}} \) */ \ +/* _alpha : normalized filter bandwidth, _alpha > 0 */ \ +IIRFILT() IIRFILT(_create_dc_blocker)(float _alpha); \ + \ +/* Create filter to operate as second-order integrating phase-locked */ \ +/* loop (active lag design) */ \ +/* _w : filter bandwidth, 0 < _w < 1 */ \ +/* _zeta : damping factor, \( 1/\sqrt{2} \) suggested, 0 < _zeta < 1 */ \ +/* _K : loop gain, 1000 suggested, _K > 0 */ \ +IIRFILT() IIRFILT(_create_pll)(float _w, \ + float _zeta, \ + float _K); \ + \ +/* Destroy iirfilt object, freeing all internal memory */ \ +void IIRFILT(_destroy)(IIRFILT() _q); \ + \ +/* Print iirfilt object properties to stdout */ \ +void IIRFILT(_print)(IIRFILT() _q); \ + \ +/* Reset iirfilt object internals */ \ +void IIRFILT(_reset)(IIRFILT() _q); \ + \ +/* Compute filter output given a signle input sample */ \ +/* _q : iirfilt object */ \ +/* _x : input sample */ \ +/* _y : output sample pointer */ \ +void IIRFILT(_execute)(IIRFILT() _q, \ + TI _x, \ + TO * _y); \ + \ +/* Execute the filter on a block of input samples; */ \ +/* in-place operation is permitted (the input and output buffers may be */ \ +/* the same) */ \ +/* _q : filter object */ \ +/* _x : pointer to input array, [size: _n x 1] */ \ +/* _n : number of input, output samples, _n > 0 */ \ +/* _y : pointer to output array, [size: _n x 1] */ \ +void IIRFILT(_execute_block)(IIRFILT() _q, \ + TI * _x, \ + unsigned int _n, \ + TO * _y); \ + \ +/* Return number of coefficients for iirfilt object (maximum between */ \ +/* the feed-forward and feed-back coefficients). Note that the filter */ \ +/* length = filter order + 1 */ \ +unsigned int IIRFILT(_get_length)(IIRFILT() _q); \ + \ +/* Compute complex frequency response of filter object */ \ +/* _q : filter object */ \ +/* _fc : normalized frequency for evaluation */ \ +/* _H : pointer to output complex frequency response */ \ +void IIRFILT(_freqresponse)(IIRFILT() _q, \ + float _fc, \ + liquid_float_complex * _H); \ + \ +/* Compute and return group delay of filter object */ \ +/* _q : filter object */ \ +/* _fc : frequency to evaluate */ \ +float IIRFILT(_groupdelay)(IIRFILT() _q, float _fc); \ + +LIQUID_IIRFILT_DEFINE_API(LIQUID_IIRFILT_MANGLE_RRRF, + float, + float, + float) + +LIQUID_IIRFILT_DEFINE_API(LIQUID_IIRFILT_MANGLE_CRCF, + liquid_float_complex, + float, + liquid_float_complex) + +LIQUID_IIRFILT_DEFINE_API(LIQUID_IIRFILT_MANGLE_CCCF, + liquid_float_complex, + liquid_float_complex, + liquid_float_complex) + + +// +// FIR Polyphase filter bank +// +#define LIQUID_FIRPFB_MANGLE_RRRF(name) LIQUID_CONCAT(firpfb_rrrf,name) +#define LIQUID_FIRPFB_MANGLE_CRCF(name) LIQUID_CONCAT(firpfb_crcf,name) +#define LIQUID_FIRPFB_MANGLE_CCCF(name) LIQUID_CONCAT(firpfb_cccf,name) + +// Macro: +// FIRPFB : name-mangling macro +// TO : output data type +// TC : coefficients data type +// TI : input data type +#define LIQUID_FIRPFB_DEFINE_API(FIRPFB,TO,TC,TI) \ + \ +/* Finite impulse response (FIR) polyphase filter bank (PFB) */ \ +typedef struct FIRPFB(_s) * FIRPFB(); \ + \ +/* Create firpfb object with _M sub-filter each of length _h_len/_M */ \ +/* from an external array of coefficients */ \ +/* _M : number of filters in the bank, _M > 1 */ \ +/* _h : coefficients, [size: _h_len x 1] */ \ +/* _h_len : filter length (multiple of _M), _h_len >= _M */ \ +FIRPFB() FIRPFB(_create)(unsigned int _M, \ + TC * _h, \ + unsigned int _h_len); \ + \ +/* Create firpfb object using Kaiser-Bessel windowed sinc filter design */ \ +/* method, using default values for cut-off frequency and stop-band */ \ +/* attenuation. This is equivalent to: */ \ +/* FIRPFB(_create_kaiser)(_M, _m, 0.5, 60.0) */ \ +/* which creates a Nyquist filter at the appropriate cut-off frequency. */ \ +/* _M : number of filters in the bank, _M > 0 */ \ +/* _m : filter semi-length [samples], _m > 0 */ \ +FIRPFB() FIRPFB(_create_default)(unsigned int _M, \ + unsigned int _m); \ + \ +/* Create firpfb object using Kaiser-Bessel windowed sinc filter design */ \ +/* method */ \ +/* _M : number of filters in the bank, _M > 0 */ \ +/* _m : filter semi-length [samples], _m > 0 */ \ +/* _fc : filter normalized cut-off frequency, 0 < _fc < 0.5 */ \ +/* _As : filter stop-band suppression [dB], _As > 0 */ \ +FIRPFB() FIRPFB(_create_kaiser)(unsigned int _M, \ + unsigned int _m, \ + float _fc, \ + float _As); \ + \ +/* Create firpfb from square-root Nyquist prototype */ \ +/* _type : filter type (e.g. LIQUID_FIRFILT_RRC) */ \ +/* _M : number of filters in the bank, _M > 0 */ \ +/* _k : nominal samples/symbol, _k > 1 */ \ +/* _m : filter delay [symbols], _m > 0 */ \ +/* _beta : rolloff factor, 0 < _beta <= 1 */ \ +FIRPFB() FIRPFB(_create_rnyquist)(int _type, \ + unsigned int _M, \ + unsigned int _k, \ + unsigned int _m, \ + float _beta); \ + \ +/* Create from square-root derivative Nyquist prototype */ \ +/* _type : filter type (e.g. LIQUID_FIRFILT_RRC) */ \ +/* _M : number of filters in the bank, _M > 0 */ \ +/* _k : nominal samples/symbol, _k > 1 */ \ +/* _m : filter delay [symbols], _m > 0 */ \ +/* _beta : rolloff factor, 0 < _beta <= 1 */ \ +FIRPFB() FIRPFB(_create_drnyquist)(int _type, \ + unsigned int _M, \ + unsigned int _k, \ + unsigned int _m, \ + float _beta); \ + \ +/* Re-create firpfb object of potentially a different length with */ \ +/* different coefficients. If the length of the filter does not change, */ \ +/* not memory reallocation is invoked. */ \ +/* _q : original firpfb object */ \ +/* _M : number of filters in the bank, _M > 1 */ \ +/* _h : coefficients, [size: _h_len x 1] */ \ +/* _h_len : filter length (multiple of _M), _h_len >= _M */ \ +FIRPFB() FIRPFB(_recreate)(FIRPFB() _q, \ + unsigned int _M, \ + TC * _h, \ + unsigned int _h_len); \ + \ +/* Destroy firpfb object, freeing all internal memory and destroying */ \ +/* all internal objects */ \ +void FIRPFB(_destroy)(FIRPFB() _q); \ + \ +/* Print firpfb object's parameters to stdout */ \ +void FIRPFB(_print)(FIRPFB() _q); \ + \ +/* Set output scaling for filter */ \ +/* _q : filter object */ \ +/* _scale : scaling factor to apply to each output sample */ \ +void FIRPFB(_set_scale)(FIRPFB() _q, \ + TC _scale); \ + \ +/* Get output scaling for filter */ \ +/* _q : filter object */ \ +/* _scale : scaling factor applied to each output sample */ \ +void FIRPFB(_get_scale)(FIRPFB() _q, \ + TC * _scale); \ + \ +/* Reset firpfb object's internal buffer */ \ +void FIRPFB(_reset)(FIRPFB() _q); \ + \ +/* Push sample into filter object's internal buffer */ \ +/* _q : filter object */ \ +/* _x : single input sample */ \ +void FIRPFB(_push)(FIRPFB() _q, \ + TI _x); \ + \ +/* Execute vector dot product on the filter's internal buffer and */ \ +/* coefficients using the coefficients from sub-filter at index _i */ \ +/* _q : firpfb object */ \ +/* _i : index of filter to use */ \ +/* _y : pointer to output sample */ \ +void FIRPFB(_execute)(FIRPFB() _q, \ + unsigned int _i, \ + TO * _y); \ + \ +/* Execute the filter on a block of input samples, all using index _i. */ \ +/* In-place operation is permitted (_x and _y may point to the same */ \ +/* place in memory) */ \ +/* _q : firpfb object */ \ +/* _i : index of filter to use */ \ +/* _x : pointer to input array [size: _n x 1] */ \ +/* _n : number of input, output samples */ \ +/* _y : pointer to output array [size: _n x 1] */ \ +void FIRPFB(_execute_block)(FIRPFB() _q, \ + unsigned int _i, \ + TI * _x, \ + unsigned int _n, \ + TO * _y); \ + +LIQUID_FIRPFB_DEFINE_API(LIQUID_FIRPFB_MANGLE_RRRF, + float, + float, + float) + +LIQUID_FIRPFB_DEFINE_API(LIQUID_FIRPFB_MANGLE_CRCF, + liquid_float_complex, + float, + liquid_float_complex) + +LIQUID_FIRPFB_DEFINE_API(LIQUID_FIRPFB_MANGLE_CCCF, + liquid_float_complex, + liquid_float_complex, + liquid_float_complex) + +// +// Interpolators +// + +// firinterp : finite impulse response interpolator +#define LIQUID_FIRINTERP_MANGLE_RRRF(name) LIQUID_CONCAT(firinterp_rrrf,name) +#define LIQUID_FIRINTERP_MANGLE_CRCF(name) LIQUID_CONCAT(firinterp_crcf,name) +#define LIQUID_FIRINTERP_MANGLE_CCCF(name) LIQUID_CONCAT(firinterp_cccf,name) + +#define LIQUID_FIRINTERP_DEFINE_API(FIRINTERP,TO,TC,TI) \ + \ +/* Finite impulse response (FIR) interpolator */ \ +typedef struct FIRINTERP(_s) * FIRINTERP(); \ + \ +/* Create interpolator from external coefficients. Internally the */ \ +/* interpolator creates a polyphase filter bank to efficiently realize */ \ +/* resampling of the input signal. */ \ +/* If the input filter length is not a multiple of the interpolation */ \ +/* factor, the object internally pads the coefficients with zeros to */ \ +/* compensate. */ \ +/* _M : interpolation factor, _M >= 2 */ \ +/* _h : filter coefficients, [size: _h_len x 1] */ \ +/* _h_len : filter length, _h_len >= _M */ \ +FIRINTERP() FIRINTERP(_create)(unsigned int _M, \ + TC * _h, \ + unsigned int _h_len); \ + \ +/* Create interpolator from filter prototype prototype (Kaiser-Bessel */ \ +/* windowed-sinc function) */ \ +/* _M : interpolation factor, _M >= 2 */ \ +/* _m : filter delay [symbols], _m >= 1 */ \ +/* _As : stop-band attenuation [dB], _As >= 0 */ \ +FIRINTERP() FIRINTERP(_create_kaiser)(unsigned int _M, \ + unsigned int _m, \ + float _As); \ + \ +/* Create interpolator object from filter prototype */ \ +/* _type : filter type (e.g. LIQUID_FIRFILT_RCOS) */ \ +/* _M : interpolation factor, _M > 1 */ \ +/* _m : filter delay (symbols), _m > 0 */ \ +/* _beta : excess bandwidth factor, 0 <= _beta <= 1 */ \ +/* _dt : fractional sample delay, -1 <= _dt <= 1 */ \ +FIRINTERP() FIRINTERP(_create_prototype)(int _type, \ + unsigned int _M, \ + unsigned int _m, \ + float _beta, \ + float _dt); \ + \ +/* Create linear interpolator object */ \ +/* _M : interpolation factor, _M > 1 */ \ +FIRINTERP() FIRINTERP(_create_linear)(unsigned int _M); \ + \ +/* Create window interpolator object */ \ +/* _M : interpolation factor, _M > 1 */ \ +/* _m : filter semi-length, _m > 0 */ \ +FIRINTERP() FIRINTERP(_create_window)(unsigned int _M, \ + unsigned int _m); \ + \ +/* Destroy firinterp object, freeing all internal memory */ \ +void FIRINTERP(_destroy)(FIRINTERP() _q); \ + \ +/* Print firinterp object's internal properties to stdout */ \ +void FIRINTERP(_print)(FIRINTERP() _q); \ + \ +/* Reset internal state */ \ +void FIRINTERP(_reset)(FIRINTERP() _q); \ + \ +/* Get interpolation rate */ \ +unsigned int FIRINTERP(_get_interp_rate)(FIRINTERP() _q); \ + \ +/* Set output scaling for interpolator */ \ +/* _q : interpolator object */ \ +/* _scale : scaling factor to apply to each output sample */ \ +void FIRINTERP(_set_scale)(FIRINTERP() _q, \ + TC _scale); \ + \ +/* Get output scaling for interpolator */ \ +/* _q : interpolator object */ \ +/* _scale : scaling factor to apply to each output sample */ \ +void FIRINTERP(_get_scale)(FIRINTERP() _q, \ + TC * _scale); \ + \ +/* Execute interpolation on single input sample and write \(M\) output */ \ +/* samples (\(M\) is the interpolation factor) */ \ +/* _q : firinterp object */ \ +/* _x : input sample */ \ +/* _y : output sample array, [size: _M x 1] */ \ +void FIRINTERP(_execute)(FIRINTERP() _q, \ + TI _x, \ + TO * _y); \ + \ +/* Execute interpolation on block of input samples */ \ +/* _q : firinterp object */ \ +/* _x : input array, [size: _n x 1] */ \ +/* _n : size of input array */ \ +/* _y : output sample array, [size: _M*_n x 1] */ \ +void FIRINTERP(_execute_block)(FIRINTERP() _q, \ + TI * _x, \ + unsigned int _n, \ + TO * _y); \ + +LIQUID_FIRINTERP_DEFINE_API(LIQUID_FIRINTERP_MANGLE_RRRF, + float, + float, + float) + +LIQUID_FIRINTERP_DEFINE_API(LIQUID_FIRINTERP_MANGLE_CRCF, + liquid_float_complex, + float, + liquid_float_complex) + +LIQUID_FIRINTERP_DEFINE_API(LIQUID_FIRINTERP_MANGLE_CCCF, + liquid_float_complex, + liquid_float_complex, + liquid_float_complex) + +// iirinterp : infinite impulse response interpolator +#define LIQUID_IIRINTERP_MANGLE_RRRF(name) LIQUID_CONCAT(iirinterp_rrrf,name) +#define LIQUID_IIRINTERP_MANGLE_CRCF(name) LIQUID_CONCAT(iirinterp_crcf,name) +#define LIQUID_IIRINTERP_MANGLE_CCCF(name) LIQUID_CONCAT(iirinterp_cccf,name) + +#define LIQUID_IIRINTERP_DEFINE_API(IIRINTERP,TO,TC,TI) \ + \ +/* Infinite impulse response (IIR) interpolator */ \ +typedef struct IIRINTERP(_s) * IIRINTERP(); \ + \ +/* Create infinite impulse response interpolator from external */ \ +/* coefficients. */ \ +/* Note that the number of feed-forward and feed-back coefficients do */ \ +/* not need to be equal, but they do need to be non-zero. */ \ +/* Furthermore, the first feed-back coefficient \(a_0\) cannot be */ \ +/* equal to zero, otherwise the filter will be invalid as this value is */ \ +/* factored out from all coefficients. */ \ +/* For stability reasons the number of coefficients should reasonably */ \ +/* not exceed about 8 for single-precision floating-point. */ \ +/* _M : interpolation factor, _M >= 2 */ \ +/* _b : feed-forward coefficients (numerator), [size: _nb x 1] */ \ +/* _nb : number of feed-forward coefficients, _nb > 0 */ \ +/* _a : feed-back coefficients (denominator), [size: _na x 1] */ \ +/* _na : number of feed-back coefficients, _na > 0 */ \ +IIRINTERP() IIRINTERP(_create)(unsigned int _M, \ + TC * _b, \ + unsigned int _nb, \ + TC * _a, \ + unsigned int _na); \ + \ +/* Create interpolator object with default Butterworth prototype */ \ +/* _M : interpolation factor, _M >= 2 */ \ +/* _order : filter order, _order > 0 */ \ +IIRINTERP() IIRINTERP(_create_default)(unsigned int _M, \ + unsigned int _order); \ + \ +/* Create IIR interpolator from prototype */ \ +/* _M : interpolation factor, _M >= 2 */ \ +/* _ftype : filter type (e.g. LIQUID_IIRDES_BUTTER) */ \ +/* _btype : band type (e.g. LIQUID_IIRDES_BANDPASS) */ \ +/* _format : coefficients format (e.g. LIQUID_IIRDES_SOS) */ \ +/* _order : filter order, _order > 0 */ \ +/* _fc : low-pass prototype cut-off frequency, 0 <= _fc <= 0.5 */ \ +/* _f0 : center frequency (band-pass, band-stop), 0 <= _f0 <= 0.5 */ \ +/* _Ap : pass-band ripple in dB, _Ap > 0 */ \ +/* _As : stop-band ripple in dB, _As > 0 */ \ +IIRINTERP() IIRINTERP(_create_prototype)( \ + unsigned int _M, \ + liquid_iirdes_filtertype _ftype, \ + liquid_iirdes_bandtype _btype, \ + liquid_iirdes_format _format, \ + unsigned int _order, \ + float _fc, \ + float _f0, \ + float _Ap, \ + float _As); \ + \ +/* Destroy interpolator object and free internal memory */ \ +void IIRINTERP(_destroy)(IIRINTERP() _q); \ + \ +/* Print interpolator object internals to stdout */ \ +void IIRINTERP(_print)(IIRINTERP() _q); \ + \ +/* Reset interpolator object */ \ +void IIRINTERP(_reset)(IIRINTERP() _q); \ + \ +/* Execute interpolation on single input sample and write \(M\) output */ \ +/* samples (\(M\) is the interpolation factor) */ \ +/* _q : iirinterp object */ \ +/* _x : input sample */ \ +/* _y : output sample array, [size: _M x 1] */ \ +void IIRINTERP(_execute)(IIRINTERP() _q, \ + TI _x, \ + TO * _y); \ + \ +/* Execute interpolation on block of input samples */ \ +/* _q : iirinterp object */ \ +/* _x : input array, [size: _n x 1] */ \ +/* _n : size of input array */ \ +/* _y : output sample array, [size: _M*_n x 1] */ \ +void IIRINTERP(_execute_block)(IIRINTERP() _q, \ + TI * _x, \ + unsigned int _n, \ + TO * _y); \ + \ +/* Compute and return group delay of object */ \ +/* _q : filter object */ \ +/* _fc : frequency to evaluate */ \ +float IIRINTERP(_groupdelay)(IIRINTERP() _q, \ + float _fc); \ + +LIQUID_IIRINTERP_DEFINE_API(LIQUID_IIRINTERP_MANGLE_RRRF, + float, + float, + float) + +LIQUID_IIRINTERP_DEFINE_API(LIQUID_IIRINTERP_MANGLE_CRCF, + liquid_float_complex, + float, + liquid_float_complex) + +LIQUID_IIRINTERP_DEFINE_API(LIQUID_IIRINTERP_MANGLE_CCCF, + liquid_float_complex, + liquid_float_complex, + liquid_float_complex) + +// +// Decimators +// + +// firdecim : finite impulse response decimator +#define LIQUID_FIRDECIM_MANGLE_RRRF(name) LIQUID_CONCAT(firdecim_rrrf,name) +#define LIQUID_FIRDECIM_MANGLE_CRCF(name) LIQUID_CONCAT(firdecim_crcf,name) +#define LIQUID_FIRDECIM_MANGLE_CCCF(name) LIQUID_CONCAT(firdecim_cccf,name) + +#define LIQUID_FIRDECIM_DEFINE_API(FIRDECIM,TO,TC,TI) \ + \ +/* Finite impulse response (FIR) decimator */ \ +typedef struct FIRDECIM(_s) * FIRDECIM(); \ + \ +/* Create decimator from external coefficients */ \ +/* _M : decimation factor, _M >= 2 */ \ +/* _h : filter coefficients, [size: _h_len x 1] */ \ +/* _h_len : filter length, _h_len >= _M */ \ +FIRDECIM() FIRDECIM(_create)(unsigned int _M, \ + TC * _h, \ + unsigned int _h_len); \ + \ +/* Create decimator from filter prototype prototype (Kaiser-Bessel */ \ +/* windowed-sinc function) */ \ +/* _M : decimation factor, _M >= 2 */ \ +/* _m : filter delay [symbols], _m >= 1 */ \ +/* _As : stop-band attenuation [dB], _As >= 0 */ \ +FIRDECIM() FIRDECIM(_create_kaiser)(unsigned int _M, \ + unsigned int _m, \ + float _As); \ + \ +/* Create decimator object from filter prototype */ \ +/* _type : filter type (e.g. LIQUID_FIRFILT_RCOS) */ \ +/* _M : interpolation factor, _M > 1 */ \ +/* _m : filter delay (symbols), _m > 0 */ \ +/* _beta : excess bandwidth factor, 0 <= _beta <= 1 */ \ +/* _dt : fractional sample delay, -1 <= _dt <= 1 */ \ +FIRDECIM() FIRDECIM(_create_prototype)(int _type, \ + unsigned int _M, \ + unsigned int _m, \ + float _beta, \ + float _dt); \ + \ +/* Destroy decimator object, freeing all internal memory */ \ +void FIRDECIM(_destroy)(FIRDECIM() _q); \ + \ +/* Print decimator object propreties to stdout */ \ +void FIRDECIM(_print)(FIRDECIM() _q); \ + \ +/* Reset decimator object internal state */ \ +void FIRDECIM(_reset)(FIRDECIM() _q); \ + \ +/* Get decimation rate */ \ +unsigned int FIRDECIM(_get_decim_rate)(FIRDECIM() _q); \ + \ +/* Set output scaling for decimator */ \ +/* _q : decimator object */ \ +/* _scale : scaling factor to apply to each output sample */ \ +void FIRDECIM(_set_scale)(FIRDECIM() _q, \ + TC _scale); \ + \ +/* Get output scaling for decimator */ \ +/* _q : decimator object */ \ +/* _scale : scaling factor to apply to each output sample */ \ +void FIRDECIM(_get_scale)(FIRDECIM() _q, \ + TC * _scale); \ + \ +/* Execute decimator on _M input samples */ \ +/* _q : decimator object */ \ +/* _x : input samples, [size: _M x 1] */ \ +/* _y : output sample pointer */ \ +void FIRDECIM(_execute)(FIRDECIM() _q, \ + TI * _x, \ + TO * _y); \ + \ +/* Execute decimator on block of _n*_M input samples */ \ +/* _q : decimator object */ \ +/* _x : input array, [size: _n*_M x 1] */ \ +/* _n : number of _output_ samples */ \ +/* _y : output array, [_size: _n x 1] */ \ +void FIRDECIM(_execute_block)(FIRDECIM() _q, \ + TI * _x, \ + unsigned int _n, \ + TO * _y); \ + +LIQUID_FIRDECIM_DEFINE_API(LIQUID_FIRDECIM_MANGLE_RRRF, + float, + float, + float) + +LIQUID_FIRDECIM_DEFINE_API(LIQUID_FIRDECIM_MANGLE_CRCF, + liquid_float_complex, + float, + liquid_float_complex) + +LIQUID_FIRDECIM_DEFINE_API(LIQUID_FIRDECIM_MANGLE_CCCF, + liquid_float_complex, + liquid_float_complex, + liquid_float_complex) + + +// iirdecim : infinite impulse response decimator +#define LIQUID_IIRDECIM_MANGLE_RRRF(name) LIQUID_CONCAT(iirdecim_rrrf,name) +#define LIQUID_IIRDECIM_MANGLE_CRCF(name) LIQUID_CONCAT(iirdecim_crcf,name) +#define LIQUID_IIRDECIM_MANGLE_CCCF(name) LIQUID_CONCAT(iirdecim_cccf,name) + +#define LIQUID_IIRDECIM_DEFINE_API(IIRDECIM,TO,TC,TI) \ + \ +/* Infinite impulse response (IIR) decimator */ \ +typedef struct IIRDECIM(_s) * IIRDECIM(); \ + \ +/* Create infinite impulse response decimator from external */ \ +/* coefficients. */ \ +/* Note that the number of feed-forward and feed-back coefficients do */ \ +/* not need to be equal, but they do need to be non-zero. */ \ +/* Furthermore, the first feed-back coefficient \(a_0\) cannot be */ \ +/* equal to zero, otherwise the filter will be invalid as this value is */ \ +/* factored out from all coefficients. */ \ +/* For stability reasons the number of coefficients should reasonably */ \ +/* not exceed about 8 for single-precision floating-point. */ \ +/* _M : decimation factor, _M >= 2 */ \ +/* _b : feed-forward coefficients (numerator), [size: _nb x 1] */ \ +/* _nb : number of feed-forward coefficients, _nb > 0 */ \ +/* _a : feed-back coefficients (denominator), [size: _na x 1] */ \ +/* _na : number of feed-back coefficients, _na > 0 */ \ +IIRDECIM() IIRDECIM(_create)(unsigned int _M, \ + TC * _b, \ + unsigned int _nb, \ + TC * _a, \ + unsigned int _na); \ + \ +/* Create decimator object with default Butterworth prototype */ \ +/* _M : decimation factor, _M >= 2 */ \ +/* _order : filter order, _order > 0 */ \ +IIRDECIM() IIRDECIM(_create_default)(unsigned int _M, \ + unsigned int _order); \ + \ +/* Create IIR decimator from prototype */ \ +/* _M : decimation factor, _M >= 2 */ \ +/* _ftype : filter type (e.g. LIQUID_IIRDES_BUTTER) */ \ +/* _btype : band type (e.g. LIQUID_IIRDES_BANDPASS) */ \ +/* _format : coefficients format (e.g. LIQUID_IIRDES_SOS) */ \ +/* _order : filter order, _order > 0 */ \ +/* _fc : low-pass prototype cut-off frequency, 0 <= _fc <= 0.5 */ \ +/* _f0 : center frequency (band-pass, band-stop), 0 <= _f0 <= 0.5 */ \ +/* _Ap : pass-band ripple in dB, _Ap > 0 */ \ +/* _As : stop-band ripple in dB, _As > 0 */ \ +IIRDECIM() IIRDECIM(_create_prototype)( \ + unsigned int _M, \ + liquid_iirdes_filtertype _ftype, \ + liquid_iirdes_bandtype _btype, \ + liquid_iirdes_format _format, \ + unsigned int _order, \ + float _fc, \ + float _f0, \ + float _Ap, \ + float _As); \ + \ +/* Destroy decimator object and free internal memory */ \ +void IIRDECIM(_destroy)(IIRDECIM() _q); \ + \ +/* Print decimator object internals */ \ +void IIRDECIM(_print)(IIRDECIM() _q); \ + \ +/* Reset decimator object */ \ +void IIRDECIM(_reset)(IIRDECIM() _q); \ + \ +/* Execute decimator on _M input samples */ \ +/* _q : decimator object */ \ +/* _x : input samples, [size: _M x 1] */ \ +/* _y : output sample pointer */ \ +void IIRDECIM(_execute)(IIRDECIM() _q, \ + TI * _x, \ + TO * _y); \ + \ +/* Execute decimator on block of _n*_M input samples */ \ +/* _q : decimator object */ \ +/* _x : input array, [size: _n*_M x 1] */ \ +/* _n : number of _output_ samples */ \ +/* _y : output array, [_sze: _n x 1] */ \ +void IIRDECIM(_execute_block)(IIRDECIM() _q, \ + TI * _x, \ + unsigned int _n, \ + TO * _y); \ + \ +/* Compute and return group delay of object */ \ +/* _q : filter object */ \ +/* _fc : frequency to evaluate */ \ +float IIRDECIM(_groupdelay)(IIRDECIM() _q, \ + float _fc); \ + +LIQUID_IIRDECIM_DEFINE_API(LIQUID_IIRDECIM_MANGLE_RRRF, + float, + float, + float) + +LIQUID_IIRDECIM_DEFINE_API(LIQUID_IIRDECIM_MANGLE_CRCF, + liquid_float_complex, + float, + liquid_float_complex) + +LIQUID_IIRDECIM_DEFINE_API(LIQUID_IIRDECIM_MANGLE_CCCF, + liquid_float_complex, + liquid_float_complex, + liquid_float_complex) + + + +// +// Half-band resampler +// +#define LIQUID_RESAMP2_MANGLE_RRRF(name) LIQUID_CONCAT(resamp2_rrrf,name) +#define LIQUID_RESAMP2_MANGLE_CRCF(name) LIQUID_CONCAT(resamp2_crcf,name) +#define LIQUID_RESAMP2_MANGLE_CCCF(name) LIQUID_CONCAT(resamp2_cccf,name) + +#define LIQUID_RESAMP2_DEFINE_API(RESAMP2,TO,TC,TI) \ + \ +/* Half-band resampler, implemented as a dyadic (half-band) polyphase */ \ +/* filter bank for interpolation, decimation, synthesis, and analysis. */ \ +typedef struct RESAMP2(_s) * RESAMP2(); \ + \ +/* Create half-band resampler from design prototype. */ \ +/* _m : filter semi-length (h_len = 4*m+1), _m >= 2 */ \ +/* _f0 : filter center frequency, -0.5 <= _f0 <= 0.5 */ \ +/* _As : stop-band attenuation [dB], _As > 0 */ \ +RESAMP2() RESAMP2(_create)(unsigned int _m, \ + float _f0, \ + float _As); \ + \ +/* Re-create half-band resampler with new properties */ \ +/* _q : original half-band resampler object */ \ +/* _m : filter semi-length (h_len = 4*m+1), _m >= 2 */ \ +/* _f0 : filter center frequency, -0.5 <= _f0 <= 0.5 */ \ +/* _As : stop-band attenuation [dB], _As > 0 */ \ +RESAMP2() RESAMP2(_recreate)(RESAMP2() _q, \ + unsigned int _m, \ + float _f0, \ + float _As); \ + \ +/* Destroy resampler, freeing all internally-allocated memory */ \ +void RESAMP2(_destroy)(RESAMP2() _q); \ + \ +/* print resampler object's internals to stdout */ \ +void RESAMP2(_print)(RESAMP2() _q); \ + \ +/* Reset internal buffer */ \ +void RESAMP2(_reset)(RESAMP2() _q); \ + \ +/* Get resampler filter delay (semi-length m) */ \ +unsigned int RESAMP2(_get_delay)(RESAMP2() _q); \ + \ +/* Execute resampler as half-band filter for a single input sample */ \ +/* \(x\) where \(y_0\) is the output of the effective low-pass filter, */ \ +/* and \(y_1\) is the output of the effective high-pass filter. */ \ +/* _q : resampler object */ \ +/* _x : input sample */ \ +/* _y0 : output sample pointer (low frequency) */ \ +/* _y1 : output sample pointer (high frequency) */ \ +void RESAMP2(_filter_execute)(RESAMP2() _q, \ + TI _x, \ + TO * _y0, \ + TO * _y1); \ + \ +/* Execute resampler as half-band analysis filterbank on a pair of */ \ +/* sequential time-domain input samples. */ \ +/* The decimated outputs of the low- and high-pass equivalent filters */ \ +/* are stored in \(y_0\) and \(y_1\), respectively. */ \ +/* _q : resampler object */ \ +/* _x : input array, [size: 2 x 1] */ \ +/* _y : output array, [size: 2 x 1] */ \ +void RESAMP2(_analyzer_execute)(RESAMP2() _q, \ + TI * _x, \ + TO * _y); \ + \ +/* Execute resampler as half-band synthesis filterbank on a pair of */ \ +/* input samples. The low- and high-pass input samples are provided by */ \ +/* \(x_0\) and \(x_1\), respectively. The sequential time-domain output */ \ +/* samples are stored in \(y_0\) and \(y_1\). */ \ +/* _q : resampler object */ \ +/* _x : input array [size: 2 x 1] */ \ +/* _y : output array [size: 2 x 1] */ \ +void RESAMP2(_synthesizer_execute)(RESAMP2() _q, \ + TI * _x, \ + TO * _y); \ + \ +/* Execute resampler as half-band decimator on a pair of sequential */ \ +/* time-domain input samples. */ \ +/* _q : resampler object */ \ +/* _x : input array [size: 2 x 1] */ \ +/* _y : output sample pointer */ \ +void RESAMP2(_decim_execute)(RESAMP2() _q, \ + TI * _x, \ + TO * _y); \ + \ +/* Execute resampler as half-band interpolator on a single input sample */ \ +/* _q : resampler object */ \ +/* _x : input sample */ \ +/* _y : output array [size: 2 x 1] */ \ +void RESAMP2(_interp_execute)(RESAMP2() _q, \ + TI _x, \ + TO * _y); \ + +LIQUID_RESAMP2_DEFINE_API(LIQUID_RESAMP2_MANGLE_RRRF, + float, + float, + float) + +LIQUID_RESAMP2_DEFINE_API(LIQUID_RESAMP2_MANGLE_CRCF, + liquid_float_complex, + float, + liquid_float_complex) + +LIQUID_RESAMP2_DEFINE_API(LIQUID_RESAMP2_MANGLE_CCCF, + liquid_float_complex, + liquid_float_complex, + liquid_float_complex) + + +// +// Rational resampler +// +#define LIQUID_RRESAMP_MANGLE_RRRF(name) LIQUID_CONCAT(rresamp_rrrf,name) +#define LIQUID_RRESAMP_MANGLE_CRCF(name) LIQUID_CONCAT(rresamp_crcf,name) +#define LIQUID_RRESAMP_MANGLE_CCCF(name) LIQUID_CONCAT(rresamp_cccf,name) + +#define LIQUID_RRESAMP_DEFINE_API(RRESAMP,TO,TC,TI) \ + \ +/* Rational rate resampler, implemented as a polyphase filterbank */ \ +typedef struct RRESAMP(_s) * RRESAMP(); \ + \ +/* Create rational-rate resampler object from external coeffcients to */ \ +/* resample at an exact rate P/Q. */ \ +/* Note that to preserve the input filter coefficients, the greatest */ \ +/* common divisor (gcd) is not removed internally from _P and _Q when */ \ +/* this method is called. */ \ +/* _P : interpolation factor, P > 0 */ \ +/* _Q : decimation factor, Q > 0 */ \ +/* _m : filter semi-length (delay), 0 < _m */ \ +/* _h : filter coefficients, [size: 2*_P*_m x 1] */ \ +RRESAMP() RRESAMP(_create)(unsigned int _P, \ + unsigned int _Q, \ + unsigned int _m, \ + TC * _h); \ + \ +/* Create rational-rate resampler object from filter prototype to */ \ +/* resample at an exact rate P/Q. */ \ +/* Note that because the filter coefficients are computed internally */ \ +/* here, the greatest common divisor (gcd) from _P and _Q is internally */ \ +/* removed to improve speed. */ \ +/* _P : interpolation factor, P > 0 */ \ +/* _Q : decimation factor, Q > 0 */ \ +/* _m : filter semi-length (delay), 0 < _m */ \ +/* _bw : filter bandwidth relative to sample rate, 0 < _bw <= 0.5 */ \ +/* _As : filter stop-band attenuation [dB], 0 < _As */ \ +RRESAMP() RRESAMP(_create_kaiser)(unsigned int _P, \ + unsigned int _Q, \ + unsigned int _m, \ + float _bw, \ + float _As); \ + \ +/* Create rational-rate resampler object from filter prototype to */ \ +/* resample at an exact rate P/Q. */ \ +/* Note that because the filter coefficients are computed internally */ \ +/* here, the greatest common divisor (gcd) from _P and _Q is internally */ \ +/* removed to improve speed. */ \ +RRESAMP() RRESAMP(_create_prototype)(int _type, \ + unsigned int _P, \ + unsigned int _Q, \ + unsigned int _m, \ + float _beta); \ + \ +/* Create rational resampler object with a specified resampling rate of */ \ +/* exactly P/Q with default parameters. This is a simplified method to */ \ +/* provide a basic resampler with a baseline set of parameters, */ \ +/* abstracting away some of the complexities with the filterbank */ \ +/* design. */ \ +/* The default parameters are */ \ +/* m = 12 (filter semi-length), */ \ +/* bw = 0.5 (filter bandwidth), and */ \ +/* As = 60 dB (filter stop-band attenuation) */ \ +/* _P : interpolation factor, P > 0 */ \ +/* _Q : decimation factor, Q > 0 */ \ +RRESAMP() RRESAMP(_create_default)(unsigned int _P, \ + unsigned int _Q); \ + \ +/* Destroy resampler object, freeing all internal memory */ \ +void RRESAMP(_destroy)(RRESAMP() _q); \ + \ +/* Print resampler object internals to stdout */ \ +void RRESAMP(_print)(RRESAMP() _q); \ + \ +/* Reset resampler object internals */ \ +void RRESAMP(_reset)(RRESAMP() _q); \ + \ +/* Set output scaling for filter, default: \( 2 w \sqrt{P/Q} \) */ \ +/* _q : resampler object */ \ +/* _scale : scaling factor to apply to each output sample */ \ +void RRESAMP(_set_scale)(RRESAMP() _q, \ + TC _scale); \ + \ +/* Get output scaling for filter */ \ +/* _q : resampler object */ \ +/* _scale : scaling factor to apply to each output sample */ \ +void RRESAMP(_get_scale)(RRESAMP() _q, \ + TC * _scale); \ + \ +/* Get resampler delay (filter semi-length \(m\)) */ \ +unsigned int RRESAMP(_get_delay)(RRESAMP() _q); \ + \ +/* Get original interpolation factor \(P\) when object was created */ \ +/* before removing greatest common divisor */ \ +unsigned int RRESAMP(_get_P)(RRESAMP() _q); \ + \ +/* Get internal interpolation factor of resampler, \(P\), after */ \ +/* removing greatest common divisor */ \ +unsigned int RRESAMP(_get_interp)(RRESAMP() _q); \ + \ +/* Get original decimation factor \(Q\) when object was created */ \ +/* before removing greatest common divisor */ \ +unsigned int RRESAMP(_get_Q)(RRESAMP() _q); \ + \ +/* Get internal decimation factor of resampler, \(Q\), after removing */ \ +/* greatest common divisor */ \ +unsigned int RRESAMP(_get_decim)(RRESAMP() _q); \ + \ +/* Get block length (e.g. greatest common divisor) between original P */ \ +/* and Q values */ \ +unsigned int RRESAMP(_get_block_len)(RRESAMP() _q); \ + \ +/* Get rate of resampler, \(r = P/Q\) */ \ +float RRESAMP(_get_rate)(RRESAMP() _q); \ + \ +/* Execute rational-rate resampler on a block of input samples and */ \ +/* store the resulting samples in the output array. */ \ +/* Note that the size of the input and output buffers correspond to the */ \ +/* values of P and Q passed when the object was created, even if they */ \ +/* share a common divisor. Internally the rational resampler reduces P */ \ +/* and Q by their greatest commmon denominator to reduce processing; */ \ +/* however sometimes it is convenienct to create the object based on */ \ +/* expected output/input block sizes. This expectation is preserved. So */ \ +/* if an object is created with P=80 and Q=72, the object will */ \ +/* internally set P=10 and Q=9 (with a g.c.d of 8); however when */ \ +/* "execute" is called the resampler will still expect an input buffer */ \ +/* of 72 and an output buffer of 80. */ \ +/* _q : resamp object */ \ +/* _x : input sample array, [size: Q x 1] */ \ +/* _y : output sample array [size: P x 1] */ \ +void RRESAMP(_execute)(RRESAMP() _q, \ + TI * _x, \ + TO * _y); \ + +LIQUID_RRESAMP_DEFINE_API(LIQUID_RRESAMP_MANGLE_RRRF, + float, + float, + float) + +LIQUID_RRESAMP_DEFINE_API(LIQUID_RRESAMP_MANGLE_CRCF, + liquid_float_complex, + float, + liquid_float_complex) + +LIQUID_RRESAMP_DEFINE_API(LIQUID_RRESAMP_MANGLE_CCCF, + liquid_float_complex, + liquid_float_complex, + liquid_float_complex) + + +// +// Arbitrary resampler +// +#define LIQUID_RESAMP_MANGLE_RRRF(name) LIQUID_CONCAT(resamp_rrrf,name) +#define LIQUID_RESAMP_MANGLE_CRCF(name) LIQUID_CONCAT(resamp_crcf,name) +#define LIQUID_RESAMP_MANGLE_CCCF(name) LIQUID_CONCAT(resamp_cccf,name) + +#define LIQUID_RESAMP_DEFINE_API(RESAMP,TO,TC,TI) \ + \ +/* Arbitrary rate resampler, implemented as a polyphase filterbank */ \ +typedef struct RESAMP(_s) * RESAMP(); \ + \ +/* Create arbitrary resampler object from filter prototype */ \ +/* _rate : arbitrary resampling rate, 0 < _rate */ \ +/* _m : filter semi-length (delay), 0 < _m */ \ +/* _fc : filter cutoff frequency, 0 < _fc < 0.5 */ \ +/* _As : filter stop-band attenuation [dB], 0 < _As */ \ +/* _npfb : number of filters in the bank, 0 < _npfb */ \ +RESAMP() RESAMP(_create)(float _rate, \ + unsigned int _m, \ + float _fc, \ + float _As, \ + unsigned int _npfb); \ + \ +/* Create arbitrary resampler object with a specified input resampling */ \ +/* rate and default parameters. This is a simplified method to provide */ \ +/* a basic resampler with a baseline set of parameters, abstracting */ \ +/* away some of the complexities with the filterbank design. */ \ +/* The default parameters are */ \ +/* m = 7 (filter semi-length), */ \ +/* fc = min(0.49,_rate/2) (filter cutoff frequency), */ \ +/* As = 60 dB (filter stop-band attenuation), and */ \ +/* npfb = 64 (number of filters in the bank). */ \ +/* _rate : arbitrary resampling rate, 0 < _rate */ \ +RESAMP() RESAMP(_create_default)(float _rate); \ + \ +/* Destroy arbitrary resampler object, freeing all internal memory */ \ +void RESAMP(_destroy)(RESAMP() _q); \ + \ +/* Print resamp object internals to stdout */ \ +void RESAMP(_print)(RESAMP() _q); \ + \ +/* Reset resamp object internals */ \ +void RESAMP(_reset)(RESAMP() _q); \ + \ +/* Get resampler delay (filter semi-length \(m\)) */ \ +unsigned int RESAMP(_get_delay)(RESAMP() _q); \ + \ +/* Set rate of arbitrary resampler */ \ +/* _q : resampling object */ \ +/* _rate : new sampling rate, _rate > 0 */ \ +void RESAMP(_set_rate)(RESAMP() _q, \ + float _rate); \ + \ +/* Get rate of arbitrary resampler */ \ +float RESAMP(_get_rate)(RESAMP() _q); \ + \ +/* adjust rate of arbitrary resampler */ \ +/* _q : resampling object */ \ +/* _gamma : rate adjustment factor: rate <- rate * gamma, _gamma > 0 */ \ +void RESAMP(_adjust_rate)(RESAMP() _q, \ + float _gamma); \ + \ +/* Set resampling timing phase */ \ +/* _q : resampling object */ \ +/* _tau : sample timing phase, -1 <= _tau <= 1 */ \ +void RESAMP(_set_timing_phase)(RESAMP() _q, \ + float _tau); \ + \ +/* Adjust resampling timing phase */ \ +/* _q : resampling object */ \ +/* _delta : sample timing adjustment, -1 <= _delta <= 1 */ \ +void RESAMP(_adjust_timing_phase)(RESAMP() _q, \ + float _delta); \ + \ +/* Execute arbitrary resampler on a single input sample and store the */ \ +/* resulting samples in the output array. The number of output samples */ \ +/* is depenent upon the resampling rate but will be at most */ \ +/* \( \lceil{ r \rceil} \) samples. */ \ +/* _q : resamp object */ \ +/* _x : single input sample */ \ +/* _y : output sample array (pointer) */ \ +/* _num_written : number of samples written to _y */ \ +void RESAMP(_execute)(RESAMP() _q, \ + TI _x, \ + TO * _y, \ + unsigned int * _num_written); \ + \ +/* Execute arbitrary resampler on a block of input samples and store */ \ +/* the resulting samples in the output array. The number of output */ \ +/* samples is depenent upon the resampling rate and the number of input */ \ +/* samples but will be at most \( \lceil{ r n_x \rceil} \) samples. */ \ +/* _q : resamp object */ \ +/* _x : input buffer, [size: _nx x 1] */ \ +/* _nx : input buffer */ \ +/* _y : output sample array (pointer) */ \ +/* _ny : number of samples written to _y */ \ +void RESAMP(_execute_block)(RESAMP() _q, \ + TI * _x, \ + unsigned int _nx, \ + TO * _y, \ + unsigned int * _ny); \ + +LIQUID_RESAMP_DEFINE_API(LIQUID_RESAMP_MANGLE_RRRF, + float, + float, + float) + +LIQUID_RESAMP_DEFINE_API(LIQUID_RESAMP_MANGLE_CRCF, + liquid_float_complex, + float, + liquid_float_complex) + +LIQUID_RESAMP_DEFINE_API(LIQUID_RESAMP_MANGLE_CCCF, + liquid_float_complex, + liquid_float_complex, + liquid_float_complex) + + +// +// Multi-stage half-band resampler +// + +// resampling type (interpolator/decimator) +typedef enum { + LIQUID_RESAMP_INTERP=0, // interpolator + LIQUID_RESAMP_DECIM, // decimator +} liquid_resamp_type; + +#define LIQUID_MSRESAMP2_MANGLE_RRRF(name) LIQUID_CONCAT(msresamp2_rrrf,name) +#define LIQUID_MSRESAMP2_MANGLE_CRCF(name) LIQUID_CONCAT(msresamp2_crcf,name) +#define LIQUID_MSRESAMP2_MANGLE_CCCF(name) LIQUID_CONCAT(msresamp2_cccf,name) + +#define LIQUID_MSRESAMP2_DEFINE_API(MSRESAMP2,TO,TC,TI) \ + \ +/* Multi-stage half-band resampler, implemented as cascaded dyadic */ \ +/* (half-band) polyphase filter banks for interpolation and decimation. */ \ +typedef struct MSRESAMP2(_s) * MSRESAMP2(); \ + \ +/* Create multi-stage half-band resampler as either decimator or */ \ +/* interpolator. */ \ +/* _type : resampler type (e.g. LIQUID_RESAMP_DECIM) */ \ +/* _num_stages : number of resampling stages, _num_stages <= 16 */ \ +/* _fc : filter cut-off frequency, 0 < _fc < 0.5 */ \ +/* _f0 : filter center frequency (set to zero) */ \ +/* _As : stop-band attenuation [dB], _As > 0 */ \ +MSRESAMP2() MSRESAMP2(_create)(int _type, \ + unsigned int _num_stages, \ + float _fc, \ + float _f0, \ + float _As); \ + \ +/* Destroy multi-stage half-band resampler, freeing all internal memory */ \ +void MSRESAMP2(_destroy)(MSRESAMP2() _q); \ + \ +/* Print msresamp object internals to stdout */ \ +void MSRESAMP2(_print)(MSRESAMP2() _q); \ + \ +/* Reset msresamp object internal state */ \ +void MSRESAMP2(_reset)(MSRESAMP2() _q); \ + \ +/* Get multi-stage half-band resampling rate */ \ +float MSRESAMP2(_get_rate)(MSRESAMP2() _q); \ + \ +/* Get number of half-band resampling stages in object */ \ +unsigned int MSRESAMP2(_get_num_stages)(MSRESAMP2() _q); \ + \ +/* Get resampling type (LIQUID_RESAMP_DECIM, LIQUID_RESAMP_INTERP) */ \ +int MSRESAMP2(_get_type)(MSRESAMP2() _q); \ + \ +/* Get group delay (number of output samples) */ \ +float MSRESAMP2(_get_delay)(MSRESAMP2() _q); \ + \ +/* Execute multi-stage resampler, M = 2^num_stages */ \ +/* LIQUID_RESAMP_INTERP: input: 1, output: M */ \ +/* LIQUID_RESAMP_DECIM: input: M, output: 1 */ \ +/* _q : msresamp object */ \ +/* _x : input sample array */ \ +/* _y : output sample array */ \ +void MSRESAMP2(_execute)(MSRESAMP2() _q, \ + TI * _x, \ + TO * _y); \ + +LIQUID_MSRESAMP2_DEFINE_API(LIQUID_MSRESAMP2_MANGLE_RRRF, + float, + float, + float) + +LIQUID_MSRESAMP2_DEFINE_API(LIQUID_MSRESAMP2_MANGLE_CRCF, + liquid_float_complex, + float, + liquid_float_complex) + +LIQUID_MSRESAMP2_DEFINE_API(LIQUID_MSRESAMP2_MANGLE_CCCF, + liquid_float_complex, + liquid_float_complex, + liquid_float_complex) + + +// +// Multi-stage arbitrary resampler +// +#define LIQUID_MSRESAMP_MANGLE_RRRF(name) LIQUID_CONCAT(msresamp_rrrf,name) +#define LIQUID_MSRESAMP_MANGLE_CRCF(name) LIQUID_CONCAT(msresamp_crcf,name) +#define LIQUID_MSRESAMP_MANGLE_CCCF(name) LIQUID_CONCAT(msresamp_cccf,name) + +#define LIQUID_MSRESAMP_DEFINE_API(MSRESAMP,TO,TC,TI) \ + \ +/* Multi-stage half-band resampler, implemented as cascaded dyadic */ \ +/* (half-band) polyphase filter banks followed by an arbitrary rate */ \ +/* resampler for interpolation and decimation. */ \ +typedef struct MSRESAMP(_s) * MSRESAMP(); \ + \ +/* Create multi-stage arbitrary resampler */ \ +/* _r : resampling rate (output/input), _r > 0 */ \ +/* _As : stop-band attenuation [dB], _As > 0 */ \ +MSRESAMP() MSRESAMP(_create)(float _r, \ + float _As); \ + \ +/* Destroy multi-stage arbitrary resampler */ \ +void MSRESAMP(_destroy)(MSRESAMP() _q); \ + \ +/* Print msresamp object internals to stdout */ \ +void MSRESAMP(_print)(MSRESAMP() _q); \ + \ +/* Reset msresamp object internal state */ \ +void MSRESAMP(_reset)(MSRESAMP() _q); \ + \ +/* Get filter delay (output samples) */ \ +float MSRESAMP(_get_delay)(MSRESAMP() _q); \ + \ +/* get overall resampling rate */ \ +float MSRESAMP(_get_rate)(MSRESAMP() _q); \ + \ +/* Execute multi-stage resampler on one or more input samples. */ \ +/* The number of output samples is dependent upon the resampling rate */ \ +/* and the number of input samples. In general it is good practice to */ \ +/* allocate at least \( \lceil{ 1 + 2 r n_x \rceil} \) samples in the */ \ +/* output array to avoid overflows. */ \ +/* _q : msresamp object */ \ +/* _x : input sample array, [size: _nx x 1] */ \ +/* _nx : input sample array size */ \ +/* _y : pointer to output array for storing result */ \ +/* _ny : number of samples written to _y */ \ +void MSRESAMP(_execute)(MSRESAMP() _q, \ + TI * _x, \ + unsigned int _nx, \ + TO * _y, \ + unsigned int * _ny); \ + +LIQUID_MSRESAMP_DEFINE_API(LIQUID_MSRESAMP_MANGLE_RRRF, + float, + float, + float) + +LIQUID_MSRESAMP_DEFINE_API(LIQUID_MSRESAMP_MANGLE_CRCF, + liquid_float_complex, + float, + liquid_float_complex) + +LIQUID_MSRESAMP_DEFINE_API(LIQUID_MSRESAMP_MANGLE_CCCF, + liquid_float_complex, + liquid_float_complex, + liquid_float_complex) + +// +// Direct digital [up/down] synthesizer +// + +#define DDS_MANGLE_CCCF(name) LIQUID_CONCAT(dds_cccf,name) + +#define LIQUID_DDS_DEFINE_API(DDS,TO,TC,TI) \ +typedef struct DDS(_s) * DDS(); \ + \ +/* create digital synthesizer object */ \ +DDS() DDS(_create)(unsigned int _num_stages, \ + float _fc, \ + float _bw, \ + float _As); \ + \ +/* destroy digital synthesizer object */ \ +void DDS(_destroy)(DDS() _q); \ + \ +/* print synthesizer object internals to stdout */ \ +void DDS(_print)(DDS() _q); \ + \ +/* reset synthesizer object internals */ \ +void DDS(_reset)(DDS() _q); \ + \ +void DDS(_decim_execute)(DDS() _q, \ + TI * _x, \ + TO * _y); \ +void DDS(_interp_execute)(DDS() _q, \ + TI _x, \ + TO * _y); \ + +LIQUID_DDS_DEFINE_API(DDS_MANGLE_CCCF, + liquid_float_complex, + liquid_float_complex, + liquid_float_complex) + + +// +// Symbol timing recovery (symbol synchronizer) +// +#define LIQUID_SYMSYNC_MANGLE_RRRF(name) LIQUID_CONCAT(symsync_rrrf,name) +#define LIQUID_SYMSYNC_MANGLE_CRCF(name) LIQUID_CONCAT(symsync_crcf,name) + +#define LIQUID_SYMSYNC_DEFINE_API(SYMSYNC,TO,TC,TI) \ + \ +/* Multi-rate symbol synchronizer for symbol timing recovery. */ \ +typedef struct SYMSYNC(_s) * SYMSYNC(); \ + \ +/* Create synchronizer object from external coefficients */ \ +/* _k : samples per symbol, _k >= 2 */ \ +/* _M : number of filters in the bank, _M > 0 */ \ +/* _h : matched filter coefficients, [size: _h_len x 1] */ \ +/* _h_len : length of matched filter; \( h_{len} = 2 k m + 1 \) */ \ +SYMSYNC() SYMSYNC(_create)(unsigned int _k, \ + unsigned int _M, \ + TC * _h, \ + unsigned int _h_len); \ + \ +/* Create square-root Nyquist symbol synchronizer from prototype */ \ +/* _type : filter type (e.g. LIQUID_FIRFILT_RRC) */ \ +/* _k : samples/symbol, _k >= 2 */ \ +/* _m : symbol delay, _m > 0 */ \ +/* _beta : rolloff factor, 0 <= _beta <= 1 */ \ +/* _M : number of filters in the bank, _M > 0 */ \ +SYMSYNC() SYMSYNC(_create_rnyquist)(int _type, \ + unsigned int _k, \ + unsigned int _m, \ + float _beta, \ + unsigned int _M); \ + \ +/* Create symsync using Kaiser filter interpolator. This is useful when */ \ +/* the input signal has its matched filter applied already. */ \ +/* _k : input samples/symbol, _k >= 2 */ \ +/* _m : symbol delay, _m > 0 */ \ +/* _beta : rolloff factor, 0<= _beta <= 1 */ \ +/* _M : number of filters in the bank, _M > 0 */ \ +SYMSYNC() SYMSYNC(_create_kaiser)(unsigned int _k, \ + unsigned int _m, \ + float _beta, \ + unsigned int _M); \ + \ +/* Destroy symsync object, freeing all internal memory */ \ +void SYMSYNC(_destroy)(SYMSYNC() _q); \ + \ +/* Print symsync object's parameters to stdout */ \ +void SYMSYNC(_print)(SYMSYNC() _q); \ + \ +/* Reset symsync internal state */ \ +void SYMSYNC(_reset)(SYMSYNC() _q); \ + \ +/* Lock the symbol synchronizer's loop control */ \ +void SYMSYNC(_lock)(SYMSYNC() _q); \ + \ +/* Unlock the symbol synchronizer's loop control */ \ +void SYMSYNC(_unlock)(SYMSYNC() _q); \ + \ +/* Set synchronizer output rate (samples/symbol) */ \ +/* _q : synchronizer object */ \ +/* _k_out : output samples/symbol, _k_out > 0 */ \ +void SYMSYNC(_set_output_rate)(SYMSYNC() _q, \ + unsigned int _k_out); \ + \ +/* Set loop-filter bandwidth */ \ +/* _q : synchronizer object */ \ +/* _bt : loop bandwidth, 0 <= _bt <= 1 */ \ +void SYMSYNC(_set_lf_bw)(SYMSYNC() _q, \ + float _bt); \ + \ +/* Return instantaneous fractional timing offset estimate */ \ +float SYMSYNC(_get_tau)(SYMSYNC() _q); \ + \ +/* Execute synchronizer on input data array */ \ +/* _q : synchronizer object */ \ +/* _x : input data array, [size: _nx x 1] */ \ +/* _nx : number of input samples */ \ +/* _y : output data array */ \ +/* _ny : number of samples written to output buffer */ \ +void SYMSYNC(_execute)(SYMSYNC() _q, \ + TI * _x, \ + unsigned int _nx, \ + TO * _y, \ + unsigned int * _ny); \ + +LIQUID_SYMSYNC_DEFINE_API(LIQUID_SYMSYNC_MANGLE_RRRF, + float, + float, + float) + +LIQUID_SYMSYNC_DEFINE_API(LIQUID_SYMSYNC_MANGLE_CRCF, + liquid_float_complex, + float, + liquid_float_complex) + + +// +// Finite impulse response Farrow filter +// + +#define LIQUID_FIRFARROW_MANGLE_RRRF(name) LIQUID_CONCAT(firfarrow_rrrf,name) +#define LIQUID_FIRFARROW_MANGLE_CRCF(name) LIQUID_CONCAT(firfarrow_crcf,name) +//#define LIQUID_FIRFARROW_MANGLE_CCCF(name) LIQUID_CONCAT(firfarrow_cccf,name) + +// Macro: +// FIRFARROW : name-mangling macro +// TO : output data type +// TC : coefficients data type +// TI : input data type +#define LIQUID_FIRFARROW_DEFINE_API(FIRFARROW,TO,TC,TI) \ + \ +/* Finite impulse response (FIR) Farrow filter for timing delay */ \ +typedef struct FIRFARROW(_s) * FIRFARROW(); \ + \ +/* Create firfarrow object */ \ +/* _h_len : filter length, _h_len >= 2 */ \ +/* _p : polynomial order, _p >= 1 */ \ +/* _fc : filter cutoff frequency, 0 <= _fc <= 0.5 */ \ +/* _As : stopband attenuation [dB], _As > 0 */ \ +FIRFARROW() FIRFARROW(_create)(unsigned int _h_len, \ + unsigned int _p, \ + float _fc, \ + float _As); \ + \ +/* Destroy firfarrow object, freeing all internal memory */ \ +void FIRFARROW(_destroy)(FIRFARROW() _q); \ + \ +/* Print firfarrow object's internal properties */ \ +void FIRFARROW(_print)(FIRFARROW() _q); \ + \ +/* Reset firfarrow object's internal state */ \ +void FIRFARROW(_reset)(FIRFARROW() _q); \ + \ +/* Push sample into firfarrow object */ \ +/* _q : firfarrow object */ \ +/* _x : input sample */ \ +void FIRFARROW(_push)(FIRFARROW() _q, \ + TI _x); \ + \ +/* Set fractional delay of firfarrow object */ \ +/* _q : firfarrow object */ \ +/* _mu : fractional sample delay, -1 <= _mu <= 1 */ \ +void FIRFARROW(_set_delay)(FIRFARROW() _q, \ + float _mu); \ + \ +/* Execute firfarrow internal dot product */ \ +/* _q : firfarrow object */ \ +/* _y : output sample pointer */ \ +void FIRFARROW(_execute)(FIRFARROW() _q, \ + TO * _y); \ + \ +/* Execute firfarrow filter on block of samples. */ \ +/* In-place operation is permitted (the input and output arrays may */ \ +/* share the same pointer) */ \ +/* _q : firfarrow object */ \ +/* _x : input array, [size: _n x 1] */ \ +/* _n : input, output array size */ \ +/* _y : output array, [size: _n x 1] */ \ +void FIRFARROW(_execute_block)(FIRFARROW() _q, \ + TI * _x, \ + unsigned int _n, \ + TO * _y); \ + \ +/* Get length of firfarrow object (number of filter taps) */ \ +unsigned int FIRFARROW(_get_length)(FIRFARROW() _q); \ + \ +/* Get coefficients of firfarrow object */ \ +/* _q : firfarrow object */ \ +/* _h : output coefficients pointer, [size: _h_len x 1] */ \ +void FIRFARROW(_get_coefficients)(FIRFARROW() _q, \ + float * _h); \ + \ +/* Compute complex frequency response */ \ +/* _q : filter object */ \ +/* _fc : frequency */ \ +/* _H : output frequency response */ \ +void FIRFARROW(_freqresponse)(FIRFARROW() _q, \ + float _fc, \ + liquid_float_complex * _H); \ + \ +/* Compute group delay [samples] */ \ +/* _q : filter object */ \ +/* _fc : frequency */ \ +float FIRFARROW(_groupdelay)(FIRFARROW() _q, \ + float _fc); \ + +LIQUID_FIRFARROW_DEFINE_API(LIQUID_FIRFARROW_MANGLE_RRRF, + float, + float, + float) + +LIQUID_FIRFARROW_DEFINE_API(LIQUID_FIRFARROW_MANGLE_CRCF, + liquid_float_complex, + float, + liquid_float_complex) + + +// +// Order-statistic filter +// + +#define LIQUID_ORDFILT_MANGLE_RRRF(name) LIQUID_CONCAT(ordfilt_rrrf,name) + +// Macro: +// ORDFILT : name-mangling macro +// TO : output data type +// TC : coefficients data type +// TI : input data type +#define LIQUID_ORDFILT_DEFINE_API(ORDFILT,TO,TC,TI) \ + \ +/* Finite impulse response (FIR) filter */ \ +typedef struct ORDFILT(_s) * ORDFILT(); \ + \ +/* Create a order-statistic filter (ordfilt) object by specifying */ \ +/* the buffer size and appropriate sample index of order statistic. */ \ +/* _n : buffer size, _n > 0 */ \ +/* _k : sample index for order statistic, 0 <= _k < _n */ \ +ORDFILT() ORDFILT(_create)(unsigned int _n, \ + unsigned int _k); \ + \ +/* Create a median filter by specifying buffer semi-length. */ \ +/* _m : buffer semi-length */ \ +ORDFILT() ORDFILT(_create_medfilt)(unsigned int _m); \ + \ +/* Destroy filter object and free all internal memory */ \ +void ORDFILT(_destroy)(ORDFILT() _q); \ + \ +/* Reset filter object's internal buffer */ \ +void ORDFILT(_reset)(ORDFILT() _q); \ + \ +/* Print filter object information to stdout */ \ +void ORDFILT(_print)(ORDFILT() _q); \ + \ +/* Push sample into filter object's internal buffer */ \ +/* _q : filter object */ \ +/* _x : single input sample */ \ +void ORDFILT(_push)(ORDFILT() _q, \ + TI _x); \ + \ +/* Write block of samples into object's internal buffer */ \ +/* _q : filter object */ \ +/* _x : array of input samples, [size: _n x 1] */ \ +/* _n : number of input elements */ \ +void ORDFILT(_write)(ORDFILT() _q, \ + TI * _x, \ + unsigned int _n); \ + \ +/* Execute vector dot product on the filter's internal buffer and */ \ +/* coefficients */ \ +/* _q : filter object */ \ +/* _y : pointer to single output sample */ \ +void ORDFILT(_execute)(ORDFILT() _q, \ + TO * _y); \ + \ +/* Execute the filter on a block of input samples; in-place operation */ \ +/* is permitted (_x and _y may point to the same place in memory) */ \ +/* _q : filter object */ \ +/* _x : pointer to input array, [size: _n x 1] */ \ +/* _n : number of input, output samples */ \ +/* _y : pointer to output array, [size: _n x 1] */ \ +void ORDFILT(_execute_block)(ORDFILT() _q, \ + TI * _x, \ + unsigned int _n, \ + TO * _y); \ + +LIQUID_ORDFILT_DEFINE_API(LIQUID_ORDFILT_MANGLE_RRRF, + float, + float, + float) + + +// +// MODULE : framing +// + +// framesyncstats : generic frame synchronizer statistic structure + +typedef struct { + // signal quality + float evm; // error vector magnitude [dB] + float rssi; // received signal strength indicator [dB] + float cfo; // carrier frequency offset (f/Fs) + + // demodulated frame symbols + liquid_float_complex * framesyms; // pointer to array [size: framesyms x 1] + unsigned int num_framesyms; // length of framesyms + + // modulation/coding scheme etc. + unsigned int mod_scheme; // modulation scheme + unsigned int mod_bps; // modulation depth (bits/symbol) + unsigned int check; // data validity check (crc, checksum) + unsigned int fec0; // forward error-correction (inner) + unsigned int fec1; // forward error-correction (outer) +} framesyncstats_s; + +// external framesyncstats default object +extern framesyncstats_s framesyncstats_default; + +// initialize framesyncstats object on default +int framesyncstats_init_default(framesyncstats_s * _stats); + +// print framesyncstats object +int framesyncstats_print(framesyncstats_s * _stats); + + +// framedatastats : gather frame data +typedef struct { + unsigned int num_frames_detected; + unsigned int num_headers_valid; + unsigned int num_payloads_valid; + unsigned long int num_bytes_received; +} framedatastats_s; + +// reset framedatastats object +int framedatastats_reset(framedatastats_s * _stats); + +// print framedatastats object +int framedatastats_print(framedatastats_s * _stats); + + +// Generic frame synchronizer callback function type +// _header : header data [size: 8 bytes] +// _header_valid : is header valid? (0:no, 1:yes) +// _payload : payload data [size: _payload_len] +// _payload_len : length of payload (bytes) +// _payload_valid : is payload valid? (0:no, 1:yes) +// _stats : frame statistics object +// _userdata : pointer to userdata +typedef int (*framesync_callback)(unsigned char * _header, + int _header_valid, + unsigned char * _payload, + unsigned int _payload_len, + int _payload_valid, + framesyncstats_s _stats, + void * _userdata); + +// framesync csma callback functions invoked when signal levels is high or low +// _userdata : user-defined data pointer +typedef void (*framesync_csma_callback)(void * _userdata); + +// +// packet encoder/decoder +// + +typedef struct qpacketmodem_s * qpacketmodem; + +// create packet encoder +qpacketmodem qpacketmodem_create (); +int qpacketmodem_destroy(qpacketmodem _q); +int qpacketmodem_reset (qpacketmodem _q); +int qpacketmodem_print (qpacketmodem _q); + +int qpacketmodem_configure(qpacketmodem _q, + unsigned int _payload_len, + crc_scheme _check, + fec_scheme _fec0, + fec_scheme _fec1, + int _ms); + +// get length of encoded frame in symbols +unsigned int qpacketmodem_get_frame_len(qpacketmodem _q); + +// get unencoded/decoded payload length (bytes) +unsigned int qpacketmodem_get_payload_len(qpacketmodem _q); + +// regular access methods +unsigned int qpacketmodem_get_crc (qpacketmodem _q); +unsigned int qpacketmodem_get_fec0 (qpacketmodem _q); +unsigned int qpacketmodem_get_fec1 (qpacketmodem _q); +unsigned int qpacketmodem_get_modscheme(qpacketmodem _q); + +float qpacketmodem_get_demodulator_phase_error(qpacketmodem _q); +float qpacketmodem_get_demodulator_evm(qpacketmodem _q); + +// encode packet into un-modulated frame symbol indices +// _q : qpacketmodem object +// _payload : unencoded payload bytes +// _syms : encoded but un-modulated payload symbol indices +int qpacketmodem_encode_syms(qpacketmodem _q, + const unsigned char * _payload, + unsigned char * _syms); + +// decode packet from demodulated frame symbol indices (hard-decision decoding) +// _q : qpacketmodem object +// _syms : received hard-decision symbol indices [size: frame_len x 1] +// _payload : recovered decoded payload bytes +int qpacketmodem_decode_syms(qpacketmodem _q, + unsigned char * _syms, + unsigned char * _payload); + +// decode packet from demodulated frame bits (soft-decision decoding) +// _q : qpacketmodem object +// _bits : received soft-decision bits, [size: bps*frame_len x 1] +// _payload : recovered decoded payload bytes +int qpacketmodem_decode_bits(qpacketmodem _q, + unsigned char * _bits, + unsigned char * _payload); + +// encode and modulate packet into modulated frame samples +// _q : qpacketmodem object +// _payload : unencoded payload bytes +// _frame : encoded/modulated payload symbols +int qpacketmodem_encode(qpacketmodem _q, + const unsigned char * _payload, + liquid_float_complex * _frame); + +// decode packet from modulated frame samples, returning flag if CRC passed +// NOTE: hard-decision decoding +// _q : qpacketmodem object +// _frame : encoded/modulated payload symbols +// _payload : recovered decoded payload bytes +int qpacketmodem_decode(qpacketmodem _q, + liquid_float_complex * _frame, + unsigned char * _payload); + +// decode packet from modulated frame samples, returning flag if CRC passed +// NOTE: soft-decision decoding +// _q : qpacketmodem object +// _frame : encoded/modulated payload symbols +// _payload : recovered decoded payload bytes +int qpacketmodem_decode_soft(qpacketmodem _q, + liquid_float_complex * _frame, + unsigned char * _payload); + +int qpacketmodem_decode_soft_sym(qpacketmodem _q, + liquid_float_complex _symbol); + +int qpacketmodem_decode_soft_payload(qpacketmodem _q, + unsigned char * _payload); + +// +// pilot generator/synchronizer for packet burst recovery +// + +// get number of pilots in frame +unsigned int qpilot_num_pilots(unsigned int _payload_len, + unsigned int _pilot_spacing); + +// get length of frame with a particular payload length and pilot spacing +unsigned int qpilot_frame_len(unsigned int _payload_len, + unsigned int _pilot_spacing); + +// +// pilot generator for packet burst recovery +// + +typedef struct qpilotgen_s * qpilotgen; + +// create packet encoder +qpilotgen qpilotgen_create(unsigned int _payload_len, + unsigned int _pilot_spacing); + +qpilotgen qpilotgen_recreate(qpilotgen _q, + unsigned int _payload_len, + unsigned int _pilot_spacing); + +int qpilotgen_destroy(qpilotgen _q); +int qpilotgen_reset( qpilotgen _q); +int qpilotgen_print( qpilotgen _q); + +unsigned int qpilotgen_get_frame_len(qpilotgen _q); + +// insert pilot symbols +int qpilotgen_execute(qpilotgen _q, + liquid_float_complex * _payload, + liquid_float_complex * _frame); + +// +// pilot synchronizer for packet burst recovery +// +typedef struct qpilotsync_s * qpilotsync; + +// create packet encoder +qpilotsync qpilotsync_create(unsigned int _payload_len, + unsigned int _pilot_spacing); + +qpilotsync qpilotsync_recreate(qpilotsync _q, + unsigned int _payload_len, + unsigned int _pilot_spacing); + +int qpilotsync_destroy(qpilotsync _q); +int qpilotsync_reset( qpilotsync _q); +int qpilotsync_print( qpilotsync _q); + +unsigned int qpilotsync_get_frame_len(qpilotsync _q); + +// recover frame symbols from received frame +int qpilotsync_execute(qpilotsync _q, + liquid_float_complex * _frame, + liquid_float_complex * _payload); + +// get estimates +float qpilotsync_get_dphi(qpilotsync _q); +float qpilotsync_get_phi (qpilotsync _q); +float qpilotsync_get_gain(qpilotsync _q); +float qpilotsync_get_evm (qpilotsync _q); + + +// +// Basic frame generator (64 bytes data payload) +// + +// frame length in samples +#define LIQUID_FRAME64_LEN (1440) + +typedef struct framegen64_s * framegen64; + +// create frame generator +framegen64 framegen64_create(); + +// destroy frame generator +int framegen64_destroy(framegen64 _q); + +// print frame generator internal properties +int framegen64_print(framegen64 _q); + +// generate frame +// _q : frame generator object +// _header : 8-byte header data, NULL for random +// _payload : 64-byte payload data, NULL for random +// _frame : output frame samples [size: LIQUID_FRAME64_LEN x 1] +int framegen64_execute(framegen64 _q, + unsigned char * _header, + unsigned char * _payload, + liquid_float_complex * _frame); + +typedef struct framesync64_s * framesync64; + +// create framesync64 object +// _callback : callback function +// _userdata : user data pointer passed to callback function +framesync64 framesync64_create(framesync_callback _callback, + void * _userdata); + +// destroy frame synchronizer +int framesync64_destroy(framesync64 _q); + +// print frame synchronizer internal properties +int framesync64_print(framesync64 _q); + +// reset frame synchronizer internal state +int framesync64_reset(framesync64 _q); + +// push samples through frame synchronizer +// _q : frame synchronizer object +// _x : input samples [size: _n x 1] +// _n : number of input samples +int framesync64_execute(framesync64 _q, + liquid_float_complex * _x, + unsigned int _n); + +// enable/disable debugging +int framesync64_debug_enable(framesync64 _q); +int framesync64_debug_disable(framesync64 _q); +int framesync64_debug_print(framesync64 _q, const char * _filename); + +// frame data statistics +int framesync64_reset_framedatastats(framesync64 _q); +framedatastats_s framesync64_get_framedatastats (framesync64 _q); + +#if 0 +// advanced modes +int framesync64_set_csma_callbacks(framesync64 _q, + framesync_csma_callback _csma_lock, + framesync_csma_callback _csma_unlock, + void * _csma_userdata); +#endif + +// +// Flexible frame : adjustable payload, mod scheme, etc., but bring +// your own error correction, redundancy check +// + +// frame generator +typedef struct { + unsigned int check; // data validity check + unsigned int fec0; // forward error-correction scheme (inner) + unsigned int fec1; // forward error-correction scheme (outer) + unsigned int mod_scheme; // modulation scheme +} flexframegenprops_s; + +int flexframegenprops_init_default(flexframegenprops_s * _fgprops); + +typedef struct flexframegen_s * flexframegen; + +// create flexframegen object +// _props : frame properties (modulation scheme, etc.) +flexframegen flexframegen_create(flexframegenprops_s * _props); + +// destroy flexframegen object +int flexframegen_destroy(flexframegen _q); + +// print flexframegen object internals +int flexframegen_print(flexframegen _q); + +// reset flexframegen object internals +int flexframegen_reset(flexframegen _q); + +// is frame assembled? +int flexframegen_is_assembled(flexframegen _q); + +// get frame properties +int flexframegen_getprops(flexframegen _q, flexframegenprops_s * _props); + +// set frame properties +int flexframegen_setprops(flexframegen _q, flexframegenprops_s * _props); + +// set length of user-defined portion of header +int flexframegen_set_header_len(flexframegen _q, unsigned int _len); + +// set properties for header section +int flexframegen_set_header_props(flexframegen _q, + flexframegenprops_s * _props); + +// get length of assembled frame (samples) +unsigned int flexframegen_getframelen(flexframegen _q); + +// assemble a frame from an array of data +// _q : frame generator object +// _header : frame header +// _payload : payload data [size: _payload_len x 1] +// _payload_len : payload data length +int flexframegen_assemble(flexframegen _q, + const unsigned char * _header, + const unsigned char * _payload, + unsigned int _payload_len); + +// write samples of assembled frame, two samples at a time, returning +// '1' when frame is complete, '0' otherwise. Zeros will be written +// to the buffer if the frame is not assembled +// _q : frame generator object +// _buffer : output buffer [size: _buffer_len x 1] +// _buffer_len : output buffer length +int flexframegen_write_samples(flexframegen _q, + liquid_float_complex * _buffer, + unsigned int _buffer_len); + +// frame synchronizer + +typedef struct flexframesync_s * flexframesync; + +// create flexframesync object +// _callback : callback function +// _userdata : user data pointer passed to callback function +flexframesync flexframesync_create(framesync_callback _callback, + void * _userdata); + +// destroy frame synchronizer +int flexframesync_destroy(flexframesync _q); + +// print frame synchronizer internal properties +int flexframesync_print(flexframesync _q); + +// reset frame synchronizer internal state +int flexframesync_reset(flexframesync _q); + +// has frame been detected? +int flexframesync_is_frame_open(flexframesync _q); + +// change length of user-defined region in header +int flexframesync_set_header_len(flexframesync _q, + unsigned int _len); + +// enable or disable soft decoding of header +int flexframesync_decode_header_soft(flexframesync _q, + int _soft); + +// enable or disable soft decoding of payload +int flexframesync_decode_payload_soft(flexframesync _q, + int _soft); + +// set properties for header section +int flexframesync_set_header_props(flexframesync _q, + flexframegenprops_s * _props); + +// push samples through frame synchronizer +// _q : frame synchronizer object +// _x : input samples [size: _n x 1] +// _n : number of input samples +int flexframesync_execute(flexframesync _q, + liquid_float_complex * _x, + unsigned int _n); + +// frame data statistics +int flexframesync_reset_framedatastats(flexframesync _q); +framedatastats_s flexframesync_get_framedatastats (flexframesync _q); + +// enable/disable debugging +int flexframesync_debug_enable(flexframesync _q); +int flexframesync_debug_disable(flexframesync _q); +int flexframesync_debug_print(flexframesync _q, + const char * _filename); + +// +// bpacket : binary packet suitable for data streaming +// + +// +// bpacket generator/encoder +// +typedef struct bpacketgen_s * bpacketgen; + +// create bpacketgen object +// _m : p/n sequence length (ignored) +// _dec_msg_len : decoded message length (original uncoded data) +// _crc : data validity check (e.g. cyclic redundancy check) +// _fec0 : inner forward error-correction code scheme +// _fec1 : outer forward error-correction code scheme +bpacketgen bpacketgen_create(unsigned int _m, + unsigned int _dec_msg_len, + int _crc, + int _fec0, + int _fec1); + +// re-create bpacketgen object from old object +// _q : old bpacketgen object +// _m : p/n sequence length (ignored) +// _dec_msg_len : decoded message length (original uncoded data) +// _crc : data validity check (e.g. cyclic redundancy check) +// _fec0 : inner forward error-correction code scheme +// _fec1 : outer forward error-correction code scheme +bpacketgen bpacketgen_recreate(bpacketgen _q, + unsigned int _m, + unsigned int _dec_msg_len, + int _crc, + int _fec0, + int _fec1); + +// destroy bpacketgen object, freeing all internally-allocated memory +void bpacketgen_destroy(bpacketgen _q); + +// print bpacketgen internals +void bpacketgen_print(bpacketgen _q); + +// return length of full packet +unsigned int bpacketgen_get_packet_len(bpacketgen _q); + +// encode packet +void bpacketgen_encode(bpacketgen _q, + unsigned char * _msg_dec, + unsigned char * _packet); + +// +// bpacket synchronizer/decoder +// +typedef struct bpacketsync_s * bpacketsync; +typedef int (*bpacketsync_callback)(unsigned char * _payload, + int _payload_valid, + unsigned int _payload_len, + framesyncstats_s _stats, + void * _userdata); +bpacketsync bpacketsync_create(unsigned int _m, + bpacketsync_callback _callback, + void * _userdata); +int bpacketsync_destroy(bpacketsync _q); +int bpacketsync_print(bpacketsync _q); +int bpacketsync_reset(bpacketsync _q); + +// run synchronizer on array of input bytes +// _q : bpacketsync object +// _bytes : input data array [size: _n x 1] +// _n : input array size +int bpacketsync_execute(bpacketsync _q, + unsigned char * _bytes, + unsigned int _n); + +// run synchronizer on input byte +// _q : bpacketsync object +// _byte : input byte +int bpacketsync_execute_byte(bpacketsync _q, + unsigned char _byte); + +// run synchronizer on input symbol +// _q : bpacketsync object +// _sym : input symbol with _bps significant bits +// _bps : number of bits in input symbol +int bpacketsync_execute_sym(bpacketsync _q, + unsigned char _sym, + unsigned int _bps); + +// execute one bit at a time +int bpacketsync_execute_bit(bpacketsync _q, + unsigned char _bit); + +// +// M-FSK frame generator +// + +typedef struct fskframegen_s * fskframegen; + +// create M-FSK frame generator +fskframegen fskframegen_create(); +int fskframegen_destroy (fskframegen _fg); +int fskframegen_print (fskframegen _fg); +int fskframegen_reset (fskframegen _fg); +int fskframegen_assemble(fskframegen _fg, + unsigned char * _header, + unsigned char * _payload, + unsigned int _payload_len, + crc_scheme _check, + fec_scheme _fec0, + fec_scheme _fec1); +unsigned int fskframegen_getframelen(fskframegen _q); +int fskframegen_write_samples(fskframegen _fg, + liquid_float_complex * _buf, + unsigned int _buf_len); + + +// +// M-FSK frame synchronizer +// + +typedef struct fskframesync_s * fskframesync; + +// create M-FSK frame synchronizer +// _callback : callback function +// _userdata : user data pointer passed to callback function +fskframesync fskframesync_create(framesync_callback _callback, + void * _userdata); +int fskframesync_destroy(fskframesync _q); +int fskframesync_print (fskframesync _q); +int fskframesync_reset (fskframesync _q); +int fskframesync_execute(fskframesync _q, + liquid_float_complex _x); +int fskframesync_execute_block(fskframesync _q, + liquid_float_complex * _x, + unsigned int _n); + +// debugging +int fskframesync_debug_enable (fskframesync _q); +int fskframesync_debug_disable(fskframesync _q); +int fskframesync_debug_export (fskframesync _q, const char * _filename); + + +// +// GMSK frame generator +// + +typedef struct gmskframegen_s * gmskframegen; + +// create GMSK frame generator +gmskframegen gmskframegen_create(); +int gmskframegen_destroy (gmskframegen _q); +int gmskframegen_is_assembled (gmskframegen _q); +int gmskframegen_print (gmskframegen _q); +int gmskframegen_set_header_len(gmskframegen _q, unsigned int _len); +int gmskframegen_reset (gmskframegen _q); +int gmskframegen_assemble (gmskframegen _q, + const unsigned char * _header, + const unsigned char * _payload, + unsigned int _payload_len, + crc_scheme _check, + fec_scheme _fec0, + fec_scheme _fec1); +unsigned int gmskframegen_getframelen(gmskframegen _q); +int gmskframegen_write_samples(gmskframegen _q, + liquid_float_complex * _y); + +// write samples of assembled frame +// _q : frame generator object +// _buf : output buffer [size: _buf_len x 1] +// _buf_len : output buffer length +int gmskframegen_write(gmskframegen _q, + liquid_float_complex * _buf, + unsigned int _buf_len); + + +// +// GMSK frame synchronizer +// + +typedef struct gmskframesync_s * gmskframesync; + +// create GMSK frame synchronizer +// _callback : callback function +// _userdata : user data pointer passed to callback function +gmskframesync gmskframesync_create(framesync_callback _callback, + void * _userdata); +int gmskframesync_destroy(gmskframesync _q); +int gmskframesync_print(gmskframesync _q); +int gmskframesync_set_header_len(gmskframesync _q, unsigned int _len); +int gmskframesync_reset(gmskframesync _q); +int gmskframesync_is_frame_open(gmskframesync _q); +int gmskframesync_execute(gmskframesync _q, + liquid_float_complex * _x, + unsigned int _n); + +// debugging +int gmskframesync_debug_enable(gmskframesync _q); +int gmskframesync_debug_disable(gmskframesync _q); +int gmskframesync_debug_print(gmskframesync _q, const char * _filename); + + +// +// DSSS frame generator +// + +typedef struct { + unsigned int check; + unsigned int fec0; + unsigned int fec1; +} dsssframegenprops_s; + +typedef struct dsssframegen_s * dsssframegen; + +dsssframegen dsssframegen_create(dsssframegenprops_s * _props); +int dsssframegen_destroy(dsssframegen _q); +int dsssframegen_reset(dsssframegen _q); +int dsssframegen_is_assembled(dsssframegen _q); +int dsssframegen_getprops(dsssframegen _q, dsssframegenprops_s * _props); +int dsssframegen_setprops(dsssframegen _q, dsssframegenprops_s * _props); +int dsssframegen_set_header_len(dsssframegen _q, unsigned int _len); +int dsssframegen_set_header_props(dsssframegen _q, + dsssframegenprops_s * _props); +unsigned int dsssframegen_getframelen(dsssframegen _q); + +// assemble a frame from an array of data +// _q : frame generator object +// _header : frame header +// _payload : payload data [size: _payload_len x 1] +// _payload_len : payload data length +int dsssframegen_assemble(dsssframegen _q, + const unsigned char * _header, + const unsigned char * _payload, + unsigned int _payload_len); + +int dsssframegen_write_samples(dsssframegen _q, + liquid_float_complex * _buffer, + unsigned int _buffer_len); + + +// +// DSSS frame synchronizer +// + +typedef struct dsssframesync_s * dsssframesync; + +dsssframesync dsssframesync_create(framesync_callback _callback, void * _userdata); +int dsssframesync_destroy (dsssframesync _q); +int dsssframesync_print (dsssframesync _q); +int dsssframesync_reset (dsssframesync _q); +int dsssframesync_is_frame_open (dsssframesync _q); +int dsssframesync_set_header_len (dsssframesync _q, unsigned int _len); +int dsssframesync_decode_header_soft (dsssframesync _q, int _soft); +int dsssframesync_decode_payload_soft (dsssframesync _q, int _soft); +int dsssframesync_set_header_props (dsssframesync _q, dsssframegenprops_s * _props); +int dsssframesync_execute (dsssframesync _q, liquid_float_complex * _x, unsigned int _n); +int dsssframesync_reset_framedatastats(dsssframesync _q); +int dsssframesync_debug_enable (dsssframesync _q); +int dsssframesync_debug_disable (dsssframesync _q); +int dsssframesync_debug_print (dsssframesync _q, const char * _filename); +framedatastats_s dsssframesync_get_framedatastats (dsssframesync _q); + +// +// OFDM flexframe generator +// + +// ofdm frame generator properties +typedef struct { + unsigned int check; // data validity check + unsigned int fec0; // forward error-correction scheme (inner) + unsigned int fec1; // forward error-correction scheme (outer) + unsigned int mod_scheme; // modulation scheme + //unsigned int block_size; // framing block size +} ofdmflexframegenprops_s; +int ofdmflexframegenprops_init_default(ofdmflexframegenprops_s * _props); + +typedef struct ofdmflexframegen_s * ofdmflexframegen; + +// create OFDM flexible framing generator object +// _M : number of subcarriers, >10 typical +// _cp_len : cyclic prefix length +// _taper_len : taper length (OFDM symbol overlap) +// _p : subcarrier allocation (null, pilot, data), [size: _M x 1] +// _fgprops : frame properties (modulation scheme, etc.) +ofdmflexframegen ofdmflexframegen_create(unsigned int _M, + unsigned int _cp_len, + unsigned int _taper_len, + unsigned char * _p, + ofdmflexframegenprops_s * _fgprops); + +// destroy ofdmflexframegen object +int ofdmflexframegen_destroy(ofdmflexframegen _q); + +// print parameters, properties, etc. +int ofdmflexframegen_print(ofdmflexframegen _q); + +// reset ofdmflexframegen object internals +int ofdmflexframegen_reset(ofdmflexframegen _q); + +// is frame assembled? +int ofdmflexframegen_is_assembled(ofdmflexframegen _q); + +// get properties +int ofdmflexframegen_getprops(ofdmflexframegen _q, + ofdmflexframegenprops_s * _props); + +// set properties +int ofdmflexframegen_setprops(ofdmflexframegen _q, + ofdmflexframegenprops_s * _props); + +// set user-defined header length +int ofdmflexframegen_set_header_len(ofdmflexframegen _q, + unsigned int _len); + +int ofdmflexframegen_set_header_props(ofdmflexframegen _q, + ofdmflexframegenprops_s * _props); + +// get length of frame (symbols) +// _q : OFDM frame generator object +unsigned int ofdmflexframegen_getframelen(ofdmflexframegen _q); + +// assemble a frame from an array of data (NULL pointers will use random data) +// _q : OFDM frame generator object +// _header : frame header [8 bytes] +// _payload : payload data [size: _payload_len x 1] +// _payload_len : payload data length +int ofdmflexframegen_assemble(ofdmflexframegen _q, + const unsigned char * _header, + const unsigned char * _payload, + unsigned int _payload_len); + +// write samples of assembled frame +// _q : OFDM frame generator object +// _buf : output buffer [size: _buf_len x 1] +// _buf_len : output buffer length +int ofdmflexframegen_write(ofdmflexframegen _q, + liquid_float_complex * _buf, + unsigned int _buf_len); + +// +// OFDM flex frame synchronizer +// + +typedef struct ofdmflexframesync_s * ofdmflexframesync; + +// create OFDM flexible framing synchronizer object +// _M : number of subcarriers +// _cp_len : cyclic prefix length +// _taper_len : taper length (OFDM symbol overlap) +// _p : subcarrier allocation (null, pilot, data), [size: _M x 1] +// _callback : user-defined callback function +// _userdata : user-defined data pointer +ofdmflexframesync ofdmflexframesync_create(unsigned int _M, + unsigned int _cp_len, + unsigned int _taper_len, + unsigned char * _p, + framesync_callback _callback, + void * _userdata); + +int ofdmflexframesync_destroy(ofdmflexframesync _q); +int ofdmflexframesync_print(ofdmflexframesync _q); +// set user-defined header length +int ofdmflexframesync_set_header_len(ofdmflexframesync _q, + unsigned int _len); + +int ofdmflexframesync_decode_header_soft(ofdmflexframesync _q, + int _soft); + +int ofdmflexframesync_decode_payload_soft(ofdmflexframesync _q, + int _soft); + +int ofdmflexframesync_set_header_props(ofdmflexframesync _q, + ofdmflexframegenprops_s * _props); + +int ofdmflexframesync_reset(ofdmflexframesync _q); +int ofdmflexframesync_is_frame_open(ofdmflexframesync _q); +int ofdmflexframesync_execute(ofdmflexframesync _q, + liquid_float_complex * _x, + unsigned int _n); + +// query the received signal strength indication +float ofdmflexframesync_get_rssi(ofdmflexframesync _q); + +// query the received carrier offset estimate +float ofdmflexframesync_get_cfo(ofdmflexframesync _q); + +// frame data statistics +int ofdmflexframesync_reset_framedatastats(ofdmflexframesync _q); +framedatastats_s ofdmflexframesync_get_framedatastats (ofdmflexframesync _q); + +// set the received carrier offset estimate +int ofdmflexframesync_set_cfo(ofdmflexframesync _q, float _cfo); + +// enable/disable debugging +int ofdmflexframesync_debug_enable(ofdmflexframesync _q); +int ofdmflexframesync_debug_disable(ofdmflexframesync _q); +int ofdmflexframesync_debug_print(ofdmflexframesync _q, + const char * _filename); + + + +// +// Binary P/N synchronizer +// +#define LIQUID_BSYNC_MANGLE_RRRF(name) LIQUID_CONCAT(bsync_rrrf,name) +#define LIQUID_BSYNC_MANGLE_CRCF(name) LIQUID_CONCAT(bsync_crcf,name) +#define LIQUID_BSYNC_MANGLE_CCCF(name) LIQUID_CONCAT(bsync_cccf,name) + +// Macro: +// BSYNC : name-mangling macro +// TO : output data type +// TC : coefficients data type +// TI : input data type +#define LIQUID_BSYNC_DEFINE_API(BSYNC,TO,TC,TI) \ + \ +/* Binary P/N synchronizer */ \ +typedef struct BSYNC(_s) * BSYNC(); \ + \ +/* Create bsync object */ \ +/* _n : sequence length */ \ +/* _v : correlation sequence [size: _n x 1] */ \ +BSYNC() BSYNC(_create)(unsigned int _n, \ + TC * _v); \ + \ +/* Create binary synchronizer from m-sequence */ \ +/* _g : m-sequence generator polynomial */ \ +/* _k : samples/symbol (over-sampling factor) */ \ +BSYNC() BSYNC(_create_msequence)(unsigned int _g, \ + unsigned int _k); \ + \ +/* Destroy binary synchronizer object, freeing all internal memory */ \ +/* _q : bsync object */ \ +void BSYNC(_destroy)(BSYNC() _q); \ + \ +/* Print object internals to stdout */ \ +/* _q : bsync object */ \ +void BSYNC(_print)(BSYNC() _q); \ + \ +/* Correlate input signal against internal sequence */ \ +/* _q : bsync object */ \ +/* _x : input sample */ \ +/* _y : pointer to output sample */ \ +void BSYNC(_correlate)(BSYNC() _q, \ + TI _x, \ + TO * _y); \ + +LIQUID_BSYNC_DEFINE_API(LIQUID_BSYNC_MANGLE_RRRF, + float, + float, + float) + +LIQUID_BSYNC_DEFINE_API(LIQUID_BSYNC_MANGLE_CRCF, + liquid_float_complex, + float, + liquid_float_complex) + +LIQUID_BSYNC_DEFINE_API(LIQUID_BSYNC_MANGLE_CCCF, + liquid_float_complex, + liquid_float_complex, + liquid_float_complex) + + +// +// Pre-demodulation synchronizers (binary and otherwise) +// +#define LIQUID_PRESYNC_MANGLE_CCCF(name) LIQUID_CONCAT( presync_cccf,name) +#define LIQUID_BPRESYNC_MANGLE_CCCF(name) LIQUID_CONCAT(bpresync_cccf,name) + +// Macro: +// PRESYNC : name-mangling macro +// TO : output data type +// TC : coefficients data type +// TI : input data type +#define LIQUID_PRESYNC_DEFINE_API(PRESYNC,TO,TC,TI) \ + \ +/* Pre-demodulation signal synchronizer */ \ +typedef struct PRESYNC(_s) * PRESYNC(); \ + \ +/* Create pre-demod synchronizer from external sequence */ \ +/* _v : baseband sequence, [size: _n x 1] */ \ +/* _n : baseband sequence length, _n > 0 */ \ +/* _dphi_max : maximum absolute frequency deviation for detection */ \ +/* _m : number of correlators, _m > 0 */ \ +PRESYNC() PRESYNC(_create)(TC * _v, \ + unsigned int _n, \ + float _dphi_max, \ + unsigned int _m); \ + \ +/* Destroy pre-demod synchronizer, freeing all internal memory */ \ +int PRESYNC(_destroy)(PRESYNC() _q); \ + \ +/* Print pre-demod synchronizer internal state */ \ +int PRESYNC(_print)(PRESYNC() _q); \ + \ +/* Reset pre-demod synchronizer internal state */ \ +int PRESYNC(_reset)(PRESYNC() _q); \ + \ +/* Push input sample into pre-demod synchronizer */ \ +/* _q : pre-demod synchronizer object */ \ +/* _x : input sample */ \ +int PRESYNC(_push)(PRESYNC() _q, \ + TI _x); \ + \ +/* Correlate original sequence with internal input buffer */ \ +/* _q : pre-demod synchronizer object */ \ +/* _rxy : output cross correlation */ \ +/* _dphi_hat : output frequency offset estimate */ \ +int PRESYNC(_execute)(PRESYNC() _q, \ + TO * _rxy, \ + float * _dphi_hat); \ + +// non-binary pre-demodulation synchronizer +LIQUID_PRESYNC_DEFINE_API(LIQUID_PRESYNC_MANGLE_CCCF, + liquid_float_complex, + liquid_float_complex, + liquid_float_complex) + +// binary pre-demodulation synchronizer +LIQUID_PRESYNC_DEFINE_API(LIQUID_BPRESYNC_MANGLE_CCCF, + liquid_float_complex, + liquid_float_complex, + liquid_float_complex) + +// +// Frame detector +// + +typedef struct qdetector_cccf_s * qdetector_cccf; + +// create detector with generic sequence +// _s : sample sequence +// _s_len : length of sample sequence +qdetector_cccf qdetector_cccf_create(liquid_float_complex * _s, + unsigned int _s_len); + +// create detector from sequence of symbols using internal linear interpolator +// _sequence : symbol sequence +// _sequence_len : length of symbol sequence +// _ftype : filter prototype (e.g. LIQUID_FIRFILT_RRC) +// _k : samples/symbol +// _m : filter delay +// _beta : excess bandwidth factor +qdetector_cccf qdetector_cccf_create_linear(liquid_float_complex * _sequence, + unsigned int _sequence_len, + int _ftype, + unsigned int _k, + unsigned int _m, + float _beta); + +// create detector from sequence of GMSK symbols +// _sequence : bit sequence +// _sequence_len : length of bit sequence +// _k : samples/symbol +// _m : filter delay +// _beta : excess bandwidth factor +qdetector_cccf qdetector_cccf_create_gmsk(unsigned char * _sequence, + unsigned int _sequence_len, + unsigned int _k, + unsigned int _m, + float _beta); + +// create detector from sequence of CP-FSK symbols (assuming one bit/symbol) +// _sequence : bit sequence +// _sequence_len : length of bit sequence +// _bps : bits per symbol, 0 < _bps <= 8 +// _h : modulation index, _h > 0 +// _k : samples/symbol +// _m : filter delay +// _beta : filter bandwidth parameter, _beta > 0 +// _type : filter type (e.g. LIQUID_CPFSK_SQUARE) +qdetector_cccf qdetector_cccf_create_cpfsk(unsigned char * _sequence, + unsigned int _sequence_len, + unsigned int _bps, + float _h, + unsigned int _k, + unsigned int _m, + float _beta, + int _type); + +int qdetector_cccf_destroy(qdetector_cccf _q); +int qdetector_cccf_print (qdetector_cccf _q); +int qdetector_cccf_reset (qdetector_cccf _q); + +// run detector, looking for sequence; return pointer to aligned, buffered samples +void * qdetector_cccf_execute(qdetector_cccf _q, + liquid_float_complex _x); + +// set detection threshold (should be between 0 and 1, good starting point is 0.5) +int qdetector_cccf_set_threshold(qdetector_cccf _q, + float _threshold); + +// set carrier offset search range +int qdetector_cccf_set_range(qdetector_cccf _q, + float _dphi_max); + +// access methods +unsigned int qdetector_cccf_get_seq_len (qdetector_cccf _q); // sequence length +const void * qdetector_cccf_get_sequence(qdetector_cccf _q); // pointer to sequence +unsigned int qdetector_cccf_get_buf_len (qdetector_cccf _q); // buffer length +float qdetector_cccf_get_rxy (qdetector_cccf _q); // correlator output +float qdetector_cccf_get_tau (qdetector_cccf _q); // fractional timing offset estimate +float qdetector_cccf_get_gamma (qdetector_cccf _q); // channel gain +float qdetector_cccf_get_dphi (qdetector_cccf _q); // carrier frequency offset estimate +float qdetector_cccf_get_phi (qdetector_cccf _q); // carrier phase offset estimate + +// +// Pre-demodulation detector +// + +typedef struct detector_cccf_s * detector_cccf; + +// create pre-demod detector +// _s : sequence +// _n : sequence length +// _threshold : detection threshold (default: 0.7) +// _dphi_max : maximum carrier offset +detector_cccf detector_cccf_create(liquid_float_complex * _s, + unsigned int _n, + float _threshold, + float _dphi_max); + +// destroy pre-demo detector object +void detector_cccf_destroy(detector_cccf _q); + +// print pre-demod detector internal state +void detector_cccf_print(detector_cccf _q); + +// reset pre-demod detector internal state +void detector_cccf_reset(detector_cccf _q); + +// Run sample through pre-demod detector's correlator. +// Returns '1' if signal was detected, '0' otherwise +// _q : pre-demod detector +// _x : input sample +// _tau_hat : fractional sample offset estimate (set when detected) +// _dphi_hat : carrier frequency offset estimate (set when detected) +// _gamma_hat : channel gain estimate (set when detected) +int detector_cccf_correlate(detector_cccf _q, + liquid_float_complex _x, + float * _tau_hat, + float * _dphi_hat, + float * _gamma_hat); + + +// +// symbol streaming for testing (no meaningful data, just symbols) +// +#define LIQUID_SYMSTREAM_MANGLE_CFLOAT(name) LIQUID_CONCAT(symstreamcf,name) + +#define LIQUID_SYMSTREAM_DEFINE_API(SYMSTREAM,TO) \ + \ +/* Symbol streaming generator object */ \ +typedef struct SYMSTREAM(_s) * SYMSTREAM(); \ + \ +/* Create symstream object with default parameters. */ \ +/* This is equivalent to invoking the create_linear() method */ \ +/* with _ftype=LIQUID_FIRFILT_ARKAISER, _k=2, _m=7, _beta=0.3, and */ \ +/* with _ms=LIQUID_MODEM_QPSK */ \ +SYMSTREAM() SYMSTREAM(_create)(void); \ + \ +/* Create symstream object with linear modulation */ \ +/* _ftype : filter type (e.g. LIQUID_FIRFILT_RRC) */ \ +/* _k : samples per symbol, _k >= 2 */ \ +/* _m : filter delay (symbols), _m > 0 */ \ +/* _beta : filter excess bandwidth, 0 < _beta <= 1 */ \ +/* _ms : modulation scheme, e.g. LIQUID_MODEM_QPSK */ \ +SYMSTREAM() SYMSTREAM(_create_linear)(int _ftype, \ + unsigned int _k, \ + unsigned int _m, \ + float _beta, \ + int _ms); \ + \ +/* Destroy symstream object, freeing all internal memory */ \ +int SYMSTREAM(_destroy)(SYMSTREAM() _q); \ + \ +/* Print symstream object's parameters */ \ +int SYMSTREAM(_print)(SYMSTREAM() _q); \ + \ +/* Reset symstream internal state */ \ +int SYMSTREAM(_reset)(SYMSTREAM() _q); \ + \ +/* Set internal linear modulation scheme, leaving the filter parameters */ \ +/* (interpolator) unmodified */ \ +int SYMSTREAM(_set_scheme)(SYMSTREAM() _q, \ + int _ms); \ + \ +/* Get internal linear modulation scheme */ \ +int SYMSTREAM(_get_scheme)(SYMSTREAM() _q); \ + \ +/* Set internal linear gain (before interpolation) */ \ +int SYMSTREAM(_set_gain)(SYMSTREAM() _q, \ + float _gain); \ + \ +/* Get internal linear gain (before interpolation) */ \ +float SYMSTREAM(_get_gain)(SYMSTREAM() _q); \ + \ +/* Write block of samples to output buffer */ \ +/* _q : synchronizer object */ \ +/* _buf : output buffer [size: _buf_len x 1] */ \ +/* _buf_len: output buffer size */ \ +int SYMSTREAM(_write_samples)(SYMSTREAM() _q, \ + TO * _buf, \ + unsigned int _buf_len); \ + +LIQUID_SYMSTREAM_DEFINE_API(LIQUID_SYMSTREAM_MANGLE_CFLOAT, liquid_float_complex) + + + +// +// multi-signal source for testing (no meaningful data, just signals) +// + +#define LIQUID_MSOURCE_MANGLE_CFLOAT(name) LIQUID_CONCAT(msourcecf,name) + +#define LIQUID_MSOURCE_DEFINE_API(MSOURCE,TO) \ + \ +/* Multi-signal source generator object */ \ +typedef struct MSOURCE(_s) * MSOURCE(); \ + \ +/* Create msource object by specifying channelizer parameters */ \ +/* _M : number of channels in analysis channelizer object */ \ +/* _m : prototype channelizer filter semi-length */ \ +/* _As : prototype channelizer filter stop-band suppression (dB) */ \ +MSOURCE() MSOURCE(_create)(unsigned int _M, \ + unsigned int _m, \ + float _As); \ + \ +/* Create default msource object with default parameters: */ \ +/* M = 1200, m = 4, As = 60 */ \ +MSOURCE() MSOURCE(_create_default)(void); \ + \ +/* Destroy msource object */ \ +int MSOURCE(_destroy)(MSOURCE() _q); \ + \ +/* Print msource object */ \ +int MSOURCE(_print)(MSOURCE() _q); \ + \ +/* Reset msource object */ \ +int MSOURCE(_reset)(MSOURCE() _q); \ + \ +/* user-defined callback for generating samples */ \ +typedef int (*MSOURCE(_callback))(void * _userdata, \ + TO * _v, \ + unsigned int _n); \ + \ +/* Add user-defined signal generator */ \ +int MSOURCE(_add_user)(MSOURCE() _q, \ + float _fc, \ + float _bw, \ + float _gain, \ + void * _userdata, \ + MSOURCE(_callback) _callback); \ + \ +/* Add tone to signal generator, returning id of signal */ \ +int MSOURCE(_add_tone)(MSOURCE() _q, \ + float _fc, \ + float _bw, \ + float _gain); \ + \ +/* Add chirp to signal generator, returning id of signal */ \ +/* _q : multi-signal source object */ \ +/* _duration : duration of chirp [samples] */ \ +/* _negate : negate frequency direction */ \ +/* _single : run single chirp? or repeatedly */ \ +int MSOURCE(_add_chirp)(MSOURCE() _q, \ + float _fc, \ + float _bw, \ + float _gain, \ + float _duration, \ + int _negate, \ + int _repeat); \ + \ +/* Add noise source to signal generator, returning id of signal */ \ +/* _q : multi-signal source object */ \ +/* _fc : ... */ \ +/* _bw : ... */ \ +/* _nstd : ... */ \ +int MSOURCE(_add_noise)(MSOURCE() _q, \ + float _fc, \ + float _bw, \ + float _gain); \ + \ +/* Add modem signal source, returning id of signal */ \ +/* _q : multi-signal source object */ \ +/* _ms : modulation scheme, e.g. LIQUID_MODEM_QPSK */ \ +/* _m : filter delay (symbols), _m > 0 */ \ +/* _beta : filter excess bandwidth, 0 < _beta <= 1 */ \ +int MSOURCE(_add_modem)(MSOURCE() _q, \ + float _fc, \ + float _bw, \ + float _gain, \ + int _ms, \ + unsigned int _m, \ + float _beta); \ + \ +/* Add frequency-shift keying modem signal source, returning id of */ \ +/* signal */ \ +/* _q : multi-signal source object */ \ +/* _m : bits per symbol, _bps > 0 */ \ +/* _k : samples/symbol, _k >= 2^_m */ \ +int MSOURCE(_add_fsk)(MSOURCE() _q, \ + float _fc, \ + float _bw, \ + float _gain, \ + unsigned int _m, \ + unsigned int _k); \ + \ +/* Add GMSK modem signal source, returning id of signal */ \ +/* _q : multi-signal source object */ \ +/* _m : filter delay (symbols), _m > 0 */ \ +/* _bt : filter bandwidth-time factor, 0 < _bt <= 1 */ \ +int MSOURCE(_add_gmsk)(MSOURCE() _q, \ + float _fc, \ + float _bw, \ + float _gain, \ + unsigned int _m, \ + float _bt); \ + \ +/* Remove signal with a particular id, returning 0 upon success */ \ +/* _q : multi-signal source object */ \ +/* _id : signal source id */ \ +int MSOURCE(_remove)(MSOURCE() _q, \ + int _id); \ + \ +/* Enable signal source with a particular id */ \ +int MSOURCE(_enable)(MSOURCE() _q, \ + int _id); \ + \ +/* Disable signal source with a particular id */ \ +int MSOURCE(_disable)(MSOURCE() _q, \ + int _id); \ + \ +/* Set gain in decibels on signal */ \ +/* _q : msource object */ \ +/* _id : source id */ \ +/* _gain : signal gain [dB] */ \ +int MSOURCE(_set_gain)(MSOURCE() _q, \ + int _id, \ + float _gain); \ + \ +/* Get gain in decibels on signal */ \ +/* _q : msource object */ \ +/* _id : source id */ \ +/* _gain : signal gain output [dB] */ \ +int MSOURCE(_get_gain)(MSOURCE() _q, \ + int _id, \ + float * _gain); \ + \ +/* Get number of samples generated by the object so far */ \ +/* _q : msource object */ \ +/* _return : number of time-domain samples generated */ \ +unsigned long long int MSOURCE(_get_num_samples)(MSOURCE() _q); \ + \ +/* Set carrier offset to signal */ \ +/* _q : msource object */ \ +/* _id : source id */ \ +/* _fc : normalized carrier frequency offset, -0.5 <= _fc <= 0.5 */ \ +int MSOURCE(_set_frequency)(MSOURCE() _q, \ + int _id, \ + float _dphi); \ + \ +/* Get carrier offset to signal */ \ +/* _q : msource object */ \ +/* _id : source id */ \ +/* _fc : normalized carrier frequency offset */ \ +int MSOURCE(_get_frequency)(MSOURCE() _q, \ + int _id, \ + float * _dphi); \ + \ +/* Write block of samples to output buffer */ \ +/* _q : synchronizer object */ \ +/* _buf : output buffer, [size: _buf_len x 1] */ \ +/* _buf_len: output buffer size */ \ +int MSOURCE(_write_samples)(MSOURCE() _q, \ + TO * _buf, \ + unsigned int _buf_len); \ + +LIQUID_MSOURCE_DEFINE_API(LIQUID_MSOURCE_MANGLE_CFLOAT, liquid_float_complex) + + + + +// +// Symbol tracking: AGC > symsync > EQ > carrier recovery +// +#define LIQUID_SYMTRACK_MANGLE_RRRF(name) LIQUID_CONCAT(symtrack_rrrf,name) +#define LIQUID_SYMTRACK_MANGLE_CCCF(name) LIQUID_CONCAT(symtrack_cccf,name) + +// large macro +// SYMTRACK : name-mangling macro +// T : data type, primitive +// TO : data type, output +// TC : data type, coefficients +// TI : data type, input +#define LIQUID_SYMTRACK_DEFINE_API(SYMTRACK,T,TO,TC,TI) \ + \ +/* Symbol synchronizer and tracking object */ \ +typedef struct SYMTRACK(_s) * SYMTRACK(); \ + \ +/* Create symtrack object, specifying parameters for operation */ \ +/* _ftype : filter type (e.g. LIQUID_FIRFILT_RRC) */ \ +/* _k : samples per symbol, _k >= 2 */ \ +/* _m : filter delay [symbols], _m > 0 */ \ +/* _beta : excess bandwidth factor, 0 <= _beta <= 1 */ \ +/* _ms : modulation scheme, _ms(LIQUID_MODEM_BPSK) */ \ +SYMTRACK() SYMTRACK(_create)(int _ftype, \ + unsigned int _k, \ + unsigned int _m, \ + float _beta, \ + int _ms); \ + \ +/* Create symtrack object using default parameters. */ \ +/* The default parameters are */ \ +/* ftype = LIQUID_FIRFILT_ARKAISER (filter type), */ \ +/* k = 2 (samples per symbol), */ \ +/* m = 7 (filter delay), */ \ +/* beta = 0.3 (excess bandwidth factor), and */ \ +/* ms = LIQUID_MODEM_QPSK (modulation scheme) */ \ +SYMTRACK() SYMTRACK(_create_default)(); \ + \ +/* Destroy symtrack object, freeing all internal memory */ \ +int SYMTRACK(_destroy)(SYMTRACK() _q); \ + \ +/* Print symtrack object's parameters */ \ +int SYMTRACK(_print)(SYMTRACK() _q); \ + \ +/* Reset symtrack internal state */ \ +int SYMTRACK(_reset)(SYMTRACK() _q); \ + \ +/* Set symtrack modulation scheme */ \ +/* _q : symtrack object */ \ +/* _ms : modulation scheme, _ms(LIQUID_MODEM_BPSK) */ \ +int SYMTRACK(_set_modscheme)(SYMTRACK() _q, \ + int _ms); \ + \ +/* Set symtrack internal bandwidth */ \ +/* _q : symtrack object */ \ +/* _bw : tracking bandwidth, _bw > 0 */ \ +int SYMTRACK(_set_bandwidth)(SYMTRACK() _q, \ + float _bw); \ + \ +/* Adjust internal NCO by requested phase */ \ +/* _q : symtrack object */ \ +/* _dphi : NCO phase adjustment [radians] */ \ +int SYMTRACK(_adjust_phase)(SYMTRACK() _q, \ + T _dphi); \ + \ +/* Set symtrack equalization strategy to constant modulus (default) */ \ +int SYMTRACK(_set_eq_cm)(SYMTRACK() _q); \ + \ +/* Set symtrack equalization strategy to decision directed */ \ +int SYMTRACK(_set_eq_dd)(SYMTRACK() _q); \ + \ +/* Disable symtrack equalization */ \ +int SYMTRACK(_set_eq_off)(SYMTRACK() _q); \ + \ +/* Execute synchronizer on single input sample */ \ +/* _q : synchronizer object */ \ +/* _x : input data sample */ \ +/* _y : output data array, [size: 2 x 1] */ \ +/* _ny : number of samples written to output buffer (0, 1, or 2) */ \ +int SYMTRACK(_execute)(SYMTRACK() _q, \ + TI _x, \ + TO * _y, \ + unsigned int * _ny); \ + \ +/* execute synchronizer on input data array */ \ +/* _q : synchronizer object */ \ +/* _x : input data array */ \ +/* _nx : number of input samples */ \ +/* _y : output data array, [size: 2 _nx x 1] */ \ +/* _ny : number of samples written to output buffer */ \ +int SYMTRACK(_execute_block)(SYMTRACK() _q, \ + TI * _x, \ + unsigned int _nx, \ + TO * _y, \ + unsigned int * _ny); \ + +LIQUID_SYMTRACK_DEFINE_API(LIQUID_SYMTRACK_MANGLE_RRRF, + float, + float, + float, + float) + +LIQUID_SYMTRACK_DEFINE_API(LIQUID_SYMTRACK_MANGLE_CCCF, + float, + liquid_float_complex, + liquid_float_complex, + liquid_float_complex) + + + +// +// MODULE : math +// + +// ln( Gamma(z) ) +float liquid_lngammaf(float _z); + +// Gamma(z) +float liquid_gammaf(float _z); + +// ln( gamma(z,alpha) ) : lower incomplete gamma function +float liquid_lnlowergammaf(float _z, float _alpha); + +// ln( Gamma(z,alpha) ) : upper incomplete gamma function +float liquid_lnuppergammaf(float _z, float _alpha); + +// gamma(z,alpha) : lower incomplete gamma function +float liquid_lowergammaf(float _z, float _alpha); + +// Gamma(z,alpha) : upper incomplete gamma function +float liquid_uppergammaf(float _z, float _alpha); + +// n! +float liquid_factorialf(unsigned int _n); + + + +// ln(I_v(z)) : log Modified Bessel function of the first kind +float liquid_lnbesselif(float _nu, float _z); + +// I_v(z) : Modified Bessel function of the first kind +float liquid_besselif(float _nu, float _z); + +// I_0(z) : Modified Bessel function of the first kind (order zero) +float liquid_besseli0f(float _z); + +// J_v(z) : Bessel function of the first kind +float liquid_besseljf(float _nu, float _z); + +// J_0(z) : Bessel function of the first kind (order zero) +float liquid_besselj0f(float _z); + + +// Q function +float liquid_Qf(float _z); + +// Marcum Q-function +float liquid_MarcumQf(int _M, + float _alpha, + float _beta); + +// Marcum Q-function (M=1) +float liquid_MarcumQ1f(float _alpha, + float _beta); + +// sin(pi x) / (pi x) +float sincf(float _x); + +// next power of 2 : y = ceil(log2(_x)) +unsigned int liquid_nextpow2(unsigned int _x); + +// (n choose k) = n! / ( k! (n-k)! ) +float liquid_nchoosek(unsigned int _n, unsigned int _k); + +// +// Windowing functions +// + +// number of window functions available, including "unknown" type +#define LIQUID_WINDOW_NUM_FUNCTIONS (10) + +// prototypes +typedef enum { + LIQUID_WINDOW_UNKNOWN=0, // unknown/unsupported scheme + + LIQUID_WINDOW_HAMMING, // Hamming + LIQUID_WINDOW_HANN, // Hann + LIQUID_WINDOW_BLACKMANHARRIS, // Blackman-harris (4-term) + LIQUID_WINDOW_BLACKMANHARRIS7, // Blackman-harris (7-term) + LIQUID_WINDOW_KAISER, // Kaiser (beta factor unspecified) + LIQUID_WINDOW_FLATTOP, // flat top (includes negative values) + LIQUID_WINDOW_TRIANGULAR, // triangular + LIQUID_WINDOW_RCOSTAPER, // raised-cosine taper (taper size unspecified) + LIQUID_WINDOW_KBD, // Kaiser-Bessel derived window (beta factor unspecified) +} liquid_window_type; + +// pretty names for window +extern const char * liquid_window_str[LIQUID_WINDOW_NUM_FUNCTIONS][2]; + +// Print compact list of existing and available windowing functions +void liquid_print_windows(); + +// returns window type based on input string +liquid_window_type liquid_getopt_str2window(const char * _str); + +// generic window function given type +// _type : window type, e.g. LIQUID_WINDOW_KAISER +// _i : window index, _i in [0,_wlen-1] +// _wlen : length of window +// _arg : window-specific argument, if required +float liquid_windowf(liquid_window_type _type, + unsigned int _i, + unsigned int _wlen, + float _arg); + +// Kaiser window +// _i : window index, _i in [0,_wlen-1] +// _wlen : full window length +// _beta : Kaiser-Bessel window shape parameter +float liquid_kaiser(unsigned int _i, + unsigned int _wlen, + float _beta); + +// Hamming window +// _i : window index, _i in [0,_wlen-1] +// _wlen : full window length +float liquid_hamming(unsigned int _i, + unsigned int _wlen); + +// Hann window +// _i : window index, _i in [0,_wlen-1] +// _wlen : full window length +float liquid_hann(unsigned int _i, + unsigned int _wlen); + +// Blackman-harris window +// _i : window index, _i in [0,_wlen-1] +// _wlen : full window length +float liquid_blackmanharris(unsigned int _i, + unsigned int _wlen); + +// 7th order Blackman-harris window +// _i : window index, _i in [0,_wlen-1] +// _wlen : full window length +float liquid_blackmanharris7(unsigned int _i, + unsigned int _wlen); + +// Flat-top window +// _i : window index, _i in [0,_wlen-1] +// _wlen : full window length +float liquid_flattop(unsigned int _i, + unsigned int _wlen); + +// Triangular window +// _i : window index, _i in [0,_wlen-1] +// _wlen : full window length +// _L : triangle length, _L in {_wlen-1, _wlen, _wlen+1} +float liquid_triangular(unsigned int _i, + unsigned int _wlen, + unsigned int _L); + +// raised-cosine tapering window +// _i : window index +// _wlen : full window length +// _t : taper length, _t in [0,_wlen/2] +float liquid_rcostaper_window(unsigned int _i, + unsigned int _wlen, + unsigned int _t); + +// Kaiser-Bessel derived window (single sample) +// _i : window index, _i in [0,_wlen-1] +// _wlen : length of filter (must be even) +// _beta : Kaiser window parameter (_beta > 0) +float liquid_kbd(unsigned int _i, + unsigned int _wlen, + float _beta); + +// Kaiser-Bessel derived window (full window) +// _wlen : full window length (must be even) +// _beta : Kaiser window parameter (_beta > 0) +// _w : window output buffer, [size: _wlen x 1] +int liquid_kbd_window(unsigned int _wlen, + float _beta, + float * _w); + + +// polynomials + + +#define LIQUID_POLY_MANGLE_DOUBLE(name) LIQUID_CONCAT(poly, name) +#define LIQUID_POLY_MANGLE_FLOAT(name) LIQUID_CONCAT(polyf, name) + +#define LIQUID_POLY_MANGLE_CDOUBLE(name) LIQUID_CONCAT(polyc, name) +#define LIQUID_POLY_MANGLE_CFLOAT(name) LIQUID_CONCAT(polycf, name) + +// large macro +// POLY : name-mangling macro +// T : data type +// TC : data type (complex) +#define LIQUID_POLY_DEFINE_API(POLY,T,TC) \ + \ +/* Evaluate polynomial _p at value _x */ \ +/* _p : polynomial coefficients [size _k x 1] */ \ +/* _k : polynomial coefficients length, order is _k - 1 */ \ +/* _x : input to evaluate polynomial */ \ +T POLY(_val)(T * _p, \ + unsigned int _k, \ + T _x); \ + \ +/* Perform least-squares polynomial fit on data set */ \ +/* _x : x-value sample set [size: _n x 1] */ \ +/* _y : y-value sample set [size: _n x 1] */ \ +/* _n : number of samples in _x and _y */ \ +/* _p : polynomial coefficients output [size _k x 1] */ \ +/* _k : polynomial coefficients length, order is _k - 1 */ \ +int POLY(_fit)(T * _x, \ + T * _y, \ + unsigned int _n, \ + T * _p, \ + unsigned int _k); \ + \ +/* Perform Lagrange polynomial exact fit on data set */ \ +/* _x : x-value sample set, size [_n x 1] */ \ +/* _y : y-value sample set, size [_n x 1] */ \ +/* _n : number of samples in _x and _y */ \ +/* _p : polynomial coefficients output [size _n x 1] */ \ +int POLY(_fit_lagrange)(T * _x, \ + T * _y, \ + unsigned int _n, \ + T * _p); \ + \ +/* Perform Lagrange polynomial interpolation on data set without */ \ +/* computing coefficients as an intermediate step. */ \ +/* _x : x-value sample set [size: _n x 1] */ \ +/* _y : y-value sample set [size: _n x 1] */ \ +/* _n : number of samples in _x and _y */ \ +/* _x0 : x-value to evaluate and compute interpolant */ \ +T POLY(_interp_lagrange)(T * _x, \ + T * _y, \ + unsigned int _n, \ + T _x0); \ + \ +/* Compute Lagrange polynomial fit in the barycentric form. */ \ +/* _x : x-value sample set, size [_n x 1] */ \ +/* _n : number of samples in _x */ \ +/* _w : barycentric weights normalized so _w[0]=1, size [_n x 1] */ \ +int POLY(_fit_lagrange_barycentric)(T * _x, \ + unsigned int _n, \ + T * _w); \ + \ +/* Perform Lagrange polynomial interpolation using the barycentric form */ \ +/* of the weights. */ \ +/* _x : x-value sample set [size: _n x 1] */ \ +/* _y : y-value sample set [size: _n x 1] */ \ +/* _w : barycentric weights [size: _n x 1] */ \ +/* _x0 : x-value to evaluate and compute interpolant */ \ +/* _n : number of samples in _x, _y, and _w */ \ +T POLY(_val_lagrange_barycentric)(T * _x, \ + T * _y, \ + T * _w, \ + T _x0, \ + unsigned int _n); \ + \ +/* Perform binomial expansion on the polynomial */ \ +/* \( P_n(x) = (1+x)^n \) */ \ +/* as */ \ +/* \( P_n(x) = p[0] + p[1]x + p[2]x^2 + ... + p[n]x^n \) */ \ +/* NOTE: _p has order n (coefficients has length n+1) */ \ +/* _n : polynomial order */ \ +/* _p : polynomial coefficients [size: _n+1 x 1] */ \ +int POLY(_expandbinomial)(unsigned int _n, \ + T * _p); \ + \ +/* Perform positive/negative binomial expansion on the polynomial */ \ +/* \( P_n(x) = (1+x)^m (1-x)^k \) */ \ +/* as */ \ +/* \( P_n(x) = p[0] + p[1]x + p[2]x^2 + ... + p[n]x^n \) */ \ +/* NOTE: _p has order n=m+k (array is length n+1) */ \ +/* _m : number of '1+x' terms */ \ +/* _k : number of '1-x' terms */ \ +/* _p : polynomial coefficients [size: _m+_k+1 x 1] */ \ +int POLY(_expandbinomial_pm)(unsigned int _m, \ + unsigned int _k, \ + T * _p); \ + \ +/* Perform root expansion on the polynomial */ \ +/* \( P_n(x) = (x-r[0]) (x-r[1]) ... (x-r[n-1]) \) */ \ +/* as */ \ +/* \( P_n(x) = p[0] + p[1]x + ... + p[n]x^n \) */ \ +/* where \( r[0],r[1],...,r[n-1]\) are the roots of \( P_n(x) \). */ \ +/* NOTE: _p has order _n (array is length _n+1) */ \ +/* _r : roots of polynomial [size: _n x 1] */ \ +/* _n : number of roots in polynomial */ \ +/* _p : polynomial coefficients [size: _n+1 x 1] */ \ +int POLY(_expandroots)(T * _r, \ + unsigned int _n, \ + T * _p); \ + \ +/* Perform root expansion on the polynomial */ \ +/* \( P_n(x) = (xb[0]-a[0]) (xb[1]-a[1])...(xb[n-1]-a[n-1]) \) */ \ +/* as */ \ +/* \( P_n(x) = p[0] + p[1]x + ... + p[n]x^n \) */ \ +/* NOTE: _p has order _n (array is length _n+1) */ \ +/* _a : subtractant of polynomial rotos [size: _n x 1] */ \ +/* _b : multiplicant of polynomial roots [size: _n x 1] */ \ +/* _n : number of roots in polynomial */ \ +/* _p : polynomial coefficients [size: _n+1 x 1] */ \ +int POLY(_expandroots2)(T * _a, \ + T * _b, \ + unsigned int _n, \ + T * _p); \ + \ +/* Find the complex roots of a polynomial. */ \ +/* _p : polynomial coefficients [size: _n x 1] */ \ +/* _k : polynomial length */ \ +/* _roots : resulting complex roots [size: _k-1 x 1] */ \ +int POLY(_findroots)(T * _poly, \ + unsigned int _n, \ + TC * _roots); \ + \ +/* Find the complex roots of the polynomial using the Durand-Kerner */ \ +/* method */ \ +/* _p : polynomial coefficients [size: _n x 1] */ \ +/* _k : polynomial length */ \ +/* _roots : resulting complex roots [size: _k-1 x 1] */ \ +int POLY(_findroots_durandkerner)(T * _p, \ + unsigned int _k, \ + TC * _roots); \ + \ +/* Find the complex roots of the polynomial using Bairstow's method. */ \ +/* _p : polynomial coefficients [size: _n x 1] */ \ +/* _k : polynomial length */ \ +/* _roots : resulting complex roots [size: _k-1 x 1] */ \ +int POLY(_findroots_bairstow)(T * _p, \ + unsigned int _k, \ + TC * _roots); \ + \ +/* Expand the multiplication of two polynomials */ \ +/* \( ( a[0] + a[1]x + a[2]x^2 + ...) (b[0] + b[1]x + b[]x^2 + ...) \) */ \ +/* as */ \ +/* \( c[0] + c[1]x + c[2]x^2 + ... + c[n]x^n \) */ \ +/* where order(c) = order(a) + order(b) + 1 */ \ +/* and therefore length(c) = length(a) + length(b) - 1 */ \ +/* _a : 1st polynomial coefficients (length is _order_a+1) */ \ +/* _order_a : 1st polynomial order */ \ +/* _b : 2nd polynomial coefficients (length is _order_b+1) */ \ +/* _order_b : 2nd polynomial order */ \ +/* _c : output polynomial [size: _order_a+_order_b+1 x 1] */ \ +int POLY(_mul)(T * _a, \ + unsigned int _order_a, \ + T * _b, \ + unsigned int _order_b, \ + T * _c); \ + +LIQUID_POLY_DEFINE_API(LIQUID_POLY_MANGLE_DOUBLE, + double, + liquid_double_complex) + +LIQUID_POLY_DEFINE_API(LIQUID_POLY_MANGLE_FLOAT, + float, + liquid_float_complex) + +LIQUID_POLY_DEFINE_API(LIQUID_POLY_MANGLE_CDOUBLE, + liquid_double_complex, + liquid_double_complex) + +LIQUID_POLY_DEFINE_API(LIQUID_POLY_MANGLE_CFLOAT, + liquid_float_complex, + liquid_float_complex) + +#if 0 +// expands the polynomial: (1+x)^n +void poly_binomial_expand(unsigned int _n, int * _c); + +// expands the polynomial: (1+x)^k * (1-x)^(n-k) +void poly_binomial_expand_pm(unsigned int _n, + unsigned int _k, + int * _c); +#endif + +// +// modular arithmetic, etc. +// + +// maximum number of factors +#define LIQUID_MAX_FACTORS (40) + +// is number prime? +int liquid_is_prime(unsigned int _n); + +// compute number's prime factors +// _n : number to factor +// _factors : pre-allocated array of factors [size: LIQUID_MAX_FACTORS x 1] +// _num_factors: number of factors found, sorted ascending +int liquid_factor(unsigned int _n, + unsigned int * _factors, + unsigned int * _num_factors); + +// compute number's unique prime factors +// _n : number to factor +// _factors : pre-allocated array of factors [size: LIQUID_MAX_FACTORS x 1] +// _num_factors: number of unique factors found, sorted ascending +int liquid_unique_factor(unsigned int _n, + unsigned int * _factors, + unsigned int * _num_factors); + +// compute greatest common divisor between to numbers P and Q +unsigned int liquid_gcd(unsigned int _P, + unsigned int _Q); + +// compute c = base^exp (mod n) +unsigned int liquid_modpow(unsigned int _base, + unsigned int _exp, + unsigned int _n); + +// find smallest primitive root of _n +unsigned int liquid_primitive_root(unsigned int _n); + +// find smallest primitive root of _n, assuming _n is prime +unsigned int liquid_primitive_root_prime(unsigned int _n); + +// Euler's totient function +unsigned int liquid_totient(unsigned int _n); + + +// +// MODULE : matrix +// + +#define LIQUID_MATRIX_MANGLE_DOUBLE(name) LIQUID_CONCAT(matrix, name) +#define LIQUID_MATRIX_MANGLE_FLOAT(name) LIQUID_CONCAT(matrixf, name) + +#define LIQUID_MATRIX_MANGLE_CDOUBLE(name) LIQUID_CONCAT(matrixc, name) +#define LIQUID_MATRIX_MANGLE_CFLOAT(name) LIQUID_CONCAT(matrixcf, name) + +// large macro +// MATRIX : name-mangling macro +// T : data type +#define LIQUID_MATRIX_DEFINE_API(MATRIX,T) \ + \ +/* Print array as matrix to stdout */ \ +/* _x : input matrix, [size: _r x _c] */ \ +/* _r : rows in matrix */ \ +/* _c : columns in matrix */ \ +int MATRIX(_print)(T * _x, \ + unsigned int _r, \ + unsigned int _c); \ + \ +/* Perform point-wise addition between two matrices \(\vec{X}\) */ \ +/* and \(\vec{Y}\), saving the result in the output matrix \(\vec{Z}\). */ \ +/* That is, \(\vec{Z}_{i,j}=\vec{X}_{i,j}+\vec{Y}_{i,j} \), */ \ +/* \( \forall_{i \in r} \) and \( \forall_{j \in c} \) */ \ +/* _x : input matrix, [size: _r x _c] */ \ +/* _y : input matrix, [size: _r x _c] */ \ +/* _z : output matrix, [size: _r x _c] */ \ +/* _r : number of rows in each matrix */ \ +/* _c : number of columns in each matrix */ \ +int MATRIX(_add)(T * _x, \ + T * _y, \ + T * _z, \ + unsigned int _r, \ + unsigned int _c); \ + \ +/* Perform point-wise subtraction between two matrices \(\vec{X}\) */ \ +/* and \(\vec{Y}\), saving the result in the output matrix \(\vec{Z}\) */ \ +/* That is, \(\vec{Z}_{i,j}=\vec{X}_{i,j}-\vec{Y}_{i,j} \), */ \ +/* \( \forall_{i \in r} \) and \( \forall_{j \in c} \) */ \ +/* _x : input matrix, [size: _r x _c] */ \ +/* _y : input matrix, [size: _r x _c] */ \ +/* _z : output matrix, [size: _r x _c] */ \ +/* _r : number of rows in each matrix */ \ +/* _c : number of columns in each matrix */ \ +int MATRIX(_sub)(T * _x, \ + T * _y, \ + T * _z, \ + unsigned int _r, \ + unsigned int _c); \ + \ +/* Perform point-wise multiplication between two matrices \(\vec{X}\) */ \ +/* and \(\vec{Y}\), saving the result in the output matrix \(\vec{Z}\) */ \ +/* That is, \(\vec{Z}_{i,j}=\vec{X}_{i,j} \vec{Y}_{i,j} \), */ \ +/* \( \forall_{i \in r} \) and \( \forall_{j \in c} \) */ \ +/* _x : input matrix, [size: _r x _c] */ \ +/* _y : input matrix, [size: _r x _c] */ \ +/* _z : output matrix, [size: _r x _c] */ \ +/* _r : number of rows in each matrix */ \ +/* _c : number of columns in each matrix */ \ +int MATRIX(_pmul)(T * _x, \ + T * _y, \ + T * _z, \ + unsigned int _r, \ + unsigned int _c); \ + \ +/* Perform point-wise division between two matrices \(\vec{X}\) */ \ +/* and \(\vec{Y}\), saving the result in the output matrix \(\vec{Z}\) */ \ +/* That is, \(\vec{Z}_{i,j}=\vec{X}_{i,j}/\vec{Y}_{i,j} \), */ \ +/* \( \forall_{i \in r} \) and \( \forall_{j \in c} \) */ \ +/* _x : input matrix, [size: _r x _c] */ \ +/* _y : input matrix, [size: _r x _c] */ \ +/* _z : output matrix, [size: _r x _c] */ \ +/* _r : number of rows in each matrix */ \ +/* _c : number of columns in each matrix */ \ +int MATRIX(_pdiv)(T * _x, \ + T * _y, \ + T * _z, \ + unsigned int _r, \ + unsigned int _c); \ + \ +/* Multiply two matrices \(\vec{X}\) and \(\vec{Y}\), storing the */ \ +/* result in \(\vec{Z}\). */ \ +/* NOTE: _rz = _rx, _cz = _cy, and _cx = _ry */ \ +/* _x : input matrix, [size: _rx x _cx] */ \ +/* _rx : number of rows in _x */ \ +/* _cx : number of columns in _x */ \ +/* _y : input matrix, [size: _ry x _cy] */ \ +/* _ry : number of rows in _y */ \ +/* _cy : number of columns in _y */ \ +/* _z : output matrix, [size: _rz x _cz] */ \ +/* _rz : number of rows in _z */ \ +/* _cz : number of columns in _z */ \ +int MATRIX(_mul)(T * _x, unsigned int _rx, unsigned int _cx, \ + T * _y, unsigned int _ry, unsigned int _cy, \ + T * _z, unsigned int _rz, unsigned int _cz); \ + \ +/* Solve \(\vec{X} = \vec{Y} \vec{Z}\) for \(\vec{Z}\) for square */ \ +/* matrices of size \(n\) */ \ +/* _x : input matrix, [size: _n x _n] */ \ +/* _y : input matrix, [size: _n x _n] */ \ +/* _z : output matrix, [size: _n x _n] */ \ +/* _n : number of rows and columns in each matrix */ \ +int MATRIX(_div)(T * _x, \ + T * _y, \ + T * _z, \ + unsigned int _n); \ + \ +/* Compute the determinant of a square matrix \(\vec{X}\) */ \ +/* _x : input matrix, [size: _r x _c] */ \ +/* _r : rows */ \ +/* _c : columns */ \ +T MATRIX(_det)(T * _x, \ + unsigned int _r, \ + unsigned int _c); \ + \ +/* Compute the in-place transpose of the matrix \(\vec{X}\) */ \ +/* _x : input matrix, [size: _r x _c] */ \ +/* _r : rows */ \ +/* _c : columns */ \ +int MATRIX(_trans)(T * _x, \ + unsigned int _r, \ + unsigned int _c); \ + \ +/* Compute the in-place Hermitian transpose of the matrix \(\vec{X}\) */ \ +/* _x : input matrix, [size: _r x _c] */ \ +/* _r : rows */ \ +/* _c : columns */ \ +int MATRIX(_hermitian)(T * _x, \ + unsigned int _r, \ + unsigned int _c); \ + \ +/* Compute \(\vec{X}\vec{X}^T\) on a \(m \times n\) matrix. */ \ +/* The result is a \(m \times m\) matrix. */ \ +/* _x : input matrix, [size: _m x _n] */ \ +/* _m : input rows */ \ +/* _n : input columns */ \ +/* _xxT : output matrix, [size: _m x _m] */ \ +int MATRIX(_mul_transpose)(T * _x, \ + unsigned int _m, \ + unsigned int _n, \ + T * _xxT); \ + \ +/* Compute \(\vec{X}^T\vec{X}\) on a \(m \times n\) matrix. */ \ +/* The result is a \(n \times n\) matrix. */ \ +/* _x : input matrix, [size: _m x _n] */ \ +/* _m : input rows */ \ +/* _n : input columns */ \ +/* _xTx : output matrix, [size: _n x _n] */ \ +int MATRIX(_transpose_mul)(T * _x, \ + unsigned int _m, \ + unsigned int _n, \ + T * _xTx); \ + \ +/* Compute \(\vec{X}\vec{X}^H\) on a \(m \times n\) matrix. */ \ +/* The result is a \(m \times m\) matrix. */ \ +/* _x : input matrix, [size: _m x _n] */ \ +/* _m : input rows */ \ +/* _n : input columns */ \ +/* _xxH : output matrix, [size: _m x _m] */ \ +int MATRIX(_mul_hermitian)(T * _x, \ + unsigned int _m, \ + unsigned int _n, \ + T * _xxH); \ + \ +/* Compute \(\vec{X}^H\vec{X}\) on a \(m \times n\) matrix. */ \ +/* The result is a \(n \times n\) matrix. */ \ +/* _x : input matrix, [size: _m x _n] */ \ +/* _m : input rows */ \ +/* _n : input columns */ \ +/* _xHx : output matrix, [size: _n x _n] */ \ +int MATRIX(_hermitian_mul)(T * _x, \ + unsigned int _m, \ + unsigned int _n, \ + T * _xHx); \ + \ + \ +/* Augment two matrices \(\vec{X}\) and \(\vec{Y}\), storing the result */ \ +/* in \(\vec{Z}\) */ \ +/* NOTE: _rz = _rx = _ry, _rx = _ry, and _cz = _cx + _cy */ \ +/* _x : input matrix, [size: _rx x _cx] */ \ +/* _rx : number of rows in _x */ \ +/* _cx : number of columns in _x */ \ +/* _y : input matrix, [size: _ry x _cy] */ \ +/* _ry : number of rows in _y */ \ +/* _cy : number of columns in _y */ \ +/* _z : output matrix, [size: _rz x _cz] */ \ +/* _rz : number of rows in _z */ \ +/* _cz : number of columns in _z */ \ +int MATRIX(_aug)(T * _x, unsigned int _rx, unsigned int _cx, \ + T * _y, unsigned int _ry, unsigned int _cy, \ + T * _z, unsigned int _rz, unsigned int _cz); \ + \ +/* Compute the inverse of a square matrix \(\vec{X}\) */ \ +/* _x : input/output matrix, [size: _r x _c] */ \ +/* _r : rows */ \ +/* _c : columns */ \ +int MATRIX(_inv)(T * _x, \ + unsigned int _r, \ + unsigned int _c); \ + \ +/* Generate the identity square matrix of size \(n\) */ \ +/* _x : output matrix, [size: _n x _n] */ \ +/* _n : dimensions of _x */ \ +int MATRIX(_eye)(T * _x, \ + unsigned int _n); \ + \ +/* Generate the all-ones matrix of size \(n\) */ \ +/* _x : output matrix, [size: _r x _c] */ \ +/* _r : rows */ \ +/* _c : columns */ \ +int MATRIX(_ones)(T * _x, \ + unsigned int _r, \ + unsigned int _c); \ + \ +/* Generate the all-zeros matrix of size \(n\) */ \ +/* _x : output matrix, [size: _r x _c] */ \ +/* _r : rows */ \ +/* _c : columns */ \ +int MATRIX(_zeros)(T * _x, \ + unsigned int _r, \ + unsigned int _c); \ + \ +/* Perform Gauss-Jordan elimination on matrix \(\vec{X}\) */ \ +/* _x : input/output matrix, [size: _r x _c] */ \ +/* _r : rows */ \ +/* _c : columns */ \ +int MATRIX(_gjelim)(T * _x, \ + unsigned int _r, \ + unsigned int _c); \ + \ +/* Pivot on element \(\vec{X}_{i,j}\) */ \ +/* _x : output matrix, [size: _r x _c] */ \ +/* _r : rows of _x */ \ +/* _c : columns of _x */ \ +/* _i : pivot row */ \ +/* _j : pivot column */ \ +int MATRIX(_pivot)(T * _x, \ + unsigned int _r, \ + unsigned int _c, \ + unsigned int _i, \ + unsigned int _j); \ + \ +/* Swap rows _r1 and _r2 of matrix \(\vec{X}\) */ \ +/* _x : input/output matrix, [size: _r x _c] */ \ +/* _r : rows of _x */ \ +/* _c : columns of _x */ \ +/* _r1 : first row to swap */ \ +/* _r2 : second row to swap */ \ +int MATRIX(_swaprows)(T * _x, \ + unsigned int _r, \ + unsigned int _c, \ + unsigned int _r1, \ + unsigned int _r2); \ + \ +/* Solve linear system of \(n\) equations: \(\vec{A}\vec{x} = \vec{b}\) */ \ +/* _A : system matrix, [size: _n x _n] */ \ +/* _n : system size */ \ +/* _b : equality vector, [size: _n x 1] */ \ +/* _x : solution vector, [size: _n x 1] */ \ +/* _opts : options (ignored for now) */ \ +int MATRIX(_linsolve)(T * _A, \ + unsigned int _n, \ + T * _b, \ + T * _x, \ + void * _opts); \ + \ +/* Solve linear system of equations using conjugate gradient method. */ \ +/* _A : symmetric positive definite square matrix */ \ +/* _n : system dimension */ \ +/* _b : equality, [size: _n x 1] */ \ +/* _x : solution estimate, [size: _n x 1] */ \ +/* _opts : options (ignored for now) */ \ +int MATRIX(_cgsolve)(T * _A, \ + unsigned int _n, \ + T * _b, \ + T * _x, \ + void * _opts); \ + \ +/* Perform L/U/P decomposition using Crout's method */ \ +/* _x : input/output matrix, [size: _rx x _cx] */ \ +/* _rx : rows of _x */ \ +/* _cx : columns of _x */ \ +/* _L : first row to swap */ \ +/* _U : first row to swap */ \ +/* _P : first row to swap */ \ +int MATRIX(_ludecomp_crout)(T * _x, \ + unsigned int _rx, \ + unsigned int _cx, \ + T * _L, \ + T * _U, \ + T * _P); \ + \ +/* Perform L/U/P decomposition, Doolittle's method */ \ +/* _x : input/output matrix, [size: _rx x _cx] */ \ +/* _rx : rows of _x */ \ +/* _cx : columns of _x */ \ +/* _L : first row to swap */ \ +/* _U : first row to swap */ \ +/* _P : first row to swap */ \ +int MATRIX(_ludecomp_doolittle)(T * _x, \ + unsigned int _rx, \ + unsigned int _cx, \ + T * _L, \ + T * _U, \ + T * _P); \ + \ +/* Perform orthnormalization using the Gram-Schmidt algorithm */ \ +/* _A : input matrix, [size: _r x _c] */ \ +/* _r : rows */ \ +/* _c : columns */ \ +/* _v : output matrix */ \ +int MATRIX(_gramschmidt)(T * _A, \ + unsigned int _r, \ + unsigned int _c, \ + T * _v); \ + \ +/* Perform Q/R decomposition using the Gram-Schmidt algorithm such that */ \ +/* \( \vec{A} = \vec{Q} \vec{R} \) */ \ +/* and \( \vec{Q}^T \vec{Q} = \vec{I}_n \) */ \ +/* and \(\vec{R\}\) is a diagonal \(m \times m\) matrix */ \ +/* NOTE: all matrices are square */ \ +/* _A : input matrix, [size: _m x _m] */ \ +/* _m : rows */ \ +/* _n : columns (same as cols) */ \ +/* _Q : output matrix, [size: _m x _m] */ \ +/* _R : output matrix, [size: _m x _m] */ \ +int MATRIX(_qrdecomp_gramschmidt)(T * _A, \ + unsigned int _m, \ + unsigned int _n, \ + T * _Q, \ + T * _R); \ + \ +/* Compute Cholesky decomposition of a symmetric/Hermitian */ \ +/* positive-definite matrix as \( \vec{A} = \vec{L}\vec{L}^T \) */ \ +/* _A : input square matrix, [size: _n x _n] */ \ +/* _n : input matrix dimension */ \ +/* _L : output lower-triangular matrix */ \ +int MATRIX(_chol)(T * _A, \ + unsigned int _n, \ + T * _L); \ + +#define matrix_access(X,R,C,r,c) ((X)[(r)*(C)+(c)]) + +#define matrixc_access(X,R,C,r,c) matrix_access(X,R,C,r,c) +#define matrixf_access(X,R,C,r,c) matrix_access(X,R,C,r,c) +#define matrixcf_access(X,R,C,r,c) matrix_access(X,R,C,r,c) + +LIQUID_MATRIX_DEFINE_API(LIQUID_MATRIX_MANGLE_FLOAT, float) +LIQUID_MATRIX_DEFINE_API(LIQUID_MATRIX_MANGLE_DOUBLE, double) + +LIQUID_MATRIX_DEFINE_API(LIQUID_MATRIX_MANGLE_CFLOAT, liquid_float_complex) +LIQUID_MATRIX_DEFINE_API(LIQUID_MATRIX_MANGLE_CDOUBLE, liquid_double_complex) + + +#define LIQUID_SMATRIX_MANGLE_BOOL(name) LIQUID_CONCAT(smatrixb, name) +#define LIQUID_SMATRIX_MANGLE_FLOAT(name) LIQUID_CONCAT(smatrixf, name) +#define LIQUID_SMATRIX_MANGLE_INT(name) LIQUID_CONCAT(smatrixi, name) + +// sparse 'alist' matrix type (similar to MacKay, Davey Lafferty convention) +// large macro +// SMATRIX : name-mangling macro +// T : primitive data type +#define LIQUID_SMATRIX_DEFINE_API(SMATRIX,T) \ + \ +/* Sparse matrix object (similar to MacKay, Davey, Lafferty convention) */ \ +typedef struct SMATRIX(_s) * SMATRIX(); \ + \ +/* Create _M x _N sparse matrix, initialized with zeros */ \ +SMATRIX() SMATRIX(_create)(unsigned int _M, \ + unsigned int _N); \ + \ +/* Create _M x _N sparse matrix, initialized on array */ \ +/* _x : input matrix, [size: _m x _n] */ \ +/* _m : number of rows in input matrix */ \ +/* _n : number of columns in input matrix */ \ +SMATRIX() SMATRIX(_create_array)(T * _x, \ + unsigned int _m, \ + unsigned int _n); \ + \ +/* Destroy object, freeing all internal memory */ \ +int SMATRIX(_destroy)(SMATRIX() _q); \ + \ +/* Print sparse matrix in compact form to stdout */ \ +int SMATRIX(_print)(SMATRIX() _q); \ + \ +/* Print sparse matrix in expanded form to stdout */ \ +int SMATRIX(_print_expanded)(SMATRIX() _q); \ + \ +/* Get size of sparse matrix (number of rows and columns) */ \ +/* _q : sparse matrix object */ \ +/* _m : number of rows in matrix */ \ +/* _n : number of columns in matrix */ \ +int SMATRIX(_size)(SMATRIX() _q, \ + unsigned int * _m, \ + unsigned int * _n); \ + \ +/* Zero all elements and retain allocated memory */ \ +int SMATRIX(_clear)(SMATRIX() _q); \ + \ +/* Zero all elements and clear memory */ \ +int SMATRIX(_reset)(SMATRIX() _q); \ + \ +/* Determine if value has been set (allocated memory) */ \ +/* _q : sparse matrix object */ \ +/* _m : row index of value to query */ \ +/* _n : column index of value to query */ \ +int SMATRIX(_isset)(SMATRIX() _q, \ + unsigned int _m, \ + unsigned int _n); \ + \ +/* Insert an element at index, allocating memory as necessary */ \ +/* _q : sparse matrix object */ \ +/* _m : row index of value to insert */ \ +/* _n : column index of value to insert */ \ +/* _v : value to insert */ \ +int SMATRIX(_insert)(SMATRIX() _q, \ + unsigned int _m, \ + unsigned int _n, \ + T _v); \ + \ +/* Delete an element at index, freeing memory */ \ +/* _q : sparse matrix object */ \ +/* _m : row index of value to delete */ \ +/* _n : column index of value to delete */ \ +int SMATRIX(_delete)(SMATRIX() _q, \ + unsigned int _m, \ + unsigned int _n); \ + \ +/* Set the value in matrix at specified row and column, allocating */ \ +/* memory if needed */ \ +/* _q : sparse matrix object */ \ +/* _m : row index of value to set */ \ +/* _n : column index of value to set */ \ +/* _v : value to set in matrix */ \ +int SMATRIX(_set)(SMATRIX() _q, \ + unsigned int _m, \ + unsigned int _n, \ + T _v); \ + \ +/* Get the value from matrix at specified row and column */ \ +/* _q : sparse matrix object */ \ +/* _m : row index of value to get */ \ +/* _n : column index of value to get */ \ +T SMATRIX(_get)(SMATRIX() _q, \ + unsigned int _m, \ + unsigned int _n); \ + \ +/* Initialize to identity matrix; set all diagonal elements to 1, all */ \ +/* others to 0. This is done with both square and non-square matrices. */ \ +int SMATRIX(_eye)(SMATRIX() _q); \ + \ +/* Multiply two sparse matrices, \( \vec{Z} = \vec{X} \vec{Y} \) */ \ +/* _x : sparse matrix object (input) */ \ +/* _y : sparse matrix object (input) */ \ +/* _z : sparse matrix object (output) */ \ +int SMATRIX(_mul)(SMATRIX() _x, \ + SMATRIX() _y, \ + SMATRIX() _z); \ + \ +/* Multiply sparse matrix by vector */ \ +/* _q : sparse matrix */ \ +/* _x : input vector, [size: _n x 1] */ \ +/* _y : output vector, [size: _m x 1] */ \ +int SMATRIX(_vmul)(SMATRIX() _q, \ + T * _x, \ + T * _y); \ + +LIQUID_SMATRIX_DEFINE_API(LIQUID_SMATRIX_MANGLE_BOOL, unsigned char) +LIQUID_SMATRIX_DEFINE_API(LIQUID_SMATRIX_MANGLE_FLOAT, float) +LIQUID_SMATRIX_DEFINE_API(LIQUID_SMATRIX_MANGLE_INT, short int) + +// +// smatrix cross methods +// + +// multiply sparse binary matrix by floating-point matrix +// _q : sparse matrix [size: A->M x A->N] +// _x : input vector [size: mx x nx ] +// _y : output vector [size: my x ny ] +int smatrixb_mulf(smatrixb _A, + float * _x, + unsigned int _mx, + unsigned int _nx, + float * _y, + unsigned int _my, + unsigned int _ny); + +// multiply sparse binary matrix by floating-point vector +// _q : sparse matrix +// _x : input vector [size: _N x 1] +// _y : output vector [size: _M x 1] +int smatrixb_vmulf(smatrixb _q, + float * _x, + float * _y); + + +// +// MODULE : modem (modulator/demodulator) +// + +// Maximum number of allowed bits per symbol +#define MAX_MOD_BITS_PER_SYMBOL 8 + +// Modulation schemes available +#define LIQUID_MODEM_NUM_SCHEMES (52) + +typedef enum { + LIQUID_MODEM_UNKNOWN=0, // Unknown modulation scheme + + // Phase-shift keying (PSK) + LIQUID_MODEM_PSK2, LIQUID_MODEM_PSK4, + LIQUID_MODEM_PSK8, LIQUID_MODEM_PSK16, + LIQUID_MODEM_PSK32, LIQUID_MODEM_PSK64, + LIQUID_MODEM_PSK128, LIQUID_MODEM_PSK256, + + // Differential phase-shift keying (DPSK) + LIQUID_MODEM_DPSK2, LIQUID_MODEM_DPSK4, + LIQUID_MODEM_DPSK8, LIQUID_MODEM_DPSK16, + LIQUID_MODEM_DPSK32, LIQUID_MODEM_DPSK64, + LIQUID_MODEM_DPSK128, LIQUID_MODEM_DPSK256, + + // amplitude-shift keying + LIQUID_MODEM_ASK2, LIQUID_MODEM_ASK4, + LIQUID_MODEM_ASK8, LIQUID_MODEM_ASK16, + LIQUID_MODEM_ASK32, LIQUID_MODEM_ASK64, + LIQUID_MODEM_ASK128, LIQUID_MODEM_ASK256, + + // rectangular quadrature amplitude-shift keying (QAM) + LIQUID_MODEM_QAM4, + LIQUID_MODEM_QAM8, LIQUID_MODEM_QAM16, + LIQUID_MODEM_QAM32, LIQUID_MODEM_QAM64, + LIQUID_MODEM_QAM128, LIQUID_MODEM_QAM256, + + // amplitude phase-shift keying (APSK) + LIQUID_MODEM_APSK4, + LIQUID_MODEM_APSK8, LIQUID_MODEM_APSK16, + LIQUID_MODEM_APSK32, LIQUID_MODEM_APSK64, + LIQUID_MODEM_APSK128, LIQUID_MODEM_APSK256, + + // specific modem types + LIQUID_MODEM_BPSK, // Specific: binary PSK + LIQUID_MODEM_QPSK, // specific: quaternary PSK + LIQUID_MODEM_OOK, // Specific: on/off keying + LIQUID_MODEM_SQAM32, // 'square' 32-QAM + LIQUID_MODEM_SQAM128, // 'square' 128-QAM + LIQUID_MODEM_V29, // V.29 star constellation + LIQUID_MODEM_ARB16OPT, // optimal 16-QAM + LIQUID_MODEM_ARB32OPT, // optimal 32-QAM + LIQUID_MODEM_ARB64OPT, // optimal 64-QAM + LIQUID_MODEM_ARB128OPT, // optimal 128-QAM + LIQUID_MODEM_ARB256OPT, // optimal 256-QAM + LIQUID_MODEM_ARB64VT, // Virginia Tech logo + + // arbitrary modem type + LIQUID_MODEM_ARB // arbitrary QAM +} modulation_scheme; + +// structure for holding full modulation type descriptor +struct modulation_type_s { + const char * name; // short name (e.g. 'bpsk') + const char * fullname; // full name (e.g. 'binary phase-shift keying') + modulation_scheme scheme; // modulation scheme (e.g. LIQUID_MODEM_BPSK) + unsigned int bps; // modulation depth (e.g. 1) +}; + +// full modulation type descriptor +extern const struct modulation_type_s modulation_types[LIQUID_MODEM_NUM_SCHEMES]; + +// Print compact list of existing and available modulation schemes +int liquid_print_modulation_schemes(); + +// returns modulation_scheme based on input string +modulation_scheme liquid_getopt_str2mod(const char * _str); + +// query basic modulation types +int liquid_modem_is_psk(modulation_scheme _ms); +int liquid_modem_is_dpsk(modulation_scheme _ms); +int liquid_modem_is_ask(modulation_scheme _ms); +int liquid_modem_is_qam(modulation_scheme _ms); +int liquid_modem_is_apsk(modulation_scheme _ms); + +// useful functions + +// counts the number of different bits between two symbols +unsigned int count_bit_errors(unsigned int _s1, unsigned int _s2); + +// counts the number of different bits between two arrays of symbols +// _msg0 : original message [size: _n x 1] +// _msg1 : copy of original message [size: _n x 1] +// _n : message size +unsigned int count_bit_errors_array(unsigned char * _msg0, + unsigned char * _msg1, + unsigned int _n); + +// converts binary-coded decimal (BCD) to gray, ensuring successive values +// differ by exactly one bit +unsigned int gray_encode(unsigned int symbol_in); + +// converts a gray-encoded symbol to binary-coded decimal (BCD) +unsigned int gray_decode(unsigned int symbol_in); + +// pack soft bits into symbol +// _soft_bits : soft input bits [size: _bps x 1] +// _bps : bits per symbol +// _sym_out : output symbol, value in [0,2^_bps) +int liquid_pack_soft_bits(unsigned char * _soft_bits, + unsigned int _bps, + unsigned int * _sym_out); + +// unpack soft bits into symbol +// _sym_in : input symbol, value in [0,2^_bps) +// _bps : bits per symbol +// _soft_bits : soft output bits [size: _bps x 1] +int liquid_unpack_soft_bits(unsigned int _sym_in, + unsigned int _bps, + unsigned char * _soft_bits); + + +// +// Linear modem +// + +#define LIQUID_MODEM_MANGLE_FLOAT(name) LIQUID_CONCAT(modem,name) + +// Macro : MODEM +// MODEM : name-mangling macro +// T : primitive data type +// TC : primitive data type (complex) +#define LIQUID_MODEM_DEFINE_API(MODEM,T,TC) \ + \ +/* Linear modulator/demodulator (modem) object */ \ +typedef struct MODEM(_s) * MODEM(); \ + \ +/* Create digital modem object with a particular scheme */ \ +/* _scheme : linear modulation scheme (e.g. LIQUID_MODEM_QPSK) */ \ +MODEM() MODEM(_create)(modulation_scheme _scheme); \ + \ +/* Create linear digital modem object with arbitrary constellation */ \ +/* points defined by an external table of symbols. Sample points are */ \ +/* provided as complex float pairs and converted internally if needed. */ \ +/* _table : array of complex constellation points, [size: _M x 1] */ \ +/* _M : modulation order and table size, _M must be power of 2 */ \ +MODEM() MODEM(_create_arbitrary)(liquid_float_complex * _table, \ + unsigned int _M); \ + \ +/* Recreate modulation scheme, re-allocating memory as necessary */ \ +/* _q : modem object */ \ +/* _scheme : linear modulation scheme (e.g. LIQUID_MODEM_QPSK) */ \ +MODEM() MODEM(_recreate)(MODEM() _q, \ + modulation_scheme _scheme); \ + \ +/* Destroy modem object, freeing all allocated memory */ \ +int MODEM(_destroy)(MODEM() _q); \ + \ +/* Print modem status to stdout */ \ +int MODEM(_print)(MODEM() _q); \ + \ +/* Reset internal state of modem object; note that this is only */ \ +/* relevant for modulation types that retain an internal state such as */ \ +/* LIQUID_MODEM_DPSK4 as most linear modulation types are stateless */ \ +int MODEM(_reset)(MODEM() _q); \ + \ +/* Generate random symbol for modulation */ \ +unsigned int MODEM(_gen_rand_sym)(MODEM() _q); \ + \ +/* Get number of bits per symbol (bps) of modem object */ \ +unsigned int MODEM(_get_bps)(MODEM() _q); \ + \ +/* Get modulation scheme of modem object */ \ +modulation_scheme MODEM(_get_scheme)(MODEM() _q); \ + \ +/* Modulate input symbol (bits) and generate output complex sample */ \ +/* _q : modem object */ \ +/* _s : input symbol, 0 <= _s <= M-1 */ \ +/* _y : output complex sample */ \ +int MODEM(_modulate)(MODEM() _q, \ + unsigned int _s, \ + TC * _y); \ + \ +/* Demodulate input sample and provide maximum-likelihood estimate of */ \ +/* symbol that would have generated it. */ \ +/* The output is a hard decision value on the input sample. */ \ +/* This is performed efficiently by taking advantage of symmetry on */ \ +/* most modulation types. */ \ +/* For example, square and rectangular quadrature amplitude modulation */ \ +/* with gray coding can use a bisection search indepdently on its */ \ +/* in-phase and quadrature channels. */ \ +/* Arbitrary modulation schemes are relatively slow, however, for large */ \ +/* modulation types as the demodulator must compute the distance */ \ +/* between the received sample and all possible symbols to derive the */ \ +/* optimal symbol. */ \ +/* _q : modem object */ \ +/* _x : input sample */ \ +/* _s : output hard symbol, 0 <= _s <= M-1 */ \ +int MODEM(_demodulate)(MODEM() _q, \ + TC _x, \ + unsigned int * _s); \ + \ +/* Demodulate input sample and provide (approximate) log-likelihood */ \ +/* ratio (LLR, soft bits) as an output. */ \ +/* Similarly to the hard-decision demodulation method, this is computed */ \ +/* efficiently for most modulation types. */ \ +/* _q : modem object */ \ +/* _x : input sample */ \ +/* _s : output hard symbol, 0 <= _s <= M-1 */ \ +/* _soft_bits : output soft bits, [size: log2(M) x 1] */ \ +int MODEM(_demodulate_soft)(MODEM() _q, \ + TC _x, \ + unsigned int * _s, \ + unsigned char * _soft_bits); \ + \ +/* Get demodulator's estimated transmit sample */ \ +int MODEM(_get_demodulator_sample)(MODEM() _q, \ + TC * _x_hat); \ + \ +/* Get demodulator phase error */ \ +float MODEM(_get_demodulator_phase_error)(MODEM() _q); \ + \ +/* Get demodulator error vector magnitude */ \ +float MODEM(_get_demodulator_evm)(MODEM() _q); \ + +// define modem APIs +LIQUID_MODEM_DEFINE_API(LIQUID_MODEM_MANGLE_FLOAT,float,liquid_float_complex) + + +// +// continuous-phase modulation +// + +// gmskmod : GMSK modulator +typedef struct gmskmod_s * gmskmod; + +// create gmskmod object +// _k : samples/symbol +// _m : filter delay (symbols) +// _BT : excess bandwidth factor +gmskmod gmskmod_create(unsigned int _k, + unsigned int _m, + float _BT); +int gmskmod_destroy(gmskmod _q); +int gmskmod_print(gmskmod _q); +int gmskmod_reset(gmskmod _q); +int gmskmod_modulate(gmskmod _q, + unsigned int _sym, + liquid_float_complex * _y); + + +// gmskdem : GMSK demodulator +typedef struct gmskdem_s * gmskdem; + +// create gmskdem object +// _k : samples/symbol +// _m : filter delay (symbols) +// _BT : excess bandwidth factor +gmskdem gmskdem_create(unsigned int _k, + unsigned int _m, + float _BT); +int gmskdem_destroy(gmskdem _q); +int gmskdem_print(gmskdem _q); +int gmskdem_reset(gmskdem _q); +int gmskdem_set_eq_bw(gmskdem _q, float _bw); +int gmskdem_demodulate(gmskdem _q, + liquid_float_complex * _y, + unsigned int * _sym); + +// +// continuous phase frequency-shift keying (CP-FSK) modems +// + +// CP-FSK filter prototypes +typedef enum { + LIQUID_CPFSK_SQUARE=0, // square pulse + LIQUID_CPFSK_RCOS_FULL, // raised-cosine (full response) + LIQUID_CPFSK_RCOS_PARTIAL, // raised-cosine (partial response) + LIQUID_CPFSK_GMSK, // Gauss minimum-shift keying pulse +} liquid_cpfsk_filter; + +// CP-FSK modulator +typedef struct cpfskmod_s * cpfskmod; + +// create cpfskmod object (frequency modulator) +// _bps : bits per symbol, _bps > 0 +// _h : modulation index, _h > 0 +// _k : samples/symbol, _k > 1, _k even +// _m : filter delay (symbols), _m > 0 +// _beta : filter bandwidth parameter, _beta > 0 +// _type : filter type (e.g. LIQUID_CPFSK_SQUARE) +cpfskmod cpfskmod_create(unsigned int _bps, + float _h, + unsigned int _k, + unsigned int _m, + float _beta, + int _type); +//cpfskmod cpfskmod_create_msk(unsigned int _k); +//cpfskmod cpfskmod_create_gmsk(unsigned int _k, float _BT); + +// destroy cpfskmod object +int cpfskmod_destroy(cpfskmod _q); + +// print cpfskmod object internals +int cpfskmod_print(cpfskmod _q); + +// reset state +int cpfskmod_reset(cpfskmod _q); + +// get transmit delay [symbols] +unsigned int cpfskmod_get_delay(cpfskmod _q); + +// modulate sample +// _q : frequency modulator object +// _s : input symbol +// _y : output sample array [size: _k x 1] +int cpfskmod_modulate(cpfskmod _q, + unsigned int _s, + liquid_float_complex * _y); + + + +// CP-FSK demodulator +typedef struct cpfskdem_s * cpfskdem; + +// create cpfskdem object (frequency modulator) +// _bps : bits per symbol, _bps > 0 +// _h : modulation index, _h > 0 +// _k : samples/symbol, _k > 1, _k even +// _m : filter delay (symbols), _m > 0 +// _beta : filter bandwidth parameter, _beta > 0 +// _type : filter type (e.g. LIQUID_CPFSK_SQUARE) +cpfskdem cpfskdem_create(unsigned int _bps, + float _h, + unsigned int _k, + unsigned int _m, + float _beta, + int _type); +//cpfskdem cpfskdem_create_msk(unsigned int _k); +//cpfskdem cpfskdem_create_gmsk(unsigned int _k, float _BT); + +// destroy cpfskdem object +int cpfskdem_destroy(cpfskdem _q); + +// print cpfskdem object internals +int cpfskdem_print(cpfskdem _q); + +// reset state +int cpfskdem_reset(cpfskdem _q); + +// get receive delay [symbols] +unsigned int cpfskdem_get_delay(cpfskdem _q); + +#if 0 +// demodulate array of samples +// _q : continuous-phase frequency demodulator object +// _y : input sample array [size: _n x 1] +// _n : input sample array length +// _s : output symbol array +// _nw : number of output symbols written +int cpfskdem_demodulate(cpfskdem _q, + liquid_float_complex * _y, + unsigned int _n, + unsigned int * _s, + unsigned int * _nw); +#else +// demodulate array of samples, assuming perfect timing +// _q : continuous-phase frequency demodulator object +// _y : input sample array [size: _k x 1] +unsigned int cpfskdem_demodulate(cpfskdem _q, + liquid_float_complex * _y); +#endif + + + +// +// M-ary frequency-shift keying (MFSK) modems +// + +// FSK modulator +typedef struct fskmod_s * fskmod; + +// create fskmod object (frequency modulator) +// _m : bits per symbol, _bps > 0 +// _k : samples/symbol, _k >= 2^_m +// _bandwidth : total signal bandwidth, (0,0.5) +fskmod fskmod_create(unsigned int _m, + unsigned int _k, + float _bandwidth); + +// destroy fskmod object +int fskmod_destroy(fskmod _q); + +// print fskmod object internals +int fskmod_print(fskmod _q); + +// reset state +int fskmod_reset(fskmod _q); + +// modulate sample +// _q : frequency modulator object +// _s : input symbol +// _y : output sample array [size: _k x 1] +int fskmod_modulate(fskmod _q, + unsigned int _s, + liquid_float_complex * _y); + + + +// FSK demodulator +typedef struct fskdem_s * fskdem; + +// create fskdem object (frequency demodulator) +// _m : bits per symbol, _bps > 0 +// _k : samples/symbol, _k >= 2^_m +// _bandwidth : total signal bandwidth, (0,0.5) +fskdem fskdem_create(unsigned int _m, + unsigned int _k, + float _bandwidth); + +// destroy fskdem object +int fskdem_destroy(fskdem _q); + +// print fskdem object internals +int fskdem_print(fskdem _q); + +// reset state +int fskdem_reset(fskdem _q); + +// demodulate symbol, assuming perfect symbol timing +// _q : fskdem object +// _y : input sample array [size: _k x 1] +unsigned int fskdem_demodulate(fskdem _q, + liquid_float_complex * _y); + +// get demodulator frequency error +float fskdem_get_frequency_error(fskdem _q); + +// get energy for a particular symbol within a certain range +float fskdem_get_symbol_energy(fskdem _q, + unsigned int _s, + unsigned int _range); + + +// +// Analog frequency modulator +// +#define LIQUID_FREQMOD_MANGLE_FLOAT(name) LIQUID_CONCAT(freqmod,name) + +// Macro : FREQMOD (analog frequency modulator) +// FREQMOD : name-mangling macro +// T : primitive data type +// TC : primitive data type (complex) +#define LIQUID_FREQMOD_DEFINE_API(FREQMOD,T,TC) \ + \ +/* Analog frequency modulation object */ \ +typedef struct FREQMOD(_s) * FREQMOD(); \ + \ +/* Create freqmod object with a particular modulation factor */ \ +/* _kf : modulation factor */ \ +FREQMOD() FREQMOD(_create)(float _kf); \ + \ +/* Destroy freqmod object, freeing all internal memory */ \ +int FREQMOD(_destroy)(FREQMOD() _q); \ + \ +/* Print freqmod object internals to stdout */ \ +int FREQMOD(_print)(FREQMOD() _q); \ + \ +/* Reset state */ \ +int FREQMOD(_reset)(FREQMOD() _q); \ + \ +/* Modulate single sample, producing single output sample at complex */ \ +/* baseband. */ \ +/* _q : frequency modulator object */ \ +/* _m : message signal \( m(t) \) */ \ +/* _s : complex baseband signal \( s(t) \) */ \ +int FREQMOD(_modulate)(FREQMOD() _q, \ + T _m, \ + TC * _s); \ + \ +/* Modulate block of samples */ \ +/* _q : frequency modulator object */ \ +/* _m : message signal \( m(t) \), [size: _n x 1] */ \ +/* _n : number of input, output samples */ \ +/* _s : complex baseband signal \( s(t) \), [size: _n x 1] */ \ +int FREQMOD(_modulate_block)(FREQMOD() _q, \ + T * _m, \ + unsigned int _n, \ + TC * _s); \ + +// define freqmod APIs +LIQUID_FREQMOD_DEFINE_API(LIQUID_FREQMOD_MANGLE_FLOAT,float,liquid_float_complex) + +// +// Analog frequency demodulator +// + +#define LIQUID_FREQDEM_MANGLE_FLOAT(name) LIQUID_CONCAT(freqdem,name) + +// Macro : FREQDEM (analog frequency modulator) +// FREQDEM : name-mangling macro +// T : primitive data type +// TC : primitive data type (complex) +#define LIQUID_FREQDEM_DEFINE_API(FREQDEM,T,TC) \ +typedef struct FREQDEM(_s) * FREQDEM(); \ + \ +/* create freqdem object (frequency modulator) */ \ +/* _kf : modulation factor */ \ +FREQDEM() FREQDEM(_create)(float _kf); \ + \ +/* destroy freqdem object */ \ +int FREQDEM(_destroy)(FREQDEM() _q); \ + \ +/* print freqdem object internals */ \ +int FREQDEM(_print)(FREQDEM() _q); \ + \ +/* reset state */ \ +int FREQDEM(_reset)(FREQDEM() _q); \ + \ +/* demodulate sample */ \ +/* _q : frequency modulator object */ \ +/* _r : received signal r(t) */ \ +/* _m : output message signal m(t) */ \ +int FREQDEM(_demodulate)(FREQDEM() _q, \ + TC _r, \ + T * _m); \ + \ +/* demodulate block of samples */ \ +/* _q : frequency demodulator object */ \ +/* _r : received signal r(t) [size: _n x 1] */ \ +/* _n : number of input, output samples */ \ +/* _m : message signal m(t), [size: _n x 1] */ \ +int FREQDEM(_demodulate_block)(FREQDEM() _q, \ + TC * _r, \ + unsigned int _n, \ + T * _m); \ + +// define freqdem APIs +LIQUID_FREQDEM_DEFINE_API(LIQUID_FREQDEM_MANGLE_FLOAT,float,liquid_float_complex) + + + +// amplitude modulation types +typedef enum { + LIQUID_AMPMODEM_DSB=0, // double side-band + LIQUID_AMPMODEM_USB, // single side-band (upper) + LIQUID_AMPMODEM_LSB // single side-band (lower) +} liquid_ampmodem_type; + +typedef struct ampmodem_s * ampmodem; + +// create ampmodem object +// _m : modulation index +// _type : AM type (e.g. LIQUID_AMPMODEM_DSB) +// _suppressed_carrier : carrier suppression flag +ampmodem ampmodem_create(float _mod_index, + liquid_ampmodem_type _type, + int _suppressed_carrier); + +// destroy ampmodem object +int ampmodem_destroy(ampmodem _q); + +// print ampmodem object internals +int ampmodem_print(ampmodem _q); + +// reset ampmodem object state +int ampmodem_reset(ampmodem _q); + +// accessor methods +unsigned int ampmodem_get_delay_mod (ampmodem _q); +unsigned int ampmodem_get_delay_demod(ampmodem _q); + +// modulate sample +int ampmodem_modulate(ampmodem _q, + float _x, + liquid_float_complex * _y); + +int ampmodem_modulate_block(ampmodem _q, + float * _m, + unsigned int _n, + liquid_float_complex * _s); + +// demodulate sample +int ampmodem_demodulate(ampmodem _q, + liquid_float_complex _y, + float * _x); + +int ampmodem_demodulate_block(ampmodem _q, + liquid_float_complex * _r, + unsigned int _n, + float * _m); + +// +// MODULE : multichannel +// + + +#define FIRPFBCH_NYQUIST 0 +#define FIRPFBCH_ROOTNYQUIST 1 + +#define LIQUID_ANALYZER 0 +#define LIQUID_SYNTHESIZER 1 + + +// +// Finite impulse response polyphase filterbank channelizer +// + +#define LIQUID_FIRPFBCH_MANGLE_CRCF(name) LIQUID_CONCAT(firpfbch_crcf,name) +#define LIQUID_FIRPFBCH_MANGLE_CCCF(name) LIQUID_CONCAT(firpfbch_cccf,name) + +// Macro: +// FIRPFBCH : name-mangling macro +// TO : output data type +// TC : coefficients data type +// TI : input data type +#define LIQUID_FIRPFBCH_DEFINE_API(FIRPFBCH,TO,TC,TI) \ +typedef struct FIRPFBCH(_s) * FIRPFBCH(); \ + \ +/* create finite impulse response polyphase filter-bank */ \ +/* channelizer object from external coefficients */ \ +/* _type : channelizer type, e.g. LIQUID_ANALYZER */ \ +/* _M : number of channels */ \ +/* _p : number of coefficients for each channel */ \ +/* _h : coefficients [size: _M*_p x 1] */ \ +FIRPFBCH() FIRPFBCH(_create)(int _type, \ + unsigned int _M, \ + unsigned int _p, \ + TC * _h); \ + \ +/* create FIR polyphase filterbank channelizer object with */ \ +/* prototype filter based on windowed Kaiser design */ \ +/* _type : type (LIQUID_ANALYZER | LIQUID_SYNTHESIZER) */ \ +/* _M : number of channels */ \ +/* _m : filter delay (symbols) */ \ +/* _As : stop-band attentuation [dB] */ \ +FIRPFBCH() FIRPFBCH(_create_kaiser)(int _type, \ + unsigned int _M, \ + unsigned int _m, \ + float _As); \ + \ +/* create FIR polyphase filterbank channelizer object with */ \ +/* prototype root-Nyquist filter */ \ +/* _type : type (LIQUID_ANALYZER | LIQUID_SYNTHESIZER) */ \ +/* _M : number of channels */ \ +/* _m : filter delay (symbols) */ \ +/* _beta : filter excess bandwidth factor, in [0,1] */ \ +/* _ftype : filter prototype (rrcos, rkaiser, etc.) */ \ +FIRPFBCH() FIRPFBCH(_create_rnyquist)(int _type, \ + unsigned int _M, \ + unsigned int _m, \ + float _beta, \ + int _ftype); \ + \ +/* destroy firpfbch object */ \ +int FIRPFBCH(_destroy)(FIRPFBCH() _q); \ + \ +/* clear/reset firpfbch internal state */ \ +int FIRPFBCH(_reset)(FIRPFBCH() _q); \ + \ +/* print firpfbch internal parameters to stdout */ \ +int FIRPFBCH(_print)(FIRPFBCH() _q); \ + \ +/* execute filterbank as synthesizer on block of samples */ \ +/* _q : filterbank channelizer object */ \ +/* _x : channelized input, [size: num_channels x 1] */ \ +/* _y : output time series, [size: num_channels x 1] */ \ +int FIRPFBCH(_synthesizer_execute)(FIRPFBCH() _q, \ + TI * _x, \ + TO * _y); \ + \ +/* execute filterbank as analyzer on block of samples */ \ +/* _q : filterbank channelizer object */ \ +/* _x : input time series, [size: num_channels x 1] */ \ +/* _y : channelized output, [size: num_channels x 1] */ \ +int FIRPFBCH(_analyzer_execute)(FIRPFBCH() _q, \ + TI * _x, \ + TO * _y); \ + + +LIQUID_FIRPFBCH_DEFINE_API(LIQUID_FIRPFBCH_MANGLE_CRCF, + liquid_float_complex, + float, + liquid_float_complex) + +LIQUID_FIRPFBCH_DEFINE_API(LIQUID_FIRPFBCH_MANGLE_CCCF, + liquid_float_complex, + liquid_float_complex, + liquid_float_complex) + + +// +// Finite impulse response polyphase filterbank channelizer +// with output rate 2 Fs / M +// + +#define LIQUID_FIRPFBCH2_MANGLE_CRCF(name) LIQUID_CONCAT(firpfbch2_crcf,name) + +// Macro: +// FIRPFBCH2 : name-mangling macro +// TO : output data type +// TC : coefficients data type +// TI : input data type +#define LIQUID_FIRPFBCH2_DEFINE_API(FIRPFBCH2,TO,TC,TI) \ +typedef struct FIRPFBCH2(_s) * FIRPFBCH2(); \ + \ +/* create firpfbch2 object */ \ +/* _type : channelizer type (e.g. LIQUID_ANALYZER) */ \ +/* _M : number of channels (must be even) */ \ +/* _m : prototype filter semi-length, length=2*M*m */ \ +/* _h : prototype filter coefficient array */ \ +FIRPFBCH2() FIRPFBCH2(_create)(int _type, \ + unsigned int _M, \ + unsigned int _m, \ + TC * _h); \ + \ +/* create firpfbch2 object using Kaiser window prototype */ \ +/* _type : channelizer type (e.g. LIQUID_ANALYZER) */ \ +/* _M : number of channels (must be even) */ \ +/* _m : prototype filter semi-length, length=2*M*m+1 */ \ +/* _As : filter stop-band attenuation [dB] */ \ +FIRPFBCH2() FIRPFBCH2(_create_kaiser)(int _type, \ + unsigned int _M, \ + unsigned int _m, \ + float _As); \ + \ +/* destroy firpfbch2 object, freeing internal memory */ \ +int FIRPFBCH2(_destroy)(FIRPFBCH2() _q); \ + \ +/* reset firpfbch2 object internals */ \ +int FIRPFBCH2(_reset)(FIRPFBCH2() _q); \ + \ +/* print firpfbch2 object internals */ \ +int FIRPFBCH2(_print)(FIRPFBCH2() _q); \ + \ +/* execute filterbank channelizer */ \ +/* LIQUID_ANALYZER: input: M/2, output: M */ \ +/* LIQUID_SYNTHESIZER: input: M, output: M/2 */ \ +/* _x : channelizer input */ \ +/* _y : channelizer output */ \ +int FIRPFBCH2(_execute)(FIRPFBCH2() _q, \ + TI * _x, \ + TO * _y); \ + + +LIQUID_FIRPFBCH2_DEFINE_API(LIQUID_FIRPFBCH2_MANGLE_CRCF, + liquid_float_complex, + float, + liquid_float_complex) + +// +// Finite impulse response polyphase filterbank channelizer +// with output rate Fs * P / M +// + +#define LIQUID_FIRPFBCHR_MANGLE_CRCF(name) LIQUID_CONCAT(firpfbchr_crcf,name) + +#define LIQUID_FIRPFBCHR_DEFINE_API(FIRPFBCHR,TO,TC,TI) \ +typedef struct FIRPFBCHR(_s) * FIRPFBCHR(); \ + \ +/* create rational rate resampling channelizer (firpfbchr) object by */ \ +/* specifying filter coefficients directly */ \ +/* _M : number of output channels in chanelizer */ \ +/* _P : output decimation factor (output rate is 1/P the input) */ \ +/* _m : prototype filter semi-length, length=2*M*m */ \ +/* _h : prototype filter coefficient array, [size: 2*M*m x 1] */ \ +FIRPFBCHR() FIRPFBCHR(_create)(unsigned int _M, \ + unsigned int _P, \ + unsigned int _m, \ + TC * _h); \ + \ +/* create rational rate resampling channelizer (firpfbchr) object by */ \ +/* specifying filter design parameters for Kaiser prototype */ \ +/* _M : number of output channels in chanelizer */ \ +/* _P : output decimation factor (output rate is 1/P the input) */ \ +/* _m : prototype filter semi-length, length=2*M*m */ \ +/* _As : filter stop-band attenuation [dB] */ \ +FIRPFBCHR() FIRPFBCHR(_create_kaiser)(unsigned int _M, \ + unsigned int _P, \ + unsigned int _m, \ + float _As); \ + \ +/* destroy firpfbchr object, freeing internal memory */ \ +int FIRPFBCHR(_destroy)(FIRPFBCHR() _q); \ + \ +/* reset firpfbchr object internal state and buffers */ \ +int FIRPFBCHR(_reset)(FIRPFBCHR() _q); \ + \ +/* print firpfbchr object internals to stdout */ \ +int FIRPFBCHR(_print)(FIRPFBCHR() _q); \ + \ +/* get number of output channels to channelizer */ \ +unsigned int FIRPFBCHR(_get_M)(FIRPFBCHR() _q); \ + \ +/* get decimation factor for channelizer */ \ +unsigned int FIRPFBCHR(_get_P)(FIRPFBCHR() _q); \ + \ +/* get semi-length to channelizer filter prototype */ \ +unsigned int FIRPFBCHR(_get_m)(FIRPFBCHR() _q); \ + \ +/* push buffer of samples into filter bank */ \ +/* _q : channelizer object */ \ +/* _x : channelizer input [size: P x 1] */ \ +int FIRPFBCHR(_push)(FIRPFBCHR() _q, \ + TI * _x); \ + \ +/* execute filterbank channelizer, writing complex baseband samples for */ \ +/* each channel into output array */ \ +/* _q : channelizer object */ \ +/* _y : channelizer output [size: _M x 1] */ \ +int FIRPFBCHR(_execute)(FIRPFBCHR() _q, \ + TO * _y); \ + + +LIQUID_FIRPFBCHR_DEFINE_API(LIQUID_FIRPFBCHR_MANGLE_CRCF, + liquid_float_complex, + float, + liquid_float_complex) + + + +#define OFDMFRAME_SCTYPE_NULL 0 +#define OFDMFRAME_SCTYPE_PILOT 1 +#define OFDMFRAME_SCTYPE_DATA 2 + +// initialize default subcarrier allocation +// _M : number of subcarriers +// _p : output subcarrier allocation array, [size: _M x 1] +int ofdmframe_init_default_sctype(unsigned int _M, + unsigned char * _p); + +// initialize default subcarrier allocation +// _M : number of subcarriers +// _f0 : lower frequency band, _f0 in [-0.5,0.5] +// _f1 : upper frequency band, _f1 in [-0.5,0.5] +// _p : output subcarrier allocation array, [size: _M x 1] +int ofdmframe_init_sctype_range(unsigned int _M, + float _f0, + float _f1, + unsigned char * _p); + +// validate subcarrier type (count number of null, pilot, and data +// subcarriers in the allocation) +// _p : subcarrier allocation array, [size: _M x 1] +// _M : number of subcarriers +// _M_null : output number of null subcarriers +// _M_pilot : output number of pilot subcarriers +// _M_data : output number of data subcarriers +int ofdmframe_validate_sctype(unsigned char * _p, + unsigned int _M, + unsigned int * _M_null, + unsigned int * _M_pilot, + unsigned int * _M_data); + +// print subcarrier allocation to screen +// _p : output subcarrier allocation array, [size: _M x 1] +// _M : number of subcarriers +int ofdmframe_print_sctype(unsigned char * _p, + unsigned int _M); + + +// +// OFDM frame (symbol) generator +// +typedef struct ofdmframegen_s * ofdmframegen; + +// create OFDM framing generator object +// _M : number of subcarriers, >10 typical +// _cp_len : cyclic prefix length +// _taper_len : taper length (OFDM symbol overlap) +// _p : subcarrier allocation (null, pilot, data), [size: _M x 1] +ofdmframegen ofdmframegen_create(unsigned int _M, + unsigned int _cp_len, + unsigned int _taper_len, + unsigned char * _p); + +int ofdmframegen_destroy(ofdmframegen _q); + +int ofdmframegen_print(ofdmframegen _q); + +int ofdmframegen_reset(ofdmframegen _q); + +// write first S0 symbol +int ofdmframegen_write_S0a(ofdmframegen _q, + liquid_float_complex *_y); + +// write second S0 symbol +int ofdmframegen_write_S0b(ofdmframegen _q, + liquid_float_complex *_y); + +// write S1 symbol +int ofdmframegen_write_S1(ofdmframegen _q, + liquid_float_complex *_y); + +// write data symbol +int ofdmframegen_writesymbol(ofdmframegen _q, + liquid_float_complex * _x, + liquid_float_complex *_y); + +// write tail +int ofdmframegen_writetail(ofdmframegen _q, + liquid_float_complex * _x); + +// +// OFDM frame (symbol) synchronizer +// +typedef int (*ofdmframesync_callback)(liquid_float_complex * _y, + unsigned char * _p, + unsigned int _M, + void * _userdata); +typedef struct ofdmframesync_s * ofdmframesync; + +// create OFDM framing synchronizer object +// _M : number of subcarriers, >10 typical +// _cp_len : cyclic prefix length +// _taper_len : taper length (OFDM symbol overlap) +// _p : subcarrier allocation (null, pilot, data), [size: _M x 1] +// _callback : user-defined callback function +// _userdata : user-defined data pointer +ofdmframesync ofdmframesync_create(unsigned int _M, + unsigned int _cp_len, + unsigned int _taper_len, + unsigned char * _p, + ofdmframesync_callback _callback, + void * _userdata); +int ofdmframesync_destroy(ofdmframesync _q); +int ofdmframesync_print(ofdmframesync _q); +int ofdmframesync_reset(ofdmframesync _q); +int ofdmframesync_is_frame_open(ofdmframesync _q); +int ofdmframesync_execute(ofdmframesync _q, + liquid_float_complex * _x, + unsigned int _n); + +// query methods +float ofdmframesync_get_rssi(ofdmframesync _q); // received signal strength indication +float ofdmframesync_get_cfo(ofdmframesync _q); // carrier offset estimate + +// set methods +int ofdmframesync_set_cfo(ofdmframesync _q, float _cfo); // set carrier offset estimate + +// debugging +int ofdmframesync_debug_enable(ofdmframesync _q); +int ofdmframesync_debug_disable(ofdmframesync _q); +int ofdmframesync_debug_print(ofdmframesync _q, const char * _filename); + + +// +// MODULE : nco (numerically-controlled oscillator) +// + +// oscillator type +// LIQUID_NCO : numerically-controlled oscillator (fast) +// LIQUID_VCO : "voltage"-controlled oscillator (precise) +typedef enum { + LIQUID_NCO=0, + LIQUID_VCO +} liquid_ncotype; + +#define LIQUID_NCO_MANGLE_FLOAT(name) LIQUID_CONCAT(nco_crcf, name) + +// large macro +// NCO : name-mangling macro +// T : primitive data type +// TC : input/output data type +#define LIQUID_NCO_DEFINE_API(NCO,T,TC) \ + \ +/* Numerically-controlled oscillator object */ \ +typedef struct NCO(_s) * NCO(); \ + \ +/* Create nco object with either fixed-point or floating-point phase */ \ +/* _type : oscillator type, _type in {LIQUID_NCO, LIQUID_VCO} */ \ +NCO() NCO(_create)(liquid_ncotype _type); \ + \ +/* Destroy nco object, freeing all internally allocated memory */ \ +int NCO(_destroy)(NCO() _q); \ + \ +/* Print nco object internals to stdout */ \ +int NCO(_print)(NCO() _q); \ + \ +/* Set phase/frequency to zero and reset the phase-locked loop filter */ \ +/* state */ \ +int NCO(_reset)(NCO() _q); \ + \ +/* Get frequency of nco object in radians per sample */ \ +T NCO(_get_frequency)(NCO() _q); \ + \ +/* Set frequency of nco object in radians per sample */ \ +/* _q : nco object */ \ +/* _dtheta : input frequency [radians/sample] */ \ +int NCO(_set_frequency)(NCO() _q, \ + T _dtheta); \ + \ +/* Adjust frequency of nco object by a step size in radians per sample */ \ +/* _q : nco object */ \ +/* _step : input frequency step [radians/sample] */ \ +int NCO(_adjust_frequency)(NCO() _q, \ + T _step); \ + \ +/* Get phase of nco object in radians */ \ +T NCO(_get_phase)(NCO() _q); \ + \ +/* Set phase of nco object in radians */ \ +/* _q : nco object */ \ +/* _phi : input phase of nco object [radians] */ \ +int NCO(_set_phase)(NCO() _q, \ + T _phi); \ + \ +/* Adjust phase of nco object by a step of \(\Delta \phi\) radians */ \ +/* _q : nco object */ \ +/* _dphi : input nco object phase adjustment [radians] */ \ +int NCO(_adjust_phase)(NCO() _q, \ + T _dphi); \ + \ +/* Increment phase by internal phase step (frequency) */ \ +int NCO(_step)(NCO() _q); \ + \ +/* Compute sine output given internal phase */ \ +T NCO(_sin)(NCO() _q); \ + \ +/* Compute cosine output given internal phase */ \ +T NCO(_cos)(NCO() _q); \ + \ +/* Compute sine and cosine outputs given internal phase */ \ +/* _q : nco object */ \ +/* _s : output sine component of phase */ \ +/* _c : output cosine component of phase */ \ +int NCO(_sincos)(NCO() _q, \ + T * _s, \ + T * _c); \ + \ +/* Compute complex exponential output given internal phase */ \ +/* _q : nco object */ \ +/* _y : output complex exponential */ \ +int NCO(_cexpf)(NCO() _q, \ + TC * _y); \ + \ +/* Set bandwidth of internal phase-locked loop */ \ +/* _q : nco object */ \ +/* _bw : input phase-locked loop bandwidth, _bw >= 0 */ \ +int NCO(_pll_set_bandwidth)(NCO() _q, \ + T _bw); \ + \ +/* Step internal phase-locked loop given input phase error, adjusting */ \ +/* internal phase and frequency proportional to coefficients defined by */ \ +/* internal PLL bandwidth */ \ +/* _q : nco object */ \ +/* _dphi : input phase-locked loop phase error */ \ +int NCO(_pll_step)(NCO() _q, \ + T _dphi); \ + \ +/* Rotate input sample up by nco angle. */ \ +/* Note that this does not adjust the internal phase or frequency. */ \ +/* _q : nco object */ \ +/* _x : input complex sample */ \ +/* _y : pointer to output sample location */ \ +int NCO(_mix_up)(NCO() _q, \ + TC _x, \ + TC * _y); \ + \ +/* Rotate input sample down by nco angle. */ \ +/* Note that this does not adjust the internal phase or frequency. */ \ +/* _q : nco object */ \ +/* _x : input complex sample */ \ +/* _y : pointer to output sample location */ \ +int NCO(_mix_down)(NCO() _q, \ + TC _x, \ + TC * _y); \ + \ +/* Rotate input vector up by NCO angle (stepping) */ \ +/* Note that this *does* adjust the internal phase as the signal steps */ \ +/* through each input sample. */ \ +/* _q : nco object */ \ +/* _x : array of input samples, [size: _n x 1] */ \ +/* _y : array of output samples, [size: _n x 1] */ \ +/* _n : number of input (and output) samples */ \ +int NCO(_mix_block_up)(NCO() _q, \ + TC * _x, \ + TC * _y, \ + unsigned int _n); \ + \ +/* Rotate input vector down by NCO angle (stepping) */ \ +/* Note that this *does* adjust the internal phase as the signal steps */ \ +/* through each input sample. */ \ +/* _q : nco object */ \ +/* _x : array of input samples, [size: _n x 1] */ \ +/* _y : array of output samples, [size: _n x 1] */ \ +/* _n : number of input (and output) samples */ \ +int NCO(_mix_block_down)(NCO() _q, \ + TC * _x, \ + TC * _y, \ + unsigned int _n); \ + +// Define nco APIs +LIQUID_NCO_DEFINE_API(LIQUID_NCO_MANGLE_FLOAT, float, liquid_float_complex) + + +// nco utilities + +// unwrap phase of array (basic) +void liquid_unwrap_phase(float * _theta, unsigned int _n); + +// unwrap phase of array (advanced) +void liquid_unwrap_phase2(float * _theta, unsigned int _n); + +#define SYNTH_MANGLE_FLOAT(name) LIQUID_CONCAT(synth_crcf, name) + +// large macro +// SYNTH : name-mangling macro +// T : primitive data type +// TC : input/output data type +#define LIQUID_SYNTH_DEFINE_API(SYNTH,T,TC) \ +typedef struct SYNTH(_s) * SYNTH(); \ + \ +SYNTH() SYNTH(_create)(const TC *_table, unsigned int _length); \ +void SYNTH(_destroy)(SYNTH() _q); \ + \ +void SYNTH(_reset)(SYNTH() _q); \ + \ +/* get/set/adjust internal frequency/phase */ \ +T SYNTH(_get_frequency)( SYNTH() _q); \ +void SYNTH(_set_frequency)( SYNTH() _q, T _f); \ +void SYNTH(_adjust_frequency)(SYNTH() _q, T _df); \ +T SYNTH(_get_phase)( SYNTH() _q); \ +void SYNTH(_set_phase)( SYNTH() _q, T _phi); \ +void SYNTH(_adjust_phase)( SYNTH() _q, T _dphi); \ + \ +unsigned int SYNTH(_get_length)(SYNTH() _q); \ +TC SYNTH(_get_current)(SYNTH() _q); \ +TC SYNTH(_get_half_previous)(SYNTH() _q); \ +TC SYNTH(_get_half_next)(SYNTH() _q); \ + \ +void SYNTH(_step)(SYNTH() _q); \ + \ +/* pll : phase-locked loop */ \ +void SYNTH(_pll_set_bandwidth)(SYNTH() _q, T _bandwidth); \ +void SYNTH(_pll_step)(SYNTH() _q, T _dphi); \ + \ +/* Rotate input sample up by SYNTH angle (no stepping) */ \ +void SYNTH(_mix_up)(SYNTH() _q, TC _x, TC *_y); \ + \ +/* Rotate input sample down by SYNTH angle (no stepping) */ \ +void SYNTH(_mix_down)(SYNTH() _q, TC _x, TC *_y); \ + \ +/* Rotate input vector up by SYNTH angle (stepping) */ \ +void SYNTH(_mix_block_up)(SYNTH() _q, \ + TC *_x, \ + TC *_y, \ + unsigned int _N); \ + \ +/* Rotate input vector down by SYNTH angle (stepping) */ \ +void SYNTH(_mix_block_down)(SYNTH() _q, \ + TC *_x, \ + TC *_y, \ + unsigned int _N); \ + \ +void SYNTH(_spread)(SYNTH() _q, \ + TC _x, \ + TC *_y); \ + \ +void SYNTH(_despread)(SYNTH() _q, \ + TC *_x, \ + TC *_y); \ + \ +void SYNTH(_despread_triple)(SYNTH() _q, \ + TC *_x, \ + TC *_early, \ + TC *_punctual, \ + TC *_late); \ + +// Define synth APIs +LIQUID_SYNTH_DEFINE_API(SYNTH_MANGLE_FLOAT, float, liquid_float_complex) + + + +// +// MODULE : optimization +// + +// utility function pointer definition +typedef float (*utility_function)(void * _userdata, + float * _v, + unsigned int _n); + +// n-dimensional Rosenbrock utility function (minimum at _v = {1,1,1...} +// _userdata : user-defined data structure (convenience) +// _v : input vector [size: _n x 1] +// _n : input vector size +float liquid_rosenbrock(void * _userdata, + float * _v, + unsigned int _n); + +// n-dimensional inverse Gauss utility function (minimum at _v = {0,0,0...} +// _userdata : user-defined data structure (convenience) +// _v : input vector [size: _n x 1] +// _n : input vector size +float liquid_invgauss(void * _userdata, + float * _v, + unsigned int _n); + +// n-dimensional multimodal utility function (minimum at _v = {0,0,0...} +// _userdata : user-defined data structure (convenience) +// _v : input vector [size: _n x 1] +// _n : input vector size +float liquid_multimodal(void * _userdata, + float * _v, + unsigned int _n); + +// n-dimensional spiral utility function (minimum at _v = {0,0,0...} +// _userdata : user-defined data structure (convenience) +// _v : input vector [size: _n x 1] +// _n : input vector size +float liquid_spiral(void * _userdata, + float * _v, + unsigned int _n); + + +// +// Gradient search +// + +#define LIQUID_OPTIM_MINIMIZE (0) +#define LIQUID_OPTIM_MAXIMIZE (1) + +typedef struct gradsearch_s * gradsearch; + +// Create a gradient search object +// _userdata : user data object pointer +// _v : array of parameters to optimize +// _num_parameters : array length (number of parameters to optimize) +// _u : utility function pointer +// _direction : search direction (e.g. LIQUID_OPTIM_MAXIMIZE) +gradsearch gradsearch_create(void * _userdata, + float * _v, + unsigned int _num_parameters, + utility_function _utility, + int _direction); + +// Destroy a gradsearch object +void gradsearch_destroy(gradsearch _q); + +// Prints current status of search +void gradsearch_print(gradsearch _q); + +// Iterate once +float gradsearch_step(gradsearch _q); + +// Execute the search +float gradsearch_execute(gradsearch _q, + unsigned int _max_iterations, + float _target_utility); + + +// quasi-Newton search +typedef struct qnsearch_s * qnsearch; + +// Create a simple qnsearch object; parameters are specified internally +// _userdata : userdata +// _v : array of parameters to optimize +// _num_parameters : array length +// _get_utility : utility function pointer +// _direction : search direction (e.g. LIQUID_OPTIM_MAXIMIZE) +qnsearch qnsearch_create(void * _userdata, + float * _v, + unsigned int _num_parameters, + utility_function _u, + int _direction); + +// Destroy a qnsearch object +int qnsearch_destroy(qnsearch _g); + +// Prints current status of search +int qnsearch_print(qnsearch _g); + +// Resets internal state +int qnsearch_reset(qnsearch _g); + +// Iterate once +int qnsearch_step(qnsearch _g); + +// Execute the search +float qnsearch_execute(qnsearch _g, + unsigned int _max_iterations, + float _target_utility); + +// +// chromosome (for genetic algorithm search) +// +typedef struct chromosome_s * chromosome; + +// create a chromosome object, variable bits/trait +chromosome chromosome_create(unsigned int * _bits_per_trait, + unsigned int _num_traits); + +// create a chromosome object, all traits same resolution +chromosome chromosome_create_basic(unsigned int _num_traits, + unsigned int _bits_per_trait); + +// create a chromosome object, cloning a parent +chromosome chromosome_create_clone(chromosome _parent); + +// copy existing chromosomes' internal traits (all other internal +// parameters must be equal) +int chromosome_copy(chromosome _parent, chromosome _child); + +// Destroy a chromosome object +int chromosome_destroy(chromosome _c); + +// get number of traits in chromosome +unsigned int chromosome_get_num_traits(chromosome _c); + +// Print chromosome values to screen (binary representation) +int chromosome_print(chromosome _c); + +// Print chromosome values to screen (floating-point representation) +int chromosome_printf(chromosome _c); + +// clear chromosome (set traits to zero) +int chromosome_reset(chromosome _c); + +// initialize chromosome on integer values +int chromosome_init(chromosome _c, + unsigned int * _v); + +// initialize chromosome on floating-point values +int chromosome_initf(chromosome _c, float * _v); + +// Mutates chromosome _c at _index +int chromosome_mutate(chromosome _c, unsigned int _index); + +// Resulting chromosome _c is a crossover of parents _p1 and _p2 at _threshold +int chromosome_crossover(chromosome _p1, + chromosome _p2, + chromosome _c, + unsigned int _threshold); + +// Initializes chromosome to random value +int chromosome_init_random(chromosome _c); + +// Returns integer representation of chromosome +unsigned int chromosome_value(chromosome _c, + unsigned int _index); + +// Returns floating-point representation of chromosome +float chromosome_valuef(chromosome _c, + unsigned int _index); + +// +// genetic algorithm search +// +typedef struct gasearch_s * gasearch; + +typedef float (*gasearch_utility)(void * _userdata, chromosome _c); + +// Create a simple gasearch object; parameters are specified internally +// _utility : chromosome fitness utility function +// _userdata : user data, void pointer passed to _get_utility() callback +// _parent : initial population parent chromosome, governs precision, etc. +// _minmax : search direction +gasearch gasearch_create(gasearch_utility _u, + void * _userdata, + chromosome _parent, + int _minmax); + +// Create a gasearch object, specifying search parameters +// _utility : chromosome fitness utility function +// _userdata : user data, void pointer passed to _get_utility() callback +// _parent : initial population parent chromosome, governs precision, etc. +// _minmax : search direction +// _population_size : number of chromosomes in population +// _mutation_rate : probability of mutating chromosomes +gasearch gasearch_create_advanced(gasearch_utility _utility, + void * _userdata, + chromosome _parent, + int _minmax, + unsigned int _population_size, + float _mutation_rate); + + +// Destroy a gasearch object +int gasearch_destroy(gasearch _q); + +// print search parameter internals +int gasearch_print(gasearch _q); + +// set mutation rate +int gasearch_set_mutation_rate(gasearch _q, + float _mutation_rate); + +// set population/selection size +// _q : ga search object +// _population_size : new population size (number of chromosomes) +// _selection_size : selection size (number of parents for new generation) +int gasearch_set_population_size(gasearch _q, + unsigned int _population_size, + unsigned int _selection_size); + +// Execute the search +// _q : ga search object +// _max_iterations : maximum number of iterations to run before bailing +// _target_utility : target utility +float gasearch_run(gasearch _q, + unsigned int _max_iterations, + float _target_utility); + +// iterate over one evolution of the search algorithm +int gasearch_evolve(gasearch _q); + +// get optimal chromosome +// _q : ga search object +// _c : output optimal chromosome +// _utility_opt : fitness of _c +int gasearch_getopt(gasearch _q, + chromosome _c, + float * _utility_opt); + +// +// MODULE : quantization +// + +float compress_mulaw(float _x, float _mu); +float expand_mulaw(float _x, float _mu); + +int compress_cf_mulaw(liquid_float_complex _x, float _mu, liquid_float_complex * _y); +int expand_cf_mulaw(liquid_float_complex _y, float _mu, liquid_float_complex * _x); + +//float compress_alaw(float _x, float _a); +//float expand_alaw(float _x, float _a); + +// inline quantizer: 'analog' signal in [-1, 1] +unsigned int quantize_adc(float _x, unsigned int _num_bits); +float quantize_dac(unsigned int _s, unsigned int _num_bits); + +// structured quantizer + +typedef enum { + LIQUID_COMPANDER_NONE=0, + LIQUID_COMPANDER_LINEAR, + LIQUID_COMPANDER_MULAW, + LIQUID_COMPANDER_ALAW +} liquid_compander_type; + +#define LIQUID_QUANTIZER_MANGLE_FLOAT(name) LIQUID_CONCAT(quantizerf, name) +#define LIQUID_QUANTIZER_MANGLE_CFLOAT(name) LIQUID_CONCAT(quantizercf, name) + +// large macro +// QUANTIZER : name-mangling macro +// T : data type +#define LIQUID_QUANTIZER_DEFINE_API(QUANTIZER,T) \ + \ +/* Amplitude quantization object */ \ +typedef struct QUANTIZER(_s) * QUANTIZER(); \ + \ +/* Create quantizer object given compander type, input range, and the */ \ +/* number of bits to represent the output */ \ +/* _ctype : compander type (linear, mulaw, alaw) */ \ +/* _range : maximum abosolute input range (ignored for now) */ \ +/* _num_bits : number of bits per sample */ \ +QUANTIZER() QUANTIZER(_create)(liquid_compander_type _ctype, \ + float _range, \ + unsigned int _num_bits); \ + \ +/* Destroy object, freeing all internally-allocated memory. */ \ +int QUANTIZER(_destroy)(QUANTIZER() _q); \ + \ +/* Print object properties to stdout, including compander type and */ \ +/* number of bits per sample */ \ +int QUANTIZER(_print)(QUANTIZER() _q); \ + \ +/* Execute quantizer as analog-to-digital converter, accepting input */ \ +/* sample and returning digitized output bits */ \ +/* _q : quantizer object */ \ +/* _x : input sample */ \ +/* _s : output bits */ \ +int QUANTIZER(_execute_adc)(QUANTIZER() _q, \ + T _x, \ + unsigned int * _s); \ + \ +/* Execute quantizer as digital-to-analog converter, accepting input */ \ +/* bits and returning representation of original input sample */ \ +/* _q : quantizer object */ \ +/* _s : input bits */ \ +/* _x : output sample */ \ +int QUANTIZER(_execute_dac)(QUANTIZER() _q, \ + unsigned int _s, \ + T * _x); \ + +LIQUID_QUANTIZER_DEFINE_API(LIQUID_QUANTIZER_MANGLE_FLOAT, float) +LIQUID_QUANTIZER_DEFINE_API(LIQUID_QUANTIZER_MANGLE_CFLOAT, liquid_float_complex) + + +// +// MODULE : random (number generators) +// + + +// Uniform random number generator, [0,1) +float randf(); +float randf_pdf(float _x); +float randf_cdf(float _x); + +// Uniform random number generator with arbitrary bounds, [a,b) +float randuf(float _a, float _b); +float randuf_pdf(float _x, float _a, float _b); +float randuf_cdf(float _x, float _a, float _b); + +// Gauss random number generator, N(0,1) +// f(x) = 1/sqrt(2*pi*sigma^2) * exp{-(x-eta)^2/(2*sigma^2)} +// +// where +// eta = mean +// sigma = standard deviation +// +float randnf(); +void awgn(float *_x, float _nstd); +void crandnf(liquid_float_complex *_y); +void cawgn(liquid_float_complex *_x, float _nstd); +float randnf_pdf(float _x, float _eta, float _sig); +float randnf_cdf(float _x, float _eta, float _sig); + +// Exponential +// f(x) = lambda exp{ -lambda x } +// where +// lambda = spread parameter, lambda > 0 +// x >= 0 +float randexpf(float _lambda); +float randexpf_pdf(float _x, float _lambda); +float randexpf_cdf(float _x, float _lambda); + +// Weibull +// f(x) = (a/b) (x/b)^(a-1) exp{ -(x/b)^a } +// where +// a = alpha : shape parameter +// b = beta : scaling parameter +// g = gamma : location (threshold) parameter +// +float randweibf(float _alpha, float _beta, float _gamma); +float randweibf_pdf(float _x, float _a, float _b, float _g); +float randweibf_cdf(float _x, float _a, float _b, float _g); + +// Gamma +// x^(a-1) exp(-x/b) +// f(x) = ------------------- +// Gamma(a) b^a +// where +// a = alpha : shape parameter, a > 0 +// b = beta : scale parameter, b > 0 +// Gamma(z) = regular gamma function +// x >= 0 +float randgammaf(float _alpha, float _beta); +float randgammaf_pdf(float _x, float _alpha, float _beta); +float randgammaf_cdf(float _x, float _alpha, float _beta); + +// Nakagami-m +// f(x) = (2/Gamma(m)) (m/omega)^m x^(2m-1) exp{-(m/omega)x^2} +// where +// m : shape parameter, m >= 0.5 +// omega : spread parameter, omega > 0 +// Gamma(z): regular complete gamma function +// x >= 0 +float randnakmf(float _m, float _omega); +float randnakmf_pdf(float _x, float _m, float _omega); +float randnakmf_cdf(float _x, float _m, float _omega); + +// Rice-K +// f(x) = (x/sigma^2) exp{ -(x^2+s^2)/(2sigma^2) } I0( x s / sigma^2 ) +// where +// s = sqrt( omega*K/(K+1) ) +// sigma = sqrt(0.5 omega/(K+1)) +// and +// K = shape parameter +// omega = spread parameter +// I0 = modified Bessel function of the first kind +// x >= 0 +float randricekf(float _K, float _omega); +float randricekf_cdf(float _x, float _K, float _omega); +float randricekf_pdf(float _x, float _K, float _omega); + + +// Data scrambler : whiten data sequence +void scramble_data(unsigned char * _x, unsigned int _len); +void unscramble_data(unsigned char * _x, unsigned int _len); +void unscramble_data_soft(unsigned char * _x, unsigned int _len); + +// +// MODULE : sequence +// + +// Binary sequence (generic) + +typedef struct bsequence_s * bsequence; + +// Create a binary sequence of a specific length (number of bits) +bsequence bsequence_create(unsigned int num_bits); + +// Free memory in a binary sequence +int bsequence_destroy(bsequence _bs); + +// Clear binary sequence (set to 0's) +int bsequence_reset(bsequence _bs); + +// initialize sequence on external array +int bsequence_init(bsequence _bs, + unsigned char * _v); + +// Print sequence to the screen +int bsequence_print(bsequence _bs); + +// Push bit into to back of a binary sequence +int bsequence_push(bsequence _bs, + unsigned int _bit); + +// circular shift (left) +int bsequence_circshift(bsequence _bs); + +// Correlate two binary sequences together +int bsequence_correlate(bsequence _bs1, bsequence _bs2); + +// compute the binary addition of two bit sequences +int bsequence_add(bsequence _bs1, bsequence _bs2, bsequence _bs3); + +// compute the binary multiplication of two bit sequences +int bsequence_mul(bsequence _bs1, bsequence _bs2, bsequence _bs3); + +// accumulate the 1's in a binary sequence +unsigned int bsequence_accumulate(bsequence _bs); + +// accessor functions +unsigned int bsequence_get_length(bsequence _bs); +unsigned int bsequence_index(bsequence _bs, unsigned int _i); + +// Complementary codes + +// intialize two sequences to complementary codes. sequences must +// be of length at least 8 and a power of 2 (e.g. 8, 16, 32, 64,...) +// _a : sequence 'a' (bsequence object) +// _b : sequence 'b' (bsequence object) +int bsequence_create_ccodes(bsequence _a, bsequence _b); + + +// M-Sequence + +#define LIQUID_MAX_MSEQUENCE_LENGTH 32767 + +// default m-sequence generators: g (hex) m n g (oct) g (binary) +#define LIQUID_MSEQUENCE_GENPOLY_M2 0x0007 // 2 3 7 111 +#define LIQUID_MSEQUENCE_GENPOLY_M3 0x000B // 3 7 13 1011 +#define LIQUID_MSEQUENCE_GENPOLY_M4 0x0013 // 4 15 23 10011 +#define LIQUID_MSEQUENCE_GENPOLY_M5 0x0025 // 5 31 45 100101 +#define LIQUID_MSEQUENCE_GENPOLY_M6 0x0043 // 6 63 103 1000011 +#define LIQUID_MSEQUENCE_GENPOLY_M7 0x0089 // 7 127 211 10001001 +#define LIQUID_MSEQUENCE_GENPOLY_M8 0x011D // 8 255 435 100101101 +#define LIQUID_MSEQUENCE_GENPOLY_M9 0x0211 // 9 511 1021 1000010001 +#define LIQUID_MSEQUENCE_GENPOLY_M10 0x0409 // 10 1023 2011 10000001001 +#define LIQUID_MSEQUENCE_GENPOLY_M11 0x0805 // 11 2047 4005 100000000101 +#define LIQUID_MSEQUENCE_GENPOLY_M12 0x1053 // 12 4095 10123 1000001010011 +#define LIQUID_MSEQUENCE_GENPOLY_M13 0x201b // 13 8191 20033 10000000011011 +#define LIQUID_MSEQUENCE_GENPOLY_M14 0x402b // 14 16383 40053 100000000101011 +#define LIQUID_MSEQUENCE_GENPOLY_M15 0x8003 // 15 32767 100003 1000000000000011 + +typedef struct msequence_s * msequence; + +// create a maximal-length sequence (m-sequence) object with +// an internal shift register length of _m bits. +// _m : generator polynomial length, sequence length is (2^m)-1 +// _g : generator polynomial, starting with most-significant bit +// _a : initial shift register state, default: 000...001 +msequence msequence_create(unsigned int _m, + unsigned int _g, + unsigned int _a); + +// create a maximal-length sequence (m-sequence) object from a generator polynomial +msequence msequence_create_genpoly(unsigned int _g); + +// creates a default maximal-length sequence +msequence msequence_create_default(unsigned int _m); + +// destroy an msequence object, freeing all internal memory +int msequence_destroy(msequence _m); + +// prints the sequence's internal state to the screen +int msequence_print(msequence _m); + +// advance msequence on shift register, returning output bit +unsigned int msequence_advance(msequence _ms); + +// generate pseudo-random symbol from shift register by +// advancing _bps bits and returning compacted symbol +// _ms : m-sequence object +// _bps : bits per symbol of output +unsigned int msequence_generate_symbol(msequence _ms, + unsigned int _bps); + +// reset msequence shift register to original state, typically '1' +int msequence_reset(msequence _ms); + +// initialize a bsequence object on an msequence object +// _bs : bsequence object +// _ms : msequence object +int bsequence_init_msequence(bsequence _bs, + msequence _ms); + +// get the length of the sequence +unsigned int msequence_get_length(msequence _ms); + +// get the internal state of the sequence +unsigned int msequence_get_state(msequence _ms); + +// set the internal state of the sequence +int msequence_set_state(msequence _ms, + unsigned int _a); + + +// +// MODULE : utility +// + +// pack binary array with symbol(s) +// _src : source array [size: _n x 1] +// _n : input source array length +// _k : bit index to write in _src +// _b : number of bits in input symbol +// _sym_in : input symbol +int liquid_pack_array(unsigned char * _src, + unsigned int _n, + unsigned int _k, + unsigned int _b, + unsigned char _sym_in); + +// unpack symbols from binary array +// _src : source array [size: _n x 1] +// _n : input source array length +// _k : bit index to write in _src +// _b : number of bits in output symbol +// _sym_out : output symbol +int liquid_unpack_array(unsigned char * _src, + unsigned int _n, + unsigned int _k, + unsigned int _b, + unsigned char * _sym_out); + +// pack one-bit symbols into bytes (8-bit symbols) +// _sym_in : input symbols array [size: _sym_in_len x 1] +// _sym_in_len : number of input symbols +// _sym_out : output symbols +// _sym_out_len : number of bytes allocated to output symbols array +// _num_written : number of output symbols actually written +int liquid_pack_bytes(unsigned char * _sym_in, + unsigned int _sym_in_len, + unsigned char * _sym_out, + unsigned int _sym_out_len, + unsigned int * _num_written); + +// unpack 8-bit symbols (full bytes) into one-bit symbols +// _sym_in : input symbols array [size: _sym_in_len x 1] +// _sym_in_len : number of input symbols +// _sym_out : output symbols array +// _sym_out_len : number of bytes allocated to output symbols array +// _num_written : number of output symbols actually written +int liquid_unpack_bytes(unsigned char * _sym_in, + unsigned int _sym_in_len, + unsigned char * _sym_out, + unsigned int _sym_out_len, + unsigned int * _num_written); + +// repack bytes with arbitrary symbol sizes +// _sym_in : input symbols array [size: _sym_in_len x 1] +// _sym_in_bps : number of bits per input symbol +// _sym_in_len : number of input symbols +// _sym_out : output symbols array +// _sym_out_bps : number of bits per output symbol +// _sym_out_len : number of bytes allocated to output symbols array +// _num_written : number of output symbols actually written +int liquid_repack_bytes(unsigned char * _sym_in, + unsigned int _sym_in_bps, + unsigned int _sym_in_len, + unsigned char * _sym_out, + unsigned int _sym_out_bps, + unsigned int _sym_out_len, + unsigned int * _num_written); + +// shift array to the left _b bits, filling in zeros +// _src : source address [size: _n x 1] +// _n : input data array size +// _b : number of bits to shift +int liquid_lbshift(unsigned char * _src, + unsigned int _n, + unsigned int _b); + +// shift array to the right _b bits, filling in zeros +// _src : source address [size: _n x 1] +// _n : input data array size +// _b : number of bits to shift +int liquid_rbshift(unsigned char * _src, + unsigned int _n, + unsigned int _b); + +// circularly shift array to the left _b bits +// _src : source address [size: _n x 1] +// _n : input data array size +// _b : number of bits to shift +int liquid_lbcircshift(unsigned char * _src, + unsigned int _n, + unsigned int _b); + +// circularly shift array to the right _b bits +// _src : source address [size: _n x 1] +// _n : input data array size +// _b : number of bits to shift +int liquid_rbcircshift(unsigned char * _src, + unsigned int _n, + unsigned int _b); + +// shift array to the left _b bytes, filling in zeros +// _src : source address [size: _n x 1] +// _n : input data array size +// _b : number of bytes to shift +int liquid_lshift(unsigned char * _src, + unsigned int _n, + unsigned int _b); + +// shift array to the right _b bytes, filling in zeros +// _src : source address [size: _n x 1] +// _n : input data array size +// _b : number of bytes to shift +int liquid_rshift(unsigned char * _src, + unsigned int _n, + unsigned int _b); + +// circular shift array to the left _b bytes +// _src : source address [size: _n x 1] +// _n : input data array size +// _b : number of bytes to shift +int liquid_lcircshift(unsigned char * _src, + unsigned int _n, + unsigned int _b); + +// circular shift array to the right _b bytes +// _src : source address [size: _n x 1] +// _n : input data array size +// _b : number of bytes to shift +int liquid_rcircshift(unsigned char * _src, + unsigned int _n, + unsigned int _b); + +// Count the number of ones in an integer +unsigned int liquid_count_ones(unsigned int _x); + +// count number of ones in an integer, modulo 2 +unsigned int liquid_count_ones_mod2(unsigned int _x); + +// compute bindary dot-product between two integers +unsigned int liquid_bdotprod(unsigned int _x, + unsigned int _y); + +// Count leading zeros in an integer +unsigned int liquid_count_leading_zeros(unsigned int _x); + +// Most-significant bit index +unsigned int liquid_msb_index(unsigned int _x); + +// Print string of bits to stdout +int liquid_print_bitstring(unsigned int _x, unsigned int _n); + +// reverse byte, word, etc. +unsigned char liquid_reverse_byte( unsigned char _x); +unsigned int liquid_reverse_uint16(unsigned int _x); +unsigned int liquid_reverse_uint24(unsigned int _x); +unsigned int liquid_reverse_uint32(unsigned int _x); + +// get scale for constant, particularly for plotting purposes +// _val : input value (e.g. 100e6) +// _unit : output unit character (e.g. 'M') +// _scale : output scale (e.g. 1e-6) +int liquid_get_scale(float _val, + char * _unit, + float * _scale); + +// +// MODULE : vector +// + +#define LIQUID_VECTOR_MANGLE_RF(name) LIQUID_CONCAT(liquid_vectorf, name) +#define LIQUID_VECTOR_MANGLE_CF(name) LIQUID_CONCAT(liquid_vectorcf,name) + +// large macro +// VECTOR : name-mangling macro +// T : data type +// TP : data type (primitive) +#define LIQUID_VECTOR_DEFINE_API(VECTOR,T,TP) \ + \ +/* Initialize vector with scalar: x[i] = c (scalar) */ \ +void VECTOR(_init)(T _c, \ + T * _x, \ + unsigned int _n); \ + \ +/* Add each element pointwise: z[i] = x[i] + y[i] */ \ +void VECTOR(_add)(T * _x, \ + T * _y, \ + unsigned int _n, \ + T * _z); \ + \ +/* Add scalar to each element: y[i] = x[i] + c */ \ +void VECTOR(_addscalar)(T * _x, \ + unsigned int _n, \ + T _c, \ + T * _y); \ + \ +/* Multiply each element pointwise: z[i] = x[i] * y[i] */ \ +void VECTOR(_mul)(T * _x, \ + T * _y, \ + unsigned int _n, \ + T * _z); \ + \ +/* Multiply each element with scalar: y[i] = x[i] * c */ \ +void VECTOR(_mulscalar)(T * _x, \ + unsigned int _n, \ + T _c, \ + T * _y); \ + \ +/* Compute complex phase rotation: x[i] = exp{j theta[i]} */ \ +void VECTOR(_cexpj)(TP * _theta, \ + unsigned int _n, \ + T * _x); \ + \ +/* Compute angle of each element: theta[i] = arg{ x[i] } */ \ +void VECTOR(_carg)(T * _x, \ + unsigned int _n, \ + TP * _theta); \ + \ +/* Compute absolute value of each element: y[i] = |x[i]| */ \ +void VECTOR(_abs)(T * _x, \ + unsigned int _n, \ + TP * _y); \ + \ +/* Compute sum of squares: sum{ |x|^2 } */ \ +TP VECTOR(_sumsq)(T * _x, \ + unsigned int _n); \ + \ +/* Compute l-2 norm: sqrt{ sum{ |x|^2 } } */ \ +TP VECTOR(_norm)(T * _x, \ + unsigned int _n); \ + \ +/* Compute l-p norm: { sum{ |x|^p } }^(1/p) */ \ +TP VECTOR(_pnorm)(T * _x, \ + unsigned int _n, \ + TP _p); \ + \ +/* Scale vector elements by l-2 norm: y[i] = x[i]/norm(x) */ \ +void VECTOR(_normalize)(T * _x, \ + unsigned int _n, \ + T * _y); \ + +LIQUID_VECTOR_DEFINE_API(LIQUID_VECTOR_MANGLE_RF, float, float) +LIQUID_VECTOR_DEFINE_API(LIQUID_VECTOR_MANGLE_CF, liquid_float_complex, float) + +// +// mixed types +// +#if 0 +void liquid_vectorf_add(float * _a, + float * _b, + unsigned int _n, + float * _c); +#endif + +#ifdef __cplusplus +} //extern "C" +#endif // __cplusplus + +#endif // __LIQUID_H__ + diff --git a/libs/x86_64/libad9361.so b/libs/x86_64/libad9361.so new file mode 100644 index 0000000..a4f6916 Binary files /dev/null and b/libs/x86_64/libad9361.so differ diff --git a/libs/x86_64/libad9361.so.0 b/libs/x86_64/libad9361.so.0 new file mode 100644 index 0000000..a4f6916 Binary files /dev/null and b/libs/x86_64/libad9361.so.0 differ diff --git a/libs/x86_64/libad9361.so.0.2 b/libs/x86_64/libad9361.so.0.2 new file mode 100644 index 0000000..a4f6916 Binary files /dev/null and b/libs/x86_64/libad9361.so.0.2 differ diff --git a/libs/x86_64/libiio.so b/libs/x86_64/libiio.so new file mode 100644 index 0000000..38eb2b0 Binary files /dev/null and b/libs/x86_64/libiio.so differ diff --git a/libs/x86_64/libiio.so.0 b/libs/x86_64/libiio.so.0 new file mode 100644 index 0000000..38eb2b0 Binary files /dev/null and b/libs/x86_64/libiio.so.0 differ diff --git a/libs/x86_64/libiio.so.0.19 b/libs/x86_64/libiio.so.0.19 new file mode 100644 index 0000000..f702605 Binary files /dev/null and b/libs/x86_64/libiio.so.0.19 differ diff --git a/libs/x86_64/libiio.so.0.21 b/libs/x86_64/libiio.so.0.21 new file mode 100644 index 0000000..38eb2b0 Binary files /dev/null and b/libs/x86_64/libiio.so.0.21 differ diff --git a/libs/x86_64/libliquid.so b/libs/x86_64/libliquid.so new file mode 100644 index 0000000..723192d Binary files /dev/null and b/libs/x86_64/libliquid.so differ diff --git a/libs/x86_64/libsoundio.so b/libs/x86_64/libsoundio.so new file mode 100644 index 0000000..0bc1be2 Binary files /dev/null and b/libs/x86_64/libsoundio.so differ diff --git a/libs/x86_64/libsoundio.so.2 b/libs/x86_64/libsoundio.so.2 new file mode 100644 index 0000000..0bc1be2 Binary files /dev/null and b/libs/x86_64/libsoundio.so.2 differ diff --git a/libs/x86_64/libsoundio.so.2.0.0 b/libs/x86_64/libsoundio.so.2.0.0 new file mode 100644 index 0000000..0bc1be2 Binary files /dev/null and b/libs/x86_64/libsoundio.so.2.0.0 differ diff --git a/liquid/liquiddrv.cpp b/liquid/liquiddrv.cpp new file mode 100644 index 0000000..072b78c --- /dev/null +++ b/liquid/liquiddrv.cpp @@ -0,0 +1,417 @@ +#include "../qo100trx.h" +#include + +void createSSBfilter(); +void init_beaconlock(); +void close_beaconlock(); +void exec_beaconlock(liquid_float_complex samp); + +float rxvolume = 1.0f; + +// down mixer +nco_crcf dnnco = NULL; + +// SSB Demodulator +float demod_index = 0.99f; // modulation index (bandwidth) +ampmodem demod = NULL; + +// Low pass +unsigned int lp_order = 4; // filter order +float lp_fc = 0.0050f; // cutoff frequency +float lp_f0 = 0.0f; // center frequency +float lp_Ap = 1.0f; // pass-band ripple +float lp_As = 40.0f; // stop-band attenuation +iirfilt_crcf lp_q = NULL; + +// Down-Sampler +unsigned int decim_h_len = 13; // filter semi-length (filter delay) +float decim_r = (float)((double)AUDIOSAMPRATE / (double)SAMPRATE); // resampling rate (output/input) +float decim_bw=0.001f; // cutoff frequency +float decim_slsl= 60.0f; // resampling filter sidelobe suppression level +unsigned int decim_npfb=32; // number of filters in bank (timing resolution) +resamp_crcf decim_q = NULL; + +void init_liquid() +{ + printf("init DSP\n"); + + // Downmixer + dnnco = nco_crcf_create(LIQUID_NCO); + tune_downmixer(); + + // SSB Demodulator + demod = ampmodem_create(demod_index, LIQUID_AMPMODEM_USB, 1); + + // create downsampler + decim_q = resamp_crcf_create(decim_r,decim_h_len,decim_bw,decim_slsl,decim_npfb); + if(decim_q == NULL) printf("decimq error\n"); + + // low pass + createSSBfilter(); + + init_beaconlock(); +} + +void close_liquid() +{ + printf("close DSP\n"); + + if(dnnco) nco_crcf_destroy(dnnco); + dnnco = NULL; + + if(demod) ampmodem_destroy(demod); + demod = NULL; + + if(decim_q) resamp_crcf_destroy(decim_q); + decim_q = NULL; + + if(lp_q) iirfilt_crcf_destroy(lp_q); + lp_q = NULL; + + close_beaconlock(); +} + +void createSSBfilter() +{ +static int lastrxfilter = -1; + + if(rxfilter != lastrxfilter) + { + printf("create RX SSB filter: %d\n",rxfilter); + lastrxfilter = rxfilter; + if(lp_q) iirfilt_crcf_destroy(lp_q); + + switch(rxfilter) + { + case 0: lp_fc = 0.002f; break; + case 1: lp_fc = 0.0036f; break; + case 2: lp_fc = 0.0044f; break; + case 3: lp_fc = 0.0050f; break; + } + + + lp_q = iirfilt_crcf_create_prototype(LIQUID_IIRDES_ELLIP, LIQUID_IIRDES_LOWPASS, LIQUID_IIRDES_SOS, + lp_order, lp_fc, lp_f0, lp_Ap, lp_As); + } +} + +void tune_downmixer() +{ +static int lastoffset = -1; + + int newoffset = RXoffsetfreq; + if(beaconlock) + newoffset += bcnoffset; + + if(lastoffset != newoffset) + { + lastoffset = newoffset; + printf("tune RX to %f\n",BASEQRG*1e3 + lastoffset); + float RADIANS_PER_SAMPLE = ((2.0f * (float)M_PI * (lastoffset-280000))/(float)SAMPRATE); + nco_crcf_set_phase(dnnco, 0.0f); + nco_crcf_set_frequency(dnnco, RADIANS_PER_SAMPLE); + } +} + +// convert a pluto stream into liquid samples +void streamToSamples(uint8_t *stream, int streamlen, liquid_float_complex *samples) +{ +int didx = 0; +int16_t xi; +int16_t xq; + + for(int i=0; i 1) + { + printf("decimator error, num_written=%d\n",num_written); + exit(0); + } + + //measure_maxval(fabs(soundsamp.real), 1000); + + // the rate here is 48000S/s + // demodulate + ampmodem_demodulate(demod, soundsamp, &z); + + // send z to soundcard + if(audioloop == 0 && pbidx != -1) + { + static float playvol = 1.0f; + if(((ptt && rxmute) || mute) && rfloop == 0) playvol = 0.08f; + else playvol = 2.0f; + float vol = playvol * rxvolume; + if(fabs(vol) > 1.0f) + { + // reduce volume if overdriven + rxvolume = 1.0f / playvol; + vol = playvol * rxvolume; + } + + kmaudio_playsamples(pbidx,&z,1,vol); + } + } +} + +/* ================= beaconlock =================== +the beacon lock measures the frequency of the lower CW beacon + +1) Frequency +tuner is on x,470000 +beacon is on x,500000 - x,500400 +take 2kHz from x,499200 to x,501200 +Downmix x,499200 to baseband + +2) Low pass filter with < 2kHz to eliminate aliasing + +3) Sample Rate: Downsampling by 480 +input: 1,12MS/s +output: 4000S/s which gives the required 2kHz range + +4) run an FFT with a resolution of bcn_resolution. +this give new FFT bins every 1/bcn_resolution seconds +*/ + +// FFT +fftw_complex *bcn_din = NULL; // input data for fft, output data from ifft +fftw_complex *bcn_cpout = NULL; // ouput data from fft, input data to ifft +fftw_plan bcn_plan = NULL; +const int bcn_FFTsamprate = 4000; // sample rate for FFT (required range * 2) +const int bcn_resolution = 2; // Hz per bin +const int bcn_fftlength = bcn_FFTsamprate / bcn_resolution; // 4kS/s / 5 = 800 + +// down mixer +nco_crcf bcn_dnnco = NULL; +const int startqrg = 499200; + +// Low pass +unsigned int bcn_lp_order = 4; // filter order +float bcn_lp_fc = 0.0018f; // cutoff frequency +float bcn_lp_f0 = 0.0f; // center frequency +float bcn_lp_Ap = 1.0f; // pass-band ripple +float bcn_lp_As = 40.0f; // stop-band attenuation +iirfilt_crcf bcn_lp_q = NULL; + +// decimator +unsigned int bcn_m_predec = 8; // filter delay +float bcn_As_predec = 40.0f; // stop-band att +const int bcnInterpolfactor = SAMPRATE / bcn_FFTsamprate; +firdecim_crcf bcn_decim = NULL; + +int bcnoffset = -1; + +void init_beaconlock() +{ + // Downmixer + bcn_dnnco = nco_crcf_create(LIQUID_NCO); + int offset = startqrg - 470000; + float RADIANS_PER_SAMPLE = ((2.0f * (float)M_PI * (offset-280000))/(float)SAMPRATE); + nco_crcf_set_phase(bcn_dnnco, 0.0f); + nco_crcf_set_frequency(bcn_dnnco, RADIANS_PER_SAMPLE); + + // Low pass filter + bcn_lp_q = iirfilt_crcf_create_prototype(LIQUID_IIRDES_ELLIP, LIQUID_IIRDES_LOWPASS, LIQUID_IIRDES_SOS, + bcn_lp_order, bcn_lp_fc, bcn_lp_f0, bcn_lp_Ap, bcn_lp_As); + + // decimator + bcn_decim = firdecim_crcf_create_kaiser(bcnInterpolfactor, bcn_m_predec, bcn_As_predec); + firdecim_crcf_set_scale(bcn_decim, 1.0f/(float)bcnInterpolfactor); + + // FFT + fftw_import_wisdom_from_filename("bcn_fftcfg"); + bcn_din = (fftw_complex *)fftw_malloc(sizeof(fftw_complex) * bcn_fftlength); + bcn_cpout = (fftw_complex *)fftw_malloc(sizeof(fftw_complex) * bcn_fftlength); + bcn_plan = fftw_plan_dft_1d(bcn_fftlength, bcn_din, bcn_cpout, FFTW_FORWARD, FFTW_MEASURE); + fftw_export_wisdom_to_filename("bcn_fftcfg"); +} + +void close_beaconlock() +{ + if(bcn_dnnco) nco_crcf_destroy(bcn_dnnco); + bcn_dnnco = NULL; + + if(bcn_lp_q) iirfilt_crcf_destroy(bcn_lp_q); + bcn_lp_q = NULL; + + if(bcn_decim != NULL) firdecim_crcf_destroy(bcn_decim); + bcn_decim = NULL; + + if(bcn_din) fftw_free(bcn_din); + bcn_din = NULL; + + if(bcn_cpout) fftw_free(bcn_cpout); + bcn_cpout = NULL; + +} + +void exec_beaconlock(liquid_float_complex samp) +{ +static liquid_float_complex ccol[bcnInterpolfactor]; +static int ccol_idx = 0; +static int bcn_din_idx = 0; + + if(!beaconlock) return; + + if (bcn_dnnco == NULL) return; + if (bcn_lp_q == NULL) return; + if (bcn_decim == NULL) return; + + // mix lower beacon into baseband + liquid_float_complex c; + nco_crcf_step(bcn_dnnco); + nco_crcf_mix_down(bcn_dnnco,samp,&c); + + // Filter + liquid_float_complex cfilt; + iirfilt_crcf_execute(bcn_lp_q, c, &cfilt); + + // down sampling 1,2MS/s -> 4kS/s + ccol[ccol_idx++] = cfilt; + if (ccol_idx < bcnInterpolfactor) return; + ccol_idx = 0; + + // we have bcnInterpolfactor samples in ccol + liquid_float_complex y; + firdecim_crcf_execute(bcn_decim, ccol, &y); + // the output of the pre decimator is exactly one sample in y + // the rate here is 4kS/s + + // FFT + // collect samples until we have bcn_fftlength + bcn_din[bcn_din_idx][0] = y.real; + bcn_din[bcn_din_idx][1] = y.imag; + if(++bcn_din_idx < bcn_fftlength) return; + bcn_din_idx = 0; + + fftw_execute(bcn_plan); + int numbins = bcn_fftlength/2; + + // calc absolute values and search max value + float bin[numbins]; + float real,imag; + float max = 0; + for(int i=0; imax) max=bin[i]; + } + + // from all samples > 1/2 max search the min and max frequency + int minf=99999, maxf=0; + for(int i=0; i (max*1/2)) + { + if(i < minf) minf = i; + if(i > maxf) maxf = i; + } + } + + int minqrg = minf* bcn_resolution+startqrg; + int maxqrg = maxf* bcn_resolution+startqrg; + int diff = abs(maxqrg-minqrg); + //printf("%d %d %d\n",minqrg,maxqrg,diff); + + int newoffset = 0; + if(diff > 380) + { + // we have both frequencies, then measure the beacon mir frequency + int bcnqrg = minqrg + diff/2; + int bcnqrgsoll = 500200; // expected frequency + bcnoffset = (bcnqrg - bcnqrgsoll); + //printf("lower beacon %d .. %d: mid QRG: %d kHz. Offset: %d Hz\n",minqrg,maxqrg,bcnqrg,bcnoffset); + newoffset = 1; + } + else + { + // we have only one frequency + + return; + + + int difflow = minqrg - 500000; + int diffhigh = maxqrg - 500400; + if(abs(difflow) < abs(diffhigh)) + { + //printf("lower beacon low QRG: %d kHz. Offset: %d Hz\n",minqrg,difflow); + bcnoffset = difflow; + newoffset = 1; + } + else + { + //printf("lower beacon hi QRG: %d kHz. Offset: %d Hz\n",maxqrg,diffhigh); + bcnoffset = diffhigh; + newoffset = 1; + } + } + + // send offset to GUI + if(newoffset) + { + uint8_t drift[5]; + drift[0] = 6; + drift[1] = bcnoffset >> 24; + drift[2] = bcnoffset >> 16; + drift[3] = bcnoffset >> 8; + drift[4] = bcnoffset & 0xff; + + sendUDP(gui_ip, GUI_UDPPORT, drift, 5); + + tune_downmixer(); + } +} + diff --git a/liquid/liquiddrv.h b/liquid/liquiddrv.h new file mode 100644 index 0000000..14e14fb --- /dev/null +++ b/liquid/liquiddrv.h @@ -0,0 +1,8 @@ +void streamToSamples(uint8_t *stream, int streamlen, liquid_float_complex *samples); +void downmix(liquid_float_complex *samples, int len); +void init_liquid(); +void close_liquid(); +void tune_downmixer(); +void init_liquid_modulator(); +void upmix(float *f, int len, int offsetfreq); +void close_liquid_modulator(); \ No newline at end of file diff --git a/liquid/liquiddrv.o b/liquid/liquiddrv.o new file mode 100644 index 0000000..3626241 Binary files /dev/null and b/liquid/liquiddrv.o differ diff --git a/liquid/liquiddrv_modulator.cpp b/liquid/liquiddrv_modulator.cpp new file mode 100644 index 0000000..2d1bfde --- /dev/null +++ b/liquid/liquiddrv_modulator.cpp @@ -0,0 +1,374 @@ +#include "../qo100trx.h" + +void tune_upmixer(int offset); +void sendToPluto(); +void createBandpass(); +void measureTxAudioVolume(float f); + +// Modulator +float mod_index = 0.99f; // modulation index (bandwidth) +ampmodem mod = NULL; + +// Up-Sampler +unsigned int interp_h_len = 13; // filter semi-length (filter delay) +float interp_r = (float)((double)SAMPRATE / (double)AUDIOSAMPRATE); // resampling rate (output/input) +float interp_bw=0.1f; // cutoff frequency +float interp_slsl= 60.0f; // resampling filter sidelobe suppression level +unsigned int interp_npfb=32; // number of filters in bank (timing resolution) +resamp_crcf interp_q = NULL; + +// up mixer +nco_crcf upnco = NULL; +nco_crcf upssb = NULL; +nco_crcf tone_nco = NULL; + +// ssb band pass +unsigned int tx_lp_order = 8; // filter order +float tx_lp_fc = 0.066f; // cutoff frequency +float tx_lp_f0 = 0.09f; // center frequency +float tx_lp_Ap = 1.0f; // pass-band ripple +float tx_lp_As = 80.0f; // stop-band attenuation +unsigned int tx_lp_n = 128; // number of samples +iirfilt_crcf tx_lp_q = NULL; + +// audio high pass +unsigned int au_lp_order = 2; // filter order +float au_lp_fc = 0.1f; // cutoff frequency +float au_lp_f0 = 0.2f; // center frequency +float au_lp_Ap = 1.0f; // pass-band ripple +float au_lp_As = 10.0f; // stop-band attenuation +unsigned int au_lp_n = 128; // number of samples +iirfilt_crcf au_lp_q = NULL; + +// AGC +agc_rrrf agc_q = NULL; + +int32_t plutomax = 1; + +liquid_float_complex rc(liquid_float_complex c) +{ + int r =10; + c.real /=r; + c.imag /=r; + + return c; +} + +void init_liquid_modulator() +{ + // Upmixer + upnco = nco_crcf_create(LIQUID_NCO); + tune_upmixer(0); + + // SSB Upmixer Baseband -> 3kHz + upssb = nco_crcf_create(LIQUID_NCO); + float RADIANS_PER_SAMPLE = ((2.0f * (float)M_PI * 3000.0f)/(float)AUDIOSAMPRATE); + nco_crcf_set_phase(upssb, 0.0f); + nco_crcf_set_frequency(upssb, RADIANS_PER_SAMPLE); + + // test tone 800 Hz + tone_nco = nco_crcf_create(LIQUID_NCO); + float TT_RADIANS_PER_SAMPLE = ((2.0f * (float)M_PI * 800.0f)/(float)AUDIOSAMPRATE); + nco_crcf_set_phase(tone_nco, 0.0f); + nco_crcf_set_frequency(tone_nco, TT_RADIANS_PER_SAMPLE); + + // SSB Mmodulator + mod = ampmodem_create(mod_index, LIQUID_AMPMODEM_USB, 1); + + // create upsampler + interp_q = resamp_crcf_create(interp_r,interp_h_len,interp_bw,interp_slsl,interp_npfb); + if(interp_q == NULL) printf("interp_q error\n"); + + // band pass + createBandpass(); + + // create audio filter + // LIQUID_IIRDES_BESSEL has a memory overflow error, only ELLIP works + au_lp_q = iirfilt_crcf_create_prototype(LIQUID_IIRDES_ELLIP, LIQUID_IIRDES_HIGHPASS, LIQUID_IIRDES_SOS, + au_lp_order, au_lp_fc, au_lp_f0, au_lp_Ap, au_lp_As); + + // agc + agc_q = agc_rrrf_create(); + agc_rrrf_set_bandwidth(agc_q,0.01f); // set loop filter bandwidth +} + +void close_liquid_modulator() +{ + printf("close DSP modulator\n"); + + if(upnco) nco_crcf_destroy(upnco); + upnco = NULL; + + if(upssb) nco_crcf_destroy(upssb); + upssb = NULL; + + if(tone_nco) nco_crcf_destroy(tone_nco); + tone_nco = NULL; + + if(mod) ampmodem_destroy(mod); + mod = NULL; + + if(interp_q) resamp_crcf_destroy(interp_q); + interp_q = NULL; + + if(tx_lp_q) iirfilt_crcf_destroy(tx_lp_q); + tx_lp_q = NULL; + + if(au_lp_q) iirfilt_crcf_destroy(au_lp_q); + au_lp_q = NULL; + + if(agc_q) agc_rrrf_destroy(agc_q); + agc_q = NULL; +} + +void createBandpass() +{ +static int lasttxfilter = -1; + + if(txfilter != lasttxfilter) + { + lasttxfilter = txfilter; + if(tx_lp_q) iirfilt_crcf_destroy(tx_lp_q); + + // Frequencies are designed for 3kHz carrier + switch(txfilter) + { + case 0 : {tx_lp_fc=0.079f; tx_lp_f0=0.09f;} break; + case 1 : {tx_lp_fc=0.074f; tx_lp_f0=0.09f;} break; + case 2 : {tx_lp_fc=0.070f; tx_lp_f0=0.09f;} break; + case 3 : {tx_lp_fc=0.066f; tx_lp_f0=0.09f;} break; + } + + tx_lp_q = iirfilt_crcf_create_prototype(LIQUID_IIRDES_ELLIP, LIQUID_IIRDES_BANDPASS, LIQUID_IIRDES_SOS, + tx_lp_order, tx_lp_fc, tx_lp_f0, tx_lp_Ap, tx_lp_As); + } +} + +void tune_upmixer(int offset) +{ +static int lastoffset = -1; + + if(rfloop) + { + offset = RXoffsetfreq; + } + + if(lastoffset != offset) + { + lastoffset = offset; + printf("tune TX to %f\n",BASEQRG*1e3 + offset); + float RADIANS_PER_SAMPLE = ((2.0f * (float)M_PI * (offset-280000-3000))/(float)SAMPRATE); + nco_crcf_set_phase(upnco, 0.0f); + nco_crcf_set_frequency(upnco, RADIANS_PER_SAMPLE); + } +} + +liquid_float_complex txarr[PLUTOBUFSIZE]; +int txarridx = 0; + + +void upmix(float *f, int len, int offsetfreq) +{ +float fcompr; + + if (mod == NULL) return; + if (interp_q == NULL) return; + if (upnco == NULL) return; + if (upssb == NULL) return; + if (tx_lp_q == NULL) return; + if (au_lp_q == NULL) return; + if (agc_q == NULL) return; + + // re-tune if TX grq has been changed + tune_upmixer(offsetfreq); + + // re-set bandpass if changed by user + createBandpass(); + + // loop through all samples + for(int i=0; i 0) + { + if(fcompr >= 1) fcompr = 0.99; + if(fcompr <= -1) fcompr = -0.99; + fcompr = 3.3 * log10(fcompr+1); + if(fcompr >= 1) fcompr = 0.99; + if(fcompr <= -1) fcompr = -0.99; + } + + fcompr *= micboost; + + // insert a test tone + if(sendtone) + { + // generate a 800Hz tone and send to transmitter + nco_crcf_step(tone_nco); + fcompr = nco_crcf_sin(tone_nco); + fcompr /= 10; + } + + // modulator, at 48k audio sample rate + liquid_float_complex ybase; + ampmodem_modulate(mod, fcompr, &ybase); + + ybase.real /=2; + ybase.imag /=2; + + // up mix from baseband to 3000 Hz + // this eliminates a couple of problems happening at baseband + liquid_float_complex y; + nco_crcf_step(upssb); + nco_crcf_mix_up(upssb,ybase,&y); + + // filter SSB bandwidth at 3kHz + liquid_float_complex cfilt; + iirfilt_crcf_execute(tx_lp_q, y, &cfilt); + + // audio high pass filter + liquid_float_complex aufiltout; + if(audiohighpass) + { + iirfilt_crcf_execute(au_lp_q, cfilt, &aufiltout); + aufiltout.real *= 2; + aufiltout.imag *= 2; + } + else + { + aufiltout = cfilt; + } + + // resample from AUDIOSAMPRATE (48000S/s) to pluto rate + liquid_float_complex out[(int)interp_r+2]; + unsigned int num_written; + resamp_crcf_execute(interp_q, aufiltout, out, &num_written); + if(num_written <= 0) + { + printf("mod num_written error: %d\n",num_written); + return; + } + if(num_written >= ((unsigned int)interp_r+2)) + { + printf("out array too small: %d\n",num_written); + return; + } + // num_written is the number of samples for Pluto + for(unsigned int samp=0; samp= PLUTOBUFSIZE) + { + sendToPluto(); + txarridx = 0; + } + } + } +} + +/* +this agc measures the value of the IQ samples +and then slowly ampifies/attenuates them to get a peak of "maxvol" +*/ + +float smult = 0; +void agc(int32_t *fi, int32_t *fq, int len, float maxvol) +{ + // measure peak value of these samples + int32_t p = 0; + for(int i=0; i p) p = fi[i]; + if(fi[i] < -p) p = -fi[i]; + + if(fq[i] > p) p = fq[i]; + if(fq[i] < -p) p = -fq[i]; + } + + // required multiplicator to bring peak to maxvol + float mult = maxvol / (float)p; + if(mult > 80.0f) mult = 80.0f; // limit max. amplification, so that background noise does not get too loud + + // slowly adapt smult to mult + if(mult < smult) + { + // fast attack if signal is loud + smult = mult; + } + else + { + // slow decay for weak signals + float diff = mult - smult; + smult += diff/25.0f; // x.0f = decay rate + } + + // do agc + for(int i=0; i pki) pki = fi[i]; + if(fq[i] > pkq) pkq = fq[i]; + } + printf("peak:%d smult:%f newpeak:%d %d\n",p,smult,pki,pkq); + */ +} + +float pmult = 32767.0f; // adjust to get maximum 16bit values + +void sendToPluto() +{ +int32_t xi[PLUTOBUFSIZE]; +int32_t xq[PLUTOBUFSIZE]; +uint8_t txbuf[PLUTOBUFSIZE * 4]; +int txbufidx = 0; + + for(int i=0; i> 8; + txbuf[txbufidx++] = xq[i] & 0xff; + txbuf[txbufidx++] = xq[i] >> 8; + } + + // wait for free space in TX fifo + while(keeprunning) + { + int s = fifo_usedspace(TXfifo); + if(s < 5) break; + usleep(100); + } + + write_fifo(TXfifo,txbuf,PLUTOBUFSIZE*4); +} + diff --git a/liquid/liquiddrv_modulator.o b/liquid/liquiddrv_modulator.o new file mode 100644 index 0000000..5544e02 Binary files /dev/null and b/liquid/liquiddrv_modulator.o differ diff --git a/pluto/pluto.h b/pluto/pluto.h new file mode 100644 index 0000000..15f0456 --- /dev/null +++ b/pluto/pluto.h @@ -0,0 +1,49 @@ +#define SAMPRATE 560000 // 1.12MS/s + +#define LNB_REF 24000UL // kHz +#define BASEQRG 10489470UL // kHz, spectrum range ist 10489.470 - 10490.03 +#define RXBASEQRG ((BASEQRG - 390UL*LNB_REF)*1000UL) +#define TXBASEQRG ((2400000UL - 30UL)*1000UL) +#define PLUTOBUFSIZE (SAMPRATE/10) + +#define MHZ(x) ((long long)(x*1000000.0 + .5)) +#define GHZ(x) ((long long)(x*1000000000.0 + .5)) + +enum iodev { + RX = 0, + TX +}; + +typedef struct _stream_cfg_ { + long long bw_hz; // Analog bandwidth in Hz + long long fs_hz; // Baseband sample rate in Hz + long long lo_hz; // Local oscillator frequency in Hz + const char* rfport; // Port name +} stream_cfg; + + +bool get_ad9361_stream_ch(__notused struct iio_context *ctx, enum iodev d, struct iio_device *dev, int chid, struct iio_channel **chn); +bool cfg_ad9361_streaming_ch(struct iio_context *ctx, stream_cfg *cfg, enum iodev type, int chid); +bool get_ad9361_stream_dev(struct iio_context *ctx, enum iodev d, struct iio_device **dev); +int pluto_get_USB(char *sn); +void pluto_setup(); +void init_runloop(); +void setTXfrequency(long long freq); +void setRXfrequency(long long freq); +void setTXpower(); +void release_ptt(); +void set_ptt(); + +extern stream_cfg rxcfg; +extern stream_cfg txcfg; +extern struct iio_context *ctx; +extern struct iio_buffer *rxbuf; +extern struct iio_buffer *txbuf; +extern struct iio_channel *rx0_i; +extern struct iio_channel *tx0_i; +extern float RX_BW; +extern float TX_BW; +extern double RX_FREQ; +extern double TX_FREQ; +extern float TX_GAIN; +extern char pluto_context_name[50]; diff --git a/pluto/pluto_driver.cpp b/pluto/pluto_driver.cpp new file mode 100644 index 0000000..327d042 --- /dev/null +++ b/pluto/pluto_driver.cpp @@ -0,0 +1,221 @@ +/* +* Adalm Pluto Driver +* ================== +* Author: DJ0ABR +* +* (c) DJ0ABR +* www.dj0abr.de +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 2 of the License, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You 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. +* +* ======================================= +* various subroutines to access the pluto +* ======================================= +* +* most subroutines from here: +* https://raw.githubusercontent.com/analogdevicesinc/libiio/master/examples/ad9361-iiostream.c +* +*/ + +#include "../qo100trx.h" + +void setTXfrequency(long long freq); + +// static scratch mem for strings +static char tmpstr[64]; + +// check return value of attr_write function +static void errchk(int v, const char* what) +{ + if (v < 0) + { + printf("Error %d writing to channel \"%s\"\nvalue may not be supported.\n", v, what); + } +} + +// write attribute: double +static void wr_ch_double(struct iio_channel *chn, const char* what, double val) +{ + errchk(iio_channel_attr_write_double(chn, what, val), what); +} + +// write attribute: long long int +static void wr_ch_lli(struct iio_channel *chn, const char* what, long long val) +{ + errchk(iio_channel_attr_write_longlong(chn, what, val), what); +} + +// write attribute: string +static void wr_ch_str(struct iio_channel *chn, const char* what, const char* str) +{ + errchk(iio_channel_attr_write(chn, what, str), what); +} + +// helper function generating channel names +static char* get_ch_name(const char* type, int id) +{ + snprintf(tmpstr, sizeof(tmpstr), "%s%d", type, id); + return tmpstr; +} + +// returns ad9361 phy device +static struct iio_device* get_ad9361_phy(struct iio_context *ctx) +{ + struct iio_device *dev = iio_context_find_device(ctx, "ad9361-phy"); + return dev; +} + +// finds AD9361 streaming IIO devices +bool get_ad9361_stream_dev(struct iio_context *ctx, enum iodev d, struct iio_device **dev) +{ + switch (d) { + case TX: *dev = iio_context_find_device(ctx, "cf-ad9361-dds-core-lpc"); return *dev != NULL; + case RX: *dev = iio_context_find_device(ctx, "cf-ad9361-lpc"); return *dev != NULL; + } + return 0; +} + +// finds AD9361 streaming IIO channels +bool get_ad9361_stream_ch(__notused struct iio_context *ctx, enum iodev d, struct iio_device *dev, int chid, struct iio_channel **chn) +{ + *chn = iio_device_find_channel(dev, get_ch_name("voltage", chid), d == TX); + if (!*chn) + *chn = iio_device_find_channel(dev, get_ch_name("altvoltage", chid), d == TX); + return *chn != NULL; +} + +// finds AD9361 phy IIO configuration channel with id chid +static bool get_phy_chan(struct iio_context *ctx, enum iodev d, int chid, struct iio_channel **chn) +{ + switch (d) { + case RX: *chn = iio_device_find_channel(get_ad9361_phy(ctx), get_ch_name("voltage", chid), false); return *chn != NULL; + case TX: *chn = iio_device_find_channel(get_ad9361_phy(ctx), get_ch_name("voltage", chid), true); return *chn != NULL; + } + return 0; +} + +// finds AD9361 local oscillator IIO configuration channels +static bool get_lo_chan(struct iio_context *ctx, enum iodev d, struct iio_channel **chn) +{ + switch (d) { + // LO chan is always output, i.e. true + case RX: *chn = iio_device_find_channel(get_ad9361_phy(ctx), get_ch_name("altvoltage", 0), true); return *chn != NULL; + case TX: *chn = iio_device_find_channel(get_ad9361_phy(ctx), get_ch_name("altvoltage", 1), true); return *chn != NULL; + } + return 0; +} + +// applies streaming configuration through IIO +bool cfg_ad9361_streaming_ch(struct iio_context *ctx, stream_cfg *cfg, enum iodev type, int chid) +{ + struct iio_channel *chn = NULL; + + // Configure phy and lo channels + if (!get_phy_chan(ctx, type, chid, &chn)) { return false; } + wr_ch_str(chn, "rf_port_select", cfg->rfport); + wr_ch_lli(chn, "rf_bandwidth", cfg->bw_hz); + //printf("write sampling_frequency: %lld\n",cfg->fs_hz); + wr_ch_lli(chn, "sampling_frequency", cfg->fs_hz); + + if(type == TX) + { + //wr_ch_double(chn, "hardwaregain", txcfg.hwgain); + setTXpower(); + setTXfrequency(cfg->lo_hz); + } + else + { + // show possible values: iio_attr -n 192.168.20.25 -c ad9361-phy voltage0 + wr_ch_str(chn, "gain_control_mode","slow_attack"); + //wr_ch_str(chn, "gain_control_mode","manual"); + //wr_ch_lli(chn, "hardwaregain", 66); + // Configure LO channel + setRXfrequency(cfg->lo_hz); + } + return true; +} + +int lasttxpower = -1; + +void setTXpower() +{ + if(txpower != lasttxpower) + { + if(txpower > 0) txpower = 0; // 0 is pluto's max value + + lasttxpower = txpower; + printf("set TX power to %d dBm\n",txpower); + + struct iio_channel *chn = NULL; + if (!get_phy_chan(ctx, TX, 0, &chn)) { return; } + + // txpower=-40: switches OFF the PTT in the F5OEO firmware + wr_ch_double(chn, "hardwaregain", (double)txpower); + } +} + +void set_ptt() +{ + lasttxpower = -1; + setPort("p", 1); +} + +void release_ptt() +{ + printf("release PTT by setting -40dBm\n"); + + // set the power to -40, this releases the GPO0,1 PTT in the F5OEO firmware (>V.2021) + struct iio_channel *chn = NULL; + if (!get_phy_chan(ctx, TX, 0, &chn)) { return; } + wr_ch_double(chn, "hardwaregain", (double)-40); + + setPort("p", 0); +} + +long long lastfreq = 0; + +void setTXfrequency(long long freq) +{ + freq += refoffset; + + if(freq != lastfreq) + { + lastfreq = freq; + + //printf("************* TX-QRG *************** %lld, offset:%d\n",freq,refoffset); + + struct iio_channel *chn = NULL; + if (!get_lo_chan(ctx, TX, &chn)) { return; } + wr_ch_lli(chn, "frequency", freq); + } +} + +long long lastrxfreq = 0; + +void setRXfrequency(long long freq) +{ + freq += refoffset; + + if(freq != lastrxfreq) + { + lastrxfreq = freq; + + //printf("************* RX-QRG *************** %lld, offset:%d\n",freq,refoffset); + + struct iio_channel *chn = NULL; + if (!get_lo_chan(ctx, RX, &chn)) { return; } + wr_ch_lli(chn, "frequency", freq); + } +} \ No newline at end of file diff --git a/pluto/pluto_driver.o b/pluto/pluto_driver.o new file mode 100644 index 0000000..d032c76 Binary files /dev/null and b/pluto/pluto_driver.o differ diff --git a/pluto/pluto_finder.cpp b/pluto/pluto_finder.cpp new file mode 100644 index 0000000..d8ad578 --- /dev/null +++ b/pluto/pluto_finder.cpp @@ -0,0 +1,116 @@ +/* +* Adalm Pluto Driver +* ================== +* Author: DJ0ABR +* +* (c) DJ0ABR +* www.dj0abr.de +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 2 of the License, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You 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. +* +* ========================================== +* find a pluto connected via USB or Ethernet +* ========================================== +* +*/ + +#include "../qo100trx.h" + +char pluto_context_name[50]; + +int pluto_get_IP(char *url_IP) +{ + // === connect Pluto at a given IP address === + struct sockaddr_in sa; + + int res = inet_pton(AF_INET,url_IP+3,&(sa.sin_addr)); + if(res == 1) + { + // we have a valid pluto IP continue using this IP + sprintf(pluto_context_name,"%s",url_IP); + //printf("searching Pluto on %s\n",pluto_context_name); + return 1; + } + //printf("cannot evaluate %s\n",url_IP); + return 0; +} + +int pluto_get_USB(char *sn) +{ + char s[500]; + snprintf(s,499,"iio_info -s 2>/dev/null"); + s[499] = 0; + + pluto_context_name[0] = 0; + FILE *fp = popen(s,"r"); + if(fp) + { + while (fgets(s, sizeof(s)-1, fp) != NULL) + { + // get the USB id + char usbid[50]; + char usbsn[100]; + + char *hp = strstr(s,"[usb:"); + if(hp) + { + hp += 1; + char *he = strchr(hp,']'); + if(he) + { + *he = 0; + strncpy(usbid,hp,49); + usbid[sizeof(usbid)-1] = 0; + + // read serial number + char *psn = strstr(s,"serial="); + if(psn) + { + psn+=7; + char *spn = strchr(psn,' '); + if(spn) + { + *spn = 0; + strncpy(usbsn,psn,99); + usbsn[sizeof(usbsn)-1] = 0; + printf("PLUTO found, SN:%s ID:%s\n",usbsn,usbid); + + // if no special pluto requested, then use the first found pluto + if(*sn == 0) + { + strcpy(pluto_context_name, usbid); + return 1; + } + + // search for a specific SN + if(!strcmp(sn, usbsn)) + { + strcpy(pluto_context_name, usbid); + return 1; + } + } + + } + } + } + } + pclose(fp); + } + else + printf("cannot execute iio_info command\n"); + + printf("no PLUTO found\n"); + return 0; +} \ No newline at end of file diff --git a/pluto/pluto_finder.o b/pluto/pluto_finder.o new file mode 100644 index 0000000..b458eba Binary files /dev/null and b/pluto/pluto_finder.o differ diff --git a/pluto/pluto_run.cpp b/pluto/pluto_run.cpp new file mode 100644 index 0000000..d059353 --- /dev/null +++ b/pluto/pluto_run.cpp @@ -0,0 +1,83 @@ +/* +* Adalm Pluto Driver +* ================== +* Author: DJ0ABR +* +* (c) DJ0ABR +* www.dj0abr.de +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 2 of the License, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You 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. +* +* ========================= +* runloop for RX and TX +* ========================= +* +*/ + +#include "../qo100trx.h" + +void* plutorun_threadfunction(void* param); + +void init_runloop() +{ + pthread_t plutorunthread; + pthread_create(&plutorunthread, NULL, plutorun_threadfunction, NULL); +} + +void* plutorun_threadfunction(void* param) +{ +ssize_t nbytes_rx, nbytes_tx; +uint8_t *p_dat, *p_start; + + pthread_detach(pthread_self()); + + printf("entering pluto loop, *** PID:%ld ***\n",syscall(SYS_gettid)); + + while(keeprunning) + { + // ====== receive samples from pluto ====== + // Refill RX buffer + nbytes_rx = iio_buffer_refill(rxbuf); + if (nbytes_rx < 0) { printf("Error refilling buf %d\n",(int) nbytes_rx); } + //measure_samplerate(0,nbytes_rx/4,10); + + p_start = (uint8_t *)iio_buffer_first(rxbuf, rx0_i); + + //for(int ix=0; ix<%s>\n",pbdevname,capdevname); + newaudiodevs = 1; + } + + if(pdata[0] == 8) + { + uint32_t rxbaseqrg; + rxbaseqrg = pdata[1]; + rxbaseqrg <<= 8; + rxbaseqrg += pdata[2]; + rxbaseqrg <<= 8; + rxbaseqrg += pdata[3]; + rxbaseqrg <<= 8; + rxbaseqrg += pdata[4]; + + uint32_t txbaseqrg; + txbaseqrg = pdata[5]; + txbaseqrg <<= 8; + txbaseqrg += pdata[6]; + txbaseqrg <<= 8; + txbaseqrg += pdata[7]; + txbaseqrg <<= 8; + txbaseqrg += pdata[8]; + + RX_FREQ = (double)rxbaseqrg; + TX_FREQ = (double)txbaseqrg; + + resetqrgs = 1; + } + + if(pdata[0] == 9) + { + compressor = pdata[1]; + printf("compressor: %d\n",compressor); + } + + if(pdata[0] == 10) + { + if(pdata[1] == 1) + { + // Pluto on local USB + *plutoid = 0; + printf("Pluto on local USB\n"); + } + else + { + // Pluto on ETH + memset(plutoid,0,sizeof(plutoid)); + strcpy(plutoid,"ip:"); + memcpy(plutoid+3,pdata+2,len-2); + printf("Pluto on Ethernet IP: <%s>\n",plutoid); + } + gotPlutoID = 1; + } + + if(pdata[0] == 11) + { + audiohighpass = pdata[1]; + micboost = pdata[2]; + //showbytestring("cmd11:",pdata,3,3); + } + + if(pdata[0] == 12) + rxfilter = pdata[1]; + + if(pdata[0] == 13) + txfilter = pdata[1]; + + if(pdata[0] == 14) + rxmute = pdata[1]; + + if(pdata[0] == 15) + { + int val; + val = pdata[1]; + val <<= 8; + val += pdata[2]; + val <<= 8; + val += pdata[3]; + val <<= 8; + val += pdata[4]; + + val -= 12000; + refoffset = val; + printf("refoffset: %d\n",refoffset); + + resetqrgs = 1; + } + + if(pdata[0] == 16) + beaconlock = pdata[1]; + + if(pdata[0] == 17) + fftspeed = pdata[1]; + + if(pdata[0] == 19) + { + txpower = pdata[1]; + txpower = -txpower; // convert received pos value into correct neg value + if(txpower > 0) txpower = 0; + if(txpower < -60) txpower = -60; + } + + if(pdata[0] == 20) + recpb = pdata[1]; + + if(pdata[0] == 21) + { + int r = system("shutdown now"); + exit(r); + } + + if(pdata[0] == 22) + { + // send test tone + setSendtone(1-sendtone); + } + + if(pdata[0] == 23) + { + pttmode = pdata[1]; + } +} + +void close_program() +{ + printf("\nCtrl-C pressed\n"); + keeprunning = 0; + sleep(1); + close_liquid(); + close_liquid_modulator(); + close_fft(); + close_gpio(); +} + +int main () +{ + printf("=== QO100 Transceiver Pluto-Driver, by DJ0ABR ===\n"); + + // linux error number see: + // https://github.com/torvalds/linux/blob/master/include/uapi/asm-generic/errno-base.h + /*char s1[100]; + iio_strerror(-19, s1, 99); + printf("<%s>\n",s1); + exit(0);*/ + + char url[512]; + + // check if we are connected to a router + sprintf(url,"ip route"); + char *pr = runProgram(url, sizeof(url)-1); + //printf("<%s>\n",pr); + if(strstr(pr,"default via")) + { + // we are on a router, check github for updates + sprintf(url,"wget --no-check-certificate --no-cache --no-cookies --no-http-keep-alive -O version.txt https://raw.githubusercontent.com/dj0abr/QO100_Transceiver/main/version.txt?cachekiller=%d",rand()); + int sres = system(url); + if(sres < 0) + { + printf("error %d when reading actual serial number\n",sres); + } + } + + install_signal_handler(close_program); + + // Install FIFOs + RXfifo = create_fifo(200, PLUTOBUFSIZE*4); + TXfifo = create_fifo(200, PLUTOBUFSIZE*4); + FFTfifo = create_fifo(200, PLUTOBUFSIZE*4); + CWfifo = create_fifo(10,48*4); + + // start audio (soundcard) and get connected devices + if(kmaudio_init() == -1) + { + printf("NO AUDIO device\n"); + exit(0); + } + kmaudio_getDeviceList(); + + // UDP receiver for commands from GUI + UdpRxInit(&udprxsock, 40821, udprxfunc , &keeprunning); + + // send audio devices to GUI + int len; + uint8_t *s = io_getAudioDevicelist(&len); + uint8_t ub[len+1+2]; + ub[0] = 4; // ID for sound device string + ub[1] = ((uint16_t)DRIVER_SERIAL) >> 8; // driver serial number + ub[2] = ((uint16_t)DRIVER_SERIAL) & 0xff; + memcpy(ub+3,s,len); + sendUDP(gui_ip, GUI_UDPPORT, ub, len+1+2); + + // wait for initial configuration from GUI + // the GUI sends now: + // selected Audio Device (udp code 7) + // Base QRGs (udp code 8) + // Pluto Address (udp code 10) + int to=0; + while(gotPlutoID == 0) + { + usleep(100000); + if(++to >= 50) + { + printf("no config from GUI, exit program\n"); + exit(0); + } + } + printf("initial config OK, continue\n"); + + // find plutoid + if(*plutoid == 'i') + { + strcpy(pluto_context_name,plutoid); + } + else + { + // automatically search a pluto connected via USB + int res = pluto_get_USB(plutoid); + if(!res) + { + printf("no Pluto found on USB, exit program\n"); + exit(0); + } + } + + // Pluto found, now initialize it + printf("Pluto IP/USB ID : <%s>\n",pluto_context_name); + pluto_setup(); + + // init FFT + init_fft(); + + // init DSP demodulator + init_liquid(); + + // init DSP modulator + init_liquid_modulator(); + + // pluto RX/TX is now running, samples are available in the fifos + // start the SSB receiver and transmitter + init_rx(); + init_tx(); + + // init rotary encoders on RPI + init_rotencoder(); + + release_ptt(); + + printf("initialisation finished. Enter normal operation (press Ctrl+C to cancel)\n*** main-PID:%ld ***\n",syscall(SYS_gettid)); + while(keeprunning) + { + // main loop + // time-uncritical jobs are done here + + if(newaudiodevs) + { + if(*pbdevname && *capdevname) + { + // audio device names available + printf("close streams\n"); + if(pbidx!=-1) close_stream(pbidx); + if(capidx!=-1) close_stream(capidx); + printf("init streams\n"); + + pbidx = kmaudio_startPlayback(pbdevname, AUDIOSAMPRATE); + if(pbidx == -1) + printf("NO AUDIO play device: <%s>\n",pbdevname); + + capidx = kmaudio_startCapture(capdevname, AUDIOSAMPRATE); + if(capidx == -1) + printf("NO AUDIO record device: <%s>\n",capdevname); + + newaudiodevs = 0; + } + } + + if(resetqrgs) + { + resetqrgs = 0; + + // set pluto tuner frequency if changed by user + setRXfrequency((long long)RX_FREQ); + setTXfrequency((long long)TX_FREQ); + } + + setTXpower(); + + static int ms10 = 0; + if(++ms10 >= 100) + { + ms10 = 0; + int rotfreq = getEncSteps(0); + if(rotfreq != 0) + { + uint8_t rxoff[2]; + rxoff[0] = 7; + rxoff[1] = (uint8_t)(rotfreq+128); + sendUDP(gui_ip, GUI_UDPPORT, rxoff, 2); + } + } + + int rotvol = getEncSteps(1); + if(rotvol != 0) + { + rotvol = -rotvol; + + rxvolume += (float)rotvol / 50.0f; + if(rxvolume < 0.02f) rxvolume = 0.02f; + // max volume is limited just before sending to sound driver + } + + int nptt = getPort("p"); + if(nptt == 1) extpttinput_enabled = 1; + if(extpttinput_enabled) + { + nptt = test_ptt_gpio(); + if(pttmode == 1) + { + if(nptt == 3) ptt = 1; + if(nptt == 2) ptt = 0; + } + else + if(nptt == 3) ptt = 1-ptt; + } + + int nmute = getPort("m"); + if(nmute == 1) mute_enabled = 1; + if(mute_enabled) + { + nmute = test_mute_gpio(); + if(nmute == 3) + { + if(mute) mute = 0; + else mute = 1; + } + } + + // switch PTT output according to variable "ptt" + if(ptt != lastptt) + { + if(ptt) + { + // switch to TX mode + setSendtone(0);// never start with a test tone after pressing PTT + io_fifo_clear(capidx); + fifo_clear(TXfifo); + set_ptt(); + } + + if(!ptt) release_ptt(); // switch to RX mode + + lastptt = ptt; + } + + //printf("%d\n",getPort("c")); + + usleep(1000); // do NOT change, used for some simple timings + } + + return 0; +} + +void setSendtone(int onoff) +{ + sendtone = onoff; + + uint8_t st[2]; + st[0] = 10; + st[1] = (uint8_t)sendtone; + sendUDP(gui_ip, GUI_UDPPORT, st, 2); +} diff --git a/qo100trx.h b/qo100trx.h new file mode 100644 index 0000000..e1b23ef --- /dev/null +++ b/qo100trx.h @@ -0,0 +1,68 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "libs/include/iio.h" +#include "libs/include/ad9361.h" +#include "libs/include/liquid.h" +#include "kmlib/km_helper.h" +#include "kmlib/kmfifo.h" +#include "kmlib/kmtimer.h" +#include "kmlib/rotary.h" +#include "udp/udp.h" +#include "liquid/liquiddrv.h" +#include "pluto/pluto.h" +#include "libkmaudio/libkmaudio.h" + +// is defined in the makefile ! +// don't define it here +// #define DRIVER_SERIAL 161 // V1.61 + +#define GUI_UDPPORT 40820 + +#define AUDIOSAMPRATE 48000 // internal audio rate (not the soundcard rate) + +void init_rx(); +void init_tx(); +void init_fft(); +void close_fft(); +void setSendtone(int onoff); + +extern int RXfifo; +extern int TXfifo; +extern int FFTfifo; +extern int CWfifo; +extern int pbidx, capidx; +extern char gui_ip[20]; +extern int RXoffsetfreq; +extern int TXoffsetfreq; +extern uint8_t audioloop; +extern uint8_t ptt; +extern uint8_t mute; +extern uint8_t rfloop; +extern int compressor; +extern int rxfilter; +extern int txfilter; +extern int rxmute; +extern int refoffset; +extern int bcnoffset; +extern int beaconlock; +extern int fftspeed; +extern int audiohighpass; +extern int txpower; +extern float rxvolume; +extern int sendtone; +extern int micboost; +extern int agcvalue; \ No newline at end of file diff --git a/qo100trx.o b/qo100trx.o new file mode 100644 index 0000000..e639dab Binary files /dev/null and b/qo100trx.o differ diff --git a/rx.cpp b/rx.cpp new file mode 100644 index 0000000..053b779 --- /dev/null +++ b/rx.cpp @@ -0,0 +1,71 @@ +/* +* Adalm Pluto Driver +* ================== +* Author: DJ0ABR +* +* (c) DJ0ABR +* www.dj0abr.de +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 2 of the License, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You 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. +* +* ========================= +* SSB Receiver +* ========================= +* +*/ + +#include "qo100trx.h" + +int RXoffsetfreq = 280000; + +void* rx_threadfunction(void* param); + +void init_rx() +{ + pthread_t rxthread; + pthread_create(&rxthread, NULL, rx_threadfunction, NULL); +} + +void* rx_threadfunction(void* param) +{ + pthread_detach(pthread_self()); + + printf("entering RX loop, *** PID:%ld ***\n",syscall(SYS_gettid)); + while(keeprunning) + { + uint8_t data[PLUTOBUFSIZE*4]; + if(read_fifo(RXfifo, data, PLUTOBUFSIZE*4)) + { + // Test: send RX back to TX (Repeater Mode) + //write_fifo(TXfifo,data,PLUTOBUFSIZE*4); + + // samples received + // Pluto RX tuned to 10489,47 (minus LNB and RX mixer) + // the range is 10489,47 - 10490,03 which covers the full NB band + + // convert the raw stream into complex samples + liquid_float_complex samples[PLUTOBUFSIZE]; + streamToSamples(data, PLUTOBUFSIZE*4, samples); + + // down mix the SSB channel into baseband, demodulate and send to soundcard + downmix(samples,PLUTOBUFSIZE); + } + + usleep(1000); + } + printf("exit RX loop\n"); + pthread_exit(NULL); // self terminate this thread + return NULL; +} \ No newline at end of file diff --git a/rx.o b/rx.o new file mode 100644 index 0000000..04743dd Binary files /dev/null and b/rx.o differ diff --git a/scripts/install_github_libs b/scripts/install_github_libs new file mode 100755 index 0000000..6721927 --- /dev/null +++ b/scripts/install_github_libs @@ -0,0 +1,69 @@ +set -e +echo "Install original libs for QO100_Transceiver from github" +echo "=======================================================" + +# copy prebuild libraries to lib folder +cd /tmp +mkdir -p qo100trx_libraries +cd qo100trx_libraries + +if [ ! -d "libiio" ] ; then + git clone https://github.com/dj0abr/libiio.git + cd libiio +else + cd libiio + git pull https://github.com/dj0abr/libiio.git +fi +mkdir -p build +cd build +cmake ../ +make -j$(nproc) +sudo make install +cd .. +cd .. + +if [ ! -d "libad9361-iio" ] ; then + git clone https://github.com/dj0abr/libad9361-iio + cd libad9361-iio +else + cd libad9361-iio + git pull https://github.com/dj0abr/libad9361-iio +fi +mkdir -p build +cd build +cmake ../ +make -j$(nproc) +sudo make install +cd .. +cd .. + +if [ ! -d "liquid-dsp" ] ; then + git clone https://github.com/dj0abr/liquid-dsp + cd liquid-dsp +else + cd liquid-dsp + git pull https://github.com/dj0abr/liquid-dsp +fi +./bootstrap.sh +./configure +make -j$(nproc) +sudo make install +cd .. + +if [ ! -d "libsoundio" ] ; then + git clone https://github.com/dj0abr/libsoundio + cd libsoundio +else + cd libsoundio + git pull https://github.com/dj0abr/libsoundio +fi +mkdir -p build +cd build +cmake ../ +make -j$(nproc) +sudo make install + +echo ============================= +echo Library installation finished +echo ============================= +exit 0 diff --git a/scripts/makeall b/scripts/makeall new file mode 100755 index 0000000..7b8e819 --- /dev/null +++ b/scripts/makeall @@ -0,0 +1,6 @@ +cd .. +make clean + +make -j$(nproc) + + diff --git a/scripts/prepare_mono b/scripts/prepare_mono new file mode 100755 index 0000000..97ac06a --- /dev/null +++ b/scripts/prepare_mono @@ -0,0 +1,15 @@ +# update to the correct and actual mono version + + +echo "search for ubuntu version" +# check if we are on Ubuntu + + +set -e +sudo apt install gnupg ca-certificates -y +sudo apt-get update -y +sudo apt-get install mono-complete -y +sudo apt-get autoremove -y +echo "Mono installation/upgrade complete for $repo." +exit 0 + diff --git a/scripts/prepare_ubuntu_pluto b/scripts/prepare_ubuntu_pluto new file mode 100755 index 0000000..4ef77ff --- /dev/null +++ b/scripts/prepare_ubuntu_pluto @@ -0,0 +1,102 @@ +set -e +echo "Install libraries for QO100_Transceiver" +echo "=======================================" + +echo "installing standard libraries ...please wait..." +sudo apt-get -qq update +sudo apt-get -y install build-essential libxml2-dev bison flex libcdk5-dev cmake libaio-dev libusb-1.0-0-dev libserialport-dev libavahi-client-dev +sudo apt-get -y install libasound2-dev libfftw3-dev sndfile-tools libsndfile1-dev git libad9361-dev +sudo apt-get -y install autotools-dev automake pavucontrol gpiod libgpiod-dev libpuls* + +# install newest mono version (mono from standard repositories is always too old) +echo "mono (.NET): install latest version" +pwd +sh ./prepare_mono + + +# copy prebuild libraries to lib folder +#echo "install SDR and DSP libraries" +#LIBNAME=$(find /usr -name libfftw3*.so | head -1) +#LIBFOLDER=$(dirname $LIBNAME) +#ARCHITECTURE=$(uname -m) +#if [ ${ARCHITECTURE} == 'x86_64' ]; then +# echo "install Intel/AMD 64 bit ${ARCHITECTURE} libs to $LIBFOLDER" +# sudo cp ./libs/$ARCHITECTURE/* $LIBFOLDER +#elif [ ${ARCHITECTURE} == 'aarch64' ]; then +# echo "install ARM 64 bit ${ARCHITECTURE} libs to $LIBFOLDER" +# sudo cp ./libs/$ARCHITECTURE/* $LIBFOLDER +#elif [ ${ARCHITECTURE} == 'armv7l' ]; then +# echo "install ARM 32 bit ${ARCHITECTURE} libs to $LIBFOLDER" +# sudo cp ./libs/armhf/* $LIBFOLDER +#else + set -e + echo "=======================================================" + echo "Install original libs for QO100_Transceiver from github" + echo "=======================================================" + + # copy prebuild libraries to lib folder + cd /tmp + mkdir -p qo100trx_libraries + cd qo100trx_libraries + + if [ ! -d "libiio" ] ; then + git clone https://github.com/dj0abr/libiio.git + cd libiio + else + cd libiio + git pull https://github.com/dj0abr/libiio.git + fi + mkdir -p build + cd build + cmake ../ + make -j$(nproc) + sudo make install + cd .. + cd .. + + if [ ! -d "libad9361-iio" ] ; then + git clone https://github.com/dj0abr/libad9361-iio + cd libad9361-iio + else + cd libad9361-iio + git pull https://github.com/dj0abr/libad9361-iio + fi + mkdir -p build + cd build + cmake ../ + make -j$(nproc) + sudo make install + cd .. + cd .. + + if [ ! -d "liquid-dsp" ] ; then + git clone https://github.com/dj0abr/liquid-dsp + cd liquid-dsp + else + cd liquid-dsp + git pull https://github.com/dj0abr/liquid-dsp + fi + ./bootstrap.sh + ./configure + make -j$(nproc) + sudo make install + cd .. + + if [ ! -d "libsoundio" ] ; then + git clone https://github.com/dj0abr/libsoundio + cd libsoundio + else + cd libsoundio + git pull https://github.com/dj0abr/libsoundio + fi + mkdir -p build + cd build + cmake ../ + make -j$(nproc) + sudo make install +#fi + +echo ============================= +echo Library installation finished +echo ============================= +exit 0 diff --git a/scripts/qo100trx.desktop b/scripts/qo100trx.desktop new file mode 100755 index 0000000..6aeb319 --- /dev/null +++ b/scripts/qo100trx.desktop @@ -0,0 +1,9 @@ +[Desktop Entry] +Name=QO100 transceiver +Comment=Start the Pluto QO100 Transceiver +Icon=/home/pi/QO100_Transceiver/ai.ico +Exec=lxterminal -e /home/pi/QO100_Transceiver/scripts/startTRX +Type=Application +Encoding=UTF-8 +Terminal=false +Categories=None; diff --git a/scripts/startTRX b/scripts/startTRX new file mode 100755 index 0000000..05801e6 --- /dev/null +++ b/scripts/startTRX @@ -0,0 +1,3 @@ +cd /home/pi/QO100_Transceiver/Release +./startQO100trx + diff --git a/trxGui/.vs/trxGui/v16/.suo b/trxGui/.vs/trxGui/v16/.suo new file mode 100644 index 0000000..12ea294 Binary files /dev/null and b/trxGui/.vs/trxGui/v16/.suo differ diff --git a/trxGui/App.config b/trxGui/App.config new file mode 100644 index 0000000..d740e88 --- /dev/null +++ b/trxGui/App.config @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/trxGui/Form1.Designer.cs b/trxGui/Form1.Designer.cs new file mode 100755 index 0000000..b8c077a --- /dev/null +++ b/trxGui/Form1.Designer.cs @@ -0,0 +1,486 @@ + +namespace trxGui +{ + partial class Form1 + { + /// + /// Erforderliche Designervariable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Verwendete Ressourcen bereinigen. + /// + /// True, wenn verwaltete Ressourcen gelöscht werden sollen; andernfalls False. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Vom Windows Form-Designer generierter Code + + /// + /// Erforderliche Methode für die Designerunterstützung. + /// Der Inhalt der Methode darf nicht mit dem Code-Editor geändert werden. + /// + private void InitializeComponent() + { + this.components = new System.ComponentModel.Container(); + System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(Form1)); + this.timer_draw = new System.Windows.Forms.Timer(this.components); + this.panel1 = new System.Windows.Forms.Panel(); + this.panel_qrg = new System.Windows.Forms.Panel(); + this.panel_rit = new System.Windows.Forms.Panel(); + this.panel_xit = new System.Windows.Forms.Panel(); + this.panel_copyRtoT = new System.Windows.Forms.Panel(); + this.panel_copyTtoR = new System.Windows.Forms.Panel(); + this.panel_agc = new System.Windows.Forms.Panel(); + this.panel_txmute = new System.Windows.Forms.Panel(); + this.panel_comp = new System.Windows.Forms.Panel(); + this.panel_rxfilter = new System.Windows.Forms.Panel(); + this.panel_txfilter = new System.Windows.Forms.Panel(); + this.panel_rfloop = new System.Windows.Forms.Panel(); + this.panel_audioloop = new System.Windows.Forms.Panel(); + this.panel_sync = new System.Windows.Forms.Panel(); + this.panel_beaconlock = new System.Windows.Forms.Panel(); + this.panel_pavucontrol = new System.Windows.Forms.Panel(); + this.panel_info = new System.Windows.Forms.Panel(); + this.panel_setup = new System.Windows.Forms.Panel(); + this.panel_switchbandplan = new System.Windows.Forms.Panel(); + this.panel_screen = new System.Windows.Forms.Panel(); + this.panel_recall = new System.Windows.Forms.Panel(); + this.panel_save = new System.Windows.Forms.Panel(); + this.panel_testtone = new System.Windows.Forms.Panel(); + this.panel_rxline = new trxGui.DoubleBufferedPanel(); + this.panel_bigspec = new trxGui.DoubleBufferedPanel(); + this.panel_bigwf = new trxGui.DoubleBufferedPanel(); + this.panel_bandplan = new trxGui.DoubleBufferedPanel(); + this.panel_smallwf = new trxGui.DoubleBufferedPanel(); + this.panel_smallspec = new trxGui.DoubleBufferedPanel(); + this.panel_smallqrg = new trxGui.DoubleBufferedPanel(); + this.SuspendLayout(); + // + // timer_draw + // + this.timer_draw.Interval = 60; + this.timer_draw.Tick += new System.EventHandler(this.timer_draw_Tick); + // + // panel1 + // + this.panel1.BackColor = System.Drawing.Color.Yellow; + this.panel1.Location = new System.Drawing.Point(748, 724); + this.panel1.Name = "panel1"; + this.panel1.Size = new System.Drawing.Size(187, 33); + this.panel1.TabIndex = 11; + this.panel1.Paint += new System.Windows.Forms.PaintEventHandler(this.panel1_Paint); + this.panel1.MouseClick += new System.Windows.Forms.MouseEventHandler(this.panel1_MouseClick); + this.panel1.MouseDown += new System.Windows.Forms.MouseEventHandler(this.panel1_MouseDown); + this.panel1.MouseUp += new System.Windows.Forms.MouseEventHandler(this.panel1_MouseUp); + // + // panel_qrg + // + this.panel_qrg.BackColor = System.Drawing.Color.Gray; + this.panel_qrg.Location = new System.Drawing.Point(68, 3); + this.panel_qrg.Name = "panel_qrg"; + this.panel_qrg.Size = new System.Drawing.Size(1064, 41); + this.panel_qrg.TabIndex = 5; + this.panel_qrg.Paint += new System.Windows.Forms.PaintEventHandler(this.panel_qrg_Paint); + // + // panel_rit + // + this.panel_rit.BackColor = System.Drawing.Color.White; + this.panel_rit.BackgroundImage = global::trxGui.Properties.Resources.rxqrg; + this.panel_rit.BackgroundImageLayout = System.Windows.Forms.ImageLayout.Zoom; + this.panel_rit.Location = new System.Drawing.Point(14, 709); + this.panel_rit.Name = "panel_rit"; + this.panel_rit.Size = new System.Drawing.Size(48, 48); + this.panel_rit.TabIndex = 15; + this.panel_rit.Click += new System.EventHandler(this.panel_rit_Click); + this.panel_rit.Paint += new System.Windows.Forms.PaintEventHandler(this.panel_rit_Paint); + // + // panel_xit + // + this.panel_xit.BackColor = System.Drawing.Color.White; + this.panel_xit.BackgroundImage = global::trxGui.Properties.Resources.txqrg; + this.panel_xit.BackgroundImageLayout = System.Windows.Forms.ImageLayout.Zoom; + this.panel_xit.Location = new System.Drawing.Point(68, 709); + this.panel_xit.Name = "panel_xit"; + this.panel_xit.Size = new System.Drawing.Size(48, 48); + this.panel_xit.TabIndex = 15; + this.panel_xit.Click += new System.EventHandler(this.panel_xit_Click); + this.panel_xit.Paint += new System.Windows.Forms.PaintEventHandler(this.panel_xit_Paint); + // + // panel_copyRtoT + // + this.panel_copyRtoT.BackColor = System.Drawing.Color.White; + this.panel_copyRtoT.Location = new System.Drawing.Point(122, 710); + this.panel_copyRtoT.Name = "panel_copyRtoT"; + this.panel_copyRtoT.Size = new System.Drawing.Size(48, 48); + this.panel_copyRtoT.TabIndex = 16; + this.panel_copyRtoT.Click += new System.EventHandler(this.panel_copyRtoT_Click); + this.panel_copyRtoT.Paint += new System.Windows.Forms.PaintEventHandler(this.panel_copyRtoT_Paint); + // + // panel_copyTtoR + // + this.panel_copyTtoR.BackColor = System.Drawing.Color.White; + this.panel_copyTtoR.Location = new System.Drawing.Point(176, 709); + this.panel_copyTtoR.Name = "panel_copyTtoR"; + this.panel_copyTtoR.Size = new System.Drawing.Size(48, 48); + this.panel_copyTtoR.TabIndex = 16; + this.panel_copyTtoR.Click += new System.EventHandler(this.panel_copyTtoR_Click); + this.panel_copyTtoR.Paint += new System.Windows.Forms.PaintEventHandler(this.panel_copyTtoR_Paint); + // + // panel_agc + // + this.panel_agc.BackColor = System.Drawing.Color.White; + this.panel_agc.Location = new System.Drawing.Point(230, 710); + this.panel_agc.Name = "panel_agc"; + this.panel_agc.Size = new System.Drawing.Size(48, 48); + this.panel_agc.TabIndex = 17; + this.panel_agc.Click += new System.EventHandler(this.panel_agc_Click); + this.panel_agc.Paint += new System.Windows.Forms.PaintEventHandler(this.panel_agc_Paint); + // + // panel_txmute + // + this.panel_txmute.BackColor = System.Drawing.Color.White; + this.panel_txmute.BackgroundImageLayout = System.Windows.Forms.ImageLayout.Zoom; + this.panel_txmute.Location = new System.Drawing.Point(284, 709); + this.panel_txmute.Name = "panel_txmute"; + this.panel_txmute.Size = new System.Drawing.Size(48, 48); + this.panel_txmute.TabIndex = 17; + this.panel_txmute.Click += new System.EventHandler(this.panel_txmute_Click); + this.panel_txmute.Paint += new System.Windows.Forms.PaintEventHandler(this.panel_txmute_Paint); + // + // panel_comp + // + this.panel_comp.BackColor = System.Drawing.Color.White; + this.panel_comp.BackgroundImageLayout = System.Windows.Forms.ImageLayout.Zoom; + this.panel_comp.Location = new System.Drawing.Point(338, 710); + this.panel_comp.Name = "panel_comp"; + this.panel_comp.Size = new System.Drawing.Size(48, 48); + this.panel_comp.TabIndex = 18; + this.panel_comp.Click += new System.EventHandler(this.panel_comp_Click); + this.panel_comp.Paint += new System.Windows.Forms.PaintEventHandler(this.panel_comp_Paint); + // + // panel_rxfilter + // + this.panel_rxfilter.BackColor = System.Drawing.Color.White; + this.panel_rxfilter.BackgroundImageLayout = System.Windows.Forms.ImageLayout.Zoom; + this.panel_rxfilter.Location = new System.Drawing.Point(392, 710); + this.panel_rxfilter.Name = "panel_rxfilter"; + this.panel_rxfilter.Size = new System.Drawing.Size(48, 48); + this.panel_rxfilter.TabIndex = 19; + this.panel_rxfilter.Click += new System.EventHandler(this.panel_rxfilter_Click); + this.panel_rxfilter.Paint += new System.Windows.Forms.PaintEventHandler(this.panel_rxfilter_Paint); + // + // panel_txfilter + // + this.panel_txfilter.BackColor = System.Drawing.Color.White; + this.panel_txfilter.BackgroundImageLayout = System.Windows.Forms.ImageLayout.Zoom; + this.panel_txfilter.Location = new System.Drawing.Point(446, 710); + this.panel_txfilter.Name = "panel_txfilter"; + this.panel_txfilter.Size = new System.Drawing.Size(48, 48); + this.panel_txfilter.TabIndex = 19; + this.panel_txfilter.Click += new System.EventHandler(this.panel_txfilter_Click); + this.panel_txfilter.Paint += new System.Windows.Forms.PaintEventHandler(this.panel_txfilter_Paint); + // + // panel_rfloop + // + this.panel_rfloop.BackColor = System.Drawing.Color.White; + this.panel_rfloop.BackgroundImageLayout = System.Windows.Forms.ImageLayout.Zoom; + this.panel_rfloop.Location = new System.Drawing.Point(610, 710); + this.panel_rfloop.Name = "panel_rfloop"; + this.panel_rfloop.Size = new System.Drawing.Size(48, 48); + this.panel_rfloop.TabIndex = 20; + this.panel_rfloop.Click += new System.EventHandler(this.panel_rfloop_Click); + this.panel_rfloop.Paint += new System.Windows.Forms.PaintEventHandler(this.panel_rfloop_Paint); + // + // panel_audioloop + // + this.panel_audioloop.BackColor = System.Drawing.Color.White; + this.panel_audioloop.BackgroundImageLayout = System.Windows.Forms.ImageLayout.Zoom; + this.panel_audioloop.Location = new System.Drawing.Point(556, 710); + this.panel_audioloop.Name = "panel_audioloop"; + this.panel_audioloop.Size = new System.Drawing.Size(48, 48); + this.panel_audioloop.TabIndex = 21; + this.panel_audioloop.Click += new System.EventHandler(this.panel_audioloop_Click); + this.panel_audioloop.Paint += new System.Windows.Forms.PaintEventHandler(this.panel_audioloop_Paint); + // + // panel_sync + // + this.panel_sync.BackgroundImage = global::trxGui.Properties.Resources.gauge; + this.panel_sync.BackgroundImageLayout = System.Windows.Forms.ImageLayout.None; + this.panel_sync.Location = new System.Drawing.Point(12, 59); + this.panel_sync.Name = "panel_sync"; + this.panel_sync.Size = new System.Drawing.Size(26, 17); + this.panel_sync.TabIndex = 22; + this.panel_sync.Click += new System.EventHandler(this.panel_sync_Click); + this.panel_sync.Paint += new System.Windows.Forms.PaintEventHandler(this.panel_sync_Paint); + // + // panel_beaconlock + // + this.panel_beaconlock.BackColor = System.Drawing.Color.Gray; + this.panel_beaconlock.BackgroundImage = global::trxGui.Properties.Resources.lock_open; + this.panel_beaconlock.BackgroundImageLayout = System.Windows.Forms.ImageLayout.None; + this.panel_beaconlock.Location = new System.Drawing.Point(14, 82); + this.panel_beaconlock.Name = "panel_beaconlock"; + this.panel_beaconlock.Size = new System.Drawing.Size(26, 17); + this.panel_beaconlock.TabIndex = 23; + this.panel_beaconlock.Click += new System.EventHandler(this.panel_beaconlock_Click); + this.panel_beaconlock.Paint += new System.Windows.Forms.PaintEventHandler(this.panel_beaconlock_Paint); + // + // panel_pavucontrol + // + this.panel_pavucontrol.BackColor = System.Drawing.Color.White; + this.panel_pavucontrol.BackgroundImage = global::trxGui.Properties.Resources.mixer; + this.panel_pavucontrol.BackgroundImageLayout = System.Windows.Forms.ImageLayout.Zoom; + this.panel_pavucontrol.Location = new System.Drawing.Point(976, 710); + this.panel_pavucontrol.Name = "panel_pavucontrol"; + this.panel_pavucontrol.Size = new System.Drawing.Size(48, 48); + this.panel_pavucontrol.TabIndex = 21; + this.panel_pavucontrol.Click += new System.EventHandler(this.panel_pavucontrol_Click); + // + // panel_info + // + this.panel_info.BackColor = System.Drawing.Color.White; + this.panel_info.BackgroundImage = global::trxGui.Properties.Resources.amsat_icon; + this.panel_info.BackgroundImageLayout = System.Windows.Forms.ImageLayout.Zoom; + this.panel_info.Location = new System.Drawing.Point(1084, 710); + this.panel_info.Name = "panel_info"; + this.panel_info.Size = new System.Drawing.Size(48, 48); + this.panel_info.TabIndex = 15; + this.panel_info.Click += new System.EventHandler(this.bt_info_click); + // + // panel_setup + // + this.panel_setup.BackColor = System.Drawing.Color.White; + this.panel_setup.BackgroundImage = global::trxGui.Properties.Resources.setup; + this.panel_setup.BackgroundImageLayout = System.Windows.Forms.ImageLayout.Zoom; + this.panel_setup.Location = new System.Drawing.Point(1030, 710); + this.panel_setup.Name = "panel_setup"; + this.panel_setup.Size = new System.Drawing.Size(48, 48); + this.panel_setup.TabIndex = 14; + this.panel_setup.Click += new System.EventHandler(this.butto_setup_click); + // + // panel_switchbandplan + // + this.panel_switchbandplan.BackColor = System.Drawing.Color.White; + this.panel_switchbandplan.BackgroundImage = global::trxGui.Properties.Resources.swband; + this.panel_switchbandplan.BackgroundImageLayout = System.Windows.Forms.ImageLayout.Stretch; + this.panel_switchbandplan.Location = new System.Drawing.Point(1106, 200); + this.panel_switchbandplan.Name = "panel_switchbandplan"; + this.panel_switchbandplan.Size = new System.Drawing.Size(26, 10); + this.panel_switchbandplan.TabIndex = 24; + this.panel_switchbandplan.Click += new System.EventHandler(this.panel_switchbandplan_Click); + // + // panel_screen + // + this.panel_screen.BackColor = System.Drawing.Color.Gray; + this.panel_screen.BackgroundImage = global::trxGui.Properties.Resources.monitor; + this.panel_screen.BackgroundImageLayout = System.Windows.Forms.ImageLayout.Zoom; + this.panel_screen.Location = new System.Drawing.Point(3, 3); + this.panel_screen.Name = "panel_screen"; + this.panel_screen.Size = new System.Drawing.Size(37, 41); + this.panel_screen.TabIndex = 23; + this.panel_screen.Click += new System.EventHandler(this.panel_screen_Click); + // + // panel_recall + // + this.panel_recall.BackColor = System.Drawing.Color.Gray; + this.panel_recall.BackgroundImage = global::trxGui.Properties.Resources.read; + this.panel_recall.BackgroundImageLayout = System.Windows.Forms.ImageLayout.None; + this.panel_recall.Location = new System.Drawing.Point(14, 133); + this.panel_recall.Name = "panel_recall"; + this.panel_recall.Size = new System.Drawing.Size(26, 17); + this.panel_recall.TabIndex = 24; + this.panel_recall.Click += new System.EventHandler(this.panel_recall_Click); + // + // panel_save + // + this.panel_save.BackColor = System.Drawing.Color.Gray; + this.panel_save.BackgroundImage = ((System.Drawing.Image)(resources.GetObject("panel_save.BackgroundImage"))); + this.panel_save.BackgroundImageLayout = System.Windows.Forms.ImageLayout.None; + this.panel_save.Location = new System.Drawing.Point(12, 105); + this.panel_save.Name = "panel_save"; + this.panel_save.Size = new System.Drawing.Size(26, 17); + this.panel_save.TabIndex = 25; + this.panel_save.Click += new System.EventHandler(this.panel_save_Click); + // + // panel_testtone + // + this.panel_testtone.BackColor = System.Drawing.Color.Gray; + this.panel_testtone.BackgroundImage = global::trxGui.Properties.Resources.wave; + this.panel_testtone.BackgroundImageLayout = System.Windows.Forms.ImageLayout.None; + this.panel_testtone.Location = new System.Drawing.Point(12, 156); + this.panel_testtone.Name = "panel_testtone"; + this.panel_testtone.Size = new System.Drawing.Size(26, 17); + this.panel_testtone.TabIndex = 26; + this.panel_testtone.Click += new System.EventHandler(this.panel_testtone_Click); + this.panel_testtone.Paint += new System.Windows.Forms.PaintEventHandler(this.panel_testtone_Paint); + // + // panel_rxline + // + this.panel_rxline.BackColor = System.Drawing.Color.Gray; + this.panel_rxline.Location = new System.Drawing.Point(12, 366); + this.panel_rxline.Name = "panel_rxline"; + this.panel_rxline.Size = new System.Drawing.Size(1120, 12); + this.panel_rxline.TabIndex = 3; + this.panel_rxline.Paint += new System.Windows.Forms.PaintEventHandler(this.panel_rxline_Paint); + // + // panel_bigspec + // + this.panel_bigspec.BackColor = System.Drawing.Color.LightGray; + this.panel_bigspec.Location = new System.Drawing.Point(56, 50); + this.panel_bigspec.Name = "panel_bigspec"; + this.panel_bigspec.Size = new System.Drawing.Size(1076, 150); + this.panel_bigspec.TabIndex = 0; + this.panel_bigspec.Paint += new System.Windows.Forms.PaintEventHandler(this.panel_bigspec_Paint); + this.panel_bigspec.MouseClick += new System.Windows.Forms.MouseEventHandler(this.panel_bigwf_MouseClick); + this.panel_bigspec.MouseLeave += new System.EventHandler(this.panel_bigspec_MouseLeave); + this.panel_bigspec.MouseHover += new System.EventHandler(this.panel_bigspec_MouseHover); + this.panel_bigspec.MouseMove += new System.Windows.Forms.MouseEventHandler(this.panel_bigspec_MouseMove); + // + // panel_bigwf + // + this.panel_bigwf.BackColor = System.Drawing.Color.Black; + this.panel_bigwf.Location = new System.Drawing.Point(56, 213); + this.panel_bigwf.Name = "panel_bigwf"; + this.panel_bigwf.Size = new System.Drawing.Size(1076, 150); + this.panel_bigwf.TabIndex = 1; + this.panel_bigwf.Paint += new System.Windows.Forms.PaintEventHandler(this.panel_bigwf_Paint); + this.panel_bigwf.MouseClick += new System.Windows.Forms.MouseEventHandler(this.panel_bigwf_MouseClick); + this.panel_bigwf.MouseLeave += new System.EventHandler(this.panel_bigwf_MouseLeave); + this.panel_bigwf.MouseHover += new System.EventHandler(this.panel_bigwf_MouseHover); + this.panel_bigwf.MouseMove += new System.Windows.Forms.MouseEventHandler(this.panel_bigwf_MouseMove); + // + // panel_bandplan + // + this.panel_bandplan.BackColor = System.Drawing.Color.Silver; + this.panel_bandplan.Location = new System.Drawing.Point(52, 200); + this.panel_bandplan.Name = "panel_bandplan"; + this.panel_bandplan.Size = new System.Drawing.Size(1057, 10); + this.panel_bandplan.TabIndex = 1; + this.panel_bandplan.Paint += new System.Windows.Forms.PaintEventHandler(this.panel_bandplan_Paint); + // + // panel_smallwf + // + this.panel_smallwf.BackColor = System.Drawing.Color.Black; + this.panel_smallwf.Location = new System.Drawing.Point(12, 554); + this.panel_smallwf.Name = "panel_smallwf"; + this.panel_smallwf.Size = new System.Drawing.Size(1120, 150); + this.panel_smallwf.TabIndex = 1; + this.panel_smallwf.Paint += new System.Windows.Forms.PaintEventHandler(this.panel_smallwf_Paint); + this.panel_smallwf.MouseClick += new System.Windows.Forms.MouseEventHandler(this.panel_smallwf_MouseClick); + this.panel_smallwf.MouseLeave += new System.EventHandler(this.panel_smallwf_MouseLeave); + this.panel_smallwf.MouseHover += new System.EventHandler(this.panel_smallwf_MouseHover); + this.panel_smallwf.MouseMove += new System.Windows.Forms.MouseEventHandler(this.panel_smallwf_MouseMove); + // + // panel_smallspec + // + this.panel_smallspec.BackColor = System.Drawing.Color.LightGray; + this.panel_smallspec.Location = new System.Drawing.Point(12, 384); + this.panel_smallspec.Name = "panel_smallspec"; + this.panel_smallspec.Size = new System.Drawing.Size(1120, 150); + this.panel_smallspec.TabIndex = 1; + this.panel_smallspec.Paint += new System.Windows.Forms.PaintEventHandler(this.panel_smallspec_Paint); + this.panel_smallspec.MouseClick += new System.Windows.Forms.MouseEventHandler(this.panel_smallwf_MouseClick); + this.panel_smallspec.MouseLeave += new System.EventHandler(this.panel_smallspec_MouseLeave); + this.panel_smallspec.MouseHover += new System.EventHandler(this.panel_smallspec_MouseHover); + this.panel_smallspec.MouseMove += new System.Windows.Forms.MouseEventHandler(this.panel_smallspec_MouseMove); + // + // panel_smallqrg + // + this.panel_smallqrg.BackColor = System.Drawing.Color.Silver; + this.panel_smallqrg.Location = new System.Drawing.Point(14, 536); + this.panel_smallqrg.Name = "panel_smallqrg"; + this.panel_smallqrg.Size = new System.Drawing.Size(1120, 12); + this.panel_smallqrg.TabIndex = 2; + this.panel_smallqrg.Paint += new System.Windows.Forms.PaintEventHandler(this.panel_smallqrg_Paint); + // + // Form1 + // + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.BackColor = System.Drawing.Color.Gray; + this.ClientSize = new System.Drawing.Size(1147, 775); + this.Controls.Add(this.panel_testtone); + this.Controls.Add(this.panel_save); + this.Controls.Add(this.panel_recall); + this.Controls.Add(this.panel_screen); + this.Controls.Add(this.panel_switchbandplan); + this.Controls.Add(this.panel_beaconlock); + this.Controls.Add(this.panel_sync); + this.Controls.Add(this.panel_rxline); + this.Controls.Add(this.panel_pavucontrol); + this.Controls.Add(this.panel1); + this.Controls.Add(this.panel_rfloop); + this.Controls.Add(this.panel_txfilter); + this.Controls.Add(this.panel_audioloop); + this.Controls.Add(this.panel_rxfilter); + this.Controls.Add(this.panel_comp); + this.Controls.Add(this.panel_txmute); + this.Controls.Add(this.panel_agc); + this.Controls.Add(this.panel_copyTtoR); + this.Controls.Add(this.panel_copyRtoT); + this.Controls.Add(this.panel_xit); + this.Controls.Add(this.panel_rit); + this.Controls.Add(this.panel_info); + this.Controls.Add(this.panel_setup); + this.Controls.Add(this.panel_qrg); + this.Controls.Add(this.panel_bigspec); + this.Controls.Add(this.panel_bigwf); + this.Controls.Add(this.panel_bandplan); + this.Controls.Add(this.panel_smallwf); + this.Controls.Add(this.panel_smallspec); + this.Controls.Add(this.panel_smallqrg); + this.Font = new System.Drawing.Font("Microsoft Sans Serif", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.Icon = ((System.Drawing.Icon)(resources.GetObject("$this.Icon"))); + this.MaximizeBox = false; + this.MinimizeBox = false; + this.Name = "Form1"; + this.SizeGripStyle = System.Windows.Forms.SizeGripStyle.Hide; + this.Text = "Amsat-DL QO100 Linux - Pluto Transceiver (by DJ0ABR)"; + this.FormClosing += new System.Windows.Forms.FormClosingEventHandler(this.Form1_FormClosing); + this.ResumeLayout(false); + + } + + #endregion + private System.Windows.Forms.Timer timer_draw; + private DoubleBufferedPanel panel_smallqrg; + private DoubleBufferedPanel panel_bandplan; + private DoubleBufferedPanel panel_smallwf; + private DoubleBufferedPanel panel_smallspec; + private DoubleBufferedPanel panel_bigwf; + private DoubleBufferedPanel panel_bigspec; + private System.Windows.Forms.Panel panel1; + private System.Windows.Forms.Panel panel_qrg; + private System.Windows.Forms.Panel panel_setup; + private System.Windows.Forms.Panel panel_info; + private System.Windows.Forms.Panel panel_rit; + private System.Windows.Forms.Panel panel_xit; + private System.Windows.Forms.Panel panel_copyRtoT; + private System.Windows.Forms.Panel panel_copyTtoR; + private System.Windows.Forms.Panel panel_agc; + private System.Windows.Forms.Panel panel_txmute; + private System.Windows.Forms.Panel panel_comp; + private System.Windows.Forms.Panel panel_rxfilter; + private System.Windows.Forms.Panel panel_txfilter; + private System.Windows.Forms.Panel panel_rfloop; + private System.Windows.Forms.Panel panel_audioloop; + private System.Windows.Forms.Panel panel_pavucontrol; + private DoubleBufferedPanel panel_rxline; + private System.Windows.Forms.Panel panel_sync; + private System.Windows.Forms.Panel panel_beaconlock; + private System.Windows.Forms.Panel panel_switchbandplan; + private System.Windows.Forms.Panel panel_screen; + private System.Windows.Forms.Panel panel_recall; + private System.Windows.Forms.Panel panel_save; + private System.Windows.Forms.Panel panel_testtone; + } +} + diff --git a/trxGui/Form1.cs b/trxGui/Form1.cs new file mode 100755 index 0000000..375c84b --- /dev/null +++ b/trxGui/Form1.cs @@ -0,0 +1,1762 @@ +using System; +using System.Drawing; +using System.IO; +using System.Windows.Forms; + +namespace trxGui +{ + public partial class Form1 : Form + { + int window_width = 800; + int window_height = 480; + int spec_height = 88; + int wf_height = 70; + int button_size = 32; + Font bigfnt; + int lastsendtone = 0; + bool old_hwptt = false; + bool pttkey_pressed = false; + static public UdpQueue valq = new UdpQueue(); + + String screensafertime = ""; + + public Form1() + { + InitializeComponent(); + + try + { + String s = statics.RunExternalProgram("gsettings", "get org.gnome.desktop.session idle-delay"); + screensafertime = s.Substring(7); + Console.WriteLine("disable screen saver. Time was:"+screensafertime); + statics.RunExternalProgram("gsettings", "set org.gnome.desktop.session idle-delay 0"); + } + catch + { + screensafertime = ""; + } + + load_Setup(); + + panel_bigwf.MouseWheel += panel_bigwf_MouseWheel; + panel_bigspec.MouseWheel += panel_bigwf_MouseWheel; + + panel_smallwf.MouseWheel += panel_smallwf_MouseWheel; + panel_smallspec.MouseWheel += panel_smallwf_MouseWheel; + + // set the position of the GUI elements for various screen resolutions + scaleElements(); + + // center in screen, this makes it easy to use or adapt to screen sizes + CenterToScreen(); + + // test OS type + OperatingSystem osversion = System.Environment.OSVersion; + if (osversion.VersionString.Contains("indow")) + statics.ostype = 0; // Win$ + else + statics.ostype = 1; // Linux + + // if this program was started from another loacation + // set the working directory to the path of the .exe file + // so it can find trxdriver + try + { + String s = System.Reflection.Assembly.GetExecutingAssembly().Location; + s = Path.GetDirectoryName(s); + Directory.SetCurrentDirectory(s); + Console.WriteLine("working path: " + s); + } + catch (Exception e) + { + Console.WriteLine("cannot set working path: " + e.ToString()); + } + + Udp.InitUdp(); + + statics.StartQO100trx(); + + timer_draw.Start(); + + sendAndRefreshRXTXoffset(); + } + + // buttons left side, vertical row + int but_left_leftmargin = 5; + int but_left_topmargin = 4; + int but_left_width = 24; + int but_left_heigth = 36; + int but_left_spacing = 4; + + void scaleElements() + { + int wsize = 0; + if (statics.windowsize == wsize++) + { + // sizes for screens 1920x1080 pixel + window_width = 1920; + window_height = 1080; + button_size = 64; + bigfnt = new Font("Verdana", 24.0f); + } + + if (statics.windowsize == wsize++) + { + // sizes for screens 1600x1050 pixel + window_width = 1600; + window_height = 1050; + button_size = 64; + bigfnt = new Font("Verdana", 24.0f); + } + + if (statics.windowsize == wsize++) + { + // sizes for screens 1200x720 pixel + window_width = 1155; + window_height = 720; + button_size = 48; + bigfnt = new Font("Verdana", 24.0f); + } + + if (statics.windowsize == wsize++) + { + // sizes for screens 1200x480 pixel + window_width = 1155; + window_height = 480; + button_size = 32; + bigfnt = new Font("Verdana", 24.0f); + } + + if (statics.windowsize == wsize++) + { + // sizes for screens 1024x768 pixel + window_width = 1024; + window_height = 768; + button_size = 40; + bigfnt = new Font("Verdana", 24.0f); + } + + if (statics.windowsize == wsize++) + { + // sizes for screens 1024x600 pixel + window_width = 1024; + window_height = 600; + button_size = 32; + bigfnt = new Font("Verdana", 24.0f); + } + + if (statics.windowsize == wsize++) + { + // sizes for screens 800x600 pixel + window_width = 800; + window_height = 600; + button_size = 32; + bigfnt = new Font("Verdana", 14.0f); + } + + if (statics.windowsize == wsize++) + { + // sizes for screens 800x480 pixel + window_width = 800; + window_height = 480; + button_size = 32; + bigfnt = new Font("Verdana", 14.0f); + } + + if (statics.windowsize == wsize++) + { + // sizes for screens 640x480 pixel + window_width = 640; + window_height = 480; + button_size = 32; + bigfnt = new Font("Verdana", 14.0f); + } + + if (statics.windowsize == wsize++) + { + // sizes for screens 480x320 pixel + window_width = 480; + window_height = 320; + button_size = 20; + bigfnt = new Font("Verdana", 12.0f); + } + + // size of complete window + this.Width = window_width; + this.Height = window_height; + + panel_screen.Location = new Point(but_left_leftmargin, but_left_topmargin+40); + panel_screen.Width = but_left_width; + panel_screen.Height = but_left_heigth; + + panel_sync.Location = new Point(but_left_leftmargin, panel_screen.Location.Y + panel_screen.Height + but_left_spacing); + panel_sync.Width = but_left_width; + panel_sync.Height = but_left_heigth; + + panel_beaconlock.Location = new Point(but_left_leftmargin, panel_sync.Location.Y + panel_sync.Height + but_left_spacing); + panel_beaconlock.Width = but_left_width; + panel_beaconlock.Height = but_left_heigth; + + panel_save.Location = new Point(but_left_leftmargin, panel_beaconlock.Location.Y + panel_beaconlock.Height + but_left_spacing); + panel_save.Width = but_left_width; + panel_save.Height = but_left_heigth; + + panel_recall.Location = new Point(but_left_leftmargin, panel_save.Location.Y + panel_save.Height + but_left_spacing); + panel_recall.Width = but_left_width; + panel_recall.Height = but_left_heigth; + + panel_testtone.Location = new Point(but_left_leftmargin, panel_recall.Location.Y + panel_recall.Height + but_left_spacing); + panel_testtone.Width = but_left_width; + panel_testtone.Height = but_left_heigth; + + + // main panels + int left = panel_screen.Location.X + panel_screen.Width + 4; + int panel_width = window_width - 15 - left; + int diagspacey = RectangleToScreen(ClientRectangle).Height - but_left_topmargin - 5 - 40 - 16 - 15 - 16 - 4 - button_size - 5; + spec_height = diagspacey / 4; + wf_height = diagspacey / 4; + + panel_qrg.Location = new Point(left, but_left_topmargin); + panel_qrg.Width = panel_width; + panel_qrg.Height = 40; + + + panel_bigspec.Width = panel_width; + panel_bigspec.Height = spec_height; + + panel_switchbandplan.Width = 16; + panel_switchbandplan.Height = 16; + + panel_bandplan.Width = panel_width - panel_switchbandplan.Width; + panel_bandplan.Height = 16; + + panel_bigwf.Width = panel_width; + panel_bigwf.Height = wf_height; + + panel_rxline.Width = panel_width; + panel_rxline.Height = 15; + + panel_smallspec.Width = panel_width; + panel_smallspec.Height = spec_height; + + panel_smallqrg.Width = panel_width; + panel_smallqrg.Height = 16; + + panel_smallwf.Width = panel_width; + panel_smallwf.Height = wf_height; + + + panel_bigspec.Location = new Point(left, panel_qrg.Location.Y + panel_qrg.Height + 5); + panel_bandplan.Location = new Point(left, panel_bigspec.Location.Y + panel_bigspec.Height); + panel_switchbandplan.Location = new Point(panel_bandplan.Location.X + panel_bandplan.Width, panel_bigspec.Location.Y + panel_bigspec.Height); + panel_bigwf.Location = new Point(left, panel_bandplan.Location.Y + panel_bandplan.Height); + + panel_rxline.Location = new Point(left, panel_bigwf.Location.Y + panel_bigwf.Height); + + panel_smallspec.Location = new Point(left, panel_rxline.Location.Y + panel_rxline.Height); + panel_smallqrg.Location = new Point(left, panel_smallspec.Location.Y + panel_smallspec.Height); + panel_smallwf.Location = new Point(left, panel_smallqrg.Location.Y + panel_smallqrg.Height); + + // bottom buttons + int xspace = 4; + + panel_pavucontrol.Size = panel_rxfilter.Size = panel_txfilter.Size = panel_rfloop.Size = panel_audioloop.Size = panel_comp.Size = panel_setup.Size = panel_info.Size = panel_rit.Size = panel_xit.Size = panel_copyRtoT.Size = panel_copyTtoR.Size = panel_agc.Size = panel_txmute.Size = new Size(button_size, button_size); + panel_rit.Location = new Point(left, panel_smallwf.Location.Y + panel_smallwf.Height + 4); + panel_xit.Location = new Point(panel_rit.Location.X + panel_rit.Width + xspace, panel_rit.Location.Y); + + panel_copyRtoT.Location = new Point(panel_xit.Location.X + panel_xit.Width + xspace + 6, panel_rit.Location.Y); + panel_copyTtoR.Location = new Point(panel_copyRtoT.Location.X + panel_copyRtoT.Width + xspace, panel_rit.Location.Y); + + panel_agc.Location = new Point(panel_copyTtoR.Location.X + panel_copyTtoR.Width + xspace + 6, panel_rit.Location.Y); + panel_txmute.Location = new Point(panel_agc.Location.X + panel_agc.Width + xspace, panel_rit.Location.Y); + panel_comp.Location = new Point(panel_txmute.Location.X + panel_txmute.Width + xspace, panel_rit.Location.Y); + + panel_rxfilter.Location = new Point(panel_comp.Location.X + panel_comp.Width + xspace + 6, panel_rit.Location.Y); + panel_txfilter.Location = new Point(panel_rxfilter.Location.X + panel_rxfilter.Width + xspace, panel_rit.Location.Y); + + panel_audioloop.Location = new Point(panel_txfilter.Location.X + panel_txfilter.Width + xspace + 6, panel_rit.Location.Y); + panel_rfloop.Location = new Point(panel_audioloop.Location.X + panel_audioloop.Width + xspace, panel_rit.Location.Y); + + panel_info.Location = new Point(panel_bigspec.Location.X + panel_bigspec.Width - panel_info.Width, panel_rit.Location.Y); + panel_setup.Location = new Point(panel_info.Location.X - panel_setup.Width - 5, panel_rit.Location.Y); + panel_pavucontrol.Location = new Point(panel_setup.Location.X - panel_pavucontrol.Width - 5, panel_rit.Location.Y); + + // PTT Panel + panel1.Location = new Point(panel_rfloop.Location.X + panel_rfloop.Width + xspace + 6, panel_rit.Location.Y); + panel1.Size = new Size(panel_pavucontrol.Location.X - panel1.Location.X - 6, panel_rfloop.Height); + + statics.panel_bigspec_Width = panel_bigspec.Width; + statics.panel_bigspec_Height = panel_bigspec.Height; + statics.panel_bigwf_Width = panel_bigwf.Width; + statics.panel_bigwf_Height = panel_bigwf.Height; + statics.panel_smallspec_Width = panel_smallspec.Width; + statics.panel_smallspec_Height = panel_smallspec.Height; + statics.panel_smallwf_Width = panel_smallwf.Width; + statics.panel_smallwf_Height = panel_smallwf.Height; + } + + DateTime dts = DateTime.UtcNow; + private void panel_bigspec_Paint(object sender, PaintEventArgs e) + { + Bitmap bm = Udp.getBigSpecBitmap(); + + if (bm != null) + { + e.Graphics.DrawImage(bm, 0, 0); + bm.Dispose(); + } + } + + bool pttstat = false; + + private void timer_draw_Tick(object sender, EventArgs e) + { + timer_draw.Stop(); + + if (Udp.getBigSpecBitmap_avail()) + { + panel_bigspec.Invalidate(); + } + + if (Udp.getSmallSpecBitmap_avail()) + { + panel_smallspec.Invalidate(); + } + + if (Udp.getBigWFBitmap_avail()) + { + panel_bigwf.Invalidate(); + } + + if (Udp.getSmallWFBitmap_avail()) + { + panel_smallwf.Invalidate(); + } + + if (statics.pttmode == 0) + { + // PTT on/off + if (Control.ModifierKeys == Keys.Shift && pttstat == false) + { + // PTT pressed (shift key) + statics.ptt = !statics.ptt; + panel1.Invalidate(); + setPTT(statics.ptt); + pttstat = true; + } + if (Control.ModifierKeys == Keys.None) + { + pttstat = false; + } + } + if (statics.pttmode == 1) + { + // Push to Talk + if (Control.ModifierKeys == Keys.Shift && !statics.ptt) + { + // PTT pressed (shift key) + statics.ptt = true; + pttkey_pressed = true; + panel1.Invalidate(); + setPTT(statics.ptt); + } + if (Control.ModifierKeys == Keys.None && statics.ptt && pttkey_pressed) + { + // PTT released (shift key) + statics.ptt = false; + pttkey_pressed = false; + panel1.Invalidate(); + setPTT(statics.ptt); + } + } + + // change color of PTT button if ptt state changed in the driver + if(statics.hwptt != old_hwptt) + { + old_hwptt = statics.hwptt; + statics.ptt = statics.hwptt; + panel1.Invalidate(); + } + + if (statics.GotAudioDevices == 1) + { + // this is called once just after the trxdriver has started + // do all init jobs here which needs a running trxdriver + + // just got the list of audio devices + statics.GotAudioDevices = 0; + + // check if the current selected device is in the new device list + bool pbfound = false; + foreach(String s in statics.AudioPBdevs) + { + if(s == statics.AudioPBdev) + { + pbfound = true; + break; + } + } + + bool capfound = false; + foreach (String s in statics.AudioCAPdevs) + { + if (s == statics.AudioCAPdev) + { + capfound = true; + break; + } + } + + if(!pbfound) + { + Console.WriteLine("NO Playback Device found, using default"); + if (statics.AudioPBdevs.Length == 0) + statics.AudioPBdev = "Default"; + else + statics.AudioPBdev = statics.AudioPBdevs[0]; + } + + if (!capfound) + { + Console.WriteLine("NO Captur Device found, using default"); + if (statics.AudioCAPdevs.Length == 0) + statics.AudioCAPdev = "Default"; + else + statics.AudioCAPdev = statics.AudioCAPdevs[0]; + } + + statics.newaudiodevs = true; + sendAudioDevs(); + statics.sendBaseQRG(); + sendPlutoAddress(); + panel_comp_Click(null, null); // send "compress" + panel_agc_Click(null, null); // send "AGC" + panel_txmute_Click(null, null); + panel_rxfilter_Click(null, null); + panel_txfilter_Click(null, null); + statics.sendReferenceOffset(statics.rfoffset); + sendCpuSpeed(); + sendTXpower(); + sendPTTmode(); + this.Text += " GUI: " + formatSN(statics.gui_serno) + " Driver: " + formatSN(statics.driver_serno); + // check consistency + if(statics.gui_serno != statics.driver_serno) + { + MessageBox.Show("Warning!\nGUI and Driver have different serial numbers. Please re-install this software", "Version Number Error", MessageBoxButtons.OK, MessageBoxIcon.Error); + } + // check for updates + try + { + using (StreamReader sr = new StreamReader("version.txt")) + { + int actver = ReadInt(sr); + Console.WriteLine("act version:" + actver); + if(actver > statics.gui_serno) + { + //MessageBox.Show("a new Version is avialable at Github:" + actver.ToString(), "NEW VERSION", MessageBoxButtons.OK, MessageBoxIcon.Information); + String nv = " (new:V" + ((double)actver / 100).ToString() + ")"; + this.Text += nv.Replace(',', '.'); + } + } + File.Delete("version.txt"); + } + catch { } + + panel_beaconlock.Invalidate(); + } + + if(statics.beaconoffset != oldbcnoffset) + { + oldbcnoffset = statics.beaconoffset; + panel_qrg.Invalidate(); + } + + int rsteps = Udp.GetRotary(); + if(rsteps != 0) + { + int b = Math.Abs(rsteps); + + int factor = 10000; + if (b == 1) factor = 25; + else if (b == 2) factor = 50; + else if (b == 3) factor = 100; + else if (b == 4) factor = 250; + else if (b == 5) factor = 500; + else if (b == 6) factor = 1000; + + if (rsteps > 0) factor = -factor; + + if (statics.rit) + statics.RXoffset += factor; + + if (statics.xit) + statics.TXoffset += factor; + + if (statics.rit || statics.xit) + sendAndRefreshRXTXoffset(); + } + + if (statics.corrfact != 0) + { + if (statics.corractive > 0) + { + if (statics.autosync) + { + Console.WriteLine("correct by corrfact: " + statics.corrfact); + statics.RXoffset -= statics.corrfact; + statics.TXoffset -= statics.corrfact; + sendAndRefreshRXTXoffset(); + } + statics.corractive--; + } + statics.corrfact = 0; + } + + if(lastsendtone != statics.sendtone) + { + panel_testtone.Invalidate(); + lastsendtone = statics.sendtone; + } + + if(valq.Count() > 0) + { + Byte[] tarr = valq.Getarr(); + Udp.UdpSendData(tarr); + } + + timer_draw.Start(); + } + + private String formatSN(int sn) + { + String s = "V"; + + s += (sn / 100).ToString(); + s += "."; + s += (sn - (sn / 100) * 100).ToString(); + + return s; + } + + int oldbcnoffset = -1; + + private void Form1_FormClosing(object sender, FormClosingEventArgs e) + { + statics.StartQO100trx(false); + save_Setup(); + if (screensafertime.Length > 0) + { + try + { + Console.WriteLine("restore screen saver time:" + screensafertime); + statics.RunExternalProgram("gsettings", "set org.gnome.desktop.session idle-delay " + screensafertime); + } + catch {} + } + statics.running = false; + } + + private void panel_smallspec_Paint(object sender, PaintEventArgs e) + { + Bitmap bm = Udp.getSmallSpecBitmap(); + + if (bm != null) + { + e.Graphics.DrawImage(bm, 0, 0); + bm.Dispose(); + } + } + + private void panel_bigwf_Paint(object sender, PaintEventArgs e) + { + Bitmap bm = Udp.getBigWFBitmap(); + + if (bm != null) + { + e.Graphics.DrawImage(bm, 0, 0); + bm.Dispose(); + } + } + + private void panel_smallwf_Paint(object sender, PaintEventArgs e) + { + Bitmap bm = Udp.getSmallWFBitmap(); + + if (bm != null) + { + e.Graphics.DrawImage(bm, 0, 0); + bm.Dispose(); + } + } + + private void panel_bigwf_MouseClick(object sender, MouseEventArgs e) + { + tuneBig(e); + statics.corractive = statics.corractiveanz; + } + + private void panel_smallwf_MouseClick(object sender, MouseEventArgs e) + { + tuneSmall(e); + } + + private void tuneBig(MouseEventArgs e) + { + int x = e.X; + x = x * 1120 / panel_bigspec.Width; + + // left mouse button or touch panel click + if (e.Button == MouseButtons.Left) + { + if (statics.calmode == 0) + { + // normal operation + // if both, RX and TX, is selected, keep offset between RX and TX + if (statics.rit && statics.xit) + { + statics.RXTXoffset = statics.RXoffset - statics.TXoffset; + statics.RXoffset = x * 500; + statics.TXoffset = x * 500 - statics.RXTXoffset; + } + else if (statics.rit) + statics.RXoffset = x * 500; + else if (statics.xit) + statics.TXoffset = x * 500; + + statics.RXTXoffset = statics.RXoffset - statics.TXoffset; + + sendAndRefreshRXTXoffset(); + } + else if (statics.calmode == 1) + { + // cal to BPSK beacon + int off = x * 500 - 280000; + //Console.WriteLine("Pluto offset: " + off + " Hz"); + if(off > 0) + statics.calfreq += (UInt32)off; + else if (off < 0) + statics.calfreq -= (UInt32)(-off); + + statics.sendBaseQRG(statics.calfreq); + } + else if (statics.calmode == 2) + { + int off = x * 500 - 280000; + //Console.WriteLine("offset: " + off); + statics.lnboffset += off; + statics.sendBaseQRG(); + } + } + + if (e.Button == MouseButtons.Right) + { + statics.RXoffset = x * 500; + statics.TXoffset = x * 500; + sendAndRefreshRXTXoffset(); + } + } + + private void sendAndRefreshRXTXoffset() + { + statics.sendRXTXoffset(); + + panel_qrg.Invalidate(); + panel_rxline.Invalidate(); + } + + private void tuneSmall(MouseEventArgs e) + { + // small WF: 25Hz per pixel, with the tune qrg in the middle + int x = e.X; + x = x * 1120 / panel_smallwf.Width; + int hz = (x - 560) * 25; + + + if (e.Button == MouseButtons.Left) + { + if (statics.calmode == 0) + { + if(statics.rit) + statics.RXoffset += hz; + if (statics.xit) + statics.TXoffset += hz; + sendAndRefreshRXTXoffset(); + } + else if (statics.calmode == 1) + { + //Console.WriteLine("Pluto offset: " + hz); + if (hz > 0) + statics.calfreq += (UInt32)hz; + else if (hz < 0) + statics.calfreq -= (UInt32)(-hz); + + statics.sendBaseQRG(statics.calfreq); + //Console.WriteLine("calfreq: " + statics.calfreq); + } + else if (statics.calmode == 2) + { + Console.WriteLine("offset: " + hz); + statics.lnboffset += hz; + statics.sendBaseQRG(); + } + } + + if (e.Button == MouseButtons.Right) + { + statics.RXoffset += hz; + statics.TXoffset += hz; + sendAndRefreshRXTXoffset(); + } + } + + private void panel_bigwf_MouseWheel(object sender, MouseEventArgs e) + { + int factor = 100; + if (Control.ModifierKeys == Keys.Alt) factor = 1000; + if (Control.ModifierKeys == Keys.Control) factor = 10000; + + if (statics.rit) + { + if (e.Delta > 0) //wheel direction + statics.RXoffset += factor; + else + statics.RXoffset -= factor; + + } + if (statics.xit) + { + if (e.Delta > 0) //wheel direction + statics.TXoffset += factor; + else + statics.TXoffset -= factor; + } + + if (statics.rit || statics.xit) + sendAndRefreshRXTXoffset(); + } + + private void panel_smallwf_MouseWheel(object sender, MouseEventArgs e) + { + if (statics.rit) + { + if (e.Delta > 0) //wheel direction + statics.RXoffset += 10; + else + statics.RXoffset -= 10; + } + + if (statics.xit) + { + if (e.Delta > 0) //wheel direction + statics.TXoffset += 10; + else + statics.TXoffset -= 10; + } + + if (statics.rit || statics.xit) + sendAndRefreshRXTXoffset(); + } + + private void panel_bigwf_MouseHover(object sender, EventArgs e) + { + panel_bigwf.Focus(); + } + + private void panel_bigwf_MouseMove(object sender, MouseEventArgs e) + { + panel_bigwf.Focus(); + int x = e.X * 1120 / panel_bigspec.Width; + statics.rxmouse = x * 500; + panel_qrg.Invalidate(); + } + + private void panel_bigspec_MouseLeave(object sender, EventArgs e) + { + statics.rxmouse = -1; + panel_qrg.Invalidate(); + } + + private void panel_bigspec_MouseMove(object sender, MouseEventArgs e) + { + panel_bigspec.Focus(); + int x = e.X * 1120 / panel_bigspec.Width; + statics.rxmouse = x * 500; + panel_qrg.Invalidate(); + } + + private void panel_smallspec_MouseLeave(object sender, EventArgs e) + { + statics.rxmouse = -1; + panel_qrg.Invalidate(); + } + + private void panel_smallspec_MouseMove(object sender, MouseEventArgs e) + { + panel_smallspec.Focus(); + int x = e.X * 1120 / panel_bigspec.Width; + int hz = (x - 560) * 25; + statics.rxmouse = statics.RXoffset + hz; + panel_qrg.Invalidate(); + } + + private void panel_smallwf_MouseLeave(object sender, EventArgs e) + { + statics.rxmouse = -1; + panel_qrg.Invalidate(); + } + + private void panel_smallwf_MouseMove(object sender, MouseEventArgs e) + { + panel_smallwf.Focus(); + int x = e.X * 1120 / panel_bigspec.Width; + int hz = (x - 560) * 25; + statics.rxmouse = statics.RXoffset + hz; + panel_qrg.Invalidate(); + } + + private void panel_bigwf_MouseLeave(object sender, EventArgs e) + { + statics.rxmouse = -1; + panel_qrg.Invalidate(); + } + + private void panel_bigspec_MouseHover(object sender, EventArgs e) + { + panel_bigspec.Focus(); + } + + private void panel_smallspec_MouseHover(object sender, EventArgs e) + { + panel_smallspec.Focus(); + } + + private void panel_smallwf_MouseHover(object sender, EventArgs e) + { + panel_smallwf.Focus(); + } + + Font smallfnt = new Font("Verdana", 8.0f); + private void panel_smallqrg_Paint(object sender, PaintEventArgs e) + { + using(Graphics gr = e.Graphics) + { + String s = "0 Hz"; + int x = panel_smallqrg.Width / 2 - 10; + gr.DrawString(s, smallfnt, Brushes.Black, x, 0); + for(int i=120; i<500; i+=120) + { + s = (i * 25 / 1000).ToString() + "kHz"; + x = i * panel_smallqrg.Width / 1120 + panel_smallqrg.Width / 2 - 10; + gr.DrawString(s, smallfnt, Brushes.Black, x, 0); + } + for (int i = -120; i > -500; i -= 120) + { + s = (i * 25 / 1000).ToString() + "kHz"; + x = i * panel_smallqrg.Width / 1120 + panel_smallqrg.Width / 2 - 10; + gr.DrawString(s, smallfnt, Brushes.Black, x, 0); + } + } + } + + int qrgToPixelpos(int qrg) + { + qrg -= 10489000; // rest is kHz + qrg -= 470; + qrg *= 2; + qrg = qrg * panel_bigspec.Width / 1120; + return qrg; + } + + private void panel_bandplan_Paint(object sender, PaintEventArgs e) + { + Font qrgfnt = new Font("Verdana", 9.0f); + Font bpfnt; + if (panel_bigspec.Width > 1000) + bpfnt = new Font("Verdana", 9.0f); + else + bpfnt = new Font("Verdana", 8.0f); + + Bandplan bp = new Bandplan(); + using (Graphics gr = e.Graphics) + { + if (statics.bandplan_mode == 0) + { + gr.FillRectangle(new SolidBrush(Color.DarkBlue), 0, 0, panel_bandplan.Width, panel_bandplan.Height); + if(panel_bigspec.Width > 1000) + gr.DrawString("Bandplan", bpfnt, Brushes.White, 0, -1); + for (int i = 0; i < bp.be.Length - 1; i++) + { + int x = qrgToPixelpos(bp.be[i].from); + int w = qrgToPixelpos(bp.be[i + 1].from) - x; + Color col = bp.be[i].col; + gr.FillRectangle(new SolidBrush(col), x, 0, w, panel_bandplan.Height); + String s = bp.be[i].text; + int spos = qrgToPixelpos(bp.be[i].textpos); + gr.DrawString(s, bpfnt, Brushes.White, spos, -1); + } + } + else if (statics.bandplan_mode == 1) + { + // QO100 RX qrgs + gr.FillRectangle(new SolidBrush(Color.DarkBlue), 0, 0, panel_bandplan.Width, panel_bandplan.Height); + if (panel_bigspec.Width > 1000) + gr.DrawString("RX", qrgfnt, Brushes.White, 0, -1); + for (int qrg = 10489500; qrg <= 10490000; qrg += 50) + { + int spos = qrgToPixelpos(qrg); + if (qrg > 10489500) + { + String sqrg = (qrg - 10489000).ToString(); + gr.DrawString(sqrg, qrgfnt, Brushes.White, spos - 12, 0); + } + else + { + String sqrg = String.Format("{0:0.000}", (double)qrg / 1000.0); + gr.DrawString(sqrg, qrgfnt, Brushes.White, spos - 30, 0); + } + } + } + else if (statics.bandplan_mode == 2) + { + // QO100 TX qrgs + gr.FillRectangle(new SolidBrush(Color.DarkBlue), 0, 0, panel_bandplan.Width, panel_bandplan.Height); + if (panel_bigspec.Width > 1000) + gr.DrawString("TX", qrgfnt, Brushes.White, 0, -1); + for (int qrg = 10489500; qrg <= 10490000; qrg += 50) + { + int spos = qrgToPixelpos(qrg); + if (qrg > 10489500) + { + String sqrg = (qrg - 2400000- 8089500).ToString(); + gr.DrawString(sqrg, qrgfnt, Brushes.White, spos - 12, 0); + } + else + { + String sqrg = String.Format("{0:0.000}", (qrg - 8089500) / 1000.0); + gr.DrawString(sqrg, qrgfnt, Brushes.White, spos - 30, 0); + } + } + } + else if (statics.bandplan_mode == 3) + { + // Pluto RX qrgs + gr.FillRectangle(new SolidBrush(Color.DarkBlue), 0, 0, panel_bandplan.Width, panel_bandplan.Height); + if (panel_bigspec.Width > 1000) + gr.DrawString("RX", qrgfnt, Brushes.White, 0, -1); + for (int qrg = (int)statics.rxqrg - 250000; qrg <= (int)statics.rxqrg + 250000; qrg += 50000) + { + int spos = qrgToPixelpos(qrg/1000 + 10489000 - (qrg/1000000)*1000); + if (qrg > ((int)statics.rxqrg - 250000)) + { + String sqrg = ((qrg - (((int)statics.rxqrg) / 1000000) * 1000000)/1000).ToString(); + gr.DrawString(sqrg, qrgfnt, Brushes.White, spos - 12, 0); + } + else + { + String sqrg = String.Format("{0:0.000}", (double)qrg / 1000000.0); + gr.DrawString(sqrg, qrgfnt, Brushes.White, spos - 30, 0); + } + } + } + else if (statics.bandplan_mode == 4) + { + // Pluto TX qrgs + gr.FillRectangle(new SolidBrush(Color.DarkBlue), 0, 0, panel_bandplan.Width, panel_bandplan.Height); + if (panel_bigspec.Width > 1000) + gr.DrawString("TX", qrgfnt, Brushes.White, 0, -1); + for (Int64 qrg = (Int64)statics.txqrg - 250000; qrg <= (Int64)statics.txqrg + 250000; qrg += 50000) + { + int spos = qrgToPixelpos((int)(qrg / 1000 + 10489500 - (qrg / 1000000) * 1000)); + if (qrg > ((Int64)statics.txqrg - 250000)) + { + String sqrg = ((qrg - (((Int64)statics.txqrg) / 1000000) * 1000000) / 1000).ToString(); + gr.DrawString(sqrg, qrgfnt, Brushes.White, spos - 12, 0); + } + else + { + String sqrg = String.Format("{0:0.000}", (double)qrg / 1000000.0); + gr.DrawString(sqrg, qrgfnt, Brushes.White, spos - 30, 0); + } + } + } + } + } + + + Font smlfnt = new Font("Verdana", 10.0f); + int titrightpos = 10; + int mouserightpos = 790; + int bigy = 2; + + // insert a space betwenn each char: + // string.Join(" ", s.ToCharArray()) + Brush brushrx = new SolidBrush(Color.FromArgb(0, 230, 100)); + Brush brushtx = new SolidBrush(Color.FromArgb(160, 0, 0)); + private void panel_qrg_Paint(object sender, PaintEventArgs e) + { + using (Graphics gr = e.Graphics) + { + if (panel_bigspec.Width > 900) + { + int mrp = mouserightpos; + if (panel_bigspec.Width > 1300) + mrp = 1300; + + double val = (double)(statics.RXoffset + 10489470000) / 1e6; + String s = String.Format("RX:" + "{0:0.000000}" + " MHz", val); + gr.DrawString(s, bigfnt, brushrx, titrightpos, bigy); + + val = (double)(statics.TXoffset + 10489470000) / 1e6 - 8089.5; + s = String.Format("TX:" + "{0:0.000000}" + " MHz", val); + gr.DrawString(s, bigfnt, brushtx, 420 + titrightpos, bigy); + + if (statics.rxmouse != -1) + { + val = (double)(statics.rxmouse + 10489470000) / 1e6; + s = String.Format(language.GetText("Mouse:") + " {0:0.000000}", val); + gr.DrawString(s, smlfnt, Brushes.Blue, mrp + titrightpos, 0); + } + else + { + gr.FillRectangle(Brushes.Gray, mrp + titrightpos, 0, panel_qrg.Width - (mrp + titrightpos), panel_qrg.Height); + } + + s = String.Format("Drift : {0:0}" + " Hz", statics.beaconoffset); + if (statics.beaconlock) s += " (corr)"; + gr.DrawString(s, smlfnt, Brushes.Blue, mrp + titrightpos, 20); + } + else + { + double val = (double)(statics.RXoffset + 10489470000) / 1e6; + String s = String.Format("RX:" + "{0:0.000000}" + " MHz", val); + gr.DrawString(s, bigfnt, Brushes.Green, titrightpos, bigy-5); + + val = (double)(statics.TXoffset + 10489470000) / 1e6 - 8089.5; + s = String.Format("TX:" + "{0:0.000000}" + " MHz", val); + gr.DrawString(s, bigfnt, Brushes.DarkRed, titrightpos, bigy+16); + + int mrp = 420; + if (panel_bigspec.Width < 700) mrp = 390; + if (panel_bigspec.Width < 500) mrp = 250; + + if (statics.rxmouse != -1) + { + val = (double)(statics.rxmouse + 10489470000) / 1e6; + s = String.Format(language.GetText("Mouse:") + " {0:0.000000}", val); + gr.DrawString(s, smlfnt, Brushes.Blue, mrp + titrightpos, 0); + } + else + { + gr.FillRectangle(Brushes.Gray, mrp + titrightpos, 0, panel_qrg.Width - (mrp + titrightpos), panel_qrg.Height); + } + + s = String.Format("Drift : {0:0}" + " Hz", statics.beaconoffset); + if (statics.beaconlock) s += " (corr)"; + gr.DrawString(s, smlfnt, Brushes.Blue, mrp + titrightpos, 20); + } + } + } + + private void setPTT(bool onoff) + { + Byte[] txb = new Byte[2]; + txb[0] = 4; + txb[1] = (Byte)(onoff ? 1 : 0); + Udp.UdpSendData(txb); + } + + private void panel1_Paint(object sender, PaintEventArgs e) + { + using (Graphics gr = e.Graphics) + { + if (statics.ptt) + { + gr.FillRectangle(Brushes.Red, 0, 0, panel1.Width, panel1.Height); + using (Bitmap bm = new Bitmap(Properties.Resources.ptt_tx)) + drawBitmap(gr, bm, panel1.Width / 2 - bm.Width / 2, 0,button_size*2); + } + else + { + gr.FillRectangle(Brushes.Green, 0, 0, panel1.Width, panel1.Height); + using (Bitmap bm = new Bitmap(Properties.Resources.ptt_rx)) + drawBitmap(gr, bm, panel1.Width / 2 - bm.Width / 2, 0, button_size * 2); + } + } + } + + private void panel1_MouseClick(object sender, MouseEventArgs e) + { + if (statics.pttmode == 0) + { + if (statics.ptt) statics.ptt = false; + else statics.ptt = true; + setPTT(statics.ptt); + panel1.Invalidate(); + } + } + + private void panel1_MouseDown(object sender, MouseEventArgs e) + { + if (statics.pttmode == 1 && !statics.ptt) + { + statics.ptt = true; + setPTT(statics.ptt); + panel1.Invalidate(); + } + } + + private void panel1_MouseUp(object sender, MouseEventArgs e) + { + if (statics.pttmode == 1 && statics.ptt) + { + statics.ptt = false; + setPTT(statics.ptt); + panel1.Invalidate(); + } + } + + private void butto_setup_click(object sender, EventArgs e) + { + int oldpluto = statics.plutousb; + String oldpladr = statics.plutoaddress; + + Form_setup setupForm = new Form_setup(); + + // Show the settings form + var res = setupForm.ShowDialog(); + if(res == DialogResult.OK) + { + sendAudioDevs(); + statics.sendBaseQRG(); + statics.sendReferenceOffset(statics.rfoffset); + sendCpuSpeed(); + sendTXpower(); + sendPTTmode(); + + save_Setup(); + + if (oldpluto != statics.plutousb || oldpladr != statics.plutoaddress) + { + // pluto setting has been changed, restart required + MessageBox.Show("Pluto settings changed. Press OK to close this software, then start it again", "RESTART REQUIRED", MessageBoxButtons.OK, MessageBoxIcon.Warning); + Close(); + } + } + } + + private void sendAudioDevs() + { + try + { + if (!statics.newaudiodevs) return; + statics.newaudiodevs = false; + + //Console.WriteLine("<" + statics.AudioPBdev.Trim() + ">" + "<" + statics.AudioCAPdev + ">"); + Byte[] pb = statics.StringToByteArrayUtf8(statics.AudioPBdev.Trim()); + Byte[] cap = statics.StringToByteArrayUtf8(statics.AudioCAPdev.Trim()); + + if (pb.Length > 100 || cap.Length > 100) return; + + Byte[] txb = new Byte[201]; + for (int i = 0; i < txb.Length; i++) txb[i] = 0; + Array.Copy(pb, 0, txb, 1, pb.Length); + Array.Copy(cap, 0, txb, 101, cap.Length); + txb[0] = 7; + Udp.UdpSendData(txb); + } + catch + { + // no audio devs + } + } + + + private String ReadString(StreamReader sr) + { + try + { + String s = sr.ReadLine(); + if (s != null) + { + return s; + } + } + catch { } + return " "; + } + + private int ReadInt(StreamReader sr) + { + int v; + + try + { + String s = sr.ReadLine(); + if (s != null) + { + v = Convert.ToInt32(s); + return v; + } + } + catch { } + return 0; + } + + private UInt32 ReadUInt32(StreamReader sr) + { + UInt32 v; + + try + { + String s = sr.ReadLine(); + if (s != null) + { + v = Convert.ToUInt32(s); + return v; + } + } + catch { } + return 0; + } + + private double ReadMyDouble(StreamReader sr) + { + double v; + + try + { + String s = sr.ReadLine(); + if (s != null) + { + v = statics.MyToDouble(s); + return v; + } + } + catch { } + return 0; + } + + void load_Setup() + { + try + { + String fn = statics.getHomePath("", "trx.cfg"); + using (StreamReader sr = new StreamReader(fn)) + { + statics.AudioPBdev = ReadString(sr); + statics.AudioCAPdev = ReadString(sr); + statics.RXTXoffset = ReadInt(sr); statics.TXoffset -= statics.RXTXoffset; + String dummy3 = ReadString(sr); + statics.plutousb = ReadInt(sr); + statics.plutoaddress = ReadString(sr); + String dummy1 = ReadString(sr); + bool dummy2 = ReadString(sr) == "1"; + statics.compressor = ReadString(sr) == "1"; + statics.rxfilter = ReadInt(sr); + statics.txfilter = ReadInt(sr); + statics.rxmute = ReadString(sr) == "1"; + statics.rit = ReadString(sr) == "1"; + statics.xit = ReadString(sr) == "1"; + String dummy4 = ReadString(sr); + statics.beaconlock = ReadString(sr) == "1"; + statics.rxqrg = ReadUInt32(sr); + statics.txqrg = ReadUInt32(sr); + statics.rfoffset = ReadInt(sr); + statics.lnboffset = ReadInt(sr); + statics.cpuspeed = ReadInt(sr); + statics.bandplan_mode = ReadInt(sr); + statics.language = ReadInt(sr); + statics.palette = ReadInt(sr); + statics.audioHighpass = ReadString(sr) == "1"; + statics.txpower = ReadInt(sr); + statics.windowsize = ReadInt(sr); + statics.autosync = ReadString(sr) == "1"; + statics.pttmode = ReadInt(sr); + statics.micboost = ReadInt(sr); + } + } + catch + { + } + } + + void save_Setup() + { + try + { + using (StreamWriter sw = new StreamWriter(statics.getHomePath("", "trx.cfg"))) + { + sw.WriteLine(statics.AudioPBdev); + sw.WriteLine(statics.AudioCAPdev); + sw.WriteLine(statics.RXTXoffset.ToString()); + sw.WriteLine(""); + sw.WriteLine(statics.plutousb.ToString()); + sw.WriteLine(statics.plutoaddress); + sw.WriteLine(""); + sw.WriteLine(""); + sw.WriteLine(statics.compressor ? "1" : "0"); + sw.WriteLine(statics.rxfilter.ToString()); + sw.WriteLine(statics.txfilter.ToString()); + sw.WriteLine(statics.rxmute ? "1" : "0"); + sw.WriteLine(statics.rit ? "1" : "0"); + sw.WriteLine(statics.xit ? "1" : "0"); + sw.WriteLine(""); + sw.WriteLine(statics.beaconlock ? "1" : "0"); + sw.WriteLine(statics.rxqrg.ToString()); + sw.WriteLine(statics.txqrg.ToString()); + sw.WriteLine(statics.rfoffset.ToString()); + sw.WriteLine(statics.lnboffset.ToString()); + sw.WriteLine(statics.cpuspeed.ToString()); + sw.WriteLine(statics.bandplan_mode.ToString()); + sw.WriteLine(statics.language.ToString()); + sw.WriteLine(statics.palette.ToString()); + sw.WriteLine(statics.audioHighpass ? "1" : "0"); + sw.WriteLine(statics.txpower.ToString()); + sw.WriteLine(statics.windowsize.ToString()); + sw.WriteLine(statics.autosync ? "1" : "0"); + sw.WriteLine(statics.pttmode.ToString()); + sw.WriteLine(statics.micboost.ToString()); + } + } + catch { } + } + + private void bt_info_click(object sender, EventArgs e) + { + Form_info fi = new Form_info(); + + // Show the settings form + var res = fi.ShowDialog(); + if (res == DialogResult.OK) + { + } + } + + private void sendPlutoAddress() + { + //Console.WriteLine("send pluto ID <" + statics.plutoaddress.Trim() + ">"); + Byte[] iparr = statics.StringToByteArrayUtf8(statics.plutoaddress.Trim()); + + Byte[] txb = new Byte[iparr.Length + 2]; + txb[0] = 10; + txb[1] = (Byte)statics.plutousb; + Array.Copy(iparr, 0, txb, 2, iparr.Length); + Udp.UdpSendData(txb); + } + + private void panel_rit_Click(object sender, EventArgs e) + { + statics.rit = !statics.rit; + panel_rit.Invalidate(); + } + + private void panel_xit_Click(object sender, EventArgs e) + { + statics.xit = !statics.xit; + panel_xit.Invalidate(); + } + + private void drawBitmap(Graphics gr, Bitmap bm, int x=0, int y=0, int sizex=0) + { + Bitmap bm_resized; + if (sizex != 0) + bm_resized = new Bitmap(bm, sizex, button_size); + else + bm_resized = new Bitmap(bm, button_size, button_size); + + gr.DrawImage(bm_resized, x, y); + } + + private void drawButtonPanel(Graphics gr, bool state, Bitmap bm, Bitmap bminact) + { + if (state) + drawBitmap(gr, bm); + else + drawBitmap(gr, bminact); + } + + private void panel_rit_Paint(object sender, PaintEventArgs e) + { + using (Bitmap bm = new Bitmap(Properties.Resources.rxqrg)) + using (Bitmap bminact = new Bitmap(Properties.Resources.rxqrg_inact)) + drawButtonPanel(e.Graphics, statics.rit, bm, bminact); + } + + private void panel_xit_Paint(object sender, PaintEventArgs e) + { + using (Bitmap bm = new Bitmap(Properties.Resources.txqrg)) + using (Bitmap bminact = new Bitmap(Properties.Resources.txqrg_inact)) + drawButtonPanel(e.Graphics, statics.xit, bm, bminact); + } + + + private void panel_copyRtoT_Paint(object sender, PaintEventArgs e) + { + using (Bitmap bm = new Bitmap(Properties.Resources.rt_button)) + using (Bitmap bminact = new Bitmap(Properties.Resources.rt_button_inact)) + drawButtonPanel(e.Graphics,true, bm, bminact); + } + + private void panel_copyTtoR_Paint(object sender, PaintEventArgs e) + { + using (Bitmap bm = new Bitmap(Properties.Resources.tr_button)) + using (Bitmap bminact = new Bitmap(Properties.Resources.tr_button_inact)) + drawButtonPanel(e.Graphics, true, bm, bminact); + } + + private void panel_copyRtoT_Click(object sender, EventArgs e) + { + statics.TXoffset = statics.RXoffset; + statics.RXTXoffset = 0; + sendAndRefreshRXTXoffset(); + panel_copyRtoT.Invalidate(); + } + + private void panel_agc_Paint(object sender, PaintEventArgs e) + { + using (Bitmap bm = new Bitmap(Properties.Resources.txaudio_button)) + drawButtonPanel(e.Graphics, true, bm, null); + } + + private void panel_txmute_Paint(object sender, PaintEventArgs e) + { + using (Bitmap bm = new Bitmap(Properties.Resources.mute)) + using (Bitmap bminact = new Bitmap(Properties.Resources.mute_inact)) + drawButtonPanel(e.Graphics, statics.rxmute, bm, bminact); + } + + void sendCpuSpeed() + { + Byte[] txb = new Byte[2]; + txb[0] = 17; + txb[1] = (Byte)statics.cpuspeed; + Udp.UdpSendData(txb); + } + + void sendPTTmode() + { + Byte[] txb = new Byte[2]; + txb[0] = 23; + txb[1] = (Byte)statics.pttmode; + Udp.UdpSendData(txb); + } + + void sendTXpower() + { + Byte[] txb = new Byte[2]; + txb[0] = 19; + txb[1] = (Byte)Math.Abs(statics.txpower); // send positive value + Udp.UdpSendData(txb); + } + + private void panel_agc_Click(object sender, EventArgs e) + { + if (e != null) + { + // check if alraey open + foreach (Form frm in Application.OpenForms) + if (frm.Name == "Form2_agc") return; + + Form2_agc frmagc = new Form2_agc(Location,valq); + frmagc.Show(); + } + else + { + // init after program start + Byte[] txb = new Byte[3]; + txb[0] = 11; + txb[1] = (Byte)(statics.audioHighpass ? 1 : 0); + txb[2] = (Byte)statics.micboost; + Udp.UdpSendData(txb); + } + } + + private void panel_txmute_Click(object sender, EventArgs e) + { + if (e != null) statics.rxmute = !statics.rxmute; + Byte[] txb = new Byte[2]; + txb[0] = 14; + txb[1] = (Byte)(statics.rxmute ? 1 : 0); + Udp.UdpSendData(txb); + panel_txmute.Invalidate(); + } + + private void panel_comp_Click(object sender, EventArgs e) + { + if (e != null) statics.compressor = !statics.compressor; + + Byte[] txb = new Byte[2]; + txb[0] = 9; + txb[1] = (Byte)(statics.compressor?1:0); // compression factor + Udp.UdpSendData(txb); + + panel_comp.Invalidate(); + } + + private void panel_comp_Paint(object sender, PaintEventArgs e) + { + using (Bitmap bm = new Bitmap(Properties.Resources.comp_on)) + using (Bitmap bminact = new Bitmap(Properties.Resources.comp_off)) + drawButtonPanel(e.Graphics, statics.compressor, bm, bminact); + } + + private void panel_copyTtoR_Click(object sender, EventArgs e) + { + statics.RXoffset = statics.TXoffset; + statics.RXTXoffset = 0; + sendAndRefreshRXTXoffset(); + panel_copyTtoR.Invalidate(); + } + + private void panel_rxfilter_Paint(object sender, PaintEventArgs e) + { + switch (statics.rxfilter) + { + case 0: + using (Bitmap bm = new Bitmap(Properties.Resources.rx_filter_1)) + drawBitmap(e.Graphics, bm); + break; + case 1: + using (Bitmap bm = new Bitmap(Properties.Resources.rx_filter_18)) + drawBitmap(e.Graphics, bm); + break; + case 2: + using (Bitmap bm = new Bitmap(Properties.Resources.rx_filter_27)) + drawBitmap(e.Graphics, bm); + break; + case 3: + using (Bitmap bm = new Bitmap(Properties.Resources.rx_filter_36)) + drawBitmap(e.Graphics, bm); + break; + } + } + + private void panel_txfilter_Paint(object sender, PaintEventArgs e) + { + switch (statics.txfilter) + { + case 0: + using (Bitmap bm = new Bitmap(Properties.Resources.tx_filter_1)) + drawBitmap(e.Graphics, bm); + break; + case 1: + using (Bitmap bm = new Bitmap(Properties.Resources.tx_filter_18)) + drawBitmap(e.Graphics, bm); + break; + case 2: + using (Bitmap bm = new Bitmap(Properties.Resources.tx_filter_22)) + drawBitmap(e.Graphics, bm); + break; + case 3: + case 4: + using (Bitmap bm = new Bitmap(Properties.Resources.tx_filter_27)) + drawBitmap(e.Graphics, bm); + break; + } + } + + private void panel_rxfilter_Click(object sender, EventArgs e) + { + if (e != null) if (++statics.rxfilter > 3) statics.rxfilter = 0; + + Byte[] txb = new Byte[2]; + txb[0] = 12; + txb[1] = (Byte)statics.rxfilter; + Udp.UdpSendData(txb); + + panel_rxfilter.Invalidate(); + } + + private void panel_txfilter_Click(object sender, EventArgs e) + { + if (e != null) if (++statics.txfilter > 3) statics.txfilter = 0; + + Byte[] txb = new Byte[2]; + txb[0] = 13; + txb[1] = (Byte)statics.txfilter; + Udp.UdpSendData(txb); + + panel_txfilter.Invalidate(); + } + + private void panel_audioloop_Paint(object sender, PaintEventArgs e) + { + using (Bitmap bm = new Bitmap(Properties.Resources.audioloop)) + using (Bitmap bminact = new Bitmap(Properties.Resources.audioloop_inact)) + drawButtonPanel(e.Graphics, statics.audioloop, bm, bminact); + } + + private void panel_rfloop_Paint(object sender, PaintEventArgs e) + { + using (Bitmap bm = new Bitmap(Properties.Resources.rfloop)) + using (Bitmap bminact = new Bitmap(Properties.Resources.rfloop_inact)) + drawButtonPanel(e.Graphics, statics.rfloop, bm, bminact); + } + + private void panel_audioloop_Click(object sender, EventArgs e) + { + statics.audioloop = !statics.audioloop; + if (statics.audioloop && statics.rfloop) + { + panel_rfloop_Click(null, null); + } + + Byte[] txb = new Byte[2]; + txb[0] = 3; + txb[1] = (Byte)(statics.audioloop ? 1 : 0); + + Udp.UdpSendData(txb); + panel_audioloop.Invalidate(); + panel_rfloop.Invalidate(); + } + + private void panel_rfloop_Click(object sender, EventArgs e) + { + statics.rfloop = !statics.rfloop; + if (statics.audioloop && statics.rfloop) + { + panel_audioloop_Click(null, null); + } + + statics.ptt = statics.rfloop; + panel1.Invalidate(); + setPTT(statics.ptt); + + Byte[] txb = new Byte[2]; + txb[0] = 5; + txb[1] = (Byte)(statics.rfloop ? 1 : 0); + + Udp.UdpSendData(txb); + panel_rfloop.Invalidate(); + panel_audioloop.Invalidate(); + } + + private void panel_pavucontrol_Click(object sender, EventArgs e) + { + statics.StartMixer(true); + } + + static Pen cline = new Pen(Brushes.Yellow, 2); + private void panel_rxline_Paint(object sender, PaintEventArgs e) + { + int x = statics.RXoffset / 500; + x = x * panel_rxline.Width / 1120; + //Console.WriteLine("pp " + x); + using (Graphics gr = e.Graphics) + { + gr.DrawLine(cline, panel_rxline.Width / 2, panel_rxline.Height, x, 0); + } + } + + private void panel_sync_Paint(object sender, PaintEventArgs e) + { + // size 28 x 18 px + } + + + private void panel_beaconlock_Paint(object sender, PaintEventArgs e) + { + using (Graphics gr = e.Graphics) + { + if (statics.beaconlock) + { + using (Bitmap bm = new Bitmap(Properties.Resources._lock)) + { + gr.FillRectangle(Brushes.Gray, 0, 0, panel_beaconlock.Width, panel_beaconlock.Height); + gr.DrawImage(bm, 0, 0); + } + } + else + { + using (Bitmap bm = new Bitmap(Properties.Resources.lock_open)) + { + gr.FillRectangle(Brushes.Gray, 0, 0, panel_beaconlock.Width, panel_beaconlock.Height); + gr.DrawImage(bm, 0, 0); + } + } + } + + Byte[] txb = new Byte[2]; + txb[0] = 16; + txb[1] = (Byte)(statics.beaconlock ? 1 : 0); + Udp.UdpSendData(txb); + + panel_qrg.Invalidate(); + } + + private void panel_beaconlock_Click(object sender, EventArgs e) + { + statics.beaconlock = !statics.beaconlock; + panel_beaconlock.Invalidate(); + } + + private void panel_sync_Click(object sender, EventArgs e) + { + Form_reference fr = new Form_reference(); + fr.Show(); + } + + private void panel_switchbandplan_Click(object sender, EventArgs e) + { + if (++statics.bandplan_mode >= 5) statics.bandplan_mode = 0; + panel_bandplan.Invalidate(); + } + + private void panel_screen_Click(object sender, EventArgs e) + { + int ws = statics.windowsize; + Form_screen fs = new Form_screen(); + fs.ShowDialog(); + if(ws != statics.windowsize) + { + scaleElements(); + Udp.UpdateSize(); + } + } + + private void panel_save_Click(object sender, EventArgs e) + { + statics.lastRXoffset = statics.RXoffset; + statics.lastTXoffset = statics.TXoffset; + } + private void panel_recall_Click(object sender, EventArgs e) + { + statics.RXoffset = statics.lastRXoffset; + statics.TXoffset = statics.lastTXoffset; + panel_qrg.Invalidate(); + sendAndRefreshRXTXoffset(); + } + + private void panel_testtone_Click(object sender, EventArgs e) + { + Byte[] txb = new Byte[1]; + txb[0] = 22; + Udp.UdpSendData(txb); + } + + private void panel_testtone_Paint(object sender, PaintEventArgs e) + { + if(statics.sendtone == 1) + e.Graphics.DrawImage(Properties.Resources.waveactive,0,0); + else + e.Graphics.DrawImage(Properties.Resources.wave, 0, 0); + } + } + + class DoubleBufferedPanel : Panel + { + public DoubleBufferedPanel() : base() + { + // double buffering crashes under windows + OperatingSystem osversion = System.Environment.OSVersion; + if (osversion.VersionString.Contains("indow")) + statics.ostype = 0; // Win$ + else + { + statics.ostype = 1; // Linux + DoubleBuffered = true; + } + } + } +} diff --git a/trxGui/Form1.resx b/trxGui/Form1.resx new file mode 100755 index 0000000..a18ff41 --- /dev/null +++ b/trxGui/Form1.resx @@ -0,0 +1,1394 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + 17, 17 + + + + + iVBORw0KGgoAAAANSUhEUgAAABgAAAAgCAYAAAAIXrg4AAAABGdBTUEAALGPC/xhBQAAAAlwSFlzAAAL + EwAACxMBAJqcGAAABTNJREFUSEvt1XlQVVUcB/AfaLngw9IMS8YccrKhzcqmmhERZFEUFUGEBwrIKsqi + uAziWGqhqJFK6qCYC4um4YLQKIwITxAZCNdQ0XAJ06Gyzdyy36/vebxX7z0e+k9N/3RmPvPO/d17f+fd + c373XHJ2dv5XWQ3+k8wOXNeRncvHpHFZQ5rhn8B60rhlk8Y9hzQjPiWNh7KFNJ7K1jZe23DOFGL47dZu + gKS8kX7pu+IfhOYP4qCdjhy8ty8HHezF2gp7DqmxY219N9aefIwDaokDG4gnnSIObiQOOg8X0FeaOnFM + Y09+v9nh1sRi6mc2wLicpwYEbx7Yml+9UjaWL+LM4lmyuCRU5pS6c3zZqxJW0VfCq/rIuFLiCRUkAUeI + J1aT+FeR4JjHl5L47icJ1vXgwHqqHr2LHjcbQHHNIq/wba/d36JL56zSuZJ+IELml3tzYtVgiTr2rEQ3 + OKiEHFiHRMeJtadItCdJgvBEATX6X5lwgq557iRHY06zARQMkjJrtxevO5zKK8pieGGlL6fUvcHTTjhy + 3FkHVsm0Z4gnY0rCLkEz+k3EoecwbRfojnchDTXNZ5ZccckkW9e1lKemJ/PQDFmiC+B59e9Iwtn+Etus + kYgr+qQy9VviqFaSqO/Qv45BWmx5VBHFWeYzO0BiO1VBw7LoGVTImYyyKEnXaTmt3lVmNjlJXIudSsgR + 10hibhJPu00Sf48k+lfikSWU67Wd7PVVtKWDKlr6+fQHYQXOrM114kk7HDmmxJmX68J5Yb0nz2l6kWfc + sOfYH4kjbxDH3SJOEOIU0fAUHIdeJQ65ZMOxTT35vfN9b/kXWamikM2DWkvOb5TCM6t5a91iWX80RVbq + onhRnY/MOzdYEq73FsMAEot/jQEkSTpJ/N22GNZCpjZ3Yf8aqvbZ0UEVRee/dX9f41rOa/iQs2vmcqYu + lpfUjuXUr4ZwYosDq6mJaCGO/gFP8VsbY0zxa6BrIwoeXkWzU/f58fbjy2RDTaqsOhLPH9QEyPyT70ry + pX4SdcOWp1wkUcnUv1ZUP/wKSeA5uoMSfXgVDf0IVZRFeSuLEyXn2AJZXTmD048ES9qXLpLcNEAiL3fm + kNMkoXiD1UCK6odc7MxehY+oIiNUkh32noassrmSVZnMSytDJa3WXZJPD5Kwxi4cWNv2cuFl079cIV8T + exfRhuE5ZGOZy+zAFJ7CyXfzk62ry2bysvJwTqvy5OS6l3lyXXf2Kyf2r8Tbi+0iCHuSz0GqRml2tZan + XcAU3gevoO397y0rjZS0w6MkWfe6BFdqeDT2HN8v9IPI6MPU4pH796Jasho0hS18duSel2TBwbGSVPq2 + BBY/wSMLSHx2E4+roDseeeaLaslq0NSwVWSDb0J+3N43ObHIhScU9Gb3jcRjsKt65rdfVEtWg5awhfTA + FtAQvXOIjM3uw96fkaDWs/FBareolqwGrXHfQM+PL7RvnZ7rxqP2UDW+clYX1ZLVYEcSdrl7Lt0Xd2hR + YeRz1s5bQyLSA0rgNvwCecaT6HeFn0G1VwyxGjhgck0GqGvGgGmrV+fVBZPhD3CCF2CFyc2TgOF7yDDE + psPv8DTYwBXYBB6gmvlWgcAQuA9rIAA0ZGjo74dqWAffgC30BnW9GmgoqOYGxgGMLc+QRp9oICRBPVyF + 7mBMNBs8QTU3w/XWBv7rCfRJjQ0Bf5gGvSAZVHME9Q8t2ybDPcapU3OfYYh1OIArNMJduAnGG45Cmf4i + NPSXw0+gFt5s8Q3nLafosv7G/9t/3Ij+BLpqbiDBB+hcAAAAAElFTkSuQmCC + + + + + AAABAAUAEBAAAAEAIABoBAAAVgAAABgYAAABACAAiAkAAL4EAAAgIAAAAQAgAKgQAABGDgAAMDAAAAEA + IACoJQAA7h4AAHR2AAABACAAaN0AAJZEAAAoAAAAEAAAACAAAAABACAAAAAAAAAEAAAAAAAAAAAAAAAA + AAAAAAAA/////////////////////////////////v7+//r6+v/Gw77/xcbH/+jt9P////////////7+ + /v///////////////////////////////////////fz7///////08vH/iV0m/4VTE/+CYDP/pJ2T/+vv + 9P///////v7+///////////////////////+/v7//v7+///////n6+//2NjZ/8nBt/+woZD/rope/4VN + BP9/aEf/297k///////+/v7///////////////7///////7///+unof/flAV/4x2Wv+zoIn/f1Yi/5eN + gP/LvrD/mF8X/35lRP/q7fL///7+///////+/v7//v7+//f39v+sp6H/mol0/6V3PP+lj3P/vaiP/6Jw + Mv+ijXD/t7q8/7ywof+JUAf/opmM/////////////Pv6//////+8q5P/gkwF/41xTP+Mf27/sq6n/8zI + w/+ThXX/l3tW/4BMBv+dlo3/so5i/4JbKP/n7PL//v7+///////19vb/l2gq/51dCf+bXAr/j0sA/45z + T/+uk3T/jEgA/5laCf+dWwb/imY2/7yun/+GUhD/yMfF///////Ewr7/4uPk/7Sijv+olX//q5mF/6iT + e/+9tKn/0srB/6iTfP+rmYX/qZV+/66gj//Pxrz/iVQQ/722rP/h29H/f1AT/5qPgf+Zfl7/imk//45w + Sf+HZDf/mot4/7iqmf+GZDb/jnBI/4xrP/+Ndlj/x7yw/4pUD//EvbX/xbut/5ZbEP+Odlj/pn9R/5hV + AP+ZWgn/mlgE/52DYv+4n4L/mVYB/5xdCv+XVAD/n35R/7+slP+HUw//3t7f//3///+vi2H/hmAu/7Ov + qv+gbzD/rZR2/6KXi/+4s67/zcvH/52Th/+ojWz/lWIg/8XAt/+dcTf/nHhK//r9////////3dXN/4tS + Cv+MeWD/ztXd/6GNcv+ETQT/jHNR/62VeP99SAX/loZx/9vg5/+qknL/hkwB/9fQxv///////v79//7/ + ///DsZv/iE8D/4duTf+knJP/qo9s/7Gkk//Iu63/rpFu/7evpf+dg2D/hUkA/7ypjf///////v39//// + /////v3//f///8y9rf+XZCP/gVIT/4ZrRv+VgWb/mIRq/491Uf+EVRb/j1kT/8a0nf/+/////v38//// + ///////////////+/f//////7Ozt/8q0m/+shlX/nXA3/5tuNP+nfkr/wqmL/+nn5f////////79//// + /////////////////////////v38/////////////v////f6/f/2+f3//f///////////////v38//// + /////////////wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAoAAAAGAAAADAAAAABACAAAAAAAAAJAAAAAAAAAAAAAAAAAAAAAAAA//////// + ////////////////////////////////////////////////////////8PP4/+To7v/09/v///////// + /////////v7+//////////////////////////////////////////////////////////////////// + /////////v7+//7+///v7+7/iHFV/3tkRf+Gemn/oJ6b/87S1v/2+Pv//////////v////////////// + ///////////////////////////////////////////////////+/v7//Pz7///+/v/o5+f/jVoc/5RV + Av+MUAL/fUoI/3FULP+NiIL/19vf//////////7///////////////////////////////////////// + //////////////39/f////////////7////u7/H/ysK6/8G0pP+ymXn/pXc8/5xdDP+CTgn/b19F/77C + xv/+/f7///7+///////+/v7////////////////////////////+//7/+/38///////q7/X/sa+s/4J1 + Zf+lop3/3tza/42Dd/+ho6b/vcLJ/7Wkkv+fayr/k1YH/2pTMv+9wMT///////7+/v////////////// + ///////////////////8/Pz//////8nEvf94WS//gU8O/4RIAP+LfWv/w7eq/4VJAP+AURD/clcz/6ys + qv/Tzsn/onM8/5RXCP9tWj//19ne///////+/v3///////////////////////7+/v//////1djc/6ii + m/+kfEr/pW4n/5BRAf+Sg3D/yb2u/5FTBP+hZx3/mWww/7Clmf/l7PL/wL25/6FuLv+GTwf/iIB4//f6 + /f/+/v7//////////////////f38///////Nx77/cEoa/4R3Zf+jpqz/sa+u/6mZiP/Dvrf/4t/c/7Cf + jf+4sqz/trm9/5yRgP9qSSD/q66v/7iomP+bXg//clAi/8vO0//////////////////+/v7//v7+//T2 + +P+PbUH/nV4N/5BYD/97URj/fmRC/39yXv+ysa7/397c/46CcP+Bakr/flQe/4xUC/+ZXAv/dV49/8rO + 1P+ldkD/hEwD/5qVjv////////////7+/v/9/Pv//////87Guv+OVw3/nmUc/55lG/+hZRf/nGET/4dJ + AP+Ke2j/xLiq/4hKAP+bXxD/oGQX/51lHP+iaBz/fUwM/66ytP+3noH/kFEA/4RyWf/1+f3///////// + ///7/f///////7Ccgv+SWQ7/nGYh/5pjHv+ZYh7/nWcj/5BXDf+bjHv/zMG0/5NZEv+dZyH/mWMe/5lj + Hv+eaCH/iFEK/6aelP/KvrL/k1UF/39iPP/n6/H///7+/+Xi3v+MhXv/6uzv/+Hf3v+4sq//uLOw/7mz + sf+4s7D/urSx/7Stqv/T0tD/7e3t/7y1sv+4srD/ubOw/7mzsP+5tLL/s6yn/9ja2//Ow7j/lVgK/4Bf + Mv/i5ez//////7Gegf9qNwD/mZmY/7euo/98Y0H/gGlK/39oSf9/aUn/gmtL/3ZePf+fmpP/0s7J/31l + Rf+Aakn/gGlJ/39pSf+Ca0v/dVw8/6qnof/Mwbb/lFUG/4NiNv/m6vH/4+Th/45hJf+jYxH/eFku/5SD + c/+aWwv/mV0Q/5ldEP+aXhL/nGEV/45PAP+MfGj/xrms/5BRAP+bXxP/mV4R/5ldEP+dYRP/hkoA/7Gr + ov/DsZv/jlAA/4pwTf/2+f3/2tjV/5+BXf+eYhT/f1wt/7i5u/+fbTH/nGMY/51lHf+YXRD/mF8T/45T + Cv+cj37/zMG1/5BWDf+aYBT/mV8S/5tkG/+gZxz/hloc/9nd4/+mhFf/jU8A/6CPev///////////9vb + 3f+aZCL/fE4O/6isr/+2oYn/klUG/5ZgHP+qh17/uqmY/7Grpf/Rz87/6+zs/7auqP+wnoj/poBR/5xl + H/+NTwD/rZqA/9TT0f+RWhP/iVQQ/8jGwv///////v79//n7/P+mhmP/llgF/3VfQ//DyM//sJd5/8a+ + tP+xsbL/kIR0/3dcO/+YkYj/z8rE/3tlSf+Kg3r/p6uw/7CkmP+liGL/5Onu/5R2Tv+XVwP/knRN//f5 + +//+/v3//v39///////U0Mz/mWYn/4tUCv95bV3/4Orz/7WupP95SAr/kVMB/49OAP+Nfmr/xrms/5BP + AP+MUQL/aD8J/7y6tf/3/v//lYNr/5VZC/+LWRX/0MzF///////9/fz///////7+/f/+////u66h/5ph + GP+JUwj/dGRO/62usv+/s6f/ro1k/5RhIP+fkX//0Ma5/5VhIf+tiFz/y7us/8zOz/+JdFr/j1cM/5FX + C/+zpY7///////39/f/////////////////+/v3/+v3//7eqm/+bZiP/klYG/3VTJP+EfnP/pKit/66w + sv/Jy8//1dne/7u7vv+3u8H/mJKI/31YKf+UVwb/klsT/7Gfh//8/v///P37/////v////////////// + //////7////+//7////MxcD/oX1O/5tfEf+KTwD/fE4P/35bL/99Yj//fmI//39fNP99UBL/iU4A/5da + C/+YbTf/xbqt/////////v3//v7+/////////////////////////////v/////+/f//////7O/z/8O3 + q/+riWH/n24v/5deFf+WWAz/lVgM/5VbEP+cZiX/ontO/7molf/q6uz///////79/P////////////// + ///////////////////////////////////+/f3////////////3+///5OPk/9POyP/KvrL/x72x/9DI + wP/e3dz/9ff7/////////////f38//////////////////////////////////////////////////// + /////////v7+//79/P////////////////////////////////////////////79/P/+/v7///////// + ////////////////////////AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAKAAAACAA + AABAAAAAAQAgAAAAAAAAEAAAAAAAAAAAAAAAAAAAAAAAAP////////////////////////////////// + ////////////////////////////////////////////////////////+fr7//r7/f/+/f7///7+//7/ + /////////v7+//////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////7+/v//////9vf2/6uoov+OjIj/oZ+e/7W5 + vv/W2dv/7+/w//n5+v/+/v///////////v////////////////////////////7+/v////////////// + /////////////////////////////////////////////////////////v79///////j4+P/eVAe/31K + Cf9ySRP/akog/2pZQ/+Fgnv/ub3B/+fo6v/6+fn///////////////////////////////////////// + //////////////////////////////////////////////////////////////7+/v/9/fz//v7+/+Tj + 5P+TZS7/oWMS/59kFf+fYRH/lFkO/3lMDf9mSyn/g397/8nLzv/x8vP//v7+//7//v////////////// + ///////////////////////////////////////////////////////////////////9/f3////+//// + ////////7u7v/7Spnv+4ppP/qpBx/515S/+baCb/omUV/5xhEf91SQ7/ZVZA/6yxtP/t7O3//v3+//// + //////////////7+/v///////////////////////////////////////v/+//3+/v/9/f3//v/9//// + ///1+Pv/0tba/7C0tf/P0NH//P///8zS1v+/xc3/y8/V/724sf+ih2r/nGgm/6RoGP+MVxD/Xkgo/6Ol + qP/u7e7//v7+//7+/v/////////////////////////////////////////////////9/v7/+/38//// + ///6/f//sbS1/3htW/9wUyz/WTUK/5GNiv/b2Nb/a0cb/2tQK/93bl//qKms/87T3P+4sKr/mnFA/6Jl + F/+VXRL/XUUk/6msr//z9PX///7///7+/v///////////////////////////////////////v////z9 + /P///v3/6uno/4h3Yf9vRAr/jVUO/6JnG/+IUAn/kYuD/9za2P+YYB7/nWEV/4lUDP9pRBT/dGdW/9PX + 2P/U0tH/nHlR/6JlGf+QWRL/YlA3/8bIzP/8+vz////+//7+/v////////////////////////////// + ///+/v7///////X5/P/CwsL/k3hX/6JuK/+cZBf/oGQV/4BJAf+SjYb/3dvX/5JdGP+dYRP/nWEV/5li + Fv98WS//0c/O//3////Hx8f/mnND/6VnGf99TAz/enNs/+nr7v/9/v7//v7+//////////////////// + /////////f39///////n6en/dmRO/4eDfv+9wsn/t7Wz/6yYgv+nhFr/hFoo/6ynoP/i4d7/jmQ2/6B4 + R/+pkHH/wLeu/9nd4f+rqqb/c2ZX/8PIy/+8tbH/mGYm/6BlFf9mRh3/srW5//3+/f/+/v7///////// + //////////////7+///9/f3/+/3//5J+ZP+JTwL/eUwQ/2dSM/+Hgnz/p6mu/7W8xf+5vL3/3N3e//j6 + +//S1dv/wMXN/7i8w/+bmZX/cV9E/3lMEP96RgL/c2lb/9rg5v+jiG3/n2QY/4RQC/99c2j/8fP3//// + /v///////////////////////Pz8///////MycX/glET/6JoHf+hZxz/mF4R/35NC/9vSBf/cVUx/2xb + Q/+rrKr/6Ojn/4h4YP9vVzP/bkoa/3xKCf+VWg//oWcb/6RqHP9mQhL/rrK0/83FwP+WYib/nWES/2ZO + Lf/S1dv///////////////////////7+/v/9/fz//v///56Iaf+UWg3/nGUe/5piG/+cZRz/omgd/59m + G/+hZRj/eEMA/46HgP/a19X/h1IQ/5xgE/+hZhv/oWge/51lHf+ZYhv/n2ge/4lTDP98c2X/3ePp/5x2 + TP+iZBT/cEgS/6+xs//////////////////9/v7///7+///////r7vD/kWYt/5tfDv+bYRX/m2EV/5xg + FP+bYBX/mmAV/59mGf+ETAH/lI2H/+Dc2f+UXhv/n2IT/5phFf+ZYBT/m2AU/5thFf+cYhb/ml0N/21R + Lf/b4+z/q5J3/59iFP98TAz/mJON///////+/v7///7+//z+///h5un//fz8/93d3P+Pa0H/n3M9/51x + Pv+ecj7/nXI+/51xPv+dcT3/ondA/4VaKf+wrKX/4+Lg/5JpO/+fcj7/nXI+/51yPf+dcj3/nXI9/51y + Pv+gczr/e18+/+rv9P+6qZn/mV8T/4ZRCv+Lg3f///////39/P//////pZqL/3VsYP/e4OP/+vv8/93e + 5P/Fx83/xsjO/8bHzv/Gx87/xsfO/8bIzv/Hx8//xcbK/+Pk5P/7/P3/29vg/8bHzf/HyM//xsfO/8bH + zv/Gx87/xcfP/8fHzf/Jycv/9vn8/7urm/+YXRX/i1QJ/4p+cf////////7+/+fr7f+IXiP/aj4H/42O + j//c3N3/into/3VlTf91Z1H/dWZQ/3VmUP92Z1D/dWZQ/3loUv9qXUj/q6qn/+jp5/+EdmH/dWVN/3Zn + UP91Z1D/dWdQ/3ZnUP93Z1D/dmVO/3FmVf/g5Oj/vKya/5dcEf+MUwr/jIJ1////////////s6iX/4xV + DP+iZhn/ZUki/5aYnP+OYC3/klYI/5FYD/+RVw7/kVcO/5FYDf+RVw7/mF0R/3ZBAP+OhoH/29bV/4RQ + D/+TWQ3/kVgO/5JYDv+RWA7/kVgO/5FYD/+UWAn/bEka/9/n8f+xmoD/mV0S/4RRCv+blIr//////+3w + 8f+KZzj/m2AU/6FoHf+GUgz/i4WB/6yPbv+cXxL/nWYf/55lHf+eZR3/nmYf/51mH/+iayH/hlAH/5SM + hf/e29n/lmEf/59lG/+dZR//nmYe/51lHf+eZRz/nWcg/5deDv+Ic1X/8/r//5p3S/+eYhP/e00O/7ez + sv//////7e7t/7KpoP+ddEb/omUW/3FIEf+orK7/v7Wp/5deGf+bZBn/nGQb/5xkG/+bYhT/l10Q/5xi + GP97Rgj/oJyU/+Dd2v+LWBv/mmAU/5lfFP+aYRT/m2MY/5pjG/+hZx7/g08H/7exqv/j4+X/iFoc/6Jm + Ff95UyD/2t3g//////////7//////6eUgP+eYhT/hVIM/3txY//W2+L/mXhQ/55gEv+cYRf/lFsS/5ds + Of+rjnD/vKyd/7ixqP/f3Nz/8vb1/8O6s/+yoI7/podj/5xuNf+aYRn/nWMX/5pgEf+DYTT/9Pr+/6uY + gP+RWA3/mFwQ/4dzV//5/P///v78//v7+//+/v3/zsrG/5ViJv+iZhb/ZEQc/7O3vf/GwLv/kmYt/5Vu + Pv/Dt6v/0tXa/7zByP+goJ//hoB6/7e3uP/x8fD/pKKe/5yen/+yucL/wL+//6ycjP+dcTr/glEQ/8/K + wv/d4OH/gFUd/6RpG/+CUBD/vbm0///////7/Pr///7+/////v/19vr/oIRn/59kFf+NVxD/ZldG/8rQ + 2P/Iwrz/4eLh/7y+vP94ZUv/bkod/31OEP9oNwD/jYeC/9rX1f9zRQz/c0kQ/2xPK/98cmj/sLS6/8K/ + vP/JwLb/9Pn//4VsS/+VXRL/m18P/4pwS//3+Pv//v79//7//v///////v39///////Rz87/lGg0/6Jn + GP9+Tg7/bWRX/9rf4//O0M7/dVcz/5FWCv+gYhH/qGwd/4dSC/+SjYX/3dvZ/5tkI/+laBn/nWIS/3tE + AP9qVTf/+Pr7//j9//+FdmH/i1QM/6VpHP+BVRj/0c7K///////9/fz//////////////////f39//3/ + //+4r6f/lWQj/6RnGP98Tgz/ZlpI/7K1vP/OzMv/r5qF/5lyQP+eaCL/fUUA/5eRif/e3Nj/i1YU/5Re + Fv+UaDP/sZd9/+fi4P/T1tr/dmVO/4ZRDf+lax//iFIL/7Cmk////////P38//////////////////// + ///+/v7//f79//j6/f+voZf/lmUi/6NmF/+JVRH/ZEom/4SBfv+1u8T/xcbL/7+3sP+llID/z8zI//Dw + 7/+xoY//x7yy/9jb4P/W3eb/nJmU/2tOKP+QVxD/pGob/4pVDP+oln//+/7///v9+////v7///////// + ///////////////////+/v7///7+//b5/f+5sKj/l2w4/6BkFv+eYhL/eEoM/2ZNJv93bF7/kpKP/6qt + sv+2u7//ubq+/7S4vf+ioaL/g3ps/2pOKv97Sgv/oGQW/59lFP+JWRv/sqOR//v+///+/fz//f79//7/ + ///////////////////////////////////+/v7////+//7////Rzs7/oohp/5dmJv+iZRT/nmEQ/4tU + C/97Sg7/cUkW/21KG/9uSx7/cEkX/3dJDf+JUwr/n2IS/6BlF/+SXBb/lHJI/8rEvP////////79//7+ + /v/////////////////////////////////////////////////+/v///v79///////v8vb/xsC6/6WL + bv+bbjj/nGUe/55kFP+gYhL/oWIR/6FjEf+gYhL/n2IT/5xhGP+TYib/mHdQ/7uvof/u8fT///////38 + +v/+/v7//////////////////////////////////////////////////v///////////////f39//// + ////////9Pj8/9vb2v/Bt67/rZuG/6SJav+gfln/nn1Z/6CCYf+nkHf/uKqb/9TPzP/x9Pf///////// + ///8/fz//v////////////////////////////////////////////////////////////////////// + /////////v7+//39/f/////////////////+////9/v///H09//w9Pj/9fn9//7///////////////// + ///+/fz//v7+//////////////////////////////////////////////////////////////////// + //////////////////////////////7+/v/+/f3//f39//7+/f////////////////////////79//39 + /P/9/f3//v7+//////////////////////////////////////////////////////8AAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACgA + AAAwAAAAYAAAAAEAIAAAAAAAACQAAAAAAAAAAAAAAAAAAAAAAAD///////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////z+/v/5+fr/+vn5//v6+f/7+vz//fz+/////////////f////3+/v/+/////v////7/ + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + ////////////////////////////////////////5Obn/9rc3//g4eL/5eXm/+rp6v/x8PH/+Pn5//7+ + /v///////v/+//7+/v////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////+/v7//////+zu7f+Qi4T/cmxk/3NxbP+HhH//mZmb/6+1 + uf/Iy8v/2dnX/+Pi4//v7/H/+vv9///+///+/v////////////////////////////////////////// + /////////v7+//7+/v////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////+/f3//////9zZ1v9qSCD/d0UF/29D + C/9kPQn/WjsT/1ZCKP9iW1H/h4WC/7Gzsv/JzdD/2tze/+3u7v/9/P3///////////////////////// + //////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////+/v3//////9rb + 3f+QaT3/rGoW/6FpIf+eaSD/oGYY/5VcEv97SQz/XDkN/1BBKP92cGj/q62u/87Oz//f39//9fX4///+ + ///+/v7///////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + ///9/f3//////93Z2P+IYzb/oGUW/5xiGP+dYhX/mmEW/5piHP+gZx7/pWgc/5BcEf9nPgj/Uzwl/3l6 + dv+7u7z/09TV/+zt7////v7//v/+//7+/v////////////////////////////7+/v////////////// + //////////////////////////////////////////////////////////////////////////////// + ///+/v7//v7+//7+/v/9/f3//////+Hi5P+Vhnr/n4lw/5yDaP+de1H/nHI9/55rKv+dZBj/mGAW/55l + Gf+kaxz/jloW/1w3Cf9YTjz/oaSk/8vN0P/m5uf//fz9/////////////////////////////v7+//7+ + /v////////////////////////////////////////////////////////////////////////////// + /////////v////7+/f/+/v3//f39//r6+//29ff/7e3v/+7v8P/v8fP/7/L1/+Dh5f/Hxcb/t7Sy/6ee + kv+fhmj/nXM9/59lH/+aYRP/nGYb/6JpHv94SQz/Szsg/4+Rj//Lysz/5uXn//79/v/+/v7//v7+//// + //////////////7+/v/////////////////////////////////////////////////////////+//7/ + /v/9/v7//f7+//3+/v/8/v3//f39//38/v/29vr/4ePl/8LHyP+iqKr/oaOh/8/R0v/9/f7/4uTi/7u+ + vv+/wsT/0dTW/9fY2//Hyc3/r62r/6CKeP+icjv/nmUW/5hhGf+haiD/iVcR/0w0FP+Dhoj/y8vL/+jn + 6f/+/f3//v7+//7+/v////////////////////////////////////////////////////////////// + ///////////+//3+/f/8/v7//v79//39+//8/f7/9/r8/83R1f+Qko3/Z2BR/1hEK/9aPRX/QSwT/66w + s//8/P7/emlV/1Q3Ff9bSC//ZWBW/4+Pj//CwMD/1djX/8rMzv+spaT/o4Bb/6JpI/+ZYBX/omgd/41b + F/9LMxD/iYiG/8zPz//t7vD///////7+/v///v////////////////////////////////////////// + //////////////////////////7///3+///+/v3//Pz8///////v7/X/kY6K/1ZILv9gOw3/fUwM/5Nb + Ev+nZxv/VzcP/6emq//1+///nHxY/5xeE/+PWRH/dUcK/1c6Df9YSTn/hYOL/8fFxf/Y3t7/u7/C/5+I + bv+gayz/nV8U/6FoHf+OWRT/SDMa/5iam//X2Nj/9vX5///+//////////////7+/v////////////// + ///////////////////////////////////+/////v7///z+/v/8/Pr//f7//9rY1f9wYkr/XzoF/5Ra + EP+kaB//omce/5tlHf+hZh3/XDoO/6mpqv/2+///mX5d/5tgGP+eZR//o2ke/6JnGP+CUQ7/VjgN/2Ra + S//BwsH//fz9/9XV2P+gj33/n2wu/5tgFv+gaCD/glEP/1FDL/+0tLP/4+Hl//38/f/+/v7///7+//7+ + /v////////////////////////////////////////////////////7//v7+//39/f//////9vb1/6Gb + lv+FZ0T/qnQz/6BlGv+VYhT/mGIW/5tiG/+iaBn/VjkQ/6aprP/4+/7/mn1b/5tgFv+dYxr/mmIa/5xi + Gf+iaRr/oGkc/185Df+ak47///////r6+v/R0tT/nopx/6FrI/+YXxj/pWke/2hACf9qZmH/zs/Q//Lw + 8v/8/v///v7+//7+/v///////////////////////////////////////////////////////f39//7/ + ///Nzs7/r7O2/87Q0v+7u7r/oJWG/5x/W/+hcDr/n2cf/51jFf+kZRj/WzcO/7a3uv/4/v//mnxX/5xf + Ev+bZBr/m2Ib/5ZjIf+OaDf/ln1g/762rf/w8vP/297i/72/xP/b3Nn/wMHG/5t+Wv+hZRv/mmQY/5di + Gf9SNhj/nZ2f/+Dk5f/6+/z//v7+//7+/v/////////////////////////////////+/v7//v////7+ + ///8/Pz//////8/Rz/9cQSH/Vj4k/3t7e/+8vL3/yMrP/7i7vv+rpqD/n5CB/52AZf+felD/Zk0u/87P + zv//////mYJv/5RrRP+Ydk//nINo/6mekv/IxcP/5+nr/+Pn6v+goqL/X085/1lHM/+lq6r/4OHl/62p + qP+ecTz/m2IV/6FpHf93Sgr/YFhM/8vO0P/09PP///7///z9/v////////////////////////////// + //////////////39/f/9/f3/8PHy/3RfQv+NWA//k1sU/1s5Df9WRjH/enhz/62trv/Hx8n/x83S/8bJ + y/++vb3/vbiz/+rs8P/7/v3/1tjW/8fHx//R09b/3N/j/97h5f/EyM3/kJCO/11TQ/9bOxH/jFgR/3JC + B/9aVEj/zMrI/9vd3/+ahnb/n2ci/5piGv+cZBb/UjgW/6OgoP/o6+3//f7+//7+/v////////////// + /////////////////////////v7+//v8+///////oZuU/3pKC/+haB7/nmUa/59nG/+JVRD/Yz4L/1U+ + If9jVEX/e3Rt/5KSkf+jqKv/vb66/9TW2v/6+vn/9vj5/8XHzv+bnZ3/gH98/2dbTf9cQyT/ZD4N/4VR + DP+gZhb/oGcc/55nHv9XOA3/g4WF/+Xp6f++ubX/mm0//5lhGP+maB3/cUQJ/3FpYv/d3+L/+vv7//7/ + /v/////////////////////////////////+/v7//f39//7//v/o6er/d1k3/5xhFf+bYxv/mmIa/5ti + Gv+fZhr/o2ka/5ZfFP+ATw3/bUIL/2E9Dv9cPxn/Tz8r/7a7vP/5/P7/inxq/1o/F/9gPw//a0EK/31N + DP+UXRT/omcb/6BmHf+aYhv/mWIZ/59oG/+HUxD/U0Y2/8jJyf/i4+T/nIBq/59kG/+dZRz/jlkR/1RE + Lf/CxMf/9/j5//7//v/////////////////////////////////+//7//Pz7//////+yq6L/glEO/59n + Hf+bYhr/m2Ia/5tiGf+ZYhv/mGIa/51kGv+fZx3/o2gc/6NnGP+fZhn/UzMJ/6iop//2+///lXdT/5ld + EP+fZh3/o2ge/6FnHv+dYxz/mmIa/5pjGv+aYxn/mmMa/5pjGf+iZxj/WjoQ/5OVlf/v8vX/qqSb/51k + KP+aYxn/n2Ua/1k7Ev+fo6X/9PX3//7+/f///////////////////////////////////v7//v79//n8 + /v+PeFr/lFsP/5xlHP+bYxr/mmMa/5tjG/+dYxn/nmMY/5xjGv+bYxr/mWIb/5hiHf+iaRr/WzoQ/6io + rP/7/P7/nH5g/5tgGv+dYxr/mmMb/5pjGv+bYxn/m2MZ/5tjGv+bYxv/m2Mb/5tiG/+jaB7/d0kL/2pm + Xf/n6uz/xsbF/5ZqPf+bZBf/pGge/2pBCf+Dgn3/8fD0//39/v/////////////////8/v7//P38///+ + /v/9/v3//////+To6/+LYjL/nWIT/5liGf+bYhj/m2IZ/5tjGf+aYhr/mmIa/5piGv+aYhr/m2IY/5di + F/+jZxb/XDgO/62wtv/7/v7/mn1a/5pfEv+eYxb/m2MY/5pjGP+ZYxn/mWIa/5tiGf+aYhn/mmMZ/5ti + GP+eZRv/jVYO/2BNOf/d4ub/3+Di/5JxTf+eZBj/oGkd/3hIDP9vZ1z/6uzu//39/v////////////// + ////////+v7//+jr7P/39/f//////8rLyP+EXSz/oGsi/5tnJf+dZyT/nmck/51oJP+daCT/nWcj/51n + JP+dZyT/nWgi/5loI/+gaSX/WTkR/8HDxP/8////mHtc/5pkI/+cZyb/nmcj/51nI/+daCT/nWck/51o + JP+dZyP/nWgj/51oI/+eaiT/lmQf/1tEJ//g4uP/8/b5/5d9Yv+bYBj/oGga/4RQD/9kWEj/4ufp//7+ + /v///////v7+//7+/v/39/j/sbOz/73DxP/l4uH//v///9/h4f+klo7/rJiL/6eXi/+ml4r/qJeL/6eX + i/+ol4v/p5eL/6eXi/+nl4v/p5iJ/6qXjP+qlYr/mo6B/+bp6f/9////t62n/6mVh/+pmYv/p5eL/6eX + i/+ml4r/p5eL/6eXiv+nl4r/p5eL/6aXjP+rmIz/qpaF/5aOhv/u7u7/+////56Hcv+XXhj/omgY/4pW + D/9fUDv/4eLm/////////////Pz7//////+vqJ7/RyYE/3h0cf/Ozs3/5+nr///////9////3uLm/9ja + 3f/Y2t//2Nrf/9ja3//Y2t//2Nrf/9ja3//Z2t//1trf/9na4P/U2t//3+Df/+fn6//6+/v//////+ns + 8v/X2t//2drg/9na3//Y2t//2Nrf/9na3//Z2t//2drf/9fa4P/Y29//2Nre/93f4v/q6un/9Pn9/52D + a/+YXhj/oWcd/4xXDf9hUTv/4eHq//7////9/f3//v79//H09/97YTv/ml0M/0wyE/+Lj47/2NjY/+Lj + 5P+Xk4z/enJq/3FtZ/9xbmf/cW5n/3FuZ/9xbmf/cW5n/3JuZv9xb2b/cm1n/3VuaP9vbGT/fHdx/8bJ + yv/4/Pz/vLi0/353bf9zbmX/cm9m/3JvZv9xb2b/cW9m/3FvZv9ybmb/cW5m/3JuZv91b2T/cGtl/3t6 + cv/T0tL/9/v+/5uDaP+YXhL/oGcf/45XDv9hUjz/4eTs///////6/Pr//////7a1r/99Tgn/oWwg/4lU + E/9JNiP/s7a5/7Swrf9oRRz/dkcI/3JHDP90Rgz/c0YL/3NGC/9zRgv/c0cL/3NHC/90Rwv/dEcL/3ZH + C/90SQ3/RSoI/6ysrP/6/f//f2lN/2o/BP90SQ3/c0cL/3NHC/90Rwv/dEcL/3NHC/90Rwv/dEYM/3VG + DP90Rw3/ckMK/000FP/LzM//+Pz+/5Z7Xv+YXhP/oWce/4pVDP9oW0b/6e3y///////8/v3/+fv9/4Fs + Tf+WXBL/nGIe/6dqGv9yRgv/V1JH/7O2vv+Yck3/pmgb/6FoHf+iaB3/omcd/6JnHf+iZx3/omcd/6Jn + Hf+iZx3/oWce/6JnG/+nbBz/WjoQ/6amrf/5+v//nn9e/6JkGf+jaBz/omcd/6JnHf+iZx3/omcd/6Jn + Hf+iaB3/omgd/6FoHf+gah//oGIS/2dTNP/h5+//6err/4xoPv+ZYRn/oWke/31NCv91bGD/+Pr9//7+ + /f//////w8PA/31OC/+eZRn/mWIb/5tjF/+jbB7/XjoM/5qZnP+kjXX/m2Aa/5tiGv+aYxr/m2Ia/5pi + Gv+aYhr/m2Ia/5tiGv+bYhr/mmIZ/5liG/+haBj/XDkM/6moqv/4/P//mXxc/5lfFP+aYxv/m2Ia/5pi + GP+aYxn/mmIZ/5tiGv+aYhr/mmIZ/5hiGv+fZxr/iFIK/3RtXf/9/v//0tDN/4lcI/+cYxr/omkc/3RH + C/+OiIT///////39/P//////mY+E/4xiMP+lczX/mGEZ/59mGv+TWxP/ZlE6/8bIyf+xqqL/mmUm/5xj + Fv+aYxz/m2Ic/5xjGP+bYxr/nGMb/5pjHP+bYxz/mmMa/5liGv+hZxj/WzkP/7CytP/4/v//nHxb/5te + E/+bYxn/nGIb/5liHv+bYxz/m2Ma/5pjGv+cYxj/m2Ma/5hiHP+faBr/dEgP/6Wjof//////raSZ/4xX + EP+bZR3/oGYa/2lDEP+1srL///////z8+//9////29rY/7u8vv+agGn/n2Mb/5xmHf+KVhH/UEQz/87U + 1v/Pz9D/lnVQ/6BjHP+aYxn/m2UW/5xjGv+ZYhz/mmQY/55kFf+eYxf/nGQY/51jHP+hZib/VzoU/8PF + xv/9////lntc/5tjH/+cZhr/m2MX/5phFf+aYhb/m2QY/5tkGf+aYxr/m2Ia/55kG/+dYRH/blMv/+Tl + 5//2+Pz/inFT/5ZdEP+cZR7/nGAS/2hNKv/Y3eL///////z9/f/9/v7///////////+lm5T/mWQj/5xi + Fv+gaBz/VDYK/5aXlv/l5uj/oZmT/5xrK/+dYRT/nWId/5xkGf+hZRX/m2Mb/5RiJ/+SaTn/mXhY/56J + df+il4b/pZqN/+zq7P/6////t7Or/6KOfv+iiHL/nnxX/6B0O/+eaST/nGEZ/5xgFv+cYxr/mmMZ/59o + Hf+BTwv/mZKG///////HxMH/flIZ/55kGP+fZh3/iVIK/350ZP/3+/////79//3+/v/8/f7/+vv6//7+ + /f/Kycr/kWs9/59jFP+haR//eUkJ/2BYTv/V1tf/yc3Q/5d9X/+fZiD/nmQZ/5diH/+SYyz/l3lY/62h + mP/Jxcb/3t3g/97i5v/T2t//3drb/9/g5v/6/Pr//////+Pm7//Lz9H/vL7C/66oqP+kk4T/noBb/5xu + Nf+dYxj/nmQY/5RdFP94XTz/6Ojp//n8/P+Mdl3/kFgQ/55mG/+gZh3/cUcR/7K0tf//////+/z7///+ + /f/9/v7//v7+///////y9PX/m4Nw/6FmHv+YYhr/n2Ya/040E/+Rk5f/4eDf/7q2t/+Zd03/jmIh/5J5 + X//DvLj/6evw/+Tp7v/Excn/lpeV/3t1bP9nW1L/X1dM/7zAw//9/f3/paGZ/3dyZv+Ign3/pKen/7/E + yP/Mz8//vbu6/6SalP+fgV3/oGoj/3xTG//DwL3//////6+vrf94TBP/n2Yc/51lHP+SWhD/emRI/+/x + 9f/+/v7//P3+//7+/f///v////////7+/f//////urOz/5VsO/+eYxP/nWgf/4ZRDP9UQzL/sbe//9nc + 2v+2r6n/tauk//X5+v/1/v//oaSk/2ZbSv9aQB7/XDwS/3BFCv+DUQv/SCwG/6iorP/7/f//hGlN/2xA + A/9iQA3/VTwY/11LOf+AeXj/tLW5/8nO1f+/v8D/m419/7asof//////29zf/2xSMv+UXhX/nGUa/6Fn + G/91Sg//tLKv///////8/Pv//v////////////////////7+/v///v7/7O/y/5uHdP+iaiT/mGAX/6Bp + Hv9rQAj/XFhT/8TDyP/c3N7//P///9jX1f9xYE7/XjkJ/4JODf+YXxj/o2Ya/6JoHP+max7/WzsS/6mo + rP/2+///oYBf/6RkGv+haB//nWIZ/4ZTEP9fPAz/UUAl/4qHgf/r6+r/9fb3///////l6e7/dGRQ/4tV + C/+gZhv/nGYe/5JYC/+EcFX/9Pb6//79/f/+/v7////////////////////////////8/f3//////8nI + yv+VdVP/nmUa/5hiG/+gaBv/YToG/2ViWv+/wL//2t3d/6yuqf+DalD/pnMz/59nGv+aYhj/nGMW/5li + G/+haBr/WDkN/6Wpqv/4+///mX1e/5pfFv+cYxv/mWQa/59nHf+nahz/hVEM/2NQOP/i5ef//////+Pl + 6/90aFf/ekwK/6BnHf+cYxr/m2IY/3VUJf/U1dT///////39/P/+/v7///////////////////////// + ///+/v7//P39//3+//+uqqb/nHRH/5pkE/+fYhz/oGYc/2E+Bf9eVEn/rrG3/9jX1//Bw8T/pZmN/599 + WP+ebi//mmQb/51hFf+hZhX/XTgP/7C0tP/6/f//nHxY/51gEv+eZRf/mWMW/5hgHv+OZD3/oZGF/+jj + 4P//////y8vP/2RXSf91Sg//pGcb/5dhHf+iZxr/fFEP/66roP//////+vz8//7+/v////////////// + /////////////////////////P7+//3+/v/29/j/pZqW/51xO/+aZBH/mWMd/6BoGv9tRAf/TUAw/4uJ + jf/Lycn/0NLV/7m3uv+onpX/nohu/6B3SP+hczf/Wzoa/8PEx//+////lXxh/5JmLf+XbD3/lnlf/6aa + kf/T0tD/+v7//+zu8/+bm5v/WUUo/39PDP+jZx3/mWMY/59pG/+FURH/m5GA//3+/v/7/fv//f79//// + /////////////////////////////////////////f////v9/f//////6+7w/6GUlP+gdD3/nGQS/5tg + Gv+gaCP/jVcN/1Q4DP9VUEb/kpGR/8HEyP/T1Nf/zMzP/7u+wP+yraz/qaOX/+np6f/6+vz/w7+8/7my + rf/Nzcz/5Ofo//H2+v/i4+j/pqam/2NZSv9eOxD/kFoV/6VmHP+WYhr/oGgW/4ZTFf+ajXf/+Pn7//v9 + /v/5/fz///79//////////////////////////////////////////////////7//v/9/f3//////+3u + 8f+ppKD/nnlQ/59mHv+YYBX/n2cd/59mHP97Swz/VTgO/1VLOP91c27/oZ6e/7q/vf/KzNP/2Nzd/9ba + 4f/a2t7/4OLk/9fd4P/LzdL/s7Cz/4KBff9cUD//WDsT/39NDf+jZxv/nGUc/5xmGP+bZBz/hFgi/6aY + hv/2+vv//v79//v9/P/9//3//v/+//////////////////////////////////////////////////// + /v////7//P39///////5+/v/u7e5/5yCaf+fbjD/n2IU/5phFf+haB7/nmYb/4dUDf9lPwn/VDkV/1VC + KP9dTz//Z19W/2tlXf9uZlz/a2Na/2FURv9WQyz/VTwY/2VAC/+GUg3/omYZ/59mH/+ZYxj/oGcX/5Vg + GP+GYjT/ubGo//3////+//7//v7+/////v/+//7//v////7+/v////////////////////////////// + //////////////////////////////39/v/+/v3//////9jZ3f+nnZL/mntW/5xqKv+dYxP/m2IU/59l + HP+jah3/omUb/5ZbFv+HUxH/fEwL/3pKCv96SQ3/e0sM/4VTDv+RXBP/nWQZ/6RqG/+gZxz/mGMb/5tk + Gf+bYhr/jF4t/5aDbv/Y2Nb///////z8/P/+/f3///////////////////////////////////////// + ///////////////////////////////////////////////////+/v7//P39///////2+Pn/yMjL/6ma + jP+efFn/nWw3/59lHP+dYhT/mGIV/5xlFv+fZxn/oWYd/6FoHf+gaR3/oGce/59mHP+dZBv/nWMY/59j + F/+cYhn/mWIg/45jNP+Vf2T/wr+6//j7/v//////+/z7//7+/P/+//////////////////////////// + ///////////////////////////////////////////////////+/////v///////////////f7+//v8 + /P/+/v3///////X4+v/S0tX/tK2k/6SPd/+delX/mm86/5poKf+bZCH/nmMf/55kHP+fZRv/nWQc/5pi + Hf+YYiD/lmQo/5RpOv+Vdlj/pZaE/8jGxP/09/r///////7+/P/7/fz//v79//7+/f/+//////////// + ///////////////////////////////////////////////////////////////////+/////v////// + ///////////////////+/////f39/////////////////+/x9P/X19r/wL28/6+pov+pm43/n4p0/56H + b/+dhnH/mYVv/6OQf/+pnJL/tbCs/8/Nzv/q7PD//////////////////f38//7+///+/////v////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////7+/v/+/f3//f79//////////////////// + ///6/f//8PL1/+3w8v/u8fP/7vL0//f7/v///////////////////////v38//39/f////////////// + //////////////////////////////////////////////////////////////////////////////// + /////////////////////////////////////////////////////////////////////////v/+//7+ + /v/9/f3//P38//z9+//+//3//////////////////////////v/+/f3/+/39//v9/P/9/f3//v/+//// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + /////////////////////////////////////////v7+//7+/v/+/v7//v7+//////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAoAAAAdAAAAOwAAAABACAAAAAAAODV + AAAAAAAAAAAAAAAAAAAAAAAA//////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////7/ + ///+/////v7///7+/v/9/f3//v7+//7+/v/+/v7//v3+//7+/v/+/v7//v79//7+/f/+/v7//v7+//7+ + /v/+/v7///////7////+/////v////7////+/////v7+//7+/v////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + /////////////////////////////////////////////////////////v////z+/v/8/v7/+/3+//v8 + /f/7+vz/+/r7//v7+//7+/v/+/v7//v6+//7+vz//Pv+//38/v/9/P7//v3+//7+/v/+/v7//v7+//z+ + ///8/v7//P7+//z+/v/8/v7//f7+//7////+/////v////7////+/////v////7////+//////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////+/////P7+//r8/f/6/P3/+fr8//Tz9f/u7e7/7e3t/+3t + 7f/u7u7/7+/x/+/w9P/x8ff/8/T4//b2+f/5+fr/+vr7//v6/P/8/P7/+/3+//v9/v/8/f7//P7+//z+ + /v/8/v7//f////3////9/////f////3////9/////f////7///////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////7//v/+/v7//v7+//39/f/39/f/6+vr/97e3v/X2Nj/1tbW/9jY2P/Z2tr/2t7c/9zg + 3v/g4+L/5efn/+rq6//v7e//9fHz//f09v/6+Pn/+/r8//38/f/+/v7//v7+//7+/v/+//7///////// + //////7////+/////v////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + /////////////////////////////////////////////////////////////////////////v7+//z+ + /v/8/P7//Pz8//X18f/g4uD/yczN/77Dw/++wcP/v8HF/8DDw//GxcT/y8jH/83My//P0M//0tPT/9fZ + 2v/d39//4+Pk/+rp6v/w8O//9fT0//j49//6+vr//Pz8//7+/f/+/v7//v7+//7+/v/+/v7//v7+///+ + /////v////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////+/v7//v7+//////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////+/v7//P3+//T5+v/r7u7/4+Lg/9DO + zf+4ubn/rLC0/66wtv+wtLb/tLe5/767vP/Cvb3/vry+/7q8wP+5v8H/vcPF/8LHyf/Izcv/0NXP/9nd + 1v/g4uD/6ejq//Hu8P/29PX/+/n5//z6+//8+/v//P39//z9/v/9/v7//v7///7+//////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////7+/v/+/v7//v7+///////+/v7///////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////7//v/8/v3/y87N/2FfWf9RSDz/U0Y4/05FN/9MRzz/VlFI/2di + WP93c2n/hoJ6/5CNh/+cm5j/rKyu/7Cyt/+0t7v/t7q7/7q7u//Av73/x8XC/8vKyP/Q0NH/2Njb/+Hh + 4//p6uz/7vDz//T1+v/6+v3//fz+//79/v/9/v7//v7///7+//////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////7+/v/+/v7//v7+//7+/v////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + /////////v////r7+v+9urT/QzQj/z8nDP9AIgP/PyIC/z0iA/87IQP/OiEC/zkhBf8zIwv/MykX/0M6 + Lf9YUUj/amZf/4mIg/+enpz/r6ys/7m1tv+7uLn/vby7/8G/wP/Cw8b/yMvO/8/T1//a3eL/5ejs/+/x + 9P/29/n/+fn7//z7/f/+/f7//v3+///+//////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////+/v7//v7+//// + ///+/v7//v7+//////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////7/+/r4/8e9 + s/9yVzr/i2Qz/4hZGf+KWRb/hVUX/35SGP92SxH/cUIN/2Q8Cv9XNgj/SysF/z0gAv81IAb/NygS/0I4 + LP9eWVT/enl5/5WYmf+urar/urax/7m7tv+4vbv/vb/C/8bHy//Q0db/2dzg/+Po6v/u8fH/9/f3//z6 + +//+/P7//v7+//7+/v/+/v7///////////////////////////////////////////////////////// + //////////////////////////////////////////////7+/v/+/v7///////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////7//v/7+/n/x7+3/3ZbPv+dbzf/oGUY/6Rl + Ff+hZRj/mmMd/5hjH/+aYx3/l2Eb/5NfGf+OWhj/glMW/3BHEP9cNwn/RCgF/zIgA/8xJAv/QTgk/2BZ + TP+Hgnn/p6Oc/7W0sP+2t7f/ubu7/77AwP/Iycr/09LT/93d3f/p6ur/8vL0//n4+v/8+/3//f3+//7+ + /v///v////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + /////////////////////////v7+//f5+v++vLz/b1hE/5lsOP+dYhb/o2QT/6FkFf+cYxr/mWIc/5lk + HP+ZZBv/mmQa/5tkGv+cZhv/mGUc/5JfHP+IVxz/dksV/2I6CP9KKQP/Lx0G/yskFf9KRDj/eHNr/5+c + l/+zs67/uLq2/7u7uf/CwMD/zcnL/9fV2P/h4eP/7O3u//b19//7+vz//fz+//7+///+/v7//v7+//7/ + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + /////v//+Pn7/728u/9uWEP/mWw6/55iGP+iYxX/oWQY/5xjHf+XYiD/l2Mg/5ZjHf+WZRr/mWQW/6Bj + FP+iZBX/oWUW/6FkGv+cYyD/ll8h/4pWHv9xSBj/UzUL/zgjAv8vIQz/SD4u/3VsZP+bmJb/sLK0/7W5 + u/+7vL3/x8PB/8/NzP/Y2tv/5ujp//Hy9P/6+fv//fz+//39/v/8/v7//v7///////////////////// + //////////////////////////////////////////////////////////////////////////////// + ///+/v7///////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////7+///6+vr/w764/3BZ + P/+abTj/nGMX/6JkE/+eYxX/mmMb/5hiHf+XYh3/mGIc/5piGf+cYxj/nWMY/55jGP+eYhj/nWIX/5ti + GP+bYxr/nGQc/5tkHP+PYBn/elMV/108DP9AJgP/NR8L/0g5L/95cW//n6Kk/7G1tf+9urn/wMC9/8TH + x//R0tf/4OLk/+zv8f/29vn//Pv8//39/v/+/v7//v7+//////////////////////////////////// + /////////////////////////////////////////////////////////v7+//7+/v////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + /////////////////////////////////////////v////r6+f/Hv7b/cls9/5duNf+YZBj/nGMS/5xk + Ev+cZBX/nGQV/51kFP+eZBf/nmIc/5pgHP+XYRz/lGEg/5RhIf+WYh7/l2Ma/5hjFf+dYxT/o2QW/6Jl + Fv+aZRj/kWIc/4FUGP9jOwz/QyMD/zciEP9ORjz/fX96/6Kqqf+1t7j/v7q9/8W/wv/Nzc3/2N7d/+fr + 7f/29Pb//fr7//79/f/+/v7////////////+/v7//v7+//7+/v////////////////////////////// + ///////////////////////////////////+/v7//v7+//////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////7//fr5/8m8tv90W0T/nXdK/5xsMP+fayv/nWkn/51nJP+fZSH/oWYc/6Bl + F/+dZRX/m2QX/5tjG/+YYR3/mGEf/5hhIP+ZYh7/m2Ma/51iGf+eYhn/n2QW/55lE/+fZhT/nmUX/5Vg + Gf9/UBb/XTgM/z8iA/83KRj/WVlS/5OSj/+2sq//vLq3/76+vv/EyMn/0tjY/+bn6P/18/T/+/r6//39 + /f/+/v7//v7+//7+/v/+/v7//v7+//////////////////////////////////////////////////// + /////////v7+//7+/v/+/v7///////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////7+/v/+/v7//v7+//7+/v/+/v7//v7+//7+/v/+/v7//v7+//7+ + /v/6+fn/xL2//3dmYP+pjnj/qYlo/6uJZ/+siWf/qoZh/6d/WP+ne07/o3c//51yMP+Zayj/mWUi/5xk + HP+eYxf/n2MX/55iGP+fYhn/nGIb/5dhH/+XYR//m2Ma/5xkFf+dZBP/mmQY/5ZiHv+NXR3/eEwT/1Iw + CP80IAf/Rzwq/357b/+lqaT/tLm3/7m8v//Dxcn/0tXX/+Ll5v/v8PH/+Pf5//z8/f/9/f3//v7+//// + /////////////////////////////////////////////////////////v7+//7+/v/+/v7//v7+//7+ + /v////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////+/v7//v7+//7+ + /v/+/v7//v7+//79/v/+/v7//v7+//79/v/+/v7//v7+//39/f/8/P3//P39//f7/P/L0dX/gICC/46G + gP+QhXr/joV6/46Ffv+SiH7/lop8/6CQff+pk3r/rZBx/6yLZv+phFf/pHlD/6FxMf+daSL/nGYa/51k + Fv+aYxb/lmIb/5ZhHf+bYxr/nGMY/51jGP+bZBn/mWQb/5hjHf+XYx7/h1ga/2M9Df8+JAP/OCsW/2Fh + U/+anJj/trS5/7q5v//Aw8X/ztHS/+Dg4//v7vD/+Pj5//38/f/+/v7///////////////////////// + ///////////////////////////////////+/v7//v7+//7+/v/+/v7//v7+//////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////7+/v/+/v7//v7+//7+/v/+/v7//v3+//38 + /v/9/P7//fz+//z7/f/6+fv/+fj6//j3+f/4+Pr/9vn7/+zz9f/Y3t//09XT/9TT0v/Jy8v/wMTF/77B + wf+wsa//lpOQ/42Ff/+Shn//mIl//6KRgf+plHz/sJV0/6uIWv+iekH/nG4s/5lnHf+aZBj/nWMY/51k + GP+dZBn/m2IY/5tkGP+aZBn/mGMa/5pjHP+aYx7/kV8c/3dNFP9OLgj/NiIO/1ZQQ/+PkYz/r7K1/7e6 + uv/BwsD/0NDQ/+Hg4v/w7/H/+fj5//39/f/+/v/////////////+/v7//v7+//////////////////// + ///////////////////+/v7//v7+//7+/v////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + ///////////////////+/v7//v7+//7+/v///////v7+//7+/v/9/f3/+/v9//n5+v/29ff/8/L0/+7u + 8P/q6uz/6Ofp/+jn6f/v7O7/9/X1//z8/P/9/v7//v7+//3+/v/7/f3/+Pj5/+7t7//k4uX/397f/9DQ + z/+xsrL/nJyd/4+Ni/+OioL/m46B/6uVfv+tj27/pYBS/59wMv+eZiD/nmIb/51iGP+dZBn/nWQY/5pk + F/+aZBn/mmMb/5tkGf+dZRn/mWMc/4VUGv9bOA3/NyMG/0VBL/+EiX//rrCs/725uf/DwcL/0M/R/+Lh + 4//w7/H/+fj6//79/v/+/v7///////7+/v/+/v7///////////////////////////////////////// + ///+/v7//v7+//////////////////////////////////////////////////////////////////// + /////////////////////////////////////////////////////////////////v////7///////// + //////////////7+/v/+/v7//v///////v/+/v7//v7+//////////////////7////+//////7///7+ + /v/9/f3//f39//79/v/9/Pz/+vn5//X29v/v8fL/6evs/+Tm5//e4OH/2dvc/9XX1//R09T/0dPU/9zc + 3P/v6er/+vb3//z8/v/9+/7//fz8//j39//t6ur/4d3e/9zX2P/c2tj/3uDd/+Ll5v/f4+b/0dbZ/7m9 + wP+hnqL/k4uJ/5SHgf+mk4b/tJZ3/6qDVv+fbzv/nGUn/51jGv+dZBX/m2UV/5pkF/+aYxv/m2MZ/51j + F/+cYxr/mGQd/4hbG/9jQA7/OyUD/0A4Jv9+e3b/rqyw/7q5vf/CwcP/0dDS/+Lh4//x8PL/+vn6//39 + /f/+/v7//v7+//7+/v///v7////+///+/////v7////+//////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////+/////v///////v/+//7//v/+/v7//v7+//3+ + /v/9/v7//v7+//7+/v/9/v7//v////7//v/+//7//v/+//3+/v/+/v7//v3+//z8/f/6+vv/9/b5//Px + 8v/s6+v/4+Tl/9vd3f/T1tf/y9HQ/8bJyv/Cxcb/wcLB/77AwP/Aw8T/y8/Q/93i4v/w9PT/9/v8//n8 + /v/4/Pz/8PTz/97i4f/Kzs7/wcTE/8PCxP/HxMj/ysjL/9LQ0f/c2tn/5OPh/+Tk4v/V1tP/sLCx/4+P + jf+PiID/pZSD/7GTdv+rgFP/oG4u/51mGf+bZRT/mmQV/5pjGP+dYhv/oGIc/51kHP+ZZRj/lmYZ/41g + G/9vRxH/PyME/zsvJf9zd3f/qK2w/7m5vP/DwcL/09DS/+Ti5v/x8fP/+fn6//7+/v/+/v7//v7+///+ + /v////7//v7+//7+/v////7///////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + /////////////////////v////7//////v/+//7//v/9//3+/f/9/v7//P7+//v9/v/7/f3//f////3+ + /v/8/v7/+/7+//n+/f/7//7//f7+//78/P/6+vz/9PT6/+zs9P/l5+v/3N7f/9PW1v/Ky83/wMC//7e5 + tv+mr63/kZmb/4yRkP+Ojoj/kI+K/6OmqP/Bxsz/2t3d//Tx8v/8+vz/8vT1/9bX0/+9vrT/rbGu/6is + r/+sr7P/r7Gx/7S4tP+4vLv/vL2//8LBw//Hxsf/zc7O/9fa2f/c4eT/09jc/7i6u/+Ylpb/j4iI/6CP + h/+tjnP/rHxJ/6RrJv+dYxj/lWIZ/5VkG/+aZBv/mWIc/5hiHP+aYxv/nGQb/5ZhGP91Sw//RCkG/zww + Hv9vcW//pKmr/7q7t//Gw8H/09LS/+Pj5//y8vT//Pz7//79/f/+/v7//v7+///////+/v7//v7+//// + /////////v7+//7+/v////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////+ + /////v/////+//7//v/9//3//f/9//z+/v/8/v7//P7+//3//v///v7//v7+//z+/v/8/v7/+f79//r+ + /f/8/fz/+Pf4//Dw8v/l5uv/29zi/87S1P/AxMP/sbSx/6Ghnf+Gf3r/cGhf/2FcUf9EPTD/PDIg/z4w + Gv88MCD/ZWFf/7m8wP/c3+D/8/Hy//36/P/X2Nj/cGlg/0g7Jf9GPi3/W1NG/3FoX/93cmn/i4yC/5+h + nv+qrK7/tLW4/7u6u/+/vr//w8LD/8nKy//V2Nf/4OTg/9fa2P+ztLf/lI+S/5iJhP+xlXz/solb/6Vw + Nf+dYyH/m2Ma/5xlGP+aYxr/mGEa/5piGv+cYxj/nGUY/5FgG/9vShX/QikH/zgvIf90c27/ra2o/7u8 + uf/DxcX/1NXY/+fn6f/29fX//Pv7//3+/f/+/v7///7////+/v///v7///7////////+/v7//v7+//// + //////////////////////////////////////////////////////////////////////////////// + /////////////////////////////////////////////////////////////////////////v7+//3+ + /f/8/v3//f/+//z//v/8//7//P79///+/f///vz//v79//z9/f/7/P7/9vn7//L09v/n6ur/3eDh/8/R + 0f+6vLr/nqGb/4CAdf9iXlD/S0I0/zwsGv81IAX/QCgF/0stBv9VMwf/UzIG/zUeAv88NC3/qKqp/+Hi + 5f/w8fX//Pv8/8jFw/9UQzD/VjUP/0wtB/9JKQX/QiUD/zolC/9CNSL/VEs+/2toYv+Iioj/o6Oh/7Sx + sP+9uLj/wby8/8TCwP/JzMf/1tjT/+Pi4f/W1NT/p6Wm/5CIhv+kk4L/tJFt/614Q/+jZiL/nmIX/51j + GP+cYxf/nGMX/5xjGP+aYhr/lmIf/41gIf9xSxL/QygD/0EyIf9/eXT/rK+v/7m8vP/Gx8b/2drb/+vs + 7//3+Pn//f39//7+/v/+/f///v7+///+/v///v////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////7////+///+///+/v7//P7+//z+/v/8/v7//f/9//z+ + /P/+/v3///79/////P/+/vz//Pv9//r3/P/w7vT/4uXo/87U0/+2urn/lJeS/2lnXv9KQzD/OSsM/z4o + BP9JLQn/Xz0Q/3NJE/+AURX/i1kZ/5JeHf+EVhr/Sy8M/zgxK/+kpab/5OLm/+7x9f/6+/3/zcnF/3hf + Qv+XZjD/jFog/4VUFv95TRH/Z0EN/1IxCf9BJQX/NCMK/zkxIP9YUkb/f3tw/6Cdl/+yrq7/ure6/7q8 + wP/AwsP/0M3K/9/d2//d4eP/uL3E/5WWmP+cj4L/sJR0/66CT/+gaij/m2Ib/51iFv+fYhf/oGMZ/51j + Gf+ZYxv/mGQc/5RhGP9zSQ7/QSUE/z80Kf9+fX7/sLGx/72/vf/JzM3/29/k/+/w8//6+vv//f3+//79 + ///+/v7///7+///+//////////////////////////////7+/v////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + /////////////////v////7///7///7+///8/v///P7+//z+/v/+//z//v77//7+/f/9/v7//f7+//z9 + /f/6+fz/9vP4/+bh5f/GxMX/mZqW/2lmXf9AOif/NSYL/0ktCP9lPg3/e04V/4hZGf+UYRr/nGQa/6Bi + Gv+hYxr/omQd/41bHP9OMg7/NjIt/6Okqv/m4ef/7vL2//b7/v/MysX/gGND/6hvMv+gZB//nGQb/5lk + Gv+WYxn/j10Y/35SFv9mQQ//TTAI/zsmBP86KxL/Ukc8/3hycf+bmZ7/ra66/7i2v//Dvrz/y8jC/9TW + 1P/g6Or/z9nc/5yfnv+KhXz/qJR6/66GV/+cazD/mmIe/6FiGP+jYxf/n2MZ/5xjGf+cYxn/nmUZ/5Jf + G/9pQxH/NiEH/0lAN/+RkY7/tbi4/73Bwv/Q0dP/5eXp//Tz9//8+v3//fz+//7+/////v////////// + //////////////7+/v/+/v7//v7+//////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////7////+ + ///+/////v////3////9//7//v/+//7+/f/+/v3//f7+//j8/v/3/P7/+Pr8//f4+//k5ef/trOw/3Ns + Yv9JOiT/PygH/1M0Cv9sRhT/iFcd/5heH/+dYR3/m2QX/51lFP+eZRf/nmIZ/59iGf+gYhz/i1oa/04y + DP84Myz/paWo/+ji5//t8fX/8/r+/8nKxf9+Y0P/qHAx/6FjHv+dYhn/mmMY/51kGP+gZRn/nWQa/5Rh + Gf+JWxb/d04Q/1o3Cf8/JAf/NyYW/09FQv95dnz/oqCm/7i1t/+8vbr/w8bC/9TZ1v/p7e3/4eXm/6qu + sP+Ri4X/qpJ7/6yHYf+abDb/m2Ic/6JjFv+gYxf/nWIZ/5xjGv+cYxn/mmQd/4xcHf9hPQ7/OCQK/1lT + S/+cnZz/ubq5/8jGwv/Z2Nn/6unv//f2+v/9/P3//v3+///+/v////7////////////+/v7//v7+//7+ + /v/+/v7///////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////+/v7//v7+//7////9/////P7+//3+ + /v/+//3//v78//79/f/8/P3/9/r+//f7/v/49/r/4d/e/5ydl/9PSDv/NyQK/1MxCP92Sw3/kVwX/5ti + HP+gZB7/n2Ee/51hHP+aZBf/nGMY/5tjGv+ZYh7/mGId/51jHf+PWxj/VTQJ/z41Kv+op6T/5uLm/+zw + 9f/0+/7/ycrG/3xiRv+ibjL/nGIf/5xiG/+ZYhv/mmIc/51hG/+dYxj/nWUX/55mFv+aZRf/jV4Y/3hO + Ff9XNgv/OyMI/zgqGv9fWU7/l5SO/7S1tP/Dxsf/1NfX/+no6P/39vb/8vH0/7+6vP+WjYX/pJF+/6eH + Y/+abDb/mmEe/55iFv+fZBj/nGMb/5hiHP+YYh3/mWIe/4hZGv9WNgv/NCQS/2lkXv+sqqb/wL64/8vK + yf/c3OP/7+7z//r6+v/+/f7///7+/////v///v////7///7+/v/+/v7//v7+//7+/v////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////7//v/9/v7///7///7+/v/8/v7//P7+//7//f/+/vv//P3+//j8 + /v/4+/7/9PP0/8/Kxf+EeWz/QTIb/0QtC/9sSRT/jVsc/5xkGf+jZBX/o2QX/55jF/+bYhr/m2Ec/5pi + HP+aYhv/mWMc/5ZiH/+ZYR7/nmMb/5BcF/9XNAn/PjMq/6mno//l4+T/7fH0//b7/v/Mycf/fGFI/59v + M/+aYx//nmIb/5tiHP+ZYh3/mGId/5pjGv+eYxn/oGMW/6BlFf+fZBb/mWQb/45eG/92ThL/VDYI/z0o + C/9LQC3/gX52/76/v//g4uL/8fDw//v3+P/++/z/9vT1/8vJyf+clpD/oI18/6eIZf+bbjf/mmIc/55j + GP+cYhr/mGId/5pjHP+dYxv/m2Qb/4FVFf9LLgj/PzEg/396df+1tbL/wsG//9HQ1P/l5en/9vX3//78 + /f/+/v3//v7+//7+/v///v7///////7+/v/+/v7//v7+//////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + /////////v/+//3+/v/+/v///v7+//z+/v/8/v7//v7+//7+/P/8/Pz/9vr9//b4+v/Y1tL/dWpb/1E9 + Iv9pRRP/hFgY/5NiG/+bZBv/nWQZ/55iGP+cYxr/mmQa/5lkGf+bYxn/nWMb/5xjGv+bYxr/mGIa/5tj + Gf+fZRf/jlwV/1EzCf83MSz/oqam/+Pk4f/v8fP/+vr+/87Jx/97YUb/n3Ex/5plHv+eYhr/nWIb/5xi + Gv+bYxr/mmIc/5phHf+dYhz/n2MY/55jFv+bYxf/mmUZ/5dkGP+HWRX/aUIO/0UqB/9BMSH/fnd0/9XW + 1f/2+Pn/+vv8//v8/f/6/Pz/9fn6/83Oz/+blI7/oY55/6uJX/+fbS7/nWIY/55iGP+aZBv/mmMZ/51i + F/+eZBj/lmMc/3NMEv8+JwX/SUI3/5eYmf+6urv/ycbF/9za3P/u7fD/+/n7//z9/f/8/v7//v7+//// + /v///////v7+//7+/v/+/v7///////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////7//v7+//7+ + ///9//7//f7+//7+/v/+/v7//fz7//f29v/x8vP/7u3u/8jBvP9mWU7/h3Jb/62FUf+odTb/nGck/5ph + GP+bYhn/mGIb/5djG/+XZBn/lmcW/5dlFv+bZBr/nmMa/55iGv+cYxr/nGMX/51lFv+LXBb/TTIK/zQy + Lv+gpqr/5OTi//Hw8f/6+f3/zMnG/3thRv+jcS//nGUc/5xiHP+fYhr/oWMV/6BlFP+bYxj/mWEb/5ph + Hf+bYxz/mmMa/5ljGP+ZZBf/m2UW/5tmGv+VYiL/e1Ei/0krE/9RQDn/wr+9//v+/v/4/f3/9/v5//X2 + 9v/z9vf/8/X2/8bFxP+UjYT/oo10/66GVf+gaiP/nWMX/5liGv+aYhn/nmEY/51iGP+cZBv/kF4a/2E9 + Df8zJRH/aGVl/6eprP+/v77/0s/P/+fl5f/29PX/+/v8//z9/v/9/v7//v7//////////////v7+//7+ + /v////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////+/v/+/v3//f7+//7+/v/+/v3//f79//38 + /f/39vX/6uzq/+Dh3v/d3Nn/1NDO/52bmv+OiYb/pJCG/7OTfP+qf1j/pXA4/6JnIf+cZBj/mGQY/5dk + GP+VZRb/l2QY/5hjGv+aYhv/nGEb/5tiHP+bYhr/nGQa/4tbGf9PMQv/OTQu/6aprP/r5eb/8/Lw//X5 + +//HyMb/fGBG/6luLv+eZBv/mWIc/5xiGf+eYxf/nWQX/51kGf+cYhn/nGIY/5tiGP+aYhr/mWIa/5pk + HP+daSL/nm0s/5tuNv+NaDz/dFk9/4h5bv/Z19b/+fz8//b4+P/08/D/7uvr/+bk6v/r6ej/6+rn/7W3 + uf+MhoT/pI1y/6p/Qv+dZx7/mGEf/5lhH/+dYRv/nWEb/5xjGv+bYxv/hFUX/08wCf9GNiT/hoeD/7G4 + uv/Hx8f/3dra/+vs7//2+fv/+f39//v9/v/+/v7//v7+//7+/v/+/v7//v7+//////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////7+///+/f/+/v7//v7+//z+/f/4/Pz/9/r7/+3u7v/Y3N3/ycvP/8DF + x//JzMv/0NDQ/7m1sv+OjIn/l5GF/6aUff+tj27/qYJT/6F1P/+baS//m2Qh/59iGP+fYRX/mmQT/5xl + Ev+eYxL/nmMU/59jF/+gZBn/j1sZ/1QxC/8+NTD/rrG1/+3s8P/z9fP/9Pv8/8TLxf97ZET/p3As/5tm + GP+YYxr/mWQX/5hjGv+WYh7/mWId/5xhGf+cYxb/nWQY/51mH/+bain/m24y/5xwPf+Ub0j/hmpP/4d3 + Zf+oopn/2drX//T5+v/x9PX/6uvu/+Lh5v/X1d3/0M/U/9XU0f/k493/5eXm/66tsP+RhHn/qo5l/6V2 + Ov+dYiH/nWIb/5xjGf+aYxn/mmMZ/5pjGv+TYBz/b0gT/zwkCP9bVEz/n6Kl/77Awf/Pz8//4OPo//Dz + 9//5/Pz//P7+//3+/v/+/v7//v7+//7+/v/+/v7///////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + ///+/////v////7+///9/v7/9/z+//P6/f/o6un/xMG+/7Cwrv+xtLb/tLrA/7q8wP/Hxcj/1dHN/8PJ + x/+lqqf/kY6G/5OLfP+gkXn/qZB0/6uIZP+nekv/qW85/6VoKf+baB3/m2QW/5xhEv+dYhX/n2IX/6Bj + Gf+PWhj/VDAK/0U5M/+8vsD/8/f4//T4+P/2+/3/yMvE/31jQf+mbi7/m2Qa/5phGv+bZBb/mmUa/5dj + H/+aZB7/nmUg/55pJP+cbS7/mXE7/5RzRv+Pc03/jHNX/4t6av+fl5D/ysnI/+zw8v/x9vn/6+/y/+Tm + 5v/U19j/w8fL/7q9xf+6vcH/v8PB/8/Rzf/l5eX/3d3i/6Cdn/+Th3b/qohf/6ZtLv+eYxf/nGQW/5tk + F/+aZBn/mWMZ/5hjHP+JWhz/VDEM/z0pHP+De3r/tre4/8THx//X293/6+/x//j5+v/9/f3//v7+//7+ + /v/+/v7//v7+//7+/v////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////7//v/8/v7//P7+//z8 + /v/1+f7/5+7w/6yoof9dTkH/WEs+/3lya/+goaX/sLK3/7e6uv+/wL3/x8nI/83Pzf/Dw8T/qKin/5CO + if+Si4P/npCA/6uTev+wjm//qoVc/6V+Tf+jdD7/oW4z/51pLf+bZij/nGck/4xcHf9SMgr/Sj43/8rJ + yP/7/v3/+fz8//r8///LysX/fmJF/6NtOP+ZYyb/mmMn/59nJP+hayf/oG0s/6FwNf+fcj3/mnRH/5N2 + Uv+LdFn/iXZj/5KFdv+upp3/zMzK/+bp6v/09vb/7O3w/+Lk6P/Z2d3/xcTF/5+fmv99fXb/gX97/6Kh + n/+1ubj/wMTC/9LT1f/l5+7/yc3X/4mKiv+bh3D/r4BN/6BnH/+aZBX/mmQW/5lkF/+aYxj/mWMa/5Zi + HP91SxT/PyIH/1xPRv+hoaD/vcHB/87R0v/i5uj/9PX2//z9/P/+/v7//v7+//7+/v/9/v7//f7+//// + //////////////////////////////////////////////////////////////////////////////7+ + /v/9/v7////+//7////+/////v7+//7+/v/+/v7//f7+//r+/f/7/f7/+/z+//H1+P+4t7X/VEQw/0Yn + CP9GJwb/QCgP/1RMQ/99fXv/oaSk/7a2tf/Au7v/xb/A/8nHyf/OzdT/xcnN/7W4u/+dnp7/l5OO/5GO + hP+Si3//n4t8/6WJdP+nh2v/pIJj/6F9V/+kfU7/l3NB/1tBIP9ORjz/0NHM///+/f/+/P3//fz+/87I + x/+BaVb/rIBe/592Tv+eckv/oXVM/594Tf+aeFD/l3hY/5B5YP+KfGv/kYmA/6OdmP+/u7n/393a//Hx + 7//w8fP/6erp/+Xj3//c2dX/yMfE/6Ghnv9zb2j/Sz8u/z4nDv9BKRX/Zl5W/56lov+1vb3/xMbH/9rZ + 3f/o6vH/s7i7/42Ee/+nhWf/qHc8/5xlGf+bZBf/mmQY/5ljGv+cZBn/nGQX/45eF/9aOAr/OysX/3l4 + c/+0tbX/x8fK/9rc3//x8fH//fv6///+/f///v///v3+//z9/v/8/v7///////////////////////// + /////////////////////////////////////////////////////////v7+//3+/v////7//v////3+ + /v/9/v7//v7+//7+/v/8/f3/+/39//z8/f/5+/r/1NTP/29iUP9SNQ7/flMa/35QFP9gOQn/PSQI/zww + I/9fWlL/joyG/6uop/+4trj/u7m+/7u9w//Bxcj/y83Q/83P0f/DxMb/sbe4/56kpf+Zl5j/mY+M/5WI + f/+ajX//m4l3/56Hbv+WgGL/bF1I/3JuZ//e4eL//f7+//z9/v/7/P3/1NHR/4l9dP+giHf/l4Jt/5R8 + af+XgGz/j4Bx/42Eev+clIz/qKKf/7u4uP/T1Nb/5ebo/+7u8P/q6u3/4uLl/9va3P/T09P/xMXE/6ms + qf9+gXn/UEs8/0AuFf9RMwr/az4M/1kuBf9BLRv/bnFq/6Wvr/+8v7//0szL/+fk5f/h5ef/n56e/5F/ + df+qglz/oWwr/5tjGP+dYhn/m2Ib/5xkGP+cZRX/mWUW/3ZOEv87JQb/UkxE/6Cfnf/Dw8P/0tTW/+jq + 6v/3+Pj//f39//7+/v/+/f7//f3+//3+/v////////////////////////////////////////////// + /////////////////////////////////////////////////////////v7+//7+/v/+/v7//v7+//39 + /f/9/v7//vz8/+vn5f+LgG//VDgP/3lSHP+VZB3/nGQZ/49cFv9wRhL/Sy4L/zgjCv9HOSn/ZWBZ/4aG + g/+io6D/r7Gx/7q6uv+/vb3/xsLB/8zKyP/Qzs7/ztDS/8fQ0//AxMP/tLKx/7Gxrv+rqKT/n5aR/5eM + gf+Wjof/vLu//+/z+//4+/3/+P79//n9/f/p7Oz/s7Ow/5qUjv+bmZL/qaWf/7e0sP+7vLr/xcjJ/93e + 4f/o5+n/6+nq/+fn6P/d4OP/1tne/83S2f/Cx83/t7m5/6Chn/95e3v/VFJN/z4yIP9KLw3/a0MR/4dZ + Gf+UYRr/fk4R/0gpBf9BNyj/gYWA/7W3tf/LxMH/3tfT/+7w7v/Mz9D/jIWG/5p/a/+meUf/m2Mf/59i + Gf+cYxr/mGMa/5pkF/+dZRb/jF4Y/1Q1Cv86Kx3/hH95/7y5t//MzM7/4OLk//Dz9f/6+/z//v7+//7+ + /v/+/v7//v7+//////////////////////////////////////////////////////////////////// + /////////////////////////////////////v7//v7+//7+/v/+/v7//v7+//3+/f/29vT/saup/1A7 + H/92SxD/kGAf/5tjGv+fZBX/nWQZ/5ZfHv+BVRv/ZUIQ/0wtCP88Jwv/QTYi/15YS/99enH/nJmV/7Gu + q/+7trT/v7y4/8K/vf/CwsP/wcfK/8rOzf/R0tL/0dXW/9DV2f/Oz9H/0czJ/9jT0P/i4+b/6evz//Lz + 9v/1+/r/+fz8//n9+//w9fP/4uXl/9/k5v/i5ef/4uXq/+Ll5//h4uP/3t7f/9nY2//U1dX/z8/P/8bI + yP+9vsD/qqyv/42Oj/9xbmX/Uks7/z4wHP9EKgz/YDoO/4JRFv+UXhn/mmUa/5pmG/+SXxr/bUMQ/zwl + Cf9ST0P/nZ6b/8S/vf/QzMr/4uXk/+vu7/+sp6j/jnxx/6F/Wv+fay3/nmIX/5tjGv+WYh7/m2Ia/6Bk + Fv+aZBj/dEsQ/zkiCP9iV03/r6il/8jHx//X2t3/6+/y//n7/P/+/v7//v79//7+/v/+/v7///////// + ///////////////////////////////////////////////////////////////////////////////+ + /////v///v7+//3+/v/9/v7//v7+//3+/f/9/v3//Pv6/9ra1v9eVk//Wj0U/5ReGv+WYxz/m2Ib/55l + GP+eYxb/nmQZ/5ljG/+RYRv/g1cV/2xEDf9QMQj/OyYK/zsvHP9NRj7/bmll/4qFgf+em5j/pqam/7Cx + s/+5t7r/wL28/8LAv/+8wcT/vsXL/8XJyf/Pzsf/1NLL/9DT0P/Y297/7Ont//X29//8/Pv/+v76//v9 + /f/4+Pz/6u3y/93d4v/R09j/zM7Q/8zKyf/FxMT/u73A/7K1tf+np6X/l5SP/4J7cf9mXE//Sj0s/0It + E/9JLgn/YT0L/4BSEf+UXxb/nGQX/55lF/+cZBj/mmIa/5xjHf+NWRr/WTcM/zcqF/9vbmr/srKz/8LF + xf/T2dn/7fDu/9vW1f+Wi4T/ln5j/6h5Qv+eZRv/mWMb/5VhIP+bYRz/omMW/6JlFv+MWhn/SCwL/0M1 + J/+YkYr/wMHA/9DT1v/m6e3/9fj6//3+/f/+//3//v7+//7+/v////////////////////////////// + ///////////////////////////////////////////////////+//7//v7+///9/v/+/v7/+/39//v9 + /v/+/v3//f77//z9/v/x8vP/mJeS/1E4F/+EVxr/nWIb/5ljG/+YYRr/m2IZ/51jGP+aYhj/m2QX/5tl + GP+ZZBr/lWIb/4dXGf9xShX/VjcM/0EpCf88KBL/RjUm/1VHPv9mXVT/e3Zx/42Ihf+gnJf/q6el/6Sp + rP+psbf/trm5/769tv+/v7n/vcLC/8jN0f/k4eT/9fPz//z6+//6/Pv//Pz9//Ty9//c3+j/x8jP/7W2 + uP+prq3/oqal/5SVlf+AgX7/cW1m/15TR/9QPy7/STAV/0ksCP9XNgr/b0UP/4RUFv+TXxj/nGQU/59k + E/+cZBT/m2QY/5xjG/+bYhv/m2Mc/5ZjHv98UhT/RisH/0c/Nv+PkZL/u7+//8rOzv/h5OX/8vDx/7Ku + qv+QgHD/p31X/6NqLv+ZYRr/lmIZ/5piGP+gYRn/oWMY/5ZjGf9nQA7/PCYO/3Vvaf+0tLT/zc7P/+Lj + 5//z9Pf//P39//7//f/+/v3//v7+//////////////////////////////////////////////////// + //////////////////////////////7//v/9/v7///3+//7+/v/7/v3/+/3+//39/P/9/fr/+fv7/9PU + 2P9WTkP/d0gN/51jF/+aZBr/m2IZ/5tjGf+aYhn/mmMY/5pjGv+aYhr/m2MZ/5tjGv+bYxr/nGQa/5lj + G/+PXRn/f1IU/21ED/9YNQr/SCkI/0QpCf9ALBT/Qjco/1dNPv9iWU//YmBb/3V1dP+LiIP/lY+G/5iX + kf+qsbP/vsbN/9ze4P/x8fH/+/r7//T3+P/e3dv/wLy4/6aoqf+OjYz/cm9m/19dU/9WVEz/SkI5/z8y + H/9AKw//SCsH/1UxCf9oPw7/e08V/4pbGv+YYRr/nmQZ/51jG/+cYhn/m2IZ/5ljGf+aYxr/m2Ma/5tk + GP+YYxr/lWQd/5NhGf9pQAz/NyUT/2VjYf+tsK//xcjG/9ja2//y8fP/1tjV/5SMgv+deWP/qHFE/5lh + G/+ZZBP/m2QX/55hHv+dYhz/mWYV/4RTEP9DJgX/UEpD/6KhoP/Mycj/3t3g//Dw9f/7/Pz//v/9//3+ + /v/9/v7///////////////////////////////////////////////////////////////////////// + /////////v7///7+/v////3//v7///39/v/9/v3//v79//78/P/y8vD/mZqY/1Q5Hf+MWh7/m2Mb/5pk + Gf+bYhr/m2IZ/5hjGf+bYxn/nGEa/5xhGv+cYxr/nGIZ/5xiFv+cYxP/nmQV/5xlGv+ZZBv/lGEa/4tb + G/9+Uxj/ckkR/2E7C/9RMgz/SiwH/0QnBP89Jwr/QjEX/0o5IP9KNyP/T0Q3/4KDff+7wsb/297h//Dy + 8v/8+/v/4eLh/4uDef9aSTT/T0Es/0w6IP9ELw7/QyoD/0grBP9RMAj/XDkL/2pDD/97UBX/iVoZ/5Fg + G/+YYxz/m2Qc/5xiGv+cYhr/m2Ia/5piGv+aYhr/mmMa/5tjGv+bYxn/m2MY/5pkGv+ZYxr/mWUb/4JU + GP9FKQn/Qzsw/5CSjv/AwsD/0tHR/+vo6f/x8fL/qaSg/5N5Z/+neE//nmgm/5xjFv+cYxj/nGId/5ti + HP+bZhf/kF4Y/1MyCv85MCH/jIqE/8PCwP/V19n/6uvx//r7+//9//3//P7+//z+/v////////////// + ///////////////////////////////////////////////////////////////////+/v7//v3+///+ + /f/+/v7//fz+//7++//+/v7//fv7/97a1f9eVkb/e0wc/5djH/+YYxv/m2MY/5xjG/+bYRr/m2MZ/5pi + G/+bYhv/m2IZ/5tjGf+cYxn/nGQX/5xkFv+eZBf/nmQW/5xkFv+eZRb/nWQZ/5lkG/+XYxr/lGAb/41a + HP+HVhX/gFAQ/3NJEP9oQxD/YD4O/1IyDP81IAn/SkU9/62ysf/e4uL/7vHz//j6+//IyMb/W0s2/148 + Ef9eOwz/ZkEN/25ID/96ThD/h1QR/41aFv+SXxj/lWIa/5lkG/+aZBv/nGQZ/55kGP+eZBf/nGMZ/5pj + Gf+aYhn/m2Ia/5tiGv+bYhr/m2IZ/5tjGf+cYxn/nGQZ/5tkFv+bZRj/lGAc/2lAD/87JxD/Z2Vg/7O1 + tP/OzMr/4t/f//X19v/Mysn/kIJ1/5t4Vv+lcDX/n2IW/51kF/+ZYxz/mGMc/5tjGf+YYxv/aUIP/zQm + DP9xbWT/tba0/87S1f/l5+z/+fn4//3+/P/9/v7//f7+//////////////////////////////////// + /////////////////////////////////////////////////v///v7//v7+//7+/v/+/P7//v76//3+ + /f/29vX/sqqj/1M8HP+YXx7/mWMb/5hiG/+dYxn/m2Ma/5piGv+cYxn/nGMb/5pjGv+bYhn/nGMZ/5tj + Gv+ZYxr/mWMb/5piHP+aYhn/m2IX/51jF/+dYxj/mmMY/5tkGv+dZBr/nmMZ/6BkF/+fZBj/mmQc/5Nh + Hv+OXx7/gFUb/0otCf85Miv/paek/+Lk4//u8fT/9fv8/8bIxf9yXD//lWcr/5FgHf+TYBn/k2Ic/5lk + Hf+eZRz/nWUb/51lGf+cZBn/nWMZ/5xiGv+bYhn/nGMZ/5xjGf+bYxn/m2Ma/5tjGv+bYxr/m2IZ/5ti + Gf+aYhr/m2MZ/5xkGf+bZBj/nGQX/5xkGf+dZRr/hlMS/0UqB/9GQzv/nJ+d/8nHw//c2Nj/7u/y/+bq + 6/+bl5D/j3Zd/6Z0Qf+jYxv/n2MW/5djG/+XYxz/nWIa/55kGv98UBT/PSYI/1hQRv+lp6X/ys/T/+Dj + 5//29vX//f37//7+/f/+/v3///////////////////////////////////////////////////////// + /////////////////////////v////7//v/+/v7//v7+//z9/v/+/vz//f38/+rq6P92bWL/cUkX/51l + Gf+aZBn/mWEa/5xjG/+bYxj/nGIa/5xiGf+bYhn/m2Ia/5xiGf+cYxn/mmMa/5liHP+XYh7/l2Id/5li + HP+aYhr/m2Ib/5pjG/+YYhv/mWIc/5tjG/+dZBf/oWQV/6FkFf+eZBf/m2QZ/5tlGv+NXBr/UjML/zwz + Kv+op6P/5eTj/+3x9f/2+v7/ysrG/35jRP+lcTD/nWUc/51jF/+aZBr/m2Mb/51jG/+bYhz/nGIb/5xi + HP+dYhv/m2Eb/5lhG/+ZYRz/mmIb/5tjGv+dYxv/nGMb/5tjGv+aYxj/mmMZ/5pjGv+aYxr/mmMZ/5pj + Gf+bZBn/mmMZ/55kGP+YXxb/XTkM/zYuH/+AgoD/v7+8/9LT0//m6e3/8fX3/66xrv+Ke2j/onRJ/6dn + Jf+gYhf/lmQb/5ZjHP+dYhv/n2QY/4tbFf9NLQf/ST4w/5ial//Gy87/3N7j//Lz9f/8/Pz//f79//z+ + /f////////////////////////////////////////////////////////////////////////////// + ///+/////f/+//7//v/+//7/+v7+//z8/v/7+vr/zs3H/1dHM/+QWxn/mGYT/5hlGf+YYhr/mmMa/51j + Gf+aYRr/m2Ma/5liGP+cYhr/m2Ia/5tiG/+bYxr/nGMa/5tiGf+aYxj/nGMZ/5xjGf+bYxr/mmMa/5pi + G/+aYhv/mmIb/5liG/+cYxr/nGMY/5tjGP+bYxf/nGQW/45cFv9TMwr/OjIr/6ampP/n5OT/7/D2//j5 + ///Nycf/gGFH/6ZvMv+fYx3/nmIZ/5tiGf+bYhz/mmId/5liHf+aYhz/m2Ec/5tiG/+bYhr/m2Ia/5ti + Gv+bYhr/m2Ma/5tjGv+bYxr/mmMZ/5pjGf+aYxn/m2Qb/5pjGv+aYxr/mmMa/5tjG/+ZYxr/nWQX/55k + F/92SxL/OSYM/2JhXP+vsbD/zM3P/+Di5v/y9/j/xMvJ/4mCdf+ac1D/qWwx/59iGf+WZBn/l2Mb/55j + HP+gZBj/lmEX/2I7Cv9BMRv/hYaA/7/Dxf/a297/8PHy//v8/P/9/v3//P79//////////////////// + /////////////////////////////////////////////////////////////////////v///v7+//3/ + /P/6/v3/+vv+//T08v+lnpH/XEEa/51jHP+XZRT/mWQZ/5ljGf+bYxr/nWIa/5piGv+aYxr/mmMa/5xi + Gf+bYhr/mmIa/5xjGv+fZBf/n2QU/55jFP+fYxX/n2MX/51kGP+dZBj/nWMZ/51iGf+ZYxr/lmEd/5li + Hf+ZYhz/mWMc/5tjGf+cZBb/jlwW/1QyCv85MSz/pKWo/+jk5P/x8PX/+/r9/8/Jxv9+YEj/om41/5ti + If+cYhv/nGIZ/5tiGv+bYhv/m2Ma/5tjGv+bZBn/mmMZ/5tjGP+dZBj/nWMX/5xjF/+bYxj/mmMZ/5pj + Gv+aYxr/m2Ma/5tjGv+bYxr/m2Ma/5tjGv+bYxv/m2Mb/5tiG/+cYxj/nGUY/4dYFv9MLwn/SkQ3/5mc + mv/Jys3/3t7f//D08//f5eb/lI+I/5NzV/+pcj3/nWQd/5dkF/+ZYxj/n2Ib/55iG/+bYxr/dEgN/zgm + B/9wb2f/uLu8/9nY2v/u7fD/+fr8//7+/v/9/v7///////////////////////////////////////// + ///+/////v/////////////////////////////////+///+/v/+/v7//f78//z+/f/5/P7/6Oro/4Bv + Xf93Thb/nGQe/51iGP+cYhr/mWMY/51jGv+cYhn/m2MZ/5pjGv+aYxn/m2MZ/5xjGv+bYxn/nGIa/55j + Gf+eYhf/nmMX/59iGP+dYhn/nWMa/5xkGf+dYxn/nmIa/5xjGv+ZYxr/mWIb/5liG/+ZYxz/m2MZ/51l + Fv+OXBb/VDIK/zkxLv+kpqv/5uXl//Ly8//7/Pv/z8rF/3xiRv+dbTf/l2Ij/5xiGv+eYxf/nmMX/51k + Gf+dZBj/nGQY/5xkGP+cZBj/m2MY/5tjGf+aYhj/m2IY/5tjGf+bYhn/mmIa/5tiGv+cYhr/nGIa/5ti + Gv+cYhr/nGMa/5xjGf+dYxr/nWMa/5xiG/+bZBr/k2AY/2M9C/8+MR3/gIJ//8LExf/d3Nn/7u/u//L2 + +P+loJ//j3Re/6V2RP+cZiD/mWMX/5tkGP+eYhr/m2Ed/55kG/+CUhD/OyYE/2BdVf+ysrD/2dbV/+zq + 7//3+Pz//f3+//7+/v////////////////////////////////////////////3////9/////v////7+ + /v/+/v7//v7+///////+//7//v/9//7+/f/7/v3//vz+//f7/f/a3Nv/ZEo0/5VhIv+YZBz/nWIa/5ti + Gv+YYxn/m2Ia/5pjGP+cYhn/m2Ia/5pjGf+aYxr/nGMb/5xjGv+cYxv/m2Ec/5phHP+bYh3/m2Ic/5ti + HP+aYh3/mWIb/5pjG/+bYhz/nGMa/5xjF/+bYxn/mmMY/5ljGv+dZBn/n2UY/5BbFv9TMQn/OTIu/6Oo + rf/l5uf/8/Ly//v8+//OysX/fWFG/55uNv+XYyL/m2IZ/59jFf+fYxb/nWQZ/51kGP+cYxr/m2Ia/5tj + Gf+bZBr/mWMb/5diG/+YYhv/m2Mb/5xjGv+cYhr/nGIa/5tiGv+bYxr/mmMa/5tjGv+bYxr/nGMZ/51j + Gf+dYhn/m2Ic/5tiHf+aYxn/eEoO/zwmDf9qaGX/uby+/9zc2P/u7u3/9/n8/7i1tP+Ld2X/nXND/59p + JP+bYxj/nGUY/5xjGv+aYhz/nWUa/4tZFf9HKwj/TUY9/6SkoP/X1NH/6uft//b3/P/8/v7//v7+//// + ////////////////////////////////////////+//+//z+/v/9/v7//v7+//39/f/9/f3//v7+//7/ + /v/+/v3//v79//r8/f/++/7/9vn6/8bHxf9lRib/o2ck/59lF/+WZBv/mmId/5pjG/+aYxz/mWMa/5xj + HP+cYhz/nGMc/5pjHP+aYxz/nGMc/5tjHP+aYxz/mWMd/5tiHf+bYxz/mWIc/5liHf+ZYhz/mmIc/5pj + HP+bYxz/nGIc/5xiGv+aYxr/mWMb/55jGf+jYxj/lVoX/1YvCf89MjD/q661/+vs7v/19fP/9/z8/8nK + xv9+YkX/pHAv/51kG/+aYxn/n2MV/55jF/+aYxv/m2Qa/5tkHP+aZBz/mWMb/5pjG/+aYxz/mWQc/5lj + HP+ZYxz/mmMc/5tjHP+bYxv/mmMb/5pjG/+aZBz/mmQc/5tkHP+cYxz/nWIb/5xiG/+bYhz/nGEd/5xk + HP+GVBX/RyQH/2RXUv+3uL7/3uHk/+7w8v/5+/z/0M7M/4l7bv+UbUP/pW0r/5xiGf+dZBj/mmQZ/5lk + F/+aZRr/j10b/1YwCv9DNCf/l5iU/9HT0P/m6Or/9vf7//39/v/+/v7///////////////////////7+ + /v/////////////////8//7//P7+//r+/f/7+/v/+vr6//r6+//8/P3//f3+//3+/f/8/f7//P39//7+ + /P/z9PP/o6OZ/21OJf+naCH/o2US/5VlGP+ZZBn/nGQZ/5pjG/+bYhv/m2Ib/5tjG/+cYxz/mmMb/5pj + HP+bYxz/m2Qb/5pkG/+aYxv/m2Mb/5tkGv+aYxv/m2Mb/5tjGv+cYhv/m2Mb/5ljGv+ZZBr/mmQX/5Zk + F/+VZBj/mmQX/55jFf+RWxT/UzII/z45NP+3vMD/9/b3//r49//2/P3/yMrG/35jRP+nbyr/n2UY/5li + G/+eYhf/nWMY/5tjGv+bYxr/m2Mb/5tjG/+aYxv/mmMb/5tjG/+bZBv/m2Qb/5pjHP+aYxz/mmQc/5tk + G/+aYxv/mmMb/5pjHP+aYxz/m2Qb/5tkGv+bZRj/mWUY/5lkGP+bYxn/mWUa/4hbGP9QLQn/Xk9B/7W5 + uf/m6/D/8vT3//r8/P/a2Nj/ioB4/5BsR/+mbzD/nGIa/5xjGf+aZBn/mmQV/5hkGv+SXx7/YjgL/0Ew + Hv+PkY7/zdLO/+To6P/29/r//fz+///+/v///////v7+/////////////v7+//////////////////// + /v/8/f7/9/v9//L19//v8PH/7/Dy//b29//6+vv/+/z+//v9/v/+/v3///76/+/v7v9+fm3/cFMp/6No + Iv+eYxL/lGUX/5dlF/+cZBf/m2MY/5xjF/+bYxf/m2MX/5tjF/+bYxf/nGQY/5xkGP+cZBj/m2MX/5tj + F/+bYxf/m2MX/5tjGP+cYxj/m2MY/5xjGP+cYxj/m2MX/5llFf+ZZRX/lWUV/5RkGP+WYxn/mWMX/4ta + Ff9QMwf/QT83/8PJyP/+/fz/+/v6//b8///Kycb/fWFG/6JuMf+ZYh3/lWAg/5liHP+bYxj/nGMX/5xj + F/+bYxf/m2MX/5xjF/+bYxf/nGQY/5xkGP+cZBj/m2MX/5tjF/+cZBj/nGQY/5xkGP+bYxf/m2MX/5xk + F/+cZBf/m2UX/5plF/+YZRb/l2UW/5hkF/+WZRj/iV8Z/1Q1C/9OQSv/srSs//X29//5+fr/+/39/+bm + 5v+VjYj/jWxK/6NuMP+bYhv/nGMZ/5tkGP+bYxX/mmMa/5ZiHv9pPw3/PSwW/4OFgf/Lzsr/5efo//X2 + +f/9/P3//v7+///////+/v7///////7+/v///////////////////////v7+//79/v/09vn/5Orv/9ng + 5P/b4OD/6+vp//b18//5+v7/+/z+//79/f/+/fr/7e3s/3NxZf+CaUn/rHtG/6V0N/+fdjz/oXY8/6h0 + O/+mdDr/pnU4/6d1Of+ndTn/qHY5/6h2Of+ndTj/p3U4/6d1OP+odjn/qHY5/6d1OP+mdTj/p3Q6/6d0 + Of+mdTn/pnU4/6Z1Of+odTn/qHU4/6l1OP+mdjn/o3Q9/6RzP/+mdD3/l2c0/1k7GP9JQjr/zc7N//7+ + /f/7/fz/9/z+/8vIyP+AaFT/rYBR/6V1Qf+fc0L/oXQ+/6Z1Ov+odjj/p3U5/6d1Of+odTn/qHU4/6d1 + OP+ndTj/p3U4/6d1OP+ndTj/p3U4/6d1OP+ndTj/p3U4/6d1OP+ndTj/p3Y4/6d1OP+ndTn/p3U7/6Z1 + O/+ndjr/p3U5/6Z2Ov+dcz3/Z0cl/0Y1I/+tqqP//fv8//z7/f/7/v7/9ff4/6ahn/+LbU//nWsx/5th + Hf+dYxn/nGMW/51jFf+bYxr/mGMe/3FFEP87KBD/d3Zy/8jJxv/m6On/9fX4//39/f/+/v7//v7+//// + /////////v7+///////+/v7////////////8/f7///3+//Dy8v/X3+L/w8zU/8XMzf/c3Nb/8Ozq//f2 + +v/5+/7//P39//77/P/v7u//goJ+/4Z0Z/+qhW3/oX5g/52AY/+ef2P/n35k/51+Zf+df2P/nX9k/59/ + Zf+ff2T/n39k/55/ZP+ef2T/nn9k/59/ZP+ff2T/n39k/51/Y/+efmT/nn5k/51/Y/+df2T/nn9k/5+A + Y/+ggGD/pIBg/6J/YP+gfWX/oH1n/6J+Yv+VcVX/Z086/21oY//e4eH//v7+//z9/f/4/P3/0c/Q/4V1 + av+jhWj/pINk/5x/ZP+fgGL/oIBi/59/Y/+df2T/nn5k/55/ZP+ef2P/nX9k/51/ZP+df2T/nX9k/51/ + ZP+df2T/nX9k/51/ZP+df2P/nn9j/55/Y/+df2T/nn9k/55/ZP+gf2T/on9k/6OAYv+kgGD/pIFg/5+A + Yv9yXEj/VUk//7Oxr//9/P3/+/39//r+/v/7/v7/r6uq/4puUv+aazT/m2Ig/5xiF/+cYxT/nmQU/5xj + Gf+aZB3/dkoR/zsmDP9wbWj/x8fD/+jo6v/19vj//f39/////v/+/v7//////////////////v7+//7+ + /v///////v7+//v9///q5uj/sbCq/66yrv+5wMb/uL7B/8zLxv/j3tv/8e3z//X4/f/7/P7//fv+//b2 + 9/+8v7//mJCP/6eSjv+hkIj/nZCI/52Pif+Zj4r/l5CJ/5iPiP+Xj4n/mo6K/5mPiv+Zj4r/mY+K/5mP + iv+Zj4r/mY+K/5mPiv+Zj4r/mI+J/5mPif+Yj4n/mI+K/5mPif+Zj4n/mJCJ/5iQiP+ckIb/nY+H/52N + jP+cjoz/nZCG/5uKfv+Tin//trq4//D39//8/Pz//f39//r8/f/m5un/rqmm/6KTiP+jk4j/npCI/5+Q + hv+ckIf/mY+J/5iPiv+Yj4r/mI+K/5iPif+Yj4n/mI+J/5iPiv+Yj4n/mI+J/5iPif+Yj4n/mI+J/5iP + if+Zj4r/mY+K/5iPiv+Yj4v/mI+K/5mPiv+cjor/npCI/5+Qhv+fkIX/nZCF/4yEfP+XlJL/1NbX//r7 + +//7/fz/+f39//z9/v+wqqr/iW1T/5prNf+bYyH/m2IW/5xkFP+eZBX/nGMZ/5plHP94TRD/OycJ/25q + ZP/HxcP/6ejs//X2+f/9/f3////+//////////////////7+/v/9/f3//v7+//7+/v/9/f3/8PT0/5SL + h/9OQTL/W1RF/5aWlv+1urz/v769/9TPyv/j4OX/7/L1//n7+//6/P7/+/z9//H29f/Z2dr/19PU/9TP + 0v/Nzs3/zMvN/8rLzP/Ky8v/ycvK/8jLy//Jy8z/ysvM/8rLzP/Ky8z/ysvM/8rLzP/Ky8z/ysvM/8rL + y//Ky8v/ysvM/8nKzP/Lys3/zMvL/8vLy//Hy83/xcrO/8nLzf/My87/y8jR/8nJ0P/KzMn/z83G/9bW + zv/k6ur/7/b4//f4+f/7+/z/+/z+//j6/P/q6uv/29fV/9XS0//PztL/zczO/8zMzP/Ly8z/y8rM/8vL + zf/My83/y8vM/8rLy//Ky8v/ysvM/8rLzP/Ky8z/ysvM/8rLzP/Ky8v/ysrL/8rKzP/Ky8v/y8vL/8rL + zP/Iys7/xcrP/8jKz//Ly8z/zMvL/83Lyv/My8r/zM3L/9rd3f/r7/D/9ff2//n7+//5/f3//P7+/66p + qP+JbFD/nGo1/5xiIf+bYhf/nGQW/55jF/+cYxn/m2Ua/3lODv88KAj/bmpk/8fExP/p6O3/9fb5//39 + /f////7//////////////////v7+//39/f/+/v7//v7+//7+/v+5urb/Szgg/1AxC/88IQT/TEM4/5yf + oP+9vbz/xcK+/9TT1P/i5+b/8/b0//j6/f/8/fz/+/76//r8+//y9fr/5+nv/93j4P/b3t3/3dze/9/b + 3//e2uD/3tzf/9/b3//e29//3tvf/97b3//e29//3tvf/97b3//e29//3tvf/9/b3//e2+D/3dvf/97a + 4P/f2t//39vf/9zc3//Z3N//3N3f/93c3//b2+H/2Nvh/9ne3f/f39n/4t/a/9/d4P/j5On/7/Dx//f4 + +f/7/f3//P3+//z8/v/4+Pz/7/H1/+Tn7P/c3+T/3dzg/9/b3//f2+D/4Nzh/+Db4P/f29//39vf/97b + 3//e29//39vf/9/b4P/f2+D/39vf/9/b3//f29//3tvf/97b3v/f29//39vg/93b4f/Z2+H/29zg/93c + 3v/d3N7/3tze/9zc3v/d3d3/3t7e/+Lh3//r6ej/8/T2//j7/f/7/v7/rail/4doS/+daTP/nGIg/5ph + GP+cZBj/nmIZ/51iGv+cZRr/ek4N/z4oCP9waWX/yMPG/+jo7v/09vr//P39/////v////////////7+ + /v/+/v7//v7+//7+/v/+/v7/9vb2/3BsYP9fPxX/iVgX/2Y7Cf8uHAn/WFhZ/7OytP/Avbn/xMbD/9PY + 2v/p6+7/9/X9//78+v/9/vb/+/v7/+7u+f/b3OH/z9DL/8vIxv/Jx8f/yMbI/8jGyf/Ix8f/ysbI/8jG + yP/Ixsj/yMbI/8jGyP/Ixsj/yMbI/8jGyP/Ixsj/yMbI/8nHx//Ix8j/yMfI/8nHx//Jx8f/x8fI/8jG + yf/Nxsb/zcfF/8nGyP/Cxsr/wcjJ/8fIxf/Kx8X/zsfN/9XT2f/k5+f/9Pb2//z8+//+/vz//Pz+//P2 + +v/l6Ov/1tbX/8rLyv/Hx8f/yMfI/8nHyP/KyMj/yMfI/8jGyP/Ixsj/yMbI/8jGyP/Ixsj/yMbI/8jG + yP/Ixsj/yMfI/8nHyP/Jxsj/yMbI/8jHyP/Ix8f/yMbI/8rHyP/Lx8f/zMjG/8rHx//Jxsj/x8bJ/8bH + yv/Ix8n/0c7O/9/d3f/s7/H/9vn7//z9/f+up6H/hmVF/5xnL/+cYx//mWIZ/5tjGf+dYhr/nWMb/5xl + Gv96Twz/PikI/3BpZv/Iw8j/6Ojw//P2+//7/f7//v/+///+/f/9/v7//v7+//7+/f/8/v3//f3+//// + /f/KzMr/UD8j/4JYHv+gZBf/kFoS/08vCf8tIRj/dnRx/7W3tP+5vLv/x8vI/9zc4f/w7Pf/+Pj6//b7 + 9//j5OT/0s/V/8G+vf+xr6v/qain/6aoqP+lqaf/pKmn/6Sppv+lqaf/pamn/6Wpp/+lqaf/pamn/6Wp + p/+lqaf/pamn/6Wpp/+lqaf/pamm/6Wppv+lqaf/pamm/6Wppv+kqKj/pKep/6unpv+rqKb/p6eo/6Gn + qv+jqaj/qamk/6+urP+7u8H/ycvR/93g4P/v8vP/+fr7//r9/P/29fT/4N3c/8jHx/+3tbL/rKun/6ao + pf+lqKb/pamn/6Wppv+lqab/pamn/6Wpp/+lqaf/pamn/6Wpp/+lqaf/pamn/6Wpp/+lqab/pamm/6ap + pv+mqKb/pKim/6Sppv+lqKf/p6in/6mqo/+pqqL/pqeo/6emqv+np6f/pqqo/7G2tf/ExMb/2NjY/+rs + 7v/2+Pv//P39/62npf+DZEX/nGcn/5xkHP+aYhv/m2MZ/5tiG/+eYxv/nmUa/3tPD/9AKQj/cGtm/8XF + yv/o6fD/9fb6//z9/v/+//7//P77//z+/v///f///v/7//n++v/6+/7//Pz9/4eFff9fPAn/k2Ee/6Fk + Fv+hZhX/fVAV/0AlCP80KyH/ioyJ/7m/vf+9wbr/0c7Q/+Ti6f/t8fX/ur++/3p5c/9zamH/bGNZ/2Nb + Uv9aWFT/WlhS/1xZUf9bWVL/W1hS/1tYUf9bWFL/W1hS/1tYUv9bWFL/W1hS/1tYUv9bWFL/W1hS/1tZ + Uf9cWFL/XFlR/1tZUf9cWVL/XFlR/1pYU/9aV1P/XlhR/19YU/9dV1L/WVhS/11YT/9gWE7/a2Zf/5OV + lv/Cxsr/3N7e/+zw8f/3+vz/6ezt/7Gsp/+BdWr/bmVd/2ZeVf9gWVD/XVhP/1xYUf9cWVL/XFlR/1xZ + Uf9cWVH/W1lR/1tZUf9bWVH/W1lR/1tZUf9bWVH/W1lR/1tZUf9bWVH/XFlR/1xZUf9cWFL/W1lR/1tY + Uv9bWFL/X1pM/15ZTP9aV1T/XFdV/15YTf9cXE7/cndv/66vr//Y2dn/7O3t//j5+//9/v3/qqis/4Jl + Sf+caCH/nGQZ/5phG/+cZBj/nGIb/59iG/+gZhr/e04Q/0AoCP9wbGX/xcfN/+rs8f/39/r//f3+//// + ///8//r//v////38/v/9/vv/+v77//v9///d4OL/Wks1/35RDP+XYxr/nGQX/51lF/+QYB3/a0UX/zQd + Bf9JQTn/naOh/7u8uv/Gwr//1dXU/+Pl4v9+d3H/QjQf/0oyEv9LMA//Si8P/0QuEv9DLhH/Ry8R/0Yv + Ev9GLxH/Ri4R/0YvEf9GLxH/Ri8R/0YvEf9GLxH/Ri8R/0YvEf9GLxH/Ri8Q/0cvEf9GLxD/Ri8Q/0cv + Ef9HLxD/Ri8R/0YuEv9JLxH/SS8T/0cvEv9ELxH/RjAQ/0IrDv86KBT/XFZO/7W3t//f4t//7vLw//n8 + /P/Q0dD/ZFpL/0s0Fv9ELxL/RS8Q/0YwD/9HMBD/RzAR/0cvEf9HMBD/Ri8Q/0YvEP9GMBD/RjAQ/0Yw + EP9GMBD/RjAQ/0YwEP9GMBD/RjAQ/0YvEf9GLxH/Ri8R/0YvEf9GLxH/Ri4S/0cvEv9KMA7/SS8O/0Mt + E/9FLhP/SDAN/zknDP87Myb/lpGO/93d3f/w8PH/+/v7//3+/f+pqaz/gmVJ/5xnIP+dZBj/m2Eb/5xj + GP+dYhr/n2IZ/55mGf95TRD/QCkJ/3NvaP/Iy8//7e/z//j4+v/9/f7///////z+/P////7/+/3+//v+ + /f/8/Pv//P/+/5WZk/9YORT/lmMS/5hlFv+WYhr/l2Ib/5ZiHf+MXB7/YDkN/zEbCv9bWln/s7Gy/769 + uv/GxsT/2dbP/3dmWf9wUzH/e1Me/31ND/98TQ//eE4S/3hNEv96TBH/ek0S/3pMEf95TRL/eUwR/3lM + Ef95TBH/eUwR/3lMEf95TBH/eUwR/3lNEf96ThH/ek0R/3lNEP95TRD/ek0R/3tNEP96TRH/eU0R/3xO + D/99ThD/e00S/3ZNFP92ThT/akUR/0EmBf9CNiv/qaql/+Hl4v/w8/D/+/z7/8nHxP9lUzj/dlIh/3FM + F/91TBH/d04R/3lOEf95TRH/eU0R/3pNEf95TRH/eU0R/3pOEf96ThH/ek4R/3pOEf96ThH/ek4R/3pO + Ef95ThH/ek0R/3tNEf96TRH/ekwR/3pMEf96TBP/e0wS/31ODv96TQ//dkoW/3hLFf95TBD/VzUH/zoo + FP+TiYf/4eHi//Hz9f/7+/z/+vv8/6iko/+EY0L/nGYg/5tjGv+bYhz/nGIY/51iGv+eYxf/nGYZ/3VM + EP9AKw3/endw/87R1P/v8fT/+vr7//7+/v///////f7+//3+/v/5//7/+fz///38/f/l6un/VlM+/3lL + Fv+gZxL/mmYW/5NiHv+WYR7/nGIa/59jGP+LVxj/TiwL/y4iGf9/e3r/tru8/7m9wf/Lysf/d2VZ/45u + TP+cbDL/nGIY/5xiFv+XYxj/mGMZ/5piGP+bYxr/mWIZ/5hjGf+ZYhn/mWIZ/5liGf+ZYhn/mWIZ/5li + Gf+ZYhn/mWIZ/5pjGf+aYhn/mWMZ/5liGf+aYhr/mmMZ/5liGf+ZYhr/nWMW/51jFf+bYxf/mGIb/5Zj + Hf+FWhz/TjAL/z8zKv+mpaX/4OLn//Dw8//9+vz/zsrF/3pgQ/+bbDP/lGIh/5hhG/+ZYxr/mmMZ/5li + Gf+ZYhn/mWIZ/5liGf+ZYxr/mWMZ/5ljGf+ZYxn/mWMZ/5ljGf+ZYxn/mWMZ/5ljGf+aYxn/mmMZ/5pj + Gf+aYhn/mmIZ/5piGv+bYhr/m2QW/5djGf+WXyD/nGEd/5tiGP9oQQv/RjYh/5qWmP/j5en/8fX3//v8 + /v/t7vD/mpGL/4NeNv+cZyL/mWMc/5liHf+bYhn/nGIZ/55jF/+ZZRn/bkgP/0IvFP+Kh4H/1tnc//Dz + 9P/7+/z//v7+//7+/v///f//+v7+//n//f/8+/3//v3//6alo/9ROxf/lV4d/55lF/+aYhn/l2Ie/5ti + Hf+fYhj/omQU/5xjG/94Txv/PyYE/zsxJv+Gjo//tLzF/8HEzP+Fenb/hmlP/6JyPv+cYBn/n2MX/5tj + Gf+bZBr/nGMZ/51jGv+cYxr/m2Ma/51iGv+dYhr/nWIa/51iGv+dYhr/nWIa/51iGv+cYhr/m2Ma/51i + Gv+cYhr/nGMb/51iG/+dYxv/nGIb/5xhHP+eYhn/nmIX/51jF/+cYxj/mmQb/4laG/9PMAz/OzIs/6Sj + qf/h4Or/8O75//z5/v/Oycb/f2FH/6FtM/+cYyD/oGEb/55iGv+dYxn/nWMa/51iGv+cYxr/nGIa/51i + G/+dYhr/nWIa/51iGv+dYhr/nWIa/51iGv+dYhr/nGMa/5tjGv+cYxv/nGMb/5tjGv+cZBr/nGMb/5xj + Gv+aZBj/l2Qc/5phHv+hYhn/m2EV/107Cv9PRzr/pqqz/+br8v/0+Pr//P3+/97e3v+Je23/glos/59p + JP+ZYxz/l2Id/5tjGf+dZBn/nWQY/5VjGv9kQAz/RDMc/5yal//h4+b/8/T2//z8/P/+/v7//v7+//39 + ///6//z/+//+//77/f/v8fH/aF5O/29JFf+bYxv/m2Qe/5tgHf+cYhz/n2Ia/6BjFv+gZRT/nGQZ/45h + H/9tSBD/NiEE/0FCO/+rrrH/ys/X/6ujpf95XUr/qHtM/5pgHf+fYhr/nGIa/5tjG/+bYhv/m2Ib/5xj + G/+bYxv/m2Ic/5tiHP+bYhz/m2Ic/5tiHP+bYhz/m2Ic/5tiG/+bYxv/m2Ib/5tjG/+bYxv/nGIc/5xi + HP+bYhz/mmEe/5piG/+bYhn/m2MZ/5tjGP+bZBj/i1sX/1ExCv85MSz/o6So/+Pi5//v7vj/+vn+/87K + x/9+YUf/oG0y/5xjHv+eYhn/nWMZ/5tjGf+bYhr/m2Ib/5tjG/+bYxv/m2Ib/5tiHP+bYhz/m2Ic/5ti + HP+bYhz/m2Ic/5tiHP+bYhv/mmIb/5tjG/+bYxz/m2Mb/5tjG/+aYxz/mWMb/5hjGv+XYxv/m2Ib/6Jk + F/+VXxT/TzQI/1xaUP+9wsn/7vD2//f6+v/7/v3/2tfW/4h0Xf+FWiX/oWkj/5liHP+XYx3/m2MZ/5xk + GP+cZBj/kWIc/1w6C/9GNiT/pqWl/+fp7f/29vn//f39//7+/v///////f7+//z//P/7/f////3+/77B + uP9VPRn/jF0a/5plGv+ZYR//nWEe/51iG/+eYxn/oGQV/55lE/+dZRj/lGMc/41fG/9dOwr/Kx0L/21m + X//Q09b/yMPF/3BYSP+rg1j/mWIg/59iGf+dYxr/nGMb/5pjG/+aYxr/nGMZ/5tiGv+cYhv/m2Ia/5ti + Gv+bYhr/nGMb/5xiG/+bYhr/m2Ia/5xjGv+cYxr/m2MZ/5tjGf+bYhr/nGMa/5pjGv+ZYhz/mmMa/5tj + Gf+bYxr/nWQY/59mFf+PXBP/VTII/zsxK/+lpaX/5uTj//Dx9P/4+/7/zsrG/3xhRf+gbjH/m2Mc/5xj + F/+bYxb/m2MY/5tiGv+bYRv/nGIb/5tiGf+bYxn/m2MZ/5tjGf+bYxn/m2MZ/5tjGf+bYxn/m2MZ/5ti + Gv+cYxr/nGMa/5tiG/+bYhn/m2Ia/5tiHP+ZYxr/mWQY/5hkGP+cYxf/oWUW/4xaEv9HMQr/bW1k/9TV + 1//59/n/+vz8//r9/v/JxML/h2tK/41bHv+gZiH/mWIc/5diG/+bYxn/nWQY/51lGf+NXxv/VDUK/05B + Mv+vsLL/6+3y//n5+//+/v7//v7+//7+/v/+/v7//f39//z8///z9vr/d3Ng/3BEDP+aYxn/lGQa/5tj + G/+bYxr/mmIc/5ljG/+cYxn/nWQW/51lGP+XYxj/l2Qc/4ZYHf9LLwz/NSYa/7a3t//f3uD/d2lb/6J/ + Wf+fayr/nWEa/55jGf+dYxv/nGMa/5xkGf+dZBn/nWQZ/51jGf+dYxj/nGMY/5tjGf+bYxn/nWQZ/51j + GP+cYxn/nWQZ/51kGf+cYxj/nGIZ/51jGf+cZBj/nGMZ/5tjGf+bYxf/nGMZ/5tiGv+cZBj/n2UU/5Fc + E/9WMgf/PTIs/6empf/n5eH/8fL1//j7/v/MysX/e2FE/6BvMP+aZBv/m2QW/5pkF/+bYxj/nGMZ/51j + GP+dYxj/m2MZ/5xjGP+cYxj/nGMY/5xjGP+cYxj/nGMY/51jGP+dYxj/nWMZ/5xjGf+bYxn/nGMZ/5xj + GP+cYxj/m2Ma/5tkGv+bZBf/m2QV/59jFf+eYxf/e08R/0U3Gf+Ii4X/5+Xm//35+v/9/f3/+v3+/62l + of9+XTX/k2Ec/51kHf+aYhz/l2Mb/5tjGP+eZBj/nWUb/4lcG/9PMAn/Z1xS/8LDyP/v8Pb/+vn9//7+ + ///+/v7//v7+//v/+//9/fz//v79/7/L0v9LPSb/kFYN/55jEv+QYxr/n2MU/5tkFv+WYhv/lGMc/5hi + Hv+dZBj/nmQW/5tkFv+dZB7/pG8z/31YKf80IRD/pqan/+7v7/+RiYH/jXJQ/6p5P/+aYRr/nWEa/5xi + HP+dYhz/mWEa/5xkG/+aZBr/mmIa/5xjGv+bYxr/m2Ma/5tiG/+bYxv/nGMa/5tjGv+aYxr/nGMb/5tj + G/+bYhz/nGIc/5tjGv+bZBn/nGMa/5tjGP+bYxr/mWIc/5ljGf+bZRf/jlwV/1QyCf86Mi3/pqWo/+fk + 4//v8vX/9vv+/8zJx/98YEf/om0z/51jHf+eYxj/m2Ia/5piGv+aYxr/m2Ia/5piGv+aYxr/nGMa/5tj + G/+bYxr/m2Ma/5tjGv+bYxr/mmMb/5tjG/+bYxv/m2Mb/5tjGv+bYxv/m2Ma/5tjGv+aYhz/mmMc/5tk + F/+cZBX/n2QY/5lgG/9rRBP/TUU2/6arrv/08vT//vv6//z+/v/x9fb/mI+I/3pWK/+YZB3/nGMa/5xj + G/+YZBr/nGQW/55jFv+aZBr/glca/0gsCf9+dGz/1NTb//Py+v/6+v7//f3+//7+/f/+/v7/+v/9//7+ + /f///vr/j42H/19FKP+bZyj/oWkh/6BsKP+aZSH/nGMY/5tjGP+ZZBv/lmEe/51kFv+kZBD/omUX/41c + H/94Vy7/bFg//2RZS//CwsP/7fH1/7Gwsf95Zk7/sYVQ/5tjHf+bYRn/m2MY/5xkFf+YYxn/m2Md/5hh + Hf+aYR3/nGIc/5xjGf+cYxj/m2Ma/5piG/+bYh3/m2Ic/5tiHf+cYh3/m2Mb/5tjHP+cYR3/m2Ma/5tj + Gf+bYRv/mmIa/5ljG/+ZYxr/mmMX/55lF/+PXBX/VjMI/z4zLf+nqqv/5+rm//Lz8v/0+/z/yMnH/35g + R/+lbjL/nmMd/5dhHP+YYRv/nWEc/59hHf+eYRz/m2Ea/5piGf+aYxn/mmMZ/5tkGP+cZBn/nGMa/5ti + HP+ZYhz/mWIc/5xiHP+dYhr/nGMY/5xjGP+bZBn/mmQZ/5liHP+YYxz/lmUW/5hkFv+eYRv/kVsa/1o+ + D/9oZFn/x8nS//b4+//8/fz//f7+/9jb2f+Fd2n/gFUh/59nFf+cZBf/mGEe/5hjHP+cZBf/m2MY/5dj + GP92TRD/STMX/5KMhv/h4eP/9/X7//r7/v/8/f7//v79//7+/v/8/f///f////r9+/92amD/i3Vd/6eH + ZP+oglT/sYZZ/6qAUf+bYyD/nmEU/5xjGf+WYh7/nGQX/6VkDv+hZBf/eE4Y/zYlE/9jYVz/raef/9PT + 0v/l6/P/0tnb/3hpW/+uiF7/omwr/5pgF/+eZBf/m2QU/5lkGv+bYh3/mmId/5thHf+dYxv/nWQX/5xk + Fv+bZBn/m2Ma/5xjG/+dYxr/nGIc/5piHf+XYxn/mmQa/5xkHP+bYxr/mWMa/5liHP+aYxv/mWMb/5lk + Gv+aYxn/nmUa/45cF/9TMQn/QDUx/7K2uP/u8/D/+Pf0//X7/P/Hycf/fmBG/6ZuL/+fYxv/l2Ic/5li + F/+eYhf/nmIa/51iG/+cYhz/mmIc/5lhHv+ZYhz/mmMb/5xjGv+cYhr/m2Ib/5ljG/+aZBr/nWQY/51j + F/+dYxf/nGMY/5tjG/+bYhv/m2Id/5pjHP+WZRf/mGQW/5xiHP+BUxf/TzwU/46Lg//m5Ov/9/r9//v9 + /f/9/f7/vby5/3hiSf+KWBr/omcT/5pjGP+UYR//mGId/5tjGf+bYxr/lWEW/2hACf9SQDD/qamn/+3t + 6//7+Pr/+vz///v+/v/+/v3///7+//79/v/5/v3//P38/5yWlP+DeHL/jIB1/4+Ccv+EcF//spBr/55r + L/+cXxb/nmMY/5diHv+ZYhz/omUW/5tjGP95UBb/KhYH/2ZlYv/FwL3/zM7M/97j6P/p7u//nJCK/5B0 + Vv+tfkn/m2Aa/59iGv+bYRr/mmMc/5hiG/+aZBf/mmMX/5tkF/+bZBj/nGIa/5tiHP+bYxv/nWMZ/51k + Fv+dZBj/mmMa/5ljGf+bZBn/nGMb/5pjG/+YZBr/mWQa/51kGf+dYhn/m2Ib/5xhHP+dYhz/i1oZ/04w + Cv8/Ojb/vsPG//r6+v/8+vr/+P39/8zJxv9+YUT/pW4u/6BkG/+ZYhr/nGQT/51mEf+ZZRT/l2QY/5hi + HP+YYR//mmAh/5lgH/+aYh3/m2Ma/5xkGP+aZRf/mGUW/5pkFv+bZBb/mmMY/5tjGv+aYhv/mmEd/5xg + Hv+dYR7/nGMb/5pkGf+cZBb/mGEY/2xFEv9aTDX/ubaz//f1+P/6+/3//P3+//X1+P+gmZX/c1cw/5Ng + Gf+fZRj/mGIc/5diHP+aYxn/nGMY/55jG/+RXRX/WTUH/15RR/+9wMD/9fX0//36+//6/f7/+/7+//7+ + /v////7/+/7+//j+/f/9/v7/5ufo/8TDxP/BwsL/ycrJ/4WDiP+OdFv/pnhG/51fGv+iYxn/l2Mb/5dj + H/+bYhj/mGQb/4lZHf89IgP/Pzw1/7W1s//BxcT/1trd/+ru7f/Mx8X/eGlZ/62MZf+fZib/nmAc/5xh + Hv+cYxr/mWQY/5tkFf+bZRX/m2UW/5xjGf+cYRv/m2Ed/5liHP+YYxr/mWQY/5tkFv+cZBb/nWUX/55j + Ff+cYxf/nGMZ/5tjF/+cZRX/nmQW/59iF/+cYRz/nWEh/55iI/+MWyD/UDMP/0E9N//Fycn///7+//z8 + /f/4+/3/zcrG/3xjSP+jcTj/mmIh/5RgHP+ZYRb/mWMT/5VjFP+XYxf/mWQb/5pjG/+bYhv/nGMb/5tj + Gv+aYxj/mWMX/5lkF/+ZZBf/mmQX/5pkGP+aYxr/m2Ic/5piHP+aYhz/nGEd/51iG/+bZBj/nWQX/6Jl + Ff+PWhX/Wz0W/3ZvZf/c3Nz//Pv7//v7/f/8/f7/2Nbb/4FwZv93Uh3/mmYX/5tiHP+YYh3/mmQY/5xj + F/+dYxn/oGQa/4lYEv9QMw3/eXNt/9HW2v/3+Pj//vz7//v+/v/7/v7//v7+///////9/v//+v7+//3/ + ///+/v3/9fj4//T39//3+vr/xcXJ/21aTP+viF//m2Ec/59iF/+YYhn/mGMf/5djGv+VZBz/kmAe/1k4 + A/8kHxH/kpWR/77Dxf/Pz9D/5eXk/+jn6P+Ff37/k39n/6x9Rv+bXx3/nGEc/5xjGP+cYxf/nWQV/5xk + F/+ZYxn/nGMb/51iG/+cYhv/mGIc/5ZjHP+WZBv/nGMZ/51jF/+eYxb/nGIV/5piGP+dYhv/nWQg/59q + J/+ncS//qXM1/6Z1QP+oeUr/rX9O/5x1Rf9dRiP/VVFF/9TW1f///v7/+/v9//b7/v/IyMf/e2pX/6+K + Yf+pf07/onZG/6RzPP+ibTD/nWYn/5piH/+ZYxj/mmQS/5xlEP+dZhL/nWUU/5xkFv+bYxj/nWIZ/59i + Gv+dYhv/m2Ib/5tjG/+bYxr/m2MY/5tkFv+cZBb/nWQX/55kGP+iZBj/oGQX/3pOEf9ZRiz/np+d//D0 + 9//7/Pz//f39//n8/v+uq6v/b1U7/4VWFv+dZRX/nGMc/5liHf+cZBf/nmQW/51kGf+dZBb/eE0M/005 + Hf+YmJj/4ufv//j6/P/+/v3//f7+//z+/v/+/v7///////v//f/9/////v/8//7++v/9/vr//v/7//7/ + ///q6ur/al1W/6eHaf+caSf/nmEU/59iFv+bYxz/mGQb/5ljHf+aYxr/d0wN/yMYBf9iYlz/vb/C/8nH + xv/b2db/6+zu/7GzvP90amH/t5Fo/51oJ/+ZYxj/nWQX/51iFv+dZBj/nGMa/5liHf+bZBv/nWQV/6Bk + Ff+dYxn/mmMb/5pkGv+bYhr/mmEc/5ljH/+aaCf/n24y/6Z0O/+kd0f/mnZR/5h2Uv+UdlX/jHZe/4l3 + Yv+LeGD/gnBX/3JkUf+alpL/8fHz///8/f/8/Pv/9/z9/9ba2P+Jg3v/kX5o/5qDaP+egmr/pYZr/6yG + Zv+yhmL/soRZ/6p7Q/+hcC3/nWkd/5ljFf+ZYhT/mmMW/5piGP+fYBr/oWAb/59iGv+cYxr/m2MZ/5tk + Gv+bYxn/nGQW/5plE/+aZBf/nGQa/59mF/+SXxT/Y0ET/3NnWv/N0NH/+fz+//v8/f/9/f7/5efr/4qD + d/9vTSD/k10Y/51jF/+aYxf/mWIa/5xiGf+dZBj/nWQZ/5piF/9mPwn/W04+/7S5vv/t8/r/+vz9//7+ + /f/+/v3//v/+//3////+////+/79//3///////3//v/8//7++//+/vz//P7+//n6+v+De3j/kHdf/6V3 + Pv+bYRT/oWQT/5xjF/+aYxn/m2Id/5xkGP+NWhT/PSUE/zs0JP+oqqr/xMLA/9DOyf/i5en/2+Dm/4OA + ff+dg2n/rYJJ/5djHP+ZYhj/n2IY/6FjGf+eYRz/m2Ee/5pjHP+dZRX/n2UR/6JkE/+eYhb/nGMb/51o + J/+fbjj/nXVE/5l2Tf+VdFL/i21P/4ZsVv+MeGz/l4d9/5SIgP+WlJH/naOh/66wqf+5s6r/w7u3/97a + 3//29fv/+vn6//r9+//2/v3/7fX1/87Qz/+1r6n/pZ2X/5iNiv+ViIT/mYl//5KCcP+Vgm3/pIpw/7GQ + b/+wil//q39M/6FwNf+YZCX/l2Ed/5xhGf+eYhn/nmIZ/51jGP+dZBj/nGQZ/5xiGf+aYhr/mWMa/5hi + HP+YYxv/mGQZ/3pQE/9iSi7/pqKc/+/08//5/f7/+/z+//39/f/Avbz/cV9C/3xSFP+cYhv/nmIb/5lk + Ff+ZYxf/nGEb/5xiGv+cYxr/jVkW/1Q1D/92cWv/0tjc//f6/f/8/f7//v/+//7+/v///v3//v7+//3/ + /v/9/f7//f3///79/v/+/v3//P79//v+/v/5/v7/+P7//7Svsv94Zlb/q4RW/5hiHP+fYxX/nmMX/5ti + F/+bZBr/nmQY/5hiGf9hOwr/LBoK/4B/ev/CwL//xsPA/9fa3P/l6/H/vL6//3dqW/+xk2j/m2wv/5Rg + Hf+fYhr/oWIY/51gHP+ZYB//mGMf/5hiGf+bYxb/oGUd/6NsKv+jcjf/n3NE/45tSv+HbFT/hW9g/4x+ + cv+jmJH/s6il/8i/wP/d19X/19XT/9LY2//R3N//2uDe/+Tg2//l393/5eHm/+jn7f/x8fL/9/r6//n+ + /P/4/v3/9fn5/+vs7v/d3OL/z83V/8jGy/+/wL7/qaym/5ubl/+SjIj/j4J8/5eCdv+liHT/r41u/66H + X/+jeUf/mWss/5NiHv+UYRv/mWMb/5xjGv+dYxn/nWIb/5piHf+YYiD/mGIf/5hjHf+LWxz/ZEUb/4J2 + af/a2tn/+v79//n9/f/8/f7/7+zq/5mKff9tTR7/jVwU/55jHf+dYh3/m2QV/51jFf+bYhv/mWIe/5hj + G/93Sw//UTwm/56gof/o7/D/+vv8//39/f/8//7//v7+///+/f///v3//v/+//z9///8/f7//P3+//z+ + /v/8/v7/+/7+//n+/f/3/fz/6ens/25iWf+oiWb/mGgt/5thFv+fYxX/nWMa/5tiGv+YYxv/mmUa/4JS + Ev83HgP/TEhA/7SxsP/Dv7//zs7P/93h5//h5en/joyG/5B9ZP+wiVz/kmIr/5lgGf+hZBb/nmQY/5Zh + H/+VYyL/mGUj/6BtK/+gcj7/lG9E/4hpRf+EbFL/kYN0/6qfm//Cvbz/0NDQ/+Dd3v/o5ef/5ebn/+fl + 5P/i4eD/1trc/8/X2f/R09P/1tHM/9POyf/NzM7/09Xb/+Xm6v/09vj//f37//39+//6/P3/8/b8/+bo + 8f/Z3OH/0dTW/8vR0P/Jz8//yMvQ/7zAxv+ysrj/p6Cj/5qQi/+Thnj/moZz/6iQdP+vj2b/p4BO/5ds + M/+UYSP/mGEa/51jFv+eYxf/nGMY/5piG/+bYxz/mGMc/3ZLGv9qVD//trKu//b2+P/8+/7/+vz+//n+ + /f/Cv73/dV1H/3pNFf+ZYRr/m2Mb/5ljG/+dZBf/oWMX/5piHP+XYiD/lWAY/2I+CP9lWlH/wsfM//P5 + +P/7/fr//v79//r//v/7/v7//v38///+/f///v3/+v7///r+/v/8/v7//v7+//3+/f/+/vv//f76//z9 + +f/8/v7/j4mD/452XP+ne0n/mmEZ/55jFP+eYxz/mmId/5ZiHv+aZB3/mGEW/1Q2C/8rIBb/gIF9/7++ + vf/ExMH/0dTV/+Xn6//M0ND/gnlu/6qLbP+pf0//lWEb/55mEv+bZRT/l2Uh/5dpLf+ecDz/l2s9/4Jm + S/+DcmL/nI6D/8K7t//X1df/5Obo/+fr7//n6u7/5+Tl/97f3v/Q19j/z9DP/83NzP/Gxsn/vsDE/768 + vv/Aurn/vbq5/7u+wv/DydD/3N/k//Hz8//9/Pn//v76//v7/P/y8vb/4uLm/9HS0v/FxcP/xMLB/8nE + xf/Jx8j/x8rL/8jNzv/JzM3/wcTD/7W4tP+kpJ7/k4yD/5iGdP+rj3T/so9s/6t/UP+daSv/nGMX/51j + E/+dZRP/nWUV/5tlFv+JWRL/aUYi/5WJgf/j5+X/+v39//z7/v/9/P//4OXi/4J+ef9lRyL/jFkZ/5xh + H/+aZBn/mGUZ/51jGv+gYxf/mmMc/5ZiIv+IVRL/WjwQ/4+Kh//f4+v/9/r5//z9+P/+/vz/+v7///r9 + /f/9/fz///38///+/f/9/v7//f7+//7+/v///////v/+///+/v///v3//v39//7////KyMb/dGFV/7SM + af+dZCP/oWMU/5xjGP+XYxz/mGMe/5xjG/+hZhT/gFIW/zchB/89Ojj/oqes/7u+v//LxsD/3trZ/+Xo + 7P+8t7r/h3Jt/7WVev+fd0H/kmQZ/51qIf+hbzL/kmY8/31cR/+Bc2f/r6ah/9bQz//o5+f/8fH1/+rv + 7f/j5+j/3N7h/9XV2f/NzdH/xcbO/7m8wf+sqqr/op+f/5SRlP9+e4H/cWts/21kXP9yamT/lpaZ/8DF + y//b3uD/8/Lz//37+//y8/P/xcXB/6Oflv+kpJ//paak/6Ojof+vrK3/vLq7/7y8vP+6vr3/vsDA/8LE + xP/Hycn/y87N/8rOzP+/wcD/r6qp/5eNiv+PgXj/oox5/7GRb/+me0X/mWci/5ljGP+eZRn/j18a/2VJ + H/9+dGj/0tPU//n8+f/9/fr/+fv9/+71+P+pqaP/Zk8z/35PD/+aYxj/mGIe/5xjG/+eZBb/nWMZ/5pj + Gf+aZBn/l2Ed/21EEP9hVEH/vby///f3+v/8+/r//f37//3+/v/8/v///f7+//7+/f/9/v3//v7+///+ + /v///v7///7///////////////7////+///9/v//+/7///T09P97bWj/qYdw/6dzQP+cYBf/nWQW/5dj + F/+bYx3/nGIa/55lF/+UYR//WzkM/yocEf9oZ2b/t7m9/76+u//OzMv/3+Dh/+Pm5/+opKL/intn/7qc + d/+le0j/k2o2/3xhN/99bVL/rKGZ/9bR0//v7u3/9ff0/+zv8f/j5Oz/2Nvf/9PU1P/Kx8f/uLe1/5+g + nv96fXf/amdd/1VLOv9JPCv/RTYm/z8vH/89Kxf/OycP/zUnFf9XVU//tLi5/97i4v/y8PL/+/r7/9TU + 0/9lXlP/Qzcf/0I6J/9IPS3/T0My/2BWS/91cGn/ioqF/6Sop/+tsrX/uLq9/7y9v//Cv8D/yMbD/8zL + yP/Ly8r/wMHE/6iorP+Pi4j/kYN1/7GUdf+yi1z/oXE3/5pkIv98UBf/fmpP/8bDv//19/n//Pz9//79 + +f/4/Pv/xMzP/29nXP9pRBj/kVsU/5pjGP+ZYxv/nGQa/55kGf+aYRr/mmIZ/5tkGP+IVxf/Wj0X/4yH + gP/j4ub//fz9//38/f/9/P7//f79//7+/v/+/v///f/+//3//v/9//7///7////+/////v////////// + //////////////7////5/v7//v7+/7Gopv+Aalz/sY1n/5VkI/+cZBX/nmUZ/5hiGv+aYhz/l2QY/5lj + G/+AVBf/SikE/z0tIf+UkZH/tbvA/7u8wf/Pz8z/3+Tg/9be3f+RjoL/j31q/5R3YP93Xkf/l5GB/8fO + xP/r7ez/+Pj5//T39//m7ev/3eDk/83S1v+2ubv/mpeV/4B4cP9eU0b/TUAv/zktGP88LA//SC8I/1I0 + Bf9bOwn/Y0AO/2hGEP9gQg3/PCcH/zo2Lv+mqqj/4ePm//Hx9P/7/P3/y8jG/2BNOv9hQxv/UjcO/04z + B/9KLwT/QSoL/zgoE/9ANCP/UktA/2hlX/+MiYb/p6Sl/7u1uP/AvLv/wL68/8LBwP/Fxsj/x8vR/77C + x/+joqL/koZ7/6GNdf+ojGz/g184/3lbOf+7sKP/9PXz//n9/v/5/P7//Pz7/+Xl5v+Gg4H/VkIo/35R + GP+WYR3/l2Mb/5xkGP+cYxn/mWId/5liHf+dYxj/mWIY/2tFEf9mVT7/wr+7//n3+P/9/Pz//fz9//39 + /v/+/v7//v7+///+///+/////v/+//7//v////////////7+/v////////////////////////////n8 + /v/9/f3/6OLj/3hrZ/+fhW//oXdC/5dhFP+gZRT/m2QY/5ljHf+XYxn/m2Qa/5diGP94Rwz/QSIH/1BL + Qv+hp7L/s7nD/8G/vf/Q09D/3ebl/9bT0P+mn5j/npKP/7iwrf/o6OX/9fr5//f8/v/2/Pz/7PT5/9zi + 5f+6vLz/iIqE/1xaTv9GOir/QS4V/0gtCv9XNQz/YT0T/2xIGv95Uhn/hlgX/45dF/+SXhf/k2IY/4Za + GP9NMAv/OjMr/6Slp//k4uj/8fHz//r9/f/NycX/eF1C/5RmMv+JWiL/hFga/35TFP9yTBb/YUET/1M2 + C/9GLAn/PyoQ/0MyIv9WSED/eHBt/5yamv+0tLb/v7y8/76+vf+9wsf/xsvT/8/R1v/AvLr/nZaP/4F5 + b/92bGD/qqCY/+7r6f/5/f7/9/v+//b6/f/y8vT/sKmm/1pHNv9oRhr/kl8a/5djHf+YYhz/n2QU/55k + Fv+YYh3/m2MZ/59lFf+KWRf/VDoX/4qGf//k5eX//f3+//39/f/+/f3//v3+//3//v/9//7//v////// + /////////////////////////v7+/////////////////////////////Pz///v9/f/5+Pj/rq2t/3hs + X/+yj2j/m2Yg/6BiEv+eZBn/mGIb/5pjGf+cYxz/mWMW/5RdE/9kOgj/NCER/2FhZP+osbn/ur28/8TB + xP/U09T/5+Pk/+Xi5P/d3+P/8PHy//76///9+/7//P3+//f5+v/T2Nz/k5aW/1lTSf9AMRr/RS4N/1U2 + Cf9pRA3/e1AU/4lYG/+QXB7/kF4j/5ZhHv+dYxv/oGQY/6FjFv+gZBj/kFoa/1MxDf88MS3/p6Sp/+bi + 5//w8fT/+Pz9/83Jxf9/YUT/pW4z/51jIP+ZYxr/l2Ma/5NiHf+OXh7/iFkY/35RE/9tRA7/WDMK/0Mo + C/85Jxf/RT05/2ppa/+bmJf/t7S2/72+wf/Dxsn/1tja/+fm5P/e3dj/yszL/8nP0f/m6er/+/z8//f7 + /v/x+P7/7vP6/8TDwf9yY0//YUAV/4hZGf+cZBf/mGMb/5pjHP+gZBX/nWQY/5hjG/+eZRf/nGQU/21G + EP9iV0X/vsDA//f4+v/9/P7//f3+//79/v/+/v7//v7+//7////+//////////////////////////// + ///////////////////////////////////+/v///f3+//3+/P/o6On/fnd0/6OHbv+tf0b/nWEY/5tj + Gv+bYhr/nGQX/5hgG/+ZYxv/mmMa/4ZWEf9MLAb/LSQc/3R3ef+2urv/urnA/8jByf/Z09n/5eXn/+z0 + 9P/4+/z/+/v9//76/f/z7ez/tK6o/2ZhVf8/Mx//Ri0N/2Y8DP+BTRH/kFkW/5ZfGf+ZYhv/m2Mb/5xj + Gv+cYhv/nmIZ/55jGv+eYhv/nmEa/51iHP+NWRv/UzEN/z0xLf+lpaj/5+Lm/+/v9v/1+/3/y8rG/39h + Rf+pbjH/omMe/55jGP+bYxj/nWMa/6BiHP+eYxr/m2MW/5dhF/+MWBf/dksU/1k7EP8/Kg3/MycV/0Q+ + Nf9yb2z/qqmp/8/Q0v/i4eD/9PHr//v58//3+fj/9vr8//v+/f/8/fz/9Pn9/+vy+//HyM//eW9k/1s+ + F/+BUxL/mmMV/51jFv+aYxr/m2Ma/5xkF/+aZBr/m2Qb/6FkFP+NWA//XkIg/5iUj//o6+v//f3+//38 + /v/+/f7//v7+//7+/v/+/v7///////////////////////////////////////////////////////// + ///////////////9/f/+/v7//v79//j6+/+8ubr/eGZX/7yZc/+gai7/lmIb/5piGP+eYxf/mWIb/5Nj + HP+YZBz/lmIb/3pOEv9AJAb/OzAk/4uKhv+5u77/urvA/8PExv/R0tP/4uXk/+3z8v/0+/n/3+Xi/5CN + hf9SQTX/SywN/2I8Cf99UBX/k10Z/5xhG/+eYRz/nWMd/5xiG/+eYxj/oWMW/6BkEv+eZBL/m2QW/5hj + G/+YZBv/l2Qb/4lcGf9PNAv/OTQr/6Smpf/m4uX/7u/3//X7/v/Lysf/fWFI/6ZuNP+gYh//nGEb/5pj + G/+dYhr/oGIc/55iG/+dYxr/m2Qa/5pjHP+VYh3/il0b/3tREf9iPwb/Ri4H/zsuF/9cVkj/pqWk/+bm + 6f/6+Pj//vv7//79/v/+/f///Pv8//n5+f/y9fX/z9LU/3x2c/9QOiD/dUsT/5phFf+fYxT/nGIY/55j + Gf+eYxf/mGIb/5ZhHP+bZBr/mWAV/29FDv90Zlb/zMzM//r7/P/9/f3//v3+//7+/v/+/v7//v7+//// + //////////////////////////////////////////////////////////////////////////3+//z+ + ///9/v3/+f38//Hw8P+Ujof/kHtq/7WOZf+SZCP/mWEZ/5xiGf+aYxz/l2Ic/5hjHf+ZYhr/lmEb/3RK + Df8/JAb/QDUm/4uLhf+4u7z/tbq4/77Dvv/Qz87/3uPg/+Xw6v/E0sv/XF5S/3FeUv+ccEz/lWMp/5Nf + Hv+ZYhn/lWQb/5NjHP+VYhz/mGId/55iGP+iYxX/n2QT/51kE/+bYxb/mWMa/5hkGf+aZRb/jF0V/1E1 + Cf85NSv/pael/+bk4//t8fb/9vr+/8zKx/97YUj/oG80/5tjHv+cYBv/nGIc/5xiGv+cYxr/mmIc/5pj + HP+YYhz/mGMc/5tkGf+dZBX/nGUS/5ZhDf+BVQz/YEEL/zopDP9jYFr/09bX//j9/v/5/P7//Pv+//35 + /v/39vr/7/Dw/9bTzv+Hf3P/Tjse/2dEEf+PXRj/n2MX/59kGP+cYxv/nWIX/55iF/+aYh3/l2Ie/5Zk + Hv95URX/Z1I0/7m0sP/09PX//f39//7+/v/+/v7//v7+///////+/v7//v7+//////////////////// + ///////////////////////////////////////////////////+/v7/+v7///r+/f/4/vz//Pz8/9jZ + 2f9uZWb/p416/6yCRv+YYRn/mGId/51jGf+eYxn/mmQZ/5lkGP+cZBb/kmEY/21FEP86IwX/PDUq/5KQ + jf/Avrr/u7u5/8DAwf/KzdP/19ve/9ve3/+opp//enNn/6SOdP+6mHL/oXRB/5hjHv+aZBj/mGQZ/5di + G/+YYhv/mmMZ/51jFv+cYxn/m2Ma/5tiGv+dYhv/oGMX/6FlFP+QXBT/UzEJ/zgyLf+ip6j/5uTj//Dx + 9P/4+v7/zsnH/3xiSP+ecTL/mGYc/51jF/+eYhn/nWMZ/5xjGf+ZYhr/l2Qb/5ZkG/+ZYhv/nGEb/5xh + Gf+dYxr/oGgf/55rLP+DXS3/VkEl/4B5cf/j4+X/+v7///j9/f/4+/r/9fb2/+vu8f/O0tb/hoJ9/088 + JP9kQhD/i1wX/5pjGf+aYhr/mWIa/5pjG/+eZBn/m2Ma/5ZjHf+aYx3/i1kZ/2NIH/+RjIH/5+np//z9 + /f/8/Pz//v7+//7+/v/+/v7///////7+/v/+/v7///////////////////////////////////////// + //////////////////////////////7+/v/6/f3/+v7+//v+/v/9/f3/9/f4/7WzuP92aV//vpx0/55y + Of+UYBr/mmMY/51kF/+bYxf/nGIZ/6BkGP+fYhj/jV4a/2dFDf85JAj/QTku/5GJfv+6tbX/ubu//72/ + xP/Oyc3/4dja/9/a1/+xtbH/f354/5SIev+2mnj/tYpW/6VuLv+cYR3/mmAZ/5tkGv+cZRj/mWQX/5Zi + Hv+aYh7/nGId/5xjHP+dZBn/oGUW/5JbFv9WMQr/ODEt/5+oqP/l5+P/8vLx//n6/f/Nycf/fWFH/6Jw + Mf+bZBz/nGIZ/6BhGv+cYxf/mGUU/5pkFP+ZZRT/nGQV/55jF/+cYRz/mmIm/55pM/+bbD7/h148/35f + R/+gkIT/2dTS//f5+f/5+/3/+Pf5//Hy8f/n7Or/xsrK/3p5ef9GOCn/Xj4S/4taFv+dZBb/m2QZ/5Zi + IP+WYh//mWUY/55jGP+bYxr/m2Yb/5NhGv9rSBT/e21c/8zNzf/3/Pv/+v38//v9/f/9/f3//v7+//7+ + /v/+/v7///////////////////////////////////////////////////////////////////////// + ///////////+//7+/v/7/v///v7+//7+/v/+/f3/7u/w/5aRif97cGf/sJR6/6RpKP+PYBz/lmQb/5hj + F/+kYxf/o2Af/51eIP+cZRz/k2QK/29JBv86JQr/PC8c/3dwaf+wsLH/vLy8/769uf/IxsL/0dHR/9LY + 2//Axcj/mZma/4Z/df+ciXb/tJh1/66HWP+fcDX/m2Qg/51iFP+ZYxT/k2Mb/5tiGf+dYhn/l2Mc/5Jj + G/+ZZBv/kFoa/1gyDP88Ni7/qrKu/+vu6P/09vH/9vv8/8jKxv9/YkX/qXAu/6BkHP+aYSD/nmIc/5ll + Fv+TZxP/lmYS/5lkEv+eZBP/pGgb/6duLP+kcT7/kmdD/3dcRv+BdWz/ubWy/+rp6P/4+fn/9vr5//D1 + 9P/r7O3/5ODl/7u1vv9uZGb/RTIf/14/Ev+IWhX/nmMS/6JjFf+eYR//mWAj/5diG/+bZRH/nWMX/55j + Gv+bZRb/c1EP/2RbPf+ysrP/8/L4//37/v/7/f3/+v39//z+/v/+/v7//v7+//7+/v////////////// + ///////////////////////////////////////////////////////////////////+/v7//f////3+ + /v/7/v7//f7+//3+/v/8/fz/5+Xj/4SDe/+biHj/vZFo/5NkJf+XYxP/m2YT/51iGP+dYB//nmEf/5xj + F/+bZhb/kGIX/25KFP9GKQb/MycW/2RlXv+mqK7/tLu9/7i6vv/Avr//zMrI/9fU1v/X1Nb/urm4/5uU + kP+KfHP/o5B//7SZev+zjWH/pHdC/5dnKf+UZBr/nGEU/6FiE/+eZRX/mWUV/51lGP+RWRj/WDAL/0A6 + M/+4v7//9fb4//r3+P/4+v7/ysjG/4BgRP+nbir/nmQX/5djGv+dYxj/oGIW/51hGv+aYSH/m2Yt/6Jw + Of+kdET/lG1F/3xfRP+Ec2b/sqqm/9jX1//09PX//fz7//r29f/v7/L/4+fs/9ja3f+rp6T/XlZL/0Mu + FP9kQBL/hVkf/5ZhH/+cYxr/nWMY/5tiGf+aYhv/mGMZ/5pjF/+eYxv/nWUh/4BWGP9nUib/p6OS/+7u + 7f/+/P7///z+//v+/v/5/v3/+/7+//7///////////////////////////////////////////////// + //////////////////////////////////////////////7+/v/+/////f7+//z+/v/8/v7//P7+//z+ + /v/9/Pz/29nX/4R5c/+nj4H/tIpg/5hoHP+ZYhD/mWYW/5djGv+eZBv/nGEc/5ZfH/+YYxn/lGIS/3pP + Df9KLgX/MSIU/0xLS/+Jj5b/sbS8/765vP/EvLn/ysPB/8/Pzv/X1dX/0tHW/7Cwtf+Oi4v/h350/5eH + dP+okXn/r5Fu/7GJVf+rdTn/pGkl/51mH/+ZZBr/mGMZ/41YF/9VLQr/RDo3/8LGyv/9/P7//Pv9//f7 + /v/Lycf/e19G/55sLv+XYx3/k2Qf/5toIP+lain/q287/6d1Sv+ZcU//iGhO/3tjUv+Hdmz/q6Gc/9LT + 0v/s8vL/8/n6//X3+f/08fH/7ejq/+Df4//HyM3/kI+O/1RJOf9FLw3/aEUO/4tcFf+XYR3/mGEg/5ti + Hv+bYxr/mGQV/5lkFv+bYxn/n2Ic/6BkH/+IWx7/Ykwp/5KNfv/j497/+/36//39/P/7/f7/+/3+//3+ + /v/+/v7//v////////////////////////////////////////////////////////////////////// + /////////////////////////v7+///////9/////P7+//z+/v/8/v7//P7+//z+/v/5+Pn/xMPB/29m + ZP+tk4D/r4dW/5ZgGv+ZZBL/l2UV/5hkGP+bYx3/mmIf/5xjF/+bZBD/kmIV/4BVGv9XOAv/NiMM/z4z + Lv9va2v/qKWn/7+8u/++vLv/vL69/8XFxv/NztD/0dLX/87N0f+6uLf/op2X/4uFfv+LgXb/l4Rw/62Q + cf+8l2//s41h/62GVP+rf0r/m248/1g4G/9DPDn/xsvN//7+/f/7/vv/9/38/8rJx/9+aFT/rYZX/6R8 + S/+gfE//poBQ/6R9VP+ScFD/gWdP/4FwY/+OhH//sq6t/9jY1//v8O7/9Pn4//P49//u7/H/5+bq/9/f + 5P/T1Nn/srKz/3FsZP9ENiL/TTQO/3FMFv+OXhr/mmMV/5xjF/+eYxv/nWIb/5pjGf+YZRb/lmYV/5hl + Gf+eZSD/kV0f/2lIHf+Ge2//19bW//v6+v/+/vj/+/74//v+/f/9/v3//v79//7+/v////////////// + //////////////////////////////////////////////////////////////////////////////// + ///+/v7///////3////8/v///P7+//z+/v/8/v7//f7+//7+/v/29vb/uLi5/21kZv+qkoP/s4VX/5tl + G/+ZZBD/lmYV/5djGv+dYhr/nmMX/51kF/+dZBn/mWEa/4xeGP9xRw7/TCwD/zciEP9KRDz/f4J//6mr + rv+8vMD/vLu8/7y+vf/Fw8T/0MzN/9jV1//X1tf/z9HS/7e6vv+ZmJz/jYWD/4Z7cv+Fem3/koNx/6CJ + cP+ZfV//Y044/2FcVv/c39///v78//z9+f/6/f3/zs/P/4Bzav+bg23/kHpk/4VvXP+DbFj/g3Zl/5GO + gf+vsKb/0NXR/+fu7//u9Pf/8vb4//Hy8v/s6+v/5+Pk/+Da3f/V0tb/ur2//4SIhf9LRzr/OykM/1k6 + Cf+BVBf/lmAd/55iGv+gZBn/n2QX/6BkFf+fZRL/m2US/5hkFP+YZBr/mmcj/5FfIv9sShr/hXhg/9XS + zv/3+vr//Pz9//39+//6/vv/+f79//z+/P/9/vz//v79//////////////////////////////////// + /////////////////////////////////////////////////////////////////////////v////z+ + ///8/v7//P7+//z+/v/9/////v7+//z9/f/z9fX/uLq9/3lqbP+xlIH/uIta/5pnHf+ZZBH/nGQU/59i + Ff+fYhn/mmEf/5hgH/+ZYhz/nWQb/5hiFv+EUxD/YT0K/zUkBf8rKBf/UU9M/4aDgP+vrKv/uLq6/7y6 + vP+9vL7/wMHD/8nIyf/Qz8//09XY/9PU3f/MztT/wsbI/7G1uP+dnqD/m5KO/5WJfP+PiHj/urqz//j5 + +v/+/Pv//Pz5//n8/P/p7u3/tbKv/5qPiv+imZb/ta+t/8/Lyf/Z29r/4unp/+vz8f/s8vD/6/Dw/+Xq + 7P/g4+f/3d3g/9nX2P/V0dH/v768/5KSjf9dWE3/PS8a/0YuC/9qRxb/iFod/5hhHP+eYhr/oWEa/59g + Gv+aYRr/l2IY/5hlE/+eZRH/n2MU/51mI/+OYCz/bksi/4d4X//T0cv/+vj5//v5/v/6+/7/+/7+//n+ + /v/4//3//P78//7+/P/+/v7///////////////////////////////////////////////////////// + ///////////////////////////////////////////////////+/////f////z+/v/8/v7//P7+//3+ + ///9/f7/+f7+//H+/f/09Pb/trK3/3RkZf+tlYX/t49h/5poHv+cYxX/mGIY/55hG/+fYBv/lmAh/5Zi + If+aYh3/nWQW/55lFf+QXhb/b00T/0s1Df8yIAn/MiUX/1FKQf+AgYH/oqep/7C4vP+1vL//ury9/8G/ + vf/Gwb//zcnH/9LSz//T2NX/1Nnd/9Xa4v/d3OP/3d3b/9/i2//p7ur/7vDz//Dv9v/x8fb/7/H1/+/y + 9f/t7vD/6urp/+nr6//q7u//6vDx/+vr8f/r5+7/6OXm/+Pf3//a2dn/09XW/83O0//Hx8v/t7e6/5CP + kf9YWlL/NTEd/0IoCv9mPA3/hVIX/5ReIP+YYCH/mWIc/5xkFf+gZBT/n2EZ/5dhHf+QZB//kWQb/5ll + F/+jZxz/ll8i/25KIv+DdWL/z8/I//b6+P/9/vv//v39//z9/v/4/v7/9/7+//v+/v/+/v7//v79//7/ + /v////////////////////////////////////////////////////////////////////////////// + //////////////////////////////7////+/////v7+//3+/v/+/////v7///79///8/v7/9f79//39 + /f/y8fL/ubS5/3Vub/+lk4D/u5Zp/5xrMv+RXSH/m2Ad/59jGP+aYhz/mmId/5ljHf+aZBn/nWUW/51l + G/+VYR3/h1oY/29HFf9PMQj/OSQG/zUnFP9MSDr/b3Bt/5ibmf+wsK3/wLu5/8W9uf/Fvbj/xMG4/8LE + vP/Dx8b/xsjP/83N0//Q09P/0tfU/9ba2f/a2+H/3Nvl/93c5P/h3uP/4d/h/+Hg4v/d4eH/2uDe/9jf + 3P/V3Nr/1dXY/9fP1v/XzM//1MvM/87Jyf/Bv8D/pqal/4R/e/9aUUn/PTAf/zgoCf9ROAz/eE8V/5Nc + GP+eYhn/n2Ic/5xhHf+aYhv/nGUX/55mFP+dZBj/mGMd/5FiIP+PYiH/lmgo/5JjK/9zTif/inll/9LR + yv/z+Pn/+Pv9//n8+//8/Pv//f79//n9/v/6/f7//v7+/////v/+//7//v/+//////////////////// + //////////////////////////////////////////////////////////////////////////////// + ///////////////////+/v7//v7+/////////v7//v3+//79/v/9/f3//fv7//z+/f/y8/T/xMXG/4mI + hP+Xinz/vJt4/6d2Pv+YYhj/nWYU/5xkFf+cYxb/m2QY/5lkGv+aYR7/mmMb/51iGv+eYxv/mWMa/4la + F/9zTBH/WDcH/z8nBf8zIw7/OzIk/1FPRv9zcm7/kI2Q/6yrsf+ytrL/t7u3/7q7vP/AvcL/wr3B/8C/ + vv+/wr7/v8PD/8LDyf/Cxcn/xcbH/8vIw//MycP/ysjH/8XIyf/Ex8j/xcTG/8TDxf+/wcP/ury//7i4 + t/+np6X/hIaB/19fWf9AOy//OCkU/0MpCP9dOAr/ekwW/41aH/+VYR7/m2Mb/51lF/+dZBf/nGIY/5pi + GP+aZBr/mmQZ/5plF/+dZRb/oWUa/6NpKP+NXyz/dFg3/5mPf//Z2dT/9/r5//r+/v/8/v7//f3+//3+ + /P/9/vv//P79//3+/P/+//v//f/9//3////+//////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + /v////7////+///+/v/+/v7//f79//39/f/+/f3/+v7+//v9/f/3+Pj/3N/f/46LiP+MeW7/up2C/6yF + VP+XZSP/lWEZ/5tkGf+fZRX/nmQX/5xiG/+aYxj/n2QZ/59jGP+cYxj/m2Qa/5RhGv+NXRn/fVEU/2RA + DP9LLwX/NCIH/ywfD/82LCP/SkVD/11cVv98fXT/kJCK/56amv+ppqT/tbWx/7q7u/+5vL//uLy//7i9 + v/+6vr//vb6+/72+vv+9vb//uby9/7Gwsv+koqH/mZWU/4iGg/9ub2n/VVVJ/0M8L/8zKRb/MyUJ/0Yv + CP9ePw3/d1AV/49fGv+eYhr/oGEa/5xhGv+aYRj/mmMX/5pkFf+cZhX/mmYX/5dkG/+ZZBr/nGUU/59o + Hv+eay7/h1wu/3NYO/+hmYv/4+bi//j7+//6/f7/+v79//3+/v/+/v7//v7+//7+/v/+/v3//v78//// + /f/9//7//P7+//z+/v/+/////v7+//7+/v////////////////////////////////////////////// + ///////////////////////////////////////////////////////////+/////v////7////+//7/ + /v/+/v7//f7+//3+/v/7/v7//P7+//z+/v/7/Pz/5eXl/52anf9/eXn/qJKA/7yVbv+abjv/k18i/55i + Fv+hZBX/n2MU/5tjFf+cZRj/mmIZ/5liHv+YYR7/m2Mb/5xkGf+aZBf/lWIX/4dZF/91TRX/YUAN/08z + Cf89Jwj/NiMJ/zYnEP81KBj/PTMo/01FPP9dV1D/Z2Nd/2lnYv9raWL/a2hk/2toZf9qa2X/aGpk/2dl + Yv9jX1r/WFFJ/0g+M/86LyL/NiUV/zgjDf88Jgj/Si8K/18+EP90TRT/hVgY/5FeHP+ZYhz/nmQY/6Bk + Fv+eYxj/nGIb/5thG/+bYhr/mmQY/5tkF/+bZRb/l2MY/5pkG/+gayP/lWox/3lZM/9yYEz/rqeg/+zq + 6f/7+/v//P7+//z+/v/9/v7//v7+///+///////////+//7+/v/+/v7////+//7////+/v7//v7+//7/ + ///+/v7//v7+//////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////7////+/////P7+//z+ + /v/9/v7//v7+//7+/v/9/f3/7+3v/8O/wf+CdnP/nIh3/7uggf+xiVj/m2cn/5pgFv+eYhb/nGMX/5hk + GP+aZRn/mmQY/5pkGP+aYxf/mmMY/5xkGf+cZBn/mmIb/5ZiHP+TYBv/i1sZ/4FTGf92ShX/aUAP/1g1 + Cf9NLgn/RSkK/zwjCP83IQr/NiAK/zciC/87JAv/PCIL/zsiC/86Iwr/OyML/z0jCv9CJwj/Sy8K/1Q0 + Dv9jOw//dEcS/4BRGP+LWRz/lF8c/5xjGv+iZBv/o2MZ/6JiFv+hYxb/nGQZ/5hjGv+XYxv/mGMc/5hh + G/+aYxj/nGIW/51jF/+haB7/oG4u/4tlNf9yVjP/i3lh/8rDuP/y8vD//P39//z+/v/8/v7//f7+//7+ + /v////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////7////+/////v////7+/v/9/f3//f39///+ + /v/+/Pz/+fn6/9zd3/+Zl5r/fHRp/6iUev+8nXb/pn5K/5NlKP+VXxz/mF8Y/55iFf+fZRT/nWUU/5tl + Ff+bZRn/mmIb/51iGv+cZBf/nmQU/6JkFf+jYxX/o2QY/6JjGv+eYRv/mGAc/5BdHf+HWRv/flMW/3hN + E/90TBL/dEsP/3dLD/96SxD/eksQ/3lMEP97ThH/f1ET/4VWFf+NXBn/k2Ec/5VjGv+ZZBj/nGQW/5tk + Fv+bZRX/m2UT/5xlE/+dZRT/m2QU/5hkF/+VYxv/lGIc/5ZjHP+ZYhr/m2EZ/5xiGP+eYyD/pWwx/6Jw + OP+CXjX/bVxH/6CXi//k4Nr/+fv7//j9/v/6/f7/+/3+//z9/v/+/v3//v7+//////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + /////////////////////////////////////////v7+//39/f/9/f3/+/39//79/v/+/fz/+vz9/+7y + 8//EwcH/h4J7/4h+cv+tm4b/spd2/6F4SP+ZZSb/mmAX/55jFP+fZBb/nmMX/5xjGP+dYhz/mmIc/5ll + Gv+ZZBn/nGQb/55jHP+dYhv/nmIb/55iHP+dYhz/m2Ib/5ljGv+bZBr/nGUb/5tkGv+YZBr/l2Mc/5di + IP+XYx//lmQd/5dkHv+XZB3/mGQb/5xkGv+cZBj/mmQZ/5pkG/+cZRr/nWUZ/5xkF/+bYxj/mmMa/5lj + HP+YYx3/l2Qd/5hjHP+ZYxj/m2MX/51jGP+fZhz/o24s/6ByQP+HZEP/b1hE/4p9c//Gw8D/7+/w//j5 + /P/3+/7/+P3+//r9/v/8/f3//f39//7+/v///v7///////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + ///////////////////+/v7//v7+//7+/v/+/v7//f7+//39/v/8/v3//f39//r6+v/n6ez/sLCw/315 + dv+RhHn/sZh9/7qXav+ofUX/l2Yo/5VfHv+XYBv/m2Ma/51iGv+cYhn/nGIY/5tiGv+bYx7/mmMf/5li + Hf+WYhv/mGIb/5ljG/+bZBr/nGQX/51jF/+gYxf/oGMW/55kFv+dZBv/mmId/5liHP+ZYxz/m2Md/5ph + HP+ZYhn/mmQX/5xkF/+bYxv/mWEe/5thHf+dYhr/nmMa/59jG/+cYxr/mmIc/5liHv+YYR//m2Ac/51i + Gv+bZR//n20t/6F0Ov+PbD7/dl1A/3dsX/+oqKf/4+Xo//r7+//6/P7/9/r+//j7/v/8/f7//v39//39 + /P/+/v3//f7+//3+/v////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////7///7+///9/v///P7+//v8/v/9/f3//f7+//z9/v/19vj/2dzf/6mkpP+IfHP/k4Fx/6yU + e/+8mXf/sIRb/5prO/+VYSX/mGAb/51iFv+fYhP/nmIU/5xkGP+XYxf/mGQX/5plFv+bZBj/nGQY/5xk + GP+cYxn/nGIa/5xhG/+cYBv/nGIa/5tlGf+aZRn/m2Mb/51jHP+cYxv/mmMb/5ljGv+bYxr/m2Ia/5li + G/+XYhz/mGMb/5tjGf+cYxj/nWIZ/55jG/+bYhn/l2EX/5liHP+fZif/om40/6F2Rv+PbUf/d15A/3ts + Vf+nnpH/39vX//f5+f/7/f3//v3+//v9/v/7/v7//f7+//79/f/+/vz//v78//7+/f/9/v7//v7+//// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + /////////////////////////////////////////////////////////////////////////v7+//v+ + /v/6/v7//P7+//j6/v/9/v7//v36//38+v/8+/3/9/b3/+Li4f+0srH/hoB+/4t6cf+skX7/uZqA/7mR + aP+sfUb/oGwr/5xlHP+bYhb/mWEV/5lkFv+ZZRP/mmYT/5xmFP+cZRX/mmMW/5ljGf+ZYh3/mWIf/5lg + H/+bYR3/nGQY/51kF/+dZBn/nWMZ/5xjG/+cYhr/nGIa/5xhG/+cYRr/nGMZ/5tkFv+cZBT/nWQU/55j + FP+cYhb/m2Eb/5xlH/+ibyn/qno7/6R5Sf+ScU3/emFK/3lqXv+inZr/3Nva//f19v/8/Pz//f78//3+ + /P/9/v7//P7+//3//f/9/v3//v79//7+/f/+/vv///78//3//v/+//////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + /////////////////////////////////////////////////v/+/v7//P7+//z//v/9/v3/+v3+//z+ + /v/+/fr//f36//79/P/+/v3//f38//f4+f/k5uv/ubi6/5aQif+HfnL/k4Nw/6qRdP+8nXf/tY9k/66C + UP+gcjz/lmYr/5ZiH/+WXxn/ll4Y/5hfGf+ZYRr/mmIb/5piHP+aYRz/mmEd/5tiG/+dZBj/nWQX/51k + GP+cZBj/m2MZ/5tjGf+aYhn/l2Ea/5lhGf+cYBn/nV8Y/59hG/+gYiD/omcq/6dyOv+peEj/qXpR/51z + Tf+HZUT/eWRN/4Z8b/+vqaT/29va//T3+P/7/f3//f39//79+//+/vr//v77//7+/f/+/v7//v7+//7+ + /f/+/v3//v/9//7+/f/+/v3//f7+//7///////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////7////9/////f////3/ + ///9///////////////////////+//7+/v/+/v///v7+//3+/f/9/v7//f39//39/P/8/f3/+v79//r+ + /f/8/v7//f39//v8/P/3+vr/7PHv/9HV1P+srKv/kY6M/352cf+Pf3P/qpF//7GTff+6l3f/uY9i/7GD + Uf+mdkH/oG40/51pKf+fZyL/n2Qb/6BjF/+eYhX/m2IW/5tiGP+bYBn/m2AZ/5pgGv+aYhv/m2Md/5pk + H/+daCT/oWso/6BtLf+jdDj/qn1F/6uCUP+iflT/lXZV/4RtV/9wYlP/fHNt/5+bmv+/wsH/5Ono//b5 + +f/6+/v/+/z7//3+/P/9/v3//f39//z8/P/8/P3//P7+//z+/v/8/v7//P7+//z+/f/9/v7//v/+//7+ + /v/+/v7//v////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + /////////////////////////////////////////v////3////9//////////////////////////// + //////////////////////////////////////////////7////9/v7//v7+///+/v/+/v7//v7+//3+ + /v/9/////P7///v9/v/09vf/2tvb/7i1s/+XkI7/h359/4B2cP+KfW7/lINy/6SQff+tlX7/r5J3/6+M + bP+ximb/s4hj/7OIXv+zh1n/s4Za/7OHXP+yh1z/sYZb/66FW/+thFv/q4Ne/6mDYP+qhWT/nIFp/4d3 + Z/97bV7/d2hZ/3puZf+KgX3/p6Ge/8/Mzf/v7fD//vv///7+/v/+/v7///7///79/v/9/f3////+//// + /v/+/v7//v3+//7+/////////f7+//z+/v/8/v7//v////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////7+///+/v///////v7+//39/f///v7///7+//// + /v/+/v7//v7+//v7/P/n6Oz/y8vO/727vP+jo6H/h4SD/395df+Gfnb/iH1y/4R2Z/+KeWn/jnxq/418 + af+Memn/jHlq/4t5af+Jemj/hXdl/35wYf9+cWP/g3Zp/4J1av9+dnD/j4qI/6+rqv/HxcT/3Nze//P0 + 9v/9/v7//P7+//3+/v///v3///38//7//v/9/////f////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////+/////f///v7+//z8/P/+/v3//v/9//7/ + /v/9/////f7///j9/v/z+Pn/7fLy/+nt7P/X2tn/vL+8/6qrpv+kpaD/paOi/6ako/+lo6P/paOi/6Wm + pP+mqKb/sLKx/8bIyf/g4uX/7fD1//P09v/6+ff////9//7////9//////////3+/v/8/v7//P39//39 + /f///////v////3///////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + /////////////////////////////////////////////////////////////////////////v7+//3+ + /v/9/////////////////////v////z//v/7/v3//P39//7+/v/9/vz//f78//3//f/9//////////// + ///+/////f7///79///+/f/////////////+/v7//v7+//////////////////7+/v/+/v7//v3///39 + ///9/v////7//////v/+//3//v79//7+/v/8/f7/+/3+//3+/////v////7///79///+/f/////+//// + /v////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + ///+/v7//f7+//3+/v/+/f7//v3//////v///v3///79///+/f///fz///38///////+/v///v3////9 + /////f///v3+//3+/P////7//v/9//7//f////7////+//7//f/9//3//f79//3+/P///v7//f39//v9 + /f/9////+/7///n+/f/7/vz//P/9//3+/P/9/vz//v/9//////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + /////////////////////////v7+//7+/v/////////////////////////////+///+/v7//P3+//79 + /////v/////////////+//7//P78//7++v/+//v//v/9//3+/P/9/vz//f78//7+/f/9/f3/+/39//v+ + /v/7////+v7///r+///8/v///P7///3+///+/////f///////v/+//7//f////3//////////P////r+ + /v/8/v7//v7+/////v////7///////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + ///////////////////+/v7//v7+/////////////////////v////7////+//7//v/9//7///////3/ + /v/6//3/+v/+//n+/f/5/v3//P7+//3//f/+//3///79///+/f///v3//v7+//3+/v/8/v7//P7+//z+ + /v/+/v7//v7+//7+/v///////v7///z9///7/////P////3//v/8/v3//f7+///+/////v///v7///3/ + /v////7//////////v////7//////////////////////////////v////7///////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////8AAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAA + + + \ No newline at end of file diff --git a/trxGui/Form2_agc.Designer.cs b/trxGui/Form2_agc.Designer.cs new file mode 100755 index 0000000..ad00f6d --- /dev/null +++ b/trxGui/Form2_agc.Designer.cs @@ -0,0 +1,200 @@ + +namespace trxGui +{ + partial class Form2_agc + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(Form2_agc)); + this.label1 = new System.Windows.Forms.Label(); + this.cb_bass = new System.Windows.Forms.CheckBox(); + this.button1 = new System.Windows.Forms.Button(); + this.panel1 = new System.Windows.Forms.Panel(); + this.tb_micboostcol = new ColorSlider.ColorSlider(); + this.panel2 = new System.Windows.Forms.Panel(); + this.label2 = new System.Windows.Forms.Label(); + this.SuspendLayout(); + // + // label1 + // + this.label1.AutoSize = true; + this.label1.Location = new System.Drawing.Point(15, 45); + this.label1.Name = "label1"; + this.label1.Size = new System.Drawing.Size(57, 13); + this.label1.TabIndex = 0; + this.label1.Text = "Mic-Boost:"; + // + // cb_bass + // + this.cb_bass.AutoSize = true; + this.cb_bass.Location = new System.Drawing.Point(90, 102); + this.cb_bass.Name = "cb_bass"; + this.cb_bass.Size = new System.Drawing.Size(49, 17); + this.cb_bass.TabIndex = 3; + this.cb_bass.Text = "Bass"; + this.cb_bass.UseVisualStyleBackColor = true; + this.cb_bass.CheckedChanged += new System.EventHandler(this.cb_bass_CheckedChanged); + // + // button1 + // + this.button1.Location = new System.Drawing.Point(325, 102); + this.button1.Name = "button1"; + this.button1.Size = new System.Drawing.Size(75, 23); + this.button1.TabIndex = 5; + this.button1.Text = "OK"; + this.button1.UseVisualStyleBackColor = true; + this.button1.Click += new System.EventHandler(this.button1_Click); + // + // panel1 + // + this.panel1.BackgroundImage = global::trxGui.Properties.Resources.microphone; + this.panel1.BackgroundImageLayout = System.Windows.Forms.ImageLayout.None; + this.panel1.Location = new System.Drawing.Point(23, 9); + this.panel1.Name = "panel1"; + this.panel1.Size = new System.Drawing.Size(40, 33); + this.panel1.TabIndex = 6; + // + // tb_micboostcol + // + this.tb_micboostcol.BackColor = System.Drawing.Color.Gray; + this.tb_micboostcol.BarPenColorBottom = System.Drawing.Color.FromArgb(((int)(((byte)(87)))), ((int)(((byte)(94)))), ((int)(((byte)(110))))); + this.tb_micboostcol.BarPenColorTop = System.Drawing.Color.FromArgb(((int)(((byte)(55)))), ((int)(((byte)(60)))), ((int)(((byte)(74))))); + this.tb_micboostcol.BorderRoundRectSize = new System.Drawing.Size(8, 8); + this.tb_micboostcol.ElapsedInnerColor = System.Drawing.Color.FromArgb(((int)(((byte)(21)))), ((int)(((byte)(56)))), ((int)(((byte)(152))))); + this.tb_micboostcol.ElapsedPenColorBottom = System.Drawing.Color.FromArgb(((int)(((byte)(99)))), ((int)(((byte)(130)))), ((int)(((byte)(208))))); + this.tb_micboostcol.ElapsedPenColorTop = System.Drawing.Color.FromArgb(((int)(((byte)(95)))), ((int)(((byte)(140)))), ((int)(((byte)(180))))); + this.tb_micboostcol.Font = new System.Drawing.Font("Microsoft Sans Serif", 6F); + this.tb_micboostcol.ForeColor = System.Drawing.Color.White; + this.tb_micboostcol.LargeChange = new decimal(new int[] { + 1, + 0, + 0, + 0}); + this.tb_micboostcol.Location = new System.Drawing.Point(89, 3); + this.tb_micboostcol.Maximum = new decimal(new int[] { + 10, + 0, + 0, + 0}); + this.tb_micboostcol.Minimum = new decimal(new int[] { + 1, + 0, + 0, + 0}); + this.tb_micboostcol.Name = "tb_micboostcol"; + this.tb_micboostcol.Padding = 5; + this.tb_micboostcol.ScaleDivisions = new decimal(new int[] { + 9, + 0, + 0, + 0}); + this.tb_micboostcol.ScaleSubDivisions = new decimal(new int[] { + 1, + 0, + 0, + 0}); + this.tb_micboostcol.ShowDivisionsText = true; + this.tb_micboostcol.ShowSmallScale = false; + this.tb_micboostcol.Size = new System.Drawing.Size(311, 64); + this.tb_micboostcol.SmallChange = new decimal(new int[] { + 1, + 0, + 0, + 0}); + this.tb_micboostcol.TabIndex = 0; + this.tb_micboostcol.Text = "colorSlider1"; + this.tb_micboostcol.ThumbInnerColor = System.Drawing.Color.FromArgb(((int)(((byte)(21)))), ((int)(((byte)(56)))), ((int)(((byte)(152))))); + this.tb_micboostcol.ThumbPenColor = System.Drawing.Color.FromArgb(((int)(((byte)(21)))), ((int)(((byte)(56)))), ((int)(((byte)(152))))); + this.tb_micboostcol.ThumbRoundRectSize = new System.Drawing.Size(16, 16); + this.tb_micboostcol.ThumbSize = new System.Drawing.Size(16, 16); + this.tb_micboostcol.TickAdd = 0F; + this.tb_micboostcol.TickColor = System.Drawing.Color.White; + this.tb_micboostcol.TickDivide = 0F; + this.tb_micboostcol.TickStyle = System.Windows.Forms.TickStyle.Both; + this.tb_micboostcol.Value = new decimal(new int[] { + 1, + 0, + 0, + 0}); + this.tb_micboostcol.Scroll += new System.Windows.Forms.ScrollEventHandler(this.tb_micboostcol_Scroll); + // + // panel2 + // + this.panel2.BackgroundImage = global::trxGui.Properties.Resources.note; + this.panel2.BackgroundImageLayout = System.Windows.Forms.ImageLayout.Zoom; + this.panel2.Location = new System.Drawing.Point(23, 75); + this.panel2.Name = "panel2"; + this.panel2.Size = new System.Drawing.Size(40, 43); + this.panel2.TabIndex = 7; + // + // label2 + // + this.label2.AutoSize = true; + this.label2.Location = new System.Drawing.Point(15, 121); + this.label2.Name = "label2"; + this.label2.Size = new System.Drawing.Size(53, 13); + this.label2.TabIndex = 8; + this.label2.Text = "Mic-Bass:"; + // + // Form2_agc + // + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.BackColor = System.Drawing.Color.Gray; + this.ClientSize = new System.Drawing.Size(444, 148); + this.Controls.Add(this.label2); + this.Controls.Add(this.panel2); + this.Controls.Add(this.panel1); + this.Controls.Add(this.button1); + this.Controls.Add(this.cb_bass); + this.Controls.Add(this.label1); + this.Controls.Add(this.tb_micboostcol); + this.Font = new System.Drawing.Font("Microsoft Sans Serif", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedSingle; + this.Icon = ((System.Drawing.Icon)(resources.GetObject("$this.Icon"))); + this.MaximizeBox = false; + this.MinimizeBox = false; + this.Name = "Form2_agc"; + this.ShowInTaskbar = false; + this.Text = "TX Audio"; + this.TopMost = true; + this.ResumeLayout(false); + this.PerformLayout(); + + } + + #endregion + + private ColorSlider.ColorSlider tb_micboostcol; + private System.Windows.Forms.Label label1; + private System.Windows.Forms.CheckBox cb_bass; + private System.Windows.Forms.Button button1; + private System.Windows.Forms.Panel panel1; + private System.Windows.Forms.Panel panel2; + private System.Windows.Forms.Label label2; + } +} \ No newline at end of file diff --git a/trxGui/Form2_agc.cs b/trxGui/Form2_agc.cs new file mode 100755 index 0000000..82db146 --- /dev/null +++ b/trxGui/Form2_agc.cs @@ -0,0 +1,62 @@ +using System; +using System.Drawing; +using System.Windows.Forms; + +namespace trxGui +{ + public partial class Form2_agc : Form + { + UdpQueue valq; + + public Form2_agc(Point parentpos, UdpQueue vq) + { + valq = vq; + + InitializeComponent(); + + Width = 460; + + StartPosition = FormStartPosition.Manual; + Location = new Point(parentpos.X, parentpos.Y); + + tb_micboostcol.Width = Width - tb_micboostcol.Location.X - 15; + button1.Location = new Point(tb_micboostcol.Location.X + tb_micboostcol.Width - button1.Width, button1.Location.Y); + + try + { + tb_micboostcol.Value = (decimal)statics.micboost; + } + catch + { + tb_micboostcol.Value = 1; + } + cb_bass.Checked = !statics.audioHighpass; + } + + private void button1_Click(object sender, EventArgs e) + { + Close(); + } + + void sendVals() + { + Byte[] txb = new Byte[3]; + txb[0] = 11; + txb[1] = (Byte)(statics.audioHighpass ? 1 : 0); + txb[2] = (Byte)statics.micboost; + valq.Add(txb); + } + + private void cb_bass_CheckedChanged(object sender, EventArgs e) + { + statics.audioHighpass = !cb_bass.Checked; + sendVals(); + } + + private void tb_micboostcol_Scroll(object sender, ScrollEventArgs e) + { + statics.micboost = (int)tb_micboostcol.Value; + sendVals(); + } + } +} diff --git a/trxGui/Form2_agc.resx b/trxGui/Form2_agc.resx new file mode 100755 index 0000000..75652cc --- /dev/null +++ b/trxGui/Form2_agc.resx @@ -0,0 +1,1363 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + + + AAABAAUAEBAAAAEAIABoBAAAVgAAABgYAAABACAAiAkAAL4EAAAgIAAAAQAgAKgQAABGDgAAMDAAAAEA + IACoJQAA7h4AAHR2AAABACAAaN0AAJZEAAAoAAAAEAAAACAAAAABACAAAAAAAAAEAAAAAAAAAAAAAAAA + AAAAAAAA/////////////////////////////////v7+//r6+v/Gw77/xcbH/+jt9P////////////7+ + /v///////////////////////////////////////fz7///////08vH/iV0m/4VTE/+CYDP/pJ2T/+vv + 9P///////v7+///////////////////////+/v7//v7+///////n6+//2NjZ/8nBt/+woZD/rope/4VN + BP9/aEf/297k///////+/v7///////////////7///////7///+unof/flAV/4x2Wv+zoIn/f1Yi/5eN + gP/LvrD/mF8X/35lRP/q7fL///7+///////+/v7//v7+//f39v+sp6H/mol0/6V3PP+lj3P/vaiP/6Jw + Mv+ijXD/t7q8/7ywof+JUAf/opmM/////////////Pv6//////+8q5P/gkwF/41xTP+Mf27/sq6n/8zI + w/+ThXX/l3tW/4BMBv+dlo3/so5i/4JbKP/n7PL//v7+///////19vb/l2gq/51dCf+bXAr/j0sA/45z + T/+uk3T/jEgA/5laCf+dWwb/imY2/7yun/+GUhD/yMfF///////Ewr7/4uPk/7Sijv+olX//q5mF/6iT + e/+9tKn/0srB/6iTfP+rmYX/qZV+/66gj//Pxrz/iVQQ/722rP/h29H/f1AT/5qPgf+Zfl7/imk//45w + Sf+HZDf/mot4/7iqmf+GZDb/jnBI/4xrP/+Ndlj/x7yw/4pUD//EvbX/xbut/5ZbEP+Odlj/pn9R/5hV + AP+ZWgn/mlgE/52DYv+4n4L/mVYB/5xdCv+XVAD/n35R/7+slP+HUw//3t7f//3///+vi2H/hmAu/7Ov + qv+gbzD/rZR2/6KXi/+4s67/zcvH/52Th/+ojWz/lWIg/8XAt/+dcTf/nHhK//r9////////3dXN/4tS + Cv+MeWD/ztXd/6GNcv+ETQT/jHNR/62VeP99SAX/loZx/9vg5/+qknL/hkwB/9fQxv///////v79//7/ + ///DsZv/iE8D/4duTf+knJP/qo9s/7Gkk//Iu63/rpFu/7evpf+dg2D/hUkA/7ypjf///////v39//// + /////v3//f///8y9rf+XZCP/gVIT/4ZrRv+VgWb/mIRq/491Uf+EVRb/j1kT/8a0nf/+/////v38//// + ///////////////+/f//////7Ozt/8q0m/+shlX/nXA3/5tuNP+nfkr/wqmL/+nn5f////////79//// + /////////////////////////v38/////////////v////f6/f/2+f3//f///////////////v38//// + /////////////wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAoAAAAGAAAADAAAAABACAAAAAAAAAJAAAAAAAAAAAAAAAAAAAAAAAA//////// + ////////////////////////////////////////////////////////8PP4/+To7v/09/v///////// + /////////v7+//////////////////////////////////////////////////////////////////// + /////////v7+//7+///v7+7/iHFV/3tkRf+Gemn/oJ6b/87S1v/2+Pv//////////v////////////// + ///////////////////////////////////////////////////+/v7//Pz7///+/v/o5+f/jVoc/5RV + Av+MUAL/fUoI/3FULP+NiIL/19vf//////////7///////////////////////////////////////// + //////////////39/f////////////7////u7/H/ysK6/8G0pP+ymXn/pXc8/5xdDP+CTgn/b19F/77C + xv/+/f7///7+///////+/v7////////////////////////////+//7/+/38///////q7/X/sa+s/4J1 + Zf+lop3/3tza/42Dd/+ho6b/vcLJ/7Wkkv+fayr/k1YH/2pTMv+9wMT///////7+/v////////////// + ///////////////////8/Pz//////8nEvf94WS//gU8O/4RIAP+LfWv/w7eq/4VJAP+AURD/clcz/6ys + qv/Tzsn/onM8/5RXCP9tWj//19ne///////+/v3///////////////////////7+/v//////1djc/6ii + m/+kfEr/pW4n/5BRAf+Sg3D/yb2u/5FTBP+hZx3/mWww/7Clmf/l7PL/wL25/6FuLv+GTwf/iIB4//f6 + /f/+/v7//////////////////f38///////Nx77/cEoa/4R3Zf+jpqz/sa+u/6mZiP/Dvrf/4t/c/7Cf + jf+4sqz/trm9/5yRgP9qSSD/q66v/7iomP+bXg//clAi/8vO0//////////////////+/v7//v7+//T2 + +P+PbUH/nV4N/5BYD/97URj/fmRC/39yXv+ysa7/397c/46CcP+Bakr/flQe/4xUC/+ZXAv/dV49/8rO + 1P+ldkD/hEwD/5qVjv////////////7+/v/9/Pv//////87Guv+OVw3/nmUc/55lG/+hZRf/nGET/4dJ + AP+Ke2j/xLiq/4hKAP+bXxD/oGQX/51lHP+iaBz/fUwM/66ytP+3noH/kFEA/4RyWf/1+f3///////// + ///7/f///////7Ccgv+SWQ7/nGYh/5pjHv+ZYh7/nWcj/5BXDf+bjHv/zMG0/5NZEv+dZyH/mWMe/5lj + Hv+eaCH/iFEK/6aelP/KvrL/k1UF/39iPP/n6/H///7+/+Xi3v+MhXv/6uzv/+Hf3v+4sq//uLOw/7mz + sf+4s7D/urSx/7Stqv/T0tD/7e3t/7y1sv+4srD/ubOw/7mzsP+5tLL/s6yn/9ja2//Ow7j/lVgK/4Bf + Mv/i5ez//////7Gegf9qNwD/mZmY/7euo/98Y0H/gGlK/39oSf9/aUn/gmtL/3ZePf+fmpP/0s7J/31l + Rf+Aakn/gGlJ/39pSf+Ca0v/dVw8/6qnof/Mwbb/lFUG/4NiNv/m6vH/4+Th/45hJf+jYxH/eFku/5SD + c/+aWwv/mV0Q/5ldEP+aXhL/nGEV/45PAP+MfGj/xrms/5BRAP+bXxP/mV4R/5ldEP+dYRP/hkoA/7Gr + ov/DsZv/jlAA/4pwTf/2+f3/2tjV/5+BXf+eYhT/f1wt/7i5u/+fbTH/nGMY/51lHf+YXRD/mF8T/45T + Cv+cj37/zMG1/5BWDf+aYBT/mV8S/5tkG/+gZxz/hloc/9nd4/+mhFf/jU8A/6CPev///////////9vb + 3f+aZCL/fE4O/6isr/+2oYn/klUG/5ZgHP+qh17/uqmY/7Grpf/Rz87/6+zs/7auqP+wnoj/poBR/5xl + H/+NTwD/rZqA/9TT0f+RWhP/iVQQ/8jGwv///////v79//n7/P+mhmP/llgF/3VfQ//DyM//sJd5/8a+ + tP+xsbL/kIR0/3dcO/+YkYj/z8rE/3tlSf+Kg3r/p6uw/7CkmP+liGL/5Onu/5R2Tv+XVwP/knRN//f5 + +//+/v3//v39///////U0Mz/mWYn/4tUCv95bV3/4Orz/7WupP95SAr/kVMB/49OAP+Nfmr/xrms/5BP + AP+MUQL/aD8J/7y6tf/3/v//lYNr/5VZC/+LWRX/0MzF///////9/fz///////7+/f/+////u66h/5ph + GP+JUwj/dGRO/62usv+/s6f/ro1k/5RhIP+fkX//0Ma5/5VhIf+tiFz/y7us/8zOz/+JdFr/j1cM/5FX + C/+zpY7///////39/f/////////////////+/v3/+v3//7eqm/+bZiP/klYG/3VTJP+EfnP/pKit/66w + sv/Jy8//1dne/7u7vv+3u8H/mJKI/31YKf+UVwb/klsT/7Gfh//8/v///P37/////v////////////// + //////7////+//7////MxcD/oX1O/5tfEf+KTwD/fE4P/35bL/99Yj//fmI//39fNP99UBL/iU4A/5da + C/+YbTf/xbqt/////////v3//v7+/////////////////////////////v/////+/f//////7O/z/8O3 + q/+riWH/n24v/5deFf+WWAz/lVgM/5VbEP+cZiX/ontO/7molf/q6uz///////79/P////////////// + ///////////////////////////////////+/f3////////////3+///5OPk/9POyP/KvrL/x72x/9DI + wP/e3dz/9ff7/////////////f38//////////////////////////////////////////////////// + /////////v7+//79/P////////////////////////////////////////////79/P/+/v7///////// + ////////////////////////AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAKAAAACAA + AABAAAAAAQAgAAAAAAAAEAAAAAAAAAAAAAAAAAAAAAAAAP////////////////////////////////// + ////////////////////////////////////////////////////////+fr7//r7/f/+/f7///7+//7/ + /////////v7+//////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////7+/v//////9vf2/6uoov+OjIj/oZ+e/7W5 + vv/W2dv/7+/w//n5+v/+/v///////////v////////////////////////////7+/v////////////// + /////////////////////////////////////////////////////////v79///////j4+P/eVAe/31K + Cf9ySRP/akog/2pZQ/+Fgnv/ub3B/+fo6v/6+fn///////////////////////////////////////// + //////////////////////////////////////////////////////////////7+/v/9/fz//v7+/+Tj + 5P+TZS7/oWMS/59kFf+fYRH/lFkO/3lMDf9mSyn/g397/8nLzv/x8vP//v7+//7//v////////////// + ///////////////////////////////////////////////////////////////////9/f3////+//// + ////////7u7v/7Spnv+4ppP/qpBx/515S/+baCb/omUV/5xhEf91SQ7/ZVZA/6yxtP/t7O3//v3+//// + //////////////7+/v///////////////////////////////////////v/+//3+/v/9/f3//v/9//// + ///1+Pv/0tba/7C0tf/P0NH//P///8zS1v+/xc3/y8/V/724sf+ih2r/nGgm/6RoGP+MVxD/Xkgo/6Ol + qP/u7e7//v7+//7+/v/////////////////////////////////////////////////9/v7/+/38//// + ///6/f//sbS1/3htW/9wUyz/WTUK/5GNiv/b2Nb/a0cb/2tQK/93bl//qKms/87T3P+4sKr/mnFA/6Jl + F/+VXRL/XUUk/6msr//z9PX///7///7+/v///////////////////////////////////////v////z9 + /P///v3/6uno/4h3Yf9vRAr/jVUO/6JnG/+IUAn/kYuD/9za2P+YYB7/nWEV/4lUDP9pRBT/dGdW/9PX + 2P/U0tH/nHlR/6JlGf+QWRL/YlA3/8bIzP/8+vz////+//7+/v////////////////////////////// + ///+/v7///////X5/P/CwsL/k3hX/6JuK/+cZBf/oGQV/4BJAf+SjYb/3dvX/5JdGP+dYRP/nWEV/5li + Fv98WS//0c/O//3////Hx8f/mnND/6VnGf99TAz/enNs/+nr7v/9/v7//v7+//////////////////// + /////////f39///////n6en/dmRO/4eDfv+9wsn/t7Wz/6yYgv+nhFr/hFoo/6ynoP/i4d7/jmQ2/6B4 + R/+pkHH/wLeu/9nd4f+rqqb/c2ZX/8PIy/+8tbH/mGYm/6BlFf9mRh3/srW5//3+/f/+/v7///////// + //////////////7+///9/f3/+/3//5J+ZP+JTwL/eUwQ/2dSM/+Hgnz/p6mu/7W8xf+5vL3/3N3e//j6 + +//S1dv/wMXN/7i8w/+bmZX/cV9E/3lMEP96RgL/c2lb/9rg5v+jiG3/n2QY/4RQC/99c2j/8fP3//// + /v///////////////////////Pz8///////MycX/glET/6JoHf+hZxz/mF4R/35NC/9vSBf/cVUx/2xb + Q/+rrKr/6Ojn/4h4YP9vVzP/bkoa/3xKCf+VWg//oWcb/6RqHP9mQhL/rrK0/83FwP+WYib/nWES/2ZO + Lf/S1dv///////////////////////7+/v/9/fz//v///56Iaf+UWg3/nGUe/5piG/+cZRz/omgd/59m + G/+hZRj/eEMA/46HgP/a19X/h1IQ/5xgE/+hZhv/oWge/51lHf+ZYhv/n2ge/4lTDP98c2X/3ePp/5x2 + TP+iZBT/cEgS/6+xs//////////////////9/v7///7+///////r7vD/kWYt/5tfDv+bYRX/m2EV/5xg + FP+bYBX/mmAV/59mGf+ETAH/lI2H/+Dc2f+UXhv/n2IT/5phFf+ZYBT/m2AU/5thFf+cYhb/ml0N/21R + Lf/b4+z/q5J3/59iFP98TAz/mJON///////+/v7///7+//z+///h5un//fz8/93d3P+Pa0H/n3M9/51x + Pv+ecj7/nXI+/51xPv+dcT3/ondA/4VaKf+wrKX/4+Lg/5JpO/+fcj7/nXI+/51yPf+dcj3/nXI9/51y + Pv+gczr/e18+/+rv9P+6qZn/mV8T/4ZRCv+Lg3f///////39/P//////pZqL/3VsYP/e4OP/+vv8/93e + 5P/Fx83/xsjO/8bHzv/Gx87/xsfO/8bIzv/Hx8//xcbK/+Pk5P/7/P3/29vg/8bHzf/HyM//xsfO/8bH + zv/Gx87/xcfP/8fHzf/Jycv/9vn8/7urm/+YXRX/i1QJ/4p+cf////////7+/+fr7f+IXiP/aj4H/42O + j//c3N3/into/3VlTf91Z1H/dWZQ/3VmUP92Z1D/dWZQ/3loUv9qXUj/q6qn/+jp5/+EdmH/dWVN/3Zn + UP91Z1D/dWdQ/3ZnUP93Z1D/dmVO/3FmVf/g5Oj/vKya/5dcEf+MUwr/jIJ1////////////s6iX/4xV + DP+iZhn/ZUki/5aYnP+OYC3/klYI/5FYD/+RVw7/kVcO/5FYDf+RVw7/mF0R/3ZBAP+OhoH/29bV/4RQ + D/+TWQ3/kVgO/5JYDv+RWA7/kVgO/5FYD/+UWAn/bEka/9/n8f+xmoD/mV0S/4RRCv+blIr//////+3w + 8f+KZzj/m2AU/6FoHf+GUgz/i4WB/6yPbv+cXxL/nWYf/55lHf+eZR3/nmYf/51mH/+iayH/hlAH/5SM + hf/e29n/lmEf/59lG/+dZR//nmYe/51lHf+eZRz/nWcg/5deDv+Ic1X/8/r//5p3S/+eYhP/e00O/7ez + sv//////7e7t/7KpoP+ddEb/omUW/3FIEf+orK7/v7Wp/5deGf+bZBn/nGQb/5xkG/+bYhT/l10Q/5xi + GP97Rgj/oJyU/+Dd2v+LWBv/mmAU/5lfFP+aYRT/m2MY/5pjG/+hZx7/g08H/7exqv/j4+X/iFoc/6Jm + Ff95UyD/2t3g//////////7//////6eUgP+eYhT/hVIM/3txY//W2+L/mXhQ/55gEv+cYRf/lFsS/5ds + Of+rjnD/vKyd/7ixqP/f3Nz/8vb1/8O6s/+yoI7/podj/5xuNf+aYRn/nWMX/5pgEf+DYTT/9Pr+/6uY + gP+RWA3/mFwQ/4dzV//5/P///v78//v7+//+/v3/zsrG/5ViJv+iZhb/ZEQc/7O3vf/GwLv/kmYt/5Vu + Pv/Dt6v/0tXa/7zByP+goJ//hoB6/7e3uP/x8fD/pKKe/5yen/+yucL/wL+//6ycjP+dcTr/glEQ/8/K + wv/d4OH/gFUd/6RpG/+CUBD/vbm0///////7/Pr///7+/////v/19vr/oIRn/59kFf+NVxD/ZldG/8rQ + 2P/Iwrz/4eLh/7y+vP94ZUv/bkod/31OEP9oNwD/jYeC/9rX1f9zRQz/c0kQ/2xPK/98cmj/sLS6/8K/ + vP/JwLb/9Pn//4VsS/+VXRL/m18P/4pwS//3+Pv//v79//7//v///////v39///////Rz87/lGg0/6Jn + GP9+Tg7/bWRX/9rf4//O0M7/dVcz/5FWCv+gYhH/qGwd/4dSC/+SjYX/3dvZ/5tkI/+laBn/nWIS/3tE + AP9qVTf/+Pr7//j9//+FdmH/i1QM/6VpHP+BVRj/0c7K///////9/fz//////////////////f39//3/ + //+4r6f/lWQj/6RnGP98Tgz/ZlpI/7K1vP/OzMv/r5qF/5lyQP+eaCL/fUUA/5eRif/e3Nj/i1YU/5Re + Fv+UaDP/sZd9/+fi4P/T1tr/dmVO/4ZRDf+lax//iFIL/7Cmk////////P38//////////////////// + ///+/v7//f79//j6/f+voZf/lmUi/6NmF/+JVRH/ZEom/4SBfv+1u8T/xcbL/7+3sP+llID/z8zI//Dw + 7/+xoY//x7yy/9jb4P/W3eb/nJmU/2tOKP+QVxD/pGob/4pVDP+oln//+/7///v9+////v7///////// + ///////////////////+/v7///7+//b5/f+5sKj/l2w4/6BkFv+eYhL/eEoM/2ZNJv93bF7/kpKP/6qt + sv+2u7//ubq+/7S4vf+ioaL/g3ps/2pOKv97Sgv/oGQW/59lFP+JWRv/sqOR//v+///+/fz//f79//7/ + ///////////////////////////////////+/v7////+//7////Rzs7/oohp/5dmJv+iZRT/nmEQ/4tU + C/97Sg7/cUkW/21KG/9uSx7/cEkX/3dJDf+JUwr/n2IS/6BlF/+SXBb/lHJI/8rEvP////////79//7+ + /v/////////////////////////////////////////////////+/v///v79///////v8vb/xsC6/6WL + bv+bbjj/nGUe/55kFP+gYhL/oWIR/6FjEf+gYhL/n2IT/5xhGP+TYib/mHdQ/7uvof/u8fT///////38 + +v/+/v7//////////////////////////////////////////////////v///////////////f39//// + ////////9Pj8/9vb2v/Bt67/rZuG/6SJav+gfln/nn1Z/6CCYf+nkHf/uKqb/9TPzP/x9Pf///////// + ///8/fz//v////////////////////////////////////////////////////////////////////// + /////////v7+//39/f/////////////////+////9/v///H09//w9Pj/9fn9//7///////////////// + ///+/fz//v7+//////////////////////////////////////////////////////////////////// + //////////////////////////////7+/v/+/f3//f39//7+/f////////////////////////79//39 + /P/9/f3//v7+//////////////////////////////////////////////////////8AAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACgA + AAAwAAAAYAAAAAEAIAAAAAAAACQAAAAAAAAAAAAAAAAAAAAAAAD///////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////z+/v/5+fr/+vn5//v6+f/7+vz//fz+/////////////f////3+/v/+/////v////7/ + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + ////////////////////////////////////////5Obn/9rc3//g4eL/5eXm/+rp6v/x8PH/+Pn5//7+ + /v///////v/+//7+/v////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////+/v7//////+zu7f+Qi4T/cmxk/3NxbP+HhH//mZmb/6+1 + uf/Iy8v/2dnX/+Pi4//v7/H/+vv9///+///+/v////////////////////////////////////////// + /////////v7+//7+/v////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////+/f3//////9zZ1v9qSCD/d0UF/29D + C/9kPQn/WjsT/1ZCKP9iW1H/h4WC/7Gzsv/JzdD/2tze/+3u7v/9/P3///////////////////////// + //////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////+/v3//////9rb + 3f+QaT3/rGoW/6FpIf+eaSD/oGYY/5VcEv97SQz/XDkN/1BBKP92cGj/q62u/87Oz//f39//9fX4///+ + ///+/v7///////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + ///9/f3//////93Z2P+IYzb/oGUW/5xiGP+dYhX/mmEW/5piHP+gZx7/pWgc/5BcEf9nPgj/Uzwl/3l6 + dv+7u7z/09TV/+zt7////v7//v/+//7+/v////////////////////////////7+/v////////////// + //////////////////////////////////////////////////////////////////////////////// + ///+/v7//v7+//7+/v/9/f3//////+Hi5P+Vhnr/n4lw/5yDaP+de1H/nHI9/55rKv+dZBj/mGAW/55l + Gf+kaxz/jloW/1w3Cf9YTjz/oaSk/8vN0P/m5uf//fz9/////////////////////////////v7+//7+ + /v////////////////////////////////////////////////////////////////////////////// + /////////v////7+/f/+/v3//f39//r6+//29ff/7e3v/+7v8P/v8fP/7/L1/+Dh5f/Hxcb/t7Sy/6ee + kv+fhmj/nXM9/59lH/+aYRP/nGYb/6JpHv94SQz/Szsg/4+Rj//Lysz/5uXn//79/v/+/v7//v7+//// + //////////////7+/v/////////////////////////////////////////////////////////+//7/ + /v/9/v7//f7+//3+/v/8/v3//f39//38/v/29vr/4ePl/8LHyP+iqKr/oaOh/8/R0v/9/f7/4uTi/7u+ + vv+/wsT/0dTW/9fY2//Hyc3/r62r/6CKeP+icjv/nmUW/5hhGf+haiD/iVcR/0w0FP+Dhoj/y8vL/+jn + 6f/+/f3//v7+//7+/v////////////////////////////////////////////////////////////// + ///////////+//3+/f/8/v7//v79//39+//8/f7/9/r8/83R1f+Qko3/Z2BR/1hEK/9aPRX/QSwT/66w + s//8/P7/emlV/1Q3Ff9bSC//ZWBW/4+Pj//CwMD/1djX/8rMzv+spaT/o4Bb/6JpI/+ZYBX/omgd/41b + F/9LMxD/iYiG/8zPz//t7vD///////7+/v///v////////////////////////////////////////// + //////////////////////////7///3+///+/v3//Pz8///////v7/X/kY6K/1ZILv9gOw3/fUwM/5Nb + Ev+nZxv/VzcP/6emq//1+///nHxY/5xeE/+PWRH/dUcK/1c6Df9YSTn/hYOL/8fFxf/Y3t7/u7/C/5+I + bv+gayz/nV8U/6FoHf+OWRT/SDMa/5iam//X2Nj/9vX5///+//////////////7+/v////////////// + ///////////////////////////////////+/////v7///z+/v/8/Pr//f7//9rY1f9wYkr/XzoF/5Ra + EP+kaB//omce/5tlHf+hZh3/XDoO/6mpqv/2+///mX5d/5tgGP+eZR//o2ke/6JnGP+CUQ7/VjgN/2Ra + S//BwsH//fz9/9XV2P+gj33/n2wu/5tgFv+gaCD/glEP/1FDL/+0tLP/4+Hl//38/f/+/v7///7+//7+ + /v////////////////////////////////////////////////////7//v7+//39/f//////9vb1/6Gb + lv+FZ0T/qnQz/6BlGv+VYhT/mGIW/5tiG/+iaBn/VjkQ/6aprP/4+/7/mn1b/5tgFv+dYxr/mmIa/5xi + Gf+iaRr/oGkc/185Df+ak47///////r6+v/R0tT/nopx/6FrI/+YXxj/pWke/2hACf9qZmH/zs/Q//Lw + 8v/8/v///v7+//7+/v///////////////////////////////////////////////////////f39//7/ + ///Nzs7/r7O2/87Q0v+7u7r/oJWG/5x/W/+hcDr/n2cf/51jFf+kZRj/WzcO/7a3uv/4/v//mnxX/5xf + Ev+bZBr/m2Ib/5ZjIf+OaDf/ln1g/762rf/w8vP/297i/72/xP/b3Nn/wMHG/5t+Wv+hZRv/mmQY/5di + Gf9SNhj/nZ2f/+Dk5f/6+/z//v7+//7+/v/////////////////////////////////+/v7//v////7+ + ///8/Pz//////8/Rz/9cQSH/Vj4k/3t7e/+8vL3/yMrP/7i7vv+rpqD/n5CB/52AZf+felD/Zk0u/87P + zv//////mYJv/5RrRP+Ydk//nINo/6mekv/IxcP/5+nr/+Pn6v+goqL/X085/1lHM/+lq6r/4OHl/62p + qP+ecTz/m2IV/6FpHf93Sgr/YFhM/8vO0P/09PP///7///z9/v////////////////////////////// + //////////////39/f/9/f3/8PHy/3RfQv+NWA//k1sU/1s5Df9WRjH/enhz/62trv/Hx8n/x83S/8bJ + y/++vb3/vbiz/+rs8P/7/v3/1tjW/8fHx//R09b/3N/j/97h5f/EyM3/kJCO/11TQ/9bOxH/jFgR/3JC + B/9aVEj/zMrI/9vd3/+ahnb/n2ci/5piGv+cZBb/UjgW/6OgoP/o6+3//f7+//7+/v////////////// + /////////////////////////v7+//v8+///////oZuU/3pKC/+haB7/nmUa/59nG/+JVRD/Yz4L/1U+ + If9jVEX/e3Rt/5KSkf+jqKv/vb66/9TW2v/6+vn/9vj5/8XHzv+bnZ3/gH98/2dbTf9cQyT/ZD4N/4VR + DP+gZhb/oGcc/55nHv9XOA3/g4WF/+Xp6f++ubX/mm0//5lhGP+maB3/cUQJ/3FpYv/d3+L/+vv7//7/ + /v/////////////////////////////////+/v7//f39//7//v/o6er/d1k3/5xhFf+bYxv/mmIa/5ti + Gv+fZhr/o2ka/5ZfFP+ATw3/bUIL/2E9Dv9cPxn/Tz8r/7a7vP/5/P7/inxq/1o/F/9gPw//a0EK/31N + DP+UXRT/omcb/6BmHf+aYhv/mWIZ/59oG/+HUxD/U0Y2/8jJyf/i4+T/nIBq/59kG/+dZRz/jlkR/1RE + Lf/CxMf/9/j5//7//v/////////////////////////////////+//7//Pz7//////+yq6L/glEO/59n + Hf+bYhr/m2Ia/5tiGf+ZYhv/mGIa/51kGv+fZx3/o2gc/6NnGP+fZhn/UzMJ/6iop//2+///lXdT/5ld + EP+fZh3/o2ge/6FnHv+dYxz/mmIa/5pjGv+aYxn/mmMa/5pjGf+iZxj/WjoQ/5OVlf/v8vX/qqSb/51k + KP+aYxn/n2Ua/1k7Ev+fo6X/9PX3//7+/f///////////////////////////////////v7//v79//n8 + /v+PeFr/lFsP/5xlHP+bYxr/mmMa/5tjG/+dYxn/nmMY/5xjGv+bYxr/mWIb/5hiHf+iaRr/WzoQ/6io + rP/7/P7/nH5g/5tgGv+dYxr/mmMb/5pjGv+bYxn/m2MZ/5tjGv+bYxv/m2Mb/5tiG/+jaB7/d0kL/2pm + Xf/n6uz/xsbF/5ZqPf+bZBf/pGge/2pBCf+Dgn3/8fD0//39/v/////////////////8/v7//P38///+ + /v/9/v3//////+To6/+LYjL/nWIT/5liGf+bYhj/m2IZ/5tjGf+aYhr/mmIa/5piGv+aYhr/m2IY/5di + F/+jZxb/XDgO/62wtv/7/v7/mn1a/5pfEv+eYxb/m2MY/5pjGP+ZYxn/mWIa/5tiGf+aYhn/mmMZ/5ti + GP+eZRv/jVYO/2BNOf/d4ub/3+Di/5JxTf+eZBj/oGkd/3hIDP9vZ1z/6uzu//39/v////////////// + ////////+v7//+jr7P/39/f//////8rLyP+EXSz/oGsi/5tnJf+dZyT/nmck/51oJP+daCT/nWcj/51n + JP+dZyT/nWgi/5loI/+gaSX/WTkR/8HDxP/8////mHtc/5pkI/+cZyb/nmcj/51nI/+daCT/nWck/51o + JP+dZyP/nWgj/51oI/+eaiT/lmQf/1tEJ//g4uP/8/b5/5d9Yv+bYBj/oGga/4RQD/9kWEj/4ufp//7+ + /v///////v7+//7+/v/39/j/sbOz/73DxP/l4uH//v///9/h4f+klo7/rJiL/6eXi/+ml4r/qJeL/6eX + i/+ol4v/p5eL/6eXi/+nl4v/p5iJ/6qXjP+qlYr/mo6B/+bp6f/9////t62n/6mVh/+pmYv/p5eL/6eX + i/+ml4r/p5eL/6eXiv+nl4r/p5eL/6aXjP+rmIz/qpaF/5aOhv/u7u7/+////56Hcv+XXhj/omgY/4pW + D/9fUDv/4eLm/////////////Pz7//////+vqJ7/RyYE/3h0cf/Ozs3/5+nr///////9////3uLm/9ja + 3f/Y2t//2Nrf/9ja3//Y2t//2Nrf/9ja3//Z2t//1trf/9na4P/U2t//3+Df/+fn6//6+/v//////+ns + 8v/X2t//2drg/9na3//Y2t//2Nrf/9na3//Z2t//2drf/9fa4P/Y29//2Nre/93f4v/q6un/9Pn9/52D + a/+YXhj/oWcd/4xXDf9hUTv/4eHq//7////9/f3//v79//H09/97YTv/ml0M/0wyE/+Lj47/2NjY/+Lj + 5P+Xk4z/enJq/3FtZ/9xbmf/cW5n/3FuZ/9xbmf/cW5n/3JuZv9xb2b/cm1n/3VuaP9vbGT/fHdx/8bJ + yv/4/Pz/vLi0/353bf9zbmX/cm9m/3JvZv9xb2b/cW9m/3FvZv9ybmb/cW5m/3JuZv91b2T/cGtl/3t6 + cv/T0tL/9/v+/5uDaP+YXhL/oGcf/45XDv9hUjz/4eTs///////6/Pr//////7a1r/99Tgn/oWwg/4lU + E/9JNiP/s7a5/7Swrf9oRRz/dkcI/3JHDP90Rgz/c0YL/3NGC/9zRgv/c0cL/3NHC/90Rwv/dEcL/3ZH + C/90SQ3/RSoI/6ysrP/6/f//f2lN/2o/BP90SQ3/c0cL/3NHC/90Rwv/dEcL/3NHC/90Rwv/dEYM/3VG + DP90Rw3/ckMK/000FP/LzM//+Pz+/5Z7Xv+YXhP/oWce/4pVDP9oW0b/6e3y///////8/v3/+fv9/4Fs + Tf+WXBL/nGIe/6dqGv9yRgv/V1JH/7O2vv+Yck3/pmgb/6FoHf+iaB3/omcd/6JnHf+iZx3/omcd/6Jn + Hf+iZx3/oWce/6JnG/+nbBz/WjoQ/6amrf/5+v//nn9e/6JkGf+jaBz/omcd/6JnHf+iZx3/omcd/6Jn + Hf+iaB3/omgd/6FoHf+gah//oGIS/2dTNP/h5+//6err/4xoPv+ZYRn/oWke/31NCv91bGD/+Pr9//7+ + /f//////w8PA/31OC/+eZRn/mWIb/5tjF/+jbB7/XjoM/5qZnP+kjXX/m2Aa/5tiGv+aYxr/m2Ia/5pi + Gv+aYhr/m2Ia/5tiGv+bYhr/mmIZ/5liG/+haBj/XDkM/6moqv/4/P//mXxc/5lfFP+aYxv/m2Ia/5pi + GP+aYxn/mmIZ/5tiGv+aYhr/mmIZ/5hiGv+fZxr/iFIK/3RtXf/9/v//0tDN/4lcI/+cYxr/omkc/3RH + C/+OiIT///////39/P//////mY+E/4xiMP+lczX/mGEZ/59mGv+TWxP/ZlE6/8bIyf+xqqL/mmUm/5xj + Fv+aYxz/m2Ic/5xjGP+bYxr/nGMb/5pjHP+bYxz/mmMa/5liGv+hZxj/WzkP/7CytP/4/v//nHxb/5te + E/+bYxn/nGIb/5liHv+bYxz/m2Ma/5pjGv+cYxj/m2Ma/5hiHP+faBr/dEgP/6Wjof//////raSZ/4xX + EP+bZR3/oGYa/2lDEP+1srL///////z8+//9////29rY/7u8vv+agGn/n2Mb/5xmHf+KVhH/UEQz/87U + 1v/Pz9D/lnVQ/6BjHP+aYxn/m2UW/5xjGv+ZYhz/mmQY/55kFf+eYxf/nGQY/51jHP+hZib/VzoU/8PF + xv/9////lntc/5tjH/+cZhr/m2MX/5phFf+aYhb/m2QY/5tkGf+aYxr/m2Ia/55kG/+dYRH/blMv/+Tl + 5//2+Pz/inFT/5ZdEP+cZR7/nGAS/2hNKv/Y3eL///////z9/f/9/v7///////////+lm5T/mWQj/5xi + Fv+gaBz/VDYK/5aXlv/l5uj/oZmT/5xrK/+dYRT/nWId/5xkGf+hZRX/m2Mb/5RiJ/+SaTn/mXhY/56J + df+il4b/pZqN/+zq7P/6////t7Or/6KOfv+iiHL/nnxX/6B0O/+eaST/nGEZ/5xgFv+cYxr/mmMZ/59o + Hf+BTwv/mZKG///////HxMH/flIZ/55kGP+fZh3/iVIK/350ZP/3+/////79//3+/v/8/f7/+vv6//7+ + /f/Kycr/kWs9/59jFP+haR//eUkJ/2BYTv/V1tf/yc3Q/5d9X/+fZiD/nmQZ/5diH/+SYyz/l3lY/62h + mP/Jxcb/3t3g/97i5v/T2t//3drb/9/g5v/6/Pr//////+Pm7//Lz9H/vL7C/66oqP+kk4T/noBb/5xu + Nf+dYxj/nmQY/5RdFP94XTz/6Ojp//n8/P+Mdl3/kFgQ/55mG/+gZh3/cUcR/7K0tf//////+/z7///+ + /f/9/v7//v7+///////y9PX/m4Nw/6FmHv+YYhr/n2Ya/040E/+Rk5f/4eDf/7q2t/+Zd03/jmIh/5J5 + X//DvLj/6evw/+Tp7v/Excn/lpeV/3t1bP9nW1L/X1dM/7zAw//9/f3/paGZ/3dyZv+Ign3/pKen/7/E + yP/Mz8//vbu6/6SalP+fgV3/oGoj/3xTG//DwL3//////6+vrf94TBP/n2Yc/51lHP+SWhD/emRI/+/x + 9f/+/v7//P3+//7+/f///v////////7+/f//////urOz/5VsO/+eYxP/nWgf/4ZRDP9UQzL/sbe//9nc + 2v+2r6n/tauk//X5+v/1/v//oaSk/2ZbSv9aQB7/XDwS/3BFCv+DUQv/SCwG/6iorP/7/f//hGlN/2xA + A/9iQA3/VTwY/11LOf+AeXj/tLW5/8nO1f+/v8D/m419/7asof//////29zf/2xSMv+UXhX/nGUa/6Fn + G/91Sg//tLKv///////8/Pv//v////////////////////7+/v///v7/7O/y/5uHdP+iaiT/mGAX/6Bp + Hv9rQAj/XFhT/8TDyP/c3N7//P///9jX1f9xYE7/XjkJ/4JODf+YXxj/o2Ya/6JoHP+max7/WzsS/6mo + rP/2+///oYBf/6RkGv+haB//nWIZ/4ZTEP9fPAz/UUAl/4qHgf/r6+r/9fb3///////l6e7/dGRQ/4tV + C/+gZhv/nGYe/5JYC/+EcFX/9Pb6//79/f/+/v7////////////////////////////8/f3//////8nI + yv+VdVP/nmUa/5hiG/+gaBv/YToG/2ViWv+/wL//2t3d/6yuqf+DalD/pnMz/59nGv+aYhj/nGMW/5li + G/+haBr/WDkN/6Wpqv/4+///mX1e/5pfFv+cYxv/mWQa/59nHf+nahz/hVEM/2NQOP/i5ef//////+Pl + 6/90aFf/ekwK/6BnHf+cYxr/m2IY/3VUJf/U1dT///////39/P/+/v7///////////////////////// + ///+/v7//P39//3+//+uqqb/nHRH/5pkE/+fYhz/oGYc/2E+Bf9eVEn/rrG3/9jX1//Bw8T/pZmN/599 + WP+ebi//mmQb/51hFf+hZhX/XTgP/7C0tP/6/f//nHxY/51gEv+eZRf/mWMW/5hgHv+OZD3/oZGF/+jj + 4P//////y8vP/2RXSf91Sg//pGcb/5dhHf+iZxr/fFEP/66roP//////+vz8//7+/v////////////// + /////////////////////////P7+//3+/v/29/j/pZqW/51xO/+aZBH/mWMd/6BoGv9tRAf/TUAw/4uJ + jf/Lycn/0NLV/7m3uv+onpX/nohu/6B3SP+hczf/Wzoa/8PEx//+////lXxh/5JmLf+XbD3/lnlf/6aa + kf/T0tD/+v7//+zu8/+bm5v/WUUo/39PDP+jZx3/mWMY/59pG/+FURH/m5GA//3+/v/7/fv//f79//// + /////////////////////////////////////////f////v9/f//////6+7w/6GUlP+gdD3/nGQS/5tg + Gv+gaCP/jVcN/1Q4DP9VUEb/kpGR/8HEyP/T1Nf/zMzP/7u+wP+yraz/qaOX/+np6f/6+vz/w7+8/7my + rf/Nzcz/5Ofo//H2+v/i4+j/pqam/2NZSv9eOxD/kFoV/6VmHP+WYhr/oGgW/4ZTFf+ajXf/+Pn7//v9 + /v/5/fz///79//////////////////////////////////////////////////7//v/9/f3//////+3u + 8f+ppKD/nnlQ/59mHv+YYBX/n2cd/59mHP97Swz/VTgO/1VLOP91c27/oZ6e/7q/vf/KzNP/2Nzd/9ba + 4f/a2t7/4OLk/9fd4P/LzdL/s7Cz/4KBff9cUD//WDsT/39NDf+jZxv/nGUc/5xmGP+bZBz/hFgi/6aY + hv/2+vv//v79//v9/P/9//3//v/+//////////////////////////////////////////////////// + /v////7//P39///////5+/v/u7e5/5yCaf+fbjD/n2IU/5phFf+haB7/nmYb/4dUDf9lPwn/VDkV/1VC + KP9dTz//Z19W/2tlXf9uZlz/a2Na/2FURv9WQyz/VTwY/2VAC/+GUg3/omYZ/59mH/+ZYxj/oGcX/5Vg + GP+GYjT/ubGo//3////+//7//v7+/////v/+//7//v////7+/v////////////////////////////// + //////////////////////////////39/v/+/v3//////9jZ3f+nnZL/mntW/5xqKv+dYxP/m2IU/59l + HP+jah3/omUb/5ZbFv+HUxH/fEwL/3pKCv96SQ3/e0sM/4VTDv+RXBP/nWQZ/6RqG/+gZxz/mGMb/5tk + Gf+bYhr/jF4t/5aDbv/Y2Nb///////z8/P/+/f3///////////////////////////////////////// + ///////////////////////////////////////////////////+/v7//P39///////2+Pn/yMjL/6ma + jP+efFn/nWw3/59lHP+dYhT/mGIV/5xlFv+fZxn/oWYd/6FoHf+gaR3/oGce/59mHP+dZBv/nWMY/59j + F/+cYhn/mWIg/45jNP+Vf2T/wr+6//j7/v//////+/z7//7+/P/+//////////////////////////// + ///////////////////////////////////////////////////+/////v///////////////f7+//v8 + /P/+/v3///////X4+v/S0tX/tK2k/6SPd/+delX/mm86/5poKf+bZCH/nmMf/55kHP+fZRv/nWQc/5pi + Hf+YYiD/lmQo/5RpOv+Vdlj/pZaE/8jGxP/09/r///////7+/P/7/fz//v79//7+/f/+//////////// + ///////////////////////////////////////////////////////////////////+/////v////// + ///////////////////+/////f39/////////////////+/x9P/X19r/wL28/6+pov+pm43/n4p0/56H + b/+dhnH/mYVv/6OQf/+pnJL/tbCs/8/Nzv/q7PD//////////////////f38//7+///+/////v////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////7+/v/+/f3//f79//////////////////// + ///6/f//8PL1/+3w8v/u8fP/7vL0//f7/v///////////////////////v38//39/f////////////// + //////////////////////////////////////////////////////////////////////////////// + /////////////////////////////////////////////////////////////////////////v/+//7+ + /v/9/f3//P38//z9+//+//3//////////////////////////v/+/f3/+/39//v9/P/9/f3//v/+//// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + /////////////////////////////////////////v7+//7+/v/+/v7//v7+//////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAoAAAAdAAAAOwAAAABACAAAAAAAODV + AAAAAAAAAAAAAAAAAAAAAAAA//////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////7/ + ///+/////v7///7+/v/9/f3//v7+//7+/v/+/v7//v3+//7+/v/+/v7//v79//7+/f/+/v7//v7+//7+ + /v/+/v7///////7////+/////v////7////+/////v7+//7+/v////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + /////////////////////////////////////////////////////////v////z+/v/8/v7/+/3+//v8 + /f/7+vz/+/r7//v7+//7+/v/+/v7//v6+//7+vz//Pv+//38/v/9/P7//v3+//7+/v/+/v7//v7+//z+ + ///8/v7//P7+//z+/v/8/v7//f7+//7////+/////v////7////+/////v////7////+//////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////+/////P7+//r8/f/6/P3/+fr8//Tz9f/u7e7/7e3t/+3t + 7f/u7u7/7+/x/+/w9P/x8ff/8/T4//b2+f/5+fr/+vr7//v6/P/8/P7/+/3+//v9/v/8/f7//P7+//z+ + /v/8/v7//f////3////9/////f////3////9/////f////7///////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////7//v/+/v7//v7+//39/f/39/f/6+vr/97e3v/X2Nj/1tbW/9jY2P/Z2tr/2t7c/9zg + 3v/g4+L/5efn/+rq6//v7e//9fHz//f09v/6+Pn/+/r8//38/f/+/v7//v7+//7+/v/+//7///////// + //////7////+/////v////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + /////////////////////////////////////////////////////////////////////////v7+//z+ + /v/8/P7//Pz8//X18f/g4uD/yczN/77Dw/++wcP/v8HF/8DDw//GxcT/y8jH/83My//P0M//0tPT/9fZ + 2v/d39//4+Pk/+rp6v/w8O//9fT0//j49//6+vr//Pz8//7+/f/+/v7//v7+//7+/v/+/v7//v7+///+ + /////v////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////+/v7//v7+//////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////+/v7//P3+//T5+v/r7u7/4+Lg/9DO + zf+4ubn/rLC0/66wtv+wtLb/tLe5/767vP/Cvb3/vry+/7q8wP+5v8H/vcPF/8LHyf/Izcv/0NXP/9nd + 1v/g4uD/6ejq//Hu8P/29PX/+/n5//z6+//8+/v//P39//z9/v/9/v7//v7///7+//////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////7+/v/+/v7//v7+///////+/v7///////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////7//v/8/v3/y87N/2FfWf9RSDz/U0Y4/05FN/9MRzz/VlFI/2di + WP93c2n/hoJ6/5CNh/+cm5j/rKyu/7Cyt/+0t7v/t7q7/7q7u//Av73/x8XC/8vKyP/Q0NH/2Njb/+Hh + 4//p6uz/7vDz//T1+v/6+v3//fz+//79/v/9/v7//v7///7+//////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////7+/v/+/v7//v7+//7+/v////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + /////////v////r7+v+9urT/QzQj/z8nDP9AIgP/PyIC/z0iA/87IQP/OiEC/zkhBf8zIwv/MykX/0M6 + Lf9YUUj/amZf/4mIg/+enpz/r6ys/7m1tv+7uLn/vby7/8G/wP/Cw8b/yMvO/8/T1//a3eL/5ejs/+/x + 9P/29/n/+fn7//z7/f/+/f7//v3+///+//////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////+/v7//v7+//// + ///+/v7//v7+//////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////7/+/r4/8e9 + s/9yVzr/i2Qz/4hZGf+KWRb/hVUX/35SGP92SxH/cUIN/2Q8Cv9XNgj/SysF/z0gAv81IAb/NygS/0I4 + LP9eWVT/enl5/5WYmf+urar/urax/7m7tv+4vbv/vb/C/8bHy//Q0db/2dzg/+Po6v/u8fH/9/f3//z6 + +//+/P7//v7+//7+/v/+/v7///////////////////////////////////////////////////////// + //////////////////////////////////////////////7+/v/+/v7///////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////7//v/7+/n/x7+3/3ZbPv+dbzf/oGUY/6Rl + Ff+hZRj/mmMd/5hjH/+aYx3/l2Eb/5NfGf+OWhj/glMW/3BHEP9cNwn/RCgF/zIgA/8xJAv/QTgk/2BZ + TP+Hgnn/p6Oc/7W0sP+2t7f/ubu7/77AwP/Iycr/09LT/93d3f/p6ur/8vL0//n4+v/8+/3//f3+//7+ + /v///v////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + /////////////////////////v7+//f5+v++vLz/b1hE/5lsOP+dYhb/o2QT/6FkFf+cYxr/mWIc/5lk + HP+ZZBv/mmQa/5tkGv+cZhv/mGUc/5JfHP+IVxz/dksV/2I6CP9KKQP/Lx0G/yskFf9KRDj/eHNr/5+c + l/+zs67/uLq2/7u7uf/CwMD/zcnL/9fV2P/h4eP/7O3u//b19//7+vz//fz+//7+///+/v7//v7+//7/ + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + /////v//+Pn7/728u/9uWEP/mWw6/55iGP+iYxX/oWQY/5xjHf+XYiD/l2Mg/5ZjHf+WZRr/mWQW/6Bj + FP+iZBX/oWUW/6FkGv+cYyD/ll8h/4pWHv9xSBj/UzUL/zgjAv8vIQz/SD4u/3VsZP+bmJb/sLK0/7W5 + u/+7vL3/x8PB/8/NzP/Y2tv/5ujp//Hy9P/6+fv//fz+//39/v/8/v7//v7///////////////////// + //////////////////////////////////////////////////////////////////////////////// + ///+/v7///////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////7+///6+vr/w764/3BZ + P/+abTj/nGMX/6JkE/+eYxX/mmMb/5hiHf+XYh3/mGIc/5piGf+cYxj/nWMY/55jGP+eYhj/nWIX/5ti + GP+bYxr/nGQc/5tkHP+PYBn/elMV/108DP9AJgP/NR8L/0g5L/95cW//n6Kk/7G1tf+9urn/wMC9/8TH + x//R0tf/4OLk/+zv8f/29vn//Pv8//39/v/+/v7//v7+//////////////////////////////////// + /////////////////////////////////////////////////////////v7+//7+/v////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + /////////////////////////////////////////v////r6+f/Hv7b/cls9/5duNf+YZBj/nGMS/5xk + Ev+cZBX/nGQV/51kFP+eZBf/nmIc/5pgHP+XYRz/lGEg/5RhIf+WYh7/l2Ma/5hjFf+dYxT/o2QW/6Jl + Fv+aZRj/kWIc/4FUGP9jOwz/QyMD/zciEP9ORjz/fX96/6Kqqf+1t7j/v7q9/8W/wv/Nzc3/2N7d/+fr + 7f/29Pb//fr7//79/f/+/v7////////////+/v7//v7+//7+/v////////////////////////////// + ///////////////////////////////////+/v7//v7+//////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////7//fr5/8m8tv90W0T/nXdK/5xsMP+fayv/nWkn/51nJP+fZSH/oWYc/6Bl + F/+dZRX/m2QX/5tjG/+YYR3/mGEf/5hhIP+ZYh7/m2Ma/51iGf+eYhn/n2QW/55lE/+fZhT/nmUX/5Vg + Gf9/UBb/XTgM/z8iA/83KRj/WVlS/5OSj/+2sq//vLq3/76+vv/EyMn/0tjY/+bn6P/18/T/+/r6//39 + /f/+/v7//v7+//7+/v/+/v7//v7+//////////////////////////////////////////////////// + /////////v7+//7+/v/+/v7///////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////7+/v/+/v7//v7+//7+/v/+/v7//v7+//7+/v/+/v7//v7+//7+ + /v/6+fn/xL2//3dmYP+pjnj/qYlo/6uJZ/+siWf/qoZh/6d/WP+ne07/o3c//51yMP+Zayj/mWUi/5xk + HP+eYxf/n2MX/55iGP+fYhn/nGIb/5dhH/+XYR//m2Ma/5xkFf+dZBP/mmQY/5ZiHv+NXR3/eEwT/1Iw + CP80IAf/Rzwq/357b/+lqaT/tLm3/7m8v//Dxcn/0tXX/+Ll5v/v8PH/+Pf5//z8/f/9/f3//v7+//// + /////////////////////////////////////////////////////////v7+//7+/v/+/v7//v7+//7+ + /v////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////+/v7//v7+//7+ + /v/+/v7//v7+//79/v/+/v7//v7+//79/v/+/v7//v7+//39/f/8/P3//P39//f7/P/L0dX/gICC/46G + gP+QhXr/joV6/46Ffv+SiH7/lop8/6CQff+pk3r/rZBx/6yLZv+phFf/pHlD/6FxMf+daSL/nGYa/51k + Fv+aYxb/lmIb/5ZhHf+bYxr/nGMY/51jGP+bZBn/mWQb/5hjHf+XYx7/h1ga/2M9Df8+JAP/OCsW/2Fh + U/+anJj/trS5/7q5v//Aw8X/ztHS/+Dg4//v7vD/+Pj5//38/f/+/v7///////////////////////// + ///////////////////////////////////+/v7//v7+//7+/v/+/v7//v7+//////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////7+/v/+/v7//v7+//7+/v/+/v7//v3+//38 + /v/9/P7//fz+//z7/f/6+fv/+fj6//j3+f/4+Pr/9vn7/+zz9f/Y3t//09XT/9TT0v/Jy8v/wMTF/77B + wf+wsa//lpOQ/42Ff/+Shn//mIl//6KRgf+plHz/sJV0/6uIWv+iekH/nG4s/5lnHf+aZBj/nWMY/51k + GP+dZBn/m2IY/5tkGP+aZBn/mGMa/5pjHP+aYx7/kV8c/3dNFP9OLgj/NiIO/1ZQQ/+PkYz/r7K1/7e6 + uv/BwsD/0NDQ/+Hg4v/w7/H/+fj5//39/f/+/v/////////////+/v7//v7+//////////////////// + ///////////////////+/v7//v7+//7+/v////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + ///////////////////+/v7//v7+//7+/v///////v7+//7+/v/9/f3/+/v9//n5+v/29ff/8/L0/+7u + 8P/q6uz/6Ofp/+jn6f/v7O7/9/X1//z8/P/9/v7//v7+//3+/v/7/f3/+Pj5/+7t7//k4uX/397f/9DQ + z/+xsrL/nJyd/4+Ni/+OioL/m46B/6uVfv+tj27/pYBS/59wMv+eZiD/nmIb/51iGP+dZBn/nWQY/5pk + F/+aZBn/mmMb/5tkGf+dZRn/mWMc/4VUGv9bOA3/NyMG/0VBL/+EiX//rrCs/725uf/DwcL/0M/R/+Lh + 4//w7/H/+fj6//79/v/+/v7///////7+/v/+/v7///////////////////////////////////////// + ///+/v7//v7+//////////////////////////////////////////////////////////////////// + /////////////////////////////////////////////////////////////////v////7///////// + //////////////7+/v/+/v7//v///////v/+/v7//v7+//////////////////7////+//////7///7+ + /v/9/f3//f39//79/v/9/Pz/+vn5//X29v/v8fL/6evs/+Tm5//e4OH/2dvc/9XX1//R09T/0dPU/9zc + 3P/v6er/+vb3//z8/v/9+/7//fz8//j39//t6ur/4d3e/9zX2P/c2tj/3uDd/+Ll5v/f4+b/0dbZ/7m9 + wP+hnqL/k4uJ/5SHgf+mk4b/tJZ3/6qDVv+fbzv/nGUn/51jGv+dZBX/m2UV/5pkF/+aYxv/m2MZ/51j + F/+cYxr/mGQd/4hbG/9jQA7/OyUD/0A4Jv9+e3b/rqyw/7q5vf/CwcP/0dDS/+Lh4//x8PL/+vn6//39 + /f/+/v7//v7+//7+/v///v7////+///+/////v7////+//////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////+/////v///////v/+//7//v/+/v7//v7+//3+ + /v/9/v7//v7+//7+/v/9/v7//v////7//v/+//7//v/+//3+/v/+/v7//v3+//z8/f/6+vv/9/b5//Px + 8v/s6+v/4+Tl/9vd3f/T1tf/y9HQ/8bJyv/Cxcb/wcLB/77AwP/Aw8T/y8/Q/93i4v/w9PT/9/v8//n8 + /v/4/Pz/8PTz/97i4f/Kzs7/wcTE/8PCxP/HxMj/ysjL/9LQ0f/c2tn/5OPh/+Tk4v/V1tP/sLCx/4+P + jf+PiID/pZSD/7GTdv+rgFP/oG4u/51mGf+bZRT/mmQV/5pjGP+dYhv/oGIc/51kHP+ZZRj/lmYZ/41g + G/9vRxH/PyME/zsvJf9zd3f/qK2w/7m5vP/DwcL/09DS/+Ti5v/x8fP/+fn6//7+/v/+/v7//v7+///+ + /v////7//v7+//7+/v////7///////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + /////////////////////v////7//////v/+//7//v/9//3+/f/9/v7//P7+//v9/v/7/f3//f////3+ + /v/8/v7/+/7+//n+/f/7//7//f7+//78/P/6+vz/9PT6/+zs9P/l5+v/3N7f/9PW1v/Ky83/wMC//7e5 + tv+mr63/kZmb/4yRkP+Ojoj/kI+K/6OmqP/Bxsz/2t3d//Tx8v/8+vz/8vT1/9bX0/+9vrT/rbGu/6is + r/+sr7P/r7Gx/7S4tP+4vLv/vL2//8LBw//Hxsf/zc7O/9fa2f/c4eT/09jc/7i6u/+Ylpb/j4iI/6CP + h/+tjnP/rHxJ/6RrJv+dYxj/lWIZ/5VkG/+aZBv/mWIc/5hiHP+aYxv/nGQb/5ZhGP91Sw//RCkG/zww + Hv9vcW//pKmr/7q7t//Gw8H/09LS/+Pj5//y8vT//Pz7//79/f/+/v7//v7+///////+/v7//v7+//// + /////////v7+//7+/v////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////+ + /////v/////+//7//v/9//3//f/9//z+/v/8/v7//P7+//3//v///v7//v7+//z+/v/8/v7/+f79//r+ + /f/8/fz/+Pf4//Dw8v/l5uv/29zi/87S1P/AxMP/sbSx/6Ghnf+Gf3r/cGhf/2FcUf9EPTD/PDIg/z4w + Gv88MCD/ZWFf/7m8wP/c3+D/8/Hy//36/P/X2Nj/cGlg/0g7Jf9GPi3/W1NG/3FoX/93cmn/i4yC/5+h + nv+qrK7/tLW4/7u6u/+/vr//w8LD/8nKy//V2Nf/4OTg/9fa2P+ztLf/lI+S/5iJhP+xlXz/solb/6Vw + Nf+dYyH/m2Ma/5xlGP+aYxr/mGEa/5piGv+cYxj/nGUY/5FgG/9vShX/QikH/zgvIf90c27/ra2o/7u8 + uf/DxcX/1NXY/+fn6f/29fX//Pv7//3+/f/+/v7///7////+/v///v7///7////////+/v7//v7+//// + //////////////////////////////////////////////////////////////////////////////// + /////////////////////////////////////////////////////////////////////////v7+//3+ + /f/8/v3//f/+//z//v/8//7//P79///+/f///vz//v79//z9/f/7/P7/9vn7//L09v/n6ur/3eDh/8/R + 0f+6vLr/nqGb/4CAdf9iXlD/S0I0/zwsGv81IAX/QCgF/0stBv9VMwf/UzIG/zUeAv88NC3/qKqp/+Hi + 5f/w8fX//Pv8/8jFw/9UQzD/VjUP/0wtB/9JKQX/QiUD/zolC/9CNSL/VEs+/2toYv+Iioj/o6Oh/7Sx + sP+9uLj/wby8/8TCwP/JzMf/1tjT/+Pi4f/W1NT/p6Wm/5CIhv+kk4L/tJFt/614Q/+jZiL/nmIX/51j + GP+cYxf/nGMX/5xjGP+aYhr/lmIf/41gIf9xSxL/QygD/0EyIf9/eXT/rK+v/7m8vP/Gx8b/2drb/+vs + 7//3+Pn//f39//7+/v/+/f///v7+///+/v///v////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////7////+///+///+/v7//P7+//z+/v/8/v7//f/9//z+ + /P/+/v3///79/////P/+/vz//Pv9//r3/P/w7vT/4uXo/87U0/+2urn/lJeS/2lnXv9KQzD/OSsM/z4o + BP9JLQn/Xz0Q/3NJE/+AURX/i1kZ/5JeHf+EVhr/Sy8M/zgxK/+kpab/5OLm/+7x9f/6+/3/zcnF/3hf + Qv+XZjD/jFog/4VUFv95TRH/Z0EN/1IxCf9BJQX/NCMK/zkxIP9YUkb/f3tw/6Cdl/+yrq7/ure6/7q8 + wP/AwsP/0M3K/9/d2//d4eP/uL3E/5WWmP+cj4L/sJR0/66CT/+gaij/m2Ib/51iFv+fYhf/oGMZ/51j + Gf+ZYxv/mGQc/5RhGP9zSQ7/QSUE/z80Kf9+fX7/sLGx/72/vf/JzM3/29/k/+/w8//6+vv//f3+//79 + ///+/v7///7+///+//////////////////////////////7+/v////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + /////////////////v////7///7///7+///8/v///P7+//z+/v/+//z//v77//7+/f/9/v7//f7+//z9 + /f/6+fz/9vP4/+bh5f/GxMX/mZqW/2lmXf9AOif/NSYL/0ktCP9lPg3/e04V/4hZGf+UYRr/nGQa/6Bi + Gv+hYxr/omQd/41bHP9OMg7/NjIt/6Okqv/m4ef/7vL2//b7/v/MysX/gGND/6hvMv+gZB//nGQb/5lk + Gv+WYxn/j10Y/35SFv9mQQ//TTAI/zsmBP86KxL/Ukc8/3hycf+bmZ7/ra66/7i2v//Dvrz/y8jC/9TW + 1P/g6Or/z9nc/5yfnv+KhXz/qJR6/66GV/+cazD/mmIe/6FiGP+jYxf/n2MZ/5xjGf+cYxn/nmUZ/5Jf + G/9pQxH/NiEH/0lAN/+RkY7/tbi4/73Bwv/Q0dP/5eXp//Tz9//8+v3//fz+//7+/////v////////// + //////////////7+/v/+/v7//v7+//////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////7////+ + ///+/////v////3////9//7//v/+//7+/f/+/v3//f7+//j8/v/3/P7/+Pr8//f4+//k5ef/trOw/3Ns + Yv9JOiT/PygH/1M0Cv9sRhT/iFcd/5heH/+dYR3/m2QX/51lFP+eZRf/nmIZ/59iGf+gYhz/i1oa/04y + DP84Myz/paWo/+ji5//t8fX/8/r+/8nKxf9+Y0P/qHAx/6FjHv+dYhn/mmMY/51kGP+gZRn/nWQa/5Rh + Gf+JWxb/d04Q/1o3Cf8/JAf/NyYW/09FQv95dnz/oqCm/7i1t/+8vbr/w8bC/9TZ1v/p7e3/4eXm/6qu + sP+Ri4X/qpJ7/6yHYf+abDb/m2Ic/6JjFv+gYxf/nWIZ/5xjGv+cYxn/mmQd/4xcHf9hPQ7/OCQK/1lT + S/+cnZz/ubq5/8jGwv/Z2Nn/6unv//f2+v/9/P3//v3+///+/v////7////////////+/v7//v7+//7+ + /v/+/v7///////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////+/v7//v7+//7////9/////P7+//3+ + /v/+//3//v78//79/f/8/P3/9/r+//f7/v/49/r/4d/e/5ydl/9PSDv/NyQK/1MxCP92Sw3/kVwX/5ti + HP+gZB7/n2Ee/51hHP+aZBf/nGMY/5tjGv+ZYh7/mGId/51jHf+PWxj/VTQJ/z41Kv+op6T/5uLm/+zw + 9f/0+/7/ycrG/3xiRv+ibjL/nGIf/5xiG/+ZYhv/mmIc/51hG/+dYxj/nWUX/55mFv+aZRf/jV4Y/3hO + Ff9XNgv/OyMI/zgqGv9fWU7/l5SO/7S1tP/Dxsf/1NfX/+no6P/39vb/8vH0/7+6vP+WjYX/pJF+/6eH + Y/+abDb/mmEe/55iFv+fZBj/nGMb/5hiHP+YYh3/mWIe/4hZGv9WNgv/NCQS/2lkXv+sqqb/wL64/8vK + yf/c3OP/7+7z//r6+v/+/f7///7+/////v///v////7///7+/v/+/v7//v7+//7+/v////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////7//v/9/v7///7///7+/v/8/v7//P7+//7//f/+/vv//P3+//j8 + /v/4+/7/9PP0/8/Kxf+EeWz/QTIb/0QtC/9sSRT/jVsc/5xkGf+jZBX/o2QX/55jF/+bYhr/m2Ec/5pi + HP+aYhv/mWMc/5ZiH/+ZYR7/nmMb/5BcF/9XNAn/PjMq/6mno//l4+T/7fH0//b7/v/Mycf/fGFI/59v + M/+aYx//nmIb/5tiHP+ZYh3/mGId/5pjGv+eYxn/oGMW/6BlFf+fZBb/mWQb/45eG/92ThL/VDYI/z0o + C/9LQC3/gX52/76/v//g4uL/8fDw//v3+P/++/z/9vT1/8vJyf+clpD/oI18/6eIZf+bbjf/mmIc/55j + GP+cYhr/mGId/5pjHP+dYxv/m2Qb/4FVFf9LLgj/PzEg/396df+1tbL/wsG//9HQ1P/l5en/9vX3//78 + /f/+/v3//v7+//7+/v///v7///////7+/v/+/v7//v7+//////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + /////////v/+//3+/v/+/v///v7+//z+/v/8/v7//v7+//7+/P/8/Pz/9vr9//b4+v/Y1tL/dWpb/1E9 + Iv9pRRP/hFgY/5NiG/+bZBv/nWQZ/55iGP+cYxr/mmQa/5lkGf+bYxn/nWMb/5xjGv+bYxr/mGIa/5tj + Gf+fZRf/jlwV/1EzCf83MSz/oqam/+Pk4f/v8fP/+vr+/87Jx/97YUb/n3Ex/5plHv+eYhr/nWIb/5xi + Gv+bYxr/mmIc/5phHf+dYhz/n2MY/55jFv+bYxf/mmUZ/5dkGP+HWRX/aUIO/0UqB/9BMSH/fnd0/9XW + 1f/2+Pn/+vv8//v8/f/6/Pz/9fn6/83Oz/+blI7/oY55/6uJX/+fbS7/nWIY/55iGP+aZBv/mmMZ/51i + F/+eZBj/lmMc/3NMEv8+JwX/SUI3/5eYmf+6urv/ycbF/9za3P/u7fD/+/n7//z9/f/8/v7//v7+//// + /v///////v7+//7+/v/+/v7///////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////7//v7+//7+ + ///9//7//f7+//7+/v/+/v7//fz7//f29v/x8vP/7u3u/8jBvP9mWU7/h3Jb/62FUf+odTb/nGck/5ph + GP+bYhn/mGIb/5djG/+XZBn/lmcW/5dlFv+bZBr/nmMa/55iGv+cYxr/nGMX/51lFv+LXBb/TTIK/zQy + Lv+gpqr/5OTi//Hw8f/6+f3/zMnG/3thRv+jcS//nGUc/5xiHP+fYhr/oWMV/6BlFP+bYxj/mWEb/5ph + Hf+bYxz/mmMa/5ljGP+ZZBf/m2UW/5tmGv+VYiL/e1Ei/0krE/9RQDn/wr+9//v+/v/4/f3/9/v5//X2 + 9v/z9vf/8/X2/8bFxP+UjYT/oo10/66GVf+gaiP/nWMX/5liGv+aYhn/nmEY/51iGP+cZBv/kF4a/2E9 + Df8zJRH/aGVl/6eprP+/v77/0s/P/+fl5f/29PX/+/v8//z9/v/9/v7//v7//////////////v7+//7+ + /v////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////+/v/+/v3//f7+//7+/v/+/v3//f79//38 + /f/39vX/6uzq/+Dh3v/d3Nn/1NDO/52bmv+OiYb/pJCG/7OTfP+qf1j/pXA4/6JnIf+cZBj/mGQY/5dk + GP+VZRb/l2QY/5hjGv+aYhv/nGEb/5tiHP+bYhr/nGQa/4tbGf9PMQv/OTQu/6aprP/r5eb/8/Lw//X5 + +//HyMb/fGBG/6luLv+eZBv/mWIc/5xiGf+eYxf/nWQX/51kGf+cYhn/nGIY/5tiGP+aYhr/mWIa/5pk + HP+daSL/nm0s/5tuNv+NaDz/dFk9/4h5bv/Z19b/+fz8//b4+P/08/D/7uvr/+bk6v/r6ej/6+rn/7W3 + uf+MhoT/pI1y/6p/Qv+dZx7/mGEf/5lhH/+dYRv/nWEb/5xjGv+bYxv/hFUX/08wCf9GNiT/hoeD/7G4 + uv/Hx8f/3dra/+vs7//2+fv/+f39//v9/v/+/v7//v7+//7+/v/+/v7//v7+//////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////7+///+/f/+/v7//v7+//z+/f/4/Pz/9/r7/+3u7v/Y3N3/ycvP/8DF + x//JzMv/0NDQ/7m1sv+OjIn/l5GF/6aUff+tj27/qYJT/6F1P/+baS//m2Qh/59iGP+fYRX/mmQT/5xl + Ev+eYxL/nmMU/59jF/+gZBn/j1sZ/1QxC/8+NTD/rrG1/+3s8P/z9fP/9Pv8/8TLxf97ZET/p3As/5tm + GP+YYxr/mWQX/5hjGv+WYh7/mWId/5xhGf+cYxb/nWQY/51mH/+bain/m24y/5xwPf+Ub0j/hmpP/4d3 + Zf+oopn/2drX//T5+v/x9PX/6uvu/+Lh5v/X1d3/0M/U/9XU0f/k493/5eXm/66tsP+RhHn/qo5l/6V2 + Ov+dYiH/nWIb/5xjGf+aYxn/mmMZ/5pjGv+TYBz/b0gT/zwkCP9bVEz/n6Kl/77Awf/Pz8//4OPo//Dz + 9//5/Pz//P7+//3+/v/+/v7//v7+//7+/v/+/v7///////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + ///+/////v////7+///9/v7/9/z+//P6/f/o6un/xMG+/7Cwrv+xtLb/tLrA/7q8wP/Hxcj/1dHN/8PJ + x/+lqqf/kY6G/5OLfP+gkXn/qZB0/6uIZP+nekv/qW85/6VoKf+baB3/m2QW/5xhEv+dYhX/n2IX/6Bj + Gf+PWhj/VDAK/0U5M/+8vsD/8/f4//T4+P/2+/3/yMvE/31jQf+mbi7/m2Qa/5phGv+bZBb/mmUa/5dj + H/+aZB7/nmUg/55pJP+cbS7/mXE7/5RzRv+Pc03/jHNX/4t6av+fl5D/ysnI/+zw8v/x9vn/6+/y/+Tm + 5v/U19j/w8fL/7q9xf+6vcH/v8PB/8/Rzf/l5eX/3d3i/6Cdn/+Th3b/qohf/6ZtLv+eYxf/nGQW/5tk + F/+aZBn/mWMZ/5hjHP+JWhz/VDEM/z0pHP+De3r/tre4/8THx//X293/6+/x//j5+v/9/f3//v7+//7+ + /v/+/v7//v7+//7+/v////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////7//v/8/v7//P7+//z8 + /v/1+f7/5+7w/6yoof9dTkH/WEs+/3lya/+goaX/sLK3/7e6uv+/wL3/x8nI/83Pzf/Dw8T/qKin/5CO + if+Si4P/npCA/6uTev+wjm//qoVc/6V+Tf+jdD7/oW4z/51pLf+bZij/nGck/4xcHf9SMgr/Sj43/8rJ + yP/7/v3/+fz8//r8///LysX/fmJF/6NtOP+ZYyb/mmMn/59nJP+hayf/oG0s/6FwNf+fcj3/mnRH/5N2 + Uv+LdFn/iXZj/5KFdv+upp3/zMzK/+bp6v/09vb/7O3w/+Lk6P/Z2d3/xcTF/5+fmv99fXb/gX97/6Kh + n/+1ubj/wMTC/9LT1f/l5+7/yc3X/4mKiv+bh3D/r4BN/6BnH/+aZBX/mmQW/5lkF/+aYxj/mWMa/5Zi + HP91SxT/PyIH/1xPRv+hoaD/vcHB/87R0v/i5uj/9PX2//z9/P/+/v7//v7+//7+/v/9/v7//f7+//// + //////////////////////////////////////////////////////////////////////////////7+ + /v/9/v7////+//7////+/////v7+//7+/v/+/v7//f7+//r+/f/7/f7/+/z+//H1+P+4t7X/VEQw/0Yn + CP9GJwb/QCgP/1RMQ/99fXv/oaSk/7a2tf/Au7v/xb/A/8nHyf/OzdT/xcnN/7W4u/+dnp7/l5OO/5GO + hP+Si3//n4t8/6WJdP+nh2v/pIJj/6F9V/+kfU7/l3NB/1tBIP9ORjz/0NHM///+/f/+/P3//fz+/87I + x/+BaVb/rIBe/592Tv+eckv/oXVM/594Tf+aeFD/l3hY/5B5YP+KfGv/kYmA/6OdmP+/u7n/393a//Hx + 7//w8fP/6erp/+Xj3//c2dX/yMfE/6Ghnv9zb2j/Sz8u/z4nDv9BKRX/Zl5W/56lov+1vb3/xMbH/9rZ + 3f/o6vH/s7i7/42Ee/+nhWf/qHc8/5xlGf+bZBf/mmQY/5ljGv+cZBn/nGQX/45eF/9aOAr/OysX/3l4 + c/+0tbX/x8fK/9rc3//x8fH//fv6///+/f///v///v3+//z9/v/8/v7///////////////////////// + /////////////////////////////////////////////////////////v7+//3+/v////7//v////3+ + /v/9/v7//v7+//7+/v/8/f3/+/39//z8/f/5+/r/1NTP/29iUP9SNQ7/flMa/35QFP9gOQn/PSQI/zww + I/9fWlL/joyG/6uop/+4trj/u7m+/7u9w//Bxcj/y83Q/83P0f/DxMb/sbe4/56kpf+Zl5j/mY+M/5WI + f/+ajX//m4l3/56Hbv+WgGL/bF1I/3JuZ//e4eL//f7+//z9/v/7/P3/1NHR/4l9dP+giHf/l4Jt/5R8 + af+XgGz/j4Bx/42Eev+clIz/qKKf/7u4uP/T1Nb/5ebo/+7u8P/q6u3/4uLl/9va3P/T09P/xMXE/6ms + qf9+gXn/UEs8/0AuFf9RMwr/az4M/1kuBf9BLRv/bnFq/6Wvr/+8v7//0szL/+fk5f/h5ef/n56e/5F/ + df+qglz/oWwr/5tjGP+dYhn/m2Ib/5xkGP+cZRX/mWUW/3ZOEv87JQb/UkxE/6Cfnf/Dw8P/0tTW/+jq + 6v/3+Pj//f39//7+/v/+/f7//f3+//3+/v////////////////////////////////////////////// + /////////////////////////////////////////////////////////v7+//7+/v/+/v7//v7+//39 + /f/9/v7//vz8/+vn5f+LgG//VDgP/3lSHP+VZB3/nGQZ/49cFv9wRhL/Sy4L/zgjCv9HOSn/ZWBZ/4aG + g/+io6D/r7Gx/7q6uv+/vb3/xsLB/8zKyP/Qzs7/ztDS/8fQ0//AxMP/tLKx/7Gxrv+rqKT/n5aR/5eM + gf+Wjof/vLu//+/z+//4+/3/+P79//n9/f/p7Oz/s7Ow/5qUjv+bmZL/qaWf/7e0sP+7vLr/xcjJ/93e + 4f/o5+n/6+nq/+fn6P/d4OP/1tne/83S2f/Cx83/t7m5/6Chn/95e3v/VFJN/z4yIP9KLw3/a0MR/4dZ + Gf+UYRr/fk4R/0gpBf9BNyj/gYWA/7W3tf/LxMH/3tfT/+7w7v/Mz9D/jIWG/5p/a/+meUf/m2Mf/59i + Gf+cYxr/mGMa/5pkF/+dZRb/jF4Y/1Q1Cv86Kx3/hH95/7y5t//MzM7/4OLk//Dz9f/6+/z//v7+//7+ + /v/+/v7//v7+//////////////////////////////////////////////////////////////////// + /////////////////////////////////////v7//v7+//7+/v/+/v7//v7+//3+/f/29vT/saup/1A7 + H/92SxD/kGAf/5tjGv+fZBX/nWQZ/5ZfHv+BVRv/ZUIQ/0wtCP88Jwv/QTYi/15YS/99enH/nJmV/7Gu + q/+7trT/v7y4/8K/vf/CwsP/wcfK/8rOzf/R0tL/0dXW/9DV2f/Oz9H/0czJ/9jT0P/i4+b/6evz//Lz + 9v/1+/r/+fz8//n9+//w9fP/4uXl/9/k5v/i5ef/4uXq/+Ll5//h4uP/3t7f/9nY2//U1dX/z8/P/8bI + yP+9vsD/qqyv/42Oj/9xbmX/Uks7/z4wHP9EKgz/YDoO/4JRFv+UXhn/mmUa/5pmG/+SXxr/bUMQ/zwl + Cf9ST0P/nZ6b/8S/vf/QzMr/4uXk/+vu7/+sp6j/jnxx/6F/Wv+fay3/nmIX/5tjGv+WYh7/m2Ia/6Bk + Fv+aZBj/dEsQ/zkiCP9iV03/r6il/8jHx//X2t3/6+/y//n7/P/+/v7//v79//7+/v/+/v7///////// + ///////////////////////////////////////////////////////////////////////////////+ + /////v///v7+//3+/v/9/v7//v7+//3+/f/9/v3//Pv6/9ra1v9eVk//Wj0U/5ReGv+WYxz/m2Ib/55l + GP+eYxb/nmQZ/5ljG/+RYRv/g1cV/2xEDf9QMQj/OyYK/zsvHP9NRj7/bmll/4qFgf+em5j/pqam/7Cx + s/+5t7r/wL28/8LAv/+8wcT/vsXL/8XJyf/Pzsf/1NLL/9DT0P/Y297/7Ont//X29//8/Pv/+v76//v9 + /f/4+Pz/6u3y/93d4v/R09j/zM7Q/8zKyf/FxMT/u73A/7K1tf+np6X/l5SP/4J7cf9mXE//Sj0s/0It + E/9JLgn/YT0L/4BSEf+UXxb/nGQX/55lF/+cZBj/mmIa/5xjHf+NWRr/WTcM/zcqF/9vbmr/srKz/8LF + xf/T2dn/7fDu/9vW1f+Wi4T/ln5j/6h5Qv+eZRv/mWMb/5VhIP+bYRz/omMW/6JlFv+MWhn/SCwL/0M1 + J/+YkYr/wMHA/9DT1v/m6e3/9fj6//3+/f/+//3//v7+//7+/v////////////////////////////// + ///////////////////////////////////////////////////+//7//v7+///9/v/+/v7/+/39//v9 + /v/+/v3//f77//z9/v/x8vP/mJeS/1E4F/+EVxr/nWIb/5ljG/+YYRr/m2IZ/51jGP+aYhj/m2QX/5tl + GP+ZZBr/lWIb/4dXGf9xShX/VjcM/0EpCf88KBL/RjUm/1VHPv9mXVT/e3Zx/42Ihf+gnJf/q6el/6Sp + rP+psbf/trm5/769tv+/v7n/vcLC/8jN0f/k4eT/9fPz//z6+//6/Pv//Pz9//Ty9//c3+j/x8jP/7W2 + uP+prq3/oqal/5SVlf+AgX7/cW1m/15TR/9QPy7/STAV/0ksCP9XNgr/b0UP/4RUFv+TXxj/nGQU/59k + E/+cZBT/m2QY/5xjG/+bYhv/m2Mc/5ZjHv98UhT/RisH/0c/Nv+PkZL/u7+//8rOzv/h5OX/8vDx/7Ku + qv+QgHD/p31X/6NqLv+ZYRr/lmIZ/5piGP+gYRn/oWMY/5ZjGf9nQA7/PCYO/3Vvaf+0tLT/zc7P/+Lj + 5//z9Pf//P39//7//f/+/v3//v7+//////////////////////////////////////////////////// + //////////////////////////////7//v/9/v7///3+//7+/v/7/v3/+/3+//39/P/9/fr/+fv7/9PU + 2P9WTkP/d0gN/51jF/+aZBr/m2IZ/5tjGf+aYhn/mmMY/5pjGv+aYhr/m2MZ/5tjGv+bYxr/nGQa/5lj + G/+PXRn/f1IU/21ED/9YNQr/SCkI/0QpCf9ALBT/Qjco/1dNPv9iWU//YmBb/3V1dP+LiIP/lY+G/5iX + kf+qsbP/vsbN/9ze4P/x8fH/+/r7//T3+P/e3dv/wLy4/6aoqf+OjYz/cm9m/19dU/9WVEz/SkI5/z8y + H/9AKw//SCsH/1UxCf9oPw7/e08V/4pbGv+YYRr/nmQZ/51jG/+cYhn/m2IZ/5ljGf+aYxr/m2Ma/5tk + GP+YYxr/lWQd/5NhGf9pQAz/NyUT/2VjYf+tsK//xcjG/9ja2//y8fP/1tjV/5SMgv+deWP/qHFE/5lh + G/+ZZBP/m2QX/55hHv+dYhz/mWYV/4RTEP9DJgX/UEpD/6KhoP/Mycj/3t3g//Dw9f/7/Pz//v/9//3+ + /v/9/v7///////////////////////////////////////////////////////////////////////// + /////////v7///7+/v////3//v7///39/v/9/v3//v79//78/P/y8vD/mZqY/1Q5Hf+MWh7/m2Mb/5pk + Gf+bYhr/m2IZ/5hjGf+bYxn/nGEa/5xhGv+cYxr/nGIZ/5xiFv+cYxP/nmQV/5xlGv+ZZBv/lGEa/4tb + G/9+Uxj/ckkR/2E7C/9RMgz/SiwH/0QnBP89Jwr/QjEX/0o5IP9KNyP/T0Q3/4KDff+7wsb/297h//Dy + 8v/8+/v/4eLh/4uDef9aSTT/T0Es/0w6IP9ELw7/QyoD/0grBP9RMAj/XDkL/2pDD/97UBX/iVoZ/5Fg + G/+YYxz/m2Qc/5xiGv+cYhr/m2Ia/5piGv+aYhr/mmMa/5tjGv+bYxn/m2MY/5pkGv+ZYxr/mWUb/4JU + GP9FKQn/Qzsw/5CSjv/AwsD/0tHR/+vo6f/x8fL/qaSg/5N5Z/+neE//nmgm/5xjFv+cYxj/nGId/5ti + HP+bZhf/kF4Y/1MyCv85MCH/jIqE/8PCwP/V19n/6uvx//r7+//9//3//P7+//z+/v////////////// + ///////////////////////////////////////////////////////////////////+/v7//v3+///+ + /f/+/v7//fz+//7++//+/v7//fv7/97a1f9eVkb/e0wc/5djH/+YYxv/m2MY/5xjG/+bYRr/m2MZ/5pi + G/+bYhv/m2IZ/5tjGf+cYxn/nGQX/5xkFv+eZBf/nmQW/5xkFv+eZRb/nWQZ/5lkG/+XYxr/lGAb/41a + HP+HVhX/gFAQ/3NJEP9oQxD/YD4O/1IyDP81IAn/SkU9/62ysf/e4uL/7vHz//j6+//IyMb/W0s2/148 + Ef9eOwz/ZkEN/25ID/96ThD/h1QR/41aFv+SXxj/lWIa/5lkG/+aZBv/nGQZ/55kGP+eZBf/nGMZ/5pj + Gf+aYhn/m2Ia/5tiGv+bYhr/m2IZ/5tjGf+cYxn/nGQZ/5tkFv+bZRj/lGAc/2lAD/87JxD/Z2Vg/7O1 + tP/OzMr/4t/f//X19v/Mysn/kIJ1/5t4Vv+lcDX/n2IW/51kF/+ZYxz/mGMc/5tjGf+YYxv/aUIP/zQm + DP9xbWT/tba0/87S1f/l5+z/+fn4//3+/P/9/v7//f7+//////////////////////////////////// + /////////////////////////////////////////////////v///v7//v7+//7+/v/+/P7//v76//3+ + /f/29vX/sqqj/1M8HP+YXx7/mWMb/5hiG/+dYxn/m2Ma/5piGv+cYxn/nGMb/5pjGv+bYhn/nGMZ/5tj + Gv+ZYxr/mWMb/5piHP+aYhn/m2IX/51jF/+dYxj/mmMY/5tkGv+dZBr/nmMZ/6BkF/+fZBj/mmQc/5Nh + Hv+OXx7/gFUb/0otCf85Miv/paek/+Lk4//u8fT/9fv8/8bIxf9yXD//lWcr/5FgHf+TYBn/k2Ic/5lk + Hf+eZRz/nWUb/51lGf+cZBn/nWMZ/5xiGv+bYhn/nGMZ/5xjGf+bYxn/m2Ma/5tjGv+bYxr/m2IZ/5ti + Gf+aYhr/m2MZ/5xkGf+bZBj/nGQX/5xkGf+dZRr/hlMS/0UqB/9GQzv/nJ+d/8nHw//c2Nj/7u/y/+bq + 6/+bl5D/j3Zd/6Z0Qf+jYxv/n2MW/5djG/+XYxz/nWIa/55kGv98UBT/PSYI/1hQRv+lp6X/ys/T/+Dj + 5//29vX//f37//7+/f/+/v3///////////////////////////////////////////////////////// + /////////////////////////v////7//v/+/v7//v7+//z9/v/+/vz//f38/+rq6P92bWL/cUkX/51l + Gf+aZBn/mWEa/5xjG/+bYxj/nGIa/5xiGf+bYhn/m2Ia/5xiGf+cYxn/mmMa/5liHP+XYh7/l2Id/5li + HP+aYhr/m2Ib/5pjG/+YYhv/mWIc/5tjG/+dZBf/oWQV/6FkFf+eZBf/m2QZ/5tlGv+NXBr/UjML/zwz + Kv+op6P/5eTj/+3x9f/2+v7/ysrG/35jRP+lcTD/nWUc/51jF/+aZBr/m2Mb/51jG/+bYhz/nGIb/5xi + HP+dYhv/m2Eb/5lhG/+ZYRz/mmIb/5tjGv+dYxv/nGMb/5tjGv+aYxj/mmMZ/5pjGv+aYxr/mmMZ/5pj + Gf+bZBn/mmMZ/55kGP+YXxb/XTkM/zYuH/+AgoD/v7+8/9LT0//m6e3/8fX3/66xrv+Ke2j/onRJ/6dn + Jf+gYhf/lmQb/5ZjHP+dYhv/n2QY/4tbFf9NLQf/ST4w/5ial//Gy87/3N7j//Lz9f/8/Pz//f79//z+ + /f////////////////////////////////////////////////////////////////////////////// + ///+/////f/+//7//v/+//7/+v7+//z8/v/7+vr/zs3H/1dHM/+QWxn/mGYT/5hlGf+YYhr/mmMa/51j + Gf+aYRr/m2Ma/5liGP+cYhr/m2Ia/5tiG/+bYxr/nGMa/5tiGf+aYxj/nGMZ/5xjGf+bYxr/mmMa/5pi + G/+aYhv/mmIb/5liG/+cYxr/nGMY/5tjGP+bYxf/nGQW/45cFv9TMwr/OjIr/6ampP/n5OT/7/D2//j5 + ///Nycf/gGFH/6ZvMv+fYx3/nmIZ/5tiGf+bYhz/mmId/5liHf+aYhz/m2Ec/5tiG/+bYhr/m2Ia/5ti + Gv+bYhr/m2Ma/5tjGv+bYxr/mmMZ/5pjGf+aYxn/m2Qb/5pjGv+aYxr/mmMa/5tjG/+ZYxr/nWQX/55k + F/92SxL/OSYM/2JhXP+vsbD/zM3P/+Di5v/y9/j/xMvJ/4mCdf+ac1D/qWwx/59iGf+WZBn/l2Mb/55j + HP+gZBj/lmEX/2I7Cv9BMRv/hYaA/7/Dxf/a297/8PHy//v8/P/9/v3//P79//////////////////// + /////////////////////////////////////////////////////////////////////v///v7+//3/ + /P/6/v3/+vv+//T08v+lnpH/XEEa/51jHP+XZRT/mWQZ/5ljGf+bYxr/nWIa/5piGv+aYxr/mmMa/5xi + Gf+bYhr/mmIa/5xjGv+fZBf/n2QU/55jFP+fYxX/n2MX/51kGP+dZBj/nWMZ/51iGf+ZYxr/lmEd/5li + Hf+ZYhz/mWMc/5tjGf+cZBb/jlwW/1QyCv85MSz/pKWo/+jk5P/x8PX/+/r9/8/Jxv9+YEj/om41/5ti + If+cYhv/nGIZ/5tiGv+bYhv/m2Ma/5tjGv+bZBn/mmMZ/5tjGP+dZBj/nWMX/5xjF/+bYxj/mmMZ/5pj + Gv+aYxr/m2Ma/5tjGv+bYxr/m2Ma/5tjGv+bYxv/m2Mb/5tiG/+cYxj/nGUY/4dYFv9MLwn/SkQ3/5mc + mv/Jys3/3t7f//D08//f5eb/lI+I/5NzV/+pcj3/nWQd/5dkF/+ZYxj/n2Ib/55iG/+bYxr/dEgN/zgm + B/9wb2f/uLu8/9nY2v/u7fD/+fr8//7+/v/9/v7///////////////////////////////////////// + ///+/////v/////////////////////////////////+///+/v/+/v7//f78//z+/f/5/P7/6Oro/4Bv + Xf93Thb/nGQe/51iGP+cYhr/mWMY/51jGv+cYhn/m2MZ/5pjGv+aYxn/m2MZ/5xjGv+bYxn/nGIa/55j + Gf+eYhf/nmMX/59iGP+dYhn/nWMa/5xkGf+dYxn/nmIa/5xjGv+ZYxr/mWIb/5liG/+ZYxz/m2MZ/51l + Fv+OXBb/VDIK/zkxLv+kpqv/5uXl//Ly8//7/Pv/z8rF/3xiRv+dbTf/l2Ij/5xiGv+eYxf/nmMX/51k + Gf+dZBj/nGQY/5xkGP+cZBj/m2MY/5tjGf+aYhj/m2IY/5tjGf+bYhn/mmIa/5tiGv+cYhr/nGIa/5ti + Gv+cYhr/nGMa/5xjGf+dYxr/nWMa/5xiG/+bZBr/k2AY/2M9C/8+MR3/gIJ//8LExf/d3Nn/7u/u//L2 + +P+loJ//j3Re/6V2RP+cZiD/mWMX/5tkGP+eYhr/m2Ed/55kG/+CUhD/OyYE/2BdVf+ysrD/2dbV/+zq + 7//3+Pz//f3+//7+/v////////////////////////////////////////////3////9/////v////7+ + /v/+/v7//v7+///////+//7//v/9//7+/f/7/v3//vz+//f7/f/a3Nv/ZEo0/5VhIv+YZBz/nWIa/5ti + Gv+YYxn/m2Ia/5pjGP+cYhn/m2Ia/5pjGf+aYxr/nGMb/5xjGv+cYxv/m2Ec/5phHP+bYh3/m2Ic/5ti + HP+aYh3/mWIb/5pjG/+bYhz/nGMa/5xjF/+bYxn/mmMY/5ljGv+dZBn/n2UY/5BbFv9TMQn/OTIu/6Oo + rf/l5uf/8/Ly//v8+//OysX/fWFG/55uNv+XYyL/m2IZ/59jFf+fYxb/nWQZ/51kGP+cYxr/m2Ia/5tj + Gf+bZBr/mWMb/5diG/+YYhv/m2Mb/5xjGv+cYhr/nGIa/5tiGv+bYxr/mmMa/5tjGv+bYxr/nGMZ/51j + Gf+dYhn/m2Ic/5tiHf+aYxn/eEoO/zwmDf9qaGX/uby+/9zc2P/u7u3/9/n8/7i1tP+Ld2X/nXND/59p + JP+bYxj/nGUY/5xjGv+aYhz/nWUa/4tZFf9HKwj/TUY9/6SkoP/X1NH/6uft//b3/P/8/v7//v7+//// + ////////////////////////////////////////+//+//z+/v/9/v7//v7+//39/f/9/f3//v7+//7/ + /v/+/v3//v79//r8/f/++/7/9vn6/8bHxf9lRib/o2ck/59lF/+WZBv/mmId/5pjG/+aYxz/mWMa/5xj + HP+cYhz/nGMc/5pjHP+aYxz/nGMc/5tjHP+aYxz/mWMd/5tiHf+bYxz/mWIc/5liHf+ZYhz/mmIc/5pj + HP+bYxz/nGIc/5xiGv+aYxr/mWMb/55jGf+jYxj/lVoX/1YvCf89MjD/q661/+vs7v/19fP/9/z8/8nK + xv9+YkX/pHAv/51kG/+aYxn/n2MV/55jF/+aYxv/m2Qa/5tkHP+aZBz/mWMb/5pjG/+aYxz/mWQc/5lj + HP+ZYxz/mmMc/5tjHP+bYxv/mmMb/5pjG/+aZBz/mmQc/5tkHP+cYxz/nWIb/5xiG/+bYhz/nGEd/5xk + HP+GVBX/RyQH/2RXUv+3uL7/3uHk/+7w8v/5+/z/0M7M/4l7bv+UbUP/pW0r/5xiGf+dZBj/mmQZ/5lk + F/+aZRr/j10b/1YwCv9DNCf/l5iU/9HT0P/m6Or/9vf7//39/v/+/v7///////////////////////7+ + /v/////////////////8//7//P7+//r+/f/7+/v/+vr6//r6+//8/P3//f3+//3+/f/8/f7//P39//7+ + /P/z9PP/o6OZ/21OJf+naCH/o2US/5VlGP+ZZBn/nGQZ/5pjG/+bYhv/m2Ib/5tjG/+cYxz/mmMb/5pj + HP+bYxz/m2Qb/5pkG/+aYxv/m2Mb/5tkGv+aYxv/m2Mb/5tjGv+cYhv/m2Mb/5ljGv+ZZBr/mmQX/5Zk + F/+VZBj/mmQX/55jFf+RWxT/UzII/z45NP+3vMD/9/b3//r49//2/P3/yMrG/35jRP+nbyr/n2UY/5li + G/+eYhf/nWMY/5tjGv+bYxr/m2Mb/5tjG/+aYxv/mmMb/5tjG/+bZBv/m2Qb/5pjHP+aYxz/mmQc/5tk + G/+aYxv/mmMb/5pjHP+aYxz/m2Qb/5tkGv+bZRj/mWUY/5lkGP+bYxn/mWUa/4hbGP9QLQn/Xk9B/7W5 + uf/m6/D/8vT3//r8/P/a2Nj/ioB4/5BsR/+mbzD/nGIa/5xjGf+aZBn/mmQV/5hkGv+SXx7/YjgL/0Ew + Hv+PkY7/zdLO/+To6P/29/r//fz+///+/v///////v7+/////////////v7+//////////////////// + /v/8/f7/9/v9//L19//v8PH/7/Dy//b29//6+vv/+/z+//v9/v/+/v3///76/+/v7v9+fm3/cFMp/6No + Iv+eYxL/lGUX/5dlF/+cZBf/m2MY/5xjF/+bYxf/m2MX/5tjF/+bYxf/nGQY/5xkGP+cZBj/m2MX/5tj + F/+bYxf/m2MX/5tjGP+cYxj/m2MY/5xjGP+cYxj/m2MX/5llFf+ZZRX/lWUV/5RkGP+WYxn/mWMX/4ta + Ff9QMwf/QT83/8PJyP/+/fz/+/v6//b8///Kycb/fWFG/6JuMf+ZYh3/lWAg/5liHP+bYxj/nGMX/5xj + F/+bYxf/m2MX/5xjF/+bYxf/nGQY/5xkGP+cZBj/m2MX/5tjF/+cZBj/nGQY/5xkGP+bYxf/m2MX/5xk + F/+cZBf/m2UX/5plF/+YZRb/l2UW/5hkF/+WZRj/iV8Z/1Q1C/9OQSv/srSs//X29//5+fr/+/39/+bm + 5v+VjYj/jWxK/6NuMP+bYhv/nGMZ/5tkGP+bYxX/mmMa/5ZiHv9pPw3/PSwW/4OFgf/Lzsr/5efo//X2 + +f/9/P3//v7+///////+/v7///////7+/v///////////////////////v7+//79/v/09vn/5Orv/9ng + 5P/b4OD/6+vp//b18//5+v7/+/z+//79/f/+/fr/7e3s/3NxZf+CaUn/rHtG/6V0N/+fdjz/oXY8/6h0 + O/+mdDr/pnU4/6d1Of+ndTn/qHY5/6h2Of+ndTj/p3U4/6d1OP+odjn/qHY5/6d1OP+mdTj/p3Q6/6d0 + Of+mdTn/pnU4/6Z1Of+odTn/qHU4/6l1OP+mdjn/o3Q9/6RzP/+mdD3/l2c0/1k7GP9JQjr/zc7N//7+ + /f/7/fz/9/z+/8vIyP+AaFT/rYBR/6V1Qf+fc0L/oXQ+/6Z1Ov+odjj/p3U5/6d1Of+odTn/qHU4/6d1 + OP+ndTj/p3U4/6d1OP+ndTj/p3U4/6d1OP+ndTj/p3U4/6d1OP+ndTj/p3Y4/6d1OP+ndTn/p3U7/6Z1 + O/+ndjr/p3U5/6Z2Ov+dcz3/Z0cl/0Y1I/+tqqP//fv8//z7/f/7/v7/9ff4/6ahn/+LbU//nWsx/5th + Hf+dYxn/nGMW/51jFf+bYxr/mGMe/3FFEP87KBD/d3Zy/8jJxv/m6On/9fX4//39/f/+/v7//v7+//// + /////////v7+///////+/v7////////////8/f7///3+//Dy8v/X3+L/w8zU/8XMzf/c3Nb/8Ozq//f2 + +v/5+/7//P39//77/P/v7u//goJ+/4Z0Z/+qhW3/oX5g/52AY/+ef2P/n35k/51+Zf+df2P/nX9k/59/ + Zf+ff2T/n39k/55/ZP+ef2T/nn9k/59/ZP+ff2T/n39k/51/Y/+efmT/nn5k/51/Y/+df2T/nn9k/5+A + Y/+ggGD/pIBg/6J/YP+gfWX/oH1n/6J+Yv+VcVX/Z086/21oY//e4eH//v7+//z9/f/4/P3/0c/Q/4V1 + av+jhWj/pINk/5x/ZP+fgGL/oIBi/59/Y/+df2T/nn5k/55/ZP+ef2P/nX9k/51/ZP+df2T/nX9k/51/ + ZP+df2T/nX9k/51/ZP+df2P/nn9j/55/Y/+df2T/nn9k/55/ZP+gf2T/on9k/6OAYv+kgGD/pIFg/5+A + Yv9yXEj/VUk//7Oxr//9/P3/+/39//r+/v/7/v7/r6uq/4puUv+aazT/m2Ig/5xiF/+cYxT/nmQU/5xj + Gf+aZB3/dkoR/zsmDP9wbWj/x8fD/+jo6v/19vj//f39/////v/+/v7//////////////////v7+//7+ + /v///////v7+//v9///q5uj/sbCq/66yrv+5wMb/uL7B/8zLxv/j3tv/8e3z//X4/f/7/P7//fv+//b2 + 9/+8v7//mJCP/6eSjv+hkIj/nZCI/52Pif+Zj4r/l5CJ/5iPiP+Xj4n/mo6K/5mPiv+Zj4r/mY+K/5mP + iv+Zj4r/mY+K/5mPiv+Zj4r/mI+J/5mPif+Yj4n/mI+K/5mPif+Zj4n/mJCJ/5iQiP+ckIb/nY+H/52N + jP+cjoz/nZCG/5uKfv+Tin//trq4//D39//8/Pz//f39//r8/f/m5un/rqmm/6KTiP+jk4j/npCI/5+Q + hv+ckIf/mY+J/5iPiv+Yj4r/mI+K/5iPif+Yj4n/mI+J/5iPiv+Yj4n/mI+J/5iPif+Yj4n/mI+J/5iP + if+Zj4r/mY+K/5iPiv+Yj4v/mI+K/5mPiv+cjor/npCI/5+Qhv+fkIX/nZCF/4yEfP+XlJL/1NbX//r7 + +//7/fz/+f39//z9/v+wqqr/iW1T/5prNf+bYyH/m2IW/5xkFP+eZBX/nGMZ/5plHP94TRD/OycJ/25q + ZP/HxcP/6ejs//X2+f/9/f3////+//////////////////7+/v/9/f3//v7+//7+/v/9/f3/8PT0/5SL + h/9OQTL/W1RF/5aWlv+1urz/v769/9TPyv/j4OX/7/L1//n7+//6/P7/+/z9//H29f/Z2dr/19PU/9TP + 0v/Nzs3/zMvN/8rLzP/Ky8v/ycvK/8jLy//Jy8z/ysvM/8rLzP/Ky8z/ysvM/8rLzP/Ky8z/ysvM/8rL + y//Ky8v/ysvM/8nKzP/Lys3/zMvL/8vLy//Hy83/xcrO/8nLzf/My87/y8jR/8nJ0P/KzMn/z83G/9bW + zv/k6ur/7/b4//f4+f/7+/z/+/z+//j6/P/q6uv/29fV/9XS0//PztL/zczO/8zMzP/Ly8z/y8rM/8vL + zf/My83/y8vM/8rLy//Ky8v/ysvM/8rLzP/Ky8z/ysvM/8rLzP/Ky8v/ysrL/8rKzP/Ky8v/y8vL/8rL + zP/Iys7/xcrP/8jKz//Ly8z/zMvL/83Lyv/My8r/zM3L/9rd3f/r7/D/9ff2//n7+//5/f3//P7+/66p + qP+JbFD/nGo1/5xiIf+bYhf/nGQW/55jF/+cYxn/m2Ua/3lODv88KAj/bmpk/8fExP/p6O3/9fb5//39 + /f////7//////////////////v7+//39/f/+/v7//v7+//7+/v+5urb/Szgg/1AxC/88IQT/TEM4/5yf + oP+9vbz/xcK+/9TT1P/i5+b/8/b0//j6/f/8/fz/+/76//r8+//y9fr/5+nv/93j4P/b3t3/3dze/9/b + 3//e2uD/3tzf/9/b3//e29//3tvf/97b3//e29//3tvf/97b3//e29//3tvf/9/b3//e2+D/3dvf/97a + 4P/f2t//39vf/9zc3//Z3N//3N3f/93c3//b2+H/2Nvh/9ne3f/f39n/4t/a/9/d4P/j5On/7/Dx//f4 + +f/7/f3//P3+//z8/v/4+Pz/7/H1/+Tn7P/c3+T/3dzg/9/b3//f2+D/4Nzh/+Db4P/f29//39vf/97b + 3//e29//39vf/9/b4P/f2+D/39vf/9/b3//f29//3tvf/97b3v/f29//39vg/93b4f/Z2+H/29zg/93c + 3v/d3N7/3tze/9zc3v/d3d3/3t7e/+Lh3//r6ej/8/T2//j7/f/7/v7/rail/4doS/+daTP/nGIg/5ph + GP+cZBj/nmIZ/51iGv+cZRr/ek4N/z4oCP9waWX/yMPG/+jo7v/09vr//P39/////v////////////7+ + /v/+/v7//v7+//7+/v/+/v7/9vb2/3BsYP9fPxX/iVgX/2Y7Cf8uHAn/WFhZ/7OytP/Avbn/xMbD/9PY + 2v/p6+7/9/X9//78+v/9/vb/+/v7/+7u+f/b3OH/z9DL/8vIxv/Jx8f/yMbI/8jGyf/Ix8f/ysbI/8jG + yP/Ixsj/yMbI/8jGyP/Ixsj/yMbI/8jGyP/Ixsj/yMbI/8nHx//Ix8j/yMfI/8nHx//Jx8f/x8fI/8jG + yf/Nxsb/zcfF/8nGyP/Cxsr/wcjJ/8fIxf/Kx8X/zsfN/9XT2f/k5+f/9Pb2//z8+//+/vz//Pz+//P2 + +v/l6Ov/1tbX/8rLyv/Hx8f/yMfI/8nHyP/KyMj/yMfI/8jGyP/Ixsj/yMbI/8jGyP/Ixsj/yMbI/8jG + yP/Ixsj/yMfI/8nHyP/Jxsj/yMbI/8jHyP/Ix8f/yMbI/8rHyP/Lx8f/zMjG/8rHx//Jxsj/x8bJ/8bH + yv/Ix8n/0c7O/9/d3f/s7/H/9vn7//z9/f+up6H/hmVF/5xnL/+cYx//mWIZ/5tjGf+dYhr/nWMb/5xl + Gv96Twz/PikI/3BpZv/Iw8j/6Ojw//P2+//7/f7//v/+///+/f/9/v7//v7+//7+/f/8/v3//f3+//// + /f/KzMr/UD8j/4JYHv+gZBf/kFoS/08vCf8tIRj/dnRx/7W3tP+5vLv/x8vI/9zc4f/w7Pf/+Pj6//b7 + 9//j5OT/0s/V/8G+vf+xr6v/qain/6aoqP+lqaf/pKmn/6Sppv+lqaf/pamn/6Wpp/+lqaf/pamn/6Wp + p/+lqaf/pamn/6Wpp/+lqaf/pamm/6Wppv+lqaf/pamm/6Wppv+kqKj/pKep/6unpv+rqKb/p6eo/6Gn + qv+jqaj/qamk/6+urP+7u8H/ycvR/93g4P/v8vP/+fr7//r9/P/29fT/4N3c/8jHx/+3tbL/rKun/6ao + pf+lqKb/pamn/6Wppv+lqab/pamn/6Wpp/+lqaf/pamn/6Wpp/+lqaf/pamn/6Wpp/+lqab/pamm/6ap + pv+mqKb/pKim/6Sppv+lqKf/p6in/6mqo/+pqqL/pqeo/6emqv+np6f/pqqo/7G2tf/ExMb/2NjY/+rs + 7v/2+Pv//P39/62npf+DZEX/nGcn/5xkHP+aYhv/m2MZ/5tiG/+eYxv/nmUa/3tPD/9AKQj/cGtm/8XF + yv/o6fD/9fb6//z9/v/+//7//P77//z+/v///f///v/7//n++v/6+/7//Pz9/4eFff9fPAn/k2Ee/6Fk + Fv+hZhX/fVAV/0AlCP80KyH/ioyJ/7m/vf+9wbr/0c7Q/+Ti6f/t8fX/ur++/3p5c/9zamH/bGNZ/2Nb + Uv9aWFT/WlhS/1xZUf9bWVL/W1hS/1tYUf9bWFL/W1hS/1tYUv9bWFL/W1hS/1tYUv9bWFL/W1hS/1tZ + Uf9cWFL/XFlR/1tZUf9cWVL/XFlR/1pYU/9aV1P/XlhR/19YU/9dV1L/WVhS/11YT/9gWE7/a2Zf/5OV + lv/Cxsr/3N7e/+zw8f/3+vz/6ezt/7Gsp/+BdWr/bmVd/2ZeVf9gWVD/XVhP/1xYUf9cWVL/XFlR/1xZ + Uf9cWVH/W1lR/1tZUf9bWVH/W1lR/1tZUf9bWVH/W1lR/1tZUf9bWVH/XFlR/1xZUf9cWFL/W1lR/1tY + Uv9bWFL/X1pM/15ZTP9aV1T/XFdV/15YTf9cXE7/cndv/66vr//Y2dn/7O3t//j5+//9/v3/qqis/4Jl + Sf+caCH/nGQZ/5phG/+cZBj/nGIb/59iG/+gZhr/e04Q/0AoCP9wbGX/xcfN/+rs8f/39/r//f3+//// + ///8//r//v////38/v/9/vv/+v77//v9///d4OL/Wks1/35RDP+XYxr/nGQX/51lF/+QYB3/a0UX/zQd + Bf9JQTn/naOh/7u8uv/Gwr//1dXU/+Pl4v9+d3H/QjQf/0oyEv9LMA//Si8P/0QuEv9DLhH/Ry8R/0Yv + Ev9GLxH/Ri4R/0YvEf9GLxH/Ri8R/0YvEf9GLxH/Ri8R/0YvEf9GLxH/Ri8Q/0cvEf9GLxD/Ri8Q/0cv + Ef9HLxD/Ri8R/0YuEv9JLxH/SS8T/0cvEv9ELxH/RjAQ/0IrDv86KBT/XFZO/7W3t//f4t//7vLw//n8 + /P/Q0dD/ZFpL/0s0Fv9ELxL/RS8Q/0YwD/9HMBD/RzAR/0cvEf9HMBD/Ri8Q/0YvEP9GMBD/RjAQ/0Yw + EP9GMBD/RjAQ/0YwEP9GMBD/RjAQ/0YvEf9GLxH/Ri8R/0YvEf9GLxH/Ri4S/0cvEv9KMA7/SS8O/0Mt + E/9FLhP/SDAN/zknDP87Myb/lpGO/93d3f/w8PH/+/v7//3+/f+pqaz/gmVJ/5xnIP+dZBj/m2Eb/5xj + GP+dYhr/n2IZ/55mGf95TRD/QCkJ/3NvaP/Iy8//7e/z//j4+v/9/f7///////z+/P////7/+/3+//v+ + /f/8/Pv//P/+/5WZk/9YORT/lmMS/5hlFv+WYhr/l2Ib/5ZiHf+MXB7/YDkN/zEbCv9bWln/s7Gy/769 + uv/GxsT/2dbP/3dmWf9wUzH/e1Me/31ND/98TQ//eE4S/3hNEv96TBH/ek0S/3pMEf95TRL/eUwR/3lM + Ef95TBH/eUwR/3lMEf95TBH/eUwR/3lNEf96ThH/ek0R/3lNEP95TRD/ek0R/3tNEP96TRH/eU0R/3xO + D/99ThD/e00S/3ZNFP92ThT/akUR/0EmBf9CNiv/qaql/+Hl4v/w8/D/+/z7/8nHxP9lUzj/dlIh/3FM + F/91TBH/d04R/3lOEf95TRH/eU0R/3pNEf95TRH/eU0R/3pOEf96ThH/ek4R/3pOEf96ThH/ek4R/3pO + Ef95ThH/ek0R/3tNEf96TRH/ekwR/3pMEf96TBP/e0wS/31ODv96TQ//dkoW/3hLFf95TBD/VzUH/zoo + FP+TiYf/4eHi//Hz9f/7+/z/+vv8/6iko/+EY0L/nGYg/5tjGv+bYhz/nGIY/51iGv+eYxf/nGYZ/3VM + EP9AKw3/endw/87R1P/v8fT/+vr7//7+/v///////f7+//3+/v/5//7/+fz///38/f/l6un/VlM+/3lL + Fv+gZxL/mmYW/5NiHv+WYR7/nGIa/59jGP+LVxj/TiwL/y4iGf9/e3r/tru8/7m9wf/Lysf/d2VZ/45u + TP+cbDL/nGIY/5xiFv+XYxj/mGMZ/5piGP+bYxr/mWIZ/5hjGf+ZYhn/mWIZ/5liGf+ZYhn/mWIZ/5li + Gf+ZYhn/mWIZ/5pjGf+aYhn/mWMZ/5liGf+aYhr/mmMZ/5liGf+ZYhr/nWMW/51jFf+bYxf/mGIb/5Zj + Hf+FWhz/TjAL/z8zKv+mpaX/4OLn//Dw8//9+vz/zsrF/3pgQ/+bbDP/lGIh/5hhG/+ZYxr/mmMZ/5li + Gf+ZYhn/mWIZ/5liGf+ZYxr/mWMZ/5ljGf+ZYxn/mWMZ/5ljGf+ZYxn/mWMZ/5ljGf+aYxn/mmMZ/5pj + Gf+aYhn/mmIZ/5piGv+bYhr/m2QW/5djGf+WXyD/nGEd/5tiGP9oQQv/RjYh/5qWmP/j5en/8fX3//v8 + /v/t7vD/mpGL/4NeNv+cZyL/mWMc/5liHf+bYhn/nGIZ/55jF/+ZZRn/bkgP/0IvFP+Kh4H/1tnc//Dz + 9P/7+/z//v7+//7+/v///f//+v7+//n//f/8+/3//v3//6alo/9ROxf/lV4d/55lF/+aYhn/l2Ie/5ti + Hf+fYhj/omQU/5xjG/94Txv/PyYE/zsxJv+Gjo//tLzF/8HEzP+Fenb/hmlP/6JyPv+cYBn/n2MX/5tj + Gf+bZBr/nGMZ/51jGv+cYxr/m2Ma/51iGv+dYhr/nWIa/51iGv+dYhr/nWIa/51iGv+cYhr/m2Ma/51i + Gv+cYhr/nGMb/51iG/+dYxv/nGIb/5xhHP+eYhn/nmIX/51jF/+cYxj/mmQb/4laG/9PMAz/OzIs/6Sj + qf/h4Or/8O75//z5/v/Oycb/f2FH/6FtM/+cYyD/oGEb/55iGv+dYxn/nWMa/51iGv+cYxr/nGIa/51i + G/+dYhr/nWIa/51iGv+dYhr/nWIa/51iGv+dYhr/nGMa/5tjGv+cYxv/nGMb/5tjGv+cZBr/nGMb/5xj + Gv+aZBj/l2Qc/5phHv+hYhn/m2EV/107Cv9PRzr/pqqz/+br8v/0+Pr//P3+/97e3v+Je23/glos/59p + JP+ZYxz/l2Id/5tjGf+dZBn/nWQY/5VjGv9kQAz/RDMc/5yal//h4+b/8/T2//z8/P/+/v7//v7+//39 + ///6//z/+//+//77/f/v8fH/aF5O/29JFf+bYxv/m2Qe/5tgHf+cYhz/n2Ia/6BjFv+gZRT/nGQZ/45h + H/9tSBD/NiEE/0FCO/+rrrH/ys/X/6ujpf95XUr/qHtM/5pgHf+fYhr/nGIa/5tjG/+bYhv/m2Ib/5xj + G/+bYxv/m2Ic/5tiHP+bYhz/m2Ic/5tiHP+bYhz/m2Ic/5tiG/+bYxv/m2Ib/5tjG/+bYxv/nGIc/5xi + HP+bYhz/mmEe/5piG/+bYhn/m2MZ/5tjGP+bZBj/i1sX/1ExCv85MSz/o6So/+Pi5//v7vj/+vn+/87K + x/9+YUf/oG0y/5xjHv+eYhn/nWMZ/5tjGf+bYhr/m2Ib/5tjG/+bYxv/m2Ib/5tiHP+bYhz/m2Ic/5ti + HP+bYhz/m2Ic/5tiHP+bYhv/mmIb/5tjG/+bYxz/m2Mb/5tjG/+aYxz/mWMb/5hjGv+XYxv/m2Ib/6Jk + F/+VXxT/TzQI/1xaUP+9wsn/7vD2//f6+v/7/v3/2tfW/4h0Xf+FWiX/oWkj/5liHP+XYx3/m2MZ/5xk + GP+cZBj/kWIc/1w6C/9GNiT/pqWl/+fp7f/29vn//f39//7+/v///////f7+//z//P/7/f////3+/77B + uP9VPRn/jF0a/5plGv+ZYR//nWEe/51iG/+eYxn/oGQV/55lE/+dZRj/lGMc/41fG/9dOwr/Kx0L/21m + X//Q09b/yMPF/3BYSP+rg1j/mWIg/59iGf+dYxr/nGMb/5pjG/+aYxr/nGMZ/5tiGv+cYhv/m2Ia/5ti + Gv+bYhr/nGMb/5xiG/+bYhr/m2Ia/5xjGv+cYxr/m2MZ/5tjGf+bYhr/nGMa/5pjGv+ZYhz/mmMa/5tj + Gf+bYxr/nWQY/59mFf+PXBP/VTII/zsxK/+lpaX/5uTj//Dx9P/4+/7/zsrG/3xhRf+gbjH/m2Mc/5xj + F/+bYxb/m2MY/5tiGv+bYRv/nGIb/5tiGf+bYxn/m2MZ/5tjGf+bYxn/m2MZ/5tjGf+bYxn/m2MZ/5ti + Gv+cYxr/nGMa/5tiG/+bYhn/m2Ia/5tiHP+ZYxr/mWQY/5hkGP+cYxf/oWUW/4xaEv9HMQr/bW1k/9TV + 1//59/n/+vz8//r9/v/JxML/h2tK/41bHv+gZiH/mWIc/5diG/+bYxn/nWQY/51lGf+NXxv/VDUK/05B + Mv+vsLL/6+3y//n5+//+/v7//v7+//7+/v/+/v7//f39//z8///z9vr/d3Ng/3BEDP+aYxn/lGQa/5tj + G/+bYxr/mmIc/5ljG/+cYxn/nWQW/51lGP+XYxj/l2Qc/4ZYHf9LLwz/NSYa/7a3t//f3uD/d2lb/6J/ + Wf+fayr/nWEa/55jGf+dYxv/nGMa/5xkGf+dZBn/nWQZ/51jGf+dYxj/nGMY/5tjGf+bYxn/nWQZ/51j + GP+cYxn/nWQZ/51kGf+cYxj/nGIZ/51jGf+cZBj/nGMZ/5tjGf+bYxf/nGMZ/5tiGv+cZBj/n2UU/5Fc + E/9WMgf/PTIs/6empf/n5eH/8fL1//j7/v/MysX/e2FE/6BvMP+aZBv/m2QW/5pkF/+bYxj/nGMZ/51j + GP+dYxj/m2MZ/5xjGP+cYxj/nGMY/5xjGP+cYxj/nGMY/51jGP+dYxj/nWMZ/5xjGf+bYxn/nGMZ/5xj + GP+cYxj/m2Ma/5tkGv+bZBf/m2QV/59jFf+eYxf/e08R/0U3Gf+Ii4X/5+Xm//35+v/9/f3/+v3+/62l + of9+XTX/k2Ec/51kHf+aYhz/l2Mb/5tjGP+eZBj/nWUb/4lcG/9PMAn/Z1xS/8LDyP/v8Pb/+vn9//7+ + ///+/v7//v7+//v/+//9/fz//v79/7/L0v9LPSb/kFYN/55jEv+QYxr/n2MU/5tkFv+WYhv/lGMc/5hi + Hv+dZBj/nmQW/5tkFv+dZB7/pG8z/31YKf80IRD/pqan/+7v7/+RiYH/jXJQ/6p5P/+aYRr/nWEa/5xi + HP+dYhz/mWEa/5xkG/+aZBr/mmIa/5xjGv+bYxr/m2Ma/5tiG/+bYxv/nGMa/5tjGv+aYxr/nGMb/5tj + G/+bYhz/nGIc/5tjGv+bZBn/nGMa/5tjGP+bYxr/mWIc/5ljGf+bZRf/jlwV/1QyCf86Mi3/pqWo/+fk + 4//v8vX/9vv+/8zJx/98YEf/om0z/51jHf+eYxj/m2Ia/5piGv+aYxr/m2Ia/5piGv+aYxr/nGMa/5tj + G/+bYxr/m2Ma/5tjGv+bYxr/mmMb/5tjG/+bYxv/m2Mb/5tjGv+bYxv/m2Ma/5tjGv+aYhz/mmMc/5tk + F/+cZBX/n2QY/5lgG/9rRBP/TUU2/6arrv/08vT//vv6//z+/v/x9fb/mI+I/3pWK/+YZB3/nGMa/5xj + G/+YZBr/nGQW/55jFv+aZBr/glca/0gsCf9+dGz/1NTb//Py+v/6+v7//f3+//7+/f/+/v7/+v/9//7+ + /f///vr/j42H/19FKP+bZyj/oWkh/6BsKP+aZSH/nGMY/5tjGP+ZZBv/lmEe/51kFv+kZBD/omUX/41c + H/94Vy7/bFg//2RZS//CwsP/7fH1/7Gwsf95Zk7/sYVQ/5tjHf+bYRn/m2MY/5xkFf+YYxn/m2Md/5hh + Hf+aYR3/nGIc/5xjGf+cYxj/m2Ma/5piG/+bYh3/m2Ic/5tiHf+cYh3/m2Mb/5tjHP+cYR3/m2Ma/5tj + Gf+bYRv/mmIa/5ljG/+ZYxr/mmMX/55lF/+PXBX/VjMI/z4zLf+nqqv/5+rm//Lz8v/0+/z/yMnH/35g + R/+lbjL/nmMd/5dhHP+YYRv/nWEc/59hHf+eYRz/m2Ea/5piGf+aYxn/mmMZ/5tkGP+cZBn/nGMa/5ti + HP+ZYhz/mWIc/5xiHP+dYhr/nGMY/5xjGP+bZBn/mmQZ/5liHP+YYxz/lmUW/5hkFv+eYRv/kVsa/1o+ + D/9oZFn/x8nS//b4+//8/fz//f7+/9jb2f+Fd2n/gFUh/59nFf+cZBf/mGEe/5hjHP+cZBf/m2MY/5dj + GP92TRD/STMX/5KMhv/h4eP/9/X7//r7/v/8/f7//v79//7+/v/8/f///f////r9+/92amD/i3Vd/6eH + ZP+oglT/sYZZ/6qAUf+bYyD/nmEU/5xjGf+WYh7/nGQX/6VkDv+hZBf/eE4Y/zYlE/9jYVz/raef/9PT + 0v/l6/P/0tnb/3hpW/+uiF7/omwr/5pgF/+eZBf/m2QU/5lkGv+bYh3/mmId/5thHf+dYxv/nWQX/5xk + Fv+bZBn/m2Ma/5xjG/+dYxr/nGIc/5piHf+XYxn/mmQa/5xkHP+bYxr/mWMa/5liHP+aYxv/mWMb/5lk + Gv+aYxn/nmUa/45cF/9TMQn/QDUx/7K2uP/u8/D/+Pf0//X7/P/Hycf/fmBG/6ZuL/+fYxv/l2Ic/5li + F/+eYhf/nmIa/51iG/+cYhz/mmIc/5lhHv+ZYhz/mmMb/5xjGv+cYhr/m2Ib/5ljG/+aZBr/nWQY/51j + F/+dYxf/nGMY/5tjG/+bYhv/m2Id/5pjHP+WZRf/mGQW/5xiHP+BUxf/TzwU/46Lg//m5Ov/9/r9//v9 + /f/9/f7/vby5/3hiSf+KWBr/omcT/5pjGP+UYR//mGId/5tjGf+bYxr/lWEW/2hACf9SQDD/qamn/+3t + 6//7+Pr/+vz///v+/v/+/v3///7+//79/v/5/v3//P38/5yWlP+DeHL/jIB1/4+Ccv+EcF//spBr/55r + L/+cXxb/nmMY/5diHv+ZYhz/omUW/5tjGP95UBb/KhYH/2ZlYv/FwL3/zM7M/97j6P/p7u//nJCK/5B0 + Vv+tfkn/m2Aa/59iGv+bYRr/mmMc/5hiG/+aZBf/mmMX/5tkF/+bZBj/nGIa/5tiHP+bYxv/nWMZ/51k + Fv+dZBj/mmMa/5ljGf+bZBn/nGMb/5pjG/+YZBr/mWQa/51kGf+dYhn/m2Ib/5xhHP+dYhz/i1oZ/04w + Cv8/Ojb/vsPG//r6+v/8+vr/+P39/8zJxv9+YUT/pW4u/6BkG/+ZYhr/nGQT/51mEf+ZZRT/l2QY/5hi + HP+YYR//mmAh/5lgH/+aYh3/m2Ma/5xkGP+aZRf/mGUW/5pkFv+bZBb/mmMY/5tjGv+aYhv/mmEd/5xg + Hv+dYR7/nGMb/5pkGf+cZBb/mGEY/2xFEv9aTDX/ubaz//f1+P/6+/3//P3+//X1+P+gmZX/c1cw/5Ng + Gf+fZRj/mGIc/5diHP+aYxn/nGMY/55jG/+RXRX/WTUH/15RR/+9wMD/9fX0//36+//6/f7/+/7+//7+ + /v////7/+/7+//j+/f/9/v7/5ufo/8TDxP/BwsL/ycrJ/4WDiP+OdFv/pnhG/51fGv+iYxn/l2Mb/5dj + H/+bYhj/mGQb/4lZHf89IgP/Pzw1/7W1s//BxcT/1trd/+ru7f/Mx8X/eGlZ/62MZf+fZib/nmAc/5xh + Hv+cYxr/mWQY/5tkFf+bZRX/m2UW/5xjGf+cYRv/m2Ed/5liHP+YYxr/mWQY/5tkFv+cZBb/nWUX/55j + Ff+cYxf/nGMZ/5tjF/+cZRX/nmQW/59iF/+cYRz/nWEh/55iI/+MWyD/UDMP/0E9N//Fycn///7+//z8 + /f/4+/3/zcrG/3xjSP+jcTj/mmIh/5RgHP+ZYRb/mWMT/5VjFP+XYxf/mWQb/5pjG/+bYhv/nGMb/5tj + Gv+aYxj/mWMX/5lkF/+ZZBf/mmQX/5pkGP+aYxr/m2Ic/5piHP+aYhz/nGEd/51iG/+bZBj/nWQX/6Jl + Ff+PWhX/Wz0W/3ZvZf/c3Nz//Pv7//v7/f/8/f7/2Nbb/4FwZv93Uh3/mmYX/5tiHP+YYh3/mmQY/5xj + F/+dYxn/oGQa/4lYEv9QMw3/eXNt/9HW2v/3+Pj//vz7//v+/v/7/v7//v7+///////9/v//+v7+//3/ + ///+/v3/9fj4//T39//3+vr/xcXJ/21aTP+viF//m2Ec/59iF/+YYhn/mGMf/5djGv+VZBz/kmAe/1k4 + A/8kHxH/kpWR/77Dxf/Pz9D/5eXk/+jn6P+Ff37/k39n/6x9Rv+bXx3/nGEc/5xjGP+cYxf/nWQV/5xk + F/+ZYxn/nGMb/51iG/+cYhv/mGIc/5ZjHP+WZBv/nGMZ/51jF/+eYxb/nGIV/5piGP+dYhv/nWQg/59q + J/+ncS//qXM1/6Z1QP+oeUr/rX9O/5x1Rf9dRiP/VVFF/9TW1f///v7/+/v9//b7/v/IyMf/e2pX/6+K + Yf+pf07/onZG/6RzPP+ibTD/nWYn/5piH/+ZYxj/mmQS/5xlEP+dZhL/nWUU/5xkFv+bYxj/nWIZ/59i + Gv+dYhv/m2Ib/5tjG/+bYxr/m2MY/5tkFv+cZBb/nWQX/55kGP+iZBj/oGQX/3pOEf9ZRiz/np+d//D0 + 9//7/Pz//f39//n8/v+uq6v/b1U7/4VWFv+dZRX/nGMc/5liHf+cZBf/nmQW/51kGf+dZBb/eE0M/005 + Hf+YmJj/4ufv//j6/P/+/v3//f7+//z+/v/+/v7///////v//f/9/////v/8//7++v/9/vr//v/7//7/ + ///q6ur/al1W/6eHaf+caSf/nmEU/59iFv+bYxz/mGQb/5ljHf+aYxr/d0wN/yMYBf9iYlz/vb/C/8nH + xv/b2db/6+zu/7GzvP90amH/t5Fo/51oJ/+ZYxj/nWQX/51iFv+dZBj/nGMa/5liHf+bZBv/nWQV/6Bk + Ff+dYxn/mmMb/5pkGv+bYhr/mmEc/5ljH/+aaCf/n24y/6Z0O/+kd0f/mnZR/5h2Uv+UdlX/jHZe/4l3 + Yv+LeGD/gnBX/3JkUf+alpL/8fHz///8/f/8/Pv/9/z9/9ba2P+Jg3v/kX5o/5qDaP+egmr/pYZr/6yG + Zv+yhmL/soRZ/6p7Q/+hcC3/nWkd/5ljFf+ZYhT/mmMW/5piGP+fYBr/oWAb/59iGv+cYxr/m2MZ/5tk + Gv+bYxn/nGQW/5plE/+aZBf/nGQa/59mF/+SXxT/Y0ET/3NnWv/N0NH/+fz+//v8/f/9/f7/5efr/4qD + d/9vTSD/k10Y/51jF/+aYxf/mWIa/5xiGf+dZBj/nWQZ/5piF/9mPwn/W04+/7S5vv/t8/r/+vz9//7+ + /f/+/v3//v/+//3////+////+/79//3///////3//v/8//7++//+/vz//P7+//n6+v+De3j/kHdf/6V3 + Pv+bYRT/oWQT/5xjF/+aYxn/m2Id/5xkGP+NWhT/PSUE/zs0JP+oqqr/xMLA/9DOyf/i5en/2+Dm/4OA + ff+dg2n/rYJJ/5djHP+ZYhj/n2IY/6FjGf+eYRz/m2Ee/5pjHP+dZRX/n2UR/6JkE/+eYhb/nGMb/51o + J/+fbjj/nXVE/5l2Tf+VdFL/i21P/4ZsVv+MeGz/l4d9/5SIgP+WlJH/naOh/66wqf+5s6r/w7u3/97a + 3//29fv/+vn6//r9+//2/v3/7fX1/87Qz/+1r6n/pZ2X/5iNiv+ViIT/mYl//5KCcP+Vgm3/pIpw/7GQ + b/+wil//q39M/6FwNf+YZCX/l2Ed/5xhGf+eYhn/nmIZ/51jGP+dZBj/nGQZ/5xiGf+aYhr/mWMa/5hi + HP+YYxv/mGQZ/3pQE/9iSi7/pqKc/+/08//5/f7/+/z+//39/f/Avbz/cV9C/3xSFP+cYhv/nmIb/5lk + Ff+ZYxf/nGEb/5xiGv+cYxr/jVkW/1Q1D/92cWv/0tjc//f6/f/8/f7//v/+//7+/v///v3//v7+//3/ + /v/9/f7//f3///79/v/+/v3//P79//v+/v/5/v7/+P7//7Svsv94Zlb/q4RW/5hiHP+fYxX/nmMX/5ti + F/+bZBr/nmQY/5hiGf9hOwr/LBoK/4B/ev/CwL//xsPA/9fa3P/l6/H/vL6//3dqW/+xk2j/m2wv/5Rg + Hf+fYhr/oWIY/51gHP+ZYB//mGMf/5hiGf+bYxb/oGUd/6NsKv+jcjf/n3NE/45tSv+HbFT/hW9g/4x+ + cv+jmJH/s6il/8i/wP/d19X/19XT/9LY2//R3N//2uDe/+Tg2//l393/5eHm/+jn7f/x8fL/9/r6//n+ + /P/4/v3/9fn5/+vs7v/d3OL/z83V/8jGy/+/wL7/qaym/5ubl/+SjIj/j4J8/5eCdv+liHT/r41u/66H + X/+jeUf/mWss/5NiHv+UYRv/mWMb/5xjGv+dYxn/nWIb/5piHf+YYiD/mGIf/5hjHf+LWxz/ZEUb/4J2 + af/a2tn/+v79//n9/f/8/f7/7+zq/5mKff9tTR7/jVwU/55jHf+dYh3/m2QV/51jFf+bYhv/mWIe/5hj + G/93Sw//UTwm/56gof/o7/D/+vv8//39/f/8//7//v7+///+/f///v3//v/+//z9///8/f7//P3+//z+ + /v/8/v7/+/7+//n+/f/3/fz/6ens/25iWf+oiWb/mGgt/5thFv+fYxX/nWMa/5tiGv+YYxv/mmUa/4JS + Ev83HgP/TEhA/7SxsP/Dv7//zs7P/93h5//h5en/joyG/5B9ZP+wiVz/kmIr/5lgGf+hZBb/nmQY/5Zh + H/+VYyL/mGUj/6BtK/+gcj7/lG9E/4hpRf+EbFL/kYN0/6qfm//Cvbz/0NDQ/+Dd3v/o5ef/5ebn/+fl + 5P/i4eD/1trc/8/X2f/R09P/1tHM/9POyf/NzM7/09Xb/+Xm6v/09vj//f37//39+//6/P3/8/b8/+bo + 8f/Z3OH/0dTW/8vR0P/Jz8//yMvQ/7zAxv+ysrj/p6Cj/5qQi/+Thnj/moZz/6iQdP+vj2b/p4BO/5ds + M/+UYSP/mGEa/51jFv+eYxf/nGMY/5piG/+bYxz/mGMc/3ZLGv9qVD//trKu//b2+P/8+/7/+vz+//n+ + /f/Cv73/dV1H/3pNFf+ZYRr/m2Mb/5ljG/+dZBf/oWMX/5piHP+XYiD/lWAY/2I+CP9lWlH/wsfM//P5 + +P/7/fr//v79//r//v/7/v7//v38///+/f///v3/+v7///r+/v/8/v7//v7+//3+/f/+/vv//f76//z9 + +f/8/v7/j4mD/452XP+ne0n/mmEZ/55jFP+eYxz/mmId/5ZiHv+aZB3/mGEW/1Q2C/8rIBb/gIF9/7++ + vf/ExMH/0dTV/+Xn6//M0ND/gnlu/6qLbP+pf0//lWEb/55mEv+bZRT/l2Uh/5dpLf+ecDz/l2s9/4Jm + S/+DcmL/nI6D/8K7t//X1df/5Obo/+fr7//n6u7/5+Tl/97f3v/Q19j/z9DP/83NzP/Gxsn/vsDE/768 + vv/Aurn/vbq5/7u+wv/DydD/3N/k//Hz8//9/Pn//v76//v7/P/y8vb/4uLm/9HS0v/FxcP/xMLB/8nE + xf/Jx8j/x8rL/8jNzv/JzM3/wcTD/7W4tP+kpJ7/k4yD/5iGdP+rj3T/so9s/6t/UP+daSv/nGMX/51j + E/+dZRP/nWUV/5tlFv+JWRL/aUYi/5WJgf/j5+X/+v39//z7/v/9/P//4OXi/4J+ef9lRyL/jFkZ/5xh + H/+aZBn/mGUZ/51jGv+gYxf/mmMc/5ZiIv+IVRL/WjwQ/4+Kh//f4+v/9/r5//z9+P/+/vz/+v7///r9 + /f/9/fz///38///+/f/9/v7//f7+//7+/v///////v/+///+/v///v3//v39//7////KyMb/dGFV/7SM + af+dZCP/oWMU/5xjGP+XYxz/mGMe/5xjG/+hZhT/gFIW/zchB/89Ojj/oqes/7u+v//LxsD/3trZ/+Xo + 7P+8t7r/h3Jt/7WVev+fd0H/kmQZ/51qIf+hbzL/kmY8/31cR/+Bc2f/r6ah/9bQz//o5+f/8fH1/+rv + 7f/j5+j/3N7h/9XV2f/NzdH/xcbO/7m8wf+sqqr/op+f/5SRlP9+e4H/cWts/21kXP9yamT/lpaZ/8DF + y//b3uD/8/Lz//37+//y8/P/xcXB/6Oflv+kpJ//paak/6Ojof+vrK3/vLq7/7y8vP+6vr3/vsDA/8LE + xP/Hycn/y87N/8rOzP+/wcD/r6qp/5eNiv+PgXj/oox5/7GRb/+me0X/mWci/5ljGP+eZRn/j18a/2VJ + H/9+dGj/0tPU//n8+f/9/fr/+fv9/+71+P+pqaP/Zk8z/35PD/+aYxj/mGIe/5xjG/+eZBb/nWMZ/5pj + Gf+aZBn/l2Ed/21EEP9hVEH/vby///f3+v/8+/r//f37//3+/v/8/v///f7+//7+/f/9/v3//v7+///+ + /v///v7///7///////////////7////+///9/v//+/7///T09P97bWj/qYdw/6dzQP+cYBf/nWQW/5dj + F/+bYx3/nGIa/55lF/+UYR//WzkM/yocEf9oZ2b/t7m9/76+u//OzMv/3+Dh/+Pm5/+opKL/intn/7qc + d/+le0j/k2o2/3xhN/99bVL/rKGZ/9bR0//v7u3/9ff0/+zv8f/j5Oz/2Nvf/9PU1P/Kx8f/uLe1/5+g + nv96fXf/amdd/1VLOv9JPCv/RTYm/z8vH/89Kxf/OycP/zUnFf9XVU//tLi5/97i4v/y8PL/+/r7/9TU + 0/9lXlP/Qzcf/0I6J/9IPS3/T0My/2BWS/91cGn/ioqF/6Sop/+tsrX/uLq9/7y9v//Cv8D/yMbD/8zL + yP/Ly8r/wMHE/6iorP+Pi4j/kYN1/7GUdf+yi1z/oXE3/5pkIv98UBf/fmpP/8bDv//19/n//Pz9//79 + +f/4/Pv/xMzP/29nXP9pRBj/kVsU/5pjGP+ZYxv/nGQa/55kGf+aYRr/mmIZ/5tkGP+IVxf/Wj0X/4yH + gP/j4ub//fz9//38/f/9/P7//f79//7+/v/+/v///f/+//3//v/9//7///7////+/////v////////// + //////////////7////5/v7//v7+/7Gopv+Aalz/sY1n/5VkI/+cZBX/nmUZ/5hiGv+aYhz/l2QY/5lj + G/+AVBf/SikE/z0tIf+UkZH/tbvA/7u8wf/Pz8z/3+Tg/9be3f+RjoL/j31q/5R3YP93Xkf/l5GB/8fO + xP/r7ez/+Pj5//T39//m7ev/3eDk/83S1v+2ubv/mpeV/4B4cP9eU0b/TUAv/zktGP88LA//SC8I/1I0 + Bf9bOwn/Y0AO/2hGEP9gQg3/PCcH/zo2Lv+mqqj/4ePm//Hx9P/7/P3/y8jG/2BNOv9hQxv/UjcO/04z + B/9KLwT/QSoL/zgoE/9ANCP/UktA/2hlX/+MiYb/p6Sl/7u1uP/AvLv/wL68/8LBwP/Fxsj/x8vR/77C + x/+joqL/koZ7/6GNdf+ojGz/g184/3lbOf+7sKP/9PXz//n9/v/5/P7//Pz7/+Xl5v+Gg4H/VkIo/35R + GP+WYR3/l2Mb/5xkGP+cYxn/mWId/5liHf+dYxj/mWIY/2tFEf9mVT7/wr+7//n3+P/9/Pz//fz9//39 + /v/+/v7//v7+///+///+/////v/+//7//v////////////7+/v////////////////////////////n8 + /v/9/f3/6OLj/3hrZ/+fhW//oXdC/5dhFP+gZRT/m2QY/5ljHf+XYxn/m2Qa/5diGP94Rwz/QSIH/1BL + Qv+hp7L/s7nD/8G/vf/Q09D/3ebl/9bT0P+mn5j/npKP/7iwrf/o6OX/9fr5//f8/v/2/Pz/7PT5/9zi + 5f+6vLz/iIqE/1xaTv9GOir/QS4V/0gtCv9XNQz/YT0T/2xIGv95Uhn/hlgX/45dF/+SXhf/k2IY/4Za + GP9NMAv/OjMr/6Slp//k4uj/8fHz//r9/f/NycX/eF1C/5RmMv+JWiL/hFga/35TFP9yTBb/YUET/1M2 + C/9GLAn/PyoQ/0MyIv9WSED/eHBt/5yamv+0tLb/v7y8/76+vf+9wsf/xsvT/8/R1v/AvLr/nZaP/4F5 + b/92bGD/qqCY/+7r6f/5/f7/9/v+//b6/f/y8vT/sKmm/1pHNv9oRhr/kl8a/5djHf+YYhz/n2QU/55k + Fv+YYh3/m2MZ/59lFf+KWRf/VDoX/4qGf//k5eX//f3+//39/f/+/f3//v3+//3//v/9//7//v////// + /////////////////////////v7+/////////////////////////////Pz///v9/f/5+Pj/rq2t/3hs + X/+yj2j/m2Yg/6BiEv+eZBn/mGIb/5pjGf+cYxz/mWMW/5RdE/9kOgj/NCER/2FhZP+osbn/ur28/8TB + xP/U09T/5+Pk/+Xi5P/d3+P/8PHy//76///9+/7//P3+//f5+v/T2Nz/k5aW/1lTSf9AMRr/RS4N/1U2 + Cf9pRA3/e1AU/4lYG/+QXB7/kF4j/5ZhHv+dYxv/oGQY/6FjFv+gZBj/kFoa/1MxDf88MS3/p6Sp/+bi + 5//w8fT/+Pz9/83Jxf9/YUT/pW4z/51jIP+ZYxr/l2Ma/5NiHf+OXh7/iFkY/35RE/9tRA7/WDMK/0Mo + C/85Jxf/RT05/2ppa/+bmJf/t7S2/72+wf/Dxsn/1tja/+fm5P/e3dj/yszL/8nP0f/m6er/+/z8//f7 + /v/x+P7/7vP6/8TDwf9yY0//YUAV/4hZGf+cZBf/mGMb/5pjHP+gZBX/nWQY/5hjG/+eZRf/nGQU/21G + EP9iV0X/vsDA//f4+v/9/P7//f3+//79/v/+/v7//v7+//7////+//////////////////////////// + ///////////////////////////////////+/v///f3+//3+/P/o6On/fnd0/6OHbv+tf0b/nWEY/5tj + Gv+bYhr/nGQX/5hgG/+ZYxv/mmMa/4ZWEf9MLAb/LSQc/3R3ef+2urv/urnA/8jByf/Z09n/5eXn/+z0 + 9P/4+/z/+/v9//76/f/z7ez/tK6o/2ZhVf8/Mx//Ri0N/2Y8DP+BTRH/kFkW/5ZfGf+ZYhv/m2Mb/5xj + Gv+cYhv/nmIZ/55jGv+eYhv/nmEa/51iHP+NWRv/UzEN/z0xLf+lpaj/5+Lm/+/v9v/1+/3/y8rG/39h + Rf+pbjH/omMe/55jGP+bYxj/nWMa/6BiHP+eYxr/m2MW/5dhF/+MWBf/dksU/1k7EP8/Kg3/MycV/0Q+ + Nf9yb2z/qqmp/8/Q0v/i4eD/9PHr//v58//3+fj/9vr8//v+/f/8/fz/9Pn9/+vy+//HyM//eW9k/1s+ + F/+BUxL/mmMV/51jFv+aYxr/m2Ma/5xkF/+aZBr/m2Qb/6FkFP+NWA//XkIg/5iUj//o6+v//f3+//38 + /v/+/f7//v7+//7+/v/+/v7///////////////////////////////////////////////////////// + ///////////////9/f/+/v7//v79//j6+/+8ubr/eGZX/7yZc/+gai7/lmIb/5piGP+eYxf/mWIb/5Nj + HP+YZBz/lmIb/3pOEv9AJAb/OzAk/4uKhv+5u77/urvA/8PExv/R0tP/4uXk/+3z8v/0+/n/3+Xi/5CN + hf9SQTX/SywN/2I8Cf99UBX/k10Z/5xhG/+eYRz/nWMd/5xiG/+eYxj/oWMW/6BkEv+eZBL/m2QW/5hj + G/+YZBv/l2Qb/4lcGf9PNAv/OTQr/6Smpf/m4uX/7u/3//X7/v/Lysf/fWFI/6ZuNP+gYh//nGEb/5pj + G/+dYhr/oGIc/55iG/+dYxr/m2Qa/5pjHP+VYh3/il0b/3tREf9iPwb/Ri4H/zsuF/9cVkj/pqWk/+bm + 6f/6+Pj//vv7//79/v/+/f///Pv8//n5+f/y9fX/z9LU/3x2c/9QOiD/dUsT/5phFf+fYxT/nGIY/55j + Gf+eYxf/mGIb/5ZhHP+bZBr/mWAV/29FDv90Zlb/zMzM//r7/P/9/f3//v3+//7+/v/+/v7//v7+//// + //////////////////////////////////////////////////////////////////////////3+//z+ + ///9/v3/+f38//Hw8P+Ujof/kHtq/7WOZf+SZCP/mWEZ/5xiGf+aYxz/l2Ic/5hjHf+ZYhr/lmEb/3RK + Df8/JAb/QDUm/4uLhf+4u7z/tbq4/77Dvv/Qz87/3uPg/+Xw6v/E0sv/XF5S/3FeUv+ccEz/lWMp/5Nf + Hv+ZYhn/lWQb/5NjHP+VYhz/mGId/55iGP+iYxX/n2QT/51kE/+bYxb/mWMa/5hkGf+aZRb/jF0V/1E1 + Cf85NSv/pael/+bk4//t8fb/9vr+/8zKx/97YUj/oG80/5tjHv+cYBv/nGIc/5xiGv+cYxr/mmIc/5pj + HP+YYhz/mGMc/5tkGf+dZBX/nGUS/5ZhDf+BVQz/YEEL/zopDP9jYFr/09bX//j9/v/5/P7//Pv+//35 + /v/39vr/7/Dw/9bTzv+Hf3P/Tjse/2dEEf+PXRj/n2MX/59kGP+cYxv/nWIX/55iF/+aYh3/l2Ie/5Zk + Hv95URX/Z1I0/7m0sP/09PX//f39//7+/v/+/v7//v7+///////+/v7//v7+//////////////////// + ///////////////////////////////////////////////////+/v7/+v7///r+/f/4/vz//Pz8/9jZ + 2f9uZWb/p416/6yCRv+YYRn/mGId/51jGf+eYxn/mmQZ/5lkGP+cZBb/kmEY/21FEP86IwX/PDUq/5KQ + jf/Avrr/u7u5/8DAwf/KzdP/19ve/9ve3/+opp//enNn/6SOdP+6mHL/oXRB/5hjHv+aZBj/mGQZ/5di + G/+YYhv/mmMZ/51jFv+cYxn/m2Ma/5tiGv+dYhv/oGMX/6FlFP+QXBT/UzEJ/zgyLf+ip6j/5uTj//Dx + 9P/4+v7/zsnH/3xiSP+ecTL/mGYc/51jF/+eYhn/nWMZ/5xjGf+ZYhr/l2Qb/5ZkG/+ZYhv/nGEb/5xh + Gf+dYxr/oGgf/55rLP+DXS3/VkEl/4B5cf/j4+X/+v7///j9/f/4+/r/9fb2/+vu8f/O0tb/hoJ9/088 + JP9kQhD/i1wX/5pjGf+aYhr/mWIa/5pjG/+eZBn/m2Ma/5ZjHf+aYx3/i1kZ/2NIH/+RjIH/5+np//z9 + /f/8/Pz//v7+//7+/v/+/v7///////7+/v/+/v7///////////////////////////////////////// + //////////////////////////////7+/v/6/f3/+v7+//v+/v/9/f3/9/f4/7WzuP92aV//vpx0/55y + Of+UYBr/mmMY/51kF/+bYxf/nGIZ/6BkGP+fYhj/jV4a/2dFDf85JAj/QTku/5GJfv+6tbX/ubu//72/ + xP/Oyc3/4dja/9/a1/+xtbH/f354/5SIev+2mnj/tYpW/6VuLv+cYR3/mmAZ/5tkGv+cZRj/mWQX/5Zi + Hv+aYh7/nGId/5xjHP+dZBn/oGUW/5JbFv9WMQr/ODEt/5+oqP/l5+P/8vLx//n6/f/Nycf/fWFH/6Jw + Mf+bZBz/nGIZ/6BhGv+cYxf/mGUU/5pkFP+ZZRT/nGQV/55jF/+cYRz/mmIm/55pM/+bbD7/h148/35f + R/+gkIT/2dTS//f5+f/5+/3/+Pf5//Hy8f/n7Or/xsrK/3p5ef9GOCn/Xj4S/4taFv+dZBb/m2QZ/5Zi + IP+WYh//mWUY/55jGP+bYxr/m2Yb/5NhGv9rSBT/e21c/8zNzf/3/Pv/+v38//v9/f/9/f3//v7+//7+ + /v/+/v7///////////////////////////////////////////////////////////////////////// + ///////////+//7+/v/7/v///v7+//7+/v/+/f3/7u/w/5aRif97cGf/sJR6/6RpKP+PYBz/lmQb/5hj + F/+kYxf/o2Af/51eIP+cZRz/k2QK/29JBv86JQr/PC8c/3dwaf+wsLH/vLy8/769uf/IxsL/0dHR/9LY + 2//Axcj/mZma/4Z/df+ciXb/tJh1/66HWP+fcDX/m2Qg/51iFP+ZYxT/k2Mb/5tiGf+dYhn/l2Mc/5Jj + G/+ZZBv/kFoa/1gyDP88Ni7/qrKu/+vu6P/09vH/9vv8/8jKxv9/YkX/qXAu/6BkHP+aYSD/nmIc/5ll + Fv+TZxP/lmYS/5lkEv+eZBP/pGgb/6duLP+kcT7/kmdD/3dcRv+BdWz/ubWy/+rp6P/4+fn/9vr5//D1 + 9P/r7O3/5ODl/7u1vv9uZGb/RTIf/14/Ev+IWhX/nmMS/6JjFf+eYR//mWAj/5diG/+bZRH/nWMX/55j + Gv+bZRb/c1EP/2RbPf+ysrP/8/L4//37/v/7/f3/+v39//z+/v/+/v7//v7+//7+/v////////////// + ///////////////////////////////////////////////////////////////////+/v7//f////3+ + /v/7/v7//f7+//3+/v/8/fz/5+Xj/4SDe/+biHj/vZFo/5NkJf+XYxP/m2YT/51iGP+dYB//nmEf/5xj + F/+bZhb/kGIX/25KFP9GKQb/MycW/2RlXv+mqK7/tLu9/7i6vv/Avr//zMrI/9fU1v/X1Nb/urm4/5uU + kP+KfHP/o5B//7SZev+zjWH/pHdC/5dnKf+UZBr/nGEU/6FiE/+eZRX/mWUV/51lGP+RWRj/WDAL/0A6 + M/+4v7//9fb4//r3+P/4+v7/ysjG/4BgRP+nbir/nmQX/5djGv+dYxj/oGIW/51hGv+aYSH/m2Yt/6Jw + Of+kdET/lG1F/3xfRP+Ec2b/sqqm/9jX1//09PX//fz7//r29f/v7/L/4+fs/9ja3f+rp6T/XlZL/0Mu + FP9kQBL/hVkf/5ZhH/+cYxr/nWMY/5tiGf+aYhv/mGMZ/5pjF/+eYxv/nWUh/4BWGP9nUib/p6OS/+7u + 7f/+/P7///z+//v+/v/5/v3/+/7+//7///////////////////////////////////////////////// + //////////////////////////////////////////////7+/v/+/////f7+//z+/v/8/v7//P7+//z+ + /v/9/Pz/29nX/4R5c/+nj4H/tIpg/5hoHP+ZYhD/mWYW/5djGv+eZBv/nGEc/5ZfH/+YYxn/lGIS/3pP + Df9KLgX/MSIU/0xLS/+Jj5b/sbS8/765vP/EvLn/ysPB/8/Pzv/X1dX/0tHW/7Cwtf+Oi4v/h350/5eH + dP+okXn/r5Fu/7GJVf+rdTn/pGkl/51mH/+ZZBr/mGMZ/41YF/9VLQr/RDo3/8LGyv/9/P7//Pv9//f7 + /v/Lycf/e19G/55sLv+XYx3/k2Qf/5toIP+lain/q287/6d1Sv+ZcU//iGhO/3tjUv+Hdmz/q6Gc/9LT + 0v/s8vL/8/n6//X3+f/08fH/7ejq/+Df4//HyM3/kI+O/1RJOf9FLw3/aEUO/4tcFf+XYR3/mGEg/5ti + Hv+bYxr/mGQV/5lkFv+bYxn/n2Ic/6BkH/+IWx7/Ykwp/5KNfv/j497/+/36//39/P/7/f7/+/3+//3+ + /v/+/v7//v////////////////////////////////////////////////////////////////////// + /////////////////////////v7+///////9/////P7+//z+/v/8/v7//P7+//z+/v/5+Pn/xMPB/29m + ZP+tk4D/r4dW/5ZgGv+ZZBL/l2UV/5hkGP+bYx3/mmIf/5xjF/+bZBD/kmIV/4BVGv9XOAv/NiMM/z4z + Lv9va2v/qKWn/7+8u/++vLv/vL69/8XFxv/NztD/0dLX/87N0f+6uLf/op2X/4uFfv+LgXb/l4Rw/62Q + cf+8l2//s41h/62GVP+rf0r/m248/1g4G/9DPDn/xsvN//7+/f/7/vv/9/38/8rJx/9+aFT/rYZX/6R8 + S/+gfE//poBQ/6R9VP+ScFD/gWdP/4FwY/+OhH//sq6t/9jY1//v8O7/9Pn4//P49//u7/H/5+bq/9/f + 5P/T1Nn/srKz/3FsZP9ENiL/TTQO/3FMFv+OXhr/mmMV/5xjF/+eYxv/nWIb/5pjGf+YZRb/lmYV/5hl + Gf+eZSD/kV0f/2lIHf+Ge2//19bW//v6+v/+/vj/+/74//v+/f/9/v3//v79//7+/v////////////// + //////////////////////////////////////////////////////////////////////////////// + ///+/v7///////3////8/v///P7+//z+/v/8/v7//f7+//7+/v/29vb/uLi5/21kZv+qkoP/s4VX/5tl + G/+ZZBD/lmYV/5djGv+dYhr/nmMX/51kF/+dZBn/mWEa/4xeGP9xRw7/TCwD/zciEP9KRDz/f4J//6mr + rv+8vMD/vLu8/7y+vf/Fw8T/0MzN/9jV1//X1tf/z9HS/7e6vv+ZmJz/jYWD/4Z7cv+Fem3/koNx/6CJ + cP+ZfV//Y044/2FcVv/c39///v78//z9+f/6/f3/zs/P/4Bzav+bg23/kHpk/4VvXP+DbFj/g3Zl/5GO + gf+vsKb/0NXR/+fu7//u9Pf/8vb4//Hy8v/s6+v/5+Pk/+Da3f/V0tb/ur2//4SIhf9LRzr/OykM/1k6 + Cf+BVBf/lmAd/55iGv+gZBn/n2QX/6BkFf+fZRL/m2US/5hkFP+YZBr/mmcj/5FfIv9sShr/hXhg/9XS + zv/3+vr//Pz9//39+//6/vv/+f79//z+/P/9/vz//v79//////////////////////////////////// + /////////////////////////////////////////////////////////////////////////v////z+ + ///8/v7//P7+//z+/v/9/////v7+//z9/f/z9fX/uLq9/3lqbP+xlIH/uIta/5pnHf+ZZBH/nGQU/59i + Ff+fYhn/mmEf/5hgH/+ZYhz/nWQb/5hiFv+EUxD/YT0K/zUkBf8rKBf/UU9M/4aDgP+vrKv/uLq6/7y6 + vP+9vL7/wMHD/8nIyf/Qz8//09XY/9PU3f/MztT/wsbI/7G1uP+dnqD/m5KO/5WJfP+PiHj/urqz//j5 + +v/+/Pv//Pz5//n8/P/p7u3/tbKv/5qPiv+imZb/ta+t/8/Lyf/Z29r/4unp/+vz8f/s8vD/6/Dw/+Xq + 7P/g4+f/3d3g/9nX2P/V0dH/v768/5KSjf9dWE3/PS8a/0YuC/9qRxb/iFod/5hhHP+eYhr/oWEa/59g + Gv+aYRr/l2IY/5hlE/+eZRH/n2MU/51mI/+OYCz/bksi/4d4X//T0cv/+vj5//v5/v/6+/7/+/7+//n+ + /v/4//3//P78//7+/P/+/v7///////////////////////////////////////////////////////// + ///////////////////////////////////////////////////+/////f////z+/v/8/v7//P7+//3+ + ///9/f7/+f7+//H+/f/09Pb/trK3/3RkZf+tlYX/t49h/5poHv+cYxX/mGIY/55hG/+fYBv/lmAh/5Zi + If+aYh3/nWQW/55lFf+QXhb/b00T/0s1Df8yIAn/MiUX/1FKQf+AgYH/oqep/7C4vP+1vL//ury9/8G/ + vf/Gwb//zcnH/9LSz//T2NX/1Nnd/9Xa4v/d3OP/3d3b/9/i2//p7ur/7vDz//Dv9v/x8fb/7/H1/+/y + 9f/t7vD/6urp/+nr6//q7u//6vDx/+vr8f/r5+7/6OXm/+Pf3//a2dn/09XW/83O0//Hx8v/t7e6/5CP + kf9YWlL/NTEd/0IoCv9mPA3/hVIX/5ReIP+YYCH/mWIc/5xkFf+gZBT/n2EZ/5dhHf+QZB//kWQb/5ll + F/+jZxz/ll8i/25KIv+DdWL/z8/I//b6+P/9/vv//v39//z9/v/4/v7/9/7+//v+/v/+/v7//v79//7/ + /v////////////////////////////////////////////////////////////////////////////// + //////////////////////////////7////+/////v7+//3+/v/+/////v7///79///8/v7/9f79//39 + /f/y8fL/ubS5/3Vub/+lk4D/u5Zp/5xrMv+RXSH/m2Ad/59jGP+aYhz/mmId/5ljHf+aZBn/nWUW/51l + G/+VYR3/h1oY/29HFf9PMQj/OSQG/zUnFP9MSDr/b3Bt/5ibmf+wsK3/wLu5/8W9uf/Fvbj/xMG4/8LE + vP/Dx8b/xsjP/83N0//Q09P/0tfU/9ba2f/a2+H/3Nvl/93c5P/h3uP/4d/h/+Hg4v/d4eH/2uDe/9jf + 3P/V3Nr/1dXY/9fP1v/XzM//1MvM/87Jyf/Bv8D/pqal/4R/e/9aUUn/PTAf/zgoCf9ROAz/eE8V/5Nc + GP+eYhn/n2Ic/5xhHf+aYhv/nGUX/55mFP+dZBj/mGMd/5FiIP+PYiH/lmgo/5JjK/9zTif/inll/9LR + yv/z+Pn/+Pv9//n8+//8/Pv//f79//n9/v/6/f7//v7+/////v/+//7//v/+//////////////////// + //////////////////////////////////////////////////////////////////////////////// + ///////////////////+/v7//v7+/////////v7//v3+//79/v/9/f3//fv7//z+/f/y8/T/xMXG/4mI + hP+Xinz/vJt4/6d2Pv+YYhj/nWYU/5xkFf+cYxb/m2QY/5lkGv+aYR7/mmMb/51iGv+eYxv/mWMa/4la + F/9zTBH/WDcH/z8nBf8zIw7/OzIk/1FPRv9zcm7/kI2Q/6yrsf+ytrL/t7u3/7q7vP/AvcL/wr3B/8C/ + vv+/wr7/v8PD/8LDyf/Cxcn/xcbH/8vIw//MycP/ysjH/8XIyf/Ex8j/xcTG/8TDxf+/wcP/ury//7i4 + t/+np6X/hIaB/19fWf9AOy//OCkU/0MpCP9dOAr/ekwW/41aH/+VYR7/m2Mb/51lF/+dZBf/nGIY/5pi + GP+aZBr/mmQZ/5plF/+dZRb/oWUa/6NpKP+NXyz/dFg3/5mPf//Z2dT/9/r5//r+/v/8/v7//f3+//3+ + /P/9/vv//P79//3+/P/+//v//f/9//3////+//////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + /v////7////+///+/v/+/v7//f79//39/f/+/f3/+v7+//v9/f/3+Pj/3N/f/46LiP+MeW7/up2C/6yF + VP+XZSP/lWEZ/5tkGf+fZRX/nmQX/5xiG/+aYxj/n2QZ/59jGP+cYxj/m2Qa/5RhGv+NXRn/fVEU/2RA + DP9LLwX/NCIH/ywfD/82LCP/SkVD/11cVv98fXT/kJCK/56amv+ppqT/tbWx/7q7u/+5vL//uLy//7i9 + v/+6vr//vb6+/72+vv+9vb//uby9/7Gwsv+koqH/mZWU/4iGg/9ub2n/VVVJ/0M8L/8zKRb/MyUJ/0Yv + CP9ePw3/d1AV/49fGv+eYhr/oGEa/5xhGv+aYRj/mmMX/5pkFf+cZhX/mmYX/5dkG/+ZZBr/nGUU/59o + Hv+eay7/h1wu/3NYO/+hmYv/4+bi//j7+//6/f7/+v79//3+/v/+/v7//v7+//7+/v/+/v3//v78//// + /f/9//7//P7+//z+/v/+/////v7+//7+/v////////////////////////////////////////////// + ///////////////////////////////////////////////////////////+/////v////7////+//7/ + /v/+/v7//f7+//3+/v/7/v7//P7+//z+/v/7/Pz/5eXl/52anf9/eXn/qJKA/7yVbv+abjv/k18i/55i + Fv+hZBX/n2MU/5tjFf+cZRj/mmIZ/5liHv+YYR7/m2Mb/5xkGf+aZBf/lWIX/4dZF/91TRX/YUAN/08z + Cf89Jwj/NiMJ/zYnEP81KBj/PTMo/01FPP9dV1D/Z2Nd/2lnYv9raWL/a2hk/2toZf9qa2X/aGpk/2dl + Yv9jX1r/WFFJ/0g+M/86LyL/NiUV/zgjDf88Jgj/Si8K/18+EP90TRT/hVgY/5FeHP+ZYhz/nmQY/6Bk + Fv+eYxj/nGIb/5thG/+bYhr/mmQY/5tkF/+bZRb/l2MY/5pkG/+gayP/lWox/3lZM/9yYEz/rqeg/+zq + 6f/7+/v//P7+//z+/v/9/v7//v7+///+///////////+//7+/v/+/v7////+//7////+/v7//v7+//7/ + ///+/v7//v7+//////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////7////+/////P7+//z+ + /v/9/v7//v7+//7+/v/9/f3/7+3v/8O/wf+CdnP/nIh3/7uggf+xiVj/m2cn/5pgFv+eYhb/nGMX/5hk + GP+aZRn/mmQY/5pkGP+aYxf/mmMY/5xkGf+cZBn/mmIb/5ZiHP+TYBv/i1sZ/4FTGf92ShX/aUAP/1g1 + Cf9NLgn/RSkK/zwjCP83IQr/NiAK/zciC/87JAv/PCIL/zsiC/86Iwr/OyML/z0jCv9CJwj/Sy8K/1Q0 + Dv9jOw//dEcS/4BRGP+LWRz/lF8c/5xjGv+iZBv/o2MZ/6JiFv+hYxb/nGQZ/5hjGv+XYxv/mGMc/5hh + G/+aYxj/nGIW/51jF/+haB7/oG4u/4tlNf9yVjP/i3lh/8rDuP/y8vD//P39//z+/v/8/v7//f7+//7+ + /v////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////7////+/////v////7+/v/9/f3//f39///+ + /v/+/Pz/+fn6/9zd3/+Zl5r/fHRp/6iUev+8nXb/pn5K/5NlKP+VXxz/mF8Y/55iFf+fZRT/nWUU/5tl + Ff+bZRn/mmIb/51iGv+cZBf/nmQU/6JkFf+jYxX/o2QY/6JjGv+eYRv/mGAc/5BdHf+HWRv/flMW/3hN + E/90TBL/dEsP/3dLD/96SxD/eksQ/3lMEP97ThH/f1ET/4VWFf+NXBn/k2Ec/5VjGv+ZZBj/nGQW/5tk + Fv+bZRX/m2UT/5xlE/+dZRT/m2QU/5hkF/+VYxv/lGIc/5ZjHP+ZYhr/m2EZ/5xiGP+eYyD/pWwx/6Jw + OP+CXjX/bVxH/6CXi//k4Nr/+fv7//j9/v/6/f7/+/3+//z9/v/+/v3//v7+//////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + /////////////////////////////////////////v7+//39/f/9/f3/+/39//79/v/+/fz/+vz9/+7y + 8//EwcH/h4J7/4h+cv+tm4b/spd2/6F4SP+ZZSb/mmAX/55jFP+fZBb/nmMX/5xjGP+dYhz/mmIc/5ll + Gv+ZZBn/nGQb/55jHP+dYhv/nmIb/55iHP+dYhz/m2Ib/5ljGv+bZBr/nGUb/5tkGv+YZBr/l2Mc/5di + IP+XYx//lmQd/5dkHv+XZB3/mGQb/5xkGv+cZBj/mmQZ/5pkG/+cZRr/nWUZ/5xkF/+bYxj/mmMa/5lj + HP+YYx3/l2Qd/5hjHP+ZYxj/m2MX/51jGP+fZhz/o24s/6ByQP+HZEP/b1hE/4p9c//Gw8D/7+/w//j5 + /P/3+/7/+P3+//r9/v/8/f3//f39//7+/v///v7///////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + ///////////////////+/v7//v7+//7+/v/+/v7//f7+//39/v/8/v3//f39//r6+v/n6ez/sLCw/315 + dv+RhHn/sZh9/7qXav+ofUX/l2Yo/5VfHv+XYBv/m2Ma/51iGv+cYhn/nGIY/5tiGv+bYx7/mmMf/5li + Hf+WYhv/mGIb/5ljG/+bZBr/nGQX/51jF/+gYxf/oGMW/55kFv+dZBv/mmId/5liHP+ZYxz/m2Md/5ph + HP+ZYhn/mmQX/5xkF/+bYxv/mWEe/5thHf+dYhr/nmMa/59jG/+cYxr/mmIc/5liHv+YYR//m2Ac/51i + Gv+bZR//n20t/6F0Ov+PbD7/dl1A/3dsX/+oqKf/4+Xo//r7+//6/P7/9/r+//j7/v/8/f7//v39//39 + /P/+/v3//f7+//3+/v////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////7///7+///9/v///P7+//v8/v/9/f3//f7+//z9/v/19vj/2dzf/6mkpP+IfHP/k4Fx/6yU + e/+8mXf/sIRb/5prO/+VYSX/mGAb/51iFv+fYhP/nmIU/5xkGP+XYxf/mGQX/5plFv+bZBj/nGQY/5xk + GP+cYxn/nGIa/5xhG/+cYBv/nGIa/5tlGf+aZRn/m2Mb/51jHP+cYxv/mmMb/5ljGv+bYxr/m2Ia/5li + G/+XYhz/mGMb/5tjGf+cYxj/nWIZ/55jG/+bYhn/l2EX/5liHP+fZif/om40/6F2Rv+PbUf/d15A/3ts + Vf+nnpH/39vX//f5+f/7/f3//v3+//v9/v/7/v7//f7+//79/f/+/vz//v78//7+/f/9/v7//v7+//// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + /////////////////////////////////////////////////////////////////////////v7+//v+ + /v/6/v7//P7+//j6/v/9/v7//v36//38+v/8+/3/9/b3/+Li4f+0srH/hoB+/4t6cf+skX7/uZqA/7mR + aP+sfUb/oGwr/5xlHP+bYhb/mWEV/5lkFv+ZZRP/mmYT/5xmFP+cZRX/mmMW/5ljGf+ZYh3/mWIf/5lg + H/+bYR3/nGQY/51kF/+dZBn/nWMZ/5xjG/+cYhr/nGIa/5xhG/+cYRr/nGMZ/5tkFv+cZBT/nWQU/55j + FP+cYhb/m2Eb/5xlH/+ibyn/qno7/6R5Sf+ScU3/emFK/3lqXv+inZr/3Nva//f19v/8/Pz//f78//3+ + /P/9/v7//P7+//3//f/9/v3//v79//7+/f/+/vv///78//3//v/+//////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + /////////////////////////////////////////////////v/+/v7//P7+//z//v/9/v3/+v3+//z+ + /v/+/fr//f36//79/P/+/v3//f38//f4+f/k5uv/ubi6/5aQif+HfnL/k4Nw/6qRdP+8nXf/tY9k/66C + UP+gcjz/lmYr/5ZiH/+WXxn/ll4Y/5hfGf+ZYRr/mmIb/5piHP+aYRz/mmEd/5tiG/+dZBj/nWQX/51k + GP+cZBj/m2MZ/5tjGf+aYhn/l2Ea/5lhGf+cYBn/nV8Y/59hG/+gYiD/omcq/6dyOv+peEj/qXpR/51z + Tf+HZUT/eWRN/4Z8b/+vqaT/29va//T3+P/7/f3//f39//79+//+/vr//v77//7+/f/+/v7//v7+//7+ + /f/+/v3//v/9//7+/f/+/v3//f7+//7///////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////7////9/////f////3/ + ///9///////////////////////+//7+/v/+/v///v7+//3+/f/9/v7//f39//39/P/8/f3/+v79//r+ + /f/8/v7//f39//v8/P/3+vr/7PHv/9HV1P+srKv/kY6M/352cf+Pf3P/qpF//7GTff+6l3f/uY9i/7GD + Uf+mdkH/oG40/51pKf+fZyL/n2Qb/6BjF/+eYhX/m2IW/5tiGP+bYBn/m2AZ/5pgGv+aYhv/m2Md/5pk + H/+daCT/oWso/6BtLf+jdDj/qn1F/6uCUP+iflT/lXZV/4RtV/9wYlP/fHNt/5+bmv+/wsH/5Ono//b5 + +f/6+/v/+/z7//3+/P/9/v3//f39//z8/P/8/P3//P7+//z+/v/8/v7//P7+//z+/f/9/v7//v/+//7+ + /v/+/v7//v////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + /////////////////////////////////////////v////3////9//////////////////////////// + //////////////////////////////////////////////7////9/v7//v7+///+/v/+/v7//v7+//3+ + /v/9/////P7///v9/v/09vf/2tvb/7i1s/+XkI7/h359/4B2cP+KfW7/lINy/6SQff+tlX7/r5J3/6+M + bP+ximb/s4hj/7OIXv+zh1n/s4Za/7OHXP+yh1z/sYZb/66FW/+thFv/q4Ne/6mDYP+qhWT/nIFp/4d3 + Z/97bV7/d2hZ/3puZf+KgX3/p6Ge/8/Mzf/v7fD//vv///7+/v/+/v7///7///79/v/9/f3////+//// + /v/+/v7//v3+//7+/////////f7+//z+/v/8/v7//v////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////7+///+/v///////v7+//39/f///v7///7+//// + /v/+/v7//v7+//v7/P/n6Oz/y8vO/727vP+jo6H/h4SD/395df+Gfnb/iH1y/4R2Z/+KeWn/jnxq/418 + af+Memn/jHlq/4t5af+Jemj/hXdl/35wYf9+cWP/g3Zp/4J1av9+dnD/j4qI/6+rqv/HxcT/3Nze//P0 + 9v/9/v7//P7+//3+/v///v3///38//7//v/9/////f////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////+/////f///v7+//z8/P/+/v3//v/9//7/ + /v/9/////f7///j9/v/z+Pn/7fLy/+nt7P/X2tn/vL+8/6qrpv+kpaD/paOi/6ako/+lo6P/paOi/6Wm + pP+mqKb/sLKx/8bIyf/g4uX/7fD1//P09v/6+ff////9//7////9//////////3+/v/8/v7//P39//39 + /f///////v////3///////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + /////////////////////////////////////////////////////////////////////////v7+//3+ + /v/9/////////////////////v////z//v/7/v3//P39//7+/v/9/vz//f78//3//f/9//////////// + ///+/////f7///79///+/f/////////////+/v7//v7+//////////////////7+/v/+/v7//v3///39 + ///9/v////7//////v/+//3//v79//7+/v/8/f7/+/3+//3+/////v////7///79///+/f/////+//// + /v////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + ///+/v7//f7+//3+/v/+/f7//v3//////v///v3///79///+/f///fz///38///////+/v///v3////9 + /////f///v3+//3+/P////7//v/9//7//f////7////+//7//f/9//3//f79//3+/P///v7//f39//v9 + /f/9////+/7///n+/f/7/vz//P/9//3+/P/9/vz//v/9//////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + /////////////////////////v7+//7+/v/////////////////////////////+///+/v7//P3+//79 + /////v/////////////+//7//P78//7++v/+//v//v/9//3+/P/9/vz//f78//7+/f/9/f3/+/39//v+ + /v/7////+v7///r+///8/v///P7///3+///+/////f///////v/+//7//f////3//////////P////r+ + /v/8/v7//v7+/////v////7///////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + ///////////////////+/v7//v7+/////////////////////v////7////+//7//v/9//7///////3/ + /v/6//3/+v/+//n+/f/5/v3//P7+//3//f/+//3///79///+/f///v3//v7+//3+/v/8/v7//P7+//z+ + /v/+/v7//v7+//7+/v///////v7///z9///7/////P////3//v/8/v3//f7+///+/////v///v7///3/ + /v////7//////////v////7//////////////////////////////v////7///////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////8AAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAA + + + \ No newline at end of file diff --git a/trxGui/Form_info.Designer.cs b/trxGui/Form_info.Designer.cs new file mode 100644 index 0000000..980d45e --- /dev/null +++ b/trxGui/Form_info.Designer.cs @@ -0,0 +1,122 @@ + +namespace trxGui +{ + partial class Form_info + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(Form_info)); + this.textBox1 = new System.Windows.Forms.TextBox(); + this.button_ok = new System.Windows.Forms.Button(); + this.textBox2 = new System.Windows.Forms.TextBox(); + this.panel1 = new System.Windows.Forms.Panel(); + this.button_manual = new System.Windows.Forms.Button(); + this.SuspendLayout(); + // + // textBox1 + // + this.textBox1.BackColor = System.Drawing.SystemColors.Control; + this.textBox1.BorderStyle = System.Windows.Forms.BorderStyle.None; + this.textBox1.Font = new System.Drawing.Font("Courier New", 10F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.textBox1.Location = new System.Drawing.Point(4, 96); + this.textBox1.Multiline = true; + this.textBox1.Name = "textBox1"; + this.textBox1.ReadOnly = true; + this.textBox1.Size = new System.Drawing.Size(364, 208); + this.textBox1.TabIndex = 0; + this.textBox1.Text = resources.GetString("textBox1.Text"); + // + // button_ok + // + this.button_ok.DialogResult = System.Windows.Forms.DialogResult.OK; + this.button_ok.Location = new System.Drawing.Point(704, 387); + this.button_ok.Name = "button_ok"; + this.button_ok.Size = new System.Drawing.Size(75, 23); + this.button_ok.TabIndex = 1; + this.button_ok.Text = "OK"; + this.button_ok.UseVisualStyleBackColor = true; + // + // textBox2 + // + this.textBox2.BackColor = System.Drawing.SystemColors.Control; + this.textBox2.BorderStyle = System.Windows.Forms.BorderStyle.None; + this.textBox2.Font = new System.Drawing.Font("Courier New", 10F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.textBox2.Location = new System.Drawing.Point(384, 96); + this.textBox2.Multiline = true; + this.textBox2.Name = "textBox2"; + this.textBox2.ReadOnly = true; + this.textBox2.Size = new System.Drawing.Size(347, 275); + this.textBox2.TabIndex = 2; + this.textBox2.Text = resources.GetString("textBox2.Text"); + // + // panel1 + // + this.panel1.BackgroundImage = global::trxGui.Properties.Resources.amsat_logo; + this.panel1.BackgroundImageLayout = System.Windows.Forms.ImageLayout.Zoom; + this.panel1.Location = new System.Drawing.Point(13, 7); + this.panel1.Name = "panel1"; + this.panel1.Size = new System.Drawing.Size(766, 84); + this.panel1.TabIndex = 3; + // + // button_manual + // + this.button_manual.Location = new System.Drawing.Point(13, 328); + this.button_manual.Name = "button_manual"; + this.button_manual.Size = new System.Drawing.Size(228, 23); + this.button_manual.TabIndex = 4; + this.button_manual.Text = "Open Manual"; + this.button_manual.UseVisualStyleBackColor = true; + this.button_manual.Click += new System.EventHandler(this.button_manual_Click); + // + // Form_info + // + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.BackColor = System.Drawing.SystemColors.Control; + this.ClientSize = new System.Drawing.Size(784, 422); + this.Controls.Add(this.button_manual); + this.Controls.Add(this.panel1); + this.Controls.Add(this.textBox2); + this.Controls.Add(this.button_ok); + this.Controls.Add(this.textBox1); + this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedToolWindow; + this.Name = "Form_info"; + this.Text = "Information"; + this.ResumeLayout(false); + this.PerformLayout(); + + } + + #endregion + + private System.Windows.Forms.TextBox textBox1; + private System.Windows.Forms.Button button_ok; + private System.Windows.Forms.TextBox textBox2; + private System.Windows.Forms.Panel panel1; + private System.Windows.Forms.Button button_manual; + } +} \ No newline at end of file diff --git a/trxGui/Form_info.cs b/trxGui/Form_info.cs new file mode 100644 index 0000000..528b2bf --- /dev/null +++ b/trxGui/Form_info.cs @@ -0,0 +1,36 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Data; +using System.Drawing; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows.Forms; + +namespace trxGui +{ + public partial class Form_info : Form + { + public Form_info() + { + InitializeComponent(); + + this.Width = 800; + button_ok.Location = new Point(Width - button_ok.Width - 30, Height - button_ok.Height - 30); + + foreach (Control c in Controls) + c.Text = language.GetText(c.Text); + + textBox1.Select(0, 0); + } + + private void button_manual_Click(object sender, EventArgs e) + { + if(statics.language == 0) + statics.OpenUrl("https://wiki.amsat-dl.org/doku.php?id=en:plutotrx:overview"); + if (statics.language == 1) + statics.OpenUrl("https://wiki.amsat-dl.org/doku.php?id=de:plutotrx:overview"); + } + } +} diff --git a/trxGui/Form_info.resx b/trxGui/Form_info.resx new file mode 100644 index 0000000..3f21a6f --- /dev/null +++ b/trxGui/Form_info.resx @@ -0,0 +1,148 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + AMSAT-DL QO-100 DSP Transceiver for +Adalm-Pluto and Linux +by DJ0ABR + +Open Source: https://github.com/dj0abr/QO100_Transceiver + +Manual (English / German): +https://wiki.amsat-dl.org/doku.php?id=en:plutotrx:overview + + + Credits: +======== +J.Gaeddert for his exceptional DSP library: +https://github.com/jgaeddert/liquid-dsp +MIT License + +Icons: + +Artist: Fatcow Web Hosting, +Iconset: Farm Fresh Icons (3000 icons), +License: CC Attribution 4.0 + +Artist: Oxygen Team, +Iconset: Oxygen Icons (883 icons) +License: GNU Lesser General Public License + + + \ No newline at end of file diff --git a/trxGui/Form_reference.Designer.cs b/trxGui/Form_reference.Designer.cs new file mode 100644 index 0000000..24e6ab5 --- /dev/null +++ b/trxGui/Form_reference.Designer.cs @@ -0,0 +1,281 @@ + +namespace trxGui +{ + partial class Form_reference + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + this.label1 = new System.Windows.Forms.Label(); + this.label3 = new System.Windows.Forms.Label(); + this.button_cal439 = new System.Windows.Forms.Button(); + this.label4 = new System.Windows.Forms.Label(); + this.label5 = new System.Windows.Forms.Label(); + this.label_cal439 = new System.Windows.Forms.Label(); + this.button_fin = new System.Windows.Forms.Button(); + this.label2 = new System.Windows.Forms.Label(); + this.label6 = new System.Windows.Forms.Label(); + this.label7 = new System.Windows.Forms.Label(); + this.button_lnbfinished = new System.Windows.Forms.Button(); + this.label_caliblnb = new System.Windows.Forms.Label(); + this.label9 = new System.Windows.Forms.Label(); + this.button_caliblnb = new System.Windows.Forms.Button(); + this.label11 = new System.Windows.Forms.Label(); + this.button_close = new System.Windows.Forms.Button(); + this.panel1 = new System.Windows.Forms.Panel(); + this.label8 = new System.Windows.Forms.Label(); + this.SuspendLayout(); + // + // label1 + // + this.label1.AutoSize = true; + this.label1.Font = new System.Drawing.Font("Microsoft Sans Serif", 12F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.label1.Location = new System.Drawing.Point(13, 13); + this.label1.Name = "label1"; + this.label1.Size = new System.Drawing.Size(234, 20); + this.label1.TabIndex = 0; + this.label1.Text = "PLUTO clock (TCXO) calibration"; + // + // label3 + // + this.label3.AutoSize = true; + this.label3.Location = new System.Drawing.Point(17, 52); + this.label3.Name = "label3"; + this.label3.Size = new System.Drawing.Size(149, 13); + this.label3.TabIndex = 2; + this.label3.Text = "1. click the CALIB439 button: "; + // + // button_cal439 + // + this.button_cal439.Location = new System.Drawing.Point(208, 47); + this.button_cal439.Name = "button_cal439"; + this.button_cal439.Size = new System.Drawing.Size(75, 23); + this.button_cal439.TabIndex = 3; + this.button_cal439.Text = "CALIB 439"; + this.button_cal439.UseVisualStyleBackColor = true; + this.button_cal439.Click += new System.EventHandler(this.button_cal439_Click); + // + // label4 + // + this.label4.AutoSize = true; + this.label4.Location = new System.Drawing.Point(17, 75); + this.label4.Name = "label4"; + this.label4.Size = new System.Drawing.Size(284, 13); + this.label4.TabIndex = 4; + this.label4.Text = "2. transmit a 439,000 MHz carrier using a 70cm transceiver"; + // + // label5 + // + this.label5.AutoSize = true; + this.label5.Location = new System.Drawing.Point(17, 117); + this.label5.Name = "label5"; + this.label5.Size = new System.Drawing.Size(266, 13); + this.label5.TabIndex = 5; + this.label5.Text = "4. when you are done, click the 439 FINISHED button:"; + // + // label_cal439 + // + this.label_cal439.AutoSize = true; + this.label_cal439.ForeColor = System.Drawing.Color.Red; + this.label_cal439.Location = new System.Drawing.Point(289, 52); + this.label_cal439.Name = "label_cal439"; + this.label_cal439.Size = new System.Drawing.Size(16, 13); + this.label_cal439.TabIndex = 6; + this.label_cal439.Text = "..."; + // + // button_fin + // + this.button_fin.Location = new System.Drawing.Point(340, 113); + this.button_fin.Name = "button_fin"; + this.button_fin.Size = new System.Drawing.Size(98, 23); + this.button_fin.TabIndex = 7; + this.button_fin.Text = "439 FINISHED"; + this.button_fin.UseVisualStyleBackColor = true; + this.button_fin.Click += new System.EventHandler(this.button_fin_Click); + // + // label2 + // + this.label2.AutoSize = true; + this.label2.Font = new System.Drawing.Font("Microsoft Sans Serif", 12F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.label2.Location = new System.Drawing.Point(13, 152); + this.label2.Name = "label2"; + this.label2.Size = new System.Drawing.Size(120, 20); + this.label2.TabIndex = 8; + this.label2.Text = "LNB calibration:"; + // + // label6 + // + this.label6.AutoSize = true; + this.label6.Location = new System.Drawing.Point(17, 97); + this.label6.Name = "label6"; + this.label6.Size = new System.Drawing.Size(367, 13); + this.label6.TabIndex = 9; + this.label6.Text = "3. Click the peak with the left mouse button to move it to the center 0 Hz line"; + // + // label7 + // + this.label7.AutoSize = true; + this.label7.Location = new System.Drawing.Point(17, 212); + this.label7.Name = "label7"; + this.label7.Size = new System.Drawing.Size(440, 13); + this.label7.TabIndex = 16; + this.label7.Text = "2. Click the center of the BPSK beacon with the left mouse button to move it to t" + + "he 0 Hz line"; + // + // button_lnbfinished + // + this.button_lnbfinished.Location = new System.Drawing.Point(334, 366); + this.button_lnbfinished.Name = "button_lnbfinished"; + this.button_lnbfinished.Size = new System.Drawing.Size(114, 23); + this.button_lnbfinished.TabIndex = 15; + this.button_lnbfinished.Text = "LNB FINISHED"; + this.button_lnbfinished.UseVisualStyleBackColor = true; + this.button_lnbfinished.Click += new System.EventHandler(this.button_lnbfinished_Click); + // + // label_caliblnb + // + this.label_caliblnb.AutoSize = true; + this.label_caliblnb.ForeColor = System.Drawing.Color.Red; + this.label_caliblnb.Location = new System.Drawing.Point(294, 191); + this.label_caliblnb.Name = "label_caliblnb"; + this.label_caliblnb.Size = new System.Drawing.Size(16, 13); + this.label_caliblnb.TabIndex = 14; + this.label_caliblnb.Text = "..."; + // + // label9 + // + this.label9.AutoSize = true; + this.label9.Location = new System.Drawing.Point(17, 370); + this.label9.Name = "label9"; + this.label9.Size = new System.Drawing.Size(269, 13); + this.label9.TabIndex = 13; + this.label9.Text = "3. when you are done, click the LNB FINISHED button:"; + // + // button_caliblnb + // + this.button_caliblnb.Location = new System.Drawing.Point(213, 186); + this.button_caliblnb.Name = "button_caliblnb"; + this.button_caliblnb.Size = new System.Drawing.Size(75, 23); + this.button_caliblnb.TabIndex = 11; + this.button_caliblnb.Text = "CALIB LNB"; + this.button_caliblnb.UseVisualStyleBackColor = true; + this.button_caliblnb.Click += new System.EventHandler(this.button_caliblnb_Click); + // + // label11 + // + this.label11.AutoSize = true; + this.label11.Location = new System.Drawing.Point(17, 191); + this.label11.Name = "label11"; + this.label11.Size = new System.Drawing.Size(155, 13); + this.label11.TabIndex = 10; + this.label11.Text = "1. click the CALIB LNB button: "; + // + // button_close + // + this.button_close.Location = new System.Drawing.Point(378, 409); + this.button_close.Name = "button_close"; + this.button_close.Size = new System.Drawing.Size(75, 23); + this.button_close.TabIndex = 17; + this.button_close.Text = "Close"; + this.button_close.UseVisualStyleBackColor = true; + this.button_close.Click += new System.EventHandler(this.button_close_Click); + // + // panel1 + // + this.panel1.BackgroundImage = global::trxGui.Properties.Resources.bcn_center; + this.panel1.BackgroundImageLayout = System.Windows.Forms.ImageLayout.Stretch; + this.panel1.Location = new System.Drawing.Point(20, 245); + this.panel1.Name = "panel1"; + this.panel1.Size = new System.Drawing.Size(155, 114); + this.panel1.TabIndex = 18; + // + // label8 + // + this.label8.AutoSize = true; + this.label8.Location = new System.Drawing.Point(17, 229); + this.label8.Name = "label8"; + this.label8.Size = new System.Drawing.Size(50, 13); + this.label8.TabIndex = 19; + this.label8.Text = "Example:"; + // + // Form_reference + // + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.ClientSize = new System.Drawing.Size(462, 440); + this.ControlBox = false; + this.Controls.Add(this.label8); + this.Controls.Add(this.panel1); + this.Controls.Add(this.button_close); + this.Controls.Add(this.label7); + this.Controls.Add(this.button_lnbfinished); + this.Controls.Add(this.label_caliblnb); + this.Controls.Add(this.label9); + this.Controls.Add(this.button_caliblnb); + this.Controls.Add(this.label11); + this.Controls.Add(this.label6); + this.Controls.Add(this.label2); + this.Controls.Add(this.button_fin); + this.Controls.Add(this.label_cal439); + this.Controls.Add(this.label5); + this.Controls.Add(this.label4); + this.Controls.Add(this.button_cal439); + this.Controls.Add(this.label3); + this.Controls.Add(this.label1); + this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedSingle; + this.MaximizeBox = false; + this.MinimizeBox = false; + this.Name = "Form_reference"; + this.ShowIcon = false; + this.Text = "Referenz Frequency Calibration"; + this.TopMost = true; + this.ResumeLayout(false); + this.PerformLayout(); + + } + + #endregion + + private System.Windows.Forms.Label label1; + private System.Windows.Forms.Label label3; + private System.Windows.Forms.Button button_cal439; + private System.Windows.Forms.Label label4; + private System.Windows.Forms.Label label5; + private System.Windows.Forms.Label label_cal439; + private System.Windows.Forms.Button button_fin; + private System.Windows.Forms.Label label2; + private System.Windows.Forms.Label label6; + private System.Windows.Forms.Label label7; + private System.Windows.Forms.Button button_lnbfinished; + private System.Windows.Forms.Label label_caliblnb; + private System.Windows.Forms.Label label9; + private System.Windows.Forms.Button button_caliblnb; + private System.Windows.Forms.Label label11; + private System.Windows.Forms.Button button_close; + private System.Windows.Forms.Panel panel1; + private System.Windows.Forms.Label label8; + } +} \ No newline at end of file diff --git a/trxGui/Form_reference.cs b/trxGui/Form_reference.cs new file mode 100644 index 0000000..f343089 --- /dev/null +++ b/trxGui/Form_reference.cs @@ -0,0 +1,76 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Data; +using System.Drawing; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows.Forms; + +namespace trxGui +{ + public partial class Form_reference : Form + { + public Form_reference() + { + InitializeComponent(); + + foreach (Control c in Controls) + c.Text = language.GetText(c.Text); + } + + private void button_cal439_Click(object sender, EventArgs e) + { + // set receiver to standard values, clear any offset correction + statics.calfreq = statics.calbasefreq; // shift the carrier into the center + statics.sendReferenceOffset(0); + statics.sendBaseQRG(statics.calfreq); + statics.calmode = 1; + label_cal439.Text = " CALIBRATING ... click 439 MHz peak"; + } + + private void button_fin_Click(object sender, EventArgs e) + { + statics.calmode = 0; + label_cal439.Text = ""; + + Int64 calibrFr = statics.calfreq;// + 250000; + Int64 shift439 = calibrFr - statics.calbasefreq; + Console.WriteLine("calbasefreq: " + statics.calbasefreq + " calibrFr: " + calibrFr); + // shift439 ... this is the pluto-TCXO error related to 439 MHz + //Int64 shift40 = shift439 * 40000000 / statics.calbasefreq; + int shiftRXqrg = (int)(shift439 * statics.rxqrg / statics.calbasefreq); + + Console.WriteLine("error 439 MHz: " + shift439 + "error " + statics.rxqrg / 1e6 + " MHz: " + shiftRXqrg); + statics.sendReferenceOffset(shiftRXqrg); + + // set back to QO100 frequencies + statics.sendBaseQRG(); + } + + private void button_caliblnb_Click(object sender, EventArgs e) + { + statics.RXoffset = 280000; + statics.TXoffset = 280000; + statics.lnboffset = 0; + statics.sendRXTXoffset(); + statics.sendBaseQRG(); + statics.calmode = 2; + label_caliblnb.Text = " CALIBRATING ... click center of BPSK beacon"; + } + + private void button_lnbfinished_Click(object sender, EventArgs e) + { + statics.calmode = 0; + } + + private void button_close_Click(object sender, EventArgs e) + { + if (statics.calmode != 0) + MessageBox.Show("FINISH calibration before closing this window","CALIBRATION in progress",MessageBoxButtons.OK,MessageBoxIcon.Exclamation); + else + Close(); + } + } +} diff --git a/trxGui/Form_reference.resx b/trxGui/Form_reference.resx new file mode 100644 index 0000000..29dcb1b --- /dev/null +++ b/trxGui/Form_reference.resx @@ -0,0 +1,120 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/trxGui/Form_screen.Designer.cs b/trxGui/Form_screen.Designer.cs new file mode 100755 index 0000000..52584d9 --- /dev/null +++ b/trxGui/Form_screen.Designer.cs @@ -0,0 +1,78 @@ + +namespace trxGui +{ + partial class Form_screen + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + this.comboBox1 = new System.Windows.Forms.ComboBox(); + this.SuspendLayout(); + // + // comboBox1 + // + this.comboBox1.FormattingEnabled = true; + this.comboBox1.Items.AddRange(new object[] { + "1920x1080", + "1600x1050", + "1280x720", + "1280x480", + "1024x768", + "1024x600", + "800x600", + "800x480", + "640x480", + "480x320"}); + this.comboBox1.Location = new System.Drawing.Point(2, 1); + this.comboBox1.Name = "comboBox1"; + this.comboBox1.Size = new System.Drawing.Size(139, 21); + this.comboBox1.TabIndex = 0; + this.comboBox1.Text = "1920x1080"; + this.comboBox1.DropDownClosed += new System.EventHandler(this.comboBox1_DropDownClosed); + // + // Form_screen + // + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.ClientSize = new System.Drawing.Size(155, 77); + this.Controls.Add(this.comboBox1); + this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedToolWindow; + this.MaximizeBox = false; + this.MinimizeBox = false; + this.Name = "Form_screen"; + this.ShowIcon = false; + this.ShowInTaskbar = false; + this.Text = "Monitor X x Y Pixel"; + this.TopMost = true; + this.ResumeLayout(false); + + } + + #endregion + + private System.Windows.Forms.ComboBox comboBox1; + } +} \ No newline at end of file diff --git a/trxGui/Form_screen.cs b/trxGui/Form_screen.cs new file mode 100755 index 0000000..bc83cbd --- /dev/null +++ b/trxGui/Form_screen.cs @@ -0,0 +1,33 @@ +using System; +using System.Windows.Forms; + +namespace trxGui +{ + public partial class Form_screen : Form + { + public Form_screen() + { + InitializeComponent(); + + this.Height = 80; + this.Width = 180; + + comboBox1.Width = 140; + + try + { + comboBox1.SelectedIndex = statics.windowsize; + } + catch + { + comboBox1.SelectedIndex = 0; + } + } + + private void comboBox1_DropDownClosed(object sender, EventArgs e) + { + statics.windowsize = comboBox1.SelectedIndex; + Close(); + } + } +} diff --git a/trxGui/Form_screen.resx b/trxGui/Form_screen.resx new file mode 100755 index 0000000..29dcb1b --- /dev/null +++ b/trxGui/Form_screen.resx @@ -0,0 +1,120 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/trxGui/Form_setup.Designer.cs b/trxGui/Form_setup.Designer.cs new file mode 100755 index 0000000..0543a14 --- /dev/null +++ b/trxGui/Form_setup.Designer.cs @@ -0,0 +1,546 @@ + +namespace trxGui +{ + partial class Form_setup + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + this.button1 = new System.Windows.Forms.Button(); + this.button2 = new System.Windows.Forms.Button(); + this.cb_audioPB = new System.Windows.Forms.ComboBox(); + this.label10 = new System.Windows.Forms.Label(); + this.label11 = new System.Windows.Forms.Label(); + this.cb_audioCAP = new System.Windows.Forms.ComboBox(); + this.tb_txqrg = new System.Windows.Forms.TextBox(); + this.label6 = new System.Windows.Forms.Label(); + this.label2 = new System.Windows.Forms.Label(); + this.tb_rxqrg = new System.Windows.Forms.TextBox(); + this.label3 = new System.Windows.Forms.Label(); + this.label1 = new System.Windows.Forms.Label(); + this.label4 = new System.Windows.Forms.Label(); + this.rb_plutousb = new System.Windows.Forms.RadioButton(); + this.rb_plutoeth = new System.Windows.Forms.RadioButton(); + this.tb_plutoip = new System.Windows.Forms.TextBox(); + this.label5 = new System.Windows.Forms.Label(); + this.label7 = new System.Windows.Forms.Label(); + this.tb_plutooffset = new System.Windows.Forms.TextBox(); + this.label8 = new System.Windows.Forms.Label(); + this.label9 = new System.Windows.Forms.Label(); + this.tb_lnboffset = new System.Windows.Forms.TextBox(); + this.label12 = new System.Windows.Forms.Label(); + this.comboBox_cpuspeed = new System.Windows.Forms.ComboBox(); + this.label13 = new System.Windows.Forms.Label(); + this.label14 = new System.Windows.Forms.Label(); + this.button3 = new System.Windows.Forms.Button(); + this.label15 = new System.Windows.Forms.Label(); + this.comboBox1 = new System.Windows.Forms.ComboBox(); + this.label16 = new System.Windows.Forms.Label(); + this.comboBox_color = new System.Windows.Forms.ComboBox(); + this.label17 = new System.Windows.Forms.Label(); + this.textBox_txpower = new System.Windows.Forms.TextBox(); + this.label18 = new System.Windows.Forms.Label(); + this.button_shutdown = new System.Windows.Forms.Button(); + this.cb_autosync = new System.Windows.Forms.CheckBox(); + this.label19 = new System.Windows.Forms.Label(); + this.label20 = new System.Windows.Forms.Label(); + this.cb_pttmode = new System.Windows.Forms.ComboBox(); + this.SuspendLayout(); + // + // button1 + // + this.button1.DialogResult = System.Windows.Forms.DialogResult.Cancel; + this.button1.Location = new System.Drawing.Point(588, 301); + this.button1.Name = "button1"; + this.button1.Size = new System.Drawing.Size(75, 23); + this.button1.TabIndex = 0; + this.button1.Text = "Cancel"; + this.button1.UseVisualStyleBackColor = true; + // + // button2 + // + this.button2.DialogResult = System.Windows.Forms.DialogResult.OK; + this.button2.Location = new System.Drawing.Point(507, 301); + this.button2.Name = "button2"; + this.button2.Size = new System.Drawing.Size(75, 23); + this.button2.TabIndex = 1; + this.button2.Text = "OK"; + this.button2.UseVisualStyleBackColor = true; + this.button2.Click += new System.EventHandler(this.button2_Click); + // + // cb_audioPB + // + this.cb_audioPB.FormattingEnabled = true; + this.cb_audioPB.Location = new System.Drawing.Point(154, 47); + this.cb_audioPB.Name = "cb_audioPB"; + this.cb_audioPB.Size = new System.Drawing.Size(509, 21); + this.cb_audioPB.TabIndex = 2; + // + // label10 + // + this.label10.AutoSize = true; + this.label10.Location = new System.Drawing.Point(12, 50); + this.label10.Name = "label10"; + this.label10.Size = new System.Drawing.Size(133, 13); + this.label10.TabIndex = 11; + this.label10.Text = "Loadspeaker/Headphone:"; + // + // label11 + // + this.label11.AutoSize = true; + this.label11.Location = new System.Drawing.Point(12, 76); + this.label11.Name = "label11"; + this.label11.Size = new System.Drawing.Size(66, 13); + this.label11.TabIndex = 12; + this.label11.Text = "Microphone:"; + // + // cb_audioCAP + // + this.cb_audioCAP.FormattingEnabled = true; + this.cb_audioCAP.Location = new System.Drawing.Point(154, 74); + this.cb_audioCAP.Name = "cb_audioCAP"; + this.cb_audioCAP.Size = new System.Drawing.Size(509, 21); + this.cb_audioCAP.TabIndex = 13; + // + // tb_txqrg + // + this.tb_txqrg.Location = new System.Drawing.Point(154, 127); + this.tb_txqrg.Name = "tb_txqrg"; + this.tb_txqrg.Size = new System.Drawing.Size(137, 20); + this.tb_txqrg.TabIndex = 21; + // + // label6 + // + this.label6.AutoSize = true; + this.label6.Location = new System.Drawing.Point(12, 128); + this.label6.Name = "label6"; + this.label6.Size = new System.Drawing.Size(115, 13); + this.label6.TabIndex = 20; + this.label6.Text = "Transmitter Frequency:"; + // + // label2 + // + this.label2.AutoSize = true; + this.label2.Font = new System.Drawing.Font("Microsoft Sans Serif", 7F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.label2.Location = new System.Drawing.Point(295, 104); + this.label2.Name = "label2"; + this.label2.Size = new System.Drawing.Size(307, 13); + this.label2.TabIndex = 27; + this.label2.Text = "MHz ( enter center frequency corresponding to 10489.750 MHz )"; + // + // tb_rxqrg + // + this.tb_rxqrg.Location = new System.Drawing.Point(154, 101); + this.tb_rxqrg.Name = "tb_rxqrg"; + this.tb_rxqrg.Size = new System.Drawing.Size(137, 20); + this.tb_rxqrg.TabIndex = 26; + // + // label3 + // + this.label3.AutoSize = true; + this.label3.Location = new System.Drawing.Point(12, 102); + this.label3.Name = "label3"; + this.label3.Size = new System.Drawing.Size(106, 13); + this.label3.TabIndex = 25; + this.label3.Text = "Receiver Frequency:"; + // + // label1 + // + this.label1.AutoSize = true; + this.label1.Font = new System.Drawing.Font("Microsoft Sans Serif", 7F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.label1.Location = new System.Drawing.Point(295, 130); + this.label1.Name = "label1"; + this.label1.Size = new System.Drawing.Size(301, 13); + this.label1.TabIndex = 28; + this.label1.Text = "MHz ( enter center frequency corresponding to 2400.250 MHz )"; + // + // label4 + // + this.label4.AutoSize = true; + this.label4.Location = new System.Drawing.Point(12, 15); + this.label4.Name = "label4"; + this.label4.Size = new System.Drawing.Size(75, 13); + this.label4.TabIndex = 31; + this.label4.Text = "Pluto Address:"; + // + // rb_plutousb + // + this.rb_plutousb.AutoSize = true; + this.rb_plutousb.Checked = true; + this.rb_plutousb.Location = new System.Drawing.Point(154, 15); + this.rb_plutousb.Name = "rb_plutousb"; + this.rb_plutousb.Size = new System.Drawing.Size(72, 17); + this.rb_plutousb.TabIndex = 32; + this.rb_plutousb.TabStop = true; + this.rb_plutousb.Text = "local USB"; + this.rb_plutousb.UseVisualStyleBackColor = true; + this.rb_plutousb.CheckedChanged += new System.EventHandler(this.rb_plutousb_CheckedChanged); + // + // rb_plutoeth + // + this.rb_plutoeth.AutoSize = true; + this.rb_plutoeth.Location = new System.Drawing.Point(259, 15); + this.rb_plutoeth.Name = "rb_plutoeth"; + this.rb_plutoeth.Size = new System.Drawing.Size(65, 17); + this.rb_plutoeth.TabIndex = 33; + this.rb_plutoeth.Text = "Ethernet"; + this.rb_plutoeth.UseVisualStyleBackColor = true; + this.rb_plutoeth.CheckedChanged += new System.EventHandler(this.rb_plutoeth_CheckedChanged); + // + // tb_plutoip + // + this.tb_plutoip.Enabled = false; + this.tb_plutoip.Location = new System.Drawing.Point(330, 14); + this.tb_plutoip.Name = "tb_plutoip"; + this.tb_plutoip.Size = new System.Drawing.Size(142, 20); + this.tb_plutoip.TabIndex = 34; + // + // label5 + // + this.label5.AutoSize = true; + this.label5.Location = new System.Drawing.Point(480, 17); + this.label5.Name = "label5"; + this.label5.Size = new System.Drawing.Size(141, 13); + this.label5.TabIndex = 35; + this.label5.Text = "enter IP address of the Pluto"; + // + // label7 + // + this.label7.AutoSize = true; + this.label7.Font = new System.Drawing.Font("Microsoft Sans Serif", 7F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.label7.Location = new System.Drawing.Point(295, 157); + this.label7.Name = "label7"; + this.label7.Size = new System.Drawing.Size(340, 13); + this.label7.TabIndex = 38; + this.label7.Text = "Hz (correction value for the Pluto TCXO, or use CAL calibration function)"; + // + // tb_plutooffset + // + this.tb_plutooffset.Location = new System.Drawing.Point(154, 153); + this.tb_plutooffset.Name = "tb_plutooffset"; + this.tb_plutooffset.Size = new System.Drawing.Size(137, 20); + this.tb_plutooffset.TabIndex = 37; + // + // label8 + // + this.label8.AutoSize = true; + this.label8.Location = new System.Drawing.Point(12, 154); + this.label8.Name = "label8"; + this.label8.Size = new System.Drawing.Size(65, 13); + this.label8.TabIndex = 36; + this.label8.Text = "Pluto Offset:"; + // + // label9 + // + this.label9.AutoSize = true; + this.label9.Font = new System.Drawing.Font("Microsoft Sans Serif", 7F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.label9.Location = new System.Drawing.Point(295, 183); + this.label9.Name = "label9"; + this.label9.Size = new System.Drawing.Size(306, 13); + this.label9.TabIndex = 41; + this.label9.Text = "Hz (correction value for the LNB, or use CAL calibration function)"; + // + // tb_lnboffset + // + this.tb_lnboffset.Location = new System.Drawing.Point(154, 179); + this.tb_lnboffset.Name = "tb_lnboffset"; + this.tb_lnboffset.Size = new System.Drawing.Size(137, 20); + this.tb_lnboffset.TabIndex = 40; + // + // label12 + // + this.label12.AutoSize = true; + this.label12.Location = new System.Drawing.Point(12, 180); + this.label12.Name = "label12"; + this.label12.Size = new System.Drawing.Size(62, 13); + this.label12.TabIndex = 39; + this.label12.Text = "LNB Offset:"; + // + // comboBox_cpuspeed + // + this.comboBox_cpuspeed.FormattingEnabled = true; + this.comboBox_cpuspeed.Items.AddRange(new object[] { + "fast CPU (RPI4...)", + "normal CPU", + "very slow CPU (RPI3...)"}); + this.comboBox_cpuspeed.Location = new System.Drawing.Point(154, 231); + this.comboBox_cpuspeed.Name = "comboBox_cpuspeed"; + this.comboBox_cpuspeed.Size = new System.Drawing.Size(137, 21); + this.comboBox_cpuspeed.TabIndex = 42; + this.comboBox_cpuspeed.Text = "normal CPU"; + // + // label13 + // + this.label13.AutoSize = true; + this.label13.Location = new System.Drawing.Point(11, 232); + this.label13.Name = "label13"; + this.label13.Size = new System.Drawing.Size(136, 13); + this.label13.TabIndex = 43; + this.label13.Text = "Spectrum/Waterfall Speed:"; + // + // label14 + // + this.label14.AutoSize = true; + this.label14.Font = new System.Drawing.Font("Microsoft Sans Serif", 7F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.label14.Location = new System.Drawing.Point(296, 233); + this.label14.Name = "label14"; + this.label14.Size = new System.Drawing.Size(197, 13); + this.label14.TabIndex = 44; + this.label14.Text = "to reduce CPU load on slower computers"; + // + // button3 + // + this.button3.ForeColor = System.Drawing.Color.Red; + this.button3.Location = new System.Drawing.Point(426, 302); + this.button3.Name = "button3"; + this.button3.Size = new System.Drawing.Size(75, 23); + this.button3.TabIndex = 45; + this.button3.Text = "Help"; + this.button3.UseVisualStyleBackColor = true; + this.button3.Click += new System.EventHandler(this.button3_Click); + // + // label15 + // + this.label15.AutoSize = true; + this.label15.Location = new System.Drawing.Point(11, 284); + this.label15.Name = "label15"; + this.label15.Size = new System.Drawing.Size(58, 13); + this.label15.TabIndex = 47; + this.label15.Text = "Language:"; + // + // comboBox1 + // + this.comboBox1.FormattingEnabled = true; + this.comboBox1.Items.AddRange(new object[] { + "English", + "German/Deutsch", + "French/Français", + "Spanish/Español", + "Portuguese/Portugués", + "Italian/Italiano"}); + this.comboBox1.Location = new System.Drawing.Point(154, 285); + this.comboBox1.Name = "comboBox1"; + this.comboBox1.Size = new System.Drawing.Size(137, 21); + this.comboBox1.TabIndex = 46; + this.comboBox1.Text = "English"; + this.comboBox1.SelectedIndexChanged += new System.EventHandler(this.comboBox1_SelectedIndexChanged); + // + // label16 + // + this.label16.AutoSize = true; + this.label16.Location = new System.Drawing.Point(11, 258); + this.label16.Name = "label16"; + this.label16.Size = new System.Drawing.Size(70, 13); + this.label16.TabIndex = 49; + this.label16.Text = "Color Palette:"; + // + // comboBox_color + // + this.comboBox_color.FormattingEnabled = true; + this.comboBox_color.Items.AddRange(new object[] { + "blue / blau", + "red / rot", + "green / grün", + "white / weiß"}); + this.comboBox_color.Location = new System.Drawing.Point(154, 258); + this.comboBox_color.Name = "comboBox_color"; + this.comboBox_color.Size = new System.Drawing.Size(137, 21); + this.comboBox_color.TabIndex = 48; + this.comboBox_color.Text = "blue / blau"; + // + // label17 + // + this.label17.AutoSize = true; + this.label17.Font = new System.Drawing.Font("Microsoft Sans Serif", 7F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.label17.Location = new System.Drawing.Point(295, 208); + this.label17.Name = "label17"; + this.label17.Size = new System.Drawing.Size(226, 13); + this.label17.TabIndex = 52; + this.label17.Text = "Pluto TX power [dBm], allowed values: -40 to 0"; + // + // textBox_txpower + // + this.textBox_txpower.Location = new System.Drawing.Point(154, 205); + this.textBox_txpower.Name = "textBox_txpower"; + this.textBox_txpower.Size = new System.Drawing.Size(137, 20); + this.textBox_txpower.TabIndex = 51; + this.textBox_txpower.Text = "0"; + // + // label18 + // + this.label18.AutoSize = true; + this.label18.Location = new System.Drawing.Point(12, 206); + this.label18.Name = "label18"; + this.label18.Size = new System.Drawing.Size(56, 13); + this.label18.TabIndex = 50; + this.label18.Text = "TX power:"; + // + // button_shutdown + // + this.button_shutdown.ForeColor = System.Drawing.Color.Red; + this.button_shutdown.Location = new System.Drawing.Point(588, 272); + this.button_shutdown.Name = "button_shutdown"; + this.button_shutdown.Size = new System.Drawing.Size(75, 23); + this.button_shutdown.TabIndex = 53; + this.button_shutdown.Text = "ShutDown"; + this.button_shutdown.UseVisualStyleBackColor = true; + this.button_shutdown.Click += new System.EventHandler(this.button_shutdown_Click); + // + // cb_autosync + // + this.cb_autosync.AutoSize = true; + this.cb_autosync.Location = new System.Drawing.Point(156, 313); + this.cb_autosync.Name = "cb_autosync"; + this.cb_autosync.Size = new System.Drawing.Size(65, 17); + this.cb_autosync.TabIndex = 54; + this.cb_autosync.Text = "ON / off"; + this.cb_autosync.UseVisualStyleBackColor = true; + // + // label19 + // + this.label19.AutoSize = true; + this.label19.Location = new System.Drawing.Point(12, 312); + this.label19.Name = "label19"; + this.label19.Size = new System.Drawing.Size(82, 13); + this.label19.TabIndex = 55; + this.label19.Text = "QSO Auto Sync"; + // + // label20 + // + this.label20.AutoSize = true; + this.label20.Location = new System.Drawing.Point(11, 335); + this.label20.Name = "label20"; + this.label20.Size = new System.Drawing.Size(60, 13); + this.label20.TabIndex = 57; + this.label20.Text = "PTT-mode:"; + // + // cb_pttmode + // + this.cb_pttmode.FormattingEnabled = true; + this.cb_pttmode.Items.AddRange(new object[] { + "ON/OFF", + "Push-To-Talk"}); + this.cb_pttmode.Location = new System.Drawing.Point(154, 336); + this.cb_pttmode.Name = "cb_pttmode"; + this.cb_pttmode.Size = new System.Drawing.Size(137, 21); + this.cb_pttmode.TabIndex = 56; + this.cb_pttmode.Text = "ON/OFF"; + // + // Form_setup + // + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.ClientSize = new System.Drawing.Size(671, 411); + this.Controls.Add(this.label20); + this.Controls.Add(this.cb_pttmode); + this.Controls.Add(this.label19); + this.Controls.Add(this.cb_autosync); + this.Controls.Add(this.button_shutdown); + this.Controls.Add(this.label17); + this.Controls.Add(this.textBox_txpower); + this.Controls.Add(this.label18); + this.Controls.Add(this.label16); + this.Controls.Add(this.comboBox_color); + this.Controls.Add(this.label15); + this.Controls.Add(this.comboBox1); + this.Controls.Add(this.button3); + this.Controls.Add(this.label14); + this.Controls.Add(this.label13); + this.Controls.Add(this.comboBox_cpuspeed); + this.Controls.Add(this.label9); + this.Controls.Add(this.tb_lnboffset); + this.Controls.Add(this.label12); + this.Controls.Add(this.label7); + this.Controls.Add(this.tb_plutooffset); + this.Controls.Add(this.label8); + this.Controls.Add(this.label5); + this.Controls.Add(this.tb_plutoip); + this.Controls.Add(this.rb_plutoeth); + this.Controls.Add(this.rb_plutousb); + this.Controls.Add(this.label4); + this.Controls.Add(this.label1); + this.Controls.Add(this.label2); + this.Controls.Add(this.tb_rxqrg); + this.Controls.Add(this.label3); + this.Controls.Add(this.tb_txqrg); + this.Controls.Add(this.label6); + this.Controls.Add(this.cb_audioCAP); + this.Controls.Add(this.label10); + this.Controls.Add(this.label11); + this.Controls.Add(this.cb_audioPB); + this.Controls.Add(this.button2); + this.Controls.Add(this.button1); + this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedToolWindow; + this.Name = "Form_setup"; + this.Text = "Setup"; + this.ResumeLayout(false); + this.PerformLayout(); + + } + + #endregion + + private System.Windows.Forms.Button button1; + private System.Windows.Forms.Button button2; + private System.Windows.Forms.ComboBox cb_audioPB; + private System.Windows.Forms.Label label10; + private System.Windows.Forms.Label label11; + private System.Windows.Forms.ComboBox cb_audioCAP; + private System.Windows.Forms.TextBox tb_txqrg; + private System.Windows.Forms.Label label6; + private System.Windows.Forms.Label label2; + private System.Windows.Forms.TextBox tb_rxqrg; + private System.Windows.Forms.Label label3; + private System.Windows.Forms.Label label1; + private System.Windows.Forms.Label label4; + private System.Windows.Forms.RadioButton rb_plutousb; + private System.Windows.Forms.RadioButton rb_plutoeth; + private System.Windows.Forms.TextBox tb_plutoip; + private System.Windows.Forms.Label label5; + private System.Windows.Forms.Label label7; + private System.Windows.Forms.TextBox tb_plutooffset; + private System.Windows.Forms.Label label8; + private System.Windows.Forms.Label label9; + private System.Windows.Forms.TextBox tb_lnboffset; + private System.Windows.Forms.Label label12; + private System.Windows.Forms.ComboBox comboBox_cpuspeed; + private System.Windows.Forms.Label label13; + private System.Windows.Forms.Label label14; + private System.Windows.Forms.Button button3; + private System.Windows.Forms.Label label15; + private System.Windows.Forms.ComboBox comboBox1; + private System.Windows.Forms.Label label16; + private System.Windows.Forms.ComboBox comboBox_color; + private System.Windows.Forms.Label label17; + private System.Windows.Forms.TextBox textBox_txpower; + private System.Windows.Forms.Label label18; + private System.Windows.Forms.Button button_shutdown; + private System.Windows.Forms.CheckBox cb_autosync; + private System.Windows.Forms.Label label19; + private System.Windows.Forms.Label label20; + private System.Windows.Forms.ComboBox cb_pttmode; + } +} \ No newline at end of file diff --git a/trxGui/Form_setup.cs b/trxGui/Form_setup.cs new file mode 100755 index 0000000..8d62445 --- /dev/null +++ b/trxGui/Form_setup.cs @@ -0,0 +1,176 @@ +using System; +using System.Drawing; +using System.Windows.Forms; + +namespace trxGui +{ + public partial class Form_setup : Form + { + public Form_setup() + { + InitializeComponent(); + + Width = 800; + Height = 416; + int yb = Height - 70; + button1.Location = new Point(Width - button1.Width - 20, yb); + button2.Location = new Point(button1.Location.X - button2.Width - 10, yb); + button3.Location = new Point(button2.Location.X - button3.Width - 10, yb); + + button_shutdown.Location = new Point(Width - button_shutdown.Width - 20, yb - button1.Height - 10); + + comboBox1.SelectedIndex = statics.language; + + foreach (Control c in Controls) + c.Text = language.GetText(c.Text); + + tb_rxqrg.Text = ((double)statics.rxqrg / 1000000.0).ToString(); + tb_txqrg.Text = ((double)statics.txqrg / 1000000.0).ToString(); + tb_plutooffset.Text = statics.rfoffset.ToString(); + tb_lnboffset.Text = statics.lnboffset.ToString(); + + cb_audioPB.Text = statics.AudioPBdev; + cb_audioCAP.Text = statics.AudioCAPdev; + + rb_plutousb.Checked = statics.plutousb == 1 ? true : false; + rb_plutoeth.Checked = statics.plutousb == 1 ? false : true; + tb_plutoip.Text = statics.plutoaddress; + textBox_txpower.Text = statics.txpower.ToString(); + + comboBox_cpuspeed.SelectedIndex = statics.cpuspeed; + comboBox_color.SelectedIndex = statics.palette; + + cb_autosync.Checked = statics.autosync; + cb_pttmode.SelectedIndex = statics.pttmode; + + // populate combo boxes + if (statics.AudioPBdevs != null) + { + cb_audioPB.BeginUpdate(); + cb_audioPB.Items.Clear(); + foreach (String s in statics.AudioPBdevs) + { + if (s.Length > 1) + { + cb_audioPB.Items.Add(s); + } + } + cb_audioPB.EndUpdate(); + // check if displayed text is available in the item list + findDevice(cb_audioPB); + } + + if (statics.AudioCAPdevs != null) + { + cb_audioCAP.BeginUpdate(); + cb_audioCAP.Items.Clear(); + foreach (String s in statics.AudioCAPdevs) + { + if (s.Length > 1) + { + cb_audioCAP.Items.Add(s); + } + } + cb_audioCAP.EndUpdate(); + findDevice(cb_audioCAP); + } + } + + void findDevice(ComboBox cb) + { + int pos = -1; + + if (cb.Text.Length >= 4) + { + int anz = cb.Items.Count; + for (int i = 0; i < anz; i++) + { + if (cb.Text == cb.Items[i].ToString()) + { + pos = i; + break; + } + } + } + + if (pos == -1) + { + // not available, reset to first item which usually is Default + if (cb.Items.Count == 0) + cb.Text = "no sound devices available"; + else + cb.Text = cb.Items[0].ToString(); + } + else + cb.Text = cb.Items[pos].ToString(); + } + + private void button2_Click(object sender, EventArgs e) + { + if (statics.AudioPBdev != cb_audioPB.Text || statics.AudioCAPdev != cb_audioCAP.Text) + { + statics.AudioPBdev = cb_audioPB.Text; + statics.AudioCAPdev = cb_audioCAP.Text; + statics.newaudiodevs = true; + } + + statics.rxqrg = (UInt32)(statics.MyToDouble(tb_rxqrg.Text) * 1000000.0); + statics.txqrg = (UInt32)(statics.MyToDouble(tb_txqrg.Text) * 1000000.0); + double dv = statics.MyToDouble(tb_plutooffset.Text); + statics.rfoffset = (int)dv; + dv = statics.MyToDouble(tb_lnboffset.Text); + statics.lnboffset = (int)dv; + dv = statics.MyToDouble(textBox_txpower.Text); + statics.txpower = (int)dv; + if (statics.txpower > 0) statics.txpower = 0; + if (statics.txpower < -60) statics.txpower = -60; + + statics.plutousb = rb_plutousb.Checked?1:0; + statics.plutoaddress = tb_plutoip.Text; + statics.cpuspeed = comboBox_cpuspeed.SelectedIndex; + statics.palette = comboBox_color.SelectedIndex; + statics.autosync = cb_autosync.Checked; + statics.pttmode = cb_pttmode.SelectedIndex; + } + + private void rb_plutousb_CheckedChanged(object sender, EventArgs e) + { + if (rb_plutousb.Checked) + { + tb_plutoip.Enabled = false; + } + } + + private void rb_plutoeth_CheckedChanged(object sender, EventArgs e) + { + if (rb_plutoeth.Checked) + { + tb_plutoip.Enabled = true; + } + } + + private void button3_Click(object sender, EventArgs e) + { + statics.OpenUrl("https://wiki.amsat-dl.org/doku.php?id=en:plutotrx:config"); + } + + private void comboBox1_SelectedIndexChanged(object sender, EventArgs e) + { + statics.language = comboBox1.SelectedIndex; + + foreach (Control c in Controls) + c.Text = language.GetText(c.Text); + } + + private void button_shutdown_Click(object sender, EventArgs e) + { + DialogResult dr = MessageBox.Show(language.GetText("Do you want to shut down the computer?"), "Shut Down", MessageBoxButtons.YesNo); + if (dr == DialogResult.Yes) + { + Byte[] txb = new Byte[1]; + txb[0] = 21; + Udp.UdpSendData(txb); + } + } + } +} diff --git a/trxGui/Form_setup.resx b/trxGui/Form_setup.resx new file mode 100755 index 0000000..29dcb1b --- /dev/null +++ b/trxGui/Form_setup.resx @@ -0,0 +1,120 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/trxGui/Program.cs b/trxGui/Program.cs new file mode 100644 index 0000000..be04554 --- /dev/null +++ b/trxGui/Program.cs @@ -0,0 +1,22 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using System.Windows.Forms; + +namespace trxGui +{ + static class Program + { + /// + /// Der Haupteinstiegspunkt für die Anwendung. + /// + [STAThread] + static void Main() + { + Application.EnableVisualStyles(); + Application.SetCompatibleTextRenderingDefault(false); + Application.Run(new Form1()); + } + } +} diff --git a/trxGui/Properties/AssemblyInfo.cs b/trxGui/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..a0c52f4 --- /dev/null +++ b/trxGui/Properties/AssemblyInfo.cs @@ -0,0 +1,36 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// Allgemeine Informationen über eine Assembly werden über die folgenden +// Attribute gesteuert. Ändern Sie diese Attributwerte, um die Informationen zu ändern, +// die einer Assembly zugeordnet sind. +[assembly: AssemblyTitle("trxGui")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("trxGui")] +[assembly: AssemblyCopyright("Copyright © 2021")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Durch Festlegen von ComVisible auf FALSE werden die Typen in dieser Assembly +// für COM-Komponenten unsichtbar. Wenn Sie auf einen Typ in dieser Assembly von +// COM aus zugreifen müssen, sollten Sie das ComVisible-Attribut für diesen Typ auf "True" festlegen. +[assembly: ComVisible(false)] + +// Die folgende GUID bestimmt die ID der Typbibliothek, wenn dieses Projekt für COM verfügbar gemacht wird +[assembly: Guid("b4d0ae1a-ef2f-413d-b67a-ab7cbdd6b4bb")] + +// Versionsinformationen für eine Assembly bestehen aus den folgenden vier Werten: +// +// Hauptversion +// Nebenversion +// Buildnummer +// Revision +// +// Sie können alle Werte angeben oder Standardwerte für die Build- und Revisionsnummern verwenden, +// indem Sie "*" wie unten gezeigt eingeben: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/trxGui/Properties/BTN_Thumb.bmp b/trxGui/Properties/BTN_Thumb.bmp new file mode 100644 index 0000000..4f911ce Binary files /dev/null and b/trxGui/Properties/BTN_Thumb.bmp differ diff --git a/trxGui/Properties/BTN_Thumb_Blue.bmp b/trxGui/Properties/BTN_Thumb_Blue.bmp new file mode 100644 index 0000000..b5c6c6b Binary files /dev/null and b/trxGui/Properties/BTN_Thumb_Blue.bmp differ diff --git a/trxGui/Properties/Resources.Designer.cs b/trxGui/Properties/Resources.Designer.cs new file mode 100644 index 0000000..5c8848f --- /dev/null +++ b/trxGui/Properties/Resources.Designer.cs @@ -0,0 +1,653 @@ +//------------------------------------------------------------------------------ +// +// Dieser Code wurde von einem Tool generiert. +// Laufzeitversion:4.0.30319.42000 +// +// Änderungen an dieser Datei können falsches Verhalten verursachen und gehen verloren, wenn +// der Code erneut generiert wird. +// +//------------------------------------------------------------------------------ + +namespace trxGui.Properties { + using System; + + + /// + /// Eine stark typisierte Ressourcenklasse zum Suchen von lokalisierten Zeichenfolgen usw. + /// + // Diese Klasse wurde von der StronglyTypedResourceBuilder automatisch generiert + // -Klasse über ein Tool wie ResGen oder Visual Studio automatisch generiert. + // Um einen Member hinzuzufügen oder zu entfernen, bearbeiten Sie die .ResX-Datei und führen dann ResGen + // mit der /str-Option erneut aus, oder Sie erstellen Ihr VS-Projekt neu. + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "16.0.0.0")] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] + internal class Resources { + + private static global::System.Resources.ResourceManager resourceMan; + + private static global::System.Globalization.CultureInfo resourceCulture; + + [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + internal Resources() { + } + + /// + /// Gibt die zwischengespeicherte ResourceManager-Instanz zurück, die von dieser Klasse verwendet wird. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Resources.ResourceManager ResourceManager { + get { + if (object.ReferenceEquals(resourceMan, null)) { + global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("trxGui.Properties.Resources", typeof(Resources).Assembly); + resourceMan = temp; + } + return resourceMan; + } + } + + /// + /// Überschreibt die CurrentUICulture-Eigenschaft des aktuellen Threads für alle + /// Ressourcenzuordnungen, die diese stark typisierte Ressourcenklasse verwenden. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Globalization.CultureInfo Culture { + get { + return resourceCulture; + } + set { + resourceCulture = value; + } + } + + /// + /// Sucht eine lokalisierte Ressource vom Typ System.Drawing.Bitmap. + /// + internal static System.Drawing.Bitmap _lock { + get { + object obj = ResourceManager.GetObject("_lock", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// Sucht eine lokalisierte Ressource vom Typ System.Drawing.Bitmap. + /// + internal static System.Drawing.Bitmap agc_button { + get { + object obj = ResourceManager.GetObject("agc_button", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// Sucht eine lokalisierte Ressource vom Typ System.Drawing.Bitmap. + /// + internal static System.Drawing.Bitmap agc_button_inact { + get { + object obj = ResourceManager.GetObject("agc_button_inact", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// Sucht eine lokalisierte Ressource vom Typ System.Drawing.Icon ähnlich wie (Symbol). + /// + internal static System.Drawing.Icon ai { + get { + object obj = ResourceManager.GetObject("ai", resourceCulture); + return ((System.Drawing.Icon)(obj)); + } + } + + /// + /// Sucht eine lokalisierte Ressource vom Typ System.Drawing.Bitmap. + /// + internal static System.Drawing.Bitmap amsat_icon { + get { + object obj = ResourceManager.GetObject("amsat_icon", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// Sucht eine lokalisierte Ressource vom Typ System.Drawing.Bitmap. + /// + internal static System.Drawing.Bitmap amsat_logo { + get { + object obj = ResourceManager.GetObject("amsat_logo", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// Sucht eine lokalisierte Ressource vom Typ System.Drawing.Bitmap. + /// + internal static System.Drawing.Bitmap audioloop { + get { + object obj = ResourceManager.GetObject("audioloop", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// Sucht eine lokalisierte Ressource vom Typ System.Drawing.Bitmap. + /// + internal static System.Drawing.Bitmap audioloop_inact { + get { + object obj = ResourceManager.GetObject("audioloop_inact", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// Sucht eine lokalisierte Ressource vom Typ System.Drawing.Bitmap. + /// + internal static System.Drawing.Bitmap back { + get { + object obj = ResourceManager.GetObject("back", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// Sucht eine lokalisierte Ressource vom Typ System.Drawing.Bitmap. + /// + internal static System.Drawing.Bitmap bcn_center { + get { + object obj = ResourceManager.GetObject("bcn_center", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// Sucht eine lokalisierte Ressource vom Typ System.Drawing.Bitmap. + /// + internal static System.Drawing.Bitmap calbutton { + get { + object obj = ResourceManager.GetObject("calbutton", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// Sucht eine lokalisierte Ressource vom Typ System.Drawing.Bitmap. + /// + internal static System.Drawing.Bitmap comp_off { + get { + object obj = ResourceManager.GetObject("comp_off", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// Sucht eine lokalisierte Ressource vom Typ System.Drawing.Bitmap. + /// + internal static System.Drawing.Bitmap comp_on { + get { + object obj = ResourceManager.GetObject("comp_on", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// Sucht eine lokalisierte Ressource vom Typ System.Drawing.Bitmap. + /// + internal static System.Drawing.Bitmap forward { + get { + object obj = ResourceManager.GetObject("forward", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// Sucht eine lokalisierte Ressource vom Typ System.Drawing.Bitmap. + /// + internal static System.Drawing.Bitmap freebutton { + get { + object obj = ResourceManager.GetObject("freebutton", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// Sucht eine lokalisierte Ressource vom Typ System.Drawing.Bitmap. + /// + internal static System.Drawing.Bitmap gauge { + get { + object obj = ResourceManager.GetObject("gauge", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// Sucht eine lokalisierte Ressource vom Typ System.Drawing.Bitmap. + /// + internal static System.Drawing.Bitmap gauge1 { + get { + object obj = ResourceManager.GetObject("gauge1", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// Sucht eine lokalisierte Ressource vom Typ System.Drawing.Bitmap. + /// + internal static System.Drawing.Bitmap info { + get { + object obj = ResourceManager.GetObject("info", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// Sucht eine lokalisierte Ressource vom Typ System.Drawing.Bitmap. + /// + internal static System.Drawing.Bitmap lock_open { + get { + object obj = ResourceManager.GetObject("lock_open", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// Sucht eine lokalisierte Ressource vom Typ System.Drawing.Bitmap. + /// + internal static System.Drawing.Bitmap lockbutton { + get { + object obj = ResourceManager.GetObject("lockbutton", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// Sucht eine lokalisierte Ressource vom Typ System.Drawing.Bitmap. + /// + internal static System.Drawing.Bitmap mem1 { + get { + object obj = ResourceManager.GetObject("mem1", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// Sucht eine lokalisierte Ressource vom Typ System.Drawing.Bitmap. + /// + internal static System.Drawing.Bitmap mem2 { + get { + object obj = ResourceManager.GetObject("mem2", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// Sucht eine lokalisierte Ressource vom Typ System.Drawing.Bitmap. + /// + internal static System.Drawing.Bitmap microphone { + get { + object obj = ResourceManager.GetObject("microphone", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// Sucht eine lokalisierte Ressource vom Typ System.Drawing.Bitmap. + /// + internal static System.Drawing.Bitmap mixer { + get { + object obj = ResourceManager.GetObject("mixer", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// Sucht eine lokalisierte Ressource vom Typ System.Drawing.Bitmap. + /// + internal static System.Drawing.Bitmap monitor { + get { + object obj = ResourceManager.GetObject("monitor", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// Sucht eine lokalisierte Ressource vom Typ System.Drawing.Bitmap. + /// + internal static System.Drawing.Bitmap mute { + get { + object obj = ResourceManager.GetObject("mute", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// Sucht eine lokalisierte Ressource vom Typ System.Drawing.Bitmap. + /// + internal static System.Drawing.Bitmap mute_inact { + get { + object obj = ResourceManager.GetObject("mute_inact", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// Sucht eine lokalisierte Ressource vom Typ System.Drawing.Bitmap. + /// + internal static System.Drawing.Bitmap note { + get { + object obj = ResourceManager.GetObject("note", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// Sucht eine lokalisierte Ressource vom Typ System.Drawing.Bitmap. + /// + internal static System.Drawing.Bitmap playback { + get { + object obj = ResourceManager.GetObject("playback", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// Sucht eine lokalisierte Ressource vom Typ System.Drawing.Bitmap. + /// + internal static System.Drawing.Bitmap ptt_rx { + get { + object obj = ResourceManager.GetObject("ptt_rx", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// Sucht eine lokalisierte Ressource vom Typ System.Drawing.Bitmap. + /// + internal static System.Drawing.Bitmap ptt_tx { + get { + object obj = ResourceManager.GetObject("ptt_tx", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// Sucht eine lokalisierte Ressource vom Typ System.Drawing.Bitmap. + /// + internal static System.Drawing.Bitmap read { + get { + object obj = ResourceManager.GetObject("read", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// Sucht eine lokalisierte Ressource vom Typ System.Drawing.Bitmap. + /// + internal static System.Drawing.Bitmap record { + get { + object obj = ResourceManager.GetObject("record", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// Sucht eine lokalisierte Ressource vom Typ System.Drawing.Bitmap. + /// + internal static System.Drawing.Bitmap rfloop { + get { + object obj = ResourceManager.GetObject("rfloop", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// Sucht eine lokalisierte Ressource vom Typ System.Drawing.Bitmap. + /// + internal static System.Drawing.Bitmap rfloop_inact { + get { + object obj = ResourceManager.GetObject("rfloop_inact", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// Sucht eine lokalisierte Ressource vom Typ System.Drawing.Bitmap. + /// + internal static System.Drawing.Bitmap rt_button { + get { + object obj = ResourceManager.GetObject("rt_button", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// Sucht eine lokalisierte Ressource vom Typ System.Drawing.Bitmap. + /// + internal static System.Drawing.Bitmap rt_button_inact { + get { + object obj = ResourceManager.GetObject("rt_button_inact", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// Sucht eine lokalisierte Ressource vom Typ System.Drawing.Bitmap. + /// + internal static System.Drawing.Bitmap rx_filter_1 { + get { + object obj = ResourceManager.GetObject("rx_filter_1", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// Sucht eine lokalisierte Ressource vom Typ System.Drawing.Bitmap. + /// + internal static System.Drawing.Bitmap rx_filter_18 { + get { + object obj = ResourceManager.GetObject("rx_filter_18", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// Sucht eine lokalisierte Ressource vom Typ System.Drawing.Bitmap. + /// + internal static System.Drawing.Bitmap rx_filter_27 { + get { + object obj = ResourceManager.GetObject("rx_filter_27", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// Sucht eine lokalisierte Ressource vom Typ System.Drawing.Bitmap. + /// + internal static System.Drawing.Bitmap rx_filter_36 { + get { + object obj = ResourceManager.GetObject("rx_filter_36", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// Sucht eine lokalisierte Ressource vom Typ System.Drawing.Bitmap. + /// + internal static System.Drawing.Bitmap rxqrg { + get { + object obj = ResourceManager.GetObject("rxqrg", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// Sucht eine lokalisierte Ressource vom Typ System.Drawing.Bitmap. + /// + internal static System.Drawing.Bitmap rxqrg_inact { + get { + object obj = ResourceManager.GetObject("rxqrg_inact", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// Sucht eine lokalisierte Ressource vom Typ System.Drawing.Bitmap. + /// + internal static System.Drawing.Bitmap save { + get { + object obj = ResourceManager.GetObject("save", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// Sucht eine lokalisierte Ressource vom Typ System.Drawing.Bitmap. + /// + internal static System.Drawing.Bitmap setup { + get { + object obj = ResourceManager.GetObject("setup", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// Sucht eine lokalisierte Ressource vom Typ System.Drawing.Bitmap. + /// + internal static System.Drawing.Bitmap swband { + get { + object obj = ResourceManager.GetObject("swband", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// Sucht eine lokalisierte Ressource vom Typ System.Drawing.Bitmap. + /// + internal static System.Drawing.Bitmap tr_button { + get { + object obj = ResourceManager.GetObject("tr_button", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// Sucht eine lokalisierte Ressource vom Typ System.Drawing.Bitmap. + /// + internal static System.Drawing.Bitmap tr_button_inact { + get { + object obj = ResourceManager.GetObject("tr_button_inact", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// Sucht eine lokalisierte Ressource vom Typ System.Drawing.Bitmap. + /// + internal static System.Drawing.Bitmap tx_bass { + get { + object obj = ResourceManager.GetObject("tx_bass", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// Sucht eine lokalisierte Ressource vom Typ System.Drawing.Bitmap. + /// + internal static System.Drawing.Bitmap tx_bass_inact { + get { + object obj = ResourceManager.GetObject("tx_bass_inact", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// Sucht eine lokalisierte Ressource vom Typ System.Drawing.Bitmap. + /// + internal static System.Drawing.Bitmap tx_filter_1 { + get { + object obj = ResourceManager.GetObject("tx_filter_1", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// Sucht eine lokalisierte Ressource vom Typ System.Drawing.Bitmap. + /// + internal static System.Drawing.Bitmap tx_filter_18 { + get { + object obj = ResourceManager.GetObject("tx_filter_18", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// Sucht eine lokalisierte Ressource vom Typ System.Drawing.Bitmap. + /// + internal static System.Drawing.Bitmap tx_filter_22 { + get { + object obj = ResourceManager.GetObject("tx_filter_22", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// Sucht eine lokalisierte Ressource vom Typ System.Drawing.Bitmap. + /// + internal static System.Drawing.Bitmap tx_filter_27 { + get { + object obj = ResourceManager.GetObject("tx_filter_27", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// Sucht eine lokalisierte Ressource vom Typ System.Drawing.Bitmap. + /// + internal static System.Drawing.Bitmap txaudio_button { + get { + object obj = ResourceManager.GetObject("txaudio_button", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// Sucht eine lokalisierte Ressource vom Typ System.Drawing.Bitmap. + /// + internal static System.Drawing.Bitmap txqrg { + get { + object obj = ResourceManager.GetObject("txqrg", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// Sucht eine lokalisierte Ressource vom Typ System.Drawing.Bitmap. + /// + internal static System.Drawing.Bitmap txqrg_inact { + get { + object obj = ResourceManager.GetObject("txqrg_inact", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// Sucht eine lokalisierte Ressource vom Typ System.Drawing.Bitmap. + /// + internal static System.Drawing.Bitmap wave { + get { + object obj = ResourceManager.GetObject("wave", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// Sucht eine lokalisierte Ressource vom Typ System.Drawing.Bitmap. + /// + internal static System.Drawing.Bitmap waveactive { + get { + object obj = ResourceManager.GetObject("waveactive", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + } +} diff --git a/trxGui/Properties/Resources.resx b/trxGui/Properties/Resources.resx new file mode 100755 index 0000000..8d2b622 --- /dev/null +++ b/trxGui/Properties/Resources.resx @@ -0,0 +1,298 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + + agc_button.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + agc_button_inact.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ai.ico;System.Drawing.Icon, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + amsat_icon.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + amsat_logo.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + audioloop.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + audioloop_inact.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + back.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + bcn_center.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + calbutton.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + comp_off.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + comp_on.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + forward.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + freebutton.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + gauge.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + gauge.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + info.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + lockbutton.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + lock_open.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + mem1.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + mem2.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + microphone.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + mixer.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + monitor.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + mute.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + mute_inact.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + note.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + playback.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ptt_rx.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ptt_tx.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + read.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + record.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + rfloop.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + rfloop_inact.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + rt_button.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + rt_button_inact.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + rxqrg.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + rxqrg_inact.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + rx_filter_1.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + rx_filter_18.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + rx_filter_27.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + rx_filter_36.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + save.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + setup.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + swband.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + tr_button.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + tr_button_inact.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + txaudio_button.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + txqrg.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + txqrg_inact.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + tx_bass.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + tx_bass_inact.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + tx_filter_1.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + tx_filter_18.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + tx_filter_22.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + tx_filter_27.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + wave.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + waveactive.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + lock.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + \ No newline at end of file diff --git a/trxGui/Properties/Settings.Designer.cs b/trxGui/Properties/Settings.Designer.cs new file mode 100644 index 0000000..7dc8cf8 --- /dev/null +++ b/trxGui/Properties/Settings.Designer.cs @@ -0,0 +1,29 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// Runtime Version:4.0.30319.42000 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + + +namespace trxGui.Properties +{ + [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "11.0.0.0")] + internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase + { + + private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings()))); + + public static Settings Default + { + get + { + return defaultInstance; + } + } + } +} diff --git a/trxGui/Properties/Settings.settings b/trxGui/Properties/Settings.settings new file mode 100644 index 0000000..abf36c5 --- /dev/null +++ b/trxGui/Properties/Settings.settings @@ -0,0 +1,7 @@ + + + + + + + diff --git a/trxGui/Properties/agc_button.png b/trxGui/Properties/agc_button.png new file mode 100644 index 0000000..362bd84 Binary files /dev/null and b/trxGui/Properties/agc_button.png differ diff --git a/trxGui/Properties/agc_button.xcf b/trxGui/Properties/agc_button.xcf new file mode 100644 index 0000000..9ac709c Binary files /dev/null and b/trxGui/Properties/agc_button.xcf differ diff --git a/trxGui/Properties/agc_button_inact.png b/trxGui/Properties/agc_button_inact.png new file mode 100644 index 0000000..e1a390a Binary files /dev/null and b/trxGui/Properties/agc_button_inact.png differ diff --git a/trxGui/Properties/ai.ico b/trxGui/Properties/ai.ico new file mode 100644 index 0000000..64581ff Binary files /dev/null and b/trxGui/Properties/ai.ico differ diff --git a/trxGui/Properties/amsat_icon.png b/trxGui/Properties/amsat_icon.png new file mode 100644 index 0000000..ac5946a Binary files /dev/null and b/trxGui/Properties/amsat_icon.png differ diff --git a/trxGui/Properties/amsat_icon_sw.png b/trxGui/Properties/amsat_icon_sw.png new file mode 100644 index 0000000..9d9aea1 Binary files /dev/null and b/trxGui/Properties/amsat_icon_sw.png differ diff --git a/trxGui/Properties/amsat_logo.png b/trxGui/Properties/amsat_logo.png new file mode 100644 index 0000000..14817ea Binary files /dev/null and b/trxGui/Properties/amsat_logo.png differ diff --git a/trxGui/Properties/audioloop.png b/trxGui/Properties/audioloop.png new file mode 100644 index 0000000..b946a28 Binary files /dev/null and b/trxGui/Properties/audioloop.png differ diff --git a/trxGui/Properties/audioloop.xcf b/trxGui/Properties/audioloop.xcf new file mode 100644 index 0000000..2770ad1 Binary files /dev/null and b/trxGui/Properties/audioloop.xcf differ diff --git a/trxGui/Properties/audioloop_inact.png b/trxGui/Properties/audioloop_inact.png new file mode 100644 index 0000000..e2f241a Binary files /dev/null and b/trxGui/Properties/audioloop_inact.png differ diff --git a/trxGui/Properties/back.png b/trxGui/Properties/back.png new file mode 100644 index 0000000..045acb7 Binary files /dev/null and b/trxGui/Properties/back.png differ diff --git a/trxGui/Properties/bcn_center.png b/trxGui/Properties/bcn_center.png new file mode 100644 index 0000000..7364bdf Binary files /dev/null and b/trxGui/Properties/bcn_center.png differ diff --git a/trxGui/Properties/calbutton.png b/trxGui/Properties/calbutton.png new file mode 100644 index 0000000..53efc95 Binary files /dev/null and b/trxGui/Properties/calbutton.png differ diff --git a/trxGui/Properties/comp.xcf b/trxGui/Properties/comp.xcf new file mode 100644 index 0000000..737b029 Binary files /dev/null and b/trxGui/Properties/comp.xcf differ diff --git a/trxGui/Properties/comp_button.png b/trxGui/Properties/comp_button.png new file mode 100644 index 0000000..69f900c Binary files /dev/null and b/trxGui/Properties/comp_button.png differ diff --git a/trxGui/Properties/comp_button_inact.png b/trxGui/Properties/comp_button_inact.png new file mode 100644 index 0000000..c16a872 Binary files /dev/null and b/trxGui/Properties/comp_button_inact.png differ diff --git a/trxGui/Properties/comp_high.png b/trxGui/Properties/comp_high.png new file mode 100644 index 0000000..b064eae Binary files /dev/null and b/trxGui/Properties/comp_high.png differ diff --git a/trxGui/Properties/comp_low.png b/trxGui/Properties/comp_low.png new file mode 100644 index 0000000..acecc29 Binary files /dev/null and b/trxGui/Properties/comp_low.png differ diff --git a/trxGui/Properties/comp_mid.png b/trxGui/Properties/comp_mid.png new file mode 100644 index 0000000..1611977 Binary files /dev/null and b/trxGui/Properties/comp_mid.png differ diff --git a/trxGui/Properties/comp_off.png b/trxGui/Properties/comp_off.png new file mode 100644 index 0000000..545ed93 Binary files /dev/null and b/trxGui/Properties/comp_off.png differ diff --git a/trxGui/Properties/comp_on.png b/trxGui/Properties/comp_on.png new file mode 100644 index 0000000..9a0ed98 Binary files /dev/null and b/trxGui/Properties/comp_on.png differ diff --git a/trxGui/Properties/empty_button_gray.png b/trxGui/Properties/empty_button_gray.png new file mode 100644 index 0000000..40a07c2 Binary files /dev/null and b/trxGui/Properties/empty_button_gray.png differ diff --git a/trxGui/Properties/empty_button_white.png b/trxGui/Properties/empty_button_white.png new file mode 100644 index 0000000..31606bf Binary files /dev/null and b/trxGui/Properties/empty_button_white.png differ diff --git a/trxGui/Properties/forward.png b/trxGui/Properties/forward.png new file mode 100644 index 0000000..93108bb Binary files /dev/null and b/trxGui/Properties/forward.png differ diff --git a/trxGui/Properties/freebutton.png b/trxGui/Properties/freebutton.png new file mode 100644 index 0000000..8dbc843 Binary files /dev/null and b/trxGui/Properties/freebutton.png differ diff --git a/trxGui/Properties/gauge.png b/trxGui/Properties/gauge.png new file mode 100644 index 0000000..faddc27 Binary files /dev/null and b/trxGui/Properties/gauge.png differ diff --git a/trxGui/Properties/info.png b/trxGui/Properties/info.png new file mode 100644 index 0000000..f59630d Binary files /dev/null and b/trxGui/Properties/info.png differ diff --git a/trxGui/Properties/lock.png b/trxGui/Properties/lock.png new file mode 100644 index 0000000..e102191 Binary files /dev/null and b/trxGui/Properties/lock.png differ diff --git a/trxGui/Properties/lock_open.png b/trxGui/Properties/lock_open.png new file mode 100644 index 0000000..80dd767 Binary files /dev/null and b/trxGui/Properties/lock_open.png differ diff --git a/trxGui/Properties/lockbutton.png b/trxGui/Properties/lockbutton.png new file mode 100644 index 0000000..5f838d9 Binary files /dev/null and b/trxGui/Properties/lockbutton.png differ diff --git a/trxGui/Properties/mem1.png b/trxGui/Properties/mem1.png new file mode 100644 index 0000000..754533e Binary files /dev/null and b/trxGui/Properties/mem1.png differ diff --git a/trxGui/Properties/mem2.png b/trxGui/Properties/mem2.png new file mode 100644 index 0000000..ab0f83a Binary files /dev/null and b/trxGui/Properties/mem2.png differ diff --git a/trxGui/Properties/microphone.png b/trxGui/Properties/microphone.png new file mode 100644 index 0000000..7c06f8b Binary files /dev/null and b/trxGui/Properties/microphone.png differ diff --git a/trxGui/Properties/mixer.png b/trxGui/Properties/mixer.png new file mode 100644 index 0000000..4a3d62b Binary files /dev/null and b/trxGui/Properties/mixer.png differ diff --git a/trxGui/Properties/mixer.xcf b/trxGui/Properties/mixer.xcf new file mode 100644 index 0000000..3856688 Binary files /dev/null and b/trxGui/Properties/mixer.xcf differ diff --git a/trxGui/Properties/monitor.png b/trxGui/Properties/monitor.png new file mode 100644 index 0000000..ce42748 Binary files /dev/null and b/trxGui/Properties/monitor.png differ diff --git a/trxGui/Properties/mute.png b/trxGui/Properties/mute.png new file mode 100644 index 0000000..cc1c25c Binary files /dev/null and b/trxGui/Properties/mute.png differ diff --git a/trxGui/Properties/mute.xcf b/trxGui/Properties/mute.xcf new file mode 100644 index 0000000..1b88ed4 Binary files /dev/null and b/trxGui/Properties/mute.xcf differ diff --git a/trxGui/Properties/mute_inact.png b/trxGui/Properties/mute_inact.png new file mode 100644 index 0000000..11b752e Binary files /dev/null and b/trxGui/Properties/mute_inact.png differ diff --git a/trxGui/Properties/note.png b/trxGui/Properties/note.png new file mode 100644 index 0000000..530c2e7 Binary files /dev/null and b/trxGui/Properties/note.png differ diff --git a/trxGui/Properties/playback.png b/trxGui/Properties/playback.png new file mode 100644 index 0000000..864fa55 Binary files /dev/null and b/trxGui/Properties/playback.png differ diff --git a/trxGui/Properties/ptt.xcf b/trxGui/Properties/ptt.xcf new file mode 100644 index 0000000..eee466c Binary files /dev/null and b/trxGui/Properties/ptt.xcf differ diff --git a/trxGui/Properties/ptt_rx.png b/trxGui/Properties/ptt_rx.png new file mode 100644 index 0000000..e061c2c Binary files /dev/null and b/trxGui/Properties/ptt_rx.png differ diff --git a/trxGui/Properties/ptt_tx.png b/trxGui/Properties/ptt_tx.png new file mode 100644 index 0000000..ca46ca6 Binary files /dev/null and b/trxGui/Properties/ptt_tx.png differ diff --git a/trxGui/Properties/read.png b/trxGui/Properties/read.png new file mode 100644 index 0000000..29925ed Binary files /dev/null and b/trxGui/Properties/read.png differ diff --git a/trxGui/Properties/record.png b/trxGui/Properties/record.png new file mode 100644 index 0000000..88097a1 Binary files /dev/null and b/trxGui/Properties/record.png differ diff --git a/trxGui/Properties/rfloop.png b/trxGui/Properties/rfloop.png new file mode 100644 index 0000000..d361742 Binary files /dev/null and b/trxGui/Properties/rfloop.png differ diff --git a/trxGui/Properties/rfloop.xcf b/trxGui/Properties/rfloop.xcf new file mode 100644 index 0000000..28db392 Binary files /dev/null and b/trxGui/Properties/rfloop.xcf differ diff --git a/trxGui/Properties/rfloop_inact.png b/trxGui/Properties/rfloop_inact.png new file mode 100644 index 0000000..d5f094c Binary files /dev/null and b/trxGui/Properties/rfloop_inact.png differ diff --git a/trxGui/Properties/rit.png b/trxGui/Properties/rit.png new file mode 100644 index 0000000..e753216 Binary files /dev/null and b/trxGui/Properties/rit.png differ diff --git a/trxGui/Properties/rit.xcf b/trxGui/Properties/rit.xcf new file mode 100644 index 0000000..ab31c5c Binary files /dev/null and b/trxGui/Properties/rit.xcf differ diff --git a/trxGui/Properties/rit_button.png b/trxGui/Properties/rit_button.png new file mode 100644 index 0000000..f9b7ce7 Binary files /dev/null and b/trxGui/Properties/rit_button.png differ diff --git a/trxGui/Properties/rit_button.xcf b/trxGui/Properties/rit_button.xcf new file mode 100644 index 0000000..b904132 Binary files /dev/null and b/trxGui/Properties/rit_button.xcf differ diff --git a/trxGui/Properties/rit_button_inact.png b/trxGui/Properties/rit_button_inact.png new file mode 100644 index 0000000..f0767ab Binary files /dev/null and b/trxGui/Properties/rit_button_inact.png differ diff --git a/trxGui/Properties/rit_button_inact.xcf b/trxGui/Properties/rit_button_inact.xcf new file mode 100644 index 0000000..ea7c8f9 Binary files /dev/null and b/trxGui/Properties/rit_button_inact.xcf differ diff --git a/trxGui/Properties/rt_button.png b/trxGui/Properties/rt_button.png new file mode 100644 index 0000000..ddbb61d Binary files /dev/null and b/trxGui/Properties/rt_button.png differ diff --git a/trxGui/Properties/rt_button.xcf b/trxGui/Properties/rt_button.xcf new file mode 100644 index 0000000..3f1f475 Binary files /dev/null and b/trxGui/Properties/rt_button.xcf differ diff --git a/trxGui/Properties/rt_button_inact.png b/trxGui/Properties/rt_button_inact.png new file mode 100644 index 0000000..fd5e3fe Binary files /dev/null and b/trxGui/Properties/rt_button_inact.png differ diff --git a/trxGui/Properties/rt_button_inact.xcf b/trxGui/Properties/rt_button_inact.xcf new file mode 100644 index 0000000..c4b89ee Binary files /dev/null and b/trxGui/Properties/rt_button_inact.xcf differ diff --git a/trxGui/Properties/rx_filter.xcf b/trxGui/Properties/rx_filter.xcf new file mode 100644 index 0000000..e05d7ff Binary files /dev/null and b/trxGui/Properties/rx_filter.xcf differ diff --git a/trxGui/Properties/rx_filter_1.png b/trxGui/Properties/rx_filter_1.png new file mode 100644 index 0000000..172807c Binary files /dev/null and b/trxGui/Properties/rx_filter_1.png differ diff --git a/trxGui/Properties/rx_filter_18.png b/trxGui/Properties/rx_filter_18.png new file mode 100644 index 0000000..61cb7b0 Binary files /dev/null and b/trxGui/Properties/rx_filter_18.png differ diff --git a/trxGui/Properties/rx_filter_27.png b/trxGui/Properties/rx_filter_27.png new file mode 100644 index 0000000..4bd8ade Binary files /dev/null and b/trxGui/Properties/rx_filter_27.png differ diff --git a/trxGui/Properties/rx_filter_36.png b/trxGui/Properties/rx_filter_36.png new file mode 100644 index 0000000..f0123b2 Binary files /dev/null and b/trxGui/Properties/rx_filter_36.png differ diff --git a/trxGui/Properties/rxqrg.png b/trxGui/Properties/rxqrg.png new file mode 100644 index 0000000..4187527 Binary files /dev/null and b/trxGui/Properties/rxqrg.png differ diff --git a/trxGui/Properties/rxqrg.xcf b/trxGui/Properties/rxqrg.xcf new file mode 100644 index 0000000..52189c1 Binary files /dev/null and b/trxGui/Properties/rxqrg.xcf differ diff --git a/trxGui/Properties/rxqrg_inact.png b/trxGui/Properties/rxqrg_inact.png new file mode 100644 index 0000000..a9a402b Binary files /dev/null and b/trxGui/Properties/rxqrg_inact.png differ diff --git a/trxGui/Properties/sampleGUI.png b/trxGui/Properties/sampleGUI.png new file mode 100644 index 0000000..2ebabc9 Binary files /dev/null and b/trxGui/Properties/sampleGUI.png differ diff --git a/trxGui/Properties/save.png b/trxGui/Properties/save.png new file mode 100644 index 0000000..794683b Binary files /dev/null and b/trxGui/Properties/save.png differ diff --git a/trxGui/Properties/setup.png b/trxGui/Properties/setup.png new file mode 100644 index 0000000..8ebb1ce Binary files /dev/null and b/trxGui/Properties/setup.png differ diff --git a/trxGui/Properties/swband.png b/trxGui/Properties/swband.png new file mode 100644 index 0000000..6538ffc Binary files /dev/null and b/trxGui/Properties/swband.png differ diff --git a/trxGui/Properties/tr_button.png b/trxGui/Properties/tr_button.png new file mode 100644 index 0000000..01bf105 Binary files /dev/null and b/trxGui/Properties/tr_button.png differ diff --git a/trxGui/Properties/tr_button.xcf b/trxGui/Properties/tr_button.xcf new file mode 100644 index 0000000..06b5212 Binary files /dev/null and b/trxGui/Properties/tr_button.xcf differ diff --git a/trxGui/Properties/tr_button_inact.png b/trxGui/Properties/tr_button_inact.png new file mode 100644 index 0000000..105418e Binary files /dev/null and b/trxGui/Properties/tr_button_inact.png differ diff --git a/trxGui/Properties/tr_button_inact.xcf b/trxGui/Properties/tr_button_inact.xcf new file mode 100644 index 0000000..593b840 Binary files /dev/null and b/trxGui/Properties/tr_button_inact.xcf differ diff --git a/trxGui/Properties/tx_bass.png b/trxGui/Properties/tx_bass.png new file mode 100644 index 0000000..5ddcb09 Binary files /dev/null and b/trxGui/Properties/tx_bass.png differ diff --git a/trxGui/Properties/tx_bass.xcf b/trxGui/Properties/tx_bass.xcf new file mode 100644 index 0000000..6c971ab Binary files /dev/null and b/trxGui/Properties/tx_bass.xcf differ diff --git a/trxGui/Properties/tx_bass_inact.png b/trxGui/Properties/tx_bass_inact.png new file mode 100644 index 0000000..4755b5a Binary files /dev/null and b/trxGui/Properties/tx_bass_inact.png differ diff --git a/trxGui/Properties/tx_filter_1.png b/trxGui/Properties/tx_filter_1.png new file mode 100644 index 0000000..69b6aad Binary files /dev/null and b/trxGui/Properties/tx_filter_1.png differ diff --git a/trxGui/Properties/tx_filter_18.png b/trxGui/Properties/tx_filter_18.png new file mode 100644 index 0000000..9fad0c0 Binary files /dev/null and b/trxGui/Properties/tx_filter_18.png differ diff --git a/trxGui/Properties/tx_filter_22.png b/trxGui/Properties/tx_filter_22.png new file mode 100644 index 0000000..40ad5d0 Binary files /dev/null and b/trxGui/Properties/tx_filter_22.png differ diff --git a/trxGui/Properties/tx_filter_27.png b/trxGui/Properties/tx_filter_27.png new file mode 100644 index 0000000..d6ede28 Binary files /dev/null and b/trxGui/Properties/tx_filter_27.png differ diff --git a/trxGui/Properties/txaudio_button.png b/trxGui/Properties/txaudio_button.png new file mode 100644 index 0000000..ea721a9 Binary files /dev/null and b/trxGui/Properties/txaudio_button.png differ diff --git a/trxGui/Properties/txaudio_button.xcf b/trxGui/Properties/txaudio_button.xcf new file mode 100644 index 0000000..5b277f9 Binary files /dev/null and b/trxGui/Properties/txaudio_button.xcf differ diff --git a/trxGui/Properties/txqrg.png b/trxGui/Properties/txqrg.png new file mode 100644 index 0000000..68fb757 Binary files /dev/null and b/trxGui/Properties/txqrg.png differ diff --git a/trxGui/Properties/txqrg_inact.png b/trxGui/Properties/txqrg_inact.png new file mode 100644 index 0000000..ce11f7e Binary files /dev/null and b/trxGui/Properties/txqrg_inact.png differ diff --git a/trxGui/Properties/vorlage.xcf b/trxGui/Properties/vorlage.xcf new file mode 100644 index 0000000..c150493 Binary files /dev/null and b/trxGui/Properties/vorlage.xcf differ diff --git a/trxGui/Properties/wave.png b/trxGui/Properties/wave.png new file mode 100644 index 0000000..aac5d2a Binary files /dev/null and b/trxGui/Properties/wave.png differ diff --git a/trxGui/Properties/waveactive.png b/trxGui/Properties/waveactive.png new file mode 100644 index 0000000..6a8f651 Binary files /dev/null and b/trxGui/Properties/waveactive.png differ diff --git a/trxGui/Properties/xit_button.png b/trxGui/Properties/xit_button.png new file mode 100644 index 0000000..a996d33 Binary files /dev/null and b/trxGui/Properties/xit_button.png differ diff --git a/trxGui/Properties/xit_button.xcf b/trxGui/Properties/xit_button.xcf new file mode 100644 index 0000000..4b5958c Binary files /dev/null and b/trxGui/Properties/xit_button.xcf differ diff --git a/trxGui/Properties/xit_button_inact.png b/trxGui/Properties/xit_button_inact.png new file mode 100644 index 0000000..acd93f2 Binary files /dev/null and b/trxGui/Properties/xit_button_inact.png differ diff --git a/trxGui/Properties/xit_button_inact.xcf b/trxGui/Properties/xit_button_inact.xcf new file mode 100644 index 0000000..1603170 Binary files /dev/null and b/trxGui/Properties/xit_button_inact.xcf differ diff --git a/trxGui/bin/Debug/ColorSlider.dll b/trxGui/bin/Debug/ColorSlider.dll new file mode 100755 index 0000000..2effcf8 Binary files /dev/null and b/trxGui/bin/Debug/ColorSlider.dll differ diff --git a/trxGui/bin/Debug/ColorSlider.pdb b/trxGui/bin/Debug/ColorSlider.pdb new file mode 100755 index 0000000..02fa339 Binary files /dev/null and b/trxGui/bin/Debug/ColorSlider.pdb differ diff --git a/trxGui/bin/Debug/qo100trx.exe b/trxGui/bin/Debug/qo100trx.exe new file mode 100755 index 0000000..bb7c229 Binary files /dev/null and b/trxGui/bin/Debug/qo100trx.exe differ diff --git a/trxGui/bin/Debug/qo100trx.exe.config b/trxGui/bin/Debug/qo100trx.exe.config new file mode 100755 index 0000000..d740e88 --- /dev/null +++ b/trxGui/bin/Debug/qo100trx.exe.config @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/trxGui/bin/Debug/qo100trx.pdb b/trxGui/bin/Debug/qo100trx.pdb new file mode 100755 index 0000000..af52954 Binary files /dev/null and b/trxGui/bin/Debug/qo100trx.pdb differ diff --git a/trxGui/color.cs b/trxGui/color.cs new file mode 100644 index 0000000..511efd7 --- /dev/null +++ b/trxGui/color.cs @@ -0,0 +1,323 @@ +using System.Drawing; + +namespace trxGui +{ + class color + { + // colortable from wsprx by K1JT + // used for monochrome colors only + // the full color map is calculated at runtime + + double[,] coltab = new double[256, 6] + { + // Blue Theme: r,g,b Red Theme: r,g,b + {0.0000,0.0000,0.0000,0.0000,0.0000,0.0000}, + {0.0902,0.0902,0.2558,0.0000,0.0000,0.0000}, + {0.1176,0.1176,0.2694,0.0078,0.0000,0.0000}, + {0.1412,0.1412,0.2820,0.0157,0.0000,0.0000}, + {0.1569,0.1569,0.2938,0.0235,0.0000,0.0000}, + {0.1725,0.1725,0.3049,0.0314,0.0000,0.0000}, + {0.1843,0.1843,0.3154,0.0392,0.0000,0.0000}, + {0.1961,0.1961,0.3254,0.0471,0.0000,0.0000}, + {0.2039,0.2039,0.3349,0.0549,0.0000,0.0000}, + {0.2157,0.2157,0.3440,0.0627,0.0000,0.0000}, + {0.2235,0.2235,0.3528,0.0706,0.0000,0.0000}, + {0.2314,0.2314,0.3612,0.0784,0.0000,0.0000}, + {0.2392,0.2392,0.3693,0.0863,0.0000,0.0000}, + {0.2471,0.2471,0.3772,0.0941,0.0000,0.0000}, + {0.2549,0.2549,0.3848,0.1020,0.0000,0.0000}, + {0.2588,0.2588,0.3921,0.1098,0.0000,0.0000}, + {0.2667,0.2667,0.3992,0.1176,0.0000,0.0000}, + {0.2706,0.2706,0.4061,0.1255,0.0000,0.0000}, + {0.2784,0.2784,0.4129,0.1333,0.0000,0.0000}, + {0.2824,0.2824,0.4194,0.1412,0.0000,0.0000}, + {0.2902,0.2902,0.4258,0.1490,0.0000,0.0000}, + {0.2941,0.2941,0.4319,0.1569,0.0000,0.0000}, + {0.2980,0.2980,0.4380,0.1647,0.0000,0.0000}, + {0.3059,0.3059,0.4439,0.1725,0.0000,0.0000}, + {0.3098,0.3098,0.4496,0.1804,0.0000,0.0000}, + {0.3137,0.3137,0.4553,0.1882,0.0000,0.0000}, + {0.3176,0.3176,0.4608,0.1961,0.0000,0.0000}, + {0.3216,0.3216,0.4661,0.2039,0.0000,0.0000}, + {0.3294,0.3294,0.4714,0.2118,0.0000,0.0000}, + {0.3333,0.3333,0.4765,0.2196,0.0000,0.0000}, + {0.3373,0.3373,0.4815,0.2275,0.0000,0.0000}, + {0.3412,0.3412,0.4865,0.2353,0.0000,0.0000}, + {0.3451,0.3451,0.4913,0.2431,0.0000,0.0000}, + {0.3490,0.3490,0.4960,0.2510,0.0000,0.0000}, + {0.3529,0.3529,0.5006,0.2588,0.0000,0.0000}, + {0.3569,0.3569,0.5052,0.2667,0.0000,0.0000}, + {0.3608,0.3608,0.5096,0.2745,0.0000,0.0000}, + {0.3647,0.3647,0.5140,0.2824,0.0000,0.0000}, + {0.3686,0.3686,0.5183,0.2902,0.0000,0.0000}, + {0.3725,0.3725,0.5225,0.2980,0.0000,0.0000}, + {0.3765,0.3765,0.5266,0.3059,0.0000,0.0000}, + {0.3804,0.3804,0.5306,0.3137,0.0000,0.0000}, + {0.3843,0.3843,0.5346,0.3216,0.0000,0.0000}, + {0.3843,0.3843,0.5385,0.3294,0.0000,0.0000}, + {0.3882,0.3882,0.5423,0.3373,0.0000,0.0000}, + {0.3922,0.3922,0.5460,0.3451,0.0000,0.0000}, + {0.3961,0.3961,0.5497,0.3529,0.0000,0.0000}, + {0.4000,0.4000,0.5533,0.3608,0.0000,0.0000}, + {0.4039,0.4039,0.5569,0.3686,0.0000,0.0000}, + {0.4078,0.4078,0.5603,0.3765,0.0000,0.0000}, + {0.4118,0.4118,0.5638,0.3843,0.0000,0.0000}, + {0.4118,0.4118,0.5671,0.3922,0.0000,0.0000}, + {0.4157,0.4157,0.5704,0.4000,0.0000,0.0000}, + {0.4196,0.4196,0.5736,0.4078,0.0000,0.0000}, + {0.4235,0.4235,0.5768,0.4157,0.0000,0.0000}, + {0.4275,0.4275,0.5799,0.4235,0.0000,0.0000}, + {0.4314,0.4314,0.5829,0.4314,0.0000,0.0000}, + {0.4314,0.4314,0.5859,0.4392,0.0000,0.0000}, + {0.4353,0.4353,0.5889,0.4471,0.0000,0.0000}, + {0.4392,0.4392,0.5917,0.4549,0.0000,0.0000}, + {0.4431,0.4431,0.5946,0.4627,0.0000,0.0000}, + {0.4471,0.4471,0.5973,0.4706,0.0000,0.0000}, + {0.4471,0.4471,0.6001,0.4784,0.0000,0.0000}, + {0.4510,0.4510,0.6027,0.4863,0.0000,0.0000}, + {0.4549,0.4549,0.6053,0.4941,0.0000,0.0000}, + {0.4588,0.4588,0.6079,0.5020,0.0000,0.0000}, + {0.4627,0.4627,0.6104,0.5098,0.0098,0.0000}, + {0.4627,0.4627,0.6129,0.5176,0.0176,0.0000}, + {0.4667,0.4667,0.6153,0.5255,0.0255,0.0000}, + {0.4706,0.4706,0.6176,0.5333,0.0333,0.0000}, + {0.4745,0.4745,0.6199,0.5412,0.0412,0.0000}, + {0.4745,0.4745,0.6222,0.5490,0.0490,0.0000}, + {0.4784,0.4784,0.6244,0.5569,0.0569,0.0000}, + {0.4824,0.4824,0.6266,0.5647,0.0647,0.0000}, + {0.4863,0.4863,0.6287,0.5725,0.0725,0.0000}, + {0.4863,0.4863,0.6308,0.5804,0.0804,0.0000}, + {0.4902,0.4902,0.6328,0.5882,0.0882,0.0000}, + {0.4941,0.4941,0.6348,0.5961,0.0961,0.0000}, + {0.4980,0.4980,0.6367,0.6039,0.1039,0.0000}, + {0.5020,0.5020,0.6386,0.6118,0.1118,0.0000}, + {0.5020,0.5020,0.6404,0.6196,0.1196,0.0000}, + {0.5059,0.5059,0.6422,0.6275,0.1275,0.0000}, + {0.5098,0.5098,0.6440,0.6353,0.1353,0.0000}, + {0.5098,0.5098,0.6457,0.6431,0.1431,0.0000}, + {0.5137,0.5137,0.6474,0.6510,0.1510,0.0000}, + {0.5176,0.5176,0.6490,0.6588,0.1588,0.0000}, + {0.5216,0.5216,0.6506,0.6667,0.1667,0.0000}, + {0.5216,0.5216,0.6521,0.6745,0.1745,0.0000}, + {0.5255,0.5255,0.6536,0.6824,0.1824,0.0000}, + {0.5294,0.5294,0.6551,0.6902,0.1902,0.0000}, + {0.5333,0.5333,0.6565,0.6980,0.1980,0.0000}, + {0.5333,0.5333,0.6578,0.7059,0.2059,0.0000}, + {0.5373,0.5373,0.6591,0.7137,0.2137,0.0000}, + {0.5412,0.5412,0.6604,0.7216,0.2216,0.0000}, + {0.5451,0.5451,0.6617,0.7294,0.2294,0.0000}, + {0.5451,0.5451,0.6629,0.7373,0.2373,0.0000}, + {0.5490,0.5490,0.6640,0.7451,0.2451,0.0000}, + {0.5529,0.5529,0.6651,0.7529,0.2529,0.0000}, + {0.5569,0.5569,0.6662,0.7608,0.2608,0.0000}, + {0.5569,0.5569,0.6672,0.7686,0.2686,0.0000}, + {0.5608,0.5608,0.6682,0.7765,0.2765,0.0000}, + {0.5647,0.5647,0.6692,0.7843,0.2843,0.0000}, + {0.5647,0.5647,0.6701,0.7922,0.2922,0.0000}, + {0.5686,0.5686,0.6710,0.8000,0.3000,0.0000}, + {0.5725,0.5725,0.6718,0.8078,0.3078,0.0000}, + {0.5765,0.5765,0.6726,0.8157,0.3157,0.0000}, + {0.5765,0.5765,0.6733,0.8235,0.3235,0.0000}, + {0.5804,0.5804,0.6740,0.8314,0.3314,0.0000}, + {0.5843,0.5843,0.6747,0.8392,0.3392,0.0000}, + {0.5843,0.5843,0.6753,0.8471,0.3471,0.0000}, + {0.5882,0.5882,0.6759,0.8549,0.3549,0.0000}, + {0.5922,0.5922,0.6765,0.8627,0.3627,0.0000}, + {0.5961,0.5961,0.6770,0.8706,0.3706,0.0000}, + {0.5961,0.5961,0.6774,0.8784,0.3784,0.0000}, + {0.6000,0.6000,0.6779,0.8863,0.3863,0.0000}, + {0.6039,0.6039,0.6783,0.8941,0.3941,0.0000}, + {0.6039,0.6039,0.6786,0.9020,0.4020,0.0000}, + {0.6078,0.6078,0.6789,0.9098,0.4098,0.0000}, + {0.6118,0.6118,0.6792,0.9176,0.4176,0.0000}, + {0.6157,0.6157,0.6794,0.9255,0.4255,0.0000}, + {0.6157,0.6157,0.6796,0.9333,0.4333,0.0000}, + {0.6196,0.6196,0.6798,0.9412,0.4412,0.0000}, + {0.6235,0.6235,0.6799,0.9490,0.4490,0.0000}, + {0.6235,0.6235,0.6800,0.9569,0.4569,0.0000}, + {0.6275,0.6275,0.6800,0.9647,0.4647,0.0000}, + {0.6314,0.6314,0.6800,0.9725,0.4725,0.0000}, + {0.6353,0.6353,0.6799,0.9804,0.4804,0.0000}, + {0.6353,0.6353,0.6799,0.9882,0.4882,0.0000}, + {0.6392,0.6392,0.6797,0.9961,0.4961,0.0000}, + {0.6431,0.6431,0.6796,1.0000,0.5039,0.0000}, + {0.6431,0.6431,0.6794,1.0000,0.5118,0.0118}, + {0.6471,0.6471,0.6791,1.0000,0.5196,0.0196}, + {0.6510,0.6510,0.6789,1.0000,0.5275,0.0275}, + {0.6549,0.6549,0.6785,1.0000,0.5353,0.0353}, + {0.6549,0.6549,0.6782,1.0000,0.5431,0.0431}, + {0.6588,0.6588,0.6778,1.0000,0.5510,0.0510}, + {0.6627,0.6627,0.6773,1.0000,0.5588,0.0588}, + {0.6627,0.6627,0.6769,1.0000,0.5667,0.0667}, + {0.6667,0.6667,0.6763,1.0000,0.5745,0.0745}, + {0.6706,0.6706,0.6758,1.0000,0.5824,0.0824}, + {0.6745,0.6745,0.6752,1.0000,0.5902,0.0902}, + {0.6745,0.6745,0.6746,1.0000,0.5980,0.0980}, + {0.6784,0.6784,0.6739,1.0000,0.6059,0.1059}, + {0.6824,0.6824,0.6732,1.0000,0.6137,0.1137}, + {0.6824,0.6824,0.6724,1.0000,0.6216,0.1216}, + {0.6863,0.6863,0.6716,1.0000,0.6294,0.1294}, + {0.6902,0.6902,0.6708,1.0000,0.6373,0.1373}, + {0.6941,0.6941,0.6699,1.0000,0.6451,0.1451}, + {0.6941,0.6941,0.6690,1.0000,0.6529,0.1529}, + {0.6980,0.6980,0.6680,1.0000,0.6608,0.1608}, + {0.7020,0.7020,0.6670,1.0000,0.6686,0.1686}, + {0.7020,0.7020,0.6660,1.0000,0.6765,0.1765}, + {0.7059,0.7059,0.6649,1.0000,0.6843,0.1843}, + {0.7098,0.7098,0.6638,1.0000,0.6922,0.1922}, + {0.7098,0.7098,0.6626,1.0000,0.7000,0.2000}, + {0.7137,0.7137,0.6614,1.0000,0.7078,0.2078}, + {0.7176,0.7176,0.6601,1.0000,0.7157,0.2157}, + {0.7216,0.7216,0.6589,1.0000,0.7235,0.2235}, + {0.7216,0.7216,0.6575,1.0000,0.7314,0.2314}, + {0.7255,0.7255,0.6561,1.0000,0.7392,0.2392}, + {0.7294,0.7294,0.6547,1.0000,0.7471,0.2471}, + {0.7294,0.7294,0.6533,1.0000,0.7549,0.2549}, + {0.7333,0.7333,0.6518,1.0000,0.7627,0.2627}, + {0.7373,0.7373,0.6502,1.0000,0.7706,0.2706}, + {0.7412,0.7412,0.6486,1.0000,0.7784,0.2784}, + {0.7412,0.7412,0.6470,1.0000,0.7863,0.2863}, + {0.7451,0.7451,0.6453,1.0000,0.7941,0.2941}, + {0.7490,0.7490,0.6436,1.0000,0.8020,0.3020}, + {0.7490,0.7490,0.6418,1.0000,0.8098,0.3098}, + {0.7529,0.7529,0.6400,1.0000,0.8176,0.3176}, + {0.7569,0.7569,0.6382,1.0000,0.8255,0.3255}, + {0.7608,0.7608,0.6363,1.0000,0.8333,0.3333}, + {0.7608,0.7608,0.6343,1.0000,0.8412,0.3412}, + {0.7647,0.7647,0.6324,1.0000,0.8490,0.3490}, + {0.7686,0.7686,0.6303,1.0000,0.8569,0.3569}, + {0.7686,0.7686,0.6282,1.0000,0.8647,0.3647}, + {0.7725,0.7725,0.6261,1.0000,0.8725,0.3725}, + {0.7765,0.7765,0.6239,1.0000,0.8804,0.3804}, + {0.7804,0.7804,0.6217,1.0000,0.8882,0.3882}, + {0.7804,0.7804,0.6194,1.0000,0.8961,0.3961}, + {0.7843,0.7843,0.6171,1.0000,0.9039,0.4039}, + {0.7882,0.7882,0.6147,1.0000,0.9118,0.4118}, + {0.7882,0.7882,0.6123,1.0000,0.9196,0.4196}, + {0.7922,0.7922,0.6098,1.0000,0.9275,0.4275}, + {0.7961,0.7961,0.6073,1.0000,0.9353,0.4353}, + {0.8000,0.8000,0.6047,1.0000,0.9431,0.4431}, + {0.8000,0.8000,0.6021,1.0000,0.9510,0.4510}, + {0.8039,0.8039,0.5994,1.0000,0.9588,0.4588}, + {0.8078,0.8078,0.5967,1.0000,0.9667,0.4667}, + {0.8078,0.8078,0.5939,1.0000,0.9745,0.4745}, + {0.8118,0.8118,0.5911,1.0000,0.9824,0.4824}, + {0.8157,0.8157,0.5882,1.0000,0.9902,0.4902}, + {0.8196,0.8196,0.5853,1.0000,0.9980,0.4980}, + {0.8196,0.8196,0.5823,1.0000,1.0000,0.5059}, + {0.8235,0.8235,0.5792,1.0000,1.0000,0.5137}, + {0.8275,0.8275,0.5761,1.0000,1.0000,0.5216}, + {0.8275,0.8275,0.5729,1.0000,1.0000,0.5294}, + {0.8314,0.8314,0.5697,1.0000,1.0000,0.5373}, + {0.8353,0.8353,0.5664,1.0000,1.0000,0.5451}, + {0.8392,0.8392,0.5630,1.0000,1.0000,0.5529}, + {0.8392,0.8392,0.5596,1.0000,1.0000,0.5608}, + {0.8431,0.8431,0.5561,1.0000,1.0000,0.5686}, + {0.8471,0.8471,0.5525,1.0000,1.0000,0.5765}, + {0.8471,0.8471,0.5489,1.0000,1.0000,0.5843}, + {0.8510,0.8510,0.5452,1.0000,1.0000,0.5922}, + {0.8549,0.8549,0.5414,1.0000,1.0000,0.6000}, + {0.8588,0.8588,0.5376,1.0000,1.0000,0.6078}, + {0.8588,0.8588,0.5337,1.0000,1.0000,0.6157}, + {0.8627,0.8627,0.5297,1.0000,1.0000,0.6235}, + {0.8667,0.8667,0.5257,1.0000,1.0000,0.6314}, + {0.8667,0.8667,0.5215,1.0000,1.0000,0.6392}, + {0.8706,0.8706,0.5173,1.0000,1.0000,0.6471}, + {0.8745,0.8745,0.5130,1.0000,1.0000,0.6549}, + {0.8784,0.8784,0.5086,1.0000,1.0000,0.6627}, + {0.8784,0.8784,0.5042,1.0000,1.0000,0.6706}, + {0.8824,0.8824,0.4996,1.0000,1.0000,0.6784}, + {0.8863,0.8863,0.4950,1.0000,1.0000,0.6863}, + {0.8863,0.8863,0.4902,1.0000,1.0000,0.6941}, + {0.8902,0.8902,0.4854,1.0000,1.0000,0.7020}, + {0.8941,0.8941,0.4804,1.0000,1.0000,0.7098}, + {0.8980,0.8980,0.4754,1.0000,1.0000,0.7176}, + {0.8980,0.8980,0.4702,1.0000,1.0000,0.7255}, + {0.9020,0.9020,0.4649,1.0000,1.0000,0.7333}, + {0.9059,0.9059,0.4595,1.0000,1.0000,0.7412}, + {0.9098,0.9098,0.4540,1.0000,1.0000,0.7490}, + {0.9098,0.9098,0.4484,1.0000,1.0000,0.7569}, + {0.9137,0.9137,0.4426,1.0000,1.0000,0.7647}, + {0.9176,0.9176,0.4366,1.0000,1.0000,0.7725}, + {0.9176,0.9176,0.4306,1.0000,1.0000,0.7804}, + {0.9216,0.9216,0.4243,1.0000,1.0000,0.7882}, + {0.9255,0.9255,0.4179,1.0000,1.0000,0.7961}, + {0.9294,0.9294,0.4114,1.0000,1.0000,0.8039}, + {0.9294,0.9294,0.4046,1.0000,1.0000,0.8118}, + {0.9333,0.9333,0.3977,1.0000,1.0000,0.8196}, + {0.9373,0.9373,0.3905,1.0000,1.0000,0.8275}, + {0.9373,0.9373,0.3831,1.0000,1.0000,0.8353}, + {0.9412,0.9412,0.3754,1.0000,1.0000,0.8431}, + {0.9451,0.9451,0.3675,1.0000,1.0000,0.8510}, + {0.9490,0.9490,0.3594,1.0000,1.0000,0.8588}, + {0.9490,0.9490,0.3509,1.0000,1.0000,0.8667}, + {0.9529,0.9529,0.3420,1.0000,1.0000,0.8745}, + {0.9569,0.9569,0.3328,1.0000,1.0000,0.8824}, + {0.9608,0.9608,0.3232,1.0000,1.0000,0.8902}, + {0.9608,0.9608,0.3131,1.0000,1.0000,0.8980}, + {0.9647,0.9647,0.3024,1.0000,1.0000,0.9059}, + {0.9686,0.9686,0.2912,1.0000,1.0000,0.9137}, + {0.9686,0.9686,0.2792,1.0000,1.0000,0.9216}, + {0.9725,0.9725,0.2664,1.0000,1.0000,0.9294}, + {0.9765,0.9765,0.2526,1.0000,1.0000,0.9373}, + {0.9804,0.9804,0.2375,1.0000,1.0000,0.9451}, + {0.9804,0.9804,0.2208,1.0000,1.0000,0.9529}, + {0.9843,0.9843,0.2020,1.0000,1.0000,0.9608}, + {0.9882,0.9882,0.1800,1.0000,1.0000,0.9686}, + {1.0,0.0,0.0,1.0000,1.0000,0.9765}, + {1.0,1.0,0.0,0.0,1.0,1.0}, + {0.0,1.0,0.0,0.0,1.0,0.0} + }; + + static SolidBrush[] sba = new SolidBrush[256]; + static int fba = 1; + + public SolidBrush getSolidBrush(int val) + { + if (fba == 1) + { + fba = 0; + for (int i = 0; i < 256; i++) + { + sba[i] = new SolidBrush(getColor(i)); + } + } + if (val > 255) val = 255; + if (val < 0) val = 0; + return sba[val]; + } + + public Color getColor(int val) + { + int r = 0, b = 0, g = 0; + + if (val > 255) val = 255; + if (val < 0) val = 0; + + // we use the last 3 values only, these make much better contrast + if (statics.palette == 0) + { + b = (int)(coltab[val, 3] * 255); + g = (int)(coltab[val, 4] * 255); + r = (int)(coltab[val, 5] * 255); + } + else if (statics.palette == 1) + { + r = (int)(coltab[val, 3] * 255); + g = (int)(coltab[val, 4] * 255); + b = (int)(coltab[val, 5] * 255); + } + else if (statics.palette == 2) + { + g = (int)(coltab[val, 3] * 255); + b = (int)(coltab[val, 4] * 255); + r = (int)(coltab[val, 5] * 255); + } + else + { + r = g = b = (int)((coltab[val, 3] + coltab[val, 4] + coltab[val, 5]) / 3 * 255); + } + return Color.FromArgb(r, g, b); + } + } +} diff --git a/trxGui/language.cs b/trxGui/language.cs new file mode 100755 index 0000000..098a0f4 --- /dev/null +++ b/trxGui/language.cs @@ -0,0 +1,292 @@ +using System; + +namespace trxGui +{ + static class language + { + public static String[] en = new String[] + { + "Pluto Address:", + "local USB", + "enter IP address of the Pluto", + "Loadspeaker/Headphone:", + "Microphone:", + "Receiver Frequency:", + "Transmitter Frequency:", + "Spectrum/Waterfall Speed:", + "Cancel", + "MHz ( enter center frequency corresponding to 10489.750 MHz )", + "MHz ( enter center frequency corresponding to 2400,250 MHz )", + "Hz (correction value for the Pluto TCXO, or use CAL calibration function)", + "Hz (correction value for the LNB, or use CAL calibration function)", + "normal CPU", + "to reduce CPU load on slower computers", + "Help", + "Language:", + "Open Manual", + "Mouse:", + "Color Palette:", + "Pluto TX power [dBm], allowed values: -40 to 0", + "TX power:", + + "1. click the CALIB LNB button: ", + "2. Click the center of the BPSK beacon with the left mouse button to move it to the 0 Hz line", + "LNB calibration:", + "439 FINISHED", + "LNB FINISHED", + "4. when you are done, click the 439 FINISHED button:", + "2. transmit a 439,000 MHz carrier using a 70cm transceiver", + "1. click the CALIB439 button: ", + "PLUTO clock (TCXO) calibration", + "3. Click the peak with the left mouse button to move it to the center 0 Hz line", + "3. when you are done, click the LNB FINISHED button:", + "Close", + "Example:", + "Referenz Frequency Calibration", + "Do you want to shut down the computer?", + }; + + public static String[] de = new String[] + { + "Pluto Adresse:", + "USB lokal", + "gebe IP Adresse des Plutos ein", + "Lautsprecher/Kopfhörer:", + "Mikrofon:", + "Empfangsfrequenz:", + "Sendefrequenz:", + "Spekt./Wasserf. Auflösung:", + "Abbrechen", + "MHz ( Mittenfrequenz bezogen auf 10489,750 MHz )", + "MHz ( Mittenfrequenz bezogen auf 2400,250 MHz )", + "Hz (Korrekturwert für den Pluto TCXO, oder benutze die CAL Funktion)", + "Hz (Korrekturwert für den LNB, oder benutze die CAL Funktion)", + "normale CPU", + "Reduziere die CPU Last auf langsamen Rechnern", + "Hilfe", + "Sprache:", + "Bedienungsanleitung", + "Maus:", + "Farbpalette:", + "Pluto TX Ausgangsleistung [dBm], erlaubte Werte: -40 bis 0", + "TX Leistung:", + + "1. klicke CALIB LNB: ", + "2. Klicke in die Mitte der BPSK Bake um sie auf die 0 Hz Linie zu schieben", + "LNB Kalibration:", + "439 fertig", + "LNB fertig", + "4. wenn fertig klicke auf \"439 fertig\":", + "2. sende einen Träger auf 439,000 MHz mit einem 70cm Transceiver", + "1. klicke auf CALIB439: ", + "PLUTO Takt (TCXO) Kalibration", + "3. Klicke auf die Spitze um sie zur 0 Hz Linie zu schieben", + "3. wenn fertig klicke \"LNB fertig\":", + "Schließen", + "Beispiel:", + "Referenz Frequenz Kalibration", + "Wollen sie den Rechner wirklich herunterfahren?", + }; + + public static String[] fr = new String[] + { + "Adresse Pluto :", + "USB local", + "entrer l'adresse IP du Pluto", + "Loadspeaker/Headphone :", + "Microphone :", + "Fréquence du récepteur :", + "Fréquence de l'émetteur :", + "Spectre/Vitesse de chute d'eau :", + "Annuler", + "MHz (entrer la fréquence centrale correspondant à 10489,750 MHz)", + "MHz (entrer la fréquence centrale correspondant à 2400,250 MHz)", + "Hz (valeur de correction pour le TCXO de Pluto, ou utiliser la fonction de calibration CAL)", + "Hz (valeur de correction pour le LNB, ou utiliser la fonction de calibrage CAL)", + "CPU normal", + "pour réduire la charge du CPU sur les ordinateurs plus lents", + "Aide", + "Langue :", + "Ouvrir le manuel", + "Souris :", + "Palette de couleurs :", + "Puissance TX Pluto [dBm], valeurs autorisées : -40 à 0", + "Puissance TX :", + + "1. Cliquez sur le bouton CALIB LNB : ", + "2. Cliquez sur le centre de la balise BPSK pour la déplacer sur la ligne 0 Hz", + "Calibration du LNB :", + "439 FINI", + "LNB FINI", + "4. Lorsque vous avez terminé, cliquez sur le bouton 439 FINI :", + "2. Transmettre une porteuse de 439 000 MHz à l'aide d'un émetteur-récepteur de 70 cm.", + "1. Cliquez sur le bouton CALIB439 : ", + "Calibrage de l'horloge PLUTO (TCXO)", + "3. Cliquez sur le pic pour le déplacer au centre de la ligne 0 Hz", + "3. Lorsque vous avez terminé, cliquez sur le bouton LNB FINI :", + "Fermer", + "Exemple:", + "Referenz Calibrage de la fréquence", + "Voulez-vous éteindre l'ordinateur ?", + }; + + public static String[] es = new String[] + { + "Dirección de Pluto:", + "USB local", + "introduzca la dirección IP del Pluto", + "Altavoz/Auricular:", + "Micrófono:", + "Frecuencia del receptor:", + "Frecuencia del transmisor:", + "Espectro/Velocidad de caída:", + "Cancelar", + "MHz ( introduzca la frecuencia central correspondiente a 10489,750 MHz )", + "MHz ( introduzca la frecuencia central correspondiente a 2400,250 MHz )", + "Hz (valor de corrección para el TCXO de Plutón, o utilice la función de calibración CAL)", + "Hz (valor de corrección para el LNB, o utilice la función de calibración CAL)", + "CPU normal", + "para reducir la carga de la CPU en ordenadores más lentos", + "Ayuda", + "Idioma:", + "Abrir manual", + "Ratón:", + "Paleta de colores:", + "Potencia de transmisión de Plutón [dBm], valores permitidos: -40 a 0", + "Potencia TX:", + + "1. Pulse el botón CALIB LNB: ", + "2. Haga clic en el centro de la baliza BPSK para moverla a la línea de 0 Hz", + "LNB calibración:", + "439 FINALIZADO", + "LNB FINALIZADO", + "4. Cuando haya terminado, haga clic en el botón 439 FINALIZADO:", + "2. transmitir una portadora de 439.000 MHz con un transceptor de 70 cm", + "1. Haga clic en el botón CALIB439:", + "Calibración del reloj PLUTO (TCXO)", + "3. Haga clic en el pico para moverlo a la línea central de 0 Hz", + "3. Cuando haya terminado, pulse el botón LNB FINALIZADO:", + "Cerrar", + "Ejemplo:", + "Calibración de la frecuencia de referencia", + "¿Quieres apagar el ordenador?", + + }; + + public static String[] pt = new String[] + { + "Endereço de Plutão:", + "USB local", + "introduzir o endereço IP do Plutão", + "Loadspeaker/Headphone:", + "Microfone:", + "Receptor Frequência:", + "Frequência do Transmissor:", + "Spectrum/Waterfall Speed:", + "Cancelar", + "MHz ( introduzir a frequência central correspondente a 10489.750 MHz )", + "MHz ( introduzir a frequência central correspondente a 2400,250 MHz )", + "Hz (valor de correcção para o Pluto TCXO, ou utilizar a função de calibração CAL)", + "Hz (valor de correcção para o LNB, ou utilizar a função de calibração CAL)", + "CPU normal", + "para reduzir a carga da CPU em computadores mais lentos", + "Ajuda", + "Língua:", + "Manual Aberto", + "Rato:", + "Paleta de cores:", + "Pluto TX potência [dBm], valores permitidos: -40 a 0", + "TX power:", + + "1. clique no botão CALIB LNB: ", + "2. Clique no centro do farol BPSK para o mover para a linha de 0 Hz", + "LNB calibração:", + "439 CONCLUÍDO", + "LNB CONCLUÍDO", + "4. Quando tiver terminado, clique no botão 439 CONCLUÍDO:", + "2. transmitir uma portadora de 439.000 MHz utilizando um transceiver de 70cm", + "1. clique no botão CALIB439:", + "Calibração do relógio PLUTO (TCXO)", + "3. Clique no pico para o mover para o centro da linha 0 Hz", + "3. Quando tiver terminado, clique no botão LNB CONCLUÍDO:", + "Fechar", + "Exemplo:", + "Calibração de frequência de referência", + "Quer desligar o computador?", + + }; + + public static String[] it = new String[] + { + "Indirizzo Pluto:", + "USB locale", + "inserire l'indirizzo IP del Pluto", + "Altoparlante/Cuffia:", + "Microfono:", + "Frequenza del ricevitore:", + "Frequenza del trasmettitore:", + "Spettro/Velocità della cascata:", + "Annulla", + "MHz ( inserire frequenza centrale corrispondente a 10489,750 MHz )", + "MHz ( inserire frequenza centrale corrispondente a 2400,250 MHz )", + "Hz (valore di correzione per il TCXO Pluto, o usare la funzione di calibrazione CAL)", + "Hz (valore di correzione per l'LNB, o usare la funzione di calibrazione CAL)", + "CPU normale", + "per ridurre il carico della CPU sui computer più lenti", + "Aiuto", + "Lingua:", + "Aprire il manuale", + "Mouse:", + "Tavolozza dei colori:", + "Potenza TX Pluto [dBm], valori ammessi: -40 a 0", + "Potenza TX:", + + "1. cliccate sul pulsante CALIB LNB: ", + "2. Fare clic sul centro del beacon BPSK per spostarlo sulla linea 0 Hz", + "LNB calibrazione:", + "439 FINITO", + "LNB FINITO", + "4. quando hai finito, clicca sul pulsante 439 FINITO:", + "2. trasmettere una portante di 439.000 MHz usando un ricetrasmettitore da 70 cm", + "1. cliccate sul pulsante CALIB439:", + "Taratura del clock PLUTO (TCXO)", + "3. Fare clic sul picco per spostarlo sulla linea centrale 0 Hz", + "3. quando avete finito, cliccate sul pulsante LNB FINITO:", + "Chiudere", + "Esempio:", + "Calibrazione della frequenza di riferimento", + "Vuoi spegnere il computer?", + + }; + + + + public static String GetText(String s) + { + if( en.Length != de.Length || + en.Length != fr.Length || + en.Length != es.Length || + en.Length != pt.Length || + en.Length != it.Length) + { + Console.WriteLine("***** incomplete translation *****" + en.Length + " " + de.Length + " " + fr.Length + " " + es.Length + " " + pt.Length + " " + it.Length); + return s; + } + + for(int i=0; i +using System; +using System.Reflection; +[assembly: global::System.Runtime.Versioning.TargetFrameworkAttribute(".NETFramework,Version=v4.5.2", FrameworkDisplayName = ".NET Framework 4.5.2")] diff --git a/trxGui/obj/Debug/DesignTimeResolveAssemblyReferences.cache b/trxGui/obj/Debug/DesignTimeResolveAssemblyReferences.cache new file mode 100644 index 0000000..e30db06 Binary files /dev/null and b/trxGui/obj/Debug/DesignTimeResolveAssemblyReferences.cache differ diff --git a/trxGui/obj/Debug/DesignTimeResolveAssemblyReferencesInput.cache b/trxGui/obj/Debug/DesignTimeResolveAssemblyReferencesInput.cache new file mode 100644 index 0000000..c95baef Binary files /dev/null and b/trxGui/obj/Debug/DesignTimeResolveAssemblyReferencesInput.cache differ diff --git a/trxGui/obj/Debug/TempPE/Properties.Resources.Designer.cs.dll b/trxGui/obj/Debug/TempPE/Properties.Resources.Designer.cs.dll new file mode 100644 index 0000000..c95f2cf Binary files /dev/null and b/trxGui/obj/Debug/TempPE/Properties.Resources.Designer.cs.dll differ diff --git a/trxGui/obj/Debug/qo100trx.exe b/trxGui/obj/Debug/qo100trx.exe new file mode 100644 index 0000000..bb7c229 Binary files /dev/null and b/trxGui/obj/Debug/qo100trx.exe differ diff --git a/trxGui/obj/Debug/qo100trx.pdb b/trxGui/obj/Debug/qo100trx.pdb new file mode 100644 index 0000000..af52954 Binary files /dev/null and b/trxGui/obj/Debug/qo100trx.pdb differ diff --git a/trxGui/obj/Debug/trxGui.Form1.resources b/trxGui/obj/Debug/trxGui.Form1.resources new file mode 100644 index 0000000..9eadfe3 Binary files /dev/null and b/trxGui/obj/Debug/trxGui.Form1.resources differ diff --git a/trxGui/obj/Debug/trxGui.Form2_agc.resources b/trxGui/obj/Debug/trxGui.Form2_agc.resources new file mode 100755 index 0000000..4610129 Binary files /dev/null and b/trxGui/obj/Debug/trxGui.Form2_agc.resources differ diff --git a/trxGui/obj/Debug/trxGui.Form_info.resources b/trxGui/obj/Debug/trxGui.Form_info.resources new file mode 100644 index 0000000..191788b Binary files /dev/null and b/trxGui/obj/Debug/trxGui.Form_info.resources differ diff --git a/trxGui/obj/Debug/trxGui.Form_reference.resources b/trxGui/obj/Debug/trxGui.Form_reference.resources new file mode 100644 index 0000000..6c05a97 Binary files /dev/null and b/trxGui/obj/Debug/trxGui.Form_reference.resources differ diff --git a/trxGui/obj/Debug/trxGui.Form_screen.resources b/trxGui/obj/Debug/trxGui.Form_screen.resources new file mode 100755 index 0000000..6c05a97 Binary files /dev/null and b/trxGui/obj/Debug/trxGui.Form_screen.resources differ diff --git a/trxGui/obj/Debug/trxGui.Form_setup.resources b/trxGui/obj/Debug/trxGui.Form_setup.resources new file mode 100644 index 0000000..f89b844 Binary files /dev/null and b/trxGui/obj/Debug/trxGui.Form_setup.resources differ diff --git a/trxGui/obj/Debug/trxGui.Properties.Resources.resources b/trxGui/obj/Debug/trxGui.Properties.Resources.resources new file mode 100644 index 0000000..5e823a0 Binary files /dev/null and b/trxGui/obj/Debug/trxGui.Properties.Resources.resources differ diff --git a/trxGui/obj/Debug/trxGui.csproj.CopyComplete b/trxGui/obj/Debug/trxGui.csproj.CopyComplete new file mode 100755 index 0000000..e69de29 diff --git a/trxGui/obj/Debug/trxGui.csproj.CoreCompileInputs.cache b/trxGui/obj/Debug/trxGui.csproj.CoreCompileInputs.cache new file mode 100644 index 0000000..bb60024 --- /dev/null +++ b/trxGui/obj/Debug/trxGui.csproj.CoreCompileInputs.cache @@ -0,0 +1 @@ +ee687add1f0f6adc49675adec27533ce5b120552 diff --git a/trxGui/obj/Debug/trxGui.csproj.FileListAbsolute.txt b/trxGui/obj/Debug/trxGui.csproj.FileListAbsolute.txt new file mode 100644 index 0000000..e5ae2b3 --- /dev/null +++ b/trxGui/obj/Debug/trxGui.csproj.FileListAbsolute.txt @@ -0,0 +1,31 @@ +E:\funk\sat\QO100_Transceiver\trxGui\obj\Debug\trxGui.Form1.resources +E:\funk\sat\QO100_Transceiver\trxGui\obj\Debug\trxGui.Properties.Resources.resources +E:\funk\sat\QO100_Transceiver\trxGui\obj\Debug\trxGui.csproj.GenerateResource.cache +E:\funk\sat\QO100_Transceiver\trxGui\obj\Debug\trxGui.csproj.CoreCompileInputs.cache +E:\funk\sat\QO100_Transceiver\trxGui\obj\Debug\trxGui.csprojAssemblyReference.cache +E:\funk\sat\QO100_Transceiver\trxGui\obj\Debug\trxGui.Form_setup.resources +E:\funk\sat\QO100_Transceiver\trxGui\bin\Debug\qo100trx.exe.config +E:\funk\sat\QO100_Transceiver\trxGui\bin\Debug\qo100trx.exe +E:\funk\sat\QO100_Transceiver\trxGui\bin\Debug\qo100trx.pdb +E:\funk\sat\QO100_Transceiver\trxGui\obj\Debug\trxGui.Form_info.resources +E:\funk\sat\QO100_Transceiver\trxGui\obj\Debug\qo100trx.exe +E:\funk\sat\QO100_Transceiver\trxGui\obj\Debug\qo100trx.pdb +E:\funk\sat\QO100_Transceiver_500\trxGui\bin\Debug\qo100trx.exe.config +E:\funk\sat\QO100_Transceiver_500\trxGui\bin\Debug\qo100trx.exe +E:\funk\sat\QO100_Transceiver_500\trxGui\bin\Debug\qo100trx.pdb +E:\funk\sat\QO100_Transceiver_500\trxGui\obj\Debug\trxGui.csprojAssemblyReference.cache +E:\funk\sat\QO100_Transceiver_500\trxGui\obj\Debug\trxGui.Form1.resources +E:\funk\sat\QO100_Transceiver_500\trxGui\obj\Debug\trxGui.Form_info.resources +E:\funk\sat\QO100_Transceiver_500\trxGui\obj\Debug\trxGui.Form_reference.resources +E:\funk\sat\QO100_Transceiver_500\trxGui\obj\Debug\trxGui.Form_setup.resources +E:\funk\sat\QO100_Transceiver_500\trxGui\obj\Debug\trxGui.Properties.Resources.resources +E:\funk\sat\QO100_Transceiver_500\trxGui\obj\Debug\trxGui.csproj.GenerateResource.cache +E:\funk\sat\QO100_Transceiver_500\trxGui\obj\Debug\trxGui.csproj.CoreCompileInputs.cache +E:\funk\sat\QO100_Transceiver_500\trxGui\obj\Debug\qo100trx.exe +E:\funk\sat\QO100_Transceiver_500\trxGui\obj\Debug\qo100trx.pdb +E:\funk\sat\QO100_Transceiver\trxGui\obj\Debug\trxGui.Form_reference.resources +E:\funk\sat\QO100_Transceiver\trxGui\obj\Debug\trxGui.Form_screen.resources +E:\funk\sat\QO100_Transceiver\trxGui\bin\Debug\ColorSlider.dll +E:\funk\sat\QO100_Transceiver\trxGui\bin\Debug\ColorSlider.pdb +E:\funk\sat\QO100_Transceiver\trxGui\obj\Debug\trxGui.Form2_agc.resources +E:\funk\sat\QO100_Transceiver\trxGui\obj\Debug\trxGui.csproj.CopyComplete diff --git a/trxGui/obj/Debug/trxGui.csproj.GenerateResource.cache b/trxGui/obj/Debug/trxGui.csproj.GenerateResource.cache new file mode 100755 index 0000000..b7eba6c Binary files /dev/null and b/trxGui/obj/Debug/trxGui.csproj.GenerateResource.cache differ diff --git a/trxGui/obj/Debug/trxGui.csprojAssemblyReference.cache b/trxGui/obj/Debug/trxGui.csprojAssemblyReference.cache new file mode 100755 index 0000000..050502c Binary files /dev/null and b/trxGui/obj/Debug/trxGui.csprojAssemblyReference.cache differ diff --git a/trxGui/obj/Release/.NETFramework,Version=v4.5.2.AssemblyAttributes.cs b/trxGui/obj/Release/.NETFramework,Version=v4.5.2.AssemblyAttributes.cs new file mode 100644 index 0000000..ff3eeb3 --- /dev/null +++ b/trxGui/obj/Release/.NETFramework,Version=v4.5.2.AssemblyAttributes.cs @@ -0,0 +1,4 @@ +// +using System; +using System.Reflection; +[assembly: global::System.Runtime.Versioning.TargetFrameworkAttribute(".NETFramework,Version=v4.5.2", FrameworkDisplayName = ".NET Framework 4.5.2")] diff --git a/trxGui/obj/Release/DesignTimeResolveAssemblyReferences.cache b/trxGui/obj/Release/DesignTimeResolveAssemblyReferences.cache new file mode 100755 index 0000000..318201c Binary files /dev/null and b/trxGui/obj/Release/DesignTimeResolveAssemblyReferences.cache differ diff --git a/trxGui/obj/Release/DesignTimeResolveAssemblyReferencesInput.cache b/trxGui/obj/Release/DesignTimeResolveAssemblyReferencesInput.cache new file mode 100644 index 0000000..5087802 Binary files /dev/null and b/trxGui/obj/Release/DesignTimeResolveAssemblyReferencesInput.cache differ diff --git a/trxGui/obj/Release/TempPE/Properties.Resources.Designer.cs.dll b/trxGui/obj/Release/TempPE/Properties.Resources.Designer.cs.dll new file mode 100644 index 0000000..2337bd6 Binary files /dev/null and b/trxGui/obj/Release/TempPE/Properties.Resources.Designer.cs.dll differ diff --git a/trxGui/obj/Release/TempPE/lang_de.Designer.cs.dll b/trxGui/obj/Release/TempPE/lang_de.Designer.cs.dll new file mode 100644 index 0000000..89f2127 Binary files /dev/null and b/trxGui/obj/Release/TempPE/lang_de.Designer.cs.dll differ diff --git a/trxGui/obj/Release/TempPE/lang_en.Designer.cs.dll b/trxGui/obj/Release/TempPE/lang_en.Designer.cs.dll new file mode 100644 index 0000000..91aa046 Binary files /dev/null and b/trxGui/obj/Release/TempPE/lang_en.Designer.cs.dll differ diff --git a/trxGui/obj/Release/qo100trx.exe b/trxGui/obj/Release/qo100trx.exe new file mode 100755 index 0000000..ddbfacf Binary files /dev/null and b/trxGui/obj/Release/qo100trx.exe differ diff --git a/trxGui/obj/Release/qo100trx.pdb b/trxGui/obj/Release/qo100trx.pdb new file mode 100755 index 0000000..f7784a8 Binary files /dev/null and b/trxGui/obj/Release/qo100trx.pdb differ diff --git a/trxGui/obj/Release/trxGui.Form1.resources b/trxGui/obj/Release/trxGui.Form1.resources new file mode 100755 index 0000000..9eadfe3 Binary files /dev/null and b/trxGui/obj/Release/trxGui.Form1.resources differ diff --git a/trxGui/obj/Release/trxGui.Form2_agc.resources b/trxGui/obj/Release/trxGui.Form2_agc.resources new file mode 100755 index 0000000..4610129 Binary files /dev/null and b/trxGui/obj/Release/trxGui.Form2_agc.resources differ diff --git a/trxGui/obj/Release/trxGui.Form_info.resources b/trxGui/obj/Release/trxGui.Form_info.resources new file mode 100755 index 0000000..c948e7b Binary files /dev/null and b/trxGui/obj/Release/trxGui.Form_info.resources differ diff --git a/trxGui/obj/Release/trxGui.Form_reference.resources b/trxGui/obj/Release/trxGui.Form_reference.resources new file mode 100755 index 0000000..6c05a97 Binary files /dev/null and b/trxGui/obj/Release/trxGui.Form_reference.resources differ diff --git a/trxGui/obj/Release/trxGui.Form_screen.resources b/trxGui/obj/Release/trxGui.Form_screen.resources new file mode 100755 index 0000000..6c05a97 Binary files /dev/null and b/trxGui/obj/Release/trxGui.Form_screen.resources differ diff --git a/trxGui/obj/Release/trxGui.Form_setup.resources b/trxGui/obj/Release/trxGui.Form_setup.resources new file mode 100755 index 0000000..6c05a97 Binary files /dev/null and b/trxGui/obj/Release/trxGui.Form_setup.resources differ diff --git a/trxGui/obj/Release/trxGui.Properties.Resources.resources b/trxGui/obj/Release/trxGui.Properties.Resources.resources new file mode 100755 index 0000000..a0a5a95 Binary files /dev/null and b/trxGui/obj/Release/trxGui.Properties.Resources.resources differ diff --git a/trxGui/obj/Release/trxGui.csproj.CopyComplete b/trxGui/obj/Release/trxGui.csproj.CopyComplete new file mode 100755 index 0000000..e69de29 diff --git a/trxGui/obj/Release/trxGui.csproj.CoreCompileInputs.cache b/trxGui/obj/Release/trxGui.csproj.CoreCompileInputs.cache new file mode 100755 index 0000000..cf44f9d --- /dev/null +++ b/trxGui/obj/Release/trxGui.csproj.CoreCompileInputs.cache @@ -0,0 +1 @@ +2f87e672fb39b5238b284cca9369bfd25e3c40a0 diff --git a/trxGui/obj/Release/trxGui.csproj.FileListAbsolute.txt b/trxGui/obj/Release/trxGui.csproj.FileListAbsolute.txt new file mode 100644 index 0000000..a5d1716 --- /dev/null +++ b/trxGui/obj/Release/trxGui.csproj.FileListAbsolute.txt @@ -0,0 +1,35 @@ +E:\funk\sat\QO100_Transceiver\trxGui\bin\Release\trxGui.exe.config +E:\funk\sat\QO100_Transceiver\trxGui\bin\Release\trxGui.exe +E:\funk\sat\QO100_Transceiver\trxGui\bin\Release\trxGui.pdb +E:\funk\sat\QO100_Transceiver\trxGui\obj\Release\trxGui.Form1.resources +E:\funk\sat\QO100_Transceiver\trxGui\obj\Release\trxGui.Properties.Resources.resources +E:\funk\sat\QO100_Transceiver\trxGui\obj\Release\trxGui.csproj.GenerateResource.cache +E:\funk\sat\QO100_Transceiver\trxGui\obj\Release\trxGui.csproj.CoreCompileInputs.cache +E:\funk\sat\QO100_Transceiver\trxGui\obj\Release\trxGui.Form_setup.resources +E:\funk\sat\QO100_Transceiver\trxGui\obj\Release\trxGui.Form_info.resources +E:\funk\sat\Release\trxGui.exe.config +E:\funk\sat\Release\trxGui.exe +E:\funk\sat\Release\trxGui.pdb +E:\funk\sat\QO100_Transceiver\Release\qo100trx.exe.config +E:\funk\sat\QO100_Transceiver\Release\qo100trx.exe +E:\funk\sat\QO100_Transceiver\Release\qo100trx.pdb +E:\funk\sat\QO100_Transceiver\trxGui\obj\Release\qo100trx.exe +E:\funk\sat\QO100_Transceiver\trxGui\obj\Release\qo100trx.pdb +E:\funk\sat\QO100_Transceiver\trxGui\obj\Release\trxGui.Form_reference.resources +E:\funk\sat\QO100_Transceiver_500\Release\qo100trx.exe.config +E:\funk\sat\QO100_Transceiver_500\Release\qo100trx.exe +E:\funk\sat\QO100_Transceiver_500\trxGui\obj\Release\trxGui.csprojAssemblyReference.cache +E:\funk\sat\QO100_Transceiver_500\trxGui\obj\Release\trxGui.Form1.resources +E:\funk\sat\QO100_Transceiver_500\trxGui\obj\Release\trxGui.Form_info.resources +E:\funk\sat\QO100_Transceiver_500\trxGui\obj\Release\trxGui.Form_reference.resources +E:\funk\sat\QO100_Transceiver_500\trxGui\obj\Release\trxGui.Form_setup.resources +E:\funk\sat\QO100_Transceiver_500\trxGui\obj\Release\trxGui.Properties.Resources.resources +E:\funk\sat\QO100_Transceiver_500\trxGui\obj\Release\trxGui.csproj.GenerateResource.cache +E:\funk\sat\QO100_Transceiver_500\trxGui\obj\Release\trxGui.csproj.CoreCompileInputs.cache +E:\funk\sat\QO100_Transceiver_500\trxGui\obj\Release\qo100trx.exe +E:\funk\sat\QO100_Transceiver_500\trxGui\obj\Release\qo100trx.pdb +E:\funk\sat\QO100_Transceiver_500\Release\qo100trx.pdb +E:\funk\sat\QO100_Transceiver\trxGui\obj\Release\trxGui.Form_screen.resources +E:\funk\sat\QO100_Transceiver\trxGui\obj\Release\trxGui.csprojAssemblyReference.cache +E:\funk\sat\QO100_Transceiver\trxGui\obj\Release\trxGui.Form2_agc.resources +E:\funk\sat\QO100_Transceiver\trxGui\obj\Release\trxGui.csproj.CopyComplete diff --git a/trxGui/obj/Release/trxGui.csproj.GenerateResource.cache b/trxGui/obj/Release/trxGui.csproj.GenerateResource.cache new file mode 100755 index 0000000..93f53c8 Binary files /dev/null and b/trxGui/obj/Release/trxGui.csproj.GenerateResource.cache differ diff --git a/trxGui/obj/Release/trxGui.csprojAssemblyReference.cache b/trxGui/obj/Release/trxGui.csprojAssemblyReference.cache new file mode 100755 index 0000000..a2e1b3c Binary files /dev/null and b/trxGui/obj/Release/trxGui.csprojAssemblyReference.cache differ diff --git a/trxGui/statics.cs b/trxGui/statics.cs new file mode 100755 index 0000000..c25f45e --- /dev/null +++ b/trxGui/statics.cs @@ -0,0 +1,419 @@ +using System; +using System.Diagnostics; +using System.Drawing; +using System.IO; +using System.Text; +using System.Threading; + +namespace trxGui +{ + public static class statics + { + public static UInt16 gui_serno = 173; // 123 means: V1.23 + public static UInt16 driver_serno = 0; + public static bool running = true; + public static String ModemIP; + public static int UdpTXport = 40821; + public static int UdpRXport = 40820; + public static bool ptt = false; + public static bool hwptt = false; + public static int GotAudioDevices = 0; + public static String[] AudioPBdevs; + public static String[] AudioCAPdevs; + public static String AudioPBdev; + public static String AudioCAPdev; + public static bool newaudiodevs = false; + public static int ostype; + public static int noiselevel = 1000; + public static int maxnoiselevel = 1000; + public static int difflevel = 0; + public static int maxlevel = 32000; + public static int qsolevel = 1000; + public static int plutousb = 1; + public static String plutoaddress = ""; + public static int rxmouse = -1; + public static bool rxmute = false; + public static bool rit = true; + public static bool xit = false; + public static int micboost = 1; + public static bool compressor = false; + public static int rxfilter = 3; + public static int txfilter = 3; + public static bool audioloop = false; + public static bool rfloop = false; + public static int beaconoffset = 0; + public static int corrfact = 0; + public static int corractive = 0; + public static int corractiveanz = 2; + public static bool autosync = false; + public static bool beaconlock = false; + public static int calmode = 0; // 0=off, 1=439MHz cal + public static int cpuspeed = 0; + public static bool audioHighpass = false; + public static int bandplan_mode = 0; // 0=QO100-Bandplan, 1=QO100-RX-QRGs, 2=QO100-TX-QRGs, 3=Pluto-RX-QRGs, 4=Pluto-TX-QRGs + public static int language = 1; // 0=en, 1=de + public static int palette = 1; // colors: 0=blue, 1=red, 2=green, 3=white + public static int txpower = 0; + public static int windowsize = 5; + public static int panel_bigspec_Width, panel_bigspec_Height, panel_bigwf_Width, panel_bigwf_Height, + panel_smallspec_Width, panel_smallspec_Height, panel_smallwf_Width, panel_smallwf_Height; + public static int sendtone = 0; + public static int pttmode = 0; + + // Pluto frequency settings + public static UInt32 rxqrg = 739750000; // baseband QRG of lower beacon, RX tuner = this value - 30kHz (default for 25MHz LNB) + public static UInt32 txqrg = 2400250000;// baseband QRG of lower beacon, TX tuner = this value - 30kHz + public static int RXoffset = 280000; // Tuner: 470 + Offset: 280 = 750kHz (mid Beacon) + public static int TXoffset = 280000; // Tuner: 470 + Offset: 280 = 750kHz (mid Beacon) + public static int RXTXoffset = 0; // offset between RX and TX + public static int lastRXoffset = 280000; + public static int lastTXoffset = 280000; + public static UInt32 calbasefreq = 439000000; // base frequency for calibration + public static UInt32 calfreq; // same as rxqrg, but used during offset calibration + public static int rfoffset = 0; // Pluto's TCXO offset to RX/TX frequency + public static int lnboffset = 0; // LNB offset to RX frequency + + + static Process cmdtrx = null; + public static bool StartQO100trx(bool start = true) + { + if (statics.ostype == 0) return false; + + // kill old processes already running + killall(cmdtrx, "trxdriver"); + + if (start == true) + { + // starte Prozesse + try + { + if (!File.Exists("trxdriver")) return false; + cmdtrx = new Process(); + cmdtrx.StartInfo.FileName = "trxdriver"; + + if (cmdtrx != null) + { + cmdtrx.StartInfo.WindowStyle = ProcessWindowStyle.Normal;// .Hidden; + cmdtrx.StartInfo.Arguments = ""; + cmdtrx.Start(); + Console.WriteLine("trxdriver started"); + Thread.Sleep(100); + } + } + catch { return false; } + + // and load last QRGs from gile + try + { + using (BinaryReader sw = new BinaryReader(new FileStream(statics.getHomePath("", "qrg.lst"), FileMode.Open))) + { + RXoffset = sw.ReadInt32(); + TXoffset = sw.ReadInt32(); + } + } + catch { } + } + return true; + } + + static Process cmdmixer = null; + public static bool StartMixer(bool start = true) + { + if (statics.ostype == 0) return false; + + // kill old processes already running + killall(cmdmixer, "pavucontrol"); + + if (start == true) + { + // starte Prozesse + try + { + cmdmixer = new Process(); + cmdmixer.StartInfo.FileName = "pavucontrol"; + + if (cmdmixer != null) + { + cmdmixer.StartInfo.WindowStyle = ProcessWindowStyle.Normal;// .Hidden; + cmdmixer.StartInfo.Arguments = ""; + cmdmixer.Start(); + Console.WriteLine("pavucontrol started"); + Thread.Sleep(100); + } + } + catch { return false; } + } + return true; + } + + static public void killall(Process cmd, String s) + { + // kill a Linux process + try + { + if (cmd != null) + cmd.Kill(); + cmd = null; + + Process proc = new Process(); + proc.EnableRaisingEvents = false; + proc.StartInfo.FileName = "killall"; + proc.StartInfo.UseShellExecute = false; + proc.StartInfo.RedirectStandardOutput = true; + proc.OutputDataReceived += (sender, args) => { }; // schreibe Output ins nichts + proc.StartInfo.RedirectStandardError = true; + proc.ErrorDataReceived += (sender, args) => { }; // schreibe Output ins nichts + proc.StartInfo.Arguments = s; + proc.Start(); + proc.WaitForExit(); + Thread.Sleep(100); + } + catch { } + } + + public static string ByteArrayToStringUtf8(byte[] arr, int offset = 0) + { + Byte[] ba = new byte[arr.Length]; + int dst = 0; + for (int i = offset; i < arr.Length; i++) + { + if (arr[i] != 0) ba[dst++] = arr[i]; + } + Byte[] ban = new byte[dst]; + Array.Copy(ba, ban, dst); + + System.Text.UTF8Encoding enc = new System.Text.UTF8Encoding(); + + return enc.GetString(ban); + } + + public static byte[] StringToByteArrayUtf8(string str) + { + System.Text.UTF8Encoding enc = new System.Text.UTF8Encoding(); + return enc.GetBytes(str); + } + + public static String getHomePath(String subpath, String filename) + { + String deli = "/"; + if (statics.ostype == 0) deli = "\\"; + + //String home = Application.UserAppDataPath; + String home = Environment.GetFolderPath(Environment.SpecialFolder.UserProfile); + + home = home + deli; + try { Directory.CreateDirectory(home); } catch { } + + // if not exists, create subfolder "oscardata" + if (subpath.Length > 0) + try + { + home += subpath + deli; + Directory.CreateDirectory(home); + } + catch { } + + return home + filename; + } + + // Culture invariant conversion + + public static double MyToDouble(String s) + + { + double r = 0; + + try + { + s = s.Replace(',', '.'); + r = Convert.ToDouble(s, System.Globalization.CultureInfo.InvariantCulture); + } + catch + { + } + return r; + + } + + public static void sendBaseQRG(UInt32 newrx = 0) + { + UInt32 baserx = rxqrg; + if (lnboffset > 0) + baserx += (UInt32)lnboffset; + if (lnboffset < 0) + baserx -= (UInt32)(-lnboffset); + + Byte[] txb = new Byte[9]; + txb[0] = 8; + if (newrx == 0) + { + //Console.WriteLine("*********************************** " + statics.rxqrg + " * " + statics.txqrg); + txb[1] = (Byte)(baserx >> 24); + txb[2] = (Byte)(baserx >> 16); + txb[3] = (Byte)(baserx >> 8); + txb[4] = (Byte)(baserx & 0xff); + } + else + { + //Console.WriteLine("*********************************** " + newrx + " * " + statics.txqrg); + txb[1] = (Byte)(newrx >> 24); + txb[2] = (Byte)(newrx >> 16); + txb[3] = (Byte)(newrx >> 8); + txb[4] = (Byte)(newrx & 0xff); + } + txb[5] = (Byte)(txqrg >> 24); + txb[6] = (Byte)(txqrg >> 16); + txb[7] = (Byte)(txqrg >> 8); + txb[8] = (Byte)(txqrg & 0xff); + Udp.UdpSendData(txb); + } + + // Pluto TCXO correction value, for RX and TX + public static void sendReferenceOffset(int hz = 0) + { + if (hz < -12000) hz = -12000; + if (hz > 12000) hz = 12000; + + statics.rfoffset = hz; + + //Console.WriteLine("Set Clock Reference: " + statics.rfoffset); + + int val = hz + 12000; // make it always positive + + Byte[] txb = new Byte[5]; + txb[0] = 15; + txb[1] = (Byte)(val >> 24); + txb[2] = (Byte)(val >> 16); + txb[3] = (Byte)(val >> 8); + txb[4] = (Byte)(val & 0xff); + + Udp.UdpSendData(txb); + } + + // send tuned RX and TX offsets + public static void sendRXTXoffset() + { + if (RXoffset < 0) RXoffset = 0; + if (RXoffset > 560000) RXoffset = 560000; + if (TXoffset < 0) TXoffset = 0; + if (TXoffset > 560000) TXoffset = 560000; + + int rxoff = RXoffset; + + Byte[] txb = new Byte[9]; + txb[0] = 0; + txb[1] = (Byte)(rxoff >> 24); + txb[2] = (Byte)(rxoff >> 16); + txb[3] = (Byte)(rxoff >> 8); + txb[4] = (Byte)(rxoff & 0xff); + txb[5] = (Byte)(TXoffset >> 24); + txb[6] = (Byte)(TXoffset >> 16); + txb[7] = (Byte)(TXoffset >> 8); + txb[8] = (Byte)(TXoffset & 0xff); + + Udp.UdpSendData(txb); + + // and save into a file + try + { + using (BinaryWriter sw = new BinaryWriter(new FileStream(statics.getHomePath("", "qrg.lst"),FileMode.Create))) + { + sw.Write(RXoffset); + sw.Write(TXoffset); + } + } + catch { } + } + + static public void OpenUrl(string url) + { + try + { + Process.Start(url); + } + catch + { + Process.Start("xdg-open", url); + } + } + + static public string RunExternalProgram(string filename, string arguments = null) + { + var process = new Process(); + + process.StartInfo.FileName = filename; + if (!string.IsNullOrEmpty(arguments)) + process.StartInfo.Arguments = arguments; + + process.StartInfo.CreateNoWindow = true; + process.StartInfo.WindowStyle = ProcessWindowStyle.Hidden; + process.StartInfo.UseShellExecute = false; + + process.StartInfo.RedirectStandardError = true; + process.StartInfo.RedirectStandardOutput = true; + var stdOutput = new StringBuilder(); + process.OutputDataReceived += (sender, args) => stdOutput.AppendLine(args.Data); // Use AppendLine rather than Append since args.Data is one line of output, not including the newline character. + + string stdError = null; + try + { + process.Start(); + process.BeginOutputReadLine(); + stdError = process.StandardError.ReadToEnd(); + process.WaitForExit(); + } + catch + { + return ""; + } + + if (process.ExitCode == 0) + return stdOutput.ToString(); + + return ""; + } + + static private string Format(string filename, string arguments) + { + return "'" + filename + + ((string.IsNullOrEmpty(arguments)) ? string.Empty : " " + arguments) + + "'"; + } + } + + public class Bandentry + { + public Color col; + public int from; + public String text; + public int textpos; + + public Bandentry(Color c, int f, String txt, int tp) + { + col = c; + from = f; + text = txt; + textpos = tp; + } + } + + public class Bandplan + { + public Bandentry[] be = new Bandentry[11]; + + public Bandplan() + { + be[0] = new Bandentry(Color.FromArgb(255,255,0,0), 10489500, "B", 10489500); + be[1] = new Bandentry(Color.FromArgb(0xff, 0x00, 0xaf, 0xef), 10489505, "CW", 10489510); + be[2] = new Bandentry(Color.FromArgb(0xff, 0x6f, 0x2f, 0x9f), 10489540, "NB dig", 10489550); + be[3] = new Bandentry(Color.FromArgb(0xff, 0xfe, 0xbf, 0x00), 10489580, "digital", 10489605); + be[4] = new Bandentry(Color.FromArgb(0xff, 0x91, 0xcf, 0x4f), 10489650, "SSB only", 10489688); + be[5] = new Bandentry(Color.FromArgb(0xff, 0xff, 0x00, 0x00), 10489745, "B", 10489748); + be[6] = new Bandentry(Color.FromArgb(0xff, 0x91, 0xcf, 0x4f), 10489755, "SSB only", 10489790); + be[7] = new Bandentry(Color.FromArgb(0xff, 0xc5, 0x59, 0x10), 10489850, "MIX", 10489850); + be[8] = new Bandentry(Color.FromArgb(0xff, 0xb5, 0xa9, 0x10), 10489870, "MIXED + Contest", 10489905); + be[9] = new Bandentry(Color.FromArgb(0xff, 0xff, 0x00, 0x00), 10489990, "B", 10489992); + be[10] =new Bandentry(Color.FromArgb(0xff, 0xff, 0x00, 0x00),10490000, "---", 0); + } + } +} diff --git a/trxGui/trxGui.csproj b/trxGui/trxGui.csproj new file mode 100644 index 0000000..41d6dc8 --- /dev/null +++ b/trxGui/trxGui.csproj @@ -0,0 +1,346 @@ + + + + + Debug + AnyCPU + {B4D0AE1A-EF2F-413D-B67A-AB7CBDD6B4BB} + WinExe + trxGui + qo100trx + v4.5.2 + 512 + true + true + + + AnyCPU + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + AnyCPU + pdbonly + true + ..\Release\ + TRACE + prompt + 4 + + + + ..\ColorSlider\bin\Release\ColorSlider.dll + + + + + + + + + + + + + + + + + Form + + + Form1.cs + + + Form + + + Form2_agc.cs + + + Form + + + Form_info.cs + + + Form + + + Form_reference.cs + + + Form + + + Form_screen.cs + + + Form + + + Form_setup.cs + + + + + + + + Form1.cs + + + Form2_agc.cs + + + Form_info.cs + + + Form_reference.cs + + + Form_screen.cs + + + Form_setup.cs + + + ResXFileCodeGenerator + Resources.Designer.cs + Designer + + + True + Resources.resx + True + + + SettingsSingleFileGenerator + Settings.Designer.cs + + + True + Settings.settings + True + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/trxGui/trxGui.sln b/trxGui/trxGui.sln new file mode 100644 index 0000000..481153e --- /dev/null +++ b/trxGui/trxGui.sln @@ -0,0 +1,25 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 16 +VisualStudioVersion = 16.0.31205.134 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "trxGui", "trxGui.csproj", "{B4D0AE1A-EF2F-413D-B67A-AB7CBDD6B4BB}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {B4D0AE1A-EF2F-413D-B67A-AB7CBDD6B4BB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {B4D0AE1A-EF2F-413D-B67A-AB7CBDD6B4BB}.Debug|Any CPU.Build.0 = Debug|Any CPU + {B4D0AE1A-EF2F-413D-B67A-AB7CBDD6B4BB}.Release|Any CPU.ActiveCfg = Release|Any CPU + {B4D0AE1A-EF2F-413D-B67A-AB7CBDD6B4BB}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {10D174B1-F81E-45B0-B63E-3AE5CC39CCF4} + EndGlobalSection +EndGlobal diff --git a/trxGui/udp.cs b/trxGui/udp.cs new file mode 100755 index 0000000..b15a6fb --- /dev/null +++ b/trxGui/udp.cs @@ -0,0 +1,699 @@ +using System; +using System.Collections; +using System.Drawing; +using System.Net; +using System.Net.Sockets; +using System.Threading; + +namespace trxGui +{ + public static class Udp + { + static int bigSpecW, bigSpecH, smallSpecW, smallSpecH; + static int bigWFW, bigWFH, smallWFW, smallWFH; + + static public UdpQueue bigspecQ = new UdpQueue(); + static public UdpQueue smallspecQ = new UdpQueue(); + static public UdpQueue bigWFQ = new UdpQueue(); + static public UdpQueue smallWFQ = new UdpQueue(); + static public UdpQueue uq_tx = new UdpQueue(); + static public UdpQueue uq_rotary = new UdpQueue(); + + static Bitmap bmBigWF, bmSmallWF; + + static color col = new color(); + + // this threads handle udp RX and TX + static Thread udprx_thread; + static Thread udptx_thread; + + public static void InitUdp() + { + UpdateSize(); + + // create thread for UDP RX + udprx_thread = new Thread(new ThreadStart(Udprxloop)); + udprx_thread.Start(); + + // create thread for UDP TX + udptx_thread = new Thread(new ThreadStart(Udptxloop)); + udptx_thread.Start(); + } + + public static void UpdateSize() + { + bigSpecW = statics.panel_bigspec_Width; + bigSpecH = statics.panel_bigspec_Height; + + smallSpecW = statics.panel_smallspec_Width; + smallSpecH = statics.panel_smallspec_Height; + + bigWFW = statics.panel_bigwf_Width; + bigWFH = statics.panel_bigwf_Height; + + smallWFW = statics.panel_smallwf_Width; + smallWFH = statics.panel_smallwf_Height; + + bmBigWF = new Bitmap(bigWFW, bigWFH); + bmSmallWF = new Bitmap(smallWFW, smallWFH); + } + + static void Udptxloop() + { + DateTime dt = DateTime.UtcNow; + UdpClient udpc = new UdpClient(); + + while (statics.running) + { + bool wait = true; + if (uq_tx.Count() > 0 && statics.ModemIP != null && statics.ModemIP.Length >= 7) + { + // Control Message: send immediately + Byte[] b = uq_tx.Getarr(); + udpc.Send(b, b.Length, statics.ModemIP, statics.UdpTXport); + wait = false; + } + + if(wait) Thread.Sleep(10); + } + } + + static void Udprxloop() + { + // define UDP port + UdpClient udpc = new UdpClient(statics.UdpRXport); + udpc.Client.ReceiveTimeout = 100; + + while (statics.running) + { + try + { + // receive data from UDP port + IPEndPoint RemoteEndpoint = new IPEndPoint(IPAddress.Any, 0); + Byte[] rxarr = udpc.Receive(ref RemoteEndpoint); + if (rxarr != null) + { + // Data received: + // RemoteEndpoint.Address ... IP address of the sender + IPAddress ipad = RemoteEndpoint.Address; + statics.ModemIP = ipad.ToString(); + //Console.WriteLine(statics.ModemIP); + // RemoteEndpoint.Port ... port + // b[0] ... Type of data + // b+1 ... Byte array containing the data + int rxtype = rxarr[0]; + Byte[] b = new byte[rxarr.Length - 1]; + Array.Copy(rxarr, 1, b, 0, b.Length); + + //Console.WriteLine(rxtype + " len " + b.Length); + + // check bitmap queues to avoid unnecessary graphic operations + int q1 = bigspecQ.Count(); + int q2 = smallWFQ.Count(); + int q3 = bigWFQ.Count(); + int q4 = smallspecQ.Count(); + + // for slower CPUs: allow only one graphics item in the buffer + // faster CPUs: allow more graphic updates + int maxfill = 1; + if (statics.cpuspeed == 0) maxfill = 2; // only for fast cpus + + if (rxtype == 0 && q1 < maxfill) + { + // big Spectrum, mid values + int[] arr = getSpecArr(b); + drawBigSpec(arr); + } + + if (rxtype == 1 && q4 < maxfill) + { + // small Spectrum + int[] arr = getSpecArr(b); + drawSmallSpec(arr); + } + + if (rxtype == 2 && q3 < maxfill) + { + + // big WF (raw - no mid - values) + int[] arr = getSpecArr(b); + //DateTime dts = DateTime.UtcNow; + drawBigWF(arr); + //DateTime dtact = DateTime.UtcNow; + //TimeSpan ts = dtact - dts; + //Console.WriteLine("drawtime: [ms] " + ts.TotalMilliseconds); + } + + if (rxtype == 3 && q2 < maxfill) + { + // small WF + int[] arr = getSpecArr(b); + drawSmallWF(arr); + } + + if(rxtype == 4) + { + // b contains audio devices and init status + UInt16 driversn = b[0]; + driversn <<= 8; + driversn += b[1]; + //Console.WriteLine("Driver SN:" + driversn); + statics.driver_serno = driversn; + String s = statics.ByteArrayToStringUtf8(b, 6); + //Console.WriteLine("Audio Devices:" + s); + String[] sa1 = s.Split(new char[] { '^' }); + statics.AudioPBdevs = sa1[0].Split(new char[] { '~' }); + statics.AudioCAPdevs = sa1[1].Split(new char[] { '~' }); + statics.GotAudioDevices = 1; + } + + if (rxtype == 5) + { + int v = b[0]; + v <<= 8; + v |= b[1]; + v <<= 8; + v |= b[2]; + v <<= 8; + v |= b[3]; + statics.noiselevel = v * 50 / 51; + + v = b[4]; + v <<= 8; + v |= b[5]; + v <<= 8; + v |= b[6]; + v <<= 8; + v |= b[7]; + statics.maxlevel = v * 55 / 50; + + v = b[8]; + v <<= 8; + v |= b[9]; + v <<= 8; + v |= b[10]; + v <<= 8; + v |= b[11]; + statics.qsolevel = v; + + v = b[12]; + v <<= 8; + v |= b[13]; + v <<= 8; + v |= b[14]; + v <<= 8; + v |= b[15]; + statics.maxnoiselevel = v; + + v = b[16]; + v <<= 8; + v |= b[17]; + v <<= 8; + v |= b[18]; + v <<= 8; + v |= b[19]; + statics.difflevel = v; + + statics.hwptt = (b[20] == 1); + + //Console.WriteLine("noiselevel: " + statics.noiselevel + " maxnoiselevel: " + statics.maxnoiselevel + " difflevel: " + statics.difflevel); + //Console.WriteLine(statics.noiselevel + "level: " + (statics.qsolevel - statics.noiselevel)); + } + + if (rxtype == 6) + { + int v = b[0]; + v <<= 8; + v |= b[1]; + v <<= 8; + v |= b[2]; + v <<= 8; + v |= b[3]; + + statics.beaconoffset = v; + //Console.WriteLine("beaconoffset: " + statics.beaconoffset); + } + + if (rxtype == 7) + { + // number of rotary steps for frequency setting + int steps = (int)b[0] - 128; + uq_rotary.Add(steps); + } + + if (rxtype == 9) + { + int v = b[0]; + v <<= 8; + v |= b[1]; + v <<= 8; + v |= b[2]; + v <<= 8; + v |= b[3]; + + statics.corrfact = v; + } + + if (rxtype == 10) + { + statics.sendtone = b[0]; + } + } + } + catch { } + } + } + + static int scaleY(int val, int valmin, int valmax, int max) + { + // scale + int r = max * (val - valmin) / (valmax - valmin); + + // revers up/down + return max - r; + } + + static int scaleX(int x, int maxx, int width) + { + return x * width / maxx; + } + + static int [] getSpecArr(Byte [] arr) + { + int [] sa = new int [arr.Length / 2]; + + int didx = 0; + for (int i = 0; i < arr.Length; i += 2) + { + UInt32 uv = arr[i]; + uv <<= 8; + uv |= arr[i + 1]; + + sa[didx++] = (int)uv; + } + return sa; + } + + + static Pen penmarker = new Pen(Brushes.Green, 2); + static Pen penmarkerTX = new Pen(Brushes.Red, 2); + static Brush brs = new SolidBrush(Color.FromArgb(60,60,60)); + static Pen penmarkerLN = new Pen(brs, 2); + static Font rxtx = new Font("Verdana", 8.0f); + static private Bandplan bp = new Bandplan(); + + // palette + static Color[] col_specfill = { Color.Blue, Color.FromArgb(255, 80, 80), Color.Green, Color.LightGray }; + static Color[] col_specline = { Color.LightGreen, Color.Yellow, Color.Cyan, Color.White }; + + static SolidBrush[] br_spedFill = { new SolidBrush(col_specfill[0]), new SolidBrush(col_specfill[1]), new SolidBrush(col_specfill[2]), new SolidBrush(col_specfill[3]) }; + static Pen[] penline = { new Pen(col_specline[0], 1), new Pen(col_specline[1], 1), new Pen(col_specline[2], 1), new Pen(col_specline[3], 1) }; + + static void drawBigSpec(int[] arr) + { + int noiselevel = statics.noiselevel * 54/50; + + Bitmap bmbigspec = new Bitmap(bigSpecW, bigSpecH); + // using gibt Ressourcen von gr nicht frei !!! + // mono Update auf >= 6.12.xx erforderlich !!! + using (Graphics gr = Graphics.FromImage(bmbigspec)) + { + // Make a Polyline + Point[] poly = new Point[arr.Length + 2]; + poly[0] = new Point(0, bigSpecH - 1); + poly[arr.Length + 2 - 1] = new Point(bigSpecW - 1, bigSpecH - 1); + + for (int i = 0; i < arr.Length; i++) + { + int val = scaleY(arr[i], noiselevel, statics.maxlevel, bigSpecH); + int xi = scaleX(i, arr.Length, bigSpecW); + poly[i + 1] = new Point(xi, val); + } + + gr.FillRectangle(Brushes.Black, 0, 0, bigSpecW, bigSpecH); + gr.FillPolygon(br_spedFill[statics.palette], poly); + gr.DrawPolygon(penline[statics.palette], poly); + + // vertical lines at specific frequencies + penmarkerLN.DashPattern = new float[] { 1.0f, 1.0f }; + if (statics.bandplan_mode == 0) + { + for (int i = 0; i < bp.be.Length; i++) + { + int xs = qrgToPixelpos(bp.be[i].from); + xs = xs * bigSpecW / 1120; + gr.DrawLine(penmarkerLN, xs, 0, xs, bigSpecH); + } + } + else + { + for (int qrg = 10489500; qrg <= 10490000; qrg += 50) + { + int spos = qrgToPixelpos(qrg); + spos = spos * bigSpecW / 1120; + gr.DrawLine(penmarkerLN, spos, 0, spos, bigSpecH); + } + } + + // green vertical line at RX frequency + // red vertical line at TX frequency + int x = statics.RXoffset * 2 / 1000; + x = x * bigSpecW / 1120; + int xtx = statics.TXoffset * 2 / 1000; + xtx = xtx * bigSpecW / 1120; + int xydiff = Math.Abs(x - xtx); + + penmarker.DashPattern = new float[] { 2.0f, 2.0f }; + gr.DrawLine(penmarker, x, 20, x, bigSpecH); + + // red vertical line at TX frequency + penmarkerTX.DashPattern = new float[] { 2.0f, 2.0f }; + gr.DrawLine(penmarkerTX, xtx, 24, xtx, bigSpecH - 4); + + if (xydiff > 10) + { + gr.DrawString("RX", rxtx, Brushes.LightGreen, x - 6, 0); + gr.DrawString("TX", rxtx, Brushes.LightCoral, xtx - 6, 0); + } + else + { + gr.DrawString("RX/TX", rxtx, Brushes.White, x - 15, 0); + } + } + bigspecQ.Add(bmbigspec); + } + + + static int qrgToPixelpos(int qrg) + { + qrg -= 10489000; // rest is kHz + qrg -= 470; + return qrg * 2; + } + + static Font dBfont = new Font("Arial Black", 9.0f); + static Brush br = new SolidBrush(Color.FromArgb(30,30,20)); + + static void drawSmallSpec(int[] arr) + { + Pen dotpen = new Pen(Brushes.Yellow, 1); + dotpen.DashPattern = new float[] { 2.0f, 2.0f }; + + Bitmap bmsmallspec = new Bitmap(smallSpecW, smallSpecH); + using (Graphics gr = Graphics.FromImage(bmsmallspec)) + { + // Make a Polyline + Point[] poly = new Point[arr.Length + 2]; + poly[0] = new Point(0, smallSpecH - 1); + poly[arr.Length + 2 - 1] = new Point(smallSpecW - 1, smallSpecH - 1); + + for (int i = 0; i < arr.Length; i++) + { + int val = scaleY(arr[i], statics.noiselevel, statics.maxlevel, smallSpecH); + int xi = scaleX(i, arr.Length, smallSpecW); + poly[i + 1] = new Point(xi, val); + } + + gr.FillRectangle(Brushes.Black, 0, 0, bigSpecW, smallSpecH); + + gr.FillRectangle(br, 14150 * bigSpecW / 28000, 0, 2750 * bigSpecW / 28000, smallSpecH); + gr.FillPolygon(br_spedFill[statics.palette], poly); + gr.DrawPolygon(penline[statics.palette], poly); + + // calculate level of the QSO over noise + int dB = 0; + int qlev = statics.difflevel; // qsolevel - statics.maxnoiselevel; + // ignore values below 800, these are too small to evaluate + // above 400: 120/dB + //Console.WriteLine("qlev: " + qlev + " nl " + statics.noiselevel + " mnl" + statics.maxnoiselevel); + if(qlev >= 800) + { + qlev -= 400; + dB = qlev / 120 + 6; // +6 because 400 is +6dB + String s = "+" + dB.ToString() + " dB"; + gr.DrawString(s, dBfont, Brushes.Yellow, smallSpecW / 2 + 4, 0); + } + + // tuning (middle) line + gr.DrawLine(dotpen, smallSpecW / 2, 0, smallSpecW / 2, smallSpecH); + } + smallspecQ.Add(bmsmallspec); + } + + static int scaleYWF(int val, int valmin, int valmax, int max) + { + // scale + return max * (val - valmin) / (valmax - valmin); + } + + static void drawBigWF(int[] arr) + { + int lineincrement = statics.cpuspeed + 1; + // create a new bitmap + Bitmap bmnew = new Bitmap(bigWFW, bigWFH); + using (Graphics gr = Graphics.FromImage(bmnew)) + { + + // copy existing bitmap into bmnew, n lines lower + gr.DrawImage(bmBigWF, 0, lineincrement); + + for (int i = 0; i < arr.Length; i++) + { + // scale color + int v = 255 - scaleY(arr[i], statics.noiselevel, statics.maxlevel * 47 / 50, 255); + if (v < 0) v = 0; + if (v > 255) v = 255; + //Console.WriteLine(arr[i] + ": " + v); + + int xi = scaleX(i, arr.Length, bigWFW); + gr.FillRectangle(col.getSolidBrush(v), xi, 0, xi, lineincrement); + } + + } + // copy the new bitmap back + using (Graphics grbm = Graphics.FromImage(bmBigWF)) + grbm.DrawImage(bmnew, 0, 0); + + using (Graphics gr = Graphics.FromImage(bmnew)) + { + // green vertical line at RX frequency + // red vertical line at TX frequency + int x = statics.RXoffset * 2 / 1000; + x = x * bigWFW / 1120; + int xtx = statics.TXoffset * 2 / 1000; + xtx = xtx * bigWFW / 1120; + int xydiff = Math.Abs(x - xtx); + + penmarker.DashPattern = new float[] { 2.0f, 2.0f }; + gr.DrawLine(penmarker, x, 4, x, bigWFH); + + // red vertical line at TX frequency + penmarkerTX.DashPattern = new float[] { 2.0f, 2.0f }; + gr.DrawLine(penmarkerTX, xtx, 0, xtx, bigWFH - 4); + } + + bigWFQ.Add(bmnew); + } + + static void drawSmallWF(int[] arr) + { + int lineincrement = statics.cpuspeed + 1; + + // create a new bitmap + Bitmap bmnew = new Bitmap(smallWFW, smallWFH); + using (Graphics gr = Graphics.FromImage(bmnew)) + { + // copy existing bitmap into bmnew, one line lower + gr.DrawImage(bmSmallWF, 0, lineincrement); + + for (int i = 0; i < arr.Length; i++) + { + // scale color + int v = 255 - scaleY(arr[i], statics.noiselevel * 48/50, statics.maxlevel * 47 / 50, 255); + //Console.WriteLine(arr[i] + ": " + v); + + int xi = scaleX(i, arr.Length, smallWFW); + gr.FillRectangle(col.getSolidBrush(v), xi, 0, xi, lineincrement); + } + } + + // copy the new bitmap back + using (Graphics grbm = Graphics.FromImage(bmSmallWF)) + { + grbm.DrawImage(bmnew, 0, 0); + } + + // draw scales after scrolling + using (Graphics gr = Graphics.FromImage(bmnew)) + { + // tuning (middle) line + Pen dotpen = new Pen(Brushes.Yellow, 1); + dotpen.DashPattern = new float[] { 2.0f, 2.0f }; + int xi = smallWFW / 2; + gr.DrawLine(dotpen, xi, 0, xi, smallWFH); + + // 25Hz per pixel: 120px per 3kHz + Pen dotgraypen = new Pen(Brushes.DarkGray, 1); + dotgraypen.DashPattern = new float[] { 1.0f, 3.0f }; + for (int i=120; i<500; i+=120) + { + xi = smallWFW / 2 + i * smallWFW / 1120; + gr.DrawLine(dotgraypen, xi, 0, xi, smallWFH); + } + for (int i = -120; i > -500; i -= 120) + { + xi = smallWFW / 2 + i * smallWFW / 1120; + gr.DrawLine(dotgraypen, xi, 0, xi, smallWFH); + } + } + + smallWFQ.Add(bmnew); + } + + public static Bitmap getBigSpecBitmap() + { + if (bigspecQ.Count() == 0) return null; + + return bigspecQ.GetBitmap(); + } + + public static bool getBigSpecBitmap_avail() + { + if (bigspecQ.Count() == 0) return false; + return true; + } + + public static Bitmap getSmallSpecBitmap() + { + if (smallspecQ.Count() == 0) return null; + + return smallspecQ.GetBitmap(); + } + + public static bool getSmallSpecBitmap_avail() + { + if (smallspecQ.Count() == 0) return false; + return true; + } + + public static Bitmap getBigWFBitmap() + { + if (bigWFQ.Count() == 0) return null; + + return bigWFQ.GetBitmap(); + } + + public static bool getBigWFBitmap_avail() + { + if (bigWFQ.Count() == 0) return false; + return true; + } + + public static Bitmap getSmallWFBitmap() + { + if (smallWFQ.Count() == 0) return null; + + return smallWFQ.GetBitmap(); + } + + public static bool getSmallWFBitmap_avail() + { + if (smallWFQ.Count() == 0) return false; + return true; + } + + public static void UdpSendData(Byte[] b) + { + uq_tx.Add(b); + } + + public static int GetRotary() + { + if (uq_rotary.Count() == 0) return 0; + return uq_rotary.Getint(); + } + } + + // this class is a thread safe queue wich is used + // to exchange data with the UDP RX/TX threads + public class UdpQueue + { + Queue myQ = new Queue(); + + public void Add(Byte[] b) + { + lock (myQ.SyncRoot) + { + myQ.Enqueue(b); + } + } + + public void Add(int b) + { + lock (myQ.SyncRoot) + { + myQ.Enqueue(b); + } + } + + public void Add(Bitmap bm) + { + lock (myQ.SyncRoot) + { + myQ.Enqueue(bm); + } + } + + public Bitmap GetBitmap() + { + Bitmap b; + + lock (myQ.SyncRoot) + { + b = (Bitmap)myQ.Dequeue(); + } + return b; + } + + public Byte[] Getarr() + { + Byte[] b; + + lock (myQ.SyncRoot) + { + b = (Byte[])myQ.Dequeue(); + } + return b; + } + + public int Getint() + { + int b; + + lock (myQ.SyncRoot) + { + b = (int)myQ.Dequeue(); + } + return b; + } + + public int Count() + { + int result; + + lock (myQ.SyncRoot) + { + result = myQ.Count; + } + return result; + } + + public void Clear() + { + lock (myQ.SyncRoot) + { + myQ.Clear(); + } + } + } +} diff --git a/tx.cpp b/tx.cpp new file mode 100644 index 0000000..87b10b0 --- /dev/null +++ b/tx.cpp @@ -0,0 +1,107 @@ +/* +* Adalm Pluto Driver +* ================== +* Author: DJ0ABR +* +* (c) DJ0ABR +* www.dj0abr.de +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 2 of the License, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You 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. +* +* ========================= +* SSB Transmitter +* ========================= +* +*/ + +/* +* reads len samples from device id into psamp +* returns: number of values written to psamp , -1=error +* id ... device id returned by kmaudio_startCapture +* psamp ... float array of length len getting the audio data (mono) +* len ... number of float values to write into psamp +* volume ... 0.0f..2.0f will be multiplied with the input sample +* wait ... 1=wait for data, 0=return if not enough data available (in this case psamp will return 0,0,0...) +* +* if resampling is required the number of returned samples may differ from the number of requested samples +* it can be larger, so the buffer psamp should be larger than "len" by factor 1.1 +*/ + +int kmaudio_readsamples(int id, float* psamp, int len, float volume, int wait); + + +#include "qo100trx.h" + +int TXoffsetfreq = 280000; + +void* tx_threadfunction(void* param); + +float sinus[4800]; + +void init_tx() +{ + pthread_t txthread; + pthread_create(&txthread, NULL, tx_threadfunction, NULL); + +#ifdef SINUSTEST + for(int i=0; i<4800; i++) + { + sinus[i] = (float)sin((double)(i%24)*2.0*M_PI/4800.0); + sinus[i] *= 10; + } +#endif +} + +void* tx_threadfunction(void* param) +{ + pthread_detach(pthread_self()); + + printf("entering TX loop, *** PID:%ld ***\n",syscall(SYS_gettid)); + while(keeprunning) + { + float f[4800]; + if(capidx != -1) + { + int ret = kmaudio_readsamples(capidx, f, 4800, 1.0f, 0); + if(ret) + { + if(audioloop) + { + // send back to sound output + if(pbidx != -1) + kmaudio_playsamples(pbidx,f,ret,1.0f); + } + else + { + #ifdef SINUSTEST + memcpy(f,sinus,sizeof(float)*4800); + #endif + // send to modulator + if(ptt) + { + upmix(f,ret,TXoffsetfreq); + } + } + } + else + usleep(1000); + } + else + usleep(1000); + } + printf("exit TX loop\n"); + pthread_exit(NULL); // self terminate this thread + return NULL; +} \ No newline at end of file diff --git a/tx.o b/tx.o new file mode 100644 index 0000000..8b17e61 Binary files /dev/null and b/tx.o differ diff --git a/udp/udp.cpp b/udp/udp.cpp new file mode 100644 index 0000000..e316e69 --- /dev/null +++ b/udp/udp.cpp @@ -0,0 +1,138 @@ +/* +* super simple UDP handler +* ======================== +* Author: DJ0ABR +* +* (c) DJ0ABR +* www.dj0abr.de +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 2 of the License, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You 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 +#include "udp.h" + +void* threadfunction(void* param); + +#define MAXUDPTHREADS 20 +RXCFG udprxcfg[MAXUDPTHREADS]; +int rxcfg_idx = 0; + +// start UDP reception +// sock ... pointer to a socket (just a pointer to an int) +// port ... own port, messages only to this port are received +// rxfunc ... pointer to a callback function, will be called for received data +// keeprunning ... pointer to an int. If it is set to 0, the function exits +void UdpRxInit(int *sock, int port, void (*rxfunc)(uint8_t *, int, struct sockaddr_in*), int *keeprunning) +{ + if(rxcfg_idx >= MAXUDPTHREADS) + { + printf("max number of UDP threads\n"); + exit(0); + } + + udprxcfg[rxcfg_idx].sock = sock; + udprxcfg[rxcfg_idx].port = port; + udprxcfg[rxcfg_idx].rxfunc = rxfunc; + udprxcfg[rxcfg_idx].keeprunning = keeprunning; + + // bind port + struct sockaddr_in sin; + + + *sock = socket(PF_INET, SOCK_DGRAM, 0); + if (*sock == -1){ + printf("Failed to create Socket\n"); + exit(0); + } + + char enable = 1; + setsockopt(*sock, SOL_SOCKET, SO_REUSEADDR, &enable, sizeof(int)); + + memset(&sin, 0, sizeof(struct sockaddr_in)); + sin.sin_family = AF_INET; + sin.sin_port = htons(port); + sin.sin_addr.s_addr = INADDR_ANY; + + if (bind(*sock, (struct sockaddr *)&sin, sizeof(struct sockaddr_in)) != 0) + { + printf("Failed to bind socket, port:%d\n",port); + close(*sock); + exit(0); + } + + //printf("port %d sucessfully bound\n", port); + + // port sucessfully bound + // create the receive thread + pthread_t rxthread; + pthread_create(&rxthread, NULL, threadfunction, &(udprxcfg[rxcfg_idx])); + rxcfg_idx++; +} + +void* threadfunction(void* param) +{ + socklen_t fromlen; + pthread_detach(pthread_self()); + RXCFG rxcfg; + memcpy((uint8_t *)(&rxcfg), (uint8_t *)param, sizeof(RXCFG)); + int recvlen; + const int maxUDPpacketsize = 100000; + char rxbuf[maxUDPpacketsize]; + struct sockaddr_in fromSock; + fromlen = sizeof(struct sockaddr_in); + printf("entering UDP thread, *** PID:%ld ***\n",syscall(SYS_gettid)); + while(*rxcfg.keeprunning) + { + recvlen = recvfrom(*rxcfg.sock, rxbuf, maxUDPpacketsize, 0, (struct sockaddr *)&fromSock, &fromlen); + if (recvlen > 0) + { + // data received, send it to callback function + (*rxcfg.rxfunc)((uint8_t *)rxbuf,recvlen, &fromSock); + } + if (recvlen < 0) + { + } + } + pthread_exit(NULL); // self terminate this thread + return NULL; +} + +// send UDP message +// this function can always be used without any initialisation +void sendUDP(char *destIP, int destPort, uint8_t *pdata, int len) +{ + int sockfd; + struct sockaddr_in servaddr; + + memset(&servaddr, 0, sizeof(servaddr)); + servaddr.sin_family = AF_INET; + servaddr.sin_port = htons(destPort); + servaddr.sin_addr.s_addr=inet_addr(destIP); + + // Creating socket file descriptor + if ( (sockfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0 ) { + printf("sendUDP: socket creation failed\n"); + exit(0); + } + + ssize_t sent = sendto(sockfd, (char *)pdata, len, 0, (const struct sockaddr *) &servaddr, sizeof(servaddr)); + if((int)sent != len) + { + printf("UDP tx error %d\n",(int)sent); + } + close(sockfd); +} diff --git a/udp/udp.h b/udp/udp.h new file mode 100644 index 0000000..00a8329 --- /dev/null +++ b/udp/udp.h @@ -0,0 +1,19 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +typedef struct { + int *sock; + int port; + void (*rxfunc)(uint8_t *, int, struct sockaddr_in*); + int *keeprunning; +} RXCFG; + +void UdpRxInit(int *sock, int port, void (*rxfunc)(uint8_t *, int, struct sockaddr_in*), int *keeprunning); +void sendUDP(char *destIP, int destPort, uint8_t *pdata, int len); diff --git a/udp/udp.o b/udp/udp.o new file mode 100644 index 0000000..f2a9ca0 Binary files /dev/null and b/udp/udp.o differ diff --git a/version.txt b/version.txt new file mode 100644 index 0000000..c4597e5 --- /dev/null +++ b/version.txt @@ -0,0 +1 @@ +173